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