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