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