vdr 2.8.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.68 2026/09/07 18:48:24 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) override;
61public:
62 cMenuEditCaItem(const char *Name, int *Value);
63 virtual eOSState ProcessKey(eKeys Key) override;
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) override;
104public:
105 cMenuEditSrcItem(const char *Name, int *Value);
106 virtual eOSState ProcessKey(eKeys Key) override;
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) override;
174 };
175
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.QueueMessage(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 override;
299 virtual void Set(void) override;
300 const cChannel *Channel(void) { return channel; }
301 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override;
302 };
303
305
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{
346 if (!DisplayMenu->SetItemChannel(channel, Index, Current, Selectable, sortMode == csmProvider))
347 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
348}
349
350// --- cMenuChannels ---------------------------------------------------------
351
352#define CHANNELNUMBERTIMEOUT 1000 //ms
353
354class cMenuChannels : public cOsdMenu {
355private:
359 void Set(bool Force = false);
360 cChannel *GetChannel(int Index);
361 void Propagate(cChannels *Channels);
362protected:
363 eOSState Number(eKeys Key);
364 eOSState Switch(void);
365 eOSState Edit(void);
366 eOSState New(void);
367 eOSState Delete(void);
368 virtual void Move(int From, int To) override;
369public:
370 cMenuChannels(void);
372 virtual eOSState ProcessKey(eKeys Key) override;
373 };
374
376:cOsdMenu(tr("Channels"), CHNUMWIDTH, 3)
377{
379 number = 0;
380 Set();
381}
382
386
387void cMenuChannels::Set(bool Force)
388{
389 if (Force)
392 const cChannel *CurrentChannel = GetChannel(Current());
393 if (!CurrentChannel)
394 CurrentChannel = Channels->GetByNumber(cDevice::CurrentChannel());
395 cMenuChannelItem *CurrentItem = NULL;
396 Clear();
397 for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
398 if (!Channel->GroupSep() || cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber && *Channel->Name()) {
399 cMenuChannelItem *Item = new cMenuChannelItem(Channel);
400 Add(Item);
401 if (Channel == CurrentChannel)
402 CurrentItem = Item;
403 }
404 }
407 msmNumber);
409 Sort();
410 SetCurrent(CurrentItem);
411 SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), tr("Button$Mark"));
412 Display();
414 }
415}
416
418{
420 return p ? (cChannel *)p->Channel() : NULL;
421}
422
424{
425 Channels->ReNumber();
426 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
427 ci->Set();
428 Display();
429 Channels->SetModifiedByUser();
430}
431
433{
434 if (HasSubMenu())
435 return osContinue;
436 if (numberTimer.TimedOut())
437 number = 0;
438 if (!number && Key == k0) {
440 Set(true);
441 }
442 else {
444 number = number * 10 + Key - k0;
445 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
446 if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {
447 DisplayCurrent(false);
448 SetCurrent(ci);
449 DisplayCurrent(true);
450 break;
451 }
452 }
454 }
455 return osContinue;
456}
457
459{
460 if (HasSubMenu())
461 return osContinue;
463 cChannel *ch = GetChannel(Current());
464 if (ch)
466 return osEnd;
467}
468
470{
471 if (HasSubMenu() || Count() == 0)
472 return osContinue;
474 cChannel *ch = GetChannel(Current());
475 if (ch)
477 return osContinue;
478}
479
487
489{
490 if (!HasSubMenu() && Count() > 0) {
491 LOCK_TIMERS_READ; // must lock timers before channels!
493 int Index = Current();
494 cChannel *Channel = GetChannel(Current());
495 if (!Channels->Contains(Channel)) {
497 channelsStateKey.Reset(); // makes sure the menu is refreshed
498 return osContinue;
499 }
500 bool Deleted = false;
501 int CurrentChannelNr = cDevice::CurrentChannel();
502 cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr);
503 int DeletedChannel = Channel->Number();
504 // Check if there is a timer using this channel:
505 if (Timers->UsesChannel(Channel)) {
507 Skins.QueueMessage(mtError, tr("Channel is being used by a timer!"));
508 return osContinue;
509 }
510 if (Interface->Confirm(tr("Delete channel?"))) {
511 if (CurrentChannel && Channel == CurrentChannel) {
512 int n = Channels->GetNextNormal(CurrentChannel->Index());
513 if (n < 0)
514 n = Channels->GetPrevNormal(CurrentChannel->Index());
515 CurrentChannel = Channels->Get(n);
516 CurrentChannelNr = 0; // triggers channel switch below
517 }
518 Channels->Del(Channel);
519 cOsdMenu::Del(Index);
520 Propagate(Channels);
521 isyslog("channel %d deleted", DeletedChannel);
522 Deleted = true;
523 if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
524 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
525 Channels->SwitchTo(CurrentChannel->Number());
526 else
527 cDevice::SetCurrentChannel(CurrentChannel->Number());
528 }
529 }
530 channelsStateKey.Remove(Deleted);
531 }
532 return osContinue;
533}
534
535void cMenuChannels::Move(int From, int To)
536{
538 int CurrentChannelNr = cDevice::CurrentChannel();
539 cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr);
540 cChannel *FromChannel = GetChannel(From);
541 cChannel *ToChannel = GetChannel(To);
542 if (FromChannel && ToChannel) {
543 int FromNumber = FromChannel->Number();
544 int ToNumber = ToChannel->Number();
545 if (Channels->MoveNeedsDecrement(FromChannel, ToChannel)) {
546 ToChannel = Channels->Prev(ToChannel); // cListBase::Move() doesn't know about the channel list's numbered groups!
547 To--;
548 }
549 Channels->Move(FromChannel, ToChannel);
550 cOsdMenu::Move(From, To);
551 SetCurrent(Get(To));
552 Propagate(Channels);
553 isyslog("channel %d moved to %d", FromNumber, ToNumber);
554 if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
555 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
556 Channels->SwitchTo(CurrentChannel->Number());
557 else
558 cDevice::SetCurrentChannel(CurrentChannel->Number());
559 }
560 }
562 }
563}
564
566{
567 if (!HasSubMenu())
568 Set(); // react on any changes to the channels list
569 eOSState state = cOsdMenu::ProcessKey(Key);
570
571 switch (state) {
572 case osUser1: {
573 if (cMenuEditChannel *MenuEditChannel = dynamic_cast<cMenuEditChannel *>(SubMenu())) {
574 if (cChannel *Channel = MenuEditChannel->Channel()) {
576 Add(new cMenuChannelItem(Channel), true);
577 return CloseSubMenu();
578 }
579 }
580 }
581 break;
582 default:
583 if (state == osUnknown) {
584 switch (int(Key)) {
585 case k0 ... k9:
586 return Number(Key);
587 case kOk: return Switch();
588 case kRed: return Edit();
589 case kGreen: return New();
590 case kYellow: return Delete();
591 case kBlue: if (!HasSubMenu())
592 Mark();
593 break;
594 case kChanUp|k_Repeat:
595 case kChanUp:
596 case kChanDn|k_Repeat:
597 case kChanDn: {
599 int CurrentChannelNr = cDevice::CurrentChannel();
600 for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
601 if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == CurrentChannelNr) {
602 SetCurrent(ci);
603 Display();
604 break;
605 }
606 }
607 }
608 default: break;
609 }
610 }
611 }
612 return state;
613}
614
615// --- cMenuText -------------------------------------------------------------
616
617cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font)
619{
621 text = NULL;
622 font = Font;
623 SetText(Text);
624}
625
627{
628 free(text);
629}
630
631void cMenuText::SetText(const char *Text)
632{
633 free(text);
634 text = Text ? strdup(Text) : NULL;
635}
636
638{
640 DisplayMenu()->SetText(text, font == fontFix); //XXX define control character in text to choose the font???
641 if (text)
643}
644
646{
647 switch (int(Key)) {
648 case kUp|k_Repeat:
649 case kUp:
650 case kDown|k_Repeat:
651 case kDown:
652 case kLeft|k_Repeat:
653 case kLeft:
654 case kRight|k_Repeat:
655 case kRight:
656 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
657 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
658 return osContinue;
659 default: break;
660 }
661
662 eOSState state = cOsdMenu::ProcessKey(Key);
663
664 if (state == osUnknown) {
665 switch (Key) {
666 case kOk: return osBack;
667 default: state = osContinue;
668 }
669 }
670 return state;
671}
672
673// --- cMenuFolderItem -------------------------------------------------------
674
675class cMenuFolderItem : public cOsdItem {
676private:
678public:
679 virtual void Set(void) override;
681 cNestedItem *Folder(void) { return folder; }
682 };
683
690
692{
693 if (folder->SubItems() && folder->SubItems()->Count())
694 SetText(cString::sprintf("%s...", folder->Text()));
695 else
696 SetText(folder->Text());
697}
698
699// --- cMenuEditFolder -------------------------------------------------------
700
701class cMenuEditFolder : public cOsdMenu {
702private:
705 char name[PATH_MAX];
706 eOSState Confirm(void);
707public:
708 cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder = NULL);
709 cString GetFolder(void);
710 virtual eOSState ProcessKey(eKeys Key) override;
711 };
712
714:cOsdMenu(Folder ? tr("Edit folder") : tr("New folder"), 12)
715{
717 list = List;
718 folder = Folder;
719 if (folder)
720 strn0cpy(name, folder->Text(), sizeof(name));
721 else {
722 *name = 0;
723 cRemote::Put(kRight, true); // go right into string editing mode
724 }
725 if (!isempty(Dir)) {
726 cOsdItem *DirItem = new cOsdItem(Dir);
727 DirItem->SetSelectable(false);
728 Add(DirItem);
729 }
730 Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
731}
732
734{
735 return folder ? folder->Text() : "";
736}
737
739{
740 if (!folder || strcmp(folder->Text(), name) != 0) {
741 // each name may occur only once in a folder list
742 for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
743 if (strcmp(Folder->Text(), name) == 0) {
744 Skins.QueueMessage(mtError, tr("Folder name already exists!"));
745 return osContinue;
746 }
747 }
748 char *p = strpbrk(name, "\\{}#~"); // FOLDERDELIMCHAR
749 if (p) {
750 Skins.QueueMessage(mtError, cString::sprintf(tr("Folder name must not contain '%c'!"), *p));
751 return osContinue;
752 }
753 }
754 if (folder)
756 else
757 list->Add(folder = new cNestedItem(name));
758 return osEnd;
759}
760
762{
763 eOSState state = cOsdMenu::ProcessKey(Key);
764
765 if (state == osUnknown) {
766 switch (Key) {
767 case kOk: return Confirm();
768 case kRed:
769 case kGreen:
770 case kYellow:
771 case kBlue: return osContinue;
772 default: break;
773 }
774 }
775 return state;
776}
777
778// --- cMenuFolder -----------------------------------------------------------
779
780cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
782{
784 list = nestedItemList = NestedItemList;
785 firstFolder = NULL;
786 editing = false;
787 helpKeys = -1;
788 Set();
789 DescendPath(Path);
790 Display();
791 SetHelpKeys();
792}
793
794cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
796{
798 list = List;
799 nestedItemList = NestedItemList;
800 dir = Dir;
801 firstFolder = NULL;
802 editing = false;
803 helpKeys = -1;
804 Set();
805 DescendPath(Path);
806 Display();
807 SetHelpKeys();
808}
809
811{
812 if (HasSubMenu())
813 return;
814 int NewHelpKeys = 0;
815 if (firstFolder)
816 NewHelpKeys = 1;
817 if (NewHelpKeys != helpKeys) {
818 helpKeys = NewHelpKeys;
819 SetHelp(NewHelpKeys > 0 ? tr("Button$Open") : NULL, tr("Button$New"), firstFolder ? tr("Button$Delete") : NULL, firstFolder ? tr("Button$Edit") : NULL);
820 }
821}
822
823#define FOLDERDELIMCHARSUBST 0x01
824static void AddRecordingFolders(const cRecordings *Recordings, cList<cNestedItem> *List, char *Path)
825{
826 if (Path) {
827 char *p = strchr(Path, FOLDERDELIMCHARSUBST);
828 if (p)
829 *p++ = 0;
830 cNestedItem *Folder;
831 for (Folder = List->First(); Folder; Folder = List->Next(Folder)) {
832 if (strcmp(Path, Folder->Text()) == 0)
833 break;
834 }
835 if (!Folder)
836 List->Add(Folder = new cNestedItem(Path));
837 if (p) {
838 Folder->SetSubItems(true);
839 AddRecordingFolders(Recordings, Folder->SubItems(), p);
840 }
841 }
842 else {
843 cStringList Dirs;
844 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
845 cString Folder = Recording->Folder();
846 strreplace((char *)*Folder, FOLDERDELIMCHAR, FOLDERDELIMCHARSUBST); // makes sure parent folders come before subfolders
847 if (Dirs.Find(Folder) < 0)
848 Dirs.Append(strdup(Folder));
849 }
850 Dirs.Sort();
851 for (int i = 0; i < Dirs.Size(); i++) {
852 if (char *s = Dirs[i])
853 AddRecordingFolders(Recordings, &Folders, s);
854 }
855 }
856}
857
858void cMenuFolder::Set(const char *CurrentFolder)
859{
860 static cStateKey RecordingsStateKey;
861 if (list == &Folders) {
862 if (const cRecordings *Recordings = cRecordings::GetRecordingsRead(RecordingsStateKey)) {
863 AddRecordingFolders(Recordings, &Folders, NULL);
864 RecordingsStateKey.Remove();
865 }
866 }
867 firstFolder = NULL;
868 Clear();
869 if (!isempty(dir)) {
870 cOsdItem *DirItem = new cOsdItem(dir);
871 DirItem->SetSelectable(false);
872 Add(DirItem);
873 }
874 list->Sort();
875 for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
876 cOsdItem *FolderItem = new cMenuFolderItem(Folder);
877 Add(FolderItem, CurrentFolder ? strcmp(Folder->Text(), CurrentFolder) == 0 : false);
878 if (!firstFolder)
879 firstFolder = FolderItem;
880 }
881}
882
883void cMenuFolder::DescendPath(const char *Path)
884{
885 if (Path) {
886 const char *p = strchr(Path, FOLDERDELIMCHAR);
887 if (p) {
888 for (cMenuFolderItem *Folder = (cMenuFolderItem *)firstFolder; Folder; Folder = (cMenuFolderItem *)Next(Folder)) {
889 if (strncmp(Folder->Folder()->Text(), Path, p - Path) == 0) {
890 SetCurrent(Folder);
891 if (Folder->Folder()->SubItems() && strchr(p + 1, FOLDERDELIMCHAR))
892 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));
893 break;
894 }
895 }
896 }
897 }
898}
899
901{
902 if (firstFolder) {
904 if (Folder) {
905 if (Open) {
906 Folder->Folder()->SetSubItems(true);
907 return AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text()));
908 }
909 else
910 return osEnd;
911 }
912 }
913 return osContinue;
914}
915
917{
918 editing = true;
919 return AddSubMenu(new cMenuEditFolder(dir, list));
920}
921
923{
924 if (!HasSubMenu() && firstFolder) {
926 if (Folder && Interface->Confirm(Folder->Folder()->SubItems() ? tr("Delete folder and all sub folders?") : tr("Delete folder?"))) {
927 list->Del(Folder->Folder());
928 Del(Folder->Index());
929 firstFolder = Get(isempty(dir) ? 0 : 1);
930 Display();
931 SetHelpKeys();
933 }
934 }
935 return osContinue;
936}
937
939{
940 if (!HasSubMenu() && firstFolder) {
942 if (Folder) {
943 editing = true;
944 return AddSubMenu(new cMenuEditFolder(dir, list, Folder->Folder()));
945 }
946 }
947 return osContinue;
948}
949
951{
952 if (cMenuEditFolder *mef = dynamic_cast<cMenuEditFolder *>(SubMenu())) {
953 Set(mef->GetFolder());
954 SetHelpKeys();
955 Display();
957 }
958 return CloseSubMenu();
959}
960
962{
963 if (firstFolder) {
965 if (Folder) {
966 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu()))
967 return cString::sprintf("%s%c%s", Folder->Folder()->Text(), FOLDERDELIMCHAR, *mf->GetFolder());
968 return Folder->Folder()->Text();
969 }
970 }
971 return "";
972}
973
975{
976 if (!HasSubMenu())
977 editing = false;
978 eOSState state = cOsdMenu::ProcessKey(Key);
979
980 if (state == osUnknown) {
981 switch (Key) {
982 case kOk: return Select(false);
983 case kRed: return Select(true);
984 case kGreen: return New();
985 case kYellow: return Delete();
986 case kBlue: return Edit();
987 default: state = osContinue;
988 }
989 }
990 else if (state == osEnd && HasSubMenu() && editing)
991 state = SetFolder();
992 SetHelpKeys();
993 return state;
994}
995
996// --- cMenuEditTimer --------------------------------------------------------
997
998static const char *TimerFileMacrosForPattern[] = {
1004 "",
1005 NULL
1006 };
1007
1008static const char *TimerFileMacros[] = {
1011 "",
1012 NULL
1013 };
1014
1016
1018:cOsdMenu(tr("Edit timer"), 12)
1019{
1021 addedTimer = NULL;
1022 pattern = NULL;
1023 file = NULL;
1024 day = firstday = NULL;
1025 start = stop = NULL;
1026 timer = Timer;
1027 addIfConfirmed = New;
1029 if (timer) {
1030 data = *timer;
1031 if (New)
1033 channel = data.Channel()->Number();
1034 Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive));
1035 Add(new cMenuEditChanItem(tr("Channel"), &channel));
1036 Add(day = new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays));
1037 Add(start = new cMenuEditTimeItem(tr("Start"),&data.start));
1038 Add(stop = new cMenuEditTimeItem(tr("Stop"), &data.stop));
1039 Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
1040 Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
1041 Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
1042 Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
1044 SetPatternItem(true);
1045 if (data.remote)
1046 strn0cpy(remote, data.remote, sizeof(remote));
1047 else
1048 *remote = 0;
1050 svdrpServerNames.Sort(true);
1051 svdrpServerNames.Insert(strdup(""));
1052 Add(new cMenuEditStrlItem(tr("Record on"), remote, sizeof(remote), &svdrpServerNames));
1053 }
1054 if (!data.HasFlags(tfVps)) {
1057 }
1058 }
1059 SetHelpKeys();
1060}
1061
1063{
1064 if (timer && addIfConfirmed)
1065 delete timer; // apparently it wasn't confirmed
1066}
1067
1069{
1070 const cTimer *Timer = addedTimer;
1071 addedTimer = NULL;
1072 return Timer;
1073}
1074
1076{
1077 SetHelp(tr("Button$Folder"), data.weekdays ? tr("Button$Single") : tr("Button$Repeating"), *data.pattern ? tr("Button$Regular") : tr("Button$Pattern"));
1078}
1079
1081{
1082 if (!firstday && !data.IsSingleEvent()) {
1083 Add(firstday = new cMenuEditDateItem(tr("First day"), &data.day));
1084 Display();
1085 }
1086 else if (firstday && data.IsSingleEvent()) {
1087 Del(firstday->Index());
1088 firstday = NULL;
1089 Display();
1090 }
1091}
1092
1094{
1095 if (Initial && !*data.pattern) {
1097 return;
1098 }
1099 if (!pattern) {
1100 if (data.HasFlags(tfRecording)) {
1101 Skins.QueueMessage(mtWarning, tr("Timer is recording!"));
1102 return;
1103 }
1104 if (!*data.pattern) {
1105 char *p = strgetlast(data.file, FOLDERDELIMCHAR);
1106 strn0cpy(data.pattern, p, sizeof(data.pattern));
1107 }
1108 Ins(pattern = new cMenuEditStrItem( tr("Pattern"), data.pattern, sizeof(data.pattern)), true, file);
1111 Display();
1112 }
1113 else {
1114 Del(pattern->Index());
1115 pattern = NULL;
1116 *data.pattern = 0;
1118 Display();
1119 }
1120 SetHelpKeys();
1121}
1122
1124{
1125 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
1126 cString Folder = mf->GetFolder();
1127 char *p = strgetlast(data.file, FOLDERDELIMCHAR);
1128 if (!isempty(*Folder))
1129 strn0cpy(data.file, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(data.file));
1130 else if (p != data.file)
1131 memmove(data.file, p, strlen(p) + 1);
1133 Display();
1134 }
1135 return CloseSubMenu();
1136}
1137
1138static bool RemoteTimerError(const cTimer *Timer)
1139{
1140 Skins.QueueMessage(mtError, cString::sprintf("%s %d@%s!", tr("Error while accessing remote timer"), Timer->Id(), Timer->Remote()));
1141 return false; // convenience return code
1142}
1143
1144static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer = NULL)
1145{
1146 cString ErrorMessage;
1147 if (!HandleRemoteTimerModifications(NewTimer, OldTimer, &ErrorMessage)) {
1148 Skins.QueueMessage(mtError, ErrorMessage);
1149 return false;
1150 }
1151 return true;
1152}
1153
1155{
1156 bool WasVps = data.HasFlags(tfVps);
1157 eOSState state = cOsdMenu::ProcessKey(Key);
1158 bool IsVps = data.HasFlags(tfVps);
1159
1160 if (IsVps != WasVps) {
1161 time_t NewStartTime = 0;
1162 time_t NewStopTime = 0;
1163 if (WasVps) {
1164 if (oldStartTime && oldStopTime) {
1165 NewStartTime = oldStartTime;
1166 NewStopTime = oldStopTime;
1168 }
1169 else
1170 data.CalcNewStartStopTime(false, NewStartTime, NewStopTime);
1171 }
1172 else
1173 data.CalcNewStartStopTime(true, NewStartTime, NewStopTime);
1174 if (NewStartTime && NewStopTime) {
1175 day->SetDate(NewStartTime);
1176 start->SetTime(NewStartTime);
1177 stop->SetTime(NewStopTime);
1181 }
1182 }
1183
1184 if (state == osUnknown) {
1185 switch (Key) {
1186 case kOk: if (timer) {
1188 if (!addIfConfirmed && !Timers->Contains(timer)) {
1189 if (cTimer *t = Timers->GetById(timer->Id(), timer->Remote()))
1190 timer = t;
1191 else {
1192 Skins.QueueMessage(mtWarning, tr("Timer has been deleted!"));
1193 break;
1194 }
1195 }
1197 if (const cChannel *Channel = Channels->GetByNumber(channel))
1198 data.channel = Channel;
1199 else {
1200 Skins.QueueMessage(mtError, tr("*** Invalid Channel ***"));
1201 break;
1202 }
1203 if (!*data.file)
1204 strcpy(data.file, data.Channel()->ShortName(true));
1205 data.SetRemote(*remote ? remote : NULL);
1206 if (addIfConfirmed) {
1207 *timer = data;
1208 Timers->Add(timer);
1209 addedTimer = timer;
1211 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
1212 Timers->Del(timer, false);
1213 addedTimer = NULL;
1214 return osContinue;
1215 }
1216 }
1217 else {
1219 return osContinue;
1220 if (timer->Local() && timer->Recording() && data.Remote())
1222 if (timer->Remote() && data.Remote())
1223 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
1225 data.SetEvent(NULL);
1226 *timer = data;
1227 }
1230 timer->SetEventFromSchedule(Schedules);
1231 timer->Matches();
1232 addIfConfirmed = false;
1233 }
1234 return osBack;
1235 case kRed: return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, data.file));
1236 case kGreen: if (day) {
1238 SetCurrent(day);
1240 SetHelpKeys();
1241 Display();
1242 }
1243 return osContinue;
1244 case kYellow: SetPatternItem();
1245 return osContinue;
1246 case kBlue: return osContinue;
1247 default: break;
1248 }
1249 }
1250 else if (state == osEnd && HasSubMenu())
1251 state = SetFolder();
1252 if (Key != kNone)
1254 return state;
1255}
1256
1257// --- cMenuTimerItem --------------------------------------------------------
1258
1259class cMenuTimerItem : public cOsdItem {
1260private:
1262public:
1263 cMenuTimerItem(const cTimer *Timer);
1264 virtual int Compare(const cListObject &ListObject) const override;
1265 virtual void Set(void) override;
1266 const cTimer *Timer(void) { return timer; }
1267 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override;
1268 };
1269
1271{
1272 timer = Timer;
1273 Set();
1274}
1275
1276int cMenuTimerItem::Compare(const cListObject &ListObject) const
1277{
1278 return timer->Compare(*((cMenuTimerItem *)&ListObject)->timer);
1279}
1280
1282{
1283 cString day, name("");
1284 if (timer->WeekDays())
1285 day = timer->PrintDay(0, timer->WeekDays(), false);
1286 else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
1287 day = itoa(timer->GetMDay(timer->Day()));
1288 name = WeekDayName(timer->Day());
1289 }
1290 else {
1291 struct tm tm_r;
1292 time_t Day = timer->Day();
1293 localtime_r(&Day, &tm_r);
1294 char buffer[16];
1295 strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
1296 day = buffer;
1297 }
1298 const char *File = timer->Pattern();
1299 if (!*File) {
1301 if (timer->HasFlags(tfSpawned) && timer->Event() && timer->Event()->Title())
1302 File = timer->Event()->Title();
1303 else {
1304 File = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
1305 if (File && strcmp(File + 1, TIMERMACRO_TITLE) && strcmp(File + 1, TIMERMACRO_EPISODE))
1306 File++;
1307 else
1308 File = timer->File();
1309 }
1310 }
1311 SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s%s%s%s",
1312 !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
1313 timer->Channel()->Number(),
1314 *name,
1315 *name && **name ? " " : "",
1316 *day,
1317 timer->Start() / 100,
1318 timer->Start() % 100,
1319 timer->Stop() / 100,
1320 timer->Stop() % 100,
1321 timer->Remote() ? *cString::sprintf("@%s: ", timer->Remote()) : "",
1322 timer->IsPatternTimer() ? "{" : "",
1323 File,
1324 timer->IsPatternTimer() ? "}" : ""));
1325}
1326
1327void cMenuTimerItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1328{
1330 if (!DisplayMenu->SetItemTimer(timer, Index, Current, Selectable))
1331 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1332}
1333
1334// --- cMenuTimers -----------------------------------------------------------
1335
1336class cMenuTimers : public cOsdMenu {
1337private:
1341 void Set(void);
1342 eOSState Edit(void);
1343 eOSState New(void);
1344 eOSState Delete(void);
1345 eOSState OnOff(void);
1346 eOSState Info(void);
1347 cTimer *GetTimer(void);
1348 void SetHelpKeys(void);
1349public:
1350 cMenuTimers(void);
1351 virtual ~cMenuTimers() override;
1352 virtual eOSState ProcessKey(eKeys Key) override;
1353 };
1354
1356:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
1357{
1359 helpKeys = -1;
1360 showAllTimers = true;
1361 cMenuEditTimer::AddedTimer(); // to clear any leftovers
1362 Set();
1363}
1364
1368
1370{
1371 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
1372 const cTimer *CurrentTimer = GetTimer();
1373 cMenuTimerItem *CurrentItem = NULL;
1374 Clear();
1375 {
1377 for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
1378 cMenuTimerItem *Item = new cMenuTimerItem(Timer);
1379 if (showAllTimers || Timer->HasFlags(tfActive)) {
1380 Add(Item);
1381 if (CurrentTimer && Timer->Id() == CurrentTimer->Id() && (!Timer->Remote() && !CurrentTimer->Remote() || Timer->Remote() && CurrentTimer->Remote() && strcmp(Timer->Remote(), CurrentTimer->Remote()) == 0))
1382 CurrentItem = Item;
1383 }
1384 }
1385 }
1386 Sort();
1387 SetCurrent(CurrentItem ? CurrentItem : First());
1388 SetHelpKeys();
1389 Display();
1391 }
1392}
1393
1395{
1397 return item ? (cTimer *)item->Timer() : NULL;
1398}
1399
1401{
1402 int NewHelpKeys = 0;
1403 if (const cTimer *Timer = GetTimer()) {
1404 if (Timer->Event())
1405 NewHelpKeys = 2;
1406 else
1407 NewHelpKeys = 1;
1408 }
1409 if (NewHelpKeys != helpKeys) {
1410 helpKeys = NewHelpKeys;
1411 SetHelp(helpKeys > 0 ? tr("Button$On/Off") : NULL, tr("Button$New"), helpKeys > 0 ? tr("Button$Delete") : NULL, helpKeys == 2 ? tr("Button$Info") : NULL);
1412 }
1413}
1414
1416{
1417 if (HasSubMenu())
1418 return osContinue;
1419 cStateKey StateKey;
1420 cTimers *Timers = cTimers::GetTimersWrite(StateKey);
1421 cTimer *Timer = GetTimer();
1422 if (Timer) {
1423 Timer->OnOff();
1424 if (Timer->Remote()) {
1426 cStringList Response;
1427 if (!ExecSVDRPCommand(Timer->Remote(), cString::sprintf("MODT %d %s", Timer->Id(), *Timer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250)
1428 RemoteTimerError(Timer);
1429 }
1430 {
1432 Timer->SetEventFromSchedule(Schedules);
1433 }
1435 DisplayCurrent(true);
1436 if (Timer->FirstDay())
1437 isyslog("set first day of timer %s to %s", *Timer->ToDescr(), *Timer->PrintFirstDay());
1438 else
1439 isyslog("%sactivated timer %s", Timer->HasFlags(tfActive) ? "" : "de", *Timer->ToDescr());
1440 }
1441 StateKey.Remove(Timer != NULL);
1442 return osContinue;
1443}
1444
1446{
1447 if (HasSubMenu() || Count() == 0)
1448 return osContinue;
1449 return AddSubMenu(new cMenuEditTimer(GetTimer()));
1450}
1451
1453{
1454 if (HasSubMenu())
1455 return osContinue;
1456 cTimer *Timer = new cTimer;
1459 return AddSubMenu(new cMenuEditTimer(Timer, true));
1460}
1461
1463{
1465 // Check if this timer is active:
1466 cTimer *Timer = GetTimer();
1467 if (Timer) {
1468 bool TimerRecording = Timer->Recording();
1469 timersStateKey.Remove(false); // must release lock while prompting!
1470 if (Interface->Confirm(tr("Delete timer?")) && (!TimerRecording || Interface->Confirm(tr("Timer still recording - really delete?")))) {
1472 Timer = GetTimer();
1473 if (Timer) {
1474 if (!Timer->Remote())
1475 cRecordControls::Stop(Timer);
1476 if (HandleRemoteModifications(NULL, Timer)) {
1477 if (Timer->Remote())
1479 Timers->Del(Timer);
1481 Display();
1482 }
1483 }
1484 }
1485 else
1486 return osContinue;
1487 }
1488 timersStateKey.Remove(Timer != NULL);
1489 return osContinue;
1490}
1491
1493{
1494 if (HasSubMenu() || Count() == 0)
1495 return osContinue;
1499 cTimer *Timer = GetTimer();
1500 if (Timer && Timer->Event())
1501 return AddSubMenu(new cMenuEvent(Timers, Channels, Timer->Event()));
1502 return osContinue;
1503}
1504
1506{
1507 if (!HasSubMenu())
1508 Set();
1509 eOSState state = cOsdMenu::ProcessKey(Key);
1510 bool oldShowAllTimers = showAllTimers;
1511 if (state == osUnknown) {
1512 switch (Key) {
1513 case k0: showAllTimers = !showAllTimers; break;
1514 case kOk: return Edit();
1515 case kRed: state = OnOff(); break; // must go through SetHelpKeys()!
1516 case kGreen: return New();
1517 case kYellow: state = Delete(); break;
1518 case kInfo:
1519 case kBlue: return Info();
1520 break;
1521 default: break;
1522 }
1523 }
1524 if (const cTimer *Timer = cMenuEditTimer::AddedTimer()) {
1525 // a newly created timer was confirmed with Ok and the proper item needs to be added:
1527 cMenuTimerItem *CurrentItem = new cMenuTimerItem(Timer);
1528 Add(CurrentItem, true);
1529 Sort();
1530 SetCurrent(CurrentItem);
1531 SetHelpKeys();
1532 Display();
1533 }
1534 if (showAllTimers != oldShowAllTimers) {
1536 Set();
1537 }
1538 if (Key != kNone)
1539 SetHelpKeys();
1540 return state;
1541}
1542
1543// --- cMenuEvent ------------------------------------------------------------
1544
1545cMenuEvent::cMenuEvent(const cTimers *Timers, const cChannels *Channels, const cEvent *Event, bool CanSwitch, bool Buttons)
1546:cOsdMenu(tr("Event"))
1547{
1549 event = Event;
1550 if (event) {
1551 if (const cChannel *Channel = Channels->GetByChannelID(event->ChannelID(), true)) {
1552 SetTitle(Channel->Name());
1553 if (Buttons) {
1554 eTimerMatch TimerMatch = tmNone;
1555 Timers->GetMatch(event, &TimerMatch);
1556 SetHelp(TimerMatch == tmFull ? tr("Button$Timer") : tr("Button$Record"), NULL, NULL, CanSwitch ? tr("Button$Switch") : NULL);
1557 }
1558 }
1559 }
1560}
1561
1570
1572{
1573 switch (int(Key)) {
1574 case kUp|k_Repeat:
1575 case kUp:
1576 case kDown|k_Repeat:
1577 case kDown:
1578 case kLeft|k_Repeat:
1579 case kLeft:
1580 case kRight|k_Repeat:
1581 case kRight:
1582 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
1583 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
1584 return osContinue;
1585 case kInfo: return osBack;
1586 default: break;
1587 }
1588
1589 eOSState state = cOsdMenu::ProcessKey(Key);
1590
1591 if (state == osUnknown) {
1592 switch (Key) {
1593 case kGreen:
1594 case kYellow: return osContinue;
1595 case kOk: return osBack;
1596 default: break;
1597 }
1598 }
1599 return state;
1600}
1601
1602// --- cMenuScheduleItem -----------------------------------------------------
1603
1605public:
1606 enum eScheduleSortMode { ssmAllThis, ssmThisThis, ssmThisAll, ssmAllAll }; // "which event(s) on which channel(s)"
1607private:
1609public:
1616 cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel = NULL, bool WithDate = false);
1619 static eScheduleSortMode SortMode(void) { return sortMode; }
1620 virtual int Compare(const cListObject &ListObject) const override;
1621 bool Update(const cTimers *Timers, bool Force = false);
1622 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override;
1623 };
1624
1626
1627cMenuScheduleItem::cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel, bool WithDate)
1628{
1629 event = Event;
1630 channel = Channel;
1631 timer = NULL;
1632 withDate = WithDate;
1634 timerActive = false;
1635 Update(Timers, true);
1636}
1637
1638int cMenuScheduleItem::Compare(const cListObject &ListObject) const
1639{
1640 cMenuScheduleItem *p = (cMenuScheduleItem *)&ListObject;
1641 int r = -1;
1642 if (sortMode != ssmAllThis)
1643 r = strcoll(event->Title(), p->event->Title());
1644 if (sortMode == ssmAllThis || r == 0)
1645 r = event->StartTime() - p->event->StartTime();
1646 return r;
1647}
1648
1649static const char *TimerMatchChars = " tT iI";
1650
1651bool cMenuScheduleItem::Update(const cTimers *Timers, bool Force)
1652{
1655 eTimerMatch OldTimerMatch = timerMatch;
1656 bool OldTimerActive = timerActive;
1657 if (event->Schedule() && event->Schedule()->HasTimer())
1658 timer = Timers->GetMatch(event, &timerMatch);
1659 if (event->EndTime() < time(NULL) && !event->IsRunning() && (!timer || !timer->Recording()))
1662 if (Force || timerMatch != OldTimerMatch || timerActive != OldTimerActive) {
1663 cString buffer;
1664 char t = TimerMatchChars[timerMatch + (timerActive ? 0 : 3)];
1665 char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
1666 char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
1667 const char *csn = channel ? channel->ShortName(true) : NULL;
1668 cString eds = event->GetDateString();
1669 if (channel && withDate)
1670 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());
1671 else if (channel)
1672 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());
1673 else
1674 buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
1675 SetText(buffer);
1676 return true;
1677 }
1678 return false;
1679}
1680
1681void cMenuScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1682{
1686 if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch, timer))
1687 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1688}
1689
1690// --- cMenuWhatsOn ----------------------------------------------------------
1691
1692class cMenuWhatsOn : public cOsdMenu {
1693private:
1694 bool now;
1698 eOSState Record(void);
1699 eOSState Switch(void);
1700 static int currentChannel;
1701 static const cEvent *scheduleEvent;
1702 bool Update(void);
1703 void SetHelpKeys(const cChannels *Channels);
1704public:
1705 cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr);
1706 static int CurrentChannel(void) { return currentChannel; }
1707 static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
1708 static const cEvent *ScheduleEvent(void);
1709 virtual eOSState ProcessKey(eKeys Key) override;
1710 };
1711
1714
1715cMenuWhatsOn::cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr)
1716:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, CHNAMWIDTH, 6, 4)
1717{
1719 now = Now;
1720 canSwitch = false;
1721 helpKeys = 0;
1722 for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1723 if (!Channel->GroupSep()) {
1724 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1725 if (const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent())
1726 Add(new cMenuScheduleItem(Timers, Event, Channel), Channel->Number() == CurrentChannelNr);
1727 }
1728 }
1729 }
1730 if (Current() < 0)
1731 SetCurrent(First());
1732 currentChannel = CurrentChannelNr;
1733 SetHelpKeys(Channels);
1734}
1735
1737{
1738 bool result = false;
1739 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
1740 for (cOsdItem *item = First(); item; item = Next(item)) {
1741 if (((cMenuScheduleItem *)item)->Update(Timers))
1742 result = true;
1743 }
1745 }
1746 return result;
1747}
1748
1750{
1752 canSwitch = false;
1753 int NewHelpKeys = 0;
1754 if (item) {
1755 if (item->timerMatch == tmFull)
1756 NewHelpKeys |= 0x02; // "Timer"
1757 else
1758 NewHelpKeys |= 0x01; // "Record"
1759 if (now)
1760 NewHelpKeys |= 0x04; // "Next"
1761 else
1762 NewHelpKeys |= 0x08; // "Now"
1763 if (const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) {
1764 if (Channel->Number() != cDevice::CurrentChannel()) {
1765 NewHelpKeys |= 0x10; // "Switch"
1766 canSwitch = true;
1767 }
1768 }
1769 }
1770 if (NewHelpKeys != helpKeys) {
1771 const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
1772 SetHelp(Red[NewHelpKeys & 0x03], now ? tr("Button$Next") : tr("Button$Now"), tr("Button$Schedule"), canSwitch ? tr("Button$Switch") : NULL);
1773 helpKeys = NewHelpKeys;
1774 }
1775}
1776
1778{
1779 const cEvent *ei = scheduleEvent;
1780 scheduleEvent = NULL;
1781 return ei;
1782}
1783
1785{
1787 if (item) {
1789 const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true);
1790 if (Channel) {
1791 if (!cDevice::PrimaryDevice()->SwitchChannel(Channel, true))
1792 Channel = NULL;
1793 }
1794 if (Channel)
1795 return osEnd;
1796 }
1797 Skins.QueueMessage(mtError, tr("Can't switch channel!"));
1798 return osContinue;
1799}
1800
1802{
1803 if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
1807 Timers->SetExplicitModify();
1808 if (item->timerMatch == tmFull) {
1809 if (cTimer *Timer = Timers->GetMatch(item->event))
1810 return AddSubMenu(new cMenuEditTimer(Timer));
1811 }
1812 cTimer *Timer = new cTimer(item->event);
1815 if (cTimer *t = Timers->GetTimer(Timer)) {
1816 delete Timer;
1817 Timer = t;
1818 return AddSubMenu(new cMenuEditTimer(Timer));
1819 }
1820 if (Timer->Matches(0, NEWTIMERLIMIT))
1821 return AddSubMenu(new cMenuEditTimer(Timer, true));
1822 Timers->Add(Timer);
1823 Timers->SetModified();
1824 if (!HandleRemoteModifications(Timer)) {
1825 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
1826 Timers->Del(Timer);
1827 }
1828 else if (Timer->Remote())
1829 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
1830 if (HasSubMenu())
1831 CloseSubMenu();
1832 }
1833 if (Update())
1834 Display();
1836 SetHelpKeys(Channels);
1837 return osContinue;
1838}
1839
1841{
1842 bool HadSubMenu = HasSubMenu();
1843 eOSState state = cOsdMenu::ProcessKey(Key);
1844
1845 if (state == osUnknown) {
1846 switch (int(Key)) {
1847 case kRecord:
1848 case kRed: return Record();
1849 case kYellow: state = osBack;
1850 // continue with kGreen
1851 case kGreen: {
1853 if (mi) {
1855 scheduleEvent = mi->event;
1856 currentChannel = mi->channel->Number();
1857 }
1858 }
1859 break;
1860 case kBlue: if (canSwitch)
1861 return Switch();
1862 break;
1863 case kChanUp|k_Repeat:
1864 case kChanUp:
1865 case kChanDn|k_Repeat:
1866 case kChanDn: if (!HasSubMenu()) {
1869 for (cOsdItem *item = First(); item; item = Next(item)) {
1870 if (((cMenuScheduleItem *)item)->channel->Number() == cDevice::CurrentChannel()) {
1871 DisplayCurrent(false);
1872 SetCurrent(item);
1873 DisplayCurrent(true);
1874 SetHelpKeys(Channels);
1875 break;
1876 }
1877 }
1878 }
1879 break;
1880 case kInfo:
1881 case kOk: if (Count()) {
1884 return AddSubMenu(new cMenuEvent(Timers, Channels, ((cMenuScheduleItem *)Get(Current()))->event, canSwitch, true));
1885 }
1886 break;
1887 default: break;
1888 }
1889 }
1890 else if (!HasSubMenu()) {
1891 if (HadSubMenu && Update())
1892 Display();
1893 if (Key != kNone) {
1895 SetHelpKeys(Channels);
1896 }
1897 }
1898 return state;
1899}
1900
1901// --- cMenuSchedule ---------------------------------------------------------
1902
1903class cMenuSchedule : public cOsdMenu {
1904private:
1908 bool now, next;
1911 void Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel = NULL, bool Force = false);
1912 eOSState Number(void);
1913 eOSState Record(void);
1914 eOSState Switch(void);
1915 bool PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1916 bool PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1917 bool PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1918 bool PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel);
1919 bool Update(void);
1920 void SetHelpKeys(void);
1921public:
1922 cMenuSchedule(void);
1923 virtual ~cMenuSchedule() override;
1924 virtual eOSState ProcessKey(eKeys Key) override;
1925 };
1926
1928:cOsdMenu(tr("Schedule"))
1929{
1931 scheduleState = -1;
1932 now = next = false;
1933 canSwitch = false;
1934 helpKeys = 0;
1939 Set(Timers, Channels, NULL, true);
1940}
1941
1943{
1944 cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared
1945}
1946
1947void cMenuSchedule::Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel, bool Force)
1948{
1949 if (Force) {
1951 scheduleState = -1;
1952 }
1954 cMenuScheduleItem *CurrentItem = (cMenuScheduleItem *)Get(Current());
1955 const cEvent *Event = NULL;
1956 if (!Channel) {
1957 if (CurrentItem) {
1958 Event = CurrentItem->event;
1959 Channel = Channels->GetByChannelID(Event->ChannelID(), true);
1960 }
1961 else
1962 Channel = Channels->GetByNumber(cDevice::CurrentChannel());
1963 }
1964 bool Refresh = false;
1965 switch (cMenuScheduleItem::SortMode()) {
1966 case cMenuScheduleItem::ssmAllThis: Refresh = PrepareScheduleAllThis(Timers, Schedules, Event, Channel); break;
1967 case cMenuScheduleItem::ssmThisThis: Refresh = PrepareScheduleThisThis(Timers, Schedules, Event, Channel); break;
1968 case cMenuScheduleItem::ssmThisAll: Refresh = Force && PrepareScheduleThisAll(Timers, Schedules, Event, Channel); break;
1969 case cMenuScheduleItem::ssmAllAll: Refresh = Force && PrepareScheduleAllAll(Timers, Schedules, Event, Channel); break;
1970 default: esyslog("ERROR: unknown SortMode %d (%s %d)", cMenuScheduleItem::SortMode(), __FUNCTION__, __LINE__);
1971 }
1972 if (Refresh) {
1973 CurrentItem = (cMenuScheduleItem *)Get(Current());
1974 Sort();
1975 SetCurrent(CurrentItem);
1976 SetHelpKeys();
1977 Display();
1978 }
1980 }
1981}
1982
1983bool cMenuSchedule::PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
1984{
1985 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1986 if (Schedule->Modified(scheduleState)) {
1987 Clear();
1988 SetCols(7, 6, 4);
1989 SetTitle(cString::sprintf(tr("Schedule - %s"), Channel->Name()));
1990 const cEvent *PresentEvent = Event ? Event : Schedule->GetPresentEvent();
1991 time_t now = time(NULL) - Setup.EPGLinger * 60;
1992 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1993 if (ev->EndTime() > now || ev == PresentEvent)
1994 Add(new cMenuScheduleItem(Timers, ev), ev == PresentEvent);
1995 }
1996 return true;
1997 }
1998 }
1999 return false;
2000}
2001
2002bool cMenuSchedule::PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
2003{
2004 if (Event) {
2005 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
2006 if (Schedule->Modified(scheduleState)) {
2007 Clear();
2008 SetCols(7, 6, 4);
2009 SetTitle(cString::sprintf(tr("This event - %s"), Channel->Name()));
2010 time_t now = time(NULL) - Setup.EPGLinger * 60;
2011 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
2012 if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
2013 Add(new cMenuScheduleItem(Timers, ev), ev == Event);
2014 }
2015 return true;
2016 }
2017 }
2018 }
2019 return false;
2020}
2021
2022bool cMenuSchedule::PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
2023{
2024 Clear();
2025 SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
2026 SetTitle(tr("This event - all channels"));
2027 if (Event) {
2029 for (const cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch)) {
2030 if (const cSchedule *Schedule = Schedules->GetSchedule(ch)) {
2031 time_t now = time(NULL) - Setup.EPGLinger * 60;
2032 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
2033 if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
2034 Add(new cMenuScheduleItem(Timers, ev, ch, true), ev == Event && ch == Channel);
2035 }
2036 }
2037 }
2038 }
2039 return true;
2040}
2041
2042bool cMenuSchedule::PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
2043{
2044 Clear();
2045 SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
2046 SetTitle(tr("All events - all channels"));
2048 cStateKey StateKey;
2049 for (const cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch)) {
2050 if (const cSchedule *Schedule = Schedules->GetSchedule(ch)) {
2051 time_t now = time(NULL) - Setup.EPGLinger * 60;
2052 for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
2053 if (ev->EndTime() > now || ev == Event)
2054 Add(new cMenuScheduleItem(Timers, ev, ch, true), ev == Event && ch == Channel);
2055 }
2056 }
2057 }
2058 return true;
2059}
2060
2062{
2063 bool result = false;
2064 if (const cTimers *Timers = cTimers::GetTimersRead(timersStateKey)) {
2065 for (cOsdItem *item = First(); item; item = Next(item)) {
2066 if (((cMenuScheduleItem *)item)->Update(Timers))
2067 result = true;
2068 }
2070 }
2071 return result;
2072}
2073
2075{
2077 canSwitch = false;
2078 int NewHelpKeys = 0;
2079 if (item) {
2080 if (item->timerMatch == tmFull)
2081 NewHelpKeys |= 0x02; // "Timer"
2082 else
2083 NewHelpKeys |= 0x01; // "Record"
2085 if (const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) {
2086 if (Channel->Number() != cDevice::CurrentChannel()) {
2087 NewHelpKeys |= 0x10; // "Switch"
2088 canSwitch = true;
2089 }
2090 }
2091 }
2092 if (NewHelpKeys != helpKeys) {
2093 const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
2094 SetHelp(Red[NewHelpKeys & 0x03], tr("Button$Now"), tr("Button$Next"), canSwitch ? tr("Button$Switch") : NULL);
2095 helpKeys = NewHelpKeys;
2096 }
2097}
2098
2100{
2104 Set(Timers, Channels, NULL, true);
2105 return osContinue;
2106}
2107
2109{
2110 if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
2114 Timers->SetExplicitModify();
2115 if (item->timerMatch == tmFull) {
2116 if (cTimer *Timer = Timers->GetMatch(item->event))
2117 return AddSubMenu(new cMenuEditTimer(Timer));
2118 }
2119 cTimer *Timer = new cTimer(item->event);
2122 if (cTimer *t = Timers->GetTimer(Timer)) {
2123 delete Timer;
2124 Timer = t;
2125 return AddSubMenu(new cMenuEditTimer(Timer));
2126 }
2127 if (Timer->Matches(0, NEWTIMERLIMIT))
2128 return AddSubMenu(new cMenuEditTimer(Timer, true));
2129 Timers->Add(Timer);
2130 Timers->SetModified();
2131 if (!HandleRemoteModifications(Timer)) {
2132 // must add the timer before HandleRemoteModifications to get proper log messages with timer ids
2133 Timers->Del(Timer);
2134 }
2135 else if (Timer->Remote())
2136 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
2137 if (HasSubMenu())
2138 CloseSubMenu();
2139 }
2140 if (Update())
2141 Display();
2142 SetHelpKeys();
2143 return osContinue;
2144}
2145
2147{
2149 if (item) {
2151 const cChannel *Channel = NULL;
2152 if ((Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) != NULL) {
2153 if (!Channels->SwitchTo(Channel->Number()))
2154 Channel = NULL;
2155 }
2156 if (Channel)
2157 return osEnd;
2158 }
2159 Skins.QueueMessage(mtError, tr("Can't switch channel!"));
2160 return osContinue;
2161}
2162
2164{
2165 if (!HasSubMenu()) {
2168 Set(Timers, Channels); // react on any changes to the schedules list
2169 }
2170 bool HadSubMenu = HasSubMenu();
2171 eOSState state = cOsdMenu::ProcessKey(Key);
2172
2173 if (state == osUnknown) {
2174 switch (int(Key)) {
2175 case k0: return Number();
2176 case kRecord:
2177 case kRed: return Record();
2178 case kGreen: {
2182 if (!now && !next) {
2183 int ChannelNr = 0;
2184 if (Count()) {
2185 if (const cChannel *Channel = Channels->GetByChannelID(((cMenuScheduleItem *)Get(Current()))->event->ChannelID(), true))
2186 ChannelNr = Channel->Number();
2187 }
2188 now = true;
2189 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, now, ChannelNr));
2190 }
2191 now = !now;
2192 next = !next;
2193 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, now, cMenuWhatsOn::CurrentChannel()));
2194 }
2195 case kYellow: {
2199 return AddSubMenu(new cMenuWhatsOn(Timers, Channels, Schedules, false, cMenuWhatsOn::CurrentChannel()));
2200 }
2201 case kBlue: if (canSwitch)
2202 return Switch();
2203 break;
2204 case kChanUp|k_Repeat:
2205 case kChanUp:
2206 case kChanDn|k_Repeat:
2207 case kChanDn: if (!HasSubMenu()) {
2210 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
2211 Set(Timers, Channels, Channel, true);
2212 }
2213 break;
2214 case kInfo:
2215 case kOk: if (Count()) {
2219 return AddSubMenu(new cMenuEvent(Timers, Channels, ((cMenuScheduleItem *)Get(Current()))->event, canSwitch, true));
2220 }
2221 break;
2222 default: break;
2223 }
2224 }
2225 else if (!HasSubMenu()) {
2226 now = next = false;
2227 if (const cEvent *ei = cMenuWhatsOn::ScheduleEvent()) {
2230 if (const cChannel *Channel = Channels->GetByChannelID(ei->ChannelID(), true)) {
2232 Set(Timers, Channels, Channel, true);
2233 }
2234 }
2235 else if (HadSubMenu && Update())
2236 Display();
2237 if (Key != kNone)
2238 SetHelpKeys();
2239 }
2240 return state;
2241}
2242
2243// --- cMenuCommands ---------------------------------------------------------
2244
2247{
2249 result = NULL;
2250 SetHasHotkeys();
2252 parameters = Parameters;
2253 for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
2254 const char *s = Command->Text();
2255 if (Command->SubItems())
2256 Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
2257 else if (Parse(s))
2258 Add(new cOsdItem(hk(title)));
2259 }
2260}
2261
2263{
2264 free(result);
2265}
2266
2267bool cMenuCommands::Parse(const char *s)
2268{
2269 const char *p = strchr(s, ':');
2270 if (p) {
2271 int l = p - s;
2272 if (l > 0) {
2273 char t[l + 1];
2274 stripspace(strn0cpy(t, s, l + 1));
2275 l = strlen(t);
2276 if (l > 1 && t[l - 1] == '?') {
2277 t[l - 1] = 0;
2278 confirm = true;
2279 }
2280 else
2281 confirm = false;
2282 title = t;
2283 command = skipspace(p + 1);
2284 return true;
2285 }
2286 }
2287 return false;
2288}
2289
2291{
2292 cNestedItem *Command = commands->Get(Current());
2293 if (Command) {
2294 if (Command->SubItems())
2295 return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
2296 if (Parse(Command->Text())) {
2297 if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
2299 free(result);
2300 result = NULL;
2301 cString cmdbuf;
2302 if (!isempty(parameters))
2303 cmdbuf = cString::sprintf("%s %s", *command, *parameters);
2304 const char *cmd = *cmdbuf ? *cmdbuf : *command;
2305 dsyslog("executing command '%s'", cmd);
2306 cPipe p;
2307 if (p.Open(cmd, "r")) {
2308 int l = 0;
2309 int c;
2310 while ((c = fgetc(p)) != EOF) {
2311 if (l % 20 == 0) {
2312 if (char *NewBuffer = (char *)realloc(result, l + 21))
2313 result = NewBuffer;
2314 else {
2315 esyslog("ERROR: out of memory");
2316 break;
2317 }
2318 }
2319 result[l++] = char(c);
2320 }
2321 if (result)
2322 result[l] = 0;
2323 p.Close();
2324 }
2325 else
2326 esyslog("ERROR: can't open pipe for command '%s'", cmd);
2327 Skins.Message(mtStatus, NULL);
2328 if (result)
2329 return AddSubMenu(new cMenuText(title, result, fontFix));
2330 return osEnd;
2331 }
2332 }
2333 }
2334 return osContinue;
2335}
2336
2338{
2339 eOSState state = cOsdMenu::ProcessKey(Key);
2340
2341 if (state == osUnknown) {
2342 switch (Key) {
2343 case kRed:
2344 case kGreen:
2345 case kYellow:
2346 case kBlue: return osContinue;
2347 case kOk: return Execute();
2348 default: break;
2349 }
2350 }
2351 return state;
2352}
2353
2354// --- cMenuCam --------------------------------------------------------------
2355
2356static bool CamMenuIsOpen = false;
2357
2358class cMenuCam : public cOsdMenu {
2359private:
2363 char *input;
2366 void GenerateTitle(const char *s = NULL);
2367 void QueryCam(void);
2368 void AddMultiLineItem(const char *s);
2369 void Set(void);
2370 eOSState Select(void);
2371public:
2372 cMenuCam(cCamSlot *CamSlot);
2373 virtual ~cMenuCam() override;
2374 virtual eOSState ProcessKey(eKeys Key) override;
2375 };
2376
2378:cOsdMenu("", 1) // tab necessary for enquiry!
2379{
2381 camSlot = CamSlot;
2382 ciMenu = NULL;
2383 ciEnquiry = NULL;
2384 input = NULL;
2385 offset = 0;
2386 lastCamExchange = time(NULL);
2388 QueryCam();
2389 CamMenuIsOpen = true;
2390}
2391
2393{
2394 if (ciMenu)
2395 ciMenu->Abort();
2396 delete ciMenu;
2397 if (ciEnquiry)
2398 ciEnquiry->Abort();
2399 delete ciEnquiry;
2400 free(input);
2401 CamMenuIsOpen = false;
2402}
2403
2404void cMenuCam::GenerateTitle(const char *s)
2405{
2406 SetTitle(cString::sprintf("CAM %d - %s", camSlot->SlotNumber(), (s && *s) ? s : camSlot->GetCamName()));
2407}
2408
2410{
2411 delete ciMenu;
2412 ciMenu = NULL;
2413 delete ciEnquiry;
2414 ciEnquiry = NULL;
2415 if (camSlot->HasUserIO()) {
2416 ciMenu = camSlot->GetMenu();
2418 }
2419 Set();
2420}
2421
2423{
2424 if (ciMenu) {
2425 Clear();
2426 free(input);
2427 input = NULL;
2428 dsyslog("CAM %d: Menu ------------------", camSlot->SlotNumber());
2429 offset = 0;
2432 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->TitleText());
2433 if (!isempty(ciMenu->SubTitleText())) {
2434 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->SubTitleText());
2436 offset = Count();
2437 }
2438 for (int i = 0; i < ciMenu->NumEntries(); i++) {
2440 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->Entry(i));
2441 }
2442 if (!isempty(ciMenu->BottomText())) {
2444 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->BottomText());
2445 }
2447 }
2448 else if (ciEnquiry) {
2449 Clear();
2450 int Length = ciEnquiry->ExpectedLength();
2451 free(input);
2452 input = MALLOC(char, Length + 1);
2453 *input = 0;
2454 dsyslog("CAM %d: Enquiry ------------------", camSlot->SlotNumber());
2455 GenerateTitle();
2456 Add(new cOsdItem(ciEnquiry->Text(), osUnknown, false));
2457 dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciEnquiry->Text());
2458 Add(new cOsdItem("", osUnknown, false));
2459 Add(new cMenuEditNumItem("", input, Length, ciEnquiry->Blind()));
2460 }
2461 Display();
2462}
2463
2465{
2466 while (s && *s) {
2467 const char *p = strchr(s, '\n');
2468 int l = p ? p - s : strlen(s);
2469 cOsdItem *item = new cOsdItem;
2470 item->SetSelectable(false);
2471 item->SetText(strndup(s, l), false);
2472 Add(item);
2473 s = p ? p + 1 : p;
2474 }
2475}
2476
2478{
2479 if (ciMenu) {
2480 if (ciMenu->Selectable()) {
2482 dsyslog("CAM %d: select %d", camSlot->SlotNumber(), Current() - offset);
2483 }
2484 else
2485 ciMenu->Cancel();
2486 }
2487 else if (ciEnquiry) {
2488 if (ciEnquiry->ExpectedLength() < 0xFF && int(strlen(input)) != ciEnquiry->ExpectedLength()) {
2489 char buffer[64];
2490 snprintf(buffer, sizeof(buffer), tr("Please enter %d digits!"), ciEnquiry->ExpectedLength());
2491 Skins.QueueMessage(mtError, buffer);
2492 return osContinue;
2493 }
2495 dsyslog("CAM %d: entered '%s'", camSlot->SlotNumber(), ciEnquiry->Blind() ? "****" : input);
2496 }
2497 QueryCam();
2498 return osContinue;
2499}
2500
2502{
2503 if (!camSlot->HasMMI())
2504 return osBack;
2505
2506 eOSState state = cOsdMenu::ProcessKey(Key);
2507
2508 if (ciMenu || ciEnquiry) {
2509 lastCamExchange = time(NULL);
2510 if (state == osUnknown) {
2511 switch (Key) {
2512 case kOk: return Select();
2513 default: break;
2514 }
2515 }
2516 else if (state == osBack) {
2517 if (ciMenu)
2518 ciMenu->Cancel();
2519 if (ciEnquiry)
2520 ciEnquiry->Cancel();
2521 QueryCam();
2522 return osContinue;
2523 }
2524 if (ciMenu && ciMenu->HasUpdate()) {
2525 QueryCam();
2526 return osContinue;
2527 }
2528 }
2529 else if (time(NULL) - lastCamExchange < CAMRESPONSETIMEOUT)
2530 QueryCam();
2531 else {
2532 Skins.QueueMessage(mtError, tr("CAM not responding!"));
2533 return osBack;
2534 }
2535 return state;
2536}
2537
2538// --- CamControl ------------------------------------------------------------
2539
2541{
2542 for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
2543 if (CamSlot->HasUserIO())
2544 return new cMenuCam(CamSlot);
2545 }
2546 return NULL;
2547}
2548
2550{
2551 return CamMenuIsOpen;
2552}
2553
2554// --- cMenuPathEdit ---------------------------------------------------------
2555
2556#define osUserRecRenamed osUser1
2557#define osUserRecMoved osUser2
2558#define osUserRecRemoved osUser3
2559#define osUserRecEmpty osUser4
2560
2561class cMenuPathEdit : public cOsdMenu {
2562private:
2565 char folder[PATH_MAX];
2566 char name[NAME_MAX];
2569 eOSState SetFolder(void);
2570 eOSState Folder(void);
2571 eOSState ApplyChanges(void);
2572public:
2573 cMenuPathEdit(const char *Path);
2574 virtual eOSState ProcessKey(eKeys Key) override;
2575 };
2576
2578:cOsdMenu(tr("Edit path"), 12)
2579{
2581 path = Path;
2582 *folder = 0;
2583 *name = 0;
2584 const char *s = strrchr(path, FOLDERDELIMCHAR);
2585 if (s) {
2586 strn0cpy(folder, cString(path, s), sizeof(folder));
2587 s++;
2588 }
2589 else
2590 s = path;
2591 strn0cpy(name, s, sizeof(name));
2592 {
2594 pathIsInUse = Recordings->PathIsInUse(path);
2595 }
2596 oldFolder = folder;
2597 cOsdItem *p;
2598 Add(p = folderItem = new cMenuEditStrItem(tr("Folder"), folder, sizeof(folder)));
2600 Add(p = new cMenuEditStrItem(tr("Name"), name, sizeof(name)));
2602 if (*path) {
2603 int DirSize = 0;
2604 {
2606 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
2607 if (Recording->IsInPath(path)) {
2608 int FileSizeMB = Recording->FileSizeMB();
2609 if (FileSizeMB > 0 )
2610 DirSize += FileSizeMB;
2611 }
2612 }
2613 }
2614 if (DirSize > 1023)
2615 Add(new cOsdItem(cString::sprintf("%s:\t%.2f GB", tr("Size"), DirSize / 1024.), osUnknown, false));
2616 else
2617 Add(new cOsdItem(cString::sprintf("%s:\t%d MB", tr("Size"), DirSize), osUnknown, false));
2618 }
2619 if (pathIsInUse) {
2620 Add(new cOsdItem("", osUnknown, false));
2621 Add(new cOsdItem(tr("This folder is currently in use - no changes are possible!"), osUnknown, false));
2622 }
2623 Display();
2624 if (!pathIsInUse)
2625 SetHelp(tr("Button$Folder"));
2626}
2627
2629{
2630 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
2631 strn0cpy(folder, mf->GetFolder(), sizeof(folder));
2633 Display();
2634 }
2635 return CloseSubMenu();
2636}
2637
2639{
2640 return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, path));
2641}
2642
2644{
2645 if (!*name) {
2646 *name = ' '; // name must not be empty!
2647 name[1] = 0;
2648 }
2649 cString NewPath = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2651 if (strcmp(NewPath, path)) {
2652 int NumRecordings = 0;
2653 {
2655 NumRecordings = Recordings->GetNumRecordingsInPath(path);
2656 }
2657 if (NumRecordings > 1 && !Interface->Confirm(cString::sprintf(tr("Move entire folder containing %d recordings?"), NumRecordings)))
2658 return osContinue;
2659 bool Error = false;
2660 {
2662 Recordings->SetExplicitModify();
2663 Error = !Recordings->MoveRecordings(path, NewPath);
2664 if (!Error)
2665 Recordings->SetModified();
2666 }
2667 if (Error) {
2668 Skins.QueueMessage(mtError, tr("Error while moving folder!"));
2669 return osContinue;
2670 }
2671 if (strcmp(folder, oldFolder))
2672 return osUserRecMoved;
2673 return osUserRecRenamed;
2674 }
2675 return osBack;
2676}
2677
2679{
2680 eOSState state = cOsdMenu::ProcessKey(Key);
2681 if (state == osUnknown) {
2682 if (!pathIsInUse) {
2683 switch (Key) {
2684 case kRed: return Folder();
2685 case kOk: return ApplyChanges();
2686 default: break;
2687 }
2688 }
2689 else if (Key == kOk)
2690 return osBack;
2691 }
2692 else if (state == osEnd && HasSubMenu())
2693 state = SetFolder();
2694 return state;
2695}
2696
2697// --- cMenuRecordingEdit ----------------------------------------------------
2698
2700private:
2704 char folder[PATH_MAX];
2705 char name[NAME_MAX];
2711 const char *buttonFolder;
2712 const char *buttonAction;
2714 const char *actionCancel;
2715 const char *doCut;
2717 void Set(void);
2718 void SetHelpKeys(void);
2719 bool RefreshRecording(void);
2720 eOSState SetFolder(void);
2721 eOSState Folder(void);
2722 eOSState Action(void);
2723 eOSState RemoveName(void);
2724 eOSState DeleteMarks(void);
2725 eOSState ApplyChanges(void);
2726public:
2727 cMenuRecordingEdit(const cRecording *Recording);
2728 virtual eOSState ProcessKey(eKeys Key) override;
2729 };
2730
2732:cOsdMenu(tr("Edit recording"), 15)
2733{
2735 recording = Recording;
2737 strn0cpy(folder, recording->Folder(), sizeof(folder));
2738 strn0cpy(name, recording->BaseName(), sizeof(name));
2742 folderItem = NULL;
2743 nameItem = NULL;
2744 buttonFolder = NULL;
2745 buttonAction = NULL;
2746 buttonDeleteMarks = NULL;
2747 actionCancel = NULL;
2748 doCut = NULL;
2750 Set();
2751}
2752
2754{
2755 int current = Current();
2756 Clear();
2758 cOsdItem *p;
2759 Add(p = folderItem = new cMenuEditStrItem(tr("Folder"), folder, sizeof(folder)));
2761 Add(p = nameItem = new cMenuEditStrItem(tr("Name"), name, sizeof(name)));
2763 Add(p = new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY));
2765 Add(p = new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME));
2767 Add(p = new cMenuEditIntItem(tr("Parental rating"), &parentalRating, 0, MAXPARENTALRATING));
2769 if (recordingIsInUse) {
2770 Add(new cOsdItem("", osUnknown, false));
2771 Add(new cOsdItem(tr("This recording is currently in use - no changes are possible!"), osUnknown, false));
2772 }
2774 Display();
2775 SetHelpKeys();
2776}
2777
2779{
2780 buttonFolder = !recordingIsInUse ? tr("Button$Folder") : NULL;
2781 buttonAction = NULL;
2782 buttonDeleteMarks = NULL;
2783 actionCancel = NULL;
2784 doCut = NULL;
2785 if ((recordingIsInUse & ruDst) == 0) {
2786 if ((recordingIsInUse & ruCut) != 0)
2787 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel cutting") : tr("Button$Stop cutting");
2788 else if ((recordingIsInUse & ruMove) != 0)
2789 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel moving") : tr("Button$Stop moving");
2790 else if ((recordingIsInUse & ruCopy) != 0)
2791 buttonAction = actionCancel = ((recordingIsInUse & ruPending) != 0) ? tr("Button$Cancel copying") : tr("Button$Stop copying");
2792 else if (recording->HasMarks()) {
2793 buttonAction = doCut = tr("Button$Cut");
2794 buttonDeleteMarks = tr("Button$Delete marks");
2795 }
2796 }
2798}
2799
2801{
2803 if ((recording = Recordings->GetByName(originalFileName)) != NULL)
2804 Set();
2805 else {
2807 Skins.QueueMessage(mtWarning, tr("Recording vanished!"));
2808 return false;
2809 }
2811 }
2812 return true;
2813}
2814
2816{
2817 if (cMenuFolder *mf = dynamic_cast<cMenuFolder *>(SubMenu())) {
2818 strn0cpy(folder, mf->GetFolder(), sizeof(folder));
2820 Display();
2821 }
2822 return CloseSubMenu();
2823}
2824
2826{
2827 return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, recording->Name()));
2828}
2829
2831{
2832 if (actionCancel)
2834 else if (doCut) {
2835 if (access(cCutter::EditedFileName(recording->FileName()), F_OK) != 0 || Interface->Confirm(tr("Edited version already exists - overwrite?"))) {
2837 Skins.QueueMessage(mtError, tr("Not enough free disk space to start editing process!"));
2839 Skins.QueueMessage(mtError, tr("Error while queueing recording for cutting!"));
2840 }
2841 }
2844 SetHelpKeys();
2845 return osContinue;
2846}
2847
2849{
2850 if (Get(Current()) == nameItem) {
2851 if (Interface->Confirm(tr("Rename recording to folder name?"))) {
2852 char *s = strrchr(folder, FOLDERDELIMCHAR);
2853 if (s)
2854 *s++ = 0;
2855 else
2856 s = folder;
2857 strn0cpy(name, s, sizeof(name));
2858 if (s == folder)
2859 *s = 0;
2860 Set();
2861 }
2862 }
2863 return osContinue;
2864}
2865
2867{
2868 if (buttonDeleteMarks && Interface->Confirm(tr("Delete editing marks for this recording?"))) {
2870 SetHelpKeys();
2871 cMutexLock ControlMutexLock;
2872 if (cControl *Control = cControl::Control(ControlMutexLock, true)) {
2873 if (const cRecording *Recording = Control->GetRecording()) {
2874 if (strcmp(recording->FileName(), Recording->FileName()) == 0)
2875 Control->ClearEditingMarks();
2876 }
2877 }
2878 }
2879 else
2880 Skins.QueueMessage(mtError, tr("Error while deleting editing marks!"));
2881 }
2882 return osContinue;
2883}
2884
2886{
2887 cStateKey StateKey;
2888 cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
2889 cRecording *Recording = Recordings->GetByName(recording->FileName());
2890 if (!Recording) {
2891 StateKey.Remove(false);
2892 Skins.QueueMessage(mtWarning, tr("Recording vanished!"));
2893 return osBack;
2894 }
2895 bool Modified = false;
2897 if (!Recording->ChangePriorityLifetime(priority, lifetime)) {
2898 StateKey.Remove(Modified);
2899 Skins.QueueMessage(mtError, tr("Error while changing priority/lifetime!"));
2900 return osContinue;
2901 }
2902 Modified = true;
2903 }
2905 Recording->Info()->SetParentalRating(parentalRating);
2906 if (!Recording->WriteInfo()) {
2907 StateKey.Remove(Modified);
2908 Skins.QueueMessage(mtError, tr("Error while changing parental rating!"));
2909 return osContinue;
2910 }
2911 Modified = true;
2912 }
2913 if (!*name) {
2914 *name = ' '; // name must not be empty!
2915 name[1] = 0;
2916 }
2917 cString OldFolder = Recording->Folder();
2918 cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2920 if (strcmp(NewName, Recording->Name())) {
2921 if (!Recording->ChangeName(NewName)) {
2922 StateKey.Remove(Modified);
2923 Skins.QueueMessage(mtError, tr("Error while changing folder/name!"));
2924 return osContinue;
2925 }
2926 Modified = true;
2927 }
2928 if (Modified) {
2929 eOSState state = osUserRecRenamed;
2930 if (strcmp(Recording->Folder(), OldFolder))
2931 state = osUserRecMoved;
2933 StateKey.Remove(Modified);
2934 return state;
2935 }
2936 StateKey.Remove(Modified);
2937 return osBack;
2938}
2939
2941{
2942 if (!HasSubMenu()) {
2943 if (!RefreshRecording())
2944 return osBack; // the recording has vanished, so close this menu
2945 }
2946 eOSState state = cOsdMenu::ProcessKey(Key);
2947 if (state == osUnknown) {
2948 switch (Key) {
2949 case k0: return RemoveName();
2950 case kRed: return buttonFolder ? Folder() : osContinue;
2951 case kGreen: return buttonAction ? Action() : osContinue;
2953 case kOk: return !recordingIsInUse ? ApplyChanges() : osBack;
2954 default: break;
2955 }
2956 }
2957 else if (state == osEnd && HasSubMenu())
2958 state = SetFolder();
2959 return state;
2960}
2961
2962// --- cMenuRecording --------------------------------------------------------
2963
2964class cMenuRecording : public cOsdMenu {
2965private:
2970 bool RefreshRecording(void);
2971public:
2972 cMenuRecording(const cRecording *Recording, bool WithButtons = false);
2973 virtual void Display(void) override;
2974 virtual eOSState ProcessKey(eKeys Key) override;
2975};
2976
2977cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
2978:cOsdMenu(tr("Recording info"))
2979{
2981 if (cRecordings::GetRecordingsRead(recordingsStateKey)) // initializes recordingsStateKey, so we don't call Display() unnecessarily
2983 recording = Recording;
2985 withButtons = WithButtons;
2986 if (withButtons) {
2987 if (recording->Deleted())
2988 SetHelp(tr("Button$Recordings"), tr("Button$Restore"), tr("Button$Permanently delete"));
2989 else
2990 SetHelp(tr("Button$Play"), tr("Button$Rewind"), NULL, tr("Button$Edit"));
2991 }
2992 if (recording->Deleted()) {
2993 int t = recording->Deleted() + Setup.DeleteRetention * SECSINDAY - time(NULL);
2994 cString buffer;
2995 // Note how '2 * ...' is used to avoid the plural/singular problem ;-).
2996 if (t > 2 * SECSINDAY) buffer = cString::sprintf(tr("Deleted recording (%d days left)"), int(t / SECSINDAY));
2997 else if (t > 2 * 3600) buffer = cString::sprintf(tr("Deleted recording (%d hours left)"), int(t / 3600));
2998 else if (t > 2 * 60) buffer = cString::sprintf(tr("Deleted recording (%d minutes left)"), int(t / 60));
2999 else buffer = cString::sprintf(tr("Deleted recording (expired)"));
3000 SetTitle(*buffer);
3001 }
3002}
3003
3005{
3007 if ((recording = Recordings->GetByName(originalFileName)) != NULL)
3008 Display();
3009 else {
3011 Skins.QueueMessage(mtWarning, tr("Recording vanished!"));
3012 return false;
3013 }
3015 }
3016 return true;
3017}
3018
3020{
3021 if (HasSubMenu()) {
3022 SubMenu()->Display();
3023 return;
3024 }
3027 if (recording->Info()->Description())
3029}
3030
3032{
3033 if (HasSubMenu())
3034 return cOsdMenu::ProcessKey(Key);
3035 else if (!RefreshRecording())
3036 return osBack; // the recording has vanished, so close this menu
3037 switch (int(Key)) {
3038 case kUp|k_Repeat:
3039 case kUp:
3040 case kDown|k_Repeat:
3041 case kDown:
3042 case kLeft|k_Repeat:
3043 case kLeft:
3044 case kRight|k_Repeat:
3045 case kRight:
3046 DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
3047 cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
3048 return osContinue;
3049 case kInfo: return osBack;
3050 default: break;
3051 }
3052
3053 eOSState state = cOsdMenu::ProcessKey(Key);
3054
3055 if (state == osUnknown) {
3056 if (recording->Deleted()) {
3057 switch (Key) {
3058 case kRed:
3059 case kGreen:
3060 case kYellow: cRemote::Put(Key, true);
3061 // continue with osBack to close the info menu and process the key
3062 case kOk: return osBack;
3063 default: break;
3064 }
3065 }
3066 else if (withButtons) {
3067 switch (Key) {
3068 case kRed: Key = kOk; // will play the recording, even if recording commands are defined
3069 case kGreen: cRemote::Put(Key, true);
3070 // continue with osBack to close the info menu and process the key
3071 case kOk: return osBack;
3072 case kBlue: return AddSubMenu(new cMenuRecordingEdit(recording));
3073 default: break;
3074 }
3075 }
3076 }
3077 return state;
3078}
3079
3080// --- cMenuRecordingItem ----------------------------------------------------
3081
3083private:
3086 char *name;
3089public:
3092 void IncrementCounter(bool New);
3093 const char *Name(void) const { return name; }
3094 int Level(void) const { return level; }
3095 int Usage(void) { return usage; }
3096 const cRecording *Recording(void) const { return recording; }
3097 bool IsDirectory(void) const { return name != NULL; }
3099 void Update(cSkinDisplayMenu *DisplayMenu, int Index, bool Current);
3100 virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override;
3101 };
3102
3104{
3106 level = Level;
3107 name = NULL;
3109 usage = ruNone;
3110 SetText(Recording->Title('\t', true, Level));
3111 if (*Text() == '\t') // this is a folder
3112 name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
3113 else { // this is an actual recording
3114 usage = Recording->IsInUse();
3115 if ((usage & ruDst) != 0 && (usage & (ruMove | ruCopy)) != 0)
3116 SetSelectable(false);
3117 }
3118}
3119
3124
3126{
3127 totalEntries++;
3128 if (New)
3129 newEntries++;
3131}
3132
3133void cMenuRecordingItem::Update(cSkinDisplayMenu *DisplayMenu, int Index, bool Current)
3134{
3135 SetText(recording->Title('\t', true, level));
3136 SetMenuItem(DisplayMenu, Index, Current, Selectable());
3137}
3138
3139void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
3140{
3142 if (!DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
3143 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
3144}
3145
3146// --- cMenuRecordings -------------------------------------------------------
3147
3151
3152cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus, const cRecordingFilter *Filter, bool DelRecMenu)
3153:cOsdMenu(Base ? (DelRecMenu ? *cString::sprintf("%s %s", tr("Deleted in"), Base) : Base)
3154 : (DelRecMenu ? tr("Deleted recordings") : tr("Recordings")), 9, 6, 7)
3155{
3157 base = Base ? strdup(Base) : NULL;
3158 level = Setup.RecordingDirs ? Level : -1;
3160 filter = Filter;
3161 helpKeys = -1;
3162 delRecMenu = DelRecMenu;
3163 autoRefresh = false;
3164 if (Level == 0 && time(NULL) - toggleDelRec > 2)
3165 toggleDelRec = 0;
3166 Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
3167 Set();
3168 if (Current() < 0)
3169 SetCurrent(First());
3170 else if (OpenSubMenus && (cReplayControl::LastReplayed() || (delRecMenu ? *deletedName : *fileName))) {
3171 if (Open(true))
3172 return;
3173 }
3174 SetHelpKeys();
3175}
3176
3178{
3180 if (!ri->IsDirectory()) {
3181 if (delRecMenu)
3182 SetDeleted(ri->Recording()->FileName());
3183 else
3184 SetRecording(ri->Recording()->FileName());
3185 }
3186 }
3187 free(base);
3188}
3189
3191{
3193 int NewHelpKeys = 0;
3194 if (ri) {
3195 if (ri->IsDirectory())
3196 NewHelpKeys = toggleDelRec ? 1 : 2;
3197 else if (delRecMenu)
3198 NewHelpKeys = 3;
3199 else if (toggleDelRec)
3200 NewHelpKeys = 4;
3201 else
3202 NewHelpKeys = 5;
3203 }
3204 else
3205 NewHelpKeys = 6;
3206 if (NewHelpKeys != helpKeys) {
3207 switch (NewHelpKeys) {
3208 case 0: SetHelp(NULL); break;
3209 case 1: SetHelp(delRecMenu ? tr("Button$Recordings") : tr("Button$Deleted recordings"), NULL, NULL, delRecMenu ? NULL : tr("Button$Edit")); break;
3210 case 2: SetHelp(delRecMenu ? tr("Button$Recordings") : tr("Button$Open"), NULL, NULL, delRecMenu ? NULL : tr("Button$Edit")); break;
3211 case 3: SetHelp(tr("Button$Recordings"), tr("Button$Restore"), tr("Button$Permanently delete"), tr("Button$Info")); break;
3212 case 4: SetHelp(tr("Button$Deleted recordings"), tr("Button$Rewind"), tr("Button$Delete"), tr("Button$Info")); break;
3213 case 5: SetHelp(RecordingCommands.Count() ? tr("Button$Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), tr("Button$Info")); break;
3214 case 6: SetHelp(delRecMenu ? tr("Button$Recordings") : tr("Button$Deleted recordings")); break;
3215 default: ;
3216 }
3217 helpKeys = NewHelpKeys;
3218 }
3219}
3220
3221void cMenuRecordings::Set(bool Refresh)
3222{
3228 const char *CurrentRecording = NULL;
3230 CurrentRecording = ri->Recording()->FileName();
3231 if (!CurrentRecording) {
3232 if (delRecMenu)
3233 CurrentRecording = *deletedName;
3235 CurrentRecording = *fileName ? *fileName : cReplayControl::LastReplayed();
3236 else if (*fileName && strstr(fileName, DirectoryName()))
3237 CurrentRecording = *fileName;
3238 }
3239 autoRefresh = false;
3240 int current = Current();
3241 Clear();
3243 Recordings->Sort();
3244 cMenuRecordingItem *CurrentItem = NULL;
3245 cMenuRecordingItem *LastItem = NULL;
3246 time_t LastReplayTime = 0;
3247 for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
3248 if ((!filter || filter->Filter(Recording)) && (!base || (strstr(Recording->Name(), base) == Recording->Name() && Recording->Name()[strlen(base)] == FOLDERDELIMCHAR))) {
3249 cMenuRecordingItem *Item = new cMenuRecordingItem(Recording, level);
3250 cMenuRecordingItem *LastDir = NULL;
3251 if (Item->IsDirectory()) {
3252 // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
3253 for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
3254 if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
3255 LastDir = p;
3256 break;
3257 }
3258 }
3259 }
3260 if (*Item->Text() && !LastDir) {
3261 autoRefresh |= Item->Usage();
3262 Add(Item);
3263 LastItem = Item;
3264 if (Item->IsDirectory())
3265 LastDir = Item;
3266 }
3267 else
3268 delete Item;
3269 if (LastItem || LastDir) {
3270 if (CurrentRecording) {
3271 if (strcmp(CurrentRecording, Recording->FileName()) == 0)
3272 CurrentItem = LastDir ? LastDir : LastItem;
3273 }
3275 time_t t = Recording->GetLastReplayTime();
3276 if (t > LastReplayTime) {
3277 LastReplayTime = t;
3278 CurrentItem = LastDir ? LastDir : LastItem;
3279 }
3280 }
3281 }
3282 if (LastDir)
3283 LastDir->IncrementCounter(Recording->IsNew());
3284 }
3285 }
3286 SetCurrent(CurrentItem);
3287 if (Current() < 0)
3288 SetCurrent(Get(current)); // last resort, in case the recording was deleted
3290 recordingsStateKey.Remove(false); // sorting doesn't count as a real modification
3291 AdjustTitle(Count() == 0 ? osUserRecEmpty : osContinue, false);
3292 SetHelpKeys();
3293 if (Refresh)
3294 Display();
3295 }
3296 else if (autoRefresh) {
3297 int current = Current();
3298 for (cOsdItem *Item = First(); Item; Item = Next(Item)) {
3299 int Index = VisibleItem(Item->Index());
3300 if (Index >= 0) {
3302 if (!ri->IsDirectory() && ri->Usage())
3303 ri->Update(DisplayMenu(), Index, Item->Index() == current);
3304 }
3305 }
3306 }
3307}
3308
3309void cMenuRecordings::SetDeleted(const char *FileName)
3310{
3311 deletedName = FileName;
3312}
3313
3314void cMenuRecordings::SetRecording(const char *FileName)
3315{
3316 fileName = FileName;
3317}
3318
3320{
3321 if (base) {
3322 char *s = ExchangeChars(strdup(base), true);
3324 free(s);
3325 return d;
3326 }
3327 return cVideoDirectory::Name();
3328}
3329
3330bool cMenuRecordings::Open(bool OpenSubMenus)
3331{
3333 if (ri && ri->IsDirectory()) {
3334 const char *t = ri->Name();
3335 cString buffer;
3336 if (base) {
3337 buffer = cString::sprintf("%s%c%s", base, FOLDERDELIMCHAR, t);
3338 t = buffer;
3339 }
3340 AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus, filter, delRecMenu));
3341 return true;
3342 }
3343 return false;
3344}
3345
3347{
3348 if (!base) {
3349 if (State == osUserRecEmpty)
3350 SetTitle(delRecMenu ? tr("No deleted recordings") : tr("No recordings"));
3351 else
3352 SetTitle(delRecMenu ? tr("Deleted recordings") : tr("Recordings"));
3353 if (Redisplay)
3354 Display();
3355 }
3356 return State;
3357}
3358
3360{
3362 if (ri) {
3363 if (ri->IsDirectory())
3364 Open();
3365 else {
3367 return osReplay;
3368 }
3369 }
3370 return osContinue;
3371}
3372
3374{
3375 if (HasSubMenu() || Count() == 0)
3376 return osContinue;
3378 if (ri && !ri->IsDirectory()) {
3379 cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
3380 ri->Recording()->DeleteResume();
3381 return Play();
3382 }
3383 return osContinue;
3384}
3385
3386static bool TimerStillRecording(const char *FileName)
3387{
3389 // local timer
3390 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3392 if (cTimer *Timer = rc->Timer()) {
3393 cRecordControls::Stop(Timer);
3394 if (Timer->IsSingleEvent()) {
3395 Timers->Del(Timer);
3396 isyslog("deleted timer %s", *Timer->ToDescr());
3397 }
3398 else
3399 Timer->Skip();
3400 }
3401 }
3402 else
3403 return true; // user didn't confirm deletion
3404 }
3405 else {
3406 // remote timer
3407 cString TimerId = GetRecordingTimerId(FileName);
3408 if (*TimerId) {
3409 int Id;
3410 char *RemoteBuf = NULL;
3411 cString Remote;
3412 if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf) && Id != 0) {
3413 Remote = RemoteBuf;
3414 free(RemoteBuf);
3415 if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3417 if (cTimer *Timer = Timers->GetById(Id, Remote)) {
3418 cTimer OldTimer = *Timer;
3419 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
3420 if (Timer->IsSingleEvent()) {
3421 if (HandleRemoteModifications(NULL, Timer))
3422 Timers->Del(Timer);
3423 else
3424 return true; // error while deleting remote timer
3425 }
3426 else {
3427 Timer->Skip();
3428 if (!HandleRemoteModifications(Timer, &OldTimer))
3429 return true; // error while modifying remote timer
3430 }
3431 }
3432 }
3433 else
3434 return true; // user didn't confirm deletion
3435 }
3436 }
3437 }
3438 return false;
3439}
3440
3442{
3443 if (HasSubMenu() || Count() == 0)
3444 return osContinue;
3446 if (ri && !ri->IsDirectory()) {
3447 if (Interface->Confirm(tr("Delete recording?"))) {
3449 return osContinue;
3450 cString FileName;
3451 {
3453 if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName()))
3454 FileName = Recording->FileName();
3455 else
3456 return osContinue; // recording has already been deleted
3457 }
3458 if (RecordingsHandler.GetUsage(FileName)) {
3459 if (!Interface->Confirm(tr("Recording is being edited - really delete?")))
3460 return osContinue;
3461 SetNeedsFastResponse(true); // makes sure the edited version is removed from the menu ASAP
3462 }
3463 RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one!
3464 if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
3467 cStateKey StateKey;
3468 cRecordings *DeletedRecordings = cRecordings::GetDeletedRecordingsWrite(StateKey);
3469 cRecording *Recording = Recordings->GetByName(FileName);
3470 if (!Recording || Recording->Delete()) {
3472 Recordings->Del(Recording, false);
3473 DeletedRecordings->Add(Recording);
3475 SetHelpKeys();
3477 StateKey.Remove();
3479 SetDeleted(Recording->FileName());
3480 Display();
3482 if (!Count())
3483 return osUserRecEmpty;
3484 return osUserRecRemoved;
3485 }
3486 else
3487 Skins.QueueMessage(mtError, tr("Error while deleting recording!"));
3488 StateKey.Remove();
3490 }
3491 }
3492 return osContinue;
3493}
3494
3496{
3497 if (HasSubMenu() || Count() == 0)
3498 return osContinue;
3500 if (ri && !ri->IsDirectory()) {
3501 if (Interface->Confirm(tr("Restore recording?"))) {
3502 if (cRecording *Recording = ((cRecording *)ri->Recording())) {
3503 cStateKey StateKey;
3504 cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
3506 if (Recording->Undelete()) {
3507 DeletedRecordings->Del(Recording, false);
3508 Recordings->Add(Recording);
3510 SetHelpKeys();
3512 StateKey.Remove();
3514 SetRecording(Recording->FileName());
3515 Display();
3517 if (!Count())
3518 return osUserRecEmpty;
3519 return osUserRecRemoved;
3520 }
3521 else
3522 Skins.QueueMessage(mtError, tr("Error while restoring recording!"));
3523 StateKey.Remove();
3525 }
3526 }
3527 }
3528 return osContinue;
3529}
3530
3532{
3533 if (HasSubMenu() || Count() == 0)
3534 return osContinue;
3536 if (ri && !ri->IsDirectory()) {
3537 if (Interface->Confirm(tr("Permanently delete recording?")) && Interface->Confirm(tr("Are you sure? This can't be undone!"))) {
3538 if (cRecording *Recording = ((cRecording *)ri->Recording())) {
3540 if (Recording->Remove()) {
3541 DeletedRecordings->Del(Recording);
3543 SetHelpKeys();
3546 Display();
3548 if (!Count())
3549 return osUserRecEmpty;
3550 return osUserRecRemoved;
3551 }
3552 else
3553 Skins.QueueMessage(mtError, tr("Error while permanently deleting recording!"));
3555 }
3556 }
3557 }
3558 return osContinue;
3559}
3560
3562{
3563 if (HasSubMenu() || Count() == 0)
3564 return osContinue;
3566 if (ri->IsDirectory()) {
3567 if (!delRecMenu)
3568 return AddSubMenu(new cMenuPathEdit(cString(ri->Recording()->Name(), strchrn(ri->Recording()->Name(), FOLDERDELIMCHAR, ri->Level() + 1))));
3569 }
3570 else
3571 return AddSubMenu(new cMenuRecording(ri->Recording(), true));
3572 }
3573 return osContinue;
3574}
3575
3577{
3578 if (HasSubMenu() || Count() == 0)
3579 return osContinue;
3581 if (ri && !ri->IsDirectory()) {
3582 cMenuCommands *menu;
3583 eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
3584 if (Key != kNone)
3585 state = menu->ProcessKey(Key);
3586 return state;
3587 }
3588 return osContinue;
3589}
3590
3592{
3593 if (HasSubMenu())
3594 return osContinue;
3595 if (const cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()))
3596 SetRecording(ri->Recording()->FileName()); // makes sure the Recordings menu will reposition to the current recording
3599 Set(true);
3600 return osContinue;
3601}
3602
3604{
3605 eOSState state = cOsdMenu::ProcessKey(Key);
3606
3607 if (state == osUnknown) {
3608 switch (Key) {
3609 case kPlayPause:
3610 case kPlay:
3611 case kOk: if (delRecMenu) {
3612 Open();
3613 return osContinue;
3614 }
3615 else
3616 return Play();
3617 case kRed: if (delRecMenu)
3618 toggleDelRec = time(NULL);
3619 switch (helpKeys) {
3620 case 1: return delRecMenu ? osRecsOpen : osRecsDel;
3621 case 2: return delRecMenu ? osRecsOpen : Play();
3622 case 3: return osRecsOpen;
3623 case 4: return osRecsDel;
3624 case 5: return RecordingCommands.Count() ? Commands() : Play();
3625 case 6: return delRecMenu ? osRecsOpen : osRecsDel;
3626 default: ;
3627 }
3628 case kGreen: return AdjustTitle(delRecMenu ? Restore() : Rewind());
3629 case kYellow: return AdjustTitle(delRecMenu ? Purge() : Delete());
3630 case kInfo:
3631 case kBlue: return Info();
3632 case k0: return Sort();
3633 case k1...k9: return delRecMenu ? osContinue : Commands(Key);
3634 default: break;
3635 }
3636 }
3637 else if (state == osUserRecRenamed) {
3638 // a recording was renamed (within the same folder), so let's refresh the menu
3639 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3640 fileName = NULL;
3641 state = osContinue;
3642 }
3643 else if (state == osUserRecMoved) {
3644 // a recording was moved to a different folder, so let's delete the old item
3645 CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3646 fileName = NULL;
3648 Set(); // the recording might have been moved into a new subfolder of this folder
3649 if (!Count())
3650 return osUserRecEmpty;
3651 Display();
3652 state = osUserRecRemoved;
3653 }
3654 else if (state == osUserRecRemoved) {
3655 // a recording was removed from a sub folder, so update the current item
3656 if (cOsdMenu *m = SubMenu()) {
3658 if (cMenuRecordingItem *riSub = (cMenuRecordingItem *)m->Get(m->Current()))
3659 ri->SetRecording(riSub->Recording());
3660 }
3661 }
3662 // no state change here, this report goes upstream!
3663 }
3664 else if (state == osUserRecEmpty) {
3665 // a subfolder became empty, so let's go back up
3666 CloseSubMenu(false); // this is the now empty submenu
3667 cOsdMenu::Del(Current()); // the menu entry of the now empty subfolder
3668 Set(); // in case a recording was moved into a new subfolder of this folder
3669 SetHelpKeys();
3670 if (!Count()) {
3671 if (base) // don't go up beyond the top level Recordings menu
3672 return state;
3673 else {
3674 AdjustTitle(state);
3675 return osContinue; // AdjustTitle() already does the Display()
3676 }
3677 }
3678 Display();
3679 state = osContinue;
3680 }
3681 if (!HasSubMenu()) {
3682 if (state != osContinue)
3683 Set(true);
3684 if (Key != kNone)
3685 SetHelpKeys();
3686 }
3687 return state;
3688}
3689
3690// --- cMenuSetupBase --------------------------------------------------------
3691
3693protected:
3695 virtual void Store(void) override;
3696public:
3697 cMenuSetupBase(void);
3698 };
3699
3704
3706{
3707 Setup = data;
3709 Setup.Save();
3710}
3711
3712// --- cMenuSetupOSD ---------------------------------------------------------
3713
3715private:
3716 const char *useSmallFontTexts[3];
3717 const char *recSortModeTexts[2];
3718 const char *recSortDirTexts[2];
3719 const char *keyColorTexts[4];
3724 const char **skinDescriptions;
3730 virtual void Set(void);
3731public:
3732 cMenuSetupOSD(void);
3733 virtual ~cMenuSetupOSD() override;
3734 virtual eOSState ProcessKey(eKeys Key) override;
3735 };
3736
3757
3762
3764{
3765 int current = Current();
3766 for (cSkin *Skin = Skins.First(); Skin; Skin = Skins.Next(Skin))
3767 skinDescriptions[Skin->Index()] = Skin->Description();
3768 useSmallFontTexts[0] = tr("never");
3769 useSmallFontTexts[1] = tr("skin dependent");
3770 useSmallFontTexts[2] = tr("always");
3771 recSortModeTexts[0] = tr("by name");
3772 recSortModeTexts[1] = tr("by time");
3773 recSortDirTexts[0] = tr("ascending");
3774 recSortDirTexts[1] = tr("descending");
3775 keyColorTexts[0] = tr("Key$Red");
3776 keyColorTexts[1] = tr("Key$Green");
3777 keyColorTexts[2] = tr("Key$Yellow");
3778 keyColorTexts[3] = tr("Key$Blue");
3779 Clear();
3780 SetSection(tr("OSD"));
3781 Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0)));
3782 Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions));
3783 if (themes.NumThemes())
3784 Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions()));
3785 Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5));
3786 Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5));
3787 Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0));
3788 Add(new cMenuEditPrcItem( tr("Setup.OSD$Height (%)"), &data.OSDHeightP, 0.5, 1.0));
3789 Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
3790 Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"), &data.UseSmallFont, 3, useSmallFontTexts));
3791 Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"), &data.AntiAlias));
3792 Add(new cMenuEditStraItem(tr("Setup.OSD$Default font"), &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
3793 Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"), &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
3794 Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"), &fontFixIndex, fontFixNames.Size(), &fontFixNames[0]));
3795 Add(new cMenuEditPrcItem( tr("Setup.OSD$Default font size (%)"), &data.FontOsdSizeP, 0.01, 0.1, 1));
3796 Add(new cMenuEditPrcItem( tr("Setup.OSD$Small font size (%)"), &data.FontSmlSizeP, 0.01, 0.1, 1));
3797 Add(new cMenuEditPrcItem( tr("Setup.OSD$Fixed font size (%)"), &data.FontFixSizeP, 0.01, 0.1, 1));
3798 Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
3799 Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
3800 Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
3801 Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
3802 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
3803 Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
3804 Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses));
3805 Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
3806 Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu));
3807 Add(new cMenuEditBoolItem(tr("Setup.OSD$Always sort folders first"), &data.AlwaysSortFoldersFirst));
3808 Add(new cMenuEditStraItem(tr("Setup.OSD$Default sort mode for recordings"), &data.DefaultSortModeRec, 2, recSortModeTexts));
3809 Add(new cMenuEditStraItem(tr("Setup.OSD$Sorting direction for recordings"), &data.RecSortingDirection, 2, recSortDirTexts));
3810 Add(new cMenuEditBoolItem(tr("Setup.OSD$Number keys for characters"), &data.NumberKeysForChars));
3811 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 0"), &data.ColorKey0, 4, keyColorTexts));
3812 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 1"), &data.ColorKey1, 4, keyColorTexts));
3813 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 2"), &data.ColorKey2, 4, keyColorTexts));
3814 Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 3"), &data.ColorKey3, 4, keyColorTexts));
3816 Display();
3817}
3818
3820{
3821 bool ModifiedAppearance = false;
3822
3823 if (Key == kOk) {
3826 cSkin *Skin = Skins.Get(skinIndex);
3827 if (Skin) {
3828 Utf8Strn0Cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
3829 Skins.SetCurrent(Skin->Name());
3830 ModifiedAppearance = true;
3831 }
3832 }
3833 if (themes.NumThemes() && Skins.Current()->Theme()) {
3836 ModifiedAppearance |= themeIndex != originalThemeIndex;
3837 }
3839 ModifiedAppearance = true;
3841 ModifiedAppearance = true;
3846 ModifiedAppearance = true;
3848 ModifiedAppearance = true;
3850 ModifiedAppearance = true;
3853 Recordings->ClearSortNames();
3854 }
3855 }
3856
3857 int oldSkinIndex = skinIndex;
3858 int oldOsdLanguageIndex = osdLanguageIndex;
3860
3861 if (ModifiedAppearance)
3863
3864 if (osdLanguageIndex != oldOsdLanguageIndex || skinIndex != oldSkinIndex) {
3866 int OriginalOSDLanguage = I18nCurrentLanguage();
3868
3869 cSkin *Skin = Skins.Get(skinIndex);
3870 if (Skin) {
3871 char *d = themes.NumThemes() ? strdup(themes.Descriptions()[themeIndex]) : NULL;
3872 themes.Load(Skin->Name());
3873 if (skinIndex != oldSkinIndex)
3874 themeIndex = d ? themes.GetThemeIndex(d) : 0;
3875 free(d);
3876 }
3877
3878 Set();
3879 I18nSetLanguage(OriginalOSDLanguage);
3880 }
3881 return state;
3882}
3883
3884// --- cMenuSetupEPG ---------------------------------------------------------
3885
3887private:
3890 void Setup(void);
3891public:
3892 cMenuSetupEPG(void);
3893 virtual eOSState ProcessKey(eKeys Key) override;
3894 };
3895
3897{
3900 ;
3902 SetSection(tr("EPG"));
3903 SetHelp(tr("Button$Scan"));
3904 Setup();
3905}
3906
3908{
3909 int current = Current();
3910
3911 Clear();
3912
3913 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
3914 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan max. channel number (0=all)"), &data.EPGScanMaxChannel));
3915 Add(new cMenuEditBoolItem(tr("Setup.EPG$EPG pause after scan"), &data.EPGPauseAfterScan));
3916 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
3917 Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0));
3918 Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
3919 if (data.SetSystemTime)
3920 Add(new cMenuEditTranItem(Indent(2, tr("Setup.EPG$Use time from transponder")), &data.TimeTransponder, &data.TimeSource));
3921 // TRANSLATORS: note the plural!
3922 Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), &numLanguages, 0, I18nLanguages()->Size()));
3923 for (int i = 0; i < numLanguages; i++)
3924 // TRANSLATORS: note the singular!
3925 Add(new cMenuEditStraItem(Indent(2, tr("Setup.EPG$Preferred language")), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3926
3928 Display();
3929}
3930
3932{
3933 if (Key == kOk) {
3934 bool Modified = numLanguages != originalNumLanguages;
3935 if (!Modified) {
3936 for (int i = 0; i < numLanguages; i++) {
3937 if (data.EPGLanguages[i] != ::Setup.EPGLanguages[i]) {
3938 Modified = true;
3939 break;
3940 }
3941 }
3942 }
3943 if (Modified)
3945 }
3946
3947 int oldnumLanguages = numLanguages;
3948 int oldSetSystemTime = data.SetSystemTime;
3949
3951 if (Key != kNone) {
3952 if (numLanguages != oldnumLanguages || data.SetSystemTime != oldSetSystemTime) {
3953 for (int i = oldnumLanguages; i < numLanguages; i++) {
3954 data.EPGLanguages[i] = 0;
3955 for (int l = 0; l < I18nLanguages()->Size(); l++) {
3956 int k;
3957 for (k = 0; k < oldnumLanguages; k++) {
3958 if (data.EPGLanguages[k] == l)
3959 break;
3960 }
3961 if (k >= oldnumLanguages) {
3962 data.EPGLanguages[i] = l;
3963 break;
3964 }
3965 }
3966 }
3968 Setup();
3969 }
3970 if (Key == kRed) {
3972 return osEnd;
3973 }
3974 }
3975 return state;
3976}
3977
3978// --- cMenuSetupDVB ---------------------------------------------------------
3979
3981private:
3986 void Setup(void);
3988 const char *updateChannelsTexts[6];
3991public:
3992 cMenuSetupDVB(void);
3993 virtual eOSState ProcessKey(eKeys Key) override;
3994 };
3995
3997{
4000 ;
4002 ;
4005 videoDisplayFormatTexts[0] = tr("pan&scan");
4006 videoDisplayFormatTexts[1] = tr("letterbox");
4007 videoDisplayFormatTexts[2] = tr("center cut out");
4008 updateChannelsTexts[0] = tr("no");
4009 updateChannelsTexts[1] = tr("names only");
4010 updateChannelsTexts[2] = tr("PIDs only");
4011 updateChannelsTexts[3] = tr("names and PIDs");
4012 updateChannelsTexts[4] = tr("add new channels");
4013 updateChannelsTexts[5] = tr("add new transponders");
4014 displaySubtitlesTexts[0] = tr("no");
4015 displaySubtitlesTexts[1] = tr("always");
4016 displaySubtitlesTexts[2] = tr("after rewind");
4017 standardComplianceTexts[0] = "DVB";
4018 standardComplianceTexts[1] = "ANSI/SCTE";
4019 standardComplianceTexts[2] = "NORDIG";
4020
4021 SetSection(tr("DVB"));
4022 SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL);
4023 Setup();
4024}
4025
4027{
4028 int current = Current();
4029
4030 Clear();
4031
4032 Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
4033 Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"), &data.StandardCompliance, 3, standardComplianceTexts));
4034 Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
4035 if (data.VideoFormat == 0)
4036 Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
4037 Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts));
4038 Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
4039 for (int i = 0; i < numAudioLanguages; i++)
4040 Add(new cMenuEditStraItem(Indent(2, tr("Setup.DVB$Audio language")), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
4041 Add(new cMenuEditStraItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles, 3, displaySubtitlesTexts));
4043 Add(new cMenuEditIntItem(Indent(2, tr("Setup.DVB$Subtitle languages")), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
4044 for (int i = 0; i < numSubtitleLanguages; i++)
4045 Add(new cMenuEditStraItem(Indent(4, tr("Setup.DVB$Subtitle language")), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
4046 Add(new cMenuEditIntItem(Indent(2, tr("Setup.DVB$Subtitle offset")), &data.SubtitleOffset, -100, 100));
4047 Add(new cMenuEditIntItem(Indent(2, tr("Setup.DVB$Subtitle foreground transparency")), &data.SubtitleFgTransparency, 0, 9));
4048 Add(new cMenuEditIntItem(Indent(2, tr("Setup.DVB$Subtitle background transparency")), &data.SubtitleBgTransparency, 0, 10));
4049 }
4050
4052 Display();
4053}
4054
4056{
4057 int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
4058 bool oldVideoFormat = ::Setup.VideoFormat;
4059 bool newVideoFormat = data.VideoFormat;
4060 int oldDisplaySubtitles = ::Setup.DisplaySubtitles;
4061 int newDisplaySubtitles = data.DisplaySubtitles;
4062 int oldnumAudioLanguages = numAudioLanguages;
4063 int oldnumSubtitleLanguages = numSubtitleLanguages;
4065
4066 if (Key != kNone) {
4067 switch (Key) {
4068 case kGreen: cRemote::Put(kAudio, true);
4069 state = osEnd;
4070 break;
4071 case kYellow: cRemote::Put(kSubtitles, true);
4072 state = osEnd;
4073 break;
4074 default: {
4075 bool DoSetup = data.VideoFormat != newVideoFormat;
4076 DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
4077 if (numAudioLanguages != oldnumAudioLanguages) {
4078 for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
4079 data.AudioLanguages[i] = 0;
4080 for (int l = 0; l < I18nLanguages()->Size(); l++) {
4081 int k;
4082 for (k = 0; k < oldnumAudioLanguages; k++) {
4083 if (data.AudioLanguages[k] == l)
4084 break;
4085 }
4086 if (k >= oldnumAudioLanguages) {
4087 data.AudioLanguages[i] = l;
4088 break;
4089 }
4090 }
4091 }
4093 DoSetup = true;
4094 }
4095 if (numSubtitleLanguages != oldnumSubtitleLanguages) {
4096 for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
4097 data.SubtitleLanguages[i] = 0;
4098 for (int l = 0; l < I18nLanguages()->Size(); l++) {
4099 int k;
4100 for (k = 0; k < oldnumSubtitleLanguages; k++) {
4101 if (data.SubtitleLanguages[k] == l)
4102 break;
4103 }
4104 if (k >= oldnumSubtitleLanguages) {
4105 data.SubtitleLanguages[i] = l;
4106 break;
4107 }
4108 }
4109 }
4111 DoSetup = true;
4112 }
4113 if (DoSetup)
4114 Setup();
4115 }
4116 }
4117 }
4118 if (state == osBack && Key == kOk) {
4119 if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
4121 if (::Setup.VideoFormat != oldVideoFormat)
4123 if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
4126 }
4127 return state;
4128}
4129
4130// --- cMenuSetupLNB ---------------------------------------------------------
4131
4133private:
4135 void Setup(void);
4136public:
4137 cMenuSetupLNB(void);
4138 virtual eOSState ProcessKey(eKeys Key) override;
4139 };
4140
4149
4151{
4152 int current = Current();
4153
4154 Clear();
4155
4156 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
4157 if (!data.DiSEqC) {
4158 Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
4159 Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
4160 Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
4161 }
4162
4163 int NumSatDevices = 0;
4164 for (int i = 0; i < cDevice::NumDevices(); i++) {
4165 if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
4166 NumSatDevices++;
4167 }
4168 if (NumSatDevices > 1) {
4169 for (int i = 0; i < cDevice::NumDevices(); i++) {
4170 if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
4171 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")));
4172 else
4173 satCableNumbers.Array()[i] = 0;
4174 }
4175 }
4176
4177 Add(new cMenuEditBoolItem(tr("Setup.LNB$Use dish positioner"), &data.UsePositioner));
4178 if (data.UsePositioner) {
4179 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site latitude (degrees)"), &data.SiteLat, -900, 900, 10, tr("South"), tr("North")));
4180 Add(new cMenuEditIntxItem(tr("Setup.LNB$Site longitude (degrees)"), &data.SiteLon, -1800, 1800, 10, tr("West"), tr("East")));
4181 Add(new cMenuEditIntxItem(tr("Setup.LNB$Max. positioner swing (degrees)"), &data.PositionerSwing, 0, 900, 10));
4182 Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed (degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
4183 }
4184
4186 Display();
4187}
4188
4190{
4191 int oldDiSEqC = data.DiSEqC;
4192 int oldUsePositioner = data.UsePositioner;
4193 bool DeviceBondingsChanged = false;
4194 if (Key == kOk) {
4195 cString NewDeviceBondings = satCableNumbers.ToString();
4196 DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
4197 data.DeviceBondings = NewDeviceBondings;
4198 }
4200
4201 if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner != oldUsePositioner))
4202 Setup();
4203 else if (DeviceBondingsChanged)
4205 return state;
4206}
4207
4208// --- cMenuSetupCAM ---------------------------------------------------------
4209
4211private:
4213public:
4215 cCamSlot *CamSlot(void) { return camSlot; }
4216 bool Changed(void);
4217 };
4218
4225
4227{
4228 cString AssignedDevice("");
4229 const char *Activating = "";
4230 const char *CamName = camSlot->GetCamName();
4231 if (!CamName) {
4232 switch (camSlot->ModuleStatus()) {
4233 case msReset: CamName = tr("CAM reset"); break;
4234 case msPresent: CamName = tr("CAM present"); break;
4235 case msReady: CamName = tr("CAM ready"); break;
4236 default: CamName = "-"; break;
4237 }
4238 }
4239 else if (camSlot->IsActivating())
4240 // TRANSLATORS: note the leading blank!
4241 Activating = tr(" (activating)");
4242 cVector<int> DeviceNumbers;
4244 if (CamSlot == camSlot || CamSlot->MasterSlot() == camSlot)
4245 CamSlot->Devices(DeviceNumbers);
4246 }
4247 if (DeviceNumbers.Size() > 0) {
4248 AssignedDevice = cString::sprintf(" %s", tr("@ device"));
4249 DeviceNumbers.Sort(CompareInts);
4250 for (int i = 0; i < DeviceNumbers.Size(); i++)
4251 AssignedDevice = cString::sprintf("%s %d", *AssignedDevice, DeviceNumbers[i]);
4252 }
4253
4254 cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
4255 if (strcmp(buffer, Text()) != 0) {
4256 SetText(buffer);
4257 return true;
4258 }
4259 return false;
4260}
4261
4263private:
4265 const char *activationHelp;
4266 eOSState Menu(void);
4267 eOSState Reset(void);
4268 eOSState Activate(void);
4269 void SetHelpKeys(void);
4270public:
4271 cMenuSetupCAM(void);
4272 virtual eOSState ProcessKey(eKeys Key) override;
4273 };
4274
4276{
4278 activationHelp = NULL;
4280 SetSection(tr("CAM"));
4281 SetCols(15);
4282 SetHasHotkeys();
4283 for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
4284 if (CamSlot->IsMasterSlot()) // we only list master CAM slots
4285 Add(new cMenuSetupCAMItem(CamSlot));
4286 }
4287 SetHelpKeys();
4288}
4289
4291{
4292 if (HasSubMenu())
4293 return;
4295 const char *NewActivationHelp = "";
4296 if (item) {
4297 cCamSlot *CamSlot = item->CamSlot();
4298 if (CamSlot->IsActivating())
4299 NewActivationHelp = tr("Button$Cancel activation");
4300 else if (CamSlot->CanActivate())
4301 NewActivationHelp = tr("Button$Activate");
4302 }
4303 if (NewActivationHelp != activationHelp) {
4304 activationHelp = NewActivationHelp;
4305 SetHelp(tr("Button$Menu"), tr("Button$Reset"), activationHelp);
4306 }
4307}
4308
4310{
4312 if (item) {
4313 if (item->CamSlot()->EnterMenu()) {
4314 Skins.Message(mtStatus, tr("Opening CAM menu..."));
4315 time_t t0 = time(NULL);
4316 time_t t1 = t0;
4317 while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
4318 if (item->CamSlot()->HasUserIO())
4319 break;
4320 if (time(NULL) - t1 >= CAMMENURETRYTIMEOUT) {
4321 dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
4322 item->CamSlot()->EnterMenu();
4323 t1 = time(NULL);
4324 }
4325 cCondWait::SleepMs(100);
4326 }
4327 Skins.Message(mtStatus, NULL);
4328 if (item->CamSlot()->HasUserIO())
4329 return AddSubMenu(new cMenuCam(item->CamSlot()));
4330 }
4331 Skins.QueueMessage(mtError, tr("Can't open CAM menu!"));
4332 }
4333 return osContinue;
4334}
4335
4337{
4339 if (item) {
4340 cCamSlot *CamSlot = item->CamSlot();
4341 if (CamSlot->IsActivating())
4342 CamSlot->CancelActivation();
4343 else if (CamSlot->CanActivate()) {
4344 if (CamSlot->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4346 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel())) {
4347 for (int i = 0; i < cDevice::NumDevices(); i++) {
4348 if (cDevice *Device = cDevice::GetDevice(i)) {
4349 if (Device->ProvidesChannel(Channel)) {
4350 if (Device->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4351 if (CamSlot->Assign(Device, true)) { // query
4352 cControl::Shutdown(); // must end transfer mode before assigning CAM, otherwise it might be unassigned again
4353 CamSlot = CamSlot->MtdSpawn();
4354 if (CamSlot->Assign(Device)) {
4355 if (Device->SwitchChannel(Channel, true)) {
4356 CamSlot->StartActivation();
4357 return osContinue;
4358 }
4359 }
4360 }
4361 }
4362 }
4363 }
4364 }
4365 }
4366 }
4367 Skins.QueueMessage(mtError, tr("Can't activate CAM!"));
4368 }
4369 }
4370 return osContinue;
4371}
4372
4374{
4376 if (item) {
4377 if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
4378 if (!item->CamSlot()->Reset())
4379 Skins.QueueMessage(mtError, tr("Can't reset CAM!"));
4380 }
4381 }
4382 return osContinue;
4383}
4384
4386{
4388
4389 if (!HasSubMenu()) {
4390 switch (Key) {
4391 case kOk:
4392 case kRed: return Menu();
4393 case kGreen: state = Reset(); break;
4394 case kYellow: state = Activate(); break;
4395 default: break;
4396 }
4397 for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
4398 if (ci->Changed())
4399 DisplayItem(ci);
4400 }
4401 SetHelpKeys();
4402 }
4404 state = osEnd;
4405 return state;
4406}
4407
4408// --- cMenuSetupRecord ------------------------------------------------------
4409
4411private:
4414 const char *delTimeshiftRecTexts[3];
4415public:
4416 cMenuSetupRecord(void);
4417 };
4418
4420{
4422 recordKeyHandlingTexts[0] = tr("no instant recording");
4423 recordKeyHandlingTexts[1] = tr("confirm instant recording");
4424 recordKeyHandlingTexts[2] = tr("record instantly");
4425 pauseKeyHandlingTexts[0] = tr("do not pause live video");
4426 pauseKeyHandlingTexts[1] = tr("confirm pause live video");
4427 pauseKeyHandlingTexts[2] = tr("pause live video");
4428 delTimeshiftRecTexts[0] = tr("no");
4429 delTimeshiftRecTexts[1] = tr("confirm");
4430 delTimeshiftRecTexts[2] = tr("yes");
4431 SetSection(tr("Recording"));
4432 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
4433 Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
4434 Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
4435 Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
4436 Add(new cMenuEditStraItem(tr("Setup.Recording$Record key handling"), &data.RecordKeyHandling, 3, recordKeyHandlingTexts));
4437 Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
4438 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
4439 Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
4440 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
4441 Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
4442 Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
4443 Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
4444 Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
4445 Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
4446 Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
4447 Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
4448 Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
4449}
4450
4451// --- cMenuSetupReplay ------------------------------------------------------
4452
4454protected:
4455 virtual void Store(void) override;
4456public:
4457 cMenuSetupReplay(void);
4458 };
4459
4461{
4463 SetSection(tr("Replay"));
4464 Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
4465 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
4466 Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
4467 Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
4468 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
4469 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when jumping to a mark"), &data.PauseOnMarkJump));
4470 Add(new cMenuEditBoolItem(tr("Setup.Replay$Skip edited parts"), &data.SkipEdited));
4471 Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay at last mark"), &data.PauseAtLastMark));
4472 Add(new cMenuEditIntItem( tr("Setup.Replay$Initial duration for adaptive skipping (s)"), &data.AdaptiveSkipInitial, 10, 600));
4473 Add(new cMenuEditIntItem( tr("Setup.Replay$Reset timeout for adaptive skipping (s)"), &data.AdaptiveSkipTimeout, 0, 10));
4474 Add(new cMenuEditBoolItem(tr("Setup.Replay$Alternate behavior for adaptive skipping"), &data.AdaptiveSkipAlternate));
4475 Add(new cMenuEditBoolItem(tr("Setup.Replay$Use Prev/Next keys for adaptive skipping"), &data.AdaptiveSkipPrevNext));
4476 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys (s)"), &data.SkipSeconds, 5, 600));
4477 Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys in repeat (s)"), &data.SkipSecondsRepeat, 5, 600));
4478 Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
4479}
4480
4482{
4483 if (Setup.ResumeID != data.ResumeID) {
4485 Recordings->ResetResume();
4486 }
4488}
4489
4490// --- cMenuSetupMisc --------------------------------------------------------
4491
4493private:
4497 void Set(void);
4498public:
4499 cMenuSetupMisc(void);
4500 virtual eOSState ProcessKey(eKeys Key) override;
4501 };
4502
4504{
4506 svdrpPeeringModeTexts[0] = tr("off");
4507 svdrpPeeringModeTexts[1] = tr("any hosts");
4508 svdrpPeeringModeTexts[2] = tr("only default host");
4512 SetSection(tr("Miscellaneous"));
4513 Set();
4514}
4515
4517{
4518 int current = Current();
4519 Clear();
4520 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
4521 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
4522 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
4523 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$SVDRP peering"), &data.SVDRPPeering, 3, svdrpPeeringModeTexts));
4524 if (data.SVDRPPeering) {
4525 Add(new cMenuEditStrItem(Indent(2, tr("Setup.Miscellaneous$SVDRP host name")), data.SVDRPHostName, sizeof(data.SVDRPHostName)));
4527 svdrpServerNames.Sort(true);
4528 svdrpServerNames.Insert(strdup(""));
4529 Add(new cMenuEditStrlItem(Indent(2, tr("Setup.Miscellaneous$SVDRP default host")), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames));
4530 }
4531 else
4532 Add(new cMenuEditStrItem(Indent(2, tr("Setup.Miscellaneous$SVDRP default host")), data.SVDRPDefaultHost, sizeof(data.SVDRPHostName)));
4533 }
4534 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
4535 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
4536 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0, 2000));
4537 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0, 2000));
4538 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Deleted recordings retention (d)"), &data.DeleteRetention, 0));
4539 Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
4540 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
4541 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume steps"), &data.VolumeSteps, 5, 255));
4542 Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume linearize"), &data.VolumeLinearize, -20, 20));
4543 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
4544 Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource, 3, showChannelNamesWithSourceTexts));
4545 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Open Recordings menu at last replayed"), &data.OpenRecMenuAtLastReplayed));
4546 Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
4548 Display();
4549}
4550
4552{
4553 bool OldSVDRPPeering = data.SVDRPPeering;
4554 bool ModifiedSVDRPSettings = false;
4555 bool ModifiedShowChannelNamesWithSource = false;
4556 if (Key == kOk) {
4557 ModifiedSVDRPSettings = data.SVDRPPeering != Setup.SVDRPPeering || strcmp(data.SVDRPHostName, Setup.SVDRPHostName);
4558 ModifiedShowChannelNamesWithSource = data.ShowChannelNamesWithSource != Setup.ShowChannelNamesWithSource;
4559 }
4561 if (ModifiedShowChannelNamesWithSource) {
4563 for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel))
4564 Channel->UpdateNameSource();
4565 }
4566 if (data.SVDRPPeering != OldSVDRPPeering)
4567 Set();
4568 if (ModifiedSVDRPSettings) {
4570 {
4572 Timers->SetExplicitModify();
4573 if (Timers->StoreRemoteTimers(NULL, NULL))
4574 Timers->SetModified();
4575 }
4577 }
4578 return state;
4579}
4580
4581// --- cMenuSetupPluginItem --------------------------------------------------
4582
4584private:
4586public:
4587 cMenuSetupPluginItem(const char *Name, int Index);
4588 int PluginIndex(void) { return pluginIndex; }
4589 };
4590
4592:cOsdItem(Name)
4593{
4595}
4596
4597// --- cMenuSetupPlugins -----------------------------------------------------
4598
4600public:
4601 cMenuSetupPlugins(void);
4602 virtual eOSState ProcessKey(eKeys Key) override;
4603 };
4604
4606{
4608 SetSection(tr("Plugins"));
4609 SetHasHotkeys();
4610 for (int i = 0; ; i++) {
4612 if (p)
4613 Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
4614 else
4615 break;
4616 }
4617}
4618
4620{
4622
4623 if (Key == kOk) {
4624 if (state == osUnknown) {
4626 if (item) {
4628 if (p) {
4629 cMenuSetupPage *menu = p->SetupMenu();
4630 if (menu) {
4631 menu->SetPlugin(p);
4632 return AddSubMenu(menu);
4633 }
4634 Skins.QueueMessage(mtInfo, tr("This plugin has no setup parameters!"));
4635 }
4636 }
4637 }
4638 else if (state == osContinue) {
4639 Store();
4640 // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
4642 Display();
4643 }
4644 }
4645 return state;
4646}
4647
4648// --- cMenuSetup ------------------------------------------------------------
4649
4650class cMenuSetup : public cOsdMenu {
4651private:
4652 virtual void Set(void);
4653 eOSState Restart(void);
4654public:
4655 cMenuSetup(void);
4656 virtual eOSState ProcessKey(eKeys Key) override;
4657 };
4658
4660:cOsdMenu("")
4661{
4663 Set();
4664}
4665
4667{
4668 Clear();
4669 char buffer[64];
4670 snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
4671 SetTitle(buffer);
4672 SetHasHotkeys();
4673 Add(new cOsdItem(hk(tr("OSD")), osUser1));
4674 Add(new cOsdItem(hk(tr("EPG")), osUser2));
4675 Add(new cOsdItem(hk(tr("DVB")), osUser3));
4676 Add(new cOsdItem(hk(tr("LNB")), osUser4));
4677 Add(new cOsdItem(hk(tr("CAM")), osUser5));
4678 Add(new cOsdItem(hk(tr("Recording")), osUser6));
4679 Add(new cOsdItem(hk(tr("Replay")), osUser7));
4680 Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
4682 Add(new cOsdItem(hk(tr("Plugins")), osUser9));
4683 Add(new cOsdItem(hk(tr("Restart")), osUser10));
4684}
4685
4687{
4688 if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
4690 return osEnd;
4691 }
4692 return osContinue;
4693}
4694
4696{
4697 int osdLanguage = I18nCurrentLanguage();
4698 eOSState state = cOsdMenu::ProcessKey(Key);
4699
4700 switch (state) {
4701 case osUser1: return AddSubMenu(new cMenuSetupOSD);
4702 case osUser2: return AddSubMenu(new cMenuSetupEPG);
4703 case osUser3: return AddSubMenu(new cMenuSetupDVB);
4704 case osUser4: return AddSubMenu(new cMenuSetupLNB);
4705 case osUser5: return AddSubMenu(new cMenuSetupCAM);
4706 case osUser6: return AddSubMenu(new cMenuSetupRecord);
4707 case osUser7: return AddSubMenu(new cMenuSetupReplay);
4708 case osUser8: return AddSubMenu(new cMenuSetupMisc);
4709 case osUser9: return AddSubMenu(new cMenuSetupPlugins);
4710 case osUser10: return Restart();
4711 default: ;
4712 }
4713 if (I18nCurrentLanguage() != osdLanguage) {
4714 Set();
4715 if (!HasSubMenu())
4716 Display();
4717 }
4718 return state;
4719}
4720
4721// --- cMenuPluginItem -------------------------------------------------------
4722
4724private:
4726public:
4727 cMenuPluginItem(const char *Name, int Index);
4728 int PluginIndex(void) { return pluginIndex; }
4729 };
4730
4732:cOsdItem(Name, osPlugin)
4733{
4735}
4736
4737// --- cMenuMain -------------------------------------------------------------
4738
4739// TRANSLATORS: note the leading and trailing blanks!
4740#define STOP_RECORDING trNOOP(" Stop recording ")
4741
4743
4744cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
4745:cOsdMenu("")
4746{
4748 replaying = false;
4749 deletedRecordingsItem = NULL;
4750 stopReplayItem = NULL;
4751 cancelEditingItem = NULL;
4752 stopRecordingItem = NULL;
4754 Set();
4755
4756 // Initial submenus:
4757
4758 switch (State) {
4759 case osSchedule: {
4760 cOsdObject *menu = NULL;
4761 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4762 menu = new cMenuSchedule;
4763 if (menu) {
4764 if (menu->IsMenu())
4765 AddSubMenu((cOsdMenu *)menu);
4766 else
4767 delete menu;
4768 }
4769 }
4770 break;
4771 case osChannels: AddSubMenu(new cMenuChannels); break;
4772 case osTimers: AddSubMenu(new cMenuTimers); break;
4773 case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, OpenSubMenus)); break;
4774 case osSetup: AddSubMenu(new cMenuSetup); break;
4775 case osCommands: AddSubMenu(new cMenuCommands(tr("Button$Commands"), &Commands)); break;
4776 default: break;
4777 }
4778}
4779
4781{
4783 pluginOsdObject = NULL;
4784 return o;
4785}
4786
4788{
4789 Clear();
4790 SetTitle("VDR");
4791 SetHasHotkeys();
4792
4793 // Basic menu items:
4794
4795 Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
4796 Add(new cOsdItem(hk(tr("Channels")), osChannels));
4797 Add(new cOsdItem(hk(tr("Timers")), osTimers));
4798 Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
4799
4800 // Plugins:
4801
4802 for (int i = 0; ; i++) {
4804 if (p) {
4805 const char *item = p->MainMenuEntry();
4806 if (item)
4807 Add(new cMenuPluginItem(hk(item), i));
4808 }
4809 else
4810 break;
4811 }
4812
4813 // More basic menu items:
4814
4815 Add(new cOsdItem(hk(tr("Setup")), osSetup));
4816 if (Commands.Count())
4817 Add(new cOsdItem(hk(tr("Button$Commands")), osCommands));
4818
4819 Update(true);
4820
4821 Display();
4822}
4823
4824bool cMenuMain::Update(bool Force)
4825{
4826 bool result = false;
4827
4828 // Deleted recordings:
4829 {
4831 bool HasDeletedRecordings = DeletedRecordings->Count();
4832 if (HasDeletedRecordings && !deletedRecordingsItem) {
4833 // TRANSLATORS: note the leading blank!
4834 Add(deletedRecordingsItem = new cOsdItem(tr(" Deleted recordings"), osRecsDel));
4835 result = true;
4836 }
4837 else if (deletedRecordingsItem && !HasDeletedRecordings) {
4839 deletedRecordingsItem = NULL;
4840 result = true;
4841 }
4842 }
4843
4844 // Replay control:
4845 bool NewReplaying = false;
4846 {
4847 cMutexLock ControlMutexLock;
4848 NewReplaying = cControl::Control(ControlMutexLock) != NULL;
4849 }
4850 if (Force || NewReplaying != replaying) {
4851 replaying = NewReplaying;
4852 // Replay control:
4853 if (replaying && !stopReplayItem)
4854 // TRANSLATORS: note the leading blank!
4855 Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
4856 else if (stopReplayItem && !replaying) {
4858 stopReplayItem = NULL;
4859 }
4860 // Color buttons:
4861 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"));
4862 result = true;
4863 }
4864
4865 // Editing control:
4866 bool EditingActive = RecordingsHandler.Active();
4867 if (EditingActive && !cancelEditingItem) {
4868 // TRANSLATORS: note the leading blank!
4869 Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
4870 result = true;
4871 }
4872 else if (cancelEditingItem && !EditingActive) {
4874 cancelEditingItem = NULL;
4875 result = true;
4876 }
4877
4878 // Record control:
4880 while (stopRecordingItem) {
4883 stopRecordingItem = it;
4884 }
4885 const char *s = NULL;
4886 while ((s = cRecordControls::GetInstantId(s)) != NULL) {
4887 cOsdItem *item = new cOsdItem(osStopRecord);
4888 item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
4889 Add(item);
4890 if (!stopRecordingItem)
4891 stopRecordingItem = item;
4892 }
4893 result = true;
4894 }
4895
4896 return result;
4897}
4898
4900{
4901 bool HadSubMenu = HasSubMenu();
4902 int osdLanguage = I18nCurrentLanguage();
4903 eOSState state = cOsdMenu::ProcessKey(Key);
4904 HadSubMenu |= HasSubMenu();
4905
4906 switch (state) {
4907 case osSchedule: {
4908 cOsdObject *menu = NULL;
4909 if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4910 return AddSubMenu(new cMenuSchedule);
4911 if (menu) {
4912 if (menu->IsMenu())
4913 return AddSubMenu((cOsdMenu *)menu);
4914 else {
4915 pluginOsdObject = menu;
4916 return osPlugin;
4917 }
4918 }
4919 state = osContinue;
4920 }
4921 break;
4922 case osChannels: return AddSubMenu(new cMenuChannels);
4923 case osTimers: return AddSubMenu(new cMenuTimers);
4924 case osRecordings: return AddSubMenu(new cMenuRecordings);
4925 case osRecsOpen: return AddSubMenu(new cMenuRecordings(NULL, 0, true));
4926 case osRecsDel: return AddSubMenu(new cMenuRecordings(NULL, 0, true, NULL, true));
4927 case osSetup: return AddSubMenu(new cMenuSetup);
4928 case osCommands: return AddSubMenu(new cMenuCommands(tr("Button$Commands"), &Commands));
4929 case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
4930 if (cOsdItem *item = Get(Current())) {
4931 cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
4932 return osEnd;
4933 }
4934 }
4935 break;
4936 case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
4938 return osEnd;
4939 }
4940 break;
4941 case osPlugin: {
4943 if (item) {
4945 if (p) {
4946 cOsdObject *menu = p->MainMenuAction();
4947 if (menu) {
4948 if (menu->IsMenu())
4949 return AddSubMenu((cOsdMenu *)menu);
4950 else {
4951 pluginOsdObject = menu;
4952 return osPlugin;
4953 }
4954 }
4955 }
4956 }
4957 state = osEnd;
4958 }
4959 break;
4960 default: switch (Key) {
4961 case kRecord:
4962 case kRed: if (!HadSubMenu)
4964 break;
4965 case kGreen: if (!HadSubMenu) {
4966 cRemote::Put(kAudio, true);
4967 state = osEnd;
4968 }
4969 break;
4970 case kYellow: if (!HadSubMenu)
4972 break;
4973 case kBlue: if (!HadSubMenu)
4975 break;
4976 default: break;
4977 }
4978 }
4979 bool DoDisplay = Update();
4980 if (Key != kNone) {
4981 if (I18nCurrentLanguage() != osdLanguage) {
4982 Set();
4983 if (!HasSubMenu())
4984 DoDisplay = true;
4985 }
4986 }
4987 if (DoDisplay)
4988 Display();
4989 return state;
4990}
4991
4992// --- SetTrackDescriptions --------------------------------------------------
4993
4994static void SetTracksFromComponents(const cComponents *Components, bool Live)
4995{
4996 if (Components) {
4997 int indexAudio = 0;
4998 int indexDolby = 0;
4999 int indexSubtitle = 0;
5000 for (int i = 0; i < Components->NumComponents(); i++) {
5001 const tComponent *p = Components->Component(i);
5002 switch (p->stream) {
5003 case 2: if (p->type == 0x05)
5004 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, Live ? NULL : p->language, p->description);
5005 else
5006 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, Live ? NULL : p->language, p->description);
5007 break;
5008 case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, Live ? NULL : p->language, p->description);
5009 break;
5010 case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, Live ? NULL : p->language, p->description);
5011 break;
5012 default: ;
5013 }
5014 }
5015 }
5016}
5017
5018void SetTrackDescriptions(int LiveChannel)
5019{
5021 // The components must be used while the respective list is locked - the EIT
5022 // section handler thread replaces and deletes an event's components at any
5023 // time, so letting the pointer escape the lock reads freed memory:
5024 if (LiveChannel) {
5026 if (const cChannel *Channel = Channels->GetByNumber(LiveChannel)) {
5028 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
5029 if (const cEvent *Present = Schedule->GetPresentEvent())
5030 SetTracksFromComponents(Present->Components(), true);
5031 }
5032 }
5033 }
5034 else if (cReplayControl::NowReplaying()) {
5036 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::NowReplaying()))
5037 SetTracksFromComponents(Recording->Info()->Components(), false);
5038 }
5039}
5040
5041// --- cDisplayChannel -------------------------------------------------------
5042
5044
5045cDisplayChannel::cDisplayChannel(int Number, bool Switched)
5046:cOsdObject(true)
5047{
5048 currentDisplayChannel = this;
5049 group = -1;
5050 withInfo = !Switched || Setup.ShowInfoOnChSwitch;
5052 number = 0;
5053 timeout = Switched || Setup.TimeoutRequChInfo;
5054 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
5055 positioner = NULL;
5056 channel = NULL;
5057 {
5059 channel = Channels->GetByNumber(Number);
5060 lastPresent = lastFollowing = NULL;
5061 if (channel) {
5063 DisplayInfo();
5064 }
5065 }
5066 if (channel)
5068 lastTime.Set();
5069}
5070
5072:cOsdObject(true)
5073{
5074 currentDisplayChannel = this;
5075 group = -1;
5076 number = 0;
5077 timeout = true;
5078 lastPresent = lastFollowing = NULL;
5079 cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
5080 lastTime.Set();
5083 positioner = NULL;
5084 channel = NULL;
5085 {
5087 channel = Channels->GetByNumber(cDevice::CurrentChannel());
5088 }
5089 ProcessKey(FirstKey);
5090}
5091
5098
5106
5108{
5109 if (withInfo && channel) {
5111 if (const cSchedule *Schedule = Schedules->GetSchedule(channel)) {
5112 const cEvent *Present = Schedule->GetPresentEvent();
5113 const cEvent *Following = Schedule->GetFollowingEvent();
5114 if (Present != lastPresent || Following != lastFollowing) {
5116 displayChannel->SetEvents(Present, Following);
5117 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);
5118 lastPresent = Present;
5119 lastFollowing = Following;
5120 lastTime.Set();
5121 }
5122 }
5123 }
5124}
5125
5127{
5129 displayChannel->SetEvents(NULL, NULL);
5130}
5131
5132const cChannel *cDisplayChannel::NextAvailableChannel(const cChannel *Channel, int Direction)
5133{
5134 if (Direction) {
5135 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
5136 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
5138 while (Channel) {
5139 Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel);
5140 if (!Channel && Setup.ChannelsWrap)
5141 Channel = Direction > 0 ? Channels->First() : Channels->Last();
5142 if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
5143 return Channel;
5144 }
5145 }
5146 return NULL;
5147}
5148
5150{
5152 delete displayChannel;
5154 }
5155 const cChannel *NewChannel = NULL;
5156 if (Key != kNone)
5157 lastTime.Set();
5158 switch (int(Key)) {
5159 case k0:
5160 if (number == 0) {
5161 // keep the "Toggle channels" function working
5162 cRemote::Put(Key);
5163 return osEnd;
5164 }
5165 case k1 ... k9:
5166 group = -1;
5167 if (number >= 0) {
5169 number = Key - k0;
5170 else
5171 number = number * 10 + Key - k0;
5173 channel = Channels->GetByNumber(number);
5174 Refresh();
5175 withInfo = false;
5176 // Lets see if there can be any useful further input:
5177 int n = channel ? number * 10 : 0;
5178 int m = 10;
5179 const cChannel *ch = channel;
5180 while (ch && (ch = Channels->Next(ch)) != NULL) {
5181 if (!ch->GroupSep()) {
5182 if (n <= ch->Number() && ch->Number() < n + m) {
5183 n = 0;
5184 break;
5185 }
5186 if (ch->Number() > n) {
5187 n *= 10;
5188 m *= 10;
5189 }
5190 }
5191 }
5192 if (n > 0) {
5193 // This channel is the only one that fits the input, so let's take it right away:
5194 NewChannel = channel;
5195 withInfo = true;
5196 number = 0;
5197 Refresh();
5198 }
5199 }
5200 break;
5201 case kLeft|k_Repeat:
5202 case kLeft:
5203 case kRight|k_Repeat:
5204 case kRight:
5205 case kNext|k_Repeat:
5206 case kNext:
5207 case kPrev|k_Repeat:
5208 case kPrev: {
5209 withInfo = false;
5210 number = 0;
5212 if (group < 0) {
5213 if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
5214 group = Channel->Index();
5215 }
5216 if (group >= 0) {
5217 int SaveGroup = group;
5218 if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
5219 group = Channels->GetNextGroup(group) ;
5220 else
5221 group = Channels->GetPrevGroup(group < 1 ? 1 : group);
5222 if (group < 0)
5223 group = SaveGroup;
5224 channel = Channels->Get(group);
5225 if (channel) {
5226 Refresh();
5227 if (!channel->GroupSep())
5228 group = -1;
5229 }
5230 }
5231 break;
5232 }
5233 case kUp|k_Repeat:
5234 case kUp:
5235 case kDown|k_Repeat:
5236 case kDown:
5237 case kChanUp|k_Repeat:
5238 case kChanUp:
5239 case kChanDn|k_Repeat:
5240 case kChanDn: {
5241 eKeys k = NORMALKEY(Key);
5242 if (const cChannel *Channel = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1))
5243 channel = Channel;
5244 else if (channel && channel->Number() != cDevice::CurrentChannel())
5245 Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
5246 }
5247 // no break here
5248 case kUp|k_Release:
5249 case kDown|k_Release:
5250 case kChanUp|k_Release:
5251 case kChanDn|k_Release:
5252 case kNext|k_Release:
5253 case kPrev|k_Release:
5254 if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
5255 NewChannel = channel;
5256 withInfo = true;
5257 group = -1;
5258 number = 0;
5259 Refresh();
5260 break;
5261 case kNone:
5264 channel = Channels->GetByNumber(number);
5265 if (channel)
5266 NewChannel = channel;
5267 withInfo = true;
5268 number = 0;
5269 Refresh();
5270 lastTime.Set();
5271 }
5272 break;
5273 //TODO
5274 //XXX case kGreen: return osEventNow;
5275 //XXX case kYellow: return osEventNext;
5276 case kOk: {
5278 if (group >= 0) {
5279 channel = Channels->Get(Channels->GetNextNormal(group));
5280 if (channel)
5281 NewChannel = channel;
5282 withInfo = true;
5283 group = -1;
5284 Refresh();
5285 }
5286 else if (number > 0) {
5287 channel = Channels->GetByNumber(number);
5288 if (channel)
5289 NewChannel = channel;
5290 withInfo = true;
5291 number = 0;
5292 Refresh();
5293 }
5294 else {
5295 return osEnd;
5296 }
5297 }
5298 break;
5299 default:
5300 if ((Key & (k_Repeat | k_Release)) == 0) {
5301 cRemote::Put(Key);
5302 return osEnd;
5303 }
5304 };
5305 if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
5306 {
5309 // makes sure a channel switch through the SVDRP CHAN command is displayed
5310 channel = Channels->GetByNumber(cDevice::CurrentChannel());
5311 Refresh();
5312 lastTime.Set();
5313 }
5314 DisplayInfo();
5315 if (NewChannel) {
5316 SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
5317 Channels->SwitchTo(NewChannel->Number());
5318 SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
5319 channel = NewChannel;
5320 }
5321 const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
5322 bool PositionerMoving = Positioner && Positioner->IsMoving();
5323 SetNeedsFastResponse(PositionerMoving);
5324 if (!PositionerMoving) {
5325 if (positioner)
5326 lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
5327 Positioner = NULL;
5328 }
5329 if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
5330 displayChannel->SetPositioner(Positioner);
5331 positioner = Positioner;
5332 }
5334 return osContinue;
5335 }
5336 return osEnd;
5337}
5338
5339// --- cDisplayVolume --------------------------------------------------------
5340
5341#define VOLUMETIMEOUT 1000 //ms
5342#define MUTETIMEOUT 5000 //ms
5343
5345
5347:cOsdObject(true)
5348{
5349 currentDisplayVolume = this;
5351 displayVolume = Skins.Current()->DisplayVolume();
5352 Show();
5353}
5354
5360
5365
5372
5378
5380{
5381 switch (int(Key)) {
5382 case kVolUp|k_Repeat:
5383 case kVolUp:
5384 case kVolDn|k_Repeat:
5385 case kVolDn:
5386 Show();
5388 break;
5389 case kMute:
5390 if (cDevice::PrimaryDevice()->IsMute()) {
5391 Show();
5393 }
5394 else
5395 timeout.Set();
5396 break;
5397 case kNone: break;
5398 default: if ((Key & k_Release) == 0) {
5399 cRemote::Put(Key);
5400 return osEnd;
5401 }
5402 }
5403 return timeout.TimedOut() ? osEnd : osContinue;
5404}
5405
5406// --- cDisplayTracks --------------------------------------------------------
5407
5408#define TRACKTIMEOUT 5000 //ms
5409
5411
5413:cOsdObject(true)
5414{
5417 currentDisplayTracks = this;
5418 numTracks = track = 0;
5421 for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
5422 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5423 if (TrackId && TrackId->id) {
5425 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5426 if (i == CurrentAudioTrack)
5427 track = numTracks;
5428 numTracks++;
5429 }
5430 }
5431 descriptions[numTracks] = NULL;
5434 Show();
5435}
5436
5438{
5439 delete displayTracks;
5440 currentDisplayTracks = NULL;
5441 for (int i = 0; i < numTracks; i++)
5442 free(descriptions[i]);
5444}
5445
5455
5457{
5458 if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
5460 new cDisplayTracks;
5461 return currentDisplayTracks;
5462 }
5463 Skins.QueueMessage(mtWarning, tr("No audio available!"));
5464 return NULL;
5465}
5466
5472
5474{
5475 int oldTrack = track;
5476 int oldAudioChannel = audioChannel;
5477 switch (int(Key)) {
5478 case kUp|k_Repeat:
5479 case kUp:
5480 case kDown|k_Repeat:
5481 case kDown:
5482 if (NORMALKEY(Key) == kUp && track > 0)
5483 track--;
5484 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5485 track++;
5487 break;
5488 case kLeft|k_Repeat:
5489 case kLeft:
5490 case kRight|k_Repeat:
5491 case kRight: if (IS_AUDIO_TRACK(types[track])) {
5492 static int ac[] = { 1, 0, 2 };
5494 if (NORMALKEY(Key) == kLeft && audioChannel > 0)
5495 audioChannel--;
5496 else if (NORMALKEY(Key) == kRight && audioChannel < 2)
5497 audioChannel++;
5500 }
5501 break;
5502 case kAudio|k_Repeat:
5503 case kAudio:
5504 if (++track >= numTracks)
5505 track = 0;
5507 break;
5508 case kOk:
5509 if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
5510 oldTrack = -1; // make sure we explicitly switch to that track
5511 timeout.Set();
5512 break;
5513 case kNone: break;
5514 default: if ((Key & k_Release) == 0)
5515 return osEnd;
5516 }
5517 if (track != oldTrack || audioChannel != oldAudioChannel)
5518 Show();
5519 if (track != oldTrack) {
5522 }
5523 if (audioChannel != oldAudioChannel)
5525 return timeout.TimedOut() ? osEnd : osContinue;
5526}
5527
5528// --- cDisplaySubtitleTracks ------------------------------------------------
5529
5531
5533:cOsdObject(true)
5534{
5536 currentDisplayTracks = this;
5537 numTracks = track = 0;
5539 descriptions[numTracks] = strdup(tr("No subtitles"));
5540 numTracks++;
5541 eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
5542 for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
5543 const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5544 if (TrackId && TrackId->id) {
5546 descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5547 if (i == CurrentSubtitleTrack)
5548 track = numTracks;
5549 numTracks++;
5550 }
5551 }
5552 descriptions[numTracks] = NULL;
5554 displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
5555 Show();
5556}
5557
5559{
5560 delete displayTracks;
5561 currentDisplayTracks = NULL;
5562 for (int i = 0; i < numTracks; i++)
5563 free(descriptions[i]);
5565}
5566
5573
5575{
5576 if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
5579 return currentDisplayTracks;
5580 }
5581 Skins.QueueMessage(mtWarning, tr("No subtitles available!"));
5582 return NULL;
5583}
5584
5590
5592{
5593 int oldTrack = track;
5594 switch (int(Key)) {
5595 case kUp|k_Repeat:
5596 case kUp:
5597 case kDown|k_Repeat:
5598 case kDown:
5599 if (NORMALKEY(Key) == kUp && track > 0)
5600 track--;
5601 else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5602 track++;
5604 break;
5605 case kSubtitles|k_Repeat:
5606 case kSubtitles:
5607 if (++track >= numTracks)
5608 track = 0;
5610 break;
5611 case kOk:
5612 oldTrack = -1; // make sure we explicitly switch to that track
5613 timeout.Set();
5614 break;
5615 case kNone: break;
5616 default: if ((Key & k_Release) == 0)
5617 return osEnd;
5618 }
5619 if (track != oldTrack) {
5620 Show();
5625 }
5626 }
5627 return timeout.TimedOut() ? osEnd : osContinue;
5628}
5629
5630// --- cRecordControl --------------------------------------------------------
5631
5633{
5634 const char *LastReplayed = cReplayControl::LastReplayed(); // must do this before locking schedules!
5635 // Whatever happens here, the timers will be modified in some way...
5636 Timers->SetModified();
5637 cStateKey ChannelsStateKey;
5638 // To create a new timer, we need to make shure there is
5639 // a lock on Channels prior to the Schedules locking below
5640 if (!Timer)
5641 cChannels::GetChannelsRead(ChannelsStateKey);
5642 // We're going to work with an event here, so we need to prevent
5643 // others from modifying any EPG data:
5644 cStateKey SchedulesStateKey;
5645 cSchedules::GetSchedulesRead(SchedulesStateKey);
5646
5647 event = NULL;
5648 fileName = NULL;
5649 recorder = NULL;
5650 device = Device;
5651 if (!device) device = cDevice::PrimaryDevice();//XXX
5652 timer = Timer;
5653 if (!timer) {
5654 timer = new cTimer(true, Pause);
5655 Timers->Add(timer);
5656 instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->DeviceNumber() + 1);
5657 ChannelsStateKey.Remove();
5658 }
5659 timer->SetPending(true);
5660 timer->SetRecording(true);
5661 event = timer->Event();
5662
5663 if (event || GetEvent())
5664 dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
5665 cRecording Recording(timer, event);
5666 fileName = strdup(Recording.FileName());
5667
5668 // crude attempt to avoid duplicate recordings:
5670 isyslog("already recording: '%s'", fileName);
5671 if (Timer) {
5672 timer->SetPending(false);
5673 timer->SetRecording(false);
5674 timer->OnOff();
5675 }
5676 else {
5677 Timers->Del(timer);
5678 if (!LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5680 }
5681 timer = NULL;
5682 SchedulesStateKey.Remove();
5683 return;
5684 }
5685
5687 isyslog("record %s", fileName);
5688 if (MakeDirs(fileName, true)) {
5689 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!
5690 const cChannel *ch = timer->Channel();
5691 recorder = new cRecorder(fileName, ch, timer->Priority());
5693 cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
5694 if (!Timer && !LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5696 SchedulesStateKey.Remove();
5699 Recordings->AddByName(fileName);
5700 return;
5701 }
5702 else
5704 }
5705 else
5707 if (!Timer) {
5708 Timers->Del(timer);
5709 timer = NULL;
5710 }
5711 SchedulesStateKey.Remove();
5712}
5713
5715{
5716 Stop();
5717 free(fileName);
5718}
5719
5720#define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
5721
5723{
5724 const cChannel *Channel = timer->Channel();
5726 for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
5727 {
5729 if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
5730 event = Schedule->GetEventAround(Time);
5731 if (event) {
5732 if (seconds > 0)
5733 dsyslog("got EPG info after %d seconds", seconds);
5734 return true;
5735 }
5736 }
5737 }
5738 if (seconds == 0)
5739 dsyslog("waiting for EPG info...");
5740 cCondWait::SleepMs(1000);
5741 }
5742 dsyslog("no EPG info available");
5743 return false;
5744}
5745
5746void cRecordControl::Stop(bool ExecuteUserCommand)
5747{
5748 if (timer) {
5749 bool Finished = timer->HasFlags(tfActive) && !timer->Matches();
5750 if (recorder) {
5751 recorder->Stop();
5752 int Errors = recorder->Errors();
5753 isyslog("timer %s %s with %d error%s", *timer->ToDescr(), Finished ? "finished" : "stopped", Errors, Errors != 1 ? "s" : "");
5754 if (timer->HasFlags(tfAvoid) && Errors == 0 && Finished) {
5755 const char *p = strgetlast(timer->File(), FOLDERDELIMCHAR);
5757 }
5758 }
5760 timer->SetRecording(false);
5761 timer = NULL;
5763 cStatus::MsgRecording(device, NULL, fileName, false);
5764 if (ExecuteUserCommand)
5766 }
5767}
5768
5770{
5771 if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
5772 if (timer)
5773 timer->SetPending(false);
5774 return false;
5775 }
5776 return true;
5777}
5778
5779// --- cRecordControls -------------------------------------------------------
5780
5783
5784bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
5785{
5786 static time_t LastNoDiskSpaceMessage = 0;
5787 int FreeMB = 0;
5788 if (Timer) {
5789 AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
5790 Timer->SetPending(true);
5791 }
5793 if (FreeMB < MINFREEDISK) {
5794 if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
5795 isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
5796 Skins.QueueMessage(mtWarning, tr("Not enough disk space to start recording!"));
5797 LastNoDiskSpaceMessage = time(NULL);
5798 }
5799 return false;
5800 }
5801 LastNoDiskSpaceMessage = 0;
5802
5803 ChangeState();
5804 cStateKey StateKey;
5805 const cChannels *Channels = cChannels::GetChannelsRead(StateKey);
5806 int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
5807 if (const cChannel *Channel = Channels->GetByNumber(ch)) {
5808 int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
5809 cDevice *device = cDevice::GetDevice(Channel, Priority, false);
5810 if (device) {
5811 dsyslog("switching device %d to channel %d %s (%s)", device->DeviceNumber() + 1, Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
5812 if (!device->SwitchChannel(Channel, false)) {
5813 StateKey.Remove();
5815 return false;
5816 }
5817 StateKey.Remove();
5818 Channels = NULL;
5819 if (!Timer || Timer->Matches()) {
5820 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5821 if (!RecordControls[i]) {
5822 RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause);
5823 return RecordControls[i]->Process(time(NULL));
5824 }
5825 }
5826 }
5827 }
5828 else if (!Timer || !Timer->Pending()) {
5829 isyslog("no free DVB device to record channel %d (%s)!", ch, Channel->Name());
5830 Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
5831 }
5832 }
5833 else
5834 esyslog("ERROR: channel %d not defined!", ch);
5835 if (Channels)
5836 StateKey.Remove();
5837 return false;
5838}
5839
5841{
5843 return Start(Timers, NULL, Pause);
5844}
5845
5846void cRecordControls::Stop(const char *InstantId)
5847{
5849 ChangeState();
5850 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5851 if (RecordControls[i]) {
5852 const char *id = RecordControls[i]->InstantId();
5853 if (id && strcmp(id, InstantId) == 0) {
5854 cTimer *Timer = RecordControls[i]->Timer();
5855 RecordControls[i]->Stop();
5856 if (Timer) {
5857 Timers->Del(Timer);
5858 isyslog("deleted timer %s", *Timer->ToDescr());
5859 }
5860 break;
5861 }
5862 }
5863 }
5864}
5865
5867{
5868 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5869 if (RecordControls[i]) {
5870 if (RecordControls[i]->Timer() == Timer) {
5871 Timer->SetPending(false);
5873 ChangeState();
5874 break;
5875 }
5876 }
5877 }
5878}
5879
5881{
5882 Skins.Message(mtStatus, tr("Pausing live video..."));
5883 cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
5884 if (Start(true)) {
5885 cReplayControl *rc = new cReplayControl(true);
5886 cControl::Launch(rc);
5888 Skins.Message(mtStatus, NULL);
5889 return true;
5890 }
5891 Skins.Message(mtStatus, NULL);
5892 return false;
5893}
5894
5895const char *cRecordControls::GetInstantId(const char *LastInstantId)
5896{
5897 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5898 if (RecordControls[i]) {
5899 if (!LastInstantId && RecordControls[i]->InstantId())
5900 return RecordControls[i]->InstantId();
5901 if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
5902 LastInstantId = NULL;
5903 }
5904 }
5905 return NULL;
5906}
5907
5909{
5910 if (FileName) {
5911 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5912 if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
5913 return RecordControls[i];
5914 }
5915 }
5916 return NULL;
5917}
5918
5920{
5921 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5922 if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
5923 return RecordControls[i];
5924 }
5925 return NULL;
5926}
5927
5928bool cRecordControls::Process(cTimers *Timers, time_t t)
5929{
5930 bool Result = false;
5931 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5932 if (RecordControls[i]) {
5933 if (!RecordControls[i]->Process(t)) {
5935 ChangeState();
5936 Result = true;
5937 }
5938 }
5939 }
5940 return Result;
5941}
5942
5944{
5945 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5946 if (RecordControls[i]) {
5947 if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
5948 if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
5949 isyslog("stopping recording due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
5950 RecordControls[i]->Stop();
5951 // This will restart the recording, maybe even from a different
5952 // device in case conditional access has changed.
5953 ChangeState();
5954 }
5955 }
5956 }
5957 }
5958}
5959
5961{
5962 for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5963 if (RecordControls[i])
5964 return true;
5965 }
5966 return false;
5967}
5968
5970{
5971 for (int i = 0; i < MAXRECORDCONTROLS; i++)
5973 ChangeState();
5974}
5975
5977{
5978 int NewState = state;
5979 bool Result = State != NewState;
5980 State = state;
5981 return Result;
5982}
5983
5984// --- cAdaptiveSkipper ------------------------------------------------------
5985
5987{
5988 initialValue = NULL;
5989 currentValue = 0;
5990 framesPerSecond = 0;
5991 lastKey = kNone;
5992}
5993
5994void cAdaptiveSkipper::Initialize(int *InitialValue, double FramesPerSecond)
5995{
5996 initialValue = InitialValue;
5997 framesPerSecond = FramesPerSecond;
5998 currentValue = 0;
5999}
6000
6002{
6003 if (!initialValue)
6004 return 0;
6005 if (timeout.TimedOut()) {
6006 currentValue = int(round(*initialValue * framesPerSecond));
6007 lastKey = Key;
6008 }
6009 else if (Key != lastKey) {
6010 currentValue /= 2;
6012 lastKey = Key; // only halve the value when the direction is changed
6013 else
6014 lastKey = kNone; // once the direction has changed, every further call halves the value
6015 }
6017 return max(currentValue, 1);
6018}
6019
6020// --- cReplayControl --------------------------------------------------------
6021
6025
6027:cDvbPlayerControl(fileName, PauseLive)
6028{
6030 currentReplayControl = this;
6031 displayReplay = NULL;
6032 marksModified = false;
6033 visible = modeOnly = shown = displayFrames = false;
6034 lastErrors = 0;
6035 lastCurrent = lastTotal = -1;
6036 lastPlay = lastForward = false;
6037 lastSpeed = -2; // an invalid value
6038 timeoutShow = 0;
6039 timeSearchActive = false;
6040 cRecording Recording(fileName);
6041 cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
6042 marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
6043 SetMarks(&marks);
6048}
6049
6057
6059{
6060 if (timeshiftTimer) {
6062 Timers->SetExplicitModify();
6063 Timers->Del(timeshiftTimer);
6064 Timers->SetModified();
6065 isyslog("deleted timer %s", *timeshiftTimer->ToDescr());
6066 timeshiftTimer = NULL;
6067 }
6068}
6069
6071{
6072 Hide();
6073 cStatus::MsgReplaying(this, NULL, fileName, false);
6074 if (Setup.DelTimeshiftRec && *fileName) {
6076 if (rc && rc->InstantId()) {
6077 if (Active()) {
6078 if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
6079 // At this point somewhere up the call stack there may be a lock on the Channels, so we can't
6080 // lock the Timers here and have to delete this timer later:
6081 timeshiftTimer = rc->Timer();
6082 rc->Stop(false); // don't execute user command
6084 bool Error = false;
6085 {
6087 Recordings->SetExplicitModify();
6088 if (cRecording *Recording = Recordings->GetByName(fileName)) {
6089 if (Recording->Delete()) {
6091 Recordings->Del(Recording, false);
6092 DeletedRecordings->Add(Recording);
6094 Recordings->SetModified();
6095 }
6096 else
6097 Error = true;
6098 }
6099 }
6100 if (Error)
6101 Skins.QueueMessage(mtError, tr("Error while deleting recording!"));
6102 return;
6103 }
6104 }
6105 }
6106 }
6108 cMenuRecordings::SetRecording(NULL); // make sure opening the Recordings menu navigates to the last replayed recording
6109}
6110
6112{
6113 cStateKey StateKey;
6114 marks.Lock(StateKey);
6115 while (cMark *m = marks.First())
6116 marks.Del(m);
6117 StateKey.Remove();
6119}
6120
6121void cReplayControl::SetRecording(const char *FileName)
6122{
6123 fileName = FileName;
6124}
6125
6127{
6128 return currentReplayControl ? *fileName : NULL;
6129}
6130
6132{
6134 if (!Recordings->GetByName(fileName))
6135 fileName = NULL;
6136 return fileName;
6137}
6138
6139void cReplayControl::ClearLastReplayed(const char *FileName)
6140{
6141 if (*fileName && FileName && strcmp(fileName, FileName) == 0)
6142 fileName = NULL;
6143}
6144
6146{
6147 if (modeOnly)
6148 Hide();
6149 if (!visible) {
6150 shown = ShowProgress(true);
6151 timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
6152 }
6153 else if (timeoutShow && Seconds > 0)
6154 timeoutShow = time(NULL) + Seconds;
6155}
6156
6158{
6159 ShowTimed();
6160}
6161
6163{
6164 if (visible) {
6165 delete displayReplay;
6166 displayReplay = NULL;
6167 SetNeedsFastResponse(false);
6168 visible = false;
6169 modeOnly = false;
6170 lastPlay = lastForward = false;
6171 lastSpeed = -2; // an invalid value
6172 timeSearchActive = false;
6173 timeoutShow = 0;
6174 }
6175 if (marksModified) {
6176 marks.Save();
6177 marksModified = false;
6178 }
6179}
6180
6182{
6184 bool Play, Forward;
6185 int Speed;
6186 if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
6187 bool NormalPlay = (Play && Speed == -1);
6188
6189 if (!visible) {
6190 if (NormalPlay)
6191 return; // no need to do indicate ">" unless there was a different mode displayed before
6192 visible = modeOnly = true;
6194 }
6195
6196 if (modeOnly && !timeoutShow && NormalPlay)
6197 timeoutShow = time(NULL) + MODETIMEOUT;
6199 lastPlay = Play;
6201 lastSpeed = Speed;
6202 }
6203 }
6204}
6205
6207{
6208 int Current, Total;
6209 if (!(Initial || updateTimer.TimedOut()))
6210 return visible;
6211 if (GetFrameNumber(Current, Total) && Total > 0) {
6212 if (!visible) {
6217 visible = true;
6218 }
6219 if (Initial) {
6220 if (*fileName) {
6222 if (const cRecording *Recording = Recordings->GetByName(fileName))
6223 displayReplay->SetRecording(Recording);
6224 }
6225 lastCurrent = lastTotal = -1;
6226 }
6227 const cErrors *Errors = GetErrors();
6228 int NumErrors = Errors ? Errors->Size() : 0;
6229 if (Current != lastCurrent || Total != lastTotal || NumErrors != lastErrors) {
6230 if (Setup.ShowRemainingTime || Total != lastTotal) {
6231 int Index = Total;
6233 Index = Current - Index;
6235 }
6236 displayReplay->SetProgress(Current, Total);
6238 displayReplay->SetErrors(Errors);
6240 lastCurrent = Current;
6241 lastTotal = Total;
6242 lastErrors = NumErrors;
6243 }
6244 ShowMode();
6246 return true;
6247 }
6248 return false;
6249}
6250
6252{
6253 char buf[64];
6254 // TRANSLATORS: note the trailing blank!
6255 strcpy(buf, tr("Jump: "));
6256 int len = strlen(buf);
6257 char h10 = '0' + (timeSearchTime >> 24);
6258 char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
6259 char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
6260 char m1 = '0' + (timeSearchTime & 0x000000FF);
6261 char ch10 = timeSearchPos > 3 ? h10 : '-';
6262 char ch1 = timeSearchPos > 2 ? h1 : '-';
6263 char cm10 = timeSearchPos > 1 ? m10 : '-';
6264 char cm1 = timeSearchPos > 0 ? m1 : '-';
6265 sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
6266 displayReplay->SetJump(buf);
6267}
6268
6270{
6271#define STAY_SECONDS_OFF_END 10
6272 int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
6273 int Current = int(round(lastCurrent / FramesPerSecond()));
6274 int Total = int(round(lastTotal / FramesPerSecond()));
6275 switch (Key) {
6276 case k0 ... k9:
6277 if (timeSearchPos < 4) {
6278 timeSearchTime <<= 8;
6279 timeSearchTime |= Key - k0;
6280 timeSearchPos++;
6282 }
6283 break;
6284 case kFastRew:
6285 case kLeft:
6286 case kFastFwd:
6287 case kRight: {
6288 int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
6289 if (dir > 0)
6290 Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
6291 SkipSeconds(Seconds * dir);
6292 timeSearchActive = false;
6293 }
6294 break;
6295 case kPlayPause:
6296 case kPlay:
6297 case kUp:
6298 case kPause:
6299 case kDown:
6300 case kOk:
6301 if (timeSearchPos > 0) {
6302 Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
6303 bool Still = Key == kDown || Key == kPause || Key == kOk;
6304 Goto(SecondsToFrames(Seconds, FramesPerSecond()), Still);
6305 }
6306 timeSearchActive = false;
6307 break;
6308 default:
6309 if (!(Key & k_Flags)) // ignore repeat/release keys
6310 timeSearchActive = false;
6311 break;
6312 }
6313
6314 if (!timeSearchActive) {
6315 if (timeSearchHide)
6316 Hide();
6317 else
6318 displayReplay->SetJump(NULL);
6319 ShowMode();
6320 }
6321}
6322
6324{
6326 timeSearchHide = false;
6327 if (modeOnly)
6328 Hide();
6329 if (!visible) {
6330 Show();
6331 if (visible)
6332 timeSearchHide = true;
6333 else
6334 return;
6335 }
6336 timeoutShow = 0;
6338 timeSearchActive = true;
6339}
6340
6342{
6343 int Current, Total;
6344 if (GetIndex(Current, Total, true)) {
6345 lastCurrent = -1; // triggers redisplay
6346 cStateKey StateKey;
6347 marks.Lock(StateKey);
6348 if (cMark *m = marks.Get(Current))
6349 marks.Del(m);
6350 else {
6351 marks.Add(Current);
6352 bool Play, Forward;
6353 int Speed;
6354 if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
6355 Goto(Current, true);
6356 displayFrames = true;
6357 }
6358 }
6359 StateKey.Remove();
6360 ShowTimed(2);
6361 marksModified = true;
6363 }
6364}
6365
6367{
6368 int Current, Total;
6369 if (GetIndex(Current, Total)) {
6370 if (marks.Count()) {
6371 if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
6372 if (!Setup.PauseOnMarkJump) {
6373 bool Playing, Fwd;
6374 int Speed;
6375 if (GetReplayMode(Playing, Fwd, Speed) && Playing && Forward && m->Position() < Total - SecondsToFrames(3, FramesPerSecond())) {
6376 Goto(m->Position());
6377 return;
6378 }
6379 }
6380 Goto(m->Position(), true);
6381 displayFrames = true;
6382 return;
6383 }
6384 }
6385 // There are either no marks at all, or we already were at the first or last one,
6386 // so jump to the very beginning or end:
6387 Goto(Forward ? Total : 0, true);
6388 }
6389}
6390
6391void cReplayControl::MarkMove(int Frames, bool MarkRequired)
6392{
6393 int Current, Total;
6394 if (GetIndex(Current, Total)) {
6395 bool Play, Forward;
6396 int Speed;
6397 GetReplayMode(Play, Forward, Speed);
6398 cMark *m = marks.Get(Current);
6399 if (!Play && m) {
6400 displayFrames = true;
6401 cMark *m2;
6402 if (Frames > 0) {
6403 // Handle marks at the same offset:
6404 while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
6405 m = m2;
6406 // Don't skip the next mark:
6407 if ((m2 = marks.Next(m)) != NULL)
6408 Frames = min(Frames, m2->Position() - m->Position() - 1);
6409 }
6410 else {
6411 // Handle marks at the same offset:
6412 while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
6413 m = m2;
6414 // Don't skip the next mark:
6415 if ((m2 = marks.Prev(m)) != NULL)
6416 Frames = -min(-Frames, m->Position() - m2->Position() - 1);
6417 }
6418 int p = SkipFrames(Frames);
6419 m->SetPosition(p);
6420 Goto(m->Position(), true);
6421 marksModified = true;
6423 }
6424 else if (!MarkRequired)
6425 Goto(SkipFrames(Frames), !Play);
6426 }
6427}
6428
6430{
6431 const cErrors *Errors = GetErrors();
6432 int NumErrors = Errors ? Errors->Size() : 0;
6433 if (NumErrors > 0) {
6434 int Current, Total;
6435 if (GetIndex(Current, Total)) {
6436 if (Forward) {
6437 int Offset = 0;
6438 for (int i = 0; i < NumErrors; i++) {
6439 int Position = Errors->At(i);
6440 if (Offset && Position == Current + Offset) {
6441 Goto(Position, true); // Position is exactly on the next I-frame
6442 return;
6443 }
6444 if (Position > Current + Offset) {
6445 int NextIFrame = SkipFrames(Position - Current) + Offset; // this takes us to the I-frame at or right after Position
6446 if (NextIFrame > Position) {
6447 if (SkipFrames(Offset + 1) == NextIFrame) { // means Current is the I-frame right before Position
6448 Offset = NextIFrame - Current;
6449 continue;
6450 }
6451 }
6452 Goto(Position, true); // this takes us to the I-frame at or right before Position
6453 return;
6454 }
6455 }
6456 if (Current < Total)
6457 Goto(Total, true);
6458 }
6459 else {
6460 for (int i = NumErrors - 1; i >= 0; i--) {
6461 if (Errors->At(i) < Current) {
6462 int Position = Errors->At(i);
6463 Goto(Position, true); // this takes us to the I-frame at or right before Position
6464 return;
6465 }
6466 }
6467 if (Current > 0)
6468 Goto(0, true);
6469 }
6470 }
6471 }
6472}
6473
6475{
6476 if (*fileName) {
6477 Hide();
6479 if (!marks.Count())
6480 Skins.QueueMessage(mtError, tr("No editing marks defined!"));
6481 else if (!marks.GetNumSequences())
6482 Skins.QueueMessage(mtError, tr("No editing sequences defined!"));
6483 else if (access(cCutter::EditedFileName(fileName), F_OK) == 0 && !Interface->Confirm(tr("Edited version already exists - overwrite?")))
6484 ;
6486 Skins.QueueMessage(mtError, tr("Not enough free disk space to start editing process!"));
6487 else if (!RecordingsHandler.Add(ruCut, fileName))
6488 Skins.QueueMessage(mtError, tr("Can't start editing process!"));
6489 else
6490 Skins.QueueMessage(mtInfo, tr("Editing process started"));
6491 }
6492 else
6493 Skins.QueueMessage(mtError, tr("Editing process already active!"));
6494 ShowMode();
6495 }
6496}
6497
6499{
6500 int Current, Total;
6501 if (GetIndex(Current, Total)) {
6502 cMark *m = marks.Get(Current);
6503 if (!m)
6504 m = marks.GetNext(Current);
6505 if (m) {
6506 if ((m->Index() & 0x01) != 0 && !Setup.SkipEdited) // when skipping edited parts we also need to jump to end marks
6507 m = marks.Next(m);
6508 if (m)
6510 }
6511 }
6512}
6513
6515{
6517 if (const cRecording *Recording = Recordings->GetByName(cReplayControl::LastReplayed()))
6518 return new cMenuRecording(Recording, false);
6519 return NULL;
6520}
6521
6523{
6525 if (const cRecording *Recording = Recordings->GetByName(LastReplayed()))
6526 return Recording;
6527 return NULL;
6528}
6529
6531{
6532 if (!Active())
6533 return osRecordings;
6534 if (Key == kNone && !marksModified)
6535 marks.Update();
6536 if (visible) {
6537 if (timeoutShow && time(NULL) > timeoutShow) {
6538 Hide();
6539 ShowMode();
6540 timeoutShow = 0;
6541 }
6542 else if (modeOnly)
6543 ShowMode();
6544 else
6546 }
6547 bool DisplayedFrames = displayFrames;
6548 displayFrames = false;
6549 if (timeSearchActive && Key != kNone) {
6550 TimeSearchProcess(Key);
6551 return osContinue;
6552 }
6553 if (Key == kPlayPause) {
6554 bool Play, Forward;
6555 int Speed;
6556 GetReplayMode(Play, Forward, Speed);
6557 if (Speed >= 0)
6558 Key = Play ? kPlay : kPause;
6559 else
6560 Key = Play ? kPause : kPlay;
6561 }
6562 bool DoShowMode = true;
6563 switch (int(Key)) {
6564 // Positioning:
6565 case kPlay:
6566 case kUp: Play(); break;
6567 case kPause:
6568 case kDown: Pause(); break;
6569 case kFastRew|k_Release:
6570 case kLeft|k_Release:
6571 if (Setup.MultiSpeedMode) break;
6572 case kFastRew:
6573 case kLeft: Backward(); break;
6574 case kFastFwd|k_Release:
6575 case kRight|k_Release:
6576 if (Setup.MultiSpeedMode) break;
6577 case kFastFwd:
6578 case kRight: Forward(); break;
6579 case kRed: TimeSearch(); break;
6580 case kGreen|k_Repeat:
6582 case kGreen: SkipSeconds(-Setup.SkipSeconds); break;
6583 case kYellow|k_Repeat:
6585 case kYellow: SkipSeconds(Setup.SkipSeconds); break;
6586 case kStop:
6587 case kBlue: Stop();
6588 return osEnd;
6589 default: {
6590 DoShowMode = false;
6591 switch (int(Key)) {
6592 // Editing:
6593 case kMarkToggle: MarkToggle(); break;
6594 case kPrev|k_Repeat:
6595 case kPrev: if (Setup.AdaptiveSkipPrevNext) {
6596 MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6597 break;
6598 }
6599 // fall through...
6601 case kMarkJumpBack: MarkJump(false); break;
6602 case kNext|k_Repeat:
6603 case kNext: if (Setup.AdaptiveSkipPrevNext) {
6604 MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6605 break;
6606 }
6607 // fall through...
6609 case kMarkJumpForward: MarkJump(true); break;
6611 case kMarkMoveBack: MarkMove(-1, true); break;
6613 case kMarkMoveForward: MarkMove(+1, true); break;
6615 case kMarkSkipBack: MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6617 case kMarkSkipForward: MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6618 case kChanUp|k_Repeat:
6619 case kChanUp: ErrorJump(true); break;
6620 case kChanDn|k_Repeat:
6621 case kChanDn: ErrorJump(false); break;
6622 case kEditCut: EditCut(); break;
6623 case kEditTest: EditTest(); break;
6624 default: {
6625 displayFrames = DisplayedFrames;
6626 switch (Key) {
6627 // Menu control:
6628 case kOk: if (visible && !modeOnly) {
6629 Hide();
6630 DoShowMode = true;
6631 }
6632 else
6633 Show();
6634 break;
6635 case kBack: Stop();
6636 return osRecordings;
6637 default: return osUnknown;
6638 }
6639 }
6640 }
6641 }
6642 }
6643 if (DoShowMode)
6644 ShowMode();
6645 return osContinue;
6646}
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:277
#define LOCK_CHANNELS_WRITE
Definition channels.h:278
cCamSlots CamSlots
Definition ci.c:2851
@ msReady
Definition ci.h:171
@ msPresent
Definition ci.h:171
@ msReset
Definition ci.h:171
double framesPerSecond
Definition menu.h:297
cTimeMs timeout
Definition menu.h:299
cAdaptiveSkipper(void)
Definition menu.c:5986
eKeys lastKey
Definition menu.h:298
void Initialize(int *InitialValue, double FramesPerSecond)
Definition menu.c:5994
int * initialValue
Definition menu.h:295
int currentValue
Definition menu.h:296
int GetValue(eKeys Key)
Definition menu.c:6001
Definition ci.h:233
bool Devices(cVector< int > &DeviceNumbers)
Adds the numbers of any devices that currently use this CAM to the given DeviceNumbers.
Definition ci.c:2275
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:2669
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition ci.h:311
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:2458
virtual bool EnterMenu(void)
Requests the CAM in this slot to start its menu.
Definition ci.c:2481
virtual cCiEnquiry * GetEnquiry(void)
Gets a pending enquiry, or NULL if there is no enquiry.
Definition ci.c:2501
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition ci.c:2444
virtual bool HasUserIO(void)
Returns true if there is a pending user interaction, which shall be retrieved via GetMenu() or GetEnq...
Definition ci.c:2475
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:2488
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition ci.h:334
virtual bool Reset(void)
Resets the CAM in this slot.
Definition ci.c:2388
virtual void StartActivation(void)
Puts the CAM in this slot into a mode where an inserted smart card can be activated.
Definition ci.c:2411
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition ci.c:2437
virtual bool HasMMI(void)
Returns 'true' if the CAM in this slot has an active MMI.
Definition ci.c:2470
virtual bool CanActivate(void)
Returns true if there is a CAM in this slot that can be put into activation mode.
Definition ci.c:2406
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:346
virtual void CancelActivation(void)
Cancels a previously started activation (if any).
Definition ci.c:2426
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:187
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:189
int dpids[MAXDPIDS+1]
Definition channels.h:109
const int * Caids(void) const
Definition channels.h:180
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:256
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:163
const char * Text(void)
Definition ci.h:161
bool Blind(void)
Definition ci.h:162
void Abort(void)
Definition ci.c:1723
void Reply(const char *s)
Definition ci.c:1711
Definition ci.h:120
void Abort(void)
Definition ci.c:1685
bool HasUpdate(void)
Definition ci.c:1667
const char * TitleText(void)
Definition ci.h:137
const char * BottomText(void)
Definition ci.h:139
int NumEntries(void)
Definition ci.h:141
void Cancel(void)
Definition ci.c:1680
bool Selectable(void)
Definition ci.h:142
const char * SubTitleText(void)
Definition ci.h:138
void Select(int Index)
Definition ci.c:1673
const char * Entry(int n)
Definition ci.h:140
tComponent * Component(int Index) const
Definition epg.h:65
int NumComponents(void) const
Definition epg.h:62
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition thread.c:73
static cControl * Control(cMutexLock &MutexLock, bool Hidden=false, bool *LockedOtherwise=NULL)
Returns the current replay control (if any) in case it is currently visible.
Definition player.c:75
double FramesPerSecond(void) const
Definition player.h:116
static void Shutdown(void)
Definition player.c:111
static void Attach(void)
Definition player.c:98
static void Launch(cControl *Control)
Definition player.c:91
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:722
void SetKeepTracks(bool KeepTracks)
Controls whether the current audio and subtitle track settings shall be kept as they currently are,...
Definition device.h:619
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition device.c:1230
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:802
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:229
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
eTrackType GetCurrentSubtitleTrack(void) const
Definition device.h:603
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:237
eTrackType GetCurrentAudioTrack(void) const
Definition device.h:599
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:847
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:168
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition device.c:1927
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:1499
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1096
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1284
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:1177
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:1102
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:515
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:538
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1123
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1317
static int CurrentVolume(void)
Definition device.h:654
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:1147
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition device.c:1212
cTimeMs lastTime
Definition menu.h:132
const cChannel * channel
Definition menu.h:137
const cEvent * lastPresent
Definition menu.h:138
void DisplayChannel(void)
Definition menu.c:5099
const cEvent * lastFollowing
Definition menu.h:139
bool timeout
Definition menu.h:134
cSkinDisplayChannel * displayChannel
Definition menu.h:129
bool withInfo
Definition menu.h:131
virtual ~cDisplayChannel() override
Definition menu.c:5092
void Refresh(void)
Definition menu.c:5126
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:5149
const cPositioner * positioner
Definition menu.h:136
static cDisplayChannel * currentDisplayChannel
Definition menu.h:140
void DisplayInfo(void)
Definition menu.c:5107
cDisplayChannel(int Number, bool Switched)
Definition menu.c:5045
const cChannel * NextAvailableChannel(const cChannel *Channel, int Direction)
Definition menu.c:5132
virtual void Show(void) override
Definition menu.c:5567
cSkinDisplayTracks * displayTracks
Definition menu.h:187
cDisplaySubtitleTracks(void)
Definition menu.c:5532
static void Process(eKeys Key)
Definition menu.c:5585
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:190
eTrackType types[ttMaxTrackTypes]
Definition menu.h:189
static cDisplaySubtitleTracks * currentDisplayTracks
Definition menu.h:192
static cDisplaySubtitleTracks * Create(void)
Definition menu.c:5574
virtual ~cDisplaySubtitleTracks() override
Definition menu.c:5558
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:5591
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:5473
char * descriptions[ttMaxTrackTypes+1]
Definition menu.h:172
static cDisplayTracks * Create(void)
Definition menu.c:5456
cDisplayTracks(void)
Definition menu.c:5412
cTimeMs timeout
Definition menu.h:170
static cDisplayTracks * currentDisplayTracks
Definition menu.h:174
virtual void Show(void) override
Definition menu.c:5446
cSkinDisplayTracks * displayTracks
Definition menu.h:169
int numTracks
Definition menu.h:173
int audioChannel
Definition menu.h:173
static void Process(eKeys Key)
Definition menu.c:5467
virtual ~cDisplayTracks() override
Definition menu.c:5437
eTrackType types[ttMaxTrackTypes]
Definition menu.h:171
static cDisplayVolume * Create(void)
Definition menu.c:5366
cSkinDisplayVolume * displayVolume
Definition menu.h:155
virtual void Show(void) override
Definition menu.c:5361
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:5379
cTimeMs timeout
Definition menu.h:156
static void Process(eKeys Key)
Definition menu.c:5373
cDisplayVolume(void)
Definition menu.c:5346
static cDisplayVolume * currentDisplayVolume
Definition menu.h:157
virtual ~cDisplayVolume() override
Definition menu.c:5355
void Append(const char *Title)
Definition recording.c:3513
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition dvbdevice.c:2052
void SetMarks(const cMarks *Marks)
Definition dvbplayer.c:1020
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition dvbplayer.c:1082
const cErrors * GetErrors(void)
Definition dvbplayer.c:1075
void SkipSeconds(int Seconds)
Definition dvbplayer.c:1062
cDvbPlayerControl(const char *FileName, bool PauseLive=false)
Definition dvbplayer.c:1008
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition dvbplayer.c:1100
void Pause(void)
Definition dvbplayer.c:1038
int SkipFrames(int Frames)
Definition dvbplayer.c:1068
void Goto(int Index, bool Still=false)
Definition dvbplayer.c:1105
void Stop(void)
Definition dvbplayer.c:1031
void Forward(void)
Definition dvbplayer.c:1050
bool Active(void)
Definition dvbplayer.c:1026
bool GetFrameNumber(int &Current, int &Total)
Definition dvbplayer.c:1091
void Play(void)
Definition dvbplayer.c:1044
void Backward(void)
Definition dvbplayer.c:1056
static void SetupChanged(void)
void ForceScan(void)
Definition eitscan.c:129
Definition epg.h:74
const char * ShortText(void) const
Definition epg.h:109
time_t EndTime(void) const
Definition epg.h:115
const char * Description(void) const
Definition epg.h:110
bool IsRunning(bool OrAboutToStart=false) const
Definition epg.c:283
time_t StartTime(void) const
Definition epg.h:114
tChannelID ChannelID(void) const
Definition epg.c:155
cString GetTimeString(void) const
Definition epg.c:442
const char * Title(void) const
Definition epg.h:108
const cSchedule * Schedule(void) const
Definition epg.h:102
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:2316
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2260
virtual void Move(int From, int To)
Definition tools.c:2276
void SetModified(void)
Unconditionally marks this list as modified.
Definition tools.c:2330
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:618
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:2219
int Count(void) const
Definition tools.h:646
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2228
void Sort(void)
Definition tools.c:2352
cListObject(const cListObject &ListObject)
Definition tools.h:553
cListObject * Prev(void) const
Definition tools.h:565
int Index(void) const
Definition tools.c:2148
cListObject * Next(void) const
Definition tools.h:566
Definition tools.h:650
const T * Prev(const T *Object) const
Definition tools.h:666
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:662
cList(const char *NeedsLocking=NULL)
Definition tools.h:652
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:669
const T * Last(void) const
Returns the last element in this list, or NULL if the list is empty.
Definition tools.h:664
const cOsdItem * Get(int Index) const
Definition tools.h:659
void SetPosition(int Position)
Definition recording.h:421
int Position(void) const
Definition recording.h:419
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
Definition recording.c:2622
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:2555
const cMark * GetNext(int Position) const
Definition recording.c:2579
bool Update(void)
Definition recording.c:2491
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition recording.c:2479
const cMark * Get(int Position) const
Definition recording.c:2561
static bool DeleteMarksFile(const cRecording *Recording)
Definition recording.c:2468
bool Save(void)
Definition recording.c:2522
const cMark * GetPrev(int Position) const
Definition recording.c:2570
cCamSlot * camSlot
Definition menu.c:2360
void Set(void)
Definition menu.c:2422
eOSState Select(void)
Definition menu.c:2477
char * input
Definition menu.c:2363
void AddMultiLineItem(const char *s)
Definition menu.c:2464
void GenerateTitle(const char *s=NULL)
Definition menu.c:2404
void QueryCam(void)
Definition menu.c:2409
virtual ~cMenuCam() override
Definition menu.c:2392
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:2501
cMenuCam(cCamSlot *CamSlot)
Definition menu.c:2377
time_t lastCamExchange
Definition menu.c:2365
cCiEnquiry * ciEnquiry
Definition menu.c:2362
cCiMenu * ciMenu
Definition menu.c:2361
int offset
Definition menu.c:2364
static eChannelSortMode sortMode
Definition menu.c:291
cMenuChannelItem(const cChannel *Channel)
Definition menu.c:306
const cChannel * Channel(void)
Definition menu.c:300
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:314
static void SetSortMode(eChannelSortMode SortMode)
Definition menu.c:295
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override
Definition menu.c:343
virtual void Set(void) override
Definition menu.c:327
static eChannelSortMode SortMode(void)
Definition menu.c:297
const cChannel * channel
Definition menu.c:292
static void IncSortMode(void)
Definition menu.c:296
cStateKey channelsStateKey
Definition menu.c:356
eOSState Number(eKeys Key)
Definition menu.c:432
cChannel * GetChannel(int Index)
Definition menu.c:417
void Set(bool Force=false)
Definition menu.c:387
int number
Definition menu.c:357
eOSState Delete(void)
Definition menu.c:488
void Propagate(cChannels *Channels)
Definition menu.c:423
eOSState New(void)
Definition menu.c:480
cMenuChannels(void)
Definition menu.c:375
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:565
virtual void Move(int From, int To) override
Definition menu.c:535
cTimeMs numberTimer
Definition menu.c:358
eOSState Edit(void)
Definition menu.c:469
~cMenuChannels()
Definition menu.c:383
eOSState Switch(void)
Definition menu.c:458
eOSState Execute(void)
Definition menu.c:2290
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:2337
cList< cNestedItem > * commands
Definition menu.h:59
virtual ~cMenuCommands() override
Definition menu.c:2262
bool confirm
Definition menu.h:63
cMenuCommands(const char *Title, cList< cNestedItem > *Commands, const char *Parameters=NULL)
Definition menu.c:2245
cString title
Definition menu.h:61
cString command
Definition menu.h:62
bool Parse(const char *s)
Definition menu.c:2267
char * result
Definition menu.h:64
cString parameters
Definition menu.h:60
cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString=NULL, const char *TrueString=NULL)
Definition menuitems.c:156
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString=NULL, const char *TrueString=NULL)
Definition menuitems.c:139
cMenuEditCaItem(const char *Name, int *Value)
Definition menu.c:66
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:82
virtual void Set(void) override
Definition menu.c:72
cMenuEditChanItem(const char *Name, int *Value, const char *NoneString=NULL)
Definition menuitems.c:839
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
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
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:240
void ToggleRepeating(void)
Definition menuitems.c:1006
void SetDate(time_t Time)
Definition menuitems.c:998
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition menuitems.c:960
cNestedItem * folder
Definition menu.c:704
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:761
cMenuEditFolder(const char *Dir, cList< cNestedItem > *List, cNestedItem *Folder=NULL)
Definition menu.c:713
char name[PATH_MAX]
Definition menu.c:705
eOSState Confirm(void)
Definition menu.c:738
cString GetFolder(void)
Definition menu.c:733
cList< cNestedItem > * list
Definition menu.c:703
cMenuEditIntItem(const char *Name, int *Value, int Min=0, int Max=INT_MAX, const char *MinString=NULL, const char *MaxString=NULL)
Definition menuitems.c:66
virtual void Set(void) override
Definition menuitems.c:81
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:94
cMenuEditIntxItem(const char *Name, int *Value, int Min=INT_MIN, int Max=INT_MAX, int Factor=1, const char *NegString=NULL, const char *PosString=NULL)
Definition menuitems.c:227
void SetValue(const char *Value)
Definition menuitems.c:37
cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind=false)
Definition menuitems.c:173
cMenuEditPrcItem(const char *Name, double *Value, double Min=0.0, double Max=1.0, int Decimals=0)
Definition menuitems.c:271
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:124
cMenuEditSrcItem(const char *Name, int *Value)
Definition menu.c:109
const cSource * source
Definition menu.c:101
virtual void Set(void) override
Definition menu.c:116
void SetKeepSpace(void)
Definition menuitems.h:141
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed=NULL)
Definition menuitems.c:384
void SetMacros(const char **Macros)
Definition menuitems.c:415
cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char *const *Strings)
Definition menuitems.c:805
cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
Definition menuitems.c:819
cMenuEditTimeItem(const char *Name, int *Value)
Definition menuitems.c:1101
void SetTime(time_t Time)
Definition menuitems.c:1121
bool addIfConfirmed
Definition menu.h:79
time_t oldStopTime
Definition menu.h:81
time_t oldStartTime
Definition menu.h:80
eOSState SetFolder(void)
Definition menu.c:1123
cMenuEditDateItem * firstday
Definition menu.h:87
static const cTimer * addedTimer
Definition menu.h:75
int channel
Definition menu.h:78
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:1154
cTimer data
Definition menu.h:77
void SetHelpKeys(void)
Definition menu.c:1075
cMenuEditStrItem * file
Definition menu.h:85
virtual ~cMenuEditTimer() override
Definition menu.c:1062
cMenuEditTimeItem * stop
Definition menu.h:89
cMenuEditStrItem * pattern
Definition menu.h:84
cMenuEditDateItem * day
Definition menu.h:86
static const cTimer * AddedTimer(void)
Definition menu.c:1068
cTimer * timer
Definition menu.h:76
cMenuEditTimer(cTimer *Timer, bool New=false)
Definition menu.c:1017
cMenuEditTimeItem * start
Definition menu.h:88
void SetFirstDayItem(void)
Definition menu.c:1080
char remote[HOST_NAME_MAX]
Definition menu.h:83
cStringList svdrpServerNames
Definition menu.h:82
void SetPatternItem(bool Initial=false)
Definition menu.c:1093
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition menuitems.c:905
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:1571
const cEvent * event
Definition menu.h:103
virtual void Display(void) override
Definition menu.c:1562
cMenuEvent(const cTimers *Timers, const cChannels *Channels, const cEvent *Event, bool CanSwitch=false, bool Buttons=false)
Definition menu.c:1545
cMenuFolderItem(cNestedItem *Folder)
Definition menu.c:684
cNestedItem * Folder(void)
Definition menu.c:681
cNestedItem * folder
Definition menu.c:677
virtual void Set(void) override
Definition menu.c:691
cMenuFolder(const char *Title, cList< cNestedItem > *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path=NULL)
Definition menu.c:794
eOSState Delete(void)
Definition menu.c:922
int helpKeys
Definition menu.h:41
eOSState New(void)
Definition menu.c:916
cNestedItemList * nestedItemList
Definition menu.h:36
cList< cNestedItem > * list
Definition menu.h:37
eOSState SetFolder(void)
Definition menu.c:950
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:974
cString dir
Definition menu.h:38
void Set(const char *CurrentFolder=NULL)
Definition menu.c:858
void DescendPath(const char *Path)
Definition menu.c:883
cOsdItem * firstFolder
Definition menu.h:39
eOSState Edit(void)
Definition menu.c:938
eOSState Select(bool Open)
Definition menu.c:900
bool editing
Definition menu.h:40
cString GetFolder(void)
Definition menu.c:961
void SetHelpKeys(void)
Definition menu.c:810
cOsdItem * cancelEditingItem
Definition menu.h:115
cOsdItem * stopRecordingItem
Definition menu.h:116
void Set(void)
Definition menu.c:4787
int recordControlsState
Definition menu.h:117
bool replaying
Definition menu.h:112
cOsdItem * stopReplayItem
Definition menu.h:114
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4899
cOsdItem * deletedRecordingsItem
Definition menu.h:113
bool Update(bool Force=false)
Definition menu.c:4824
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition menu.c:4744
static cOsdObject * pluginOsdObject
Definition menu.h:118
static cOsdObject * PluginOsdObject(void)
Definition menu.c:4780
eOSState ApplyChanges(void)
Definition menu.c:2643
int pathIsInUse
Definition menu.c:2568
cString oldFolder
Definition menu.c:2564
eOSState Folder(void)
Definition menu.c:2638
cMenuEditStrItem * folderItem
Definition menu.c:2567
eOSState SetFolder(void)
Definition menu.c:2628
cString path
Definition menu.c:2563
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:2678
cMenuPathEdit(const char *Path)
Definition menu.c:2577
char name[NAME_MAX]
Definition menu.c:2566
char folder[PATH_MAX]
Definition menu.c:2565
cMenuPluginItem(const char *Name, int Index)
Definition menu.c:4731
int PluginIndex(void)
Definition menu.c:4728
int pluginIndex
Definition menu.c:4725
bool RefreshRecording(void)
Definition menu.c:2800
cMenuEditStrItem * nameItem
Definition menu.c:2710
const char * actionCancel
Definition menu.c:2714
cString originalFileName
Definition menu.c:2702
eOSState ApplyChanges(void)
Definition menu.c:2885
eOSState Action(void)
Definition menu.c:2830
cMenuEditStrItem * folderItem
Definition menu.c:2709
eOSState SetFolder(void)
Definition menu.c:2815
void Set(void)
Definition menu.c:2753
char name[NAME_MAX]
Definition menu.c:2705
const char * buttonAction
Definition menu.c:2712
cStateKey recordingsStateKey
Definition menu.c:2703
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:2940
const char * doCut
Definition menu.c:2715
eOSState RemoveName(void)
Definition menu.c:2848
void SetHelpKeys(void)
Definition menu.c:2778
cMenuRecordingEdit(const cRecording *Recording)
Definition menu.c:2731
const char * buttonFolder
Definition menu.c:2711
const char * buttonDeleteMarks
Definition menu.c:2713
eOSState DeleteMarks(void)
Definition menu.c:2866
const cRecording * recording
Definition menu.c:2701
eOSState Folder(void)
Definition menu.c:2825
char folder[PATH_MAX]
Definition menu.c:2704
const cRecording * recording
Definition menu.c:3084
int Level(void) const
Definition menu.c:3094
const cRecording * Recording(void) const
Definition menu.c:3096
const char * Name(void) const
Definition menu.c:3093
int Usage(void)
Definition menu.c:3095
void IncrementCounter(bool New)
Definition menu.c:3125
bool IsDirectory(void) const
Definition menu.c:3097
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override
Definition menu.c:3139
void Update(cSkinDisplayMenu *DisplayMenu, int Index, bool Current)
Definition menu.c:3133
void SetRecording(const cRecording *Recording)
Definition menu.c:3098
cMenuRecordingItem(const cRecording *Recording, int Level)
Definition menu.c:3103
const cRecording * recording
Definition menu.c:2966
bool withButtons
Definition menu.c:2969
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:3031
bool RefreshRecording(void)
Definition menu.c:3004
cString originalFileName
Definition menu.c:2967
cStateKey recordingsStateKey
Definition menu.c:2968
virtual void Display(void) override
Definition menu.c:3019
cMenuRecording(const cRecording *Recording, bool WithButtons=false)
Definition menu.c:2977
cMenuRecordings(const char *Base=NULL, int Level=0, bool OpenSubMenus=false, const cRecordingFilter *Filter=NULL, bool DelRecMenu=false)
Definition menu.c:3152
bool delRecMenu
Definition menu.h:222
void SetDeleted(const char *FileName)
Definition menu.c:3309
void Set(bool Refresh=false)
Definition menu.c:3221
bool Open(bool OpenSubMenus=false)
Definition menu.c:3330
static cString deletedName
Definition menu.h:226
eOSState Purge(void)
Definition menu.c:3531
eOSState Sort(void)
Definition menu.c:3591
static void SetRecording(const char *FileName)
Definition menu.c:3314
eOSState Info(void)
Definition menu.c:3561
eOSState Play(void)
Definition menu.c:3359
const cRecordingFilter * filter
Definition menu.h:224
static cString fileName
Definition menu.h:225
char * base
Definition menu.h:217
eOSState Rewind(void)
Definition menu.c:3373
cStateKey recordingsStateKey
Definition menu.h:219
eOSState AdjustTitle(eOSState State, bool Redisplay=true)
Definition menu.c:3346
eOSState Restore(void)
Definition menu.c:3495
int recordingsHandlerState
Definition menu.h:220
eOSState Commands(eKeys Key=kNone)
Definition menu.c:3576
cString DirectoryName(void)
Definition menu.c:3319
bool autoRefresh
Definition menu.h:223
static time_t toggleDelRec
Definition menu.h:227
void SetHelpKeys(void)
Definition menu.c:3190
eOSState Delete(void)
Definition menu.c:3441
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:3603
static void SetSortMode(eScheduleSortMode SortMode)
Definition menu.c:1617
const cChannel * channel
Definition menu.c:1611
cMenuScheduleItem(const cTimers *Timers, const cEvent *Event, const cChannel *Channel=NULL, bool WithDate=false)
Definition menu.c:1627
const cTimer * timer
Definition menu.c:1612
const cEvent * event
Definition menu.c:1610
static void IncSortMode(void)
Definition menu.c:1618
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:1638
bool Update(const cTimers *Timers, bool Force=false)
Definition menu.c:1651
static eScheduleSortMode sortMode
Definition menu.c:1608
static eScheduleSortMode SortMode(void)
Definition menu.c:1619
eTimerMatch timerMatch
Definition menu.c:1614
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override
Definition menu.c:1681
virtual ~cMenuSchedule() override
Definition menu.c:1942
bool PrepareScheduleAllAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:2042
bool canSwitch
Definition menu.c:1909
bool PrepareScheduleAllThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:1983
void SetHelpKeys(void)
Definition menu.c:2074
int helpKeys
Definition menu.c:1910
cStateKey timersStateKey
Definition menu.c:1905
bool next
Definition menu.c:1908
void Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel=NULL, bool Force=false)
Definition menu.c:1947
bool Update(void)
Definition menu.c:2061
eOSState Record(void)
Definition menu.c:2108
cMenuSchedule(void)
Definition menu.c:1927
cStateKey schedulesStateKey
Definition menu.c:1906
eOSState Number(void)
Definition menu.c:2099
int scheduleState
Definition menu.c:1907
eOSState Switch(void)
Definition menu.c:2146
bool PrepareScheduleThisThis(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:2002
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:2163
bool PrepareScheduleThisAll(const cTimers *Timers, const cSchedules *Schedules, const cEvent *Event, const cChannel *Channel)
Definition menu.c:2022
cMenuSetupBase(void)
Definition menu.c:3700
cSetup data
Definition menu.c:3694
virtual void Store(void) override
Definition menu.c:3705
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition menu.c:4219
bool Changed(void)
Definition menu.c:4226
cCamSlot * camSlot
Definition menu.c:4212
cCamSlot * CamSlot(void)
Definition menu.c:4215
void SetHelpKeys(void)
Definition menu.c:4290
cMenuSetupCAM(void)
Definition menu.c:4275
eOSState Menu(void)
Definition menu.c:4309
eOSState Reset(void)
Definition menu.c:4373
eOSState Activate(void)
Definition menu.c:4336
const char * activationHelp
Definition menu.c:4265
int currentChannel
Definition menu.c:4264
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4385
const char * updateChannelsTexts[6]
Definition menu.c:3988
int numAudioLanguages
Definition menu.c:3983
cMenuSetupDVB(void)
Definition menu.c:3996
int originalNumSubtitleLanguages
Definition menu.c:3984
void Setup(void)
Definition menu.c:4026
int numSubtitleLanguages
Definition menu.c:3985
const char * standardComplianceTexts[3]
Definition menu.c:3990
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4055
int originalNumAudioLanguages
Definition menu.c:3982
const char * videoDisplayFormatTexts[3]
Definition menu.c:3987
const char * displaySubtitlesTexts[3]
Definition menu.c:3989
int originalNumLanguages
Definition menu.c:3888
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:3931
int numLanguages
Definition menu.c:3889
void Setup(void)
Definition menu.c:3907
cMenuSetupEPG(void)
Definition menu.c:3896
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4189
cSatCableNumbers satCableNumbers
Definition menu.c:4134
cMenuSetupLNB(void)
Definition menu.c:4141
void Setup(void)
Definition menu.c:4150
void Set(void)
Definition menu.c:4516
cMenuSetupMisc(void)
Definition menu.c:4503
const char * svdrpPeeringModeTexts[3]
Definition menu.c:4494
cStringList svdrpServerNames
Definition menu.c:4496
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4551
const char * showChannelNamesWithSourceTexts[3]
Definition menu.c:4495
virtual void Set(void)
Definition menu.c:3763
cStringList fontSmlNames
Definition menu.c:3728
cStringList fontOsdNames
Definition menu.c:3728
const char * recSortDirTexts[2]
Definition menu.c:3718
const char * useSmallFontTexts[3]
Definition menu.c:3716
int numSkins
Definition menu.c:3721
cStringList fontFixNames
Definition menu.c:3728
const char * recSortModeTexts[2]
Definition menu.c:3717
int fontOsdIndex
Definition menu.c:3729
const char * keyColorTexts[4]
Definition menu.c:3719
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:3819
int skinIndex
Definition menu.c:3723
int originalSkinIndex
Definition menu.c:3722
int originalThemeIndex
Definition menu.c:3726
int fontFixIndex
Definition menu.c:3729
const char ** skinDescriptions
Definition menu.c:3724
cThemes themes
Definition menu.c:3725
int themeIndex
Definition menu.c:3727
virtual ~cMenuSetupOSD() override
Definition menu.c:3758
int fontSmlIndex
Definition menu.c:3729
cMenuSetupOSD(void)
Definition menu.c:3737
int osdLanguageIndex
Definition menu.c:3720
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:1287
cMenuSetupPage(void)
Definition menuitems.c:1250
void SetSection(const char *Section)
Definition menuitems.c:1257
virtual void Display(void) override
Definition menuitems.c:1262
void SetPlugin(cPlugin *Plugin)
Definition menuitems.c:1302
cMenuSetupPluginItem(const char *Name, int Index)
Definition menu.c:4591
int PluginIndex(void)
Definition menu.c:4588
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4619
cMenuSetupPlugins(void)
Definition menu.c:4605
const char * pauseKeyHandlingTexts[3]
Definition menu.c:4413
const char * recordKeyHandlingTexts[3]
Definition menu.c:4412
cMenuSetupRecord(void)
Definition menu.c:4419
const char * delTimeshiftRecTexts[3]
Definition menu.c:4414
virtual void Store(void) override
Definition menu.c:4481
cMenuSetupReplay(void)
Definition menu.c:4460
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:4695
virtual void Set(void)
Definition menu.c:4666
cMenuSetup(void)
Definition menu.c:4659
eOSState Restart(void)
Definition menu.c:4686
eDvbFont font
Definition menu.h:25
void SetText(const char *Text)
Definition menu.c:631
cMenuText(const char *Title, const char *Text, eDvbFont Font=fontOsd)
Definition menu.c:617
virtual void Display(void) override
Definition menu.c:637
char * text
Definition menu.h:24
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:645
virtual ~cMenuText() override
Definition menu.c:626
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable) override
Definition menu.c:1327
virtual void Set(void) override
Definition menu.c:1281
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition menu.c:1276
cMenuTimerItem(const cTimer *Timer)
Definition menu.c:1270
const cTimer * timer
Definition menu.c:1261
const cTimer * Timer(void)
Definition menu.c:1266
eOSState New(void)
Definition menu.c:1452
cMenuTimers(void)
Definition menu.c:1355
void Set(void)
Definition menu.c:1369
void SetHelpKeys(void)
Definition menu.c:1400
eOSState Info(void)
Definition menu.c:1492
eOSState Edit(void)
Definition menu.c:1445
cTimer * GetTimer(void)
Definition menu.c:1394
cStateKey timersStateKey
Definition menu.c:1338
bool showAllTimers
Definition menu.c:1340
eOSState Delete(void)
Definition menu.c:1462
int helpKeys
Definition menu.c:1339
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:1505
eOSState OnOff(void)
Definition menu.c:1415
virtual ~cMenuTimers() override
Definition menu.c:1365
void SetHelpKeys(const cChannels *Channels)
Definition menu.c:1749
static const cEvent * scheduleEvent
Definition menu.c:1701
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:1840
static const cEvent * ScheduleEvent(void)
Definition menu.c:1777
eOSState Record(void)
Definition menu.c:1801
cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr)
Definition menu.c:1715
static void SetCurrentChannel(int ChannelNr)
Definition menu.c:1707
cStateKey timersStateKey
Definition menu.c:1697
static int CurrentChannel(void)
Definition menu.c:1706
eOSState Switch(void)
Definition menu.c:1784
bool canSwitch
Definition menu.c:1695
bool Update(void)
Definition menu.c:1736
static int currentChannel
Definition menu.c:1700
bool now
Definition menu.c:1694
int helpKeys
Definition menu.c:1696
bool Save(void)
Definition config.c:259
void SetText(const char *Text)
Definition config.c:157
void SetSubItems(bool On)
Definition config.c:163
cNestedItem(const char *Text, bool WithSubItems=false)
Definition config.c:132
cList< cNestedItem > * SubItems(void)
Definition config.h:210
const char * Text(void) const
Definition config.h:209
const char * Text(void) const
Definition osdbase.h:75
void SetSelectable(bool Selectable)
Definition osdbase.c:48
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:63
eOSState state
Definition osdbase.h:63
bool Selectable(void) const
Definition osdbase.h:71
void SetText(const char *Text, bool Copy=true)
Definition osdbase.c:42
cOsdItem(eOSState State=osUnknown)
Definition osdbase.c:20
void Ins(cOsdItem *Item, bool Current=false, cOsdItem *Before=NULL)
Definition osdbase.c:234
virtual eOSState ProcessKey(eKeys Key) override
Definition osdbase.c:581
eOSState CloseSubMenu(bool ReDisplay=true)
Definition osdbase.c:569
void SetTitle(const char *Title)
Definition osdbase.c:187
void DisplayCurrent(bool Current)
Definition osdbase.c:326
int Current(void) const
Definition osdbase.h:160
const char * hk(const char *s)
Definition osdbase.c:149
void Mark(void)
Definition osdbase.c:533
cOsdMenu * SubMenu(void)
Definition osdbase.h:149
void DisplayItem(cOsdItem *Item)
Definition osdbase.c:348
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition osdbase.c:559
virtual void Clear(void) override
Definition osdbase.c:366
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition osdbase.c:227
void SetHasHotkeys(bool HasHotkeys=true)
Definition osdbase.c:173
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Sets the column widths to the given values, which are the number of characters in each column.
Definition osdbase.c:164
void SetCurrent(cOsdItem *Item)
Definition osdbase.c:311
cOsdMenu(const char *Title, int c0=0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:83
void SetMenuCategory(eMenuCategory MenuCategory)
Definition osdbase.c:125
void RefreshCurrent(void)
Definition osdbase.c:319
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition osdbase.c:203
cSkinDisplayMenu * DisplayMenu(void)
Definition osdbase.h:124
virtual void Display(void)
Definition osdbase.c:248
bool HasSubMenu(void)
Definition osdbase.h:148
int VisibleItem(int Idx)
Returns the index in the menu if the item is currently visible, -1 otherwise.
Definition osdbase.c:377
virtual void Del(int Index)
Definition osdbase.c:213
const char * Title(void)
Definition osdbase.h:133
void SetMenuSortMode(eMenuSortMode MenuSortMode)
Definition osdbase.c:130
int current
Definition osdbase.h:106
void SetNeedsFastResponse(bool NeedsFastResponse)
Definition osdbase.h:87
cOsdObject(bool FastResponse=false)
Definition osdbase.h:89
bool IsMenu(void) const
Definition osdbase.h:92
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2365
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:2338
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.c:1975
int Close(void)
Definition thread.c:1038
bool Open(const char *Command, const char *Mode)
Definition thread.c:984
static bool HasPlugins(void)
Definition plugin.c:459
static cPlugin * CallFirstService(const char *Id, void *Data=NULL)
Definition plugin.c:482
static cPlugin * GetPlugin(int Index)
Definition plugin.c:464
virtual cMenuSetupPage * SetupMenu(void)
Definition plugin.c:101
virtual const char * Version(void)=0
const char * Name(void)
Definition plugin.h:36
virtual const char * MainMenuEntry(void)
Definition plugin.c:91
virtual cOsdObject * MainMenuAction(void)
Definition plugin.c:96
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:84
virtual ~cRecordControl()
Definition menu.c:5714
const char * InstantId(void)
Definition menu.h:265
void Stop(bool ExecuteUserCommand=true)
Definition menu.c:5746
cDevice * device
Definition menu.h:252
cTimer * timer
Definition menu.h:253
bool GetEvent(void)
Definition menu.c:5722
char * fileName
Definition menu.h:257
cTimer * Timer(void)
Definition menu.h:267
cRecorder * recorder
Definition menu.h:254
cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer=NULL, bool Pause=false)
Definition menu.c:5632
cDevice * Device(void)
Definition menu.h:263
const cEvent * event
Definition menu.h:255
bool Process(time_t t)
Definition menu.c:5769
cString instantId
Definition menu.h:256
static bool StateChanged(int &State)
Definition menu.c:5976
static const char * GetInstantId(const char *LastInstantId)
Definition menu.c:5895
static void ChannelDataModified(const cChannel *Channel)
Definition menu.c:5943
static bool Process(cTimers *Timers, time_t t)
Definition menu.c:5928
static bool PauseLiveVideo(void)
Definition menu.c:5880
static void Shutdown(void)
Definition menu.c:5969
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition menu.c:5784
static cRecordControl * RecordControls[]
Definition menu.h:5781
static bool Active(void)
Definition menu.c:5960
static void Stop(const char *InstantId)
Definition menu.c:5846
static cRecordControl * GetRecordControl(const char *FileName)
Definition menu.c:5908
static int state
Definition menu.h:273
static void ChangeState(void)
Definition menu.h:289
cRecorder(const char *FileName, const cChannel *Channel, int Priority)
Creates a new recorder for the given Channel and the given Priority that will record into the file Fi...
Definition recorder.c:24
int Errors(void)
Definition recorder.h:58
void Stop(void)
Stops the recorder.
Definition recorder.c:88
virtual bool Filter(const cRecording *Recording) const =0
Returns true if the given Recording shall be displayed in the Recordings menu.
int ParentalRating(void)
Definition recording.h:105
void SetParentalRating(int ParentalRating)
Definition recording.c:529
const char * Description(void) const
Definition recording.h:99
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition recording.c:2675
bool ChangePriorityLifetime(int NewPriority, int NewLifetime)
Changes the priority and lifetime of this recording to the given values.
Definition recording.c:1398
bool HasMarks(void) const
Returns true if this recording has any editing marks.
Definition recording.c:1355
bool WriteInfo(const char *OtherFileName=NULL)
Writes the info file of this recording.
Definition recording.c:1370
int IsInUse(void) const
Checks whether this recording is currently in use and therefore shall not be tampered with.
Definition recording.c:1531
bool ChangeName(const char *NewName)
Changes the name of this recording to the given value.
Definition recording.c:1422
bool Delete(void)
Changes the file name (both internally and on disk) to make this a "deleted" recording.
Definition recording.c:1451
cString Folder(void) const
Returns the name of the folder this recording is stored in (without the video directory).
Definition recording.c:1225
void DeleteResume(void) const
Definition recording.c:1553
const char * Name(void) const
Returns the full name of the recording (without the video directory).
Definition recording.h:179
int Lifetime(void) const
Definition recording.h:165
const char * FileName(void) const
Returns the full path name to the recording directory, including the video directory and the actual '...
Definition recording.c:1237
cRecordingInfo * Info(void) const
Definition recording.h:186
cString BaseName(void) const
Returns the base name of this recording (without the video directory and folder).
Definition recording.c:1232
int Priority(void) const
Definition recording.h:164
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition recording.c:1255
double FramesPerSecond(void) const
Definition recording.h:191
bool IsPesRecording(void) const
Definition recording.h:215
time_t Deleted(void) const
Definition recording.h:166
void DelAll(void)
Deletes/terminates all operations.
Definition recording.c:2363
bool StateChanged(int &OldState)
Returns true if the state if this recordings handler has changed since the last call with the given O...
Definition recording.c:2399
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:2322
int GetUsage(const char *FileName)
Returns the usage type for the given FileName.
Definition recording.c:2372
void Del(const char *FileName)
Deletes the given FileName from the list of operations.
Definition recording.c:2354
static const cRecordings * GetRecordingsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for read access.
Definition recording.h:285
static const cRecordings * GetDeletedRecordingsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of deleted recordings for read access.
Definition recording.h:291
static cRecordings * GetDeletedRecordingsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of deleted recordings for write access.
Definition recording.h:294
static cRecordings * GetRecordingsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for write access.
Definition recording.h:288
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:1767
void Add(cRecording *Recording)
Definition recording.c:1815
const cRecording * GetByName(const char *FileName) const
Definition recording.c:1804
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition remote.c:130
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:210
static void SetRecording(const char *FileName)
Definition menu.c:6121
static const char * LastReplayed(void)
Definition menu.c:6131
void MarkToggle(void)
Definition menu.c:6341
virtual void Show(void) override
Definition menu.c:6157
static cString fileName
Definition menu.h:327
void TimeSearchDisplay(void)
Definition menu.c:6251
static void ClearLastReplayed(const char *FileName)
Definition menu.c:6139
int lastTotal
Definition menu.h:315
virtual eOSState ProcessKey(eKeys Key) override
Definition menu.c:6530
void MarkMove(int Frames, bool MarkRequired)
Definition menu.c:6391
static cReplayControl * currentReplayControl
Definition menu.h:326
bool timeSearchHide
Definition menu.h:320
virtual const cRecording * GetRecording(void) override
Returns the cRecording that is currently being replayed, or NULL if this player is not playing a cRec...
Definition menu.c:6522
void TimeSearchProcess(eKeys Key)
Definition menu.c:6269
void MarkJump(bool Forward)
Definition menu.c:6366
cMarks marks
Definition menu.h:311
void EditCut(void)
Definition menu.c:6474
int timeSearchTime
Definition menu.h:321
cSkinDisplayReplay * displayReplay
Definition menu.h:309
void Stop(void)
Definition menu.c:6070
void ShowTimed(int Seconds=0)
Definition menu.c:6145
static cTimer * timeshiftTimer
Definition menu.h:308
bool lastForward
Definition menu.h:316
virtual cOsdObject * GetInfo(void) override
Returns an OSD object that displays information about the currently played programme.
Definition menu.c:6514
bool displayFrames
Definition menu.h:313
bool shown
Definition menu.h:313
virtual void Hide(void) override
Definition menu.c:6162
time_t timeoutShow
Definition menu.h:318
void EditTest(void)
Definition menu.c:6498
bool timeSearchActive
Definition menu.h:320
bool ShowProgress(bool Initial)
Definition menu.c:6206
static void DelTimeshiftTimer(void)
Definition menu.c:6058
bool marksModified
Definition menu.h:312
int lastSpeed
Definition menu.h:317
cAdaptiveSkipper adaptiveSkipper
Definition menu.h:310
bool lastPlay
Definition menu.h:316
int timeSearchPos
Definition menu.h:321
virtual void ClearEditingMarks(void) override
Clears any editing marks this player might be showing.
Definition menu.c:6111
int lastErrors
Definition menu.h:314
virtual ~cReplayControl() override
Definition menu.c:6050
void ShowMode(void)
Definition menu.c:6181
void ErrorJump(bool Forward)
Definition menu.c:6429
cTimeMs updateTimer
Definition menu.h:319
void TimeSearch(void)
Definition menu.c:6323
bool visible
Definition menu.h:313
bool modeOnly
Definition menu.h:313
static const char * NowReplaying(void)
Definition menu.c:6126
cReplayControl(bool PauseLive=false)
Definition menu.c:6026
int lastCurrent
Definition menu.h:315
bool FromString(const char *s)
Definition config.c:82
int * Array(void)
Definition config.h:107
cString ToString(void)
Definition config.c:108
bool HasTimer(void) const
Definition epg.h:185
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition epg.c:1396
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition epg.c:1291
static void ResetVersions(void)
Definition epg.c:1322
int DefaultLifetime
Definition config.h:317
int VolumeSteps
Definition config.h:377
int EmergencyExit
Definition config.h:384
int SplitEditedFiles
Definition config.h:356
int RcRepeatDelay
Definition config.h:314
int ColorKey3
Definition config.h:330
int MenuScrollPage
Definition config.h:276
int EPGBugfixLevel
Definition config.h:306
int ColorKey2
Definition config.h:330
int VideoDisplayFormat
Definition config.h:331
int SubtitleFgTransparency
Definition config.h:301
int MinUserInactivity
Definition config.h:358
int AntiAlias
Definition config.h:345
int ShowInfoOnChSwitch
Definition config.h:274
int DeleteRetention
Definition config.h:316
int SkipSecondsRepeat
Definition config.h:373
int StandardCompliance
Definition config.h:295
char SVDRPDefaultHost[HOST_NAME_MAX]
Definition config.h:311
bool Save(void)
Definition config.c:742
int TimeoutRequChInfo
Definition config.h:275
int ResumeID
Definition config.h:374
char OSDTheme[MaxThemeName]
Definition config.h:272
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:299
int SVDRPTimeout
Definition config.h:308
int LnbSLOF
Definition config.h:282
int EPGLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:302
char OSDSkin[MaxSkinName]
Definition config.h:271
int UsePositioner
Definition config.h:286
int AlwaysSortFoldersFirst
Definition config.h:326
int AdaptiveSkipInitial
Definition config.h:368
int RecSortingDirection
Definition config.h:328
int VpsMargin
Definition config.h:323
char OSDLanguage[I18N_MAX_LOCALE_LEN]
Definition config.h:270
int ShowChannelNamesWithSource
Definition config.h:382
int DefaultPriority
Definition config.h:317
int ZapTimeout
Definition config.h:312
double OSDWidthP
Definition config.h:340
int RecordKeyHandling
Definition config.h:318
int PauseKeyHandling
Definition config.h:319
double OSDHeightP
Definition config.h:340
int PositionerSpeed
Definition config.h:289
int MarginStart
Definition config.h:296
double FontOsdSizeP
Definition config.h:349
int PauseAtLastMark
Definition config.h:367
int AdaptiveSkipPrevNext
Definition config.h:371
int LnbFrequLo
Definition config.h:283
int EPGPauseAfterScan
Definition config.h:304
int OpenRecMenuAtLastReplayed
Definition config.h:383
int UseSmallFont
Definition config.h:344
int SubtitleOffset
Definition config.h:300
int MarginStop
Definition config.h:296
int SVDRPPeering
Definition config.h:309
int ProgressDisplayTime
Definition config.h:363
int UpdateChannels
Definition config.h:333
int SkipSeconds
Definition config.h:372
int SubtitleBgTransparency
Definition config.h:301
int ColorKey0
Definition config.h:330
int FoldersInTimerMenu
Definition config.h:325
int MenuScrollWrap
Definition config.h:277
int EPGLinger
Definition config.h:307
int ShowReplayMode
Definition config.h:361
int SiteLon
Definition config.h:288
int AdaptiveSkipAlternate
Definition config.h:370
int UseVps
Definition config.h:322
int DisplaySubtitles
Definition config.h:298
int ChannelInfoTime
Definition config.h:339
int SiteLat
Definition config.h:287
int VolumeLinearize
Definition config.h:378
int ChannelsWrap
Definition config.h:381
int EPGScanMaxChannel
Definition config.h:303
double FontFixSizeP
Definition config.h:351
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:297
int OSDMessageTime
Definition config.h:343
int MarkInstantRecord
Definition config.h:279
double OSDLeftP
Definition config.h:340
int RecordingDirs
Definition config.h:324
int PausePriority
Definition config.h:320
double FontSmlSizeP
Definition config.h:350
int AdaptiveSkipTimeout
Definition config.h:369
int MenuKeyCloses
Definition config.h:278
int DiSEqC
Definition config.h:285
char NameInstantRecord[NAME_MAX+1]
Definition config.h:280
char FontOsd[MAXFONTNAME]
Definition config.h:346
int UseSubtitle
Definition config.h:321
int MinEventTimeout
Definition config.h:358
int ChannelInfoPos
Definition config.h:338
int LnbFrequHi
Definition config.h:284
char FontSml[MAXFONTNAME]
Definition config.h:347
int MultiSpeedMode
Definition config.h:360
int EPGScanTimeout
Definition config.h:305
int TimeTransponder
Definition config.h:294
int VideoFormat
Definition config.h:332
int MaxVideoFileSize
Definition config.h:355
cString DeviceBondings
Definition config.h:387
int PositionerSwing
Definition config.h:290
double OSDTopP
Definition config.h:340
int PauseOnMarkSet
Definition config.h:364
int DelTimeshiftRec
Definition config.h:357
int SetSystemTime
Definition config.h:292
int PrimaryDVB
Definition config.h:273
int ChannelEntryTimeout
Definition config.h:313
char FontFix[MAXFONTNAME]
Definition config.h:348
int TimeSource
Definition config.h:293
int PauseOnMarkJump
Definition config.h:365
int ColorKey1
Definition config.h:330
int ShowRemainingTime
Definition config.h:362
int CurrentDolby
Definition config.h:379
cString InitialChannel
Definition config.h:386
int DefaultSortModeRec
Definition config.h:327
char SVDRPHostName[HOST_NAME_MAX]
Definition config.h:310
int RcRepeatDelta
Definition config.h:315
int InstantRecordTime
Definition config.h:281
int NumberKeysForChars
Definition config.h:329
int SkipEdited
Definition config.h:366
int PauseLifetime
Definition config.h:320
int InitialVolume
Definition config.h:380
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition shutdown.c:104
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition shutdown.c:219
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:270
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:111
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:239
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:261
virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable)
Sets the item at the given Index to Timer.
Definition skins.h:254
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:234
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:229
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition skins.c:224
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:405
cTheme * Theme(void)
Definition skins.h:425
const char * Name(void)
Definition skins.h:424
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:269
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:288
cSkin * Current(void)
Returns a pointer to the current skin.
Definition skins.h:471
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:334
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:904
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:899
static void MsgMarksModified(const cMarks *Marks)
Definition status.c:63
static void MsgOsdChannel(const char *Text)
Definition status.c:135
static void MsgSetAudioChannel(int AudioChannel)
Definition status.c:81
static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
Definition status.c:141
static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On)
Definition status.c:57
static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On)
Definition status.c:51
static void MsgOsdClear(void)
Definition status.c:93
static void MsgSetAudioTrack(int Index, const char *const *Tracks)
Definition status.c:75
static void MsgOsdTextItem(const char *Text, bool Scroll=false)
Definition status.c:129
static void MsgSetSubtitleTrack(int Index, const char *const *Tracks)
Definition status.c:87
void Sort(bool IgnoreCase=false)
Definition tools.h:866
int Find(const char *s) const
Definition tools.c:1679
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:1236
cString(const char *S=NULL, bool TakePointer=false)
Definition tools.c:1138
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1242
const char * Description(void)
Returns a user visible, single line description of this theme.
Definition themes.c:62
bool Load(const char *FileName, bool OnlyDescriptions=false)
Loads the theme data from the given file.
Definition themes.c:70
int NumThemes(void)
Definition themes.h:73
int GetThemeIndex(const char *Description)
Definition themes.c:245
const char * Name(int Index)
Definition themes.h:74
bool Load(const char *SkinName)
Definition themes.c:209
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:355
uint64_t Elapsed(void) const
Returns the number of milliseconds that have elapsed since the last call to Set().
Definition tools.c:855
void Set(int Ms=0)
Sets the timer.
Definition tools.c:842
bool TimedOut(void) const
Returns true if the number of milliseconds given in the last call to Set() have passed.
Definition tools.c:850
int Stop(void) const
Definition timers.h:74
void OnOff(void)
Definition timers.c:1148
const char * File(void) const
Definition timers.h:78
cString PrintFirstDay(void) const
Definition timers.c:436
bool CalcNewStartStopTime(bool ToVps, time_t &NewStartTime, time_t &NewStopTime) const
Calculates new start and stop time of this timer, when switching VPS control on/off.
Definition timers.c:1166
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:46
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
Definition timers.h:47
bool IsSingleEvent(void) const
Definition timers.c:513
void SetPending(bool Pending)
Definition timers.c:1060
cTimer(bool Instant=false, bool Pause=false, const cChannel *Channel=NULL)
Definition timers.c:28
time_t StopTime(void) const
The stop time of this timer, which is the time as given by the user (for normal timers) or the end ti...
Definition timers.c:836
time_t FirstDay(void) const
Definition timers.h:79
bool Recording(void) const
Definition timers.h:66
int priority
Definition timers.h:50
char file[NAME_MAX *2+1]
Definition timers.h:53
void SetFlags(uint Flags)
Definition timers.c:1120
int Start(void) const
Definition timers.h:73
int start
the start and stop time of this timer as given by the user,
Definition timers.h:48
void SetDeferred(int Seconds)
Definition timers.c:1114
bool IsPatternTimer(void) const
Definition timers.h:98
const char * Pattern(void) const
Definition timers.h:77
int WeekDays(void) const
Definition timers.h:72
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition timers.c:402
void TriggerRespawn(void)
Definition timers.c:967
time_t Day(void) const
Definition timers.h:71
void SetRemote(const char *Remote)
Definition timers.c:1108
char * remote
Definition timers.h:55
bool SetEvent(const cEvent *Event)
Definition timers.c:1031
const cChannel * channel
Definition timers.h:45
int stop
in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm
Definition timers.h:49
bool Local(void) const
Definition timers.h:82
const cEvent * Event(void) const
Definition timers.h:87
time_t StartTime(void) const
The start time of this timer, which is the time as given by the user (for normal timers) or the start...
Definition timers.c:828
const cChannel * Channel(void) const
Definition timers.h:70
bool Pending(void) const
Definition timers.h:67
cString ToDescr(void) const
Definition timers.c:333
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition timers.c:297
bool SetEventFromSchedule(const cSchedules *Schedules)
Definition timers.c:981
int Priority(void) const
Definition timers.h:75
void SetRecording(bool Recording)
Definition timers.c:1051
bool Matches(void) const
Definition timers.h:111
char pattern[NAME_MAX *2+1]
Definition timers.h:52
static int GetMDay(time_t t)
Definition timers.c:518
bool HasFlags(uint Flags) const
Definition timers.c:1135
const char * Remote(void) const
Definition timers.h:81
int lifetime
Definition timers.h:51
int Id(void) const
Definition timers.h:65
uint flags
Definition timers.h:44
cString ToText(bool UseChannelID=false) const
Definition timers.c:323
void Add(cTimer *Timer, cTimer *After=NULL)
Definition timers.c:1328
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition timers.c:1323
void Del(cTimer *Timer, bool DeleteObject=true)
Definition timers.c:1342
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition timers.c:1318
const cTimer * GetMatch(time_t t) const
Definition timers.c:1244
int Size(void) const
Definition tools.h:773
void Sort(__compar_fn_t Compare)
Definition tools.h:834
virtual void Insert(T Data, int Before=0)
Definition tools.h:775
virtual void Append(T Data)
Definition tools.h:794
T & At(int Index) const
Definition tools.h:750
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:276
cSetup Setup
Definition config.c:373
cNestedItemList Folders
Definition config.c:275
cNestedItemList RecordingCommands
Definition config.c:277
#define SUBTITLES_NO
Definition config.h:82
#define TIMERMACRO_MATCH
Definition config.h:53
#define TIMERMACRO_AFTER
Definition config.h:54
#define MAXLIFETIME
Definition config.h:46
#define MAXPRIORITY
Definition config.h:41
#define VDRVERSION
Definition config.h:25
#define TIMERMACRO_BEFORE
Definition config.h:52
#define TIMERMACRO_EPISODE
Definition config.h:51
#define SUBTITLES_REWIND
Definition config.h:84
#define TIMERMACRO_TITLE
Definition config.h:50
#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 MAXPARENTALRATING
Definition epg.h:22
#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:280
const cStringList * I18nLanguages(void)
Returns the list of available languages.
Definition i18n.c:263
int I18nNumLanguagesWithLocale(void)
Returns the number of entries in the list returned by I18nLanguages() that actually have a locale.
Definition i18n.c:258
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition i18n.c:245
void I18nSetLocale(const char *Locale)
Sets the current locale to Locale.
Definition i18n.c:231
void I18nSetLanguage(int Language)
Sets the current language index to Language.
Definition i18n.c:250
#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:1649
static const char * TimerFileMacrosForPattern[]
Definition menu.c:998
#define NEWTIMERLIMIT
Definition menu.c:38
#define osUserRecRenamed
Definition menu.c:2556
#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:1138
static void AddRecordingFolders(const cRecordings *Recordings, cList< cNestedItem > *List, char *Path)
Definition menu.c:824
#define CAMMENURETRYTIMEOUT
Definition menu.c:46
#define osUserRecEmpty
Definition menu.c:2559
cOsdObject * CamControl(void)
Definition menu.c:2540
bool CamMenuActive(void)
Definition menu.c:2549
#define STAY_SECONDS_OFF_END
#define osUserRecMoved
Definition menu.c:2557
#define MUTETIMEOUT
Definition menu.c:5342
void SetTrackDescriptions(int LiveChannel)
Definition menu.c:5018
#define MODETIMEOUT
Definition menu.c:37
#define TRACKTIMEOUT
Definition menu.c:5408
static bool CamMenuIsOpen
Definition menu.c:2356
#define CHANNELNUMBERTIMEOUT
Definition menu.c:352
static void SetTracksFromComponents(const cComponents *Components, bool Live)
Definition menu.c:4994
static const char * TimerFileMacros[]
Definition menu.c:1008
#define INSTANT_REC_EPG_LOOKAHEAD
Definition menu.c:5720
#define FOLDERDELIMCHARSUBST
Definition menu.c:823
#define CHNAMWIDTH
Definition menu.c:54
#define CHNUMWIDTH
Definition menu.c:53
#define osUserRecRemoved
Definition menu.c:2558
#define MAXWAITFORCAMMENU
Definition menu.c:45
#define VOLUMETIMEOUT
Definition menu.c:5341
#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:3386
static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer=NULL)
Definition menu.c:1144
#define MAXWAIT4EPGINFO
Definition menu.c:36
#define STOP_RECORDING
Definition menu.c:4740
void SetTrackDescriptions(int LiveChannel)
Definition menu.c:5018
eOSState
Definition osdbase.h:18
@ osUser5
Definition osdbase.h:42
@ osRecordings
Definition osdbase.h:23
@ osCancelEdit
Definition osdbase.h:34
@ osPause
Definition osdbase.h:29
@ osPlugin
Definition osdbase.h:26
@ osChannels
Definition osdbase.h:21
@ osStopReplay
Definition osdbase.h:33
@ osUser1
Definition osdbase.h:38
@ osUser8
Definition osdbase.h:45
@ osUser10
Definition osdbase.h:47
@ osRecord
Definition osdbase.h:30
@ osEnd
Definition osdbase.h:36
@ osSetup
Definition osdbase.h:27
@ osUser4
Definition osdbase.h:41
@ osStopRecord
Definition osdbase.h:32
@ osContinue
Definition osdbase.h:19
@ osUser6
Definition osdbase.h:43
@ osTimers
Definition osdbase.h:22
@ osReplay
Definition osdbase.h:31
@ osUser3
Definition osdbase.h:40
@ osRecsOpen
Definition osdbase.h:24
@ osUser2
Definition osdbase.h:39
@ osRecsDel
Definition osdbase.h:25
@ osUnknown
Definition osdbase.h:18
@ osUser9
Definition osdbase.h:46
@ osSchedule
Definition osdbase.h:20
@ osCommands
Definition osdbase.h:28
@ osBack
Definition osdbase.h:35
@ osUser7
Definition osdbase.h:44
cString GetRecordingTimerId(const char *Directory)
Definition recording.c:3664
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition recording.c:3559
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:3616
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition recording.c:3586
eRecordingsSortMode RecordingsSortMode
Definition recording.c:3609
bool EnoughFreeDiskSpaceForEdit(const char *FileName)
Definition recording.c:3709
char * ExchangeChars(char *s, bool ToFileSystem)
Definition recording.c:757
void IncRecordingsSortMode(const char *Directory)
Definition recording.c:3635
cDoneRecordings DoneRecordingsPattern
Definition recording.c:3466
cRecordingsHandler RecordingsHandler
Definition recording.c:2268
void SetRecordingTimerId(const char *Directory, const char *TimerId)
Definition recording.c:3646
@ 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:484
@ rsmName
Definition recording.h:621
#define RUC_AFTERRECORDING
Definition recording.h:486
#define LOCK_RECORDINGS_READ
Definition recording.h:352
#define MAXVIDEOFILESIZETS
Definition recording.h:511
#define LOCK_DELETEDRECORDINGS_WRITE
Definition recording.h:355
#define FOLDERDELIMCHAR
Definition recording.h:22
#define LOCK_DELETEDRECORDINGS_READ
Definition recording.h:354
#define LOCK_RECORDINGS_WRITE
Definition recording.h:353
#define MINVIDEOFILESIZE
Definition recording.h:513
cShutdownHandler ShutdownHandler
Definition shutdown.c:27
cSkins Skins
Definition skins.c:257
@ mcSetupMisc
Definition skins.h:129
@ mcSetupOsd
Definition skins.h:122
@ mcSetupLnb
Definition skins.h:125
@ mcMain
Definition skins.h:107
@ mcSetup
Definition skins.h:121
@ mcChannel
Definition skins.h:111
@ mcRecordingInfo
Definition skins.h:117
@ mcSetupDvb
Definition skins.h:124
@ mcSetupRecord
Definition skins.h:127
@ mcCam
Definition skins.h:135
@ mcSetupReplay
Definition skins.h:128
@ mcRecordingDel
Definition skins.h:116
@ mcChannelEdit
Definition skins.h:112
@ mcCommand
Definition skins.h:131
@ mcEvent
Definition skins.h:132
@ mcSetupCam
Definition skins.h:126
@ mcSchedule
Definition skins.h:108
@ mcText
Definition skins.h:133
@ mcRecording
Definition skins.h:115
@ mcRecordingEdit
Definition skins.h:118
@ mcTimerEdit
Definition skins.h:114
@ mcScheduleNow
Definition skins.h:109
@ mcSetupPlugins
Definition skins.h:130
@ mcFolder
Definition skins.h:134
@ mcSetupEpg
Definition skins.h:123
@ 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:143
@ msmTime
Definition skins.h:142
@ msmName
Definition skins.h:141
@ msmNumber
Definition skins.h:140
cSourceParams SourceParams
cSources Sources
Definition sources.c:114
char language[MAXLANGCODE2]
Definition epg.h:48
uchar stream
Definition epg.h:46
uchar type
Definition epg.h:47
char * description
Definition epg.h:49
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:2879
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:2890
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:2899
void StartSVDRPHandler(void)
Definition svdrp.c:2863
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:1532
#define LOCK_TIMERS_READ
Definition timers.h:277
#define LOCK_TIMERS_WRITE
Definition timers.h:278
@ 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:111
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:962
bool isempty(const char *s)
Definition tools.c:387
char * strreplace(char *s, char c1, char c2)
Definition tools.c:139
cString strescape(const char *s, const char *chars)
Definition tools.c:310
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition tools.c:542
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition tools.c:1265
cString Indent(int n, const char *s)
Returns the given string s, preceeded with n blanks for indentation.
Definition tools.c:440
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:937
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:128
cString itoa(int n)
Definition tools.c:485
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
#define SECSINDAY
Definition tools.h:42
#define dsyslog(a...)
Definition tools.h:37
int CompareInts(const void *a, const void *b)
Definition tools.h:840
#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