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:
280 private:
283 public:
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:
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:
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;
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;
2840 public:
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 
2876 void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
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;
3242  virtual void Set(void);
3243 public:
3244  cMenuSetupOSD(void);
3245  virtual ~cMenuSetupOSD();
3246  virtual eOSState ProcessKey(eKeys Key);
3247  };
3248 
3250 {
3253  numSkins = Skins.Count();
3255  skinDescriptions = new const char*[numSkins];
3256  themes.Load(Skins.Current()->Name());
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) {
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()) {
3342  ModifiedAppearance |= themeIndex != originalThemeIndex;
3343  }
3345  ModifiedAppearance = true;
3347  ModifiedAppearance = true;
3352  ModifiedAppearance = true;
3354  ModifiedAppearance = true;
3356  ModifiedAppearance = true;
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) {
3372  int OriginalOSDLanguage = I18nCurrentLanguage();
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 {
3406  ;
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  }
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 {
3503  ;
3505  ;
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  }
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  }
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)
3628  cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
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:
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 {
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 {
4041 
4042  if (Key == kOk) {
4043  if (state == osUnknown) {
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:
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()
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()
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
5099  }
5100  else
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();
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) {
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  }
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)) {
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++)
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 
5693 void cReplayControl::MarkJump(bool Forward)
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
int fontOsdIndex
Definition: menu.c:3241
cChannel * Channel(void)
Definition: menu.c:290
const char * videoDisplayFormatTexts[3]
Definition: menu.c:3491
#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
void SetRecording(bool Recording)
Definition: timers.c:585
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
bool Load(const char *SkinName)
Definition: themes.c:239
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
int currentValue
Definition: menu.h:276
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
cDevice * Device(void)
Definition: menu.h:245
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
cTimeMs timeout
Definition: menu.h:279
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
cStringList fontOsdNames
Definition: menu.c:3240
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
int * initialValue
Definition: menu.h:275
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
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition: device.c:1663
Definition: menu.h:22
char * fileName
Definition: menu.h:239
bool confirm
Definition: menu.h:63
cChannel * channel
Definition: timers.h:35
virtual bool CanActivate(void)
Returns true if there is a CAM in this slot that can be put into activation mode. ...
Definition: ci.c:1914
char FontSml[MAXFONTNAME]
Definition: config.h: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
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 'M' 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
int MenuKeyCloses
Definition: config.h:267
eOSState SetFolder(void)
Definition: menu.c:901
void SetPosition(int Position)
Definition: recording.h:346
void SetText(const char *Text)
Definition: config.c:156
virtual ~cMenuSchedule()
Definition: menu.c: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
int ColorKey2
Definition: config.h:311
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 GetThemeIndex(const char *Description)
Definition: themes.c:283
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 eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition: ci.c:1945
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
cString instantId
Definition: menu.h:238
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
eKeys lastKey
Definition: menu.h:278
eOSState Number(eKeys Key)
Definition: menu.c:424
Definition: skins.h:107
bool ChangeName(const char *NewName)
Changes the name of this recording to the given value.
Definition: recording.c: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'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
int TimeTransponder
Definition: config.h:283
static cString fileName
Definition: menu.h:212
virtual bool SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New)
Sets the item at the given Index to Recording.
Definition: skins.h:240
static const char * Name(void)
Definition: videodir.c:53
virtual 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
int fontFixIndex
Definition: menu.c:3241
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
bool Selectable(void) const
Definition: osdbase.h:60
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
int NumberKeysForChars
Definition: config.h:310
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
const char * useSmallFontTexts[3]
Definition: menu.c:3230
#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
const char * standardComplianceTexts[3]
Definition: menu.c:3493
Definition: keys.h:40
virtual void Insert(T Data, int Before=0)
Definition: tools.h:552
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
int SubtitleFgTransparency
Definition: config.h:291
void TimeSearch(void)
Definition: menu.c:5649
char diskStatus
Definition: menu.c:1076
const char *const * Descriptions(void)
Definition: themes.h:76
cMenuSetup(void)
Definition: menu.c:4079
virtual ~cDisplayVolume()
Definition: menu.c:4750
int ChannelInfoPos
Definition: config.h:316
void SetFirstDayItem(void)
Definition: menu.c:989
const char * Text(void)
Definition: ci.h:66
virtual bool HasUserIO(void)
Returns true if there is a pending user interaction, which shall be retrieved via GetMenu() or GetEnq...
Definition: ci.c:1976
double framesPerSecond
Definition: menu.h:277
void SetHelpKeys(void)
Definition: menu.c: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
cDevice * device
Definition: menu.h:234
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
bool IsAttached(void)
Returns true if this receiver is (still) attached to a device.
Definition: receiver.h:77
void DescendPath(const char *Path)
Definition: menu.c:836
eOSState Confirm(void)
Definition: menu.c:687
eOSState SetFolder(void)
Definition: menu.c: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 SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:289
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 TimeSource
Definition: config.h:282
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
int EPGScanTimeout
Definition: config.h:293
cSchedulesLock schedulesLock
Definition: menu.c:1783
int SubtitleOffset
Definition: config.h:290
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
cRecorder * recorder
Definition: menu.h:236
static time_t IncDay(time_t t, int Days)
Definition: timers.c:369
#define RUC_AFTERRECORDING
Definition: recording.h:397
int ColorKey3
Definition: config.h:311
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 'c' 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
cStringList fontFixNames
Definition: menu.c:3240
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
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:205
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
const char * Name(int Index)
Definition: themes.h:74
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 SetSystemTime
Definition: config.h:281
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
int UseDolbyDigital
Definition: config.h:315
#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 'c' in 's'.
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
const char * delTimeshiftRecTexts[3]
Definition: menu.c:3902
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:286
cMenuFolder(const char *Title, cList< cNestedItem > *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path=NULL)
Definition: menu.c:745
static cOsdObject * pluginOsdObject
Definition: menu.h:107
void Reply(const char *s)
Definition: ci.c:1372
int ColorKey1
Definition: config.h:311
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 'true' 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
void SetDeferred(int Seconds)
Definition: timers.c:643
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
int UpdateChannels
Definition: config.h:314
const char * pauseKeyHandlingTexts[3]
Definition: menu.c:3901
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
static void ChangeState(void)
Definition: menu.h:269
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition: recording.c: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
int EPGBugfixLevel
Definition: config.h:294
const cEvent * event
Definition: menu.h:237
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
int ColorKey0
Definition: config.h:311
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...
int MenuScrollWrap
Definition: config.h:266
#define kMarkJumpBack
Definition: keys.h:72
void PrepareScheduleThisThis(const cEvent *Event, const cChannel *Channel)
Definition: menu.c:1846
cSourceParam * sourceParam
Definition: menu.c:164
int MenuScrollPage
Definition: config.h:265
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
int SupportTeletext
Definition: config.h:288
virtual void Set(void)
Definition: menu.c:317
cMenuCam(cCamSlot *CamSlot)
Definition: menu.c:2200
int AdaptiveSkipInitial
Definition: config.h:347
const char * keyColorTexts[4]
Definition: menu.c:3231
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
const char * updateChannelsTexts[6]
Definition: menu.c:3492
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
const char * FileName(int Index)
Definition: themes.h:75
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'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
char OSDTheme[MaxThemeName]
Definition: config.h:261
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
char OSDSkin[MaxSkinName]
Definition: config.h:260
bool Save(void)
Definition: config.c:258
int OSDMessageTime
Definition: config.h:321
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 '...
Definition: recording.c:1042
cTimer * timer
Definition: menu.h:235
cMenuEditDateItem * day
Definition: menu.h:80
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition: osdbase.c:549
int NumThemes(void)
Definition: themes.h:73
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
char OSDLanguage[I18N_MAX_LOCALE_LEN]
Definition: config.h:259
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
int SubtitleBgTransparency
Definition: config.h:291
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