summaryrefslogtreecommitdiff
path: root/menu_conflictcheck.c
diff options
context:
space:
mode:
authorChristian Wieninger <winni@debian.(none)>2007-11-11 15:40:28 +0100
committerChristian Wieninger <winni@debian.(none)>2007-11-11 15:40:28 +0100
commit8d4f8607dc1558ce73eb4c376bdbf78ddb65da83 (patch)
treed0c5dde81a36ab2e8a2edc7c1e6922556518b312 /menu_conflictcheck.c
downloadvdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.gz
vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.bz2
Initial commit
Diffstat (limited to 'menu_conflictcheck.c')
-rw-r--r--menu_conflictcheck.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/menu_conflictcheck.c b/menu_conflictcheck.c
new file mode 100644
index 0000000..40bedc5
--- /dev/null
+++ b/menu_conflictcheck.c
@@ -0,0 +1,450 @@
+/*
+Copyright (C) 2004-2007 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 <vector>
+#include <string>
+#include "menu_conflictcheck.h"
+#include "menu_commands.h"
+#include "menu_event.h"
+#include "conflictcheck.h"
+#include "timer_thread.h"
+#include <vdr/menu.h>
+
+using std::string;
+
+// --- cMenuConflictCheckItem -------------------------------------------------------
+cMenuConflictCheckItem::cMenuConflictCheckItem(cConflictCheckTime* Ct, cConflictCheckTimerObj* TimerObj)
+{
+ checktime = Ct;
+ timerObj = TimerObj;
+ char* buffer = NULL;
+ if (!TimerObj) // print header
+ {
+ struct tm tm_r;
+ const time_t t = checktime->evaltime;
+ tm *tm = localtime_r(&t, &tm_r);
+ char dateshort[7] = "";
+ strftime(dateshort, sizeof(dateshort), "%d.%m.", tm);
+ asprintf(&buffer, "%s\t%s %s", WEEKDAYNAME(t), dateshort, TIMESTRING(t));
+ SetSelectable(false);
+ }
+ else
+ {
+ cTimer* t = timerObj->timer;
+ int recPart = timerObj->recDuration * 100 / (timerObj->stop - timerObj->start);
+ asprintf(&buffer, "%d\t%s\t%d\t%2d%%\t%s", t->Channel()->Number(), t->Channel()->ShortName(true), t->Priority(), recPart, t->File());
+ }
+ SetText(buffer, false);
+}
+
+// --- cMenuConflictCheck -------------------------------------------------------
+
+cMenuConflictCheck::cMenuConflictCheck()
+:cOsdMenu("", 4, 12, 4, 5, 30)
+{
+ showAll = false;
+ lastSel = -1;
+ BuildList();
+ Update();
+}
+
+void cMenuConflictCheck::Update()
+{
+ if (conflictCheck.numConflicts > 0)
+ {
+ if (conflictCheck.numConflicts==conflictCheck.relevantConflicts)
+ SetHelp(conflictCheck.relevantConflicts?tr("Button$Details"):NULL, NULL, NULL, NULL);
+ else if (showAll)
+ SetHelp(tr("Button$Details"), NULL, NULL, tr("Button$Filter"));
+ else
+ SetHelp(conflictCheck.relevantConflicts?tr("Button$Details"):NULL, NULL, NULL, tr("Button$Show all"));
+ }
+ else
+ SetHelp(NULL, NULL, NULL, NULL);
+
+ char *buffer = NULL;
+ asprintf(&buffer, "%s - %d/%d %s", tr("Timer conflicts"),
+ showAll?conflictCheck.numConflicts:conflictCheck.relevantConflicts,
+ conflictCheck.numConflicts,
+ tr("conflicts"));
+ SetTitle(buffer);
+ Display();
+ free(buffer);
+}
+
+bool cMenuConflictCheck::BuildList()
+{
+ Clear();
+ conflictCheck.Check();
+
+ if ((showAll && conflictCheck.numConflicts > 0) ||
+ conflictCheck.relevantConflicts > 0)
+ {
+ cList<cConflictCheckTime>* failedList = conflictCheck.GetFailed();
+ for(cConflictCheckTime* ct = failedList->First(); ct; ct = failedList->Next(ct))
+ {
+ if (!showAll && ct->ignore) continue;
+ Add(new cMenuConflictCheckItem(ct));
+ std::set<cConflictCheckTimerObj*,TimerObjSort>::iterator it;
+ for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); it++)
+ if (!(*it)->ignore || showAll)
+ Add(new cMenuConflictCheckItem(ct, *it));
+ }
+ }
+ else
+ {
+ cOsdItem* pInfoItem = new cOsdItem(conflictCheck.numConflicts==0?tr("no conflicts!"):tr("no important conflicts!"));
+ pInfoItem->SetSelectable(false);
+ Add(pInfoItem);
+ }
+ SetCurrent(Get(lastSel));
+ return false;
+}
+
+cConflictCheckTimerObj* cMenuConflictCheck::CurrentTimerObj(void)
+{
+ cMenuConflictCheckItem *item = (cMenuConflictCheckItem *)Get(Current());
+ return (item && item->Selectable())? item->timerObj : NULL;
+}
+
+eOSState cMenuConflictCheck::ProcessKey(eKeys Key)
+{
+ bool HadSubMenu = HasSubMenu();
+ eOSState state = cOsdMenu::ProcessKey(Key);
+ if (state == osUnknown)
+ {
+ switch (Key)
+ {
+ case kOk:
+ if (Count() == 1)
+ return osBack;
+ case kRed:
+ if (CurrentTimerObj())
+ state = AddSubMenu(new cMenuConflictCheckDetails(CurrentTimerObj(), &conflictCheck));
+ break;
+ case kBlue:
+ showAll = !showAll;
+ BuildList();
+ Update();
+ state = osContinue;
+ break;
+ default: break;
+ }
+ }
+ if (HadSubMenu && !HasSubMenu()) // Update conflict list
+ {
+ lastSel = Current();
+ BuildList();
+ Update();
+ }
+ return state;
+}
+
+// --- cMenuConflictCheckDetailsItem -------------------------------------------------------
+cMenuConflictCheckDetailsItem::cMenuConflictCheckDetailsItem(cConflictCheckTimerObj* TimerObj)
+{
+ timerObj = TimerObj;
+ hasTimer = timerObj->timer->HasFlags(tfActive);
+ Update(true);
+}
+
+bool cMenuConflictCheckDetailsItem::Update(bool Force)
+{
+ bool oldhasTimer = hasTimer;
+ hasTimer = timerObj->timer->HasFlags(tfActive);
+ if (Force || hasTimer != oldhasTimer)
+ {
+ cTimer* timer = timerObj->timer;
+ char* buffer = NULL;
+ char device[2]="";
+ if (hasTimer)
+ {
+ if (!timerObj->conflCheckTime && timerObj->device > -1)
+ sprintf(device, "%d", timerObj->device+1);
+ else
+ strcpy(device, tr("C"));
+ }
+
+ asprintf(&buffer, "%s\t%d\t%s - %s\t%d\t%s\t%s", hasTimer?">":"", timer->Channel()->Number(), TIMESTRING(timerObj->start), TIMESTRING(timerObj->stop), timer->Priority(), device, timer->File());
+
+ SetText(buffer, false);
+ }
+ return true;
+}
+
+// --- cMenuConflictCheckDetails -------------------------------------------------------
+
+cMenuConflictCheckDetails::cMenuConflictCheckDetails(cConflictCheckTimerObj* TimerObj, cConflictCheck* ConflictCheck)
+:cOsdMenu(tr("Timer conflicts"), 2, 4, 13, 3, 2)
+{
+ timerObj = TimerObj;
+ checktime = timerObj->conflCheckTime;
+ conflictCheck = ConflictCheck;
+ BuildList();
+ SetHelpKeys();
+ string title = string(DATESTRING(checktime->evaltime)) + " " + TIMESTRING(checktime->evaltime);
+ SetTitle(title.c_str());
+}
+
+bool cMenuConflictCheckDetails::BuildList()
+{
+ Clear();
+ int sel = -1;
+
+ std::set<cConflictCheckTimerObj*,TimerObjSort>::iterator it;
+ if (timerObj->concurrentTimers)
+ for (it = timerObj->concurrentTimers->begin(); it != timerObj->concurrentTimers->end(); it++)
+ {
+ Add(new cMenuConflictCheckDetailsItem(*it));
+ if ((*it)->Event())
+ eventObjects.Add((*it)->Event());
+ if ((*it) == timerObj) sel = Count()-1;
+ }
+ SetCurrent(Get(sel));
+ return true;
+}
+
+void cMenuConflictCheckDetails::SetHelpKeys()
+{
+ cConflictCheckTimerObj* curTimerObj = CurrentTimerObj();
+ bool hasTimer = true;
+ if (curTimerObj)
+ hasTimer = curTimerObj->timer->HasFlags(tfActive);
+ bool hasEvent = curTimerObj->Event();
+ SetHelp(hasEvent?tr("Button$Repeats"):NULL, trVDR("Button$On/Off"), hasTimer?trVDR("Button$Delete"):NULL, tr("Button$Commands"));
+}
+
+cConflictCheckTimerObj* cMenuConflictCheckDetails::CurrentTimerObj(void)
+{
+ cMenuConflictCheckDetailsItem *item = (cMenuConflictCheckDetailsItem *)Get(Current());
+ return item ? item->timerObj : NULL;
+}
+
+eOSState cMenuConflictCheckDetails::Commands(eKeys Key)
+{
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ cConflictCheckTimerObj* curTimerObj = CurrentTimerObj();
+ if (curTimerObj && curTimerObj->Event())
+ {
+ cMenuSearchCommands *menu;
+ eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands"), curTimerObj->Event(), true));
+ if (Key != kNone)
+ state = menu->ProcessKey(Key);
+ return state;
+ }
+ return osContinue;
+}
+
+eOSState cMenuConflictCheckDetails::ToggleTimer(cConflictCheckTimerObj* TimerObj)
+{
+ if (!TimerObj) return osContinue;
+ TimerObj->timer->OnOff();
+ Timers.SetModified();
+ Update();
+ Display();
+ return osContinue;
+}
+
+bool cMenuConflictCheckDetails::Update(bool Force)
+{
+ bool result = false;
+ for (cOsdItem *item = First(); item; item = Next(item)) {
+ if (item->Selectable() && ((cMenuConflictCheckDetailsItem *)item)->Update(Force))
+ result = true;
+ }
+ return result;
+}
+
+eOSState cMenuConflictCheckDetails::DeleteTimer(cConflictCheckTimerObj* TimerObj)
+{
+ cTimer* timer = TimerObj->timer;
+ // Check if this timer is active:
+ if (timer) {
+ if (Interface->Confirm(tr("Delete timer?"))) {
+ if (timer->Recording()) {
+ if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ }
+ else
+ return osContinue;
+ }
+ LogFile.iSysLog("deleting timer %s", *timer->ToDescr());
+ Timers.Del(timer);
+ cOsdMenu::Del(Current());
+ Timers.SetModified();
+ Display();
+ return osBack;
+ }
+ }
+ return osContinue;
+}
+
+
+eOSState cMenuConflictCheckDetails::ShowSummary()
+{
+ cConflictCheckTimerObj* curTimerObj = CurrentTimerObj();
+ if (!curTimerObj)
+ return osContinue;
+
+ const cEvent *ei = curTimerObj->Event();
+ if (ei)
+ {
+ cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true, true);
+ if (channel)
+ return AddSubMenu(new cMenuEventSearchSimple(ei, eventObjects));
+ }
+ return osContinue;
+}
+
+void cMenuConflictCheckDetails::UpdateCurrent()
+{
+ cEventObj* cureventObj = eventObjects.GetCurrent();
+ if (cureventObj && cureventObj->Event())
+ for (cMenuConflictCheckDetailsItem *item = (cMenuConflictCheckDetailsItem *)First(); item; item = (cMenuConflictCheckDetailsItem *)Next(item))
+ if (item->timerObj && item->timerObj->Event() == cureventObj->Event())
+ {
+ cureventObj->Select(false);
+ SetCurrent(item);
+ Display();
+ break;
+ }
+}
+
+eOSState cMenuConflictCheckDetails::ProcessKey(eKeys Key)
+{
+ 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 k1...k9:
+ if (!HasSubMenu())
+ return Commands(Key);
+ else
+ state = osContinue;
+ break;
+ case kOk:
+ if (!HasSubMenu())
+ return ShowSummary();
+ else
+ state = osContinue;
+ break;
+ case kRed:
+ if(!HasSubMenu())
+ {
+ if (CurrentTimerObj() && CurrentTimerObj()->Event())
+ return Commands(k1);
+ else
+ state = osContinue;
+ }
+ else
+ state = osContinue;
+ break;
+ case kGreen:
+ if(!HasSubMenu())
+ state = ToggleTimer(CurrentTimerObj());
+ break;
+ case kYellow:
+ if(!HasSubMenu())
+ state = DeleteTimer(CurrentTimerObj());
+ break;
+ case kBlue:
+ if(!HasSubMenu())
+ {
+ if (CurrentTimerObj() && CurrentTimerObj()->Event())
+ return AddSubMenu(new cMenuSearchCommands(tr("EPG Commands"),CurrentTimerObj()->Event()));
+ else
+ state = osContinue;
+ }
+ else
+ state = osContinue;
+ break;
+ default: break;
+ }
+ }
+ if (!HasSubMenu())
+ {
+ // perhaps a timer was deleted, so first check this
+ if (conflictCheck)
+ {
+ std::set<cConflictCheckTimerObj*,TimerObjSort>::iterator it;
+ if (timerObj->concurrentTimers)
+ {
+ for (it = timerObj->concurrentTimers->begin(); it != timerObj->concurrentTimers->end(); it++)
+ {
+ bool found = false;
+ for(cTimer* checkT = Timers.First(); checkT; checkT = Timers.Next(checkT))
+ {
+ checkT->Matches();
+ if (checkT == (*it)->timer) // ok -> found, check for changes
+ {
+ if (checkT->IsSingleEvent())
+ {
+ if (checkT->StartTime() == (*it)->start && checkT->StopTime() == (*it)->stop)
+ {
+ found = true;
+ break;
+ }
+ }
+ else // repeating timer
+ {
+ if (checkT->DayMatches((*it)->start)) // same day?
+ {
+ int begin = cTimer::TimeToInt(checkT->Start()); // seconds from midnight
+ int length = cTimer::TimeToInt(checkT->Stop()) - begin;
+ if (length < 0)
+ length += SECSINDAY;
+
+ time_t Start = cTimer::SetTime((*it)->start, cTimer::TimeToInt(checkT->Start()));
+ if (Start == (*it)->start && (*it)->stop == (*it)->start + length)
+ found = true;
+ }
+ }
+ }
+ }
+ if (!found) return osBack;
+ }
+ }
+ }
+
+ if (Key != kNone)
+ SetHelpKeys();
+ if ((HadSubMenu || gl_TimerProgged) && Update(true))
+ {
+ if (gl_TimerProgged) // when using epgsearch's timer edit menu, update is delayed because of SVDRP
+ {
+ gl_TimerProgged = 0;
+ SetHelpKeys();
+ }
+ Display();
+ }
+ }
+ return state;
+}