File: | menu_whatson.c |
Location: | line 492, column 13 |
Description: | Value stored to 'nextShowMode' during its initialization is never read |
1 | /* -*- c++ -*- |
2 | Copyright (C) 2004-2013 Christian Wieninger |
3 | |
4 | This program is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU General Public License |
6 | as published by the Free Software Foundation; either version 2 |
7 | of the License, or (at your option) any later version. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
18 | |
19 | The author can be reached at cwieninger@gmx.de |
20 | |
21 | The project's page is at http://winni.vdr-developer.org/epgsearch |
22 | */ |
23 | |
24 | #include <vector> |
25 | #include <iostream> |
26 | #include <sstream> |
27 | #include <string> |
28 | #include "uservars.h" |
29 | #include "menu_whatson.h" |
30 | #include "epgsearchext.h" |
31 | #include "menu_event.h" |
32 | #include "menu_myedittimer.h" |
33 | #include "menu_searchresults.h" |
34 | #include "menu_search.h" |
35 | #include "menu_commands.h" |
36 | #include "epgsearchcfg.h" |
37 | #include "switchtimer.h" |
38 | #include "epgsearchcats.h" |
39 | #include "conflictcheck.h" |
40 | #include <math.h> |
41 | #include <vdr/menu.h> |
42 | #include "menu_conflictcheck.h" |
43 | #include "templatefile.h" |
44 | #include "menu_deftimercheckmethod.h" |
45 | #include "timerstatus.h" |
46 | |
47 | #define HOURS(x)((x)/100) ((x)/100) |
48 | #define MINUTES(x)((x)%100) ((x)%100) |
49 | |
50 | #define SKIPHOURS20 20 |
51 | #define HOURS2SECS(x)(x*60*60) (x*60*60) |
52 | |
53 | extern int exitToMainMenu; |
54 | extern bool isUTF8; |
55 | int gl_InfoConflict = 0; |
56 | |
57 | // --- cMenuMyScheduleItem ------------------------------------------------------ |
58 | cMenuMyScheduleItem::cMenuMyScheduleItem(const cEvent *Event, cChannel *Channel, showMode Mode, cMenuTemplate* MenuTemplate) |
59 | { |
60 | event = Event; |
61 | channel = Channel; |
62 | mode = Mode; |
63 | timerMatch = tmNone; |
64 | inSwitchList = false; |
65 | menuTemplate = MenuTemplate; |
66 | Update(true); |
67 | } |
68 | |
69 | bool cMenuMyScheduleItem::Update(bool Force) |
70 | { |
71 | if (!menuTemplate) |
72 | return false; |
73 | |
74 | const char* menutemplate = menuTemplate->MenuTemplate(); |
75 | if (!menutemplate || strlen(menutemplate) == 0) |
76 | return false; |
77 | |
78 | bool result = false; |
79 | |
80 | eTimerMatch OldTimerMatch = timerMatch; |
81 | bool OldInSwitchList = inSwitchList; |
82 | bool hasMatch = false; |
83 | cTimer* timer = NULL__null; |
84 | if (event) timer = Timers.GetMatch(event, &timerMatch); |
85 | if (event) inSwitchList = (SwitchTimers.InSwitchList(event)!=NULL__null); |
86 | if (timer) hasMatch = true; |
87 | |
88 | if (Force || timerMatch != OldTimerMatch || inSwitchList != OldInSwitchList) |
89 | { |
90 | char szProgressPart[Utf8BufSize(12)((12) * 4)] = ""; |
91 | char szProgressPartT2S[12] = ""; |
92 | time_t now = time(NULL__null); |
93 | if (channel) |
94 | { |
95 | if (event) |
96 | { |
97 | time_t startTime = event->StartTime(); |
98 | if ((now - event->StartTime()) >= 0 || strstr(menutemplate, "%time%") != NULL__null) |
99 | { |
100 | int frac = 0; |
101 | if (mode == showNow) |
102 | { |
103 | int dur = event->Duration(); |
104 | if (dur != 0) |
105 | frac = ((now - startTime) * 8 + (dur >> 1)) / dur; |
106 | } |
107 | if (mode == showNext) |
108 | frac = ( ( 30*60 - min((time_t)30*60, startTime - now) ) * 8 + 15*60 ) / (30*60); |
109 | |
110 | frac = min(8,max(0, frac)); |
111 | |
112 | szProgressPartT2S[0] = '['; |
113 | memset(szProgressPartT2S + 1,'|',frac); |
114 | memset(szProgressPartT2S + 1 + frac ,' ', 8 - frac); |
115 | szProgressPartT2S[9] = ']'; |
116 | szProgressPartT2S[10] = 0; |
117 | |
118 | if (!isUTF8) |
119 | { |
120 | szProgressPart[0] = ICON_BAR_OPEN0x87; |
121 | memset(szProgressPart + 1, ICON_BAR_EMPTY0x89, 6); |
122 | szProgressPart[7] = ICON_BAR_CLOSE0x8A; |
123 | szProgressPart[8] = 0; |
124 | memset(szProgressPart, ICON_BAR_FULL0x88, frac?frac:sizeof(szProgressPart)); |
125 | } |
126 | else |
127 | { |
128 | #if defined(__GNUC__4) && __GNUC__4 < 3 && __GNUC_MINOR__2 < 96 |
129 | #else |
130 | std::stringstream buffer; |
131 | buffer << ICON_BAR_OPEN_UTF8"\uE007"; |
132 | for(int i=0;i<8;i++) buffer << (i<frac?ICON_BAR_FULL_UTF8"\uE008":ICON_BAR_EMPTY_UTF8"\uE009"); |
133 | buffer << ICON_BAR_CLOSE_UTF8"\uE00A"; |
134 | char* temp = strdup(buffer.str().c_str()); |
135 | sprintf(szProgressPart, "%s", temp); |
136 | free(temp); |
137 | #endif |
138 | } |
139 | } |
140 | else |
141 | { |
142 | strncpy(szProgressPart, *event->GetTimeString(), 12); |
143 | szProgressPart[11] = 0; |
144 | memcpy(szProgressPartT2S, szProgressPart, 12); |
145 | } |
146 | } |
147 | } |
148 | |
149 | char t[Utf8BufSize(2)((2) * 4)],v[Utf8BufSize(2)((2) * 4)],r[Utf8BufSize(2)((2) * 4)]; |
150 | char szStatus[Utf8BufSize(4)((4) * 4)]; |
151 | szStatus[3] = 0; |
152 | t[1]=v[1]=r[1] = 0; |
153 | |
154 | if (EPGSearchConfig.WarEagle) |
155 | { |
156 | if (!isUTF8) |
157 | { |
158 | t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?ICON_REC0x8B:ICON_CLOCK0x8C) : ICON_CLOCK_HALF0x94 : ' '; |
159 | v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS0x93 : ' '; |
160 | r[0] = event && event->IsRunning() ? ICON_RUNNING0x92 : ' '; |
161 | } |
162 | else |
163 | { |
164 | #if defined(__GNUC__4) && __GNUC__4 < 3 && __GNUC_MINOR__2 < 96 |
165 | #else |
166 | sprintf(t, "%s", (event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?ICON_REC_UTF8"\uE00B":ICON_CLOCK_UTF8"\uE00C") : ICON_CLOCK_HALF_UTF8"\uE014" : " ")); |
167 | sprintf(v, "%s", event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS_UTF8"\uE013" : " "); |
168 | sprintf(r, "%s", (event && event->IsRunning() ? ICON_RUNNING_UTF8"\uE012" : " ")); |
169 | #endif |
170 | } |
171 | } |
172 | else |
173 | { |
174 | t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?'R':'T') : 't' : ' '; |
175 | v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; |
176 | r[0] = event && event->IsRunning() ? '*' : ' '; |
177 | } |
178 | |
179 | if (event && inSwitchList) |
180 | { |
181 | cSwitchTimer* s = SwitchTimers.InSwitchList(event); |
182 | t[0] = (s && s->mode==1)?'s':'S'; |
183 | } |
184 | if (EPGSearchConfig.WarEagle && isUTF8) |
185 | { |
186 | std::stringstream buffer; |
187 | buffer << t << v << r; |
188 | char* temp = strdup(buffer.str().c_str()); |
189 | sprintf(szStatus, "%s", temp); |
190 | free(temp); |
191 | } |
192 | else |
193 | { |
194 | szStatus[0] = t[0]; |
195 | szStatus[1] = v[0]; |
196 | szStatus[2] = r[0]; |
197 | } |
198 | |
199 | char* buffer = strdup(menutemplate); |
200 | strreplace(buffer, '|', '\t'); |
201 | |
202 | char* title; |
203 | title = strdup(event?event->Title():tr(">>> no info! <<<")I18nTranslate(">>> no info! <<<", "vdr-" "epgsearch" )); |
204 | |
205 | title = strreplacei(title, ":", "%colon%"); // assume a title has the form "a?b:c", |
206 | // we need to replace the colon to avoid misinterpretation of the expression as a condition |
207 | buffer = strreplacei(buffer, "%title%", title); |
208 | free(title); |
209 | |
210 | if (channel) |
211 | { |
212 | char szChannelNr[6] = ""; |
213 | snprintf(szChannelNr, 6, "%d", channel->Number()); |
214 | buffer = strreplacei(buffer, "%chnr%", szChannelNr); |
215 | buffer = strreplacei(buffer, "%chsh%", channel->ShortName(true)); |
216 | buffer = strreplacei(buffer, "%chlng%", channel->Name()); |
217 | buffer = strreplacei(buffer, "%progr%", szProgressPart); |
218 | buffer = strreplacei(buffer, "%progrT2S%", szProgressPartT2S); |
219 | } |
220 | |
221 | // parse the epxression and evaluate it |
222 | cVarExpr varExpr(buffer); |
223 | char* tmp = strdup(varExpr.Evaluate(event).c_str()); |
224 | free(buffer); |
225 | buffer = tmp; |
226 | |
227 | buffer = strreplacei(buffer, "$status$", szStatus); |
228 | buffer = strreplacei(buffer, "$t_status$", t); |
229 | buffer = strreplacei(buffer, "$v_status$", v); |
230 | buffer = strreplacei(buffer, "$r_status$", r); |
231 | |
232 | buffer = FixSeparators(buffer, '~'); |
233 | buffer = FixSeparators(buffer, ':'); |
234 | buffer = FixSeparators(buffer, '-'); |
235 | |
236 | SetText(buffer, false); |
237 | |
238 | if (gl_InfoConflict == 0 && EPGSearchConfig.checkTimerConflAfterTimerProg && !Force && timer && timerMatch && timerMatch != OldTimerMatch) |
239 | { |
240 | cConflictCheck C; |
241 | C.Check(); |
242 | if (C.TimerInConflict(timer)) |
243 | gl_InfoConflict = 1; |
244 | } |
245 | return true; |
246 | } |
247 | return result; |
248 | } |
249 | |
250 | void cMenuMyScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) |
251 | { |
252 | #if APIVERSNUM20000 >= 10733 |
253 | bool withDate = (channel == NULL__null); // search for a better way to determine this |
254 | if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch)) |
255 | DisplayMenu->SetItem(Text(), Index, Current, Selectable); |
256 | #endif |
257 | } |
258 | |
259 | // --- cMenuMyScheduleSepItem ------------------------------------------------------ |
260 | cMenuMyScheduleSepItem::cMenuMyScheduleSepItem(const cEvent *Event, cChannel *Channel) |
261 | : cMenuMyScheduleItem(Event, Channel, showNow, NULL__null) |
262 | { |
263 | event = Event; |
264 | channel = Channel; |
265 | dummyEvent = NULL__null; |
266 | SetSelectable(false); |
267 | Update(true); |
268 | } |
269 | |
270 | cMenuMyScheduleSepItem::~cMenuMyScheduleSepItem() |
271 | { |
272 | if (dummyEvent) |
273 | delete dummyEvent; |
274 | } |
275 | |
276 | bool cMenuMyScheduleSepItem::Update(bool Force) |
277 | { |
278 | if (channel) |
279 | SetText(cString::sprintf("%s\t %s %s", MENU_SEPARATOR_ITEMS"----------------------------------------", channel->Name(), MENU_SEPARATOR_ITEMS"----------------------------------------")); |
280 | else if (event) |
281 | { |
282 | dummyEvent = new cEvent(0); |
283 | dummyEvent->SetTitle(cString::sprintf("%s\t %s %s", MENU_SEPARATOR_ITEMS"----------------------------------------", GETDATESTRING(event)*(event->GetDateString()), MENU_SEPARATOR_ITEMS"----------------------------------------")); |
284 | SetText(dummyEvent->Title()); |
285 | } |
286 | return true; |
287 | } |
288 | |
289 | void cMenuMyScheduleSepItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) |
290 | { |
291 | #if APIVERSNUM20000 >= 10733 |
292 | bool withDate = (channel == NULL__null); // search for a better way to determine this |
293 | if (!DisplayMenu->SetItemEvent(dummyEvent, Index, Current, Selectable, channel, withDate, timerMatch)) |
294 | DisplayMenu->SetItem(Text(), Index, Current, Selectable); |
295 | #endif |
296 | } |
297 | |
298 | |
299 | // --- cMenuWhatsOnSearch ---------------------------------------------------------- |
300 | |
301 | int cMenuWhatsOnSearch::currentChannel = 0; |
302 | showMode cMenuWhatsOnSearch::currentShowMode = showNow; |
303 | cChannel *cMenuWhatsOnSearch::scheduleChannel = NULL__null; |
304 | extern const char *ShowModes[]; |
305 | cList<cShowMode> cMenuWhatsOnSearch::showModes; |
306 | time_t cMenuWhatsOnSearch::seekTime = 0; |
307 | int cMenuWhatsOnSearch::shiftTime = 0; |
308 | |
309 | cMenuWhatsOnSearch::cMenuWhatsOnSearch(const cSchedules *Schedules, int CurrentChannelNr) |
310 | :cOsdMenu("", GetTab(1), GetTab(2), GetTab(3), GetTab(4), GetTab(5)) |
311 | { |
312 | #if VDRVERSNUM20005 >= 10734 |
313 | if (currentShowMode == showNow) |
314 | SetMenuCategory(mcScheduleNow); |
315 | else if (currentShowMode == showNext) |
316 | SetMenuCategory(mcScheduleNext); |
317 | else |
318 | SetMenuCategory(mcSchedule); |
319 | #endif |
320 | |
321 | helpKeys = -1; |
322 | shiftTime = 0; |
323 | schedules = Schedules; |
324 | |
325 | CreateShowModes(); |
326 | |
327 | LoadSchedules(); |
328 | |
329 | currentChannel = CurrentChannelNr; |
330 | |
331 | SetHelpKeys(); |
332 | } |
333 | |
334 | cMenuWhatsOnSearch::~cMenuWhatsOnSearch() |
335 | { |
336 | } |
337 | |
338 | #ifdef USE_GRAPHTFT |
339 | const char* cMenuWhatsOnSearch::MenuKind() |
340 | { |
341 | if (currentShowMode == showNow) return "MenuEpgsWhatsOnNow"; |
342 | if (currentShowMode == showNext) return "MenuEpgsWhatsOnNext"; |
343 | if (currentShowMode > showNext) return "MenuEpgsWhatsOnElse"; |
344 | else return "MenuWhatsOnElse"; |
345 | } |
346 | |
347 | void cMenuWhatsOnSearch::Display(void) |
348 | { |
349 | cOsdMenu::Display(); |
350 | |
351 | if (Count() > 0) |
352 | { |
353 | int i = 0; |
354 | |
355 | for (cOsdItem *item = First(); item; item = Next(item)) |
356 | cStatus::MsgOsdEventItem(!item->Selectable() ? 0 : |
357 | ((cMenuMyScheduleItem*)item)->event, |
358 | item->Text(), i++, Count()); |
359 | } |
360 | } |
361 | #endif /* GRAPHTFT */ |
362 | |
363 | int cMenuWhatsOnSearch::GetTab(int Tab) |
364 | { |
365 | if (currentShowMode == showNow) |
366 | return cTemplFile::GetTemplateByName("MenuWhatsOnNow")->Tab(Tab-1); |
367 | if (currentShowMode == showNext) |
368 | return cTemplFile::GetTemplateByName("MenuWhatsOnNext")->Tab(Tab-1); |
369 | if (currentShowMode > showNext) |
370 | return cTemplFile::GetTemplateByName("MenuWhatsOnElse")->Tab(Tab-1); |
371 | else |
372 | return 0; |
373 | } |
374 | |
375 | void cMenuWhatsOnSearch::LoadSchedules() |
376 | { |
377 | Clear(); |
378 | eventObjects.Clear(); |
379 | |
380 | // time_t SeekTime; |
381 | cString szTitle; |
382 | cShowMode* mode = GetShowMode(currentShowMode); |
383 | if (!mode) return; |
384 | |
385 | if (shiftTime != 0) |
386 | { |
387 | if (currentShowMode == showNow || currentShowMode == showNext) |
388 | seekTime = time(NULL__null); |
389 | else |
390 | { |
391 | if (mode) |
392 | seekTime = GetTimeT(mode->GetTime()); |
393 | if (seekTime < time(NULL__null)) seekTime += HOURS2SECS(24)(24*60*60); |
394 | } |
395 | seekTime += shiftTime*60; |
396 | |
397 | struct tm tm_r; |
398 | time_t now = time(NULL__null); |
399 | |
400 | tm tm_seek = *localtime_r(&seekTime, &tm_r); |
401 | tm tm_now = *localtime_r(&now, &tm_r); |
402 | if (tm_seek.tm_mday != tm_now.tm_mday) |
403 | szTitle = cString::sprintf("%s - %s", tr("Overview")I18nTranslate("Overview", "vdr-" "epgsearch"), DAYDATETIME(seekTime)*DayDateTime(seekTime)); |
404 | else |
405 | szTitle = cString::sprintf("%s - %02d:%02d", tr("Overview")I18nTranslate("Overview", "vdr-" "epgsearch"), tm_seek.tm_hour, tm_seek.tm_min); |
406 | } |
407 | else |
408 | { |
409 | seekTime = GetTimeT(mode->GetTime()); |
410 | if (seekTime < time(NULL__null) && currentShowMode != showNow && currentShowMode != showNext) |
411 | { |
412 | seekTime += HOURS2SECS(24)(24*60*60); |
413 | szTitle = cString::sprintf("%s - %s (%s)", tr("Overview")I18nTranslate("Overview", "vdr-" "epgsearch"), mode->GetDescription(), *WeekDayName(seekTime)); |
414 | } |
415 | else |
416 | szTitle = cString::sprintf("%s - %s", tr("Overview")I18nTranslate("Overview", "vdr-" "epgsearch"), mode->GetDescription()); |
417 | } |
418 | SetTitle(szTitle); |
419 | |
420 | cMenuTemplate* currentTemplate = NULL__null; |
421 | if (currentShowMode == showNow) |
422 | currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnNow"); |
423 | if (currentShowMode == showNext) |
424 | currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnNext"); |
425 | if (currentShowMode > showNext) |
426 | currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnElse"); |
427 | |
428 | int maxChannel = EPGSearchConfig.maxChannelMenuNow; |
429 | if (currentChannel > maxChannel) |
430 | maxChannel = 0; |
431 | |
432 | for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) |
433 | { |
434 | if (!Channel->GroupSep()) |
435 | { |
436 | if (maxChannel && Channel->Number() > maxChannel) break; |
437 | if (EPGSearchConfig.showRadioChannels == 0 && ISRADIO(Channel)((Channel)->Vpid()==0||(Channel)->Vpid()==1||(Channel)-> Vpid()==0x1fff)) |
438 | continue; |
439 | |
440 | const cSchedule *Schedule = schedules->GetSchedule(Channel); |
441 | const cEvent *Event = NULL__null; |
442 | if (Schedule) |
443 | { |
444 | if (shiftTime != 0) |
445 | Event = Schedule->GetEventAround(seekTime); |
446 | else |
447 | { |
448 | switch(currentShowMode) |
449 | { |
450 | default: |
451 | case showNow: |
452 | Event = Schedule->GetPresentEvent(); |
453 | break; |
454 | case showNext: |
455 | Event = Schedule->GetFollowingEvent(); |
456 | break; |
457 | case showUserMode1: |
458 | case showUserMode2: |
459 | case showUserMode3: |
460 | case showUserMode4: |
461 | Event = Schedule->GetEventAround(seekTime); |
462 | break; |
463 | } |
464 | } |
465 | } |
466 | if (!EPGSearchConfig.showEmptyChannels && !Event) |
467 | continue; |
468 | |
469 | Add(new cMenuMyScheduleItem(Event, Channel, currentShowMode, currentTemplate), Channel->Number() == currentChannel); |
470 | if (Event) eventObjects.Add(Event); |
471 | } |
472 | else |
473 | { |
474 | if (EPGSearchConfig.showChannelGroups && strlen(Channel->Name())) |
475 | Add(new cMenuMyScheduleSepItem(NULL__null, Channel)); |
476 | } |
477 | } |
478 | } |
479 | |
480 | time_t cMenuWhatsOnSearch::GetTimeT(int iTime) |
481 | { |
482 | struct tm tm_r; |
483 | time_t t = time(NULL__null); |
484 | tm* tmnow = localtime_r(&t, &tm_r); |
485 | tmnow->tm_hour = HOURS(iTime)((iTime)/100); |
486 | tmnow->tm_min = MINUTES(iTime)((iTime)%100); |
487 | return mktime(tmnow); |
488 | } |
489 | |
490 | showMode cMenuWhatsOnSearch::GetNextMode() |
491 | { |
492 | showMode nextShowMode = currentShowMode; |
Value stored to 'nextShowMode' during its initialization is never read | |
493 | cShowMode* Mode = GetShowMode(currentShowMode); |
494 | if (Mode) |
495 | { |
496 | cShowMode* ModeNext = showModes.Next(Mode); |
497 | if (ModeNext == NULL__null) |
498 | nextShowMode = showNow; |
499 | else |
500 | nextShowMode = ModeNext->GetMode(); |
501 | } |
502 | else // no mode found? fall back to 'now' |
503 | nextShowMode = showNow; |
504 | return nextShowMode; |
505 | } |
506 | |
507 | void cMenuWhatsOnSearch::CreateShowModes() |
508 | { |
509 | showModes.Clear(); |
510 | |
511 | cShowMode* ModeNow = new cShowMode(showNow, trVDR("Button$Now")I18nTranslate("Button$Now")); |
512 | showModes.Add(ModeNow); |
513 | cShowMode* ModeNext = new cShowMode(showNext, trVDR("Button$Next")I18nTranslate("Button$Next")); |
514 | showModes.Add(ModeNext); |
515 | |
516 | time_t now = time(NULL__null); |
517 | for(int i=showUserMode1; i<showModeMax; i++) |
518 | { |
519 | if (!EPGSearchConfig.ShowModes[i].GetUsage()) |
520 | continue; |
521 | |
522 | time_t SeekTime = GetTimeT(EPGSearchConfig.ShowModes[i].GetTime()); |
523 | if (SeekTime < now) |
524 | SeekTime += HOURS2SECS(24)(24*60*60); |
525 | if (SeekTime - now > HOURS2SECS(SKIPHOURS)(20*60*60)) |
526 | continue; |
527 | cShowMode* Mode = new cShowMode((showMode)i, EPGSearchConfig.ShowModes[i].GetDescription(), |
528 | 1, EPGSearchConfig.ShowModes[i].GetTime(), SeekTime); |
529 | showModes.Add(Mode); |
530 | } |
531 | if (EPGSearchConfig.showFavoritesMenu) |
532 | { |
533 | cShowMode* ModeFav = new cShowMode(showFavorites, tr("Button$Favorites")I18nTranslate("Button$Favorites", "vdr-" "epgsearch")); |
534 | showModes.Add(ModeFav); |
535 | } |
536 | showModes.Sort(); |
537 | } |
538 | |
539 | cShowMode* cMenuWhatsOnSearch::GetShowMode(showMode mode) |
540 | { |
541 | for (cShowMode *showMode = showModes.First(); showMode; showMode = showModes.Next(showMode)) |
542 | if (mode == showMode->GetMode()) |
543 | return showMode; |
544 | return NULL__null; |
545 | } |
546 | |
547 | cChannel *cMenuWhatsOnSearch::ScheduleChannel(cChannel *force_channel) |
548 | { |
549 | cChannel *ch = force_channel?force_channel:scheduleChannel; |
550 | scheduleChannel = NULL__null; |
551 | return ch; |
552 | } |
553 | |
554 | |
555 | eOSState cMenuWhatsOnSearch::Switch(void) |
556 | { |
557 | cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); |
558 | if (item && item->channel) { |
559 | if (cDevice::PrimaryDevice()->SwitchChannel(item->channel, true)) |
560 | return osEnd; |
561 | } |
562 | INFO(trVDR("Can't switch channel!"))Skins.Message(mtInfo, I18nTranslate("Can't switch channel!")); |
563 | return osContinue; |
564 | } |
565 | |
566 | eOSState cMenuWhatsOnSearch::Record(void) |
567 | { |
568 | cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); |
569 | if (item) |
570 | { |
571 | if (item->timerMatch == tmFull) |
572 | { |
573 | eTimerMatch tm = tmNone; |
574 | cTimer *timer = Timers.GetMatch(item->event, &tm); |
575 | if (timer) |
576 | { |
577 | if (EPGSearchConfig.useVDRTimerEditMenu) |
578 | return AddSubMenu(new cMenuEditTimer(timer)); |
579 | else |
580 | return AddSubMenu(new cMenuMyEditTimer(timer, false, item->event, item->channel)); |
581 | } |
582 | } |
583 | |
584 | cTimer *timer = NULL__null; |
585 | if (item->event) |
586 | { |
587 | timer = new cTimer(item->event); |
588 | PrepareTimerFile(item->event, timer); |
589 | } |
590 | else |
591 | timer = new cTimer(false, false, item->channel); |
592 | |
593 | cTimer *t = Timers.GetTimer(timer); |
594 | if (EPGSearchConfig.onePressTimerCreation == 0 || t || !item->event || (!t && item->event && item->event->StartTime() - (Setup.MarginStart+2) * 60 < time(NULL__null))) |
595 | { |
596 | if (t) |
597 | { |
598 | delete timer; |
599 | timer = t; |
600 | } |
601 | timer->SetFlags(tfActive); |
602 | if (EPGSearchConfig.useVDRTimerEditMenu) |
603 | return AddSubMenu(new cMenuEditTimer(timer, !t)); |
604 | else |
605 | return AddSubMenu(new cMenuMyEditTimer(timer, !t, item->event, item->channel)); |
606 | } |
607 | else |
608 | { |
609 | string fullaux = ""; |
610 | string aux = ""; |
611 | if (item->event) |
612 | { |
613 | const cEvent* event = item->event; |
614 | int bstart = event->StartTime() - timer->StartTime(); |
615 | int bstop = timer->StopTime() - event->EndTime(); |
616 | int checkmode = DefTimerCheckModes.GetMode(timer->Channel()); |
617 | aux = UpdateAuxValue(aux, "channel", NumToString(timer->Channel()->Number()) + " - " + CHANNELNAME(timer->Channel())(timer->Channel() ? timer->Channel()->ShortName(true ) : "")); |
618 | aux = UpdateAuxValue(aux, "update", checkmode); |
619 | aux = UpdateAuxValue(aux, "eventid", event->EventID()); |
620 | aux = UpdateAuxValue(aux, "bstart", bstart); |
621 | aux = UpdateAuxValue(aux, "bstop", bstop); |
622 | fullaux = UpdateAuxValue(fullaux, "epgsearch", aux); |
623 | } |
624 | #ifdef USE_PINPLUGIN |
625 | aux = ""; |
626 | aux = UpdateAuxValue(aux, "protected", timer->FskProtection() ? "yes" : "no"); |
627 | fullaux = UpdateAuxValue(fullaux, "pin-plugin", aux); |
628 | #endif |
629 | SetAux(timer, fullaux); |
630 | Timers.Add(timer); |
631 | gl_timerStatusMonitor->SetConflictCheckAdvised(); |
632 | timer->Matches(); |
633 | Timers.SetModified(); |
634 | LogFile.iSysLog("timer %s added (active)", *timer->ToDescr()); |
635 | |
636 | if (HasSubMenu()) |
637 | CloseSubMenu(); |
638 | if (Update()) |
639 | Display(); |
640 | SetHelpKeys(); |
641 | } |
642 | } |
643 | return osContinue; |
644 | } |
645 | |
646 | bool cMenuWhatsOnSearch::Update(void) |
647 | { |
648 | bool result = false; |
649 | for (cOsdItem *item = First(); item; item = Next(item)) { |
650 | if (item->Selectable() && ((cMenuMyScheduleItem *)item)->Update()) |
651 | result = true; |
652 | } |
653 | return result; |
654 | } |
655 | |
656 | eOSState cMenuWhatsOnSearch::Commands(eKeys Key) |
657 | { |
658 | if (HasSubMenu() || Count() == 0) |
659 | return osContinue; |
660 | |
661 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
662 | if (mi) |
663 | { |
664 | if (!mi->event) |
665 | { |
666 | if (Key == k3) |
667 | return Switch(); |
668 | else if (Key == k2) |
669 | return Record(); |
670 | else |
671 | return osContinue; |
672 | } |
673 | cMenuSearchCommands *menu; |
674 | eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands")I18nTranslate("EPG Commands", "vdr-" "epgsearch"), mi->event, true)); |
675 | if (Key != kNone) |
676 | state = menu->ProcessKey(Key); |
677 | return state; |
678 | } |
679 | return osContinue; |
680 | } |
681 | |
682 | eOSState cMenuWhatsOnSearch::ExtendedSearch(void) |
683 | { |
684 | return AddSubMenu(new cMenuEPGSearchExt()); |
685 | } |
686 | |
687 | void cMenuWhatsOnSearch::SetHelpKeys(bool Force) |
688 | { |
689 | cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); |
690 | int NewHelpKeys = 0; |
691 | if (item) { |
692 | if (item->Selectable() && item->timerMatch == tmFull) |
693 | NewHelpKeys = 2; |
694 | else |
695 | NewHelpKeys = 1; |
696 | } |
697 | |
698 | bool hasTimer = (NewHelpKeys == 2); |
699 | if (NewHelpKeys != helpKeys || Force) |
700 | { |
701 | showMode nextShowMode = GetNextMode(); |
702 | cShowMode* mode = GetShowMode(nextShowMode); |
703 | const char* szButtonGreen = NULL__null; |
704 | if (mode) |
705 | szButtonGreen = mode->GetDescription(); |
706 | if (toggleKeys==0) |
707 | SetHelp((EPGSearchConfig.redkeymode==0?(hasTimer?trVDR("Button$Timer")I18nTranslate("Button$Timer"):trVDR("Button$Record")I18nTranslate("Button$Record")):tr("Button$Commands")I18nTranslate("Button$Commands", "vdr-" "epgsearch")), |
708 | szButtonGreen, |
709 | trVDR("Button$Schedule")I18nTranslate("Button$Schedule"), |
710 | EPGSearchConfig.bluekeymode==0?(EPGSearchConfig.useOkForSwitch?trVDR("Button$Info")I18nTranslate("Button$Info"):trVDR("Button$Switch")I18nTranslate("Button$Switch")):tr("Button$Search")I18nTranslate("Button$Search", "vdr-" "epgsearch")); |
711 | else |
712 | SetHelp((EPGSearchConfig.redkeymode==1?(hasTimer?trVDR("Button$Timer")I18nTranslate("Button$Timer"):trVDR("Button$Record")I18nTranslate("Button$Record")):tr("Button$Commands")I18nTranslate("Button$Commands", "vdr-" "epgsearch")), |
713 | (EPGSearchConfig.toggleGreenYellow==0?szButtonGreen:"<<"), |
714 | (EPGSearchConfig.toggleGreenYellow==0?trVDR("Button$Schedule")I18nTranslate("Button$Schedule"):">>"), |
715 | EPGSearchConfig.bluekeymode==1?(EPGSearchConfig.useOkForSwitch?trVDR("Button$Info")I18nTranslate("Button$Info"):trVDR("Button$Switch")I18nTranslate("Button$Switch")):tr("Button$Search")I18nTranslate("Button$Search", "vdr-" "epgsearch")); |
716 | helpKeys = NewHelpKeys; |
717 | } |
718 | } |
719 | |
720 | eOSState cMenuWhatsOnSearch::Shift(int iMinutes) |
721 | { |
722 | shiftTime += iMinutes; |
723 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
724 | int TempChannel = currentChannel; |
725 | if (mi) |
726 | { |
727 | currentChannel = mi->channel->Number(); |
728 | scheduleChannel = Channels.GetByNumber(currentChannel); |
729 | } |
730 | LoadSchedules(); |
731 | Display(); |
732 | currentChannel = TempChannel; |
733 | SetHelpKeys(); |
734 | return osContinue; |
735 | } |
736 | |
737 | eOSState cMenuWhatsOnSearch::ShowSummary() |
738 | { |
739 | if (Count()) |
740 | { |
741 | const cEvent *ei = ((cMenuMyScheduleItem *)Get(Current()))->event; |
742 | if (ei) |
743 | { |
744 | cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true, true); |
745 | if (channel) |
746 | return AddSubMenu(new cMenuEventSearch(ei, eventObjects, SurfModeChannel)); |
747 | } |
748 | } |
749 | return osContinue; |
750 | } |
751 | |
752 | void cMenuWhatsOnSearch::UpdateCurrent() |
753 | { |
754 | // navigation in summary could have changed current item, so update it |
755 | cEventObj* cureventObj = eventObjects.GetCurrent(); |
756 | if (cureventObj && cureventObj->Event()) |
757 | for (cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)First(); item; item = (cMenuMyScheduleItem *)Next(item)) |
758 | if (item->Selectable() && item->event == cureventObj->Event()) |
759 | { |
760 | cureventObj->Select(false); |
761 | SetCurrent(item); |
762 | Display(); |
763 | break; |
764 | } |
765 | } |
766 | |
767 | eOSState cMenuWhatsOnSearch::ProcessKey(eKeys Key) |
768 | { |
769 | exitToMainMenu = 0; |
770 | if (!HasSubMenu() && Key == kBack) |
771 | { |
772 | exitToMainMenu = 1; |
773 | return osBack; |
774 | } |
775 | |
776 | bool HadSubMenu = HasSubMenu(); |
777 | eOSState state = cOsdMenu::ProcessKey(Key); |
778 | |
779 | if (!HasSubMenu() && HadSubMenu) // navigation in summary could have changed current item, so update it |
780 | UpdateCurrent(); |
781 | |
782 | if (state == osUnknown) { |
783 | switch (Key) { |
784 | case kFastRew: |
785 | if(!HasSubMenu()) |
786 | return Shift(-EPGSearchConfig.timeShiftValue); |
787 | break; |
788 | case kFastFwd: |
789 | if(!HasSubMenu()) |
790 | return Shift(EPGSearchConfig.timeShiftValue); |
791 | break; |
792 | case kRecord: |
793 | case kRed: |
794 | if(HasSubMenu()) { |
795 | UpdateCurrent(); |
796 | state = Record(); |
797 | break; |
798 | } |
799 | if (Count()) |
800 | { |
801 | if (EPGSearchConfig.redkeymode==toggleKeys) |
802 | state = Record(); |
803 | else |
804 | { |
805 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
806 | if (mi && mi->Selectable()) { |
807 | if (mi->event) |
808 | return AddSubMenu(new cMenuSearchCommands(tr("EPG Commands")I18nTranslate("EPG Commands", "vdr-" "epgsearch"),mi->event)); |
809 | else |
810 | return osContinue; |
811 | } |
812 | } |
813 | } |
814 | break; |
815 | |
816 | case k0: |
817 | if(!HasSubMenu()) |
818 | { |
819 | toggleKeys = 1 - toggleKeys; |
820 | SetHelpKeys(true); |
821 | } |
822 | state = osContinue; |
823 | break; |
824 | case k1...k9: return Commands(Key); |
825 | case kYellow: |
826 | if(!HasSubMenu()) |
827 | { |
828 | if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) |
829 | { |
830 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
831 | if (mi && mi->Selectable() && mi->channel) |
832 | { |
833 | const cSchedule *Schedule = schedules->GetSchedule(mi->channel); |
834 | if (Schedule) |
835 | { |
836 | time_t now = time(NULL__null); |
837 | bool hasFutureEvents = false; |
838 | for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) |
839 | if (e->StartTime() > now) |
840 | { |
841 | hasFutureEvents = true; |
842 | break; |
843 | } |
844 | if (!hasFutureEvents) |
845 | return osContinue; |
846 | } |
847 | else |
848 | return osContinue; |
849 | } |
850 | state = osBack; |
851 | // continue with kGreen |
852 | } |
853 | else |
854 | return Shift(EPGSearchConfig.timeShiftValue); |
855 | } |
856 | case kGreen: |
857 | if(!HasSubMenu()) |
858 | { |
859 | if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) |
860 | { |
861 | if (Key == kYellow) |
862 | currentShowMode = showNow; |
863 | else |
864 | currentShowMode = GetNextMode(); |
865 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
866 | if (mi && mi->Selectable()) |
867 | { |
868 | currentChannel = mi->channel->Number(); |
869 | scheduleChannel = Channels.GetByNumber(currentChannel); |
870 | } |
871 | } |
872 | else |
873 | return Shift(-EPGSearchConfig.timeShiftValue); |
874 | } |
875 | break; |
876 | case kBlue: |
877 | if (HasSubMenu()) |
878 | { |
879 | UpdateCurrent(); |
880 | return Switch(); |
881 | } |
882 | if (EPGSearchConfig.bluekeymode==toggleKeys) |
883 | return EPGSearchConfig.useOkForSwitch?ShowSummary():Switch(); |
884 | else |
885 | return ExtendedSearch(); |
886 | break; |
887 | case kOk: |
888 | { |
889 | cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); |
890 | if (mi && mi->Selectable()) |
891 | { |
892 | if (!mi->event) // no EPG, so simply switch to channel |
893 | return Switch(); |
894 | else |
895 | return EPGSearchConfig.useOkForSwitch?Switch():ShowSummary(); |
896 | } |
897 | } |
898 | break; |
899 | case kInfo: |
900 | return ShowSummary(); |
901 | break; |
902 | default: break; |
903 | } |
904 | } |
905 | if (!HasSubMenu()) |
906 | { |
907 | if ((HadSubMenu || gl_TimerProgged) && Update()) |
908 | { |
909 | if (gl_TimerProgged) // when using epgsearch's timer edit menu, update is delayed because of SVDRP |
910 | { |
911 | gl_TimerProgged = 0; |
912 | SetHelpKeys(); |
913 | } |
914 | Display(); |
915 | } |
916 | if (Key != kNone) |
917 | SetHelpKeys(); |
918 | if (gl_InfoConflict) |
919 | { |
920 | gl_InfoConflict = 0; |
921 | if (Interface->Confirm(tr("Timer conflict! Show?")I18nTranslate("Timer conflict! Show?", "vdr-" "epgsearch"))) |
922 | return AddSubMenu(new cMenuConflictCheck()); |
923 | } |
924 | } |
925 | |
926 | return state; |
927 | } |
928 | |
929 |