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