MythTV  master
xmlparsebase.cpp
Go to the documentation of this file.
1 
2 // Own header
3 #include "xmlparsebase.h"
4 
5 // C++/C headers
6 #include <typeinfo>
7 
8 // QT headers
9 #include <QFile>
10 #include <QDomDocument>
11 #include <QString>
12 #include <QBrush>
13 #include <QLinearGradient>
14 #include <QRadialGradient>
15 
16 // libmythbase headers
17 #include "libmythbase/mythconfig.h"
19 
20 // Mythui headers
21 #include "mythmainwindow.h"
22 #include "mythuihelper.h"
23 
24 /* ui type includes */
25 #include "mythscreentype.h"
26 #include "mythuiimage.h"
27 #include "mythuiprocedural.h"
28 #include "mythuitext.h"
29 #include "mythuitextedit.h"
30 #include "mythuiclock.h"
31 #include "mythuibuttonlist.h"
32 #include "mythuibutton.h"
33 #include "mythuispinbox.h"
34 #include "mythuicheckbox.h"
35 #include "mythuiprogressbar.h"
36 #include "mythuiscrollbar.h"
37 #include "mythuigroup.h"
38 
39 #if CONFIG_QTWEBKIT
40 #include "mythuiwebbrowser.h"
41 #endif
42 
43 #include "mythuiguidegrid.h"
44 #include "mythuishape.h"
45 #include "mythuibuttontree.h"
46 #include "mythuivideo.h"
47 #include "mythuieditbar.h"
48 #include "mythfontproperties.h"
49 
50 #define LOC QString("XMLParseBase: ")
51 
52 QString XMLParseBase::getFirstText(QDomElement &element)
53 {
54  for (QDomNode dname = element.firstChild(); !dname.isNull();
55  dname = dname.nextSibling())
56  {
57  QDomText t = dname.toText();
58  if (!t.isNull())
59  return t.data();
60  }
61  return {};
62 }
63 
64 bool XMLParseBase::parseBool(const QString &text)
65 {
66  QString s = text.toLower();
67  return (s == "yes" || s == "true" || (s.toInt() != 0));
68 }
69 
70 bool XMLParseBase::parseBool(QDomElement &element)
71 {
72  return parseBool(getFirstText(element));
73 }
74 
75 MythPoint XMLParseBase::parsePoint(const QString &text, bool normalize)
76 {
77  MythPoint retval;
78  QStringList values = text.split(',', Qt::SkipEmptyParts);
79  if (values.size() == 2)
80  retval = MythPoint(values[0], values[1]);
81 
82  if (normalize)
83  retval.NormPoint();
84 
85  return retval;
86 }
87 
88 MythPoint XMLParseBase::parsePoint(QDomElement &element, bool normalize)
89 {
90  return parsePoint(getFirstText(element), normalize);
91 }
92 
93 QSize XMLParseBase::parseSize(const QString &text, bool normalize)
94 {
95  int x = 0;
96  int y = 0;
97  QSize retval;
98 
99  QStringList tmp = text.split(",");
100  bool x_ok = false;
101  bool y_ok = false;
102  if (tmp.size() >= 2)
103  {
104  x = tmp[0].toInt(&x_ok);
105  y = tmp[1].toInt(&y_ok);
106  }
107 
108  if (x_ok && y_ok)
109  {
110  if (x == -1 || y == -1)
111  {
112  QRect uiSize = GetMythMainWindow()->GetUIScreenRect();
113  x = uiSize.width();
114  y = uiSize.height();
115  normalize = false;
116  }
117 
118  retval = QSize(x, y);
119  }
120 
121  if (normalize)
122  retval = GetMythMainWindow()->NormSize(retval);
123 
124  return retval;
125 }
126 
127 QSize XMLParseBase::parseSize(QDomElement &element, bool normalize)
128 {
129  return parseSize(getFirstText(element), normalize);
130 }
131 
132 MythRect XMLParseBase::parseRect(const QString &text, bool normalize)
133 {
134  MythRect retval;
135  QStringList values = text.split(',', Qt::SkipEmptyParts);
136  if (values.size() == 4)
137  retval = MythRect(values[0], values[1], values[2], values[3]);
138  if (values.size() == 5)
139  retval = MythRect(values[0], values[1], values[2], values[3],
140  values[4]);
141 
142  if (normalize)
143  retval.NormRect();
144 
145  return retval;
146 }
147 
148 MythRect XMLParseBase::parseRect(QDomElement &element, bool normalize)
149 {
150  return parseRect(getFirstText(element), normalize);
151 }
152 
153 int XMLParseBase::parseAlignment(const QString &text)
154 {
155  int alignment = Qt::AlignLeft | Qt::AlignTop;
156 
157  QStringList values = text.split(',');
158 
159  QStringList::Iterator it;
160  for ( it = values.begin(); it != values.end(); ++it )
161  {
162 
163  QString align = *it;
164  align = align.trimmed();
165  align = align.toLower();
166 
167  if (align == "center" || align == "allcenter")
168  {
169  alignment &= ~(Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask);
170  alignment |= Qt::AlignCenter;
171  break;
172  }
173  if (align == "justify")
174  {
175  alignment &= ~Qt::AlignHorizontal_Mask;
176  alignment |= Qt::AlignJustify;
177  }
178  else if (align == "left")
179  {
180  alignment &= ~Qt::AlignHorizontal_Mask;
181  alignment |= Qt::AlignLeft;
182  }
183  else if (align == "hcenter")
184  {
185  alignment &= ~Qt::AlignHorizontal_Mask;
186  alignment |= Qt::AlignHCenter;
187  }
188  else if (align == "right")
189  {
190  alignment &= ~Qt::AlignHorizontal_Mask;
191  alignment |= Qt::AlignRight;
192  }
193  else if (align == "top")
194  {
195  alignment &= ~Qt::AlignVertical_Mask;
196  alignment |= Qt::AlignTop;
197  }
198  else if (align == "vcenter")
199  {
200  alignment &= ~Qt::AlignVertical_Mask;
201  alignment |= Qt::AlignVCenter;
202  }
203  else if (align == "bottom")
204  {
205  alignment &= ~Qt::AlignVertical_Mask;
206  alignment |= Qt::AlignBottom;
207  }
208  }
209 
210  return alignment;
211 }
212 
213 int XMLParseBase::parseAlignment(QDomElement &element)
214 {
215  return parseAlignment(getFirstText(element));
216 }
217 
218 QBrush XMLParseBase::parseGradient(const QDomElement &element)
219 {
220  QBrush brush;
221  QString gradientStart = element.attribute("start", "");
222  QString gradientEnd = element.attribute("end", "");
223  int gradientAlpha = element.attribute("alpha", "255").toInt();
224  QString direction = element.attribute("direction", "vertical");
225 
226  QGradientStops stops;
227 
228  if (!gradientStart.isEmpty())
229  {
230  auto startColor = QColor(gradientStart);
231  startColor.setAlpha(gradientAlpha);
232  QGradientStop stop(0.0, startColor);
233  stops.append(stop);
234  }
235 
236  for (QDomNode child = element.firstChild(); !child.isNull();
237  child = child.nextSibling())
238  {
239  QDomElement childElem = child.toElement();
240  if (childElem.tagName() == "stop")
241  {
242  float position = childElem.attribute("position", "0").toFloat();
243  QString color = childElem.attribute("color", "");
244  int alpha = childElem.attribute("alpha", "-1").toInt();
245  if (alpha < 0)
246  alpha = gradientAlpha;
247  auto stopColor = QColor(color);
248  stopColor.setAlpha(alpha);
249  QGradientStop stop((position / 100), stopColor);
250  stops.append(stop);
251  }
252  }
253 
254  if (!gradientEnd.isEmpty())
255  {
256  auto endColor = QColor(gradientEnd);
257  endColor.setAlpha(gradientAlpha);
258  QGradientStop stop(1.0, endColor);
259  stops.append(stop);
260  }
261 
262  if (direction == "radial")
263  {
264  QRadialGradient gradient;
265  gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
266  float x1 = 0.5;
267  float y1 = 0.5;
268  float radius = 0.5;
269  gradient.setCenter(x1,y1);
270  gradient.setFocalPoint(x1,y1);
271  gradient.setRadius(radius);
272  gradient.setStops(stops);
273  brush = QBrush(gradient);
274  }
275  else // Linear
276  {
277  QLinearGradient gradient;
278  gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
279  float x1 = 0.0;
280  float y1 = 0.0;
281  float x2 = 0.0;
282  float y2 = 0.0;
283  if (direction == "vertical")
284  {
285  x1 = 0.5;
286  x2 = 0.5;
287  y1 = 0.0;
288  y2 = 1.0;
289  }
290  else if (direction == "diagonal")
291  {
292  x1 = 0.0;
293  x2 = 1.0;
294  y1 = 0.0;
295  y2 = 1.0;
296  }
297  else // Horizontal
298  {
299  x1 = 0.0;
300  x2 = 1.0;
301  y1 = 0.5;
302  y2 = 0.5;
303  }
304 
305  gradient.setStart(x1, y1);
306  gradient.setFinalStop(x2, y2);
307  gradient.setStops(stops);
308  brush = QBrush(gradient);
309  }
310 
311 
312  return brush;
313 }
314 
315 QString XMLParseBase::parseText(QDomElement &element)
316 {
317  QString text = getFirstText(element);
318 
319  // Escape xml-escaped newline
320  text.replace("\\n", QString("<newline>"));
321 
322  // Remove newline whitespace added by
323  // xml formatting
324  QStringList lines = text.split('\n');
325  QStringList::iterator lineIt;
326 
327  for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
328  {
329  (*lineIt) = (*lineIt).trimmed();
330  }
331 
332  text = lines.join(" ");
333 
334  text.replace(QString("<newline>"), QString("\n"));
335 
336  return text;
337 }
338 
339 static MythUIType *globalObjectStore = nullptr;
340 static QStringList loadedBaseFiles;
341 
343 {
344  if (!globalObjectStore)
345  globalObjectStore = new MythUIType(nullptr, "global store");
346  return globalObjectStore;
347 }
348 
350 {
351  delete globalObjectStore;
352  globalObjectStore = nullptr;
354 
355  // clear any loaded base xml files which will force a reload the next time they are used
356  loadedBaseFiles.clear();
357 }
358 
360  QDomElement &element,
361  MythUIType *parent,
362  bool showWarnings)
363 {
364  if (!parent)
365  {
366  LOG(VB_GENERAL, LOG_ERR, LOC + "Parent is NULL");
367  return;
368  }
369 
370  QMap<QString, QString> dependsMap;
371  for (QDomNode child = element.firstChild(); !child.isNull();
372  child = child.nextSibling())
373  {
374  QDomElement info = child.toElement();
375  if (!info.isNull())
376  {
377  QString type = info.tagName();
378  if (type == "fontdef")
379  {
380  bool global = (GetGlobalObjectStore() == parent);
382  filename, info, parent, global, showWarnings);
383 
384  if (!global && font)
385  {
386  QString name = info.attribute("name");
387  parent->AddFont(name, font);
388  }
389 
390  delete font;
391  }
392  else if (type == "imagetype" ||
393  type == "procedural" ||
394  type == "textarea" ||
395  type == "group" ||
396  type == "textedit" ||
397  type == "button" ||
398  type == "buttonlist" ||
399  type == "buttonlist2" ||
400  type == "buttontree" ||
401  type == "spinbox" ||
402  type == "checkbox" ||
403  type == "statetype" ||
404  type == "clock" ||
405  type == "progressbar" ||
406  type == "scrollbar" ||
407  type == "webbrowser" ||
408  type == "guidegrid" ||
409  type == "shape" ||
410  type == "editbar" ||
411  type == "video")
412  {
413  ParseUIType(filename, info, type, parent, nullptr, showWarnings, dependsMap);
414  }
415  else
416  {
417  // This will print an error if there is no match.
418  parent->ParseElement(filename, info, showWarnings);
419  }
420  }
421  }
422  parent->SetDependsMap(dependsMap);
423  parent->ConnectDependants(true);
424  parent->Finalize();
425 }
426 
428  const QString &filename,
429  QDomElement &element, const QString &type,
430  MythUIType *parent,
431  MythScreenType *screen,
432  bool showWarnings,
433  QMap<QString, QString> &parentDependsMap)
434 {
435  QString name = element.attribute("name", "");
436  if (name.isEmpty())
437  {
438  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
439  "This element requires a name");
440  return nullptr;
441  }
442 
443  MythUIType *olduitype = nullptr;
444 
445  // check for name in immediate parent as siblings cannot share names
446  if (parent && parent->GetChild(name))
447  {
448  // if we're the global object store, assume it's just a theme overriding
449  // the defaults..
450  if (parent == GetGlobalObjectStore())
451  return nullptr;
452 
453  // Reuse the existing child and reparse
454  olduitype = parent->GetChild(name);
455  }
456 
457  MythUIType *uitype = nullptr;
458  MythUIType *base = nullptr;
459 
460  QString inherits = element.attribute("from", "");
461  if (!inherits.isEmpty())
462  {
463  if (parent)
464  base = parent->GetChild(inherits);
465 
466  // might remove this
467  if (screen && !base)
468  base = screen->GetChild(inherits);
469 
470  if (!base)
471  base = GetGlobalObjectStore()->GetChild(inherits);
472 
473  if (!base)
474  {
475  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
476  QString("Couldn't find object '%1' to inherit '%2' from")
477  .arg(inherits, name));
478  return nullptr;
479  }
480  }
481 
482  if (type == "imagetype")
483  uitype = new MythUIImage(parent, name);
484  else if (type == "procedural")
485  uitype = new MythUIProcedural(parent, name);
486  else if (type == "textarea")
487  uitype = new MythUIText(parent, name);
488  else if (type == "group")
489  uitype = new MythUIGroup(parent, name);
490  else if (type == "textedit")
491  uitype = new MythUITextEdit(parent, name);
492  else if (type == "button")
493  uitype = new MythUIButton(parent, name);
494  else if (type == "buttonlist2" || type == "buttonlist")
495  uitype = new MythUIButtonList(parent, name);
496  else if (type == "buttontree")
497  uitype = new MythUIButtonTree(parent, name);
498  else if (type == "spinbox")
499  uitype = new MythUISpinBox(parent, name);
500  else if (type == "checkbox")
501  uitype = new MythUICheckBox(parent, name);
502  else if (type == "statetype")
503  uitype = new MythUIStateType(parent, name);
504  else if (type == "clock")
505  uitype = new MythUIClock(parent, name);
506  else if (type == "progressbar")
507  uitype = new MythUIProgressBar(parent, name);
508  else if (type == "scrollbar") {
509  uitype = new MythUIScrollBar(parent, name);
510 #if CONFIG_QTWEBKIT
511  } else if (type == "webbrowser") {
512  uitype = new MythUIWebBrowser(parent, name);
513 #endif
514  } else if (type == "guidegrid") {
515  uitype = new MythUIGuideGrid(parent, name);
516  } else if (type == "shape") {
517  uitype = new MythUIShape(parent, name);
518  } else if (type == "editbar") {
519  uitype = new MythUIEditBar(parent, name);
520  } else if (type == "video") {
521  uitype = new MythUIVideo(parent, name);
522  } else if (type == "window" && parent == GetGlobalObjectStore()) {
523  uitype = new MythScreenType(parent, name);
524  } else {
525  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
526  "Unknown widget type.");
527  return nullptr;
528  }
529 
530  if (!uitype)
531  {
532  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
533  "Failed to instantiate widget type.");
534  return nullptr;
535  }
536 
537  if (olduitype && parent)
538  {
539  if (typeid(*olduitype) != typeid(*uitype))
540  {
541  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
542  QString("Duplicate name: '%1' in parent '%2'")
543  .arg(name, parent->objectName()));
544  parent->DeleteChild(olduitype);
545  }
546  else
547  {
548  parent->DeleteChild(uitype);
549  uitype = olduitype;
550  }
551  }
552 
553  if (base)
554  {
555  if (typeid(*base) != typeid(*uitype))
556  {
557  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
558  QString("Type of new widget '%1' doesn't match old '%2'")
559  .arg(name, inherits));
560  if (parent)
561  parent->DeleteChild(uitype);
562  return nullptr;
563  }
564  uitype->CopyFrom(base);
565 
566  }
567 
568  QString dependee = element.attribute("depends", "");
569  if (!dependee.isEmpty())
570  parentDependsMap.insert(name, dependee);
571 
572  QFileInfo fi(filename);
573  uitype->SetXMLName(name);
574  uitype->SetXMLLocation(fi.fileName(), element.lineNumber());
575 
576  // If this was copied from another uitype then it already has a depends
577  // map so we want to append to that one
578  QMap<QString, QString> dependsMap = uitype->GetDependsMap();
579  for (QDomNode child = element.firstChild(); !child.isNull();
580  child = child.nextSibling())
581  {
582  QDomElement info = child.toElement();
583  if (!info.isNull())
584  {
585  if (info.tagName() == "fontdef")
586  {
587  bool global = (GetGlobalObjectStore() == parent);
589  filename, info, parent, global, showWarnings);
590 
591  if (!global && font)
592  {
593  QString name2 = info.attribute("name");
594  uitype->AddFont(name2, font);
595  }
596 
597  delete font;
598  }
599  else if (info.tagName() == "imagetype" ||
600  info.tagName() == "procedural" ||
601  info.tagName() == "textarea" ||
602  info.tagName() == "group" ||
603  info.tagName() == "textedit" ||
604  info.tagName() == "button" ||
605  info.tagName() == "buttonlist" ||
606  info.tagName() == "buttonlist2" ||
607  info.tagName() == "buttontree" ||
608  info.tagName() == "spinbox" ||
609  info.tagName() == "checkbox" ||
610  info.tagName() == "statetype" ||
611  info.tagName() == "clock" ||
612  info.tagName() == "progressbar" ||
613  info.tagName() == "scrollbar" ||
614  info.tagName() == "webbrowser" ||
615  info.tagName() == "guidegrid" ||
616  info.tagName() == "shape" ||
617  info.tagName() == "editbar" ||
618  info.tagName() == "video")
619  {
620  ParseUIType(filename, info, info.tagName(),
621  uitype, screen, showWarnings, dependsMap);
622  }
623  else
624  {
625  // This will print an error if there is no match.
626  uitype->ParseElement(filename, info, showWarnings);
627  }
628  }
629  }
630  uitype->SetDependsMap(dependsMap);
631 
632  uitype->Finalize();
633  return uitype;
634 }
635 
636 bool XMLParseBase::WindowExists(const QString &xmlfile,
637  const QString &windowname)
638 {
639  const QStringList searchpath = GetMythUI()->GetThemeSearchPath();
640  for (const auto & dir : std::as_const(searchpath))
641  {
642  QString themefile = dir + xmlfile;
643  QFile f(themefile);
644 
645  if (!f.open(QIODevice::ReadOnly))
646  continue;
647 
648  QDomDocument doc;
649  QString errorMsg;
650  int errorLine = 0;
651  int errorColumn = 0;
652 
653  if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
654  {
655  LOG(VB_GENERAL, LOG_ERR, LOC +
656  QString("Location: '%1' @ %2 column: %3"
657  "\n\t\t\tError: %4")
658  .arg(qPrintable(themefile)).arg(errorLine).arg(errorColumn)
659  .arg(qPrintable(errorMsg)));
660  f.close();
661  continue;
662  }
663 
664  f.close();
665 
666  QDomElement docElem = doc.documentElement();
667  QDomNode n = docElem.firstChild();
668  while (!n.isNull())
669  {
670  QDomElement e = n.toElement();
671  if (!e.isNull())
672  {
673  if (e.tagName() == "window")
674  {
675  QString name = e.attribute("name", "");
676  if (name == windowname)
677  return true;
678  }
679  }
680  n = n.nextSibling();
681  }
682  }
683 
684  return false;
685 }
686 
687 bool XMLParseBase::LoadWindowFromXML(const QString &xmlfile,
688  const QString &windowname,
689  MythUIType *parent)
690 {
691  bool onlyLoadWindows = true;
692  bool showWarnings = true;
693 
694  const QStringList searchpath = GetMythUI()->GetThemeSearchPath();
695  for (const auto & dir : std::as_const(searchpath))
696  {
697  QString themefile = dir + xmlfile;
698  LOG(VB_GUI, LOG_INFO, LOC + QString("Loading window %1 from %2").arg(windowname, themefile));
699  if (doLoad(windowname, parent, themefile,
700  onlyLoadWindows, showWarnings))
701  {
702  return true;
703  }
704  LOG(VB_FILE, LOG_ERR, LOC + "No theme file " + themefile);
705  }
706 
707  LOG(VB_GENERAL, LOG_ERR, LOC +
708  QString("Unable to load window '%1' from '%2'")
709  .arg(windowname, xmlfile));
710 
711  return false;
712 }
713 
714 bool XMLParseBase::doLoad(const QString &windowname,
715  MythUIType *parent,
716  const QString &filename,
717  bool onlyLoadWindows,
718  bool showWarnings)
719 {
720  QDomDocument doc;
721  QFile f(filename);
722 
723  if (!f.open(QIODevice::ReadOnly))
724  return false;
725 
726  QString errorMsg;
727  int errorLine = 0;
728  int errorColumn = 0;
729 
730  if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
731  {
732  LOG(VB_GENERAL, LOG_ERR, LOC +
733  QString("Location: '%1' @ %2 column: %3"
734  "\n\t\t\tError: %4")
735  .arg(qPrintable(filename)).arg(errorLine).arg(errorColumn)
736  .arg(qPrintable(errorMsg)));
737  f.close();
738  return false;
739  }
740 
741  f.close();
742 
743  QDomElement docElem = doc.documentElement();
744  QDomNode n = docElem.firstChild();
745  while (!n.isNull())
746  {
747  QDomElement e = n.toElement();
748  if (!e.isNull())
749  {
750  if (e.tagName() == "include")
751  {
752  QString include = getFirstText(e);
753 
754  if (!include.isEmpty())
755  LoadBaseTheme(include);
756  }
757 
758  if (onlyLoadWindows && e.tagName() == "window")
759  {
760  QString name = e.attribute("name", "");
761  QString include = e.attribute("include", "");
762  if (name.isEmpty())
763  {
764  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, e,
765  "Window needs a name");
766  return false;
767  }
768 
769  if (!include.isEmpty())
770  LoadBaseTheme(include);
771 
772  if (name == windowname)
773  {
774  ParseChildren(filename, e, parent, showWarnings);
775  return true;
776  }
777  }
778 
779  if (!onlyLoadWindows)
780  {
781  QString type = e.tagName();
782  if (type == "font" || type == "fontdef")
783  {
784  bool global = (GetGlobalObjectStore() == parent);
786  filename, e, parent, global, showWarnings);
787 
788  if (!global && font)
789  {
790  QString name = e.attribute("name");
791  parent->AddFont(name, font);
792  }
793  delete font;
794  }
795  else if (type == "imagetype" ||
796  type == "procedural" ||
797  type == "textarea" ||
798  type == "group" ||
799  type == "textedit" ||
800  type == "button" ||
801  type == "buttonlist" ||
802  type == "buttonlist2" ||
803  type == "buttontree" ||
804  type == "spinbox" ||
805  type == "checkbox" ||
806  type == "statetype" ||
807  type == "window" ||
808  type == "clock" ||
809  type == "progressbar" ||
810  type == "scrollbar" ||
811  type == "webbrowser" ||
812  type == "guidegrid" ||
813  type == "shape" ||
814  type == "editbar" ||
815  type == "video")
816  {
817 
818  // We don't want widgets in base.xml
819  // depending on each other so ignore dependsMap
820  QMap<QString, QString> dependsMap;
821  MythUIType *uitype = nullptr;
822  uitype = ParseUIType(filename, e, type, parent,
823  nullptr, showWarnings, dependsMap);
824  if (uitype)
825  uitype->ConnectDependants(true);
826  }
827  else
828  {
829  VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, e,
830  "Unknown widget type");
831  }
832  }
833  }
834  n = n.nextSibling();
835  }
836  return !onlyLoadWindows;
837 }
838 
840 {
841  bool ok = false;
842  bool loadOnlyWindows = false;
843  bool showWarnings = true;
844 
845  const QStringList searchpath = GetMythUI()->GetThemeSearchPath();
846  for (const auto & dir : std::as_const(searchpath))
847  {
848  QString themefile = dir + "base.xml";
849  if (doLoad(QString(), GetGlobalObjectStore(), themefile,
850  loadOnlyWindows, showWarnings))
851  {
852  LOG(VB_GUI, LOG_INFO, LOC +
853  QString("Loaded base theme from '%1'").arg(themefile));
854  // Don't complain about duplicate definitions after first
855  // successful load (set showWarnings to false).
856  showWarnings = false;
857  ok = true;
858  }
859  else
860  {
861  LOG(VB_GUI | VB_FILE, LOG_WARNING, LOC +
862  QString("No theme file '%1'").arg(themefile));
863  }
864  }
865 
866  return ok;
867 }
868 
869 bool XMLParseBase::LoadBaseTheme(const QString &baseTheme)
870 {
871  LOG(VB_GUI, LOG_INFO, LOC +
872  QString("Asked to load base file from '%1'").arg(baseTheme));
873 
874  if (loadedBaseFiles.contains(baseTheme))
875  {
876  LOG(VB_GUI, LOG_INFO, LOC +
877  QString("Base file already loaded '%1'").arg(baseTheme));
878  return true;
879  }
880 
881  bool ok = false;
882  bool loadOnlyWindows = false;
883  bool showWarnings = true;
884 
885  const QStringList searchpath = GetMythUI()->GetThemeSearchPath();
886  for (const auto & dir : std::as_const(searchpath))
887  {
888  QString themefile = dir + baseTheme;
889  if (doLoad(QString(), GetGlobalObjectStore(), themefile,
890  loadOnlyWindows, showWarnings))
891  {
892  LOG(VB_GUI, LOG_INFO, LOC +
893  QString("Loaded base theme from '%1'").arg(themefile));
894  // Don't complain about duplicate definitions after first
895  // successful load (set showWarnings to false).
896  showWarnings = false;
897  ok = true;
898  }
899  else
900  {
901  LOG(VB_GUI | VB_FILE, LOG_WARNING, LOC +
902  QString("No theme file '%1'").arg(themefile));
903  }
904  }
905 
906  if (ok)
907  loadedBaseFiles.append(baseTheme);
908 
909  return ok;
910 }
911 
912 bool XMLParseBase::CopyWindowFromBase(const QString &windowname,
913  MythScreenType *win)
914 {
915  MythUIType *ui = GetGlobalObjectStore()->GetChild(windowname);
916  if (!ui)
917  {
918  LOG(VB_GENERAL, LOG_ERR, LOC +
919  QString("Unable to load window '%1' from base") .arg(windowname));
920  return false;
921  }
922 
923  auto *st = dynamic_cast<MythScreenType *>(ui);
924  if (!st)
925  {
926  LOG(VB_GENERAL, LOG_ERR, LOC +
927  QString("UI Object '%1' is not a ScreenType") .arg(windowname));
928  return false;
929  }
930 
931  win->CopyFrom(st);
932  return true;
933 }
MythUIType::SetXMLLocation
void SetXMLLocation(const QString &filename, int where)
Definition: mythuitype.h:178
mythuibuttontree.h
XMLParseBase::LoadBaseTheme
static bool LoadBaseTheme(void)
Definition: xmlparsebase.cpp:839
mythuitext.h
mythuiprogressbar.h
XMLParseBase::parseAlignment
static int parseAlignment(const QString &text)
Definition: xmlparsebase.cpp:153
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
XMLParseBase::parsePoint
static MythPoint parsePoint(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:75
MythUIType::DeleteChild
void DeleteChild(const QString &name)
Delete a named child of this UIType.
Definition: mythuitype.cpp:150
MythUIScreenBounds::GetUIScreenRect
QRect GetUIScreenRect()
Definition: mythuiscreenbounds.cpp:198
MythUIType::ConnectDependants
void ConnectDependants(bool recurse=false)
Definition: mythuitype.cpp:1444
mythuivideo.h
x2
static int x2
Definition: mythsocket.cpp:51
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:135
MythUIEditBar
A narrow purpose widget used to represent cut positions and regions when editing a video.
Definition: mythuieditbar.h:16
XMLParseBase::ClearGlobalObjectStore
static void ClearGlobalObjectStore(void)
Definition: xmlparsebase.cpp:349
mythuiscrollbar.h
MythUITextEdit
A text entry and edit widget.
Definition: mythuitextedit.h:34
MythUIType::AddFont
bool AddFont(const QString &text, MythFontProperties *fontProp)
Definition: mythuitype.cpp:1332
MythUIGroup
Create a group of widgets.
Definition: mythuigroup.h:11
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
XMLParseBase::GetGlobalObjectStore
static MythUIType * GetGlobalObjectStore(void)
Definition: xmlparsebase.cpp:342
MythUIGuideGrid
A narrow purpose widget used to show television programs and the timeslots they occupy on channels....
Definition: mythuiguidegrid.h:43
MythUIClock
A simple text clock widget.
Definition: mythuiclock.h:25
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
mythuieditbar.h
MythScreenType::CopyFrom
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
Definition: mythscreentype.cpp:511
mythuibuttonlist.h
mythuiimage.h
mythuiclock.h
mythuiguidegrid.h
XMLParseBase::parseText
static QString parseText(QDomElement &element)
Definition: xmlparsebase.cpp:315
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
loadedBaseFiles
static QStringList loadedBaseFiles
Definition: xmlparsebase.cpp:340
MythUIType::GetDependsMap
QMap< QString, QString > GetDependsMap() const
Definition: mythuitype.h:202
mythfontproperties.h
mythlogging.h
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
hardwareprofile.i18n.t
t
Definition: i18n.py:36
VERBOSE_XML
#define VERBOSE_XML(type, level, filename, element, msg)
Definition: xmlparsebase.h:15
MythFontProperties
Definition: mythfontproperties.h:13
x1
static int x1
Definition: mythsocket.cpp:50
XMLParseBase::CopyWindowFromBase
static bool CopyWindowFromBase(const QString &windowname, MythScreenType *win)
Definition: xmlparsebase.cpp:912
XMLParseBase::getFirstText
static QString getFirstText(QDomElement &element)
Definition: xmlparsebase.cpp:52
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
MythUIButtonTree
A tree widget for displaying and navigating a MythGenericTree()
Definition: mythuibuttontree.h:16
MythUIType::CopyFrom
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
Definition: mythuitype.cpp:1176
xmlparsebase.h
MythUIThemeHelper::GetThemeSearchPath
QStringList GetThemeSearchPath()
Definition: mythuithemehelper.cpp:151
XMLParseBase::parseGradient
static QBrush parseGradient(const QDomElement &element)
Definition: xmlparsebase.cpp:218
MythPoint::NormPoint
void NormPoint(void)
Definition: mythrect.cpp:471
XMLParseBase::parseRect
static MythRect parseRect(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:132
MythUIScrollBar
Scroll bar widget.
Definition: mythuiscrollbar.h:15
MythUIProcedural
Definition: mythuiprocedural.h:12
XMLParseBase::WindowExists
static bool WindowExists(const QString &xmlfile, const QString &windowname)
Definition: xmlparsebase.cpp:636
MythUICheckBox
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
Definition: mythuicheckbox.h:15
mythuigroup.h
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:85
MythUIShape
A widget for rendering primitive shapes and lines.
Definition: mythuishape.h:21
MythUIType::SetDependsMap
void SetDependsMap(QMap< QString, QString > dependsMap)
Definition: mythuitype.cpp:1434
mythuispinbox.h
mythuihelper.h
MythRect::NormRect
void NormRect(void)
Definition: mythrect.cpp:109
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
MythUIVideo
Video widget, displays raw image data.
Definition: mythuivideo.h:14
XMLParseBase::ParseUIType
static MythUIType * ParseUIType(const QString &filename, QDomElement &element, const QString &type, MythUIType *parent, MythScreenType *screen, bool showWarnings, QMap< QString, QString > &parentDependsMap)
Definition: xmlparsebase.cpp:427
XMLParseBase::doLoad
static bool doLoad(const QString &windowname, MythUIType *parent, const QString &filename, bool onlyLoadWindows, bool showWarnings)
Definition: xmlparsebase.cpp:714
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
MythUIType::SetXMLName
void SetXMLName(const QString &name)
Definition: mythuitype.h:182
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MythFontProperties::ParseFromXml
static MythFontProperties * ParseFromXml(const QString &filename, const QDomElement &element, MythUIType *parent=nullptr, bool addToGlobal=false, bool showWarnings=true)
Definition: mythfontproperties.cpp:173
MythUISpinBox
A widget for offering a range of numerical values where only the the bounding values and interval are...
Definition: mythuispinbox.h:16
XMLParseBase::ParseChildren
static void ParseChildren(const QString &filename, QDomElement &element, MythUIType *parent, bool showWarnings)
Definition: xmlparsebase.cpp:359
mythuibutton.h
XMLParseBase::parseSize
static QSize parseSize(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:93
MythUIWebBrowser
Web browsing widget.
Definition: mythuiwebbrowser.h:132
mythuicheckbox.h
globalObjectStore
static MythUIType * globalObjectStore
Definition: xmlparsebase.cpp:339
MythUIType::ParseElement
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
Definition: mythuitype.cpp:1242
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
mythuiwebbrowser.h
build_compdb.filename
filename
Definition: build_compdb.py:21
mythmainwindow.h
XMLParseBase::parseBool
static bool parseBool(const QString &text)
Definition: xmlparsebase.cpp:64
LOC
#define LOC
Definition: xmlparsebase.cpp:50
mythuishape.h
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:22
MythUIType::Finalize
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
Definition: mythuitype.cpp:1318
mythscreentype.h
MythUIScreenBounds::NormSize
QSize NormSize(QSize Size) const
Definition: mythuiscreenbounds.cpp:219
MythPoint
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:88
mythuiprocedural.h