]> git.vomp.tv Git - vompclient.git/blob - vtimerlist.cc
20 CWFs, fix some snprintf calls
[vompclient.git] / vtimerlist.cc
1 /*
2     Copyright 2004-2020 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <cstdio>
23 #include <vector>
24
25 #include "message.h"
26 #include "input.h"
27 #include "wsymbol.h"
28 #include "colour.h"
29 #include "video.h"
30 #include "i18n.h"
31 #include "timers.h"
32 #include "vtimeredit.h"
33 #include "command.h"
34 #include "boxstack.h"
35 #include "vinfo.h"
36 #include "log.h"
37 #include "staticartwork.h"
38
39 #include "vtimerlist.h"
40
41 VTimerList::VTimerList()
42 {
43   clockRegion.x = 420;
44   clockRegion.y = 0;
45   clockRegion.w = 150;
46   clockRegion.h = 30;
47
48   setSize(570, 420);
49   createBuffer();
50
51   indicatorsRegion.x = 6;
52   indicatorsRegion.y = 44;
53   indicatorsRegion.w = 18;
54   indicatorsRegion.h = 15 * (getFontHeight() + 1);
55
56   if (Video::getInstance()->getFormat() == Video::PAL)
57   {
58     setPosition(80, 70);
59   }
60   else
61   {
62     setPosition(70, 35);
63   }
64
65   setTitleBarOn(1);
66   setTitleText(tr("Timers"));
67   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
68   TVMediaInfo *info= new TVMediaInfo();
69   info->setStaticArtwork(sa_timers);
70   setTitleBarIcon(info);
71
72   sl.setPosition(30, 30 + 5);
73   sl.setSize(area.w - 40, area.h - 30 - 15 - 30);
74   add(&sl);
75 }
76
77 void VTimerList::preDelete()
78 {
79   Timers::getInstance()->cancelTimer(this, 1);
80 }
81
82 VTimerList::~VTimerList()
83 {
84   if (recTimerList)
85   {
86     for (UINT i = 0; i < recTimerList->size(); i++)
87     {
88       delete (*recTimerList)[i];
89     }
90
91     recTimerList->clear();
92     delete recTimerList;
93   }
94 }
95
96 void VTimerList::draw()
97 {
98   // Draw statics
99
100   TBBoxx::draw();
101
102   WSymbol w;
103   TEMPADD(&w);
104
105   w.nextSymbol = WSymbol::UP;
106   w.setPosition(20, 385);
107   w.draw();
108
109   w.nextSymbol = WSymbol::DOWN;
110   w.setPosition(50, 385);
111   w.draw();
112
113   w.nextSymbol = WSymbol::SKIPBACK;
114   w.setPosition(85, 385);
115   w.draw();
116
117   w.nextSymbol = WSymbol::SKIPFORWARD;
118   w.setPosition(115, 385);
119   w.draw();
120
121   drawTextRJ("[ok] = edit", 560, 385, DrawStyle::LIGHTTEXT);
122
123   drawClock();
124   drawShowing();
125   drawIndicators();
126 }
127
128 bool VTimerList::load()
129 {
130   recTimerList = VDR::getInstance()->getRecTimersList();
131
132   if (!recTimerList) return false;
133
134   char strA[300];
135   char strB[300];
136
137   struct tm btime;
138
139   // FIXME all drawing stuff in this class and sl.clear somewhere?!
140
141   sl.addColumn(0);
142   sl.addColumn(110);
143
144   RecTimer* recTimer;
145   int first = 1;
146
147   for (UINT i = 0; i < recTimerList->size(); i++)
148   {
149     recTimer = (*recTimerList)[i];
150     time_t rectime = recTimer->startTime;
151     LOCALTIME_R(&rectime, &btime);
152     strftime(strA, 299, "%d/%m %H:%M ", &btime);
153     int check = SNPRINTF(strB, 300, "%s\t%s", strA, recTimer->getName());
154     if ((check < 0) || (check > 299)) Log::getInstance()->log("VTimerList", Log::ERR, "String too big");
155     sl.addOption(strB, recTimer, first);
156     first = 0;
157   }
158
159   return true;
160 }
161
162 void VTimerList::drawClock()
163 {
164   // Blank the area first
165 #ifndef GRADIENT_DRAWING
166   rectangle(area.w - 150, 0, 150, 30, titleBarColour);
167 #endif
168
169   char timeString[20];
170   time_t t;
171   time(&t);
172   struct tm tms;
173   LOCALTIME_R(&t, &tms);
174   strftime(timeString, 19, "%d/%m %H:%M:%S", &tms);
175   drawTextRJ(timeString, 560, 5, DrawStyle::LIGHTTEXT);
176
177   Timers::getInstance()->setTimerT(this, 1, t + 1);
178 }
179
180 void VTimerList::drawShowing()
181 {
182   int topOption = sl.getTopOption() + 1;
183   if (sl.getNumOptions() == 0) topOption = 0;
184 #ifndef GRADIENT_DRAWING
185   rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);
186 #endif
187   char showing[200];
188   sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
189   drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);
190 }
191
192 void VTimerList::quickUpdate() { //only quick for plattform that need it!
193 #ifdef GRADIENT_DRAWING
194       draw();
195 #else
196       sl.draw();
197       drawShowing();
198       drawIndicators();
199 #endif
200 }
201
202 void VTimerList::drawIndicators()
203 {
204   int top = sl.getTopOption();
205   int bottom = sl.getBottomOption();
206   int yinc = getFontHeight() + 1;
207   RecTimer* recTimer;
208 #ifndef GRADIENT_DRAWING
209   rectangle(6, 44, 18, 15*yinc, DrawStyle::VIEWBACKGROUND);
210 #endif
211   // The indexes recorded from the wselectlist into the index member of the RecTimer
212   // Is the same as the position in the vector of RecTimers
213   // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively
214
215   int ypos = 44;
216   for (int current = top; current < bottom; current++)
217   {
218     recTimer = (*recTimerList)[current];
219
220     if (recTimer->recording) // Flashing red square
221     {
222       if (flipflop)
223       {
224         rectangle(6, ypos, 18, 16, DrawStyle::RED);
225         drawText("R", 8, ypos-3, DrawStyle::LIGHTTEXT);
226       }
227     }
228     else if (recTimer->pending)
229     {
230       rectangle(6, ypos, 18, 16, DrawStyle::RED);
231       drawText("X", 8, ypos-3, DrawStyle::BLACK);
232     }
233     else if (recTimer->active == 0)
234     {
235       rectangle(6, ypos, 18, 16, DrawStyle::SELECTHIGHLIGHT);
236       drawText("X", 8, ypos-3, DrawStyle::BLACK);
237     }
238     else
239     {
240 //      if (flipflop) rectangle(6, ypos, 18, 16, DrawStyle::GREEN);
241     }
242
243     ypos += yinc;
244   }
245 }
246
247 void VTimerList::timercall(int /* clientReference */)
248 {
249         flipflop = !flipflop;
250 #ifndef GRADIENT_DRAWING
251   drawClock();
252   BoxStack::getInstance()->update(this, &clockRegion);
253
254   drawIndicators();
255   BoxStack::getInstance()->update(this, &indicatorsRegion);
256 #else
257   draw();
258   BoxStack::getInstance()->update(this);
259 #endif
260 }
261
262 int VTimerList::handleCommand(int command)
263 {
264   switch(command)
265   {
266     case Input::UP:
267     {
268       sl.up();
269       quickUpdate();
270       BoxStack::getInstance()->update(this);
271       return 2;
272     }
273     case Input::DOWN:
274     {
275       sl.down();
276       quickUpdate();
277       BoxStack::getInstance()->update(this);
278       return 2;
279     }
280     case Input::SKIPBACK:
281     {
282       sl.pageUp();
283       quickUpdate();
284       BoxStack::getInstance()->update(this);
285       return 2;
286     }
287     case Input::SKIPFORWARD:
288     {
289       sl.pageDown();
290       quickUpdate();
291       BoxStack::getInstance()->update(this);
292       return 2;
293     }
294     case Input::OK:
295     {
296       RecTimer* recTimer = NULL;
297       if (recTimerList) recTimer = reinterpret_cast<RecTimer*>(sl.getCurrentOptionData());
298       if (recTimer == NULL) return 2;
299
300       VTimerEdit* v = new VTimerEdit(recTimer);
301       v->setParent(this);
302       v->draw();
303       BoxStack::getInstance()->add(v);
304       BoxStack::getInstance()->update(v);
305
306       return 2;
307     }
308     case Input::BACK:
309     {
310       return 4;
311     }
312   }
313   // stop command getting to any more views
314   return 1;
315 }
316
317 void VTimerList::processMessage(Message* m)
318 {
319   if (m->message == Message::MOUSE_MOVE)
320   {
321     if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
322     {
323         quickUpdate();
324       BoxStack::getInstance()->update(this);
325     }
326   }
327   else if (m->message == Message::MOUSE_LBDOWN)
328   {
329     if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
330     {
331       BoxStack::getInstance()->handleCommand(Input::OK); //simulate OK press
332     }
333     else if (coordsOutsideBox(m))
334     {
335       BoxStack::getInstance()->handleCommand(Input::BACK); //simulate cancel press
336     }
337   }
338   else if (m->message == Message::DELETE_SELECTED_TIMER)
339   {
340     RecTimer* recTimer = reinterpret_cast<RecTimer*>(sl.getCurrentOptionData());
341     if (recTimer == NULL) return;
342     Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");
343
344   
345     ULONG retval = VDR::getInstance()->deleteTimer(recTimer);
346     if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }
347     Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);
348     
349     if (retval != 10)
350     {
351       VInfo* errorBox = new VInfo();
352       errorBox->setSize(360, 200);
353       errorBox->createBuffer();
354       if (Video::getInstance()->getFormat() == Video::PAL)
355         errorBox->setPosition(190, 170);
356       else
357         errorBox->setPosition(180, 120);
358
359     
360       if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));
361       else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));
362       else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));
363       else                   errorBox->setOneLiner(tr("Unknown error"));
364
365       errorBox->setExitable();
366       errorBox->setBorderOn(1);
367       errorBox->setTitleBarColour(DrawStyle::DANGER);
368       errorBox->okButton();
369       errorBox->draw();
370       BoxStack::getInstance()->add(errorBox);
371       BoxStack::getInstance()->update(errorBox);
372     }
373     
374     int saveIndex = sl.getCurrentOption();
375     int saveTop = sl.getTopOption();
376      
377     if (recTimerList)
378     {
379       for (UINT i = 0; i < recTimerList->size(); i++)
380       {
381         delete (*recTimerList)[i];
382       }
383
384       recTimerList->clear();
385       delete recTimerList;
386     }
387
388     sl.clear();
389     load();
390
391     sl.hintSetCurrent(saveIndex);
392     sl.hintSetTop(saveTop);
393     draw();
394     BoxStack::getInstance()->update(this);
395   }
396 }
397