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