summaryrefslogtreecommitdiff
path: root/client/menu.c
diff options
context:
space:
mode:
authorlordjaxom <lordjaxom>2004-12-30 22:43:55 +0000
committerlordjaxom <lordjaxom>2004-12-30 22:43:55 +0000
commit302fa2e67276bd0674e81e2a9a01b9e91dd45d8c (patch)
treea454884a16e0ffa48b5ce3e4ce1a66eb874a9de0 /client/menu.c
downloadvdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.gz
vdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.bz2
Initial revision
Diffstat (limited to 'client/menu.c')
-rw-r--r--client/menu.c1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/client/menu.c b/client/menu.c
new file mode 100644
index 0000000..4499268
--- /dev/null
+++ b/client/menu.c
@@ -0,0 +1,1047 @@
+/*
+ * $Id: menu.c,v 1.1 2004/12/30 22:44:01 lordjaxom Exp $
+ */
+
+#include <vdr/menuitems.h>
+#include <vdr/interface.h>
+
+#include "client/menu.h"
+#include "client/socket.h"
+#include "i18n.h"
+
+#define CHNUMWIDTH (numdigits(Channels.MaxNumber()) + 1)
+
+// --- cMenuText -------------------------------------------------------------
+
+class cMenuText : public cOsdMenu {
+public:
+ cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cStreamdevMenu --------------------------------------------------------
+
+cStreamdevMenu::cStreamdevMenu(void):
+ cOsdMenu(tr("Streaming Control")) {
+ SetHasHotkeys();
+ Add(new cOsdItem(hk(tr("Remote Schedule")), (eOSState)subSchedule));
+ Add(new cOsdItem(hk(tr("Remote Timers")), (eOSState)subTimers));
+ Add(new cOsdItem(hk(tr("Remote Recordings")), (eOSState)subRecordings));
+ Add(new cOsdItem(hk(tr("Suspend Server")), (eOSState)subSuspend));
+ Add(new cOsdItem(hk(tr("Synchronize EPG")), (eOSState)subSyncEPG));
+}
+
+cStreamdevMenu::~cStreamdevMenu() {
+}
+
+eOSState cStreamdevMenu::ProcessKey(eKeys Key) {
+ eOSState state = cOsdMenu::ProcessKey(Key);
+ switch (state) {
+ case subSchedule: return AddSubMenu(new cStreamdevMenuSchedule);
+ case subTimers: return AddSubMenu(new cStreamdevMenuTimers);
+ case subRecordings: return AddSubMenu(new cStreamdevMenuRecordings);
+ case subSuspend: SuspendServer(); return osEnd;
+ case subSyncEPG: ClientSocket.SynchronizeEPG(); return osEnd;
+ default: return state;
+ }
+}
+
+void cStreamdevMenu::SuspendServer(void) {
+ cTBString buffer;
+
+ if (ClientSocket.SuspendServer())
+ INFO(tr("Server is suspended"));
+ else
+ ERROR(tr("Couldn't suspend Server!"));
+}
+
+#if VDRVERSNUM < 10307
+// --- cMenuEditChanItem -----------------------------------------------------
+
+class cMenuEditChanItem : public cMenuEditIntItem {
+protected:
+ virtual void Set(void);
+public:
+ cMenuEditChanItem(const char *Name, int *Value);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuEditDateItem -----------------------------------------------------
+
+class cMenuEditDateItem : public cMenuEditItem {
+protected:
+ time_t *value;
+ virtual void Set(void);
+public:
+ cMenuEditDateItem(const char *Name, time_t *Value);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuEditDayItem ------------------------------------------------------
+
+class cMenuEditDayItem : public cMenuEditIntItem {
+protected:
+ static int days[];
+ int d;
+ virtual void Set(void);
+public:
+ cMenuEditDayItem(const char *Name, int *Value);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuEditTimeItem -----------------------------------------------------
+
+class cMenuEditTimeItem : public cMenuEditItem {
+protected:
+ int *value;
+ int hh, mm;
+ int pos;
+ virtual void Set(void);
+public:
+ cMenuEditTimeItem(const char *Name, int *Value);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+#endif // VDRVERSNUM < 10307
+
+// --- cStreamdevMenuEditTimer -----------------------------------------------
+
+class cStreamdevMenuEditTimer : public cOsdMenu {
+private:
+ int m_Channel;
+ bool m_AddIfConfirmed;
+ cRemoteTimer *m_Timer;
+ cRemoteTimer m_Data;
+ cMenuEditDateItem *m_FirstDay;
+
+protected:
+ void SetFirstDayItem(void);
+
+public:
+ cStreamdevMenuEditTimer(cRemoteTimer *Timer, bool New = false);
+ virtual ~cStreamdevMenuEditTimer();
+
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+cStreamdevMenuEditTimer::cStreamdevMenuEditTimer(cRemoteTimer *Timer, bool New):
+ cOsdMenu(tr("Edit remote timer"), 12) {
+ m_FirstDay = NULL;
+ m_Timer = Timer;
+ m_AddIfConfirmed = New;
+
+ if (m_Timer) {
+ m_Data = *m_Timer;
+ if (New)
+ m_Data.m_Active = 1;
+ m_Channel = m_Data.Channel()->Number();
+#if VDRVERSNUM < 10300
+ Add(new cMenuEditBoolItem(tr("Active"), &m_Data.m_Active));
+#else
+ Add(new cMenuEditBitItem( tr("Active"), &m_Data.m_Active, tfActive));
+#endif
+ Add(new cMenuEditChanItem(tr("Channel"), &m_Channel));
+ Add(new cMenuEditDayItem( tr("Day"), &m_Data.m_Day));
+ Add(new cMenuEditTimeItem(tr("Start"), &m_Data.m_Start));
+ Add(new cMenuEditTimeItem(tr("Stop"), &m_Data.m_Stop));
+#if VDRVERSNUM >= 10300
+ Add(new cMenuEditBitItem( tr("VPS"), &m_Data.m_Active, tfVps));
+#endif
+ Add(new cMenuEditIntItem( tr("Priority"), &m_Data.m_Priority, 0,
+ MAXPRIORITY));
+ Add(new cMenuEditIntItem( tr("Lifetime"), &m_Data.m_Lifetime, 0,
+ MAXLIFETIME));
+ Add(new cMenuEditStrItem( tr("File"), m_Data.m_File,
+ sizeof(m_Data.m_File), tr(FileNameChars)));
+ SetFirstDayItem();
+ }
+}
+
+cStreamdevMenuEditTimer::~cStreamdevMenuEditTimer() {
+ if (m_Timer && m_AddIfConfirmed) {
+ Dprintf("SOMETHING GETS DELETED\n");
+ delete m_Timer; // apparently it wasn't confirmed
+ }
+}
+
+void cStreamdevMenuEditTimer::SetFirstDayItem(void) {
+ if (!m_FirstDay && !m_Data.IsSingleEvent()) {
+ Add(m_FirstDay = new cMenuEditDateItem(tr("First day"),&m_Data.m_FirstDay));
+ Display();
+ } else if (m_FirstDay && m_Data.IsSingleEvent()) {
+ Del(m_FirstDay->Index());
+ m_FirstDay = NULL;
+ m_Data.m_FirstDay = 0;
+ Display();
+ }
+}
+
+eOSState cStreamdevMenuEditTimer::ProcessKey(eKeys Key) {
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk:
+ {
+ cChannel *ch = Channels.GetByNumber(m_Channel);
+ if (ch)
+ m_Data.m_Channel = ch;
+ else {
+ ERROR(tr("*** Invalid Channel ***"));
+ break;
+ }
+ if (!*m_Data.m_File)
+ strcpy(m_Data.m_File, m_Data.Channel()->Name());
+ if (m_Timer) {
+ bool success = true;
+ if (m_Data != *m_Timer) {
+ // Timer has changed
+ if ((success = ClientSocket.SaveTimer(m_Timer, m_Data))) {
+ *m_Timer = m_Data;
+ if (m_Timer->m_Active)
+ m_Timer->m_Active = 1;
+ // allows external programs to mark active timers with
+ // values > 1 and recognize if the user has modified them
+ }
+ }
+ if (success) {
+ if (m_AddIfConfirmed)
+ RemoteTimers.Add(m_Timer);
+ isyslog("timer %d %s (%s)", m_Timer->Index() + 1,
+ m_AddIfConfirmed ? "added" : "modified",
+ m_Timer->m_Active ? "active" : "inactive");
+ m_AddIfConfirmed = false;
+ }
+ }
+ }
+ return osBack;
+
+ case kRed:
+ case kGreen:
+ case kYellow:
+ case kBlue: return osContinue;
+ default: break;
+ }
+ }
+ if (Key != kNone)
+ SetFirstDayItem();
+ return state;
+}
+
+// --- cMenuWhatsOnItem ------------------------------------------------------
+
+#if VDRVERSNUM < 10300
+class cMenuWhatsOnItem : public cOsdItem {
+public:
+ const cEventInfo *eventInfo;
+# ifdef HAVE_BEAUTYPATCH
+ cMenuWhatsOnItem(const cEventInfo *EventInfo, bool ShowProgressBar);
+ ~cMenuWhatsOnItem();
+ virtual void Display(int Offset= -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
+protected:
+ cBitmap *progressBar;
+ bool showProgressBar;
+ float percent;
+private:
+ void DrawProgressBar(eDvbColor FgColor, eDvbColor BgColor);
+# else
+ cMenuWhatsOnItem(const cEventInfo *EventInfo);
+# endif
+};
+#else
+class cMenuWhatsOnItem : public cOsdItem {
+public:
+ const cEvent *event;
+ const cChannel *channel;
+ cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel);
+};
+#endif
+
+// --- cMenuEvent ------------------------------------------------------------
+
+#if VDRVERSNUM < 10300
+class cMenuEvent : public cOsdMenu {
+private:
+ const cEventInfo *eventInfo;
+public:
+ cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false);
+ cMenuEvent(bool Now);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+#elif VDRVERSNUM < 10307
+class cMenuEvent : public cOsdMenu {
+private:
+ const cEvent *event;
+public:
+ cMenuEvent(const cEvent *Event, bool CanSwitch = false);
+ cMenuEvent(bool Now);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+#else
+class cMenuEvent : public cOsdMenu {
+private:
+ const cEvent *event;
+public:
+ cMenuEvent(const cEvent *Event, bool CanSwitch = false);
+ virtual void Display(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+#endif
+
+// --- cStreamdevMenuWhatsOn -------------------------------------------------
+
+int cStreamdevMenuWhatsOn::m_CurrentChannel = 0;
+#if VDRVERSNUM < 10300
+const cEventInfo *cStreamdevMenuWhatsOn::m_ScheduleEventInfo = NULL;
+#else
+const cEvent *cStreamdevMenuWhatsOn::m_ScheduleEventInfo = NULL;
+#endif
+
+#if VDRVERSNUM < 10300
+static int CompareEventChannel(const void *p1, const void *p2) {
+ return (int)((*(const cEventInfo**)p1)->GetChannelNumber()
+ - (*(const cEventInfo**)p2)->GetChannelNumber());
+}
+#endif
+
+cStreamdevMenuWhatsOn::cStreamdevMenuWhatsOn(const cSchedules *Schedules,
+ bool Now, int CurrentChannel):
+ cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH,
+ 7, 6) {
+#if VDRVERSNUM < 10300
+ const cSchedule *Schedule = Schedules->First();
+ const cEventInfo **pArray = NULL;
+ int num = 0;
+
+ while (Schedule) {
+ pArray=(const cEventInfo**)realloc(pArray, (num + 1) * sizeof(cEventInfo*));
+ pArray[num] = Now ? Schedule->GetPresentEvent()
+ : Schedule->GetFollowingEvent();
+ if (pArray[num]) {
+ cChannel *channel
+ = Channels.GetByChannelID(pArray[num]->GetChannelID(), true);
+ if (channel)
+ pArray[num++]->SetChannelNumber(channel->Number());
+ }
+ Schedule = Schedules->Next(Schedule);
+ }
+
+ qsort(pArray, num, sizeof(cEventInfo*), CompareEventChannel);
+ for (int a = 0; a < num; ++a) {
+ int channelnr = pArray[a]->GetChannelNumber();
+# ifdef HAVE_BEAUTYPATCH
+ Add(new cMenuWhatsOnItem(pArray[a],Now), channelnr == CurrentChannel);
+# else
+ Add(new cMenuWhatsOnItem(pArray[a]), channelnr == CurrentChannel);
+# endif
+ }
+
+ free(pArray);
+#else
+ for (cChannel *Channel = Channels.First(); Channel;
+ Channel = Channels.Next(Channel)) {
+ if (!Channel->GroupSep()) {
+ const cSchedule *Schedule
+ = Schedules->GetSchedule(Channel->GetChannelID());
+ if (Schedule) {
+ const cEvent *Event = Now ? Schedule->GetPresentEvent()
+ : Schedule->GetFollowingEvent();
+ if (Event)
+ Add(new cMenuWhatsOnItem(Event, Channel),
+ Channel->Number() == CurrentChannel);
+ }
+ }
+ }
+#endif
+ m_CurrentChannel = CurrentChannel;
+ SetHelp(Count() ? tr("Record") : NULL, Now ? tr("Next") : tr("Now"),
+ tr("Schedule"), tr("Switch"));
+}
+
+#if VDRVERSNUM < 10300
+const cEventInfo *cStreamdevMenuWhatsOn::ScheduleEventInfo(void) {
+ const cEventInfo *ei = m_ScheduleEventInfo;
+ m_ScheduleEventInfo = NULL;
+ return ei;
+}
+#else
+const cEvent *cStreamdevMenuWhatsOn::ScheduleEventInfo(void) {
+ const cEvent *ei = m_ScheduleEventInfo;
+ m_ScheduleEventInfo = NULL;
+ return ei;
+}
+#endif
+
+eOSState cStreamdevMenuWhatsOn::Switch(void) {
+ cMenuWhatsOnItem *item = (cMenuWhatsOnItem*)Get(Current());
+ if (item) {
+ cChannel *channel
+#if VDRVERSNUM < 10300
+ = Channels.GetByChannelID(item->eventInfo->GetChannelID(), true);
+#else
+ = Channels.GetByChannelID(item->event->ChannelID(), true);
+#endif
+ if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
+ return osEnd;
+ }
+ ERROR(tr("Can't switch channel!"));
+ return osContinue;
+}
+
+eOSState cStreamdevMenuWhatsOn::Record(void) {
+ cMenuWhatsOnItem *item = (cMenuWhatsOnItem*)Get(Current());
+ if (item) {
+ cRemoteTimer *timer
+#if VDRVERSNUM < 10300
+ = new cRemoteTimer(item->eventInfo);
+#else
+ = new cRemoteTimer(item->event);
+#endif
+ return AddSubMenu(new cStreamdevMenuEditTimer(timer));
+ // Load remote timers and see if timer exists before editing
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuWhatsOn::ProcessKey(eKeys Key) {
+ eOSState state = cOsdMenu::ProcessKey(Key);
+ if (state == osUnknown) {
+ switch (Key) {
+ case kRecord:
+ case kRed:
+ return Record();
+
+ case kYellow:
+ state = osBack;
+ case kGreen:
+ {
+ cMenuWhatsOnItem *mi = (cMenuWhatsOnItem*)Get(Current());
+ if (mi) {
+#if VDRVERSNUM < 10300
+ m_ScheduleEventInfo = mi->eventInfo;
+ m_CurrentChannel = mi->eventInfo->GetChannelNumber();
+#else
+ m_ScheduleEventInfo = mi->event;
+ m_CurrentChannel = mi->channel->Number();
+#endif
+ }
+ }
+ break;
+
+ case kBlue:
+ return Switch();
+
+ case kOk:
+ if (Count())
+#if VDRVERSNUM < 10300
+ return AddSubMenu(new cMenuEvent(
+ ((cMenuWhatsOnItem*)Get(Current()))->eventInfo, true));
+#else
+ return AddSubMenu(new cMenuEvent(
+ ((cMenuWhatsOnItem*)Get(Current()))->event, true));
+#endif
+ break;
+
+ default:
+ break;
+ }
+ }
+ return state;
+}
+
+// --- cMenuScheduleItem -----------------------------------------------------
+
+#if VDRVERSNUM < 10300
+class cMenuScheduleItem : public cOsdItem {
+public:
+ const cEventInfo *eventInfo;
+ cMenuScheduleItem(const cEventInfo *EventInfo);
+};
+#else
+class cMenuScheduleItem : public cOsdItem {
+public:
+ const cEvent *event;
+ cMenuScheduleItem(const cEvent *Event);
+};
+#endif
+
+// --- cStreamdevMenuSchedule ------------------------------------------------
+
+cStreamdevMenuSchedule::cStreamdevMenuSchedule(void):
+#if VDRVERSNUM < 10300
+ cOsdMenu("", 6, 6)
+#else
+ cOsdMenu("", 7, 6, 4)
+#endif
+{
+ m_Now = false;
+ m_Next = false;
+ m_OtherChannel = -1;
+ m_Schedules = NULL;
+
+ cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
+ if (channel) {
+#if VDRVERSNUM < 10300
+ m_Schedules = cSIProcessor::Schedules(m_Lock);
+#else
+ m_Schedules = cSchedules::Schedules(m_Lock);
+#endif
+ PrepareSchedule(channel);
+ SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next"));
+ }
+}
+
+cStreamdevMenuSchedule::~cStreamdevMenuSchedule() {
+}
+
+#if VDRVERSNUM < 10307
+static int CompareEventTime(const void *p1, const void *p2) {
+#if VDRVERSNUM < 10300
+ return (int)((*(cEventInfo **)p1)->GetTime()
+ - (*(cEventInfo **)p2)->GetTime());
+#else
+ return (int)((*(cEvent**)p1)->StartTime()
+ - (*(cEvent**)p2)->StartTime());
+#endif
+}
+#endif
+
+void cStreamdevMenuSchedule::PrepareSchedule(cChannel *Channel) {
+#if VDRVERSNUM < 10300
+ cTBString buffer;
+ Clear();
+ buffer.Format(tr("Schedule - %s"), Channel->Name());
+ SetTitle(buffer);
+ if (m_Schedules) {
+ const cSchedule *Schedule=m_Schedules->GetSchedule(Channel->GetChannelID());
+ if (Schedule) {
+ int num = Schedule->NumEvents();
+ const cEventInfo **pArray = MALLOC(const cEventInfo*, num);
+ if (pArray) {
+ time_t now = time(NULL);
+ int numreal = 0;
+ for (int a = 0; a < num; ++a) {
+ const cEventInfo *EventInfo = Schedule->GetEventNumber(a);
+ if (EventInfo->GetTime() + EventInfo->GetDuration() > now)
+ pArray[numreal++] = EventInfo;
+ }
+
+ qsort(pArray, numreal, sizeof(cEventInfo*), CompareEventTime);
+ for (int a = 0; a < numreal; ++a)
+ Add(new cMenuScheduleItem(pArray[a]));
+ free(pArray);
+ }
+ }
+ }
+#else
+ Clear();
+ char *buffer = NULL;
+ asprintf(&buffer, tr("Schedule - %s"), Channel->Name());
+ SetTitle(buffer);
+ free(buffer);
+ if (m_Schedules) {
+ const cSchedule *Schedule = m_Schedules->GetSchedule(Channel->GetChannelID());
+ if (Schedule) {
+ const cEvent *PresentEvent = Schedule->GetPresentEvent(Channel->Number() == cDevice::CurrentChannel());
+ time_t now = time(NULL) - Setup.EPGLinger * 60;
+ for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) {
+ if (Event->EndTime() > now || Event == PresentEvent)
+ Add(new cMenuScheduleItem(Event), Event == PresentEvent);
+ }
+ }
+ }
+#endif
+}
+
+eOSState cStreamdevMenuSchedule::Switch(void) {
+ if (m_OtherChannel) {
+ if (Channels.SwitchTo(m_OtherChannel))
+ return osEnd;
+ }
+ ERROR(tr("Can't switch channel!"));
+ return osContinue;
+}
+
+eOSState cStreamdevMenuSchedule::Record(void) {
+ cMenuScheduleItem *item = (cMenuScheduleItem*)Get(Current());
+ if (item) {
+ cRemoteTimer *timer
+#if VDRVERSNUM < 10300
+ = new cRemoteTimer(item->eventInfo);
+#else
+ = new cRemoteTimer(item->event);
+#endif
+ return AddSubMenu(new cStreamdevMenuEditTimer(timer));
+ // Load remote timers and see if timer exists before editing
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuSchedule::ProcessKey(eKeys Key) {
+ eOSState state = cOsdMenu::ProcessKey(Key);
+ if (state == osUnknown) {
+ switch (Key) {
+ case kRecord:
+ case kRed:
+ return Record();
+
+ case kGreen:
+ if (m_Schedules) {
+ if (!m_Now && !m_Next) {
+ int channelnr = 0;
+ if (Count()) {
+ cChannel *channel
+#if VDRVERSNUM < 10300
+ = Channels.GetByChannelID(
+ ((cMenuScheduleItem*)Get(Current()))->eventInfo->GetChannelID(),
+ true);
+#else
+ = Channels.GetByChannelID(
+ ((cMenuScheduleItem*)Get(Current()))->event->ChannelID(), true);
+#endif
+ if (channel)
+ channelnr = channel->Number();
+ }
+ m_Now = true;
+ return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, true,
+ channelnr));
+ }
+ m_Now = !m_Now;
+ m_Next = !m_Next;
+ return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, m_Now,
+ cStreamdevMenuWhatsOn::CurrentChannel()));
+ }
+
+ case kYellow:
+ if (m_Schedules)
+ return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, false,
+ cStreamdevMenuWhatsOn::CurrentChannel()));
+ break;
+
+ case kBlue:
+ if (Count())
+ return Switch();
+ break;
+
+ case kOk:
+ if (Count())
+#if VDRVERSNUM < 10300
+ return AddSubMenu(new cMenuEvent(
+ ((cMenuScheduleItem*)Get(Current()))->eventInfo, m_OtherChannel));
+#else
+ return AddSubMenu(new cMenuEvent(
+ ((cMenuScheduleItem*)Get(Current()))->event, m_OtherChannel));
+#endif
+ break;
+
+ default:
+ break;
+ }
+ } else if (!HasSubMenu()) {
+ m_Now = false;
+ m_Next = false;
+#if VDRVERSNUM < 10300
+ const cEventInfo *ei
+#else
+ const cEvent *ei
+#endif
+ = cStreamdevMenuWhatsOn::ScheduleEventInfo();
+ if (ei) {
+ cChannel *channel
+#if VDRVERSNUM < 10300
+ = Channels.GetByChannelID(ei->GetChannelID(), true);
+#else
+ = Channels.GetByChannelID(ei->ChannelID(), true);
+#endif
+ if (channel) {
+ PrepareSchedule(channel);
+ if (channel->Number() != cDevice::CurrentChannel()) {
+ m_OtherChannel = channel->Number();
+ SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next"),
+ tr("Switch"));
+ }
+ Display();
+ }
+ }
+ }
+ return state;
+}
+
+// --- cStreamdevMenuRecordingItem -------------------------------------------
+
+class cStreamdevMenuRecordingItem: public cOsdItem {
+private:
+ int m_Total;
+ int m_New;
+ char *m_FileName;
+ char *m_Name;
+
+public:
+ cStreamdevMenuRecordingItem(cRemoteRecording *Recording, int Level);
+ virtual ~cStreamdevMenuRecordingItem();
+
+ void IncrementCounter(bool New);
+ const char *Name(void) const { return m_Name; }
+ const char *FileName(void) const { return m_FileName; }
+ bool IsDirectory(void) const { return m_Name != NULL; }
+};
+
+cStreamdevMenuRecordingItem::cStreamdevMenuRecordingItem(
+ cRemoteRecording *Recording, int Level) {
+ m_FileName = strdup(Recording->Name());
+ m_Name = NULL;
+ m_Total = m_New = 0;
+ SetText(Recording->Title('\t', true, Level));
+ if (*Text() == '\t')
+ m_Name = strdup(Text() + 2);
+}
+
+cStreamdevMenuRecordingItem::~cStreamdevMenuRecordingItem() {
+}
+
+void cStreamdevMenuRecordingItem::IncrementCounter(bool New) {
+ ++m_Total;
+ if (New) ++m_New;
+ char *buffer = NULL;
+ asprintf(&buffer, "%d\t%d\t%s", m_Total, m_New, m_Name);
+ SetText(buffer, false);
+}
+
+// --- cStreamdevMenuRecordings ----------------------------------------------
+
+cRemoteRecordings cStreamdevMenuRecordings::Recordings;
+int cStreamdevMenuRecordings::HelpKeys = -1;
+
+cStreamdevMenuRecordings::cStreamdevMenuRecordings(const char *Base, int Level,
+ bool OpenSubMenus):
+ cOsdMenu(Base ? Base : tr("Remote Recordings"), 6, 6) {
+ m_Base = Base ? strdup(Base) : NULL;
+ m_Level = Setup.RecordingDirs ? Level : -1;
+
+ Display(); // this keeps the higher level menus from showing up briefly when
+ // pressing 'Back' during replay
+
+ if (!Base) {
+ STATUS(tr("Fetching recordings..."));
+ FLUSH();
+ }
+
+ if (Base || Recordings.Load()) {
+ cStreamdevMenuRecordingItem *LastItem = NULL;
+ char *LastItemText = NULL;
+ for (cRemoteRecording *r = Recordings.First(); r; r = Recordings.Next(r)) {
+ if (!Base || (strstr(r->Name(), Base) == r->Name()
+ && r->Name()[strlen(Base)] == '~')) {
+ cStreamdevMenuRecordingItem *Item = new cStreamdevMenuRecordingItem(r,
+ m_Level);
+ if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText)
+ != 0)) {
+ Add(Item);
+ LastItem = Item;
+ free(LastItemText);
+ LastItemText = strdup(LastItem->Text());
+ } else
+ delete Item;
+
+ if (LastItem) {
+ if (LastItem->IsDirectory())
+ LastItem->IncrementCounter(r->IsNew());
+ }
+ }
+ }
+ free(LastItemText);
+ if (Current() < 0)
+ SetCurrent(First());
+ else if (OpenSubMenus && Open(true))
+ return;
+ }
+
+#if VDRVERSNUM >= 10307
+ STATUS(NULL);
+ FLUSH();
+#endif
+
+ SetHelpKeys();
+}
+
+cStreamdevMenuRecordings::~cStreamdevMenuRecordings() {
+ if (m_Base != NULL) free(m_Base);
+ HelpKeys = -1;
+}
+
+void cStreamdevMenuRecordings::SetHelpKeys(void) {
+ cStreamdevMenuRecordingItem *ri =(cStreamdevMenuRecordingItem*)Get(Current());
+ int NewHelpKeys = HelpKeys;
+ if (ri) {
+ if (ri->IsDirectory())
+ NewHelpKeys = 1;
+ else {
+ NewHelpKeys = 2;
+ cRemoteRecording *recording = GetRecording(ri);
+ if (recording && recording->Summary())
+ NewHelpKeys = 3;
+ }
+ }
+ if (NewHelpKeys != HelpKeys) {
+ switch (NewHelpKeys) {
+ case 0: SetHelp(NULL); break;
+ case 1: SetHelp(tr("Open")); break;
+ case 2:
+ case 3: SetHelp(NULL, NULL, tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL);
+ //SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL); XXX
+ }
+ HelpKeys = NewHelpKeys;
+ }
+}
+
+cRemoteRecording *cStreamdevMenuRecordings::GetRecording(
+ cStreamdevMenuRecordingItem *Item) {
+ Dprintf("looking for %s\n", Item->FileName());
+ cRemoteRecording *recording = Recordings.GetByName(Item->FileName());
+ if (!recording)
+ ERROR(tr("Error while accessing recording!"));
+ return recording;
+}
+
+bool cStreamdevMenuRecordings::Open(bool OpenSubMenus) {
+ cStreamdevMenuRecordingItem *ri
+ = (cStreamdevMenuRecordingItem*)Get(Current());
+
+ if (ri && ri->IsDirectory()) {
+ const char *t = ri->Name();
+ char *buffer = NULL;
+ if (m_Base) {
+ asprintf(&buffer, "%s~%s", m_Base, t);
+ t = buffer;
+ }
+ AddSubMenu(new cStreamdevMenuRecordings(t, m_Level + 1, OpenSubMenus));
+ if (buffer != NULL) free(buffer);
+ return true;
+ }
+ return false;
+}
+
+eOSState cStreamdevMenuRecordings::Select(void) {
+ cStreamdevMenuRecordingItem *ri
+ = (cStreamdevMenuRecordingItem*)Get(Current());
+
+ if (ri) {
+ if (ri->IsDirectory())
+ Open();
+ /*else {
+ cControl::Launch(new cStreamdevPlayerControl(ri->FileName()));
+ return osEnd;
+ } XXX */
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuRecordings::Delete(void) {
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ cStreamdevMenuRecordingItem *ri
+ = (cStreamdevMenuRecordingItem*)Get(Current());
+ if (ri && !ri->IsDirectory()) {
+ if (Interface->Confirm(tr("Delete recording?"))) {
+ cRemoteRecording *recording = GetRecording(ri);
+ if (recording) {
+ if (ClientSocket.DeleteRecording(recording)) {
+ cOsdMenu::Del(Current());
+ Recordings.Del(recording);
+ Display();
+ if (!Count())
+ return osBack;
+ }
+ }
+ }
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuRecordings::Summary(void) {
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ cStreamdevMenuRecordingItem *ri=(cStreamdevMenuRecordingItem *)Get(Current());
+ if (ri && !ri->IsDirectory()) {
+ cRemoteRecording *recording = GetRecording(ri);
+ if (recording && recording->Summary() && *recording->Summary())
+ return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary()));
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuRecordings::ProcessKey(eKeys Key) {
+ bool HadSubMenu = HasSubMenu();
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk:
+ case kRed: return Select();
+ case kYellow: return Delete();
+ case kBlue: return Summary();
+ default: break;
+ }
+ }
+
+ if (Key == kYellow && HadSubMenu && !HasSubMenu()) {
+ cOsdMenu::Del(Current());
+ if (!Count())
+ return osBack;
+ Display();
+ }
+
+ if (!HasSubMenu() && Key != kNone)
+ SetHelpKeys();
+ return state;
+}
+
+// --- cStreamdevMenuTimerItem -----------------------------------------------
+
+class cStreamdevMenuTimerItem: public cOsdItem {
+private:
+ cRemoteTimer *m_Timer;
+
+public:
+ cStreamdevMenuTimerItem(cRemoteTimer *Timer);
+ virtual ~cStreamdevMenuTimerItem();
+
+ virtual void Set(void);
+
+ cRemoteTimer *Timer(void) const { return m_Timer; }
+};
+
+cStreamdevMenuTimerItem::cStreamdevMenuTimerItem(cRemoteTimer *Timer) {
+ m_Timer = Timer;
+ Set();
+}
+
+cStreamdevMenuTimerItem::~cStreamdevMenuTimerItem() {
+}
+
+void cStreamdevMenuTimerItem::Set(void) {
+ char *buffer = NULL;
+ asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s",
+ !m_Timer->Active() ? ' ' :
+ m_Timer->FirstDay() ? '!' :
+ /*m_Timer->Recording() ? '#' :*/ '>',
+ m_Timer->Channel()->Number(),
+ m_Timer->PrintDay(m_Timer->Day()),
+ m_Timer->Start() / 100,
+ m_Timer->Start() % 100,
+ m_Timer->Stop() / 100,
+ m_Timer->Stop() % 100,
+ m_Timer->File());
+ SetText(buffer, false);
+}
+
+// --- cStreamdevMenuTimers --------------------------------------------------
+
+cStreamdevMenuTimers::cStreamdevMenuTimers(void):
+ cOsdMenu(tr("Remote Timers"), 2, CHNUMWIDTH, 10, 6, 6) {
+ Refresh();
+ SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("On/Off"));
+}
+
+cStreamdevMenuTimers::~cStreamdevMenuTimers() {
+}
+
+eOSState cStreamdevMenuTimers::ProcessKey(eKeys Key) {
+ int timerNum = HasSubMenu() ? Count() : -1;
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk: return Summary();
+ case kRed: return Edit();
+ case kGreen: return New();
+ case kYellow: return Delete();
+ case kBlue: OnOff(); break;
+ default: break;
+ }
+ }
+
+ if (timerNum >= 0 && !HasSubMenu()) {
+ Refresh();
+ Display();
+ }
+ return state;
+}
+
+eOSState cStreamdevMenuTimers::Edit(void) {
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ isyslog("Streamdev: Editing remote timer %d", CurrentTimer()->Index() + 1);
+ return AddSubMenu(new cStreamdevMenuEditTimer(CurrentTimer()));
+}
+
+eOSState cStreamdevMenuTimers::New(void) {
+ if (HasSubMenu())
+ return osContinue;
+ return AddSubMenu(new cStreamdevMenuEditTimer(new cRemoteTimer, true));
+}
+
+eOSState cStreamdevMenuTimers::Delete(void) {
+ cRemoteTimer *ti = CurrentTimer();
+ if (ti) {
+ if (Interface->Confirm(tr("Delete timer?"))) {
+ int idx = ti->Index();
+ if (ClientSocket.DeleteTimer(ti)) {
+ RemoteTimers.Del(ti);
+ cOsdMenu::Del(Current());
+ isyslog("Streamdev: Remote timer %d deleted", idx + 1);
+ }
+ Refresh();
+ Display();
+ }
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuTimers::OnOff(void) {
+ cRemoteTimer *timer = CurrentTimer();
+ if (timer) {
+ cRemoteTimer data = *timer;
+ data.OnOff();
+ if (data.FirstDay())
+ isyslog("Streamdev: Remote timer %d first day set to %s",
+ data.Index() + 1, data.PrintFirstDay());
+ else
+ isyslog("Streamdev: Remote timer %d %sactivated", data.Index() + 1,
+ data.Active() ? "" : "de");
+
+ if (ClientSocket.SaveTimer(timer, data)) {
+ *timer = data;
+ RefreshCurrent();
+ DisplayCurrent(true);
+ } else {
+ Refresh();
+ Display();
+ }
+ }
+ return osContinue;
+}
+
+eOSState cStreamdevMenuTimers::Summary(void) {
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+
+ cRemoteTimer *ti = CurrentTimer();
+ if (ti && !ti->Summary().IsNull())
+ return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary()));
+
+ return osContinue;
+}
+
+cRemoteTimer *cStreamdevMenuTimers::CurrentTimer(void) {
+ cStreamdevMenuTimerItem *item = (cStreamdevMenuTimerItem*)Get(Current());
+ return item ? item->Timer() : NULL;
+}
+
+void cStreamdevMenuTimers::Refresh(void) {
+ Clear();
+ if (RemoteTimers.Load()) {
+ for (cRemoteTimer *t = RemoteTimers.First(); t; t = RemoteTimers.Next(t)) {
+ Add(new cStreamdevMenuTimerItem(t));
+ }
+ }
+}