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