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