| 1 |  | 
| 2 |  | 
| 3 |   | 
| 4 |  | 
| 5 |  | 
| 6 |  | 
| 7 |  | 
| 8 |   | 
| 9 |  | 
| 10 |  | 
| 11 |  | 
| 12 |  | 
| 13 |   | 
| 14 |  | 
| 15 |  | 
| 16 |  | 
| 17 |  | 
| 18 |   | 
| 19 |  | 
| 20 |   | 
| 21 |  | 
| 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 |  | 
| 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 | 	 | 
| 140 |          buffer = strreplacei(buffer, "%title%", "%title% ~ %subtitle%"); | 
| 141 |       if (episodeOnly) | 
| 142 |          buffer = strreplacei(buffer, "%title%", ""); | 
| 143 |   | 
| 144 |        | 
| 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 |  | 
| 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)  | 
| 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)  | 
| 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 |  | 
| 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;  | 
| 589 |                BuildList(); | 
| 590 |   | 
| 591 |                state = osContinue; | 
| 592 |             } | 
| 593 |             break; | 
| 594 |          default: | 
| 595 |             break; | 
| 596 |       } | 
| 597 |    } | 
| 598 |    return state; | 
| 599 | } | 
| 600 |   | 
| 601 |  | 
| 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); | 
| 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 |  | 
| 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 |     | 
| 711 |    if (query) | 
| 712 |    { | 
| 713 |       searchExt = new cSearchExt; | 
| 714 |       strcpy(searchExt->search, query); | 
| 715 |       searchExt->mode = 0;  | 
| 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 |  | 
| 733 |     | 
| 734 |        | 
| 735 |        | 
| 736 |        | 
| 737 |        | 
| 738 |        | 
| 739 |        | 
| 740 |           | 
| 741 |              | 
| 742 |           | 
| 743 |           | 
| 744 |        | 
| 745 |     | 
| 746 |    return bRes; | 
| 747 | } | 
| 748 |   | 
| 749 |  | 
| 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;  | 
| 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)) { | 
 | 1  | Loop condition is true.  Entering loop body |  |  
  | 
 | 13  |  | Loop condition is true.  Entering loop body |  |  
  | 
 | 25  |  | Loop condition is true.  Entering loop body |  |  
  | 
 | 36  |  | Loop condition is false. Execution continues on line 820 |  |  
  | 
| 777 |      const cRecordingInfo *recInfo = recording->Info(); | 
| 778 |      if (!recInfo) continue; | 
 | 2  |  | Assuming 'recInfo' is non-null |  |  
  | 
 |  | 
 | 14  |  | Assuming 'recInfo' is non-null |  |  
  | 
 |  | 
 | 26  |  | Assuming 'recInfo' is non-null |  |  
  | 
 |  | 
| 779 |      string s1 = (recInfo && recInfo->Title())?recInfo->Title():""; | 
 |  | 
 |  | 
 |  | 
| 780 |      string s2 = searchExt->search; | 
| 781 |      if (s1.empty() || s2.empty()) continue; | 
 |  | 
 |  | 
 |  | 
| 782 |   | 
| 783 |       | 
| 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 | 	  | 
| 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 | 	  | 
| 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) | 
 | 34  |  | Assuming 'tmp' is non-null |  |  
  | 
 |  | 
| 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++) | 
 | 37  |  | Loop condition is true.  Entering loop body |  |  
  | 
 | 38  |  | Loop condition is false. Execution continues on line 823 |  |  
  | 
| 822 |       Add(new cMenuSearchResultsItem(pArray[a])); | 
| 823 |    delete pArray; | 
 | 39  |  | Memory allocated by realloc() should be deallocated by free(), not 'delete' |  
  | 
| 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 |  | 
| 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 | } |