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