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