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