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 cMenuEditBoolItem(tr("Setup.DVB$Use automatic channel numbering"), &data.UseAutoChannelNumbering));
3540  Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
3541  for (int i = 0; i < numAudioLanguages; i++)
3542  Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3543  Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
3544  if (data.DisplaySubtitles) {
3545  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
3546  for (int i = 0; i < numSubtitleLanguages; i++)
3547  Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
3548  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -100, 100));
3549  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
3550  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
3551  }
3552  Add(new cMenuEditBoolItem(tr("Setup.DVB$Enable teletext support"), &data.SupportTeletext));
3553 
3554  SetCurrent(Get(current));
3555  Display();
3556 }
3557 
3559 {
3560  int oldPrimaryDVB = ::Setup.PrimaryDVB;
3561  int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
3562  bool oldVideoFormat = ::Setup.VideoFormat;
3563  bool newVideoFormat = data.VideoFormat;
3564  bool oldUseAutoChannelNumbering = ::Setup.UseAutoChannelNumbering;
3565  bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
3566  bool newDisplaySubtitles = data.DisplaySubtitles;
3567  int oldnumAudioLanguages = numAudioLanguages;
3568  int oldnumSubtitleLanguages = numSubtitleLanguages;
3569  eOSState state = cMenuSetupBase::ProcessKey(Key);
3570 
3571  if (Key != kNone) {
3572  switch (Key) {
3573  case kGreen: cRemote::Put(kAudio, true);
3574  state = osEnd;
3575  break;
3576  case kYellow: cRemote::Put(kSubtitles, true);
3577  state = osEnd;
3578  break;
3579  default: {
3580  bool DoSetup = data.VideoFormat != newVideoFormat;
3581  DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
3582  if (numAudioLanguages != oldnumAudioLanguages) {
3583  for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
3584  data.AudioLanguages[i] = 0;
3585  for (int l = 0; l < I18nLanguages()->Size(); l++) {
3586  int k;
3587  for (k = 0; k < oldnumAudioLanguages; k++) {
3588  if (data.AudioLanguages[k] == l)
3589  break;
3590  }
3591  if (k >= oldnumAudioLanguages) {
3592  data.AudioLanguages[i] = l;
3593  break;
3594  }
3595  }
3596  }
3598  DoSetup = true;
3599  }
3600  if (numSubtitleLanguages != oldnumSubtitleLanguages) {
3601  for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
3602  data.SubtitleLanguages[i] = 0;
3603  for (int l = 0; l < I18nLanguages()->Size(); l++) {
3604  int k;
3605  for (k = 0; k < oldnumSubtitleLanguages; k++) {
3606  if (data.SubtitleLanguages[k] == l)
3607  break;
3608  }
3609  if (k >= oldnumSubtitleLanguages) {
3610  data.SubtitleLanguages[i] = l;
3611  break;
3612  }
3613  }
3614  }
3616  DoSetup = true;
3617  }
3618  if (DoSetup)
3619  Setup();
3620  }
3621  }
3622  }
3623  if (state == osBack && Key == kOk) {
3624  if (::Setup.PrimaryDVB != oldPrimaryDVB)
3625  state = osSwitchDvb;
3626  if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
3628  if (::Setup.VideoFormat != oldVideoFormat)
3629  cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
3630  if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
3632  if (::Setup.UseAutoChannelNumbering != oldUseAutoChannelNumbering)
3633  Channels.ReNumber();
3635  }
3636  return state;
3637 }
3638 
3639 // --- cMenuSetupLNB ---------------------------------------------------------
3640 
3642 private:
3644  void Setup(void);
3645 public:
3646  cMenuSetupLNB(void);
3647  virtual eOSState ProcessKey(eKeys Key);
3648  };
3649 
3651 :satCableNumbers(MAXDEVICES)
3652 {
3655  SetSection(tr("LNB"));
3656  Setup();
3657 }
3658 
3660 {
3661  int current = Current();
3662 
3663  Clear();
3664 
3665  Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
3666  if (!data.DiSEqC) {
3667  Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
3668  Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
3669  Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
3670  }
3671 
3672  int NumSatDevices = 0;
3673  for (int i = 0; i < cDevice::NumDevices(); i++) {
3675  NumSatDevices++;
3676  }
3677  if (NumSatDevices > 1) {
3678  for (int i = 0; i < cDevice::NumDevices(); i++) {
3680  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")));
3681  else
3682  satCableNumbers.Array()[i] = 0;
3683  }
3684  }
3685 
3686  Add(new cMenuEditBoolItem(tr("Setup.LNB$Use dish positioner"), &data.UsePositioner));
3687  if (data.UsePositioner) {
3688  Add(new cMenuEditIntxItem(tr("Setup.LNB$Site latitude (degrees)"), &data.SiteLat, -900, 900, 10, tr("South"), tr("North")));
3689  Add(new cMenuEditIntxItem(tr("Setup.LNB$Site longitude (degrees)"), &data.SiteLon, -1800, 1800, 10, tr("West"), tr("East")));
3690  Add(new cMenuEditIntxItem(tr("Setup.LNB$Max. positioner swing (degrees)"), &data.PositionerSwing, 0, 900, 10));
3691  Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed (degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
3692  }
3693 
3694  SetCurrent(Get(current));
3695  Display();
3696 }
3697 
3699 {
3700  int oldDiSEqC = data.DiSEqC;
3701  int oldUsePositioner = data.UsePositioner;
3702  bool DeviceBondingsChanged = false;
3703  if (Key == kOk) {
3704  cString NewDeviceBondings = satCableNumbers.ToString();
3705  DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
3706  data.DeviceBondings = NewDeviceBondings;
3707  }
3708  eOSState state = cMenuSetupBase::ProcessKey(Key);
3709 
3710  if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner != oldUsePositioner))
3711  Setup();
3712  else if (DeviceBondingsChanged)
3714  return state;
3715 }
3716 
3717 // --- cMenuSetupCAM ---------------------------------------------------------
3718 
3719 class cMenuSetupCAMItem : public cOsdItem {
3720 private:
3722 public:
3724  cCamSlot *CamSlot(void) { return camSlot; }
3725  bool Changed(void);
3726  };
3727 
3729 {
3730  camSlot = CamSlot;
3731  SetText("");
3732  Changed();
3733 }
3734 
3736 {
3737  const char *Activating = "";
3738  const char *CamName = camSlot->GetCamName();
3739  if (!CamName) {
3740  switch (camSlot->ModuleStatus()) {
3741  case msReset: CamName = tr("CAM reset"); break;
3742  case msPresent: CamName = tr("CAM present"); break;
3743  case msReady: CamName = tr("CAM ready"); break;
3744  default: CamName = "-"; break;
3745  }
3746  }
3747  else if (camSlot->IsActivating())
3748  // TRANSLATORS: note the leading blank!
3749  Activating = tr(" (activating)");
3750  cString buffer = cString::sprintf(" %d %s%s", camSlot->SlotNumber(), CamName, Activating);
3751  if (strcmp(buffer, Text()) != 0) {
3752  SetText(buffer);
3753  return true;
3754  }
3755  return false;
3756 }
3757 
3759 private:
3760  const char *activationHelp;
3761  eOSState Menu(void);
3762  eOSState Reset(void);
3763  eOSState Activate(void);
3764  void SetHelpKeys(void);
3765 public:
3766  cMenuSetupCAM(void);
3767  virtual eOSState ProcessKey(eKeys Key);
3768  };
3769 
3771 {
3772  activationHelp = NULL;
3774  SetSection(tr("CAM"));
3775  SetCols(15);
3776  SetHasHotkeys();
3777  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
3778  Add(new cMenuSetupCAMItem(CamSlot));
3779  SetHelpKeys();
3780 }
3781 
3783 {
3784  if (HasSubMenu())
3785  return;
3787  const char *NewActivationHelp = "";
3788  if (item) {
3789  cCamSlot *CamSlot = item->CamSlot();
3790  if (CamSlot->IsActivating())
3791  NewActivationHelp = tr("Button$Cancel activation");
3792  else if (CamSlot->CanActivate())
3793  NewActivationHelp = tr("Button$Activate");
3794  }
3795  if (NewActivationHelp != activationHelp) {
3796  activationHelp = NewActivationHelp;
3797  SetHelp(tr("Button$Menu"), tr("Button$Reset"), activationHelp);
3798  }
3799 }
3800 
3802 {
3804  if (item) {
3805  if (item->CamSlot()->EnterMenu()) {
3806  Skins.Message(mtStatus, tr("Opening CAM menu..."));
3807  time_t t0 = time(NULL);
3808  time_t t1 = t0;
3809  while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
3810  if (item->CamSlot()->HasUserIO())
3811  break;
3812  if (time(NULL) - t1 >= CAMMENURETYTIMEOUT) {
3813  dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
3814  item->CamSlot()->EnterMenu();
3815  t1 = time(NULL);
3816  }
3817  cCondWait::SleepMs(100);
3818  }
3819  Skins.Message(mtStatus, NULL);
3820  if (item->CamSlot()->HasUserIO())
3821  return AddSubMenu(new cMenuCam(item->CamSlot()));
3822  }
3823  Skins.Message(mtError, tr("Can't open CAM menu!"));
3824  }
3825  return osContinue;
3826 }
3827 
3829 {
3831  if (item) {
3832  cCamSlot *CamSlot = item->CamSlot();
3833  if (CamSlot->IsActivating())
3834  CamSlot->CancelActivation();
3835  else if (CamSlot->CanActivate()) {
3836  if (CamSlot->Priority() < LIVEPRIORITY) { // don't interrupt recordings
3838  for (int i = 0; i < cDevice::NumDevices(); i++) {
3839  if (cDevice *Device = cDevice::GetDevice(i)) {
3840  if (Device->ProvidesChannel(Channel)) {
3841  if (Device->Priority() < LIVEPRIORITY) { // don't interrupt recordings
3842  if (CamSlot->CanActivate()) {
3843  if (CamSlot->Assign(Device, true)) { // query
3844  cControl::Shutdown(); // must end transfer mode before assigning CAM, otherwise it might be unassigned again
3845  if (CamSlot->Assign(Device)) {
3846  if (Device->SwitchChannel(Channel, true)) {
3847  CamSlot->StartActivation();
3848  return osContinue;
3849  }
3850  }
3851  }
3852  }
3853  }
3854  }
3855  }
3856  }
3857  }
3858  }
3859  Skins.Message(mtError, tr("Can't activate CAM!"));
3860  }
3861  }
3862  return osContinue;
3863 }
3864 
3866 {
3868  if (item) {
3869  if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
3870  if (!item->CamSlot()->Reset())
3871  Skins.Message(mtError, tr("Can't reset CAM!"));
3872  }
3873  }
3874  return osContinue;
3875 }
3876 
3878 {
3880 
3881  if (!HasSubMenu()) {
3882  switch (Key) {
3883  case kOk:
3884  case kRed: return Menu();
3885  case kGreen: state = Reset(); break;
3886  case kYellow: state = Activate(); break;
3887  default: break;
3888  }
3889  for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
3890  if (ci->Changed())
3891  DisplayItem(ci);
3892  }
3893  SetHelpKeys();
3894  }
3895  return state;
3896 }
3897 
3898 // --- cMenuSetupRecord ------------------------------------------------------
3899 
3901 private:
3902  const char *pauseKeyHandlingTexts[3];
3903  const char *delTimeshiftRecTexts[3];
3904 public:
3905  cMenuSetupRecord(void);
3906  };
3907 
3909 {
3911  pauseKeyHandlingTexts[0] = tr("do not pause live video");
3912  pauseKeyHandlingTexts[1] = tr("confirm pause live video");
3913  pauseKeyHandlingTexts[2] = tr("pause live video");
3914  delTimeshiftRecTexts[0] = tr("no");
3915  delTimeshiftRecTexts[1] = tr("confirm");
3916  delTimeshiftRecTexts[2] = tr("yes");
3917  SetSection(tr("Recording"));
3918  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
3919  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
3920  Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
3921  Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
3922  Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
3923  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
3924  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
3925  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
3926  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
3927  Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
3928  Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
3929  Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
3930  Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
3931  Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
3932  Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
3933  Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
3934  Add(new cMenuEditBoolItem(tr("Setup.Recording$Dump NALU Fill data"), &data.DumpNaluFill));
3935 }
3936 
3937 // --- cMenuSetupReplay ------------------------------------------------------
3938 
3940 protected:
3941  virtual void Store(void);
3942 public:
3943  cMenuSetupReplay(void);
3944  };
3945 
3947 {
3949  SetSection(tr("Replay"));
3950  Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
3951  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
3952  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
3953  Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
3954  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
3955  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when jumping to a mark"), &data.PauseOnMarkJump));
3956  Add(new cMenuEditBoolItem(tr("Setup.Replay$Skip edited parts"), &data.SkipEdited));
3957  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay at last mark"), &data.PauseAtLastMark));
3958  Add(new cMenuEditIntItem( tr("Setup.Replay$Initial duration for adaptive skipping (s)"), &data.AdaptiveSkipInitial, 10, 600));
3959  Add(new cMenuEditIntItem( tr("Setup.Replay$Reset timeout for adaptive skipping (s)"), &data.AdaptiveSkipTimeout, 0, 10));
3960  Add(new cMenuEditBoolItem(tr("Setup.Replay$Alternate behavior for adaptive skipping"), &data.AdaptiveSkipAlternate));
3961  Add(new cMenuEditBoolItem(tr("Setup.Replay$Use Prev/Next keys for adaptive skipping"), &data.AdaptiveSkipPrevNext));
3962  Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys (s)"), &data.SkipSeconds, 5, 600));
3963  Add(new cMenuEditIntItem( tr("Setup.Replay$Skip distance with Green/Yellow keys in repeat (s)"), &data.SkipSecondsRepeat, 5, 600));
3964  Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
3965 }
3966 
3968 {
3969  if (Setup.ResumeID != data.ResumeID)
3972 }
3973 
3974 // --- cMenuSetupMisc --------------------------------------------------------
3975 
3977 public:
3978  cMenuSetupMisc(void);
3979  };
3980 
3982 {
3984  SetSection(tr("Miscellaneous"));
3985  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
3986  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
3987  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
3988  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
3989  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
3990  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0));
3991  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0));
3992  Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
3993  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
3994  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume steps"), &data.VolumeSteps, 5, 255));
3995  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Volume linearize"), &data.VolumeLinearize, -20, 20));
3996  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
3997  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource));
3998  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
3999 }
4000 
4001 // --- cMenuSetupPluginItem --------------------------------------------------
4002 
4004 private:
4006 public:
4007  cMenuSetupPluginItem(const char *Name, int Index);
4008  int PluginIndex(void) { return pluginIndex; }
4009  };
4010 
4012 :cOsdItem(Name)
4013 {
4014  pluginIndex = Index;
4015 }
4016 
4017 // --- cMenuSetupPlugins -----------------------------------------------------
4018 
4020 public:
4021  cMenuSetupPlugins(void);
4022  virtual eOSState ProcessKey(eKeys Key);
4023  };
4024 
4026 {
4028  SetSection(tr("Plugins"));
4029  SetHasHotkeys();
4030  for (int i = 0; ; i++) {
4032  if (p)
4033  Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
4034  else
4035  break;
4036  }
4037 }
4038 
4040 {
4042 
4043  if (Key == kOk) {
4044  if (state == osUnknown) {
4046  if (item) {
4048  if (p) {
4049  cMenuSetupPage *menu = p->SetupMenu();
4050  if (menu) {
4051  menu->SetPlugin(p);
4052  return AddSubMenu(menu);
4053  }
4054  Skins.Message(mtInfo, tr("This plugin has no setup parameters!"));
4055  }
4056  }
4057  }
4058  else if (state == osContinue) {
4059  Store();
4060  // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
4062  SetDisplayMenu();
4063  Display();
4064  }
4065  }
4066  return state;
4067 }
4068 
4069 // --- cMenuSetup ------------------------------------------------------------
4070 
4071 class cMenuSetup : public cOsdMenu {
4072 private:
4073  virtual void Set(void);
4074  eOSState Restart(void);
4075 public:
4076  cMenuSetup(void);
4077  virtual eOSState ProcessKey(eKeys Key);
4078  };
4079 
4081 :cOsdMenu("")
4082 {
4084  Set();
4085 }
4086 
4088 {
4089  Clear();
4090  char buffer[64];
4091  snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
4092  SetTitle(buffer);
4093  SetHasHotkeys();
4094  Add(new cOsdItem(hk(tr("OSD")), osUser1));
4095  Add(new cOsdItem(hk(tr("EPG")), osUser2));
4096  Add(new cOsdItem(hk(tr("DVB")), osUser3));
4097  Add(new cOsdItem(hk(tr("LNB")), osUser4));
4098  Add(new cOsdItem(hk(tr("CAM")), osUser5));
4099  Add(new cOsdItem(hk(tr("Recording")), osUser6));
4100  Add(new cOsdItem(hk(tr("Replay")), osUser7));
4101  Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
4103  Add(new cOsdItem(hk(tr("Plugins")), osUser9));
4104  Add(new cOsdItem(hk(tr("Restart")), osUser10));
4105 }
4106 
4108 {
4109  if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
4110  ShutdownHandler.Exit(1);
4111  return osEnd;
4112  }
4113  return osContinue;
4114 }
4115 
4117 {
4118  int osdLanguage = I18nCurrentLanguage();
4119  eOSState state = cOsdMenu::ProcessKey(Key);
4120 
4121  switch (state) {
4122  case osUser1: return AddSubMenu(new cMenuSetupOSD);
4123  case osUser2: return AddSubMenu(new cMenuSetupEPG);
4124  case osUser3: return AddSubMenu(new cMenuSetupDVB);
4125  case osUser4: return AddSubMenu(new cMenuSetupLNB);
4126  case osUser5: return AddSubMenu(new cMenuSetupCAM);
4127  case osUser6: return AddSubMenu(new cMenuSetupRecord);
4128  case osUser7: return AddSubMenu(new cMenuSetupReplay);
4129  case osUser8: return AddSubMenu(new cMenuSetupMisc);
4130  case osUser9: return AddSubMenu(new cMenuSetupPlugins);
4131  case osUser10: return Restart();
4132  default: ;
4133  }
4134  if (I18nCurrentLanguage() != osdLanguage) {
4135  Set();
4136  if (!HasSubMenu())
4137  Display();
4138  }
4139  return state;
4140 }
4141 
4142 // --- cMenuPluginItem -------------------------------------------------------
4143 
4144 class cMenuPluginItem : public cOsdItem {
4145 private:
4147 public:
4148  cMenuPluginItem(const char *Name, int Index);
4149  int PluginIndex(void) { return pluginIndex; }
4150  };
4151 
4152 cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
4153 :cOsdItem(Name, osPlugin)
4154 {
4155  pluginIndex = Index;
4156 }
4157 
4158 // --- cMenuMain -------------------------------------------------------------
4159 
4160 // TRANSLATORS: note the leading and trailing blanks!
4161 #define STOP_RECORDING trNOOP(" Stop recording ")
4162 
4164 
4165 cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
4166 :cOsdMenu("")
4167 {
4169  replaying = false;
4170  stopReplayItem = NULL;
4171  cancelEditingItem = NULL;
4172  stopRecordingItem = NULL;
4173  recordControlsState = 0;
4174  Set();
4175 
4176  // Initial submenus:
4177 
4178  cOsdObject *menu = NULL;
4179  switch (State) {
4180  case osSchedule:
4181  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4182  menu = new cMenuSchedule;
4183  break;
4184  case osChannels:
4185  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4186  menu = new cMenuChannels;
4187  break;
4188  case osTimers:
4189  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4190  menu = new cMenuTimers;
4191  break;
4192  case osRecordings:
4193  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4194  menu = new cMenuRecordings(NULL, 0, OpenSubMenus);
4195  break;
4196  case osSetup: menu = new cMenuSetup; break;
4197  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4198  default: break;
4199  }
4200  if (menu)
4201  if (menu->IsMenu())
4202  AddSubMenu((cOsdMenu *) menu);
4203 }
4204 
4206 {
4208  pluginOsdObject = NULL;
4209  return o;
4210 }
4211 
4212 void cMenuMain::Set(void)
4213 {
4214  Clear();
4215  SetTitle("VDR");
4216  SetHasHotkeys();
4217 
4218  // Basic menu items:
4219 
4220  Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
4221  Add(new cOsdItem(hk(tr("Channels")), osChannels));
4222  Add(new cOsdItem(hk(tr("Timers")), osTimers));
4223  Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
4224 
4225  // Plugins:
4226 
4227  for (int i = 0; ; i++) {
4229  if (p) {
4230  const char *item = p->MainMenuEntry();
4231  if (item)
4232  Add(new cMenuPluginItem(hk(item), i));
4233  }
4234  else
4235  break;
4236  }
4237 
4238  // More basic menu items:
4239 
4240  Add(new cOsdItem(hk(tr("Setup")), osSetup));
4241  if (Commands.Count())
4242  Add(new cOsdItem(hk(tr("Commands")), osCommands));
4243 
4244  Update(true);
4245 
4246  Display();
4247 }
4248 
4249 bool cMenuMain::Update(bool Force)
4250 {
4251  bool result = false;
4252 
4253  bool NewReplaying = cControl::Control() != NULL;
4254  if (Force || NewReplaying != replaying) {
4255  replaying = NewReplaying;
4256  // Replay control:
4257  if (replaying && !stopReplayItem)
4258  // TRANSLATORS: note the leading blank!
4259  Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
4260  else if (stopReplayItem && !replaying) {
4261  Del(stopReplayItem->Index());
4262  stopReplayItem = NULL;
4263  }
4264  // Color buttons:
4265  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"));
4266  result = true;
4267  }
4268 
4269  // Editing control:
4270  bool EditingActive = RecordingsHandler.Active();
4271  if (EditingActive && !cancelEditingItem) {
4272  // TRANSLATORS: note the leading blank!
4273  Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
4274  result = true;
4275  }
4276  else if (cancelEditingItem && !EditingActive) {
4278  cancelEditingItem = NULL;
4279  result = true;
4280  }
4281 
4282  // Record control:
4284  while (stopRecordingItem) {
4287  stopRecordingItem = it;
4288  }
4289  const char *s = NULL;
4290  while ((s = cRecordControls::GetInstantId(s)) != NULL) {
4291  cOsdItem *item = new cOsdItem(osStopRecord);
4292  item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
4293  Add(item);
4294  if (!stopRecordingItem)
4295  stopRecordingItem = item;
4296  }
4297  result = true;
4298  }
4299 
4300  return result;
4301 }
4302 
4304 {
4305  bool HadSubMenu = HasSubMenu();
4306  int osdLanguage = I18nCurrentLanguage();
4307  eOSState state = cOsdMenu::ProcessKey(Key);
4308  HadSubMenu |= HasSubMenu();
4309 
4310  cOsdObject *menu = NULL;
4311  switch (state) {
4312  case osSchedule:
4313  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
4314  menu = new cMenuSchedule;
4315  else
4316  state = osContinue;
4317  break;
4318  case osChannels:
4319  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
4320  menu = new cMenuChannels;
4321  else
4322  state = osContinue;
4323  break;
4324  case osTimers:
4325  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
4326  menu = new cMenuTimers;
4327  else
4328  state = osContinue;
4329  break;
4330  case osRecordings:
4331  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
4332  menu = new cMenuRecordings;
4333  else
4334  state = osContinue;
4335  break;
4336  case osSetup: menu = new cMenuSetup; break;
4337  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
4338  case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
4339  cOsdItem *item = Get(Current());
4340  if (item) {
4341  cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
4342  return osEnd;
4343  }
4344  }
4345  break;
4346  case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
4348  return osEnd;
4349  }
4350  break;
4351  case osPlugin: {
4353  if (item) {
4355  if (p) {
4356  cOsdObject *menu = p->MainMenuAction();
4357  if (menu) {
4358  if (menu->IsMenu())
4359  return AddSubMenu((cOsdMenu *)menu);
4360  else {
4361  pluginOsdObject = menu;
4362  return osPlugin;
4363  }
4364  }
4365  }
4366  }
4367  state = osEnd;
4368  }
4369  break;
4370  default: switch (Key) {
4371  case kRecord:
4372  case kRed: if (!HadSubMenu)
4373  state = replaying ? osContinue : osRecord;
4374  break;
4375  case kGreen: if (!HadSubMenu) {
4376  cRemote::Put(kAudio, true);
4377  state = osEnd;
4378  }
4379  break;
4380  case kYellow: if (!HadSubMenu)
4382  break;
4383  case kBlue: if (!HadSubMenu)
4385  break;
4386  default: break;
4387  }
4388  }
4389  if (menu) {
4390  if (menu->IsMenu())
4391  return AddSubMenu((cOsdMenu *) menu);
4392  pluginOsdObject = menu;
4393  return osPlugin;
4394  }
4395  if (!HasSubMenu() && Update(HadSubMenu))
4396  Display();
4397  if (Key != kNone) {
4398  if (I18nCurrentLanguage() != osdLanguage) {
4399  Set();
4400  if (!HasSubMenu())
4401  Display();
4402  }
4403  }
4404  return state;
4405 }
4406 
4407 // --- SetTrackDescriptions --------------------------------------------------
4408 
4409 static void SetTrackDescriptions(int LiveChannel)
4410 {
4412  const cComponents *Components = NULL;
4413  cSchedulesLock SchedulesLock;
4414  if (LiveChannel) {
4415  cChannel *Channel = Channels.GetByNumber(LiveChannel);
4416  if (Channel) {
4417  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
4418  if (Schedules) {
4419  const cSchedule *Schedule = Schedules->GetSchedule(Channel);
4420  if (Schedule) {
4421  const cEvent *Present = Schedule->GetPresentEvent();
4422  if (Present)
4423  Components = Present->Components();
4424  }
4425  }
4426  }
4427  }
4428  else if (cReplayControl::NowReplaying()) {
4429  cThreadLock RecordingsLock(&Recordings);
4431  if (Recording)
4432  Components = Recording->Info()->Components();
4433  }
4434  if (Components) {
4435  int indexAudio = 0;
4436  int indexDolby = 0;
4437  int indexSubtitle = 0;
4438  for (int i = 0; i < Components->NumComponents(); i++) {
4439  const tComponent *p = Components->Component(i);
4440  switch (p->stream) {
4441  case 2: if (p->type == 0x05)
4442  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4443  else
4444  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
4445  break;
4446  case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
4447  break;
4448  case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
4449  break;
4450  default: ;
4451  }
4452  }
4453  }
4454 }
4455 
4456 // --- cDisplayChannel -------------------------------------------------------
4457 
4459 
4460 cDisplayChannel::cDisplayChannel(int Number, bool Switched)
4461 :cOsdObject(true)
4462 {
4463  currentDisplayChannel = this;
4464  group = -1;
4465  withInfo = !Switched || Setup.ShowInfoOnChSwitch;
4467  number = 0;
4468  timeout = Switched || Setup.TimeoutRequChInfo;
4469  cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
4470  positioner = NULL;
4471  channel = Channels.GetByNumber(Number);
4472  lastPresent = lastFollowing = NULL;
4473  if (channel) {
4474  DisplayChannel();
4475  DisplayInfo();
4476  displayChannel->Flush();
4477  }
4478  lastTime.Set();
4479 }
4480 
4482 :cOsdObject(true)
4483 {
4484  currentDisplayChannel = this;
4485  group = -1;
4486  number = 0;
4487  timeout = true;
4488  lastPresent = lastFollowing = NULL;
4489  lastTime.Set();
4492  positioner = NULL;
4494  ProcessKey(FirstKey);
4495 }
4496 
4498 {
4499  delete displayChannel;
4501  currentDisplayChannel = NULL;
4502 }
4503 
4505 {
4508  lastPresent = lastFollowing = NULL;
4509 }
4510 
4512 {
4513  if (withInfo && channel) {
4514  cSchedulesLock SchedulesLock;
4515  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
4516  if (Schedules) {
4517  const cSchedule *Schedule = Schedules->GetSchedule(channel);
4518  if (Schedule) {
4519  const cEvent *Present = Schedule->GetPresentEvent();
4520  const cEvent *Following = Schedule->GetFollowingEvent();
4521  if (Present != lastPresent || Following != lastFollowing) {
4523  displayChannel->SetEvents(Present, Following);
4524  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);
4525  lastPresent = Present;
4526  lastFollowing = Following;
4527  }
4528  }
4529  }
4530  }
4531 }
4532 
4534 {
4535  DisplayChannel();
4536  displayChannel->SetEvents(NULL, NULL);
4537 }
4538 
4540 {
4541  if (Direction) {
4542  while (Channel) {
4543  Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel);
4544  if (!Channel && Setup.ChannelsWrap)
4545  Channel = Direction > 0 ? Channels.First() : Channels.Last();
4546  if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
4547  return Channel;
4548  }
4549  }
4550  return NULL;
4551 }
4552 
4554 {
4556  delete displayChannel;
4558  }
4559  cChannel *NewChannel = NULL;
4560  if (Key != kNone)
4561  lastTime.Set();
4562  switch (int(Key)) {
4563  case k0:
4564  if (number == 0) {
4565  // keep the "Toggle channels" function working
4566  cRemote::Put(Key);
4567  return osEnd;
4568  }
4569  case k1 ... k9:
4570  group = -1;
4571  if (number >= 0) {
4572  if (number > Channels.MaxNumber())
4573  number = Key - k0;
4574  else
4575  number = number * 10 + Key - k0;
4577  Refresh();
4578  withInfo = false;
4579  // Lets see if there can be any useful further input:
4580  int n = channel ? number * 10 : 0;
4581  int m = 10;
4582  cChannel *ch = channel;
4583  while (ch && (ch = Channels.Next(ch)) != NULL) {
4584  if (!ch->GroupSep()) {
4585  if (n <= ch->Number() && ch->Number() < n + m) {
4586  n = 0;
4587  break;
4588  }
4589  if (ch->Number() > n) {
4590  n *= 10;
4591  m *= 10;
4592  }
4593  }
4594  }
4595  if (n > 0) {
4596  // This channel is the only one that fits the input, so let's take it right away:
4597  NewChannel = channel;
4598  withInfo = true;
4599  number = 0;
4600  Refresh();
4601  }
4602  }
4603  break;
4604  case kLeft|k_Repeat:
4605  case kLeft:
4606  case kRight|k_Repeat:
4607  case kRight:
4608  case kNext|k_Repeat:
4609  case kNext:
4610  case kPrev|k_Repeat:
4611  case kPrev:
4612  withInfo = false;
4613  number = 0;
4614  if (group < 0) {
4616  if (channel)
4617  group = channel->Index();
4618  }
4619  if (group >= 0) {
4620  int SaveGroup = group;
4621  if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
4623  else
4624  group = Channels.GetPrevGroup(group < 1 ? 1 : group);
4625  if (group < 0)
4626  group = SaveGroup;
4628  if (channel) {
4629  Refresh();
4630  if (!channel->GroupSep())
4631  group = -1;
4632  }
4633  }
4634  break;
4635  case kUp|k_Repeat:
4636  case kUp:
4637  case kDown|k_Repeat:
4638  case kDown:
4639  case kChanUp|k_Repeat:
4640  case kChanUp:
4641  case kChanDn|k_Repeat:
4642  case kChanDn: {
4643  eKeys k = NORMALKEY(Key);
4644  cChannel *ch = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1);
4645  if (ch)
4646  channel = ch;
4647  else if (channel && channel->Number() != cDevice::CurrentChannel())
4648  Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
4649  }
4650  // no break here
4651  case kUp|k_Release:
4652  case kDown|k_Release:
4653  case kChanUp|k_Release:
4654  case kChanDn|k_Release:
4655  case kNext|k_Release:
4656  case kPrev|k_Release:
4657  if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
4658  NewChannel = channel;
4659  withInfo = true;
4660  group = -1;
4661  number = 0;
4662  Refresh();
4663  break;
4664  case kNone:
4667  if (channel)
4668  NewChannel = channel;
4669  withInfo = true;
4670  number = 0;
4671  Refresh();
4672  lastTime.Set();
4673  }
4674  break;
4675  //TODO
4676  //XXX case kGreen: return osEventNow;
4677  //XXX case kYellow: return osEventNext;
4678  case kOk:
4679  if (group >= 0) {
4681  if (channel)
4682  NewChannel = channel;
4683  withInfo = true;
4684  group = -1;
4685  Refresh();
4686  }
4687  else if (number > 0) {
4689  if (channel)
4690  NewChannel = channel;
4691  withInfo = true;
4692  number = 0;
4693  Refresh();
4694  }
4695  else
4696  return osEnd;
4697  break;
4698  default:
4699  if ((Key & (k_Repeat | k_Release)) == 0) {
4700  cRemote::Put(Key);
4701  return osEnd;
4702  }
4703  };
4704  if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
4705  if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
4706  // makes sure a channel switch through the SVDRP CHAN command is displayed
4708  Refresh();
4709  lastTime.Set();
4710  }
4711  DisplayInfo();
4712  if (NewChannel) {
4713  SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
4714  Channels.SwitchTo(NewChannel->Number());
4715  SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
4716  channel = NewChannel;
4717  }
4718  const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
4719  bool PositionerMoving = Positioner && Positioner->IsMoving();
4720  SetNeedsFastResponse(PositionerMoving);
4721  if (!PositionerMoving) {
4722  if (positioner)
4723  lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
4724  Positioner = NULL;
4725  }
4726  if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
4727  displayChannel->SetPositioner(Positioner);
4728  positioner = Positioner;
4729  displayChannel->Flush();
4730  return osContinue;
4731  }
4732  return osEnd;
4733 }
4734 
4735 // --- cDisplayVolume --------------------------------------------------------
4736 
4737 #define VOLUMETIMEOUT 1000 //ms
4738 #define MUTETIMEOUT 5000 //ms
4739 
4741 
4743 :cOsdObject(true)
4744 {
4745  currentDisplayVolume = this;
4748  Show();
4749 }
4750 
4752 {
4753  delete displayVolume;
4754  currentDisplayVolume = NULL;
4755 }
4756 
4758 {
4760 }
4761 
4763 {
4764  if (!currentDisplayVolume)
4765  new cDisplayVolume;
4766  return currentDisplayVolume;
4767 }
4768 
4770 {
4773 }
4774 
4776 {
4777  switch (int(Key)) {
4778  case kVolUp|k_Repeat:
4779  case kVolUp:
4780  case kVolDn|k_Repeat:
4781  case kVolDn:
4782  Show();
4784  break;
4785  case kMute:
4786  if (cDevice::PrimaryDevice()->IsMute()) {
4787  Show();
4789  }
4790  else
4791  timeout.Set();
4792  break;
4793  case kNone: break;
4794  default: if ((Key & k_Release) == 0) {
4795  cRemote::Put(Key);
4796  return osEnd;
4797  }
4798  }
4799  return timeout.TimedOut() ? osEnd : osContinue;
4800 }
4801 
4802 // --- cDisplayTracks --------------------------------------------------------
4803 
4804 #define TRACKTIMEOUT 5000 //ms
4805 
4807 
4809 :cOsdObject(true)
4810 {
4812  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
4813  currentDisplayTracks = this;
4814  numTracks = track = 0;
4816  eTrackType CurrentAudioTrack = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
4817  for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
4818  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
4819  if (TrackId && TrackId->id) {
4820  types[numTracks] = eTrackType(i);
4821  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
4822  if (i == CurrentAudioTrack)
4823  track = numTracks;
4824  numTracks++;
4825  }
4826  }
4827  descriptions[numTracks] = NULL;
4830  Show();
4831 }
4832 
4834 {
4835  delete displayTracks;
4836  currentDisplayTracks = NULL;
4837  for (int i = 0; i < numTracks; i++)
4838  free(descriptions[i]);
4840 }
4841 
4843 {
4844  int ac = IS_AUDIO_TRACK(types[track]) ? audioChannel : -1;
4847  displayTracks->Flush();
4850 }
4851 
4853 {
4854  if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
4855  if (!currentDisplayTracks)
4856  new cDisplayTracks;
4857  return currentDisplayTracks;
4858  }
4859  Skins.Message(mtWarning, tr("No audio available!"));
4860  return NULL;
4861 }
4862 
4864 {
4867 }
4868 
4870 {
4871  int oldTrack = track;
4872  int oldAudioChannel = audioChannel;
4873  switch (int(Key)) {
4874  case kUp|k_Repeat:
4875  case kUp:
4876  case kDown|k_Repeat:
4877  case kDown:
4878  if (NORMALKEY(Key) == kUp && track > 0)
4879  track--;
4880  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
4881  track++;
4883  break;
4884  case kLeft|k_Repeat:
4885  case kLeft:
4886  case kRight|k_Repeat:
4887  case kRight: if (IS_AUDIO_TRACK(types[track])) {
4888  static int ac[] = { 1, 0, 2 };
4890  if (NORMALKEY(Key) == kLeft && audioChannel > 0)
4891  audioChannel--;
4892  else if (NORMALKEY(Key) == kRight && audioChannel < 2)
4893  audioChannel++;
4894  audioChannel = ac[audioChannel];
4896  }
4897  break;
4898  case kAudio|k_Repeat:
4899  case kAudio:
4900  if (++track >= numTracks)
4901  track = 0;
4903  break;
4904  case kOk:
4905  if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
4906  oldTrack = -1; // make sure we explicitly switch to that track
4907  timeout.Set();
4908  break;
4909  case kNone: break;
4910  default: if ((Key & k_Release) == 0)
4911  return osEnd;
4912  }
4913  if (track != oldTrack || audioChannel != oldAudioChannel)
4914  Show();
4915  if (track != oldTrack) {
4918  }
4919  if (audioChannel != oldAudioChannel)
4921  return timeout.TimedOut() ? osEnd : osContinue;
4922 }
4923 
4924 // --- cDisplaySubtitleTracks ------------------------------------------------
4925 
4927 
4929 :cOsdObject(true)
4930 {
4931  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
4932  currentDisplayTracks = this;
4933  numTracks = track = 0;
4934  types[numTracks] = ttNone;
4935  descriptions[numTracks] = strdup(tr("No subtitles"));
4936  numTracks++;
4937  eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
4938  for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
4939  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
4940  if (TrackId && TrackId->id) {
4941  types[numTracks] = eTrackType(i);
4942  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
4943  if (i == CurrentSubtitleTrack)
4944  track = numTracks;
4945  numTracks++;
4946  }
4947  }
4948  descriptions[numTracks] = NULL;
4950  displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
4951  Show();
4952 }
4953 
4955 {
4956  delete displayTracks;
4957  currentDisplayTracks = NULL;
4958  for (int i = 0; i < numTracks; i++)
4959  free(descriptions[i]);
4961 }
4962 
4964 {
4966  displayTracks->Flush();
4968 }
4969 
4971 {
4972  if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
4973  if (!currentDisplayTracks)
4975  return currentDisplayTracks;
4976  }
4977  Skins.Message(mtWarning, tr("No subtitles available!"));
4978  return NULL;
4979 }
4980 
4982 {
4985 }
4986 
4988 {
4989  int oldTrack = track;
4990  switch (int(Key)) {
4991  case kUp|k_Repeat:
4992  case kUp:
4993  case kDown|k_Repeat:
4994  case kDown:
4995  if (NORMALKEY(Key) == kUp && track > 0)
4996  track--;
4997  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
4998  track++;
5000  break;
5001  case kSubtitles|k_Repeat:
5002  case kSubtitles:
5003  if (++track >= numTracks)
5004  track = 0;
5006  break;
5007  case kOk:
5008  if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
5009  oldTrack = -1; // make sure we explicitly switch to that track
5010  timeout.Set();
5011  break;
5012  case kNone: break;
5013  default: if ((Key & k_Release) == 0)
5014  return osEnd;
5015  }
5016  if (track != oldTrack) {
5017  Show();
5019  }
5020  return timeout.TimedOut() ? osEnd : osContinue;
5021 }
5022 
5023 // --- cRecordControl --------------------------------------------------------
5024 
5025 cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
5026 {
5027  // Whatever happens here, the timers will be modified in some way...
5028  Timers.SetModified();
5029  // We're going to manipulate an event here, so we need to prevent
5030  // others from modifying any EPG data:
5031  cSchedulesLock SchedulesLock;
5032  cSchedules::Schedules(SchedulesLock);
5033 
5034  event = NULL;
5035  fileName = NULL;
5036  recorder = NULL;
5037  device = Device;
5038  if (!device) device = cDevice::PrimaryDevice();//XXX
5039  timer = Timer;
5040  if (!timer) {
5041  timer = new cTimer(true, Pause);
5042  Timers.Add(timer);
5043  instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->CardIndex() + 1);
5044  }
5045  timer->SetPending(true);
5046  timer->SetRecording(true);
5047  event = timer->Event();
5048 
5049  if (event || GetEvent())
5050  dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
5051  cRecording Recording(timer, event);
5052  fileName = strdup(Recording.FileName());
5053 
5054  // crude attempt to avoid duplicate recordings:
5056  isyslog("already recording: '%s'", fileName);
5057  if (Timer) {
5058  timer->SetPending(false);
5059  timer->SetRecording(false);
5060  timer->OnOff();
5061  }
5062  else {
5063  Timers.Del(timer);
5064  if (!cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5066  }
5067  timer = NULL;
5068  return;
5069  }
5070 
5072  isyslog("record %s", fileName);
5073  if (MakeDirs(fileName, true)) {
5074  const cChannel *ch = timer->Channel();
5075  recorder = new cRecorder(fileName, ch, timer->Priority());
5076  if (device->AttachReceiver(recorder)) {
5077  Recording.WriteInfo();
5078  cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
5079  if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
5082  if (Timer && !Timer->IsSingleEvent()) {
5083  char *Directory = strdup(fileName);
5084  // going up two directory levels to get the series folder
5085  if (char *p = strrchr(Directory, '/')) {
5086  while (p > Directory && *--p != '/')
5087  ;
5088  *p = 0;
5089  if (!HasRecordingsSortMode(Directory)) {
5090  dsyslog("setting %s to be sorted by time", Directory);
5091  SetRecordingsSortMode(Directory, rsmTime);
5092  }
5093  }
5094  free(Directory);
5095  }
5096  return;
5097  }
5098  else
5100  }
5101  else
5103  if (!Timer) {
5104  Timers.Del(timer);
5105  timer = NULL;
5106  }
5107 }
5108 
5110 {
5111  Stop();
5112  free(fileName);
5113 }
5114 
5115 #define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
5116 
5118 {
5119  const cChannel *channel = timer->Channel();
5121  for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
5122  {
5123  cSchedulesLock SchedulesLock;
5124  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
5125  if (Schedules) {
5126  const cSchedule *Schedule = Schedules->GetSchedule(channel);
5127  if (Schedule) {
5128  event = Schedule->GetEventAround(Time);
5129  if (event) {
5130  if (seconds > 0)
5131  dsyslog("got EPG info after %d seconds", seconds);
5132  return true;
5133  }
5134  }
5135  }
5136  }
5137  if (seconds == 0)
5138  dsyslog("waiting for EPG info...");
5139  cCondWait::SleepMs(1000);
5140  }
5141  dsyslog("no EPG info available");
5142  return false;
5143 }
5144 
5145 void cRecordControl::Stop(bool ExecuteUserCommand)
5146 {
5147  if (timer) {
5149  timer->SetRecording(false);
5150  timer = NULL;
5151  cStatus::MsgRecording(device, NULL, fileName, false);
5152  if (ExecuteUserCommand)
5154  Timers.SetModified();
5155  }
5156 }
5157 
5159 {
5160  if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
5161  if (timer)
5162  timer->SetPending(false);
5163  return false;
5164  }
5166  return true;
5167 }
5168 
5169 // --- cRecordControls -------------------------------------------------------
5170 
5172 int cRecordControls::state = 0;
5173 
5174 bool cRecordControls::Start(cTimer *Timer, bool Pause)
5175 {
5176  static time_t LastNoDiskSpaceMessage = 0;
5177  int FreeMB = 0;
5178  if (Timer) {
5179  AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
5180  Timer->SetPending(true);
5181  }
5183  if (FreeMB < MINFREEDISK) {
5184  if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
5185  isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
5186  Skins.Message(mtWarning, tr("Not enough disk space to start recording!"));
5187  LastNoDiskSpaceMessage = time(NULL);
5188  }
5189  return false;
5190  }
5191  LastNoDiskSpaceMessage = 0;
5192 
5193  ChangeState();
5194  int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
5195  cChannel *channel = Channels.GetByNumber(ch);
5196 
5197  if (channel) {
5198  int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
5199  cDevice *device = cDevice::GetDevice(channel, Priority, false);
5200  if (device) {
5201  dsyslog("switching device %d to channel %d (%s)", device->DeviceNumber() + 1, channel->Number(), channel->Name());
5202  if (!device->SwitchChannel(channel, false)) {
5204  return false;
5205  }
5206  if (!Timer || Timer->Matches()) {
5207  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5208  if (!RecordControls[i]) {
5209  RecordControls[i] = new cRecordControl(device, Timer, Pause);
5210  return RecordControls[i]->Process(time(NULL));
5211  }
5212  }
5213  }
5214  }
5215  else if (!Timer || !Timer->Pending()) {
5216  isyslog("no free DVB device to record channel %d (%s)!", ch, channel->Name());
5217  Skins.Message(mtError, tr("No free DVB device to record!"));
5218  }
5219  }
5220  else
5221  esyslog("ERROR: channel %d not defined!", ch);
5222  return false;
5223 }
5224 
5225 void cRecordControls::Stop(const char *InstantId)
5226 {
5227  ChangeState();
5228  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5229  if (RecordControls[i]) {
5230  const char *id = RecordControls[i]->InstantId();
5231  if (id && strcmp(id, InstantId) == 0) {
5232  cTimer *timer = RecordControls[i]->Timer();
5233  RecordControls[i]->Stop();
5234  if (timer) {
5235  isyslog("deleting timer %s", *timer->ToDescr());
5236  Timers.Del(timer);
5237  Timers.SetModified();
5238  }
5239  break;
5240  }
5241  }
5242  }
5243 }
5244 
5246 {
5247  Skins.Message(mtStatus, tr("Pausing live video..."));
5248  cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
5249  if (Start(NULL, true)) {
5250  cReplayControl *rc = new cReplayControl(true);
5251  cControl::Launch(rc);
5252  cControl::Attach();
5253  Skins.Message(mtStatus, NULL);
5254  return true;
5255  }
5256  Skins.Message(mtStatus, NULL);
5257  return false;
5258 }
5259 
5260 const char *cRecordControls::GetInstantId(const char *LastInstantId)
5261 {
5262  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5263  if (RecordControls[i]) {
5264  if (!LastInstantId && RecordControls[i]->InstantId())
5265  return RecordControls[i]->InstantId();
5266  if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
5267  LastInstantId = NULL;
5268  }
5269  }
5270  return NULL;
5271 }
5272 
5274 {
5275  if (FileName) {
5276  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5277  if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
5278  return RecordControls[i];
5279  }
5280  }
5281  return NULL;
5282 }
5283 
5285 {
5286  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5287  if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
5288  return RecordControls[i];
5289  }
5290  return NULL;
5291 }
5292 
5294 {
5295  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5296  if (RecordControls[i]) {
5297  if (!RecordControls[i]->Process(t)) {
5299  ChangeState();
5300  }
5301  }
5302  }
5303 }
5304 
5306 {
5307  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5308  if (RecordControls[i]) {
5309  if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
5310  if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
5311  isyslog("stopping recording due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
5312  RecordControls[i]->Stop();
5313  // This will restart the recording, maybe even from a different
5314  // device in case conditional access has changed.
5315  ChangeState();
5316  }
5317  }
5318  }
5319  }
5320 }
5321 
5323 {
5324  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
5325  if (RecordControls[i])
5326  return true;
5327  }
5328  return false;
5329 }
5330 
5332 {
5333  for (int i = 0; i < MAXRECORDCONTROLS; i++)
5335  ChangeState();
5336 }
5337 
5339 {
5340  int NewState = state;
5341  bool Result = State != NewState;
5342  State = state;
5343  return Result;
5344 }
5345 
5346 // --- cAdaptiveSkipper ------------------------------------------------------
5347 
5349 {
5350  initialValue = NULL;
5351  currentValue = 0;
5352  framesPerSecond = 0;
5353  lastKey = kNone;
5354 }
5355 
5356 void cAdaptiveSkipper::Initialize(int *InitialValue, double FramesPerSecond)
5357 {
5358  initialValue = InitialValue;
5359  framesPerSecond = FramesPerSecond;
5360  currentValue = 0;
5361 }
5362 
5364 {
5365  if (!initialValue)
5366  return 0;
5367  if (timeout.TimedOut()) {
5368  currentValue = int(round(*initialValue * framesPerSecond));
5369  lastKey = Key;
5370  }
5371  else if (Key != lastKey) {
5372  currentValue /= 2;
5374  lastKey = Key; // only halve the value when the direction is changed
5375  else
5376  lastKey = kNone; // once the direction has changed, every further call halves the value
5377  }
5379  return max(currentValue, 1);
5380 }
5381 
5382 // --- cReplayControl --------------------------------------------------------
5383 
5386 
5388 :cDvbPlayerControl(fileName, PauseLive)
5389 {
5390  cDevice::PrimaryDevice()->SetKeepTracks(PauseLive);
5391  currentReplayControl = this;
5392  displayReplay = NULL;
5393  marksModified = false;
5394  visible = modeOnly = shown = displayFrames = false;
5395  lastCurrent = lastTotal = -1;
5396  lastPlay = lastForward = false;
5397  lastSpeed = -2; // an invalid value
5398  timeoutShow = 0;
5399  timeSearchActive = false;
5400  cRecording Recording(fileName);
5401  cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
5402  marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
5403  SetMarks(&marks);
5405  SetTrackDescriptions(false);
5408 }
5409 
5411 {
5413  Hide();
5414  cStatus::MsgReplaying(this, NULL, fileName, false);
5415  Stop();
5416  if (currentReplayControl == this)
5417  currentReplayControl = NULL;
5418 }
5419 
5421 {
5422  if (Setup.DelTimeshiftRec && *fileName) {
5424  if (rc && rc->InstantId()) {
5425  if (Active()) {
5426  if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
5427  cTimer *timer = rc->Timer();
5428  rc->Stop(false); // don't execute user command
5429  if (timer) {
5430  isyslog("deleting timer %s", *timer->ToDescr());
5431  Timers.Del(timer);
5432  Timers.SetModified();
5433  }
5435  cRecording *recording = Recordings.GetByName(fileName);
5436  if (recording) {
5437  if (recording->Delete()) {
5440  }
5441  else
5442  Skins.Message(mtError, tr("Error while deleting recording!"));
5443  }
5444  return;
5445  }
5446  }
5447  }
5448  }
5450  cMenuRecordings::SetRecording(NULL); // make sure opening the Recordings menu navigates to the last replayed recording
5451 }
5452 
5453 void cReplayControl::SetRecording(const char *FileName)
5454 {
5455  fileName = FileName;
5456 }
5457 
5459 {
5460  return currentReplayControl ? *fileName : NULL;
5461 }
5462 
5464 {
5466  fileName = NULL;
5467  return fileName;
5468 }
5469 
5470 void cReplayControl::ClearLastReplayed(const char *FileName)
5471 {
5472  if (*fileName && FileName && strcmp(fileName, FileName) == 0)
5473  fileName = NULL;
5474 }
5475 
5476 void cReplayControl::ShowTimed(int Seconds)
5477 {
5478  if (modeOnly)
5479  Hide();
5480  if (!visible) {
5481  shown = ShowProgress(true);
5482  timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
5483  }
5484  else if (timeoutShow && Seconds > 0)
5485  timeoutShow = time(NULL) + Seconds;
5486 }
5487 
5489 {
5490  ShowTimed();
5491 }
5492 
5494 {
5495  if (visible) {
5496  delete displayReplay;
5497  displayReplay = NULL;
5498  SetNeedsFastResponse(false);
5499  visible = false;
5500  modeOnly = false;
5501  lastPlay = lastForward = false;
5502  lastSpeed = -2; // an invalid value
5503  timeSearchActive = false;
5504  timeoutShow = 0;
5505  }
5506  if (marksModified) {
5507  marks.Save();
5508  marksModified = false;
5509  }
5510 }
5511 
5513 {
5514  if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) {
5515  bool Play, Forward;
5516  int Speed;
5517  if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
5518  bool NormalPlay = (Play && Speed == -1);
5519 
5520  if (!visible) {
5521  if (NormalPlay)
5522  return; // no need to do indicate ">" unless there was a different mode displayed before
5523  visible = modeOnly = true;
5525  }
5526 
5527  if (modeOnly && !timeoutShow && NormalPlay)
5528  timeoutShow = time(NULL) + MODETIMEOUT;
5529  displayReplay->SetMode(Play, Forward, Speed);
5530  lastPlay = Play;
5531  lastForward = Forward;
5532  lastSpeed = Speed;
5533  }
5534  }
5535 }
5536 
5538 {
5539  int Current, Total;
5540 
5541  if (GetIndex(Current, Total) && Total > 0) {
5542  if (!visible) {
5545  SetNeedsFastResponse(true);
5546  visible = true;
5547  }
5548  if (Initial) {
5549  if (*fileName) {
5550  if (cRecording *Recording = Recordings.GetByName(fileName))
5551  displayReplay->SetRecording(Recording);
5552  }
5553  lastCurrent = lastTotal = -1;
5554  }
5555  if (Current != lastCurrent || Total != lastTotal) {
5556  if (Setup.ShowRemainingTime || Total != lastTotal) {
5557  int Index = Total;
5559  Index = Current - Index;
5561  if (!Initial)
5562  displayReplay->Flush();
5563  }
5564  displayReplay->SetProgress(Current, Total);
5565  if (!Initial)
5566  displayReplay->Flush();
5568  displayReplay->Flush();
5569  lastCurrent = Current;
5570  }
5571  lastTotal = Total;
5572  ShowMode();
5573  return true;
5574  }
5575  return false;
5576 }
5577 
5579 {
5580  char buf[64];
5581  // TRANSLATORS: note the trailing blank!
5582  strcpy(buf, tr("Jump: "));
5583  int len = strlen(buf);
5584  char h10 = '0' + (timeSearchTime >> 24);
5585  char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
5586  char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
5587  char m1 = '0' + (timeSearchTime & 0x000000FF);
5588  char ch10 = timeSearchPos > 3 ? h10 : '-';
5589  char ch1 = timeSearchPos > 2 ? h1 : '-';
5590  char cm10 = timeSearchPos > 1 ? m10 : '-';
5591  char cm1 = timeSearchPos > 0 ? m1 : '-';
5592  sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
5593  displayReplay->SetJump(buf);
5594 }
5595 
5597 {
5598 #define STAY_SECONDS_OFF_END 10
5599  int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
5600  int Current = int(round(lastCurrent / FramesPerSecond()));
5601  int Total = int(round(lastTotal / FramesPerSecond()));
5602  switch (Key) {
5603  case k0 ... k9:
5604  if (timeSearchPos < 4) {
5605  timeSearchTime <<= 8;
5606  timeSearchTime |= Key - k0;
5607  timeSearchPos++;
5609  }
5610  break;
5611  case kFastRew:
5612  case kLeft:
5613  case kFastFwd:
5614  case kRight: {
5615  int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
5616  if (dir > 0)
5617  Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
5618  SkipSeconds(Seconds * dir);
5619  timeSearchActive = false;
5620  }
5621  break;
5622  case kPlayPause:
5623  case kPlay:
5624  case kUp:
5625  case kPause:
5626  case kDown:
5627  case kOk:
5628  if (timeSearchPos > 0) {
5629  Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
5630  bool Still = Key == kDown || Key == kPause || Key == kOk;
5631  Goto(SecondsToFrames(Seconds, FramesPerSecond()), Still);
5632  }
5633  timeSearchActive = false;
5634  break;
5635  default:
5636  if (!(Key & k_Flags)) // ignore repeat/release keys
5637  timeSearchActive = false;
5638  break;
5639  }
5640 
5641  if (!timeSearchActive) {
5642  if (timeSearchHide)
5643  Hide();
5644  else
5645  displayReplay->SetJump(NULL);
5646  ShowMode();
5647  }
5648 }
5649 
5651 {
5653  timeSearchHide = false;
5654  if (modeOnly)
5655  Hide();
5656  if (!visible) {
5657  Show();
5658  if (visible)
5659  timeSearchHide = true;
5660  else
5661  return;
5662  }
5663  timeoutShow = 0;
5665  timeSearchActive = true;
5666 }
5667 
5669 {
5670  int Current, Total;
5671  if (GetIndex(Current, Total, true)) {
5672  lastCurrent = -1; // triggers redisplay
5673  if (cMark *m = marks.Get(Current)) {
5674  marks.Lock();
5675  marks.Del(m);
5676  marks.Unlock();
5677  }
5678  else {
5679  marks.Lock();
5680  marks.Add(Current);
5681  marks.Unlock();
5682  bool Play, Forward;
5683  int Speed;
5684  if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
5685  Goto(Current, true);
5686  displayFrames = true;
5687  }
5688  }
5689  ShowTimed(2);
5690  marksModified = true;
5691  }
5692 }
5693 
5694 void cReplayControl::MarkJump(bool Forward)
5695 {
5696  int Current, Total;
5697  if (GetIndex(Current, Total)) {
5698  if (marks.Count()) {
5699  if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
5700  if (!Setup.PauseOnMarkJump) {
5701  bool Playing, Fwd;
5702  int Speed;
5703  if (GetReplayMode(Playing, Fwd, Speed) && Playing && Forward && m->Position() < Total - SecondsToFrames(3, FramesPerSecond())) {
5704  Goto(m->Position());
5705  return;
5706  }
5707  }
5708  Goto(m->Position(), true);
5709  displayFrames = true;
5710  return;
5711  }
5712  }
5713  // There are either no marks at all, or we already were at the first or last one,
5714  // so jump to the very beginning or end:
5715  Goto(Forward ? Total : 0, true);
5716  }
5717 }
5718 
5719 void cReplayControl::MarkMove(int Frames, bool MarkRequired)
5720 {
5721  int Current, Total;
5722  if (GetIndex(Current, Total)) {
5723  bool Play, Forward;
5724  int Speed;
5725  GetReplayMode(Play, Forward, Speed);
5726  cMark *m = marks.Get(Current);
5727  if (!Play && m) {
5728  displayFrames = true;
5729  cMark *m2;
5730  if (Frames > 0) {
5731  // Handle marks at the same offset:
5732  while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
5733  m = m2;
5734  // Don't skip the next mark:
5735  if ((m2 = marks.Next(m)) != NULL)
5736  Frames = min(Frames, m2->Position() - m->Position() - 1);
5737  }
5738  else {
5739  // Handle marks at the same offset:
5740  while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
5741  m = m2;
5742  // Don't skip the next mark:
5743  if ((m2 = marks.Prev(m)) != NULL)
5744  Frames = -min(-Frames, m->Position() - m2->Position() - 1);
5745  }
5746  int p = SkipFrames(Frames);
5747  m->SetPosition(p);
5748  Goto(m->Position(), true);
5749  marksModified = true;
5750  }
5751  else if (!MarkRequired)
5752  Goto(SkipFrames(Frames), !Play);
5753  }
5754 }
5755 
5757 {
5758  if (*fileName) {
5759  Hide();
5761  if (!marks.Count())
5762  Skins.Message(mtError, tr("No editing marks defined!"));
5763  else if (!marks.GetNumSequences())
5764  Skins.Message(mtError, tr("No editing sequences defined!"));
5765  else if (access(cCutter::EditedFileName(fileName), F_OK) == 0 && !Interface->Confirm(tr("Edited version already exists - overwrite?")))
5766  ;
5767  else if (!RecordingsHandler.Add(ruCut, fileName))
5768  Skins.Message(mtError, tr("Can't start editing process!"));
5769  else
5770  Skins.Message(mtInfo, tr("Editing process started"));
5771  }
5772  else
5773  Skins.Message(mtError, tr("Editing process already active!"));
5774  ShowMode();
5775  }
5776 }
5777 
5779 {
5780  int Current, Total;
5781  if (GetIndex(Current, Total)) {
5782  cMark *m = marks.Get(Current);
5783  if (!m)
5784  m = marks.GetNext(Current);
5785  if (m) {
5786  if ((m->Index() & 0x01) != 0 && !Setup.SkipEdited) // when skipping edited parts we also need to jump to end marks
5787  m = marks.Next(m);
5788  if (m)
5790  }
5791  }
5792 }
5793 
5795 {
5797  if (Recording)
5798  return new cMenuRecording(Recording, false);
5799  return NULL;
5800 }
5801 
5803 {
5804  if (const cRecording *Recording = Recordings.GetByName(LastReplayed()))
5805  return Recording;
5806  return NULL;
5807 }
5808 
5810 {
5811  if (!Active())
5812  return osEnd;
5813  if (Key == kNone && !marksModified)
5814  marks.Update();
5815  if (visible) {
5816  if (timeoutShow && time(NULL) > timeoutShow) {
5817  Hide();
5818  ShowMode();
5819  timeoutShow = 0;
5820  }
5821  else if (modeOnly)
5822  ShowMode();
5823  else
5824  shown = ShowProgress(!shown) || shown;
5825  }
5826  bool DisplayedFrames = displayFrames;
5827  displayFrames = false;
5828  if (timeSearchActive && Key != kNone) {
5829  TimeSearchProcess(Key);
5830  return osContinue;
5831  }
5832  if (Key == kPlayPause) {
5833  bool Play, Forward;
5834  int Speed;
5835  GetReplayMode(Play, Forward, Speed);
5836  if (Speed >= 0)
5837  Key = Play ? kPlay : kPause;
5838  else
5839  Key = Play ? kPause : kPlay;
5840  }
5841  bool DoShowMode = true;
5842  switch (int(Key)) {
5843  // Positioning:
5844  case kPlay:
5845  case kUp: Play(); break;
5846  case kPause:
5847  case kDown: Pause(); break;
5848  case kFastRew|k_Release:
5849  case kLeft|k_Release:
5850  if (Setup.MultiSpeedMode) break;
5851  case kFastRew:
5852  case kLeft: Backward(); break;
5853  case kFastFwd|k_Release:
5854  case kRight|k_Release:
5855  if (Setup.MultiSpeedMode) break;
5856  case kFastFwd:
5857  case kRight: Forward(); break;
5858  case kRed: TimeSearch(); break;
5859  case kGreen|k_Repeat:
5861  case kGreen: SkipSeconds(-Setup.SkipSeconds); break;
5862  case kYellow|k_Repeat:
5864  case kYellow: SkipSeconds(Setup.SkipSeconds); break;
5865  case kStop:
5866  case kBlue: Hide();
5867  Stop();
5868  return osEnd;
5869  default: {
5870  DoShowMode = false;
5871  switch (int(Key)) {
5872  // Editing:
5873  case kMarkToggle: MarkToggle(); break;
5874  case kPrev|k_Repeat:
5875  case kPrev: if (Setup.AdaptiveSkipPrevNext) {
5876  MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false);
5877  break;
5878  }
5879  // fall through...
5880  case kMarkJumpBack|k_Repeat:
5881  case kMarkJumpBack: MarkJump(false); break;
5882  case kNext|k_Repeat:
5883  case kNext: if (Setup.AdaptiveSkipPrevNext) {
5884  MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false);
5885  break;
5886  }
5887  // fall through...
5889  case kMarkJumpForward: MarkJump(true); break;
5890  case kMarkMoveBack|k_Repeat:
5891  case kMarkMoveBack: MarkMove(-1, true); break;
5893  case kMarkMoveForward: MarkMove(+1, true); break;
5894  case kMarkSkipBack|k_Repeat:
5895  case kMarkSkipBack: MarkMove(-adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
5897  case kMarkSkipForward: MarkMove(+adaptiveSkipper.GetValue(RAWKEY(Key)), false); break;
5898  case kEditCut: EditCut(); break;
5899  case kEditTest: EditTest(); break;
5900  default: {
5901  displayFrames = DisplayedFrames;
5902  switch (Key) {
5903  // Menu control:
5904  case kOk: if (visible && !modeOnly) {
5905  Hide();
5906  DoShowMode = true;
5907  }
5908  else
5909  Show();
5910  break;
5911  case kBack: Hide();
5912  Stop();
5913  return osRecordings;
5914  default: return osUnknown;
5915  }
5916  }
5917  }
5918  }
5919  }
5920  if (DoShowMode)
5921  ShowMode();
5922  return osContinue;
5923 }
int Find(const char *s) const
Definition: tools.c:1484
cDisplaySubtitleTracks(void)
Definition: menu.c:4928
void Setup(void)
Definition: menu.c:384
void ShowTimed(int Seconds=0)
Definition: menu.c:5476
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:5488
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:4775
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:366
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:5809
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:5578
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
int UseAutoChannelNumbering
Definition: config.h:362
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:4504
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:4008
void MarkToggle(void)
Definition: menu.c:5668
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:5025
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:5802
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:3782
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:5331
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:3643
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:4025
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:5348
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:4842
void QueryCam(void)
Definition: menu.c:2232
void Refresh(void)
Definition: menu.c:4533
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:5493
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:4762
int ppid
Definition: channels.h:118
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition: menu.c:4165
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:3698
#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:5305
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:5293
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:3877
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:729
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:4987
cDisplayTracks(void)
Definition: menu.c:4808
static void Process(eKeys Key)
Definition: menu.c:4981
int RecordingDirs
Definition: config.h:307
virtual void Show(void)
Definition: menu.c:4963
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:5338
eOSState Reset(void)
Definition: menu.c:3865
int pluginIndex
Definition: menu.c:4146
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:5363
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
#define NORMALKEY(k)
Definition: keys.h:79
virtual void Set(void)
Definition: menu.c:4087
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
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:3659
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:4303
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:5453
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:363
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:4460
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:4757
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:4149
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:5158
void IncrementCounter(bool New)
Definition: menu.c:2868
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:5719
int UsePositioner
Definition: config.h:275
void GetRecordingsSortMode(const char *Directory)
Definition: recording.c:3028
const char * useSmallFontTexts[3]
Definition: menu.c:3230
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:3650
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:5650
char diskStatus
Definition: menu.c:1076
const char *const * Descriptions(void)
Definition: themes.h:76
cMenuSetup(void)
Definition: menu.c:4080
virtual ~cDisplayVolume()
Definition: menu.c:4751
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:3828
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:5794
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:5117
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:5322
virtual void Display(void)
Definition: osdbase.c:223
virtual cMenuSetupPage * SetupMenu(void)
Definition: plugin.c:100
virtual ~cDisplayChannel()
Definition: menu.c:4497
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:5410
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:5225
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:4970
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:5109
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:5145
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:5694
static const char * LastReplayed(void)
Definition: menu.c:5463
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:5537
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:4869
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:5260
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:5596
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:5470
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
#define RAWKEY(k)
Definition: keys.h:77
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:5778
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:4553
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:5512
static void Attach(void)
Definition: player.c:87
static void Process(eKeys Key)
Definition: menu.c:4769
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:4863
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:3770
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4039
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:3903
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:4539
void SetDeferred(int Seconds)
Definition: timers.c:643
eOSState Folder(void)
Definition: menu.c:2609
virtual ~cDisplayTracks()
Definition: menu.c:4833
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:3981
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:4852
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:4116
cDisplayVolume(void)
Definition: menu.c:4742
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:3760
bool IsSingleEvent(void) const
Definition: timers.c:346
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition: menu.c:3728
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:3902
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:3724
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:3721
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:4511
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:5273
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:4954
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:3735
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
virtual bool Filter(const cRecording *Recording) const =0
Returns true if the given Recording shall be displayed in the Recordings menu.
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:4205
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:4212
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:4107
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:5387
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:3908
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:5356
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:365
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:5245
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:3801
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:4152
void Del(cTimer *Timer, bool DeleteObject=true)
Definition: timers.c:786
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3558
void SkipSeconds(int Seconds)
Definition: dvbplayer.c:987
bool Update(bool Force=false)
Definition: menu.c:4249
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:3967
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:4011
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:5756
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:5458
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:3946
double OSDTopP
Definition: config.h:318
void Stop(void)
Definition: menu.c:5420
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:5174
int DiSEqC
Definition: config.h:274