/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include #include "uservars.h" #include "menu_whatson.h" #include "epgsearchext.h" #include "menu_event.h" #include "menu_myedittimer.h" #include "menu_searchresults.h" #include "menu_search.h" #include "menu_commands.h" #include "epgsearchcfg.h" #include "switchtimer.h" #include "epgsearchcats.h" #include "conflictcheck.h" #include #include #include "menu_conflictcheck.h" #include "templatefile.h" #include "menu_deftimercheckmethod.h" #include "timerstatus.h" #define HOURS(x) ((x)/100) #define MINUTES(x) ((x)%100) #define SKIPHOURS 20 #define HOURS2SECS(x) (x*60*60) extern int exitToMainMenu; extern bool isUTF8; int gl_InfoConflict = 0; // --- cMenuMyScheduleItem ------------------------------------------------------ cMenuMyScheduleItem::cMenuMyScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel, showMode Mode, cMenuTemplate* MenuTemplate) { event = Event; channel = Channel; mode = Mode; timerMatch = tmNone; isRemote = false; inSwitchList = false; timerActive = false; menuTemplate = MenuTemplate; Update(Timers, true); } bool cMenuMyScheduleItem::Update(const cTimers* Timers, bool Force) { if (!menuTemplate) return false; const char* menutemplate = menuTemplate->MenuTemplate(); if (!menutemplate || strlen(menutemplate) == 0) return false; bool result = false; eTimerMatch OldTimerMatch = timerMatch; bool OldIsRemote = isRemote; bool OldInSwitchList = inSwitchList; bool OldtimerActive = timerActive; bool hasMatch = false; const cTimer* timer = NULL; if (event) timer = Timers->GetMatch(event, &timerMatch); if (event) inSwitchList = (SwitchTimers.InSwitchList(event) != NULL); if (timer) hasMatch = true; if (timer) timerActive = timer->HasFlags(tfActive); if (timer) isRemote = timer->Remote(); if (Force || timerMatch != OldTimerMatch || inSwitchList != OldInSwitchList || isRemote != OldIsRemote || timerActive != OldtimerActive) { char szProgressPart[Utf8BufSize(12)] = ""; char szProgressPartT2S[12] = ""; time_t now = time(NULL); if (channel) { if (event) { time_t startTime = event->StartTime(); if ((now - event->StartTime()) >= 0 || strstr(menutemplate, "%time%") != NULL) { int frac = 0; if (mode == showNow) { int dur = event->Duration(); if (dur != 0) frac = ((now - startTime) * 8 + (dur >> 1)) / dur; } if (mode == showNext) frac = ((30 * 60 - std::min((time_t)30 * 60, startTime - now)) * 8 + 15 * 60) / (30 * 60); frac = std::min(8, std::max(0, frac)); szProgressPartT2S[0] = '['; memset(szProgressPartT2S + 1, '|', frac); memset(szProgressPartT2S + 1 + frac , ' ', 8 - frac); szProgressPartT2S[9] = ']'; szProgressPartT2S[10] = 0; if (!isUTF8) { szProgressPart[0] = ICON_BAR_OPEN; memset(szProgressPart + 1, ICON_BAR_EMPTY, 6); szProgressPart[7] = ICON_BAR_CLOSE; szProgressPart[8] = 0; memset(szProgressPart, ICON_BAR_FULL, frac ? frac : sizeof(szProgressPart)); } else { #if defined(__GNUC__) && __GNUC__ < 3 && __GNUC_MINOR__ < 96 #else std::stringstream buffer; buffer << ICON_BAR_OPEN_UTF8; for (int i = 0; i < 8; i++) buffer << (i < frac ? ICON_BAR_FULL_UTF8 : ICON_BAR_EMPTY_UTF8); buffer << ICON_BAR_CLOSE_UTF8; char* temp = strdup(buffer.str().c_str()); sprintf(szProgressPart, "%s", temp); free(temp); #endif } } else { strncpy(szProgressPart, *event->GetTimeString(), 12); szProgressPart[11] = 0; memcpy(szProgressPartT2S, szProgressPart, 12); } } } char t[Utf8BufSize(2)], v[Utf8BufSize(2)], r[Utf8BufSize(2)]; char szStatus[Utf8BufSize(4)]; szStatus[3] = 0; t[1] = v[1] = r[1] = 0; if (EPGSearchConfig.WarEagle) { if (!isUTF8) { t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording()) ? ICON_REC : (timerActive ? ICON_CLOCK : ICON_TIMER_INACT)) : (timerActive ? ICON_CLOCK_HALF : ' ') : ' '; v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS : ' '; r[0] = event && event->IsRunning() ? ICON_RUNNING : ' '; } else { #if defined(__GNUC__) && __GNUC__ < 3 && __GNUC_MINOR__ < 96 #else sprintf(t, "%s", (event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording()) ? ICON_REC_UTF8 : (timerActive ? ICON_CLOCK_UTF8 : ICON_TIMER_INACT_UTF8)) : (timerActive ? ICON_CLOCK_HALF_UTF8 : " ") : " ")); sprintf(v, "%s", event && event->Vps() && (event->Vps() - event->StartTime()) ? ICON_VPS_UTF8 : " "); sprintf(r, "%s", (event && event->IsRunning() ? ICON_RUNNING_UTF8 : " ")); #endif } } else { t[0] = event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording()) ? 'R' : (timerActive ? 'T' : 'i')) : (timerActive ? 't' : ' ') : ' '; v[0] = event && event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; r[0] = event && event->IsRunning() ? '*' : ' '; } if (event && inSwitchList) { cSwitchTimer* s = SwitchTimers.InSwitchList(event); t[0] = (s && s->mode == 1) ? 's' : 'S'; } if (EPGSearchConfig.WarEagle && isUTF8) { std::stringstream buffer; buffer << t << v << r; char* temp = strdup(buffer.str().c_str()); sprintf(szStatus, "%s", temp); free(temp); } else { szStatus[0] = t[0]; szStatus[1] = v[0]; szStatus[2] = r[0]; } char* buffer = strdup(menutemplate); strreplace(buffer, '|', '\t'); char* title = NULL; title = strdup((event && event->Title()) ? event->Title() : tr(">>> no info! <<<")); title = strreplacei(title, ":", "%colon%"); // assume a title has the form "a?b:c", // we need to replace the colon to avoid misinterpretation of the expression as a condition buffer = strreplacei(buffer, "%title%", title); free(title); if (channel) { char szChannelNr[6] = ""; snprintf(szChannelNr, 6, "%d", channel->Number()); buffer = strreplacei(buffer, "%chnr%", szChannelNr); buffer = strreplacei(buffer, "%chsh%", channel->ShortName(true)); buffer = strreplacei(buffer, "%chlng%", channel->Name()); buffer = strreplacei(buffer, "%progr%", szProgressPart); buffer = strreplacei(buffer, "%progrT2S%", szProgressPartT2S); } // parse the epxression and evaluate it cVarExpr varExpr(buffer); char* tmp = strdup(varExpr.Evaluate(event).c_str()); free(buffer); buffer = tmp; buffer = strreplacei(buffer, "$status$", szStatus); buffer = strreplacei(buffer, "$t_status$", t); buffer = strreplacei(buffer, "$v_status$", v); buffer = strreplacei(buffer, "$r_status$", r); buffer = FixSeparators(buffer, '~'); buffer = FixSeparators(buffer, ':'); buffer = FixSeparators(buffer, '-'); SetText(buffer, false); if (gl_InfoConflict == 0 && EPGSearchConfig.checkTimerConflAfterTimerProg && !Force && timer && ((timerMatch && timerMatch != OldTimerMatch) || (isRemote != OldIsRemote))) { cConflictCheck C; C.Check(); if (C.TimerInConflict(timer)) gl_InfoConflict = 1; } return true; } return result; } void cMenuMyScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) { bool withDate = (channel == NULL); // search for a better way to determine this if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch, timerActive)) DisplayMenu->SetItem(Text(), Index, Current, Selectable); } // --- cMenuMyScheduleSepItem ------------------------------------------------------ cMenuMyScheduleSepItem::cMenuMyScheduleSepItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel) : cMenuMyScheduleItem(Timers, Event, Channel, showNow, NULL) { event = Event; channel = Channel; dummyEvent = NULL; SetSelectable(false); Update(Timers, true); } cMenuMyScheduleSepItem::~cMenuMyScheduleSepItem() { if (dummyEvent) delete dummyEvent; } bool cMenuMyScheduleSepItem::Update(const cTimers *Timers, bool Force) { if (channel) SetText(cString::sprintf("%s\t %s %s", MENU_SEPARATOR_ITEMS, channel->Name(), MENU_SEPARATOR_ITEMS)); else if (event) { dummyEvent = new cEvent(0); dummyEvent->SetTitle(cString::sprintf("%s\t %s %s", MENU_SEPARATOR_ITEMS, GETDATESTRING(event), MENU_SEPARATOR_ITEMS)); SetText(dummyEvent->Title()); } return true; } void cMenuMyScheduleSepItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) { bool withDate = (channel == NULL); // search for a better way to determine this if (!DisplayMenu->SetItemEvent(dummyEvent, Index, Current, Selectable, channel, withDate, timerMatch, timerActive)) DisplayMenu->SetItem(Text(), Index, Current, Selectable); } // --- cMenuWhatsOnSearch ---------------------------------------------------------- int cMenuWhatsOnSearch::currentChannel = 0; showMode cMenuWhatsOnSearch::currentShowMode = showNow; const cChannel *cMenuWhatsOnSearch::scheduleChannel = NULL; extern const char *ShowModes[]; cList cMenuWhatsOnSearch::showModes; time_t cMenuWhatsOnSearch::seekTime = 0; int cMenuWhatsOnSearch::shiftTime = 0; cMenuWhatsOnSearch::cMenuWhatsOnSearch(int CurrentChannelNr) : cOsdMenu("", GetTab(1), GetTab(2), GetTab(3), GetTab(4), GetTab(5)) { if (currentShowMode == showNow) SetMenuCategory(mcScheduleNow); else if (currentShowMode == showNext) SetMenuCategory(mcScheduleNext); else SetMenuCategory(mcSchedule); helpKeys = -1; shiftTime = 0; CreateShowModes(); LoadSchedules(); currentChannel = CurrentChannelNr; SetHelpKeys(); } cMenuWhatsOnSearch::~cMenuWhatsOnSearch() { } #ifdef USE_GRAPHTFT const char* cMenuWhatsOnSearch::MenuKind() { if (currentShowMode == showNow) return "MenuEpgsWhatsOnNow"; if (currentShowMode == showNext) return "MenuEpgsWhatsOnNext"; if (currentShowMode > showNext) return "MenuEpgsWhatsOnElse"; else return "MenuWhatsOnElse"; } void cMenuWhatsOnSearch::Display(void) { cOsdMenu::Display(); if (Count() > 0) { int i = 0; for (cOsdItem *item = First(); item; item = Next(item)) cStatus::MsgOsdEventItem(!item->Selectable() ? 0 : ((cMenuMyScheduleItem*)item)->event, item->Text(), i++, Count()); } } #endif /* GRAPHTFT */ int cMenuWhatsOnSearch::GetTab(int Tab) { if (currentShowMode == showNow) return cTemplFile::GetTemplateByName("MenuWhatsOnNow")->Tab(Tab - 1); if (currentShowMode == showNext) return cTemplFile::GetTemplateByName("MenuWhatsOnNext")->Tab(Tab - 1); if (currentShowMode > showNext) return cTemplFile::GetTemplateByName("MenuWhatsOnElse")->Tab(Tab - 1); else return 0; } void cMenuWhatsOnSearch::LoadSchedules() { Clear(); eventObjects.Clear(); // time_t SeekTime; cString szTitle; cShowMode* mode = GetShowMode(currentShowMode); if (!mode) return; if (shiftTime != 0) { if (currentShowMode == showNow || currentShowMode == showNext) seekTime = time(NULL); else { if (mode) seekTime = GetTimeT(mode->GetTime()); if (seekTime < time(NULL)) seekTime += HOURS2SECS(24); } seekTime += shiftTime * 60; struct tm tm_r; time_t now = time(NULL); tm tm_seek = *localtime_r(&seekTime, &tm_r); tm tm_now = *localtime_r(&now, &tm_r); if (tm_seek.tm_mday != tm_now.tm_mday) szTitle = cString::sprintf("%s - %s", tr("Overview"), DAYDATETIME(seekTime)); else szTitle = cString::sprintf("%s - %02d:%02d", tr("Overview"), tm_seek.tm_hour, tm_seek.tm_min); } else { seekTime = GetTimeT(mode->GetTime()); if (seekTime < time(NULL) && currentShowMode != showNow && currentShowMode != showNext) { seekTime += HOURS2SECS(24); szTitle = cString::sprintf("%s - %s (%s)", tr("Overview"), mode->GetDescription(), *WeekDayName(seekTime)); } else szTitle = cString::sprintf("%s - %s", tr("Overview"), mode->GetDescription()); } SetTitle(szTitle); cMenuTemplate* currentTemplate = NULL; if (currentShowMode == showNow) currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnNow"); if (currentShowMode == showNext) currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnNext"); if (currentShowMode > showNext) currentTemplate = cTemplFile::GetTemplateByName("MenuWhatsOnElse"); int maxChannel = EPGSearchConfig.maxChannelMenuNow; if (currentChannel > maxChannel) maxChannel = 0; LOCK_TIMERS_READ; // needed in MyScheduleItem LOCK_CHANNELS_READ; for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) { if (!Channel->GroupSep()) { if (maxChannel && Channel->Number() > maxChannel) break; if (EPGSearchConfig.showRadioChannels == 0 && ISRADIO(Channel)) continue; LOCK_SCHEDULES_READ; const cSchedule *Schedule; Schedule = Schedules->GetSchedule(Channel); const cEvent *Event = NULL; if (Schedule) { if (shiftTime != 0) Event = Schedule->GetEventAround(seekTime); else { switch (currentShowMode) { default: case showNow: Event = Schedule->GetPresentEvent(); break; case showNext: Event = Schedule->GetFollowingEvent(); break; case showUserMode1: case showUserMode2: case showUserMode3: case showUserMode4: Event = Schedule->GetEventAround(seekTime); break; } } } if (!EPGSearchConfig.showEmptyChannels && !Event) continue; Add(new cMenuMyScheduleItem(Timers, Event, Channel, currentShowMode, currentTemplate), Channel->Number() == currentChannel); if (Event) eventObjects.Add(Event); } else { if (EPGSearchConfig.showChannelGroups && strlen(Channel->Name())) Add(new cMenuMyScheduleSepItem(NULL, NULL, Channel)); } } } time_t cMenuWhatsOnSearch::GetTimeT(int iTime) { struct tm tm_r; time_t t = time(NULL); tm* tmnow = localtime_r(&t, &tm_r); tmnow->tm_hour = HOURS(iTime); tmnow->tm_min = MINUTES(iTime); return mktime(tmnow); } showMode cMenuWhatsOnSearch::GetNextMode() { showMode nextShowMode = currentShowMode; cShowMode* Mode = GetShowMode(currentShowMode); if (Mode) { cShowMode* ModeNext = showModes.Next(Mode); if (ModeNext == NULL) nextShowMode = showNow; else nextShowMode = ModeNext->GetMode(); } else // no mode found? fall back to 'now' nextShowMode = showNow; return nextShowMode; } void cMenuWhatsOnSearch::CreateShowModes() { showModes.Clear(); cShowMode* ModeNow = new cShowMode(showNow, trVDR("Button$Now")); showModes.Add(ModeNow); cShowMode* ModeNext = new cShowMode(showNext, trVDR("Button$Next")); showModes.Add(ModeNext); time_t now = time(NULL); for (int i = showUserMode1; i < showModeMax; i++) { if (!EPGSearchConfig.ShowModes[i].GetUsage()) continue; time_t SeekTime = GetTimeT(EPGSearchConfig.ShowModes[i].GetTime()); if (SeekTime < now) SeekTime += HOURS2SECS(24); if (SeekTime - now > HOURS2SECS(SKIPHOURS)) continue; cShowMode* Mode = new cShowMode((showMode)i, EPGSearchConfig.ShowModes[i].GetDescription(), 1, EPGSearchConfig.ShowModes[i].GetTime(), SeekTime); showModes.Add(Mode); } if (EPGSearchConfig.showFavoritesMenu) { cShowMode* ModeFav = new cShowMode(showFavorites, tr("Button$Favorites")); showModes.Add(ModeFav); } showModes.Sort(); } cShowMode* cMenuWhatsOnSearch::GetShowMode(showMode mode) { for (cShowMode *showMode = showModes.First(); showMode; showMode = showModes.Next(showMode)) if (mode == showMode->GetMode()) return showMode; return NULL; } const cChannel *cMenuWhatsOnSearch::ScheduleChannel(const cChannel *force_channel) { const cChannel *ch = force_channel ? force_channel : scheduleChannel; scheduleChannel = NULL; return ch; } eOSState cMenuWhatsOnSearch::Switch(void) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); if (item && item->channel) { if (cDevice::PrimaryDevice()->SwitchChannel(item->channel, true)) return osEnd; } INFO(trVDR("Can't switch channel!")); return osContinue; } eOSState cMenuWhatsOnSearch::Record(void) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); if (item) { LOCK_TIMERS_WRITE; Timers->SetExplicitModify(); if (item->timerMatch == tmFull) { eTimerMatch tm = tmNone; cTimer *timer = Timers->GetMatch(item->event, &tm); if (timer) { if (EPGSearchConfig.useVDRTimerEditMenu) return AddSubMenu(new cMenuEditTimer(timer)); else return AddSubMenu(new cMenuMyEditTimer(timer, false, item->event, item->channel)); } } cTimer *timer = NULL; if (item->event) { timer = new cTimer(item->event); PrepareTimerFile(item->event, timer); } else timer = new cTimer(false, false, item->channel); cTimer *t = Timers->GetTimer(timer); if (EPGSearchConfig.onePressTimerCreation == 0 || t || !item->event || (!t && item->event && item->event->StartTime() - (Setup.MarginStart + 2) * 60 < time(NULL))) { if (t) { delete timer; timer = t; } timer->SetFlags(tfActive); if (EPGSearchConfig.useVDRTimerEditMenu) return AddSubMenu(new cMenuEditTimer(timer, !t)); else return AddSubMenu(new cMenuMyEditTimer(timer, !t, item->event, item->channel)); } else { string fullaux = ""; string aux = ""; if (item->event) { const cEvent* event = item->event; int bstart = event->StartTime() - timer->StartTime(); int bstop = timer->StopTime() - event->EndTime(); int checkmode = DefTimerCheckModes.GetMode(timer->Channel()); aux = UpdateAuxValue(aux, "channel", NumToString(timer->Channel()->Number()) + " - " + CHANNELNAME(timer->Channel())); aux = UpdateAuxValue(aux, "update", checkmode); aux = UpdateAuxValue(aux, "eventid", event->EventID()); aux = UpdateAuxValue(aux, "bstart", bstart); aux = UpdateAuxValue(aux, "bstop", bstop); fullaux = UpdateAuxValue(fullaux, "epgsearch", aux); } #ifdef USE_PINPLUGIN aux = ""; aux = UpdateAuxValue(aux, "protected", timer->FskProtection() ? "yes" : "no"); fullaux = UpdateAuxValue(fullaux, "pin-plugin", aux); #endif SetAux(timer, fullaux); if (Setup.SVDRPPeering && *Setup.SVDRPDefaultHost) timer->SetRemote(Setup.SVDRPDefaultHost); Timers->Add(timer); if (!HandleRemoteTimerModifications(timer)) { Timers->Del(timer); ERROR(tr("Epgsearch: RemoteTimerModifications failed")); } else { gl_timerStatusMonitor->SetConflictCheckAdvised(); timer->Matches(); Timers->SetModified(); LogFile.iSysLog("timer %s added (active)", *timer->ToDescr()); } if (HasSubMenu()) CloseSubMenu(); if (Update()) Display(); SetHelpKeys(); } } return osContinue; } bool cMenuWhatsOnSearch::Update(void) { bool result = false; LOCK_TIMERS_READ; for (cOsdItem *item = First(); item; item = Next(item)) { if (item->Selectable() && ((cMenuMyScheduleItem *)item)->Update(Timers)) result = true; } return result; } eOSState cMenuWhatsOnSearch::Commands(eKeys Key) { if (HasSubMenu() || Count() == 0) return osContinue; cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi) { if (!mi->event) { if (Key == k3) return Switch(); else if (Key == k2) return Record(); else return osContinue; } cMenuSearchCommands *menu; eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands"), mi->event, true)); if (Key != kNone) state = menu->ProcessKey(Key); return state; } return osContinue; } eOSState cMenuWhatsOnSearch::ExtendedSearch(void) { return AddSubMenu(new cMenuEPGSearchExt()); } void cMenuWhatsOnSearch::SetHelpKeys(bool Force) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); int NewHelpKeys = 0; if (item) { if (item->Selectable() && item->timerMatch == tmFull) NewHelpKeys = 2; else NewHelpKeys = 1; } bool hasTimer = (NewHelpKeys == 2); if (NewHelpKeys != helpKeys || Force) { showMode nextShowMode = GetNextMode(); cShowMode* mode = GetShowMode(nextShowMode); const char* szButtonGreen = NULL; if (mode) szButtonGreen = mode->GetDescription(); if (toggleKeys == 0) SetHelp((EPGSearchConfig.redkeymode == 0 ? (hasTimer ? trVDR("Button$Timer") : trVDR("Button$Record")) : tr("Button$Commands")), szButtonGreen, trVDR("Button$Schedule"), EPGSearchConfig.bluekeymode == 0 ? (EPGSearchConfig.useOkForSwitch ? trVDR("Button$Info") : trVDR("Button$Switch")) : tr("Button$Search")); else SetHelp((EPGSearchConfig.redkeymode == 1 ? (hasTimer ? trVDR("Button$Timer") : trVDR("Button$Record")) : tr("Button$Commands")), (EPGSearchConfig.toggleGreenYellow == 0 ? szButtonGreen : "<<"), (EPGSearchConfig.toggleGreenYellow == 0 ? trVDR("Button$Schedule") : ">>"), EPGSearchConfig.bluekeymode == 1 ? (EPGSearchConfig.useOkForSwitch ? trVDR("Button$Info") : trVDR("Button$Switch")) : tr("Button$Search")); helpKeys = NewHelpKeys; } } eOSState cMenuWhatsOnSearch::Shift(int iMinutes) { shiftTime += iMinutes; cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); int TempChannel = currentChannel; if (mi) { currentChannel = mi->channel->Number(); LOCK_CHANNELS_READ; scheduleChannel = Channels->GetByNumber(currentChannel); } LoadSchedules(); Display(); currentChannel = TempChannel; SetHelpKeys(); return osContinue; } eOSState cMenuWhatsOnSearch::ShowSummary() { if (Count()) { const cEvent *ei = ((cMenuMyScheduleItem *)Get(Current()))->event; if (ei) { const cChannel *channel; { LOCK_CHANNELS_READ; channel = Channels->GetByChannelID(ei->ChannelID(), true, true); } if (channel) return AddSubMenu(new cMenuEventSearch(ei, eventObjects, SurfModeChannel)); } } return osContinue; } void cMenuWhatsOnSearch::UpdateCurrent() { // navigation in summary could have changed current item, so update it cEventObj* cureventObj = eventObjects.GetCurrent(); if (cureventObj && cureventObj->Event()) for (cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)First(); item; item = (cMenuMyScheduleItem *)Next(item)) if (item->Selectable() && item->event == cureventObj->Event()) { cureventObj->Select(false); SetCurrent(item); Display(); break; } } eOSState cMenuWhatsOnSearch::ProcessKey(eKeys Key) { exitToMainMenu = 0; if (!HasSubMenu() && Key == kBack) { exitToMainMenu = 1; return osBack; } bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (!HasSubMenu() && HadSubMenu) // navigation in summary could have changed current item, so update it UpdateCurrent(); if (state == osUnknown) { switch (Key) { case kFastRew: if (!HasSubMenu()) return Shift(-EPGSearchConfig.timeShiftValue); break; case kFastFwd: if (!HasSubMenu()) return Shift(EPGSearchConfig.timeShiftValue); break; case kRecord: case kRed: if (HasSubMenu()) { UpdateCurrent(); state = Record(); break; } if (Count()) { if (EPGSearchConfig.redkeymode == toggleKeys) state = Record(); else { cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->Selectable()) { if (mi->event) return AddSubMenu(new cMenuSearchCommands(tr("EPG Commands"), mi->event)); else return osContinue; } } } break; case k0: if (!HasSubMenu()) { toggleKeys = 1 - toggleKeys; SetHelpKeys(true); } state = osContinue; break; case k1...k9: return Commands(Key); case kYellow: if (!HasSubMenu()) { if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) { cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->Selectable() && mi->channel) { LOCK_SCHEDULES_READ; const cSchedule *Schedule = Schedules->GetSchedule(mi->channel); if (Schedule) { time_t now = time(NULL); bool hasFutureEvents = false; for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) if (e->StartTime() > now) { hasFutureEvents = true; break; } if (!hasFutureEvents) return osContinue; } else return osContinue; } state = osBack; // continue with kGreen } else return Shift(EPGSearchConfig.timeShiftValue); } case kGreen: if (!HasSubMenu()) { if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) { if (Key == kYellow) currentShowMode = showNow; else currentShowMode = GetNextMode(); cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->Selectable()) { currentChannel = mi->channel->Number(); LOCK_CHANNELS_READ; scheduleChannel = Channels->GetByNumber(currentChannel); } } else return Shift(-EPGSearchConfig.timeShiftValue); } break; case kBlue: if (HasSubMenu()) { UpdateCurrent(); return Switch(); } if (EPGSearchConfig.bluekeymode == toggleKeys) return EPGSearchConfig.useOkForSwitch ? ShowSummary() : Switch(); else return ExtendedSearch(); break; case kOk: { cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->Selectable()) { if (!mi->event) // no EPG, so simply switch to channel return Switch(); else return EPGSearchConfig.useOkForSwitch ? Switch() : ShowSummary(); } } break; case kInfo: return ShowSummary(); break; default: break; } } if (!HasSubMenu()) { if ((HadSubMenu || gl_TimerProgged) && Update()) { if (gl_TimerProgged) { // when using epgsearch's timer edit menu, update is delayed because of SVDRP gl_TimerProgged = 0; SetHelpKeys(); } Display(); } if (Key != kNone) SetHelpKeys(); if (gl_InfoConflict) { gl_InfoConflict = 0; if (Interface->Confirm(tr("Timer conflict! Show?"))) return AddSubMenu(new cMenuConflictCheck()); } } return state; }