vdr 2.6.4
menu.c
Go to the documentation of this file.
1/*
2 * menu.c: The actual menu implementations
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: menu.c 5.9 2022/12/01 13:09:04 kls Exp $
8 */
9
10#include "menu.h"
11#include <ctype.h>
12#include <limits.h>
13#include <math.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include "channels.h"
18#include "config.h"
19#include "cutter.h"
20#include "eitscan.h"
21#include "i18n.h"
22#include "interface.h"
23#include "plugin.h"
24#include "recording.h"
25#include "remote.h"
26#include "shutdown.h"
27#include "sourceparams.h"
28#include "sources.h"
29#include "status.h"
30#include "svdrp.h"
31#include "themes.h"
32#include "timers.h"
33#include "transfer.h"
34#include "videodir.h"
35
36#define MAXWAIT4EPGINFO 3 // seconds
37#define MODETIMEOUT 3 // seconds
38#define NEWTIMERLIMIT 120 // seconds until the start time of a new timer created from the Schedule menu,
39 // within which it will go directly into the "Edit timer" menu to allow
40 // further parameter settings
41#define DEFERTIMER 60 // seconds by which a timer is deferred in case of problems
42
43#define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
44#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
45#define MAXWAITFORCAMMENU 10 // seconds to wait for the CAM menu to open
46#define CAMMENURETRYTIMEOUT 3 // seconds after which opening the CAM menu is retried
47#define CAMRESPONSETIMEOUT 5 // seconds to wait for a response from a CAM
48#define PROGRESSTIMEOUT 100 // milliseconds to wait before updating the replay progress display
49#define MINFREEDISK 300 // minimum free disk space (in MB) required to start recording
50#define NODISKSPACEDELTA 300 // seconds between "Not enough disk space to start recording!" messages
51#define MAXCHNAMWIDTH 16 // maximum number of characters of channels' short names shown in schedules menus
52
53#define CHNUMWIDTH (numdigits(cChannels::MaxNumber()) + 1)
54#define CHNAMWIDTH (min(MAXCHNAMWIDTH, cChannels::MaxShortChannelNameLength() + 1))
55
56// --- cMenuEditCaItem -------------------------------------------------------
57
59protected:
60 virtual void Set(void);
61public:
62 cMenuEditCaItem(const char *Name, int *Value);
64 };
65
66cMenuEditCaItem::cMenuEditCaItem(const char *Name, int *Value)
67:cMenuEditIntItem(Name, Value, 0)
68{
69 Set();
70}
71
73{
74 if (*value == CA_FTA)
75 SetValue(tr("Free To Air"));
76 else if (*value >= CA_ENCRYPTED_MIN)
77 SetValue(tr("encrypted"));
78 else
80}
81
83{
85
86 if (state == osUnknown) {
87 if (NORMALKEY(Key) == kLeft && *value >= CA_ENCRYPTED_MIN)
88 *value = CA_FTA;
89 else
91 Set();
93 }
94 return state;
95}
96
97// --- cMenuEditSrcItem ------------------------------------------------------
98
100private:
102protected:
103 virtual void Set(void);
104public:
105 cMenuEditSrcItem(const char *Name, int *Value);
107 };
108
109cMenuEditSrcItem::cMenuEditSrcItem(const char *Name, int *Value)
110:cMenuEditIntItem(Name, Value, 0)
111{
112 source = Sources.Get(*Value);
113 Set();
114}
115
117{
118 if (source)
120 else
122}
123
125{
127
128 if (state == osUnknown) {
129 bool IsRepeat = Key & k_Repeat;
130 Key = NORMALKEY(Key);
131 if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
132 if (source) {
133 if (source->Prev())
134 source = (cSource *)source->Prev();
135 else if (!IsRepeat)
136 source = Sources.Last();
137 *value = source->Code();
138 }
139 }
140 else if (Key == kRight) {
141 if (source) {
142 if (source->Next())
143 source = (cSource *)source->Next();
144 else if (!IsRepeat)
145 source = Sources.First();
146 }
147 else
148 source = Sources.First();
149 if (source)
150 *value = source->Code();
151 }
152 else
153 return state; // we don't call cMenuEditIntItem::ProcessKey(Key) here since we don't accept numerical input
154 Set();
156 }
157 return state;
158}
159
160// --- cMenuEditChannel ------------------------------------------------------
161
163private:
168 char name[256];
169 void Setup(void);
170public:
171 cMenuEditChannel(cStateKey *ChannelsStateKey, cChannel *Channel, bool New = false);
172 cChannel *Channel(void) { return channel; }
173 virtual eOSState ProcessKey(eKeys Key);
174 };
175
176cMenuEditChannel::cMenuEditChannel(cStateKey *ChannelsStateKey, cChannel *Channel, bool New)
177:cOsdMenu(tr("Edit channel"), 16)
178{
180 channelsStateKey = ChannelsStateKey;
182 sourceParam = NULL;
183 *name = 0;
184 if (channel) {
185 data = *channel;
186 strn0cpy(name, data.name, sizeof(name));
187 if (New) {
188 channel = NULL;
189 // clear non-editable members:
190 data.nid = 0;
191 data.tid = 0;
192 data.rid = 0;
193 *data.shortName = 0;
194 *data.provider = 0;
195 *data.portalName = 0;
196 }
197 }
198 Setup();
199}
200
202{
203 int current = Current();
204
205 Clear();
206
207 // Parameters for all types of sources:
208 Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
209 Add(new cMenuEditSrcItem( tr("Source"), &data.source));
210 Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency));
211 Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF));
212 Add(new cMenuEditIntItem( tr("Ppid"), &data.ppid, 0, 0x1FFF));
213 Add(new cMenuEditIntItem( tr("Apid1"), &data.apids[0], 0, 0x1FFF));
214 Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 0, 0x1FFF));
215 Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF));
216 Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF));
217 Add(new cMenuEditIntItem( tr("Spid1"), &data.spids[0], 0, 0x1FFF));
218 Add(new cMenuEditIntItem( tr("Spid2"), &data.spids[1], 0, 0x1FFF));
219 Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
220 Add(new cMenuEditCaItem( tr("CA"), &data.caids[0]));
221 Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF));
222 Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
223 Add(new cMenuEditIntItem( tr("Tid"), &data.tid, 0));
224 /* XXX not yet used
225 Add(new cMenuEditIntItem( tr("Rid"), &data.rid, 0));
226 XXX*/
227 // Parameters for specific types of sources:
229 if (sourceParam) {
231 cOsdItem *Item;
232 while ((Item = sourceParam->GetOsdItem()) != NULL)
233 Add(Item);
234 }
235
237 Display();
238}
239
241{
242 int oldSource = data.source;
243 eOSState state = cOsdMenu::ProcessKey(Key);
244
245 if (state == osUnknown) {
246 if (Key == kOk) {
248 bool Modified = false;
249 if (sourceParam)
251 if (Channels->HasUniqueChannelID(&data, channel)) {
253 if (channel) {
254 *channel = data;
255 isyslog("edited channel %d %s", channel->Number(), *channel->ToText());
256 state = osBack;
257 }
258 else {
259 channel = new cChannel;
260 *channel = data;
261 Channels->Add(channel);
262 Channels->ReNumber();
263 isyslog("added channel %d %s", channel->Number(), *channel->ToText());
264 state = osUser1;
265 }
266 Channels->SetModifiedByUser();
267 Modified = true;
268 }
269 else {
270 Skins.Message(mtError, tr("Channel settings are not unique!"));
271 state = osContinue;
272 }
273 channelsStateKey->Remove(Modified);
274 }
275 }
276 if (Key != kNone && (data.source & cSource::st_Mask) != (oldSource & cSource::st_Mask)) {
278 if (sourceParam)
280 Setup();
281 }
282 return state;
283}
284
285// --- cMenuChannelItem ------------------------------------------------------
286
288public:
290private:
293public:
297 static eChannelSortMode SortMode(void) { return sortMode; }
298 virtual int Compare(const cListObject &ListObject) const;
299 virtual void Set(void);
300 const cChannel *Channel(void) { return channel; }
301 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
302 };
303
305
307{
309 if (channel->GroupSep())
310 SetSelectable(false);
311 Set();
312}
313
314int cMenuChannelItem::Compare(const cListObject &ListObject) const
315{
316 cMenuChannelItem *p = (cMenuChannelItem *)&ListObject;
317 int r = -1;
318 if (sortMode == csmProvider)
319 r = strcoll(channel->Provider(), p->channel->Provider());
320 if (sortMode == csmName || r == 0)
321 r = strcoll(channel->Name(), p->channel->Name());
322 if (sortMode == csmNumber || r == 0)
323 r = channel->Number() - p->channel->Number();
324 return r;
325}
326
328{
329 cString buffer;
330 if (!channel->GroupSep()) {
331 const char *X = *channel->Caids() >= CA_ENCRYPTED_MIN ? "X" : "";
332 const char *R = !channel->Vpid() && (*channel->Apids() || *channel->Dpids()) ? "R" : "";
333 if (sortMode == csmProvider)
334 buffer = cString::sprintf("%d\t%s%s\t%s - %s", channel->Number(), X, R, channel->Provider(), channel->Name());
335 else
336 buffer = cString::sprintf("%d\t%s%s\t%s", channel->Number(), X, R, channel->Name());
337 }
338 else
339 buffer = cString::sprintf("\t\t%s", channel->Name());
340 SetText(buffer);
341}
342
343void cMenuChannelItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
344{
345 if (!DisplayMenu->SetItemChannel(channel, Index, Current, Selectable, sortMode == csmProvider))
346 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
347}
348
349// --- cMenuChannels ---------------------------------------------------------
350
351#define CHANNELNUMBERTIMEOUT 1000 //ms
352
353class cMenuChannels : public cOsdMenu {
354private:
358 void Set(bool Force = false);
359 cChannel *GetChannel(int Index);
360 void Propagate(cChannels *Channels);
361protected:
362 eOSState Number(eKeys Key);
363 eOSState Switch(void);
364 eOSState Edit(void);
365 eOSState New(void);
366 eOSState Delete(void);
367 virtual void Move(int From, int To);
368public:
369 cMenuChannels(void);
371 virtual eOSState ProcessKey(eKeys Key);
372 };
373
375:cOsdMenu(tr("Channels"), CHNUMWIDTH, 3)
376{
378 number = 0;
379 Set();
380}
381
383{
384}
385
386void cMenuChannels::Set(bool Force)
387{
388 if (Force)
391 const cChannel *CurrentChannel = GetChannel(Current());
392 if (!CurrentChannel)
393 CurrentChannel = Channels->GetByNumber(cDevice::CurrentChannel());
394 cMenuChannelItem *CurrentItem = NULL;
395 Clear();
396 for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
397 if (!Channel->GroupSep() || cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber && *Channel->Name()) {
398 cMenuChannelItem *Item = new cMenuChannelItem(Channel);
399 Add(Item);
400 if (Channel == CurrentChannel)
401 CurrentItem = Item;
402 }
403 }
406 msmNumber);
408 Sort();
409 SetCurrent(CurrentItem);
410 SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), tr("Button$Mark"));
411 Display();
413 }
414}
415
417{
419 return p ? (cChannel *)p->Channel() : NULL;
420}
421
423{
424 Channels->ReNumber();
425 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
426 ci->Set();
427 Display();
428 Channels->SetModifiedByUser();
429}
430
432{
433 if (HasSubMenu())
434 return osContinue;
435 if (numberTimer.TimedOut())
436 number = 0;
437 if (!number && Key == k0) {
439 Set(true);
440 }
441 else {
443 number = number * 10 + Key - k0;
444 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
445 if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {
446 SetCurrent(ci);
447 Display();
448 break;
449 }
450 }
452 }
453 return osContinue;
454}
455
457{
458 if (HasSubMenu())
459 return osContinue;
461 cChannel *ch = GetChannel(Current());
462 if (ch)
464 return osEnd;
465}
466
468{
469 if (HasSubMenu() || Count() == 0)
470 return osContinue;
472 cChannel *ch = GetChannel(Current());
473 if (ch)
475 return osContinue;
476}
477
479{
480 if (HasSubMenu())
481 return osContinue;
484}
485
487{
488 if (!HasSubMenu() && Count() > 0) {
489 LOCK_TIMERS_READ; // must lock timers before channels!
491 int Index = Current();
492 cChannel *Channel = GetChannel(Current());
493 if (!Channels->Contains(Channel)) {
495 channelsStateKey.Reset(); // makes sure the menu is refreshed
496 return osContinue;
497 }
498 bool Deleted = false;
499 int CurrentChannelNr = cDevice::CurrentChannel();
500 cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr);
501 int DeletedChannel = Channel->Number();
502 // Check if there is a timer using this channel:
503 if (Timers->UsesChannel(Channel)) {
505 Skins.Message(mtError, tr("Channel is being used by a timer!"));
506 return osContinue;
507 }
508 if (Interface->Confirm(tr("Delete channel?"))) {
509 if (CurrentChannel && Channel == CurrentChannel) {
510 int n = Channels->GetNextNormal(CurrentChannel->Index());
511 if (n < 0)
512 n = Channels->GetPrevNormal(CurrentChannel->Index());
513 CurrentChannel = Channels->Get(n);
514 CurrentChannelNr = 0; // triggers channel switch below
515 }
516 Channels->Del(Channel);
517 cOsdMenu::Del(Index);
518 Propagate(Channels);
519 isyslog("channel %d deleted", DeletedChannel);
520 Deleted = true;
521 if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
522 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
523 Channels->SwitchTo(CurrentChannel->Number());
524 else
525 cDevice::SetCurrentChannel(CurrentChannel->Number());
526 }
527 }
528 channelsStateKey.Remove(Deleted);
529 }
530 return osContinue;
531}
532
533void cMenuChannels::Move(int From, int To)
534{
536 int CurrentChannelNr = cDevice::CurrentChannel();
537 cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr);
538 cChannel *FromChannel = GetChannel(From);
539 cChannel *ToChannel = GetChannel(To);
540 if (FromChannel && ToChannel) {
541 int FromNumber = FromChannel->Number();
542 int ToNumber = ToChannel->Number();
543 if (Channels->MoveNeedsDecrement(FromChannel, ToChannel)) {
544 ToChannel = Channels->Prev(ToChannel); // cListBase::Move() doesn't know about the channel list's numbered groups!
545 To--;
546 }
547 Channels->Move(FromChannel, ToChannel);
548 cOsdMenu::Move(From, To);
549 SetCurrent(Get(To));
550 Propagate(Channels);
551 isyslog("channel %d moved to %d", FromNumber, ToNumber);
552 if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
553 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
554 Channels->SwitchTo(CurrentChannel->Number());
555 else
556 cDevice::SetCurrentChannel(CurrentChannel->Number());
557 }
558 }
560 }
561}
562
564{
565 if (!HasSubMenu())
566 Set(); // react on any changes to the channels list
567 eOSState state = cOsdMenu::ProcessKey(Key);
568
569 switch (state) {
570 case osUser1: {
571 if (cMenuEditChannel *MenuEditChannel = dynamic_cast<cMenuEditChannel *>(SubMenu())) {
572 if (cChannel *Channel = MenuEditChannel->Channel()) {
574 Add(new cMenuChannelItem(Channel), true);
575 return CloseSubMenu();
576 }
577 }
578 }
579 break;
580 default:
581 if (state == osUnknown) {
582 switch (int(Key)) {
583 case k0 ... k9:
584 return Number(Key);
585 case kOk: return Switch();
586 case kRed: return Edit();
587 case kGreen: return New();
588 case kYellow: return Delete();
589 case kBlue: if (!HasSubMenu())
590 Mark();
591 break;
592 case kChanUp|k_Repeat:
593 case kChanUp:
594 case kChanDn|k_Repeat:
595 case kChanDn: {
597 int CurrentChannelNr = cDevice::CurrentChannel();
598 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
599 if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == CurrentChannelNr) {
600 SetCurrent(ci);
601 Display();
602 break;
603 }
604 }
605 }
606 default: break;
607 }
608 }
609 }
610 return state;
611}
612
613// --- cMenuText -------------------------------------------------------------
614
615cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font)
616:cOsdMenu(Title)
617{
619 text = NULL;
620 font = Font;
621 SetText(Text);
622}
623
625{
626 free(text);
627}
628
629void cMenuText::SetText(const char *Text)
630{
631 free(text);
632 text = Text ? strdup(Text) : NULL;
633}
634
636{
638 DisplayMenu()->SetText(text, font == fontFix); //XXX define control character in text to choose the font???
639 if (text)
641}
642
644{
645 switch (int(Key)) {
646 case kUp|k_Repeat:
647 case kUp:
648 case kDown|k_Repeat:
649 case kDown:
650 case kLeft|k_Repeat:
651 case kLeft:
652 case kRight|k_Repeat:
653 case kRight:
654 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
655 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
656 return osContinue;
657 default: break;
658 }
659
660 eOSState state = cOsdMenu::ProcessKey(Key);
661
662 if (state == osUnknown) {
663 switch (Key) {
664 case kOk: return osBack;
665 default: state = osContinue;
666 }
667 }
668 return state;
669}
670
671// --- cMenuFolderItem -------------------------------------------------------
672
673class cMenuFolderItem : public cOsdItem {
674private:
676public:
677 virtual void Set(void);
679 cNestedItem *Folder(void) { return folder; }
680 };
681
683:cOsdItem(Folder->Text())
684{
685 folder = Folder;
686 Set();
687}
688
690{
691 if (folder->SubItems() && folder->SubItems()->Count())
692 SetText(cString::sprintf("%s...", folder->Text()));
693 else
694 SetText(folder->Text());
695}
696
697// --- cMenuEditFolder -------------------------------------------------------
698
699class cMenuEditFolder : public cOsdMenu {
700private:
703 char name[PATH_MAX];
704 eOSState Confirm(void);
705public:
706 cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder = NULL);
707 cString GetFolder(void);
708 virtual eOSState ProcessKey(eKeys Key);
709 };
710
712:cOsdMenu(Folder ? tr("Edit folder") : tr("New folder"), 12)
713{
715 list = List;
716 folder = Folder;
717 if (folder)
718 strn0cpy(name, folder->Text(), sizeof(name));
719 else {
720 *name = 0;
721 cRemote::Put(kRight, true); // go right into string editing mode
722 }
723 if (!isempty(Dir)) {
724 cOsdItem *DirItem = new cOsdItem(Dir);
725 DirItem->SetSelectable(false);
726 Add(DirItem);
727 }
728 Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
729}
730
732{
733 return folder ? folder->Text() : "";
734}
735
737{
738 if (!folder || strcmp(folder->Text(), name) != 0) {
739 // each name may occur only once in a folder list
740 for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
741 if (strcmp(Folder->Text(), name) == 0) {
742 Skins.Message(mtError, tr("Folder name already exists!"));
743 return osContinue;
744 }
745 }
746 char *p = strpbrk(name, "\\{}#~"); // FOLDERDELIMCHAR
747 if (p) {
748 Skins.Message(mtError, cString::sprintf(tr("Folder name must not contain '%c'!"), *p));
749 return osContinue;
750 }
751 }
752 if (folder)
754 else
755 list->Add(folder = new cNestedItem(name));
756 return osEnd;
757}
758
760{
761 eOSState state = cOsdMenu::ProcessKey(Key);
762
763 if (state == osUnknown) {
764 switch (Key) {
765 case kOk: return Confirm();
766 case kRed:
767 case kGreen:
768 case kYellow:
769 case kBlue: return osContinue;
770 default: break;
771 }
772 }
773 return state;
774}
775
776// --- cMenuFolder -----------------------------------------------------------
777
778cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
779:cOsdMenu(Title)
780{
782 list = nestedItemList = NestedItemList;
783 firstFolder = NULL;
784 editing = false;
785 helpKeys = -1;
786 Set();
787 DescendPath(Path);
788 Display();
789 SetHelpKeys();
790}
791
792cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
793:cOsdMenu(Title)
794{
796 list = List;
797 nestedItemList = NestedItemList;
798 dir = Dir;
799 firstFolder = NULL;
800 editing = false;
801 helpKeys = -1;
802 Set();
803 DescendPath(Path);
804 Display();
805 SetHelpKeys();
806}
807
809{
810 if (HasSubMenu())
811 return;
812 int NewHelpKeys = 0;
813 if (firstFolder)
814 NewHelpKeys = 1;
815 if (NewHelpKeys != helpKeys) {
816 helpKeys = NewHelpKeys;
817 SetHelp(NewHelpKeys > 0 ? tr("Button$Open") : NULL, tr("Button$New"), firstFolder ? tr("Button$Delete") : NULL, firstFolder ? tr("Button$Edit") : NULL);
818 }
819}
820
821#define FOLDERDELIMCHARSUBST 0x01
822static void AddRecordingFolders(const cRecordings *Recordings, cList<cNestedItem> *List, char *Path)
823{
824 if (Path) {
825 char *p = strchr(Path, FOLDERDELIMCHARSUBST);
826 if (p)
827 *p++ = 0;
828 cNestedItem *Folder;
829 for (Folder = List->First(); Folder; Folder = List->Next(Folder)) {
830 if (strcmp(Path, Folder->Text()) == 0)
831 break;
832 }
833 if (!Folder)
834 List->Add(Folder = new cNestedItem(Path));
835 if (p) {
836 Folder->SetSubItems(true);
837 AddRecordingFolders(Recordings, Folder->SubItems(), p);
838 }
839 }
840 else {
841 cStringList Dirs;
842 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
843 cString Folder = Recording->Folder();
844 strreplace((char *)*Folder, FOLDERDELIMCHAR, FOLDERDELIMCHARSUBST); // makes sure parent folders come before subfolders
845 if (Dirs.Find(Folder) < 0)
846 Dirs.Append(strdup(Folder));
847 }
848 Dirs.Sort();
849 for (int i = 0; i < Dirs.Size(); i++) {
850 if (char *s = Dirs[i])
851 AddRecordingFolders(Recordings, &Folders, s);
852 }
853 }
854}
855
856void cMenuFolder::Set(const char *CurrentFolder)
857{
858 static cStateKey RecordingsStateKey;
859 if (list == &Folders) {
860 if (const cRecordings *Recordings = cRecordings::GetRecordingsRead(RecordingsStateKey)) {
861 AddRecordingFolders(Recordings, &Folders, NULL);
862 RecordingsStateKey.Remove();
863 }
864 }
865 firstFolder = NULL;
866 Clear();
867 if (!isempty(dir)) {
868 cOsdItem *DirItem = new cOsdItem(dir);
869 DirItem->SetSelectable(false);
870 Add(DirItem);
871 }
872 list->Sort();
873 for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
874 cOsdItem *FolderItem = new cMenuFolderItem(Folder);
875 Add(FolderItem, CurrentFolder ? strcmp(Folder->Text(), CurrentFolder) == 0 : false);
876 if (!firstFolder)
877 firstFolder = FolderItem;
878 }
879}
880
881void cMenuFolder::DescendPath(const char *Path)
882{
883 if (Path) {
884 const char *p = strchr(Path, FOLDERDELIMCHAR);
885 if (p) {
886 for (cMenuFolderItem *Folder = (cMenuFolderItem *)firstFolder; Folder; Folder = (cMenuFolderItem *)Next(Folder)) {
887 if (strncmp(Folder->Folder()->Text(), Path, p - Path) == 0) {
888 SetCurrent(Folder);
889 if (Folder->Folder()->SubItems() && strchr(p + 1, FOLDERDELIMCHAR))
890 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));
891 break;
892 }
893 }
894 }
895 }
896}
897
899{
900 if (firstFolder) {
902 if (Folder) {
903 if (Open) {
904 Folder->Folder()->SetSubItems(true);
905 return AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text()));
906 }
907 else
908 return osEnd;
909 }
910 }
911 return osContinue;
912}
913
915{
916 editing = true;
917 return AddSubMenu(new cMenuEditFolder(dir, list));
918}
919
921{
922 if (!HasSubMenu() && firstFolder) {
924 if (Folder && Interface->Confirm(Folder->Folder()->SubItems() ? tr("Delete folder and all sub folders?") : tr("Delete folder?"))) {
925 list->Del(Folder->Folder());
926 Del(Folder->Index());
927 firstFolder = Get(isempty(dir) ? 0 : 1);
928 Display();
929 SetHelpKeys();
931 }
932 }
933 return osContinue;
934}
935
937{
938 if (!HasSubMenu() && firstFolder) {
940 if (Folder) {
941 editing = true;
942 return AddSubMenu(new cMenuEditFolder(dir, list, Folder->Folder()));
943 }
944 }
945 return osContinue;
946}
947
949{
950 if (cMenuEditFolder *mef = dynamic_cast<cMenuEditFolder *>(SubMenu())) {
951 Set(mef->GetFolder());
952 SetHelpKeys();
953 Display();
955 }
956 return CloseSubMenu();
957}
958
960{
961 if (firstFolder) {
963 if (Folder) {
964 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu()))
965 return cString::sprintf("%s%c%s", Folder->Folder()->Text(), FOLDERDELIMCHAR, *mf->GetFolder());
966 return Folder->Folder()->Text();
967 }
968 }
969 return "";
970}
971
973{
974 if (!HasSubMenu())
975 editing = false;
976 eOSState state = cOsdMenu::ProcessKey(Key);
977
978 if (state == osUnknown) {
979 switch (Key) {
980 case kOk: return Select(false);
981 case kRed: return Select(true);
982 case kGreen: return New();
983 case kYellow: return Delete();
984 case kBlue: return Edit();
985 default: state = osContinue;
986 }
987 }
988 else if (state == osEnd && HasSubMenu() && editing)
989 state = SetFolder();
990 SetHelpKeys();
991 return state;
992}
993
994// --- cMenuEditTimer --------------------------------------------------------
995
996static const char *TimerFileMacrosForPattern[] = {
1002 "",
1003 NULL
1004 };
1005
1006static const char *TimerFileMacros[] = {
1009 "",
1010 NULL
1011 };
1012
1014
1016:cOsdMenu(tr("Edit timer"), 12)
1017{
1019 addedTimer = NULL;
1020 pattern = NULL;
1021 file = NULL;
1022 day = firstday = NULL;
1023 timer = Timer;
1024 addIfConfirmed = New;
1025 if (timer) {
1026 data = *timer;
1027 if (New)
1029 channel = data.Channel()->Number();
1030 Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive));
1031 Add(new cMenuEditChanItem(tr("Channel"), &channel));
1032 Add(day = new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays));
1033 Add(new cMenuEditTimeItem(tr("Start"), &data.start));
1034 Add(new cMenuEditTimeItem(tr("Stop"), &data.stop));
1035 Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
1036 Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
1037 Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
1038 Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
1040 SetPatternItem(true);
1041 if (data.remote)
1042 strn0cpy(remote, data.remote, sizeof(remote));
1043 else
1044 *remote = 0;
1046 svdrpServerNames.Sort(true);
1047 svdrpServerNames.Insert(strdup(""));
1048 Add(new cMenuEditStrlItem(tr("Record on"), remote, sizeof(remote), &svdrpServerNames));
1049 }
1050 }
1051 SetHelpKeys();
1052}
1053
1055{
1056 if (timer && addIfConfirmed)
1057 delete timer; // apparently it wasn't confirmed
1058}
1059
1061{
1062 const cTimer *Timer = addedTimer;
1063 addedTimer = NULL;
1064 return Timer;
1065}
1066
1068{
1069 SetHelp(tr("Button$Folder"), data.weekdays ? tr("Button$Single") : tr("Button$Repeating"), *data.pattern ? tr("Button$Regular") : tr("Button$Pattern"));
1070}
1071
1073{
1074 if (!firstday && !data.IsSingleEvent()) {
1075 Add(firstday = new cMenuEditDateItem(tr("First day"), &data.day));
1076 Display();
1077 }
1078 else if (firstday && data.IsSingleEvent()) {
1079 Del(firstday->Index());
1080 firstday = NULL;
1081 Display();
1082 }
1083}
1084
1086{
1087 if (Initial && !*data.pattern) {
1089 return;
1090 }
1091 if (!pattern) {
1092 if (data.HasFlags(tfRecording)) {
1093 Skins.Message(mtWarning, tr("Timer is recording!"));
1094 return;
1095 }
1096 if (!*data.pattern) {
1097 char *p = strgetlast(data.file, FOLDERDELIMCHAR);
1098 strn0cpy(data.pattern, p, sizeof(data.pattern));
1099 }
1100 Ins(pattern = new cMenuEditStrItem( tr("Pattern"), data.pattern, sizeof(data.pattern)), true, file);
1103 Display();
1104 }
1105 else {
1106 Del(pattern->Index());
1107 pattern = NULL;
1108 *data.pattern = 0;
1110 Display();
1111 }
1112 SetHelpKeys();
1113}
1114
1116{
1117 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
1118 cString Folder = mf->GetFolder();
1119 char *p = strgetlast(data.file, FOLDERDELIMCHAR);
1120 if (!isempty(*Folder))
1121 strn0cpy(data.file, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(data.file));
1122 else if (p != data.file)
1123 memmove(data.file, p, strlen(p) + 1);
1125 Display();
1126 }
1127 return CloseSubMenu();
1128}
1129
1130static bool RemoteTimerError(const cTimer *Timer)
1131{
1132 Skins.Message(mtError, cString::sprintf("%s %d@%s!", tr("Error while accessing remote timer"), Timer->Id(), Timer->Remote()));
1133 return false; // convenience return code
1134}
1135
1136static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer = NULL)
1137{
1138 cString ErrorMessage;
1139 if (!HandleRemoteTimerModifications(NewTimer, OldTimer, &ErrorMessage)) {
1140 Skins.QueueMessage(mtError, ErrorMessage);
1141 return false;
1142 }
1143 return true;
1144}
1145
1147{
1148 eOSState state = cOsdMenu::ProcessKey(Key);
1149
1150 if (state == osUnknown) {
1151 switch (Key) {
1152 case kOk: if (timer) {
1154 if (!addIfConfirmed && !Timers->Contains(timer)) {
1155 if (cTimer *t = Timers->GetById(timer->Id(), timer->Remote()))
1156 timer = t;
1157 else {
1158 Skins.Message(mtWarning, tr("Timer has been deleted!"));
1159 break;
1160 }
1161 }
1163 if (const cChannel *Channel = Channels->GetByNumber(channel))
1164 data.channel = Channel;
1165 else {
1166 Skins.Message(mtError, tr("*** Invalid Channel ***"));
1167 break;
1168 }
1169 if (!*data.file)
1170 strcpy(data.file, data.Channel()->ShortName(true));
1171 data.SetRemote(*remote ? remote : NULL);
1172 if (addIfConfirmed) {
1173 *timer = data;
1174 Timers->Add(timer);
1175 addedTimer = timer;
1177 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
1178 Timers->Del(timer, false);
1179 addedTimer = NULL;
1180 return osContinue;
1181 }
1182 }
1183 else {
1185 return osContinue;
1186 if (timer->Local() && timer->Recording() && data.Remote())
1188 if (timer->Remote() && data.Remote())
1189 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
1191 data.SetEvent(NULL);
1192 *timer = data;
1193 }
1196 timer->SetEventFromSchedule(Schedules);
1197 timer->Matches();
1198 addIfConfirmed = false;
1199 }
1200 return osBack;
1201 case kRed: return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, data.file));
1202 case kGreen: if (day) {
1204 SetCurrent(day);
1206 SetHelpKeys();
1207 Display();
1208 }
1209 return osContinue;
1210 case kYellow: SetPatternItem();
1211 return osContinue;
1212 case kBlue: return osContinue;
1213 default: break;
1214 }
1215 }
1216 else if (state == osEnd && HasSubMenu())
1217 state = SetFolder();
1218 if (Key != kNone)
1220 return state;
1221}
1222
1223// --- cMenuTimerItem --------------------------------------------------------
1224
1225class cMenuTimerItem : public cOsdItem {
1226private:
1228public:
1229 cMenuTimerItem(const cTimer *Timer);
1230 virtual int Compare(const cListObject &ListObject) const;
1231 virtual void Set(void);
1232 const cTimer *Timer(void) { return timer; }
1233 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
1234 };
1235
1237{
1238 timer = Timer;
1239 Set();
1240}
1241
1242int cMenuTimerItem::Compare(const cListObject &ListObject) const
1243{
1244 return timer->Compare(*((cMenuTimerItem *)&ListObject)->timer);
1245}
1246
1248{
1249 cString day, name("");
1250 if (timer->WeekDays())
1251 day = timer->PrintDay(0, timer->WeekDays(), false);
1252 else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
1253 day = itoa(timer->GetMDay(timer->Day()));
1254 name = WeekDayName(timer->Day());
1255 }
1256 else {
1257 struct tm tm_r;
1258 time_t Day = timer->Day();
1259 localtime_r(&Day, &tm_r);
1260 char buffer[16];
1261 strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
1262 day = buffer;
1263 }
1264 const char *File = timer->Pattern();
1265 if (!*File) {
1266 if (timer->HasFlags(tfSpawned) && timer->Event() && timer->Event()->Title())
1267 File = timer->Event()->Title();
1268 else {
1269 File = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
1270 if (File && strcmp(File + 1, TIMERMACRO_TITLE) && strcmp(File + 1, TIMERMACRO_EPISODE))
1271 File++;
1272 else
1273 File = timer->File();
1274 }
1275 }
1276 SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s%s%s%s",
1277 !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
1278 timer->Channel()->Number(),
1279 *name,
1280 *name && **name ? " " : "",
1281 *day,
1282 timer->Start() / 100,
1283 timer->Start() % 100,
1284 timer->Stop() / 100,
1285 timer->Stop() % 100,
1286 timer->Remote() ? *cString::sprintf("@%s: ", timer->Remote()) : "",
1287 timer->IsPatternTimer() ? "{" : "",
1288 File,
1289 timer->IsPatternTimer() ? "}" : ""));
1290}
1291
1292void cMenuTimerItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1293{
1294 if (!DisplayMenu->SetItemTimer(timer, Index, Current, Selectable))
1295 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1296}
1297
1298// --- cMenuTimers -----------------------------------------------------------
1299
1300class cMenuTimers : public cOsdMenu {
1301private:
1304 void Set(void);
1305 eOSState Edit(void);
1306 eOSState New(void);
1307 eOSState Delete(void);
1308 eOSState OnOff(void);
1309 eOSState Info(void);
1310 cTimer *GetTimer(void);
1311 void SetHelpKeys(void);
1312public:
1313 cMenuTimers(void);
1314 virtual ~cMenuTimers();
1315 virtual eOSState ProcessKey(eKeys Key);
1316 };
1317
1319:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
1320{
1322 helpKeys = -1;
1323 cMenuEditTimer::AddedTimer(); // to clear any leftovers
1324 Set();
1325}
1326
1328{
1329}
1330
1332{
1333 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
1334 const cTimer *CurrentTimer = GetTimer();
1335 cMenuTimerItem *CurrentItem = NULL;
1336 Clear();
1337 for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
1338 cMenuTimerItem *Item = new cMenuTimerItem(Timer);
1339 Add(Item);
1340 if (CurrentTimer && Timer->Id() == CurrentTimer->Id() && (!Timer->Remote() && !CurrentTimer->Remote() || Timer->Remote() && CurrentTimer->Remote() && strcmp(Timer->Remote(), CurrentTimer->Remote()) == 0))
1341 CurrentItem = Item;
1342 }
1343 Sort();
1344 SetCurrent(CurrentItem ? CurrentItem : First());
1345 SetHelpKeys();
1346 Display();
1348 }
1349}
1350
1352{
1354 return item ? (cTimer *)item->Timer() : NULL;
1355}
1356
1358{
1359 int NewHelpKeys = 0;
1360 if (const cTimer *Timer = GetTimer()) {
1361 if (Timer->Event())
1362 NewHelpKeys = 2;
1363 else
1364 NewHelpKeys = 1;
1365 }
1366 if (NewHelpKeys != helpKeys) {
1367 helpKeys = NewHelpKeys;
1368 SetHelp(helpKeys > 0 ? tr("Button$On/Off") : NULL, tr("Button$New"), helpKeys > 0 ? tr("Button$Delete") : NULL, helpKeys == 2 ? tr("Button$Info") : NULL);
1369 }
1370}
1371
1373{
1374 if (HasSubMenu())
1375 return osContinue;
1376 cStateKey StateKey;
1377 cTimers *Timers = cTimers::GetTimersWrite(StateKey);
1378 cTimer *Timer = GetTimer();
1379 if (Timer) {
1380 Timer->OnOff();
1381 if (Timer->Remote()) {
1383 cStringList Response;
1384 if (!ExecSVDRPCommand(Timer->Remote(), cString::sprintf("MODT %d %s", Timer->Id(), *Timer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250)
1385 RemoteTimerError(Timer);
1386 }
1387 {
1389 Timer->SetEventFromSchedule(Schedules);
1390 }
1392 DisplayCurrent(true);
1393 if (Timer->FirstDay())
1394 isyslog("set first day of timer %s to %s", *Timer->ToDescr(), *Timer->PrintFirstDay());
1395 else
1396 isyslog("%sactivated timer %s", Timer->HasFlags(tfActive) ? "" : "de", *Timer->ToDescr());
1397 }
1398 StateKey.Remove(Timer != NULL);
1399 return osContinue;
1400}
1401
1403{
1404 if (HasSubMenu() || Count() == 0)
1405 return osContinue;
1406 return AddSubMenu(new cMenuEditTimer(GetTimer()));
1407}
1408
1410{
1411 if (HasSubMenu())
1412 return osContinue;
1413 cTimer *Timer = new cTimer;
1416 return AddSubMenu(new cMenuEditTimer(Timer, true));
1417}
1418
1420{
1422 // Check if this timer is active:
1423 cTimer *Timer = GetTimer();
1424 if (Timer) {
1425 bool TimerRecording = Timer->Recording();
1426 timersStateKey.Remove(false); // must release lock while prompting!
1427 if (Interface->Confirm(tr("Delete timer?")) && (!TimerRecording || Interface->Confirm(tr("Timer still recording - really delete?")))) {
1429 Timer = GetTimer();
1430 if (Timer) {
1431 if (!Timer->Remote()) {
1432 Timer->Skip();
1433 cRecordControls::Process(Timers, time(NULL));
1434 }
1435 if (HandleRemoteModifications(NULL, Timer)) {
1436 if (Timer->Remote())
1438 Timers->Del(Timer);
1440 Display();
1441 }
1442 }
1443 }
1444 else
1445 return osContinue;
1446 }
1447 timersStateKey.Remove(Timer != NULL);
1448 return osContinue;
1449}
1450
1452{
1453 if (HasSubMenu() || Count() == 0)
1454 return osContinue;
1457 cTimer *Timer = GetTimer();
1458 if (Timer && Timer->Event())
1459 return AddSubMenu(new cMenuEvent(Timers, Channels, Timer->Event()));
1460 return osContinue;
1461}
1462
1464{
1465 if (!HasSubMenu())
1466 Set();
1467 eOSState state = cOsdMenu::ProcessKey(Key);
1468 if (state == osUnknown) {
1469 switch (Key) {
1470 case kOk: return Edit();
1471 case kRed: state = OnOff(); break; // must go through SetHelpKeys()!
1472 case kGreen: return New();
1473 case kYellow: state = Delete(); break;
1474 case kInfo:
1475 case kBlue: return Info();
1476 break;
1477 default: break;
1478 }
1479 }
1480 if (const cTimer *Timer = cMenuEditTimer::AddedTimer()) {
1481 // a newly created timer was confirmed with Ok and the proper item needs to be added:
1483 cMenuTimerItem *CurrentItem = new cMenuTimerItem(Timer);
1484 Add(CurrentItem, true);
1485 Sort();
1486 SetCurrent(CurrentItem);
1487 SetHelpKeys();
1488 Display();
1489 }
1490 if (Key != kNone)
1491 SetHelpKeys();
1492 return state;
1493}
1494
1495// --- cMenuEvent ------------------------------------------------------------
1496
1497cMenuEvent::cMenuEvent(const cTimers *Timers, const cChannels *Channels, const cEvent *Event, bool CanSwitch, bool Buttons)
1498:cOsdMenu(tr("Event"))
1499{
1501 event = Event;
1502 if (event) {
1503 if (const cChannel *Channel = Channels->GetByChannelID(event->ChannelID(), true)) {
1504 SetTitle(Channel->Name());
1505 if (Buttons) {
1506 eTimerMatch TimerMatch = tmNone;
1507 Timers->GetMatch(event, &TimerMatch);
1508 SetHelp(TimerMatch == tmFull ? tr("Button$Timer") : tr("Button$Record"), NULL, NULL, CanSwitch ? tr("Button$Switch") : NULL);
1509 }
1510 }
1511 }
1512}
1513
1515{
1518 if (event->Description())
1520}
1521
1523{
1524 switch (int(Key)) {
1525 case kUp|k_Repeat:
1526 case kUp:
1527 case kDown|k_Repeat:
1528 case kDown:
1529 case kLeft|k_Repeat:
1530 case kLeft:
1531 case kRight|k_Repeat:
1532 case kRight:
1533 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
1534 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
1535 return osContinue;
1536 case kInfo: return osBack;
1537 default: break;
1538 }
1539
1540 eOSState state = cOsdMenu::ProcessKey(Key);
1541
1542 if (state == osUnknown) {
1543 switch (Key) {
1544 case kGreen:
1545 case kYellow: return osContinue;
1546 case kOk: return osBack;
1547 default: break;
1548 }
1549 }
1550 return state;
1551}
1552
1553// --- cMenuScheduleItem -----------------------------------------------------
1554
1556public:
1557 enum eScheduleSortMode { ssmAllThis, ssmThisThis, ssmThisAll, ssmAllAll }; // "which event(s) on which channel(s)"
1558private:
1560public:
1566 cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel = NULL, bool WithDate = false);
1569 static eScheduleSortMode SortMode(void) { return sortMode; }
1570 virtual int Compare(const cListObject &ListObject) const;
1571 bool Update(const cTimers *Timers, bool Force = false);
1572 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
1573 };
1574
1576
1577cMenuScheduleItem::cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel, bool WithDate)
1578{
1579 event = Event;
1580 channel = Channel;
1581 withDate = WithDate;
1583 timerActive = false;
1584 Update(Timers, true);
1585}
1586
1587int cMenuScheduleItem::Compare(const cListObject &ListObject) const
1588{
1589 cMenuScheduleItem *p = (cMenuScheduleItem *)&ListObject;
1590 int r = -1;
1591 if (sortMode != ssmAllThis)
1592 r = strcoll(event->Title(), p->event->Title());
1593 if (sortMode == ssmAllThis || r == 0)
1594 r = event->StartTime() - p->event->StartTime();
1595 return r;
1596}
1597
1598static const char *TimerMatchChars = " tT iI";
1599
1600bool cMenuScheduleItem::Update(const cTimers *Timers, bool Force)
1601{
1602 eTimerMatch OldTimerMatch = timerMatch;
1603 bool OldTimerActive = timerActive;
1604 const cTimer *Timer = Timers->GetMatch(event, &timerMatch);
1605 if (event->EndTime() < time(NULL) && !event->IsRunning() && (!Timer || !Timer->Recording()))
1607 timerActive = Timer && Timer->HasFlags(tfActive);
1608 if (Force || timerMatch != OldTimerMatch || timerActive != OldTimerActive) {
1609 cString buffer;
1610 char t = TimerMatchChars[timerMatch + (timerActive ? 0 : 3)];
1611 char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
1612 char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
1613 const char *csn = channel ? channel->ShortName(true) : NULL;
1614 cString eds = event->GetDateString();
1615 if (channel && withDate)
1616 buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 999), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
1617 else if (channel)
1618 buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 999), csn, *event->GetTimeString(), t, v, r, event->Title());
1619 else
1620 buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
1621 SetText(buffer);
1622 return true;
1623 }
1624 return false;
1625}
1626
1627void cMenuScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1628{
1629 if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch, timerActive))
1630 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1631}
1632
1633// --- cMenuWhatsOn ----------------------------------------------------------
1634
1635class cMenuWhatsOn : public cOsdMenu {
1636private:
1637 bool now;
1641 eOSState Record(void);
1642 eOSState Switch(void);
1643 static int currentChannel;
1644 static const cEvent *scheduleEvent;
1645 bool Update(void);
1646 void SetHelpKeys(const cChannels *Channels);
1647public:
1648 cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr);
1649 static int CurrentChannel(void) { return currentChannel; }
1650 static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
1651 static const cEvent *ScheduleEvent(void);
1652 virtual eOSState ProcessKey(eKeys Key);
1653 };
1654
1657
1658cMenuWhatsOn::cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr)
1659:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, CHNAMWIDTH, 6, 4)
1660{
1662 now = Now;
1663 canSwitch = false;
1664 helpKeys = 0;
1665 for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1666 if (!Channel->GroupSep()) {
1667 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1668 if (const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent())
1669 Add(new cMenuScheduleItem(Timers, Event, Channel), Channel->Number() == CurrentChannelNr);
1670 }
1671 }
1672 }
1673 currentChannel = CurrentChannelNr;
1674 Display();
1675 SetHelpKeys(Channels);
1676}
1677
1679{
1680 bool result = false;
1681 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
1682 for (cOsdItem *item = First(); item; item = Next(item)) {
1683 if (((cMenuScheduleItem *)item)->Update(Timers))
1684 result = true;
1685 }
1687 }
1688 return result;
1689}
1690
1692{
1694 canSwitch = false;
1695 int NewHelpKeys = 0;
1696 if (item) {
1697 if (item->timerMatch == tmFull)
1698 NewHelpKeys |= 0x02; // "Timer"
1699 else
1700 NewHelpKeys |= 0x01; // "Record"
1701 if (now)
1702 NewHelpKeys |= 0x04; // "Next"
1703 else
1704 NewHelpKeys |= 0x08; // "Now"
1705 if (const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) {
1706 if (Channel->Number() != cDevice::CurrentChannel()) {
1707 NewHelpKeys |= 0x10; // "Switch"
1708 canSwitch = true;
1709 }
1710 }
1711 }
1712 if (NewHelpKeys != helpKeys) {
1713 const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
1714 SetHelp(Red[NewHelpKeys & 0x03], now ? tr("Button$Next") : tr("Button$Now"), tr("Button$Schedule"), canSwitch ? tr("Button$Switch") : NULL);
1715 helpKeys = NewHelpKeys;
1716 }
1717}
1718
1720{
1721 const cEvent *ei = scheduleEvent;
1722 scheduleEvent = NULL;
1723 return ei;
1724}
1725
1727{
1729 if (item) {
1731 const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true);
1732 if (Channel) {
1733 if (!cDevice::PrimaryDevice()->SwitchChannel(Channel, true))
1734 Channel = NULL;
1735 }
1736 if (Channel)
1737 return osEnd;
1738 }
1739 Skins.Message(mtError, tr("Can't switch channel!"));
1740 return osContinue;
1741}
1742
1744{
1745 if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
1749 Timers->SetExplicitModify();
1750 if (item->timerMatch == tmFull) {
1751 if (cTimer *Timer = Timers->GetMatch(item->event))
1752 return AddSubMenu(new cMenuEditTimer(Timer));
1753 }
1754 cTimer *Timer = new cTimer(item->event);
1757 if (cTimer *t = Timers->GetTimer(Timer)) {
1758 delete Timer;
1759 Timer = t;
1760 return AddSubMenu(new cMenuEditTimer(Timer));
1761 }
1762 if (Timer->Matches(0, false, NEWTIMERLIMIT))
1763 return AddSubMenu(new cMenuEditTimer(Timer, true));
1764 Timers->Add(Timer);
1765 Timers->SetModified();
1766 if (!HandleRemoteModifications(Timer)) {
1767 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
1768 Timers->Del(Timer);
1769 }
1770 else if (Timer->Remote())
1771 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
1772 if (HasSubMenu())
1773 CloseSubMenu();
1774 }
1775 if (Update()) {
1777 Display();
1778 }
1780 SetHelpKeys(Channels);
1781 return osContinue;
1782}
1783
1785{
1786 bool HadSubMenu = HasSubMenu();
1787 eOSState state = cOsdMenu::ProcessKey(Key);
1788
1789 if (state == osUnknown) {
1790 switch (int(Key)) {
1791 case kRecord:
1792 case kRed: return Record();
1793 case kYellow: state = osBack;
1794 // continue with kGreen
1795 case kGreen: {
1797 if (mi) {
1798 scheduleEvent = mi->event;
1799 currentChannel = mi->channel->Number();
1800 }
1801 }
1802 break;
1803 case kBlue: if (canSwitch)
1804 return Switch();
1805 break;
1806 case kChanUp|k_Repeat:
1807 case kChanUp:
1808 case kChanDn|k_Repeat:
1809 case kChanDn: if (!HasSubMenu()) {
1810 for (cOsdItem *item = First(); item; item = Next(item)) {
1811 if (((cMenuScheduleItem *)item)->channel->Number() == cDevice::CurrentChannel()) {
1812 SetCurrent(item);
1813 {
1815 Display();
1816 }
1818 SetHelpKeys(Channels);
1819 break;
1820 }
1821 }
1822 }
1823 break;
1824 case kInfo:
1825 case kOk: if (Count()) {
1828 return AddSubMenu(new cMenuEvent(Timers, Channels, ((cMenuScheduleItem *)Get(Current()))->event, canSwitch, true));
1829 }
1830 break;
1831 default: break;
1832 }
1833 }
1834 else if (!HasSubMenu()) {
1835 if (HadSubMenu && Update()) {
1837 Display();
1838 }
1839 if (Key != kNone) {
1841 SetHelpKeys(Channels);
1842 }
1843 }
1844 return state;
1845}
1846
1847// --- cMenuSchedule ---------------------------------------------------------
1848
1849class cMenuSchedule : public cOsdMenu {
1850private:
1854 bool now, next;
1857 void Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel = NULL, bool Force = false);
1858 eOSState Number(void);
1859 eOSState Record(void);
1860 eOSState Switch(void);
1861 bool PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1862 bool PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1863 bool PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1864 bool PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1865 bool Update(void);
1866 void SetHelpKeys(void);
1867public:
1868 cMenuSchedule(void);
1869 virtual ~cMenuSchedule();
1870 virtual eOSState ProcessKey(eKeys Key);
1871 };
1872
1874:cOsdMenu(tr("Schedule"))
1875{
1877 scheduleState = -1;
1878 now = next = false;
1879 canSwitch = false;
1880 helpKeys = 0;
1885 Set(Timers, Channels, NULL, true);
1886}
1887
1889{
1890 cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared
1891}
1892
1893void cMenuSchedule::Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel, bool Force)
1894{
1895 if (Force) {
1897 scheduleState = -1;
1898 }
1900 cMenuScheduleItem *CurrentItem = (cMenuScheduleItem *)Get(Current());
1901 const cEvent *Event = NULL;
1902 if (!Channel) {
1903 if (CurrentItem) {
1904 Event = CurrentItem->event;
1905 Channel = Channels->GetByChannelID(Event->ChannelID(), true);
1906 }
1907 else
1908 Channel = Channels->GetByNumber(cDevice::CurrentChannel());
1909 }
1910 bool Refresh = false;
1911 switch (cMenuScheduleItem::SortMode()) {
1912 case cMenuScheduleItem::ssmAllThis: Refresh = PrepareScheduleAllThis(Timers, Schedules, Event, Channel); break;
1913 case cMenuScheduleItem::ssmThisThis: Refresh = PrepareScheduleThisThis(Timers, Schedules, Event, Channel); break;
1914 case cMenuScheduleItem::ssmThisAll: Refresh = Force && PrepareScheduleThisAll(Timers, Schedules, Event, Channel); break;
1915 case cMenuScheduleItem::ssmAllAll: Refresh = Force && PrepareScheduleAllAll(Timers, Schedules, Event, Channel); break;
1916 default: esyslog("ERROR: unknown SortMode %d (%s %d)", cMenuScheduleItem::SortMode(), __FUNCTION__, __LINE__);
1917 }
1918 if (Refresh) {
1919 CurrentItem = (cMenuScheduleItem *)Get(Current());
1920 Sort();
1921 SetCurrent(CurrentItem);
1922 SetHelpKeys();
1923 Display();
1924 }
1926 }
1927}
1928
1929bool cMenuSchedule::PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
1930{
1931 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1932 if (Schedule->Modified(scheduleState)) {
1933 Clear();
1934 SetCols(7, 6, 4);
1935 SetTitle(cString::sprintf(tr("Schedule - %s"), Channel->Name()));
1936 const cEvent *PresentEvent = Event ? Event : Schedule->GetPresentEvent();
1937 time_t now = time(NULL) - Setup.EPGLinger * 60;
1938 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1939 if (ev->EndTime() > now || ev == PresentEvent)
1940 Add(new cMenuScheduleItem(Timers, ev), ev == PresentEvent);
1941 }
1942 return true;
1943 }
1944 }
1945 return false;
1946}
1947
1948bool cMenuSchedule::PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
1949{
1950 if (Event) {
1951 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1952 if (Schedule->Modified(scheduleState)) {
1953 Clear();
1954 SetCols(7, 6, 4);
1955 SetTitle(cString::sprintf(tr("This event - %s"), Channel->Name()));
1956 time_t now = time(NULL) - Setup.EPGLinger * 60;
1957 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1958 if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
1959 Add(new cMenuScheduleItem(Timers, ev), ev == Event);
1960 }
1961 return true;
1962 }
1963 }
1964 }
1965 return false;
1966}
1967
1968bool cMenuSchedule::PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
1969{
1970 Clear();
1971 SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
1972 SetTitle(tr("This event - all channels"));
1973 if (Event) {
1975 for (const cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch)) {
1976 if (const cSchedule *Schedule = Schedules->GetSchedule(ch)) {
1977 time_t now = time(NULL) - Setup.EPGLinger * 60;
1978 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1979 if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
1980 Add(new cMenuScheduleItem(Timers, ev, ch, true), ev == Event && ch == Channel);
1981 }
1982 }
1983 }
1984 }
1985 return true;
1986}
1987
1988bool cMenuSchedule::PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
1989{
1990 Clear();
1991 SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
1992 SetTitle(tr("All events - all channels"));
1994 cStateKey StateKey;
1995 for (const cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch)) {
1996 if (const cSchedule *Schedule = Schedules->GetSchedule(ch)) {
1997 time_t now = time(NULL) - Setup.EPGLinger * 60;
1998 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1999 if (ev->EndTime() > now || ev == Event)
2000 Add(new cMenuScheduleItem(Timers, ev, ch, true), ev == Event && ch == Channel);
2001 }
2002 }
2003 }
2004 return true;
2005}
2006
2008{
2009 bool result = false;
2010 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
2011 for (cOsdItem *item = First(); item; item = Next(item)) {
2012 if (((cMenuScheduleItem *)item)->Update(Timers))
2013 result = true;
2014 }
2016 }
2017 return result;
2018}
2019
2021{
2023 canSwitch = false;
2024 int NewHelpKeys = 0;
2025 if (item) {
2026 if (item->timerMatch == tmFull)
2027 NewHelpKeys |= 0x02; // "Timer"
2028 else
2029 NewHelpKeys |= 0x01; // "Record"
2031 if (const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) {
2032 if (Channel->Number() != cDevice::CurrentChannel()) {
2033 NewHelpKeys |= 0x10; // "Switch"
2034 canSwitch = true;
2035 }
2036 }
2037 }
2038 if (NewHelpKeys != helpKeys) {
2039 const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
2040 SetHelp(Red[NewHelpKeys & 0x03], tr("Button$Now"), tr("Button$Next"), canSwitch ? tr("Button$Switch") : NULL);
2041 helpKeys = NewHelpKeys;
2042 }
2043}
2044
2046{
2050 Set(Timers, Channels, NULL, true);
2051 return osContinue;
2052}
2053
2055{
2056 if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
2060 Timers->SetExplicitModify();
2061 if (item->timerMatch == tmFull) {
2062 if (cTimer *Timer = Timers->GetMatch(item->event))
2063 return AddSubMenu(new cMenuEditTimer(Timer));
2064 }
2065 cTimer *Timer = new cTimer(item->event);
2068 if (cTimer *t = Timers->GetTimer(Timer)) {
2069 delete Timer;
2070 Timer = t;
2071 return AddSubMenu(new cMenuEditTimer(Timer));
2072 }
2073 if (Timer->Matches(0, false, NEWTIMERLIMIT))
2074 return AddSubMenu(new cMenuEditTimer(Timer, true));
2075 Timers->Add(Timer);
2076 Timers->SetModified();
2077 if (!HandleRemoteModifications(Timer)) {
2078 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
2079 Timers->Del(Timer);
2080 }
2081 else if (Timer->Remote())
2082 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
2083 if (HasSubMenu())
2084 CloseSubMenu();
2085 }
2086 if (Update()) {
2088 Display();
2089 }
2090 SetHelpKeys();
2091 return osContinue;
2092}
2093
2095{
2097 if (item) {
2099 const cChannel *Channel = NULL;
2100 if ((Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) != NULL) {
2101 if (!Channels->SwitchTo(Channel->Number()))
2102 Channel = NULL;
2103 }
2104 if (Channel)
2105 return osEnd;
2106 }
2107 Skins.Message(mtError, tr("Can't switch channel!"));
2108 return osContinue;
2109}
2110
2112{
2113 if (!HasSubMenu()) {
2116 Set(Timers, Channels); // react on any changes to the schedules list
2117 }
2118 bool HadSubMenu = HasSubMenu();
2119 eOSState state = cOsdMenu::ProcessKey(Key);
2120
2121 if (state == osUnknown) {
2122 switch (int(Key)) {
2123 case k0: return Number();
2124 case kRecord:
2125 case kRed: return Record();
2126 case kGreen: {
2130 if (!now && !next) {
2131 int ChannelNr = 0;
2132 if (Count()) {
2133 if (const cChannel *Channel = Channels->GetByChannelID(((cMenuScheduleItem *)Get(Current()))->event->ChannelID(), true))
2134 ChannelNr = Channel->Number();
2135 }
2136 now = true;
2137 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, now, ChannelNr));
2138 }
2139 now = !now;
2140 next = !next;
2141 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, now, cMenuWhatsOn::CurrentChannel()));
2142 }
2143 case kYellow: {
2147 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, false, cMenuWhatsOn::CurrentChannel()));
2148 }
2149 case kBlue: if (canSwitch)
2150 return Switch();
2151 break;
2152 case kChanUp|k_Repeat:
2153 case kChanUp:
2154 case kChanDn|k_Repeat:
2155 case kChanDn: if (!HasSubMenu()) {
2158 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
2159 Set(Timers, Channels, Channel, true);
2160 }
2161 break;
2162 case kInfo:
2163 case kOk: if (Count()) {
2167 return AddSubMenu(new cMenuEvent(Timers, Channels, ((cMenuScheduleItem *)Get(Current()))->event, canSwitch, true));
2168 }
2169 break;
2170 default: break;
2171 }
2172 }
2173 else if (!HasSubMenu()) {
2174 now = next = false;
2175 if (const cEvent *ei = cMenuWhatsOn::ScheduleEvent()) {
2178 if (const cChannel *Channel = Channels->GetByChannelID(ei->ChannelID(), true)) {
2180 Set(Timers, Channels, Channel, true);
2181 }
2182 }
2183 else if (HadSubMenu && Update()) {
2185 Display();
2186 }
2187 if (Key != kNone)
2188 SetHelpKeys();
2189 }
2190 return state;
2191}
2192
2193// --- cMenuCommands ---------------------------------------------------------
2194
2195cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
2196:cOsdMenu(Title)
2197{
2199 result = NULL;
2200 SetHasHotkeys();
2202 parameters = Parameters;
2203 for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
2204 const char *s = Command->Text();
2205 if (Command->SubItems())
2206 Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
2207 else if (Parse(s))
2208 Add(new cOsdItem(hk(title)));
2209 }
2210}
2211
2213{
2214 free(result);
2215}
2216
2217bool cMenuCommands::Parse(const char *s)
2218{
2219 const char *p = strchr(s, ':');
2220 if (p) {
2221 int l = p - s;
2222 if (l > 0) {
2223 char t[l + 1];
2224 stripspace(strn0cpy(t, s, l + 1));
2225 l = strlen(t);
2226 if (l > 1 && t[l - 1] == '?') {
2227 t[l - 1] = 0;
2228 confirm = true;
2229 }
2230 else
2231 confirm = false;
2232 title = t;
2233 command = skipspace(p + 1);
2234 return true;
2235 }
2236 }
2237 return false;
2238}
2239
2241{
2242 cNestedItem *Command = commands->Get(Current());
2243 if (Command) {
2244 if (Command->SubItems())
2245 return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
2246 if (Parse(Command->Text())) {
2247 if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
2249 free(result);
2250 result = NULL;
2251 cString cmdbuf;
2252 if (!isempty(parameters))
2253 cmdbuf = cString::sprintf("%s %s", *command, *parameters);
2254 const char *cmd = *cmdbuf ? *cmdbuf : *command;
2255 dsyslog("executing command '%s'", cmd);
2256 cPipe p;
2257 if (p.Open(cmd, "r")) {
2258 int l = 0;
2259 int c;
2260 while ((c = fgetc(p)) != EOF) {
2261 if (l % 20 == 0) {
2262 if (char *NewBuffer = (char *)realloc(result, l + 21))
2263 result = NewBuffer;
2264 else {
2265 esyslog("ERROR: out of memory");
2266 break;
2267 }
2268 }
2269 result[l++] = char(c);
2270 }
2271 if (result)
2272 result[l] = 0;
2273 p.Close();
2274 }
2275 else
2276 esyslog("ERROR: can't open pipe for command '%s'", cmd);
2277 Skins.Message(mtStatus, NULL);
2278 if (result)
2279 return AddSubMenu(new cMenuText(title, result, fontFix));
2280 return osEnd;
2281 }
2282 }
2283 }
2284 return osContinue;
2285}
2286
2288{
2289 eOSState state = cOsdMenu::ProcessKey(Key);
2290
2291 if (state == osUnknown) {
2292 switch (Key) {
2293 case kRed:
2294 case kGreen:
2295 case kYellow:
2296 case kBlue: return osContinue;
2297 case kOk: return Execute();
2298 default: break;
2299 }
2300 }
2301 return state;
2302}
2303
2304// --- cMenuCam --------------------------------------------------------------
2305
2306static bool CamMenuIsOpen = false;
2307
2308class cMenuCam : public cOsdMenu {
2309private:
2313 char *input;
2316 void GenerateTitle(const char *s = NULL);
2317 void QueryCam(void);
2318 void AddMultiLineItem(const char *s);
2319 void Set(void);
2320 eOSState Select(void);
2321public:
2322 cMenuCam(cCamSlot *CamSlot);
2323 virtual ~cMenuCam();
2324 virtual eOSState ProcessKey(eKeys Key);
2325 };
2326
2328:cOsdMenu("", 1) // tab necessary for enquiry!
2329{
2331 camSlot = CamSlot;
2332 ciMenu = NULL;
2333 ciEnquiry = NULL;
2334 input = NULL;
2335 offset = 0;
2336 lastCamExchange = time(NULL);
2338 QueryCam();
2339 CamMenuIsOpen = true;
2340}
2341
2343{
2344 if (ciMenu)
2345 ciMenu->Abort();
2346 delete ciMenu;
2347 if (ciEnquiry)
2348 ciEnquiry->Abort();
2349 delete ciEnquiry;
2350 free(input);
2351 CamMenuIsOpen = false;
2352}
2353
2354void cMenuCam::GenerateTitle(const char *s)
2355{
2356 SetTitle(cString::sprintf("CAM %d - %s", camSlot->SlotNumber(), (s && *s) ? s : camSlot->GetCamName()));
2357}
2358
2360{
2361 delete ciMenu;
2362 ciMenu = NULL;
2363 delete ciEnquiry;
2364 ciEnquiry = NULL;
2365 if (camSlot->HasUserIO()) {
2366 ciMenu = camSlot->GetMenu();
2368 }
2369 Set();
2370}
2371
2373{
2374 if (ciMenu) {
2375 Clear();
2376 free(input);
2377 input = NULL;
2378 dsyslog("CAM %d: Menu ------------------", camSlot->SlotNumber());
2379 offset = 0;
2382 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->TitleText());
2383 if (!isempty(ciMenu->SubTitleText())) {
2384 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->SubTitleText());
2386 offset = Count();
2387 }
2388 for (int i = 0; i < ciMenu->NumEntries(); i++) {
2390 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->Entry(i));
2391 }
2392 if (!isempty(ciMenu->BottomText())) {
2394 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->BottomText());
2395 }
2397 }
2398 else if (ciEnquiry) {
2399 Clear();
2400 int Length = ciEnquiry->ExpectedLength();
2401 free(input);
2402 input = MALLOC(char, Length + 1);
2403 *input = 0;
2404 dsyslog("CAM %d: Enquiry ------------------", camSlot->SlotNumber());
2405 GenerateTitle();
2406 Add(new cOsdItem(ciEnquiry->Text(), osUnknown, false));
2407 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciEnquiry->Text());
2408 Add(new cOsdItem("", osUnknown, false));
2409 Add(new cMenuEditNumItem("", input, Length, ciEnquiry->Blind()));
2410 }
2411 Display();
2412}
2413
2415{
2416 while (s && *s) {
2417 const char *p = strchr(s, '\n');
2418 int l = p ? p - s : strlen(s);
2419 cOsdItem *item = new cOsdItem;
2420 item->SetSelectable(false);
2421 item->SetText(strndup(s, l), false);
2422 Add(item);
2423 s = p ? p + 1 : p;
2424 }
2425}
2426
2428{
2429 if (ciMenu) {
2430 if (ciMenu->Selectable()) {
2432 dsyslog("CAM %d: select %d", camSlot->SlotNumber(), Current() - offset);
2433 }
2434 else
2435 ciMenu->Cancel();
2436 }
2437 else if (ciEnquiry) {
2438 if (ciEnquiry->ExpectedLength() < 0xFF && int(strlen(input)) != ciEnquiry->ExpectedLength()) {
2439 char buffer[64];
2440 snprintf(buffer, sizeof(buffer), tr("Please enter %d digits!"), ciEnquiry->ExpectedLength());
2441 Skins.Message(mtError, buffer);
2442 return osContinue;
2443 }
2445 dsyslog("CAM %d: entered '%s'", camSlot->SlotNumber(), ciEnquiry->Blind() ? "****" : input);
2446 }
2447 QueryCam();
2448 return osContinue;
2449}
2450
2452{
2453 if (!camSlot->HasMMI())
2454 return osBack;
2455
2456 eOSState state = cOsdMenu::ProcessKey(Key);
2457
2458 if (ciMenu || ciEnquiry) {
2459 lastCamExchange = time(NULL);
2460 if (state == osUnknown) {
2461 switch (Key) {
2462 case kOk: return Select();
2463 default: break;
2464 }
2465 }
2466 else if (state == osBack) {
2467 if (ciMenu)
2468 ciMenu->Cancel();
2469 if (ciEnquiry)
2470 ciEnquiry->Cancel();
2471 QueryCam();
2472 return osContinue;
2473 }
2474 if (ciMenu && ciMenu->HasUpdate()) {
2475 QueryCam();
2476 return osContinue;
2477 }
2478 }
2479 else if (time(NULL) - lastCamExchange < CAMRESPONSETIMEOUT)
2480 QueryCam();
2481 else {
2482 Skins.Message(mtError, tr("CAM not responding!"));
2483 return osBack;
2484 }
2485 return state;
2486}
2487
2488// --- CamControl ------------------------------------------------------------
2489
2491{
2492 for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
2493 if (CamSlot->HasUserIO())
2494 return new cMenuCam(CamSlot);
2495 }
2496 return NULL;
2497}
2498
2500{
2501 return CamMenuIsOpen;
2502}
2503
2504// --- cMenuPathEdit ---------------------------------------------------------
2505
2506#define osUserRecRenamed osUser1
2507#define osUserRecMoved osUser2
2508#define osUserRecRemoved osUser3
2509#define osUserRecEmpty osUser4
2510
2511class cMenuPathEdit : public cOsdMenu {
2512private:
2515 char folder[PATH_MAX];
2516 char name[NAME_MAX];
2519 eOSState SetFolder(void);
2520 eOSState Folder(void);
2521 eOSState ApplyChanges(void);
2522public:
2523 cMenuPathEdit(const char *Path);
2524 virtual eOSState ProcessKey(eKeys Key);
2525 };
2526
2528:cOsdMenu(tr("Edit path"), 12)
2529{
2531 path = Path;
2532 *folder = 0;
2533 *name = 0;
2534 const char *s = strrchr(path, FOLDERDELIMCHAR);
2535 if (s) {
2536 strn0cpy(folder, cString(path, s), sizeof(folder));
2537 s++;
2538 }
2539 else
2540 s = path;
2541 strn0cpy(name, s, sizeof(name));
2542 {
2544 pathIsInUse = Recordings->PathIsInUse(path);
2545 }
2546 oldFolder = folder;
2547 cOsdItem *p;
2548 Add(p = folderItem = new cMenuEditStrItem(tr("Folder"), folder, sizeof(folder)));
2550 Add(p = new cMenuEditStrItem(tr("Name"), name, sizeof(name)));
2552 if (*path) {
2553 int DirSize = 0;
2554 {
2556 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
2557 if (Recording->IsInPath(path)) {
2558 int FileSizeMB = Recording->FileSizeMB();
2559 if (FileSizeMB > 0 )
2560 DirSize += FileSizeMB;
2561 }
2562 }
2563 }
2564 if (DirSize > 1023)
2565 Add(new cOsdItem(cString::sprintf("%s:\t%.2f GB", tr("Size"), DirSize / 1024.), osUnknown, false));
2566 else
2567 Add(new cOsdItem(cString::sprintf("%s:\t%d MB", tr("Size"), DirSize), osUnknown, false));
2568 }
2569 if (pathIsInUse) {
2570 Add(new cOsdItem("", osUnknown, false));
2571 Add(new cOsdItem(tr("This folder is currently in use - no changes are possible!"), osUnknown, false));
2572 }
2573 Display();
2574 if (!pathIsInUse)
2575 SetHelp(tr("Button$Folder"));
2576}
2577
2579{
2580 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
2581 strn0cpy(folder, mf->GetFolder(), sizeof(folder));
2583 Display();
2584 }
2585 return CloseSubMenu();
2586}
2587
2589{
2590 return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, path));
2591}
2592
2594{
2595 if (!*name) {
2596 *name = ' '; // name must not be empty!
2597 name[1] = 0;
2598 }
2599 cString NewPath = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2601 if (strcmp(NewPath, path)) {
2602 int NumRecordings = 0;
2603 {
2605 NumRecordings = Recordings->GetNumRecordingsInPath(path);
2606 }
2607 if (NumRecordings > 1 && !Interface->Confirm(cString::sprintf(tr("Move entire folder containing %d recordings?"), NumRecordings)))
2608 return osContinue;
2609 bool Error = false;
2610 {
2612 Recordings->SetExplicitModify();
2613 Error = !Recordings->MoveRecordings(path, NewPath);
2614 if (!Error)
2615 Recordings->SetModified();
2616 }
2617 if (Error) {
2618 Skins.Message(mtError, tr("Error while moving folder!"));
2619 return osContinue;
2620 }
2621 if (strcmp(folder, oldFolder))
2622 return osUserRecMoved;
2623 return osUserRecRenamed;
2624 }
2625 return osBack;
2626}
2627
2629{
2630 eOSState state = cOsdMenu::ProcessKey(Key);
2631 if (state == osUnknown) {
2632 if (!pathIsInUse) {
2633 switch (Key) {
2634 case kRed: return Folder();
2635 case kOk: return ApplyChanges();
2636 default: break;
2637 }
2638 }
2639 else if (Key == kOk)
2640 return osBack;
2641 }
2642 else if (state == osEnd && HasSubMenu())
2643 state = SetFolder();
2644 return state;
2645}
2646
2647// --- cMenuRecordingEdit ----------------------------------------------------
2648
2650private:
2654 char folder[PATH_MAX];
2655 char name[NAME_MAX];
2660 const char *buttonFolder;
2661 const char *buttonAction;
2662 const char *buttonDelete;
2663 const char *actionCancel;
2664 const char *doCut;
2665 const char *doCopy;
2668 void Set(void);
2669 void SetHelpKeys(void);
2670 bool RefreshRecording(void);
2671 eOSState SetFolder(void);
2672 eOSState Folder(void);
2673 eOSState Action(void);
2674 eOSState RemoveName(void);
2675 eOSState Delete(void);
2676 eOSState ApplyChanges(void);
2677public:
2678 cMenuRecordingEdit(const cRecording *Recording);
2679 virtual eOSState ProcessKey(eKeys Key);
2680 };
2681
2683:cOsdMenu(tr("Edit recording"), 12)
2684{
2686 recording = Recording;
2688 strn0cpy(folder, recording->Folder(), sizeof(folder));
2689 strn0cpy(name, recording->BaseName(), sizeof(name));
2692 folderItem = NULL;
2693 nameItem = NULL;
2694 buttonFolder = NULL;
2695 buttonAction = NULL;
2696 buttonDelete = NULL;
2697 actionCancel = NULL;
2698 doCut = NULL;
2699 doCopy = NULL;
2700 extraAction = false;
2702 Set();
2703}
2704
2706{
2707 int current = Current();
2708 Clear();
2710 cOsdItem *p;
2711 Add(p = folderItem = new cMenuEditStrItem(tr("Folder"), folder, sizeof(folder)));
2713 Add(p = nameItem = new cMenuEditStrItem(tr("Name"), name, sizeof(name)));
2715 Add(p = new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY));
2717 Add(p = new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME));
2719 if (recordingIsInUse) {
2720 Add(new cOsdItem("", osUnknown, false));
2721 Add(new cOsdItem(tr("This recording is currently in use - no changes are possible!"), osUnknown, false));
2722 }
2724 Display();
2725 SetHelpKeys();
2726}
2727
2729{
2730 buttonFolder = !recordingIsInUse ? tr("Button$Folder") : NULL;
2731 buttonAction = NULL;
2732 buttonDelete = NULL;
2733 actionCancel = NULL;
2734 doCut = NULL;
2735 doCopy = NULL;
2736 if ((recordingIsInUse & ruCut) != 0)
2737 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel cutting") : tr("Button$Stop cutting");
2738 else if ((recordingIsInUse & ruMove) != 0)
2739 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel moving") : tr("Button$Stop moving");
2740 else if ((recordingIsInUse & ruCopy) != 0)
2741 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel copying") : tr("Button$Stop copying");
2742 else if (extraAction) {
2744 buttonAction = doCopy = tr("Button$Copy");
2745 buttonDelete = (ResumeFile.Read() != -1) ? tr("Button$Delete resume") : NULL;
2746 }
2747 else if (recording->HasMarks()) {
2748 buttonAction = doCut = tr("Button$Cut");
2749 buttonDelete = tr("Button$Delete marks");
2750 }
2751 SetHelp(buttonFolder, buttonAction, buttonDelete, tr("Button$Toggle commands"));
2752}
2753
2755{
2757 if ((recording = Recordings->GetByName(originalFileName)) != NULL)
2758 Set();
2759 else {
2761 Skins.Message(mtWarning, tr("Recording vanished!"));
2762 return false;
2763 }
2765 }
2766 return true;
2767}
2768
2770{
2771 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
2772 strn0cpy(folder, mf->GetFolder(), sizeof(folder));
2774 Display();
2775 }
2776 return CloseSubMenu();
2777}
2778
2780{
2781 return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, recording->Name()));
2782}
2783
2785{
2786 if (actionCancel)
2788 else if (doCut) {
2789 if (access(cCutter::EditedFileName(recording->FileName()), F_OK) != 0 || Interface->Confirm(tr("Edited version already exists - overwrite?"))) {
2791 Skins.Message(mtError, tr("Error while queueing recording for cutting!"));
2792 }
2793 }
2794 else if (doCopy) {
2795 if (!*name)
2796 *name = ' '; // name must not be empty!
2797 cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2799 if (strcmp(NewName, recording->Name())) {
2800 cString FromName = cString(ExchangeChars(strdup(recording->Name()), true), true);
2801 cString ToName = cString(ExchangeChars(strdup(*NewName), true), true);
2802 cString FileName = cString(strreplace(strdup(recording->FileName()), *FromName, *ToName), true);
2803 if (access(*FileName, F_OK) != 0 || Interface->Confirm(tr("Edited version already exists - overwrite?"))) {
2804 if (MakeDirs(FileName, true) && !RecordingsHandler.Add(ruCopy, recording->FileName(), FileName))
2805 Skins.Message(mtError, tr("Error while queueing recording for copying!"));
2806 else {
2808 Recordings->AddByName(FileName);
2809 }
2810 }
2811 }
2812 }
2815 SetHelpKeys();
2816 return osContinue;
2817}
2818
2820{
2821 if (Get(Current()) == nameItem) {
2822 if (Interface->Confirm(tr("Rename recording to folder name?"))) {
2823 char *s = strrchr(folder, FOLDERDELIMCHAR);
2824 if (s)
2825 *s++ = 0;
2826 else
2827 s = folder;
2828 strn0cpy(name, s, sizeof(name));
2829 if (s == folder)
2830 *s = 0;
2831 Set();
2832 }
2833 }
2834 return osContinue;
2835}
2836
2838{
2839 if (extraAction) {
2840 if (buttonDelete && Interface->Confirm(tr("Delete resume for this recording?"))) {
2842 ResumeFile.Delete();
2843 SetHelpKeys();
2844 }
2845 }
2846 else {
2847 if (buttonDelete && Interface->Confirm(tr("Delete editing marks for this recording?"))) {
2849 SetHelpKeys();
2850 cMutexLock ControlMutexLock;
2851 if (cControl *Control = cControl::Control(ControlMutexLock, true)) {
2852 if (const cRecording *Recording = Control->GetRecording()) {
2853 if (strcmp(recording->FileName(), Recording->FileName()) == 0)
2854 Control->ClearEditingMarks();
2855 }
2856 }
2857 }
2858 else
2859 Skins.Message(mtError, tr("Error while deleting editing marks!"));
2860 }
2861 }
2862 return osContinue;
2863}
2864
2866{
2867 cStateKey StateKey;
2868 cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
2869 cRecording *Recording = Recordings->GetByName(recording->FileName());
2870 if (!Recording) {
2871 StateKey.Remove(false);
2872 Skins.Message(mtWarning, tr("Recording vanished!"));
2873 return osBack;
2874 }
2875 bool Modified = false;
2877 if (!Recording->ChangePriorityLifetime(priority, lifetime)) {
2878 StateKey.Remove(Modified);
2879 Skins.Message(mtError, tr("Error while changing priority/lifetime!"));
2880 return osContinue;
2881 }
2882 Modified = true;
2883 }
2884 if (!*name) {
2885 *name = ' '; // name must not be empty!
2886 name[1] = 0;
2887 }
2888 cString OldFolder = Recording->Folder();
2889 cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2891 if (strcmp(NewName, Recording->Name())) {
2892 if (!Recording->ChangeName(NewName)) {
2893 StateKey.Remove(Modified);
2894 Skins.Message(mtError, tr("Error while changing folder/name!"));
2895 return osContinue;
2896 }
2897 Modified = true;
2898 }
2899 if (Modified) {
2900 eOSState state = osUserRecRenamed;
2901 if (strcmp(Recording->Folder(), OldFolder))
2902 state = osUserRecMoved;
2903 Recordings->TouchUpdate();
2904 StateKey.Remove(Modified);
2905 return state;
2906 }
2907 StateKey.Remove(Modified);
2908 return osBack;
2909}
2910
2912{
2913 if (!HasSubMenu()) {
2914 if (!RefreshRecording())
2915 return osBack; // the recording has vanished, so close this menu
2916 }
2917 eOSState state = cOsdMenu::ProcessKey(Key);
2918 if (state == osUnknown) {
2919 switch (Key) {
2920 case k0: return RemoveName();
2921 case kRed: return buttonFolder ? Folder() : osContinue;
2922 case kGreen: return buttonAction ? Action() : osContinue;
2923 case kYellow: return buttonDelete ? Delete() : osContinue;
2925 case kOk: return !recordingIsInUse ? ApplyChanges() : osBack;
2926 default: break;
2927 }
2928 }
2929 else if (state == osEnd && HasSubMenu())
2930 state = SetFolder();
2931 return state;
2932}
2933
2934// --- cMenuRecording --------------------------------------------------------
2935
2936class cMenuRecording : public cOsdMenu {
2937private:
2942 bool RefreshRecording(void);
2943public:
2944 cMenuRecording(const cRecording *Recording, bool WithButtons = false);
2945 virtual void Display(void);
2946 virtual eOSState ProcessKey(eKeys Key);
2947};
2948
2949cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
2950:cOsdMenu(tr("Recording info"))
2951{
2953 if (cRecordings::GetRecordingsRead(recordingsStateKey)) // initializes recordingsStateKey, so we don't call Display() unnecessarily
2955 recording = Recording;
2957 withButtons = WithButtons;
2958 if (withButtons)
2959 SetHelp(tr("Button$Play"), tr("Button$Rewind"), NULL, tr("Button$Edit"));
2960}
2961
2963{
2965 if ((recording = Recordings->GetByName(originalFileName)) != NULL)
2966 Display();
2967 else {
2969 Skins.Message(mtWarning, tr("Recording vanished!"));
2970 return false;
2971 }
2973 }
2974 return true;
2975}
2976
2978{
2979 if (HasSubMenu()) {
2980 SubMenu()->Display();
2981 return;
2982 }
2985 if (recording->Info()->Description())
2987}
2988
2990{
2991 if (HasSubMenu())
2992 return cOsdMenu::ProcessKey(Key);
2993 else if (!RefreshRecording())
2994 return osBack; // the recording has vanished, so close this menu
2995 switch (int(Key)) {
2996 case kUp|k_Repeat:
2997 case kUp:
2998 case kDown|k_Repeat:
2999 case kDown:
3000 case kLeft|k_Repeat:
3001 case kLeft:
3002 case kRight|k_Repeat:
3003 case kRight:
3004 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
3005 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
3006 return osContinue;
3007 case kInfo: return osBack;
3008 default: break;
3009 }
3010
3011 eOSState state = cOsdMenu::ProcessKey(Key);
3012
3013 if (state == osUnknown) {
3014 switch (Key) {
3015 case kRed: if (withButtons)
3016 Key = kOk; // will play the recording, even if recording commands are defined
3017 case kGreen: if (!withButtons)
3018 break;
3019 cRemote::Put(Key, true);
3020 // continue with osBack to close the info menu and process the key
3021 case kOk: return osBack;
3022 case kBlue: if (withButtons)
3024 break;
3025 default: break;
3026 }
3027 }
3028 return state;
3029}
3030
3031// --- cMenuRecordingItem ----------------------------------------------------
3032
3034private:
3037 char *name;
3039public:
3042 void IncrementCounter(bool New);
3043 const char *Name(void) const { return name; }
3044 int Level(void) const { return level; }
3045 const cRecording *Recording(void) const { return recording; }
3046 bool IsDirectory(void) const { return name != NULL; }
3048 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
3049 };
3050
3052{
3054 level = Level;
3055 name = NULL;
3057 SetText(Recording->Title('\t', true, Level));
3058 if (*Text() == '\t') // this is a folder
3059 name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
3060 else { // this is an actual recording
3061 int Usage = Recording->IsInUse();
3062 if ((Usage & ruDst) != 0 && (Usage & (ruMove | ruCopy)) != 0)
3063 SetSelectable(false);
3064 }
3065}
3066
3068{
3069 free(name);
3070}
3071
3073{
3074 totalEntries++;
3075 if (New)
3076 newEntries++;
3078}
3079
3080void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
3081{
3082 if (!DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
3083 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
3084}
3085
3086// --- cMenuRecordings -------------------------------------------------------
3087
3090
3091cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus, const cRecordingFilter *Filter)
3092:cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
3093{
3095 base = Base ? strdup(Base) : NULL;
3096 level = Setup.RecordingDirs ? Level : -1;
3097 filter = Filter;
3098 helpKeys = -1;
3099 Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
3100 Set();
3101 if (Current() < 0)
3102 SetCurrent(First());
3103 else if (OpenSubMenus && (cReplayControl::LastReplayed() || *path || *fileName)) {
3104 if (!*path || Level < strcountchr(path, FOLDERDELIMCHAR)) {
3105 if (Open(true))
3106 return;
3107 }
3108 }
3109 Display();
3110 SetHelpKeys();
3111}
3112
3114{
3116 if (!ri->IsDirectory())
3117 SetRecording(ri->Recording()->FileName());
3118 }
3119 free(base);
3120}
3121
3123{
3125 int NewHelpKeys = 0;
3126 if (ri) {
3127 if (ri->IsDirectory())
3128 NewHelpKeys = 1;
3129 else
3130 NewHelpKeys = 2;
3131 }
3132 if (NewHelpKeys != helpKeys) {
3133 switch (NewHelpKeys) {
3134 case 0: SetHelp(NULL); break;
3135 case 1: SetHelp(tr("Button$Open"), NULL, NULL, tr("Button$Edit")); break;
3136 case 2: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), tr("Button$Info"));
3137 default: ;
3138 }
3139 helpKeys = NewHelpKeys;
3140 }
3141}
3142
3143void cMenuRecordings::Set(bool Refresh)
3144{
3147 cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting!
3148 const char *CurrentRecording = NULL;
3150 CurrentRecording = ri->Recording()->FileName();
3151 if (!CurrentRecording)
3152 CurrentRecording = *fileName ? *fileName : cReplayControl::LastReplayed();
3153 int current = Current();
3154 Clear();
3156 Recordings->Sort();
3157 cMenuRecordingItem *CurrentItem = NULL;
3158 cMenuRecordingItem *LastItem = NULL;
3159 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
3160 if ((!filter || filter->Filter(Recording)) && (!base || (strstr(Recording->Name(), base) == Recording->Name() && Recording->Name()[strlen(base)] == FOLDERDELIMCHAR))) {
3161 cMenuRecordingItem *Item = new cMenuRecordingItem(Recording, level);
3162 cMenuRecordingItem *LastDir = NULL;
3163 if (Item->IsDirectory()) {
3164 // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
3165 for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
3166 if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
3167 LastDir = p;
3168 break;
3169 }
3170 }
3171 }
3172 if (*Item->Text() && !LastDir) {
3173 Add(Item);
3174 LastItem = Item;
3175 if (Item->IsDirectory())
3176 LastDir = Item;
3177 }
3178 else
3179 delete Item;
3180 if (LastItem || LastDir) {
3181 if (*path) {
3182 if (strcmp(path, Recording->Folder()) == 0)
3183 CurrentItem = LastDir ? LastDir : LastItem;
3184 }
3185 else if (CurrentRecording && strcmp(CurrentRecording, Recording->FileName()) == 0)
3186 CurrentItem = LastDir ? LastDir : LastItem;
3187 }
3188 if (LastDir)
3189 LastDir->IncrementCounter(Recording->IsNew());
3190 }
3191 }
3192 SetCurrent(CurrentItem);
3193 if (Current() < 0)
3194 SetCurrent(Get(current)); // last resort, in case the recording was deleted
3196 recordingsStateKey.Remove(false); // sorting doesn't count as a real modification
3197 if (Refresh)
3198 Display();
3199 }
3200}
3201
3202void cMenuRecordings::SetPath(const char *Path)
3203{
3204 path = Path;
3205}
3206
3207void cMenuRecordings::SetRecording(const char *FileName)
3208{
3209 fileName = FileName;
3210}
3211
3213{
3215 if (base) {
3216 char *s = ExchangeChars(strdup(base), true);
3217 d = AddDirectory(d, s);
3218 free(s);
3219 }
3220 return d;
3221}
3222
3223bool cMenuRecordings::Open(bool OpenSubMenus)
3224{
3226 if (ri && ri->IsDirectory() && (!*path || strcountchr(path, FOLDERDELIMCHAR) > 0)) {
3227 const char *t = ri->Name();
3228 cString buffer;
3229 if (base) {
3230 buffer = cString::sprintf("%s%c%s", base, FOLDERDELIMCHAR, t);
3231 t = buffer;
3232 }
3233 AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus, filter));
3234 return true;
3235 }
3236 return false;
3237}
3238
3240{
3242 if (ri) {
3243 if (ri->IsDirectory())
3244 Open();
3245 else {
3247 return osReplay;
3248 }
3249 }
3250 return osContinue;
3251}
3252
3254{
3255 if (HasSubMenu() || Count() == 0)
3256 return osContinue;
3258 if (ri && !ri->IsDirectory()) {
3259 cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
3260 cResumeFile ResumeFile(ri->Recording()->FileName(), ri->Recording()->IsPesRecording());
3261 ResumeFile.Delete();
3262 return Play();
3263 }
3264 return osContinue;
3265}
3266
3267static bool TimerStillRecording(const char *FileName)
3268{
3270 // local timer
3271 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3273 if (cTimer *Timer = rc->Timer()) {
3274 Timer->Skip();
3275 cRecordControls::Process(Timers, time(NULL));
3276 if (Timer->IsSingleEvent()) {
3277 Timers->Del(Timer);
3278 isyslog("deleted timer %s", *Timer->ToDescr());
3279 }
3280 }
3281 }
3282 else
3283 return true; // user didn't confirm deletion
3284 }
3285 else {
3286 // remote timer
3287 cString TimerId = GetRecordingTimerId(FileName);
3288 if (*TimerId) {
3289 int Id;
3290 char *RemoteBuf = NULL;
3291 cString Remote;
3292 if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf) && Id != 0) {
3293 Remote = RemoteBuf;
3294 free(RemoteBuf);
3295 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3297 if (cTimer *Timer = Timers->GetById(Id, Remote)) {
3298 cTimer OldTimer = *Timer;
3299 Timer->Skip();
3300 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
3301 if (Timer->IsSingleEvent()) {
3302 if (HandleRemoteModifications(NULL, Timer))
3303 Timers->Del(Timer);
3304 else
3305 return true; // error while deleting remote timer
3306 }
3307 else if (!HandleRemoteModifications(Timer, &OldTimer))
3308 return true; // error while modifying remote timer
3309 }
3310 }
3311 else
3312 return true; // user didn't confirm deletion
3313 }
3314 }
3315 }
3316 return false;
3317}
3318
3320{
3321 if (HasSubMenu() || Count() == 0)
3322 return osContinue;
3324 if (ri && !ri->IsDirectory()) {
3325 if (Interface->Confirm(tr("Delete recording?"))) {
3327 return osContinue;
3328 cString FileName;
3329 {
3331 if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) {
3332 FileName = Recording->FileName();
3333 if (RecordingsHandler.GetUsage(FileName)) {
3334 if (!Interface->Confirm(tr("Recording is being edited - really delete?")))
3335 return osContinue;
3336 }
3337 }
3338 }
3339 RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one!
3340 if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
3343 Recordings->SetExplicitModify();
3344 cRecording *Recording = Recordings->GetByName(FileName);
3345 if (!Recording || Recording->Delete()) {
3347 Recordings->DelByName(FileName);
3349 SetHelpKeys();
3351 Recordings->SetModified();
3353 Display();
3354 if (!Count())
3355 return osUserRecEmpty;
3356 return osUserRecRemoved;
3357 }
3358 else
3359 Skins.Message(mtError, tr("Error while deleting recording!"));
3361 }
3362 }
3363 return osContinue;
3364}
3365
3367{
3368 if (HasSubMenu() || Count() == 0)
3369 return osContinue;
3371 if (ri->IsDirectory())
3372 return AddSubMenu(new cMenuPathEdit(cString(ri->Recording()->Name(), strchrn(ri->Recording()->Name(), FOLDERDELIMCHAR, ri->Level() + 1))));
3373 else
3374 return AddSubMenu(new cMenuRecording(ri->Recording(), true));
3375 }
3376 return osContinue;
3377}
3378
3380{
3381 if (HasSubMenu() || Count() == 0)
3382 return osContinue;
3384 if (ri && !ri->IsDirectory()) {
3385 cMenuCommands *menu;
3386 eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
3387 if (Key != kNone)
3388 state = menu->ProcessKey(Key);
3389 return state;
3390 }
3391 return osContinue;
3392}
3393
3395{
3396 if (HasSubMenu())
3397 return osContinue;
3398 if (const cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()))
3399 SetRecording(ri->Recording()->FileName()); // makes sure the Recordings menu will reposition to the current recording
3402 Set(true);
3403 return osContinue;
3404}
3405
3407{
3408 eOSState state = cOsdMenu::ProcessKey(Key);
3409
3410 if (state == osUnknown) {
3411 switch (Key) {
3412 case kPlayPause:
3413 case kPlay:
3414 case kOk: return Play();
3415 case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
3416 case kGreen: return Rewind();
3417 case kYellow: return Delete();
3418 case kInfo:
3419 case kBlue: return Info();
3420 case k0: return Sort();
3421 case k1...k9: return Commands(Key);
3422 default: break;
3423 }
3424 }
3425 else if (state == osUserRecRenamed) {
3426 // a recording was renamed (within the same folder), so let's refresh the menu
3427 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3428 path = NULL;
3429 fileName = NULL;
3430 state = osContinue;
3431 }
3432 else if (state == osUserRecMoved) {
3433 // a recording was moved to a different folder, so let's delete the old item
3434 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3435 path = NULL;
3436 fileName = NULL;
3438 Set(); // the recording might have been moved into a new subfolder of this folder
3439 if (!Count())
3440 return osUserRecEmpty;
3441 Display();
3442 state = osUserRecRemoved;
3443 }
3444 else if (state == osUserRecRemoved) {
3445 // a recording was removed from a sub folder, so update the current item
3446 if (cOsdMenu *m = SubMenu()) {
3448 if (cMenuRecordingItem *riSub = (cMenuRecordingItem *)m->Get(m->Current()))
3449 ri->SetRecording(riSub->Recording());
3450 }
3451 }
3452 // no state change here, this report goes upstream!
3453 }
3454 else if (state == osUserRecEmpty) {
3455 // a subfolder became empty, so let's go back up
3456 CloseSubMenu(false); // this is the now empty submenu
3457 cOsdMenu::Del(Current()); // the menu entry of the now empty subfolder
3458 Set(); // in case a recording was moved into a new subfolder of this folder
3459 if (base && !Count()) // base: don't go up beyond the top level Recordings menu
3460 return state;
3461 Display();
3462 state = osContinue;
3463 }
3464 if (!HasSubMenu()) {
3465 Set(true);
3466 if (Key != kNone)
3467 SetHelpKeys();
3468 }
3469 return state;
3470}
3471
3472// --- cMenuSetupBase --------------------------------------------------------
3473
3475protected:
3477 virtual void Store(void);
3478public:
3479 cMenuSetupBase(void);
3480 };
3481
3483{
3484 data = Setup;
3485}
3486
3488{
3489 Setup = data;
3491 Setup.Save();
3492}
3493
3494// --- cMenuSetupOSD ---------------------------------------------------------
3495
3497private:
3498 const char *useSmallFontTexts[3];
3499 const char *recSortModeTexts[2];
3500 const char *recSortDirTexts[2];
3501 const char *keyColorTexts[4];
3506 const char **skinDescriptions;
3512 virtual void Set(void);
3513public:
3514 cMenuSetupOSD(void);
3515 virtual ~cMenuSetupOSD();
3516 virtual eOSState ProcessKey(eKeys Key);
3517 };
3518
3520{
3523 numSkins = Skins.Count();
3525 skinDescriptions = new const char*[numSkins];
3537 Set();
3538}
3539
3541{
3542 delete[] skinDescriptions;
3543}
3544
3546{
3547 int current = Current();
3548 for (cSkin *Skin = Skins.First(); Skin; Skin = Skins.Next(Skin))
3549 skinDescriptions[Skin->Index()] = Skin->Description();
3550 useSmallFontTexts[0] = tr("never");
3551 useSmallFontTexts[1] = tr("skin dependent");
3552 useSmallFontTexts[2] = tr("always");
3553 recSortModeTexts[0] = tr("by name");
3554 recSortModeTexts[1] = tr("by time");
3555 recSortDirTexts[0] = tr("ascending");
3556 recSortDirTexts[1] = tr("descending");
3557 keyColorTexts[0] = tr("Key$Red");
3558 keyColorTexts[1] = tr("Key$Green");
3559 keyColorTexts[2] = tr("Key$Yellow");
3560 keyColorTexts[3] = tr("Key$Blue");
3561 Clear();
3562 SetSection(tr("OSD"));
3563 Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0)));
3564 Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions));
3565 if (themes.NumThemes())
3566 Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions()));
3567 Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5));
3568 Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5));
3569 Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0));
3570 Add(new cMenuEditPrcItem( tr("Setup.OSD$Height (%)"), &data.OSDHeightP, 0.5, 1.0));
3571 Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
3572 Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"), &data.UseSmallFont, 3, useSmallFontTexts));
3573 Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"), &data.AntiAlias));
3574 Add(new cMenuEditStraItem(tr("Setup.OSD$Default font"), &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
3575 Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"), &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
3576 Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"), &fontFixIndex, fontFixNames.Size(), &fontFixNames[0]));
3577 Add(new cMenuEditPrcItem( tr("Setup.OSD$Default font size (%)"), &data.FontOsdSizeP, 0.01, 0.1, 1));
3578 Add(new cMenuEditPrcItem( tr("Setup.OSD$Small font size (%)"), &data.FontSmlSizeP, 0.01, 0.1, 1));
3579 Add(new cMenuEditPrcItem( tr("Setup.OSD$Fixed font size (%)"), &data.FontFixSizeP, 0.01, 0.1, 1));
3580 Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
3581 Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
3582 Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
3583 Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
3584 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
3585 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
3586 Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses));
3587 Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
3588 Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu));
3589 Add(new cMenuEditBoolItem(tr("Setup.OSD$Always sort folders first"), &data.AlwaysSortFoldersFirst));
3590 Add(new cMenuEditStraItem(tr("Setup.OSD$Default sort mode for recordings"), &data.DefaultSortModeRec, 2, recSortModeTexts));
3591 Add(new cMenuEditStraItem(tr("Setup.OSD$Sorting direction for recordings"), &data.RecSortingDirection, 2, recSortDirTexts));
3592 Add(new cMenuEditBoolItem(tr("Setup.OSD$Number keys for characters"), &data.NumberKeysForChars));
3593 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 0"), &data.ColorKey0, 4, keyColorTexts));
3594 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 1"), &data.ColorKey1, 4, keyColorTexts));
3595 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 2"), &data.ColorKey2, 4, keyColorTexts));
3596 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 3"), &data.ColorKey3, 4, keyColorTexts));
3598 Display();
3599}
3600
3602{
3603 bool ModifiedAppearance = false;
3604
3605 if (Key == kOk) {
3608 cSkin *Skin = Skins.Get(skinIndex);
3609 if (Skin) {
3610 Utf8Strn0Cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
3611 Skins.SetCurrent(Skin->Name());
3612 ModifiedAppearance = true;
3613 }
3614 }
3615 if (themes.NumThemes() && Skins.Current()->Theme()) {
3618 ModifiedAppearance |= themeIndex != originalThemeIndex;
3619 }
3621 ModifiedAppearance = true;
3623 ModifiedAppearance = true;
3628 ModifiedAppearance = true;
3630 ModifiedAppearance = true;
3632 ModifiedAppearance = true;
3635 Recordings->ClearSortNames();
3636 }
3637 }
3638
3639 int oldSkinIndex = skinIndex;
3640 int oldOsdLanguageIndex = osdLanguageIndex;
3642
3643 if (ModifiedAppearance)
3645
3646 if (osdLanguageIndex != oldOsdLanguageIndex || skinIndex != oldSkinIndex) {
3648 int OriginalOSDLanguage = I18nCurrentLanguage();
3650
3651 cSkin *Skin = Skins.Get(skinIndex);
3652 if (Skin) {
3653 char *d = themes.NumThemes() ? strdup(themes.Descriptions()[themeIndex]) : NULL;
3654 themes.Load(Skin->Name());
3655 if (skinIndex != oldSkinIndex)
3656 themeIndex = d ? themes.GetThemeIndex(d) : 0;
3657 free(d);
3658 }
3659
3660 Set();
3661 I18nSetLanguage(OriginalOSDLanguage);
3662 }
3663 return state;
3664}
3665
3666// --- cMenuSetupEPG ---------------------------------------------------------
3667
3669private:
3672 void Setup(void);
3673public:
3674 cMenuSetupEPG(void);
3675 virtual eOSState ProcessKey(eKeys Key);
3676 };
3677
3679{
3682 ;
3684 SetSection(tr("EPG"));
3685 SetHelp(tr("Button$Scan"));
3686 Setup();
3687}
3688
3690{
3691 int current = Current();
3692
3693 Clear();
3694
3695 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
3696 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
3697 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0));
3698 Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
3699 if (data.SetSystemTime)
3700 Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource));
3701 // TRANSLATORS: note the plural!
3702 Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), &numLanguages, 0, I18nLanguages()->Size()));
3703 for (int i = 0; i < numLanguages; i++)
3704 // TRANSLATORS: note the singular!
3705 Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3706
3708 Display();
3709}
3710
3712{
3713 if (Key == kOk) {
3714 bool Modified = numLanguages != originalNumLanguages;
3715 if (!Modified) {
3716 for (int i = 0; i < numLanguages; i++) {
3717 if (data.EPGLanguages[i] != ::Setup.EPGLanguages[i]) {
3718 Modified = true;
3719 break;
3720 }
3721 }
3722 }
3723 if (Modified)
3725 }
3726
3727 int oldnumLanguages = numLanguages;
3728 int oldSetSystemTime = data.SetSystemTime;
3729
3731 if (Key != kNone) {
3732 if (numLanguages != oldnumLanguages || data.SetSystemTime != oldSetSystemTime) {
3733 for (int i = oldnumLanguages; i < numLanguages; i++) {
3734 data.EPGLanguages[i] = 0;
3735 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3736 int k;
3737 for (k = 0; k < oldnumLanguages; k++) {
3738 if (data.EPGLanguages[k] == l)
3739 break;
3740 }
3741 if (k >= oldnumLanguages) {
3742 data.EPGLanguages[i] = l;
3743 break;
3744 }
3745 }
3746 }
3748 Setup();
3749 }
3750 if (Key == kRed) {
3752 return osEnd;
3753 }
3754 }
3755 return state;
3756}
3757
3758// --- cMenuSetupDVB ---------------------------------------------------------
3759
3761private:
3766 void Setup(void);
3768 const char *updateChannelsTexts[6];
3770public:
3771 cMenuSetupDVB(void);
3772 virtual eOSState ProcessKey(eKeys Key);
3773 };
3774
3776{
3779 ;
3781 ;
3784 videoDisplayFormatTexts[0] = tr("pan&scan");
3785 videoDisplayFormatTexts[1] = tr("letterbox");
3786 videoDisplayFormatTexts[2] = tr("center cut out");
3787 updateChannelsTexts[0] = tr("no");
3788 updateChannelsTexts[1] = tr("names only");
3789 updateChannelsTexts[2] = tr("PIDs only");
3790 updateChannelsTexts[3] = tr("names and PIDs");
3791 updateChannelsTexts[4] = tr("add new channels");
3792 updateChannelsTexts[5] = tr("add new transponders");
3793 standardComplianceTexts[0] = "DVB";
3794 standardComplianceTexts[1] = "ANSI/SCTE";
3795 standardComplianceTexts[2] = "NORDIG";
3796
3797 SetSection(tr("DVB"));
3798 SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL);
3799 Setup();
3800}
3801
3803{
3804 int current = Current();
3805
3806 Clear();
3807
3808 Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
3809 Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"), &data.StandardCompliance, 3, standardComplianceTexts));
3810 Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
3811 if (data.VideoFormat == 0)
3812 Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
3813 Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital));
3814 Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts));
3815 Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
3816 for (int i = 0; i < numAudioLanguages; i++)
3817 Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3818 Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
3819 if (data.DisplaySubtitles) {
3820 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
3821 for (int i = 0; i < numSubtitleLanguages; i++)
3822 Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3823 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -100, 100));
3824 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
3825 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
3826 }
3827
3829 Display();
3830}
3831
3833{
3834 int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
3835 bool oldVideoFormat = ::Setup.VideoFormat;
3836 bool newVideoFormat = data.VideoFormat;
3837 bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
3838 bool newDisplaySubtitles = data.DisplaySubtitles;
3839 int oldnumAudioLanguages = numAudioLanguages;
3840 int oldnumSubtitleLanguages = numSubtitleLanguages;
3842
3843 if (Key != kNone) {
3844 switch (Key) {
3845 case kGreen: cRemote::Put(kAudio, true);
3846 state = osEnd;
3847 break;
3848 case kYellow: cRemote::Put(kSubtitles, true);
3849 state = osEnd;
3850 break;
3851 default: {
3852 bool DoSetup = data.VideoFormat != newVideoFormat;
3853 DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
3854 if (numAudioLanguages != oldnumAudioLanguages) {
3855 for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
3856 data.AudioLanguages[i] = 0;
3857 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3858 int k;
3859 for (k = 0; k < oldnumAudioLanguages; k++) {
3860 if (data.AudioLanguages[k] == l)
3861 break;
3862 }
3863 if (k >= oldnumAudioLanguages) {
3864 data.AudioLanguages[i] = l;
3865 break;
3866 }
3867 }
3868 }
3870 DoSetup = true;
3871 }
3872 if (numSubtitleLanguages != oldnumSubtitleLanguages) {
3873 for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
3874 data.SubtitleLanguages[i] = 0;
3875 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3876 int k;
3877 for (k = 0; k < oldnumSubtitleLanguages; k++) {
3878 if (data.SubtitleLanguages[k] == l)
3879 break;
3880 }
3881 if (k >= oldnumSubtitleLanguages) {
3882 data.SubtitleLanguages[i] = l;
3883 break;
3884 }
3885 }
3886 }
3888 DoSetup = true;
3889 }
3890 if (DoSetup)
3891 Setup();
3892 }
3893 }
3894 }
3895 if (state == osBack && Key == kOk) {
3896 if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
3898 if (::Setup.VideoFormat != oldVideoFormat)
3900 if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
3903 }
3904 return state;
3905}
3906
3907// --- cMenuSetupLNB ---------------------------------------------------------
3908
3910private:
3912 void Setup(void);
3913public:
3914 cMenuSetupLNB(void);
3915 virtual eOSState ProcessKey(eKeys Key);
3916 };
3917
3919:satCableNumbers(MAXDEVICES)
3920{
3923 SetSection(tr("LNB"));
3924 Setup();
3925}
3926
3928{
3929 int current = Current();
3930
3931 Clear();
3932
3933 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
3934 if (!data.DiSEqC) {
3935 Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
3936 Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
3937 Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
3938 }
3939
3940 int NumSatDevices = 0;
3941 for (int i = 0; i < cDevice::NumDevices(); i++) {
3943 NumSatDevices++;
3944 }
3945 if (NumSatDevices > 1) {
3946 for (int i = 0; i < cDevice::NumDevices(); i++) {
3948 Add(new cMenuEditIntItem(cString::sprintf(tr("Setup.LNB$Device %d connected to sat cable"), i + 1), &satCableNumbers.Array()[i], 0, NumSatDevices, tr("Setup.LNB$own")));
3949 else
3950 satCableNumbers.Array()[i] = 0;
3951 }
3952 }
3953
3954 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use dish positioner"), &data.UsePositioner));
3955 if (data.UsePositioner) {
3956 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site latitude (degrees)"), &data.SiteLat, -900, 900, 10, tr("South"), tr("North")));
3957 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site longitude (degrees)"), &data.SiteLon, -1800, 1800, 10, tr("West"), tr("East")));
3958 Add(new cMenuEditIntxItem(tr("Setup.LNB$Max. positioner swing (degrees)"), &data.PositionerSwing, 0, 900, 10));
3959 Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed (degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
3960 }
3961
3963 Display();
3964}
3965
3967{
3968 int oldDiSEqC = data.DiSEqC;
3969 int oldUsePositioner = data.UsePositioner;
3970 bool DeviceBondingsChanged = false;
3971 if (Key == kOk) {
3972 cString NewDeviceBondings = satCableNumbers.ToString();
3973 DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
3974 data.DeviceBondings = NewDeviceBondings;
3975 }
3977
3978 if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner != oldUsePositioner))
3979 Setup();
3980 else if (DeviceBondingsChanged)
3982 return state;
3983}
3984
3985// --- cMenuSetupCAM ---------------------------------------------------------
3986
3988private:
3990public:
3992 cCamSlot *CamSlot(void) { return camSlot; }
3993 bool Changed(void);
3994 };
3995
3997{
3998 camSlot = CamSlot;
3999 SetText("");
4000 Changed();
4001}
4002
4004{
4005 cString AssignedDevice("");
4006 const char *Activating = "";
4007 const char *CamName = camSlot->GetCamName();
4008 if (!CamName) {
4009 switch (camSlot->ModuleStatus()) {
4010 case msReset: CamName = tr("CAM reset"); break;
4011 case msPresent: CamName = tr("CAM present"); break;
4012 case msReady: CamName = tr("CAM ready"); break;
4013 default: CamName = "-"; break;
4014 }
4015 }
4016 else if (camSlot->IsActivating())
4017 // TRANSLATORS: note the leading blank!
4018 Activating = tr(" (activating)");
4019 cVector<int> DeviceNumbers;
4021 if (CamSlot == camSlot || CamSlot->MasterSlot() == camSlot)
4022 CamSlot->Devices(DeviceNumbers);
4023 }
4024 if (DeviceNumbers.Size() > 0) {
4025 AssignedDevice = cString::sprintf(" %s", tr("@ device"));
4026 DeviceNumbers.Sort(CompareInts);
4027 for (int i = 0; i < DeviceNumbers.Size(); i++)
4028 AssignedDevice = cString::sprintf("%s %d", *AssignedDevice, DeviceNumbers[i]);
4029 }
4030
4031 cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
4032 if (strcmp(buffer, Text()) != 0) {
4033 SetText(buffer);
4034 return true;
4035 }
4036 return false;
4037}
4038
4040private:
4042 const char *activationHelp;
4043 eOSState Menu(void);
4044 eOSState Reset(void);
4045 eOSState Activate(void);
4046 void SetHelpKeys(void);
4047public:
4048 cMenuSetupCAM(void);
4049 virtual eOSState ProcessKey(eKeys Key);
4050 };
4051
4053{
4055 activationHelp = NULL;
4057 SetSection(tr("CAM"));
4058 SetCols(15);
4059 SetHasHotkeys();
4060 for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
4061 if (CamSlot->IsMasterSlot()) // we only list master CAM slots
4062 Add(new cMenuSetupCAMItem(CamSlot));
4063 }
4064 SetHelpKeys();
4065}
4066
4068{
4069 if (HasSubMenu())
4070 return;
4072 const char *NewActivationHelp = "";
4073 if (item) {
4074 cCamSlot *CamSlot = item->CamSlot();
4075 if (CamSlot->IsActivating())
4076 NewActivationHelp = tr("Button$Cancel activation");
4077 else if (CamSlot->CanActivate())
4078 NewActivationHelp = tr("Button$Activate");
4079 }
4080 if (NewActivationHelp != activationHelp) {
4081 activationHelp = NewActivationHelp;
4082 SetHelp(tr("Button$Menu"), tr("Button$Reset"), activationHelp);
4083 }
4084}
4085
4087{
4089 if (item) {
4090 if (item->CamSlot()->EnterMenu()) {
4091 Skins.Message(mtStatus, tr("Opening CAM menu..."));
4092 time_t t0 = time(NULL);
4093 time_t t1 = t0;
4094 while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
4095 if (item->CamSlot()->HasUserIO())
4096 break;
4097 if (time(NULL) - t1 >= CAMMENURETRYTIMEOUT) {
4098 dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
4099 item->CamSlot()->EnterMenu();
4100 t1 = time(NULL);
4101 }
4102 cCondWait::SleepMs(100);
4103 }
4104 Skins.Message(mtStatus, NULL);
4105 if (item->CamSlot()->HasUserIO())
4106 return AddSubMenu(new cMenuCam(item->CamSlot()));
4107 }
4108 Skins.Message(mtError, tr("Can't open CAM menu!"));
4109 }
4110 return osContinue;
4111}
4112
4114{
4116 if (item) {
4117 cCamSlot *CamSlot = item->CamSlot();
4118 if (CamSlot->IsActivating())
4119 CamSlot->CancelActivation();
4120 else if (CamSlot->CanActivate()) {
4121 if (CamSlot->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4123 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel())) {
4124 for (int i = 0; i < cDevice::NumDevices(); i++) {
4125 if (cDevice *Device = cDevice::GetDevice(i)) {
4126 if (Device->ProvidesChannel(Channel)) {
4127 if (Device->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4128 if (CamSlot->Assign(Device, true)) { // query
4129 cControl::Shutdown(); // must end transfer mode before assigning CAM, otherwise it might be unassigned again
4130 CamSlot = CamSlot->MtdSpawn();
4131 if (CamSlot->Assign(Device)) {
4132 if (Device->SwitchChannel(Channel, true)) {
4133 CamSlot->StartActivation();
4134 return osContinue;
4135 }
4136 }
4137 }
4138 }
4139 }
4140 }
4141 }
4142 }
4143 }
4144 Skins.Message(mtError, tr("Can't activate CAM!"));
4145 }
4146 }
4147 return osContinue;
4148}
4149
4151{
4153 if (item) {
4154 if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
4155 if (!item->CamSlot()->Reset())
4156 Skins.Message(mtError, tr("Can't reset CAM!"));
4157 }
4158 }
4159 return osContinue;
4160}
4161
4163{
4165
4166 if (!HasSubMenu()) {
4167 switch (Key) {
4168 case kOk:
4169 case kRed: return Menu();
4170 case kGreen: state = Reset(); break;
4171 case kYellow: state = Activate(); break;
4172 default: break;
4173 }
4174 for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
4175 if (ci->Changed())
4176 DisplayItem(ci);
4177 }
4178 SetHelpKeys();
4179 }
4181 state = osEnd;
4182 return state;
4183}
4184
4185// --- cMenuSetupRecord ------------------------------------------------------
4186
4188private:
4191 const char *delTimeshiftRecTexts[3];
4192public:
4193 cMenuSetupRecord(void);
4194 };
4195
4197{
4199 recordKeyHandlingTexts[0] = tr("no instant recording");
4200 recordKeyHandlingTexts[1] = tr("confirm instant recording");
4201 recordKeyHandlingTexts[2] = tr("record instantly");
4202 pauseKeyHandlingTexts[0] = tr("do not pause live video");
4203 pauseKeyHandlingTexts[1] = tr("confirm pause live video");
4204 pauseKeyHandlingTexts[2] = tr("pause live video");
4205 delTimeshiftRecTexts[0] = tr("no");
4206 delTimeshiftRecTexts[1] = tr("confirm");
4207 delTimeshiftRecTexts[2] = tr("yes");
4208 SetSection(tr("Recording"));
4209 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
4210 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
4211 Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
4212 Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
4213 Add(new cMenuEditStraItem(tr("Setup.Recording$Record key handling"), &data.RecordKeyHandling, 3, recordKeyHandlingTexts));
4214 Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
4215 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
4216 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
4217 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
4218 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
4219 Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
4220 Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
4221 Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
4222 Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
4223 Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
4224 Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
4225 Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
4226}
4227
4228// --- cMenuSetupReplay ------------------------------------------------------
4229
4231protected:
4232 virtual void Store(void);
4233public:
4234 cMenuSetupReplay(void);
4235 };
4236
4238{
4240 SetSection(tr("Replay"));
4241 Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
4242 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
4243 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
4244 Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
4245 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
4246 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when jumping to a mark"), &data.PauseOnMarkJump));
4247 Add(new cMenuEditBoolItem(tr("Setup.Replay$Skip edited parts"), &data.SkipEdited));
4248 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay at last mark"), &data.PauseAtLastMark));
4249 Add(new cMenuEditIntItem( tr("Setup.Replay$Initial duration for adaptive skipping (s)"), &data.AdaptiveSkipInitial, 10, 600));
4250 Add(new cMenuEditIntItem( tr("Setup.Replay$Reset timeout for adaptive skipping (s)"), &data.AdaptiveSkipTimeout, 0, 10));
4251 Add(new cMenuEditBoolItem(tr("Setup.Replay$Alternate behavior for adaptive skipping"), &data.AdaptiveSkipAlternate));
4252 Add(new cMenuEditBoolItem(tr("Setup.Replay$Use Prev/Next keys for adaptive skipping"), &data.AdaptiveSkipPrevNext));
4253 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys (s)"), &data.SkipSeconds, 5, 600));
4254 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys in repeat (s)"), &data.SkipSecondsRepeat, 5, 600));
4255 Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
4256}
4257
4259{
4260 if (Setup.ResumeID != data.ResumeID) {
4262 Recordings->ResetResume();
4263 }
4265}
4266
4267// --- cMenuSetupMisc --------------------------------------------------------
4268
4270private:
4274 void Set(void);
4275public:
4276 cMenuSetupMisc(void);
4277 virtual eOSState ProcessKey(eKeys Key);
4278 };
4279
4281{
4283 svdrpPeeringModeTexts[0] = tr("off");
4284 svdrpPeeringModeTexts[1] = tr("any hosts");
4285 svdrpPeeringModeTexts[2] = tr("only default host");
4289 SetSection(tr("Miscellaneous"));
4290 Set();
4291}
4292
4294{
4295 int current = Current();
4296 Clear();
4297 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
4298 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
4299 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
4300 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$SVDRP peering"), &data.SVDRPPeering, 3, svdrpPeeringModeTexts));
4301 if (data.SVDRPPeering) {
4302 Add(new cMenuEditStrItem( tr("Setup.Miscellaneous$SVDRP host name"), data.SVDRPHostName, sizeof(data.SVDRPHostName)));
4304 svdrpServerNames.Sort(true);
4305 svdrpServerNames.Insert(strdup(""));
4306 Add(new cMenuEditStrlItem(tr("Setup.Miscellaneous$SVDRP default host"), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames));
4307 }
4308 }
4309 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
4310 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
4311 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0));
4312 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0));
4313 Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
4314 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
4315 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume steps"), &data.VolumeSteps, 5, 255));
4316 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume linearize"), &data.VolumeLinearize, -20, 20));
4317 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
4318 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource, 3, showChannelNamesWithSourceTexts));
4319 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
4321 Display();
4322}
4323
4325{
4326 bool OldSVDRPPeering = data.SVDRPPeering;
4327 bool ModifiedSVDRPSettings = false;
4328 if (Key == kOk)
4329 ModifiedSVDRPSettings = data.SVDRPPeering != Setup.SVDRPPeering || strcmp(data.SVDRPHostName, Setup.SVDRPHostName);
4331 if (data.SVDRPPeering != OldSVDRPPeering)
4332 Set();
4333 if (ModifiedSVDRPSettings) {
4335 {
4337 Timers->SetExplicitModify();
4338 if (Timers->StoreRemoteTimers(NULL, NULL))
4339 Timers->SetModified();
4340 }
4342 }
4343 return state;
4344}
4345
4346// --- cMenuSetupPluginItem --------------------------------------------------
4347
4349private:
4351public:
4352 cMenuSetupPluginItem(const char *Name, int Index);
4353 int PluginIndex(void) { return pluginIndex; }
4354 };
4355
4357:cOsdItem(Name)
4358{
4360}
4361
4362// --- cMenuSetupPlugins -----------------------------------------------------
4363
4365public:
4366 cMenuSetupPlugins(void);
4367 virtual eOSState ProcessKey(eKeys Key);
4368 };
4369
4371{
4373 SetSection(tr("Plugins"));
4374 SetHasHotkeys();
4375 for (int i = 0; ; i++) {
4377 if (p)
4378 Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
4379 else
4380 break;
4381 }
4382}
4383
4385{
4387
4388 if (Key == kOk) {
4389 if (state == osUnknown) {
4391 if (item) {
4393 if (p) {
4394 cMenuSetupPage *menu = p->SetupMenu();
4395 if (menu) {
4396 menu->SetPlugin(p);
4397 return AddSubMenu(menu);
4398 }
4399 Skins.Message(mtInfo, tr("This plugin has no setup parameters!"));
4400 }
4401 }
4402 }
4403 else if (state == osContinue) {
4404 Store();
4405 // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
4407 Display();
4408 }
4409 }
4410 return state;
4411}
4412
4413// --- cMenuSetup ------------------------------------------------------------
4414
4415class cMenuSetup : public cOsdMenu {
4416private:
4417 virtual void Set(void);
4418 eOSState Restart(void);
4419public:
4420 cMenuSetup(void);
4421 virtual eOSState ProcessKey(eKeys Key);
4422 };
4423
4425:cOsdMenu("")
4426{
4428 Set();
4429}
4430
4432{
4433 Clear();
4434 char buffer[64];
4435 snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
4436 SetTitle(buffer);
4437 SetHasHotkeys();
4438 Add(new cOsdItem(hk(tr("OSD")), osUser1));
4439 Add(new cOsdItem(hk(tr("EPG")), osUser2));
4440 Add(new cOsdItem(hk(tr("DVB")), osUser3));
4441 Add(new cOsdItem(hk(tr("LNB")), osUser4));
4442 Add(new cOsdItem(hk(tr("CAM")), osUser5));
4443 Add(new cOsdItem(hk(tr("Recording")), osUser6));
4444 Add(new cOsdItem(hk(tr("Replay")), osUser7));
4445 Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
4447 Add(new cOsdItem(hk(tr("Plugins")), osUser9));
4448 Add(new cOsdItem(hk(tr("Restart")), osUser10));
4449}
4450
4452{
4453 if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
4455 return osEnd;
4456 }
4457 return osContinue;
4458}
4459
4461{
4462 int osdLanguage = I18nCurrentLanguage();
4463 eOSState state = cOsdMenu::ProcessKey(Key);
4464
4465 switch (state) {
4466 case osUser1: return AddSubMenu(new cMenuSetupOSD);
4467 case osUser2: return AddSubMenu(new cMenuSetupEPG);
4468 case osUser3: return AddSubMenu(new cMenuSetupDVB);
4469 case osUser4: return AddSubMenu(new cMenuSetupLNB);
4470 case osUser5: return AddSubMenu(new cMenuSetupCAM);
4471 case osUser6: return AddSubMenu(new cMenuSetupRecord);
4472 case osUser7: return AddSubMenu(new cMenuSetupReplay);
4473 case osUser8: return AddSubMenu(new cMenuSetupMisc);
4474 case osUser9: return AddSubMenu(new cMenuSetupPlugins);
4475 case osUser10: return Restart();
4476 default: ;
4477 }
4478 if (I18nCurrentLanguage() != osdLanguage) {
4479 Set();
4480 if (!HasSubMenu())
4481 Display();
4482 }
4483 return state;
4484}
4485
4486// --- cMenuPluginItem -------------------------------------------------------
4487
4489private:
4491public:
4492 cMenuPluginItem(const char *Name, int Index);
4493 int PluginIndex(void) { return pluginIndex; }
4494 };
4495
4496cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
4497:cOsdItem(Name, osPlugin)
4498{
4500}
4501
4502// --- cMenuMain -------------------------------------------------------------
4503
4504// TRANSLATORS: note the leading and trailing blanks!
4505#define STOP_RECORDING trNOOP(" Stop recording ")
4506
4508
4509cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
4510:cOsdMenu("")
4511{
4513 replaying = false;
4514 stopReplayItem = NULL;
4515 cancelEditingItem = NULL;
4516 stopRecordingItem = NULL;
4518 Set();
4519
4520 // Initial submenus:
4521
4522 cOsdObject *menu = NULL;
4523 switch (State) {
4524 case osSchedule:
4525 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4526 menu = new cMenuSchedule;
4527 break;
4528 case osChannels:
4529 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4530 menu = new cMenuChannels;
4531 break;
4532 case osTimers:
4533 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4534 menu = new cMenuTimers;
4535 break;
4536 case osRecordings:
4537 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4538 menu = new cMenuRecordings(NULL, 0, true);
4539 break;
4540 case osSetup: menu = new cMenuSetup; break;
4541 case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4542 default: break;
4543 }
4544 if (menu)
4545 if (menu->IsMenu())
4546 AddSubMenu((cOsdMenu *) menu);
4547}
4548
4550{
4552 pluginOsdObject = NULL;
4553 return o;
4554}
4555
4557{
4558 Clear();
4559 SetTitle("VDR");
4560 SetHasHotkeys();
4561
4562 // Basic menu items:
4563
4564 Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
4565 Add(new cOsdItem(hk(tr("Channels")), osChannels));
4566 Add(new cOsdItem(hk(tr("Timers")), osTimers));
4567 Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
4568
4569 // Plugins:
4570
4571 for (int i = 0; ; i++) {
4573 if (p) {
4574 const char *item = p->MainMenuEntry();
4575 if (item)
4576 Add(new cMenuPluginItem(hk(item), i));
4577 }
4578 else
4579 break;
4580 }
4581
4582 // More basic menu items:
4583
4584 Add(new cOsdItem(hk(tr("Setup")), osSetup));
4585 if (Commands.Count())
4586 Add(new cOsdItem(hk(tr("Commands")), osCommands));
4587
4588 Update(true);
4589
4590 Display();
4591}
4592
4593bool cMenuMain::Update(bool Force)
4594{
4595 bool result = false;
4596
4597 bool NewReplaying = false;
4598 {
4599 cMutexLock ControlMutexLock;
4600 NewReplaying = cControl::Control(ControlMutexLock) != NULL;
4601 }
4602 if (Force || NewReplaying != replaying) {
4603 replaying = NewReplaying;
4604 // Replay control:
4605 if (replaying && !stopReplayItem)
4606 // TRANSLATORS: note the leading blank!
4607 Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
4608 else if (stopReplayItem && !replaying) {
4610 stopReplayItem = NULL;
4611 }
4612 // Color buttons:
4613 SetHelp(!replaying && Setup.RecordKeyHandling ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying || !Setup.PauseKeyHandling ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : tr("Button$Play"));
4614 result = true;
4615 }
4616
4617 // Editing control:
4618 bool EditingActive = RecordingsHandler.Active();
4619 if (EditingActive && !cancelEditingItem) {
4620 // TRANSLATORS: note the leading blank!
4621 Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
4622 result = true;
4623 }
4624 else if (cancelEditingItem && !EditingActive) {
4626 cancelEditingItem = NULL;
4627 result = true;
4628 }
4629
4630 // Record control:
4632 while (stopRecordingItem) {
4635 stopRecordingItem = it;
4636 }
4637 const char *s = NULL;
4638 while ((s = cRecordControls::GetInstantId(s)) != NULL) {
4639 cOsdItem *item = new cOsdItem(osStopRecord);
4640 item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
4641 Add(item);
4642 if (!stopRecordingItem)
4643 stopRecordingItem = item;
4644 }
4645 result = true;
4646 }
4647
4648 return result;
4649}
4650
4652{
4653 bool HadSubMenu = HasSubMenu();
4654 int osdLanguage = I18nCurrentLanguage();
4655 eOSState state = cOsdMenu::ProcessKey(Key);
4656 HadSubMenu |= HasSubMenu();
4657
4658 cOsdObject *menu = NULL;
4659 switch (state) {
4660 case osSchedule:
4661 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4662 menu = new cMenuSchedule;
4663 else
4664 state = osContinue;
4665 break;
4666 case osChannels:
4667 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4668 menu = new cMenuChannels;
4669 else
4670 state = osContinue;
4671 break;
4672 case osTimers:
4673 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4674 menu = new cMenuTimers;
4675 else
4676 state = osContinue;
4677 break;
4678 case osRecordings:
4679 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4680 menu = new cMenuRecordings;
4681 else
4682 state = osContinue;
4683 break;
4684 case osSetup: menu = new cMenuSetup; break;
4685 case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4686 case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
4687 if (cOsdItem *item = Get(Current())) {
4688 cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
4689 return osEnd;
4690 }
4691 }
4692 break;
4693 case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
4695 return osEnd;
4696 }
4697 break;
4698 case osPlugin: {
4700 if (item) {
4702 if (p) {
4703 cOsdObject *menu = p->MainMenuAction();
4704 if (menu) {
4705 if (menu->IsMenu())
4706 return AddSubMenu((cOsdMenu *)menu);
4707 else {
4708 pluginOsdObject = menu;
4709 return osPlugin;
4710 }
4711 }
4712 }
4713 }
4714 state = osEnd;
4715 }
4716 break;
4717 default: switch (Key) {
4718 case kRecord:
4719 case kRed: if (!HadSubMenu)
4721 break;
4722 case kGreen: if (!HadSubMenu) {
4723 cRemote::Put(kAudio, true);
4724 state = osEnd;
4725 }
4726 break;
4727 case kYellow: if (!HadSubMenu)
4729 break;
4730 case kBlue: if (!HadSubMenu)
4732 break;
4733 default: break;
4734 }
4735 }
4736 if (menu) {
4737 if (menu->IsMenu())
4738 return AddSubMenu((cOsdMenu *) menu);
4739 pluginOsdObject = menu;
4740 return osPlugin;
4741 }
4742 if (!HasSubMenu() && Update(HadSubMenu))
4743 Display();
4744 if (Key != kNone) {
4745 if (I18nCurrentLanguage() != osdLanguage) {
4746 Set();
4747 if (!HasSubMenu())
4748 Display();
4749 }
4750 }
4751 return state;
4752}
4753
4754// --- SetTrackDescriptions --------------------------------------------------
4755
4756static void SetTrackDescriptions(int LiveChannel)
4757{
4759 const cComponents *Components = NULL;
4760 if (LiveChannel) {
4762 if (const cChannel *Channel = Channels->GetByNumber(LiveChannel)) {
4764 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
4765 const cEvent *Present = Schedule->GetPresentEvent();
4766 if (Present)
4767 Components = Present->Components();
4768 }
4769 }
4770 }
4771 else if (cReplayControl::NowReplaying()) {
4773 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::NowReplaying()))
4774 Components = Recording->Info()->Components();
4775 }
4776 if (Components) {
4777 int indexAudio = 0;
4778 int indexDolby = 0;
4779 int indexSubtitle = 0;
4780 for (int i = 0; i < Components->NumComponents(); i++) {
4781 const tComponent *p = Components->Component(i);
4782 switch (p->stream) {
4783 case 2: if (p->type == 0x05)
4784 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4785 else
4786 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
4787 break;
4788 case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
4789 break;
4790 case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4791 break;
4792 default: ;
4793 }
4794 }
4795 }
4796}
4797
4798// --- cDisplayChannel -------------------------------------------------------
4799
4801
4802cDisplayChannel::cDisplayChannel(int Number, bool Switched)
4803:cOsdObject(true)
4804{
4805 currentDisplayChannel = this;
4806 group = -1;
4807 withInfo = !Switched || Setup.ShowInfoOnChSwitch;
4809 number = 0;
4810 timeout = Switched || Setup.TimeoutRequChInfo;
4811 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4812 positioner = NULL;
4813 channel = NULL;
4814 {
4816 channel = Channels->GetByNumber(Number);
4817 lastPresent = lastFollowing = NULL;
4818 if (channel) {
4820 DisplayInfo();
4821 }
4822 }
4823 if (channel)
4825 lastTime.Set();
4826}
4827
4829:cOsdObject(true)
4830{
4831 currentDisplayChannel = this;
4832 group = -1;
4833 number = 0;
4834 timeout = true;
4835 lastPresent = lastFollowing = NULL;
4836 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4837 lastTime.Set();
4840 positioner = NULL;
4841 channel = NULL;
4842 {
4844 channel = Channels->GetByNumber(cDevice::CurrentChannel());
4845 }
4846 ProcessKey(FirstKey);
4847}
4848
4850{
4851 delete displayChannel;
4852 currentDisplayChannel = NULL;
4854}
4855
4857{
4860 lastPresent = lastFollowing = NULL;
4861 lastTime.Set();
4862}
4863
4865{
4866 if (withInfo && channel) {
4868 if (const cSchedule *Schedule = Schedules->GetSchedule(channel)) {
4869 const cEvent *Present = Schedule->GetPresentEvent();
4870 const cEvent *Following = Schedule->GetFollowingEvent();
4871 if (Present != lastPresent || Following != lastFollowing) {
4873 displayChannel->SetEvents(Present, Following);
4874 cStatus::MsgOsdProgramme(Present ? Present->StartTime() : 0, Present ? Present->Title() : NULL, Present ? Present->ShortText() : NULL, Following ? Following->StartTime() : 0, Following ? Following->Title() : NULL, Following ? Following->ShortText() : NULL);
4875 lastPresent = Present;
4876 lastFollowing = Following;
4877 lastTime.Set();
4878 }
4879 }
4880 }
4881}
4882
4884{
4886 displayChannel->SetEvents(NULL, NULL);
4887}
4888
4889const cChannel *cDisplayChannel::NextAvailableChannel(const cChannel *Channel, int Direction)
4890{
4891 if (Direction) {
4892 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
4893 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
4895 while (Channel) {
4896 Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel);
4897 if (!Channel && Setup.ChannelsWrap)
4898 Channel = Direction > 0 ? Channels->First() : Channels->Last();
4899 if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
4900 return Channel;
4901 }
4902 }
4903 return NULL;
4904}
4905
4907{
4909 delete displayChannel;
4911 }
4912 const cChannel *NewChannel = NULL;
4913 if (Key != kNone)
4914 lastTime.Set();
4915 switch (int(Key)) {
4916 case k0:
4917 if (number == 0) {
4918 // keep the "Toggle channels" function working
4919 cRemote::Put(Key);
4920 return osEnd;
4921 }
4922 case k1 ... k9:
4923 group = -1;
4924 if (number >= 0) {
4926 number = Key - k0;
4927 else
4928 number = number * 10 + Key - k0;
4930 channel = Channels->GetByNumber(number);
4931 Refresh();
4932 withInfo = false;
4933 // Lets see if there can be any useful further input:
4934 int n = channel ? number * 10 : 0;
4935 int m = 10;
4936 const cChannel *ch = channel;
4937 while (ch && (ch = Channels->Next(ch)) != NULL) {
4938 if (!ch->GroupSep()) {
4939 if (n <= ch->Number() && ch->Number() < n + m) {
4940 n = 0;
4941 break;
4942 }
4943 if (ch->Number() > n) {
4944 n *= 10;
4945 m *= 10;
4946 }
4947 }
4948 }
4949 if (n > 0) {
4950 // This channel is the only one that fits the input, so let's take it right away:
4951 NewChannel = channel;
4952 withInfo = true;
4953 number = 0;
4954 Refresh();
4955 }
4956 }
4957 break;
4958 case kLeft|k_Repeat:
4959 case kLeft:
4960 case kRight|k_Repeat:
4961 case kRight:
4962 case kNext|k_Repeat:
4963 case kNext:
4964 case kPrev|k_Repeat:
4965 case kPrev: {
4966 withInfo = false;
4967 number = 0;
4969 if (group < 0) {
4970 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
4971 group = Channel->Index();
4972 }
4973 if (group >= 0) {
4974 int SaveGroup = group;
4975 if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
4976 group = Channels->GetNextGroup(group) ;
4977 else
4978 group = Channels->GetPrevGroup(group < 1 ? 1 : group);
4979 if (group < 0)
4980 group = SaveGroup;
4981 channel = Channels->Get(group);
4982 if (channel) {
4983 Refresh();
4984 if (!channel->GroupSep())
4985 group = -1;
4986 }
4987 }
4988 break;
4989 }
4990 case kUp|k_Repeat:
4991 case kUp:
4992 case kDown|k_Repeat:
4993 case kDown:
4994 case kChanUp|k_Repeat:
4995 case kChanUp:
4996 case kChanDn|k_Repeat:
4997 case kChanDn: {
4998 eKeys k = NORMALKEY(Key);
4999 if (const cChannel *Channel = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1))
5000 channel = Channel;
5001 else if (channel && channel->Number() != cDevice::CurrentChannel())
5002 Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
5003 }
5004 // no break here
5005 case kUp|k_Release:
5006 case kDown|k_Release:
5007 case kChanUp|k_Release:
5008 case kChanDn|k_Release:
5009 case kNext|k_Release:
5010 case kPrev|k_Release:
5011 if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
5012 NewChannel = channel;
5013 withInfo = true;
5014 group = -1;
5015 number = 0;
5016 Refresh();
5017 break;
5018 case kNone:
5021 channel = Channels->GetByNumber(number);
5022 if (channel)
5023 NewChannel = channel;
5024 withInfo = true;
5025 number = 0;
5026 Refresh();
5027 lastTime.Set();
5028 }
5029 break;
5030 //TODO
5031 //XXX case kGreen: return osEventNow;
5032 //XXX case kYellow: return osEventNext;
5033 case kOk: {
5035 if (group >= 0) {
5036 channel = Channels->Get(Channels->GetNextNormal(group));
5037 if (channel)
5038 NewChannel = channel;
5039 withInfo = true;
5040 group = -1;
5041 Refresh();
5042 }
5043 else if (number > 0) {
5044 channel = Channels->GetByNumber(number);
5045 if (channel)
5046 NewChannel = channel;
5047 withInfo = true;
5048 number = 0;
5049 Refresh();
5050 }
5051 else {
5052 return osEnd;
5053 }
5054 }
5055 break;
5056 default:
5057 if ((Key & (k_Repeat | k_Release)) == 0) {
5058 cRemote::Put(Key);
5059 return osEnd;
5060 }
5061 };
5062 if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
5063 {
5065 if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
5066 // makes sure a channel switch through the SVDRP CHAN command is displayed
5067 channel = Channels->GetByNumber(cDevice::CurrentChannel());
5068 Refresh();
5069 lastTime.Set();
5070 }
5071 DisplayInfo();
5072 if (NewChannel) {
5073 SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
5074 Channels->SwitchTo(NewChannel->Number());
5075 SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
5076 channel = NewChannel;
5077 }
5078 const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
5079 bool PositionerMoving = Positioner && Positioner->IsMoving();
5080 SetNeedsFastResponse(PositionerMoving);
5081 if (!PositionerMoving) {
5082 if (positioner)
5083 lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
5084 Positioner = NULL;
5085 }
5086 if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
5087 displayChannel->SetPositioner(Positioner);
5088 positioner = Positioner;
5089 }
5091 return osContinue;
5092 }
5093 return osEnd;
5094}
5095
5096// --- cDisplayVolume --------------------------------------------------------
5097
5098#define VOLUMETIMEOUT 1000 //ms
5099#define MUTETIMEOUT 5000 //ms
5100
5102
5104:cOsdObject(true)
5105{
5106 currentDisplayVolume = this;
5109 Show();
5110}
5111
5113{
5114 delete displayVolume;
5115 currentDisplayVolume = NULL;
5116}
5117
5119{
5121}
5122
5124{
5126 new cDisplayVolume;
5127 return currentDisplayVolume;
5128}
5129
5131{
5134}
5135
5137{
5138 switch (int(Key)) {
5139 case kVolUp|k_Repeat:
5140 case kVolUp:
5141 case kVolDn|k_Repeat:
5142 case kVolDn:
5143 Show();
5145 break;
5146 case kMute:
5147 if (cDevice::PrimaryDevice()->IsMute()) {
5148 Show();
5150 }
5151 else
5152 timeout.Set();
5153 break;
5154 case kNone: break;
5155 default: if ((Key & k_Release) == 0) {
5156 cRemote::Put(Key);
5157 return osEnd;
5158 }
5159 }
5160 return timeout.TimedOut() ? osEnd : osContinue;
5161}
5162
5163// --- cDisplayTracks --------------------------------------------------------
5164
5165#define TRACKTIMEOUT 5000 //ms
5166
5168
5170:cOsdObject(true)
5171{
5174 currentDisplayTracks = this;
5175 numTracks = track = 0;
5178 for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
5179 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5180 if (TrackId && TrackId->id) {
5182 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5183 if (i == CurrentAudioTrack)
5184 track = numTracks;
5185 numTracks++;
5186 }
5187 }
5188 descriptions[numTracks] = NULL;
5191 Show();
5192}
5193
5195{
5196 delete displayTracks;
5197 currentDisplayTracks = NULL;
5198 for (int i = 0; i < numTracks; i++)
5199 free(descriptions[i]);
5201}
5202
5204{
5205 int ac = IS_AUDIO_TRACK(types[track]) ? audioChannel : -1;
5211}
5212
5214{
5215 if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
5217 new cDisplayTracks;
5218 return currentDisplayTracks;
5219 }
5220 Skins.Message(mtWarning, tr("No audio available!"));
5221 return NULL;
5222}
5223
5225{
5228}
5229
5231{
5232 int oldTrack = track;
5233 int oldAudioChannel = audioChannel;
5234 switch (int(Key)) {
5235 case kUp|k_Repeat:
5236 case kUp:
5237 case kDown|k_Repeat:
5238 case kDown:
5239 if (NORMALKEY(Key) == kUp && track > 0)
5240 track--;
5241 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5242 track++;
5244 break;
5245 case kLeft|k_Repeat:
5246 case kLeft:
5247 case kRight|k_Repeat:
5248 case kRight: if (IS_AUDIO_TRACK(types[track])) {
5249 static int ac[] = { 1, 0, 2 };
5251 if (NORMALKEY(Key) == kLeft && audioChannel > 0)
5252 audioChannel--;
5253 else if (NORMALKEY(Key) == kRight && audioChannel < 2)
5254 audioChannel++;
5257 }
5258 break;
5259 case kAudio|k_Repeat:
5260 case kAudio:
5261 if (++track >= numTracks)
5262 track = 0;
5264 break;
5265 case kOk:
5266 if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
5267 oldTrack = -1; // make sure we explicitly switch to that track
5268 timeout.Set();
5269 break;
5270 case kNone: break;
5271 default: if ((Key & k_Release) == 0)
5272 return osEnd;
5273 }
5274 if (track != oldTrack || audioChannel != oldAudioChannel)
5275 Show();
5276 if (track != oldTrack) {
5279 }
5280 if (audioChannel != oldAudioChannel)
5282 return timeout.TimedOut() ? osEnd : osContinue;
5283}
5284
5285// --- cDisplaySubtitleTracks ------------------------------------------------
5286
5288
5290:cOsdObject(true)
5291{
5293 currentDisplayTracks = this;
5294 numTracks = track = 0;
5296 descriptions[numTracks] = strdup(tr("No subtitles"));
5297 numTracks++;
5298 eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
5299 for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
5300 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5301 if (TrackId && TrackId->id) {
5303 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5304 if (i == CurrentSubtitleTrack)
5305 track = numTracks;
5306 numTracks++;
5307 }
5308 }
5309 descriptions[numTracks] = NULL;
5311 displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
5312 Show();
5313}
5314
5316{
5317 delete displayTracks;
5318 currentDisplayTracks = NULL;
5319 for (int i = 0; i < numTracks; i++)
5320 free(descriptions[i]);
5322}
5323
5325{
5329}
5330
5332{
5333 if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
5336 return currentDisplayTracks;
5337 }
5338 Skins.Message(mtWarning, tr("No subtitles available!"));
5339 return NULL;
5340}
5341
5343{
5346}
5347
5349{
5350 int oldTrack = track;
5351 switch (int(Key)) {
5352 case kUp|k_Repeat:
5353 case kUp:
5354 case kDown|k_Repeat:
5355 case kDown:
5356 if (NORMALKEY(Key) == kUp && track > 0)
5357 track--;
5358 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5359 track++;
5361 break;
5362 case kSubtitles|k_Repeat:
5363 case kSubtitles:
5364 if (++track >= numTracks)
5365 track = 0;
5367 break;
5368 case kOk:
5369 if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
5370 oldTrack = -1; // make sure we explicitly switch to that track
5371 timeout.Set();
5372 break;
5373 case kNone: break;
5374 default: if ((Key & k_Release) == 0)
5375 return osEnd;
5376 }
5377 if (track != oldTrack) {
5378 Show();
5380 }
5381 return timeout.TimedOut() ? osEnd : osContinue;
5382}
5383
5384// --- cRecordControl --------------------------------------------------------
5385
5386cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause)
5387{
5388 const char *LastReplayed = cReplayControl::LastReplayed(); // must do this before locking schedules!
5389 // Whatever happens here, the timers will be modified in some way...
5390 Timers->SetModified();
5391 cStateKey ChannelsStateKey;
5392 // To create a new timer, we need to make shure there is
5393 // a lock on Channels prior to the Schedules locking below
5394 if (!Timer)
5395 cChannels::GetChannelsRead(ChannelsStateKey);
5396 // We're going to work with an event here, so we need to prevent
5397 // others from modifying any EPG data:
5398 cStateKey SchedulesStateKey;
5399 cSchedules::GetSchedulesRead(SchedulesStateKey);
5400
5401 event = NULL;
5402 fileName = NULL;
5403 recorder = NULL;
5404 device = Device;
5405 if (!device) device = cDevice::PrimaryDevice();//XXX
5406 timer = Timer;
5407 if (!timer) {
5408 timer = new cTimer(true, Pause);
5409 Timers->Add(timer);
5410 instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->DeviceNumber() + 1);
5411 ChannelsStateKey.Remove();
5412 }
5413 timer->SetPending(true);
5414 timer->SetRecording(true);
5415 event = timer->Event();
5416
5417 if (event || GetEvent())
5418 dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
5419 cRecording Recording(timer, event);
5420 fileName = strdup(Recording.FileName());
5421
5422 // crude attempt to avoid duplicate recordings:
5424 isyslog("already recording: '%s'", fileName);
5425 if (Timer) {
5426 timer->SetPending(false);
5427 timer->SetRecording(false);
5428 timer->OnOff();
5429 }
5430 else {
5431 Timers->Del(timer);
5432 if (!LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5434 }
5435 timer = NULL;
5436 SchedulesStateKey.Remove();
5437 return;
5438 }
5439
5441 isyslog("record %s", fileName);
5442 if (MakeDirs(fileName, true)) {
5443 Recording.WriteInfo(); // we write this *before* attaching the recorder to the device, to make sure the info file is present when the recorder needs to update the fps value!
5444 const cChannel *ch = timer->Channel();
5445 recorder = new cRecorder(fileName, ch, timer->Priority());
5447 cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
5448 if (!Timer && !LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5450 SchedulesStateKey.Remove();
5453 Recordings->AddByName(fileName);
5454 return;
5455 }
5456 else
5458 }
5459 else
5461 if (!Timer) {
5462 Timers->Del(timer);
5463 timer = NULL;
5464 }
5465 SchedulesStateKey.Remove();
5466}
5467
5469{
5470 Stop();
5471 free(fileName);
5472}
5473
5474#define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
5475
5477{
5478 const cChannel *Channel = timer->Channel();
5480 for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
5481 {
5483 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
5484 event = Schedule->GetEventAround(Time);
5485 if (event) {
5486 if (seconds > 0)
5487 dsyslog("got EPG info after %d seconds", seconds);
5488 return true;
5489 }
5490 }
5491 }
5492 if (seconds == 0)
5493 dsyslog("waiting for EPG info...");
5494 cCondWait::SleepMs(1000);
5495 }
5496 dsyslog("no EPG info available");
5497 return false;
5498}
5499
5500void cRecordControl::Stop(bool ExecuteUserCommand)
5501{
5502 if (timer) {
5503 bool Finished = timer->HasFlags(tfActive) && !timer->Matches();
5504 if (recorder) {
5505 int Errors = recorder->Errors();
5506 isyslog("timer %s %s with %d error%s", *timer->ToDescr(), Finished ? "finished" : "stopped", Errors, Errors != 1 ? "s" : "");
5507 if (timer->HasFlags(tfAvoid) && Errors == 0 && Finished) {
5508 const char *p = strgetlast(timer->File(), FOLDERDELIMCHAR);
5510 }
5511 }
5513 timer->SetRecording(false);
5514 timer = NULL;
5516 cStatus::MsgRecording(device, NULL, fileName, false);
5517 if (ExecuteUserCommand && Finished)
5519 }
5520}
5521
5523{
5524 if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
5525 if (timer)
5526 timer->SetPending(false);
5527 return false;
5528 }
5529 return true;
5530}
5531
5532// --- cRecordControls -------------------------------------------------------
5533
5536
5537bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
5538{
5539 static time_t LastNoDiskSpaceMessage = 0;
5540 int FreeMB = 0;
5541 if (Timer) {
5542 AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
5543 Timer->SetPending(true);
5544 }
5546 if (FreeMB < MINFREEDISK) {
5547 if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
5548 isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
5549 Skins.Message(mtWarning, tr("Not enough disk space to start recording!"));
5550 LastNoDiskSpaceMessage = time(NULL);
5551 }
5552 return false;
5553 }
5554 LastNoDiskSpaceMessage = 0;
5555
5556 ChangeState();
5557 cStateKey StateKey;
5558 const cChannels *Channels = cChannels::GetChannelsRead(StateKey);
5559 int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
5560 if (const cChannel *Channel = Channels->GetByNumber(ch)) {
5561 int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
5562 cDevice *device = cDevice::GetDevice(Channel, Priority, false);
5563 if (device) {
5564 dsyslog("switching device %d to channel %d %s (%s)", device->DeviceNumber() + 1, Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
5565 if (!device->SwitchChannel(Channel, false)) {
5566 StateKey.Remove();
5568 return false;
5569 }
5570 StateKey.Remove();
5571 Channels = NULL;
5572 if (!Timer || Timer->Matches()) {
5573 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5574 if (!RecordControls[i]) {
5575 RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause);
5576 return RecordControls[i]->Process(time(NULL));
5577 }
5578 }
5579 }
5580 }
5581 else if (!Timer || !Timer->Pending()) {
5582 isyslog("no free DVB device to record channel %d (%s)!", ch, Channel->Name());
5583 Skins.Message(mtError, tr("No free DVB device to record!"));
5584 }
5585 }
5586 else
5587 esyslog("ERROR: channel %d not defined!", ch);
5588 if (Channels)
5589 StateKey.Remove();
5590 return false;
5591}
5592
5594{
5596 return Start(Timers, NULL, Pause);
5597}
5598
5599void cRecordControls::Stop(const char *InstantId)
5600{
5602 ChangeState();
5603 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5604 if (RecordControls[i]) {
5605 const char *id = RecordControls[i]->InstantId();
5606 if (id && strcmp(id, InstantId) == 0) {
5607 cTimer *Timer = RecordControls[i]->Timer();
5608 RecordControls[i]->Stop();
5609 if (Timer) {
5610 Timers->Del(Timer);
5611 isyslog("deleted timer %s", *Timer->ToDescr());
5612 }
5613 break;
5614 }
5615 }
5616 }
5617}
5618
5620{
5621 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5622 if (RecordControls[i]) {
5623 if (RecordControls[i]->Timer() == Timer) {
5625 ChangeState();
5626 break;
5627 }
5628 }
5629 }
5630}
5631
5633{
5634 Skins.Message(mtStatus, tr("Pausing live video..."));
5635 cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
5636 if (Start(true)) {
5637 cReplayControl *rc = new cReplayControl(true);
5638 cControl::Launch(rc);
5640 Skins.Message(mtStatus, NULL);
5641 return true;
5642 }
5643 Skins.Message(mtStatus, NULL);
5644 return false;
5645}
5646
5647const char *cRecordControls::GetInstantId(const char *LastInstantId)
5648{
5649 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5650 if (RecordControls[i]) {
5651 if (!LastInstantId && RecordControls[i]->InstantId())
5652 return RecordControls[i]->InstantId();
5653 if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
5654 LastInstantId = NULL;
5655 }
5656 }
5657 return NULL;
5658}
5659
5661{
5662 if (FileName) {
5663 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5664 if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
5665 return RecordControls[i];
5666 }
5667 }
5668 return NULL;
5669}
5670
5672{
5673 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5674 if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
5675 return RecordControls[i];
5676 }
5677 return NULL;
5678}
5679
5680bool cRecordControls::Process(cTimers *Timers, time_t t)
5681{
5682 bool Result = false;
5683 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5684 if (RecordControls[i]) {
5685 if (!RecordControls[i]->Process(t)) {
5687 ChangeState();
5688 Result = true;
5689 }
5690 }
5691 }
5692 return Result;
5693}
5694
5696{
5697 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5698 if (RecordControls[i]) {
5699 if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
5700 if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
5701 isyslog("stopping recording due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
5702 RecordControls[i]->Stop();
5703 // This will restart the recording, maybe even from a different
5704 // device in case conditional access has changed.
5705 ChangeState();
5706 }
5707 }
5708 }
5709 }
5710}
5711
5713{
5714 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5715 if (RecordControls[i])
5716 return true;
5717 }
5718 return false;
5719}
5720
5722{
5723 for (int i = 0; i < MAXRECORDCONTROLS; i++)
5725 ChangeState();
5726}
5727
5729{
5730 int NewState = state;
5731 bool Result = State != NewState;
5732 State = state;
5733 return Result;
5734}
5735
5736// --- cAdaptiveSkipper ------------------------------------------------------
5737
5739{
5740 initialValue = NULL;
5741 currentValue = 0;
5742 framesPerSecond = 0;
5743 lastKey = kNone;
5744}
5745
5746void cAdaptiveSkipper::Initialize(int *InitialValue, double FramesPerSecond)
5747{
5748 initialValue = InitialValue;
5749 framesPerSecond = FramesPerSecond;
5750 currentValue = 0;
5751}
5752
5754{
5755 if (!initialValue)
5756 return 0;
5757 if (timeout.TimedOut()) {
5758 currentValue = int(round(*initialValue * framesPerSecond));
5759 lastKey = Key;
5760 }
5761 else if (Key != lastKey) {
5762 currentValue /= 2;
5764 lastKey = Key; // only halve the value when the direction is changed
5765 else
5766 lastKey = kNone; // once the direction has changed, every further call halves the value
5767 }
5769 return max(currentValue, 1);
5770}
5771
5772// --- cReplayControl --------------------------------------------------------
5773
5776
5778:cDvbPlayerControl(fileName, PauseLive)
5779{
5781 currentReplayControl = this;
5782 displayReplay = NULL;
5783 marksModified = false;
5784 visible = modeOnly = shown = displayFrames = false;
5785 lastCurrent = lastTotal = -1;
5786 lastPlay = lastForward = false;
5787 lastSpeed = -2; // an invalid value
5788 timeoutShow = 0;
5789 timeSearchActive = false;
5790 cRecording Recording(fileName);
5791 cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
5792 marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
5793 SetMarks(&marks);
5795 SetTrackDescriptions(false);
5798}
5799
5801{
5803 Stop();
5804 if (currentReplayControl == this)
5805 currentReplayControl = NULL;
5806}
5807
5809{
5810 Hide();
5811 cStatus::MsgReplaying(this, NULL, fileName, false);
5812 if (Setup.DelTimeshiftRec && *fileName) {
5814 if (rc && rc->InstantId()) {
5815 if (Active()) {
5816 if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
5817 {
5819 Timers->SetExplicitModify();
5820 cTimer *Timer = rc->Timer();
5821 rc->Stop(false); // don't execute user command
5822 if (Timer) {
5823 Timers->Del(Timer);
5824 Timers->SetModified();
5825 isyslog("deleted timer %s", *Timer->ToDescr());
5826 }
5827 }
5829 bool Error = false;
5830 {
5832 Recordings->SetExplicitModify();
5833 if (cRecording *Recording = Recordings->GetByName(fileName)) {
5834 if (Recording->Delete()) {
5835 Recordings->DelByName(fileName);
5837 Recordings->SetModified();
5838 }
5839 else
5840 Error = true;
5841 }
5842 }
5843 if (Error)
5844 Skins.Message(mtError, tr("Error while deleting recording!"));
5845 return;
5846 }
5847 }
5848 }
5849 }
5851 cMenuRecordings::SetRecording(NULL); // make sure opening the Recordings menu navigates to the last replayed recording
5852}
5853
5855{
5856 cStateKey StateKey;
5857 marks.Lock(StateKey);
5858 while (cMark *m = marks.First())
5859 marks.Del(m);
5860 StateKey.Remove();
5862}
5863
5864void cReplayControl::SetRecording(const char *FileName)
5865{
5866 fileName = FileName;
5867}
5868
5870{
5871 return currentReplayControl ? *fileName : NULL;
5872}
5873
5875{
5877 if (!Recordings->GetByName(fileName))
5878 fileName = NULL;
5879 return fileName;
5880}
5881
5882void cReplayControl::ClearLastReplayed(const char *FileName)
5883{
5884 if (*fileName && FileName && strcmp(fileName, FileName) == 0)
5885 fileName = NULL;
5886}
5887
5889{
5890 if (modeOnly)
5891 Hide();
5892 if (!visible) {
5893 shown = ShowProgress(true);
5894 timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
5895 }
5896 else if (timeoutShow && Seconds > 0)
5897 timeoutShow = time(NULL) + Seconds;
5898}
5899
5901{
5902 ShowTimed();
5903}
5904
5906{
5907 if (visible) {
5908 delete displayReplay;
5909 displayReplay = NULL;
5910 SetNeedsFastResponse(false);
5911 visible = false;
5912 modeOnly = false;
5913 lastPlay = lastForward = false;
5914 lastSpeed = -2; // an invalid value
5915 timeSearchActive = false;
5916 timeoutShow = 0;
5917 }
5918 if (marksModified) {
5919 marks.Save();
5920 marksModified = false;
5921 }
5922}
5923
5925{
5927 bool Play, Forward;
5928 int Speed;
5929 if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
5930 bool NormalPlay = (Play && Speed == -1);
5931
5932 if (!visible) {
5933 if (NormalPlay)
5934 return; // no need to do indicate ">" unless there was a different mode displayed before
5935 visible = modeOnly = true;
5937 }
5938
5939 if (modeOnly && !timeoutShow && NormalPlay)
5940 timeoutShow = time(NULL) + MODETIMEOUT;
5942 lastPlay = Play;
5944 lastSpeed = Speed;
5945 }
5946 }
5947}
5948
5950{
5951 int Current, Total;
5952 if (!(Initial || updateTimer.TimedOut()))
5953 return visible;
5954 if (GetFrameNumber(Current, Total) && Total > 0) {
5955 if (!visible) {
5959 visible = true;
5960 }
5961 if (Initial) {
5962 if (*fileName) {
5964 if (const cRecording *Recording = Recordings->GetByName(fileName))
5965 displayReplay->SetRecording(Recording);
5966 }
5967 lastCurrent = lastTotal = -1;
5968 }
5969 if (Current != lastCurrent || Total != lastTotal) {
5970 if (Setup.ShowRemainingTime || Total != lastTotal) {
5971 int Index = Total;
5973 Index = Current - Index;
5975 }
5976 displayReplay->SetProgress(Current, Total);
5979 lastCurrent = Current;
5980 }
5981 lastTotal = Total;
5982 ShowMode();
5984 return true;
5985 }
5986 return false;
5987}
5988
5990{
5991 char buf[64];
5992 // TRANSLATORS: note the trailing blank!
5993 strcpy(buf, tr("Jump: "));
5994 int len = strlen(buf);
5995 char h10 = '0' + (timeSearchTime >> 24);
5996 char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
5997 char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
5998 char m1 = '0' + (timeSearchTime & 0x000000FF);
5999 char ch10 = timeSearchPos > 3 ? h10 : '-';
6000 char ch1 = timeSearchPos > 2 ? h1 : '-';
6001 char cm10 = timeSearchPos > 1 ? m10 : '-';
6002 char cm1 = timeSearchPos > 0 ? m1 : '-';
6003 sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
6004 displayReplay->SetJump(buf);
6005}
6006
6008{
6009#define STAY_SECONDS_OFF_END 10
6010 int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
6011 int Current = int(round(lastCurrent / FramesPerSecond()));
6012 int Total = int(round(lastTotal / FramesPerSecond()));
6013 switch (Key) {
6014 case k0 ... k9:
6015 if (timeSearchPos < 4) {
6016 timeSearchTime <<= 8;
6017 timeSearchTime |= Key - k0;
6018 timeSearchPos++;
6020 }
6021 break;
6022 case kFastRew:
6023 case kLeft:
6024 case kFastFwd:
6025 case kRight: {
6026 int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
6027 if (dir > 0)
6028 Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
6029 SkipSeconds(Seconds * dir);
6030 timeSearchActive = false;
6031 }
6032 break;
6033 case kPlayPause:
6034 case kPlay:
6035 case kUp:
6036 case kPause:
6037 case kDown:
6038 case kOk:
6039 if (timeSearchPos > 0) {
6040 Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
6041 bool Still = Key == kDown || Key == kPause || Key == kOk;
6042 Goto(SecondsToFrames(Seconds, FramesPerSecond()), Still);
6043 }
6044 timeSearchActive = false;
6045 break;
6046 default:
6047 if (!(Key & k_Flags)) // ignore repeat/release keys
6048 timeSearchActive = false;
6049 break;
6050 }
6051
6052 if (!timeSearchActive) {
6053 if (timeSearchHide)
6054 Hide();
6055 else
6056 displayReplay->SetJump(NULL);
6057 ShowMode();
6058 }
6059}
6060
6062{
6064 timeSearchHide = false;
6065 if (modeOnly)
6066 Hide();
6067 if (!visible) {
6068 Show();
6069 if (visible)
6070 timeSearchHide = true;
6071 else
6072 return;
6073 }
6074 timeoutShow = 0;
6076 timeSearchActive = true;
6077}
6078
6080{
6081 int Current, Total;
6082 if (GetIndex(Current, Total, true)) {
6083 lastCurrent = -1; // triggers redisplay
6084 cStateKey StateKey;
6085 marks.Lock(StateKey);
6086 if (cMark *m = marks.Get(Current))
6087 marks.Del(m);
6088 else {
6089 marks.Add(Current);
6090 bool Play, Forward;
6091 int Speed;
6092 if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
6093 Goto(Current, true);
6094 displayFrames = true;
6095 }
6096 }
6097 StateKey.Remove();
6098 ShowTimed(2);
6099 marksModified = true;
6101 }
6102}
6103
6105{
6106 int Current, Total;
6107 if (GetIndex(Current, Total)) {
6108 if (marks.Count()) {
6109 if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
6110 if (!Setup.PauseOnMarkJump) {
6111 bool Playing, Fwd;
6112 int Speed;
6113 if (GetReplayMode(Playing, Fwd, Speed) && Playing && Forward && m->Position() < Total - SecondsToFrames(3, FramesPerSecond())) {
6114 Goto(m->Position());
6115 return;
6116 }
6117 }
6118 Goto(m->Position(), true);
6119 displayFrames = true;
6120 return;
6121 }
6122 }
6123 // There are either no marks at all, or we already were at the first or last one,
6124 // so jump to the very beginning or end:
6125 Goto(Forward ? Total : 0, true);
6126 }
6127}
6128
6129void cReplayControl::MarkMove(int Frames, bool MarkRequired)
6130{
6131 int Current, Total;
6132 if (GetIndex(Current, Total)) {
6133 bool Play, Forward;
6134 int Speed;
6135 GetReplayMode(Play, Forward, Speed);
6136 cMark *m = marks.Get(Current);
6137 if (!Play && m) {
6138 displayFrames = true;
6139 cMark *m2;
6140 if (Frames > 0) {
6141 // Handle marks at the same offset:
6142 while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
6143 m = m2;
6144 // Don't skip the next mark:
6145 if ((m2 = marks.Next(m)) != NULL)
6146 Frames = min(Frames, m2->Position() - m->Position() - 1);
6147 }
6148 else {
6149 // Handle marks at the same offset:
6150 while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
6151 m = m2;
6152 // Don't skip the next mark:
6153 if ((m2 = marks.Prev(m)) != NULL)
6154 Frames = -min(-Frames, m->Position() - m2->Position() - 1);
6155 }
6156 int p = SkipFrames(Frames);
6157 m->SetPosition(p);
6158 Goto(m->Position(), true);
6159 marksModified = true;
6161 }
6162 else if (!MarkRequired)
6163 Goto(SkipFrames(Frames), !Play);
6164 }
6165}
6166
6168{
6169 if (*fileName) {
6170 Hide();
6172 if (!marks.Count())
6173 Skins.Message(mtError, tr("No editing marks defined!"));
6174 else if (!marks.GetNumSequences())
6175 Skins.Message(mtError, tr("No editing sequences defined!"));
6176 else if (access(cCutter::EditedFileName(fileName), F_OK) == 0 && !Interface->Confirm(tr("Edited version already exists - overwrite?")))
6177 ;
6178 else if (!RecordingsHandler.Add(ruCut, fileName))
6179 Skins.Message(mtError, tr("Can't start editing process!"));
6180 else
6181 Skins.Message(mtInfo, tr("Editing process started"));
6182 }
6183 else
6184 Skins.Message(mtError, tr("Editing process already active!"));
6185 ShowMode();
6186 }
6187}
6188
6190{
6191 int Current, Total;
6192 if (GetIndex(Current, Total)) {
6193 cMark *m = marks.Get(Current);
6194 if (!m)
6195 m = marks.GetNext(Current);
6196 if (m) {
6197 if ((m->Index() & 0x01) != 0 && !Setup.SkipEdited) // when skipping edited parts we also need to jump to end marks
6198 m = marks.Next(m);
6199 if (m)
6201 }
6202 }
6203}
6204
6206{
6208 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::LastReplayed()))
6209 return new cMenuRecording(Recording, false);
6210 return NULL;
6211}
6212
6214{
6216 if (const cRecording *Recording = Recordings->GetByName(LastReplayed()))
6217 return Recording;
6218 return NULL;
6219}
6220
6222{
6223 if (!Active())
6224 return osEnd;
6225 if (Key == kNone && !marksModified)
6226 marks.Update();
6227 if (visible) {
6228 if (timeoutShow && time(NULL) > timeoutShow) {
6229 Hide();
6230 ShowMode();
6231 timeoutShow = 0;
6232 }
6233 else if (modeOnly)
6234 ShowMode();
6235 else
6237 }
6238 bool DisplayedFrames = displayFrames;
6239 displayFrames = false;
6240 if (timeSearchActive && Key != kNone) {
6241 TimeSearchProcess(Key);
6242 return osContinue;
6243 }
6244 if (Key == kPlayPause) {
6245 bool Play, Forward;
6246 int Speed;
6247 GetReplayMode(Play, Forward, Speed);
6248 if (Speed >= 0)
6249 Key = Play ? kPlay : kPause;
6250 else
6251 Key = Play ? kPause : kPlay;
6252 }
6253 bool DoShowMode = true;
6254 switch (int(Key)) {
6255 // Positioning:
6256 case kPlay:
6257 case kUp: Play(); break;
6258 case kPause:
6259 case kDown: Pause(); break;
6260 case kFastRew|k_Release:
6261 case kLeft|k_Release:
6262 if (Setup.MultiSpeedMode) break;
6263 case kFastRew:
6264 case kLeft: Backward(); break;
6265 case kFastFwd|k_Release:
6266 case kRight|k_Release:
6267 if (Setup.MultiSpeedMode) break;
6268 case kFastFwd:
6269 case kRight: Forward(); break;
6270 case kRed: TimeSearch(); break;
6271 case kGreen|k_Repeat:
6273 case kGreen: SkipSeconds(-Setup.SkipSeconds); break;
6274 case kYellow|k_Repeat:
6276 case kYellow: SkipSeconds(Setup.SkipSeconds); break;
6277 case kStop:
6278 case kBlue: Stop();
6279 return osEnd;
6280 default: {
6281 DoShowMode = false;
6282 switch (int(Key)) {
6283 // Editing:
6284 case kMarkToggle: MarkToggle(); break;
6285 case kPrev|k_Repeat:
6286 case kPrev: if (Setup.AdaptiveSkipPrevNext) {
6287 MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6288 break;
6289 }
6290 // fall through...
6292 case kMarkJumpBack: MarkJump(false); break;
6293 case kNext|k_Repeat:
6294 case kNext: if (Setup.AdaptiveSkipPrevNext) {
6295 MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6296 break;
6297 }
6298 // fall through...
6300 case kMarkJumpForward: MarkJump(true); break;
6302 case kMarkMoveBack: MarkMove(-1, true); break;
6304 case kMarkMoveForward: MarkMove(+1, true); break;
6306 case kMarkSkipBack: MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6308 case kMarkSkipForward: MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6309 case kEditCut: EditCut(); break;
6310 case kEditTest: EditTest(); break;
6311 default: {
6312 displayFrames = DisplayedFrames;
6313 switch (Key) {
6314 // Menu control:
6315 case kOk: if (visible && !modeOnly) {
6316 Hide();
6317 DoShowMode = true;
6318 }
6319 else
6320 Show();
6321 break;
6322 case kBack: Stop();
6323 return osRecordings;
6324 default: return osUnknown;
6325 }
6326 }
6327 }
6328 }
6329 }
6330 if (DoShowMode)
6331 ShowMode();
6332 return osContinue;
6333}
cString ChannelString(const cChannel *Channel, int Number)
Definition channels.c:1139
#define CA_ENCRYPTED_MIN
Definition channels.h:44
#define CA_FTA
Definition channels.h:39
#define LOCK_CHANNELS_READ
Definition channels.h:269
#define LOCK_CHANNELS_WRITE
Definition channels.h:270
cCamSlots CamSlots
Definition ci.c:2838
@ msReady
Definition ci.h:170
@ msPresent
Definition ci.h:170
@ msReset
Definition ci.h:170
double framesPerSecond
Definition menu.h:285
cTimeMs timeout
Definition menu.h:287
cAdaptiveSkipper(void)
Definition menu.c:5738
eKeys lastKey
Definition menu.h:286
void Initialize(int *InitialValue, double FramesPerSecond)
Definition menu.c:5746
int * initialValue
Definition menu.h:283
int currentValue
Definition menu.h:284
int GetValue(eKeys Key)
Definition menu.c:5753
Definition ci.h:232
bool Devices(cVector< int > &DeviceNumbers)
Adds the numbers of any devices that currently use this CAM to the given DeviceNumbers.
Definition ci.c:2262
int Priority(void)
Returns the priority of the device this slot is currently assigned to, or IDLEPRIORITY if it is not a...
Definition ci.c:2656
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition ci.h:309
virtual const char * GetCamName(void)
Returns the name of the CAM in this slot, or NULL if there is no ready CAM in this slot.
Definition ci.c:2445
virtual bool EnterMenu(void)
Requests the CAM in this slot to start its menu.
Definition ci.c:2468
virtual cCiEnquiry * GetEnquiry(void)
Gets a pending enquiry, or NULL if there is no enquiry.
Definition ci.c:2488
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition ci.c:2431
virtual bool HasUserIO(void)
Returns true if there is a pending user interaction, which shall be retrieved via GetMenu() or GetEnq...
Definition ci.c:2462
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition ci.c:2221
virtual cCiMenu * GetMenu(void)
Gets a pending menu, or NULL if there is no menu.
Definition ci.c:2475
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition ci.h:332
virtual bool Reset(void)
Resets the CAM in this slot.
Definition ci.c:2375
virtual void StartActivation(void)
Puts the CAM in this slot into a mode where an inserted smart card can be activated.
Definition ci.c:2398
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition ci.c:2424
virtual bool HasMMI(void)
Returns 'true' if the CAM in this slot has an active MMI.
Definition ci.c:2457
virtual bool CanActivate(void)
Returns true if there is a CAM in this slot that can be put into activation mode.
Definition ci.c:2393
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition ci.c:2213
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition ci.h:344
virtual void CancelActivation(void)
Cancels a previously started activation (if any).
Definition ci.c:2413
int ppid
Definition channels.h:103
const int * Dpids(void) const
Definition channels.h:157
int tpid
Definition channels.h:116
int source
Definition channels.h:100
char * shortName
Definition channels.h:94
int vpid
Definition channels.h:102
int frequency
Definition channels.h:98
int rid
Definition channels.h:121
static cString ToText(const cChannel *Channel)
Definition channels.c:551
int caids[MAXCAIDS+1]
Definition channels.h:117
int nid
Definition channels.h:118
int Vpid(void) const
Definition channels.h:153
int Number(void) const
Definition channels.h:178
const char * Name(void) const
Definition channels.c:107
char * name
Definition channels.h:93
int sid
Definition channels.h:120
bool GroupSep(void) const
Definition channels.h:180
int dpids[MAXDPIDS+1]
Definition channels.h:108
const int * Caids(void) const
Definition channels.h:171
const char * ShortName(bool OrName=false) const
Definition channels.c:121
int tid
Definition channels.h:119
int spids[MAXSPIDS+1]
Definition channels.h:111
int apids[MAXAPIDS+1]
Definition channels.h:105
const int * Apids(void) const
Definition channels.h:156
char * portalName
Definition channels.h:96
const char * Provider(void) const
Definition channels.h:146
char * provider
Definition channels.h:95
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition channels.c:860
bool HasUniqueChannelID(const cChannel *NewChannel, const cChannel *OldChannel=NULL) const
Definition channels.c:1052
static int MaxNumber(void)
Definition channels.h:248
int GetPrevNormal(int Idx) const
Get previous normal channel (not group)
Definition channels.c:929
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition channels.c:855
void ReNumber(void)
Recalculate 'number' based on channel type.
Definition channels.c:937
const cChannel * GetByNumber(int Number, int SkipGap=0) const
Definition channels.c:982
void SetModifiedByUser(void)
Definition channels.c:1092
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition channels.c:1010
bool SwitchTo(int Number) const
Definition channels.c:1062
void Del(cChannel *Channel)
Delete the given Channel from the list.
Definition channels.c:974
int GetNextNormal(int Idx) const
Get next normal channel (not group)
Definition channels.c:921
void Cancel(void)
Definition ci.c:1718
int ExpectedLength(void)
Definition ci.h:162
const char * Text(void)
Definition ci.h:160
bool Blind(void)
Definition ci.h:161
void Abort(void)
Definition ci.c:1723
void Reply(const char *s)
Definition ci.c:1711
Definition ci.h:119
void Abort(void)
Definition ci.c:1685
bool HasUpdate(void)
Definition ci.c:1667
const char * TitleText(void)
Definition ci.h:136
const char * BottomText(void)
Definition ci.h:138
int NumEntries(void)
Definition ci.h:140
void Cancel(void)
Definition ci.c:1680
bool Selectable(void)
Definition ci.h:141
const char * SubTitleText(void)
Definition ci.h:137
void Select(int Index)
Definition ci.c:1673
const char * Entry(int n)
Definition ci.h:139
tComponent * Component(int Index) const
Definition epg.h:64
int NumComponents(void) const
Definition epg.h:61
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition thread.c:72
double FramesPerSecond(void) const
Definition player.h:111
static void Shutdown(void)
Definition player.c:108
static void Attach(void)
Definition player.c:95
static cControl * Control(bool Hidden=false)
Old version of this function, for backwards compatibility with plugins.
Definition player.c:74
static void Launch(cControl *Control)
Definition player.c:87
static cString EditedFileName(const char *FileName)
Returns the full path name of the edited version of the recording with the given FileName.
Definition cutter.c:656
void SetKeepTracks(bool KeepTracks)
Controls whether the current audio and subtitle track settings shall be kept as they currently are,...
Definition device.h:599
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition device.c:1151
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition device.c:772
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition device.c:716
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:220
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
eTrackType GetCurrentSubtitleTrack(void) const
Definition device.h:585
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:228
eTrackType GetCurrentAudioTrack(void) const
Definition device.h:581
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:807
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:165
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition device.c:1778
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition device.h:358
void StopReplay(void)
Stops the current replay session (if any).
Definition device.c:1386
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1029
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1179
const tTrackId * GetTrack(eTrackType Type)
Returns a pointer to the given track id, or NULL if Type is not less than ttMaxTrackTypes.
Definition device.c:1108
static void SetCurrentChannel(int ChannelNumber)
Sets the number of the current channel on the primary device, without actually switching to it.
Definition device.h:366
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1035
static int NumDevices(void)
Returns the total number of devices.
Definition device.h:129
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder).
Definition device.c:498
virtual void SetVideoFormat(bool VideoFormat16_9)
Sets the output video format to either 16:9 or 4:3 (only useful if this device has an MPEG decoder).
Definition device.c:521
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1056
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1212
static int CurrentVolume(void)
Definition device.h:634
bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language=NULL, const char *Description=NULL)
Sets the track of the given Type and Index to the given values.
Definition device.c:1079
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition device.c:1133
cTimeMs lastTime
Definition menu.h:127
const cChannel * channel
Definition menu.h:132
const cEvent * lastPresent
Definition menu.h:133
void DisplayChannel(void)
Definition menu.c:4856
virtual ~cDisplayChannel()
Definition menu.c:4849
const cEvent * lastFollowing
Definition menu.h:134
bool timeout
Definition menu.h:129
cSkinDisplayChannel * displayChannel
Definition menu.h:124
bool withInfo
Definition menu.h:126
void Refresh(void)
Definition menu.c:4883
const cPositioner * positioner
Definition menu.h:131
static cDisplayChannel * currentDisplayChannel
Definition menu.h:135
void DisplayInfo(void)
Definition menu.c:4864
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4906
cDisplayChannel(int Number, bool Switched)
Definition menu.c:4802
const cChannel * NextAvailableChannel(const cChannel *Channel, int Direction)
Definition menu.c:4889
cSkinDisplayTracks * displayTracks
Definition menu.h:182
cDisplaySubtitleTracks(void)
Definition menu.c:5289
static void Process(eKeys Key)
Definition menu.c:5342
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:185
eTrackType types[ttMaxTrackTypes]
Definition menu.h:184
virtual void Show(void)
Definition menu.c:5324
static cDisplaySubtitleTracks * currentDisplayTracks
Definition menu.h:187
virtual ~cDisplaySubtitleTracks()
Definition menu.c:5315
static cDisplaySubtitleTracks * Create(void)
Definition menu.c:5331
eOSState ProcessKey(eKeys Key)
Definition menu.c:5348
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:167
static cDisplayTracks * Create(void)
Definition menu.c:5213
cDisplayTracks(void)
Definition menu.c:5169
cTimeMs timeout
Definition menu.h:165
virtual void Show(void)
Definition menu.c:5203
virtual ~cDisplayTracks()
Definition menu.c:5194
eOSState ProcessKey(eKeys Key)
Definition menu.c:5230
static cDisplayTracks * currentDisplayTracks
Definition menu.h:169
cSkinDisplayTracks * displayTracks
Definition menu.h:164
int numTracks
Definition menu.h:168
int audioChannel
Definition menu.h:168
static void Process(eKeys Key)
Definition menu.c:5224
eTrackType types[ttMaxTrackTypes]
Definition menu.h:166
static cDisplayVolume * Create(void)
Definition menu.c:5123
cSkinDisplayVolume * displayVolume
Definition menu.h:150
virtual ~cDisplayVolume()
Definition menu.c:5112
eOSState ProcessKey(eKeys Key)
Definition menu.c:5136
cTimeMs timeout
Definition menu.h:151
static void Process(eKeys Key)
Definition menu.c:5130
virtual void Show(void)
Definition menu.c:5118
cDisplayVolume(void)
Definition menu.c:5103
static cDisplayVolume * currentDisplayVolume
Definition menu.h:152
void Append(const char *Title)
Definition recording.c:3146
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition dvbdevice.c:2002
void SetMarks(const cMarks *Marks)
Definition dvbplayer.c:995
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition dvbplayer.c:1050
void SkipSeconds(int Seconds)
Definition dvbplayer.c:1037
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition dvbplayer.c:1068
void Pause(void)
Definition dvbplayer.c:1013
int SkipFrames(int Frames)
Definition dvbplayer.c:1043
void Goto(int Index, bool Still=false)
Definition dvbplayer.c:1073
void Stop(void)
Definition dvbplayer.c:1006
void Forward(void)
Definition dvbplayer.c:1025
bool Active(void)
Definition dvbplayer.c:1001
bool GetFrameNumber(int &Current, int &Total)
Definition dvbplayer.c:1059
void Play(void)
Definition dvbplayer.c:1019
void Backward(void)
Definition dvbplayer.c:1031
static void SetupChanged(void)
void ForceScan(void)
Definition eitscan.c:113
Definition epg.h:73
const char * ShortText(void) const
Definition epg.h:106
time_t EndTime(void) const
Definition epg.h:112
const cComponents * Components(void) const
Definition epg.h:108
const char * Description(void) const
Definition epg.h:107
bool IsRunning(bool OrAboutToStart=false) const
Definition epg.c:274
time_t StartTime(void) const
Definition epg.h:111
tChannelID ChannelID(void) const
Definition epg.c:151
cString GetTimeString(void) const
Definition epg.c:433
const char * Title(void) const
Definition epg.h:105
static bool GetAvailableFontNames(cStringList *FontNames, bool Monospaced=false)
Queries the font configuration for a list of available font names, which is returned in FontNames.
Definition font.c:440
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition interface.c:59
bool Contains(const cListObject *Object) const
If a pointer to an object contained in this list has been obtained while holding a lock,...
Definition tools.c:2276
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2220
virtual void Move(int From, int To)
Definition tools.c:2236
void SetExplicitModify(void)
If you have obtained a write lock on this list, and you don't want it to be automatically marked as m...
Definition tools.c:2285
void SetModified(void)
Unconditionally marks this list as modified.
Definition tools.c:2290
void SetSyncStateKey(cStateKey &StateKey)
When making changes to this list (while holding a write lock) that shall not affect some other code t...
Definition tools.h:609
bool Lock(cStateKey &StateKey, bool Write=false, int TimeoutMs=0) const
Tries to get a lock on this list and returns true if successful.
Definition tools.c:2179
int Count(void) const
Definition tools.h:637
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2188
void Sort(void)
Definition tools.c:2312
cListObject * Prev(void) const
Definition tools.h:556
int Index(void) const
Definition tools.c:2108
cListObject * Next(void) const
Definition tools.h:557
Definition tools.h:641
const T * Prev(const T *Object) const
Definition tools.h:657
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:653
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition tools.h:660
const T * Last(void) const
Returns the last element in this list, or NULL if the list is empty.
Definition tools.h:655
const cOsdItem * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition tools.h:650
void SetPosition(int Position)
Definition recording.h:365
int Position(void) const
Definition recording.h:363
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
Definition recording.c:2330
void Add(int Position)
If this cMarks object is used by multiple threads, the caller must Lock() it before calling Add() and...
Definition recording.c:2263
const cMark * GetNext(int Position) const
Definition recording.c:2287
bool Update(void)
Definition recording.c:2199
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition recording.c:2187
const cMark * Get(int Position) const
Definition recording.c:2269
static bool DeleteMarksFile(const cRecording *Recording)
Definition recording.c:2176
bool Save(void)
Definition recording.c:2230
const cMark * GetPrev(int Position) const
Definition recording.c:2278
cCamSlot * camSlot
Definition menu.c:2310
void Set(void)
Definition menu.c:2372
eOSState Select(void)
Definition menu.c:2427
char * input
Definition menu.c:2313
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2451
void AddMultiLineItem(const char *s)
Definition menu.c:2414
void GenerateTitle(const char *s=NULL)
Definition menu.c:2354
void QueryCam(void)
Definition menu.c:2359
cMenuCam(cCamSlot *CamSlot)
Definition menu.c:2327
time_t lastCamExchange
Definition menu.c:2315
virtual ~cMenuCam()
Definition menu.c:2342
cCiEnquiry * ciEnquiry
Definition menu.c:2312
cCiMenu * ciMenu
Definition menu.c:2311
int offset
Definition menu.c:2314
static eChannelSortMode sortMode
Definition menu.c:291
cMenuChannelItem(const cChannel *Channel)
Definition menu.c:306
const cChannel * Channel(void)
Definition menu.c:300
static void SetSortMode(eChannelSortMode SortMode)
Definition menu.c:295
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:314
virtual void Set(void)
Definition menu.c:327
static eChannelSortMode SortMode(void)
Definition menu.c:297
const cChannel * channel
Definition menu.c:292
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition menu.c:343
static void IncSortMode(void)
Definition menu.c:296
cStateKey channelsStateKey
Definition menu.c:355
eOSState Number(eKeys Key)
Definition menu.c:431
cChannel * GetChannel(int Index)
Definition menu.c:416
void Set(bool Force=false)
Definition menu.c:386
int number
Definition menu.c:356
eOSState Delete(void)
Definition menu.c:486
void Propagate(cChannels *Channels)
Definition menu.c:422
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:563
eOSState New(void)
Definition menu.c:478
cMenuChannels(void)
Definition menu.c:374
cTimeMs numberTimer
Definition menu.c:357
eOSState Edit(void)
Definition menu.c:467
~cMenuChannels()
Definition menu.c:382
eOSState Switch(void)
Definition menu.c:456
virtual void Move(int From, int To)
Definition menu.c:533
eOSState Execute(void)
Definition menu.c:2240
cList< cNestedItem > * commands
Definition menu.h:59
bool confirm
Definition menu.h:63
cMenuCommands(const char *Title, cList< cNestedItem > *Commands, const char *Parameters=NULL)
Definition menu.c:2195
virtual ~cMenuCommands()
Definition menu.c:2212
cString title
Definition menu.h:61
cString command
Definition menu.h:62
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2287
bool Parse(const char *s)
Definition menu.c:2217
char * result
Definition menu.h:64
cString parameters
Definition menu.h:60
cMenuEditCaItem(const char *Name, int *Value)
Definition menu.c:66
virtual void Set(void)
Definition menu.c:72
eOSState ProcessKey(eKeys Key)
Definition menu.c:82
cStateKey * channelsStateKey
Definition menu.c:164
cChannel data
Definition menu.c:166
void Setup(void)
Definition menu.c:201
cChannel * channel
Definition menu.c:165
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:240
cSourceParam * sourceParam
Definition menu.c:167
char name[256]
Definition menu.c:168
cChannel * Channel(void)
Definition menu.c:172
cMenuEditChannel(cStateKey *ChannelsStateKey, cChannel *Channel, bool New=false)
Definition menu.c:176
void ToggleRepeating(void)
Definition menuitems.c:999
cNestedItem * folder
Definition menu.c:702
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:759
cMenuEditFolder(const char *Dir, cList< cNestedItem > *List, cNestedItem *Folder=NULL)
Definition menu.c:711
char name[PATH_MAX]
Definition menu.c:703
eOSState Confirm(void)
Definition menu.c:736
cString GetFolder(void)
Definition menu.c:731
cList< cNestedItem > * list
Definition menu.c:701
virtual void Set(void)
Definition menuitems.c:82
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:95
void SetValue(const char *Value)
Definition menuitems.c:37
eOSState ProcessKey(eKeys Key)
Definition menu.c:124
virtual void Set(void)
Definition menu.c:116
cMenuEditSrcItem(const char *Name, int *Value)
Definition menu.c:109
const cSource * source
Definition menu.c:101
void SetKeepSpace(void)
Definition menuitems.h:141
void SetMacros(const char **Macros)
Definition menuitems.c:415
bool addIfConfirmed
Definition menu.h:79
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:1146
eOSState SetFolder(void)
Definition menu.c:1115
cMenuEditDateItem * firstday
Definition menu.h:85
static const cTimer * addedTimer
Definition menu.h:75
int channel
Definition menu.h:78
cTimer data
Definition menu.h:77
void SetHelpKeys(void)
Definition menu.c:1067
cMenuEditStrItem * file
Definition menu.h:83
cMenuEditStrItem * pattern
Definition menu.h:82
cMenuEditDateItem * day
Definition menu.h:84
static const cTimer * AddedTimer(void)
Definition menu.c:1060
cTimer * timer
Definition menu.h:76
cMenuEditTimer(cTimer *Timer, bool New=false)
Definition menu.c:1015
void SetFirstDayItem(void)
Definition menu.c:1072
char remote[HOST_NAME_MAX]
Definition menu.h:81
cStringList svdrpServerNames
Definition menu.h:80
void SetPatternItem(bool Initial=false)
Definition menu.c:1085
virtual ~cMenuEditTimer()
Definition menu.c:1054
const cEvent * event
Definition menu.h:99
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:1522
virtual void Display(void)
Definition menu.c:1514
cMenuEvent(const cTimers *Timers, const cChannels *Channels, const cEvent *Event, bool CanSwitch=false, bool Buttons=false)
Definition menu.c:1497
cMenuFolderItem(cNestedItem *Folder)
Definition menu.c:682
virtual void Set(void)
Definition menu.c:689
cNestedItem * Folder(void)
Definition menu.c:679
cNestedItem * folder
Definition menu.c:675
cMenuFolder(const char *Title, cList< cNestedItem > *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path=NULL)
Definition menu.c:792
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:972
eOSState Delete(void)
Definition menu.c:920
int helpKeys
Definition menu.h:41
eOSState New(void)
Definition menu.c:914
cNestedItemList * nestedItemList
Definition menu.h:36
cList< cNestedItem > * list
Definition menu.h:37
eOSState SetFolder(void)
Definition menu.c:948
cString dir
Definition menu.h:38
void Set(const char *CurrentFolder=NULL)
Definition menu.c:856
void DescendPath(const char *Path)
Definition menu.c:881
cOsdItem * firstFolder
Definition menu.h:39
eOSState Edit(void)
Definition menu.c:936
eOSState Select(bool Open)
Definition menu.c:898
bool editing
Definition menu.h:40
cString GetFolder(void)
Definition menu.c:959
void SetHelpKeys(void)
Definition menu.c:808
cOsdItem * cancelEditingItem
Definition menu.h:110
cOsdItem * stopRecordingItem
Definition menu.h:111
void Set(void)
Definition menu.c:4556
int recordControlsState
Definition menu.h:112
bool replaying
Definition menu.h:108
cOsdItem * stopReplayItem
Definition menu.h:109
bool Update(bool Force=false)
Definition menu.c:4593
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4651
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition menu.c:4509
static cOsdObject * pluginOsdObject
Definition menu.h:113
static cOsdObject * PluginOsdObject(void)
Definition menu.c:4549
eOSState ApplyChanges(void)
Definition menu.c:2593
int pathIsInUse
Definition menu.c:2518
cString oldFolder
Definition menu.c:2514
eOSState Folder(void)
Definition menu.c:2588
cMenuEditStrItem * folderItem
Definition menu.c:2517
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2628
eOSState SetFolder(void)
Definition menu.c:2578
cString path
Definition menu.c:2513
cMenuPathEdit(const char *Path)
Definition menu.c:2527
char name[NAME_MAX]
Definition menu.c:2516
char folder[PATH_MAX]
Definition menu.c:2515
cMenuPluginItem(const char *Name, int Index)
Definition menu.c:4496
int PluginIndex(void)
Definition menu.c:4493
int pluginIndex
Definition menu.c:4490
bool RefreshRecording(void)
Definition menu.c:2754
cMenuEditStrItem * nameItem
Definition menu.c:2659
const char * actionCancel
Definition menu.c:2663
cString originalFileName
Definition menu.c:2652
eOSState ApplyChanges(void)
Definition menu.c:2865
const char * doCopy
Definition menu.c:2665
eOSState Action(void)
Definition menu.c:2784
cMenuEditStrItem * folderItem
Definition menu.c:2658
eOSState SetFolder(void)
Definition menu.c:2769
void Set(void)
Definition menu.c:2705
char name[NAME_MAX]
Definition menu.c:2655
const char * buttonAction
Definition menu.c:2661
cStateKey recordingsStateKey
Definition menu.c:2653
const char * doCut
Definition menu.c:2664
eOSState RemoveName(void)
Definition menu.c:2819
void SetHelpKeys(void)
Definition menu.c:2728
eOSState Delete(void)
Definition menu.c:2837
const char * buttonDelete
Definition menu.c:2662
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2911
cMenuRecordingEdit(const cRecording *Recording)
Definition menu.c:2682
const char * buttonFolder
Definition menu.c:2660
const cRecording * recording
Definition menu.c:2651
eOSState Folder(void)
Definition menu.c:2779
char folder[PATH_MAX]
Definition menu.c:2654
const cRecording * recording
Definition menu.c:3035
int Level(void) const
Definition menu.c:3044
const cRecording * Recording(void) const
Definition menu.c:3045
const char * Name(void) const
Definition menu.c:3043
void IncrementCounter(bool New)
Definition menu.c:3072
bool IsDirectory(void) const
Definition menu.c:3046
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition menu.c:3080
void SetRecording(const cRecording *Recording)
Definition menu.c:3047
cMenuRecordingItem(const cRecording *Recording, int Level)
Definition menu.c:3051
virtual void Display(void)
Definition menu.c:2977
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2989
const cRecording * recording
Definition menu.c:2938
bool withButtons
Definition menu.c:2941
bool RefreshRecording(void)
Definition menu.c:2962
cString originalFileName
Definition menu.c:2939
cStateKey recordingsStateKey
Definition menu.c:2940
cMenuRecording(const cRecording *Recording, bool WithButtons=false)
Definition menu.c:2949
static cString path
Definition menu.h:217
void Set(bool Refresh=false)
Definition menu.c:3143
bool Open(bool OpenSubMenus=false)
Definition menu.c:3223
eOSState Sort(void)
Definition menu.c:3394
static void SetRecording(const char *FileName)
Definition menu.c:3207
eOSState Info(void)
Definition menu.c:3366
eOSState Play(void)
Definition menu.c:3239
const cRecordingFilter * filter
Definition menu.h:216
static cString fileName
Definition menu.h:218
char * base
Definition menu.h:212
eOSState Rewind(void)
Definition menu.c:3253
static void SetPath(const char *Path)
Definition menu.c:3202
cStateKey recordingsStateKey
Definition menu.h:214
cMenuRecordings(const char *Base=NULL, int Level=0, bool OpenSubMenus=false, const cRecordingFilter *Filter=NULL)
Definition menu.c:3091
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3406
eOSState Commands(eKeys Key=kNone)
Definition menu.c:3379
cString DirectoryName(void)
Definition menu.c:3212
void SetHelpKeys(void)
Definition menu.c:3122
eOSState Delete(void)
Definition menu.c:3319
static void SetSortMode(eScheduleSortMode SortMode)
Definition menu.c:1567
const cChannel * channel
Definition menu.c:1562
cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel=NULL, bool WithDate=false)
Definition menu.c:1577
const cEvent * event
Definition menu.c:1561
static void IncSortMode(void)
Definition menu.c:1568
bool Update(const cTimers *Timers, bool Force=false)
Definition menu.c:1600
static eScheduleSortMode sortMode
Definition menu.c:1559
static eScheduleSortMode SortMode(void)
Definition menu.c:1569
eTimerMatch timerMatch
Definition menu.c:1564
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition menu.c:1627
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:1587
bool PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:1988
bool canSwitch
Definition menu.c:1855
bool PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:1929
void SetHelpKeys(void)
Definition menu.c:2020
virtual ~cMenuSchedule()
Definition menu.c:1888
int helpKeys
Definition menu.c:1856
cStateKey timersStateKey
Definition menu.c:1851
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2111
bool next
Definition menu.c:1854
void Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel=NULL, bool Force=false)
Definition menu.c:1893
bool Update(void)
Definition menu.c:2007
eOSState Record(void)
Definition menu.c:2054
cMenuSchedule(void)
Definition menu.c:1873
cStateKey schedulesStateKey
Definition menu.c:1852
eOSState Number(void)
Definition menu.c:2045
int scheduleState
Definition menu.c:1853
eOSState Switch(void)
Definition menu.c:2094
bool PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:1948
bool PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:1968
cMenuSetupBase(void)
Definition menu.c:3482
cSetup data
Definition menu.c:3476
virtual void Store(void)
Definition menu.c:3487
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition menu.c:3996
bool Changed(void)
Definition menu.c:4003
cCamSlot * camSlot
Definition menu.c:3989
cCamSlot * CamSlot(void)
Definition menu.c:3992
void SetHelpKeys(void)
Definition menu.c:4067
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4162
cMenuSetupCAM(void)
Definition menu.c:4052
eOSState Menu(void)
Definition menu.c:4086
eOSState Reset(void)
Definition menu.c:4150
eOSState Activate(void)
Definition menu.c:4113
const char * activationHelp
Definition menu.c:4042
int currentChannel
Definition menu.c:4041
const char * updateChannelsTexts[6]
Definition menu.c:3768
int numAudioLanguages
Definition menu.c:3763
cMenuSetupDVB(void)
Definition menu.c:3775
int originalNumSubtitleLanguages
Definition menu.c:3764
void Setup(void)
Definition menu.c:3802
int numSubtitleLanguages
Definition menu.c:3765
const char * standardComplianceTexts[3]
Definition menu.c:3769
int originalNumAudioLanguages
Definition menu.c:3762
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3832
const char * videoDisplayFormatTexts[3]
Definition menu.c:3767
int originalNumLanguages
Definition menu.c:3670
int numLanguages
Definition menu.c:3671
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3711
void Setup(void)
Definition menu.c:3689
cMenuSetupEPG(void)
Definition menu.c:3678
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3966
cSatCableNumbers satCableNumbers
Definition menu.c:3911
cMenuSetupLNB(void)
Definition menu.c:3918
void Setup(void)
Definition menu.c:3927
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4324
void Set(void)
Definition menu.c:4293
cMenuSetupMisc(void)
Definition menu.c:4280
const char * svdrpPeeringModeTexts[3]
Definition menu.c:4271
cStringList svdrpServerNames
Definition menu.c:4273
const char * showChannelNamesWithSourceTexts[3]
Definition menu.c:4272
virtual void Set(void)
Definition menu.c:3545
virtual ~cMenuSetupOSD()
Definition menu.c:3540
cStringList fontSmlNames
Definition menu.c:3510
cStringList fontOsdNames
Definition menu.c:3510
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3601
const char * recSortDirTexts[2]
Definition menu.c:3500
const char * useSmallFontTexts[3]
Definition menu.c:3498
int numSkins
Definition menu.c:3503
cStringList fontFixNames
Definition menu.c:3510
const char * recSortModeTexts[2]
Definition menu.c:3499
int fontOsdIndex
Definition menu.c:3511
const char * keyColorTexts[4]
Definition menu.c:3501
int skinIndex
Definition menu.c:3505
int originalSkinIndex
Definition menu.c:3504
int originalThemeIndex
Definition menu.c:3508
int fontFixIndex
Definition menu.c:3511
const char ** skinDescriptions
Definition menu.c:3506
cThemes themes
Definition menu.c:3507
int themeIndex
Definition menu.c:3509
int fontSmlIndex
Definition menu.c:3511
cMenuSetupOSD(void)
Definition menu.c:3519
int osdLanguageIndex
Definition menu.c:3502
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1245
void SetSection(const char *Section)
Definition menuitems.c:1240
void SetPlugin(cPlugin *Plugin)
Definition menuitems.c:1260
cMenuSetupPluginItem(const char *Name, int Index)
Definition menu.c:4356
int PluginIndex(void)
Definition menu.c:4353
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4384
cMenuSetupPlugins(void)
Definition menu.c:4370
const char * pauseKeyHandlingTexts[3]
Definition menu.c:4190
const char * recordKeyHandlingTexts[3]
Definition menu.c:4189
cMenuSetupRecord(void)
Definition menu.c:4196
const char * delTimeshiftRecTexts[3]
Definition menu.c:4191
virtual void Store(void)
Definition menu.c:4258
cMenuSetupReplay(void)
Definition menu.c:4237
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4460
virtual void Set(void)
Definition menu.c:4431
cMenuSetup(void)
Definition menu.c:4424
eOSState Restart(void)
Definition menu.c:4451
eDvbFont font
Definition menu.h:25
void SetText(const char *Text)
Definition menu.c:629
virtual void Display(void)
Definition menu.c:635
cMenuText(const char *Title, const char *Text, eDvbFont Font=fontOsd)
Definition menu.c:615
virtual ~cMenuText()
Definition menu.c:624
char * text
Definition menu.h:24
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:643
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:1242
virtual void Set(void)
Definition menu.c:1247
cMenuTimerItem(const cTimer *Timer)
Definition menu.c:1236
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition menu.c:1292
const cTimer * timer
Definition menu.c:1227
const cTimer * Timer(void)
Definition menu.c:1232
eOSState New(void)
Definition menu.c:1409
cMenuTimers(void)
Definition menu.c:1318
void Set(void)
Definition menu.c:1331
void SetHelpKeys(void)
Definition menu.c:1357
virtual ~cMenuTimers()
Definition menu.c:1327
eOSState Info(void)
Definition menu.c:1451
eOSState Edit(void)
Definition menu.c:1402
cTimer * GetTimer(void)
Definition menu.c:1351
cStateKey timersStateKey
Definition menu.c:1302
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:1463
eOSState Delete(void)
Definition menu.c:1419
int helpKeys
Definition menu.c:1303
eOSState OnOff(void)
Definition menu.c:1372
void SetHelpKeys(const cChannels *Channels)
Definition menu.c:1691
static const cEvent * scheduleEvent
Definition menu.c:1644
static const cEvent * ScheduleEvent(void)
Definition menu.c:1719
eOSState Record(void)
Definition menu.c:1743
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:1784
cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr)
Definition menu.c:1658
static void SetCurrentChannel(int ChannelNr)
Definition menu.c:1650
cStateKey timersStateKey
Definition menu.c:1640
static int CurrentChannel(void)
Definition menu.c:1649
eOSState Switch(void)
Definition menu.c:1726
bool canSwitch
Definition menu.c:1638
bool Update(void)
Definition menu.c:1678
static int currentChannel
Definition menu.c:1643
bool now
Definition menu.c:1637
int helpKeys
Definition menu.c:1639
bool Save(void)
Definition config.c:258
void SetText(const char *Text)
Definition config.c:156
void SetSubItems(bool On)
Definition config.c:162
cList< cNestedItem > * SubItems(void)
Definition config.h:205
const char * Text(void) const
Definition config.h:204
const char * Text(void) const
Definition osdbase.h:63
void SetSelectable(bool Selectable)
Definition osdbase.c:48
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:63
eOSState state
Definition osdbase.h:51
bool Selectable(void) const
Definition osdbase.h:59
void SetText(const char *Text, bool Copy=true)
Definition osdbase.c:42
void Ins(cOsdItem *Item, bool Current=false, cOsdItem *Before=NULL)
Definition osdbase.c:220
eOSState CloseSubMenu(bool ReDisplay=true)
Definition osdbase.c:529
void SetTitle(const char *Title)
Definition osdbase.c:174
void DisplayCurrent(bool Current)
Definition osdbase.c:297
int Current(void) const
Definition osdbase.h:138
const char * hk(const char *s)
Definition osdbase.c:137
void Mark(void)
Definition osdbase.c:496
cOsdMenu * SubMenu(void)
Definition osdbase.h:127
void DisplayItem(cOsdItem *Item)
Definition osdbase.c:315
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition osdbase.c:521
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition osdbase.c:213
void SetHasHotkeys(bool HasHotkeys=true)
Definition osdbase.c:161
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:152
void SetCurrent(cOsdItem *Item)
Definition osdbase.c:282
void SetMenuCategory(eMenuCategory MenuCategory)
Definition osdbase.c:118
void RefreshCurrent(void)
Definition osdbase.c:290
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition osdbase.c:189
cSkinDisplayMenu * DisplayMenu(void)
Definition osdbase.h:107
virtual void Display(void)
Definition osdbase.c:227
bool HasSubMenu(void)
Definition osdbase.h:126
virtual void Del(int Index)
Definition osdbase.c:199
const char * Title(void)
Definition osdbase.h:112
virtual void Clear(void)
Definition osdbase.c:329
void SetMenuSortMode(eMenuSortMode MenuSortMode)
Definition osdbase.c:123
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:540
int current
Definition osdbase.h:93
void SetNeedsFastResponse(bool NeedsFastResponse)
Definition osdbase.h:75
bool IsMenu(void) const
Definition osdbase.h:80
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2262
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition osd.c:2235
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.h:813
int Close(void)
Definition thread.c:1003
bool Open(const char *Command, const char *Mode)
Definition thread.c:947
static bool HasPlugins(void)
Definition plugin.c:464
static cPlugin * CallFirstService(const char *Id, void *Data=NULL)
Definition plugin.c:487
static cPlugin * GetPlugin(int Index)
Definition plugin.c:469
virtual cMenuSetupPage * SetupMenu(void)
Definition plugin.c:100
virtual const char * Version(void)=0
const char * Name(void)
Definition plugin.h:36
virtual const char * MainMenuEntry(void)
Definition plugin.c:90
virtual cOsdObject * MainMenuAction(void)
Definition plugin.c:95
virtual const char * Description(void)=0
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
virtual bool IsMoving(void) const
Returns true if the dish is currently moving as a result of a call to GotoPosition() or GotoAngle().
Definition positioner.c:127
bool IsAttached(void)
Returns true if this receiver is (still) attached to a device.
Definition receiver.h:82
virtual ~cRecordControl()
Definition menu.c:5468
const char * InstantId(void)
Definition menu.h:253
void Stop(bool ExecuteUserCommand=true)
Definition menu.c:5500
cDevice * device
Definition menu.h:240
cTimer * timer
Definition menu.h:241
bool GetEvent(void)
Definition menu.c:5476
char * fileName
Definition menu.h:245
cTimer * Timer(void)
Definition menu.h:255
cRecorder * recorder
Definition menu.h:242
cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer=NULL, bool Pause=false)
Definition menu.c:5386
cDevice * Device(void)
Definition menu.h:251
const cEvent * event
Definition menu.h:243
bool Process(time_t t)
Definition menu.c:5522
cString instantId
Definition menu.h:244
static bool StateChanged(int &State)
Definition menu.c:5728
static const char * GetInstantId(const char *LastInstantId)
Definition menu.c:5647
static void ChannelDataModified(const cChannel *Channel)
Definition menu.c:5695
static bool Process(cTimers *Timers, time_t t)
Definition menu.c:5680
static bool PauseLiveVideo(void)
Definition menu.c:5632
static void Shutdown(void)
Definition menu.c:5721
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition menu.c:5537
static cRecordControl * RecordControls[]
Definition menu.h:260
static bool Active(void)
Definition menu.c:5712
static void Stop(const char *InstantId)
Definition menu.c:5599
static cRecordControl * GetRecordControl(const char *FileName)
Definition menu.c:5660
static int state
Definition menu.h:261
static void ChangeState(void)
Definition menu.h:277
int Errors(void)
Definition recorder.h:57
virtual bool Filter(const cRecording *Recording) const =0
Returns true if the given Recording shall be displayed in the Recordings menu.
const char * Description(void) const
Definition recording.h:86
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition recording.c:2351
bool ChangePriorityLifetime(int NewPriority, int NewLifetime)
Changes the priority and lifetime of this recording to the given values.
Definition recording.c:1235
bool HasMarks(void) const
Returns true if this recording has any editing marks.
Definition recording.c:1189
bool WriteInfo(const char *OtherFileName=NULL)
Writes in info file of this recording.
Definition recording.c:1207
int IsInUse(void) const
Checks whether this recording is currently in use and therefore shall not be tampered with.
Definition recording.c:1350
bool ChangeName(const char *NewName)
Changes the name of this recording to the given value.
Definition recording.c:1260
bool Delete(void)
Changes the file name so that it will no longer be visible in the "Recordings" menu Returns false in ...
Definition recording.c:1287
cString Folder(void) const
Returns the name of the folder this recording is stored in (without the video directory).
Definition recording.c:1061
const char * Name(void) const
Returns the full name of the recording (without the video directory).
Definition recording.h:149
int Lifetime(void) const
Definition recording.h:136
const char * FileName(void) const
Returns the full path name to the recording directory, including the video directory and the actual '...
Definition recording.c:1073
cRecordingInfo * Info(void) const
Definition recording.h:156
cString BaseName(void) const
Returns the base name of this recording (without the video directory and folder).
Definition recording.c:1068
int Priority(void) const
Definition recording.h:135
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition recording.c:1091
double FramesPerSecond(void) const
Definition recording.h:160
bool IsPesRecording(void) const
Definition recording.h:174
void DelAll(void)
Deletes/terminates all operations.
Definition recording.c:2102
bool Add(int Usage, const char *FileNameSrc, const char *FileNameDst=NULL)
Adds the given FileNameSrc to the recordings handler for (later) processing.
Definition recording.c:2064
int GetUsage(const char *FileName)
Returns the usage type for the given FileName.
Definition recording.c:2109
void Del(const char *FileName)
Deletes the given FileName from the list of operations.
Definition recording.c:2095
static const cRecordings * GetRecordingsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for read access.
Definition recording.h:240
static cRecordings * GetRecordingsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for write access.
Definition recording.h:243
static void TouchUpdate(void)
Touches the '.update' file in the video directory, so that other instances of VDR that access the sam...
Definition recording.c:1541
void DelByName(const char *FileName)
Definition recording.c:1604
const cRecording * GetByName(const char *FileName) const
Definition recording.c:1578
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition remote.c:124
static void TriggerLastActivity(void)
Simulates user activity, for instance to keep the current menu open even if no remote control key has...
Definition remote.c:204
static void SetRecording(const char *FileName)
Definition menu.c:5864
static const char * LastReplayed(void)
Definition menu.c:5874
void MarkToggle(void)
Definition menu.c:6079
static cString fileName
Definition menu.h:313
void TimeSearchDisplay(void)
Definition menu.c:5989
static void ClearLastReplayed(const char *FileName)
Definition menu.c:5882
int lastTotal
Definition menu.h:301
void MarkMove(int Frames, bool MarkRequired)
Definition menu.c:6129
static cReplayControl * currentReplayControl
Definition menu.h:312
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:6221
bool timeSearchHide
Definition menu.h:306
void TimeSearchProcess(eKeys Key)
Definition menu.c:6007
void MarkJump(bool Forward)
Definition menu.c:6104
cMarks marks
Definition menu.h:298
void EditCut(void)
Definition menu.c:6167
int timeSearchTime
Definition menu.h:307
cSkinDisplayReplay * displayReplay
Definition menu.h:296
void Stop(void)
Definition menu.c:5808
void ShowTimed(int Seconds=0)
Definition menu.c:5888
virtual const cRecording * GetRecording(void)
Returns the cRecording that is currently being replayed, or NULL if this player is not playing a cRec...
Definition menu.c:6213
virtual void ClearEditingMarks(void)
Clears any editing marks this player might be showing.
Definition menu.c:5854
bool lastForward
Definition menu.h:302
bool displayFrames
Definition menu.h:300
bool shown
Definition menu.h:300
time_t timeoutShow
Definition menu.h:304
void EditTest(void)
Definition menu.c:6189
bool timeSearchActive
Definition menu.h:306
virtual void Hide(void)
Definition menu.c:5905
bool ShowProgress(bool Initial)
Definition menu.c:5949
bool marksModified
Definition menu.h:299
int lastSpeed
Definition menu.h:303
cAdaptiveSkipper adaptiveSkipper
Definition menu.h:297
bool lastPlay
Definition menu.h:302
int timeSearchPos
Definition menu.h:307
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition menu.c:6205
void ShowMode(void)
Definition menu.c:5924
virtual ~cReplayControl()
Definition menu.c:5800
virtual void Show(void)
Definition menu.c:5900
cTimeMs updateTimer
Definition menu.h:305
void TimeSearch(void)
Definition menu.c:6061
bool visible
Definition menu.h:300
bool modeOnly
Definition menu.h:300
static const char * NowReplaying(void)
Definition menu.c:5869
cReplayControl(bool PauseLive=false)
Definition menu.c:5777
int lastCurrent
Definition menu.h:301
int Read(void)
Definition recording.c:261
void Delete(void)
Definition recording.c:344
bool FromString(const char *s)
Definition config.c:81
int * Array(void)
Definition config.h:102
cString ToString(void)
Definition config.c:107
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition epg.c:1374
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition epg.c:1269
static void ResetVersions(void)
Definition epg.c:1300
int DefaultLifetime
Definition config.h:309
int VolumeSteps
Definition config.h:366
int EmergencyExit
Definition config.h:372
int SplitEditedFiles
Definition config.h:345
int RcRepeatDelay
Definition config.h:307
int ColorKey3
Definition config.h:322
int MenuScrollPage
Definition config.h:271
int EPGBugfixLevel
Definition config.h:299
int ColorKey2
Definition config.h:322
int VideoDisplayFormat
Definition config.h:323
int SubtitleFgTransparency
Definition config.h:296
int MinUserInactivity
Definition config.h:347
int AntiAlias
Definition config.h:334
int ShowInfoOnChSwitch
Definition config.h:269
int SkipSecondsRepeat
Definition config.h:362
int StandardCompliance
Definition config.h:290
char SVDRPDefaultHost[HOST_NAME_MAX]
Definition config.h:304
bool Save(void)
Definition config.c:734
int TimeoutRequChInfo
Definition config.h:270
int ResumeID
Definition config.h:363
char OSDTheme[MaxThemeName]
Definition config.h:267
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:294
int SVDRPTimeout
Definition config.h:301
int LnbSLOF
Definition config.h:277
int EPGLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:297
char OSDSkin[MaxSkinName]
Definition config.h:266
int UsePositioner
Definition config.h:281
int AlwaysSortFoldersFirst
Definition config.h:318
int AdaptiveSkipInitial
Definition config.h:357
int RecSortingDirection
Definition config.h:320
int VpsMargin
Definition config.h:315
char OSDLanguage[I18N_MAX_LOCALE_LEN]
Definition config.h:265
int ShowChannelNamesWithSource
Definition config.h:371
int DefaultPriority
Definition config.h:309
int ZapTimeout
Definition config.h:305
double OSDWidthP
Definition config.h:329
int RecordKeyHandling
Definition config.h:310
int PauseKeyHandling
Definition config.h:311
double OSDHeightP
Definition config.h:329
int PositionerSpeed
Definition config.h:284
int MarginStart
Definition config.h:291
double FontOsdSizeP
Definition config.h:338
int PauseAtLastMark
Definition config.h:356
int AdaptiveSkipPrevNext
Definition config.h:360
int LnbFrequLo
Definition config.h:278
int UseSmallFont
Definition config.h:333
int SubtitleOffset
Definition config.h:295
int MarginStop
Definition config.h:291
int SVDRPPeering
Definition config.h:302
int ProgressDisplayTime
Definition config.h:352
int UpdateChannels
Definition config.h:325
int SkipSeconds
Definition config.h:361
int SubtitleBgTransparency
Definition config.h:296
int ColorKey0
Definition config.h:322
int FoldersInTimerMenu
Definition config.h:317
int MenuScrollWrap
Definition config.h:272
int EPGLinger
Definition config.h:300
int ShowReplayMode
Definition config.h:350
int SiteLon
Definition config.h:283
int AdaptiveSkipAlternate
Definition config.h:359
int UseVps
Definition config.h:314
int DisplaySubtitles
Definition config.h:293
int ChannelInfoTime
Definition config.h:328
int SiteLat
Definition config.h:282
int VolumeLinearize
Definition config.h:367
int ChannelsWrap
Definition config.h:370
double FontFixSizeP
Definition config.h:340
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:292
int OSDMessageTime
Definition config.h:332
int MarkInstantRecord
Definition config.h:274
double OSDLeftP
Definition config.h:329
int RecordingDirs
Definition config.h:316
int PausePriority
Definition config.h:312
double FontSmlSizeP
Definition config.h:339
int AdaptiveSkipTimeout
Definition config.h:358
int MenuKeyCloses
Definition config.h:273
int DiSEqC
Definition config.h:280
char NameInstantRecord[NAME_MAX+1]
Definition config.h:275
char FontOsd[MAXFONTNAME]
Definition config.h:335
int UseSubtitle
Definition config.h:313
int MinEventTimeout
Definition config.h:347
int ChannelInfoPos
Definition config.h:327
int LnbFrequHi
Definition config.h:279
char FontSml[MAXFONTNAME]
Definition config.h:336
int MultiSpeedMode
Definition config.h:349
int EPGScanTimeout
Definition config.h:298
int TimeTransponder
Definition config.h:289
int VideoFormat
Definition config.h:324
int MaxVideoFileSize
Definition config.h:344
cString DeviceBondings
Definition config.h:375
int PositionerSwing
Definition config.h:285
double OSDTopP
Definition config.h:329
int PauseOnMarkSet
Definition config.h:353
int DelTimeshiftRec
Definition config.h:346
int SetSystemTime
Definition config.h:287
int PrimaryDVB
Definition config.h:268
int ChannelEntryTimeout
Definition config.h:306
char FontFix[MAXFONTNAME]
Definition config.h:337
int TimeSource
Definition config.h:288
int UseDolbyDigital
Definition config.h:326
int PauseOnMarkJump
Definition config.h:354
int ColorKey1
Definition config.h:322
int ShowRemainingTime
Definition config.h:351
int CurrentDolby
Definition config.h:368
cString InitialChannel
Definition config.h:374
int DefaultSortModeRec
Definition config.h:319
char SVDRPHostName[HOST_NAME_MAX]
Definition config.h:303
int RcRepeatDelta
Definition config.h:308
int InstantRecordTime
Definition config.h:276
int NumberKeysForChars
Definition config.h:321
int SkipEdited
Definition config.h:355
int PauseLifetime
Definition config.h:312
int InitialVolume
Definition config.h:369
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition shutdown.c:93
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition shutdown.c:209
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition shutdown.h:54
virtual void SetEvents(const cEvent *Present, const cEvent *Following)=0
Sets the Present and Following EPG events.
virtual void SetPositioner(const cPositioner *Positioner)
Sets the Positioner used to move the satellite dish.
Definition skins.c:73
virtual void SetChannel(const cChannel *Channel, int Number)=0
Sets the current channel to Channel.
virtual void SetRecording(const cRecording *Recording)=0
Sets the Recording that shall be displayed, using the entire central area of the menu.
virtual bool SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New)
Sets the item at the given Index to Recording.
Definition skins.h:272
virtual void Scroll(bool Up, bool Page)
If this menu contains a text area that can be scrolled, this function will be called to actually scro...
Definition skins.c:107
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable)=0
Sets the item at the given Index to Text.
virtual void SetEvent(const cEvent *Event)=0
Sets the Event that shall be displayed, using the entire central area of the menu.
virtual bool SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch, bool TimerActive)
Sets the item at the given Index to Event.
Definition skins.h:236
virtual bool SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider)
Sets the item at the given Index to Channel.
Definition skins.h:263
virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable)
Sets the item at the given Index to Timer.
Definition skins.h:256
virtual void SetText(const char *Text, bool FixedFont)=0
Sets the Text that shall be displayed, using the entire central area of the menu.
virtual void SetJump(const char *Jump)=0
Sets the prompt that allows the user to enter a jump point.
virtual void SetMarks(const cMarks *Marks)
Sets the editing marks to Marks, which shall be used to display the progress bar through a cProgressB...
Definition skins.c:196
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition skins.c:191
virtual void SetCurrent(const char *Current)=0
Sets the current position within the recording, as a user readable string if the form "h:mm:ss....
virtual void SetProgress(int Current, int Total)=0
This function will be called whenever the position in or the total length of the recording has change...
virtual void SetMode(bool Play, bool Forward, int Speed)=0
Sets the current replay mode, which can be used to display some indicator, showing the user whether w...
virtual void SetTotal(const char *Total)=0
Sets the total length of the recording, as a user readable string if the form "h:mm:ss".
virtual void SetAudioChannel(int AudioChannel)=0
Sets the audio channel indicator.
virtual void SetTrack(int Index, const char *const *Tracks)=0
< This class implements the track display.
virtual void SetVolume(int Current, int Total, bool Mute)=0
< This class implements the volume/mute display.
virtual void Flush(void)
Actually draws the OSD display to the output device.
Definition skins.h:59
Definition skins.h:402
cTheme * Theme(void)
Definition skins.h:422
const char * Name(void)
Definition skins.h:421
virtual cSkinDisplayReplay * DisplayReplay(bool ModeOnly)=0
Creates and returns a new object for displaying replay progress.
virtual cSkinDisplayVolume * DisplayVolume(void)=0
Creates and returns a new object for displaying the current volume.
virtual cSkinDisplayTracks * DisplayTracks(const char *Title, int NumTracks, const char *const *Tracks)=0
Creates and returns a new object for displaying the available tracks.
virtual cSkinDisplayChannel * DisplayChannel(bool WithInfo)=0
Creates and returns a new object for displaying the current channel.
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition skins.c:231
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition skins.c:250
cSkin * Current(void)
Returns a pointer to the current skin.
Definition skins.h:468
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition skins.c:296
virtual void SetData(cChannel *Channel)=0
Sets all source specific parameters to those of the given Channel.
virtual cOsdItem * GetOsdItem(void)=0
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
virtual void GetData(cChannel *Channel)=0
Copies all source specific parameters to the given Channel.
cSourceParam * Get(char Source)
int Code(void) const
Definition sources.h:34
static cString ToString(int Code)
Definition sources.c:55
const char * Description(void) const
Definition sources.h:44
@ st_Mask
Definition sources.h:23
@ stSat
Definition sources.h:21
cSource * Get(int Code)
Definition sources.c:119
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition thread.c:867
void Reset(void)
Resets the state of this key, so that the next call to a lock's Lock() function with this key will re...
Definition thread.c:862
static void MsgMarksModified(const cMarks *Marks)
Definition status.c:56
static void MsgOsdChannel(const char *Text)
Definition status.c:128
static void MsgSetAudioChannel(int AudioChannel)
Definition status.c:74
static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
Definition status.c:134
static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On)
Definition status.c:50
static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On)
Definition status.c:44
static void MsgOsdClear(void)
Definition status.c:86
static void MsgSetAudioTrack(int Index, const char *const *Tracks)
Definition status.c:68
static void MsgOsdTextItem(const char *Text, bool Scroll=false)
Definition status.c:122
static void MsgSetSubtitleTrack(int Index, const char *const *Tracks)
Definition status.c:80
void Sort(bool IgnoreCase=false)
Definition tools.h:853
int Find(const char *s) const
Definition tools.c:1584
cString & CompactChars(char c)
Compact any sequence of characters 'c' to a single character, and strip all of them from the beginnin...
Definition tools.c:1143
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1149
const char * Description(void)
Returns a user visible, single line description of this theme.
Definition themes.c:75
bool Load(const char *FileName, bool OnlyDescriptions=false)
Loads the theme data from the given file.
Definition themes.c:83
int NumThemes(void)
Definition themes.h:73
int GetThemeIndex(const char *Description)
Definition themes.c:283
const char * Name(int Index)
Definition themes.h:74
bool Load(const char *SkinName)
Definition themes.c:239
const char *const * Descriptions(void)
Definition themes.h:76
const char * FileName(int Index)
Definition themes.h:75
bool Active(void)
Checks whether the thread is still alive.
Definition thread.c:329
uint64_t Elapsed(void) const
Definition tools.c:802
void Set(int Ms=0)
Sets the timer.
Definition tools.c:792
bool TimedOut(void) const
Definition tools.c:797
int Stop(void) const
Definition timers.h:71
void OnOff(void)
Definition timers.c:1022
const char * File(void) const
Definition timers.h:75
cString PrintFirstDay(void) const
Definition timers.c:424
time_t day
midnight of the day this timer shall hit, or of the first day it shall hit in case of a repeating tim...
Definition timers.h:43
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
Definition timers.h:44
bool IsSingleEvent(void) const
Definition timers.c:501
void SetPending(bool Pending)
Definition timers.c:935
time_t StopTime(void) const
the stop time as given by the user
Definition timers.c:712
time_t FirstDay(void) const
Definition timers.h:76
bool Recording(void) const
Definition timers.h:63
int priority
Definition timers.h:47
char file[NAME_MAX *2+1]
Definition timers.h:50
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition timers.c:285
void SetFlags(uint Flags)
Definition timers.c:995
int Start(void) const
Definition timers.h:70
int start
the start and stop time of this timer as given by the user,
Definition timers.h:45
void SetDeferred(int Seconds)
Definition timers.c:989
bool IsPatternTimer(void) const
Definition timers.h:95
const char * Pattern(void) const
Definition timers.h:74
int WeekDays(void) const
Definition timers.h:69
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition timers.c:390
void TriggerRespawn(void)
Definition timers.c:843
time_t Day(void) const
Definition timers.h:68
void SetRemote(const char *Remote)
Definition timers.c:983
char * remote
Definition timers.h:52
bool SetEvent(const cEvent *Event)
Definition timers.c:906
const cChannel * channel
Definition timers.h:42
int stop
in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm
Definition timers.h:46
bool Local(void) const
Definition timers.h:79
const cEvent * Event(void) const
Definition timers.h:84
void Skip(void)
Definition timers.c:1015
time_t StartTime(void) const
the start time as given by the user
Definition timers.c:705
const cChannel * Channel(void) const
Definition timers.h:67
bool Pending(void) const
Definition timers.h:64
cString ToDescr(void) const
Definition timers.c:321
bool SetEventFromSchedule(const cSchedules *Schedules)
Definition timers.c:857
int Priority(void) const
Definition timers.h:72
void SetRecording(bool Recording)
Definition timers.c:926
char pattern[NAME_MAX *2+1]
Definition timers.h:49
static int GetMDay(time_t t)
Definition timers.c:506
bool HasFlags(uint Flags) const
Definition timers.c:1010
const char * Remote(void) const
Definition timers.h:78
int lifetime
Definition timers.h:48
int Id(void) const
Definition timers.h:62
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
Definition timers.c:560
uint flags
Definition timers.h:41
cString ToText(bool UseChannelID=false) const
Definition timers.c:311
void Add(cTimer *Timer, cTimer *After=NULL)
Definition timers.c:1178
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition timers.c:1173
void Del(cTimer *Timer, bool DeleteObject=true)
Definition timers.c:1192
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition timers.c:1168
const cTimer * GetMatch(time_t t) const
Definition timers.c:1095
int Size(void) const
Definition tools.h:764
void Sort(__compar_fn_t Compare)
Definition tools.h:821
virtual void Insert(T Data, int Before=0)
Definition tools.h:765
virtual void Append(T Data)
Definition tools.h:784
static const char * Name(void)
Definition videodir.c:60
static int VideoDiskSpace(int *FreeMB=NULL, int *UsedMB=NULL)
Definition videodir.c:152
static void ForceCheck(void)
To avoid unnecessary load, the video disk usage is only actually checked every DISKSPACECHEK seconds.
Definition videodir.h:101
cNestedItemList Commands
Definition config.c:275
cSetup Setup
Definition config.c:372
cNestedItemList Folders
Definition config.c:274
cNestedItemList RecordingCommands
Definition config.c:276
#define TIMERMACRO_MATCH
Definition config.h:54
#define TIMERMACRO_AFTER
Definition config.h:55
#define MAXLIFETIME
Definition config.h:48
#define MAXPRIORITY
Definition config.h:43
#define VDRVERSION
Definition config.h:25
#define TIMERMACRO_BEFORE
Definition config.h:53
#define TIMERMACRO_EPISODE
Definition config.h:52
#define TIMERMACRO_TITLE
Definition config.h:51
#define LIVEPRIORITY
Definition config.h:45
#define MAXVOLUME
Definition device.h:32
eVideoDisplayFormat
Definition device.h:58
#define MAXDEVICES
Definition device.h:29
#define IS_AUDIO_TRACK(t)
Definition device.h:76
eTrackType
Definition device.h:63
@ ttSubtitle
Definition device.h:70
@ ttDolbyLast
Definition device.h:69
@ ttDolby
Definition device.h:67
@ ttAudioFirst
Definition device.h:65
@ ttSubtitleLast
Definition device.h:72
@ ttSubtitleFirst
Definition device.h:71
@ ttAudio
Definition device.h:64
@ ttNone
Definition device.h:63
#define IS_DOLBY_TRACK(t)
Definition device.h:77
cEITScanner EITScanner
Definition eitscan.c:90
#define LOCK_SCHEDULES_READ
Definition epg.h:233
#define MAXEPGBUGFIXLEVEL
Definition epg.h:21
const char * DefaultFontOsd
Definition font.c:24
const char * DefaultFontSml
Definition font.c:25
const char * DefaultFontFix
Definition font.c:26
eDvbFont
Definition font.h:21
@ fontFix
Definition font.h:23
const char * I18nLocale(int Language)
Returns the locale code of the given Language (which is an index as returned by I18nCurrentLanguage()...
Definition i18n.c:266
const cStringList * I18nLanguages(void)
Returns the list of available languages.
Definition i18n.c:249
int I18nNumLanguagesWithLocale(void)
Returns the number of entries in the list returned by I18nLanguages() that actually have a locale.
Definition i18n.c:244
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition i18n.c:231
void I18nSetLocale(const char *Locale)
Sets the current locale to Locale.
Definition i18n.c:217
void I18nSetLanguage(int Language)
Sets the current language index to Language.
Definition i18n.c:236
#define tr(s)
Definition i18n.h:85
cInterface * Interface
Definition interface.c:20
#define kMarkMoveForward
Definition keys.h:71
#define kMarkSkipForward
Definition keys.h:69
#define kMarkJumpBack
Definition keys.h:72
#define kEditCut
Definition keys.h:74
#define kMarkToggle
Definition keys.h:67
#define kMarkJumpForward
Definition keys.h:73
#define RAWKEY(k)
Definition keys.h:77
#define kEditTest
Definition keys.h:75
#define kMarkSkipBack
Definition keys.h:68
#define kMarkMoveBack
Definition keys.h:70
#define NORMALKEY(k)
Definition keys.h:79
eKeys
Definition keys.h:16
@ kRecord
Definition keys.h:34
@ kPlayPause
Definition keys.h:30
@ kRight
Definition keys.h:23
@ k_Flags
Definition keys.h:63
@ kPause
Definition keys.h:32
@ k9
Definition keys.h:28
@ kRed
Definition keys.h:24
@ kUp
Definition keys.h:17
@ kChanUp
Definition keys.h:40
@ kNone
Definition keys.h:55
@ kPlay
Definition keys.h:31
@ kFastFwd
Definition keys.h:35
@ k_Release
Definition keys.h:62
@ kDown
Definition keys.h:18
@ kGreen
Definition keys.h:25
@ k1
Definition keys.h:28
@ kStop
Definition keys.h:33
@ kSubtitles
Definition keys.h:47
@ kLeft
Definition keys.h:22
@ kBlue
Definition keys.h:27
@ kAudio
Definition keys.h:46
@ kMute
Definition keys.h:45
@ kPrev
Definition keys.h:38
@ k0
Definition keys.h:28
@ kYellow
Definition keys.h:26
@ kBack
Definition keys.h:21
@ k_Repeat
Definition keys.h:61
@ kFastRew
Definition keys.h:36
@ kChanDn
Definition keys.h:41
@ kVolDn
Definition keys.h:44
@ kNext
Definition keys.h:37
@ kOk
Definition keys.h:20
@ kVolUp
Definition keys.h:43
@ kInfo
Definition keys.h:29
static const char * TimerMatchChars
Definition menu.c:1598
static const char * TimerFileMacrosForPattern[]
Definition menu.c:996
#define NEWTIMERLIMIT
Definition menu.c:38
#define osUserRecRenamed
Definition menu.c:2506
#define MAXINSTANTRECTIME
Definition menu.c:44
#define NODISKSPACEDELTA
Definition menu.c:50
#define CAMRESPONSETIMEOUT
Definition menu.c:47
#define MAXRECORDCONTROLS
Definition menu.c:43
static bool RemoteTimerError(const cTimer *Timer)
Definition menu.c:1130
static void AddRecordingFolders(const cRecordings *Recordings, cList< cNestedItem > *List, char *Path)
Definition menu.c:822
#define CAMMENURETRYTIMEOUT
Definition menu.c:46
#define osUserRecEmpty
Definition menu.c:2509
cOsdObject * CamControl(void)
Definition menu.c:2490
bool CamMenuActive(void)
Definition menu.c:2499
#define STAY_SECONDS_OFF_END
#define osUserRecMoved
Definition menu.c:2507
#define MUTETIMEOUT
Definition menu.c:5099
#define MODETIMEOUT
Definition menu.c:37
#define TRACKTIMEOUT
Definition menu.c:5165
static bool CamMenuIsOpen
Definition menu.c:2306
#define CHANNELNUMBERTIMEOUT
Definition menu.c:351
static const char * TimerFileMacros[]
Definition menu.c:1006
#define INSTANT_REC_EPG_LOOKAHEAD
Definition menu.c:5474
#define FOLDERDELIMCHARSUBST
Definition menu.c:821
#define CHNAMWIDTH
Definition menu.c:54
#define CHNUMWIDTH
Definition menu.c:53
#define osUserRecRemoved
Definition menu.c:2508
#define MAXWAITFORCAMMENU
Definition menu.c:45
#define VOLUMETIMEOUT
Definition menu.c:5098
#define DEFERTIMER
Definition menu.c:41
#define PROGRESSTIMEOUT
Definition menu.c:48
#define MINFREEDISK
Definition menu.c:49
static bool TimerStillRecording(const char *FileName)
Definition menu.c:3267
static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer=NULL)
Definition menu.c:1136
#define MAXWAIT4EPGINFO
Definition menu.c:36
#define STOP_RECORDING
Definition menu.c:4505
static void SetTrackDescriptions(int LiveChannel)
Definition menu.c:4756
eOSState
Definition osdbase.h:18
@ osUser5
Definition osdbase.h:40
@ osRecordings
Definition osdbase.h:23
@ osCancelEdit
Definition osdbase.h:32
@ osPause
Definition osdbase.h:27
@ osPlugin
Definition osdbase.h:24
@ osChannels
Definition osdbase.h:21
@ osStopReplay
Definition osdbase.h:31
@ osUser1
Definition osdbase.h:36
@ osUser8
Definition osdbase.h:43
@ osUser10
Definition osdbase.h:45
@ osRecord
Definition osdbase.h:28
@ osEnd
Definition osdbase.h:34
@ osSetup
Definition osdbase.h:25
@ osUser4
Definition osdbase.h:39
@ osStopRecord
Definition osdbase.h:30
@ osContinue
Definition osdbase.h:19
@ osUser6
Definition osdbase.h:41
@ osTimers
Definition osdbase.h:22
@ osReplay
Definition osdbase.h:29
@ osUser3
Definition osdbase.h:38
@ osUser2
Definition osdbase.h:37
@ osUnknown
Definition osdbase.h:18
@ osUser9
Definition osdbase.h:44
@ osSchedule
Definition osdbase.h:20
@ osCommands
Definition osdbase.h:26
@ osBack
Definition osdbase.h:33
@ osUser7
Definition osdbase.h:42
cString GetRecordingTimerId(const char *Directory)
Definition recording.c:3297
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition recording.c:3192
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition recording.c:153
void GetRecordingsSortMode(const char *Directory)
Definition recording.c:3249
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition recording.c:3219
eRecordingsSortMode RecordingsSortMode
Definition recording.c:3242
char * ExchangeChars(char *s, bool ToFileSystem)
Definition recording.c:607
void IncRecordingsSortMode(const char *Directory)
Definition recording.c:3268
cDoneRecordings DoneRecordingsPattern
Definition recording.c:3099
cRecordingsHandler RecordingsHandler
Definition recording.c:2012
void SetRecordingTimerId(const char *Directory, const char *TimerId)
Definition recording.c:3279
@ ruCut
Definition recording.h:33
@ ruCopy
Definition recording.h:35
@ ruDst
Definition recording.h:38
@ ruNone
Definition recording.h:29
@ ruMove
Definition recording.h:34
@ ruPending
Definition recording.h:40
#define RUC_BEFORERECORDING
Definition recording.h:421
@ rsmName
Definition recording.h:550
#define RUC_AFTERRECORDING
Definition recording.h:423
#define LOCK_RECORDINGS_READ
Definition recording.h:307
#define MAXVIDEOFILESIZETS
Definition recording.h:448
#define FOLDERDELIMCHAR
Definition recording.h:21
#define LOCK_RECORDINGS_WRITE
Definition recording.h:308
#define MINVIDEOFILESIZE
Definition recording.h:450
cShutdownHandler ShutdownHandler
Definition shutdown.c:27
static const cCursesFont Font
Definition skincurses.c:31
cSkins Skins
Definition skins.c:219
@ mcSetupMisc
Definition skins.h:128
@ mcSetupOsd
Definition skins.h:121
@ mcSetupLnb
Definition skins.h:124
@ mcMain
Definition skins.h:107
@ mcSetup
Definition skins.h:120
@ mcChannel
Definition skins.h:111
@ mcRecordingInfo
Definition skins.h:116
@ mcSetupDvb
Definition skins.h:123
@ mcSetupRecord
Definition skins.h:126
@ mcCam
Definition skins.h:134
@ mcSetupReplay
Definition skins.h:127
@ mcChannelEdit
Definition skins.h:112
@ mcCommand
Definition skins.h:130
@ mcEvent
Definition skins.h:131
@ mcSetupCam
Definition skins.h:125
@ mcSchedule
Definition skins.h:108
@ mcText
Definition skins.h:132
@ mcRecording
Definition skins.h:115
@ mcRecordingEdit
Definition skins.h:117
@ mcTimerEdit
Definition skins.h:114
@ mcScheduleNow
Definition skins.h:109
@ mcSetupPlugins
Definition skins.h:129
@ mcFolder
Definition skins.h:133
@ mcSetupEpg
Definition skins.h:122
@ mcTimer
Definition skins.h:113
@ mcScheduleNext
Definition skins.h:110
@ mtWarning
Definition skins.h:37
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
@ mtStatus
Definition skins.h:37
@ msmProvider
Definition skins.h:142
@ msmTime
Definition skins.h:141
@ msmName
Definition skins.h:140
@ msmNumber
Definition skins.h:139
cSourceParams SourceParams
cSources Sources
Definition sources.c:117
Definition runvdr.c:107
char language[MAXLANGCODE2]
Definition epg.h:47
uchar stream
Definition epg.h:45
uchar type
Definition epg.h:46
char * description
Definition epg.h:48
char language[MAXLANGCODE2]
Definition device.h:82
char description[32]
Definition device.h:83
uint16_t id
Definition device.h:81
void StopSVDRPHandler(void)
Definition svdrp.c:2837
bool GetSVDRPServerNames(cStringList *ServerNames)
Gets a list of all available VDRs this VDR is connected to via SVDRP, and stores it in the given Serv...
Definition svdrp.c:2846
bool ExecSVDRPCommand(const char *ServerName, const char *Command, cStringList *Response)
Sends the given SVDRP Command string to the remote VDR identified by ServerName and collects all of t...
Definition svdrp.c:2855
void StartSVDRPHandler(void)
Definition svdrp.c:2821
int SVDRPCode(const char *s)
Returns the value of the three digit reply code of the given SVDRP response string.
Definition svdrp.h:47
cStateKey StateKeySVDRPRemoteTimersPoll
Controls whether a change to the local list of timers needs to result in sending a POLL to the remote...
bool HandleRemoteTimerModifications(cTimer *NewTimer, cTimer *OldTimer, cString *Msg)
Performs any operations necessary to synchronize changes to a timer between peer VDR machines.
Definition timers.c:1382
#define LOCK_TIMERS_READ
Definition timers.h:244
#define LOCK_TIMERS_WRITE
Definition timers.h:245
@ tfAvoid
Definition timers.h:24
@ tfInstant
Definition timers.h:20
@ tfActive
Definition timers.h:19
@ tfVps
Definition timers.h:21
@ tfRecording
Definition timers.h:22
@ tfSpawned
Definition timers.h:23
eTimerMatch
Definition timers.h:27
@ tmFull
Definition timers.h:27
@ tmNone
Definition timers.h:27
char * strcpyrealloc(char *dest, const char *src)
Definition tools.c:114
const char * strgetlast(const char *s, char c)
Definition tools.c:213
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition tools.c:899
bool isempty(const char *s)
Definition tools.c:349
char * strreplace(char *s, char c1, char c2)
Definition tools.c:139
cString strescape(const char *s, const char *chars)
Definition tools.c:272
int strcountchr(const char *s, char c)
returns the number of occurrences of 'c' in 's'.
Definition tools.c:191
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition tools.c:499
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition tools.c:1172
char * stripspace(char *s)
Definition tools.c:219
int Utf8SymChars(const char *s, int Symbols)
Returns the number of character bytes at the beginning of the given string that form at most the give...
Definition tools.c:874
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:131
cString itoa(int n)
Definition tools.c:442
const char * strchrn(const char *s, char c, size_t n)
returns a pointer to the n'th occurrence (counting from 1) of c in s, or NULL if no such character wa...
Definition tools.c:178
cString AddDirectory(const char *DirName, const char *FileName)
Definition tools.c:402
#define SECSINDAY
Definition tools.h:42
#define dsyslog(a...)
Definition tools.h:37
int CompareInts(const void *a, const void *b)
Definition tools.h:827
#define MALLOC(type, size)
Definition tools.h:47
char * skipspace(const char *s)
Definition tools.h:241
void DELETENULL(T *&p)
Definition tools.h:49
bool DoubleEqual(double a, double b)
Definition tools.h:97
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36