summaryrefslogtreecommitdiff
path: root/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'menu.c')
-rw-r--r--menu.c402
1 files changed, 377 insertions, 25 deletions
diff --git a/menu.c b/menu.c
index b0077a0..7ddf0cf 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 2.10 2009/12/06 11:29:05 kls Exp $
+ * $Id: menu.c 2.14 2010/01/31 12:43:24 kls Exp $
*/
#include "menu.h"
@@ -623,11 +623,276 @@ eOSState cMenuText::ProcessKey(eKeys Key)
return state;
}
+// --- cMenuFolderItem -------------------------------------------------------
+
+class cMenuFolderItem : public cOsdItem {
+private:
+ cNestedItem *folder;
+public:
+ cMenuFolderItem(cNestedItem *Folder);
+ cNestedItem *Folder(void) { return folder; }
+ };
+
+cMenuFolderItem::cMenuFolderItem(cNestedItem *Folder)
+:cOsdItem(Folder->Text())
+{
+ folder = Folder;
+ if (folder->SubItems())
+ SetText(cString::sprintf("%s...", folder->Text()));
+}
+
+// --- cMenuEditFolder -------------------------------------------------------
+
+class cMenuEditFolder : public cOsdMenu {
+private:
+ cList<cNestedItem> *list;
+ cNestedItem *folder;
+ char name[PATH_MAX];
+ int subFolder;
+ eOSState Confirm(void);
+public:
+ cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder = NULL);
+ cString GetFolder(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+cMenuEditFolder::cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder)
+:cOsdMenu(Folder ? tr("Edit folder") : tr("New folder"), 12)
+{
+ list = List;
+ folder = Folder;
+ if (folder) {
+ strn0cpy(name, folder->Text(), sizeof(name));
+ subFolder = folder->SubItems() != NULL;
+ }
+ else {
+ *name = 0;
+ subFolder = 0;
+ cRemote::Put(kRight, true); // go right into string editing mode
+ }
+ if (!isempty(Dir)) {
+ cOsdItem *DirItem = new cOsdItem(Dir);
+ DirItem->SetSelectable(false);
+ Add(DirItem);
+ }
+ Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
+ Add(new cMenuEditBoolItem(tr("Sub folder"), &subFolder));
+}
+
+cString cMenuEditFolder::GetFolder(void)
+{
+ return folder ? folder->Text() : "";
+}
+
+eOSState cMenuEditFolder::Confirm(void)
+{
+ if (!folder || strcmp(folder->Text(), name) != 0) {
+ // each name may occur only once in a folder list
+ for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
+ if (strcmp(Folder->Text(), name) == 0) {
+ Skins.Message(mtError, tr("Folder name already exists!"));
+ return osContinue;
+ }
+ }
+ char *p = strpbrk(name, "\\{}#~"); // FOLDERDELIMCHAR
+ if (p) {
+ Skins.Message(mtError, cString::sprintf(tr("Folder name must not contain '%c'!"), *p));
+ return osContinue;
+ }
+ }
+ if (folder) {
+ folder->SetText(name);
+ folder->SetSubItems(subFolder);
+ }
+ else
+ list->Add(folder = new cNestedItem(name, subFolder));
+ return osEnd;
+}
+
+eOSState cMenuEditFolder::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk: return Confirm();
+ case kRed:
+ case kGreen:
+ case kYellow:
+ case kBlue: return osContinue;
+ default: break;
+ }
+ }
+ return state;
+}
+
+// --- cMenuFolder -----------------------------------------------------------
+
+cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
+:cOsdMenu(Title)
+{
+ list = nestedItemList = NestedItemList;
+ firstFolder = NULL;
+ editing = false;
+ Set();
+ SetHelpKeys();
+ DescendPath(Path);
+}
+
+cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
+:cOsdMenu(Title)
+{
+ list = List;
+ nestedItemList = NestedItemList;
+ dir = Dir;
+ firstFolder = NULL;
+ editing = false;
+ Set();
+ SetHelpKeys();
+ DescendPath(Path);
+}
+
+void cMenuFolder::SetHelpKeys(void)
+{
+ SetHelp(firstFolder ? tr("Button$Select") : NULL, tr("Button$New"), firstFolder ? tr("Button$Delete") : NULL, firstFolder ? tr("Button$Edit") : NULL);
+}
+
+void cMenuFolder::Set(const char *CurrentFolder)
+{
+ firstFolder = NULL;
+ Clear();
+ if (!isempty(dir)) {
+ cOsdItem *DirItem = new cOsdItem(dir);
+ DirItem->SetSelectable(false);
+ Add(DirItem);
+ }
+ list->Sort();
+ for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
+ cOsdItem *FolderItem = new cMenuFolderItem(Folder);
+ Add(FolderItem, CurrentFolder ? strcmp(Folder->Text(), CurrentFolder) == 0 : false);
+ if (!firstFolder)
+ firstFolder = FolderItem;
+ }
+}
+
+void cMenuFolder::DescendPath(const char *Path)
+{
+ if (Path) {
+ const char *p = strchr(Path, FOLDERDELIMCHAR);
+ if (p) {
+ for (cMenuFolderItem *Folder = (cMenuFolderItem *)firstFolder; Folder; Folder = (cMenuFolderItem *)Next(Folder)) {
+ if (strncmp(Folder->Folder()->Text(), Path, p - Path) == 0) {
+ SetCurrent(Folder);
+ if (Folder->Folder()->SubItems())
+ AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text(), p + 1));
+ break;
+ }
+ }
+ }
+ }
+}
+
+eOSState cMenuFolder::Select(void)
+{
+ if (firstFolder) {
+ cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
+ if (Folder) {
+ if (Folder->Folder()->SubItems())
+ return AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text()));
+ else
+ return osEnd;
+ }
+ }
+ return osContinue;
+}
+
+eOSState cMenuFolder::New(void)
+{
+ editing = true;
+ return AddSubMenu(new cMenuEditFolder(dir, list));
+}
+
+eOSState cMenuFolder::Delete(void)
+{
+ if (!HasSubMenu() && firstFolder) {
+ cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
+ if (Folder && Interface->Confirm(Folder->Folder()->SubItems() ? tr("Delete folder and all sub folders?") : tr("Delete folder?"))) {
+ list->Del(Folder->Folder());
+ Del(Folder->Index());
+ firstFolder = Get(isempty(dir) ? 0 : 1);
+ Display();
+ SetHelpKeys();
+ nestedItemList->Save();
+ }
+ }
+ return osContinue;
+}
+
+eOSState cMenuFolder::Edit(void)
+{
+ if (!HasSubMenu() && firstFolder) {
+ cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
+ if (Folder) {
+ editing = true;
+ return AddSubMenu(new cMenuEditFolder(dir, list, Folder->Folder()));
+ }
+ }
+ return osContinue;
+}
+
+eOSState cMenuFolder::SetFolder(void)
+{
+ cMenuEditFolder *mef = (cMenuEditFolder *)SubMenu();
+ if (mef) {
+ Set(mef->GetFolder());
+ SetHelpKeys();
+ Display();
+ nestedItemList->Save();
+ }
+ return CloseSubMenu();
+}
+
+cString cMenuFolder::GetFolder(void)
+{
+ if (firstFolder) {
+ cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
+ if (Folder) {
+ cMenuFolder *mf = (cMenuFolder *)SubMenu();
+ if (mf)
+ return cString::sprintf("%s%c%s", Folder->Folder()->Text(), FOLDERDELIMCHAR, *mf->GetFolder());
+ return Folder->Folder()->Text();
+ }
+ }
+ return "";
+}
+
+eOSState cMenuFolder::ProcessKey(eKeys Key)
+{
+ if (!HasSubMenu())
+ editing = false;
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk:
+ case kRed: return Select();
+ case kGreen: return New();
+ case kYellow: return Delete();
+ case kBlue: return Edit();
+ default: state = osContinue;
+ }
+ }
+ else if (state == osEnd && HasSubMenu() && editing)
+ state = SetFolder();
+ return state;
+}
+
// --- cMenuEditTimer --------------------------------------------------------
cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
:cOsdMenu(tr("Edit timer"), 12)
{
+ file = NULL;
firstday = NULL;
timer = Timer;
addIfConfirmed = New;
@@ -644,9 +909,10 @@ cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
- Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
+ Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
SetFirstDayItem();
}
+ SetHelpKeys();
Timers.IncBeingEdited();
}
@@ -657,6 +923,11 @@ cMenuEditTimer::~cMenuEditTimer()
Timers.DecBeingEdited();
}
+void cMenuEditTimer::SetHelpKeys(void)
+{
+ SetHelp(tr("Button$Folder"));
+}
+
void cMenuEditTimer::SetFirstDayItem(void)
{
if (!firstday && !data.IsSingleEvent()) {
@@ -670,6 +941,26 @@ void cMenuEditTimer::SetFirstDayItem(void)
}
}
+eOSState cMenuEditTimer::SetFolder(void)
+{
+ cMenuFolder *mf = (cMenuFolder *)SubMenu();
+ if (mf) {
+ cString Folder = mf->GetFolder();
+ char *p = strrchr(data.file, FOLDERDELIMCHAR);
+ if (p)
+ p++;
+ else
+ p = data.file;
+ if (!isempty(*Folder))
+ strn0cpy(data.file, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(data.file));
+ else if (p != data.file)
+ memmove(data.file, p, strlen(p) + 1);
+ SetCurrent(file);
+ Display();
+ }
+ return CloseSubMenu();
+}
+
eOSState cMenuEditTimer::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
@@ -699,13 +990,15 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
}
}
return osBack;
- case kRed:
+ case kRed: return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, data.file));
case kGreen:
case kYellow:
case kBlue: return osContinue;
default: break;
}
}
+ else if (state == osEnd && HasSubMenu())
+ state = SetFolder();
if (Key != kNone)
SetFirstDayItem();
return state;
@@ -1490,44 +1783,100 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
class cMenuCommands : public cOsdMenu {
private:
- cCommands *commands;
- char *parameters;
+ cList<cNestedItem> *commands;
+ cString parameters;
+ cString title;
+ cString command;
+ bool confirm;
+ char *result;
+ bool Parse(const char *s);
eOSState Execute(void);
public:
- cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL);
+ cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters = NULL);
virtual ~cMenuCommands();
virtual eOSState ProcessKey(eKeys Key);
};
-cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters)
+cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
:cOsdMenu(Title)
{
+ result = NULL;
SetHasHotkeys();
commands = Commands;
- parameters = Parameters ? strdup(Parameters) : NULL;
- for (cCommand *command = commands->First(); command; command = commands->Next(command))
- Add(new cOsdItem(hk(command->Title())));
+ parameters = Parameters;
+ for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
+ const char *s = Command->Text();
+ if (Command->SubItems())
+ Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
+ else if (Parse(s))
+ Add(new cOsdItem(hk(title)));
+ }
}
cMenuCommands::~cMenuCommands()
{
- free(parameters);
+ free(result);
+}
+
+bool cMenuCommands::Parse(const char *s)
+{
+ const char *p = strchr(s, ':');
+ if (p) {
+ int l = p - s;
+ if (l > 0) {
+ char t[l + 1];
+ stripspace(strn0cpy(t, s, l + 1));
+ l = strlen(t);
+ if (l > 1 && t[l - 1] == '?') {
+ t[l - 1] = 0;
+ confirm = true;
+ }
+ else
+ confirm = false;
+ title = t;
+ command = skipspace(p + 1);
+ return true;
+ }
+ }
+ return false;
}
eOSState cMenuCommands::Execute(void)
{
- cCommand *command = commands->Get(Current());
- if (command) {
- bool confirmed = true;
- if (command->Confirm())
- confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title()));
- if (confirmed) {
- Skins.Message(mtStatus, cString::sprintf("%s...", command->Title()));
- const char *Result = command->Execute(parameters);
- Skins.Message(mtStatus, NULL);
- if (Result)
- return AddSubMenu(new cMenuText(command->Title(), Result, fontFix));
- return osEnd;
+ cNestedItem *Command = commands->Get(Current());
+ if (Command) {
+ if (Command->SubItems())
+ return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
+ if (Parse(Command->Text())) {
+ if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
+ Skins.Message(mtStatus, cString::sprintf("%s...", *title));
+ free(result);
+ result = NULL;
+ cString cmdbuf;
+ if (!isempty(parameters))
+ cmdbuf = cString::sprintf("%s %s", *command, *parameters);
+ const char *cmd = *cmdbuf ? *cmdbuf : *command;
+ dsyslog("executing command '%s'", cmd);
+ cPipe p;
+ if (p.Open(cmd, "r")) {
+ int l = 0;
+ int c;
+ while ((c = fgetc(p)) != EOF) {
+ if (l % 20 == 0)
+ result = (char *)realloc(result, l + 21);
+ result[l++] = char(c);
+ }
+ if (result)
+ result[l] = 0;
+ p.Close();
+ }
+ else
+ esyslog("ERROR: can't open pipe for command '%s'", cmd);
+ Skins.Message(mtStatus, NULL);
+ if (result)
+ return AddSubMenu(new cMenuText(title, result, fontFix));
+ return osEnd;
+ }
}
}
return osContinue;
@@ -1921,7 +2270,7 @@ void cMenuRecordings::Set(bool Refresh)
Clear();
Recordings.Sort();
for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
- if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) {
+ if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == FOLDERDELIMCHAR)) {
cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level);
if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) {
Add(Item);
@@ -2746,6 +3095,7 @@ cMenuSetupMisc::cMenuSetupMisc(void)
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
+ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
}
@@ -3245,6 +3595,8 @@ cChannel *cDisplayChannel::NextAvailableChannel(cChannel *Channel, int Direction
if (Direction) {
while (Channel) {
Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel);
+ if (!Channel && Setup.ChannelsWrap)
+ Channel = Direction > 0 ? Channels.First() : Channels.Last();
if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true))
return Channel;
}
@@ -3759,7 +4111,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
isyslog("record %s", fileName);
if (MakeDirs(fileName, true)) {
const cChannel *ch = timer->Channel();
- recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
+ recorder = new cRecorder(fileName, ch, timer->Priority());
if (device->AttachReceiver(recorder)) {
Recording.WriteInfo();
cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);