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