File: | menu_searchresults.c |
Location: | line 694, column 2 |
Description: | Value stored to 'nextModeBlue' 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 "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 | |
44 | const char* ButtonBlue[3] = {NULL__null, NULL__null, NULL__null}; |
45 | extern int gl_InfoConflict; |
46 | extern bool isUTF8; |
47 | |
48 | static 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 ------------------------------------------------------- |
58 | cMenuSearchResultsItem::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 | |
73 | bool 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 | |
174 | cMenuSearchResultsItem::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 | |
187 | void 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 | |
200 | const cEvent *cMenuSearchResults::scheduleEventInfo = NULL__null; |
201 | |
202 | cMenuSearchResults::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 | |
217 | int cMenuSearchResults::GetTab(int Tab) |
218 | { |
219 | if (!menuTemplate) |
220 | menuTemplate = cTemplFile::GetTemplateByName("MenuSearchResults"); |
221 | |
222 | return menuTemplate->Tab(Tab-1); |
223 | } |
224 | |
225 | bool 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 | |
235 | eOSState 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 | |
310 | eOSState 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 | |
323 | eOSState 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 | |
338 | eOSState 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 | |
353 | eOSState 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 | |
377 | eOSState 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 | |
389 | eOSState 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 | |
401 | void 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 | |
415 | eOSState 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 ------------------------------------------------------- |
479 | cMenuSearchResultsForSearch::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 | |
495 | bool 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 | |
537 | void 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 | |
564 | eOSState 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 ------------------------------------------------------- |
602 | cMenuSearchResultsForBlacklist::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 | |
616 | bool 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 | |
651 | eOSState 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 | |
677 | void 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 ------------------------------------------------------- |
705 | cMenuSearchResultsForQuery::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 | |
724 | cMenuSearchResultsForQuery::~cMenuSearchResultsForQuery() |
725 | { |
726 | delete searchExt; |
727 | } |
728 | |
729 | bool 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 ------------------------------------------------------- |
750 | cMenuSearchResultsForRecs::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 | |
769 | bool 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 | |
832 | cRecording *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 | |
840 | eOSState 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 | |
858 | eOSState 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 ------------------------------------------------------- |
878 | cMenuSearchResultsForList::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 | |
892 | void 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 | |
914 | bool 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 | |
943 | eOSState 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 | } |