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