vdr 2.7.3
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.18 2024/10/11 14:10:50 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
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
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
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
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("Not enough free disk space to start editing process!"));
2793 Skins.Message(mtError, tr("Error while queueing recording for cutting!"));
2794 }
2795 }
2796 else if (doCopy) {
2797 if (!*name)
2798 *name = ' '; // name must not be empty!
2799 cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2801 if (strcmp(NewName, recording->Name())) {
2802 cString FromName = cString(ExchangeChars(strdup(recording->Name()), true), true);
2803 cString ToName = cString(ExchangeChars(strdup(*NewName), true), true);
2804 cString FileName = cString(strreplace(strdup(recording->FileName()), *FromName, *ToName), true);
2805 if (access(*FileName, F_OK) != 0 || Interface->Confirm(tr("Edited version already exists - overwrite?"))) {
2806 if (MakeDirs(FileName, true) && !RecordingsHandler.Add(ruCopy, recording->FileName(), FileName))
2807 Skins.Message(mtError, tr("Error while queueing recording for copying!"));
2808 else {
2810 Recordings->AddByName(FileName);
2811 }
2812 }
2813 }
2814 }
2817 SetHelpKeys();
2818 return osContinue;
2819}
2820
2822{
2823 if (Get(Current()) == nameItem) {
2824 if (Interface->Confirm(tr("Rename recording to folder name?"))) {
2825 char *s = strrchr(folder, FOLDERDELIMCHAR);
2826 if (s)
2827 *s++ = 0;
2828 else
2829 s = folder;
2830 strn0cpy(name, s, sizeof(name));
2831 if (s == folder)
2832 *s = 0;
2833 Set();
2834 }
2835 }
2836 return osContinue;
2837}
2838
2840{
2841 if (extraAction) {
2842 if (buttonDelete && Interface->Confirm(tr("Delete resume for this recording?"))) {
2844 ResumeFile.Delete();
2845 SetHelpKeys();
2846 }
2847 }
2848 else {
2849 if (buttonDelete && Interface->Confirm(tr("Delete editing marks for this recording?"))) {
2851 SetHelpKeys();
2852 cMutexLock ControlMutexLock;
2853 if (cControl *Control = cControl::Control(ControlMutexLock, true)) {
2854 if (const cRecording *Recording = Control->GetRecording()) {
2855 if (strcmp(recording->FileName(), Recording->FileName()) == 0)
2856 Control->ClearEditingMarks();
2857 }
2858 }
2859 }
2860 else
2861 Skins.Message(mtError, tr("Error while deleting editing marks!"));
2862 }
2863 }
2864 return osContinue;
2865}
2866
2868{
2869 cStateKey StateKey;
2870 cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
2871 cRecording *Recording = Recordings->GetByName(recording->FileName());
2872 if (!Recording) {
2873 StateKey.Remove(false);
2874 Skins.Message(mtWarning, tr("Recording vanished!"));
2875 return osBack;
2876 }
2877 bool Modified = false;
2879 if (!Recording->ChangePriorityLifetime(priority, lifetime)) {
2880 StateKey.Remove(Modified);
2881 Skins.Message(mtError, tr("Error while changing priority/lifetime!"));
2882 return osContinue;
2883 }
2884 Modified = true;
2885 }
2886 if (!*name) {
2887 *name = ' '; // name must not be empty!
2888 name[1] = 0;
2889 }
2890 cString OldFolder = Recording->Folder();
2891 cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2893 if (strcmp(NewName, Recording->Name())) {
2894 if (!Recording->ChangeName(NewName)) {
2895 StateKey.Remove(Modified);
2896 Skins.Message(mtError, tr("Error while changing folder/name!"));
2897 return osContinue;
2898 }
2899 Modified = true;
2900 }
2901 if (Modified) {
2902 eOSState state = osUserRecRenamed;
2903 if (strcmp(Recording->Folder(), OldFolder))
2904 state = osUserRecMoved;
2905 Recordings->TouchUpdate();
2906 StateKey.Remove(Modified);
2907 return state;
2908 }
2909 StateKey.Remove(Modified);
2910 return osBack;
2911}
2912
2914{
2915 if (!HasSubMenu()) {
2916 if (!RefreshRecording())
2917 return osBack; // the recording has vanished, so close this menu
2918 }
2919 eOSState state = cOsdMenu::ProcessKey(Key);
2920 if (state == osUnknown) {
2921 switch (Key) {
2922 case k0: return RemoveName();
2923 case kRed: return buttonFolder ? Folder() : osContinue;
2924 case kGreen: return buttonAction ? Action() : osContinue;
2925 case kYellow: return buttonDelete ? Delete() : osContinue;
2927 case kOk: return !recordingIsInUse ? ApplyChanges() : osBack;
2928 default: break;
2929 }
2930 }
2931 else if (state == osEnd && HasSubMenu())
2932 state = SetFolder();
2933 return state;
2934}
2935
2936// --- cMenuRecording --------------------------------------------------------
2937
2938class cMenuRecording : public cOsdMenu {
2939private:
2944 bool RefreshRecording(void);
2945public:
2946 cMenuRecording(const cRecording *Recording, bool WithButtons = false);
2947 virtual void Display(void);
2948 virtual eOSState ProcessKey(eKeys Key);
2949};
2950
2951cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
2952:cOsdMenu(tr("Recording info"))
2953{
2955 if (cRecordings::GetRecordingsRead(recordingsStateKey)) // initializes recordingsStateKey, so we don't call Display() unnecessarily
2957 recording = Recording;
2959 withButtons = WithButtons;
2960 if (withButtons)
2961 SetHelp(tr("Button$Play"), tr("Button$Rewind"), NULL, tr("Button$Edit"));
2962}
2963
2965{
2967 if ((recording = Recordings->GetByName(originalFileName)) != NULL)
2968 Display();
2969 else {
2971 Skins.Message(mtWarning, tr("Recording vanished!"));
2972 return false;
2973 }
2975 }
2976 return true;
2977}
2978
2980{
2981 if (HasSubMenu()) {
2982 SubMenu()->Display();
2983 return;
2984 }
2987 if (recording->Info()->Description())
2989}
2990
2992{
2993 if (HasSubMenu())
2994 return cOsdMenu::ProcessKey(Key);
2995 else if (!RefreshRecording())
2996 return osBack; // the recording has vanished, so close this menu
2997 switch (int(Key)) {
2998 case kUp|k_Repeat:
2999 case kUp:
3000 case kDown|k_Repeat:
3001 case kDown:
3002 case kLeft|k_Repeat:
3003 case kLeft:
3004 case kRight|k_Repeat:
3005 case kRight:
3006 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
3007 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
3008 return osContinue;
3009 case kInfo: return osBack;
3010 default: break;
3011 }
3012
3013 eOSState state = cOsdMenu::ProcessKey(Key);
3014
3015 if (state == osUnknown) {
3016 switch (Key) {
3017 case kRed: if (withButtons)
3018 Key = kOk; // will play the recording, even if recording commands are defined
3019 case kGreen: if (!withButtons)
3020 break;
3021 cRemote::Put(Key, true);
3022 // continue with osBack to close the info menu and process the key
3023 case kOk: return osBack;
3024 case kBlue: if (withButtons)
3026 break;
3027 default: break;
3028 }
3029 }
3030 return state;
3031}
3032
3033// --- cMenuRecordingItem ----------------------------------------------------
3034
3036private:
3039 char *name;
3041public:
3044 void IncrementCounter(bool New);
3045 const char *Name(void) const { return name; }
3046 int Level(void) const { return level; }
3047 const cRecording *Recording(void) const { return recording; }
3048 bool IsDirectory(void) const { return name != NULL; }
3050 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
3051 };
3052
3054{
3056 level = Level;
3057 name = NULL;
3059 SetText(Recording->Title('\t', true, Level));
3060 if (*Text() == '\t') // this is a folder
3061 name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
3062 else { // this is an actual recording
3063 int Usage = Recording->IsInUse();
3064 if ((Usage & ruDst) != 0 && (Usage & (ruMove | ruCopy)) != 0)
3065 SetSelectable(false);
3066 }
3067}
3068
3073
3075{
3076 totalEntries++;
3077 if (New)
3078 newEntries++;
3080}
3081
3082void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
3083{
3084 if (!DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
3085 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
3086}
3087
3088// --- cMenuRecordings -------------------------------------------------------
3089
3092
3093cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus, const cRecordingFilter *Filter)
3094:cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
3095{
3097 base = Base ? strdup(Base) : NULL;
3098 level = Setup.RecordingDirs ? Level : -1;
3099 filter = Filter;
3100 helpKeys = -1;
3101 Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
3102 Set();
3103 if (Current() < 0)
3104 SetCurrent(First());
3105 else if (OpenSubMenus && (cReplayControl::LastReplayed() || *path || *fileName)) {
3106 if (!*path || Level < strcountchr(path, FOLDERDELIMCHAR)) {
3107 if (Open(true))
3108 return;
3109 }
3110 }
3111 SetHelpKeys();
3112}
3113
3115{
3117 if (!ri->IsDirectory())
3118 SetRecording(ri->Recording()->FileName());
3119 }
3120 free(base);
3121}
3122
3124{
3126 int NewHelpKeys = 0;
3127 if (ri) {
3128 if (ri->IsDirectory())
3129 NewHelpKeys = 1;
3130 else
3131 NewHelpKeys = 2;
3132 }
3133 if (NewHelpKeys != helpKeys) {
3134 switch (NewHelpKeys) {
3135 case 0: SetHelp(NULL); break;
3136 case 1: SetHelp(tr("Button$Open"), NULL, NULL, tr("Button$Edit")); break;
3137 case 2: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), tr("Button$Info"));
3138 default: ;
3139 }
3140 helpKeys = NewHelpKeys;
3141 }
3142}
3143
3144void cMenuRecordings::Set(bool Refresh)
3145{
3148 cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting!
3149 const char *CurrentRecording = NULL;
3151 CurrentRecording = ri->Recording()->FileName();
3152 if (!CurrentRecording)
3153 CurrentRecording = *fileName ? *fileName : cReplayControl::LastReplayed();
3154 int current = Current();
3155 Clear();
3157 Recordings->Sort();
3158 cMenuRecordingItem *CurrentItem = NULL;
3159 cMenuRecordingItem *LastItem = NULL;
3160 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
3161 if ((!filter || filter->Filter(Recording)) && (!base || (strstr(Recording->Name(), base) == Recording->Name() && Recording->Name()[strlen(base)] == FOLDERDELIMCHAR))) {
3162 cMenuRecordingItem *Item = new cMenuRecordingItem(Recording, level);
3163 cMenuRecordingItem *LastDir = NULL;
3164 if (Item->IsDirectory()) {
3165 // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
3166 for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
3167 if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
3168 LastDir = p;
3169 break;
3170 }
3171 }
3172 }
3173 if (*Item->Text() && !LastDir) {
3174 Add(Item);
3175 LastItem = Item;
3176 if (Item->IsDirectory())
3177 LastDir = Item;
3178 }
3179 else
3180 delete Item;
3181 if (LastItem || LastDir) {
3182 if (*path) {
3183 if (strcmp(path, Recording->Folder()) == 0)
3184 CurrentItem = LastDir ? LastDir : LastItem;
3185 }
3186 else if (CurrentRecording && strcmp(CurrentRecording, Recording->FileName()) == 0)
3187 CurrentItem = LastDir ? LastDir : LastItem;
3188 }
3189 if (LastDir)
3190 LastDir->IncrementCounter(Recording->IsNew());
3191 }
3192 }
3193 SetCurrent(CurrentItem);
3194 if (Current() < 0)
3195 SetCurrent(Get(current)); // last resort, in case the recording was deleted
3197 recordingsStateKey.Remove(false); // sorting doesn't count as a real modification
3198 if (Refresh)
3199 Display();
3200 }
3201}
3202
3203void cMenuRecordings::SetRecording(const char *FileName)
3204{
3205 fileName = FileName;
3206}
3207
3209{
3211 if (base) {
3212 char *s = ExchangeChars(strdup(base), true);
3213 d = AddDirectory(d, s);
3214 free(s);
3215 }
3216 return d;
3217}
3218
3219bool cMenuRecordings::Open(bool OpenSubMenus)
3220{
3222 if (ri && ri->IsDirectory() && (!*path || strcountchr(path, FOLDERDELIMCHAR) > 0)) {
3223 const char *t = ri->Name();
3224 cString buffer;
3225 if (base) {
3226 buffer = cString::sprintf("%s%c%s", base, FOLDERDELIMCHAR, t);
3227 t = buffer;
3228 }
3229 AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus, filter));
3230 return true;
3231 }
3232 return false;
3233}
3234
3236{
3238 if (ri) {
3239 if (ri->IsDirectory())
3240 Open();
3241 else {
3243 return osReplay;
3244 }
3245 }
3246 return osContinue;
3247}
3248
3250{
3251 if (HasSubMenu() || Count() == 0)
3252 return osContinue;
3254 if (ri && !ri->IsDirectory()) {
3255 cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
3256 cResumeFile ResumeFile(ri->Recording()->FileName(), ri->Recording()->IsPesRecording());
3257 ResumeFile.Delete();
3258 return Play();
3259 }
3260 return osContinue;
3261}
3262
3263static bool TimerStillRecording(const char *FileName)
3264{
3266 // local timer
3267 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3269 if (cTimer *Timer = rc->Timer()) {
3270 Timer->Skip();
3271 cRecordControls::Process(Timers, time(NULL));
3272 if (Timer->IsSingleEvent()) {
3273 Timers->Del(Timer);
3274 isyslog("deleted timer %s", *Timer->ToDescr());
3275 }
3276 }
3277 }
3278 else
3279 return true; // user didn't confirm deletion
3280 }
3281 else {
3282 // remote timer
3283 cString TimerId = GetRecordingTimerId(FileName);
3284 if (*TimerId) {
3285 int Id;
3286 char *RemoteBuf = NULL;
3287 cString Remote;
3288 if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf) && Id != 0) {
3289 Remote = RemoteBuf;
3290 free(RemoteBuf);
3291 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3293 if (cTimer *Timer = Timers->GetById(Id, Remote)) {
3294 cTimer OldTimer = *Timer;
3295 Timer->Skip();
3296 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
3297 if (Timer->IsSingleEvent()) {
3298 if (HandleRemoteModifications(NULL, Timer))
3299 Timers->Del(Timer);
3300 else
3301 return true; // error while deleting remote timer
3302 }
3303 else if (!HandleRemoteModifications(Timer, &OldTimer))
3304 return true; // error while modifying remote timer
3305 }
3306 }
3307 else
3308 return true; // user didn't confirm deletion
3309 }
3310 }
3311 }
3312 return false;
3313}
3314
3316{
3317 if (HasSubMenu() || Count() == 0)
3318 return osContinue;
3320 if (ri && !ri->IsDirectory()) {
3321 if (Interface->Confirm(tr("Delete recording?"))) {
3323 return osContinue;
3324 cString FileName;
3325 {
3327 if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) {
3328 FileName = Recording->FileName();
3329 if (RecordingsHandler.GetUsage(FileName)) {
3330 if (!Interface->Confirm(tr("Recording is being edited - really delete?")))
3331 return osContinue;
3332 SetNeedsFastResponse(true); // makes sure the edited version is removed from the menu ASAP
3333 }
3334 }
3335 else
3336 return osContinue; // recording has already been deleted
3337 }
3338 RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one!
3339 if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
3342 Recordings->SetExplicitModify();
3343 cRecording *Recording = Recordings->GetByName(FileName);
3344 if (!Recording || Recording->Delete()) {
3346 Recordings->DelByName(FileName);
3348 SetHelpKeys();
3350 Recordings->SetModified();
3352 Display();
3353 if (!Count())
3354 return osUserRecEmpty;
3355 return osUserRecRemoved;
3356 }
3357 else
3358 Skins.Message(mtError, tr("Error while deleting recording!"));
3360 }
3361 }
3362 return osContinue;
3363}
3364
3366{
3367 if (HasSubMenu() || Count() == 0)
3368 return osContinue;
3370 if (ri->IsDirectory())
3371 return AddSubMenu(new cMenuPathEdit(cString(ri->Recording()->Name(), strchrn(ri->Recording()->Name(), FOLDERDELIMCHAR, ri->Level() + 1))));
3372 else
3373 return AddSubMenu(new cMenuRecording(ri->Recording(), true));
3374 }
3375 return osContinue;
3376}
3377
3379{
3380 if (HasSubMenu() || Count() == 0)
3381 return osContinue;
3383 if (ri && !ri->IsDirectory()) {
3384 cMenuCommands *menu;
3385 eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
3386 if (Key != kNone)
3387 state = menu->ProcessKey(Key);
3388 return state;
3389 }
3390 return osContinue;
3391}
3392
3394{
3395 if (HasSubMenu())
3396 return osContinue;
3397 if (const cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()))
3398 SetRecording(ri->Recording()->FileName()); // makes sure the Recordings menu will reposition to the current recording
3401 Set(true);
3402 return osContinue;
3403}
3404
3406{
3407 eOSState state = cOsdMenu::ProcessKey(Key);
3408
3409 if (state == osUnknown) {
3410 switch (Key) {
3411 case kPlayPause:
3412 case kPlay:
3413 case kOk: return Play();
3414 case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
3415 case kGreen: return Rewind();
3416 case kYellow: return Delete();
3417 case kInfo:
3418 case kBlue: return Info();
3419 case k0: return Sort();
3420 case k1...k9: return Commands(Key);
3421 default: break;
3422 }
3423 }
3424 else if (state == osUserRecRenamed) {
3425 // a recording was renamed (within the same folder), so let's refresh the menu
3426 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3427 path = NULL;
3428 fileName = NULL;
3429 state = osContinue;
3430 }
3431 else if (state == osUserRecMoved) {
3432 // a recording was moved to a different folder, so let's delete the old item
3433 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3434 path = NULL;
3435 fileName = NULL;
3437 Set(); // the recording might have been moved into a new subfolder of this folder
3438 if (!Count())
3439 return osUserRecEmpty;
3440 Display();
3441 state = osUserRecRemoved;
3442 }
3443 else if (state == osUserRecRemoved) {
3444 // a recording was removed from a sub folder, so update the current item
3445 if (cOsdMenu *m = SubMenu()) {
3447 if (cMenuRecordingItem *riSub = (cMenuRecordingItem *)m->Get(m->Current()))
3448 ri->SetRecording(riSub->Recording());
3449 }
3450 }
3451 // no state change here, this report goes upstream!
3452 }
3453 else if (state == osUserRecEmpty) {
3454 // a subfolder became empty, so let's go back up
3455 CloseSubMenu(false); // this is the now empty submenu
3456 cOsdMenu::Del(Current()); // the menu entry of the now empty subfolder
3457 Set(); // in case a recording was moved into a new subfolder of this folder
3458 if (base && !Count()) // base: don't go up beyond the top level Recordings menu
3459 return state;
3460 Display();
3461 state = osContinue;
3462 }
3463 if (!HasSubMenu()) {
3464 Set(true);
3465 if (Key != kNone)
3466 SetHelpKeys();
3467 }
3468 return state;
3469}
3470
3471// --- cMenuSetupBase --------------------------------------------------------
3472
3474protected:
3476 virtual void Store(void);
3477public:
3478 cMenuSetupBase(void);
3479 };
3480
3485
3487{
3488 Setup = data;
3490 Setup.Save();
3491}
3492
3493// --- cMenuSetupOSD ---------------------------------------------------------
3494
3517
3538
3543
3545{
3546 int current = Current();
3547 for (cSkin *Skin = Skins.First(); Skin; Skin = Skins.Next(Skin))
3548 skinDescriptions[Skin->Index()] = Skin->Description();
3549 useSmallFontTexts[0] = tr("never");
3550 useSmallFontTexts[1] = tr("skin dependent");
3551 useSmallFontTexts[2] = tr("always");
3552 recSortModeTexts[0] = tr("by name");
3553 recSortModeTexts[1] = tr("by time");
3554 recSortDirTexts[0] = tr("ascending");
3555 recSortDirTexts[1] = tr("descending");
3556 keyColorTexts[0] = tr("Key$Red");
3557 keyColorTexts[1] = tr("Key$Green");
3558 keyColorTexts[2] = tr("Key$Yellow");
3559 keyColorTexts[3] = tr("Key$Blue");
3560 Clear();
3561 SetSection(tr("OSD"));
3562 Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0)));
3563 Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions));
3564 if (themes.NumThemes())
3565 Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions()));
3566 Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5));
3567 Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5));
3568 Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0));
3569 Add(new cMenuEditPrcItem( tr("Setup.OSD$Height (%)"), &data.OSDHeightP, 0.5, 1.0));
3570 Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
3571 Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"), &data.UseSmallFont, 3, useSmallFontTexts));
3572 Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"), &data.AntiAlias));
3573 Add(new cMenuEditStraItem(tr("Setup.OSD$Default font"), &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
3574 Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"), &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
3575 Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"), &fontFixIndex, fontFixNames.Size(), &fontFixNames[0]));
3576 Add(new cMenuEditPrcItem( tr("Setup.OSD$Default font size (%)"), &data.FontOsdSizeP, 0.01, 0.1, 1));
3577 Add(new cMenuEditPrcItem( tr("Setup.OSD$Small font size (%)"), &data.FontSmlSizeP, 0.01, 0.1, 1));
3578 Add(new cMenuEditPrcItem( tr("Setup.OSD$Fixed font size (%)"), &data.FontFixSizeP, 0.01, 0.1, 1));
3579 Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
3580 Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
3581 Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
3582 Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
3583 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
3584 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
3585 Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses));
3586 Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
3587 Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu));
3588 Add(new cMenuEditBoolItem(tr("Setup.OSD$Always sort folders first"), &data.AlwaysSortFoldersFirst));
3589 Add(new cMenuEditStraItem(tr("Setup.OSD$Default sort mode for recordings"), &data.DefaultSortModeRec, 2, recSortModeTexts));
3590 Add(new cMenuEditStraItem(tr("Setup.OSD$Sorting direction for recordings"), &data.RecSortingDirection, 2, recSortDirTexts));
3591 Add(new cMenuEditBoolItem(tr("Setup.OSD$Number keys for characters"), &data.NumberKeysForChars));
3592 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 0"), &data.ColorKey0, 4, keyColorTexts));
3593 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 1"), &data.ColorKey1, 4, keyColorTexts));
3594 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 2"), &data.ColorKey2, 4, keyColorTexts));
3595 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 3"), &data.ColorKey3, 4, keyColorTexts));
3597 Display();
3598}
3599
3601{
3602 bool ModifiedAppearance = false;
3603
3604 if (Key == kOk) {
3607 cSkin *Skin = Skins.Get(skinIndex);
3608 if (Skin) {
3609 Utf8Strn0Cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
3610 Skins.SetCurrent(Skin->Name());
3611 ModifiedAppearance = true;
3612 }
3613 }
3614 if (themes.NumThemes() && Skins.Current()->Theme()) {
3617 ModifiedAppearance |= themeIndex != originalThemeIndex;
3618 }
3620 ModifiedAppearance = true;
3622 ModifiedAppearance = true;
3627 ModifiedAppearance = true;
3629 ModifiedAppearance = true;
3631 ModifiedAppearance = true;
3634 Recordings->ClearSortNames();
3635 }
3636 }
3637
3638 int oldSkinIndex = skinIndex;
3639 int oldOsdLanguageIndex = osdLanguageIndex;
3641
3642 if (ModifiedAppearance)
3644
3645 if (osdLanguageIndex != oldOsdLanguageIndex || skinIndex != oldSkinIndex) {
3647 int OriginalOSDLanguage = I18nCurrentLanguage();
3649
3650 cSkin *Skin = Skins.Get(skinIndex);
3651 if (Skin) {
3652 char *d = themes.NumThemes() ? strdup(themes.Descriptions()[themeIndex]) : NULL;
3653 themes.Load(Skin->Name());
3654 if (skinIndex != oldSkinIndex)
3655 themeIndex = d ? themes.GetThemeIndex(d) : 0;
3656 free(d);
3657 }
3658
3659 Set();
3660 I18nSetLanguage(OriginalOSDLanguage);
3661 }
3662 return state;
3663}
3664
3665// --- cMenuSetupEPG ---------------------------------------------------------
3666
3668private:
3671 void Setup(void);
3672public:
3673 cMenuSetupEPG(void);
3674 virtual eOSState ProcessKey(eKeys Key);
3675 };
3676
3678{
3681 ;
3683 SetSection(tr("EPG"));
3684 SetHelp(tr("Button$Scan"));
3685 Setup();
3686}
3687
3689{
3690 int current = Current();
3691
3692 Clear();
3693
3694 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
3695 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan max. channel number (0=all)"), &data.EPGScanMaxChannel));
3696 Add(new cMenuEditBoolItem(tr("Setup.EPG$EPG pause after scan"), &data.EPGPauseAfterScan));
3697 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
3698 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0));
3699 Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
3700 if (data.SetSystemTime)
3701 Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource));
3702 // TRANSLATORS: note the plural!
3703 Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), &numLanguages, 0, I18nLanguages()->Size()));
3704 for (int i = 0; i < numLanguages; i++)
3705 // TRANSLATORS: note the singular!
3706 Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3707
3709 Display();
3710}
3711
3713{
3714 if (Key == kOk) {
3715 bool Modified = numLanguages != originalNumLanguages;
3716 if (!Modified) {
3717 for (int i = 0; i < numLanguages; i++) {
3718 if (data.EPGLanguages[i] != ::Setup.EPGLanguages[i]) {
3719 Modified = true;
3720 break;
3721 }
3722 }
3723 }
3724 if (Modified)
3726 }
3727
3728 int oldnumLanguages = numLanguages;
3729 int oldSetSystemTime = data.SetSystemTime;
3730
3732 if (Key != kNone) {
3733 if (numLanguages != oldnumLanguages || data.SetSystemTime != oldSetSystemTime) {
3734 for (int i = oldnumLanguages; i < numLanguages; i++) {
3735 data.EPGLanguages[i] = 0;
3736 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3737 int k;
3738 for (k = 0; k < oldnumLanguages; k++) {
3739 if (data.EPGLanguages[k] == l)
3740 break;
3741 }
3742 if (k >= oldnumLanguages) {
3743 data.EPGLanguages[i] = l;
3744 break;
3745 }
3746 }
3747 }
3749 Setup();
3750 }
3751 if (Key == kRed) {
3753 return osEnd;
3754 }
3755 }
3756 return state;
3757}
3758
3759// --- cMenuSetupDVB ---------------------------------------------------------
3760
3762private:
3767 void Setup(void);
3769 const char *updateChannelsTexts[6];
3771public:
3772 cMenuSetupDVB(void);
3773 virtual eOSState ProcessKey(eKeys Key);
3774 };
3775
3777{
3780 ;
3782 ;
3785 videoDisplayFormatTexts[0] = tr("pan&scan");
3786 videoDisplayFormatTexts[1] = tr("letterbox");
3787 videoDisplayFormatTexts[2] = tr("center cut out");
3788 updateChannelsTexts[0] = tr("no");
3789 updateChannelsTexts[1] = tr("names only");
3790 updateChannelsTexts[2] = tr("PIDs only");
3791 updateChannelsTexts[3] = tr("names and PIDs");
3792 updateChannelsTexts[4] = tr("add new channels");
3793 updateChannelsTexts[5] = tr("add new transponders");
3794 standardComplianceTexts[0] = "DVB";
3795 standardComplianceTexts[1] = "ANSI/SCTE";
3796 standardComplianceTexts[2] = "NORDIG";
3797
3798 SetSection(tr("DVB"));
3799 SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL);
3800 Setup();
3801}
3802
3804{
3805 int current = Current();
3806
3807 Clear();
3808
3809 Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
3810 Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"), &data.StandardCompliance, 3, standardComplianceTexts));
3811 Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
3812 if (data.VideoFormat == 0)
3813 Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
3814 Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital));
3815 Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts));
3816 Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
3817 for (int i = 0; i < numAudioLanguages; i++)
3818 Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3819 Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
3820 if (data.DisplaySubtitles) {
3821 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
3822 for (int i = 0; i < numSubtitleLanguages; i++)
3823 Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3824 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -100, 100));
3825 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
3826 Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
3827 }
3828
3830 Display();
3831}
3832
3834{
3835 int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
3836 bool oldVideoFormat = ::Setup.VideoFormat;
3837 bool newVideoFormat = data.VideoFormat;
3838 bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
3839 bool newDisplaySubtitles = data.DisplaySubtitles;
3840 int oldnumAudioLanguages = numAudioLanguages;
3841 int oldnumSubtitleLanguages = numSubtitleLanguages;
3843
3844 if (Key != kNone) {
3845 switch (Key) {
3846 case kGreen: cRemote::Put(kAudio, true);
3847 state = osEnd;
3848 break;
3849 case kYellow: cRemote::Put(kSubtitles, true);
3850 state = osEnd;
3851 break;
3852 default: {
3853 bool DoSetup = data.VideoFormat != newVideoFormat;
3854 DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
3855 if (numAudioLanguages != oldnumAudioLanguages) {
3856 for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
3857 data.AudioLanguages[i] = 0;
3858 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3859 int k;
3860 for (k = 0; k < oldnumAudioLanguages; k++) {
3861 if (data.AudioLanguages[k] == l)
3862 break;
3863 }
3864 if (k >= oldnumAudioLanguages) {
3865 data.AudioLanguages[i] = l;
3866 break;
3867 }
3868 }
3869 }
3871 DoSetup = true;
3872 }
3873 if (numSubtitleLanguages != oldnumSubtitleLanguages) {
3874 for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
3875 data.SubtitleLanguages[i] = 0;
3876 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3877 int k;
3878 for (k = 0; k < oldnumSubtitleLanguages; k++) {
3879 if (data.SubtitleLanguages[k] == l)
3880 break;
3881 }
3882 if (k >= oldnumSubtitleLanguages) {
3883 data.SubtitleLanguages[i] = l;
3884 break;
3885 }
3886 }
3887 }
3889 DoSetup = true;
3890 }
3891 if (DoSetup)
3892 Setup();
3893 }
3894 }
3895 }
3896 if (state == osBack && Key == kOk) {
3897 if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
3899 if (::Setup.VideoFormat != oldVideoFormat)
3901 if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
3904 }
3905 return state;
3906}
3907
3908// --- cMenuSetupLNB ---------------------------------------------------------
3909
3911private:
3913 void Setup(void);
3914public:
3915 cMenuSetupLNB(void);
3916 virtual eOSState ProcessKey(eKeys Key);
3917 };
3918
3920:satCableNumbers(MAXDEVICES)
3921{
3924 SetSection(tr("LNB"));
3925 Setup();
3926}
3927
3929{
3930 int current = Current();
3931
3932 Clear();
3933
3934 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
3935 if (!data.DiSEqC) {
3936 Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
3937 Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
3938 Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
3939 }
3940
3941 int NumSatDevices = 0;
3942 for (int i = 0; i < cDevice::NumDevices(); i++) {
3943 if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
3944 NumSatDevices++;
3945 }
3946 if (NumSatDevices > 1) {
3947 for (int i = 0; i < cDevice::NumDevices(); i++) {
3948 if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
3949 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")));
3950 else
3951 satCableNumbers.Array()[i] = 0;
3952 }
3953 }
3954
3955 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use dish positioner"), &data.UsePositioner));
3956 if (data.UsePositioner) {
3957 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site latitude (degrees)"), &data.SiteLat, -900, 900, 10, tr("South"), tr("North")));
3958 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site longitude (degrees)"), &data.SiteLon, -1800, 1800, 10, tr("West"), tr("East")));
3959 Add(new cMenuEditIntxItem(tr("Setup.LNB$Max. positioner swing (degrees)"), &data.PositionerSwing, 0, 900, 10));
3960 Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed (degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
3961 }
3962
3964 Display();
3965}
3966
3968{
3969 int oldDiSEqC = data.DiSEqC;
3970 int oldUsePositioner = data.UsePositioner;
3971 bool DeviceBondingsChanged = false;
3972 if (Key == kOk) {
3973 cString NewDeviceBondings = satCableNumbers.ToString();
3974 DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
3975 data.DeviceBondings = NewDeviceBondings;
3976 }
3978
3979 if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner != oldUsePositioner))
3980 Setup();
3981 else if (DeviceBondingsChanged)
3983 return state;
3984}
3985
3986// --- cMenuSetupCAM ---------------------------------------------------------
3987
3989private:
3991public:
3993 cCamSlot *CamSlot(void) { return camSlot; }
3994 bool Changed(void);
3995 };
3996
3998{
3999 camSlot = CamSlot;
4000 SetText("");
4001 Changed();
4002}
4003
4005{
4006 cString AssignedDevice("");
4007 const char *Activating = "";
4008 const char *CamName = camSlot->GetCamName();
4009 if (!CamName) {
4010 switch (camSlot->ModuleStatus()) {
4011 case msReset: CamName = tr("CAM reset"); break;
4012 case msPresent: CamName = tr("CAM present"); break;
4013 case msReady: CamName = tr("CAM ready"); break;
4014 default: CamName = "-"; break;
4015 }
4016 }
4017 else if (camSlot->IsActivating())
4018 // TRANSLATORS: note the leading blank!
4019 Activating = tr(" (activating)");
4020 cVector<int> DeviceNumbers;
4022 if (CamSlot == camSlot || CamSlot->MasterSlot() == camSlot)
4023 CamSlot->Devices(DeviceNumbers);
4024 }
4025 if (DeviceNumbers.Size() > 0) {
4026 AssignedDevice = cString::sprintf(" %s", tr("@ device"));
4027 DeviceNumbers.Sort(CompareInts);
4028 for (int i = 0; i < DeviceNumbers.Size(); i++)
4029 AssignedDevice = cString::sprintf("%s %d", *AssignedDevice, DeviceNumbers[i]);
4030 }
4031
4032 cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
4033 if (strcmp(buffer, Text()) != 0) {
4034 SetText(buffer);
4035 return true;
4036 }
4037 return false;
4038}
4039
4041private:
4043 const char *activationHelp;
4044 eOSState Menu(void);
4045 eOSState Reset(void);
4046 eOSState Activate(void);
4047 void SetHelpKeys(void);
4048public:
4049 cMenuSetupCAM(void);
4050 virtual eOSState ProcessKey(eKeys Key);
4051 };
4052
4054{
4056 activationHelp = NULL;
4058 SetSection(tr("CAM"));
4059 SetCols(15);
4060 SetHasHotkeys();
4061 for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
4062 if (CamSlot->IsMasterSlot()) // we only list master CAM slots
4063 Add(new cMenuSetupCAMItem(CamSlot));
4064 }
4065 SetHelpKeys();
4066}
4067
4069{
4070 if (HasSubMenu())
4071 return;
4073 const char *NewActivationHelp = "";
4074 if (item) {
4075 cCamSlot *CamSlot = item->CamSlot();
4076 if (CamSlot->IsActivating())
4077 NewActivationHelp = tr("Button$Cancel activation");
4078 else if (CamSlot->CanActivate())
4079 NewActivationHelp = tr("Button$Activate");
4080 }
4081 if (NewActivationHelp != activationHelp) {
4082 activationHelp = NewActivationHelp;
4083 SetHelp(tr("Button$Menu"), tr("Button$Reset"), activationHelp);
4084 }
4085}
4086
4088{
4090 if (item) {
4091 if (item->CamSlot()->EnterMenu()) {
4092 Skins.Message(mtStatus, tr("Opening CAM menu..."));
4093 time_t t0 = time(NULL);
4094 time_t t1 = t0;
4095 while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
4096 if (item->CamSlot()->HasUserIO())
4097 break;
4098 if (time(NULL) - t1 >= CAMMENURETRYTIMEOUT) {
4099 dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
4100 item->CamSlot()->EnterMenu();
4101 t1 = time(NULL);
4102 }
4103 cCondWait::SleepMs(100);
4104 }
4105 Skins.Message(mtStatus, NULL);
4106 if (item->CamSlot()->HasUserIO())
4107 return AddSubMenu(new cMenuCam(item->CamSlot()));
4108 }
4109 Skins.Message(mtError, tr("Can't open CAM menu!"));
4110 }
4111 return osContinue;
4112}
4113
4115{
4117 if (item) {
4118 cCamSlot *CamSlot = item->CamSlot();
4119 if (CamSlot->IsActivating())
4120 CamSlot->CancelActivation();
4121 else if (CamSlot->CanActivate()) {
4122 if (CamSlot->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4124 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel())) {
4125 for (int i = 0; i < cDevice::NumDevices(); i++) {
4126 if (cDevice *Device = cDevice::GetDevice(i)) {
4127 if (Device->ProvidesChannel(Channel)) {
4128 if (Device->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4129 if (CamSlot->Assign(Device, true)) { // query
4130 cControl::Shutdown(); // must end transfer mode before assigning CAM, otherwise it might be unassigned again
4131 CamSlot = CamSlot->MtdSpawn();
4132 if (CamSlot->Assign(Device)) {
4133 if (Device->SwitchChannel(Channel, true)) {
4134 CamSlot->StartActivation();
4135 return osContinue;
4136 }
4137 }
4138 }
4139 }
4140 }
4141 }
4142 }
4143 }
4144 }
4145 Skins.Message(mtError, tr("Can't activate CAM!"));
4146 }
4147 }
4148 return osContinue;
4149}
4150
4152{
4154 if (item) {
4155 if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
4156 if (!item->CamSlot()->Reset())
4157 Skins.Message(mtError, tr("Can't reset CAM!"));
4158 }
4159 }
4160 return osContinue;
4161}
4162
4164{
4166
4167 if (!HasSubMenu()) {
4168 switch (Key) {
4169 case kOk:
4170 case kRed: return Menu();
4171 case kGreen: state = Reset(); break;
4172 case kYellow: state = Activate(); break;
4173 default: break;
4174 }
4175 for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
4176 if (ci->Changed())
4177 DisplayItem(ci);
4178 }
4179 SetHelpKeys();
4180 }
4182 state = osEnd;
4183 return state;
4184}
4185
4186// --- cMenuSetupRecord ------------------------------------------------------
4187
4189private:
4192 const char *delTimeshiftRecTexts[3];
4193public:
4194 cMenuSetupRecord(void);
4195 };
4196
4198{
4200 recordKeyHandlingTexts[0] = tr("no instant recording");
4201 recordKeyHandlingTexts[1] = tr("confirm instant recording");
4202 recordKeyHandlingTexts[2] = tr("record instantly");
4203 pauseKeyHandlingTexts[0] = tr("do not pause live video");
4204 pauseKeyHandlingTexts[1] = tr("confirm pause live video");
4205 pauseKeyHandlingTexts[2] = tr("pause live video");
4206 delTimeshiftRecTexts[0] = tr("no");
4207 delTimeshiftRecTexts[1] = tr("confirm");
4208 delTimeshiftRecTexts[2] = tr("yes");
4209 SetSection(tr("Recording"));
4210 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
4211 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
4212 Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
4213 Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
4214 Add(new cMenuEditStraItem(tr("Setup.Recording$Record key handling"), &data.RecordKeyHandling, 3, recordKeyHandlingTexts));
4215 Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
4216 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
4217 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
4218 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
4219 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
4220 Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
4221 Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
4222 Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
4223 Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
4224 Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
4225 Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
4226 Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
4227}
4228
4229// --- cMenuSetupReplay ------------------------------------------------------
4230
4232protected:
4233 virtual void Store(void);
4234public:
4235 cMenuSetupReplay(void);
4236 };
4237
4239{
4241 SetSection(tr("Replay"));
4242 Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
4243 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
4244 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
4245 Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
4246 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
4247 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when jumping to a mark"), &data.PauseOnMarkJump));
4248 Add(new cMenuEditBoolItem(tr("Setup.Replay$Skip edited parts"), &data.SkipEdited));
4249 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay at last mark"), &data.PauseAtLastMark));
4250 Add(new cMenuEditIntItem( tr("Setup.Replay$Initial duration for adaptive skipping (s)"), &data.AdaptiveSkipInitial, 10, 600));
4251 Add(new cMenuEditIntItem( tr("Setup.Replay$Reset timeout for adaptive skipping (s)"), &data.AdaptiveSkipTimeout, 0, 10));
4252 Add(new cMenuEditBoolItem(tr("Setup.Replay$Alternate behavior for adaptive skipping"), &data.AdaptiveSkipAlternate));
4253 Add(new cMenuEditBoolItem(tr("Setup.Replay$Use Prev/Next keys for adaptive skipping"), &data.AdaptiveSkipPrevNext));
4254 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys (s)"), &data.SkipSeconds, 5, 600));
4255 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys in repeat (s)"), &data.SkipSecondsRepeat, 5, 600));
4256 Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
4257}
4258
4260{
4261 if (Setup.ResumeID != data.ResumeID) {
4263 Recordings->ResetResume();
4264 }
4266}
4267
4268// --- cMenuSetupMisc --------------------------------------------------------
4269
4271private:
4275 void Set(void);
4276public:
4277 cMenuSetupMisc(void);
4278 virtual eOSState ProcessKey(eKeys Key);
4279 };
4280
4282{
4284 svdrpPeeringModeTexts[0] = tr("off");
4285 svdrpPeeringModeTexts[1] = tr("any hosts");
4286 svdrpPeeringModeTexts[2] = tr("only default host");
4290 SetSection(tr("Miscellaneous"));
4291 Set();
4292}
4293
4295{
4296 int current = Current();
4297 Clear();
4298 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
4299 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
4300 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
4301 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$SVDRP peering"), &data.SVDRPPeering, 3, svdrpPeeringModeTexts));
4302 if (data.SVDRPPeering) {
4303 Add(new cMenuEditStrItem( tr("Setup.Miscellaneous$SVDRP host name"), data.SVDRPHostName, sizeof(data.SVDRPHostName)));
4305 svdrpServerNames.Sort(true);
4306 svdrpServerNames.Insert(strdup(""));
4307 Add(new cMenuEditStrlItem(tr("Setup.Miscellaneous$SVDRP default host"), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames));
4308 }
4309 }
4310 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
4311 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
4312 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0));
4313 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0));
4314 Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
4315 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
4316 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume steps"), &data.VolumeSteps, 5, 255));
4317 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume linearize"), &data.VolumeLinearize, -20, 20));
4318 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
4319 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource, 3, showChannelNamesWithSourceTexts));
4320 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
4322 Display();
4323}
4324
4326{
4327 bool OldSVDRPPeering = data.SVDRPPeering;
4328 bool ModifiedSVDRPSettings = false;
4329 bool ModifiedShowChannelNamesWithSource = false;
4330 if (Key == kOk) {
4331 ModifiedSVDRPSettings = data.SVDRPPeering != Setup.SVDRPPeering || strcmp(data.SVDRPHostName, Setup.SVDRPHostName);
4332 ModifiedShowChannelNamesWithSource = data.ShowChannelNamesWithSource != Setup.ShowChannelNamesWithSource;
4333 }
4335 if (ModifiedShowChannelNamesWithSource) {
4337 for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel))
4338 Channel->UpdateNameSource();
4339 }
4340 if (data.SVDRPPeering != OldSVDRPPeering)
4341 Set();
4342 if (ModifiedSVDRPSettings) {
4344 {
4346 Timers->SetExplicitModify();
4347 if (Timers->StoreRemoteTimers(NULL, NULL))
4348 Timers->SetModified();
4349 }
4351 }
4352 return state;
4353}
4354
4355// --- cMenuSetupPluginItem --------------------------------------------------
4356
4358private:
4360public:
4361 cMenuSetupPluginItem(const char *Name, int Index);
4362 int PluginIndex(void) { return pluginIndex; }
4363 };
4364
4366:cOsdItem(Name)
4367{
4369}
4370
4371// --- cMenuSetupPlugins -----------------------------------------------------
4372
4374public:
4375 cMenuSetupPlugins(void);
4376 virtual eOSState ProcessKey(eKeys Key);
4377 };
4378
4380{
4382 SetSection(tr("Plugins"));
4383 SetHasHotkeys();
4384 for (int i = 0; ; i++) {
4386 if (p)
4387 Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
4388 else
4389 break;
4390 }
4391}
4392
4394{
4396
4397 if (Key == kOk) {
4398 if (state == osUnknown) {
4400 if (item) {
4402 if (p) {
4403 cMenuSetupPage *menu = p->SetupMenu();
4404 if (menu) {
4405 menu->SetPlugin(p);
4406 return AddSubMenu(menu);
4407 }
4408 Skins.Message(mtInfo, tr("This plugin has no setup parameters!"));
4409 }
4410 }
4411 }
4412 else if (state == osContinue) {
4413 Store();
4414 // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
4416 Display();
4417 }
4418 }
4419 return state;
4420}
4421
4422// --- cMenuSetup ------------------------------------------------------------
4423
4424class cMenuSetup : public cOsdMenu {
4425private:
4426 virtual void Set(void);
4427 eOSState Restart(void);
4428public:
4429 cMenuSetup(void);
4430 virtual eOSState ProcessKey(eKeys Key);
4431 };
4432
4434:cOsdMenu("")
4435{
4437 Set();
4438}
4439
4441{
4442 Clear();
4443 char buffer[64];
4444 snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
4445 SetTitle(buffer);
4446 SetHasHotkeys();
4447 Add(new cOsdItem(hk(tr("OSD")), osUser1));
4448 Add(new cOsdItem(hk(tr("EPG")), osUser2));
4449 Add(new cOsdItem(hk(tr("DVB")), osUser3));
4450 Add(new cOsdItem(hk(tr("LNB")), osUser4));
4451 Add(new cOsdItem(hk(tr("CAM")), osUser5));
4452 Add(new cOsdItem(hk(tr("Recording")), osUser6));
4453 Add(new cOsdItem(hk(tr("Replay")), osUser7));
4454 Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
4456 Add(new cOsdItem(hk(tr("Plugins")), osUser9));
4457 Add(new cOsdItem(hk(tr("Restart")), osUser10));
4458}
4459
4461{
4462 if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
4464 return osEnd;
4465 }
4466 return osContinue;
4467}
4468
4470{
4471 int osdLanguage = I18nCurrentLanguage();
4472 eOSState state = cOsdMenu::ProcessKey(Key);
4473
4474 switch (state) {
4475 case osUser1: return AddSubMenu(new cMenuSetupOSD);
4476 case osUser2: return AddSubMenu(new cMenuSetupEPG);
4477 case osUser3: return AddSubMenu(new cMenuSetupDVB);
4478 case osUser4: return AddSubMenu(new cMenuSetupLNB);
4479 case osUser5: return AddSubMenu(new cMenuSetupCAM);
4480 case osUser6: return AddSubMenu(new cMenuSetupRecord);
4481 case osUser7: return AddSubMenu(new cMenuSetupReplay);
4482 case osUser8: return AddSubMenu(new cMenuSetupMisc);
4483 case osUser9: return AddSubMenu(new cMenuSetupPlugins);
4484 case osUser10: return Restart();
4485 default: ;
4486 }
4487 if (I18nCurrentLanguage() != osdLanguage) {
4488 Set();
4489 if (!HasSubMenu())
4490 Display();
4491 }
4492 return state;
4493}
4494
4495// --- cMenuPluginItem -------------------------------------------------------
4496
4498private:
4500public:
4501 cMenuPluginItem(const char *Name, int Index);
4502 int PluginIndex(void) { return pluginIndex; }
4503 };
4504
4505cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
4506:cOsdItem(Name, osPlugin)
4507{
4509}
4510
4511// --- cMenuMain -------------------------------------------------------------
4512
4513// TRANSLATORS: note the leading and trailing blanks!
4514#define STOP_RECORDING trNOOP(" Stop recording ")
4515
4517
4518cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
4519:cOsdMenu("")
4520{
4522 replaying = false;
4523 stopReplayItem = NULL;
4524 cancelEditingItem = NULL;
4525 stopRecordingItem = NULL;
4527 Set();
4528
4529 // Initial submenus:
4530
4531 switch (State) {
4532 case osSchedule: AddSubMenu(new cMenuSchedule); break;
4533 case osChannels: AddSubMenu(new cMenuChannels); break;
4534 case osTimers: AddSubMenu(new cMenuTimers); break;
4535 case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, OpenSubMenus)); break;
4536 case osSetup: AddSubMenu(new cMenuSetup); break;
4537 case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break;
4538 default: break;
4539 }
4540}
4541
4543{
4545 pluginOsdObject = NULL;
4546 return o;
4547}
4548
4550{
4551 Clear();
4552 SetTitle("VDR");
4553 SetHasHotkeys();
4554
4555 // Basic menu items:
4556
4557 Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
4558 Add(new cOsdItem(hk(tr("Channels")), osChannels));
4559 Add(new cOsdItem(hk(tr("Timers")), osTimers));
4560 Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
4561
4562 // Plugins:
4563
4564 for (int i = 0; ; i++) {
4566 if (p) {
4567 const char *item = p->MainMenuEntry();
4568 if (item)
4569 Add(new cMenuPluginItem(hk(item), i));
4570 }
4571 else
4572 break;
4573 }
4574
4575 // More basic menu items:
4576
4577 Add(new cOsdItem(hk(tr("Setup")), osSetup));
4578 if (Commands.Count())
4579 Add(new cOsdItem(hk(tr("Commands")), osCommands));
4580
4581 Update(true);
4582
4583 Display();
4584}
4585
4586bool cMenuMain::Update(bool Force)
4587{
4588 bool result = false;
4589
4590 bool NewReplaying = false;
4591 {
4592 cMutexLock ControlMutexLock;
4593 NewReplaying = cControl::Control(ControlMutexLock) != NULL;
4594 }
4595 if (Force || NewReplaying != replaying) {
4596 replaying = NewReplaying;
4597 // Replay control:
4598 if (replaying && !stopReplayItem)
4599 // TRANSLATORS: note the leading blank!
4600 Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
4601 else if (stopReplayItem && !replaying) {
4603 stopReplayItem = NULL;
4604 }
4605 // Color buttons:
4606 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"));
4607 result = true;
4608 }
4609
4610 // Editing control:
4611 bool EditingActive = RecordingsHandler.Active();
4612 if (EditingActive && !cancelEditingItem) {
4613 // TRANSLATORS: note the leading blank!
4614 Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
4615 result = true;
4616 }
4617 else if (cancelEditingItem && !EditingActive) {
4619 cancelEditingItem = NULL;
4620 result = true;
4621 }
4622
4623 // Record control:
4625 while (stopRecordingItem) {
4628 stopRecordingItem = it;
4629 }
4630 const char *s = NULL;
4631 while ((s = cRecordControls::GetInstantId(s)) != NULL) {
4632 cOsdItem *item = new cOsdItem(osStopRecord);
4633 item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
4634 Add(item);
4635 if (!stopRecordingItem)
4636 stopRecordingItem = item;
4637 }
4638 result = true;
4639 }
4640
4641 return result;
4642}
4643
4645{
4646 bool HadSubMenu = HasSubMenu();
4647 int osdLanguage = I18nCurrentLanguage();
4648 eOSState state = cOsdMenu::ProcessKey(Key);
4649 HadSubMenu |= HasSubMenu();
4650
4651 switch (state) {
4652 case osSchedule: return AddSubMenu(new cMenuSchedule);
4653 case osChannels: return AddSubMenu(new cMenuChannels);
4654 case osTimers: return AddSubMenu(new cMenuTimers);
4655 case osRecordings: return AddSubMenu(new cMenuRecordings);
4656 case osSetup: return AddSubMenu(new cMenuSetup);
4657 case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands));
4658 case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
4659 if (cOsdItem *item = Get(Current())) {
4660 cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
4661 return osEnd;
4662 }
4663 }
4664 break;
4665 case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
4667 return osEnd;
4668 }
4669 break;
4670 case osPlugin: {
4672 if (item) {
4674 if (p) {
4675 cOsdObject *menu = p->MainMenuAction();
4676 if (menu) {
4677 if (menu->IsMenu())
4678 return AddSubMenu((cOsdMenu *)menu);
4679 else {
4680 pluginOsdObject = menu;
4681 return osPlugin;
4682 }
4683 }
4684 }
4685 }
4686 state = osEnd;
4687 }
4688 break;
4689 default: switch (Key) {
4690 case kRecord:
4691 case kRed: if (!HadSubMenu)
4693 break;
4694 case kGreen: if (!HadSubMenu) {
4695 cRemote::Put(kAudio, true);
4696 state = osEnd;
4697 }
4698 break;
4699 case kYellow: if (!HadSubMenu)
4701 break;
4702 case kBlue: if (!HadSubMenu)
4704 break;
4705 default: break;
4706 }
4707 }
4708 if (!HasSubMenu() && Update(HadSubMenu))
4709 Display();
4710 if (Key != kNone) {
4711 if (I18nCurrentLanguage() != osdLanguage) {
4712 Set();
4713 if (!HasSubMenu())
4714 Display();
4715 }
4716 }
4717 return state;
4718}
4719
4720// --- SetTrackDescriptions --------------------------------------------------
4721
4722void SetTrackDescriptions(int LiveChannel)
4723{
4725 const cComponents *Components = NULL;
4726 if (LiveChannel) {
4728 if (const cChannel *Channel = Channels->GetByNumber(LiveChannel)) {
4730 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
4731 const cEvent *Present = Schedule->GetPresentEvent();
4732 if (Present)
4733 Components = Present->Components();
4734 }
4735 }
4736 }
4737 else if (cReplayControl::NowReplaying()) {
4739 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::NowReplaying()))
4740 Components = Recording->Info()->Components();
4741 }
4742 if (Components) {
4743 int indexAudio = 0;
4744 int indexDolby = 0;
4745 int indexSubtitle = 0;
4746 for (int i = 0; i < Components->NumComponents(); i++) {
4747 const tComponent *p = Components->Component(i);
4748 switch (p->stream) {
4749 case 2: if (p->type == 0x05)
4750 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4751 else
4752 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
4753 break;
4754 case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
4755 break;
4756 case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4757 break;
4758 default: ;
4759 }
4760 }
4761 }
4762}
4763
4764// --- cDisplayChannel -------------------------------------------------------
4765
4767
4768cDisplayChannel::cDisplayChannel(int Number, bool Switched)
4769:cOsdObject(true)
4770{
4771 currentDisplayChannel = this;
4772 group = -1;
4773 withInfo = !Switched || Setup.ShowInfoOnChSwitch;
4775 number = 0;
4776 timeout = Switched || Setup.TimeoutRequChInfo;
4777 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4778 positioner = NULL;
4779 channel = NULL;
4780 {
4782 channel = Channels->GetByNumber(Number);
4783 lastPresent = lastFollowing = NULL;
4784 if (channel) {
4786 DisplayInfo();
4787 }
4788 }
4789 if (channel)
4791 lastTime.Set();
4792}
4793
4795:cOsdObject(true)
4796{
4797 currentDisplayChannel = this;
4798 group = -1;
4799 number = 0;
4800 timeout = true;
4801 lastPresent = lastFollowing = NULL;
4802 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4803 lastTime.Set();
4806 positioner = NULL;
4807 channel = NULL;
4808 {
4810 channel = Channels->GetByNumber(cDevice::CurrentChannel());
4811 }
4812 ProcessKey(FirstKey);
4813}
4814
4821
4829
4831{
4832 if (withInfo && channel) {
4834 if (const cSchedule *Schedule = Schedules->GetSchedule(channel)) {
4835 const cEvent *Present = Schedule->GetPresentEvent();
4836 const cEvent *Following = Schedule->GetFollowingEvent();
4837 if (Present != lastPresent || Following != lastFollowing) {
4839 displayChannel->SetEvents(Present, Following);
4840 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);
4841 lastPresent = Present;
4842 lastFollowing = Following;
4843 lastTime.Set();
4844 }
4845 }
4846 }
4847}
4848
4850{
4852 displayChannel->SetEvents(NULL, NULL);
4853}
4854
4855const cChannel *cDisplayChannel::NextAvailableChannel(const cChannel *Channel, int Direction)
4856{
4857 if (Direction) {
4858 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
4859 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
4861 while (Channel) {
4862 Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel);
4863 if (!Channel && Setup.ChannelsWrap)
4864 Channel = Direction > 0 ? Channels->First() : Channels->Last();
4865 if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
4866 return Channel;
4867 }
4868 }
4869 return NULL;
4870}
4871
4873{
4875 delete displayChannel;
4877 }
4878 const cChannel *NewChannel = NULL;
4879 if (Key != kNone)
4880 lastTime.Set();
4881 switch (int(Key)) {
4882 case k0:
4883 if (number == 0) {
4884 // keep the "Toggle channels" function working
4885 cRemote::Put(Key);
4886 return osEnd;
4887 }
4888 case k1 ... k9:
4889 group = -1;
4890 if (number >= 0) {
4892 number = Key - k0;
4893 else
4894 number = number * 10 + Key - k0;
4896 channel = Channels->GetByNumber(number);
4897 Refresh();
4898 withInfo = false;
4899 // Lets see if there can be any useful further input:
4900 int n = channel ? number * 10 : 0;
4901 int m = 10;
4902 const cChannel *ch = channel;
4903 while (ch && (ch = Channels->Next(ch)) != NULL) {
4904 if (!ch->GroupSep()) {
4905 if (n <= ch->Number() && ch->Number() < n + m) {
4906 n = 0;
4907 break;
4908 }
4909 if (ch->Number() > n) {
4910 n *= 10;
4911 m *= 10;
4912 }
4913 }
4914 }
4915 if (n > 0) {
4916 // This channel is the only one that fits the input, so let's take it right away:
4917 NewChannel = channel;
4918 withInfo = true;
4919 number = 0;
4920 Refresh();
4921 }
4922 }
4923 break;
4924 case kLeft|k_Repeat:
4925 case kLeft:
4926 case kRight|k_Repeat:
4927 case kRight:
4928 case kNext|k_Repeat:
4929 case kNext:
4930 case kPrev|k_Repeat:
4931 case kPrev: {
4932 withInfo = false;
4933 number = 0;
4935 if (group < 0) {
4936 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
4937 group = Channel->Index();
4938 }
4939 if (group >= 0) {
4940 int SaveGroup = group;
4941 if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
4942 group = Channels->GetNextGroup(group) ;
4943 else
4944 group = Channels->GetPrevGroup(group < 1 ? 1 : group);
4945 if (group < 0)
4946 group = SaveGroup;
4947 channel = Channels->Get(group);
4948 if (channel) {
4949 Refresh();
4950 if (!channel->GroupSep())
4951 group = -1;
4952 }
4953 }
4954 break;
4955 }
4956 case kUp|k_Repeat:
4957 case kUp:
4958 case kDown|k_Repeat:
4959 case kDown:
4960 case kChanUp|k_Repeat:
4961 case kChanUp:
4962 case kChanDn|k_Repeat:
4963 case kChanDn: {
4964 eKeys k = NORMALKEY(Key);
4965 if (const cChannel *Channel = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1))
4966 channel = Channel;
4967 else if (channel && channel->Number() != cDevice::CurrentChannel())
4968 Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
4969 }
4970 // no break here
4971 case kUp|k_Release:
4972 case kDown|k_Release:
4973 case kChanUp|k_Release:
4974 case kChanDn|k_Release:
4975 case kNext|k_Release:
4976 case kPrev|k_Release:
4977 if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
4978 NewChannel = channel;
4979 withInfo = true;
4980 group = -1;
4981 number = 0;
4982 Refresh();
4983 break;
4984 case kNone:
4987 channel = Channels->GetByNumber(number);
4988 if (channel)
4989 NewChannel = channel;
4990 withInfo = true;
4991 number = 0;
4992 Refresh();
4993 lastTime.Set();
4994 }
4995 break;
4996 //TODO
4997 //XXX case kGreen: return osEventNow;
4998 //XXX case kYellow: return osEventNext;
4999 case kOk: {
5001 if (group >= 0) {
5002 channel = Channels->Get(Channels->GetNextNormal(group));
5003 if (channel)
5004 NewChannel = channel;
5005 withInfo = true;
5006 group = -1;
5007 Refresh();
5008 }
5009 else if (number > 0) {
5010 channel = Channels->GetByNumber(number);
5011 if (channel)
5012 NewChannel = channel;
5013 withInfo = true;
5014 number = 0;
5015 Refresh();
5016 }
5017 else {
5018 return osEnd;
5019 }
5020 }
5021 break;
5022 default:
5023 if ((Key & (k_Repeat | k_Release)) == 0) {
5024 cRemote::Put(Key);
5025 return osEnd;
5026 }
5027 };
5028 if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
5029 {
5032 // makes sure a channel switch through the SVDRP CHAN command is displayed
5033 channel = Channels->GetByNumber(cDevice::CurrentChannel());
5034 Refresh();
5035 lastTime.Set();
5036 }
5037 DisplayInfo();
5038 if (NewChannel) {
5039 SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
5040 Channels->SwitchTo(NewChannel->Number());
5041 SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
5042 channel = NewChannel;
5043 }
5044 const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
5045 bool PositionerMoving = Positioner && Positioner->IsMoving();
5046 SetNeedsFastResponse(PositionerMoving);
5047 if (!PositionerMoving) {
5048 if (positioner)
5049 lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
5050 Positioner = NULL;
5051 }
5052 if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
5053 displayChannel->SetPositioner(Positioner);
5054 positioner = Positioner;
5055 }
5057 return osContinue;
5058 }
5059 return osEnd;
5060}
5061
5062// --- cDisplayVolume --------------------------------------------------------
5063
5064#define VOLUMETIMEOUT 1000 //ms
5065#define MUTETIMEOUT 5000 //ms
5066
5068
5070:cOsdObject(true)
5071{
5072 currentDisplayVolume = this;
5074 displayVolume = Skins.Current()->DisplayVolume();
5075 Show();
5076}
5077
5083
5088
5095
5101
5103{
5104 switch (int(Key)) {
5105 case kVolUp|k_Repeat:
5106 case kVolUp:
5107 case kVolDn|k_Repeat:
5108 case kVolDn:
5109 Show();
5111 break;
5112 case kMute:
5113 if (cDevice::PrimaryDevice()->IsMute()) {
5114 Show();
5116 }
5117 else
5118 timeout.Set();
5119 break;
5120 case kNone: break;
5121 default: if ((Key & k_Release) == 0) {
5122 cRemote::Put(Key);
5123 return osEnd;
5124 }
5125 }
5126 return timeout.TimedOut() ? osEnd : osContinue;
5127}
5128
5129// --- cDisplayTracks --------------------------------------------------------
5130
5131#define TRACKTIMEOUT 5000 //ms
5132
5134
5136:cOsdObject(true)
5137{
5140 currentDisplayTracks = this;
5141 numTracks = track = 0;
5144 for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
5145 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5146 if (TrackId && TrackId->id) {
5148 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5149 if (i == CurrentAudioTrack)
5150 track = numTracks;
5151 numTracks++;
5152 }
5153 }
5154 descriptions[numTracks] = NULL;
5157 Show();
5158}
5159
5161{
5162 delete displayTracks;
5163 currentDisplayTracks = NULL;
5164 for (int i = 0; i < numTracks; i++)
5165 free(descriptions[i]);
5167}
5168
5178
5180{
5181 if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
5183 new cDisplayTracks;
5184 return currentDisplayTracks;
5185 }
5186 Skins.Message(mtWarning, tr("No audio available!"));
5187 return NULL;
5188}
5189
5195
5197{
5198 int oldTrack = track;
5199 int oldAudioChannel = audioChannel;
5200 switch (int(Key)) {
5201 case kUp|k_Repeat:
5202 case kUp:
5203 case kDown|k_Repeat:
5204 case kDown:
5205 if (NORMALKEY(Key) == kUp && track > 0)
5206 track--;
5207 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5208 track++;
5210 break;
5211 case kLeft|k_Repeat:
5212 case kLeft:
5213 case kRight|k_Repeat:
5214 case kRight: if (IS_AUDIO_TRACK(types[track])) {
5215 static int ac[] = { 1, 0, 2 };
5217 if (NORMALKEY(Key) == kLeft && audioChannel > 0)
5218 audioChannel--;
5219 else if (NORMALKEY(Key) == kRight && audioChannel < 2)
5220 audioChannel++;
5223 }
5224 break;
5225 case kAudio|k_Repeat:
5226 case kAudio:
5227 if (++track >= numTracks)
5228 track = 0;
5230 break;
5231 case kOk:
5232 if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
5233 oldTrack = -1; // make sure we explicitly switch to that track
5234 timeout.Set();
5235 break;
5236 case kNone: break;
5237 default: if ((Key & k_Release) == 0)
5238 return osEnd;
5239 }
5240 if (track != oldTrack || audioChannel != oldAudioChannel)
5241 Show();
5242 if (track != oldTrack) {
5245 }
5246 if (audioChannel != oldAudioChannel)
5248 return timeout.TimedOut() ? osEnd : osContinue;
5249}
5250
5251// --- cDisplaySubtitleTracks ------------------------------------------------
5252
5254
5256:cOsdObject(true)
5257{
5259 currentDisplayTracks = this;
5260 numTracks = track = 0;
5262 descriptions[numTracks] = strdup(tr("No subtitles"));
5263 numTracks++;
5264 eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
5265 for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
5266 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5267 if (TrackId && TrackId->id) {
5269 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5270 if (i == CurrentSubtitleTrack)
5271 track = numTracks;
5272 numTracks++;
5273 }
5274 }
5275 descriptions[numTracks] = NULL;
5277 displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
5278 Show();
5279}
5280
5282{
5283 delete displayTracks;
5284 currentDisplayTracks = NULL;
5285 for (int i = 0; i < numTracks; i++)
5286 free(descriptions[i]);
5288}
5289
5296
5298{
5299 if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
5302 return currentDisplayTracks;
5303 }
5304 Skins.Message(mtWarning, tr("No subtitles available!"));
5305 return NULL;
5306}
5307
5313
5315{
5316 int oldTrack = track;
5317 switch (int(Key)) {
5318 case kUp|k_Repeat:
5319 case kUp:
5320 case kDown|k_Repeat:
5321 case kDown:
5322 if (NORMALKEY(Key) == kUp && track > 0)
5323 track--;
5324 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5325 track++;
5327 break;
5328 case kSubtitles|k_Repeat:
5329 case kSubtitles:
5330 if (++track >= numTracks)
5331 track = 0;
5333 break;
5334 case kOk:
5335 if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
5336 oldTrack = -1; // make sure we explicitly switch to that track
5337 timeout.Set();
5338 break;
5339 case kNone: break;
5340 default: if ((Key & k_Release) == 0)
5341 return osEnd;
5342 }
5343 if (track != oldTrack) {
5344 Show();
5346 }
5347 return timeout.TimedOut() ? osEnd : osContinue;
5348}
5349
5350// --- cRecordControl --------------------------------------------------------
5351
5352cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause)
5353{
5354 const char *LastReplayed = cReplayControl::LastReplayed(); // must do this before locking schedules!
5355 // Whatever happens here, the timers will be modified in some way...
5356 Timers->SetModified();
5357 cStateKey ChannelsStateKey;
5358 // To create a new timer, we need to make shure there is
5359 // a lock on Channels prior to the Schedules locking below
5360 if (!Timer)
5361 cChannels::GetChannelsRead(ChannelsStateKey);
5362 // We're going to work with an event here, so we need to prevent
5363 // others from modifying any EPG data:
5364 cStateKey SchedulesStateKey;
5365 cSchedules::GetSchedulesRead(SchedulesStateKey);
5366
5367 event = NULL;
5368 fileName = NULL;
5369 recorder = NULL;
5370 device = Device;
5371 if (!device) device = cDevice::PrimaryDevice();//XXX
5372 timer = Timer;
5373 if (!timer) {
5374 timer = new cTimer(true, Pause);
5375 Timers->Add(timer);
5376 instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->DeviceNumber() + 1);
5377 ChannelsStateKey.Remove();
5378 }
5379 timer->SetPending(true);
5380 timer->SetRecording(true);
5381 event = timer->Event();
5382
5383 if (event || GetEvent())
5384 dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
5385 cRecording Recording(timer, event);
5386 fileName = strdup(Recording.FileName());
5387
5388 // crude attempt to avoid duplicate recordings:
5390 isyslog("already recording: '%s'", fileName);
5391 if (Timer) {
5392 timer->SetPending(false);
5393 timer->SetRecording(false);
5394 timer->OnOff();
5395 }
5396 else {
5397 Timers->Del(timer);
5398 if (!LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5400 }
5401 timer = NULL;
5402 SchedulesStateKey.Remove();
5403 return;
5404 }
5405
5407 isyslog("record %s", fileName);
5408 if (MakeDirs(fileName, true)) {
5409 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!
5410 const cChannel *ch = timer->Channel();
5411 recorder = new cRecorder(fileName, ch, timer->Priority());
5413 cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
5414 if (!Timer && !LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5416 SchedulesStateKey.Remove();
5419 Recordings->AddByName(fileName);
5420 return;
5421 }
5422 else
5424 }
5425 else
5427 if (!Timer) {
5428 Timers->Del(timer);
5429 timer = NULL;
5430 }
5431 SchedulesStateKey.Remove();
5432}
5433
5435{
5436 Stop();
5437 free(fileName);
5438}
5439
5440#define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
5441
5443{
5444 const cChannel *Channel = timer->Channel();
5446 for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
5447 {
5449 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
5450 event = Schedule->GetEventAround(Time);
5451 if (event) {
5452 if (seconds > 0)
5453 dsyslog("got EPG info after %d seconds", seconds);
5454 return true;
5455 }
5456 }
5457 }
5458 if (seconds == 0)
5459 dsyslog("waiting for EPG info...");
5460 cCondWait::SleepMs(1000);
5461 }
5462 dsyslog("no EPG info available");
5463 return false;
5464}
5465
5466void cRecordControl::Stop(bool ExecuteUserCommand)
5467{
5468 if (timer) {
5469 bool Finished = timer->HasFlags(tfActive) && !timer->Matches();
5470 if (recorder) {
5471 int Errors = recorder->Errors();
5472 isyslog("timer %s %s with %d error%s", *timer->ToDescr(), Finished ? "finished" : "stopped", Errors, Errors != 1 ? "s" : "");
5473 if (timer->HasFlags(tfAvoid) && Errors == 0 && Finished) {
5474 const char *p = strgetlast(timer->File(), FOLDERDELIMCHAR);
5476 }
5477 }
5479 timer->SetRecording(false);
5480 timer = NULL;
5482 cStatus::MsgRecording(device, NULL, fileName, false);
5483 if (ExecuteUserCommand && Finished)
5485 }
5486}
5487
5489{
5490 if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
5491 if (timer)
5492 timer->SetPending(false);
5493 return false;
5494 }
5495 return true;
5496}
5497
5498// --- cRecordControls -------------------------------------------------------
5499
5502
5503bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
5504{
5505 static time_t LastNoDiskSpaceMessage = 0;
5506 int FreeMB = 0;
5507 if (Timer) {
5508 AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
5509 Timer->SetPending(true);
5510 }
5512 if (FreeMB < MINFREEDISK) {
5513 if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
5514 isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
5515 Skins.Message(mtWarning, tr("Not enough disk space to start recording!"));
5516 LastNoDiskSpaceMessage = time(NULL);
5517 }
5518 return false;
5519 }
5520 LastNoDiskSpaceMessage = 0;
5521
5522 ChangeState();
5523 cStateKey StateKey;
5524 const cChannels *Channels = cChannels::GetChannelsRead(StateKey);
5525 int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
5526 if (const cChannel *Channel = Channels->GetByNumber(ch)) {
5527 int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
5528 cDevice *device = cDevice::GetDevice(Channel, Priority, false);
5529 if (device) {
5530 dsyslog("switching device %d to channel %d %s (%s)", device->DeviceNumber() + 1, Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
5531 if (!device->SwitchChannel(Channel, false)) {
5532 StateKey.Remove();
5534 return false;
5535 }
5536 StateKey.Remove();
5537 Channels = NULL;
5538 if (!Timer || Timer->Matches()) {
5539 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5540 if (!RecordControls[i]) {
5541 RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause);
5542 return RecordControls[i]->Process(time(NULL));
5543 }
5544 }
5545 }
5546 }
5547 else if (!Timer || !Timer->Pending()) {
5548 isyslog("no free DVB device to record channel %d (%s)!", ch, Channel->Name());
5549 Skins.Message(mtError, tr("No free DVB device to record!"));
5550 }
5551 }
5552 else
5553 esyslog("ERROR: channel %d not defined!", ch);
5554 if (Channels)
5555 StateKey.Remove();
5556 return false;
5557}
5558
5560{
5562 return Start(Timers, NULL, Pause);
5563}
5564
5565void cRecordControls::Stop(const char *InstantId)
5566{
5568 ChangeState();
5569 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5570 if (RecordControls[i]) {
5571 const char *id = RecordControls[i]->InstantId();
5572 if (id && strcmp(id, InstantId) == 0) {
5573 cTimer *Timer = RecordControls[i]->Timer();
5574 RecordControls[i]->Stop();
5575 if (Timer) {
5576 Timers->Del(Timer);
5577 isyslog("deleted timer %s", *Timer->ToDescr());
5578 }
5579 break;
5580 }
5581 }
5582 }
5583}
5584
5586{
5587 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5588 if (RecordControls[i]) {
5589 if (RecordControls[i]->Timer() == Timer) {
5591 ChangeState();
5592 break;
5593 }
5594 }
5595 }
5596}
5597
5599{
5600 Skins.Message(mtStatus, tr("Pausing live video..."));
5601 cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
5602 if (Start(true)) {
5603 cReplayControl *rc = new cReplayControl(true);
5604 cControl::Launch(rc);
5606 Skins.Message(mtStatus, NULL);
5607 return true;
5608 }
5609 Skins.Message(mtStatus, NULL);
5610 return false;
5611}
5612
5613const char *cRecordControls::GetInstantId(const char *LastInstantId)
5614{
5615 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5616 if (RecordControls[i]) {
5617 if (!LastInstantId && RecordControls[i]->InstantId())
5618 return RecordControls[i]->InstantId();
5619 if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
5620 LastInstantId = NULL;
5621 }
5622 }
5623 return NULL;
5624}
5625
5627{
5628 if (FileName) {
5629 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5630 if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
5631 return RecordControls[i];
5632 }
5633 }
5634 return NULL;
5635}
5636
5638{
5639 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5640 if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
5641 return RecordControls[i];
5642 }
5643 return NULL;
5644}
5645
5646bool cRecordControls::Process(cTimers *Timers, time_t t)
5647{
5648 bool Result = false;
5649 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5650 if (RecordControls[i]) {
5651 if (!RecordControls[i]->Process(t)) {
5653 ChangeState();
5654 Result = true;
5655 }
5656 }
5657 }
5658 return Result;
5659}
5660
5662{
5663 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5664 if (RecordControls[i]) {
5665 if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
5666 if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
5667 isyslog("stopping recording due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
5668 RecordControls[i]->Stop();
5669 // This will restart the recording, maybe even from a different
5670 // device in case conditional access has changed.
5671 ChangeState();
5672 }
5673 }
5674 }
5675 }
5676}
5677
5679{
5680 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5681 if (RecordControls[i])
5682 return true;
5683 }
5684 return false;
5685}
5686
5688{
5689 for (int i = 0; i < MAXRECORDCONTROLS; i++)
5691 ChangeState();
5692}
5693
5695{
5696 int NewState = state;
5697 bool Result = State != NewState;
5698 State = state;
5699 return Result;
5700}
5701
5702// --- cAdaptiveSkipper ------------------------------------------------------
5703
5705{
5706 initialValue = NULL;
5707 currentValue = 0;
5708 framesPerSecond = 0;
5709 lastKey = kNone;
5710}
5711
5712void cAdaptiveSkipper::Initialize(int *InitialValue, double FramesPerSecond)
5713{
5714 initialValue = InitialValue;
5715 framesPerSecond = FramesPerSecond;
5716 currentValue = 0;
5717}
5718
5720{
5721 if (!initialValue)
5722 return 0;
5723 if (timeout.TimedOut()) {
5724 currentValue = int(round(*initialValue * framesPerSecond));
5725 lastKey = Key;
5726 }
5727 else if (Key != lastKey) {
5728 currentValue /= 2;
5730 lastKey = Key; // only halve the value when the direction is changed
5731 else
5732 lastKey = kNone; // once the direction has changed, every further call halves the value
5733 }
5735 return max(currentValue, 1);
5736}
5737
5738// --- cReplayControl --------------------------------------------------------
5739
5742
5744:cDvbPlayerControl(fileName, PauseLive)
5745{
5747 currentReplayControl = this;
5748 displayReplay = NULL;
5749 marksModified = false;
5750 visible = modeOnly = shown = displayFrames = false;
5751 lastErrors = 0;
5752 lastCurrent = lastTotal = -1;
5753 lastPlay = lastForward = false;
5754 lastSpeed = -2; // an invalid value
5755 timeoutShow = 0;
5756 timeSearchActive = false;
5757 cRecording Recording(fileName);
5758 cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
5759 marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
5760 SetMarks(&marks);
5762 SetTrackDescriptions(false);
5765}
5766
5774
5776{
5777 Hide();
5778 cStatus::MsgReplaying(this, NULL, fileName, false);
5779 if (Setup.DelTimeshiftRec && *fileName) {
5781 if (rc && rc->InstantId()) {
5782 if (Active()) {
5783 if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
5784 {
5786 Timers->SetExplicitModify();
5787 cTimer *Timer = rc->Timer();
5788 rc->Stop(false); // don't execute user command
5789 if (Timer) {
5790 Timers->Del(Timer);
5791 Timers->SetModified();
5792 isyslog("deleted timer %s", *Timer->ToDescr());
5793 }
5794 }
5796 bool Error = false;
5797 {
5799 Recordings->SetExplicitModify();
5800 if (cRecording *Recording = Recordings->GetByName(fileName)) {
5801 if (Recording->Delete()) {
5802 Recordings->DelByName(fileName);
5804 Recordings->SetModified();
5805 }
5806 else
5807 Error = true;
5808 }
5809 }
5810 if (Error)
5811 Skins.Message(mtError, tr("Error while deleting recording!"));
5812 return;
5813 }
5814 }
5815 }
5816 }
5818 cMenuRecordings::SetRecording(NULL); // make sure opening the Recordings menu navigates to the last replayed recording
5819}
5820
5822{
5823 cStateKey StateKey;
5824 marks.Lock(StateKey);
5825 while (cMark *m = marks.First())
5826 marks.Del(m);
5827 StateKey.Remove();
5829}
5830
5831void cReplayControl::SetRecording(const char *FileName)
5832{
5833 fileName = FileName;
5834}
5835
5837{
5838 return currentReplayControl ? *fileName : NULL;
5839}
5840
5842{
5844 if (!Recordings->GetByName(fileName))
5845 fileName = NULL;
5846 return fileName;
5847}
5848
5849void cReplayControl::ClearLastReplayed(const char *FileName)
5850{
5851 if (*fileName && FileName && strcmp(fileName, FileName) == 0)
5852 fileName = NULL;
5853}
5854
5856{
5857 if (modeOnly)
5858 Hide();
5859 if (!visible) {
5860 shown = ShowProgress(true);
5861 timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
5862 }
5863 else if (timeoutShow && Seconds > 0)
5864 timeoutShow = time(NULL) + Seconds;
5865}
5866
5868{
5869 ShowTimed();
5870}
5871
5873{
5874 if (visible) {
5875 delete displayReplay;
5876 displayReplay = NULL;
5877 SetNeedsFastResponse(false);
5878 visible = false;
5879 modeOnly = false;
5880 lastPlay = lastForward = false;
5881 lastSpeed = -2; // an invalid value
5882 timeSearchActive = false;
5883 timeoutShow = 0;
5884 }
5885 if (marksModified) {
5886 marks.Save();
5887 marksModified = false;
5888 }
5889}
5890
5892{
5894 bool Play, Forward;
5895 int Speed;
5896 if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
5897 bool NormalPlay = (Play && Speed == -1);
5898
5899 if (!visible) {
5900 if (NormalPlay)
5901 return; // no need to do indicate ">" unless there was a different mode displayed before
5902 visible = modeOnly = true;
5904 }
5905
5906 if (modeOnly && !timeoutShow && NormalPlay)
5907 timeoutShow = time(NULL) + MODETIMEOUT;
5909 lastPlay = Play;
5911 lastSpeed = Speed;
5912 }
5913 }
5914}
5915
5917{
5918 int Current, Total;
5919 if (!(Initial || updateTimer.TimedOut()))
5920 return visible;
5921 if (GetFrameNumber(Current, Total) && Total > 0) {
5922 if (!visible) {
5927 visible = true;
5928 }
5929 if (Initial) {
5930 if (*fileName) {
5932 if (const cRecording *Recording = Recordings->GetByName(fileName))
5933 displayReplay->SetRecording(Recording);
5934 }
5935 lastCurrent = lastTotal = -1;
5936 }
5937 const cErrors *Errors = GetErrors();
5938 int NumErrors = Errors ? Errors->Size() : 0;
5939 if (Current != lastCurrent || Total != lastTotal || NumErrors != lastErrors) {
5940 if (Setup.ShowRemainingTime || Total != lastTotal) {
5941 int Index = Total;
5943 Index = Current - Index;
5945 }
5946 displayReplay->SetProgress(Current, Total);
5948 displayReplay->SetErrors(Errors);
5950 lastCurrent = Current;
5951 lastTotal = Total;
5952 lastErrors = NumErrors;
5953 }
5954 ShowMode();
5956 return true;
5957 }
5958 return false;
5959}
5960
5962{
5963 char buf[64];
5964 // TRANSLATORS: note the trailing blank!
5965 strcpy(buf, tr("Jump: "));
5966 int len = strlen(buf);
5967 char h10 = '0' + (timeSearchTime >> 24);
5968 char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
5969 char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
5970 char m1 = '0' + (timeSearchTime & 0x000000FF);
5971 char ch10 = timeSearchPos > 3 ? h10 : '-';
5972 char ch1 = timeSearchPos > 2 ? h1 : '-';
5973 char cm10 = timeSearchPos > 1 ? m10 : '-';
5974 char cm1 = timeSearchPos > 0 ? m1 : '-';
5975 sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
5976 displayReplay->SetJump(buf);
5977}
5978
5980{
5981#define STAY_SECONDS_OFF_END 10
5982 int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
5983 int Current = int(round(lastCurrent / FramesPerSecond()));
5984 int Total = int(round(lastTotal / FramesPerSecond()));
5985 switch (Key) {
5986 case k0 ... k9:
5987 if (timeSearchPos < 4) {
5988 timeSearchTime <<= 8;
5989 timeSearchTime |= Key - k0;
5990 timeSearchPos++;
5992 }
5993 break;
5994 case kFastRew:
5995 case kLeft:
5996 case kFastFwd:
5997 case kRight: {
5998 int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
5999 if (dir > 0)
6000 Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
6001 SkipSeconds(Seconds * dir);
6002 timeSearchActive = false;
6003 }
6004 break;
6005 case kPlayPause:
6006 case kPlay:
6007 case kUp:
6008 case kPause:
6009 case kDown:
6010 case kOk:
6011 if (timeSearchPos > 0) {
6012 Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
6013 bool Still = Key == kDown || Key == kPause || Key == kOk;
6014 Goto(SecondsToFrames(Seconds, FramesPerSecond()), Still);
6015 }
6016 timeSearchActive = false;
6017 break;
6018 default:
6019 if (!(Key & k_Flags)) // ignore repeat/release keys
6020 timeSearchActive = false;
6021 break;
6022 }
6023
6024 if (!timeSearchActive) {
6025 if (timeSearchHide)
6026 Hide();
6027 else
6028 displayReplay->SetJump(NULL);
6029 ShowMode();
6030 }
6031}
6032
6034{
6036 timeSearchHide = false;
6037 if (modeOnly)
6038 Hide();
6039 if (!visible) {
6040 Show();
6041 if (visible)
6042 timeSearchHide = true;
6043 else
6044 return;
6045 }
6046 timeoutShow = 0;
6048 timeSearchActive = true;
6049}
6050
6052{
6053 int Current, Total;
6054 if (GetIndex(Current, Total, true)) {
6055 lastCurrent = -1; // triggers redisplay
6056 cStateKey StateKey;
6057 marks.Lock(StateKey);
6058 if (cMark *m = marks.Get(Current))
6059 marks.Del(m);
6060 else {
6061 marks.Add(Current);
6062 bool Play, Forward;
6063 int Speed;
6064 if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
6065 Goto(Current, true);
6066 displayFrames = true;
6067 }
6068 }
6069 StateKey.Remove();
6070 ShowTimed(2);
6071 marksModified = true;
6073 }
6074}
6075
6077{
6078 int Current, Total;
6079 if (GetIndex(Current, Total)) {
6080 if (marks.Count()) {
6081 if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
6082 if (!Setup.PauseOnMarkJump) {
6083 bool Playing, Fwd;
6084 int Speed;
6085 if (GetReplayMode(Playing, Fwd, Speed) && Playing && Forward && m->Position() < Total - SecondsToFrames(3, FramesPerSecond())) {
6086 Goto(m->Position());
6087 return;
6088 }
6089 }
6090 Goto(m->Position(), true);
6091 displayFrames = true;
6092 return;
6093 }
6094 }
6095 // There are either no marks at all, or we already were at the first or last one,
6096 // so jump to the very beginning or end:
6097 Goto(Forward ? Total : 0, true);
6098 }
6099}
6100
6101void cReplayControl::MarkMove(int Frames, bool MarkRequired)
6102{
6103 int Current, Total;
6104 if (GetIndex(Current, Total)) {
6105 bool Play, Forward;
6106 int Speed;
6107 GetReplayMode(Play, Forward, Speed);
6108 cMark *m = marks.Get(Current);
6109 if (!Play && m) {
6110 displayFrames = true;
6111 cMark *m2;
6112 if (Frames > 0) {
6113 // Handle marks at the same offset:
6114 while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
6115 m = m2;
6116 // Don't skip the next mark:
6117 if ((m2 = marks.Next(m)) != NULL)
6118 Frames = min(Frames, m2->Position() - m->Position() - 1);
6119 }
6120 else {
6121 // Handle marks at the same offset:
6122 while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
6123 m = m2;
6124 // Don't skip the next mark:
6125 if ((m2 = marks.Prev(m)) != NULL)
6126 Frames = -min(-Frames, m->Position() - m2->Position() - 1);
6127 }
6128 int p = SkipFrames(Frames);
6129 m->SetPosition(p);
6130 Goto(m->Position(), true);
6131 marksModified = true;
6133 }
6134 else if (!MarkRequired)
6135 Goto(SkipFrames(Frames), !Play);
6136 }
6137}
6138
6140{
6141 const cErrors *Errors = GetErrors();
6142 int NumErrors = Errors ? Errors->Size() : 0;
6143 if (NumErrors > 0) {
6144 int Current, Total;
6145 if (GetIndex(Current, Total)) {
6146 if (Forward) {
6147 int Offset = 0;
6148 for (int i = 0; i < NumErrors; i++) {
6149 int Position = Errors->At(i);
6150 if (Position > Current + Offset) {
6151 int NextIFrame = SkipFrames(Position - Current) + Offset; // this takes us to the I-frame at or right after Position
6152 if (NextIFrame > Position) {
6153 if (SkipFrames(Offset + 1) == NextIFrame) { // means Current is the I-frame right before Position
6154 Offset = NextIFrame - Current;
6155 continue;
6156 }
6157 }
6158 Goto(Position, true); // this takes us to the I-frame at or right before Position
6159 return;
6160 }
6161 }
6162 if (Current < Total)
6163 Goto(Total, true);
6164 }
6165 else {
6166 for (int i = NumErrors - 1; i >= 0; i--) {
6167 if (Errors->At(i) < Current) {
6168 int Position = Errors->At(i);
6169 Goto(Position, true); // this takes us to the I-frame at or right before Position
6170 return;
6171 }
6172 }
6173 if (Current > 0)
6174 Goto(0, true);
6175 }
6176 }
6177 }
6178}
6179
6181{
6182 if (*fileName) {
6183 Hide();
6185 if (!marks.Count())
6186 Skins.Message(mtError, tr("No editing marks defined!"));
6187 else if (!marks.GetNumSequences())
6188 Skins.Message(mtError, tr("No editing sequences defined!"));
6189 else if (access(cCutter::EditedFileName(fileName), F_OK) == 0 && !Interface->Confirm(tr("Edited version already exists - overwrite?")))
6190 ;
6192 Skins.Message(mtError, tr("Not enough free disk space to start editing process!"));
6193 else if (!RecordingsHandler.Add(ruCut, fileName))
6194 Skins.Message(mtError, tr("Can't start editing process!"));
6195 else
6196 Skins.Message(mtInfo, tr("Editing process started"));
6197 }
6198 else
6199 Skins.Message(mtError, tr("Editing process already active!"));
6200 ShowMode();
6201 }
6202}
6203
6205{
6206 int Current, Total;
6207 if (GetIndex(Current, Total)) {
6208 cMark *m = marks.Get(Current);
6209 if (!m)
6210 m = marks.GetNext(Current);
6211 if (m) {
6212 if ((m->Index() & 0x01) != 0 && !Setup.SkipEdited) // when skipping edited parts we also need to jump to end marks
6213 m = marks.Next(m);
6214 if (m)
6216 }
6217 }
6218}
6219
6221{
6223 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::LastReplayed()))
6224 return new cMenuRecording(Recording, false);
6225 return NULL;
6226}
6227
6229{
6231 if (const cRecording *Recording = Recordings->GetByName(LastReplayed()))
6232 return Recording;
6233 return NULL;
6234}
6235
6237{
6238 if (!Active())
6239 return osEnd;
6240 if (Key == kNone && !marksModified)
6241 marks.Update();
6242 if (visible) {
6243 if (timeoutShow && time(NULL) > timeoutShow) {
6244 Hide();
6245 ShowMode();
6246 timeoutShow = 0;
6247 }
6248 else if (modeOnly)
6249 ShowMode();
6250 else
6252 }
6253 bool DisplayedFrames = displayFrames;
6254 displayFrames = false;
6255 if (timeSearchActive && Key != kNone) {
6256 TimeSearchProcess(Key);
6257 return osContinue;
6258 }
6259 if (Key == kPlayPause) {
6260 bool Play, Forward;
6261 int Speed;
6262 GetReplayMode(Play, Forward, Speed);
6263 if (Speed >= 0)
6264 Key = Play ? kPlay : kPause;
6265 else
6266 Key = Play ? kPause : kPlay;
6267 }
6268 bool DoShowMode = true;
6269 switch (int(Key)) {
6270 // Positioning:
6271 case kPlay:
6272 case kUp: Play(); break;
6273 case kPause:
6274 case kDown: Pause(); break;
6275 case kFastRew|k_Release:
6276 case kLeft|k_Release:
6277 if (Setup.MultiSpeedMode) break;
6278 case kFastRew:
6279 case kLeft: Backward(); break;
6280 case kFastFwd|k_Release:
6281 case kRight|k_Release:
6282 if (Setup.MultiSpeedMode) break;
6283 case kFastFwd:
6284 case kRight: Forward(); break;
6285 case kRed: TimeSearch(); break;
6286 case kGreen|k_Repeat:
6288 case kGreen: SkipSeconds(-Setup.SkipSeconds); break;
6289 case kYellow|k_Repeat:
6291 case kYellow: SkipSeconds(Setup.SkipSeconds); break;
6292 case kStop:
6293 case kBlue: Stop();
6294 return osEnd;
6295 default: {
6296 DoShowMode = false;
6297 switch (int(Key)) {
6298 // Editing:
6299 case kMarkToggle: MarkToggle(); break;
6300 case kPrev|k_Repeat:
6301 case kPrev: if (Setup.AdaptiveSkipPrevNext) {
6302 MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6303 break;
6304 }
6305 // fall through...
6307 case kMarkJumpBack: MarkJump(false); break;
6308 case kNext|k_Repeat:
6309 case kNext: if (Setup.AdaptiveSkipPrevNext) {
6310 MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6311 break;
6312 }
6313 // fall through...
6315 case kMarkJumpForward: MarkJump(true); break;
6317 case kMarkMoveBack: MarkMove(-1, true); break;
6319 case kMarkMoveForward: MarkMove(+1, true); break;
6321 case kMarkSkipBack: MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6323 case kMarkSkipForward: MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6324 case kChanUp|k_Repeat:
6325 case kChanUp: ErrorJump(true); break;
6326 case kChanDn|k_Repeat:
6327 case kChanDn: ErrorJump(false); break;
6328 case kEditCut: EditCut(); break;
6329 case kEditTest: EditTest(); break;
6330 default: {
6331 displayFrames = DisplayedFrames;
6332 switch (Key) {
6333 // Menu control:
6334 case kOk: if (visible && !modeOnly) {
6335 Hide();
6336 DoShowMode = true;
6337 }
6338 else
6339 Show();
6340 break;
6341 case kBack: Stop();
6342 return osRecordings;
6343 default: return osUnknown;
6344 }
6345 }
6346 }
6347 }
6348 }
6349 if (DoShowMode)
6350 ShowMode();
6351 return osContinue;
6352}
cString ChannelString(const cChannel *Channel, int Number)
Definition channels.c:1140
#define CA_ENCRYPTED_MIN
Definition channels.h:44
#define CA_FTA
Definition channels.h:39
#define LOCK_CHANNELS_READ
Definition channels.h:270
#define LOCK_CHANNELS_WRITE
Definition channels.h:271
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:284
cTimeMs timeout
Definition menu.h:286
cAdaptiveSkipper(void)
Definition menu.c:5704
eKeys lastKey
Definition menu.h:285
void Initialize(int *InitialValue, double FramesPerSecond)
Definition menu.c:5712
int * initialValue
Definition menu.h:282
int currentValue
Definition menu.h:283
int GetValue(eKeys Key)
Definition menu.c:5719
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:104
const int * Dpids(void) const
Definition channels.h:158
int tpid
Definition channels.h:117
int source
Definition channels.h:101
char * shortName
Definition channels.h:95
int vpid
Definition channels.h:103
int frequency
Definition channels.h:99
int rid
Definition channels.h:122
static cString ToText(const cChannel *Channel)
Definition channels.c:554
int caids[MAXCAIDS+1]
Definition channels.h:118
int nid
Definition channels.h:119
int Vpid(void) const
Definition channels.h:154
int Number(void) const
Definition channels.h:179
const char * Name(void) const
Definition channels.c:121
char * name
Definition channels.h:94
int sid
Definition channels.h:121
bool GroupSep(void) const
Definition channels.h:181
int dpids[MAXDPIDS+1]
Definition channels.h:109
const int * Caids(void) const
Definition channels.h:172
const char * ShortName(bool OrName=false) const
Definition channels.c:130
int tid
Definition channels.h:120
int spids[MAXSPIDS+1]
Definition channels.h:112
int apids[MAXAPIDS+1]
Definition channels.h:106
const int * Apids(void) const
Definition channels.h:157
char * portalName
Definition channels.h:97
const char * Provider(void) const
Definition channels.h:147
char * provider
Definition channels.h:96
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition channels.c:861
bool HasUniqueChannelID(const cChannel *NewChannel, const cChannel *OldChannel=NULL) const
Definition channels.c:1053
static int MaxNumber(void)
Definition channels.h:249
int GetPrevNormal(int Idx) const
Get previous normal channel (not group)
Definition channels.c:930
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition channels.c:856
void ReNumber(void)
Recalculate 'number' based on channel type.
Definition channels.c:938
const cChannel * GetByNumber(int Number, int SkipGap=0) const
Definition channels.c:983
void SetModifiedByUser(void)
Definition channels.c:1093
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition channels.c:1011
bool SwitchTo(int Number) const
Definition channels.c:1063
void Del(cChannel *Channel)
Delete the given Channel from the list.
Definition channels.c:975
int GetNextNormal(int Idx) const
Get next normal channel (not group)
Definition channels.c:922
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
static cControl * Control(cMutexLock &MutexLock, bool Hidden=false)
Returns the current replay control (if any) in case it is currently visible.
Definition player.c:81
double FramesPerSecond(void) const
Definition player.h:113
static void Shutdown(void)
Definition player.c:108
static void Attach(void)
Definition player.c:95
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:693
void SetKeepTracks(bool KeepTracks)
Controls whether the current audio and subtitle track settings shall be kept as they currently are,...
Definition device.h:611
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition device.c:1186
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:780
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:222
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
eTrackType GetCurrentSubtitleTrack(void) const
Definition device.h:597
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:230
eTrackType GetCurrentAudioTrack(void) const
Definition device.h:593
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:825
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:167
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition device.c:1815
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition device.h:371
void StopReplay(void)
Stops the current replay session (if any).
Definition device.c:1421
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1064
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1214
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:1143
static void SetCurrentChannel(int ChannelNumber)
Sets the number of the current channel on the primary device, without actually switching to it.
Definition device.h:373
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1070
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:506
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:529
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1091
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1247
static int CurrentVolume(void)
Definition device.h:646
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:1114
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition device.c:1168
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:4822
virtual ~cDisplayChannel()
Definition menu.c:4815
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:4849
const cPositioner * positioner
Definition menu.h:131
static cDisplayChannel * currentDisplayChannel
Definition menu.h:135
void DisplayInfo(void)
Definition menu.c:4830
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4872
cDisplayChannel(int Number, bool Switched)
Definition menu.c:4768
const cChannel * NextAvailableChannel(const cChannel *Channel, int Direction)
Definition menu.c:4855
cSkinDisplayTracks * displayTracks
Definition menu.h:182
cDisplaySubtitleTracks(void)
Definition menu.c:5255
static void Process(eKeys Key)
Definition menu.c:5308
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:185
eTrackType types[ttMaxTrackTypes]
Definition menu.h:184
virtual void Show(void)
Definition menu.c:5290
static cDisplaySubtitleTracks * currentDisplayTracks
Definition menu.h:187
virtual ~cDisplaySubtitleTracks()
Definition menu.c:5281
static cDisplaySubtitleTracks * Create(void)
Definition menu.c:5297
eOSState ProcessKey(eKeys Key)
Definition menu.c:5314
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:167
static cDisplayTracks * Create(void)
Definition menu.c:5179
cDisplayTracks(void)
Definition menu.c:5135
cTimeMs timeout
Definition menu.h:165
virtual void Show(void)
Definition menu.c:5169
virtual ~cDisplayTracks()
Definition menu.c:5160
eOSState ProcessKey(eKeys Key)
Definition menu.c:5196
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:5190
eTrackType types[ttMaxTrackTypes]
Definition menu.h:166
static cDisplayVolume * Create(void)
Definition menu.c:5089
cSkinDisplayVolume * displayVolume
Definition menu.h:150
virtual ~cDisplayVolume()
Definition menu.c:5078
eOSState ProcessKey(eKeys Key)
Definition menu.c:5102
cTimeMs timeout
Definition menu.h:151
static void Process(eKeys Key)
Definition menu.c:5096
virtual void Show(void)
Definition menu.c:5084
cDisplayVolume(void)
Definition menu.c:5069
static cDisplayVolume * currentDisplayVolume
Definition menu.h:152
void Append(const char *Title)
Definition recording.c:3337
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition dvbdevice.c:2042
void SetMarks(const cMarks *Marks)
Definition dvbplayer.c:1003
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition dvbplayer.c:1065
const cErrors * GetErrors(void)
Definition dvbplayer.c:1058
void SkipSeconds(int Seconds)
Definition dvbplayer.c:1045
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition dvbplayer.c:1083
void Pause(void)
Definition dvbplayer.c:1021
int SkipFrames(int Frames)
Definition dvbplayer.c:1051
void Goto(int Index, bool Still=false)
Definition dvbplayer.c:1088
void Stop(void)
Definition dvbplayer.c:1014
void Forward(void)
Definition dvbplayer.c:1033
bool Active(void)
Definition dvbplayer.c:1009
bool GetFrameNumber(int &Current, int &Total)
Definition dvbplayer.c:1074
void Play(void)
Definition dvbplayer.c:1027
void Backward(void)
Definition dvbplayer.c:1039
static void SetupChanged(void)
void ForceScan(void)
Definition eitscan.c:129
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:277
time_t StartTime(void) const
Definition epg.h:111
tChannelID ChannelID(void) const
Definition epg.c:154
cString GetTimeString(void) const
Definition epg.c:436
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:2256
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2200
virtual void Move(int From, int To)
Definition tools.c:2216
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:2265
void SetModified(void)
Unconditionally marks this list as modified.
Definition tools.c:2270
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:599
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:2159
int Count(void) const
Definition tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2168
void Sort(void)
Definition tools.c:2292
cListObject * Prev(void) const
Definition tools.h:546
int Index(void) const
Definition tools.c:2088
cListObject * Next(void) const
Definition tools.h:547
Definition tools.h:631
const T * Prev(const T *Object) const
Definition tools.h:647
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:643
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:650
const T * Last(void) const
Returns the last element in this list, or NULL if the list is empty.
Definition tools.h:645
const cOsdItem * Get(int Index) const
Definition tools.h:640
void SetPosition(int Position)
Definition recording.h:389
int Position(void) const
Definition recording.h:387
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
Definition recording.c:2442
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:2375
const cMark * GetNext(int Position) const
Definition recording.c:2399
bool Update(void)
Definition recording.c:2311
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition recording.c:2299
const cMark * Get(int Position) const
Definition recording.c:2381
static bool DeleteMarksFile(const cRecording *Recording)
Definition recording.c:2288
bool Save(void)
Definition recording.c:2342
const cMark * GetPrev(int Position) const
Definition recording.c:2390
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:996
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:4549
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:4586
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4644
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition menu.c:4518
static cOsdObject * pluginOsdObject
Definition menu.h:113
static cOsdObject * PluginOsdObject(void)
Definition menu.c:4542
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:4505
int PluginIndex(void)
Definition menu.c:4502
int pluginIndex
Definition menu.c:4499
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:2867
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:2821
void SetHelpKeys(void)
Definition menu.c:2728
eOSState Delete(void)
Definition menu.c:2839
const char * buttonDelete
Definition menu.c:2662
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2913
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:3037
int Level(void) const
Definition menu.c:3046
const cRecording * Recording(void) const
Definition menu.c:3047
const char * Name(void) const
Definition menu.c:3045
void IncrementCounter(bool New)
Definition menu.c:3074
bool IsDirectory(void) const
Definition menu.c:3048
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition menu.c:3082
void SetRecording(const cRecording *Recording)
Definition menu.c:3049
cMenuRecordingItem(const cRecording *Recording, int Level)
Definition menu.c:3053
virtual void Display(void)
Definition menu.c:2979
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:2991
const cRecording * recording
Definition menu.c:2940
bool withButtons
Definition menu.c:2943
bool RefreshRecording(void)
Definition menu.c:2964
cString originalFileName
Definition menu.c:2941
cStateKey recordingsStateKey
Definition menu.c:2942
cMenuRecording(const cRecording *Recording, bool WithButtons=false)
Definition menu.c:2951
static cString path
Definition menu.h:217
void Set(bool Refresh=false)
Definition menu.c:3144
bool Open(bool OpenSubMenus=false)
Definition menu.c:3219
eOSState Sort(void)
Definition menu.c:3393
static void SetRecording(const char *FileName)
Definition menu.c:3203
eOSState Info(void)
Definition menu.c:3365
eOSState Play(void)
Definition menu.c:3235
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:3249
cStateKey recordingsStateKey
Definition menu.h:214
cMenuRecordings(const char *Base=NULL, int Level=0, bool OpenSubMenus=false, const cRecordingFilter *Filter=NULL)
Definition menu.c:3093
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3405
eOSState Commands(eKeys Key=kNone)
Definition menu.c:3378
cString DirectoryName(void)
Definition menu.c:3208
void SetHelpKeys(void)
Definition menu.c:3123
eOSState Delete(void)
Definition menu.c:3315
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:3481
cSetup data
Definition menu.c:3475
virtual void Store(void)
Definition menu.c:3486
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition menu.c:3997
bool Changed(void)
Definition menu.c:4004
cCamSlot * camSlot
Definition menu.c:3990
cCamSlot * CamSlot(void)
Definition menu.c:3993
void SetHelpKeys(void)
Definition menu.c:4068
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4163
cMenuSetupCAM(void)
Definition menu.c:4053
eOSState Menu(void)
Definition menu.c:4087
eOSState Reset(void)
Definition menu.c:4151
eOSState Activate(void)
Definition menu.c:4114
const char * activationHelp
Definition menu.c:4043
int currentChannel
Definition menu.c:4042
const char * updateChannelsTexts[6]
Definition menu.c:3769
int numAudioLanguages
Definition menu.c:3764
cMenuSetupDVB(void)
Definition menu.c:3776
int originalNumSubtitleLanguages
Definition menu.c:3765
void Setup(void)
Definition menu.c:3803
int numSubtitleLanguages
Definition menu.c:3766
const char * standardComplianceTexts[3]
Definition menu.c:3770
int originalNumAudioLanguages
Definition menu.c:3763
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3833
const char * videoDisplayFormatTexts[3]
Definition menu.c:3768
int originalNumLanguages
Definition menu.c:3669
int numLanguages
Definition menu.c:3670
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3712
void Setup(void)
Definition menu.c:3688
cMenuSetupEPG(void)
Definition menu.c:3677
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3967
cSatCableNumbers satCableNumbers
Definition menu.c:3912
cMenuSetupLNB(void)
Definition menu.c:3919
void Setup(void)
Definition menu.c:3928
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4325
void Set(void)
Definition menu.c:4294
cMenuSetupMisc(void)
Definition menu.c:4281
const char * svdrpPeeringModeTexts[3]
Definition menu.c:4272
cStringList svdrpServerNames
Definition menu.c:4274
const char * showChannelNamesWithSourceTexts[3]
Definition menu.c:4273
virtual void Set(void)
Definition menu.c:3544
virtual ~cMenuSetupOSD()
Definition menu.c:3539
cStringList fontSmlNames
Definition menu.c:3509
cStringList fontOsdNames
Definition menu.c:3509
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:3600
const char * recSortDirTexts[2]
Definition menu.c:3499
const char * useSmallFontTexts[3]
Definition menu.c:3497
int numSkins
Definition menu.c:3502
cStringList fontFixNames
Definition menu.c:3509
const char * recSortModeTexts[2]
Definition menu.c:3498
int fontOsdIndex
Definition menu.c:3510
const char * keyColorTexts[4]
Definition menu.c:3500
int skinIndex
Definition menu.c:3504
int originalSkinIndex
Definition menu.c:3503
int originalThemeIndex
Definition menu.c:3507
int fontFixIndex
Definition menu.c:3510
const char ** skinDescriptions
Definition menu.c:3505
cThemes themes
Definition menu.c:3506
int themeIndex
Definition menu.c:3508
int fontSmlIndex
Definition menu.c:3510
cMenuSetupOSD(void)
Definition menu.c:3518
int osdLanguageIndex
Definition menu.c:3501
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1242
void SetSection(const char *Section)
Definition menuitems.c:1237
void SetPlugin(cPlugin *Plugin)
Definition menuitems.c:1257
cMenuSetupPluginItem(const char *Name, int Index)
Definition menu.c:4365
int PluginIndex(void)
Definition menu.c:4362
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4393
cMenuSetupPlugins(void)
Definition menu.c:4379
const char * pauseKeyHandlingTexts[3]
Definition menu.c:4191
const char * recordKeyHandlingTexts[3]
Definition menu.c:4190
cMenuSetupRecord(void)
Definition menu.c:4197
const char * delTimeshiftRecTexts[3]
Definition menu.c:4192
virtual void Store(void)
Definition menu.c:4259
cMenuSetupReplay(void)
Definition menu.c:4238
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:4469
virtual void Set(void)
Definition menu.c:4440
cMenuSetup(void)
Definition menu.c:4433
eOSState Restart(void)
Definition menu.c:4460
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:203
const char * Text(void) const
Definition config.h:202
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:525
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:492
cOsdMenu * SubMenu(void)
Definition osdbase.h:127
void DisplayItem(cOsdItem *Item)
Definition osdbase.c:315
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition osdbase.c:517
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:536
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:2337
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:2310
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.h:837
int Close(void)
Definition thread.c:1001
bool Open(const char *Command, const char *Mode)
Definition thread.c:947
static bool HasPlugins(void)
Definition plugin.c:464
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:5434
const char * InstantId(void)
Definition menu.h:252
void Stop(bool ExecuteUserCommand=true)
Definition menu.c:5466
cDevice * device
Definition menu.h:239
cTimer * timer
Definition menu.h:240
bool GetEvent(void)
Definition menu.c:5442
char * fileName
Definition menu.h:244
cTimer * Timer(void)
Definition menu.h:254
cRecorder * recorder
Definition menu.h:241
cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer=NULL, bool Pause=false)
Definition menu.c:5352
cDevice * Device(void)
Definition menu.h:250
const cEvent * event
Definition menu.h:242
bool Process(time_t t)
Definition menu.c:5488
cString instantId
Definition menu.h:243
static bool StateChanged(int &State)
Definition menu.c:5694
static const char * GetInstantId(const char *LastInstantId)
Definition menu.c:5613
static void ChannelDataModified(const cChannel *Channel)
Definition menu.c:5661
static bool Process(cTimers *Timers, time_t t)
Definition menu.c:5646
static bool PauseLiveVideo(void)
Definition menu.c:5598
static void Shutdown(void)
Definition menu.c:5687
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition menu.c:5503
static cRecordControl * RecordControls[]
Definition menu.h:5500
static bool Active(void)
Definition menu.c:5678
static void Stop(const char *InstantId)
Definition menu.c:5565
static cRecordControl * GetRecordControl(const char *FileName)
Definition menu.c:5626
static int state
Definition menu.h:260
static void ChangeState(void)
Definition menu.h:276
int Errors(void)
Definition recorder.h:52
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:91
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition recording.c:2495
bool ChangePriorityLifetime(int NewPriority, int NewLifetime)
Changes the priority and lifetime of this recording to the given values.
Definition recording.c:1303
bool HasMarks(void) const
Returns true if this recording has any editing marks.
Definition recording.c:1257
bool WriteInfo(const char *OtherFileName=NULL)
Writes in info file of this recording.
Definition recording.c:1275
int IsInUse(void) const
Checks whether this recording is currently in use and therefore shall not be tampered with.
Definition recording.c:1418
bool ChangeName(const char *NewName)
Changes the name of this recording to the given value.
Definition recording.c:1328
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:1355
cString Folder(void) const
Returns the name of the folder this recording is stored in (without the video directory).
Definition recording.c:1129
const char * Name(void) const
Returns the full name of the recording (without the video directory).
Definition recording.h:162
int Lifetime(void) const
Definition recording.h:149
const char * FileName(void) const
Returns the full path name to the recording directory, including the video directory and the actual '...
Definition recording.c:1141
cRecordingInfo * Info(void) const
Definition recording.h:169
cString BaseName(void) const
Returns the base name of this recording (without the video directory and folder).
Definition recording.c:1136
int Priority(void) const
Definition recording.h:148
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition recording.c:1159
double FramesPerSecond(void) const
Definition recording.h:173
bool IsPesRecording(void) const
Definition recording.h:194
void DelAll(void)
Deletes/terminates all operations.
Definition recording.c:2196
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:2158
int GetUsage(const char *FileName)
Returns the usage type for the given FileName.
Definition recording.c:2203
void Del(const char *FileName)
Deletes the given FileName from the list of operations.
Definition recording.c:2189
static const cRecordings * GetRecordingsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for read access.
Definition recording.h:260
static cRecordings * GetRecordingsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for write access.
Definition recording.h:263
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:1631
void DelByName(const char *FileName)
Definition recording.c:1694
const cRecording * GetByName(const char *FileName) const
Definition recording.c:1668
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:5831
static const char * LastReplayed(void)
Definition menu.c:5841
void MarkToggle(void)
Definition menu.c:6051
static cString fileName
Definition menu.h:313
void TimeSearchDisplay(void)
Definition menu.c:5961
static void ClearLastReplayed(const char *FileName)
Definition menu.c:5849
int lastTotal
Definition menu.h:301
void MarkMove(int Frames, bool MarkRequired)
Definition menu.c:6101
static cReplayControl * currentReplayControl
Definition menu.h:312
virtual eOSState ProcessKey(eKeys Key)
Definition menu.c:6236
bool timeSearchHide
Definition menu.h:306
void TimeSearchProcess(eKeys Key)
Definition menu.c:5979
void MarkJump(bool Forward)
Definition menu.c:6076
cMarks marks
Definition menu.h:297
void EditCut(void)
Definition menu.c:6180
int timeSearchTime
Definition menu.h:307
cSkinDisplayReplay * displayReplay
Definition menu.h:295
void Stop(void)
Definition menu.c:5775
void ShowTimed(int Seconds=0)
Definition menu.c:5855
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:6228
virtual void ClearEditingMarks(void)
Clears any editing marks this player might be showing.
Definition menu.c:5821
bool lastForward
Definition menu.h:302
bool displayFrames
Definition menu.h:299
bool shown
Definition menu.h:299
time_t timeoutShow
Definition menu.h:304
void EditTest(void)
Definition menu.c:6204
bool timeSearchActive
Definition menu.h:306
virtual void Hide(void)
Definition menu.c:5872
bool ShowProgress(bool Initial)
Definition menu.c:5916
bool marksModified
Definition menu.h:298
int lastSpeed
Definition menu.h:303
cAdaptiveSkipper adaptiveSkipper
Definition menu.h:296
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:6220
int lastErrors
Definition menu.h:300
void ShowMode(void)
Definition menu.c:5891
virtual ~cReplayControl()
Definition menu.c:5767
virtual void Show(void)
Definition menu.c:5867
void ErrorJump(bool Forward)
Definition menu.c:6139
cTimeMs updateTimer
Definition menu.h:305
void TimeSearch(void)
Definition menu.c:6033
bool visible
Definition menu.h:299
bool modeOnly
Definition menu.h:299
static const char * NowReplaying(void)
Definition menu.c:5836
cReplayControl(bool PauseLive=false)
Definition menu.c:5743
int lastCurrent
Definition menu.h:301
int Read(void)
Definition recording.c:260
void Delete(void)
Definition recording.c:343
bool FromString(const char *s)
Definition config.c:81
int * Array(void)
Definition config.h:100
cString ToString(void)
Definition config.c:107
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition epg.c:1393
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition epg.c:1288
static void ResetVersions(void)
Definition epg.c:1319
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:269
int EPGBugfixLevel
Definition config.h:299
int ColorKey2
Definition config.h:322
int VideoDisplayFormat
Definition config.h:323
int SubtitleFgTransparency
Definition config.h:294
int MinUserInactivity
Definition config.h:347
int AntiAlias
Definition config.h:334
int ShowInfoOnChSwitch
Definition config.h:267
int SkipSecondsRepeat
Definition config.h:362
int StandardCompliance
Definition config.h:288
char SVDRPDefaultHost[HOST_NAME_MAX]
Definition config.h:304
bool Save(void)
Definition config.c:738
int TimeoutRequChInfo
Definition config.h:268
int ResumeID
Definition config.h:363
char OSDTheme[MaxThemeName]
Definition config.h:265
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:292
int SVDRPTimeout
Definition config.h:301
int LnbSLOF
Definition config.h:275
int EPGLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:295
char OSDSkin[MaxSkinName]
Definition config.h:264
int UsePositioner
Definition config.h:279
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:263
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:282
int MarginStart
Definition config.h:289
double FontOsdSizeP
Definition config.h:338
int PauseAtLastMark
Definition config.h:356
int AdaptiveSkipPrevNext
Definition config.h:360
int LnbFrequLo
Definition config.h:276
int EPGPauseAfterScan
Definition config.h:297
int UseSmallFont
Definition config.h:333
int SubtitleOffset
Definition config.h:293
int MarginStop
Definition config.h:289
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:294
int ColorKey0
Definition config.h:322
int FoldersInTimerMenu
Definition config.h:317
int MenuScrollWrap
Definition config.h:270
int EPGLinger
Definition config.h:300
int ShowReplayMode
Definition config.h:350
int SiteLon
Definition config.h:281
int AdaptiveSkipAlternate
Definition config.h:359
int UseVps
Definition config.h:314
int DisplaySubtitles
Definition config.h:291
int ChannelInfoTime
Definition config.h:328
int SiteLat
Definition config.h:280
int VolumeLinearize
Definition config.h:367
int ChannelsWrap
Definition config.h:370
int EPGScanMaxChannel
Definition config.h:296
double FontFixSizeP
Definition config.h:340
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:290
int OSDMessageTime
Definition config.h:332
int MarkInstantRecord
Definition config.h:272
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:271
int DiSEqC
Definition config.h:278
char NameInstantRecord[NAME_MAX+1]
Definition config.h:273
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:277
char FontSml[MAXFONTNAME]
Definition config.h:336
int MultiSpeedMode
Definition config.h:349
int EPGScanTimeout
Definition config.h:298
int TimeTransponder
Definition config.h:287
int VideoFormat
Definition config.h:324
int MaxVideoFileSize
Definition config.h:344
cString DeviceBondings
Definition config.h:375
int PositionerSwing
Definition config.h:283
double OSDTopP
Definition config.h:329
int PauseOnMarkSet
Definition config.h:353
int DelTimeshiftRec
Definition config.h:346
int SetSystemTime
Definition config.h:285
int PrimaryDVB
Definition config.h:266
int ChannelEntryTimeout
Definition config.h:306
char FontFix[MAXFONTNAME]
Definition config.h:337
int TimeSource
Definition config.h:286
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:274
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:263
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:254
virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable)
Sets the item at the given Index to Timer.
Definition skins.h:247
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 SetErrors(const cErrors *Errors)
Sets the errors found in the recording to Errors, which shall be used to display the progress bar thr...
Definition skins.c:230
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:225
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition skins.c:220
virtual void SetCurrent(const char *Current)=0
Sets the current position within the recording, as a user readable string in 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 in 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:398
cTheme * Theme(void)
Definition skins.h:418
const char * Name(void)
Definition skins.h:417
virtual cSkinDisplayReplay * DisplayReplay(bool ModeOnly)=0
Creates and returns a new object for displaying replay progress.
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:265
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:284
cSkin * Current(void)
Returns a pointer to the current skin.
Definition skins.h:464
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:330
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:52
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:116
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:843
int Find(const char *s) const
Definition tools.c:1623
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:1182
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1188
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:815
void Set(int Ms=0)
Sets the timer.
Definition tools.c:805
bool TimedOut(void) const
Definition tools.c:810
int Stop(void) const
Definition timers.h:73
void OnOff(void)
Definition timers.c:1083
const char * File(void) const
Definition timers.h:77
cString PrintFirstDay(void) const
Definition timers.c:432
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:45
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
Definition timers.h:46
bool IsSingleEvent(void) const
Definition timers.c:509
void SetPending(bool Pending)
Definition timers.c:996
time_t StopTime(void) const
the stop time as given by the user
Definition timers.c:773
time_t FirstDay(void) const
Definition timers.h:78
bool Recording(void) const
Definition timers.h:65
int priority
Definition timers.h:49
char file[NAME_MAX *2+1]
Definition timers.h:52
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:293
void SetFlags(uint Flags)
Definition timers.c:1056
int Start(void) const
Definition timers.h:72
int start
the start and stop time of this timer as given by the user,
Definition timers.h:47
void SetDeferred(int Seconds)
Definition timers.c:1050
bool IsPatternTimer(void) const
Definition timers.h:97
const char * Pattern(void) const
Definition timers.h:76
int WeekDays(void) const
Definition timers.h:71
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition timers.c:398
void TriggerRespawn(void)
Definition timers.c:904
time_t Day(void) const
Definition timers.h:70
void SetRemote(const char *Remote)
Definition timers.c:1044
char * remote
Definition timers.h:54
bool SetEvent(const cEvent *Event)
Definition timers.c:967
const cChannel * channel
Definition timers.h:44
int stop
in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm
Definition timers.h:48
bool Local(void) const
Definition timers.h:81
const cEvent * Event(void) const
Definition timers.h:86
void Skip(void)
Definition timers.c:1076
time_t StartTime(void) const
the start time as given by the user
Definition timers.c:766
const cChannel * Channel(void) const
Definition timers.h:69
bool Pending(void) const
Definition timers.h:66
cString ToDescr(void) const
Definition timers.c:329
bool SetEventFromSchedule(const cSchedules *Schedules)
Definition timers.c:918
int Priority(void) const
Definition timers.h:74
void SetRecording(bool Recording)
Definition timers.c:987
char pattern[NAME_MAX *2+1]
Definition timers.h:51
static int GetMDay(time_t t)
Definition timers.c:514
bool HasFlags(uint Flags) const
Definition timers.c:1071
const char * Remote(void) const
Definition timers.h:80
int lifetime
Definition timers.h:50
int Id(void) const
Definition timers.h:64
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
Definition timers.c:569
uint flags
Definition timers.h:43
cString ToText(bool UseChannelID=false) const
Definition timers.c:319
void Add(cTimer *Timer, cTimer *After=NULL)
Definition timers.c:1239
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition timers.c:1234
void Del(cTimer *Timer, bool DeleteObject=true)
Definition timers.c:1253
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition timers.c:1229
const cTimer * GetMatch(time_t t) const
Definition timers.c:1156
int Size(void) const
Definition tools.h:754
void Sort(__compar_fn_t Compare)
Definition tools.h:811
virtual void Insert(T Data, int Before=0)
Definition tools.h:755
virtual void Append(T Data)
Definition tools.h:774
T & At(int Index) const
Definition tools.h:731
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:52
#define TIMERMACRO_AFTER
Definition config.h:53
#define MAXLIFETIME
Definition config.h:46
#define MAXPRIORITY
Definition config.h:41
#define VDRVERSION
Definition config.h:25
#define TIMERMACRO_BEFORE
Definition config.h:51
#define TIMERMACRO_EPISODE
Definition config.h:50
#define TIMERMACRO_TITLE
Definition config.h:49
#define LIVEPRIORITY
Definition config.h:43
#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:104
#define LOCK_SCHEDULES_READ
Definition epg.h:232
#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:5065
void SetTrackDescriptions(int LiveChannel)
Definition menu.c:4722
#define MODETIMEOUT
Definition menu.c:37
#define TRACKTIMEOUT
Definition menu.c:5131
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:5440
#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:5064
#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:3263
static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer=NULL)
Definition menu.c:1136
#define MAXWAIT4EPGINFO
Definition menu.c:36
#define STOP_RECORDING
Definition menu.c:4514
void SetTrackDescriptions(int LiveChannel)
Definition menu.c:4722
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:3488
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition recording.c:3383
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:152
void GetRecordingsSortMode(const char *Directory)
Definition recording.c:3440
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition recording.c:3410
eRecordingsSortMode RecordingsSortMode
Definition recording.c:3433
bool EnoughFreeDiskSpaceForEdit(const char *FileName)
Definition recording.c:3520
char * ExchangeChars(char *s, bool ToFileSystem)
Definition recording.c:675
void IncRecordingsSortMode(const char *Directory)
Definition recording.c:3459
cDoneRecordings DoneRecordingsPattern
Definition recording.c:3290
cRecordingsHandler RecordingsHandler
Definition recording.c:2106
void SetRecordingTimerId(const char *Directory, const char *TimerId)
Definition recording.c:3470
@ ruCut
Definition recording.h:34
@ ruCopy
Definition recording.h:36
@ ruDst
Definition recording.h:39
@ ruNone
Definition recording.h:30
@ ruMove
Definition recording.h:35
@ ruPending
Definition recording.h:41
#define RUC_BEFORERECORDING
Definition recording.h:452
@ rsmName
Definition recording.h:585
#define RUC_AFTERRECORDING
Definition recording.h:454
#define LOCK_RECORDINGS_READ
Definition recording.h:327
#define MAXVIDEOFILESIZETS
Definition recording.h:479
#define FOLDERDELIMCHAR
Definition recording.h:22
#define LOCK_RECORDINGS_WRITE
Definition recording.h:328
#define MINVIDEOFILESIZE
Definition recording.h:481
cShutdownHandler ShutdownHandler
Definition shutdown.c:27
static const cCursesFont Font
Definition skincurses.c:31
cSkins Skins
Definition skins.c:253
@ 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:114
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:2888
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:2897
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:2906
void StartSVDRPHandler(void)
Definition svdrp.c:2872
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:1443
#define LOCK_TIMERS_READ
Definition timers.h:246
#define LOCK_TIMERS_WRITE
Definition timers.h:247
@ 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:218
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:912
bool isempty(const char *s)
Definition tools.c:354
char * strreplace(char *s, char c1, char c2)
Definition tools.c:139
cString strescape(const char *s, const char *chars)
Definition tools.c:277
int strcountchr(const char *s, char c)
returns the number of occurrences of 'c' in 's'.
Definition tools.c:196
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition tools.c:504
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition tools.c:1211
char * stripspace(char *s)
Definition tools.c:224
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:887
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:131
cString itoa(int n)
Definition tools.c:447
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:183
cString AddDirectory(const char *DirName, const char *FileName)
Definition tools.c:407
#define SECSINDAY
Definition tools.h:42
#define dsyslog(a...)
Definition tools.h:37
int CompareInts(const void *a, const void *b)
Definition tools.h:817
#define MALLOC(type, size)
Definition tools.h:47
char * skipspace(const char *s)
Definition tools.h:244
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