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