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