]> git.vomp.tv Git - vompclient.git/blob - vmedialist.cc
Display channel name, duration, resume point and size on recording info screen
[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, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 /*
22    Hints for the directory playing:
23    depending on the configValue directoryMode: none|audio|picture|count
24    it will be decided what to do if a directory is selected with [PLAY]:
25     none:    as currently - simply go into
26     audio:   start picture viewer and audio, audio on top
27     picture: start picture viewer and audio, picture on top
28     count:   count occurence of both types, decide for audio/picture
29    Synchronization is done via the "directoryDone" call,
30    this is issued if the Viewer top engine has finished it's list
31    (getMedia returned 0)
32    We will the go back one level and continue
33    Currently we will traverse to new directories only at the beginning 
34    or the real end of each dir.
35    This is handled only by playAll (never by getMedia).
36    As we sort always in a way that all directories come first this should be OK.
37    there are 2 situations where we give the user a chance to interrupt (this is handled
38    by starting a 10ms timer and afterwrads sending a PLAYER_EVENT with the timer ref as
39    parameter):
40    empty directory found - timer 1 - call directoryDone
41    after changing to a new directory the first entry is again a directory - timer 2 - playAll
42    controlling flags:
43      directoryPlaying: globally set as long as we play a dir, reset on any key press here
44      startLevel:       in DirList - set to the level where we started playing, if we are
45                        back to this playing is finished
46      configuredDirmode: configured mode
47      
48 */
49
50
51
52 #include <vector>
53 #include <time.h>
54 #include <string.h>
55 #ifndef WIN32
56 #include "unistd.h"
57 #endif
58 #include "vmedialist.h"
59
60 #include "vmediaview.h"
61 #include "vvideomedia.h"
62 #include "remote.h"
63 #include "wsymbol.h"
64 #include "boxstack.h"
65 #include "colour.h"
66 #include "video.h"
67 #include "i18n.h"
68 #include "vdr.h"
69 #include "command.h"
70 #include "vinfo.h"
71 #include "media.h"
72 #include "mediaplayer.h"
73 #include "log.h"
74 #include "localmediafile.h"
75 #include "mediaoptions.h"
76
77 using namespace std;
78 //a ref count holder
79 class MediaListHolder {
80   public:
81     MediaListHolder(MediaList *l) {
82       _list=l;
83       _ref=1;
84     }
85     MediaList * list() {
86       return _list;
87     }
88     void ref() {
89       _ref++;
90       Log::getInstance()->log("##MLH",Log::DEBUG,"ref %p now %d",_list,_ref);
91     }
92     void unref() {
93       if (_ref >0 ) _ref--;
94       Log::getInstance()->log("##MLH",Log::DEBUG,"unref %p now %d",_list,_ref);
95       if (_ref == 0) delete this;
96     }
97     ~MediaListHolder() {
98       if (_list) delete _list;
99     }
100   private:
101     UINT _ref;
102     MediaList *_list;
103 };
104
105 class MediaDirectory {
106         private:
107     MediaURI *uri;
108                 int selection;
109                 int sortorder;
110                 ULONG mtype;
111     MediaListHolder *holder;
112         public:
113                 void setMediaType(ULONG n) {mtype=n;}
114                 void setSortorder(int s) {
115                         sortorder=s;
116                 }
117                 void setSelection(int s) {
118                         selection=s;
119                 }
120                 int getSelection() {
121                         return selection;
122                 }
123     bool move(ULONG mv) {
124       if (! holder) return false;
125       switch(mv) {
126         case VMediaList::MV_NEXT:
127           if (selection < ((int)holder->list()->size() -1)) {
128             selection++;
129             return true;
130           }
131           break;
132         case VMediaList::MV_PREV:
133           if (selection > 0) {
134             selection--;
135             return true;
136           }
137           break;
138       }
139       return false;
140     }
141
142                 ULONG getMediaType(){return mtype;}
143                 int getSortorder() {
144                         return sortorder;
145                 }
146     const MediaURI * getURI() {
147       return uri;
148     }
149     const char * getDisplayName() {
150       if (! uri || ! uri->getDisplayName()) return "/";
151       return uri->getDisplayName();
152     }
153     //get the holder (increment refcount)
154     MediaListHolder *getHolder() {
155       if ( !holder) return NULL;
156       holder->ref();
157       return holder;
158     }
159     //assign a holder to the directory (auto ref)
160     void assignHolder(MediaListHolder *h) {
161       if (holder) holder->unref();
162       holder=NULL;
163       if (! h) return;
164       h->ref();
165       holder=h;
166     }
167     //constructor with copy!
168                 MediaDirectory(const MediaURI *u) : selection(0),
169             sortorder(0),mtype(MEDIA_TYPE_ALL),holder(NULL){
170         if (u) 
171           uri=new MediaURI(u);
172         else
173           uri=NULL;
174                   }
175                 MediaDirectory(MediaDirectory &c) {
176                         setSelection(c.getSelection());
177                         setMediaType(c.getMediaType());
178                         setSortorder(c.getSortorder());
179       uri=new MediaURI(c.getURI());
180       holder=c.getHolder();
181                 }
182                 ~MediaDirectory() {
183       if (uri) delete uri;
184       if (holder) holder->unref();
185                 }
186 };
187
188 typedef vector<MediaDirectory*> MDirList;
189 class DirList {
190         private:
191                 int current;
192     int startlevel;
193     MDirList list;
194         public:
195                 DirList() {
196                         current=0;
197       startlevel=0;
198                         list.push_back(new MediaDirectory(NULL));
199                 }
200     DirList(DirList *cp) {
201       current=-1;
202       for (MDirList::iterator it=cp->list.begin();it<cp->list.end();it++) {
203         list.push_back(new MediaDirectory(*(*it)));
204         current++;
205       }
206       if (current < 0) {
207         list.push_back(new MediaDirectory(NULL));
208         current=0;
209       }
210       startlevel=cp->startlevel;
211       if (startlevel > current) startlevel=current;
212     }
213                 ~DirList() {
214                         MDirList::iterator it;
215                         for (it=list.begin();it<list.end();it++) {
216                                 delete *it;
217                         }
218                 }
219                 MediaDirectory *getCurrent() {
220                         return list[current];
221                 }
222                 const MediaURI * getURI() {
223                         return getCurrent()->getURI();
224                 }
225                 int dropTop() {
226                         if (current > 0) {
227                                 current--;
228                                 delete list.back();
229                                 list.pop_back();
230                         }
231                         return current;
232                 }
233                 int append(const MediaURI *uri) {
234                         if (! uri) return current;
235                         MediaDirectory* md=new MediaDirectory(uri);
236                         list.push_back(md);
237                         current++;
238                         return current;
239                 }
240
241                 int getLevel() {
242                         return current;
243                 }
244     void setStartLevel() {
245       startlevel=current;
246     }
247     bool isOnStartLevel() {
248       return (startlevel == current);
249     }
250
251 };
252
253
254 class MediaSorterName
255 {
256   public:
257   bool operator() (const Media* a, const Media* b)
258   {
259     if (b->getMediaType() == MEDIA_TYPE_DIR &&
260          a->getMediaType() != MEDIA_TYPE_DIR)
261       return false;
262     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
263         a->getMediaType() == MEDIA_TYPE_DIR)
264       return true;
265     int c = strcmp(b->getFileName(), a->getFileName());
266     if (c > 0) return true;
267     return false;
268   }
269 };
270
271 //a sorter with a randomly initialized order
272 class MediaSorterRandom
273 {
274   public:
275   MediaSorterRandom(int start) {
276     mystart=start;
277   }
278   bool operator() (const Media* a, const Media* b)
279   {
280     if (b->getMediaType() == MEDIA_TYPE_DIR &&
281          a->getMediaType() != MEDIA_TYPE_DIR)
282       return false;
283     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
284         a->getMediaType() == MEDIA_TYPE_DIR)
285       return true;
286     unsigned char suma=sum(a->getFileName(),(unsigned char)mystart);
287     unsigned char sumb=sum(b->getFileName(),(unsigned char)mystart);
288     if (sumb > suma) return true;
289     return false;
290   }
291   private:
292   unsigned char sum(const char *name,unsigned char start) {
293     for (;*name!=0;name++) start=start ^ (unsigned char)*name;
294     return start;
295   }
296   int mystart;
297 };
298
299
300 struct MediaSorterTime
301 {
302   bool operator() (const Media* a, const Media* b)
303   {
304     if (b->getMediaType() == MEDIA_TYPE_DIR &&
305          a->getMediaType() != MEDIA_TYPE_DIR)
306       return false;
307     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
308         a->getMediaType() == MEDIA_TYPE_DIR)
309       return true;
310     if (b->getTime()>a->getTime()) return true;
311     return false;
312   }
313 };
314
315
316 VMediaList::VMediaList()
317 {
318   boxstack = BoxStack::getInstance();
319
320   Log::getInstance()->log("VMediaList::VMediaList", Log::DEBUG, "start");
321         dirlist=new DirList();
322   audiodirlist=NULL;
323   Log::getInstance()->log("VMediaList::VMediaList", Log::DEBUG, "dirlist=%p,curren=%p",dirlist,dirlist->getCurrent());
324         dirlist->getCurrent()->setSortorder(SORT_NAME);
325   setSize(570, 420);
326   createBuffer();
327   if (Video::getInstance()->getFormat() == Video::PAL)
328     setPosition(80, 70);
329   else
330     setPosition(70, 35);
331
332   setTitleBarOn(1);
333   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
334
335   sl.setPosition(10, 30 + 5);
336   sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
337   sl.addColumn(0);
338   sl.addColumn(60);
339   add(&sl);
340   
341   loading=true;
342   sortOrder=SORT_NONE;
343   viewer=NULL;
344   dirmode=M_NONE;
345   const char *dmstring=MediaOptions::getInstance()->getStringOption("DirectoryPlayMode");
346   if (dmstring) {
347     if (strcmp(dmstring,"count") == 0) dirmode=M_COUNT;
348     else if (strcmp(dmstring,"audio") == 0) dirmode=M_AUDIO;
349     else if (strcmp(dmstring,"picture") == 0) dirmode=M_PICTURE;
350   }
351   playingAll=false;
352   //init additional providers
353 #ifndef WIN32
354   LocalMediaFile::init();
355 #endif
356 }
357
358
359 VMediaList::~VMediaList()
360 {
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 Remote::ONE:
721                         {
722       sl.hintSetCurrent(0);
723       sl.draw();
724       updateSelection();
725       doShowingBar();
726       boxstack->update(this);
727       return 2;
728                         }
729     case Remote::DF_UP:
730     case Remote::UP:
731     {
732       sl.up();
733       sl.draw();
734       updateSelection();
735
736       doShowingBar();
737       boxstack->update(this);
738       return 2;
739     }
740     case Remote::DF_DOWN:
741     case Remote::DOWN:
742     {
743       sl.down();
744       sl.draw();
745       updateSelection();
746
747       doShowingBar();
748       boxstack->update(this);
749       return 2;
750     }
751     case Remote::SKIPBACK:
752     {
753       sl.pageUp();
754       sl.draw();
755       updateSelection();
756
757       doShowingBar();
758       boxstack->update(this);
759       return 2;
760     }
761     case Remote::SKIPFORWARD:
762     {
763       sl.pageDown();
764       sl.draw();
765       updateSelection();
766
767       doShowingBar();
768       boxstack->update(this);
769       return 2;
770     }
771     case Remote::BLUE:
772     {
773       switch(sortOrder) {
774         case SORT_NAME:
775           sortList(SORT_TIME);
776           boxstack->update(this);
777           return 2;
778         case SORT_TIME:
779           sortList(SORT_RANDOM);
780           boxstack->update(this);
781           return 2;
782         default:
783           sortList(SORT_NAME);
784           boxstack->update(this);
785           return 2;
786       }
787     }
788     case Remote::OK:
789     case Remote::PLAY:
790     {
791       Media* media = NULL;
792       if (dirlist) media = getCurrentMedia(dirlist);
793       if (media == NULL) return 2;
794       Log::getInstance()->log("VMediaList", Log::DEBUG, "activated %lu", media->index);
795       switch(media->getMediaType())
796       {
797         case MEDIA_TYPE_DIR:
798         { 
799         //create child
800         Log::getInstance()->log("VMediaList", Log::DEBUG, "create child for %s",media->getFileName());
801         if (media->getFileName() == NULL ) return 2;
802         if (command == Remote::PLAY) {
803           dirlist->setStartLevel();
804           playingAll=true;
805         }
806         bool rt=changeDirectory(media);
807         if (command == Remote::PLAY && rt) {
808           playAll();
809         }
810         else {
811           playingAll=false;
812         }
813         break;
814         }
815         case MEDIA_TYPE_AUDIO:
816         Log::getInstance()->log("VMediaList", Log::DEBUG, "play audio file %s",
817           media->getFileName());
818         if (dirmode != M_NONE && command == Remote::PLAY)
819           playAll();
820         else
821           playAudio(command==Remote::PLAY,true,true);
822         break;
823         case MEDIA_TYPE_VIDEO: {
824 #ifndef WIN32 //Only DVB style MPEG is supported by the Windows Part!
825         Log::getInstance()->log("VMediaList", Log::DEBUG, "play video file %s",
826           media->getFileName());
827         //OK - simply today
828         if (! media->getURI()) {
829           //addURI
830           MediaListHolder *h=dirlist->getCurrent()->getHolder();
831           if (!h) {
832             Log::getInstance()->log("VMediaList", Log::ERR, "no media List");
833             break;
834           }
835           MediaURI *u=h->list()->getURI(media);
836           media->setURI(u);
837           delete u;
838           h->unref();
839         }
840         removeViewer();
841         VVideoMedia *v=new VVideoMedia(media,this);
842         BoxStack::getInstance()->add(v);
843         BoxStack::getInstance()->update(v);
844         v->go(false);
845         //play video
846 #endif
847       }break;
848         case MEDIA_TYPE_PICTURE:
849         Log::getInstance()->log("VMediaList", Log::DEBUG, "show picture file %s",
850          media->getFileName());
851         if (dirmode != M_NONE && command == Remote::PLAY)
852           playAll();
853         else
854           getViewer()->showPicture(MV_NONE,command==Remote::PLAY,true);
855         break;
856         default:
857         Log::getInstance()->log("VMediaList", Log::DEBUG, "unknown media type %d file %s",
858           media->getMediaType(),media->getFileName());
859
860         }
861       /*
862       VVideoLive* v = new VVideoLive(dirlist->getCurrent()->getHolder(), media->type, this);
863
864       v->draw();
865       boxstack->add(v);
866       boxstack->updatev);
867
868       v->medianelChange(VVideoLive::NUMBER, media->number);
869       */
870
871       return 2;
872     }
873     case Remote::BACK:
874     {
875                         if (dirlist->getLevel() < 1) return 4;
876                         dirlist->dropTop();
877                         load();
878     }
879   }
880   // stop command getting to any more views
881   return 1;
882 }
883
884 //go to the next level dir
885 //if OK - delete current medialist
886 bool VMediaList::changeDirectory(Media *media) {
887   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd to %s",media->getFileName());
888   updateSelection();
889   dirlist->getCurrent()->setSortorder(sortOrder);
890   if (dirlist->getLevel() > 200) {
891     Log::getInstance()->log("VMediaList",Log::ERR,"above 300 levels, stop here...");
892     return false;
893   }
894   MediaListHolder *h=dirlist->getCurrent()->getHolder();
895   dirlist->getCurrent()->assignHolder(NULL); //prepare old holder for deletion
896   if (! h) {
897     return false;
898   }
899   MediaURI *uri=h->list()->getURI(media);
900   dirlist->append(uri);
901   delete uri;
902   //same sort order for next level
903   dirlist->getCurrent()->setSortorder(sortOrder);
904   int rt=load();
905   if (rt == 0) {
906     h->unref(); //this deletes now the old list
907     Log::getInstance()->log("VMediaList",Log::DEBUG,"cd OK");
908     return true;
909   }
910   //we were no able to load the new list - so go back to our current list
911   dirlist->dropTop();
912   dirlist->getCurrent()->assignHolder(h); //OK so we saved our list...
913   h->unref();
914   Log::getInstance()->log("VMediaList",Log::DEBUG,"cd  failed");
915   return false;
916 }
917
918 void VMediaList::directoryDone() {
919   if (! playingAll) return;
920   //go up until we are on the startlevel
921   Log::getInstance()->log("VMediaList", Log::DEBUG, "DirectoryDone ");
922   while ( ! dirlist->isOnStartLevel()) {
923     dirlist->dropTop();
924     load();
925     if (dirlist->isOnStartLevel()) break;
926     if (dirlist->getCurrent()->move(MV_NEXT))
927       break;
928   }
929   if ( dirlist->isOnStartLevel()) {
930     //OK we are done
931     playingAll=false;
932     Log::getInstance()->log("VMediaList", Log::DEBUG, "finished playing all l=%lu",dirlist->getLevel());
933     return;
934   }
935   updateSelection(true);
936   playAll();
937 }
938
939 bool VMediaList::playAll() {
940   if (dirmode == M_NONE) return false;
941   bool started=false;
942   if (! playingAll) {
943     //starting now
944     dirlist->setStartLevel();
945     playingAll=true;
946     started=true;
947   }
948   Media *media=getCurrentMedia(dirlist);
949   if (! media) {
950     //empty directory
951     Log::getInstance()->log("VMediaList", Log::DEBUG, "empty dir when calling playall");
952     //directoryDone
953     Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
954     return true;
955   }
956   Media *mcopy=new Media(media);
957   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s,t=%lu, started=%d",
958       mcopy->getDisplayName(),mcopy->getMediaType(),(int)started);
959   while (mcopy->getMediaType()==MEDIA_TYPE_DIR) {
960     //recurse to the next directory
961     bool rt=changeDirectory(mcopy);
962     if (rt ) {
963       //OK succesfully changed dir
964       int entries=getNumEntries(MEDIA_TYPE_AUDIO|MEDIA_TYPE_DIR|MEDIA_TYPE_PICTURE);
965       Log::getInstance()->log("VMediaList", Log::DEBUG, "cd OK, entries=%d",entries);
966       media=getCurrentMedia(dirlist);
967       if (entries==0 || media == NULL) {
968         Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all name=%s empty",mcopy->getDisplayName());
969         delete mcopy;
970         //trigger directory end with the ability of user intervention
971         Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
972         return true;
973       }
974       delete mcopy;
975       mcopy=NULL;
976       if (media->getMediaType()==MEDIA_TYPE_DIR) {
977         //send a defered event to give the user a chance to interrupt
978         //will again call playAll (but this does not chage the start level)
979         Timers::getInstance()->setTimerD(this,2,0,10000000l); //10ms
980         return true;
981       }
982       break;
983     }
984     else 
985     {
986       //unable to change to the directory
987       if (dirlist->getCurrent()->move(MV_NEXT)) {
988         //OK there is still a next medium here
989         updateSelection(true);
990         media=getCurrentMedia(dirlist);
991         if (!media) {
992           Timers::getInstance()->setTimerD(this,1,0,10000000l); //10ms
993           return true;
994         }
995         delete mcopy;
996         mcopy=new Media(media);
997         continue;
998       }
999       //hmm - no entries here any more
1000       //so we have to stop
1001       delete mcopy;
1002       playingAll=false;
1003       return false;
1004     }
1005   }
1006   Log::getInstance()->log("VMediaList", Log::DEBUG, "playing all on level %d, sele=%d",
1007       dirlist->getLevel(),dirlist->getCurrent()->getSelection());
1008   delete mcopy;
1009   enum Dirmode currentMode=dirmode;
1010   //OK now we handled all directories - now deal with the current one
1011   //1st determine the number of entries
1012   int aentries=getNumEntries(MEDIA_TYPE_AUDIO,-1,true);
1013   int pentries=getNumEntries(MEDIA_TYPE_PICTURE,-1,true);
1014   if (aentries == 0 && pentries == 0) {
1015     directoryDone();
1016     return false;
1017   }
1018   if (currentMode == M_COUNT) {
1019     if (aentries > pentries) currentMode=M_AUDIO;
1020     else currentMode=M_PICTURE;
1021   }
1022   Log::getInstance()->log("VMediaList", Log::DEBUG, "mode=%d,ae=%d,pe=%d",currentMode,aentries,pentries);
1023   //now find the matching entries and start playing
1024   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1025   if (! h) {
1026     Log::getInstance()->log("VMediaList", Log::ERR, "playing all empty medialist");
1027     playingAll=false;
1028     return false;
1029   }
1030   Media *maudio=NULL;
1031   Media *mpicture=NULL;
1032   int audioselection=-1;
1033   int pictureselection=-1;
1034   for (int i=dirlist->getCurrent()->getSelection();i<(int)h->list()->size();i++) {
1035     Media *m=(*h->list())[i];
1036     if (m->getMediaType() == MEDIA_TYPE_AUDIO && maudio == NULL) {
1037       maudio=m;
1038       audioselection=i;
1039     }
1040     if (m->getMediaType() == MEDIA_TYPE_PICTURE && mpicture == NULL) {
1041       mpicture=m;
1042       pictureselection=i;
1043     }
1044     if (maudio != NULL && mpicture != NULL) break;
1045   }
1046   //OK now we found the first media for both - start players
1047   if (maudio != NULL) {
1048     dirlist->getCurrent()->setSelection(audioselection);
1049     playAudio(true,currentMode==M_AUDIO,mpicture==NULL); //this makes now a copy of dirlist...
1050   }
1051   if (mpicture != NULL) {
1052     dirlist->getCurrent()->setSelection(pictureselection);
1053     getViewer()->showPicture(MV_NONE,true,currentMode==M_PICTURE);
1054   }
1055   h->unref();
1056   updateSelection(true);
1057   return true;
1058 }
1059
1060
1061     
1062
1063   
1064
1065
1066  
1067 void VMediaList::processMessage(Message* m)
1068 {
1069   if (m->message == Message::MOUSE_MOVE)
1070   {
1071     if (sl.mouseMove((m->parameter.num>>16)-getScreenX(),(m->parameter.num&0xFFFF)-getScreenY()))
1072     {
1073       sl.draw();
1074       doShowingBar();
1075       boxstack->update(this);
1076       updateSelection();
1077     }
1078   }
1079   else if (m->message == Message::MOUSE_LBDOWN)
1080   {
1081     if (sl.mouseLBDOWN((m->parameter.num>>16)-getScreenX(),(m->parameter.num&0xFFFF)-getScreenY()))
1082     {
1083       updateSelection();
1084       boxstack->handleCommand(Remote::OK); //simulate OK press
1085     }
1086     else
1087     { //check if press is outside this view! then simulate cancel
1088       int x=(m->parameter.num>>16)-getScreenX();
1089       int y=(m->parameter.num&0xFFFF)-getScreenY();
1090       if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
1091       {
1092         boxstack->handleCommand(Remote::BACK); //simulate cancel press
1093       }
1094     }
1095   }
1096   else if (m->message == Message::PLAYER_EVENT) {
1097     switch (m->parameter.num) {
1098       case 1:
1099         directoryDone();
1100         break;
1101       case 2:
1102         playAll();
1103         break;
1104     }
1105   }
1106 }
1107
1108 int VMediaList::createList() {
1109    Log::getInstance()->log("VMediaList::createList", Log::DEBUG, "");
1110    VMediaList *vmn=new VMediaList();
1111    //show the "loading" indicator
1112    BoxStack::getInstance()->add(vmn);
1113    int rt=vmn->load();
1114    if ( rt != 0) {
1115      BoxStack::getInstance()->remove(vmn);
1116      }
1117    return rt;
1118 }
1119
1120 void VMediaList::sortList(int newSort) {
1121   MediaListHolder *h=dirlist->getCurrent()->getHolder();
1122   if (! h) return;
1123   Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "p=%p,sort=%d,osort=%d, size=%d",this,newSort,sortOrder,h->list()->size());
1124   if (sortOrder == newSort) return;
1125    if (h->list()->begin() != h->list()->end()) {
1126    switch (newSort) {
1127      case SORT_TIME:
1128        ::sort(h->list()->begin(),h->list()->end(),MediaSorterTime());
1129        break;
1130      case SORT_NAME:
1131        ::sort(h->list()->begin(),h->list()->end(),MediaSorterName());
1132        break;
1133      case SORT_RANDOM:
1134        ::sort(h->list()->begin(),h->list()->end(),MediaSorterRandom(time(NULL)));
1135        break;
1136      }
1137    }
1138    sortOrder=newSort;
1139    updateSelectList();
1140    h->unref();
1141    Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "done ");
1142 }
1143
1144
1145 int VMediaList::load() {
1146         
1147         loading=true;
1148         draw();
1149   boxstack->update(this);
1150   MediaPlayer * mp=MediaPlayer::getInstance();
1151   Log::getInstance()->log("VMediaList::load", Log::DEBUG, "load list for %p",dirlist->getURI());
1152         MediaDirectory *md=dirlist->getCurrent();
1153   MediaList *mn=NULL;
1154   if (md->getURI()) {
1155     mn=mp->getMediaList(md->getURI());
1156   }
1157   else {
1158     mn=mp->getRootList();
1159   }
1160   if (mn != NULL) {
1161     MediaListHolder *h=new MediaListHolder(mn);
1162     setList(h);
1163     h->unref();
1164     h=NULL;
1165     draw();
1166     boxstack->update(this);
1167     return 0;
1168     }
1169   else {
1170     Log::getInstance()->log("VMediaList", Log::ERR, "unable to get MediaList for %p",dirlist->getURI());
1171
1172     VInfo* vi = new VInfo();
1173     vi->setSize(400, 150);
1174     vi->createBuffer();
1175     vi->setExitable();
1176     vi->setBorderOn(1);
1177     vi->setTitleBarOn(0);
1178
1179     if (Video::getInstance()->getFormat() == Video::PAL)
1180       vi->setPosition(170, 200);
1181     else
1182       vi->setPosition(160, 150);
1183     vi->setOneLiner(tr("unable to get media list"));
1184     vi->draw();
1185
1186     Message* m = new Message();
1187     m->message = Message::ADD_VIEW;
1188     m->to = boxstack;
1189     m->parameter.num = (ULONG)vi;
1190     Command::getInstance()->postMessageNoLock(m);
1191   }
1192   return 1;
1193 }
1194
1195 const char * VMediaList::getDirname(ULONG mtype) const {
1196   if (mtype == MEDIA_TYPE_AUDIO && audiodirlist) {
1197     return audiodirlist->getCurrent()->getDisplayName();
1198   }
1199   return dirlist->getCurrent()->getDisplayName();
1200 }
1201
1202 void VMediaList::timercall(int ref) {
1203   if (ref == 1 || ref == 2 ) {
1204     //send a directory done event 
1205     Message* m = new Message();
1206     m->message = Message::PLAYER_EVENT;
1207     m->to = this;
1208     m->parameter.num = ref;
1209     Command::getInstance()->postMessageFromOuterSpace(m);
1210   }
1211 }
1212  
1213