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