]> git.vomp.tv Git - vompclient.git/blob - vrecordinglist.cc
Windows Makefile fix
[vompclient.git] / vrecordinglist.cc
1 /*
2     Copyright 2004-2007 Chris Tallon
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 "vrecordinglist.h"
22
23 #include "recman.h"
24 #include "directory.h"
25 #include "recording.h"
26 #include "remote.h"
27 #include "wsymbol.h"
28 #include "boxstack.h"
29 #include "vrecordingmenu.h"
30 #include "vrecording.h"
31 #include "vdr.h"
32 #include "vvideorec.h"
33 #include "vradiorec.h"
34 #include "colour.h"
35 #include "video.h"
36 #include "i18n.h"
37 #include "command.h"
38 #include "vinfo.h"
39 #include "log.h"
40
41 VRecordingList::VRecordingList()
42 {
43   boxstack = BoxStack::getInstance();
44   recman = NULL;
45   loading = true;
46
47   setSize(570, 420);
48   createBuffer();
49   if (Video::getInstance()->getFormat() == Video::PAL)
50   {
51     setPosition(80, 70);
52   }
53   else
54   {
55     setPosition(70, 35);
56   }
57
58   setTitleBarOn(1);
59   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
60
61   sl.setPosition(10, 30 + 5);
62   sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
63   add(&sl);
64 }
65
66 VRecordingList::~VRecordingList()
67 {
68   delete recman;
69 }
70
71 void VRecordingList::drawData(bool doIndexPop)
72 {
73   int saveIndex = sl.getCurrentOption();
74   int saveTop = sl.getTopOption();
75   sl.clear();
76   sl.addColumn(0);
77   sl.addColumn(110);
78
79   int first = 1;
80
81   char tempA[300]; // FIXME  this is guesswork!
82   char tempB[300]; // FIXME
83   struct tm* btime;
84
85   Directory* currentSubDir;
86   DirectoryList::iterator i;
87   DirectoryList* dirList = recman->getDirectories();
88   for (i = dirList->begin(); i != dirList->end(); i++)
89   {
90     currentSubDir = *i;
91     SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);
92     currentSubDir->index = sl.addOption(tempA, 0, first);
93     first = 0;
94   }
95   // FIXME convert the whole program to time_t's
96
97   Recording* currentRec;
98   RecordingList::iterator j;
99   RecordingList* recList = recman->getRecordings();
100   for (j = recList->begin(); j != recList->end(); j++)
101   {
102     currentRec = *j;
103     time_t recStartTime = (time_t)currentRec->getStartTime();
104     btime = localtime(&recStartTime);
105 //NMT does not like this too!
106         //#ifndef _MSC_VER
107 //    strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);
108 //#else
109     strftime(tempA, 299, "%d/%m %H:%M ", btime);
110 //#endif
111     sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());
112     currentRec->index = sl.addOption(tempB, 0, first);
113     first = 0;
114   }
115
116   if (doIndexPop)
117   {
118     sl.hintSetCurrent(slIndexStack.top());
119     slIndexStack.pop();
120   }
121   else
122   {
123     sl.hintSetCurrent(saveIndex);
124     sl.hintSetTop(saveTop);
125   }
126   sl.draw();
127   doShowingBar();
128 }
129
130 void VRecordingList::draw(bool doIndexPop)
131 {
132   if (!loading)
133   {
134     if (recman->isSubDir())
135     {
136       char title[300];
137       SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());
138       setTitleText(title, 364);
139     }
140     else
141     {
142       setTitleText(tr("Recordings"));
143     }
144   }
145
146   TBBoxx::draw();
147
148   if (loading)
149   {
150     drawText(tr("Loading..."), 240, 180, DrawStyle::LIGHTTEXT);
151   }
152   else
153   {
154     char freeSpace[50];
155     int gigFree = recman->getFreeSpace() / 1024;
156     SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);
157     drawTextRJ(freeSpace, 560, 5, DrawStyle::LIGHTTEXT);
158     // Symbols
159
160     WSymbol w;
161     TEMPADD(&w);
162     w.nextSymbol = WSymbol::UP;
163     w.setPosition(20, 385);
164     w.draw();
165     w.nextSymbol = WSymbol::DOWN;
166     w.setPosition(50, 385);
167     w.draw();
168     w.nextSymbol = WSymbol::SKIPBACK;
169     w.setPosition(85, 385);
170     w.draw();
171     w.nextSymbol = WSymbol::SKIPFORWARD;
172     w.setPosition(115, 385);
173     w.draw();
174     w.nextSymbol = WSymbol::PLAY;
175     w.setPosition(150, 385);
176     w.draw();
177     drawTextRJ(tr("[ok] = menu"), 560, 385, DrawStyle::LIGHTTEXT);
178
179     // All static stuff done
180     drawData(doIndexPop);
181   }
182 }
183
184 void VRecordingList::doShowingBar()
185 {
186   int topOption = sl.getTopOption() + 1;
187   if (sl.getNumOptions() == 0) topOption = 0;
188
189   rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);
190   char showing[200];
191   sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
192   drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);
193 }
194
195 void VRecordingList::processMessage(Message* m)
196 {
197   Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);
198
199   if (m->message == Message::MOUSE_MOVE)
200   {
201     if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
202     {
203       sl.draw();
204       doShowingBar();
205       boxstack->update(this);
206     }
207   }
208   else if (m->message == Message::MOUSE_LBDOWN)
209   {
210     if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
211     {
212       boxstack->handleCommand(Remote::OK); //simulate OK press
213     }
214     else
215     {
216       //check if press is outside this view! then simulate cancel
217       int x=(m->parameter>>16)-getScreenX();
218       int y=(m->parameter&0xFFFF)-getScreenY();
219       if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
220       {
221         boxstack->handleCommand(Remote::BACK); //simulate cancel press
222       }
223     }
224   }
225   else if (m->message == Message::DELETE_SELECTED_RECORDING)
226   {
227     Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");
228     doDeleteSelected();
229   }
230   else if (m->message == Message::MOVE_RECORDING)
231   {
232     Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");
233     doMoveRecording((Directory*)m->parameter);
234   }
235   else if (m->message == Message::PLAY_SELECTED_RECORDING)
236   {
237     doPlay(false);
238   }
239   else if (m->message == Message::RESUME_SELECTED_RECORDING)
240   {
241     doPlay(true);
242   }
243 }
244
245 void VRecordingList::doDeleteSelected()
246 {
247   Recording* toDelete = getCurrentOptionRecording();
248
249   if (!toDelete) return;
250
251   Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());
252
253   int success = recman->deleteRecording(toDelete);
254   if (!VDR::getInstance()->isConnected())
255   {
256     Command::getInstance()->connectionLost();
257     return;
258   }
259
260   if (success != 1)
261   {
262     VInfo* vi = new VInfo();
263     vi->setSize(360, 200);
264     vi->createBuffer();
265     if (Video::getInstance()->getFormat() == Video::PAL)
266       vi->setPosition(190, 170);
267     else
268       vi->setPosition(180, 120);
269     vi->setOneLiner(tr("Failed to delete recording"));
270     vi->setExitable();
271     vi->setBorderOn(1);
272     vi->setTitleBarColour(DrawStyle::DANGER);
273     vi->okButton();
274     vi->draw();
275     boxstack->add(vi);
276     boxstack->update(vi);
277   }
278   else
279   {
280     draw();
281     boxstack->update(this);
282   }
283
284 }
285
286 void VRecordingList::doMoveRecording(Directory* toDir)
287 {
288   Recording* toMove = getCurrentOptionRecording();
289   if (!toMove || !toDir) return;
290
291   Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);
292
293   int success = recman->moveRecording(toMove, toDir);
294   if (!VDR::getInstance()->isConnected())
295   {
296     Command::getInstance()->connectionLost();
297     return;
298   }
299
300   if (success != 1)
301   {
302     VInfo* vi = new VInfo();
303     vi->setSize(360, 200);
304     vi->createBuffer();
305     if (Video::getInstance()->getFormat() == Video::PAL)
306       vi->setPosition(190, 170);
307     else
308       vi->setPosition(180, 120);
309     vi->setOneLiner(tr("Failed to move recording"));
310     vi->setExitable();
311     vi->setBorderOn(1);
312     vi->setTitleBarColour(DrawStyle::DANGER);
313     vi->okButton();
314     vi->draw();
315     boxstack->add(vi);
316     boxstack->update(vi);
317   }
318   else
319   {
320     draw();
321     boxstack->update(this);
322   }
323 }
324
325 int VRecordingList::doPlay(bool resume)
326 {
327   Recording* toPlay = getCurrentOptionRecording();
328   if (toPlay)
329   {
330     toPlay->loadRecInfo(); // check if still need this
331     toPlay->loadMarks();
332         bool ish264;
333
334     bool isRadio = toPlay->isRadio(ish264);
335
336     if (isRadio)
337     {
338       VRadioRec* radrec = new VRadioRec(toPlay);
339       radrec->draw();
340       boxstack->add(radrec);
341       boxstack->update(radrec);
342       radrec->go();
343     }
344     else
345     {
346                 if (ish264 && !Video::getInstance()->supportsh264()) {
347                         VInfo* vi = new VInfo();
348                         vi->setSize(360, 200);
349                         vi->createBuffer();
350                         if (Video::getInstance()->getFormat() == Video::PAL)
351                                 vi->setPosition(190, 170);
352                         else
353                                 vi->setPosition(180, 120);
354                         vi->setOneLiner(tr("H264 video not supported"));
355                         vi->setExitable();
356                         vi->setBorderOn(1);
357                         vi->setTitleBarColour(DrawStyle::DANGER);
358                         vi->okButton();
359                         vi->draw();
360                         boxstack->add(vi);
361                         boxstack->update(vi);
362                         
363                 } else if (!ish264 && !Video::getInstance()->supportsmpeg2()) {
364                         VInfo* vi = new VInfo();
365                         vi->setSize(360, 200);
366                         vi->createBuffer();
367                         if (Video::getInstance()->getFormat() == Video::PAL)
368                                 vi->setPosition(190, 170);
369                         else
370                                 vi->setPosition(180, 120);
371                         vi->setOneLiner(tr("Mpeg2 video not supported"));
372                         vi->setExitable();
373                         vi->setBorderOn(1);
374                         vi->setTitleBarColour(DrawStyle::DANGER);
375                         vi->okButton();
376                         vi->draw();
377                         boxstack->add(vi);
378                         boxstack->update(vi);
379
380                 }else {
381                         VVideoRec* vidrec = new VVideoRec(toPlay, ish264);
382                         vidrec->draw();
383                         boxstack->add(vidrec);
384                         boxstack->update(vidrec);
385                         vidrec->go(resume);
386                 }
387     }
388     return 1;
389   }
390   // should not get to here
391   return 0;
392 }
393
394 Recording* VRecordingList::getCurrentOptionRecording()
395 {
396   Recording* currentRec;
397   RecordingList::iterator j;
398   RecordingList* recList = recman->getRecordings();
399   for (j = recList->begin(); j != recList->end(); j++)
400   {
401     currentRec = *j;
402     if (currentRec->index == sl.getCurrentOption()) return currentRec;
403   }
404
405   return NULL;
406 }
407
408 int VRecordingList::handleCommand(int command)
409 {
410   switch(command)
411   {
412     case Remote::DF_UP:
413     case Remote::UP:
414     {
415       sl.up();
416       sl.draw();
417
418       doShowingBar();
419       boxstack->update(this);
420       return 2;
421     }
422     case Remote::DF_DOWN:
423     case Remote::DOWN:
424     {
425       sl.down();
426       sl.draw();
427
428       doShowingBar();
429       boxstack->update(this);
430       return 2;
431     }
432     case Remote::SKIPBACK:
433     {
434       sl.pageUp();
435       sl.draw();
436
437       doShowingBar();
438       boxstack->update(this);
439       return 2;
440     }
441     case Remote::SKIPFORWARD:
442     {
443       sl.pageDown();
444       sl.draw();
445
446       doShowingBar();
447       boxstack->update(this);
448       return 2;
449     }
450     case Remote::OK:
451     {
452       if (sl.getNumOptions() == 0) return 2;
453
454       // Check to see if it is a sub directory
455       Directory* currentSubDir;
456       DirectoryList::iterator i;
457       DirectoryList* dirList = recman->getDirectories();
458       for (i = dirList->begin(); i != dirList->end(); i++)
459       {
460         currentSubDir = *i;
461         if (currentSubDir->index == sl.getCurrentOption())
462         {
463           if (recman->down(currentSubDir))
464           {
465             slIndexStack.push(sl.getCurrentOption());
466             sl.clear();
467             draw();
468             boxstack->update(this);
469           }
470           return 2;
471         }
472       }
473
474       // check to see if it's a recording
475       Recording* current = getCurrentOptionRecording();
476       if (current)
477       {
478         Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());
479
480 /*
481         VRecordingMenu* v = new VRecordingMenu(recman);
482         v->setParent(this);
483         v->setRecording(current);
484         v->draw();
485         boxstack->add(v);
486         boxstack->update(v);
487 */        
488         VRecording* vr = new VRecording(recman, current);
489         vr->setParent(this);
490         vr->draw();
491         boxstack->add(vr);
492         boxstack->update(vr);
493         
494         return 2;
495       }
496       // should not get to here
497       return 1;
498     }
499     case Remote::BACK:
500     {
501       if (recman->isSubDir())
502       {
503         recman->up();
504         sl.clear();
505         draw(true);
506         boxstack->update(this);
507         return 2;
508       }
509       else
510       {
511         return 4;
512       }
513     }
514     case Remote::PLAYPAUSE:
515     case Remote::PLAY:
516     {
517       if (doPlay(true)) return 2;
518       return 1;
519     }
520     case Remote::LEFT:
521     case Remote::RIGHT:
522     case Remote::ZERO:
523     {
524       reSort();
525       return 2;
526     }
527   }
528   // stop command getting to any more views
529   return 1;
530 }
531
532 bool VRecordingList::load()
533 {
534   VDR* vdr = VDR::getInstance();
535
536   recman = new RecMan();
537
538   bool success = vdr->getRecordingsList(recman);
539
540   if (success)
541   {
542     loading = false;
543     char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");
544     if (defaultSortOrder)
545     {
546       if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();
547       delete[] defaultSortOrder;
548     }
549     recman->sort();
550     draw();
551     boxstack->update(this);
552   }
553
554   return success;
555 }
556
557 void VRecordingList::reSort()
558 {
559   recman->toggleSortOrder();
560   recman->sort();
561   sl.clear();
562   draw();
563   boxstack->update(this);
564 }
565