Bug Summary

File:menu_searchresults.c
Location:line 694, column 2
Description:Value stored to 'nextModeBlue' is never read

Annotated Source Code

1/* -*- c++ -*-
2Copyright (C) 2004-2013 Christian Wieninger
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18
19The author can be reached at cwieninger@gmx.de
20
21The project's page is at http://winni.vdr-developer.org/epgsearch
22*/
23
24#include <vector>
25#include "menu_searchresults.h"
26#include "blacklist.h"
27#include "epgsearchext.h"
28#include "menu_myedittimer.h"
29#include "menu_event.h"
30#include "menu_commands.h"
31#include "epgsearchcfg.h"
32#include "epgsearchtools.h"
33#include "changrp.h"
34#include "recdone.h"
35#include "epgsearchcats.h"
36#include <vdr/menu.h>
37#include "menu_conflictcheck.h"
38#include "uservars.h"
39#include "menu_deftimercheckmethod.h"
40#include "afuzzy.h"
41#include "timerstatus.h"
42#include "switchtimer.h"
43
44const char* ButtonBlue[3] = {NULL__null, NULL__null, NULL__null};
45extern int gl_InfoConflict;
46extern bool isUTF8;
47
48static int CompareRecording(const void *p1, const void *p2)
49{
50#if APIVERSNUM20000 < 10721
51 return (int)((*(cRecording **)p1)->start - (*(cRecording **)p2)->start);
52#else
53 return (int)((*(cRecording **)p1)->Start() - (*(cRecording **)p2)->Start());
54#endif
55}
56
57// --- cMenuSearchResultsItem -------------------------------------------------------
58cMenuSearchResultsItem::cMenuSearchResultsItem(const cEvent *EventInfo, bool EpisodeOnly,
59 bool PreviewTimer, cMenuTemplate* MenuTemplate,
60 const cSearchExt* Search)
61{
62 fileName = NULL__null;
63 event = EventInfo;
64 timerMatch = tmNone;
65 episodeOnly = EpisodeOnly;
66 previewTimer = PreviewTimer;
67 menuTemplate = MenuTemplate?MenuTemplate:cTemplFile::GetTemplateByName("MenuSearchResults");
68 search = Search;
69 inSwitchList = false;
70 Update(true);
71}
72
73bool cMenuSearchResultsItem::Update(bool Force)
74{
75 if (!menuTemplate)
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 t[Utf8BufSize(2)((2) * 4)]="",v[Utf8BufSize(2)((2) * 4)]="",r[Utf8BufSize(2)((2) * 4)]="";
91 char szStatus[Utf8BufSize(4)((4) * 4)] = "";
92 if (EPGSearchConfig.WarEagle)
93 {
94 if (!isUTF8)
95 {
96 t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?ICON_REC0x8B:ICON_CLOCK0x8C) : ICON_CLOCK_HALF0x94 : ' ';
97 t[1] = '\0';
98 v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS0x93 : ' ';
99 v[1] = '\0';
100 r[0] = event && event->IsRunning() ? ICON_RUNNING0x92 : ' ';
101 r[1] = '\0';
102
103 }
104 else
105 {
106#if defined(__GNUC__4) && __GNUC__4 < 3 && __GNUC_MINOR__2 < 96
107#else
108 sprintf(t, "%s", (event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?ICON_REC_UTF8"\uE00B":ICON_CLOCK_UTF8"\uE00C") : ICON_CLOCK_HALF_UTF8"\uE014" : " "));
109 sprintf(v, "%s", event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS_UTF8"\uE013" : " ");
110 sprintf(r, "%s", (event && event->IsRunning() ? ICON_RUNNING_UTF8"\uE012" : " "));
111#endif
112 }
113 }
114 else
115 {
116 t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?'R':'T') : 't' : ' ';
117 t[1] = '\0';
118 v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
119 v[1] = '\0';
120 r[0] = event && event->IsRunning() ? '*' : ' ';
121 r[1] = '\0';
122 }
123 if (event && inSwitchList)
124 {
125 cSwitchTimer* s = SwitchTimers.InSwitchList(event);
126 t[0] = (s && s->mode==1)?'s':'S';
127 }
128 if (t[0] != 'T' && previewTimer)
129 t[0] = 'P';
130
131 strcpy(szStatus, t);
132 strcat(szStatus, v);
133 strcat(szStatus, r);
134
135 char* buffer = strdup(menuTemplate->MenuTemplate());
136 strreplace(buffer, '|', '\t');
137
138 if (!strcasestr(buffer, "%subtitle%") && cTemplFile::GetTemplateByName("MenuFavorites") != menuTemplate)
139 // make sure, there is a subtitle
140 buffer = strreplacei(buffer, "%title%", "%title% ~ %subtitle%");
141 if (episodeOnly)
142 buffer = strreplacei(buffer, "%title%", "");
143
144 // parse the epxression and evaluate it
145 cVarExpr varExpr(buffer);
146 char* tmp = strdup(varExpr.Evaluate(event).c_str());
147 free(buffer);
148 buffer = tmp;
149
150 buffer = strreplacei(buffer, "$status$", szStatus);
151 buffer = strreplacei(buffer, "$t_status$", t);
152 buffer = strreplacei(buffer, "$v_status$", v);
153 buffer = strreplacei(buffer, "$r_status$", r);
154
155 buffer = FixSeparators(buffer, '~');
156 buffer = FixSeparators(buffer, ':');
157 buffer = FixSeparators(buffer, '-');
158
159 SetText(buffer, false);
160
161 if (EPGSearchConfig.checkTimerConflAfterTimerProg && !Force && timer && timerMatch && timerMatch != OldTimerMatch)
162 {
163 cConflictCheck C;
164 C.Check();
165 if (C.TimerInConflict(timer))
166 gl_InfoConflict = 1;
167 }
168
169 return true;
170 }
171 return result;
172}
173
174cMenuSearchResultsItem::cMenuSearchResultsItem(cRecording *Recording)
175{
176 previewTimer = false;
177 episodeOnly = false;
178 menuTemplate = NULL__null;
179 timerMatch = tmNone;
180 inSwitchList = false;
181 event = NULL__null;
182 search = NULL__null;
183 fileName = strdup(Recording->FileName());
184 SetText(Recording->Title('\t'));
185}
186
187void cMenuSearchResultsItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
188{
189#if APIVERSNUM20000 >= 10733
190 cChannel *channel = event?Channels.GetByChannelID(event->ChannelID(), true, true):NULL__null;
191 if (!event)
192 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
193 else if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, true, timerMatch))
194 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
195#endif
196}
197
198// --- cMenuSearchResults -------------------------------------------------------
199
200const cEvent *cMenuSearchResults::scheduleEventInfo = NULL__null;
201
202cMenuSearchResults::cMenuSearchResults(cMenuTemplate* MenuTemplate)
203 :cOsdMenu("", MenuTemplate->Tab(0), MenuTemplate->Tab(1), MenuTemplate->Tab(2), MenuTemplate->Tab(3), MenuTemplate->Tab(4))
204{
205#if VDRVERSNUM20005 >= 10728
206 SetMenuCategory(mcSchedule);
207#endif
208
209 helpKeys = -1;
210 menuTemplate = MenuTemplate;
211 modeYellow = showTitleEpisode;
212 modeBlue = showAll;
213 m_bSort = false;
214 ignoreRunning = false;
215}
216
217int cMenuSearchResults::GetTab(int Tab)
218{
219 if (!menuTemplate)
220 menuTemplate = cTemplFile::GetTemplateByName("MenuSearchResults");
221
222 return menuTemplate->Tab(Tab-1);
223}
224
225bool cMenuSearchResults::Update(void)
226{
227 bool result = false;
228 for (cOsdItem *item = First(); item; item = Next(item)) {
229 if (((cMenuSearchResultsItem *)item)->Update())
230 result = true;
231 }
232 return result;
233}
234
235eOSState cMenuSearchResults::Record(void)
236{
237 UpdateCurrent();
238 cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current());
239 if (item) {
240 if (item->timerMatch == tmFull)
241 {
242 eTimerMatch tm = tmNone;
243 cTimer *timer = Timers.GetMatch(item->event, &tm);
244 if (timer)
245 {
246 if (EPGSearchConfig.useVDRTimerEditMenu)
247 return AddSubMenu(new cMenuEditTimer(timer));
248 else
249 return AddSubMenu(new cMenuMyEditTimer(timer, false, item->event));
250 }
251 }
252
253 cTimer *timer = new cTimer(item->event);
254 PrepareTimerFile(item->event, timer);
255 cTimer *t = Timers.GetTimer(timer);
256 if (EPGSearchConfig.onePressTimerCreation == 0 || t || !item->event || (!t && item->event && item->event->StartTime() - (Setup.MarginStart+2) * 60 < time(NULL__null)))
257 {
258 if (t)
259 {
260 delete timer;
261 timer = t;
262 }
263 if (EPGSearchConfig.useVDRTimerEditMenu)
264 return AddSubMenu(new cMenuEditTimer(timer, !t));
265 else
266 return AddSubMenu(new cMenuMyEditTimer(timer, !t, item->event));
267 }
268 else
269 {
270 string fullaux = "";
271 string aux = "";
272 if (item->event)
273 {
274 const cEvent* event = item->event;
275 int bstart = event->StartTime() - timer->StartTime();
276 int bstop = timer->StopTime() - event->EndTime();
277 int checkmode = DefTimerCheckModes.GetMode(timer->Channel());
278 aux = UpdateAuxValue(aux, "channel", NumToString(timer->Channel()->Number()) + " - " + CHANNELNAME(timer->Channel())(timer->Channel() ? timer->Channel()->ShortName(true
) : "")
);
279 aux = UpdateAuxValue(aux, "update", checkmode);
280 aux = UpdateAuxValue(aux, "eventid", event->EventID());
281 aux = UpdateAuxValue(aux, "bstart", bstart);
282 aux = UpdateAuxValue(aux, "bstop", bstop);
283 fullaux = UpdateAuxValue(fullaux, "epgsearch", aux);
284 }
285
286#ifdef USE_PINPLUGIN
287 aux = "";
288 aux = UpdateAuxValue(aux, "protected", timer->FskProtection() ? "yes" : "no");
289 fullaux = UpdateAuxValue(fullaux, "pin-plugin", aux);
290#endif
291
292 SetAux(timer, fullaux);
293 Timers.Add(timer);
294 gl_timerStatusMonitor->SetConflictCheckAdvised();
295 timer->Matches();
296 Timers.SetModified();
297 LogFile.iSysLog("timer %s added (active)", *timer->ToDescr());
298
299 if (HasSubMenu())
300 CloseSubMenu();
301 if (Update())
302 Display();
303 SetHelpKeys();
304 }
305 }
306 return osContinue;
307}
308
309
310eOSState cMenuSearchResults::Switch(void)
311{
312 UpdateCurrent();
313 cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current());
314 if (item) {
315 cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true, true);
316 if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
317 return osEnd;
318 }
319 INFO(trVDR("Can't switch channel!"))Skins.Message(mtInfo, I18nTranslate("Can't switch channel!"));
320 return osContinue;
321}
322
323eOSState cMenuSearchResults::Commands(eKeys Key, cSearchExt* SearchExt)
324{
325 if (HasSubMenu() || Count() == 0)
326 return osContinue;
327 cMenuSearchResultsItem *mi = (cMenuSearchResultsItem *)Get(Current());
328 if (mi && mi->event) {
329 cMenuSearchCommands *menu;
330 eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands")I18nTranslate("EPG Commands", "vdr-" "epgsearch"), mi->event, true, SearchExt));
331 if (Key != kNone)
332 state = menu->ProcessKey(Key);
333 return state;
334 }
335 return osContinue;
336}
337
338eOSState cMenuSearchResults::ShowSummary()
339{
340 if (Count())
341 {
342 const cEvent *ei = ((cMenuSearchResultsItem *)Get(Current()))->event;
343 if (ei)
344 {
345 cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true, true);
346 if (channel)
347 return AddSubMenu(new cMenuEventSearch(ei, eventObjects));
348 }
349 }
350 return osContinue;
351}
352
353eOSState cMenuSearchResults::OnRed(cSearchExt* searchExt)
354{
355 eOSState state = osUnknown;
356
357 if(HasSubMenu())
358 return Record();
359
360 if (Count())
361 {
362 if (EPGSearchConfig.redkeymode==toggleKeys)
363 state = Record();
364 else
365 {
366 cMenuSearchResultsItem* mi = (cMenuSearchResultsItem*)Get(Current());
367 if (mi) {
368 if (mi->event) {
369 state = AddSubMenu(new cMenuSearchCommands(tr("EPG Commands")I18nTranslate("EPG Commands", "vdr-" "epgsearch"),mi->event, false, searchExt));
370 }
371 }
372 }
373 }
374 return state;
375}
376
377eOSState cMenuSearchResults::OnGreen()
378{
379 eOSState state = osUnknown;
380 if(!HasSubMenu())
381 {
382 m_bSort=!m_bSort;
383 BuildList();
384 state = osContinue;
385 }
386 return state;
387}
388
389eOSState cMenuSearchResults::OnYellow()
390{
391 eOSState state = osUnknown;
392 if(!HasSubMenu())
393 {
394 modeYellow = (modeYellow==showTitleEpisode?showEpisode:showTitleEpisode);
395 BuildList();
396 state = osContinue;
397 }
398 return state;
399}
400
401void cMenuSearchResults::UpdateCurrent()
402{
403 cEventObj* cureventObj = eventObjects.GetCurrent();
404 if (cureventObj && cureventObj->Event())
405 for (cMenuSearchResultsItem* item = (cMenuSearchResultsItem*)First(); item; item = (cMenuSearchResultsItem*)Next(item))
406 if (item->Selectable() && item->event == cureventObj->Event())
407 {
408 cureventObj->Select(false);
409 SetCurrent(item);
410 Display();
411 break;
412 }
413}
414
415eOSState cMenuSearchResults::ProcessKey(eKeys Key)
416{
417 bool HadSubMenu = HasSubMenu();
418 eOSState state = cOsdMenu::ProcessKey(Key);
419
420 if (!HasSubMenu() && HadSubMenu) // navigation in summary could have changed current item, so update it
421 UpdateCurrent();
422
423 if (state == osUnknown) {
424 switch (Key) {
425 case k0:
426 if(!HasSubMenu())
427 {
428 toggleKeys = 1 - toggleKeys;
429 SetHelpKeys(true);
430 }
431 state = osContinue;
432 break;
433 case kGreen:
434 state = OnGreen();
435 break;
436 case kYellow:
437 state = OnYellow();
438 break;
439 case kOk:
440 case kInfo:
441 if(HasSubMenu())
442 {
443 state = cOsdMenu::ProcessKey(Key);
444 break;
445 }
446 if (Count())
447 state = ShowSummary();
448 else
449 state = osBack;
450 break;
451 default:
452 break;
453 }
454 }
455 if (!HasSubMenu())
456 {
457 if ((HadSubMenu || gl_TimerProgged) && Update())
458 {
459 if (gl_TimerProgged) // when using epgsearch's timer edit menu, update is delayed because of SVDRP
460 {
461 gl_TimerProgged = 0;
462 SetHelpKeys();
463 }
464 Display();
465 }
466 if (Key != kNone)
467 SetHelpKeys();
468 if (gl_InfoConflict)
469 {
470 gl_InfoConflict = 0;
471 if (Interface->Confirm(tr("Timer conflict! Show?")I18nTranslate("Timer conflict! Show?", "vdr-" "epgsearch")))
472 state = AddSubMenu(new cMenuConflictCheck());
473 }
474 }
475 return state;
476}
477
478// --- cMenuSearchResultsForSearch -------------------------------------------------------
479cMenuSearchResultsForSearch::cMenuSearchResultsForSearch(cSearchExt* SearchExt, cMenuTemplate* MenuTemplate)
480 :cMenuSearchResults(MenuTemplate)
481{
482 ButtonBlue[0] = tr("Button$all channels")I18nTranslate("Button$all channels", "vdr-" "epgsearch");
483 ButtonBlue[1] = tr("Button$only FTA")I18nTranslate("Button$only FTA", "vdr-" "epgsearch");
484 ButtonBlue[2] = tr("Button$Timer preview")I18nTranslate("Button$Timer preview", "vdr-" "epgsearch");
485
486 searchExt = SearchExt;
487 m_bSort = true;
488 if (searchExt)
489 {
490 modeBlue = searchExt->useChannel==3?showNoPayTV:(EPGSearchConfig.ignorePayTV?showNoPayTV:showAll);
491 BuildList();
492 }
493}
494
495bool cMenuSearchResultsForSearch::BuildList()
496{
497 bool hasResults = false;
498 int current = Current();
499 Clear();
500 time_t now = time(NULL__null);
501 cSearchResults* pSearchResults = searchExt->Run(modeBlue == showNoPayTV?1:0, false, 0, NULL__null, modeBlue != showTimerPreview);
502 Clear();
503 eventObjects.Clear();
504
505 if (pSearchResults)
506 {
507 pSearchResults->SortBy(m_bSort? CompareEventTime: CompareEventChannel);
508
509 for (cSearchResult* pResultObj = pSearchResults->First();
510 pResultObj;
511 pResultObj = pSearchResults->Next(pResultObj))
512 {
513 if (ignoreRunning && now > pResultObj->event->StartTime())
514 continue;
515 if (!(searchExt->useAsSearchTimer && searchExt->avoidRepeats && modeBlue == showTimerPreview))
516 pResultObj->needsTimer = false;
517 hasResults = true;
518 Add(new cMenuSearchResultsItem(pResultObj->event, modeYellow == showEpisode, pResultObj->needsTimer, menuTemplate));
519 eventObjects.Add(pResultObj->event);
520 }
521
522 delete pSearchResults;
523 }
524 if (Count())
525 SetCurrent(Get(0));
526 SetHelpKeys(true);
527
528 cString szTitle = cString::sprintf("%d %s - %s", Count(), tr("Search results")I18nTranslate("Search results", "vdr-" "epgsearch"), searchExt->search);
529 SetTitle(szTitle);
530
531 SetCurrent(Get(current));
532 Display();
533
534 return hasResults;
535}
536
537void cMenuSearchResultsForSearch::SetHelpKeys(bool Force)
538{
539 cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current());
540 int NewHelpKeys = 0;
541 if (item) {
542 if (item->Selectable() && item->timerMatch == tmFull)
543 NewHelpKeys = 2;
544 else
545 NewHelpKeys = 1;
546 }
547
548 bool hasTimer = (NewHelpKeys == 2);
549 if (NewHelpKeys != helpKeys || Force)
550 {
551 ModeBlueSR nextModeBlue = (ModeBlueSR)(((int)modeBlue+1)%3);
552 if (nextModeBlue == showTimerPreview &&
553 (searchExt->useAsSearchTimer == 0 || searchExt->avoidRepeats == 0))
554 nextModeBlue = (ModeBlueSR)(((int)nextModeBlue+1)%3);
555
556 if (toggleKeys==0)
557 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), ButtonBlue[(int)nextModeBlue]);
558 else
559 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), ButtonBlue[(int)nextModeBlue]);
560 helpKeys = NewHelpKeys;
561 }
562}
563
564eOSState cMenuSearchResultsForSearch::ProcessKey(eKeys Key)
565{
566 eOSState state = cMenuSearchResults::ProcessKey(Key);
567
568 if (state == osUnknown) {
569 switch (Key) {
570 case kRecord:
571 case kRed:
572 state = OnRed(searchExt);
573 break;
574 case k1...k9:
575 state = HasSubMenu()?osContinue:Commands(Key, searchExt);
576 break;
577 case kBlue:
578 if (HasSubMenu())
579 state = Switch();
580 else
581 {
582 modeBlue = (ModeBlueSR)(((int)modeBlue+1)%3);
583 if (modeBlue == showTimerPreview &&
584 (!searchExt || (searchExt && (searchExt->useAsSearchTimer == 0 || searchExt->avoidRepeats == 0))))
585 modeBlue = (ModeBlueSR)(((int)modeBlue+1)%3);
586
587 if (modeBlue == showTimerPreview)
588 m_bSort = true; // show always sorted by channel
589 BuildList();
590
591 state = osContinue;
592 }
593 break;
594 default:
595 break;
596 }
597 }
598 return state;
599}
600
601// --- cMenuSearchResultsForBlacklist -------------------------------------------------------
602cMenuSearchResultsForBlacklist::cMenuSearchResultsForBlacklist(cBlacklist* Blacklist)
603 :cMenuSearchResults(cTemplFile::GetTemplateByName("MenuSearchResults"))
604{
605 ButtonBlue[0] = tr("Button$all channels")I18nTranslate("Button$all channels", "vdr-" "epgsearch");
606 ButtonBlue[1] = tr("Button$only FTA")I18nTranslate("Button$only FTA", "vdr-" "epgsearch");
607 ButtonBlue[2] = tr("Button$Timer preview")I18nTranslate("Button$Timer preview", "vdr-" "epgsearch");
608
609 blacklist = Blacklist;
610 m_bSort = true;
611 modeBlue = blacklist->useChannel==3?showNoPayTV:(EPGSearchConfig.ignorePayTV?showNoPayTV:showAll);
612
613 BuildList();
614}
615
616bool cMenuSearchResultsForBlacklist::BuildList()
617{
618 int current = Current();
619 time_t now = time(NULL__null);
620 cSearchResults* pSearchResults = blacklist->Run();
621 Clear();
622 eventObjects.Clear();
623 if (pSearchResults)
624 {
625 pSearchResults->SortBy(m_bSort? CompareEventTime: CompareEventChannel);
626
627 for (cSearchResult* pResultObj = pSearchResults->First();
628 pResultObj;
629 pResultObj = pSearchResults->Next(pResultObj))
630 {
631 if (ignoreRunning && now > pResultObj->event->StartTime())
632 continue;
633 Add(new cMenuSearchResultsItem(pResultObj->event, modeYellow == showEpisode, false));
634 eventObjects.Add(pResultObj->event);
635 }
636
637 delete pSearchResults;
638 }
639 if (Count())
640 SetCurrent(Get(0));
641 SetHelpKeys();
642 cString szTitle = cString::sprintf("%d %s - %s", Count(), tr("Blacklist results")I18nTranslate("Blacklist results", "vdr-" "epgsearch"), blacklist->search);
643 SetTitle(szTitle);
644
645 SetCurrent(Get(current));
646 Display();
647
648 return true;
649}
650
651eOSState cMenuSearchResultsForBlacklist::ProcessKey(eKeys Key)
652{
653 eOSState state = cMenuSearchResults::ProcessKey(Key);
654
655 if (state == osUnknown) {
656 switch (Key) {
657 case k1...k9:
658 state = HasSubMenu()?osContinue:Commands(Key);
659 break;
660 case kRecord:
661 case kRed:
662 state = OnRed();
663 break;
664 case kBlue:
665 if (HasSubMenu())
666 state = Switch();
667 else
668 state = osContinue;
669 break;
670 default:
671 break;
672 }
673 }
674 return state;
675}
676
677void cMenuSearchResultsForBlacklist::SetHelpKeys(bool Force)
678{
679 cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current());
680 int NewHelpKeys = 0;
681 if (item) {
682 if (item->Selectable() && item->timerMatch == tmFull)
683 NewHelpKeys = 2;
684 else
685 NewHelpKeys = 1;
686 }
687
688 bool hasTimer = (NewHelpKeys == 2);
689 if (NewHelpKeys != helpKeys || Force)
690 {
691
692 ModeBlueSR nextModeBlue = (ModeBlueSR)(((int)modeBlue+1)%3);
693 if (nextModeBlue == showTimerPreview)
694 nextModeBlue = (ModeBlueSR)(((int)nextModeBlue+1)%3);
Value stored to 'nextModeBlue' is never read
695
696 if (toggleKeys==0)
697 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), NULL__null);
698 else
699 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), NULL__null);
700 helpKeys = NewHelpKeys;
701 }
702}
703
704// --- cMenuSearchResultsForQuery -------------------------------------------------------
705cMenuSearchResultsForQuery::cMenuSearchResultsForQuery(const char *query, bool IgnoreRunning)
706 :cMenuSearchResultsForSearch(NULL__null, cTemplFile::GetTemplateByName("MenuSearchResults"))
707{
708 modeBlue = EPGSearchConfig.ignorePayTV?showNoPayTV:showAll;
709 ignoreRunning = IgnoreRunning;
710 // create a dummy search
711 if (query)
712 {
713 searchExt = new cSearchExt;
714 strcpy(searchExt->search, query);
715 searchExt->mode = 0; // substring
716 searchExt->useTitle = 1;
717 searchExt->useSubtitle = 0;
718 searchExt->useDescription = 0;
719 searchExt->blacklistMode = blacklistsNone;
720 BuildList();
721 }
722}
723
724cMenuSearchResultsForQuery::~cMenuSearchResultsForQuery()
725{
726 delete searchExt;
727}
728
729bool cMenuSearchResultsForQuery::BuildList()
730{
731 bool bRes = cMenuSearchResultsForSearch::BuildList();
732/* if (!bRes)
733 {
734 char* szMessage = NULL;
735 asprintf(&szMessage, tr("No results! Try again with tolerance %d?"), searchExt->mode == 5?searchExt->fuzzyTolerance+1:1);
736 string sMessage = szMessage;
737 free(szMessage);
738 if (Interface->Confirm(sMessage.c_str()))
739 {
740 if (searchExt->mode == 5) // fuzzy
741 searchExt->fuzzyTolerance++;
742 searchExt->mode = 5;
743 return BuildList();
744 }
745 }
746*/ return bRes;
747}
748
749// --- cMenuSearchResultsForRecs -------------------------------------------------------
750cMenuSearchResultsForRecs::cMenuSearchResultsForRecs(const char *query)
751 :cMenuSearchResultsForQuery(NULL__null)
752{
753#if VDRVERSNUM20005 >= 10728
754 SetMenuCategory(mcCommand);
755#endif
756 SetTitle(tr("found recordings")I18nTranslate("found recordings", "vdr-" "epgsearch"));
757 if (query)
758 {
759 searchExt = new cSearchExt;
760 strcpy(searchExt->search, query);
761 searchExt->mode = 0; // substring
762 searchExt->useTitle = 1;
763 searchExt->useSubtitle = 0;
764 searchExt->useDescription = 0;
765 BuildList();
766 }
767}
768
769bool cMenuSearchResultsForRecs::BuildList()
770{
771 cRecording **pArray = NULL__null;
772 int num = 0;
773
774 int current = Current();
775 Clear();
776 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
777 const cRecordingInfo *recInfo = recording->Info();
778 if (!recInfo) continue;
779 string s1 = (recInfo && recInfo->Title())?recInfo->Title():"";
780 string s2 = searchExt->search;
781 if (s1.empty() || s2.empty()) continue;
782
783 // tolerance for fuzzy searching: 90% of the shorter text length, but at least 1
784 int tolerance = std::max(1, (int)std::min(s1.size(), s2.size()) / 10);
785
786 bool match = FindIgnoreCase(s1, s2) >= 0 ||
787 FindIgnoreCase(s2, s1) >= 0;
788
789 if (!match)
790 {
791 AFUZZY af = { NULL__null, NULL__null, NULL__null, NULL__null, NULL__null, NULL__null, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
792 if (s1.size() > 32) s1 = s1.substr(0, 32);
793 afuzzy_init(s1.c_str(), tolerance, 0, &af);
794 /* Checking substring */
795 int res = afuzzy_checkSUB(s2.c_str(), &af);
796 afuzzy_free(&af);
797 match = (res > 0);
798 }
799 if (!match)
800 {
801 AFUZZY af = { NULL__null, NULL__null, NULL__null, NULL__null, NULL__null, NULL__null, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
802 if (s2.size() > 32) s2 = s2.substr(0, 32);
803 afuzzy_init(s2.c_str(), tolerance, 0, &af);
804 /* Checking substring */
805 int res = afuzzy_checkSUB(s1.c_str(), &af);
806 afuzzy_free(&af);
807 match = (res > 0);
808 }
809
810 if (match) {
811 cRecording **tmp = (cRecording **)realloc(pArray, (num + 1) * sizeof(cRecording *));
812 if (tmp)
813 {
814 pArray=tmp;
815 pArray[num++] = recording;
816 }
817 }
818 }
819
820 qsort(pArray, num, sizeof(cRecording *), CompareRecording);
821 for (int a = 0; a < num; a++)
822 Add(new cMenuSearchResultsItem(pArray[a]));
823 delete pArray;
824
825 SetHelp(NULL__null);
826
827 SetCurrent(Get(current));
828 Display();
829 return true;
830}
831
832cRecording *cMenuSearchResultsForRecs::GetRecording(cMenuSearchResultsItem *Item)
833{
834 cRecording *recording = Recordings.GetByName(Item->FileName());
835 if (!recording)
836 ERROR(tr("Error while accessing recording!"))Skins.Message(mtError, I18nTranslate("Error while accessing recording!"
, "vdr-" "epgsearch"))
;
837 return recording;
838}
839
840eOSState cMenuSearchResultsForRecs::Play(void)
841{
842 cMenuSearchResultsItem *ri = (cMenuSearchResultsItem*)Get(Current());
843 if (ri)
844 {
845 cRecording *recording = GetRecording(ri);
846 if (recording) {
847#if APIVERSNUM20000 < 10728
848 cReplayControl::SetRecording(recording->FileName(), recording->Title());
849#else
850 cReplayControl::SetRecording(recording->FileName());
851#endif
852 return osReplay;
853 }
854 }
855 return osContinue;
856}
857
858eOSState cMenuSearchResultsForRecs::ProcessKey(eKeys Key)
859{
860 eOSState state = cOsdMenu::ProcessKey(Key);
861
862 if (state == osUnknown)
863 {
864 if (Key == kOk)
865 {
866 if (Count() > 0)
867 state = Play();
868 else
869 state = osBack;
870 }
871 else
872 state = osContinue;
873 }
874 return state;
875}
876
877// --- cMenuSearchResultsForList -------------------------------------------------------
878cMenuSearchResultsForList::cMenuSearchResultsForList(cSearchResults& SearchResults, const char* Title, bool IgnoreRunning)
879 :cMenuSearchResults(cTemplFile::GetTemplateByName("MenuSearchResults"))
880{
881 ButtonBlue[0] = tr("Button$Setup")I18nTranslate("Button$Setup", "vdr-" "epgsearch");
882 searchResults = &SearchResults;
883 m_bSort = true;
884 ignoreRunning = IgnoreRunning;
885
886 BuildList();
887
888 cString szTitle = cString::sprintf(Title, Count());
889 SetTitle(szTitle);
890}
891
892void cMenuSearchResultsForList::SetHelpKeys(bool Force)
893{
894 cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current());
895 int NewHelpKeys = 0;
896 if (item) {
897 if (item->Selectable() && item->timerMatch == tmFull)
898 NewHelpKeys = 2;
899 else
900 NewHelpKeys = 1;
901 }
902
903 bool hasTimer = (NewHelpKeys == 2);
904 if (NewHelpKeys != helpKeys || Force)
905 {
906 if (toggleKeys==0)
907 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), ButtonBlue[0]);
908 else
909 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")), m_bSort? tr("Button$by channel")I18nTranslate("Button$by channel", "vdr-" "epgsearch"):tr("Button$by time")I18nTranslate("Button$by time", "vdr-" "epgsearch"), modeYellow==showTitleEpisode?tr("Button$Episode")I18nTranslate("Button$Episode", "vdr-" "epgsearch"):tr("Button$Title")I18nTranslate("Button$Title", "vdr-" "epgsearch"), ButtonBlue[0]);
910 helpKeys = NewHelpKeys;
911 }
912}
913
914bool cMenuSearchResultsForList::BuildList()
915{
916 time_t now = time(NULL__null);
917 int current = Current();
918
919 Clear();
920 eventObjects.Clear();
921 searchResults->SortBy(m_bSort? CompareEventTime: CompareEventChannel);
922
923 for (cSearchResult* pResultObj = searchResults->First();
924 pResultObj;
925 pResultObj = searchResults->Next(pResultObj))
926 {
927 if (ignoreRunning && now > pResultObj->event->StartTime())
928 continue;
929 Add(new cMenuSearchResultsItem(pResultObj->event, modeYellow == showEpisode, false, menuTemplate, pResultObj->search));
930 eventObjects.Add(pResultObj->event);
931 }
932 if (Count())
933 SetCurrent(Get(0));
934
935 SetHelpKeys();
936
937 SetCurrent(Get(current));
938 Display();
939
940 return true;
941}
942
943eOSState cMenuSearchResultsForList::ProcessKey(eKeys Key)
944{
945 eOSState state = cMenuSearchResults::ProcessKey(Key);
946
947 if (state == osUnknown) {
948 switch (Key) {
949 case k1...k9:
950 state = HasSubMenu()?osContinue:Commands(Key);
951 break;
952 case kRecord:
953 case kRed:
954 state = OnRed();
955 break;
956 default:
957 break;
958 }
959 }
960 return state;
961}