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