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 
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  }
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));
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 
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 
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 
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 }
cDisplaySubtitleTracks(void)
Definition: menu.c:4715
void Setup(void)
Definition: menu.c:384
void ShowTimed(int Seconds=0)
Definition: menu.c:5263
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
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition: recording.c:1061
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
int AntiAlias
Definition: config.h:322
void SetModified(void)
Definition: timers.c:768
Definition: epg.h:71
bool now
Definition: menu.c:1433
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 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
Definition: skins.h:121
eOSState ProcessKey(eKeys Key)
Definition: menu.c:4562
const char * buttonDeleteMarks
Definition: menu.c:2322
T * First(void) const
Definition: tools.h:492
void DisplayItem(cOsdItem *Item)
Definition: osdbase.c:305
cList< cNestedItem > * commands
Definition: menu.h:59
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.
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 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
const char * Provider(void) const
Definition: channels.h:147
time_t StartTime(void) const
Definition: epg.h:106
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
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
int stop
Definition: timers.h:39
double FontOsdSizeP
Definition: config.h:326
bool shown
Definition: menu.h:292
int NumComponents(void) const
Definition: epg.h:59
const char * Description(void) const
Definition: recording.h:87
Definition: keys.h:43
char description[32]
Definition: device.h:90
cMenuEditStrItem * folderItem
Definition: menu.c:2318
virtual void SetVolume(int Current, int Total, bool Mute)=0
< This class implements the volume/mute display.
cString BaseName(void) const
Returns the base name of this recording (without the video directory and folder). ...
Definition: recording.c:1036
static void Shutdown(void)
Definition: menu.c:5118
cChannel * channel
Definition: menu.c:163
cDevice * Device(void)
Definition: menu.h:245
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
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
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 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
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
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
bool HasFlags(uint Flags) const
Definition: timers.c:664
const char * FileName(void) const
Returns the full path name to the recording directory, including the video directory and the actual &#39;...
Definition: recording.c:1043
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
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
Definition: timers.c:400
uint64_t Elapsed(void) const
Definition: tools.c:748
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
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
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
const char * Name(void) const
Returns the full name of the recording (without the video directory.
Definition: recording.h:142
virtual cOsdObject * MainMenuAction(void)
Definition: plugin.c:95
cString ToDescr(void) const
Definition: timers.c:179
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
cString command
Definition: menu.h:62
Definition: plugin.h:20
cMenuChannels(void)
Definition: menu.c:370
Definition: keys.h:17
cTimer * GetMatch(time_t t)
Definition: timers.c:716
eOSState Delete(void)
Definition: menu.c:475
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
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:261
int Priority(void) const
Definition: timers.h:61
int Index(void) const
Definition: tools.c:1989
Definition: ci.h:77
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
static const cEvent * scheduleEvent
Definition: menu.c:1440
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
Definition: keys.h:27
void SetSubItems(bool On)
Definition: config.c:162
const cComponents * Components(void) const
Definition: recording.h:88
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
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1182
int EPGLinger
Definition: config.h:294
const cPositioner * positioner
Definition: menu.h:125
cString Folder(void) const
Returns the name of the folder this recording is stored in (without the video directory).
Definition: recording.c:1029
const cRecordingInfo * Info(void) const
Definition: recording.h:149
void SetDisplayMenu(void)
Definition: osdbase.c:124
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 &#39;M&#39; 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
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
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
T min(T a, T b)
Definition: tools.h:54
int Ca(int Index=0) const
Definition: channels.h:173
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
eTrackType GetCurrentAudioTrack(void) const
Definition: device.h:535
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4090
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: device.c:675
#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 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 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
int Start(void) const
Definition: timers.h:59
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
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
cString PrintFirstDay(void) const
Definition: timers.c:282
#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&#39;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 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
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
eOSState
Definition: osdbase.h:18
virtual void SetMarks(const cMarks *Marks)
Sets the editing marks to Marks, which shall be used to display the progress bar through a cProgressB...
Definition: skins.c:196
cOsdItem * firstFolder
Definition: menu.h:39
int 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
cTimer * GetTimer(cTimer *Timer)
Definition: timers.c:704
void SetHasHotkeys(bool HasHotkeys=true)
Definition: osdbase.c:157
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
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 * 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
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:1392
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
time_t FirstDay(void) const
Definition: timers.h:64
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
int Code(void) const
Definition: sources.h:34
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
int Lifetime(void) const
Definition: recording.h:130
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
eOSState Activate(void)
Definition: menu.c:3616
double OSDLeftP
Definition: config.h:317
cListObject * Prev(void) const
Definition: tools.h:467
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
int Size(void) const
Definition: tools.h:551
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
const char * Text(void) const
Definition: config.h:197
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
cDevice * device
Definition: menu.h:234
void Backward(void)
Definition: dvbplayer.c:981
T * Next(const T *object) const
Definition: tools.h:495
~cMenuChannels()
Definition: menu.c:379
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
bool GroupSep(void) const
Definition: channels.h:181
static int GetMDay(time_t t)
Definition: timers.c:351
int lifetime
Definition: timers.h:41
int SVDRPTimeout
Definition: config.h:295
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
Definition: keys.h:18
void Sort(void)
Definition: tools.c:2115
static void SetCurrentChannel(int ChannelNr)
Definition: menu.c:1446
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
int WeekDays(void) const
Definition: timers.h:58
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 char * ShortText(void) const
Definition: epg.h:101
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
T * Last(void) const
Definition: tools.h:493
virtual cMenuSetupPage * SetupMenu(void)
Definition: plugin.c:100
virtual ~cDisplayChannel()
Definition: menu.c:4284
int FoldersInTimerMenu
Definition: config.h:307
const cEvent * GetPresentEvent(void) const
Definition: epg.c:921
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
cSourceParam * Get(char Source) const
Definition: sourceparams.c:36
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
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:130
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
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition: epg.c:1328
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
int Find(const char *s) const
Definition: tools.c:1484
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 cChannel * Channel(void) const
Definition: timers.h:56
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
#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
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:831
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 &#39;c&#39; 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 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
bool IsPesRecording(void) const
Definition: recording.h:167
int MaxVideoFileSize
Definition: config.h:332
#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
tChannelID ChannelID(void) const
Definition: epg.c:147
const cEvent * GetEventAround(time_t Time) const
Definition: epg.c:961
static cDisplaySubtitleTracks * currentDisplayTracks
Definition: menu.h:181
cNestedItemList Folders
Definition: config.c:274
cOsdItem * Get(int Index) const
Definition: tools.h:491
cTimer * timer
Definition: menu.h:75
const char * Name(void) const
Definition: channels.c:122
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
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
int Vpid(void) const
Definition: channels.h:154
const char * Name(int Index)
Definition: themes.h:74
const cComponents * Components(void) const
Definition: epg.h:103
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
int ExpectedLength(void)
Definition: ci.h:68
void TimeSearchProcess(eKeys Key)
Definition: menu.c:5383
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
const char * Title(void) const
Definition: epg.h:100
#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
#define ICON_CLOCK
Definition: iconpatch.h:33
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 &#39;c&#39; in &#39;s&#39;.
Definition: tools.c:189
time_t StopTime(void) const
Definition: timers.c:504
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 DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:197
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
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
const cEvent * Event(void) const
Definition: timers.h:69
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 &#39;true&#39; 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
bool Recording(void) const
Definition: timers.h:52
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
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
bool Selectable(void) const
Definition: osdbase.h:60
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
int Priority(void) const
Definition: recording.h:129
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
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
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
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition: device.c:1284
int PauseOnMarkSet
Definition: config.h:341
int UpdateChannels
Definition: config.h:313
const char * pauseKeyHandlingTexts[3]
Definition: menu.c:3690
const char * Description(void) const
Definition: sources.h:44
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
cListObject * Next(void) const
Definition: tools.h:468
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
int NumEntries(void)
Definition: ci.h:46
void IncRecordingsSortMode(const char *Directory)
Definition: recording.c:3048
int DelTimeshiftRec
Definition: config.h:334
int TimeoutRequChInfo
Definition: config.h:264
static void SetPath(const char *Path)
Definition: menu.c:2782
bool Pending(void) const
Definition: timers.h:53
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
T * Prev(const T *object) const
Definition: tools.h:494
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
bool IsSingleEvent(void) const
Definition: timers.c:346
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
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
cString GetTimeString(void) const
Definition: epg.c:414
void SetKeepTracks(bool KeepTracks)
Controls whether the current audio and subtitle track settings shall be kept as they currently are...
Definition: device.h:553
const cEvent * GetFollowingEvent(void) const
Definition: epg.c:936
eOSState Delete(void)
Definition: menu.c:2847
double FramesPerSecond(void) const
Definition: recording.h:153
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 IsInUse(void) const
Checks whether this recording is currently in use and therefore shall not be tampered with...
Definition: recording.c:1318
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
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition: recording.c:2061
bool SwitchTo(int Number)
Definition: channels.c:988
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
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
bool IsMenu(void) const
Definition: osdbase.h:81
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
bool HasTimer(void) const
Definition: channels.c:170
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
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
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
const cList< cEvent > * Events(void) const
Definition: epg.h:171
tComponent * Component(int Index) const
Definition: epg.h:62
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&#39;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 * ShortName(bool OrName=false) const
Definition: channels.c:132
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
int Position(void) const
Definition: recording.h:344
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
int Stop(void) const
Definition: timers.h:60
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
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
int Current(void) const
Definition: osdbase.h:138
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
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.
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
int Count(void) const
Definition: tools.h:485
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
bool Replaying(void) const
Returns true if we are currently replaying.
Definition: device.c:1279
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
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:183
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 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
time_t StartTime(void) const
Definition: timers.c:497
int Number(void) const
Definition: channels.h:179
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 * Text(void) const
Definition: osdbase.h:64
const char * TitleText(void)
Definition: ci.h:42
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:175
const char * File(void) const
Definition: timers.h:63
uint16_t id
Definition: device.h:88
Definition: skins.h:118
static eScheduleSortMode sortMode
Definition: menu.c:1355
bool TimedOut(void) const
Definition: tools.c:743
const char * Description(void) const
Definition: epg.h:102
eTrackType GetCurrentSubtitleTrack(void) const
Definition: device.h:539
static bool Start(cTimer *Timer=NULL, bool Pause=false)
Definition: menu.c:4961
int DiSEqC
Definition: config.h:274