]> git.vomp.tv Git - vompclient.git/blob - vmedialist.cc
Fix text corruption in live TV OSD clock
[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 "oldlog.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   MessageQueue::getInstance()->addReceiver(this);
355 }
356
357
358 VMediaList::~VMediaList()
359 {
360   MessageQueue::getInstance()->removeReceiver(this);
361   Log::getInstance()->log("VMediaList::~VMediaList", Log::DEBUG, "start");
362   Timers::getInstance()->cancelTimer(this,1);
363   Timers::getInstance()->cancelTimer(this,2);
364   removeViewer();
365   delete dirlist;
366   if (audiodirlist) delete audiodirlist;
367   Log::getInstance()->log("VMediaList::~VMediaList", Log::DEBUG, "finished");
368 }
369
370 void VMediaList::removeViewer() {
371   if (viewer) {
372       BoxStack::getInstance()->remove(viewer);
373   }
374   viewer=NULL;
375 }
376
377 VMediaView * VMediaList::getViewer() {
378   if (! viewer) {
379     viewer=VMediaView::createViewer(this);
380   }
381   return viewer;
382 }
383
384
385 void VMediaList::playAudio(bool all,bool activate, bool showInfo) {
386   MediaListHolder *h=dirlist->getCurrent()->getHolder();
387   if (! h) return;
388   VMediaView *player=getViewer();
389   //OK make a copy of the current active list for audio playing
390   if (audiodirlist) delete audiodirlist;
391   audiodirlist=new DirList(dirlist);
392   player->play(all,activate,MV_NONE,showInfo);
393   h->unref();
394 }
395
396 void VMediaList::updateAll() {
397   BoxStack::getInstance()->update(this);
398   if (viewer) BoxStack::getInstance()->update(viewer);
399   BoxStack::getInstance()->update(NULL);
400 }
401
402
403
404
405 int VMediaList::getNumEntries(ULONG mediaType,int lowerThen,bool noAudioList) {
406   MediaListHolder *h=dirlist->getCurrent()->getHolder();
407   Log::getInstance()->log("VMediaList",Log::DEBUG,"getNumEntries type=%lu,lt=%d,na=%d,h=%p,l=%p",
408       mediaType,lowerThen,(int)noAudioList,h,(h?h->list():0));
409   if (! h) return 0;
410   if (mediaType == MEDIA_TYPE_ALL && lowerThen < 0) {
411     h->unref();
412     return h->list()->size();
413   }
414   if (lowerThen < 0) lowerThen=h->list()->size();
415   int rt=0;
416   MediaList *ml=h->list();
417   h->unref();
418   if (mediaType == MEDIA_TYPE_AUDIO) {
419     //OK we look into the separate audiolist (if we have it...)
420     if (audiodirlist && ! noAudioList) {
421       MediaListHolder *ah=audiodirlist->getCurrent()->getHolder();
422       if (ah) {
423         ml=ah->list();
424         ah->unref();
425       }
426     }
427   }
428   for (int i=0;i<(int)(ml->size()) && i <= lowerThen;i++) {
429     if ((*ml)[i]->getMediaType() & mediaType) rt++;
430   }
431   return rt;
432 }
433
434 void VMediaList::setList(MediaListHolder* tlist)
435 {
436   dirlist->getCurrent()->assignHolder(tlist);
437   sortOrder=SORT_NONE;
438   sortList(dirlist->getCurrent()->getSortorder());
439   updateSelectList(dirlist->getCurrent()->getSelection());
440 }
441
442
443 void VMediaList::updateSelectList(){
444         updateSelectList(-1);
445 }
446 void VMediaList::updateSelectList(int currentNumber){
447   MediaListHolder *h=dirlist->getCurrent()->getHolder();
448   char str[5000];
449   char tempA[Media::TIMEBUFLEN];
450   Log::getInstance()->log("VMediaList::updateSelectList", Log::DEBUG, "media=%p",h);
451   if (! h) return;
452
453   ULONG currentSelection=0;
454   if (sl.getNumOptions() >= 1 && currentNumber < 0) {
455     currentSelection=sl.getCurrentOptionData();
456         }
457   sl.clear();
458
459   Media* media;
460   int first = 1;
461   if (h && h->list())
462   {
463     for (UINT i = 0; i < h->list()->size(); i++)
464     {
465       media = (*h->list())[i];
466       if (media->getMediaType() == MEDIA_TYPE_DIR) {
467         sprintf(str, "%04u  %s  [%s]", i,media->getTimeString(tempA), media->getDisplayName());
468         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
469         media->index = sl.addOption(str, (ULONG)media, first);
470       }
471       else {
472         sprintf(str, "%04u  %s  %s", i,media->getTimeString(tempA), media->getDisplayName());
473         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
474         media->index = sl.addOption(str, (ULONG)media, first);
475       }
476       first = 0;
477     }
478   }
479         if (currentNumber >= 0) sl.hintSetCurrent(currentNumber);
480         else sl.hintSetCurrent(0);
481   if (currentSelection != 0) {
482     bool found=false;
483     //position to the previous selection
484     for (int i=0;i<sl.getNumOptions();i++) {
485       sl.hintSetCurrent(i);
486       if (sl.getCurrentOptionData() == currentSelection) {
487         found=true;
488         break;
489       }
490     }
491     if (! found) sl.hintSetCurrent(0);
492   }
493   loading=false;
494   if (sl.getNumOptions() > 0)
495     sl.draw();
496   doShowingBar();
497   if (h) h->unref();
498 }
499
500
501 void VMediaList::draw()
502 {
503   Log::getInstance()->log("VMediaList::draw", Log::DEBUG, "namestr=%s",dirlist->getCurrent()->getDisplayName());
504   char title[400];
505   SNPRINTF(title, 398, tr("Media - %s"), dirlist->getCurrent()->getDisplayName());
506   title[399]=0;
507   setTitleText(title);
508   
509   if (loading)
510   {
511     sl.setVisible(false);
512     TBBoxx::draw();
513     drawText(tr("Loading..."), 240, 180, DrawStyle::LIGHTTEXT);
514   }
515   else 
516   {
517     //if (sl.getNumOptions() > 0) sl.draw();
518     sl.setVisible(true);
519     TBBoxx::draw();
520
521     // Put the status stuff at the bottom
522
523     WSymbol w;
524     TEMPADD(&w);
525
526     w.nextSymbol = WSymbol::UP;
527     w.setPosition(20, 385);
528     w.draw();
529
530     w.nextSymbol = WSymbol::DOWN;
531     w.setPosition(50, 385);
532     w.draw();
533
534     w.nextSymbol = WSymbol::SKIPBACK;
535     w.setPosition(85, 385);
536     w.draw();
537
538     w.nextSymbol = WSymbol::SKIPFORWARD;
539     w.setPosition(115, 385);
540     w.draw();
541
542     w.nextSymbol = WSymbol::PLAY;
543     w.setPosition(150, 385);
544     w.draw();
545
546     doShowingBar();
547   }
548 }
549
550 void VMediaList::doShowingBar()
551 {
552   int topOption = sl.getTopOption() + 1;
553   if (sl.getNumOptions() == 0) topOption = 0;
554
555   char showing[250];
556   const char* strmode=NULL;
557   switch (sortOrder) {
558     case SORT_TIME:
559       strmode=tr("Time");
560       break;
561     case SORT_NAME:
562       strmode=tr("Name");
563       break;
564     default:
565       strmode=tr("Rand");
566       break;
567   }
568   SNPRINTF(showing, 250,tr("%i to %i of %i"), 
569       topOption, sl.getBottomOption(), sl.getNumOptions());
570
571 //  Box b;
572 //  b.setSurfaceOffset(220, 385);
573 //  b.setDimensions(160, 25);
574 //  b.fillColour(DrawStyle::VIEWBACKGROUND);
575 //  b.drawText(showing, 0, 0, DrawStyle::LIGHTTEXT);
576
577   rectangle(200, 384, 18, 16, DrawStyle::VIDEOBLUE);
578   rectangle(220, 385, 220+160, 385+25, DrawStyle::VIEWBACKGROUND);
579   drawText(strmode, 220, 385, DrawStyle::LIGHTTEXT);
580   drawText(showing, 280, 385, DrawStyle::LIGHTTEXT);
581   if (sl.getCurrentOptionData() != 0) Log::getInstance()->log("VMediaList",Log::DEBUG,"selected %s",((Media *)sl.getCurrentOptionData())->getDisplayName());
582 }
583
584 //find the next entry in the media list
585 //return the index in the list (starting with 0)
586 //return -1 if none found
587 int VMediaList::findNextEntry(int current, MediaList *list,ULONG ltype, ULONG move,bool wrap) {
588   if (! list) return -1;
589   if (current < 0) current=0;
590   if (current >= (int)list->size()) current=list->size()-1;
591   int next=current;
592   int rt=-1;
593   bool again=true;
594   while (again) {
595     switch (move) {
596       case MV_PREV:
597         next--;
598         break;
599       case MV_NEXT:
600         next++;
601         break;
602       default:
603         again=false;
604         break;
605     }
606     if (next < 0) {
607       if (! wrap) {
608         break;
609       }
610       else {
611         next=list->size()-1;
612       }
613     }
614     if (next >= (int)list->size()) {
615       if (! wrap) {
616         break;
617       }
618       else {
619         next=0;
620       }
621     }
622     if (next == current && move != MV_NONE) {
623       break;
624     }
625     if (((*list)[next])->getMediaType() != ltype) {
626       ;
627     } 
628     else {
629       rt=next;
630       break;
631     }
632   }
633   return rt;
634 }
635
636
637
638
639 Media * VMediaList::getMedia(ULONG ltype,ULONG move) {
640   Media *rt=NULL;
641   MediaList *list=NULL;
642   MediaListHolder *h=NULL;
643   Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia, t=%lu, mv=%lu",ltype,move);
644   //we have 2 lists:
645   //the currently active one (dirlist->getCurrent()->getHolder())
646   //and potentially a second one for audio (audiolist)
647   //currently (no recursive playing) we should always have an attached medialist in the audiolist
648   if (ltype == MEDIA_TYPE_AUDIO && audiodirlist != NULL ) {
649     h=audiodirlist->getCurrent()->getHolder();
650     if (! h) {
651       Log::getInstance()->log("VMediaList",Log::ERR,"getMedia AUDIO empty medialist");
652       return NULL;
653     }
654     int nentry=findNextEntry(audiodirlist->getCurrent()->getSelection(),h->list(),ltype,move,false);
655     if (nentry < 0) {
656       Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia AUDIO no next entry");
657       h->unref();
658       return NULL;
659     }
660     audiodirlist->getCurrent()->setSelection(nentry);
661     list=h->list();
662     rt=new Media((*list)[nentry]);
663     h->unref();
664     Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia AUDIO next entry %d",nentry);
665   }
666   else {
667     h=dirlist->getCurrent()->getHolder();
668     if (! h) {
669       Log::getInstance()->log("VMediaList",Log::ERR,"getMedia PICTURE empty medialist");
670       return NULL;
671     }
672     int nentry=findNextEntry(dirlist->getCurrent()->getSelection(),h->list(),ltype,move,false);
673     if (nentry < 0) {
674       Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia type=%lu no next entry",ltype);
675       h->unref();
676       return NULL;
677     }
678     Log::getInstance()->log("VMediaList",Log::DEBUG,"getMedia type=%lu next entry %d",ltype,nentry);
679     dirlist->getCurrent()->setSelection(nentry);
680     updateSelection(true);
681     list=h->list();
682     h->unref();
683     rt=new Media((*list)[nentry]);
684   }
685   if (! rt->getURI()) {
686     MediaURI *uri=list->getURI(rt);
687     rt->setURI(uri);
688     delete uri;
689   }
690   return rt;
691 }
692
693 void VMediaList::updateSelection(bool toSelectList) {
694   if (! toSelectList) 
695     dirlist->getCurrent()->setSelection(sl.getCurrentOption());
696   else {
697     sl.hintSetCurrent(dirlist->getCurrent()->getSelection());
698     sl.draw();
699   }
700 }
701
702 Media * VMediaList::getCurrentMedia(DirList *dl) {
703   if (! dl) return NULL;
704   MediaDirectory *d=dirlist->getCurrent();
705   if (! d) return NULL;
706   MediaListHolder *h=d->getHolder();
707   if (! h) return NULL;
708   if (d->getSelection() < 0 || d->getSelection() >= (int)h->list()->size()) return NULL;
709   Media *rt= (*h->list())[d->getSelection()];
710   h->unref();
711   return rt;
712 }
713
714
715 int VMediaList::handleCommand(int command)
716 {
717   playingAll=false;
718   switch(command)
719   {
720     case Input::ONE:
721     {
722       sl.hintSetCurrent(0);
723       sl.draw();
724       updateSelection();
725       doShowingBar();
726       boxstack->update(this);
727       return BoxStack::COMMAND_HANDLED;
728     }
729     case Input::UP:
730     {
731       sl.up();
732       sl.draw();
733       updateSelection();
734
735       doShowingBar();
736       boxstack->update(this);
737       return BoxStack::COMMAND_HANDLED;
738     }
739     case Input::DOWN:
740     {
741       sl.down();
742       sl.draw();
743       updateSelection();
744
745       doShowingBar();
746       boxstack->update(this);
747       return BoxStack::COMMAND_HANDLED;
748     }
749     case Input::SKIPBACK:
750     {
751       sl.pageUp();
752       sl.draw();
753       updateSelection();
754
755       doShowingBar();
756       boxstack->update(this);
757       return BoxStack::COMMAND_HANDLED;
758     }
759     case Input::SKIPFORWARD:
760     {
761       sl.pageDown();
762       sl.draw();
763       updateSelection();
764
765       doShowingBar();
766       boxstack->update(this);
767       return BoxStack::COMMAND_HANDLED;
768     }
769     case Input::BLUE:
770     {
771       switch(sortOrder) {
772         case SORT_NAME:
773           sortList(SORT_TIME);
774           boxstack->update(this);
775           return BoxStack::COMMAND_HANDLED;
776         case SORT_TIME:
777           sortList(SORT_RANDOM);
778           boxstack->update(this);
779           return BoxStack::COMMAND_HANDLED;
780         default:
781           sortList(SORT_NAME);
782           boxstack->update(this);
783           return BoxStack::COMMAND_HANDLED;
784       }
785     }
786     case Input::OK:
787     case Input::PLAY:
788     {
789       Media* media = NULL;
790       if (dirlist) media = getCurrentMedia(dirlist);
791       if (media == NULL) return BoxStack::COMMAND_HANDLED;
792       Log::getInstance()->log("VMediaList", Log::DEBUG, "activated %lu", media->index);
793       switch(media->getMediaType())
794       {
795         case MEDIA_TYPE_DIR:
796         { 
797         //create child
798         Log::getInstance()->log("VMediaList", Log::DEBUG, "create child for %s",media->getFileName());
799         if (media->getFileName() == NULL ) return BoxStack::COMMAND_HANDLED;
800         if (command == Input::PLAY) {
801           dirlist->setStartLevel();
802           playingAll=true;
803         }
804         bool rt=changeDirectory(media);
805         if (command == Input::PLAY && rt) {
806           playAll();
807         }
808         else {
809           playingAll=false;
810         }
811         break;
812         }
813         case MEDIA_TYPE_AUDIO:
814         Log::getInstance()->log("VMediaList", Log::DEBUG, "play audio file %s",
815           media->getFileName());
816         if (dirmode != M_NONE && command == Input::PLAY)
817           playAll();
818         else
819           playAudio(command==Input::PLAY,true,true);
820         break;
821         case MEDIA_TYPE_VIDEO: {
822 #ifndef WIN32 //Only DVB style MPEG is supported by the Windows Part!
823         Log::getInstance()->log("VMediaList", Log::DEBUG, "play video file %s",
824           media->getFileName());
825         //OK - simply today
826         if (! media->getURI()) {
827           //addURI
828           MediaListHolder *h=dirlist->getCurrent()->getHolder();
829           if (!h) {
830             Log::getInstance()->log("VMediaList", Log::ERR, "no media List");
831             break;
832           }
833           MediaURI *u=h->list()->getURI(media);
834           media->setURI(u);
835           delete u;
836           h->unref();
837         }
838         removeViewer();
839         VVideoMedia *v=new VVideoMedia(media,this);
840         BoxStack::getInstance()->add(v);
841         BoxStack::getInstance()->update(v);
842         v->go(false);
843         //play video
844 #endif
845       }break;
846         case MEDIA_TYPE_PICTURE:
847         Log::getInstance()->log("VMediaList", Log::DEBUG, "show picture file %s",
848          media->getFileName());
849         if (dirmode != M_NONE && command == Input::PLAY)
850           playAll();
851         else
852           getViewer()->showPicture(MV_NONE,command==Input::PLAY,true);
853         break;
854         default:
855         Log::getInstance()->log("VMediaList", Log::DEBUG, "unknown media type %d file %s",
856           media->getMediaType(),media->getFileName());
857
858         }
859       /*
860       VVideoLive* v = new VVideoLive(dirlist->getCurrent()->getHolder(), media->type, this);
861
862       v->draw();
863       boxstack->add(v);
864       boxstack->updatev);
865
866       v->medianelChange(VVideoLive::NUMBER, media->number);
867       */
868
869       return BoxStack::COMMAND_HANDLED;
870     }
871     case Input::BACK:
872     {
873             if (dirlist->getLevel() < 1) return BoxStack::DELETE_ME;
874                         dirlist->dropTop();
875                         load();
876     }
877   }
878   // stop command getting to any more views
879   return BoxStack::ABANDON_COMMAND;
880 }
881
882 //go to the next level dir
883 //if OK - delete current medialist
884 bool VMediaList::changeDirectory(Media *media) {
885   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd to %s",media->getFileName());
886   updateSelection();
887   dirlist->getCurrent()->setSortorder(sortOrder);
888   if (dirlist->getLevel() > 200) {
889     Log::getInstance()->log("VMediaList",Log::ERR,"above 300 levels, stop here...");
890     return false;
891   }
892   MediaListHolder *h=dirlist->getCurrent()->getHolder();
893   dirlist->getCurrent()->assignHolder(NULL); //prepare old holder for deletion
894   if (! h) {
895     return false;
896   }
897   MediaURI *uri=h->list()->getURI(media);
898   dirlist->append(uri);
899   delete uri;
900   //same sort order for next level
901   dirlist->getCurrent()->setSortorder(sortOrder);
902   int rt=load();
903   if (rt == 0) {
904     h->unref(); //this deletes now the old list
905     Log::getInstance()->log("VMediaList",Log::DEBUG,"cd OK");
906     return true;
907   }
908   //we were no able to load the new list - so go back to our current list
909   dirlist->dropTop();
910   dirlist->getCurrent()->assignHolder(h); //OK so we saved our list...
911   h->unref();
912   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd  failed");
913   return false;
914 }
915
916 void VMediaList::directoryDone() {
917   if (! playingAll) return;
918   //go up until we are on the startlevel
919   Log::getInstance()->log("VMediaList", Log::DEBUG, "DirectoryDone ");
920   while ( ! dirlist->isOnStartLevel()) {
921     dirlist->dropTop();
922     load();
923     if (dirlist->isOnStartLevel()) break;
924     if (dirlist->getCurrent()->move(MV_NEXT))
925       break;
926   }
927   if ( dirlist->isOnStartLevel()) {
928     //OK we are done
929     playingAll=false;
930     Log::getInstance()->log("VMediaList", Log::DEBUG, "finished playing all l=%lu",dirlist->getLevel());
931     return;
932   }
933   updateSelection(true);
934   playAll();
935 }
936
937 bool VMediaList::playAll() {
938   if (dirmode == M_NONE) return false;
939   bool started=false;
940   if (! playingAll) {
941     //starting now
942     dirlist->setStartLevel();
943     playingAll=true;
944     started=true;
945   }
946   Media *media=getCurrentMedia(dirlist);
947   if (! media) {
948     //empty directory
949     Log::getInstance()->log("VMediaList", Log::DEBUG, "empty dir when calling playall");
950     //directoryDone
951     Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
952     return true;
953   }
954   Media *mcopy=new Media(media);
955   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s,t=%lu, started=%d",
956       mcopy->getDisplayName(),mcopy->getMediaType(),(int)started);
957   while (mcopy->getMediaType()==MEDIA_TYPE_DIR) {
958     //recurse to the next directory
959     bool rt=changeDirectory(mcopy);
960     if (rt ) {
961       //OK succesfully changed dir
962       int entries=getNumEntries(MEDIA_TYPE_AUDIO|MEDIA_TYPE_DIR|MEDIA_TYPE_PICTURE);
963       Log::getInstance()->log("VMediaList", Log::DEBUG, "cd OK, entries=%d",entries);
964       media=getCurrentMedia(dirlist);
965       if (entries==0 || media == NULL) {
966         Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s empty",mcopy->getDisplayName());
967         delete mcopy;
968         //trigger directory end with the ability of user intervention
969         Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
970         return true;
971       }
972       delete mcopy;
973       mcopy=NULL;
974       if (media->getMediaType()==MEDIA_TYPE_DIR) {
975         //send a defered event to give the user a chance to interrupt
976         //will again call playAll (but this does not chage the start level)
977         Timers::getInstance()->setTimerD(this,2,0,10000000l); //10ms
978         return true;
979       }
980       break;
981     }
982     else 
983     {
984       //unable to change to the directory
985       if (dirlist->getCurrent()->move(MV_NEXT)) {
986         //OK there is still a next medium here
987         updateSelection(true);
988         media=getCurrentMedia(dirlist);
989         if (!media) {
990           Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
991           return true;
992         }
993         delete mcopy;
994         mcopy=new Media(media);
995         continue;
996       }
997       //hmm - no entries here any more
998       //so we have to stop
999       delete mcopy;
1000       playingAll=false;
1001       return false;
1002     }
1003   }
1004   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all on level %d, sele=%d",
1005       dirlist->getLevel(),dirlist->getCurrent()->getSelection());
1006   delete mcopy;
1007   enum Dirmode currentMode=dirmode;
1008   //OK now we handled all directories - now deal with the current one
1009   //1st determine the number of entries
1010   int aentries=getNumEntries(MEDIA_TYPE_AUDIO,-1,true);
1011   int pentries=getNumEntries(MEDIA_TYPE_PICTURE,-1,true);
1012   if (aentries == 0 && pentries == 0) {
1013     directoryDone();
1014     return false;
1015   }
1016   if (currentMode == M_COUNT) {
1017     if (aentries > pentries) currentMode=M_AUDIO;
1018     else currentMode=M_PICTURE;
1019   }
1020   Log::getInstance()->log("VMediaList", Log::DEBUG, "mode=%d,ae=%d,pe=%d",currentMode,aentries,pentries);
1021   //now find the matching entries and start playing
1022   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1023   if (! h) {
1024     Log::getInstance()->log("VMediaList", Log::ERR, "playing all empty medialist");
1025     playingAll=false;
1026     return false;
1027   }
1028   Media *maudio=NULL;
1029   Media *mpicture=NULL;
1030   int audioselection=-1;
1031   int pictureselection=-1;
1032   for (int i=dirlist->getCurrent()->getSelection();i<(int)h->list()->size();i++) {
1033     Media *m=(*h->list())[i];
1034     if (m->getMediaType() == MEDIA_TYPE_AUDIO && maudio == NULL) {
1035       maudio=m;
1036       audioselection=i;
1037     }
1038     if (m->getMediaType() == MEDIA_TYPE_PICTURE && mpicture == NULL) {
1039       mpicture=m;
1040       pictureselection=i;
1041     }
1042     if (maudio != NULL && mpicture != NULL) break;
1043   }
1044   //OK now we found the first media for both - start players
1045   if (maudio != NULL) {
1046     dirlist->getCurrent()->setSelection(audioselection);
1047     playAudio(true,currentMode==M_AUDIO,mpicture==NULL); //this makes now a copy of dirlist...
1048   }
1049   if (mpicture != NULL) {
1050     dirlist->getCurrent()->setSelection(pictureselection);
1051     getViewer()->showPicture(MV_NONE,true,currentMode==M_PICTURE);
1052   }
1053   h->unref();
1054   updateSelection(true);
1055   return true;
1056 }
1057
1058
1059     
1060
1061   
1062
1063
1064  
1065 void VMediaList::processMessage(Message* m)
1066 {
1067   if (m->message == Message::MOUSE_MOVE)
1068   {
1069     if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
1070     {
1071       sl.draw();
1072       doShowingBar();
1073       boxstack->update(this);
1074       updateSelection();
1075     }
1076   }
1077   else if (m->message == Message::MOUSE_LBDOWN)
1078   {
1079     if (sl.mouseLBDOWN(m->parameter - getScreenX(), m->tag - getScreenY()))
1080     {
1081       updateSelection();
1082       Input::sendInputKey(Input::OK);
1083     }
1084     else if (coordsOutsideBox(m))
1085     {
1086       Input::sendInputKey(Input::BACK);
1087     }
1088   }
1089   else if (m->message == Message::PLAYER_EVENT) {
1090     switch (m->parameter) {
1091       case 1:
1092         directoryDone();
1093         break;
1094       case 2:
1095         playAll();
1096         break;
1097     }
1098   }
1099 }
1100
1101 int VMediaList::createList() {
1102    Log::getInstance()->log("VMediaList::createList", Log::DEBUG, "");
1103    VMediaList *vmn=new VMediaList();
1104    //show the "loading" indicator
1105    BoxStack::getInstance()->add(vmn);
1106    int rt=vmn->load();
1107    if ( rt != 0) {
1108      BoxStack::getInstance()->remove(vmn);
1109      }
1110    return rt;
1111 }
1112
1113 void VMediaList::sortList(int newSort) {
1114   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1115   if (! h) return;
1116   Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "p=%p,sort=%d,osort=%d, size=%d",this,newSort,sortOrder,h->list()->size());
1117   if (sortOrder == newSort) return;
1118    if (h->list()->begin() != h->list()->end()) {
1119    switch (newSort) {
1120      case SORT_TIME:
1121        ::sort(h->list()->begin(),h->list()->end(),MediaSorterTime());
1122        break;
1123      case SORT_NAME:
1124        ::sort(h->list()->begin(),h->list()->end(),MediaSorterName());
1125        break;
1126      case SORT_RANDOM:
1127        ::sort(h->list()->begin(),h->list()->end(),MediaSorterRandom(time(NULL)));
1128        break;
1129      }
1130    }
1131    sortOrder=newSort;
1132    updateSelectList();
1133    h->unref();
1134    Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "done ");
1135 }
1136
1137
1138 int VMediaList::load() {
1139         
1140         loading=true;
1141         draw();
1142   boxstack->update(this);
1143   MediaPlayer * mp=MediaPlayer::getInstance();
1144   Log::getInstance()->log("VMediaList::load", Log::DEBUG, "load list for %p",dirlist->getURI());
1145         MediaDirectory *md=dirlist->getCurrent();
1146   MediaList *mn=NULL;
1147   if (md->getURI()) {
1148     mn=mp->getMediaList(md->getURI());
1149   }
1150   else {
1151     mn=mp->getRootList();
1152   }
1153   if (mn != NULL) {
1154     MediaListHolder *h=new MediaListHolder(mn);
1155     setList(h);
1156     h->unref();
1157     h=NULL;
1158     draw();
1159     boxstack->update(this);
1160     return 0;
1161     }
1162   else {
1163     Log::getInstance()->log("VMediaList", Log::ERR, "unable to get MediaList for %p",dirlist->getURI());
1164
1165     VInfo* vi = new VInfo();
1166     vi->setSize(400, 150);
1167     vi->createBuffer();
1168     vi->setExitable();
1169     vi->setBorderOn(1);
1170     vi->setTitleBarOn(0);
1171
1172     if (Video::getInstance()->getFormat() == Video::PAL)
1173       vi->setPosition(170, 200);
1174     else
1175       vi->setPosition(160, 150);
1176     vi->setOneLiner(tr("unable to get media list"));
1177     vi->draw();
1178
1179     Message* m = new Message();
1180     m->message = Message::ADD_VIEW;
1181     m->p_to = Message::BOXSTACK;
1182     m->data = reinterpret_cast<void*>(vi);
1183     MessageQueue::getInstance()->postMessage(m);
1184   }
1185   return 1;
1186 }
1187
1188 const char * VMediaList::getDirname(ULONG mtype) const {
1189   if (mtype == MEDIA_TYPE_AUDIO && audiodirlist) {
1190     return audiodirlist->getCurrent()->getDisplayName();
1191   }
1192   return dirlist->getCurrent()->getDisplayName();
1193 }
1194
1195 void VMediaList::timercall(int ref) {
1196   if (ref == 1 || ref == 2 ) {
1197     //send a directory done event 
1198     Message* m = new Message();
1199     m->message = Message::PLAYER_EVENT;
1200     m->to = this;
1201     m->parameter = ref;
1202     MessageQueue::getInstance()->postMessage(m);
1203   }
1204 }
1205  
1206