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