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