MythTV  master
mythtvmenu.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QFile>
3 #include <QCoreApplication>
4 
5 // MythTV
6 #include "mythlogging.h"
7 #include "mythdirs.h"
8 #include "mythuihelper.h"
9 #include "osd.h"
10 #include "mythtvmenu.h"
11 
12 #define LOC QString("TVMenu: ")
13 
14 bool MythTVMenuItemContext::AddButton(MythOSDDialogData *Menu, bool Active, const QString& Action,
15  const QString& DefaultTextActive,
16  const QString& DefaultTextInactive,
17  bool IsMenu, const QString& TextArg) const
18 {
19  bool result = false;
21  {
22  if ((m_showContext != kMenuShowInactive && Active) || (m_showContext != kMenuShowActive && !Active))
23  {
24  result = true;
25  if (m_doDisplay)
26  {
27  QString text = m_actionText;
28  if (text.isEmpty())
29  text = (Active || DefaultTextInactive.isEmpty()) ? DefaultTextActive : DefaultTextInactive;
30 
31  if (!TextArg.isEmpty())
32  text = text.arg(TextArg);
33 
34  bool current = false;
36  current = Active;
38  current = true;
39 
40  Menu->m_buttons.push_back( { text, Action, IsMenu, current });
41  }
42  }
43  }
44  return result;
45 }
46 
47 // Constructor for a menu element.
48 MythTVMenuItemContext::MythTVMenuItemContext(const MythTVMenu& Menu, const QDomNode& Node,
49  QString Name, MenuCurrentContext Current, bool Display)
50  : m_menu(Menu),
51  m_node(Node),
52  m_category(kMenuCategoryMenu),
53  m_menuName(std::move(Name)),
54  m_showContext(kMenuShowAlways),
55  m_currentContext(Current),
56  m_doDisplay(Display)
57 {
58 }
59 
60 // Constructor for an item element.
61 MythTVMenuItemContext::MythTVMenuItemContext(const MythTVMenu& Menu, const QDomNode& Node,
62  MenuShowContext Context, MenuCurrentContext Current,
63  QString Action, QString ActionText, bool Display)
64  : m_menu(Menu),
65  m_node(Node),
66  m_showContext(Context),
67  m_currentContext(Current),
68  m_action(std::move(Action)),
69  m_actionText(std::move(ActionText)),
70  m_doDisplay(Display)
71 {
72 }
73 
74 // Constructor for an itemlist element.
75 MythTVMenuItemContext::MythTVMenuItemContext(const MythTVMenu& Menu, const QDomNode& Node,
76  MenuShowContext Context, MenuCurrentContext Current,
77  QString Action, bool Display)
78  : m_menu(Menu),
79  m_node(Node),
80  m_category(kMenuCategoryItemlist),
81  m_showContext(Context),
82  m_currentContext(Current),
83  m_action(std::move(Action)),
84  m_doDisplay(Display)
85 {
86 }
87 
89 {
90  delete m_document;
91 }
92 
93 QString MythTVMenu::GetName() const
94 {
95  return m_menuName;
96 }
97 
99 {
100  return m_document != nullptr;
101 }
102 
103 QDomElement MythTVMenu::GetRoot() const
104 {
105  return m_document->documentElement();
106 }
107 
109 {
110  return m_translationContext;
111 }
112 
113 const QString& MythTVMenu::GetKeyBindingContext() const
114 {
115  return m_keyBindingContext;
116 }
117 
118 QString MythTVMenu::Translate(const QString& Text) const
119 {
120  return QCoreApplication::translate(m_translationContext, Text.toUtf8(), nullptr);
121 }
122 
123 bool MythTVMenu::MatchesGroup(const QString &Name, const QString &Prefix,
124  MenuCategory Category, QString &OutPrefix)
125 {
126  OutPrefix = Name;
127  return ((Category == kMenuCategoryItem && Name.startsWith(Prefix)) ||
128  (Category == kMenuCategoryItemlist && Name == Prefix));
129 }
130 
131 bool MythTVMenu::LoadFromFile(const QString& Filename, const QString& Menuname,
132  const char * TranslationContext, const QString& KeyBindingContext,
133  int IncludeLevel)
134 {
135  bool result = false;
136 
137  m_translationContext = TranslationContext;
138  m_keyBindingContext = KeyBindingContext;
139  QStringList searchpath = GetMythUI()->GetThemeSearchPath();
140  searchpath.prepend(GetConfDir() + '/');
141  for (auto it = searchpath.cbegin(); !result && it != searchpath.cend(); ++it)
142  {
143  QString themefile = *it + Filename;
144  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Loading menu %1").arg(themefile));
145  QFile file(themefile);
146  if (file.open(QIODevice::ReadOnly))
147  {
148  m_document = new QDomDocument();
149  if (m_document->setContent(&file))
150  {
151  result = true;
152  QDomElement root = GetRoot();
153  m_menuName = Translate(root.attribute("text", Menuname));
154  ProcessIncludes(root, IncludeLevel);
155  }
156  else
157  {
158  delete m_document;
159  m_document = nullptr;
160  }
161  file.close();
162  }
163 
164  if (!result)
165  LOG(VB_FILE, LOG_ERR, LOC + "No theme file " + themefile);
166  }
167 
168  return result;
169 }
170 
171 bool MythTVMenu::LoadFromString(const QString& Text, const QString& Menuname,
172  const char * TranslationContext, const QString& KeyBindingContext,
173  int IncludeLevel)
174 {
175  bool result = false;
176 
177  m_translationContext = TranslationContext;
178  m_keyBindingContext = KeyBindingContext;
179  m_document = new QDomDocument();
180  if (m_document->setContent(Text))
181  {
182  result = true;
183  QDomElement root = GetRoot();
184  m_menuName = Translate(root.attribute("text", Menuname));
185  ProcessIncludes(root, IncludeLevel);
186  }
187  else
188  {
189  delete m_document;
190  m_document = nullptr;
191  }
192  return result;
193 }
194 
195 void MythTVMenu::ProcessIncludes(QDomElement& Root, int IncludeLevel)
196 {
197  const int maxInclude = 10;
198  for (QDomNode node = Root.firstChild(); !node.isNull(); node = node.nextSibling())
199  {
200  if (node.isElement())
201  {
202  QDomElement element = node.toElement();
203  if (element.tagName() == "include")
204  {
205  QString include = element.attribute("file", "");
206  if (include.isEmpty())
207  continue;
208 
209  if (IncludeLevel >= maxInclude)
210  {
211  LOG(VB_GENERAL, LOG_ERR, QString("Maximum include depth (%1) exceeded for %2")
212  .arg(maxInclude).arg(include));
213  return;
214  }
215 
217  if (menu.LoadFromFile(include, include, m_translationContext,
218  m_keyBindingContext, IncludeLevel + 1))
219  {
220  QDomNode newChild = menu.GetRoot();
221  newChild = m_document->importNode(newChild, true);
222  Root.replaceChild(newChild, node);
223  node = newChild;
224  }
225  }
226  else if (element.tagName() == "menu")
227  {
228  ProcessIncludes(element, IncludeLevel + 1);
229  }
230  }
231  }
232 }
233 
234 bool MythTVMenu::Show(const QDomNode& Node, const QDomNode& Selected,
235  MythTVMenuItemDisplayer& Displayer, MythOSDDialogData* Menu,
236  bool Display) const
237 {
238  bool hasSelected = false;
239  bool displayed = false;
240  for (QDomNode node = Node.firstChild(); !node.isNull(); node = node.nextSibling())
241  {
242  if (node == Selected)
243  hasSelected = true;
244  }
245 
246  for (QDomNode node = Node.firstChild(); !node.isNull(); node = node.nextSibling())
247  {
248  if (node.isElement())
249  {
250  QDomElement element = node.toElement();
251  QString text = Translate(element.attribute("text", ""));
252  QString show = element.attribute("show", "");
253  MenuShowContext showContext =
254  (show == "active" ? kMenuShowActive :
255  show == "inactive" ? kMenuShowInactive : kMenuShowAlways);
256  QString current = element.attribute("current", "");
257  MenuCurrentContext currentContext = kMenuCurrentDefault;
258  if ((current == "active") && !hasSelected)
259  currentContext = kMenuCurrentActive;
260  else if (((current.startsWith("y") || current.startsWith("t") || current == "1")) && !hasSelected)
261  currentContext = kMenuCurrentAlways;
262 
263  if (element.tagName() == "menu")
264  {
265  if (hasSelected && node == Selected)
266  currentContext = kMenuCurrentAlways;
267  MythTVMenuItemContext context(*this, node, text, currentContext, Display);
268  displayed |= Displayer.MenuItemDisplay(context, Menu);
269  }
270  else if (element.tagName() == "item")
271  {
272  QString action = element.attribute("action", "");
273  MythTVMenuItemContext context(*this, node, showContext, currentContext, action, text, Display);
274  displayed |= Displayer.MenuItemDisplay(context, Menu);
275  }
276  else if (element.tagName() == "itemlist")
277  {
278  QString actiongroup = element.attribute("actiongroup", "");
279  MythTVMenuItemContext context(*this, node, showContext, currentContext, actiongroup, Display);
280  displayed |= Displayer.MenuItemDisplay(context, Menu);
281  }
282  }
283 
284  // early exit optimization
285  if (!Display && displayed)
286  break;
287  }
288  return displayed;
289 }
290 
291 MythTVMenuNodeTuple::MythTVMenuNodeTuple(const MythTVMenu& Menu, const QDomNode& Node)
292  : m_menu(Menu),
293  m_node(Node)
294 {
295 }
296 
298  : m_menu(dummy_menubase)
299 {
300 }
301 
302 
kMenuShowInactive
@ kMenuShowInactive
Definition: mythtvmenu.h:21
MythTVMenu::GetTranslationContext
const char * GetTranslationContext() const
Definition: mythtvmenu.cpp:108
MythTVMenu::ProcessIncludes
void ProcessIncludes(QDomElement &Root, int IncludeLevel)
Definition: mythtvmenu.cpp:195
MythTVMenuItemDisplayer
Definition: mythtvmenu.h:63
MythTVMenu::LoadFromString
bool LoadFromString(const QString &Text, const QString &Menuname, const char *TranslationContext, const QString &KeyBindingContext, int IncludeLevel=0)
Definition: mythtvmenu.cpp:171
root
QDomElement root
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:656
MythTVMenu::Show
bool Show(const QDomNode &Node, const QDomNode &Selected, MythTVMenuItemDisplayer &Displayer, MythOSDDialogData *Menu, bool Display=true) const
Definition: mythtvmenu.cpp:234
kMenuCategoryItemlist
@ kMenuCategoryItemlist
Definition: mythtvmenu.h:14
MythTVMenu::LoadFromFile
bool LoadFromFile(const QString &Filename, const QString &Menuname, const char *TranslationContext, const QString &KeyBindingContext, int IncludeLevel=0)
Definition: mythtvmenu.cpp:131
MythTVMenuItemContext::m_doDisplay
bool m_doDisplay
Definition: mythtvmenu.h:60
MythTVMenuItemContext
Definition: mythtvmenu.h:36
kMenuCategoryItem
@ kMenuCategoryItem
Definition: mythtvmenu.h:13
arg
arg(title).arg(filename).arg(doDelete))
osd.h
MythTVMenuItemContext::m_currentContext
MenuCurrentContext m_currentContext
Definition: mythtvmenu.h:57
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
show
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:339
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
MythTVMenu::GetKeyBindingContext
const QString & GetKeyBindingContext() const
Definition: mythtvmenu.cpp:113
menu
static MythThemedMenu * menu
Definition: mythtv/programs/mythtv-setup/main.cpp:53
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
Action
An action (for this plugin) consists of a description, and a set of key sequences.
Definition: action.h:40
MythTVMenuItemContext::MythTVMenuItemContext
MythTVMenuItemContext(const MythTVMenu &Menu, const QDomNode &Node, QString Name, MenuCurrentContext Current, bool Display)
Definition: mythtvmenu.cpp:48
MythTVMenu::m_keyBindingContext
QString m_keyBindingContext
Definition: mythtvmenu.h:99
MythTVMenuItemContext::m_actionText
const QString m_actionText
Definition: mythtvmenu.h:59
MythTVMenu::GetName
QString GetName() const
Definition: mythtvmenu.cpp:93
mythlogging.h
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
MythOSDDialogData
Definition: osd.h:65
MythTVMenu::IsLoaded
bool IsLoaded() const
Definition: mythtvmenu.cpp:98
Root
static FRACTAL * Root
Definition: ifs.cpp:145
MythTVMenu::MatchesGroup
static bool MatchesGroup(const QString &Name, const QString &Prefix, MenuCategory Category, QString &OutPrefix)
Definition: mythtvmenu.cpp:123
MenuShowContext
MenuShowContext
Definition: mythtvmenu.h:18
kMenuCategoryMenu
@ kMenuCategoryMenu
Definition: mythtvmenu.h:15
LOC
#define LOC
Definition: mythtvmenu.cpp:12
MythTVMenu::GetRoot
QDomElement GetRoot() const
Definition: mythtvmenu.cpp:103
MythUIThemeHelper::GetThemeSearchPath
QStringList GetThemeSearchPath()
Definition: mythuithemehelper.cpp:150
MenuCurrentContext
MenuCurrentContext
Definition: mythtvmenu.h:25
kMenuShowAlways
@ kMenuShowAlways
Definition: mythtvmenu.h:22
MythTVMenu::Translate
QString Translate(const QString &Text) const
Definition: mythtvmenu.cpp:118
kMenuShowActive
@ kMenuShowActive
Definition: mythtvmenu.h:20
MenuCategory
MenuCategory
Definition: mythtvmenu.h:11
mythuihelper.h
MythOSDDialogData::m_buttons
std::vector< MythOSDDialogButton > m_buttons
Definition: osd.h:88
MythTVMenuItemContext::AddButton
bool AddButton(MythOSDDialogData *Menu, bool Active, const QString &Action, const QString &DefaultTextActive, const QString &DefaultTextInactive, bool IsMenu, const QString &TextArg) const
Definition: mythtvmenu.cpp:14
MythTVMenuItemDisplayer::MenuItemDisplay
virtual bool MenuItemDisplay(const MythTVMenuItemContext &Context, MythOSDDialogData *Menu)=0
MythTVMenu::m_document
QDomDocument * m_document
Definition: mythtvmenu.h:96
mythtvmenu.h
Name
Definition: channelsettings.cpp:46
MythTVMenu
Definition: mythtvmenu.h:70
MythTVMenu::m_translationContext
const char * m_translationContext
Definition: mythtvmenu.h:97
kMenuCurrentDefault
@ kMenuCurrentDefault
Definition: mythtvmenu.h:27
MythTVMenuItemContext::m_category
MenuCategory m_category
Definition: mythtvmenu.h:54
build_compdb.action
action
Definition: build_compdb.py:9
kMenuCurrentAlways
@ kMenuCurrentAlways
Definition: mythtvmenu.h:29
MythTVMenu::~MythTVMenu
~MythTVMenu()
Definition: mythtvmenu.cpp:88
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
MythTVMenu::m_menuName
QString m_menuName
Definition: mythtvmenu.h:98
dummy_menubase
static const MythTVMenu dummy_menubase
Definition: mythtvmenu.h:102
MythTVMenuNodeTuple::MythTVMenuNodeTuple
MythTVMenuNodeTuple()
Definition: mythtvmenu.cpp:297
MythTVMenuItemContext::m_showContext
MenuShowContext m_showContext
Definition: mythtvmenu.h:56
kMenuCurrentActive
@ kMenuCurrentActive
Definition: mythtvmenu.h:28
MythTVMenuItemContext::m_action
const QString m_action
Definition: mythtvmenu.h:58