]> git.vomp.tv Git - vompclient.git/blob - vmedialist.cc
Media Player From Andreas Vogel
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include <vector>
22 #include "unistd.h"
23 #include "vmedialist.h"
24 #include <time.h>
25 #include <string.h>
26 #include "vpicture.h"
27 #include "vaudioplayer.h"
28
29
30 using namespace std;
31 class MediaDirectory {
32         private:
33                 char * dirname;
34                 char * displayname;
35                 char * fullpath;
36                 int selection;
37                 int sortorder;
38                 ULONG mtype;
39         public:
40                 void setDirname(const char * n) {
41                         if (dirname) delete dirname;
42                         dirname=NULL;
43                         if (!n) return;
44                         dirname=new char[strlen(n)+1];
45                         strcpy(dirname,n);
46                 }
47                 void setDisplayname(const char * n) {
48                         if (displayname) delete displayname;
49                         displayname=NULL;
50                         if (!n) return;
51                         displayname=new char[strlen(n)+1];
52                         strcpy(displayname,n);
53                 }
54                 void setFullpath(const char * n) {
55                         if (fullpath) delete fullpath;
56                         fullpath=NULL;
57                         if (!n) return;
58                         fullpath=new char[strlen(n)+1];
59                         strcpy(fullpath,n);
60                 }
61                 void setSelection(int s) {
62                         selection=s;
63                 }
64                 void setMediaType(ULONG n) {mtype=n;}
65                 void setSortorder(int s) {
66                         sortorder=s;
67                 }
68                 const char * getDirname() {
69                         return dirname;
70                 }
71                 const char * getDisplayname() {
72                         if (displayname) return displayname;
73                         if (fullpath) return fullpath;
74                         if (dirname) return dirname;
75                         return "/";
76                 }
77                 const char * getFullPath() {
78                         return fullpath;
79                 }
80                 int getSelection() {
81                         return selection;
82                 }
83                 ULONG getMediaType(){return mtype;}
84                 int getSortorder() {
85                         return sortorder;
86                 }
87         public:
88                 MediaDirectory(const char *d) : dirname(NULL),displayname(NULL),fullpath(NULL),selection(0),
89             sortorder(0),mtype(MEDIA_TYPE_ALL){
90                   setDirname(d);
91                   }
92                 MediaDirectory(MediaDirectory &c) {
93                         MediaDirectory(c.getDirname());
94                         setDisplayname(c.getDisplayname());
95                         setSelection(c.getSelection());
96                         setMediaType(c.getMediaType());
97                         setSortorder(c.getSortorder());
98                 }
99                 ~MediaDirectory() {
100                         if (dirname) delete dirname;
101                         if (displayname) delete displayname;
102                         if (fullpath) delete fullpath;
103                 }
104 };
105
106 typedef vector<MediaDirectory*> MDirList;
107 class DirList {
108         private:
109                 int current;
110     MDirList list;
111         public:
112                 DirList() {
113                         current=0;
114                         list.push_back(new MediaDirectory(NULL));
115                 }
116                 ~DirList() {
117                         MDirList::iterator it;
118                         for (it=list.begin();it<list.end();it++) {
119                                 delete *it;
120                         }
121                 }
122                 MediaDirectory *getCurrent() {
123                         return list[current];
124                 }
125                 const char * getPath() {
126                         return getCurrent()->getFullPath();
127                 }
128                 int dropTop() {
129                         if (current > 0) {
130                                 current--;
131                                 delete list.back();
132                                 list.pop_back();
133                         }
134                         return current;
135                 }
136                 int append(const char *dirname) {
137                         if (! dirname) return current;
138                         MediaDirectory* md=new MediaDirectory(dirname);
139                         const char *cp=getCurrent()->getFullPath();
140                         int len=strlen(dirname)+2;
141                         if (cp) len+=strlen(cp);
142                         char * fp=new char[len];
143                         *fp=0;
144                         if (cp) {
145                                 strcpy(fp,cp);
146                                 strcat(fp,"/");
147                         }
148                         else if (*dirname != '/' ) strcpy(fp,"/");
149                         strcat(fp,dirname);
150                         md->setFullpath(fp);
151                         delete fp;
152                         list.push_back(md);
153                         current++;
154                         return current;
155                 }
156
157                 int getLevel() {
158                         return current;
159                 }
160
161 };
162
163
164 class MediaSorterName
165 {
166   public:
167   bool operator() (const Media* a, const Media* b)
168   {
169     if (b->getMediaType() == MEDIA_TYPE_DIR &&
170          a->getMediaType() != MEDIA_TYPE_DIR)
171       return false;
172     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
173         a->getMediaType() == MEDIA_TYPE_DIR)
174       return true;
175     int c = strcmp(b->getFileName(), a->getFileName());
176     if (c > 0) return true;
177     return false;
178   }
179 };
180
181 //a sorter with a randomly initialized order
182 class MediaSorterRandom
183 {
184   public:
185   MediaSorterRandom(int start) {
186     mystart=start;
187   }
188   bool operator() (const Media* a, const Media* b)
189   {
190     if (b->getMediaType() == MEDIA_TYPE_DIR &&
191          a->getMediaType() != MEDIA_TYPE_DIR)
192       return false;
193     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
194         a->getMediaType() == MEDIA_TYPE_DIR)
195       return true;
196     unsigned char suma=sum(a->getFileName(),(unsigned char)mystart);
197     unsigned char sumb=sum(b->getFileName(),(unsigned char)mystart);
198     if (sumb > suma) return true;
199     return false;
200   }
201   private:
202   unsigned char sum(const char *name,unsigned char start) {
203     for (;*name!=0;name++) start=start ^ (unsigned char)*name;
204     return start;
205   }
206   int mystart;
207 };
208
209
210 struct MediaSorterTime
211 {
212   bool operator() (const Media* a, const Media* b)
213   {
214     if (b->getMediaType() == MEDIA_TYPE_DIR &&
215          a->getMediaType() != MEDIA_TYPE_DIR)
216       return false;
217     if ( b->getMediaType() != MEDIA_TYPE_DIR &&
218         a->getMediaType() == MEDIA_TYPE_DIR)
219       return true;
220     if (b->getTime()>a->getTime()) return true;
221     return false;
222   }
223 };
224
225
226 VMediaList::VMediaList()
227 {
228         dirlist=new DirList();
229   Log::getInstance()->log("VMediaList::VMediaList", Log::DEBUG, "dirlist=%p,curren=%p",dirlist,dirlist->getCurrent());
230         dirlist->getCurrent()->setSortorder(SORT_NAME);
231   create(570, 420);
232   if (Video::getInstance()->getFormat() == Video::PAL)
233   {
234     setScreenPos(80, 70);
235   }
236   else
237   {
238     setScreenPos(70, 35);
239   }
240
241   setBackgroundColour(Colour::VIEWBACKGROUND);
242   setTitleBarOn(1);
243   setTitleBarColour(Colour::TITLEBARBACKGROUND);
244
245   sl.setSurface(surface);
246   sl.setSurfaceOffset(10, 30 + 5);
247   sl.setDimensions(area.w - 20, area.h - 30 - 15 - 30);
248   sl.addColumn(0);
249   sl.addColumn(60);
250   mediaList=NULL;
251   loading=true;
252   sortOrder=SORT_NONE;
253
254
255 }
256
257 VMediaList::~VMediaList()
258 {
259         delete dirlist;
260   clearMediaList();
261 }
262
263 void VMediaList::clearMediaList() {
264   if (mediaList)
265   {
266     for (UINT i = 0; i < mediaList->size(); i++)
267     {
268       delete (*mediaList)[i];
269     }
270
271     mediaList->clear();
272     delete mediaList;
273   }
274 }
275
276
277
278 int VMediaList::getNumEntries(int mediaType,int lowerThen) {
279   if (mediaType == MEDIA_TYPE_ALL && lowerThen < 0) return mediaList->size();
280   if (lowerThen < 0) lowerThen=mediaList->size();
281   int rt=0;
282   for (int i=0;i<(int)(mediaList->size()) && i <= lowerThen;i++) {
283     if ((*mediaList)[i]->getMediaType() & mediaType) rt++;
284   }
285   return rt;
286 }
287
288 void VMediaList::setList(MediaList* tlist)
289 {
290   if (mediaList != tlist) {
291     clearMediaList();
292   }
293   sortOrder=SORT_NONE;
294   mediaList = tlist;
295   sortList(dirlist->getCurrent()->getSortorder());
296   updateSelectList(dirlist->getCurrent()->getSelection());
297 }
298
299
300 void VMediaList::updateSelectList(){
301         updateSelectList(-1);
302 }
303 void VMediaList::updateSelectList(int currentNumber){
304   char str[5000];
305   char tempA[Media::TIMEBUFLEN];
306   Log::getInstance()->log("VMediaList::updateSelectList", Log::DEBUG, "media=%p",mediaList);
307
308   ULONG currentSelection=0;
309   if (sl.getNumOptions() >= 1 && currentNumber < 0) {
310     currentSelection=sl.getCurrentOptionData();
311         }
312   sl.clear();
313
314   Media* media;
315   int first = 1;
316   if (mediaList)
317   {
318     for (UINT i = 0; i < mediaList->size(); i++)
319     {
320       media = (*mediaList)[i];
321       if (media->getMediaType() == MEDIA_TYPE_DIR) {
322         sprintf(str, "%04u  %s  [%s]", i,media->getTimeString(tempA), media->getDisplayName());
323         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
324         media->index = sl.addOption(str, (ULONG)media, first);
325       }
326       else {
327         sprintf(str, "%04u  %s  %s", i,media->getTimeString(tempA), media->getDisplayName());
328         //Log::getInstance()->log("VMediaList", Log::DEBUG, "add to select list %s",str);
329         media->index = sl.addOption(str, (ULONG)media, first);
330       }
331       first = 0;
332     }
333   }
334         if (currentNumber >= 0) sl.hintSetCurrent(currentNumber);
335         else sl.hintSetCurrent(0);
336   if (currentSelection != 0) {
337     bool found=false;
338     //position to the previous selection
339     for (int i=0;i<sl.getNumOptions();i++) {
340       sl.hintSetCurrent(i);
341       if (sl.getCurrentOptionData() == currentSelection) {
342         found=true;
343         break;
344       }
345     }
346     if (! found) sl.hintSetCurrent(0);
347   }
348   loading=false;
349   if (sl.getNumOptions() > 0)
350     sl.draw();
351   doShowingBar();
352 }
353
354 void VMediaList::highlightMedia(Media* media)
355 {
356   sl.hintSetCurrent(media->index);
357   sl.draw();
358   doShowingBar();
359   ViewMan::getInstance()->updateView(this);
360 }
361
362 void VMediaList::draw()
363 {
364   Log::getInstance()->log("VMediaList::draw", Log::DEBUG, "namestr=%s",dirlist->getCurrent()->getDisplayname());
365   char title[400];
366   SNPRINTF(title, 398, tr("Media - %s"), dirlist->getCurrent()->getDisplayname());
367   title[399]=0;
368   setTitleText(title);
369   View::draw();
370   if (loading)
371   {
372     drawText(tr("Loading..."), 240, 180, Colour::LIGHTTEXT);
373   }
374   else {
375   if (sl.getNumOptions() > 0) sl.draw();
376
377   // Put the status stuff at the bottom
378
379   WSymbol w;
380   w.setSurface(surface);
381
382   w.nextSymbol = WSymbol::UP;
383   w.setSurfaceOffset(20, 385);
384   w.draw();
385
386   w.nextSymbol = WSymbol::DOWN;
387   w.setSurfaceOffset(50, 385);
388   w.draw();
389
390   w.nextSymbol = WSymbol::SKIPBACK;
391   w.setSurfaceOffset(85, 385);
392   w.draw();
393
394   w.nextSymbol = WSymbol::SKIPFORWARD;
395   w.setSurfaceOffset(115, 385);
396   w.draw();
397
398   w.nextSymbol = WSymbol::PLAY;
399   w.setSurfaceOffset(150, 385);
400   w.draw();
401
402   doShowingBar();
403   }
404 }
405
406 void VMediaList::doShowingBar()
407 {
408   int topOption = sl.getTopOption() + 1;
409   if (sl.getNumOptions() == 0) topOption = 0;
410
411   char showing[250];
412   char * strmode=tr("Name");
413   switch (sortOrder) {
414     case SORT_TIME:
415       strmode=tr("Rand");
416       break;
417     case SORT_NAME:
418       strmode=tr("Time");
419       break;
420     default:
421       break;
422   }
423   snprintf(showing, 250,tr("%i to %i of %i"), 
424       topOption, sl.getBottomOption(), sl.getNumOptions());
425
426 //  Box b;
427 //  b.setSurfaceOffset(220, 385);
428 //  b.setDimensions(160, 25);
429 //  b.fillColour(Colour::VIEWBACKGROUND);
430 //  b.drawText(showing, 0, 0, Colour::LIGHTTEXT);
431
432   rectangle(200, 384, 18, 16, Colour::VIDEOBLUE);
433   rectangle(220, 385, 220+160, 385+25, Colour::VIEWBACKGROUND);
434   drawText(strmode, 220, 385, Colour::LIGHTTEXT);
435   drawText(showing, 280, 385, Colour::LIGHTTEXT);
436   if (sl.getCurrentOptionData() != 0) Log::getInstance()->log("VMediaList",Log::DEBUG,"selected %s",((Media *)sl.getCurrentOptionData())->getDisplayName());
437 }
438
439 Media * VMediaList::getMedia(int ltype,ULONG move) {
440   int cur=sl.getCurrentOption();
441   Media *m;
442   bool more=true;
443   while (more) {
444     int last=sl.getCurrentOption();
445     switch (move) {
446       case MV_NEXT:
447         sl.down();
448         break;
449       case MV_PREV:
450         sl.up();
451         break;
452       default:
453         more=false;
454       break;
455     }
456     m=(Media*)sl.getCurrentOptionData();
457     if (m->getMediaType() & ltype) {
458                         sl.draw();
459                         return m;
460                 }
461     //stop if we are done
462     if (sl.getCurrentOption() == cur || sl.getCurrentOption() == last) break;
463   }
464   return NULL;
465 }
466
467 int VMediaList::handleCommand(int command)
468 {
469   switch(command)
470   {
471                 case Remote::ONE:
472                         {
473       sl.hintSetCurrent(0);
474       sl.draw();
475       doShowingBar();
476       ViewMan::getInstance()->updateView(this);
477       return 2;
478                         }
479     case Remote::DF_UP:
480     case Remote::UP:
481     {
482       sl.up();
483       sl.draw();
484
485       doShowingBar();
486       ViewMan::getInstance()->updateView(this);
487       return 2;
488     }
489     case Remote::DF_DOWN:
490     case Remote::DOWN:
491     {
492       sl.down();
493       sl.draw();
494
495       doShowingBar();
496       ViewMan::getInstance()->updateView(this);
497       return 2;
498     }
499     case Remote::SKIPBACK:
500     {
501       sl.pageUp();
502       sl.draw();
503
504       doShowingBar();
505       ViewMan::getInstance()->updateView(this);
506       return 2;
507     }
508     case Remote::SKIPFORWARD:
509     {
510       sl.pageDown();
511       sl.draw();
512
513       doShowingBar();
514       ViewMan::getInstance()->updateView(this);
515       return 2;
516     }
517     case Remote::BLUE:
518     {
519       switch(sortOrder) {
520         case SORT_NAME:
521           sortList(SORT_TIME);
522           ViewMan::getInstance()->updateView(this);
523           return 2;
524         case SORT_TIME:
525           sortList(SORT_RANDOM);
526           ViewMan::getInstance()->updateView(this);
527           return 2;
528         default:
529           sortList(SORT_NAME);
530           ViewMan::getInstance()->updateView(this);
531           return 2;
532       }
533     }
534     case Remote::OK:
535     case Remote::PLAY:
536     {
537       Media* media = NULL;
538       if (mediaList) media = (Media*)sl.getCurrentOptionData();
539       if (media == NULL) return 2;
540       Log::getInstance()->log("VMediaList", Log::DEBUG, "activated %lu", media->index);
541       switch(media->getMediaType())
542       {
543         case MEDIA_TYPE_DIR:
544         { 
545         //create child
546         Log::getInstance()->log("VMediaList", Log::DEBUG, "create child for %s",media->getFileName());
547         if (media->getFileName() == NULL ) return 2;
548                                 if (sl.getNumOptions() >=1) {
549                                         dirlist->getCurrent()->setSelection(sl.getCurrentOption());
550                                 }
551                                 dirlist->getCurrent()->setSortorder(sortOrder);
552                                 dirlist->append(media->getFileName());
553                                 //same sort order for next level
554                                 dirlist->getCurrent()->setSortorder(sortOrder);
555                                 load();
556         break;
557         }
558         case MEDIA_TYPE_AUDIO:
559         Log::getInstance()->log("VMediaList", Log::DEBUG, "play audio file %s",
560           media->getFileName());
561         VAudioplayer::createPlayer(this,command==Remote::PLAY);
562         break;
563         case MEDIA_TYPE_VIDEO:
564         Log::getInstance()->log("VMediaList", Log::DEBUG, "play video file %s",
565           media->getFileName());
566         //play video
567         break;
568         case MEDIA_TYPE_PICTURE:
569         Log::getInstance()->log("VMediaList", Log::DEBUG, "show picture file %s",
570          media->getFileName());
571         VPicture::createViewer(this,command==Remote::PLAY);
572               //play video
573         break;
574         default:
575         Log::getInstance()->log("VMediaList", Log::DEBUG, "unknown media type %d file %s",
576           media->getMediaType(),media->getFileName());
577
578         }
579       /*
580       VVideoLive* v = new VVideoLive(mediaList, media->type, this);
581
582       v->draw();
583       ViewMan::getInstance()->add(v);
584       ViewMan::getInstance()->updateView(v);
585
586       v->medianelChange(VVideoLive::NUMBER, media->number);
587       */
588
589       return 2;
590     }
591     case Remote::BACK:
592     {
593                         if (dirlist->getLevel() < 1) return 4;
594                         dirlist->dropTop();
595                         load();
596     }
597   }
598   // stop command getting to any more views
599   return 1;
600 }
601
602 void VMediaList::processMessage(Message* m)
603 {
604   if (m->message == Message::MOUSE_MOVE)
605   {
606     if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
607     {
608       sl.draw();
609       doShowingBar();
610       ViewMan::getInstance()->updateView(this);
611     }
612   }
613   else if (m->message == Message::MOUSE_LBDOWN)
614   {
615     if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
616     {
617       ViewMan::getInstance()->handleCommand(Remote::OK); //simulate OK press
618     }
619     else
620     { //check if press is outside this view! then simulate cancel
621       int x=(m->parameter>>16)-getScreenX();
622       int y=(m->parameter&0xFFFF)-getScreenY();
623       if (x<0 || y <0 || x>getWidth() || y>getHeight())
624       {
625         ViewMan::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
626       }
627     }
628   }
629 }
630
631 int VMediaList::createList() {
632    Log::getInstance()->log("VMediaList::createList", Log::DEBUG, "");
633    VMediaList *vmn=new VMediaList();
634    //show the "loading" indicator
635    ViewMan::getInstance()->add(vmn);
636    int rt=vmn->load();
637    if ( rt != 0) {
638      ViewMan::getInstance()->removeView(vmn);
639      }
640    return rt;
641 }
642
643 void VMediaList::sortList(int newSort) {
644   if (sortOrder == newSort) return;
645    Log::getInstance()->log("VMediaList::sortList", Log::DEBUG, "p=%p,sort=%d, size=%d",this,newSort,mediaList->size());
646    if (mediaList->begin() != mediaList->end()) {
647    switch (newSort) {
648      case SORT_TIME:
649        ::sort(mediaList->begin(),mediaList->end(),MediaSorterTime());
650        break;
651      case SORT_NAME:
652        ::sort(mediaList->begin(),mediaList->end(),MediaSorterName());
653        break;
654      case SORT_RANDOM:
655        ::sort(mediaList->begin(),mediaList->end(),MediaSorterRandom(time(NULL)));
656        break;
657      }
658    }
659    sortOrder=newSort;
660    updateSelectList();
661 }
662
663
664 int VMediaList::load() {
665         
666         loading=true;
667         draw();
668   ViewMan::getInstance()->updateView(this);
669   VDR* vdr=VDR::getInstance();
670    Log::getInstance()->log("VMediaList::load", Log::DEBUG, "load list for %s",dirlist->getPath());
671   if (vdr->isConnected()) {
672                  MediaDirectory *md=dirlist->getCurrent();
673      MediaList *mn=vdr->getMediaList(md->getFullPath(),md->getMediaType());
674      if (mn != NULL) {
675        setList(mn);
676                          draw();
677        ViewMan::getInstance()->updateView(this);
678        return 0;
679        }
680   }
681   if (! vdr->isConnected()) {
682     Command::getInstance()->connectionLost();
683   }
684   else {
685     Log::getInstance()->log("VMediaList", Log::ERR, "unable to get MediaList for %s",dirlist->getPath());
686     VInfo* vi = new VInfo();
687     vi->create(400, 150);
688     vi->setExitable();
689     vi->setBorderOn(1);
690     vi->setTitleBarOn(0);
691
692     if (Video::getInstance()->getFormat() == Video::PAL)
693       vi->setScreenPos(170, 200);
694     else
695       vi->setScreenPos(160, 150);
696     vi->setOneLiner(tr("unable to get media list"));
697     vi->draw();
698
699     Message* m = new Message();
700     m->message = Message::ADD_VIEW;
701     m->to = ViewMan::getInstance();
702     m->parameter = (ULONG)vi;
703     Command::getInstance()->postMessageNoLock(m);
704   }
705   return 1;
706 }
707
708 const char * VMediaList::getDirname() const {
709         return dirlist->getCurrent()->getFullPath();
710 }