]> git.vomp.tv Git - vompclient.git/blob - vmedialist.cc
Windows fixes
[vompclient.git] / vmedialist.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 /*
21    Hints for the directory playing:
22    depending on the configValue directoryMode: none|audio|picture|count
23    it will be decided what to do if a directory is selected with [PLAY]:
24     none:    as currently - simply go into
25     audio:   start picture viewer and audio, audio on top
26     picture: start picture viewer and audio, picture on top
27     count:   count occurence of both types, decide for audio/picture
28    Synchronization is done via the "directoryDone" call,
29    this is issued if the Viewer top engine has finished it's list
30    (getMedia returned 0)
31    We will the go back one level and continue
32    Currently we will traverse to new directories only at the beginning 
33    or the real end of each dir.
34    This is handled only by playAll (never by getMedia).
35    As we sort always in a way that all directories come first this should be OK.
36    there are 2 situations where we give the user a chance to interrupt (this is handled
37    by starting a 10ms timer and afterwrads sending a PLAYER_EVENT with the timer ref as
38    parameter):
39    empty directory found - timer 1 - call directoryDone
40    after changing to a new directory the first entry is again a directory - timer 2 - playAll
41    controlling flags:
42      directoryPlaying: globally set as long as we play a dir, reset on any key press here
43      startLevel:       in DirList - set to the level where we started playing, if we are
44                        back to this playing is finished
45      configuredDirmode: configured mode
46      
47 */
48
49
50
51 #include <vector>
52 #include <time.h>
53 #include <string.h>
54 #ifndef WIN32
55 #include "unistd.h"
56 #endif
57 #include "vmedialist.h"
58
59 #include "vmediaview.h"
60 #include "vvideomedia.h"
61 #include "input.h"
62 #include "wsymbol.h"
63 #include "boxstack.h"
64 #include "colour.h"
65 #include "video.h"
66 #include "i18n.h"
67 #include "vdr.h"
68 #include "messagequeue.h"
69 #include "vinfo.h"
70 #include "media.h"
71 #include "mediaplayer.h"
72 #include "log.h"
73 #include "localmediafile.h"
74 #include "mediaoptions.h"
75
76 //a ref count holder
77 class MediaListHolder {
78   public:
79     MediaListHolder(MediaList *l) {
80       _list=l;
81       _ref=1;
82     }
83     MediaList * list() {
84       return _list;
85     }
86     void ref() {
87       _ref++;
88       Log::getInstance()->log("##MLH",Log::DEBUG,"ref %p now %d",_list,_ref);
89     }
90     void unref() {
91       if (_ref >0 ) _ref--;
92       Log::getInstance()->log("##MLH",Log::DEBUG,"unref %p now %d",_list,_ref);
93       if (_ref == 0) delete this;
94     }
95     ~MediaListHolder() {
96       if (_list) delete _list;
97     }
98   private:
99     UINT _ref;
100     MediaList *_list;
101 };
102
103 class MediaDirectory {
104         private:
105     MediaURI *uri;
106                 int selection;
107                 int sortorder;
108                 ULONG mtype;
109     MediaListHolder *holder;
110         public:
111                 void setMediaType(ULONG n) {mtype=n;}
112                 void setSortorder(int s) {
113                         sortorder=s;
114                 }
115                 void setSelection(int s) {
116                         selection=s;
117                 }
118                 int getSelection() {
119                         return selection;
120                 }
121     bool move(ULONG mv) {
122       if (! holder) return false;
123       switch(mv) {
124         case VMediaList::MV_NEXT:
125           if (selection < ((int)holder->list()->size() -1)) {
126             selection++;
127             return true;
128           }
129           break;
130         case VMediaList::MV_PREV:
131           if (selection > 0) {
132             selection--;
133             return true;
134           }
135           break;
136       }
137       return false;
138     }
139
140                 ULONG getMediaType(){return mtype;}
141                 int getSortorder() {
142                         return sortorder;
143                 }
144     const MediaURI * getURI() {
145       return uri;
146     }
147     const char * getDisplayName() {
148       if (! uri || ! uri->getDisplayName()) return "/";
149       return uri->getDisplayName();
150     }
151     //get the holder (increment refcount)
152     MediaListHolder *getHolder() {
153       if ( !holder) return NULL;
154       holder->ref();
155       return holder;
156     }
157     //assign a holder to the directory (auto ref)
158     void assignHolder(MediaListHolder *h) {
159       if (holder) holder->unref();
160       holder=NULL;
161       if (! h) return;
162       h->ref();
163       holder=h;
164     }
165     //constructor with copy!
166                 MediaDirectory(const MediaURI *u) : selection(0),
167             sortorder(0),mtype(MEDIA_TYPE_ALL),holder(NULL){
168         if (u) 
169           uri=new MediaURI(u);
170         else
171           uri=NULL;
172                   }
173                 MediaDirectory(MediaDirectory &c) {
174                         setSelection(c.getSelection());
175                         setMediaType(c.getMediaType());
176                         setSortorder(c.getSortorder());
177       uri=new MediaURI(c.getURI());
178       holder=c.getHolder();
179                 }
180                 ~MediaDirectory() {
181       if (uri) delete uri;
182       if (holder) holder->unref();
183                 }
184 };
185
186 typedef std::vector<MediaDirectory*> MDirList;
187 class DirList {
188         private:
189                 int current;
190     int startlevel;
191     MDirList list;
192         public:
193                 DirList() {
194                         current=0;
195       startlevel=0;
196                         list.push_back(new MediaDirectory(NULL));
197                 }
198     DirList(DirList *cp) {
199       current=-1;
200       for (MDirList::iterator it=cp->list.begin();it<cp->list.end();it++) {
201         list.push_back(new MediaDirectory(*(*it)));
202         current++;
203       }
204       if (current < 0) {
205         list.push_back(new MediaDirectory(NULL));
206         current=0;
207       }
208       startlevel=cp->startlevel;
209       if (startlevel > current) startlevel=current;
210     }
211                 ~DirList() {
212                         MDirList::iterator it;
213                         for (it=list.begin();it<list.end();it++) {
214                                 delete *it;
215                         }
216                 }
217                 MediaDirectory *getCurrent() {
218                         return list[current];
219                 }
220                 const MediaURI * getURI() {
221                         return getCurrent()->getURI();
222                 }
223                 int dropTop() {
224                         if (current > 0) {
225                                 current--;
226                                 delete list.back();
227                                 list.pop_back();
228                         }
229                         return current;
230                 }
231                 int append(const MediaURI *uri) {
232                         if (! uri) return current;
233                         MediaDirectory* md=new MediaDirectory(uri);
234                         list.push_back(md);
235                         current++;
236                         return current;
237                 }
238
239                 int getLevel() {
240                         return current;
241                 }
242     void setStartLevel() {
243       startlevel=current;
244     }
245     bool isOnStartLevel() {
246       return (startlevel == current);
247     }
248
249 };
250
251
252 class MediaSorterName
253 {
254   public:
255   bool operator() (const Media* a, const Media* b)
256   {
257     if (b->getMediaType() == MEDIA_TYPE_DIR &&
258          a->getMediaType() != MEDIA_TYPE_DIR)
259       return false;
260     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
261         a->getMediaType() == MEDIA_TYPE_DIR)
262       return true;
263     int c = strcmp(b->getFileName(), a->getFileName());
264     if (c > 0) return true;
265     return false;
266   }
267 };
268
269 //a sorter with a randomly initialized order
270 class MediaSorterRandom
271 {
272   public:
273   MediaSorterRandom(int start) {
274     mystart=start;
275   }
276   bool operator() (const Media* a, const Media* b)
277   {
278     if (b->getMediaType() == MEDIA_TYPE_DIR &&
279          a->getMediaType() != MEDIA_TYPE_DIR)
280       return false;
281     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
282         a->getMediaType() == MEDIA_TYPE_DIR)
283       return true;
284     unsigned char suma=sum(a->getFileName(),(unsigned char)mystart);
285     unsigned char sumb=sum(b->getFileName(),(unsigned char)mystart);
286     if (sumb > suma) return true;
287     return false;
288   }
289   private:
290   unsigned char sum(const char *name,unsigned char start) {
291     for (;*name!=0;name++) start=start ^ (unsigned char)*name;
292     return start;
293   }
294   int mystart;
295 };
296
297
298 struct MediaSorterTime
299 {
300   bool operator() (const Media* a, const Media* b)
301   {
302     if (b->getMediaType() == MEDIA_TYPE_DIR &&
303          a->getMediaType() != MEDIA_TYPE_DIR)
304       return false;
305     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
306         a->getMediaType() == MEDIA_TYPE_DIR)
307       return true;
308     if (b->getTime()>a->getTime()) return true;
309     return false;
310   }
311 };
312
313
314 VMediaList::VMediaList()
315 {
316   boxstack = BoxStack::getInstance();
317
318   Log::getInstance()->log("VMediaList::VMediaList", Log::DEBUG, "start");
319         dirlist=new DirList();
320   audiodirlist=NULL;
321   Log::getInstance()->log("VMediaList::VMediaList", Log::DEBUG, "dirlist=%p,curren=%p",dirlist,dirlist->getCurrent());
322         dirlist->getCurrent()->setSortorder(SORT_NAME);
323   setSize(570, 420);
324   createBuffer();
325   if (Video::getInstance()->getFormat() == Video::PAL)
326     setPosition(80, 70);
327   else
328     setPosition(70, 35);
329
330   setTitleBarOn(1);
331   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
332
333   sl.setPosition(10, 30 + 5);
334   sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
335   sl.addColumn(0);
336   sl.addColumn(60);
337   add(&sl);
338   
339   loading=true;
340   sortOrder=SORT_NONE;
341   viewer=NULL;
342   dirmode=M_NONE;
343   const char *dmstring=MediaOptions::getInstance()->getStringOption("DirectoryPlayMode");
344   if (dmstring) {
345     if (strcmp(dmstring,"count") == 0) dirmode=M_COUNT;
346     else if (strcmp(dmstring,"audio") == 0) dirmode=M_AUDIO;
347     else if (strcmp(dmstring,"picture") == 0) dirmode=M_PICTURE;
348   }
349   playingAll=false;
350   //init additional providers
351 #ifndef WIN32
352   LocalMediaFile::init();
353 #endif
354 }
355
356
357 VMediaList::~VMediaList()
358 {
359   Log::getInstance()->log("VMediaList::~VMediaList", Log::DEBUG, "start");
360   Timers::getInstance()->cancelTimer(this,1);
361   Timers::getInstance()->cancelTimer(this,2);
362   removeViewer();
363   delete dirlist;
364   if (audiodirlist) delete audiodirlist;
365   Log::getInstance()->log("VMediaList::~VMediaList", Log::DEBUG, "finished");
366 }
367
368 void VMediaList::removeViewer() {
369   if (viewer) {
370       BoxStack::getInstance()->remove(viewer);
371   }
372   viewer=NULL;
373 }
374
375 VMediaView * VMediaList::getViewer() {
376   if (! viewer) {
377     viewer=VMediaView::createViewer(this);
378   }
379   return viewer;
380 }
381
382
383 void VMediaList::playAudio(bool all,bool activate, bool showInfo) {
384   MediaListHolder *h=dirlist->getCurrent()->getHolder();
385   if (! h) return;
386   VMediaView *player=getViewer();
387   //OK make a copy of the current active list for audio playing
388   if (audiodirlist) delete audiodirlist;
389   audiodirlist=new DirList(dirlist);
390   player->play(all,activate,MV_NONE,showInfo);
391   h->unref();
392 }
393
394 void VMediaList::updateAll() {
395   BoxStack::getInstance()->update(this);
396   if (viewer) BoxStack::getInstance()->update(viewer);
397   BoxStack::getInstance()->update(NULL);
398 }
399
400
401
402
403 int VMediaList::getNumEntries(ULONG mediaType,int lowerThen,bool noAudioList) {
404   MediaListHolder *h=dirlist->getCurrent()->getHolder();
405   Log::getInstance()->log("VMediaList",Log::DEBUG,"getNumEntries type=%lu,lt=%d,na=%d,h=%p,l=%p",
406       mediaType,lowerThen,(int)noAudioList,h,(h?h->list():0));
407   if (! h) return 0;
408   if (mediaType == MEDIA_TYPE_ALL && lowerThen < 0) {
409     h->unref();
410     return h->list()->size();
411   }
412   if (lowerThen < 0) lowerThen=h->list()->size();
413   int rt=0;
414   MediaList *ml=h->list();
415   h->unref();
416   if (mediaType == MEDIA_TYPE_AUDIO) {
417     //OK we look into the separate audiolist (if we have it...)
418     if (audiodirlist && ! noAudioList) {
419       MediaListHolder *ah=audiodirlist->getCurrent()->getHolder();
420       if (ah) {
421         ml=ah->list();
422         ah->unref();
423       }
424     }
425   }
426   for (int i=0;i<(int)(ml->size()) && i <= lowerThen;i++) {
427     if ((*ml)[i]->getMediaType() & mediaType) rt++;
428   }
429   return rt;
430 }
431
432 void VMediaList::setList(MediaListHolder* tlist)
433 {
434   dirlist->getCurrent()->assignHolder(tlist);
435   sortOrder=SORT_NONE;
436   sortList(dirlist->getCurrent()->getSortorder());
437   updateSelectList(dirlist->getCurrent()->getSelection());
438 }
439
440
441 void VMediaList::updateSelectList(){
442         updateSelectList(-1);
443 }
444 void VMediaList::updateSelectList(int currentNumber){
445   MediaListHolder *h=dirlist->getCurrent()->getHolder();
446   char str[5000];
447   char tempA[Media::TIMEBUFLEN];
448   Log::getInstance()->log("VMediaList::updateSelectList", Log::DEBUG, "media=%p",h);
449   if (! h) return;
450
451   ULONG currentSelection=0;
452   if (sl.getNumOptions() >= 1 && currentNumber < 0) {
453     currentSelection=sl.getCurrentOptionData();
454         }
455   sl.clear();
456
457   Media* media;
458   int first = 1;
459   if (h && h->list())
460   {
461     for (UINT i = 0; i < h->list()->size(); i++)
462     {
463       media = (*h->list())[i];
464       if (media->getMediaType() == MEDIA_TYPE_DIR) {
465         sprintf(str, "%04u  %s  [%s]", i,media->getTimeString(tempA), media->getDisplayName());
466         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
467         media->index = sl.addOption(str, (ULONG)media, first);
468       }
469       else {
470         sprintf(str, "%04u  %s  %s", i,media->getTimeString(tempA), media->getDisplayName());
471         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
472         media->index = sl.addOption(str, (ULONG)media, first);
473       }
474       first = 0;
475     }
476   }
477         if (currentNumber >= 0) sl.hintSetCurrent(currentNumber);
478         else sl.hintSetCurrent(0);
479   if (currentSelection != 0) {
480     bool found=false;
481     //position to the previous selection
482     for (int i=0;i<sl.getNumOptions();i++) {
483       sl.hintSetCurrent(i);
484       if (sl.getCurrentOptionData() == currentSelection) {
485         found=true;
486         break;
487       }
488     }
489     if (! found) sl.hintSetCurrent(0);
490   }
491   loading=false;
492   if (sl.getNumOptions() > 0)
493     sl.draw();
494   doShowingBar();
495   if (h) h->unref();
496 }
497
498
499 void VMediaList::draw()
500 {
501   Log::getInstance()->log("VMediaList::draw", Log::DEBUG, "namestr=%s",dirlist->getCurrent()->getDisplayName());
502   char title[400];
503   SNPRINTF(title, 398, tr("Media - %s"), dirlist->getCurrent()->getDisplayName());
504   title[399]=0;
505   setTitleText(title);
506   
507   if (loading)
508   {
509     sl.setVisible(false);
510     TBBoxx::draw();
511     drawText(tr("Loading..."), 240, 180, DrawStyle::LIGHTTEXT);
512   }
513   else 
514   {
515     //if (sl.getNumOptions() > 0) sl.draw();
516     sl.setVisible(true);
517     TBBoxx::draw();
518
519     // Put the status stuff at the bottom
520
521     WSymbol w;
522     TEMPADD(&w);
523
524     w.nextSymbol = WSymbol::UP;
525     w.setPosition(20, 385);
526     w.draw();
527
528     w.nextSymbol = WSymbol::DOWN;
529     w.setPosition(50, 385);
530     w.draw();
531
532     w.nextSymbol = WSymbol::SKIPBACK;
533     w.setPosition(85, 385);
534     w.draw();
535
536     w.nextSymbol = WSymbol::SKIPFORWARD;
537     w.setPosition(115, 385);
538     w.draw();
539
540     w.nextSymbol = WSymbol::PLAY;
541     w.setPosition(150, 385);
542     w.draw();
543
544     doShowingBar();
545   }
546 }
547
548 void VMediaList::doShowingBar()
549 {
550   int topOption = sl.getTopOption() + 1;
551   if (sl.getNumOptions() == 0) topOption = 0;
552
553   char showing[250];
554   const char* strmode=NULL;
555   switch (sortOrder) {
556     case SORT_TIME:
557       strmode=tr("Time");
558       break;
559     case SORT_NAME:
560       strmode=tr("Name");
561       break;
562     default:
563       strmode=tr("Rand");
564       break;
565   }
566   SNPRINTF(showing, 250,tr("%i to %i of %i"), 
567       topOption, sl.getBottomOption(), sl.getNumOptions());
568
569 //  Box b;
570 //  b.setSurfaceOffset(220, 385);
571 //  b.setDimensions(160, 25);
572 //  b.fillColour(DrawStyle::VIEWBACKGROUND);
573 //  b.drawText(showing, 0, 0, DrawStyle::LIGHTTEXT);
574
575   rectangle(200, 384, 18, 16, DrawStyle::VIDEOBLUE);
576   rectangle(220, 385, 220+160, 385+25, DrawStyle::VIEWBACKGROUND);
577   drawText(strmode, 220, 385, DrawStyle::LIGHTTEXT);
578   drawText(showing, 280, 385, DrawStyle::LIGHTTEXT);
579   if (sl.getCurrentOptionData() != 0) Log::getInstance()->log("VMediaList",Log::DEBUG,"selected %s",((Media *)sl.getCurrentOptionData())->getDisplayName());
580 }
581
582 //find the next entry in the media list
583 //return the index in the list (starting with 0)
584 //return -1 if none found
585 int VMediaList::findNextEntry(int current, MediaList *list,ULONG ltype, ULONG move,bool wrap) {
586   if (! list) return -1;
587   if (current < 0) current=0;
588   if (current >= (int)list->size()) current=list->size()-1;
589   int next=current;
590   int rt=-1;
591   bool again=true;
592   while (again) {
593     switch (move) {
594       case MV_PREV:
595         next--;
596         break;
597       case MV_NEXT:
598         next++;
599         break;
600       default:
601         again=false;
602         break;
603     }
604     if (next < 0) {
605       if (! wrap) {
606         break;
607       }
608       else {
609         next=list->size()-1;
610       }
611     }
612     if (next >= (int)list->size()) {
613       if (! wrap) {
614         break;
615       }
616       else {
617         next=0;
618       }
619     }
620     if (next == current && move != MV_NONE) {
621       break;
622     }
623     if (((*list)[next])->getMediaType() != ltype) {
624       ;
625     } 
626     else {
627       rt=next;
628       break;
629     }
630   }
631   return rt;
632 }
633
634
635
636
637 Media * VMediaList::getMedia(ULONG ltype,ULONG move) {
638   Media *rt=NULL;
639   MediaList *list=NULL;
640   MediaListHolder *h=NULL;
641   Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia, t=%lu, mv=%lu",ltype,move);
642   //we have 2 lists:
643   //the currently active one (dirlist->getCurrent()->getHolder())
644   //and potentially a second one for audio (audiolist)
645   //currently (no recursive playing) we should always have an attached medialist in the audiolist
646   if (ltype == MEDIA_TYPE_AUDIO && audiodirlist != NULL ) {
647     h=audiodirlist->getCurrent()->getHolder();
648     if (! h) {
649       Log::getInstance()->log("VMediaList",Log::ERR,"getMedia AUDIO empty medialist");
650       return NULL;
651     }
652     int nentry=findNextEntry(audiodirlist->getCurrent()->getSelection(),h->list(),ltype,move,false);
653     if (nentry < 0) {
654       Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia AUDIO no next entry");
655       h->unref();
656       return NULL;
657     }
658     audiodirlist->getCurrent()->setSelection(nentry);
659     list=h->list();
660     rt=new Media((*list)[nentry]);
661     h->unref();
662     Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia AUDIO next entry %d",nentry);
663   }
664   else {
665     h=dirlist->getCurrent()->getHolder();
666     if (! h) {
667       Log::getInstance()->log("VMediaList",Log::ERR,"getMedia PICTURE empty medialist");
668       return NULL;
669     }
670     int nentry=findNextEntry(dirlist->getCurrent()->getSelection(),h->list(),ltype,move,false);
671     if (nentry < 0) {
672       Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia type=%lu no next entry",ltype);
673       h->unref();
674       return NULL;
675     }
676     Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia type=%lu next entry %d",ltype,nentry);
677     dirlist->getCurrent()->setSelection(nentry);
678     updateSelection(true);
679     list=h->list();
680     h->unref();
681     rt=new Media((*list)[nentry]);
682   }
683   if (! rt->getURI()) {
684     MediaURI *uri=list->getURI(rt);
685     rt->setURI(uri);
686     delete uri;
687   }
688   return rt;
689 }
690
691 void VMediaList::updateSelection(bool toSelectList) {
692   if (! toSelectList) 
693     dirlist->getCurrent()->setSelection(sl.getCurrentOption());
694   else {
695     sl.hintSetCurrent(dirlist->getCurrent()->getSelection());
696     sl.draw();
697   }
698 }
699
700 Media * VMediaList::getCurrentMedia(DirList *dl) {
701   if (! dl) return NULL;
702   MediaDirectory *d=dirlist->getCurrent();
703   if (! d) return NULL;
704   MediaListHolder *h=d->getHolder();
705   if (! h) return NULL;
706   if (d->getSelection() < 0 || d->getSelection() >= (int)h->list()->size()) return NULL;
707   Media *rt= (*h->list())[d->getSelection()];
708   h->unref();
709   return rt;
710 }
711
712
713 int VMediaList::handleCommand(int command)
714 {
715   playingAll=false;
716   switch(command)
717   {
718     case Input::ONE:
719     {
720       sl.hintSetCurrent(0);
721       sl.draw();
722       updateSelection();
723       doShowingBar();
724       boxstack->update(this);
725       return 2;
726     }
727     case Input::UP:
728     {
729       sl.up();
730       sl.draw();
731       updateSelection();
732
733       doShowingBar();
734       boxstack->update(this);
735       return 2;
736     }
737     case Input::DOWN:
738     {
739       sl.down();
740       sl.draw();
741       updateSelection();
742
743       doShowingBar();
744       boxstack->update(this);
745       return 2;
746     }
747     case Input::SKIPBACK:
748     {
749       sl.pageUp();
750       sl.draw();
751       updateSelection();
752
753       doShowingBar();
754       boxstack->update(this);
755       return 2;
756     }
757     case Input::SKIPFORWARD:
758     {
759       sl.pageDown();
760       sl.draw();
761       updateSelection();
762
763       doShowingBar();
764       boxstack->update(this);
765       return 2;
766     }
767     case Input::BLUE:
768     {
769       switch(sortOrder) {
770         case SORT_NAME:
771           sortList(SORT_TIME);
772           boxstack->update(this);
773           return 2;
774         case SORT_TIME:
775           sortList(SORT_RANDOM);
776           boxstack->update(this);
777           return 2;
778         default:
779           sortList(SORT_NAME);
780           boxstack->update(this);
781           return 2;
782       }
783     }
784     case Input::OK:
785     case Input::PLAY:
786     {
787       Media* media = NULL;
788       if (dirlist) media = getCurrentMedia(dirlist);
789       if (media == NULL) return 2;
790       Log::getInstance()->log("VMediaList", Log::DEBUG, "activated %lu", media->index);
791       switch(media->getMediaType())
792       {
793         case MEDIA_TYPE_DIR:
794         { 
795         //create child
796         Log::getInstance()->log("VMediaList", Log::DEBUG, "create child for %s",media->getFileName());
797         if (media->getFileName() == NULL ) return 2;
798         if (command == Input::PLAY) {
799           dirlist->setStartLevel();
800           playingAll=true;
801         }
802         bool rt=changeDirectory(media);
803         if (command == Input::PLAY && rt) {
804           playAll();
805         }
806         else {
807           playingAll=false;
808         }
809         break;
810         }
811         case MEDIA_TYPE_AUDIO:
812         Log::getInstance()->log("VMediaList", Log::DEBUG, "play audio file %s",
813           media->getFileName());
814         if (dirmode != M_NONE && command == Input::PLAY)
815           playAll();
816         else
817           playAudio(command==Input::PLAY,true,true);
818         break;
819         case MEDIA_TYPE_VIDEO: {
820 #ifndef WIN32 //Only DVB style MPEG is supported by the Windows Part!
821         Log::getInstance()->log("VMediaList", Log::DEBUG, "play video file %s",
822           media->getFileName());
823         //OK - simply today
824         if (! media->getURI()) {
825           //addURI
826           MediaListHolder *h=dirlist->getCurrent()->getHolder();
827           if (!h) {
828             Log::getInstance()->log("VMediaList", Log::ERR, "no media List");
829             break;
830           }
831           MediaURI *u=h->list()->getURI(media);
832           media->setURI(u);
833           delete u;
834           h->unref();
835         }
836         removeViewer();
837         VVideoMedia *v=new VVideoMedia(media,this);
838         BoxStack::getInstance()->add(v);
839         BoxStack::getInstance()->update(v);
840         v->go(false);
841         //play video
842 #endif
843       }break;
844         case MEDIA_TYPE_PICTURE:
845         Log::getInstance()->log("VMediaList", Log::DEBUG, "show picture file %s",
846          media->getFileName());
847         if (dirmode != M_NONE && command == Input::PLAY)
848           playAll();
849         else
850           getViewer()->showPicture(MV_NONE,command==Input::PLAY,true);
851         break;
852         default:
853         Log::getInstance()->log("VMediaList", Log::DEBUG, "unknown media type %d file %s",
854           media->getMediaType(),media->getFileName());
855
856         }
857       /*
858       VVideoLive* v = new VVideoLive(dirlist->getCurrent()->getHolder(), media->type, this);
859
860       v->draw();
861       boxstack->add(v);
862       boxstack->updatev);
863
864       v->medianelChange(VVideoLive::NUMBER, media->number);
865       */
866
867       return 2;
868     }
869     case Input::BACK:
870     {
871                         if (dirlist->getLevel() < 1) return 4;
872                         dirlist->dropTop();
873                         load();
874     }
875   }
876   // stop command getting to any more views
877   return 1;
878 }
879
880 //go to the next level dir
881 //if OK - delete current medialist
882 bool VMediaList::changeDirectory(Media *media) {
883   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd to %s",media->getFileName());
884   updateSelection();
885   dirlist->getCurrent()->setSortorder(sortOrder);
886   if (dirlist->getLevel() > 200) {
887     Log::getInstance()->log("VMediaList",Log::ERR,"above 300 levels, stop here...");
888     return false;
889   }
890   MediaListHolder *h=dirlist->getCurrent()->getHolder();
891   dirlist->getCurrent()->assignHolder(NULL); //prepare old holder for deletion
892   if (! h) {
893     return false;
894   }
895   MediaURI *uri=h->list()->getURI(media);
896   dirlist->append(uri);
897   delete uri;
898   //same sort order for next level
899   dirlist->getCurrent()->setSortorder(sortOrder);
900   int rt=load();
901   if (rt == 0) {
902     h->unref(); //this deletes now the old list
903     Log::getInstance()->log("VMediaList",Log::DEBUG,"cd OK");
904     return true;
905   }
906   //we were no able to load the new list - so go back to our current list
907   dirlist->dropTop();
908   dirlist->getCurrent()->assignHolder(h); //OK so we saved our list...
909   h->unref();
910   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd  failed");
911   return false;
912 }
913
914 void VMediaList::directoryDone() {
915   if (! playingAll) return;
916   //go up until we are on the startlevel
917   Log::getInstance()->log("VMediaList", Log::DEBUG, "DirectoryDone ");
918   while ( ! dirlist->isOnStartLevel()) {
919     dirlist->dropTop();
920     load();
921     if (dirlist->isOnStartLevel()) break;
922     if (dirlist->getCurrent()->move(MV_NEXT))
923       break;
924   }
925   if ( dirlist->isOnStartLevel()) {
926     //OK we are done
927     playingAll=false;
928     Log::getInstance()->log("VMediaList", Log::DEBUG, "finished playing all l=%lu",dirlist->getLevel());
929     return;
930   }
931   updateSelection(true);
932   playAll();
933 }
934
935 bool VMediaList::playAll() {
936   if (dirmode == M_NONE) return false;
937   bool started=false;
938   if (! playingAll) {
939     //starting now
940     dirlist->setStartLevel();
941     playingAll=true;
942     started=true;
943   }
944   Media *media=getCurrentMedia(dirlist);
945   if (! media) {
946     //empty directory
947     Log::getInstance()->log("VMediaList", Log::DEBUG, "empty dir when calling playall");
948     //directoryDone
949     Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
950     return true;
951   }
952   Media *mcopy=new Media(media);
953   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s,t=%lu, started=%d",
954       mcopy->getDisplayName(),mcopy->getMediaType(),(int)started);
955   while (mcopy->getMediaType()==MEDIA_TYPE_DIR) {
956     //recurse to the next directory
957     bool rt=changeDirectory(mcopy);
958     if (rt ) {
959       //OK succesfully changed dir
960       int entries=getNumEntries(MEDIA_TYPE_AUDIO|MEDIA_TYPE_DIR|MEDIA_TYPE_PICTURE);
961       Log::getInstance()->log("VMediaList", Log::DEBUG, "cd OK, entries=%d",entries);
962       media=getCurrentMedia(dirlist);
963       if (entries==0 || media == NULL) {
964         Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s empty",mcopy->getDisplayName());
965         delete mcopy;
966         //trigger directory end with the ability of user intervention
967         Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
968         return true;
969       }
970       delete mcopy;
971       mcopy=NULL;
972       if (media->getMediaType()==MEDIA_TYPE_DIR) {
973         //send a defered event to give the user a chance to interrupt
974         //will again call playAll (but this does not chage the start level)
975         Timers::getInstance()->setTimerD(this,2,0,10000000l); //10ms
976         return true;
977       }
978       break;
979     }
980     else 
981     {
982       //unable to change to the directory
983       if (dirlist->getCurrent()->move(MV_NEXT)) {
984         //OK there is still a next medium here
985         updateSelection(true);
986         media=getCurrentMedia(dirlist);
987         if (!media) {
988           Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
989           return true;
990         }
991         delete mcopy;
992         mcopy=new Media(media);
993         continue;
994       }
995       //hmm - no entries here any more
996       //so we have to stop
997       delete mcopy;
998       playingAll=false;
999       return false;
1000     }
1001   }
1002   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all on level %d, sele=%d",
1003       dirlist->getLevel(),dirlist->getCurrent()->getSelection());
1004   delete mcopy;
1005   enum Dirmode currentMode=dirmode;
1006   //OK now we handled all directories - now deal with the current one
1007   //1st determine the number of entries
1008   int aentries=getNumEntries(MEDIA_TYPE_AUDIO,-1,true);
1009   int pentries=getNumEntries(MEDIA_TYPE_PICTURE,-1,true);
1010   if (aentries == 0 && pentries == 0) {
1011     directoryDone();
1012     return false;
1013   }
1014   if (currentMode == M_COUNT) {
1015     if (aentries > pentries) currentMode=M_AUDIO;
1016     else currentMode=M_PICTURE;
1017   }
1018   Log::getInstance()->log("VMediaList", Log::DEBUG, "mode=%d,ae=%d,pe=%d",currentMode,aentries,pentries);
1019   //now find the matching entries and start playing
1020   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1021   if (! h) {
1022     Log::getInstance()->log("VMediaList", Log::ERR, "playing all empty medialist");
1023     playingAll=false;
1024     return false;
1025   }
1026   Media *maudio=NULL;
1027   Media *mpicture=NULL;
1028   int audioselection=-1;
1029   int pictureselection=-1;
1030   for (int i=dirlist->getCurrent()->getSelection();i<(int)h->list()->size();i++) {
1031     Media *m=(*h->list())[i];
1032     if (m->getMediaType() == MEDIA_TYPE_AUDIO && maudio == NULL) {
1033       maudio=m;
1034       audioselection=i;
1035     }
1036     if (m->getMediaType() == MEDIA_TYPE_PICTURE && mpicture == NULL) {
1037       mpicture=m;
1038       pictureselection=i;
1039     }
1040     if (maudio != NULL && mpicture != NULL) break;
1041   }
1042   //OK now we found the first media for both - start players
1043   if (maudio != NULL) {
1044     dirlist->getCurrent()->setSelection(audioselection);
1045     playAudio(true,currentMode==M_AUDIO,mpicture==NULL); //this makes now a copy of dirlist...
1046   }
1047   if (mpicture != NULL) {
1048     dirlist->getCurrent()->setSelection(pictureselection);
1049     getViewer()->showPicture(MV_NONE,true,currentMode==M_PICTURE);
1050   }
1051   h->unref();
1052   updateSelection(true);
1053   return true;
1054 }
1055
1056
1057     
1058
1059   
1060
1061
1062  
1063 void VMediaList::processMessage(Message* m)
1064 {
1065   if (m->message == Message::MOUSE_MOVE)
1066   {
1067     if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
1068     {
1069       sl.draw();
1070       doShowingBar();
1071       boxstack->update(this);
1072       updateSelection();
1073     }
1074   }
1075   else if (m->message == Message::MOUSE_LBDOWN)
1076   {
1077     if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
1078     {
1079       updateSelection();
1080       boxstack->handleCommand(Input::OK); //simulate OK press
1081     }
1082     else if (coordsOutsideBox(m))
1083     {
1084       boxstack->handleCommand(Input::BACK); //simulate cancel press
1085     }
1086   }
1087   else if (m->message == Message::PLAYER_EVENT) {
1088     switch (m->parameter) {
1089       case 1:
1090         directoryDone();
1091         break;
1092       case 2:
1093         playAll();
1094         break;
1095     }
1096   }
1097 }
1098
1099 int VMediaList::createList() {
1100    Log::getInstance()->log("VMediaList::createList", Log::DEBUG, "");
1101    VMediaList *vmn=new VMediaList();
1102    //show the "loading" indicator
1103    BoxStack::getInstance()->add(vmn);
1104    int rt=vmn->load();
1105    if ( rt != 0) {
1106      BoxStack::getInstance()->remove(vmn);
1107      }
1108    return rt;
1109 }
1110
1111 void VMediaList::sortList(int newSort) {
1112   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1113   if (! h) return;
1114   Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "p=%p,sort=%d,osort=%d, size=%d",this,newSort,sortOrder,h->list()->size());
1115   if (sortOrder == newSort) return;
1116    if (h->list()->begin() != h->list()->end()) {
1117    switch (newSort) {
1118      case SORT_TIME:
1119        ::sort(h->list()->begin(),h->list()->end(),MediaSorterTime());
1120        break;
1121      case SORT_NAME:
1122        ::sort(h->list()->begin(),h->list()->end(),MediaSorterName());
1123        break;
1124      case SORT_RANDOM:
1125        ::sort(h->list()->begin(),h->list()->end(),MediaSorterRandom(time(NULL)));
1126        break;
1127      }
1128    }
1129    sortOrder=newSort;
1130    updateSelectList();
1131    h->unref();
1132    Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "done ");
1133 }
1134
1135
1136 int VMediaList::load() {
1137         
1138         loading=true;
1139         draw();
1140   boxstack->update(this);
1141   MediaPlayer * mp=MediaPlayer::getInstance();
1142   Log::getInstance()->log("VMediaList::load", Log::DEBUG, "load list for %p",dirlist->getURI());
1143         MediaDirectory *md=dirlist->getCurrent();
1144   MediaList *mn=NULL;
1145   if (md->getURI()) {
1146     mn=mp->getMediaList(md->getURI());
1147   }
1148   else {
1149     mn=mp->getRootList();
1150   }
1151   if (mn != NULL) {
1152     MediaListHolder *h=new MediaListHolder(mn);
1153     setList(h);
1154     h->unref();
1155     h=NULL;
1156     draw();
1157     boxstack->update(this);
1158     return 0;
1159     }
1160   else {
1161     Log::getInstance()->log("VMediaList", Log::ERR, "unable to get MediaList for %p",dirlist->getURI());
1162
1163     VInfo* vi = new VInfo();
1164     vi->setSize(400, 150);
1165     vi->createBuffer();
1166     vi->setExitable();
1167     vi->setBorderOn(1);
1168     vi->setTitleBarOn(0);
1169
1170     if (Video::getInstance()->getFormat() == Video::PAL)
1171       vi->setPosition(170, 200);
1172     else
1173       vi->setPosition(160, 150);
1174     vi->setOneLiner(tr("unable to get media list"));
1175     vi->draw();
1176
1177     Message* m = new Message();
1178     m->message = Message::ADD_VIEW;
1179     m->to = boxstack;
1180     m->data = reinterpret_cast<void*>(vi);
1181     MessageQueue::getInstance()->postMessage(m);
1182   }
1183   return 1;
1184 }
1185
1186 const char * VMediaList::getDirname(ULONG mtype) const {
1187   if (mtype == MEDIA_TYPE_AUDIO && audiodirlist) {
1188     return audiodirlist->getCurrent()->getDisplayName();
1189   }
1190   return dirlist->getCurrent()->getDisplayName();
1191 }
1192
1193 void VMediaList::timercall(int ref) {
1194   if (ref == 1 || ref == 2 ) {
1195     //send a directory done event 
1196     Message* m = new Message();
1197     m->message = Message::PLAYER_EVENT;
1198     m->to = this;
1199     m->parameter = ref;
1200     MessageQueue::getInstance()->postMessage(m);
1201   }
1202 }
1203  
1204