vdr  2.6.9
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.14 2024/06/25 19:00:06 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)) != NULL) {
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("Not enough free disk space to start editing process!"));
2792  else if (!RecordingsHandler.Add(ruCut, recording->FileName()))
2793  Skins.Message(mtError, tr("Error while queueing recording for cutting!"));
2794  }
2795  }
2796  else if (doCopy) {
2797  if (!*name)
2798  *name = ' '; // name must not be empty!
2799  cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2800  NewName.CompactChars(FOLDERDELIMCHAR);
2801  if (strcmp(NewName, recording->Name())) {
2802  cString FromName = cString(ExchangeChars(strdup(recording->Name()), true), true);
2803  cString ToName = cString(ExchangeChars(strdup(*NewName), true), true);
2804  cString FileName = cString(strreplace(strdup(recording->FileName()), *FromName, *ToName), true);
2805  if (access(*FileName, F_OK) != 0 || Interface->Confirm(tr("Edited version already exists - overwrite?"))) {
2806  if (MakeDirs(FileName, true) && !RecordingsHandler.Add(ruCopy, recording->FileName(), FileName))
2807  Skins.Message(mtError, tr("Error while queueing recording for copying!"));
2808  else {
2810  Recordings->AddByName(FileName);
2811  }
2812  }
2813  }
2814  }
2816  RefreshRecording();
2817  SetHelpKeys();
2818  return osContinue;
2819 }
2820 
2822 {
2823  if (Get(Current()) == nameItem) {
2824  if (Interface->Confirm(tr("Rename recording to folder name?"))) {
2825  char *s = strrchr(folder, FOLDERDELIMCHAR);
2826  if (s)
2827  *s++ = 0;
2828  else
2829  s = folder;
2830  strn0cpy(name, s, sizeof(name));
2831  if (s == folder)
2832  *s = 0;
2833  Set();
2834  }
2835  }
2836  return osContinue;
2837 }
2838 
2840 {
2841  if (extraAction) {
2842  if (buttonDelete && Interface->Confirm(tr("Delete resume for this recording?"))) {
2844  ResumeFile.Delete();
2845  SetHelpKeys();
2846  }
2847  }
2848  else {
2849  if (buttonDelete && Interface->Confirm(tr("Delete editing marks for this recording?"))) {
2851  SetHelpKeys();
2852  cMutexLock ControlMutexLock;
2853  if (cControl *Control = cControl::Control(ControlMutexLock, true)) {
2854  if (const cRecording *Recording = Control->GetRecording()) {
2855  if (strcmp(recording->FileName(), Recording->FileName()) == 0)
2856  Control->ClearEditingMarks();
2857  }
2858  }
2859  }
2860  else
2861  Skins.Message(mtError, tr("Error while deleting editing marks!"));
2862  }
2863  }
2864  return osContinue;
2865 }
2866 
2868 {
2869  cStateKey StateKey;
2870  cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
2871  cRecording *Recording = Recordings->GetByName(recording->FileName());
2872  if (!Recording) {
2873  StateKey.Remove(false);
2874  Skins.Message(mtWarning, tr("Recording vanished!"));
2875  return osBack;
2876  }
2877  bool Modified = false;
2878  if (priority != recording->Priority() || lifetime != recording->Lifetime()) {
2879  if (!Recording->ChangePriorityLifetime(priority, lifetime)) {
2880  StateKey.Remove(Modified);
2881  Skins.Message(mtError, tr("Error while changing priority/lifetime!"));
2882  return osContinue;
2883  }
2884  Modified = true;
2885  }
2886  if (!*name) {
2887  *name = ' '; // name must not be empty!
2888  name[1] = 0;
2889  }
2890  cString OldFolder = Recording->Folder();
2891  cString NewName = *folder ? cString::sprintf("%s%c%s", folder, FOLDERDELIMCHAR, name) : name;
2892  NewName.CompactChars(FOLDERDELIMCHAR);
2893  if (strcmp(NewName, Recording->Name())) {
2894  if (!Recording->ChangeName(NewName)) {
2895  StateKey.Remove(Modified);
2896  Skins.Message(mtError, tr("Error while changing folder/name!"));
2897  return osContinue;
2898  }
2899  Modified = true;
2900  }
2901  if (Modified) {
2902  eOSState state = osUserRecRenamed;
2903  if (strcmp(Recording->Folder(), OldFolder))
2904  state = osUserRecMoved;
2905  Recordings->TouchUpdate();
2906  StateKey.Remove(Modified);
2907  return state;
2908  }
2909  StateKey.Remove(Modified);
2910  return osBack;
2911 }
2912 
2914 {
2915  if (!HasSubMenu()) {
2916  if (!RefreshRecording())
2917  return osBack; // the recording has vanished, so close this menu
2918  }
2919  eOSState state = cOsdMenu::ProcessKey(Key);
2920  if (state == osUnknown) {
2921  switch (Key) {
2922  case k0: return RemoveName();
2923  case kRed: return buttonFolder ? Folder() : osContinue;
2924  case kGreen: return buttonAction ? Action() : osContinue;
2925  case kYellow: return buttonDelete ? Delete() : osContinue;
2926  case kBlue: extraAction = !extraAction; SetHelpKeys(); return osContinue;
2927  case kOk: return !recordingIsInUse ? ApplyChanges() : osBack;
2928  default: break;
2929  }
2930  }
2931  else if (state == osEnd && HasSubMenu())
2932  state = SetFolder();
2933  return state;
2934 }
2935 
2936 // --- cMenuRecording --------------------------------------------------------
2937 
2938 class cMenuRecording : public cOsdMenu {
2939 private:
2944  bool RefreshRecording(void);
2945 public:
2946  cMenuRecording(const cRecording *Recording, bool WithButtons = false);
2947  virtual void Display(void);
2948  virtual eOSState ProcessKey(eKeys Key);
2949 };
2950 
2951 cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
2952 :cOsdMenu(tr("Recording info"))
2953 {
2955  if (cRecordings::GetRecordingsRead(recordingsStateKey)) // initializes recordingsStateKey, so we don't call Display() unnecessarily
2957  recording = Recording;
2959  withButtons = WithButtons;
2960  if (withButtons)
2961  SetHelp(tr("Button$Play"), tr("Button$Rewind"), NULL, tr("Button$Edit"));
2962 }
2963 
2965 {
2967  if ((recording = Recordings->GetByName(originalFileName)) != NULL)
2968  Display();
2969  else {
2971  Skins.Message(mtWarning, tr("Recording vanished!"));
2972  return false;
2973  }
2975  }
2976  return true;
2977 }
2978 
2980 {
2981  if (HasSubMenu()) {
2982  SubMenu()->Display();
2983  return;
2984  }
2987  if (recording->Info()->Description())
2989 }
2990 
2992 {
2993  if (HasSubMenu())
2994  return cOsdMenu::ProcessKey(Key);
2995  else if (!RefreshRecording())
2996  return osBack; // the recording has vanished, so close this menu
2997  switch (int(Key)) {
2998  case kUp|k_Repeat:
2999  case kUp:
3000  case kDown|k_Repeat:
3001  case kDown:
3002  case kLeft|k_Repeat:
3003  case kLeft:
3004  case kRight|k_Repeat:
3005  case kRight:
3006  DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
3007  cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
3008  return osContinue;
3009  case kInfo: return osBack;
3010  default: break;
3011  }
3012 
3013  eOSState state = cOsdMenu::ProcessKey(Key);
3014 
3015  if (state == osUnknown) {
3016  switch (Key) {
3017  case kRed: if (withButtons)
3018  Key = kOk; // will play the recording, even if recording commands are defined
3019  case kGreen: if (!withButtons)
3020  break;
3021  cRemote::Put(Key, true);
3022  // continue with osBack to close the info menu and process the key
3023  case kOk: return osBack;
3024  case kBlue: if (withButtons)
3026  break;
3027  default: break;
3028  }
3029  }
3030  return state;
3031 }
3032 
3033 // --- cMenuRecordingItem ----------------------------------------------------
3034 
3036 private:
3038  int level;
3039  char *name;
3041 public:
3044  void IncrementCounter(bool New);
3045  const char *Name(void) const { return name; }
3046  int Level(void) const { return level; }
3047  const cRecording *Recording(void) const { return recording; }
3048  bool IsDirectory(void) const { return name != NULL; }
3050  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
3051  };
3052 
3054 {
3055  recording = Recording;
3056  level = Level;
3057  name = NULL;
3058  totalEntries = newEntries = 0;
3059  SetText(Recording->Title('\t', true, Level));
3060  if (*Text() == '\t') // this is a folder
3061  name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
3062  else { // this is an actual recording
3063  int Usage = Recording->IsInUse();
3064  if ((Usage & ruDst) != 0 && (Usage & (ruMove | ruCopy)) != 0)
3065  SetSelectable(false);
3066  }
3067 }
3068 
3070 {
3071  free(name);
3072 }
3073 
3075 {
3076  totalEntries++;
3077  if (New)
3078  newEntries++;
3079  SetText(cString::sprintf("%d\t\t%d\t%s", totalEntries, newEntries, name));
3080 }
3081 
3082 void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
3083 {
3084  if (!DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
3085  DisplayMenu->SetItem(Text(), Index, Current, Selectable);
3086 }
3087 
3088 // --- cMenuRecordings -------------------------------------------------------
3089 
3092 
3093 cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus, const cRecordingFilter *Filter)
3094 :cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
3095 {
3097  base = Base ? strdup(Base) : NULL;
3098  level = Setup.RecordingDirs ? Level : -1;
3099  filter = Filter;
3100  helpKeys = -1;
3101  Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
3102  Set();
3103  if (Current() < 0)
3104  SetCurrent(First());
3105  else if (OpenSubMenus && (cReplayControl::LastReplayed() || *path || *fileName)) {
3106  if (!*path || Level < strcountchr(path, FOLDERDELIMCHAR)) {
3107  if (Open(true))
3108  return;
3109  }
3110  }
3111  SetHelpKeys();
3112 }
3113 
3115 {
3117  if (!ri->IsDirectory())
3118  SetRecording(ri->Recording()->FileName());
3119  }
3120  free(base);
3121 }
3122 
3124 {
3126  int NewHelpKeys = 0;
3127  if (ri) {
3128  if (ri->IsDirectory())
3129  NewHelpKeys = 1;
3130  else
3131  NewHelpKeys = 2;
3132  }
3133  if (NewHelpKeys != helpKeys) {
3134  switch (NewHelpKeys) {
3135  case 0: SetHelp(NULL); break;
3136  case 1: SetHelp(tr("Button$Open"), NULL, NULL, tr("Button$Edit")); break;
3137  case 2: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), tr("Button$Info"));
3138  default: ;
3139  }
3140  helpKeys = NewHelpKeys;
3141  }
3142 }
3143 
3144 void cMenuRecordings::Set(bool Refresh)
3145 {
3148  cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting!
3149  const char *CurrentRecording = NULL;
3151  CurrentRecording = ri->Recording()->FileName();
3152  if (!CurrentRecording)
3153  CurrentRecording = *fileName ? *fileName : cReplayControl::LastReplayed();
3154  int current = Current();
3155  Clear();
3157  Recordings->Sort();
3158  cMenuRecordingItem *CurrentItem = NULL;
3159  cMenuRecordingItem *LastItem = NULL;
3160  for (const cRecording *Recording = Recordings->First(); Recording; Recording = Recordings->Next(Recording)) {
3161  if ((!filter || filter->Filter(Recording)) && (!base || (strstr(Recording->Name(), base) == Recording->Name() && Recording->Name()[strlen(base)] == FOLDERDELIMCHAR))) {
3162  cMenuRecordingItem *Item = new cMenuRecordingItem(Recording, level);
3163  cMenuRecordingItem *LastDir = NULL;
3164  if (Item->IsDirectory()) {
3165  // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
3166  for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
3167  if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
3168  LastDir = p;
3169  break;
3170  }
3171  }
3172  }
3173  if (*Item->Text() && !LastDir) {
3174  Add(Item);
3175  LastItem = Item;
3176  if (Item->IsDirectory())
3177  LastDir = Item;
3178  }
3179  else
3180  delete Item;
3181  if (LastItem || LastDir) {
3182  if (*path) {
3183  if (strcmp(path, Recording->Folder()) == 0)
3184  CurrentItem = LastDir ? LastDir : LastItem;
3185  }
3186  else if (CurrentRecording && strcmp(CurrentRecording, Recording->FileName()) == 0)
3187  CurrentItem = LastDir ? LastDir : LastItem;
3188  }
3189  if (LastDir)
3190  LastDir->IncrementCounter(Recording->IsNew());
3191  }
3192  }
3193  SetCurrent(CurrentItem);
3194  if (Current() < 0)
3195  SetCurrent(Get(current)); // last resort, in case the recording was deleted
3197  recordingsStateKey.Remove(false); // sorting doesn't count as a real modification
3198  if (Refresh)
3199  Display();
3200  }
3201 }
3202 
3203 void cMenuRecordings::SetRecording(const char *FileName)
3204 {
3205  fileName = FileName;
3206 }
3207 
3209 {
3211  if (base) {
3212  char *s = ExchangeChars(strdup(base), true);
3213  d = AddDirectory(d, s);
3214  free(s);
3215  }
3216  return d;
3217 }
3218 
3219 bool cMenuRecordings::Open(bool OpenSubMenus)
3220 {
3222  if (ri && ri->IsDirectory() && (!*path || strcountchr(path, FOLDERDELIMCHAR) > 0)) {
3223  const char *t = ri->Name();
3224  cString buffer;
3225  if (base) {
3226  buffer = cString::sprintf("%s%c%s", base, FOLDERDELIMCHAR, t);
3227  t = buffer;
3228  }
3229  AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus, filter));
3230  return true;
3231  }
3232  return false;
3233 }
3234 
3236 {
3238  if (ri) {
3239  if (ri->IsDirectory())
3240  Open();
3241  else {
3243  return osReplay;
3244  }
3245  }
3246  return osContinue;
3247 }
3248 
3250 {
3251  if (HasSubMenu() || Count() == 0)
3252  return osContinue;
3254  if (ri && !ri->IsDirectory()) {
3255  cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
3256  cResumeFile ResumeFile(ri->Recording()->FileName(), ri->Recording()->IsPesRecording());
3257  ResumeFile.Delete();
3258  return Play();
3259  }
3260  return osContinue;
3261 }
3262 
3263 static bool TimerStillRecording(const char *FileName)
3264 {
3265  if (cRecordControl *rc = cRecordControls::GetRecordControl(FileName)) {
3266  // local timer
3267  if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3269  if (cTimer *Timer = rc->Timer()) {
3270  Timer->Skip();
3271  cRecordControls::Process(Timers, time(NULL));
3272  if (Timer->IsSingleEvent()) {
3273  Timers->Del(Timer);
3274  isyslog("deleted timer %s", *Timer->ToDescr());
3275  }
3276  }
3277  }
3278  else
3279  return true; // user didn't confirm deletion
3280  }
3281  else {
3282  // remote timer
3283  cString TimerId = GetRecordingTimerId(FileName);
3284  if (*TimerId) {
3285  int Id;
3286  char *RemoteBuf = NULL;
3287  cString Remote;
3288  if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf) && Id != 0) {
3289  Remote = RemoteBuf;
3290  free(RemoteBuf);
3291  if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
3293  if (cTimer *Timer = Timers->GetById(Id, Remote)) {
3294  cTimer OldTimer = *Timer;
3295  Timer->Skip();
3296  Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
3297  if (Timer->IsSingleEvent()) {
3298  if (HandleRemoteModifications(NULL, Timer))
3299  Timers->Del(Timer);
3300  else
3301  return true; // error while deleting remote timer
3302  }
3303  else if (!HandleRemoteModifications(Timer, &OldTimer))
3304  return true; // error while modifying remote timer
3305  }
3306  }
3307  else
3308  return true; // user didn't confirm deletion
3309  }
3310  }
3311  }
3312  return false;
3313 }
3314 
3316 {
3317  if (HasSubMenu() || Count() == 0)
3318  return osContinue;
3320  if (ri && !ri->IsDirectory()) {
3321  if (Interface->Confirm(tr("Delete recording?"))) {
3322  if (TimerStillRecording(ri->Recording()->FileName()))
3323  return osContinue;
3324  cString FileName;
3325  {
3327  if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) {
3328  FileName = Recording->FileName();
3329  if (RecordingsHandler.GetUsage(FileName)) {
3330  if (!Interface->Confirm(tr("Recording is being edited - really delete?")))
3331  return osContinue;
3332  }
3333  }
3334  }
3335  RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one!
3336  if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
3339  Recordings->SetExplicitModify();
3340  cRecording *Recording = Recordings->GetByName(FileName);
3341  if (!Recording || Recording->Delete()) {
3343  Recordings->DelByName(FileName);
3345  SetHelpKeys();
3347  Recordings->SetModified();
3349  Display();
3350  if (!Count())
3351  return osUserRecEmpty;
3352  return osUserRecRemoved;
3353  }
3354  else
3355  Skins.Message(mtError, tr("Error while deleting recording!"));
3357  }
3358  }
3359  return osContinue;
3360 }
3361 
3363 {
3364  if (HasSubMenu() || Count() == 0)
3365  return osContinue;
3367  if (ri->IsDirectory())
3368  return AddSubMenu(new cMenuPathEdit(cString(ri->Recording()->Name(), strchrn(ri->Recording()->Name(), FOLDERDELIMCHAR, ri->Level() + 1))));
3369  else
3370  return AddSubMenu(new cMenuRecording(ri->Recording(), true));
3371  }
3372  return osContinue;
3373 }
3374 
3376 {
3377  if (HasSubMenu() || Count() == 0)
3378  return osContinue;
3380  if (ri && !ri->IsDirectory()) {
3381  cMenuCommands *menu;
3382  eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
3383  if (Key != kNone)
3384  state = menu->ProcessKey(Key);
3385  return state;
3386  }
3387  return osContinue;
3388 }
3389 
3391 {
3392  if (HasSubMenu())
3393  return osContinue;
3394  if (const cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()))
3395  SetRecording(ri->Recording()->FileName()); // makes sure the Recordings menu will reposition to the current recording
3398  Set(true);
3399  return osContinue;
3400 }
3401 
3403 {
3404  eOSState state = cOsdMenu::ProcessKey(Key);
3405 
3406  if (state == osUnknown) {
3407  switch (Key) {
3408  case kPlayPause:
3409  case kPlay:
3410  case kOk: return Play();
3411  case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
3412  case kGreen: return Rewind();
3413  case kYellow: return Delete();
3414  case kInfo:
3415  case kBlue: return Info();
3416  case k0: return Sort();
3417  case k1...k9: return Commands(Key);
3418  default: break;
3419  }
3420  }
3421  else if (state == osUserRecRenamed) {
3422  // a recording was renamed (within the same folder), so let's refresh the menu
3423  CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3424  path = NULL;
3425  fileName = NULL;
3426  state = osContinue;
3427  }
3428  else if (state == osUserRecMoved) {
3429  // a recording was moved to a different folder, so let's delete the old item
3430  CloseSubMenu(false); // this is the cMenuRecordingEdit/cMenuPathEdit
3431  path = NULL;
3432  fileName = NULL;
3434  Set(); // the recording might have been moved into a new subfolder of this folder
3435  if (!Count())
3436  return osUserRecEmpty;
3437  Display();
3438  state = osUserRecRemoved;
3439  }
3440  else if (state == osUserRecRemoved) {
3441  // a recording was removed from a sub folder, so update the current item
3442  if (cOsdMenu *m = SubMenu()) {
3444  if (cMenuRecordingItem *riSub = (cMenuRecordingItem *)m->Get(m->Current()))
3445  ri->SetRecording(riSub->Recording());
3446  }
3447  }
3448  // no state change here, this report goes upstream!
3449  }
3450  else if (state == osUserRecEmpty) {
3451  // a subfolder became empty, so let's go back up
3452  CloseSubMenu(false); // this is the now empty submenu
3453  cOsdMenu::Del(Current()); // the menu entry of the now empty subfolder
3454  Set(); // in case a recording was moved into a new subfolder of this folder
3455  if (base && !Count()) // base: don't go up beyond the top level Recordings menu
3456  return state;
3457  Display();
3458  state = osContinue;
3459  }
3460  if (!HasSubMenu()) {
3461  Set(true);
3462  if (Key != kNone)
3463  SetHelpKeys();
3464  }
3465  return state;
3466 }
3467 
3468 // --- cMenuSetupBase --------------------------------------------------------
3469 
3471 protected:
3473  virtual void Store(void);
3474 public:
3475  cMenuSetupBase(void);
3476  };
3477 
3479 {
3480  data = Setup;
3481 }
3482 
3484 {
3485  Setup = data;
3487  Setup.Save();
3488 }
3489 
3490 // --- cMenuSetupOSD ---------------------------------------------------------
3491 
3493 private:
3494  const char *useSmallFontTexts[3];
3495  const char *recSortModeTexts[2];
3496  const char *recSortDirTexts[2];
3497  const char *keyColorTexts[4];
3502  const char **skinDescriptions;
3508  virtual void Set(void);
3509 public:
3510  cMenuSetupOSD(void);
3511  virtual ~cMenuSetupOSD();
3512  virtual eOSState ProcessKey(eKeys Key);
3513  };
3514 
3516 {
3519  numSkins = Skins.Count();
3521  skinDescriptions = new const char*[numSkins];
3522  themes.Load(Skins.Current()->Name());
3533  Set();
3534 }
3535 
3537 {
3538  delete[] skinDescriptions;
3539 }
3540 
3542 {
3543  int current = Current();
3544  for (cSkin *Skin = Skins.First(); Skin; Skin = Skins.Next(Skin))
3545  skinDescriptions[Skin->Index()] = Skin->Description();
3546  useSmallFontTexts[0] = tr("never");
3547  useSmallFontTexts[1] = tr("skin dependent");
3548  useSmallFontTexts[2] = tr("always");
3549  recSortModeTexts[0] = tr("by name");
3550  recSortModeTexts[1] = tr("by time");
3551  recSortDirTexts[0] = tr("ascending");
3552  recSortDirTexts[1] = tr("descending");
3553  keyColorTexts[0] = tr("Key$Red");
3554  keyColorTexts[1] = tr("Key$Green");
3555  keyColorTexts[2] = tr("Key$Yellow");
3556  keyColorTexts[3] = tr("Key$Blue");
3557  Clear();
3558  SetSection(tr("OSD"));
3559  Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0)));
3560  Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions));
3561  if (themes.NumThemes())
3562  Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions()));
3563  Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5));
3564  Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5));
3565  Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0));
3566  Add(new cMenuEditPrcItem( tr("Setup.OSD$Height (%)"), &data.OSDHeightP, 0.5, 1.0));
3567  Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
3568  Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"), &data.UseSmallFont, 3, useSmallFontTexts));
3569  Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"), &data.AntiAlias));
3570  Add(new cMenuEditStraItem(tr("Setup.OSD$Default font"), &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
3571  Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"), &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
3572  Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"), &fontFixIndex, fontFixNames.Size(), &fontFixNames[0]));
3573  Add(new cMenuEditPrcItem( tr("Setup.OSD$Default font size (%)"), &data.FontOsdSizeP, 0.01, 0.1, 1));
3574  Add(new cMenuEditPrcItem( tr("Setup.OSD$Small font size (%)"), &data.FontSmlSizeP, 0.01, 0.1, 1));
3575  Add(new cMenuEditPrcItem( tr("Setup.OSD$Fixed font size (%)"), &data.FontFixSizeP, 0.01, 0.1, 1));
3576  Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
3577  Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
3578  Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
3579  Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
3580  Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
3581  Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
3582  Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses));
3583  Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
3584  Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu));
3585  Add(new cMenuEditBoolItem(tr("Setup.OSD$Always sort folders first"), &data.AlwaysSortFoldersFirst));
3586  Add(new cMenuEditStraItem(tr("Setup.OSD$Default sort mode for recordings"), &data.DefaultSortModeRec, 2, recSortModeTexts));
3587  Add(new cMenuEditStraItem(tr("Setup.OSD$Sorting direction for recordings"), &data.RecSortingDirection, 2, recSortDirTexts));
3588  Add(new cMenuEditBoolItem(tr("Setup.OSD$Number keys for characters"), &data.NumberKeysForChars));
3589  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 0"), &data.ColorKey0, 4, keyColorTexts));
3590  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 1"), &data.ColorKey1, 4, keyColorTexts));
3591  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 2"), &data.ColorKey2, 4, keyColorTexts));
3592  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 3"), &data.ColorKey3, 4, keyColorTexts));
3594  Display();
3595 }
3596 
3598 {
3599  bool ModifiedAppearance = false;
3600 
3601  if (Key == kOk) {
3603  if (skinIndex != originalSkinIndex) {
3604  cSkin *Skin = Skins.Get(skinIndex);
3605  if (Skin) {
3606  Utf8Strn0Cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
3607  Skins.SetCurrent(Skin->Name());
3608  ModifiedAppearance = true;
3609  }
3610  }
3611  if (themes.NumThemes() && Skins.Current()->Theme()) {
3614  ModifiedAppearance |= themeIndex != originalThemeIndex;
3615  }
3617  ModifiedAppearance = true;
3619  ModifiedAppearance = true;
3624  ModifiedAppearance = true;
3626  ModifiedAppearance = true;
3628  ModifiedAppearance = true;
3631  Recordings->ClearSortNames();
3632  }
3633  }
3634 
3635  int oldSkinIndex = skinIndex;
3636  int oldOsdLanguageIndex = osdLanguageIndex;
3637  eOSState state = cMenuSetupBase::ProcessKey(Key);
3638 
3639  if (ModifiedAppearance)
3641 
3642  if (osdLanguageIndex != oldOsdLanguageIndex || skinIndex != oldSkinIndex) {
3644  int OriginalOSDLanguage = I18nCurrentLanguage();
3646 
3647  cSkin *Skin = Skins.Get(skinIndex);
3648  if (Skin) {
3649  char *d = themes.NumThemes() ? strdup(themes.Descriptions()[themeIndex]) : NULL;
3650  themes.Load(Skin->Name());
3651  if (skinIndex != oldSkinIndex)
3652  themeIndex = d ? themes.GetThemeIndex(d) : 0;
3653  free(d);
3654  }
3655 
3656  Set();
3657  I18nSetLanguage(OriginalOSDLanguage);
3658  }
3659  return state;
3660 }
3661 
3662 // --- cMenuSetupEPG ---------------------------------------------------------
3663 
3665 private:
3668  void Setup(void);
3669 public:
3670  cMenuSetupEPG(void);
3671  virtual eOSState ProcessKey(eKeys Key);
3672  };
3673 
3675 {
3678  ;
3680  SetSection(tr("EPG"));
3681  SetHelp(tr("Button$Scan"));
3682  Setup();
3683 }
3684 
3686 {
3687  int current = Current();
3688 
3689  Clear();
3690 
3691  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
3692  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan max. channel number (0=all)"), &data.EPGScanMaxChannel));
3693  Add(new cMenuEditBoolItem(tr("Setup.EPG$EPG pause after scan"), &data.EPGPauseAfterScan));
3694  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
3695  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0));
3696  Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
3697  if (data.SetSystemTime)
3698  Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource));
3699  // TRANSLATORS: note the plural!
3700  Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), &numLanguages, 0, I18nLanguages()->Size()));
3701  for (int i = 0; i < numLanguages; i++)
3702  // TRANSLATORS: note the singular!
3703  Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3704 
3706  Display();
3707 }
3708 
3710 {
3711  if (Key == kOk) {
3712  bool Modified = numLanguages != originalNumLanguages;
3713  if (!Modified) {
3714  for (int i = 0; i < numLanguages; i++) {
3715  if (data.EPGLanguages[i] != ::Setup.EPGLanguages[i]) {
3716  Modified = true;
3717  break;
3718  }
3719  }
3720  }
3721  if (Modified)
3723  }
3724 
3725  int oldnumLanguages = numLanguages;
3726  int oldSetSystemTime = data.SetSystemTime;
3727 
3728  eOSState state = cMenuSetupBase::ProcessKey(Key);
3729  if (Key != kNone) {
3730  if (numLanguages != oldnumLanguages || data.SetSystemTime != oldSetSystemTime) {
3731  for (int i = oldnumLanguages; i < numLanguages; i++) {
3732  data.EPGLanguages[i] = 0;
3733  for (int l = 0; l < I18nLanguages()->Size(); l++) {
3734  int k;
3735  for (k = 0; k < oldnumLanguages; k++) {
3736  if (data.EPGLanguages[k] == l)
3737  break;
3738  }
3739  if (k >= oldnumLanguages) {
3740  data.EPGLanguages[i] = l;
3741  break;
3742  }
3743  }
3744  }
3746  Setup();
3747  }
3748  if (Key == kRed) {
3750  return osEnd;
3751  }
3752  }
3753  return state;
3754 }
3755 
3756 // --- cMenuSetupDVB ---------------------------------------------------------
3757 
3759 private:
3764  void Setup(void);
3765  const char *videoDisplayFormatTexts[3];
3766  const char *updateChannelsTexts[6];
3767  const char *standardComplianceTexts[3];
3768 public:
3769  cMenuSetupDVB(void);
3770  virtual eOSState ProcessKey(eKeys Key);
3771  };
3772 
3774 {
3777  ;
3779  ;
3782  videoDisplayFormatTexts[0] = tr("pan&scan");
3783  videoDisplayFormatTexts[1] = tr("letterbox");
3784  videoDisplayFormatTexts[2] = tr("center cut out");
3785  updateChannelsTexts[0] = tr("no");
3786  updateChannelsTexts[1] = tr("names only");
3787  updateChannelsTexts[2] = tr("PIDs only");
3788  updateChannelsTexts[3] = tr("names and PIDs");
3789  updateChannelsTexts[4] = tr("add new channels");
3790  updateChannelsTexts[5] = tr("add new transponders");
3791  standardComplianceTexts[0] = "DVB";
3792  standardComplianceTexts[1] = "ANSI/SCTE";
3793  standardComplianceTexts[2] = "NORDIG";
3794 
3795  SetSection(tr("DVB"));
3796  SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL);
3797  Setup();
3798 }
3799 
3801 {
3802  int current = Current();
3803 
3804  Clear();
3805 
3806  Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
3807  Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"), &data.StandardCompliance, 3, standardComplianceTexts));
3808  Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
3809  if (data.VideoFormat == 0)
3810  Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
3811  Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital));
3812  Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts));
3813  Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
3814  for (int i = 0; i < numAudioLanguages; i++)
3815  Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3816  Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
3817  if (data.DisplaySubtitles) {
3818  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
3819  for (int i = 0; i < numSubtitleLanguages; i++)
3820  Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3821  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -100, 100));
3822  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
3823  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
3824  }
3825 
3827  Display();
3828 }
3829 
3831 {
3832  int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
3833  bool oldVideoFormat = ::Setup.VideoFormat;
3834  bool newVideoFormat = data.VideoFormat;
3835  bool oldStandardCompliance = ::Setup.StandardCompliance;
3836  bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
3837  bool newDisplaySubtitles = data.DisplaySubtitles;
3838  int oldnumAudioLanguages = numAudioLanguages;
3839  int oldnumSubtitleLanguages = numSubtitleLanguages;
3840  eOSState state = cMenuSetupBase::ProcessKey(Key);
3841 
3842  if (Key != kNone) {
3843  switch (Key) {
3844  case kGreen: cRemote::Put(kAudio, true);
3845  state = osEnd;
3846  break;
3847  case kYellow: cRemote::Put(kSubtitles, true);
3848  state = osEnd;
3849  break;
3850  default: {
3851  bool DoSetup = data.VideoFormat != newVideoFormat;
3852  DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
3853  if (numAudioLanguages != oldnumAudioLanguages) {
3854  for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
3855  data.AudioLanguages[i] = 0;
3856  for (int l = 0; l < I18nLanguages()->Size(); l++) {
3857  int k;
3858  for (k = 0; k < oldnumAudioLanguages; k++) {
3859  if (data.AudioLanguages[k] == l)
3860  break;
3861  }
3862  if (k >= oldnumAudioLanguages) {
3863  data.AudioLanguages[i] = l;
3864  break;
3865  }
3866  }
3867  }
3869  DoSetup = true;
3870  }
3871  if (numSubtitleLanguages != oldnumSubtitleLanguages) {
3872  for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
3873  data.SubtitleLanguages[i] = 0;
3874  for (int l = 0; l < I18nLanguages()->Size(); l++) {
3875  int k;
3876  for (k = 0; k < oldnumSubtitleLanguages; k++) {
3877  if (data.SubtitleLanguages[k] == l)
3878  break;
3879  }
3880  if (k >= oldnumSubtitleLanguages) {
3881  data.SubtitleLanguages[i] = l;
3882  break;
3883  }
3884  }
3885  }
3887  DoSetup = true;
3888  }
3889  if (DoSetup)
3890  Setup();
3891  }
3892  }
3893  }
3894  if (state == osBack && Key == kOk) {
3895  if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
3897  if (::Setup.VideoFormat != oldVideoFormat)
3898  cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
3899  if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
3901  if (::Setup.StandardCompliance != oldStandardCompliance) {
3903  Channels->SetExplicitModify();
3904  Channels->ReNumber();
3905  }
3907  }
3908  return state;
3909 }
3910 
3911 // --- cMenuSetupLNB ---------------------------------------------------------
3912 
3914 private:
3916  void Setup(void);
3917 public:
3918  cMenuSetupLNB(void);
3919  virtual eOSState ProcessKey(eKeys Key);
3920  };
3921 
3923 :satCableNumbers(MAXDEVICES)
3924 {
3927  SetSection(tr("LNB"));
3928  Setup();
3929 }
3930 
3932 {
3933  int current = Current();
3934 
3935  Clear();
3936 
3937  Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
3938  if (!data.DiSEqC) {
3939  Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
3940  Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
3941  Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
3942  }
3943 
3944  int NumSatDevices = 0;
3945  for (int i = 0; i < cDevice::NumDevices(); i++) {
3947  NumSatDevices++;
3948  }
3949  if (NumSatDevices > 1) {
3950  for (int i = 0; i < cDevice::NumDevices(); i++) {
3952  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")));
3953  else
3954  satCableNumbers.Array()[i] = 0;
3955  }
3956  }
3957 
3958  Add(new cMenuEditBoolItem(tr("Setup.LNB$Use dish positioner"), &data.UsePositioner));
3959  if (data.UsePositioner) {
3960  Add(new cMenuEditIntxItem(tr("Setup.LNB$Site latitude (degrees)"), &data.SiteLat, -900, 900, 10, tr("South"), tr("North")));
3961  Add(new cMenuEditIntxItem(tr("Setup.LNB$Site longitude (degrees)"), &data.SiteLon, -1800, 1800, 10, tr("West"), tr("East")));
3962  Add(new cMenuEditIntxItem(tr("Setup.LNB$Max. positioner swing (degrees)"), &data.PositionerSwing, 0, 900, 10));
3963  Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed (degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
3964  }
3965 
3967  Display();
3968 }
3969 
3971 {
3972  int oldDiSEqC = data.DiSEqC;
3973  int oldUsePositioner = data.UsePositioner;
3974  bool DeviceBondingsChanged = false;
3975  if (Key == kOk) {
3976  cString NewDeviceBondings = satCableNumbers.ToString();
3977  DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
3978  data.DeviceBondings = NewDeviceBondings;
3979  }
3980  eOSState state = cMenuSetupBase::ProcessKey(Key);
3981 
3982  if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner != oldUsePositioner))
3983  Setup();
3984  else if (DeviceBondingsChanged)
3986  return state;
3987 }
3988 
3989 // --- cMenuSetupCAM ---------------------------------------------------------
3990 
3991 class cMenuSetupCAMItem : public cOsdItem {
3992 private:
3994 public:
3996  cCamSlot *CamSlot(void) { return camSlot; }
3997  bool Changed(void);
3998  };
3999 
4001 {
4002  camSlot = CamSlot;
4003  SetText("");
4004  Changed();
4005 }
4006 
4008 {
4009  cString AssignedDevice("");
4010  const char *Activating = "";
4011  const char *CamName = camSlot->GetCamName();
4012  if (!CamName) {
4013  switch (camSlot->ModuleStatus()) {
4014  case msReset: CamName = tr("CAM reset"); break;
4015  case msPresent: CamName = tr("CAM present"); break;
4016  case msReady: CamName = tr("CAM ready"); break;
4017  default: CamName = "-"; break;
4018  }
4019  }
4020  else if (camSlot->IsActivating())
4021  // TRANSLATORS: note the leading blank!
4022  Activating = tr(" (activating)");
4023  cVector<int> DeviceNumbers;
4025  if (CamSlot == camSlot || CamSlot->MasterSlot() == camSlot)
4026  CamSlot->Devices(DeviceNumbers);
4027  }
4028  if (DeviceNumbers.Size() > 0) {
4029  AssignedDevice = cString::sprintf(" %s", tr("@ device"));
4030  DeviceNumbers.Sort(CompareInts);
4031  for (int i = 0; i < DeviceNumbers.Size(); i++)
4032  AssignedDevice = cString::sprintf("%s %d", *AssignedDevice, DeviceNumbers[i]);
4033  }
4034 
4035  cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
4036  if (strcmp(buffer, Text()) != 0) {
4037  SetText(buffer);
4038  return true;
4039  }
4040  return false;
4041 }
4042 
4044 private:
4046  const char *activationHelp;
4047  eOSState Menu(void);
4048  eOSState Reset(void);
4049  eOSState Activate(void);
4050  void SetHelpKeys(void);
4051 public:
4052  cMenuSetupCAM(void);
4053  virtual eOSState ProcessKey(eKeys Key);
4054  };
4055 
4057 {
4059  activationHelp = NULL;
4061  SetSection(tr("CAM"));
4062  SetCols(15);
4063  SetHasHotkeys();
4064  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
4065  if (CamSlot->IsMasterSlot()) // we only list master CAM slots
4066  Add(new cMenuSetupCAMItem(CamSlot));
4067  }
4068  SetHelpKeys();
4069 }
4070 
4072 {
4073  if (HasSubMenu())
4074  return;
4076  const char *NewActivationHelp = "";
4077  if (item) {
4078  cCamSlot *CamSlot = item->CamSlot();
4079  if (CamSlot->IsActivating())
4080  NewActivationHelp = tr("Button$Cancel activation");
4081  else if (CamSlot->CanActivate())
4082  NewActivationHelp = tr("Button$Activate");
4083  }
4084  if (NewActivationHelp != activationHelp) {
4085  activationHelp = NewActivationHelp;
4086  SetHelp(tr("Button$Menu"), tr("Button$Reset"), activationHelp);
4087  }
4088 }
4089 
4091 {
4093  if (item) {
4094  if (item->CamSlot()->EnterMenu()) {
4095  Skins.Message(mtStatus, tr("Opening CAM menu..."));
4096  time_t t0 = time(NULL);
4097  time_t t1 = t0;
4098  while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
4099  if (item->CamSlot()->HasUserIO())
4100  break;
4101  if (time(NULL) - t1 >= CAMMENURETRYTIMEOUT) {
4102  dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
4103  item->CamSlot()->EnterMenu();
4104  t1 = time(NULL);
4105  }
4106  cCondWait::SleepMs(100);
4107  }
4108  Skins.Message(mtStatus, NULL);
4109  if (item->CamSlot()->HasUserIO())
4110  return AddSubMenu(new cMenuCam(item->CamSlot()));
4111  }
4112  Skins.Message(mtError, tr("Can't open CAM menu!"));
4113  }
4114  return osContinue;
4115 }
4116 
4118 {
4120  if (item) {
4121  cCamSlot *CamSlot = item->CamSlot();
4122  if (CamSlot->IsActivating())
4123  CamSlot->CancelActivation();
4124  else if (CamSlot->CanActivate()) {
4125  if (CamSlot->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4127  if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel())) {
4128  for (int i = 0; i < cDevice::NumDevices(); i++) {
4129  if (cDevice *Device = cDevice::GetDevice(i)) {
4130  if (Device->ProvidesChannel(Channel)) {
4131  if (Device->Priority() < LIVEPRIORITY) { // don't interrupt recordings
4132  if (CamSlot->Assign(Device, true)) { // query
4133  cControl::Shutdown(); // must end transfer mode before assigning CAM, otherwise it might be unassigned again
4134  CamSlot = CamSlot->MtdSpawn();
4135  if (CamSlot->Assign(Device)) {
4136  if (Device->SwitchChannel(Channel, true)) {
4137  CamSlot->StartActivation();
4138  return osContinue;
4139  }
4140  }
4141  }
4142  }
4143  }
4144  }
4145  }
4146  }
4147  }
4148  Skins.Message(mtError, tr("Can't activate CAM!"));
4149  }
4150  }
4151  return osContinue;
4152 }
4153 
4155 {
4157  if (item) {
4158  if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
4159  if (!item->CamSlot()->Reset())
4160  Skins.Message(mtError, tr("Can't reset CAM!"));
4161  }
4162  }
4163  return osContinue;
4164 }
4165 
4167 {
4169 
4170  if (!HasSubMenu()) {
4171  switch (Key) {
4172  case kOk:
4173  case kRed: return Menu();
4174  case kGreen: state = Reset(); break;
4175  case kYellow: state = Activate(); break;
4176  default: break;
4177  }
4178  for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
4179  if (ci->Changed())
4180  DisplayItem(ci);
4181  }
4182  SetHelpKeys();
4183  }
4185  state = osEnd;
4186  return state;
4187 }
4188 
4189 // --- cMenuSetupRecord ------------------------------------------------------
4190 
4192 private:
4193  const char *recordKeyHandlingTexts[3];
4194  const char *pauseKeyHandlingTexts[3];
4195  const char *delTimeshiftRecTexts[3];
4196 public:
4197  cMenuSetupRecord(void);
4198  };
4199 
4201 {
4203  recordKeyHandlingTexts[0] = tr("no instant recording");
4204  recordKeyHandlingTexts[1] = tr("confirm instant recording");
4205  recordKeyHandlingTexts[2] = tr("record instantly");
4206  pauseKeyHandlingTexts[0] = tr("do not pause live video");
4207  pauseKeyHandlingTexts[1] = tr("confirm pause live video");
4208  pauseKeyHandlingTexts[2] = tr("pause live video");
4209  delTimeshiftRecTexts[0] = tr("no");
4210  delTimeshiftRecTexts[1] = tr("confirm");
4211  delTimeshiftRecTexts[2] = tr("yes");
4212  SetSection(tr("Recording"));
4213  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
4214  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
4215  Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
4216  Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
4217  Add(new cMenuEditStraItem(tr("Setup.Recording$Record key handling"), &data.RecordKeyHandling, 3, recordKeyHandlingTexts));
4218  Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
4219  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
4220  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
4221  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
4222  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
4223  Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
4224  Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
4225  Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
4226  Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
4227  Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
4228  Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
4229  Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
4230 }
4231 
4232 // --- cMenuSetupReplay ------------------------------------------------------
4233 
4235 protected:
4236  virtual void Store(void);
4237 public:
4238  cMenuSetupReplay(void);
4239  };
4240 
4242 {
4244  SetSection(tr("Replay"));
4245  Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
4246  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
4247  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
4248  Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
4249  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
4250  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when jumping to a mark"), &data.PauseOnMarkJump));
4251  Add(new cMenuEditBoolItem(tr("Setup.Replay$Skip edited parts"), &data.SkipEdited));
4252  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay at last mark"), &data.PauseAtLastMark));
4253  Add(new cMenuEditIntItem( tr("Setup.Replay$Initial duration for adaptive skipping (s)"), &data.AdaptiveSkipInitial, 10, 600));
4254  Add(new cMenuEditIntItem( tr("Setup.Replay$Reset timeout for adaptive skipping (s)"), &data.AdaptiveSkipTimeout, 0, 10));
4255  Add(new cMenuEditBoolItem(tr("Setup.Replay$Alternate behavior for adaptive skipping"), &data.AdaptiveSkipAlternate));
4256  Add(new cMenuEditBoolItem(tr("Setup.Replay$Use Prev/Next keys for adaptive skipping"), &data.AdaptiveSkipPrevNext));
4257  Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys (s)"), &data.SkipSeconds, 5, 600));
4258  Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys in repeat (s)"), &data.SkipSecondsRepeat, 5, 600));
4259  Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
4260 }
4261 
4263 {
4264  if (Setup.ResumeID != data.ResumeID) {
4266  Recordings->ResetResume();
4267  }
4269 }
4270 
4271 // --- cMenuSetupMisc --------------------------------------------------------
4272 
4274 private:
4275  const char *svdrpPeeringModeTexts[3];
4278  void Set(void);
4279 public:
4280  cMenuSetupMisc(void);
4281  virtual eOSState ProcessKey(eKeys Key);
4282  };
4283 
4285 {
4287  svdrpPeeringModeTexts[0] = tr("off");
4288  svdrpPeeringModeTexts[1] = tr("any hosts");
4289  svdrpPeeringModeTexts[2] = tr("only default host");
4290  showChannelNamesWithSourceTexts[0] = tr("off");
4291  showChannelNamesWithSourceTexts[1] = tr("type");
4292  showChannelNamesWithSourceTexts[2] = tr("full");
4293  SetSection(tr("Miscellaneous"));
4294  Set();
4295 }
4296 
4298 {
4299  int current = Current();
4300  Clear();
4301  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
4302  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
4303  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
4304  Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$SVDRP peering"), &data.SVDRPPeering, 3, svdrpPeeringModeTexts));
4305  if (data.SVDRPPeering) {
4306  Add(new cMenuEditStrItem( tr("Setup.Miscellaneous$SVDRP host name"), data.SVDRPHostName, sizeof(data.SVDRPHostName)));
4308  svdrpServerNames.Sort(true);
4309  svdrpServerNames.Insert(strdup(""));
4310  Add(new cMenuEditStrlItem(tr("Setup.Miscellaneous$SVDRP default host"), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames));
4311  }
4312  }
4313  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
4314  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
4315  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0));
4316  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0));
4317  Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
4318  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
4319  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume steps"), &data.VolumeSteps, 5, 255));
4320  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume linearize"), &data.VolumeLinearize, -20, 20));
4321  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
4322  Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource, 3, showChannelNamesWithSourceTexts));
4323  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
4325  Display();
4326 }
4327 
4329 {
4330  bool OldSVDRPPeering = data.SVDRPPeering;
4331  bool ModifiedSVDRPSettings = false;
4332  bool ModifiedShowChannelNamesWithSource = false;
4333  if (Key == kOk) {
4334  ModifiedSVDRPSettings = data.SVDRPPeering != Setup.SVDRPPeering || strcmp(data.SVDRPHostName, Setup.SVDRPHostName);
4335  ModifiedShowChannelNamesWithSource = data.ShowChannelNamesWithSource != Setup.ShowChannelNamesWithSource;
4336  }
4337  eOSState state = cMenuSetupBase::ProcessKey(Key);
4338  if (ModifiedShowChannelNamesWithSource) {
4340  for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel))
4341  Channel->UpdateNameSource();
4342  }
4343  if (data.SVDRPPeering != OldSVDRPPeering)
4344  Set();
4345  if (ModifiedSVDRPSettings) {
4346  StopSVDRPHandler();
4347  {
4349  Timers->SetExplicitModify();
4350  if (Timers->StoreRemoteTimers(NULL, NULL))
4351  Timers->SetModified();
4352  }
4354  }
4355  return state;
4356 }
4357 
4358 // --- cMenuSetupPluginItem --------------------------------------------------
4359 
4361 private:
4363 public:
4364  cMenuSetupPluginItem(const char *Name, int Index);
4365  int PluginIndex(void) { return pluginIndex; }
4366  };
4367 
4369 :cOsdItem(Name)
4370 {
4371  pluginIndex = Index;
4372 }
4373 
4374 // --- cMenuSetupPlugins -----------------------------------------------------
4375 
4377 public:
4378  cMenuSetupPlugins(void);
4379  virtual eOSState ProcessKey(eKeys Key);
4380  };
4381 
4383 {
4385  SetSection(tr("Plugins"));
4386  SetHasHotkeys();
4387  for (int i = 0; ; i++) {
4389  if (p)
4390  Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
4391  else
4392  break;
4393  }
4394 }
4395 
4397 {
4399 
4400  if (Key == kOk) {
4401  if (state == osUnknown) {
4403  if (item) {
4405  if (p) {
4406  cMenuSetupPage *menu = p->SetupMenu();
4407  if (menu) {
4408  menu->SetPlugin(p);
4409  return AddSubMenu(menu);
4410  }
4411  Skins.Message(mtInfo, tr("This plugin has no setup parameters!"));
4412  }
4413  }
4414  }
4415  else if (state == osContinue) {
4416  Store();
4417  // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
4419  Display();
4420  }
4421  }
4422  return state;
4423 }
4424 
4425 // --- cMenuSetup ------------------------------------------------------------
4426 
4427 class cMenuSetup : public cOsdMenu {
4428 private:
4429  virtual void Set(void);
4430  eOSState Restart(void);
4431 public:
4432  cMenuSetup(void);
4433  virtual eOSState ProcessKey(eKeys Key);
4434  };
4435 
4437 :cOsdMenu("")
4438 {
4440  Set();
4441 }
4442 
4444 {
4445  Clear();
4446  char buffer[64];
4447  snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
4448  SetTitle(buffer);
4449  SetHasHotkeys();
4450  Add(new cOsdItem(hk(tr("OSD")), osUser1));
4451  Add(new cOsdItem(hk(tr("EPG")), osUser2));
4452  Add(new cOsdItem(hk(tr("DVB")), osUser3));
4453  Add(new cOsdItem(hk(tr("LNB")), osUser4));
4454  Add(new cOsdItem(hk(tr("CAM")), osUser5));
4455  Add(new cOsdItem(hk(tr("Recording")), osUser6));
4456  Add(new cOsdItem(hk(tr("Replay")), osUser7));
4457  Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
4459  Add(new cOsdItem(hk(tr("Plugins")), osUser9));
4460  Add(new cOsdItem(hk(tr("Restart")), osUser10));
4461 }
4462 
4464 {
4465  if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
4466  ShutdownHandler.Exit(1);
4467  return osEnd;
4468  }
4469  return osContinue;
4470 }
4471 
4473 {
4474  int osdLanguage = I18nCurrentLanguage();
4475  eOSState state = cOsdMenu::ProcessKey(Key);
4476 
4477  switch (state) {
4478  case osUser1: return AddSubMenu(new cMenuSetupOSD);
4479  case osUser2: return AddSubMenu(new cMenuSetupEPG);
4480  case osUser3: return AddSubMenu(new cMenuSetupDVB);
4481  case osUser4: return AddSubMenu(new cMenuSetupLNB);
4482  case osUser5: return AddSubMenu(new cMenuSetupCAM);
4483  case osUser6: return AddSubMenu(new cMenuSetupRecord);
4484  case osUser7: return AddSubMenu(new cMenuSetupReplay);
4485  case osUser8: return AddSubMenu(new cMenuSetupMisc);
4486  case osUser9: return AddSubMenu(new cMenuSetupPlugins);
4487  case osUser10: return Restart();
4488  default: ;
4489  }
4490  if (I18nCurrentLanguage() != osdLanguage) {
4491  Set();
4492  if (!HasSubMenu())
4493  Display();
4494  }
4495  return state;
4496 }
4497 
4498 // --- cMenuPluginItem -------------------------------------------------------
4499 
4500 class cMenuPluginItem : public cOsdItem {
4501 private:
4503 public:
4504  cMenuPluginItem(const char *Name, int Index);
4505  int PluginIndex(void) { return pluginIndex; }
4506  };
4507 
4508 cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
4509 :cOsdItem(Name, osPlugin)
4510 {
4511  pluginIndex = Index;
4512 }
4513 
4514 // --- cMenuMain -------------------------------------------------------------
4515 
4516 // TRANSLATORS: note the leading and trailing blanks!
4517 #define STOP_RECORDING trNOOP(" Stop recording ")
4518 
4520 
4521 cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
4522 :cOsdMenu("")
4523 {
4525  replaying = false;
4526  stopReplayItem = NULL;
4527  cancelEditingItem = NULL;
4528  stopRecordingItem = NULL;
4529  recordControlsState = 0;
4530  Set();
4531 
4532  // Initial submenus:
4533 
4534  cOsdObject *menu = NULL;
4535  switch (State) {
4536  case osSchedule:
4537  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4538  menu = new cMenuSchedule;
4539  break;
4540  case osChannels:
4541  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4542  menu = new cMenuChannels;
4543  break;
4544  case osTimers:
4545  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4546  menu = new cMenuTimers;
4547  break;
4548  case osRecordings:
4549  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4550  menu = new cMenuRecordings(NULL, 0, true);
4551  break;
4552  case osSetup: menu = new cMenuSetup; break;
4553  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4554  default: break;
4555  }
4556  if (menu)
4557  if (menu->IsMenu())
4558  AddSubMenu((cOsdMenu *) menu);
4559 }
4560 
4562 {
4564  pluginOsdObject = NULL;
4565  return o;
4566 }
4567 
4568 void cMenuMain::Set(void)
4569 {
4570  Clear();
4571  SetTitle("VDR");
4572  SetHasHotkeys();
4573 
4574  // Basic menu items:
4575 
4576  Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
4577  Add(new cOsdItem(hk(tr("Channels")), osChannels));
4578  Add(new cOsdItem(hk(tr("Timers")), osTimers));
4579  Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
4580 
4581  // Plugins:
4582 
4583  for (int i = 0; ; i++) {
4585  if (p) {
4586  const char *item = p->MainMenuEntry();
4587  if (item)
4588  Add(new cMenuPluginItem(hk(item), i));
4589  }
4590  else
4591  break;
4592  }
4593 
4594  // More basic menu items:
4595 
4596  Add(new cOsdItem(hk(tr("Setup")), osSetup));
4597  if (Commands.Count())
4598  Add(new cOsdItem(hk(tr("Commands")), osCommands));
4599 
4600  Update(true);
4601 
4602  Display();
4603 }
4604 
4605 bool cMenuMain::Update(bool Force)
4606 {
4607  bool result = false;
4608 
4609  bool NewReplaying = false;
4610  {
4611  cMutexLock ControlMutexLock;
4612  NewReplaying = cControl::Control(ControlMutexLock) != NULL;
4613  }
4614  if (Force || NewReplaying != replaying) {
4615  replaying = NewReplaying;
4616  // Replay control:
4617  if (replaying && !stopReplayItem)
4618  // TRANSLATORS: note the leading blank!
4619  Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
4620  else if (stopReplayItem && !replaying) {
4621  Del(stopReplayItem->Index());
4622  stopReplayItem = NULL;
4623  }
4624  // Color buttons:
4625  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"));
4626  result = true;
4627  }
4628 
4629  // Editing control:
4630  bool EditingActive = RecordingsHandler.Active();
4631  if (EditingActive && !cancelEditingItem) {
4632  // TRANSLATORS: note the leading blank!
4633  Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
4634  result = true;
4635  }
4636  else if (cancelEditingItem && !EditingActive) {
4638  cancelEditingItem = NULL;
4639  result = true;
4640  }
4641 
4642  // Record control:
4644  while (stopRecordingItem) {
4647  stopRecordingItem = it;
4648  }
4649  const char *s = NULL;
4650  while ((s = cRecordControls::GetInstantId(s)) != NULL) {
4651  cOsdItem *item = new cOsdItem(osStopRecord);
4652  item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
4653  Add(item);
4654  if (!stopRecordingItem)
4655  stopRecordingItem = item;
4656  }
4657  result = true;
4658  }
4659 
4660  return result;
4661 }
4662 
4664 {
4665  bool HadSubMenu = HasSubMenu();
4666  int osdLanguage = I18nCurrentLanguage();
4667  eOSState state = cOsdMenu::ProcessKey(Key);
4668  HadSubMenu |= HasSubMenu();
4669 
4670  cOsdObject *menu = NULL;
4671  switch (state) {
4672  case osSchedule:
4673  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4674  menu = new cMenuSchedule;
4675  else
4676  state = osContinue;
4677  break;
4678  case osChannels:
4679  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4680  menu = new cMenuChannels;
4681  else
4682  state = osContinue;
4683  break;
4684  case osTimers:
4685  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4686  menu = new cMenuTimers;
4687  else
4688  state = osContinue;
4689  break;
4690  case osRecordings:
4691  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4692  menu = new cMenuRecordings;
4693  else
4694  state = osContinue;
4695  break;
4696  case osSetup: menu = new cMenuSetup; break;
4697  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4698  case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
4699  if (cOsdItem *item = Get(Current())) {
4700  cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
4701  return osEnd;
4702  }
4703  }
4704  break;
4705  case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
4707  return osEnd;
4708  }
4709  break;
4710  case osPlugin: {
4712  if (item) {
4714  if (p) {
4715  cOsdObject *menu = p->MainMenuAction();
4716  if (menu) {
4717  if (menu->IsMenu())
4718  return AddSubMenu((cOsdMenu *)menu);
4719  else {
4720  pluginOsdObject = menu;
4721  return osPlugin;
4722  }
4723  }
4724  }
4725  }
4726  state = osEnd;
4727  }
4728  break;
4729  default: switch (Key) {
4730  case kRecord:
4731  case kRed: if (!HadSubMenu)
4733  break;
4734  case kGreen: if (!HadSubMenu) {
4735  cRemote::Put(kAudio, true);
4736  state = osEnd;
4737  }
4738  break;
4739  case kYellow: if (!HadSubMenu)
4741  break;
4742  case kBlue: if (!HadSubMenu)
4744  break;
4745  default: break;
4746  }
4747  }
4748  if (menu) {
4749  if (menu->IsMenu())
4750  return AddSubMenu((cOsdMenu *) menu);
4751  pluginOsdObject = menu;
4752  return osPlugin;
4753  }
4754  if (!HasSubMenu() && Update(HadSubMenu))
4755  Display();
4756  if (Key != kNone) {
4757  if (I18nCurrentLanguage() != osdLanguage) {
4758  Set();
4759  if (!HasSubMenu())
4760  Display();
4761  }
4762  }
4763  return state;
4764 }
4765 
4766 // --- SetTrackDescriptions --------------------------------------------------
4767 
4768 static void SetTrackDescriptions(int LiveChannel)
4769 {
4771  const cComponents *Components = NULL;
4772  if (LiveChannel) {
4774  if (const cChannel *Channel = Channels->GetByNumber(LiveChannel)) {
4776  if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
4777  const cEvent *Present = Schedule->GetPresentEvent();
4778  if (Present)
4779  Components = Present->Components();
4780  }
4781  }
4782  }
4783  else if (cReplayControl::NowReplaying()) {
4785  if (const cRecording *Recording = Recordings->GetByName(cReplayControl::NowReplaying()))
4786  Components = Recording->Info()->Components();
4787  }
4788  if (Components) {
4789  int indexAudio = 0;
4790  int indexDolby = 0;
4791  int indexSubtitle = 0;
4792  for (int i = 0; i < Components->NumComponents(); i++) {
4793  const tComponent *p = Components->Component(i);
4794  switch (p->stream) {
4795  case 2: if (p->type == 0x05)
4796  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4797  else
4798  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
4799  break;
4800  case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
4801  break;
4802  case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4803  break;
4804  default: ;
4805  }
4806  }
4807  }
4808 }
4809 
4810 // --- cDisplayChannel -------------------------------------------------------
4811 
4813 
4814 cDisplayChannel::cDisplayChannel(int Number, bool Switched)
4815 :cOsdObject(true)
4816 {
4817  currentDisplayChannel = this;
4818  group = -1;
4819  withInfo = !Switched || Setup.ShowInfoOnChSwitch;
4821  number = 0;
4822  timeout = Switched || Setup.TimeoutRequChInfo;
4823  cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4824  positioner = NULL;
4825  channel = NULL;
4826  {
4828  channel = Channels->GetByNumber(Number);
4829  lastPresent = lastFollowing = NULL;
4830  if (channel) {
4831  DisplayChannel();
4832  DisplayInfo();
4833  }
4834  }
4835  if (channel)
4836  displayChannel->Flush();
4837  lastTime.Set();
4838 }
4839 
4841 :cOsdObject(true)
4842 {
4843  currentDisplayChannel = this;
4844  group = -1;
4845  number = 0;
4846  timeout = true;
4847  lastPresent = lastFollowing = NULL;
4848  cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4849  lastTime.Set();
4852  positioner = NULL;
4853  channel = NULL;
4854  {
4856  channel = Channels->GetByNumber(cDevice::CurrentChannel());
4857  }
4858  ProcessKey(FirstKey);
4859 }
4860 
4862 {
4863  delete displayChannel;
4864  currentDisplayChannel = NULL;
4866 }
4867 
4869 {
4872  lastPresent = lastFollowing = NULL;
4873  lastTime.Set();
4874 }
4875 
4877 {
4878  if (withInfo && channel) {
4880  if (const cSchedule *Schedule = Schedules->GetSchedule(channel)) {
4881  const cEvent *Present = Schedule->GetPresentEvent();
4882  const cEvent *Following = Schedule->GetFollowingEvent();
4883  if (Present != lastPresent || Following != lastFollowing) {
4885  displayChannel->SetEvents(Present, Following);
4886  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);
4887  lastPresent = Present;
4888  lastFollowing = Following;
4889  lastTime.Set();
4890  }
4891  }
4892  }
4893 }
4894 
4896 {
4897  DisplayChannel();
4898  displayChannel->SetEvents(NULL, NULL);
4899 }
4900 
4901 const cChannel *cDisplayChannel::NextAvailableChannel(const cChannel *Channel, int Direction)
4902 {
4903  if (Direction) {
4904  cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
4905  // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
4907  while (Channel) {
4908  Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel);
4909  if (!Channel && Setup.ChannelsWrap)
4910  Channel = Direction > 0 ? Channels->First() : Channels->Last();
4911  if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
4912  return Channel;
4913  }
4914  }
4915  return NULL;
4916 }
4917 
4919 {
4921  delete displayChannel;
4923  }
4924  const cChannel *NewChannel = NULL;
4925  if (Key != kNone)
4926  lastTime.Set();
4927  switch (int(Key)) {
4928  case k0:
4929  if (number == 0) {
4930  // keep the "Toggle channels" function working
4931  cRemote::Put(Key);
4932  return osEnd;
4933  }
4934  case k1 ... k9:
4935  group = -1;
4936  if (number >= 0) {
4937  if (number > cChannels::MaxNumber())
4938  number = Key - k0;
4939  else
4940  number = number * 10 + Key - k0;
4942  channel = Channels->GetByNumber(number);
4943  Refresh();
4944  withInfo = false;
4945  // Lets see if there can be any useful further input:
4946  int n = channel ? number * 10 : 0;
4947  int m = 10;
4948  const cChannel *ch = channel;
4949  while (ch && (ch = Channels->Next(ch)) != NULL) {
4950  if (!ch->GroupSep()) {
4951  if (n <= ch->Number() && ch->Number() < n + m) {
4952  n = 0;
4953  break;
4954  }
4955  if (ch->Number() > n) {
4956  n *= 10;
4957  m *= 10;
4958  }
4959  }
4960  }
4961  if (n > 0) {
4962  // This channel is the only one that fits the input, so let's take it right away:
4963  NewChannel = channel;
4964  withInfo = true;
4965  number = 0;
4966  Refresh();
4967  }
4968  }
4969  break;
4970  case kLeft|k_Repeat:
4971  case kLeft:
4972  case kRight|k_Repeat:
4973  case kRight:
4974  case kNext|k_Repeat:
4975  case kNext:
4976  case kPrev|k_Repeat:
4977  case kPrev: {
4978  withInfo = false;
4979  number = 0;
4981  if (group < 0) {
4982  if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
4983  group = Channel->Index();
4984  }
4985  if (group >= 0) {
4986  int SaveGroup = group;
4987  if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
4988  group = Channels->GetNextGroup(group) ;
4989  else
4990  group = Channels->GetPrevGroup(group < 1 ? 1 : group);
4991  if (group < 0)
4992  group = SaveGroup;
4993  channel = Channels->Get(group);
4994  if (channel) {
4995  Refresh();
4996  if (!channel->GroupSep())
4997  group = -1;
4998  }
4999  }
5000  break;
5001  }
5002  case kUp|k_Repeat:
5003  case kUp:
5004  case kDown|k_Repeat:
5005  case kDown:
5006  case kChanUp|k_Repeat:
5007  case kChanUp:
5008  case kChanDn|k_Repeat:
5009  case kChanDn: {
5010  eKeys k = NORMALKEY(Key);
5011  if (const cChannel *Channel = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1))
5012  channel = Channel;
5013  else if (channel && channel->Number() != cDevice::CurrentChannel())
5014  Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
5015  }
5016  // no break here
5017  case kUp|k_Release:
5018  case kDown|k_Release:
5019  case kChanUp|k_Release:
5020  case kChanDn|k_Release:
5021  case kNext|k_Release:
5022  case kPrev|k_Release:
5023  if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
5024  NewChannel = channel;
5025  withInfo = true;
5026  group = -1;
5027  number = 0;
5028  Refresh();
5029  break;
5030  case kNone:
5033  channel = Channels->GetByNumber(number);
5034  if (channel)
5035  NewChannel = channel;
5036  withInfo = true;
5037  number = 0;
5038  Refresh();
5039  lastTime.Set();
5040  }
5041  break;
5042  //TODO
5043  //XXX case kGreen: return osEventNow;
5044  //XXX case kYellow: return osEventNext;
5045  case kOk: {
5047  if (group >= 0) {
5048  channel = Channels->Get(Channels->GetNextNormal(group));
5049  if (channel)
5050  NewChannel = channel;
5051  withInfo = true;
5052  group = -1;
5053  Refresh();
5054  }
5055  else if (number > 0) {
5056  channel = Channels->GetByNumber(number);
5057  if (channel)
5058  NewChannel = channel;
5059  withInfo = true;
5060  number = 0;
5061  Refresh();
5062  }
5063  else {
5064  return osEnd;
5065  }
5066  }
5067  break;
5068  default:
5069  if ((Key & (k_Repeat | k_Release)) == 0) {
5070  cRemote::Put(Key);
5071  return osEnd;
5072  }
5073  };
5074  if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
5075  {
5077  if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
5078  // makes sure a channel switch through the SVDRP CHAN command is displayed
5079  channel = Channels->GetByNumber(cDevice::CurrentChannel());
5080  Refresh();
5081  lastTime.Set();
5082  }
5083  DisplayInfo();
5084  if (NewChannel) {
5085  SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
5086  Channels->SwitchTo(NewChannel->Number());
5087  SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
5088  channel = NewChannel;
5089  }
5090  const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
5091  bool PositionerMoving = Positioner && Positioner->IsMoving();
5092  SetNeedsFastResponse(PositionerMoving);
5093  if (!PositionerMoving) {
5094  if (positioner)
5095  lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
5096  Positioner = NULL;
5097  }
5098  if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
5099  displayChannel->SetPositioner(Positioner);
5100  positioner = Positioner;
5101  }
5102  displayChannel->Flush();
5103  return osContinue;
5104  }
5105  return osEnd;
5106 }
5107 
5108 // --- cDisplayVolume --------------------------------------------------------
5109 
5110 #define VOLUMETIMEOUT 1000 //ms
5111 #define MUTETIMEOUT 5000 //ms
5112 
5114 
5116 :cOsdObject(true)
5117 {
5118  currentDisplayVolume = this;
5121  Show();
5122 }
5123 
5125 {
5126  delete displayVolume;
5127  currentDisplayVolume = NULL;
5128 }
5129 
5131 {
5133 }
5134 
5136 {
5137  if (!currentDisplayVolume)
5138  new cDisplayVolume;
5139  return currentDisplayVolume;
5140 }
5141 
5143 {
5146 }
5147 
5149 {
5150  switch (int(Key)) {
5151  case kVolUp|k_Repeat:
5152  case kVolUp:
5153  case kVolDn|k_Repeat:
5154  case kVolDn:
5155  Show();
5157  break;
5158  case kMute:
5159  if (cDevice::PrimaryDevice()->IsMute()) {
5160  Show();
5162  }
5163  else
5164  timeout.Set();
5165  break;
5166  case kNone: break;
5167  default: if ((Key & k_Release) == 0) {
5168  cRemote::Put(Key);
5169  return osEnd;
5170  }
5171  }
5172  return timeout.TimedOut() ? osEnd : osContinue;
5173 }
5174 
5175 // --- cDisplayTracks --------------------------------------------------------
5176 
5177 #define TRACKTIMEOUT 5000 //ms
5178 
5180 
5182 :cOsdObject(true)
5183 {
5185  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
5186  currentDisplayTracks = this;
5187  numTracks = track = 0;
5189  eTrackType CurrentAudioTrack = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
5190  for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
5191  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5192  if (TrackId && TrackId->id) {
5193  types[numTracks] = eTrackType(i);
5194  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5195  if (i == CurrentAudioTrack)
5196  track = numTracks;
5197  numTracks++;
5198  }
5199  }
5200  descriptions[numTracks] = NULL;
5203  Show();
5204 }
5205 
5207 {
5208  delete displayTracks;
5209  currentDisplayTracks = NULL;
5210  for (int i = 0; i < numTracks; i++)
5211  free(descriptions[i]);
5213 }
5214 
5216 {
5217  int ac = IS_AUDIO_TRACK(types[track]) ? audioChannel : -1;
5220  displayTracks->Flush();
5223 }
5224 
5226 {
5227  if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
5228  if (!currentDisplayTracks)
5229  new cDisplayTracks;
5230  return currentDisplayTracks;
5231  }
5232  Skins.Message(mtWarning, tr("No audio available!"));
5233  return NULL;
5234 }
5235 
5237 {
5240 }
5241 
5243 {
5244  int oldTrack = track;
5245  int oldAudioChannel = audioChannel;
5246  switch (int(Key)) {
5247  case kUp|k_Repeat:
5248  case kUp:
5249  case kDown|k_Repeat:
5250  case kDown:
5251  if (NORMALKEY(Key) == kUp && track > 0)
5252  track--;
5253  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5254  track++;
5256  break;
5257  case kLeft|k_Repeat:
5258  case kLeft:
5259  case kRight|k_Repeat:
5260  case kRight: if (IS_AUDIO_TRACK(types[track])) {
5261  static int ac[] = { 1, 0, 2 };
5263  if (NORMALKEY(Key) == kLeft && audioChannel > 0)
5264  audioChannel--;
5265  else if (NORMALKEY(Key) == kRight && audioChannel < 2)
5266  audioChannel++;
5267  audioChannel = ac[audioChannel];
5269  }
5270  break;
5271  case kAudio|k_Repeat:
5272  case kAudio:
5273  if (++track >= numTracks)
5274  track = 0;
5276  break;
5277  case kOk:
5278  if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
5279  oldTrack = -1; // make sure we explicitly switch to that track
5280  timeout.Set();
5281  break;
5282  case kNone: break;
5283  default: if ((Key & k_Release) == 0)
5284  return osEnd;
5285  }
5286  if (track != oldTrack || audioChannel != oldAudioChannel)
5287  Show();
5288  if (track != oldTrack) {
5291  }
5292  if (audioChannel != oldAudioChannel)
5294  return timeout.TimedOut() ? osEnd : osContinue;
5295 }
5296 
5297 // --- cDisplaySubtitleTracks ------------------------------------------------
5298 
5300 
5302 :cOsdObject(true)
5303 {
5304  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
5305  currentDisplayTracks = this;
5306  numTracks = track = 0;
5307  types[numTracks] = ttNone;
5308  descriptions[numTracks] = strdup(tr("No subtitles"));
5309  numTracks++;
5310  eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
5311  for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
5312  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
5313  if (TrackId && TrackId->id) {
5314  types[numTracks] = eTrackType(i);
5315  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
5316  if (i == CurrentSubtitleTrack)
5317  track = numTracks;
5318  numTracks++;
5319  }
5320  }
5321  descriptions[numTracks] = NULL;
5323  displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
5324  Show();
5325 }
5326 
5328 {
5329  delete displayTracks;
5330  currentDisplayTracks = NULL;
5331  for (int i = 0; i < numTracks; i++)
5332  free(descriptions[i]);
5334 }
5335 
5337 {
5339  displayTracks->Flush();
5341 }
5342 
5344 {
5345  if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
5346  if (!currentDisplayTracks)
5348  return currentDisplayTracks;
5349  }
5350  Skins.Message(mtWarning, tr("No subtitles available!"));
5351  return NULL;
5352 }
5353 
5355 {
5358 }
5359 
5361 {
5362  int oldTrack = track;
5363  switch (int(Key)) {
5364  case kUp|k_Repeat:
5365  case kUp:
5366  case kDown|k_Repeat:
5367  case kDown:
5368  if (NORMALKEY(Key) == kUp && track > 0)
5369  track--;
5370  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
5371  track++;
5373  break;
5374  case kSubtitles|k_Repeat:
5375  case kSubtitles:
5376  if (++track >= numTracks)
5377  track = 0;
5379  break;
5380  case kOk:
5381  if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
5382  oldTrack = -1; // make sure we explicitly switch to that track
5383  timeout.Set();
5384  break;
5385  case kNone: break;
5386  default: if ((Key & k_Release) == 0)
5387  return osEnd;
5388  }
5389  if (track != oldTrack) {
5390  Show();
5392  }
5393  return timeout.TimedOut() ? osEnd : osContinue;
5394 }
5395 
5396 // --- cRecordControl --------------------------------------------------------
5397 
5398 cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause)
5399 {
5400  const char *LastReplayed = cReplayControl::LastReplayed(); // must do this before locking schedules!
5401  // Whatever happens here, the timers will be modified in some way...
5402  Timers->SetModified();
5403  cStateKey ChannelsStateKey;
5404  // To create a new timer, we need to make shure there is
5405  // a lock on Channels prior to the Schedules locking below
5406  if (!Timer)
5407  cChannels::GetChannelsRead(ChannelsStateKey);
5408  // We're going to work with an event here, so we need to prevent
5409  // others from modifying any EPG data:
5410  cStateKey SchedulesStateKey;
5411  cSchedules::GetSchedulesRead(SchedulesStateKey);
5412 
5413  event = NULL;
5414  fileName = NULL;
5415  recorder = NULL;
5416  device = Device;
5417  if (!device) device = cDevice::PrimaryDevice();//XXX
5418  timer = Timer;
5419  if (!timer) {
5420  timer = new cTimer(true, Pause);
5421  Timers->Add(timer);
5422  instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->DeviceNumber() + 1);
5423  ChannelsStateKey.Remove();
5424  }
5425  timer->SetPending(true);
5426  timer->SetRecording(true);
5427  event = timer->Event();
5428 
5429  if (event || GetEvent())
5430  dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
5431  cRecording Recording(timer, event);
5432  fileName = strdup(Recording.FileName());
5433 
5434  // crude attempt to avoid duplicate recordings:
5436  isyslog("already recording: '%s'", fileName);
5437  if (Timer) {
5438  timer->SetPending(false);
5439  timer->SetRecording(false);
5440  timer->OnOff();
5441  }
5442  else {
5443  Timers->Del(timer);
5444  if (!LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5446  }
5447  timer = NULL;
5448  SchedulesStateKey.Remove();
5449  return;
5450  }
5451 
5453  isyslog("record %s", fileName);
5454  if (MakeDirs(fileName, true)) {
5455  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!
5456  const cChannel *ch = timer->Channel();
5457  recorder = new cRecorder(fileName, ch, timer->Priority());
5458  if (device->AttachReceiver(recorder)) {
5459  cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
5460  if (!Timer && !LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5462  SchedulesStateKey.Remove();
5465  Recordings->AddByName(fileName);
5466  return;
5467  }
5468  else
5470  }
5471  else
5473  if (!Timer) {
5474  Timers->Del(timer);
5475  timer = NULL;
5476  }
5477  SchedulesStateKey.Remove();
5478 }
5479 
5481 {
5482  Stop();
5483  free(fileName);
5484 }
5485 
5486 #define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
5487 
5489 {
5490  const cChannel *Channel = timer->Channel();
5492  for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
5493  {
5495  if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
5496  event = Schedule->GetEventAround(Time);
5497  if (event) {
5498  if (seconds > 0)
5499  dsyslog("got EPG info after %d seconds", seconds);
5500  return true;
5501  }
5502  }
5503  }
5504  if (seconds == 0)
5505  dsyslog("waiting for EPG info...");
5506  cCondWait::SleepMs(1000);
5507  }
5508  dsyslog("no EPG info available");
5509  return false;
5510 }
5511 
5512 void cRecordControl::Stop(bool ExecuteUserCommand)
5513 {
5514  if (timer) {
5515  bool Finished = timer->HasFlags(tfActive) && !timer->Matches();
5516  if (recorder) {
5517  int Errors = recorder->Errors();
5518  isyslog("timer %s %s with %d error%s", *timer->ToDescr(), Finished ? "finished" : "stopped", Errors, Errors != 1 ? "s" : "");
5519  if (timer->HasFlags(tfAvoid) && Errors == 0 && Finished) {
5520  const char *p = strgetlast(timer->File(), FOLDERDELIMCHAR);
5522  }
5523  }
5525  timer->SetRecording(false);
5526  timer = NULL;
5528  cStatus::MsgRecording(device, NULL, fileName, false);
5529  if (ExecuteUserCommand && Finished)
5531  }
5532 }
5533 
5535 {
5536  if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
5537  if (timer)
5538  timer->SetPending(false);
5539  return false;
5540  }
5541  return true;
5542 }
5543 
5544 // --- cRecordControls -------------------------------------------------------
5545 
5547 int cRecordControls::state = 0;
5548 
5549 bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
5550 {
5551  static time_t LastNoDiskSpaceMessage = 0;
5552  int FreeMB = 0;
5553  if (Timer) {
5554  AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
5555  Timer->SetPending(true);
5556  }
5558  if (FreeMB < MINFREEDISK) {
5559  if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
5560  isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
5561  Skins.Message(mtWarning, tr("Not enough disk space to start recording!"));
5562  LastNoDiskSpaceMessage = time(NULL);
5563  }
5564  return false;
5565  }
5566  LastNoDiskSpaceMessage = 0;
5567 
5568  ChangeState();
5569  cStateKey StateKey;
5570  const cChannels *Channels = cChannels::GetChannelsRead(StateKey);
5571  int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
5572  if (const cChannel *Channel = Channels->GetByNumber(ch)) {
5573  int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
5574  cDevice *device = cDevice::GetDevice(Channel, Priority, false);
5575  if (device) {
5576  dsyslog("switching device %d to channel %d %s (%s)", device->DeviceNumber() + 1, Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
5577  if (!device->SwitchChannel(Channel, false)) {
5578  StateKey.Remove();
5580  return false;
5581  }
5582  StateKey.Remove();
5583  Channels = NULL;
5584  if (!Timer || Timer->Matches()) {
5585  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5586  if (!RecordControls[i]) {
5587  RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause);
5588  return RecordControls[i]->Process(time(NULL));
5589  }
5590  }
5591  }
5592  }
5593  else if (!Timer || !Timer->Pending()) {
5594  isyslog("no free DVB device to record channel %d (%s)!", ch, Channel->Name());
5595  Skins.Message(mtError, tr("No free DVB device to record!"));
5596  }
5597  }
5598  else
5599  esyslog("ERROR: channel %d not defined!", ch);
5600  if (Channels)
5601  StateKey.Remove();
5602  return false;
5603 }
5604 
5605 bool cRecordControls::Start(bool Pause)
5606 {
5608  return Start(Timers, NULL, Pause);
5609 }
5610 
5611 void cRecordControls::Stop(const char *InstantId)
5612 {
5614  ChangeState();
5615  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5616  if (RecordControls[i]) {
5617  const char *id = RecordControls[i]->InstantId();
5618  if (id && strcmp(id, InstantId) == 0) {
5619  cTimer *Timer = RecordControls[i]->Timer();
5620  RecordControls[i]->Stop();
5621  if (Timer) {
5622  Timers->Del(Timer);
5623  isyslog("deleted timer %s", *Timer->ToDescr());
5624  }
5625  break;
5626  }
5627  }
5628  }
5629 }
5630 
5632 {
5633  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5634  if (RecordControls[i]) {
5635  if (RecordControls[i]->Timer() == Timer) {
5637  ChangeState();
5638  break;
5639  }
5640  }
5641  }
5642 }
5643 
5645 {
5646  Skins.Message(mtStatus, tr("Pausing live video..."));
5647  cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
5648  if (Start(true)) {
5649  cReplayControl *rc = new cReplayControl(true);
5650  cControl::Launch(rc);
5651  cControl::Attach();
5652  Skins.Message(mtStatus, NULL);
5653  return true;
5654  }
5655  Skins.Message(mtStatus, NULL);
5656  return false;
5657 }
5658 
5659 const char *cRecordControls::GetInstantId(const char *LastInstantId)
5660 {
5661  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5662  if (RecordControls[i]) {
5663  if (!LastInstantId && RecordControls[i]->InstantId())
5664  return RecordControls[i]->InstantId();
5665  if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
5666  LastInstantId = NULL;
5667  }
5668  }
5669  return NULL;
5670 }
5671 
5673 {
5674  if (FileName) {
5675  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5676  if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
5677  return RecordControls[i];
5678  }
5679  }
5680  return NULL;
5681 }
5682 
5684 {
5685  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5686  if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
5687  return RecordControls[i];
5688  }
5689  return NULL;
5690 }
5691 
5692 bool cRecordControls::Process(cTimers *Timers, time_t t)
5693 {
5694  bool Result = false;
5695  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5696  if (RecordControls[i]) {
5697  if (!RecordControls[i]->Process(t)) {
5699  ChangeState();
5700  Result = true;
5701  }
5702  }
5703  }
5704  return Result;
5705 }
5706 
5708 {
5709  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5710  if (RecordControls[i]) {
5711  if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
5712  if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
5713  isyslog("stopping recording due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
5714  RecordControls[i]->Stop();
5715  // This will restart the recording, maybe even from a different
5716  // device in case conditional access has changed.
5717  ChangeState();
5718  }
5719  }
5720  }
5721  }
5722 }
5723 
5725 {
5726  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5727  if (RecordControls[i])
5728  return true;
5729  }
5730  return false;
5731 }
5732 
5734 {
5735  for (int i = 0; i < MAXRECORDCONTROLS; i++)
5737  ChangeState();
5738 }
5739 
5741 {
5742  int NewState = state;
5743  bool Result = State != NewState;
5744  State = state;
5745  return Result;
5746 }
5747 
5748 // --- cAdaptiveSkipper ------------------------------------------------------
5749 
5751 {
5752  initialValue = NULL;
5753  currentValue = 0;
5754  framesPerSecond = 0;
5755  lastKey = kNone;
5756 }
5757 
5758 void cAdaptiveSkipper::Initialize(int *InitialValue, double FramesPerSecond)
5759 {
5760  initialValue = InitialValue;
5761  framesPerSecond = FramesPerSecond;
5762  currentValue = 0;
5763 }
5764 
5766 {
5767  if (!initialValue)
5768  return 0;
5769  if (timeout.TimedOut()) {
5770  currentValue = int(round(*initialValue * framesPerSecond));
5771  lastKey = Key;
5772  }
5773  else if (Key != lastKey) {
5774  currentValue /= 2;
5776  lastKey = Key; // only halve the value when the direction is changed
5777  else
5778  lastKey = kNone; // once the direction has changed, every further call halves the value
5779  }
5781  return max(currentValue, 1);
5782 }
5783 
5784 // --- cReplayControl --------------------------------------------------------
5785 
5788 
5790 :cDvbPlayerControl(fileName, PauseLive)
5791 {
5792  cDevice::PrimaryDevice()->SetKeepTracks(PauseLive);
5793  currentReplayControl = this;
5794  displayReplay = NULL;
5795  marksModified = false;
5796  visible = modeOnly = shown = displayFrames = false;
5797  lastCurrent = lastTotal = -1;
5798  lastPlay = lastForward = false;
5799  lastSpeed = -2; // an invalid value
5800  timeoutShow = 0;
5801  timeSearchActive = false;
5802  cRecording Recording(fileName);
5803  cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
5804  marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
5805  SetMarks(&marks);
5807  SetTrackDescriptions(false);
5810 }
5811 
5813 {
5815  Stop();
5816  if (currentReplayControl == this)
5817  currentReplayControl = NULL;
5818 }
5819 
5821 {
5822  Hide();
5823  cStatus::MsgReplaying(this, NULL, fileName, false);
5824  if (Setup.DelTimeshiftRec && *fileName) {
5826  if (rc && rc->InstantId()) {
5827  if (Active()) {
5828  if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
5829  {
5831  Timers->SetExplicitModify();
5832  cTimer *Timer = rc->Timer();
5833  rc->Stop(false); // don't execute user command
5834  if (Timer) {
5835  Timers->Del(Timer);
5836  Timers->SetModified();
5837  isyslog("deleted timer %s", *Timer->ToDescr());
5838  }
5839  }
5841  bool Error = false;
5842  {
5844  Recordings->SetExplicitModify();
5845  if (cRecording *Recording = Recordings->GetByName(fileName)) {
5846  if (Recording->Delete()) {
5847  Recordings->DelByName(fileName);
5849  Recordings->SetModified();
5850  }
5851  else
5852  Error = true;
5853  }
5854  }
5855  if (Error)
5856  Skins.Message(mtError, tr("Error while deleting recording!"));
5857  return;
5858  }
5859  }
5860  }
5861  }
5863  cMenuRecordings::SetRecording(NULL); // make sure opening the Recordings menu navigates to the last replayed recording
5864 }
5865 
5867 {
5868  cStateKey StateKey;
5869  marks.Lock(StateKey);
5870  while (cMark *m = marks.First())
5871  marks.Del(m);
5872  StateKey.Remove();
5874 }
5875 
5876 void cReplayControl::SetRecording(const char *FileName)
5877 {
5878  fileName = FileName;
5879 }
5880 
5882 {
5883  return currentReplayControl ? *fileName : NULL;
5884 }
5885 
5887 {
5889  if (!Recordings->GetByName(fileName))
5890  fileName = NULL;
5891  return fileName;
5892 }
5893 
5894 void cReplayControl::ClearLastReplayed(const char *FileName)
5895 {
5896  if (*fileName && FileName && strcmp(fileName, FileName) == 0)
5897  fileName = NULL;
5898 }
5899 
5900 void cReplayControl::ShowTimed(int Seconds)
5901 {
5902  if (modeOnly)
5903  Hide();
5904  if (!visible) {
5905  shown = ShowProgress(true);
5906  timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
5907  }
5908  else if (timeoutShow && Seconds > 0)
5909  timeoutShow = time(NULL) + Seconds;
5910 }
5911 
5913 {
5914  ShowTimed();
5915 }
5916 
5918 {
5919  if (visible) {
5920  delete displayReplay;
5921  displayReplay = NULL;
5922  SetNeedsFastResponse(false);
5923  visible = false;
5924  modeOnly = false;
5925  lastPlay = lastForward = false;
5926  lastSpeed = -2; // an invalid value
5927  timeSearchActive = false;
5928  timeoutShow = 0;
5929  }
5930  if (marksModified) {
5931  marks.Save();
5932  marksModified = false;
5933  }
5934 }
5935 
5937 {
5938  if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) {
5939  bool Play, Forward;
5940  int Speed;
5941  if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
5942  bool NormalPlay = (Play && Speed == -1);
5943 
5944  if (!visible) {
5945  if (NormalPlay)
5946  return; // no need to do indicate ">" unless there was a different mode displayed before
5947  visible = modeOnly = true;
5949  }
5950 
5951  if (modeOnly && !timeoutShow && NormalPlay)
5952  timeoutShow = time(NULL) + MODETIMEOUT;
5953  displayReplay->SetMode(Play, Forward, Speed);
5954  lastPlay = Play;
5955  lastForward = Forward;
5956  lastSpeed = Speed;
5957  }
5958  }
5959 }
5960 
5962 {
5963  int Current, Total;
5964  if (!(Initial || updateTimer.TimedOut()))
5965  return visible;
5966  if (GetFrameNumber(Current, Total) && Total > 0) {
5967  if (!visible) {
5970  SetNeedsFastResponse(true);
5971  visible = true;
5972  }
5973  if (Initial) {
5974  if (*fileName) {
5976  if (const cRecording *Recording = Recordings->GetByName(fileName))
5977  displayReplay->SetRecording(Recording);
5978  }
5979  lastCurrent = lastTotal = -1;
5980  }
5981  if (Current != lastCurrent || Total != lastTotal) {
5982  if (Setup.ShowRemainingTime || Total != lastTotal) {
5983  int Index = Total;
5985  Index = Current - Index;
5987  }
5988  displayReplay->SetProgress(Current, Total);
5990  displayReplay->Flush();
5991  lastCurrent = Current;
5992  }
5993  lastTotal = Total;
5994  ShowMode();
5996  return true;
5997  }
5998  return false;
5999 }
6000 
6002 {
6003  char buf[64];
6004  // TRANSLATORS: note the trailing blank!
6005  strcpy(buf, tr("Jump: "));
6006  int len = strlen(buf);
6007  char h10 = '0' + (timeSearchTime >> 24);
6008  char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
6009  char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
6010  char m1 = '0' + (timeSearchTime & 0x000000FF);
6011  char ch10 = timeSearchPos > 3 ? h10 : '-';
6012  char ch1 = timeSearchPos > 2 ? h1 : '-';
6013  char cm10 = timeSearchPos > 1 ? m10 : '-';
6014  char cm1 = timeSearchPos > 0 ? m1 : '-';
6015  sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
6016  displayReplay->SetJump(buf);
6017 }
6018 
6020 {
6021 #define STAY_SECONDS_OFF_END 10
6022  int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
6023  int Current = int(round(lastCurrent / FramesPerSecond()));
6024  int Total = int(round(lastTotal / FramesPerSecond()));
6025  switch (Key) {
6026  case k0 ... k9:
6027  if (timeSearchPos < 4) {
6028  timeSearchTime <<= 8;
6029  timeSearchTime |= Key - k0;
6030  timeSearchPos++;
6032  }
6033  break;
6034  case kFastRew:
6035  case kLeft:
6036  case kFastFwd:
6037  case kRight: {
6038  int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
6039  if (dir > 0)
6040  Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
6041  SkipSeconds(Seconds * dir);
6042  timeSearchActive = false;
6043  }
6044  break;
6045  case kPlayPause:
6046  case kPlay:
6047  case kUp:
6048  case kPause:
6049  case kDown:
6050  case kOk:
6051  if (timeSearchPos > 0) {
6052  Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
6053  bool Still = Key == kDown || Key == kPause || Key == kOk;
6054  Goto(SecondsToFrames(Seconds, FramesPerSecond()), Still);
6055  }
6056  timeSearchActive = false;
6057  break;
6058  default:
6059  if (!(Key & k_Flags)) // ignore repeat/release keys
6060  timeSearchActive = false;
6061  break;
6062  }
6063 
6064  if (!timeSearchActive) {
6065  if (timeSearchHide)
6066  Hide();
6067  else
6068  displayReplay->SetJump(NULL);
6069  ShowMode();
6070  }
6071 }
6072 
6074 {
6076  timeSearchHide = false;
6077  if (modeOnly)
6078  Hide();
6079  if (!visible) {
6080  Show();
6081  if (visible)
6082  timeSearchHide = true;
6083  else
6084  return;
6085  }
6086  timeoutShow = 0;
6088  timeSearchActive = true;
6089 }
6090 
6092 {
6093  int Current, Total;
6094  if (GetIndex(Current, Total, true)) {
6095  lastCurrent = -1; // triggers redisplay
6096  cStateKey StateKey;
6097  marks.Lock(StateKey);
6098  if (cMark *m = marks.Get(Current))
6099  marks.Del(m);
6100  else {
6101  marks.Add(Current);
6102  bool Play, Forward;
6103  int Speed;
6104  if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
6105  Goto(Current, true);
6106  displayFrames = true;
6107  }
6108  }
6109  StateKey.Remove();
6110  ShowTimed(2);
6111  marksModified = true;
6113  }
6114 }
6115 
6116 void cReplayControl::MarkJump(bool Forward)
6117 {
6118  int Current, Total;
6119  if (GetIndex(Current, Total)) {
6120  if (marks.Count()) {
6121  if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
6122  if (!Setup.PauseOnMarkJump) {
6123  bool Playing, Fwd;
6124  int Speed;
6125  if (GetReplayMode(Playing, Fwd, Speed) && Playing && Forward && m->Position() < Total - SecondsToFrames(3, FramesPerSecond())) {
6126  Goto(m->Position());
6127  return;
6128  }
6129  }
6130  Goto(m->Position(), true);
6131  displayFrames = true;
6132  return;
6133  }
6134  }
6135  // There are either no marks at all, or we already were at the first or last one,
6136  // so jump to the very beginning or end:
6137  Goto(Forward ? Total : 0, true);
6138  }
6139 }
6140 
6141 void cReplayControl::MarkMove(int Frames, bool MarkRequired)
6142 {
6143  int Current, Total;
6144  if (GetIndex(Current, Total)) {
6145  bool Play, Forward;
6146  int Speed;
6147  GetReplayMode(Play, Forward, Speed);
6148  cMark *m = marks.Get(Current);
6149  if (!Play && m) {
6150  displayFrames = true;
6151  cMark *m2;
6152  if (Frames > 0) {
6153  // Handle marks at the same offset:
6154  while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
6155  m = m2;
6156  // Don't skip the next mark:
6157  if ((m2 = marks.Next(m)) != NULL)
6158  Frames = min(Frames, m2->Position() - m->Position() - 1);
6159  }
6160  else {
6161  // Handle marks at the same offset:
6162  while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
6163  m = m2;
6164  // Don't skip the next mark:
6165  if ((m2 = marks.Prev(m)) != NULL)
6166  Frames = -min(-Frames, m->Position() - m2->Position() - 1);
6167  }
6168  int p = SkipFrames(Frames);
6169  m->SetPosition(p);
6170  Goto(m->Position(), true);
6171  marksModified = true;
6173  }
6174  else if (!MarkRequired)
6175  Goto(SkipFrames(Frames), !Play);
6176  }
6177 }
6178 
6180 {
6181  if (*fileName) {
6182  Hide();
6184  if (!marks.Count())
6185  Skins.Message(mtError, tr("No editing marks defined!"));
6186  else if (!marks.GetNumSequences())
6187  Skins.Message(mtError, tr("No editing sequences defined!"));
6188  else if (access(cCutter::EditedFileName(fileName), F_OK) == 0 && !Interface->Confirm(tr("Edited version already exists - overwrite?")))
6189  ;
6191  Skins.Message(mtError, tr("Not enough free disk space to start editing process!"));
6192  else if (!RecordingsHandler.Add(ruCut, fileName))
6193  Skins.Message(mtError, tr("Can't start editing process!"));
6194  else
6195  Skins.Message(mtInfo, tr("Editing process started"));
6196  }
6197  else
6198  Skins.Message(mtError, tr("Editing process already active!"));
6199  ShowMode();
6200  }
6201 }
6202 
6204 {
6205  int Current, Total;
6206  if (GetIndex(Current, Total)) {
6207  cMark *m = marks.Get(Current);
6208  if (!m)
6209  m = marks.GetNext(Current);
6210  if (m) {
6211  if ((m->Index() & 0x01) != 0 && !Setup.SkipEdited) // when skipping edited parts we also need to jump to end marks
6212  m = marks.Next(m);
6213  if (m)
6215  }
6216  }
6217 }
6218 
6220 {
6222  if (const cRecording *Recording = Recordings->GetByName(cReplayControl::LastReplayed()))
6223  return new cMenuRecording(Recording, false);
6224  return NULL;
6225 }
6226 
6228 {
6230  if (const cRecording *Recording = Recordings->GetByName(LastReplayed()))
6231  return Recording;
6232  return NULL;
6233 }
6234 
6236 {
6237  if (!Active())
6238  return osEnd;
6239  if (Key == kNone && !marksModified)
6240  marks.Update();
6241  if (visible) {
6242  if (timeoutShow && time(NULL) > timeoutShow) {
6243  Hide();
6244  ShowMode();
6245  timeoutShow = 0;
6246  }
6247  else if (modeOnly)
6248  ShowMode();
6249  else
6250  shown = ShowProgress(!shown) || shown;
6251  }
6252  bool DisplayedFrames = displayFrames;
6253  displayFrames = false;
6254  if (timeSearchActive && Key != kNone) {
6255  TimeSearchProcess(Key);
6256  return osContinue;
6257  }
6258  if (Key == kPlayPause) {
6259  bool Play, Forward;
6260  int Speed;
6261  GetReplayMode(Play, Forward, Speed);
6262  if (Speed >= 0)
6263  Key = Play ? kPlay : kPause;
6264  else
6265  Key = Play ? kPause : kPlay;
6266  }
6267  bool DoShowMode = true;
6268  switch (int(Key)) {
6269  // Positioning:
6270  case kPlay:
6271  case kUp: Play(); break;
6272  case kPause:
6273  case kDown: Pause(); break;
6274  case kFastRew|k_Release:
6275  case kLeft|k_Release:
6276  if (Setup.MultiSpeedMode) break;
6277  case kFastRew:
6278  case kLeft: Backward(); break;
6279  case kFastFwd|k_Release:
6280  case kRight|k_Release:
6281  if (Setup.MultiSpeedMode) break;
6282  case kFastFwd:
6283  case kRight: Forward(); break;
6284  case kRed: TimeSearch(); break;
6285  case kGreen|k_Repeat:
6287  case kGreen: SkipSeconds(-Setup.SkipSeconds); break;
6288  case kYellow|k_Repeat:
6290  case kYellow: SkipSeconds(Setup.SkipSeconds); break;
6291  case kStop:
6292  case kBlue: Stop();
6293  return osEnd;
6294  default: {
6295  DoShowMode = false;
6296  switch (int(Key)) {
6297  // Editing:
6298  case kMarkToggle: MarkToggle(); break;
6299  case kPrev|k_Repeat:
6300  case kPrev: if (Setup.AdaptiveSkipPrevNext) {
6301  MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6302  break;
6303  }
6304  // fall through...
6305  case kMarkJumpBack|k_Repeat:
6306  case kMarkJumpBack: MarkJump(false); break;
6307  case kNext|k_Repeat:
6308  case kNext: if (Setup.AdaptiveSkipPrevNext) {
6309  MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false);
6310  break;
6311  }
6312  // fall through...
6314  case kMarkJumpForward: MarkJump(true); break;
6315  case kMarkMoveBack|k_Repeat:
6316  case kMarkMoveBack: MarkMove(-1, true); break;
6318  case kMarkMoveForward: MarkMove(+1, true); break;
6319  case kMarkSkipBack|k_Repeat:
6320  case kMarkSkipBack: MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6322  case kMarkSkipForward: MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
6323  case kEditCut: EditCut(); break;
6324  case kEditTest: EditTest(); break;
6325  default: {
6326  displayFrames = DisplayedFrames;
6327  switch (Key) {
6328  // Menu control:
6329  case kOk: if (visible && !modeOnly) {
6330  Hide();
6331  DoShowMode = true;
6332  }
6333  else
6334  Show();
6335  break;
6336  case kBack: Stop();
6337  return osRecordings;
6338  default: return osUnknown;
6339  }
6340  }
6341  }
6342  }
6343  }
6344  if (DoShowMode)
6345  ShowMode();
6346  return osContinue;
6347 }
cString ChannelString(const cChannel *Channel, int Number)
Definition: channels.c:1173
#define CA_ENCRYPTED_MIN
Definition: channels.h:44
#define CA_FTA
Definition: channels.h:39
#define LOCK_CHANNELS_READ
Definition: channels.h:273
#define LOCK_CHANNELS_WRITE
Definition: channels.h:274
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:284
cTimeMs timeout
Definition: menu.h:286
cAdaptiveSkipper(void)
Definition: menu.c:5750
eKeys lastKey
Definition: menu.h:285
void Initialize(int *InitialValue, double FramesPerSecond)
Definition: menu.c:5758
int * initialValue
Definition: menu.h:282
int currentValue
Definition: menu.h:283
int GetValue(eKeys Key)
Definition: menu.c:5765
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:106
const int * Caids(void) const
Definition: channels.h:174
int tpid
Definition: channels.h:119
int source
Definition: channels.h:103
char * shortName
Definition: channels.h:97
int vpid
Definition: channels.h:105
int frequency
Definition: channels.h:101
const int * Dpids(void) const
Definition: channels.h:160
int rid
Definition: channels.h:124
static cString ToText(const cChannel *Channel)
Definition: channels.c:555
int caids[MAXCAIDS+1]
Definition: channels.h:120
int nid
Definition: channels.h:121
int Vpid(void) const
Definition: channels.h:156
int Number(void) const
Definition: channels.h:181
const char * Name(void) const
Definition: channels.c:122
char * name
Definition: channels.h:96
int sid
Definition: channels.h:123
bool GroupSep(void) const
Definition: channels.h:183
int dpids[MAXDPIDS+1]
Definition: channels.h:111
const char * ShortName(bool OrName=false) const
Definition: channels.c:131
int tid
Definition: channels.h:122
int spids[MAXSPIDS+1]
Definition: channels.h:114
int apids[MAXAPIDS+1]
Definition: channels.h:108
const int * Apids(void) const
Definition: channels.h:159
char * portalName
Definition: channels.h:99
const char * Provider(void) const
Definition: channels.h:149
char * provider
Definition: channels.h:98
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition: channels.c:862
bool HasUniqueChannelID(const cChannel *NewChannel, const cChannel *OldChannel=NULL) const
Definition: channels.c:1086
static int MaxNumber(void)
Definition: channels.h:252
int GetPrevNormal(int Idx) const
Get previous normal channel (not group)
Definition: channels.c:931
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition: channels.c:857
void ReNumber(void)
Recalculate 'number' based on channel type.
Definition: channels.c:939
const cChannel * GetByNumber(int Number, int SkipGap=0) const
Definition: channels.c:1016
void SetModifiedByUser(void)
Definition: channels.c:1126
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition: channels.c:1044
bool SwitchTo(int Number) const
Definition: channels.c:1096
void Del(cChannel *Channel)
Delete the given Channel from the list.
Definition: channels.c:1008
int GetNextNormal(int Idx) const
Get next normal channel (not group)
Definition: channels.c:923
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:111
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:617
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition: device.c:1186
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:780
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: device.c:724
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition: device.c:222
eTrackType GetCurrentSubtitleTrack(void) const
Definition: device.h:603
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:230
eTrackType GetCurrentAudioTrack(void) const
Definition: device.h:599
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:825
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:167
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition: device.c:1815
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:371
void StopReplay(void)
Stops the current replay session (if any).
Definition: device.c:1421
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:1064
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1214
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:1143
static void SetCurrentChannel(int ChannelNumber)
Sets the number of the current channel on the primary device, without actually switching to it.
Definition: device.h:379
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition: device.c:1070
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:506
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:529
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1091
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1247
static int CurrentVolume(void)
Definition: device.h:652
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:1114
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition: device.c:1168
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:4868
virtual ~cDisplayChannel()
Definition: menu.c:4861
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:4895
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:4876
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4918
cDisplayChannel(int Number, bool Switched)
Definition: menu.c:4814
const cChannel * NextAvailableChannel(const cChannel *Channel, int Direction)
Definition: menu.c:4901
cSkinDisplayTracks * displayTracks
Definition: menu.h:182
cDisplaySubtitleTracks(void)
Definition: menu.c:5301
static void Process(eKeys Key)
Definition: menu.c:5354
char * descriptions[ttMaxTrackTypes+1]
Definition: menu.h:185
eTrackType types[ttMaxTrackTypes]
Definition: menu.h:184
virtual void Show(void)
Definition: menu.c:5336
static cDisplaySubtitleTracks * currentDisplayTracks
Definition: menu.h:187
virtual ~cDisplaySubtitleTracks()
Definition: menu.c:5327
static cDisplaySubtitleTracks * Create(void)
Definition: menu.c:5343
eOSState ProcessKey(eKeys Key)
Definition: menu.c:5360
char * descriptions[ttMaxTrackTypes+1]
Definition: menu.h:167
static cDisplayTracks * Create(void)
Definition: menu.c:5225
int track
Definition: menu.h:168
cDisplayTracks(void)
Definition: menu.c:5181
cTimeMs timeout
Definition: menu.h:165
virtual void Show(void)
Definition: menu.c:5215
virtual ~cDisplayTracks()
Definition: menu.c:5206
eOSState ProcessKey(eKeys Key)
Definition: menu.c:5242
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:5236
eTrackType types[ttMaxTrackTypes]
Definition: menu.h:166
static cDisplayVolume * Create(void)
Definition: menu.c:5135
cSkinDisplayVolume * displayVolume
Definition: menu.h:150
virtual ~cDisplayVolume()
Definition: menu.c:5124
eOSState ProcessKey(eKeys Key)
Definition: menu.c:5148
cTimeMs timeout
Definition: menu.h:151
static void Process(eKeys Key)
Definition: menu.c:5142
virtual void Show(void)
Definition: menu.c:5130
cDisplayVolume(void)
Definition: menu.c:5115
static cDisplayVolume * currentDisplayVolume
Definition: menu.h:152
void Append(const char *Title)
Definition: recording.c:3290
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:2045
void SetMarks(const cMarks *Marks)
Definition: dvbplayer.c:995
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition: dvbplayer.c:1050
void SkipSeconds(int Seconds)
Definition: dvbplayer.c:1037
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition: dvbplayer.c:1068
void Pause(void)
Definition: dvbplayer.c:1013
int SkipFrames(int Frames)
Definition: dvbplayer.c:1043
void Goto(int Index, bool Still=false)
Definition: dvbplayer.c:1073
void Stop(void)
Definition: dvbplayer.c:1006
void Forward(void)
Definition: dvbplayer.c:1025
bool Active(void)
Definition: dvbplayer.c:1001
bool GetFrameNumber(int &Current, int &Total)
Definition: dvbplayer.c:1059
void Play(void)
Definition: dvbplayer.c:1019
void Backward(void)
Definition: dvbplayer.c:1031
static void SetupChanged(void)
Definition: dvbsubtitle.c:1382
void ForceScan(void)
Definition: eitscan.c:129
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:440
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:2307
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2251
virtual void Move(int From, int To)
Definition: tools.c:2267
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:2316
void SetModified(void)
Unconditionally marks this list as modified.
Definition: tools.c:2321
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:612
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:2210
int Count(void) const
Definition: tools.h:640
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2219
void Sort(void)
Definition: tools.c:2343
cListObject * Prev(void) const
Definition: tools.h:559
int Index(void) const
Definition: tools.c:2139
cListObject * Next(void) const
Definition: tools.h:560
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:663
const T * Last(void) const
Returns the last element in this list, or NULL if the list is empty.
Definition: tools.h:658
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:656
const cOsdItem * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition: tools.h:653
const T * Prev(const T *Object) const
Definition: tools.h:660
void SetPosition(int Position)
Definition: recording.h:389
int Position(void) const
Definition: recording.h:387
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
Definition: recording.c:2438
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:2371
const cMark * GetNext(int Position) const
Definition: recording.c:2395
bool Update(void)
Definition: recording.c:2307
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition: recording.c:2295
const cMark * Get(int Position) const
Definition: recording.c:2377
static bool DeleteMarksFile(const cRecording *Recording)
Definition: recording.c:2284
bool Save(void)
Definition: recording.c:2338
const cMark * GetPrev(int Position) const
Definition: recording.c:2386
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:996
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:4568
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:4605
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4663
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition: menu.c:4521
static cOsdObject * pluginOsdObject
Definition: menu.h:113
static cOsdObject * PluginOsdObject(void)
Definition: menu.c:4561
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:4508
int PluginIndex(void)
Definition: menu.c:4505
int pluginIndex
Definition: menu.c:4502
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:2867
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:2821
void SetHelpKeys(void)
Definition: menu.c:2728
eOSState Delete(void)
Definition: menu.c:2839
const char * buttonDelete
Definition: menu.c:2662
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2913
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:3037
int Level(void) const
Definition: menu.c:3046
void IncrementCounter(bool New)
Definition: menu.c:3074
bool IsDirectory(void) const
Definition: menu.c:3048
const char * Name(void) const
Definition: menu.c:3045
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: menu.c:3082
void SetRecording(const cRecording *Recording)
Definition: menu.c:3049
const cRecording * Recording(void) const
Definition: menu.c:3047
cMenuRecordingItem(const cRecording *Recording, int Level)
Definition: menu.c:3053
virtual void Display(void)
Definition: menu.c:2979
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2991
const cRecording * recording
Definition: menu.c:2940
bool withButtons
Definition: menu.c:2943
bool RefreshRecording(void)
Definition: menu.c:2964
cString originalFileName
Definition: menu.c:2941
cStateKey recordingsStateKey
Definition: menu.c:2942
cMenuRecording(const cRecording *Recording, bool WithButtons=false)
Definition: menu.c:2951
static cString path
Definition: menu.h:217
void Set(bool Refresh=false)
Definition: menu.c:3144
bool Open(bool OpenSubMenus=false)
Definition: menu.c:3219
eOSState Sort(void)
Definition: menu.c:3390
static void SetRecording(const char *FileName)
Definition: menu.c:3203
eOSState Info(void)
Definition: menu.c:3362
eOSState Play(void)
Definition: menu.c:3235
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:3249
cStateKey recordingsStateKey
Definition: menu.h:214
cMenuRecordings(const char *Base=NULL, int Level=0, bool OpenSubMenus=false, const cRecordingFilter *Filter=NULL)
Definition: menu.c:3093
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3402
eOSState Commands(eKeys Key=kNone)
Definition: menu.c:3375
cString DirectoryName(void)
Definition: menu.c:3208
~cMenuRecordings()
Definition: menu.c:3114
void SetHelpKeys(void)
Definition: menu.c:3123
eOSState Delete(void)
Definition: menu.c:3315
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:3478
cSetup data
Definition: menu.c:3472
virtual void Store(void)
Definition: menu.c:3483
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition: menu.c:4000
cCamSlot * CamSlot(void)
Definition: menu.c:3996
bool Changed(void)
Definition: menu.c:4007
cCamSlot * camSlot
Definition: menu.c:3993
void SetHelpKeys(void)
Definition: menu.c:4071
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4166
cMenuSetupCAM(void)
Definition: menu.c:4056
eOSState Menu(void)
Definition: menu.c:4090
eOSState Reset(void)
Definition: menu.c:4154
eOSState Activate(void)
Definition: menu.c:4117
const char * activationHelp
Definition: menu.c:4046
int currentChannel
Definition: menu.c:4045
const char * updateChannelsTexts[6]
Definition: menu.c:3766
int numAudioLanguages
Definition: menu.c:3761
cMenuSetupDVB(void)
Definition: menu.c:3773
int originalNumSubtitleLanguages
Definition: menu.c:3762
void Setup(void)
Definition: menu.c:3800
int numSubtitleLanguages
Definition: menu.c:3763
const char * standardComplianceTexts[3]
Definition: menu.c:3767
int originalNumAudioLanguages
Definition: menu.c:3760
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3830
const char * videoDisplayFormatTexts[3]
Definition: menu.c:3765
int originalNumLanguages
Definition: menu.c:3666
int numLanguages
Definition: menu.c:3667
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3709
void Setup(void)
Definition: menu.c:3685
cMenuSetupEPG(void)
Definition: menu.c:3674
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3970
cSatCableNumbers satCableNumbers
Definition: menu.c:3915
cMenuSetupLNB(void)
Definition: menu.c:3922
void Setup(void)
Definition: menu.c:3931
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4328
void Set(void)
Definition: menu.c:4297
cMenuSetupMisc(void)
Definition: menu.c:4284
const char * svdrpPeeringModeTexts[3]
Definition: menu.c:4275
cStringList svdrpServerNames
Definition: menu.c:4277
const char * showChannelNamesWithSourceTexts[3]
Definition: menu.c:4276
virtual void Set(void)
Definition: menu.c:3541
virtual ~cMenuSetupOSD()
Definition: menu.c:3536
cStringList fontSmlNames
Definition: menu.c:3506
cStringList fontOsdNames
Definition: menu.c:3506
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3597
const char * recSortDirTexts[2]
Definition: menu.c:3496
const char * useSmallFontTexts[3]
Definition: menu.c:3494
int numSkins
Definition: menu.c:3499
cStringList fontFixNames
Definition: menu.c:3506
const char * recSortModeTexts[2]
Definition: menu.c:3495
int fontOsdIndex
Definition: menu.c:3507
const char * keyColorTexts[4]
Definition: menu.c:3497
int skinIndex
Definition: menu.c:3501
int originalSkinIndex
Definition: menu.c:3500
int originalThemeIndex
Definition: menu.c:3504
int fontFixIndex
Definition: menu.c:3507
const char ** skinDescriptions
Definition: menu.c:3502
cThemes themes
Definition: menu.c:3503
int themeIndex
Definition: menu.c:3505
int fontSmlIndex
Definition: menu.c:3507
cMenuSetupOSD(void)
Definition: menu.c:3515
int osdLanguageIndex
Definition: menu.c:3498
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1242
void SetSection(const char *Section)
Definition: menuitems.c:1237
void SetPlugin(cPlugin *Plugin)
Definition: menuitems.c:1257
cMenuSetupPluginItem(const char *Name, int Index)
Definition: menu.c:4368
int PluginIndex(void)
Definition: menu.c:4365
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4396
cMenuSetupPlugins(void)
Definition: menu.c:4382
const char * pauseKeyHandlingTexts[3]
Definition: menu.c:4194
const char * recordKeyHandlingTexts[3]
Definition: menu.c:4193
cMenuSetupRecord(void)
Definition: menu.c:4200
const char * delTimeshiftRecTexts[3]
Definition: menu.c:4195
virtual void Store(void)
Definition: menu.c:4262
cMenuSetupReplay(void)
Definition: menu.c:4241
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4472
virtual void Set(void)
Definition: menu.c:4443
cMenuSetup(void)
Definition: menu.c:4436
eOSState Restart(void)
Definition: menu.c:4463
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:525
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:492
cSkinDisplayMenu * DisplayMenu(void)
Definition: osdbase.h:107
void DisplayItem(cOsdItem *Item)
Definition: osdbase.c:315
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition: osdbase.c:517
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:536
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:2337
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:2310
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:837
Definition: thread.h:292
int Close(void)
Definition: thread.c:1001
bool Open(const char *Command, const char *Mode)
Definition: thread.c:947
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:250
virtual ~cRecordControl()
Definition: menu.c:5480
void Stop(bool ExecuteUserCommand=true)
Definition: menu.c:5512
cDevice * device
Definition: menu.h:239
cTimer * timer
Definition: menu.h:240
bool GetEvent(void)
Definition: menu.c:5488
char * fileName
Definition: menu.h:244
const char * InstantId(void)
Definition: menu.h:252
cRecorder * recorder
Definition: menu.h:241
cTimer * Timer(void)
Definition: menu.h:254
cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer=NULL, bool Pause=false)
Definition: menu.c:5398
const cEvent * event
Definition: menu.h:242
bool Process(time_t t)
Definition: menu.c:5534
cString instantId
Definition: menu.h:243
static bool StateChanged(int &State)
Definition: menu.c:5740
static const char * GetInstantId(const char *LastInstantId)
Definition: menu.c:5659
static void ChannelDataModified(const cChannel *Channel)
Definition: menu.c:5707
static bool Process(cTimers *Timers, time_t t)
Definition: menu.c:5692
static bool PauseLiveVideo(void)
Definition: menu.c:5644
static void Shutdown(void)
Definition: menu.c:5733
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition: menu.c:5549
static cRecordControl * RecordControls[]
Definition: menu.h:259
static bool Active(void)
Definition: menu.c:5724
static void Stop(const char *InstantId)
Definition: menu.c:5611
static cRecordControl * GetRecordControl(const char *FileName)
Definition: menu.c:5672
static int state
Definition: menu.h:260
static void ChangeState(void)
Definition: menu.h:276
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:91
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition: recording.c:2491
bool ChangePriorityLifetime(int NewPriority, int NewLifetime)
Changes the priority and lifetime of this recording to the given values.
Definition: recording.c:1303
bool HasMarks(void) const
Returns true if this recording has any editing marks.
Definition: recording.c:1257
bool WriteInfo(const char *OtherFileName=NULL)
Writes in info file of this recording.
Definition: recording.c:1275
int IsInUse(void) const
Checks whether this recording is currently in use and therefore shall not be tampered with.
Definition: recording.c:1418
bool ChangeName(const char *NewName)
Changes the name of this recording to the given value.
Definition: recording.c:1328
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:1355
const char * Name(void) const
Returns the full name of the recording (without the video directory).
Definition: recording.h:162
cString Folder(void) const
Returns the name of the folder this recording is stored in (without the video directory).
Definition: recording.c:1129
int Lifetime(void) const
Definition: recording.h:149
const char * FileName(void) const
Returns the full path name to the recording directory, including the video directory and the actual '...
Definition: recording.c:1141
cString BaseName(void) const
Returns the base name of this recording (without the video directory and folder).
Definition: recording.c:1136
int Priority(void) const
Definition: recording.h:148
cRecordingInfo * Info(void) const
Definition: recording.h:169
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition: recording.c:1159
double FramesPerSecond(void) const
Definition: recording.h:173
bool IsPesRecording(void) const
Definition: recording.h:194
void DelAll(void)
Deletes/terminates all operations.
Definition: recording.c:2192
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:2154
int GetUsage(const char *FileName)
Returns the usage type for the given FileName.
Definition: recording.c:2199
void Del(const char *FileName)
Deletes the given FileName from the list of operations.
Definition: recording.c:2185
static const cRecordings * GetRecordingsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for read access.
Definition: recording.h:260
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:1631
static cRecordings * GetRecordingsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of recordings for write access.
Definition: recording.h:263
void DelByName(const char *FileName)
Definition: recording.c:1694
const cRecording * GetByName(const char *FileName) const
Definition: recording.c:1668
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:5876
static const char * LastReplayed(void)
Definition: menu.c:5886
void MarkToggle(void)
Definition: menu.c:6091
static cString fileName
Definition: menu.h:312
void TimeSearchDisplay(void)
Definition: menu.c:6001
static void ClearLastReplayed(const char *FileName)
Definition: menu.c:5894
int lastTotal
Definition: menu.h:300
void MarkMove(int Frames, bool MarkRequired)
Definition: menu.c:6141
static cReplayControl * currentReplayControl
Definition: menu.h:311
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:6235
bool timeSearchHide
Definition: menu.h:305
void TimeSearchProcess(eKeys Key)
Definition: menu.c:6019
void MarkJump(bool Forward)
Definition: menu.c:6116
cMarks marks
Definition: menu.h:297
void EditCut(void)
Definition: menu.c:6179
int timeSearchTime
Definition: menu.h:306
cSkinDisplayReplay * displayReplay
Definition: menu.h:295
void Stop(void)
Definition: menu.c:5820
void ShowTimed(int Seconds=0)
Definition: menu.c:5900
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:6227
virtual void ClearEditingMarks(void)
Clears any editing marks this player might be showing.
Definition: menu.c:5866
bool lastForward
Definition: menu.h:301
bool displayFrames
Definition: menu.h:299
bool shown
Definition: menu.h:299
time_t timeoutShow
Definition: menu.h:303
void EditTest(void)
Definition: menu.c:6203
bool timeSearchActive
Definition: menu.h:305
virtual void Hide(void)
Definition: menu.c:5917
bool ShowProgress(bool Initial)
Definition: menu.c:5961
bool marksModified
Definition: menu.h:298
int lastSpeed
Definition: menu.h:302
cAdaptiveSkipper adaptiveSkipper
Definition: menu.h:296
bool lastPlay
Definition: menu.h:301
int timeSearchPos
Definition: menu.h:306
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition: menu.c:6219
void ShowMode(void)
Definition: menu.c:5936
virtual ~cReplayControl()
Definition: menu.c:5812
virtual void Show(void)
Definition: menu.c:5912
cTimeMs updateTimer
Definition: menu.h:304
void TimeSearch(void)
Definition: menu.c:6073
bool visible
Definition: menu.h:299
bool modeOnly
Definition: menu.h:299
static const char * NowReplaying(void)
Definition: menu.c:5881
cReplayControl(bool PauseLive=false)
Definition: menu.c:5789
int lastCurrent
Definition: menu.h:300
int Read(void)
Definition: recording.c:260
void Delete(void)
Definition: recording.c:343
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:1391
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition: epg.c:1286
static void ResetVersions(void)
Definition: epg.c:1317
Definition: config.h:252
int DefaultLifetime
Definition: config.h:311
int VolumeSteps
Definition: config.h:368
int EmergencyExit
Definition: config.h:374
int SplitEditedFiles
Definition: config.h:347
int RcRepeatDelay
Definition: config.h:309
int ColorKey3
Definition: config.h:324
int MenuScrollPage
Definition: config.h:271
int EPGBugfixLevel
Definition: config.h:301
int ColorKey2
Definition: config.h:324
int VideoDisplayFormat
Definition: config.h:325
int SubtitleFgTransparency
Definition: config.h:296
int MinUserInactivity
Definition: config.h:349
int AntiAlias
Definition: config.h:336
int ShowInfoOnChSwitch
Definition: config.h:269
int SkipSecondsRepeat
Definition: config.h:364
int StandardCompliance
Definition: config.h:290
char SVDRPDefaultHost[HOST_NAME_MAX]
Definition: config.h:306
bool Save(void)
Definition: config.c:738
int TimeoutRequChInfo
Definition: config.h:270
int ResumeID
Definition: config.h:365
char OSDTheme[MaxThemeName]
Definition: config.h:267
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:294
int SVDRPTimeout
Definition: config.h:303
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:320
int AdaptiveSkipInitial
Definition: config.h:359
int RecSortingDirection
Definition: config.h:322
int VpsMargin
Definition: config.h:317
char OSDLanguage[I18N_MAX_LOCALE_LEN]
Definition: config.h:265
int ShowChannelNamesWithSource
Definition: config.h:373
int DefaultPriority
Definition: config.h:311
int ZapTimeout
Definition: config.h:307
double OSDWidthP
Definition: config.h:331
int RecordKeyHandling
Definition: config.h:312
int PauseKeyHandling
Definition: config.h:313
double OSDHeightP
Definition: config.h:331
int PositionerSpeed
Definition: config.h:284
int MarginStart
Definition: config.h:291
double FontOsdSizeP
Definition: config.h:340
int PauseAtLastMark
Definition: config.h:358
int AdaptiveSkipPrevNext
Definition: config.h:362
int LnbFrequLo
Definition: config.h:278
int EPGPauseAfterScan
Definition: config.h:299
int UseSmallFont
Definition: config.h:335
int SubtitleOffset
Definition: config.h:295
int MarginStop
Definition: config.h:291
int SVDRPPeering
Definition: config.h:304
int ProgressDisplayTime
Definition: config.h:354
int UpdateChannels
Definition: config.h:327
int SkipSeconds
Definition: config.h:363
int SubtitleBgTransparency
Definition: config.h:296
int ColorKey0
Definition: config.h:324
int FoldersInTimerMenu
Definition: config.h:319
int MenuScrollWrap
Definition: config.h:272
int EPGLinger
Definition: config.h:302
int ShowReplayMode
Definition: config.h:352
int SiteLon
Definition: config.h:283
int AdaptiveSkipAlternate
Definition: config.h:361
int UseVps
Definition: config.h:316
int DisplaySubtitles
Definition: config.h:293
int ChannelInfoTime
Definition: config.h:330
int SiteLat
Definition: config.h:282
int VolumeLinearize
Definition: config.h:369
int ChannelsWrap
Definition: config.h:372
int EPGScanMaxChannel
Definition: config.h:298
double FontFixSizeP
Definition: config.h:342
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:292
int OSDMessageTime
Definition: config.h:334
int MarkInstantRecord
Definition: config.h:274
double OSDLeftP
Definition: config.h:331
int RecordingDirs
Definition: config.h:318
int PausePriority
Definition: config.h:314
double FontSmlSizeP
Definition: config.h:341
int AdaptiveSkipTimeout
Definition: config.h:360
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:337
int UseSubtitle
Definition: config.h:315
int MinEventTimeout
Definition: config.h:349
int ChannelInfoPos
Definition: config.h:329
int LnbFrequHi
Definition: config.h:279
char FontSml[MAXFONTNAME]
Definition: config.h:338
int MultiSpeedMode
Definition: config.h:351
int EPGScanTimeout
Definition: config.h:300
int TimeTransponder
Definition: config.h:289
int VideoFormat
Definition: config.h:326
int MaxVideoFileSize
Definition: config.h:346
cString DeviceBondings
Definition: config.h:377
int PositionerSwing
Definition: config.h:285
double OSDTopP
Definition: config.h:331
int PauseOnMarkSet
Definition: config.h:355
int DelTimeshiftRec
Definition: config.h:348
int SetSystemTime
Definition: config.h:287
int PrimaryDVB
Definition: config.h:268
int ChannelEntryTimeout
Definition: config.h:308
char FontFix[MAXFONTNAME]
Definition: config.h:339
int TimeSource
Definition: config.h:288
int UseDolbyDigital
Definition: config.h:328
int PauseOnMarkJump
Definition: config.h:356
int ColorKey1
Definition: config.h:324
int ShowRemainingTime
Definition: config.h:353
int CurrentDolby
Definition: config.h:370
cString InitialChannel
Definition: config.h:376
int DefaultSortModeRec
Definition: config.h:321
char SVDRPHostName[HOST_NAME_MAX]
Definition: config.h:305
int RcRepeatDelta
Definition: config.h:310
int InstantRecordTime
Definition: config.h:276
int NumberKeysForChars
Definition: config.h:323
int SkipEdited
Definition: config.h:357
int PauseLifetime
Definition: config.h:314
int InitialVolume
Definition: config.h:371
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 in 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 in 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:401
cTheme * Theme(void)
Definition: skins.h:421
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:420
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:467
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:867
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:862
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:856
int Find(const char *s) const
Definition: tools.c:1615
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:1174
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1180
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:404
uint64_t Elapsed(void) const
Definition: tools.c:807
void Set(int Ms=0)
Sets the timer.
Definition: tools.c:797
bool TimedOut(void) const
Definition: tools.c:802
Definition: timers.h:31
int Stop(void) const
Definition: timers.h:73
void OnOff(void)
Definition: timers.c:1054
cString PrintFirstDay(void) const
Definition: timers.c:432
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:45
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
Definition: timers.h:46
bool IsSingleEvent(void) const
Definition: timers.c:509
void SetPending(bool Pending)
Definition: timers.c:967
const char * Remote(void) const
Definition: timers.h:80
time_t StopTime(void) const
the stop time as given by the user
Definition: timers.c:744
time_t FirstDay(void) const
Definition: timers.h:78
bool Recording(void) const
Definition: timers.h:65
int priority
Definition: timers.h:49
char file[NAME_MAX *2+1]
Definition: timers.h:52
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:293
void SetFlags(uint Flags)
Definition: timers.c:1027
int Start(void) const
Definition: timers.h:72
int start
the start and stop time of this timer as given by the user,
Definition: timers.h:47
void SetDeferred(int Seconds)
Definition: timers.c:1021
bool IsPatternTimer(void) const
Definition: timers.h:97
int WeekDays(void) const
Definition: timers.h:71
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition: timers.c:398
void TriggerRespawn(void)
Definition: timers.c:875
time_t Day(void) const
Definition: timers.h:70
void SetRemote(const char *Remote)
Definition: timers.c:1015
char * remote
Definition: timers.h:54
bool SetEvent(const cEvent *Event)
Definition: timers.c:938
const cChannel * channel
Definition: timers.h:44
int stop
in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm
Definition: timers.h:48
bool Local(void) const
Definition: timers.h:81
void Skip(void)
Definition: timers.c:1047
const char * File(void) const
Definition: timers.h:77
time_t StartTime(void) const
the start time as given by the user
Definition: timers.c:737
bool Pending(void) const
Definition: timers.h:66
cString ToDescr(void) const
Definition: timers.c:329
const char * Pattern(void) const
Definition: timers.h:76
bool SetEventFromSchedule(const cSchedules *Schedules)
Definition: timers.c:889
int Priority(void) const
Definition: timers.h:74
void SetRecording(bool Recording)
Definition: timers.c:958
const cEvent * Event(void) const
Definition: timers.h:86
char pattern[NAME_MAX *2+1]
Definition: timers.h:51
static int GetMDay(time_t t)
Definition: timers.c:514
bool HasFlags(uint Flags) const
Definition: timers.c:1042
int lifetime
Definition: timers.h:50
int Id(void) const
Definition: timers.h:64
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
Definition: timers.c:569
uint flags
Definition: timers.h:43
cString ToText(bool UseChannelID=false) const
Definition: timers.c:319
const cChannel * Channel(void) const
Definition: timers.h:69
void Add(cTimer *Timer, cTimer *After=NULL)
Definition: timers.c:1210
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition: timers.c:1205
void Del(cTimer *Timer, bool DeleteObject=true)
Definition: timers.c:1224
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition: timers.c:1200
const cTimer * GetMatch(time_t t) const
Definition: timers.c:1127
int Size(void) const
Definition: tools.h:767
void Sort(__compar_fn_t Compare)
Definition: tools.h:824
virtual void Insert(T Data, int Before=0)
Definition: tools.h:768
virtual void Append(T Data)
Definition: tools.h:787
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:104
#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:249
int I18nNumLanguagesWithLocale(void)
Returns the number of entries in the list returned by I18nLanguages() that actually have a locale.
Definition: i18n.c:244
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition: i18n.c:231
const char * I18nLocale(int Language)
Returns the locale code of the given Language (which is an index as returned by I18nCurrentLanguage()...
Definition: i18n.c:266
void I18nSetLocale(const char *Locale)
Sets the current locale to Locale.
Definition: i18n.c:217
void I18nSetLanguage(int Language)
Sets the current language index to Language.
Definition: i18n.c:236
#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:5111
cOsdObject * CamControl(void)
Definition: menu.c:2490
#define MODETIMEOUT
Definition: menu.c:37
#define TRACKTIMEOUT
Definition: menu.c:5177
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:5486
#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:5110
#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:3263
static bool HandleRemoteModifications(cTimer *NewTimer, cTimer *OldTimer=NULL)
Definition: menu.c:1136
#define MAXWAIT4EPGINFO
Definition: menu.c:36
#define STOP_RECORDING
Definition: menu.c:4517
static void SetTrackDescriptions(int LiveChannel)
Definition: menu.c:4768
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:3441
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition: recording.c:3336
char * ExchangeChars(char *s, bool ToFileSystem)
Definition: recording.c:675
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:152
void GetRecordingsSortMode(const char *Directory)
Definition: recording.c:3393
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition: recording.c:3363
eRecordingsSortMode RecordingsSortMode
Definition: recording.c:3386
bool EnoughFreeDiskSpaceForEdit(const char *FileName)
Definition: recording.c:3473
void IncRecordingsSortMode(const char *Directory)
Definition: recording.c:3412
cDoneRecordings DoneRecordingsPattern
Definition: recording.c:3243
cRecordingsHandler RecordingsHandler
Definition: recording.c:2102
void SetRecordingTimerId(const char *Directory, const char *TimerId)
Definition: recording.c:3423
@ ruCut
Definition: recording.h:34
@ ruCopy
Definition: recording.h:36
@ ruDst
Definition: recording.h:39
@ ruNone
Definition: recording.h:30
@ ruMove
Definition: recording.h:35
@ ruPending
Definition: recording.h:41
#define RUC_BEFORERECORDING
Definition: recording.h:449
@ rsmName
Definition: recording.h:578
#define RUC_AFTERRECORDING
Definition: recording.h:451
#define LOCK_RECORDINGS_READ
Definition: recording.h:327
#define MAXVIDEOFILESIZETS
Definition: recording.h:476
#define FOLDERDELIMCHAR
Definition: recording.h:22
#define LOCK_RECORDINGS_WRITE
Definition: recording.h:328
#define MINVIDEOFILESIZE
Definition: recording.h:478
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:2839
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:2848
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:2857
void StartSVDRPHandler(void)
Definition: svdrp.c:2823
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:1414
#define LOCK_TIMERS_READ
Definition: timers.h:246
#define LOCK_TIMERS_WRITE
Definition: timers.h:247
@ 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:218
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
bool isempty(const char *s)
Definition: tools.c:354
cString strescape(const char *s, const char *chars)
Definition: tools.c:277
int strcountchr(const char *s, char c)
returns the number of occurrences of 'c' in 's'.
Definition: tools.c:196
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:904
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition: tools.c:504
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1203
char * strreplace(char *s, char c1, char c2)
Definition: tools.c:139
char * stripspace(char *s)
Definition: tools.c:224
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:879
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:183
cString itoa(int n)
Definition: tools.c:447
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:407
char * skipspace(const char *s)
Definition: tools.h:244
#define SECSINDAY
Definition: tools.h:42
#define dsyslog(a...)
Definition: tools.h:37
int CompareInts(const void *a, const void *b)
Definition: tools.h:830
#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