10 #include <QDomDocument> 13 #include <QLinearGradient> 14 #include <QRadialGradient> 51 #define LOC QString("XMLParseBase: ") 55 for (QDomNode dname = element.firstChild(); !dname.isNull();
56 dname = dname.nextSibling())
58 QDomText
t = dname.toText();
67 QString s = text.toLower();
68 return (s ==
"yes" || s ==
"true" || s.toInt());
79 QStringList values = text.split(
',', QString::SkipEmptyParts);
80 if (values.size() == 2)
99 QStringList
tmp = text.split(
",");
100 bool x_ok =
false, y_ok =
false;
103 x =
tmp[0].toInt(&x_ok);
104 y =
tmp[1].toInt(&y_ok);
109 if (x == -1 || y == -1)
117 retval = QSize(x, y);
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],
154 int alignment = Qt::AlignLeft | Qt::AlignTop;
156 QStringList values = text.split(
',');
158 QStringList::Iterator it;
159 for ( it = values.begin(); it != values.end(); ++it )
163 align = align.trimmed();
164 align = align.toLower();
166 if (align ==
"center" || align ==
"allcenter")
168 alignment &= ~(Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask);
169 alignment |= Qt::AlignCenter;
172 else if (align ==
"justify")
174 alignment &= ~Qt::AlignHorizontal_Mask;
175 alignment |= Qt::AlignJustify;
177 else if (align ==
"left")
179 alignment &= ~Qt::AlignHorizontal_Mask;
180 alignment |= Qt::AlignLeft;
182 else if (align ==
"hcenter")
184 alignment &= ~Qt::AlignHorizontal_Mask;
185 alignment |= Qt::AlignHCenter;
187 else if (align ==
"right")
189 alignment &= ~Qt::AlignHorizontal_Mask;
190 alignment |= Qt::AlignRight;
192 else if (align ==
"top")
194 alignment &= ~Qt::AlignVertical_Mask;
195 alignment |= Qt::AlignTop;
197 else if (align ==
"vcenter")
199 alignment &= ~Qt::AlignVertical_Mask;
200 alignment |= Qt::AlignVCenter;
202 else if (align ==
"bottom")
204 alignment &= ~Qt::AlignVertical_Mask;
205 alignment |= Qt::AlignBottom;
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");
225 QGradientStops stops;
227 if (!gradientStart.isEmpty())
229 QColor startColor = QColor(gradientStart);
230 startColor.setAlpha(gradientAlpha);
231 QGradientStop stop(0.0, startColor);
235 for (QDomNode child = element.firstChild(); !child.isNull();
236 child = child.nextSibling())
238 QDomElement childElem = child.toElement();
239 if (childElem.tagName() ==
"stop")
241 float position = childElem.attribute(
"position",
"0").toFloat();
242 QString color = childElem.attribute(
"color",
"");
243 int alpha = childElem.attribute(
"alpha",
"-1").toInt();
245 alpha = gradientAlpha;
246 QColor stopColor = QColor(color);
247 stopColor.setAlpha(alpha);
248 QGradientStop stop((position / 100), stopColor);
253 if (!gradientEnd.isEmpty())
255 QColor endColor = QColor(gradientEnd);
256 endColor.setAlpha(gradientAlpha);
257 QGradientStop stop(1.0, endColor);
261 if (direction ==
"radial")
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);
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")
284 else if (direction ==
"diagonal")
299 gradient.setStart(
x1, y1);
300 gradient.setFinalStop(
x2, y2);
301 gradient.setStops(stops);
302 brush = QBrush(gradient);
314 text.replace(
"\\n", QString(
"<newline>"));
318 QStringList lines = text.split(
'\n');
319 QStringList::iterator lineIt;
321 for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
323 (*lineIt) = (*lineIt).trimmed();
326 text = lines.join(
" ");
328 text.replace(QString(
"<newline>"), QString(
"\n"));
354 QDomElement &element,
360 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Parent is NULL");
364 QMap<QString, QString> dependsMap;
365 for (QDomNode child = element.firstChild(); !child.isNull();
366 child = child.nextSibling())
368 QDomElement info = child.toElement();
371 QString
type = info.tagName();
372 if (
type ==
"fontdef")
376 filename, info, parent, global, showWarnings);
380 QString
name = info.attribute(
"name");
386 else if (
type ==
"imagetype" ||
387 type ==
"textarea" ||
389 type ==
"textedit" ||
391 type ==
"buttonlist" ||
392 type ==
"buttonlist2" ||
393 type ==
"buttontree" ||
395 type ==
"checkbox" ||
396 type ==
"statetype" ||
398 type ==
"progressbar" ||
399 type ==
"scrollbar" ||
400 type ==
"webbrowser" ||
401 type ==
"guidegrid" ||
406 ParseUIType(filename, info,
type, parent,
nullptr, showWarnings, dependsMap);
421 const QString &filename,
422 QDomElement &element,
const QString &
type,
426 QMap<QString, QString> &parentDependsMap)
428 QString
name = element.attribute(
"name",
"");
431 VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
432 "This element requires a name");
453 QString inherits = element.attribute(
"from",
"");
454 if (!inherits.isEmpty())
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));
475 if (
type ==
"imagetype")
477 else if (
type ==
"textarea")
479 else if (
type ==
"group")
481 else if (
type ==
"textedit")
483 else if (
type ==
"button")
485 else if (
type ==
"buttonlist2" ||
type ==
"buttonlist")
487 else if (
type ==
"buttontree")
489 else if (
type ==
"spinbox")
491 else if (
type ==
"checkbox")
493 else if (
type ==
"statetype")
495 else if (
type ==
"clock")
497 else if (
type ==
"progressbar")
499 else if (
type ==
"scrollbar")
502 else if (
type ==
"webbrowser")
505 else if (
type ==
"guidegrid")
507 else if (
type ==
"shape")
509 else if (
type ==
"editbar")
511 else if (
type ==
"video")
517 VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
518 "Unknown widget type.");
524 VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
525 "Failed to instantiate widget type.");
529 if (olduitype && parent)
531 if (
typeid(*olduitype) !=
typeid(*uitype))
533 VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element,
534 QString(
"Duplicate name: '%1' in parent '%2'")
535 .arg(
name).arg(parent->objectName()));
547 if (
typeid(*base) !=
typeid(*uitype))
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));
561 QString dependee = element.attribute(
"depends",
"");
562 if (!dependee.isEmpty())
563 parentDependsMap.insert(
name, dependee);
565 QFileInfo fi(filename);
572 for (QDomNode child = element.firstChild(); !child.isNull();
573 child = child.nextSibling())
575 QDomElement info = child.toElement();
578 if (info.tagName() ==
"fontdef")
582 filename, info, parent, global, showWarnings);
586 QString name2 = info.attribute(
"name");
592 else if (info.tagName() ==
"imagetype" ||
593 info.tagName() ==
"textarea" ||
594 info.tagName() ==
"group" ||
595 info.tagName() ==
"textedit" ||
596 info.tagName() ==
"button" ||
597 info.tagName() ==
"buttonlist" ||
598 info.tagName() ==
"buttonlist2" ||
599 info.tagName() ==
"buttontree" ||
600 info.tagName() ==
"spinbox" ||
601 info.tagName() ==
"checkbox" ||
602 info.tagName() ==
"statetype" ||
603 info.tagName() ==
"clock" ||
604 info.tagName() ==
"progressbar" ||
605 info.tagName() ==
"scrollbar" ||
606 info.tagName() ==
"webbrowser" ||
607 info.tagName() ==
"guidegrid" ||
608 info.tagName() ==
"shape" ||
609 info.tagName() ==
"editbar" ||
610 info.tagName() ==
"video")
613 uitype, screen, showWarnings, dependsMap);
629 const QString &windowname)
632 QStringList::const_iterator it = searchpath.begin();
633 for (; it != searchpath.end(); ++it)
635 QString themefile = *it + xmlfile;
638 if (!f.open(QIODevice::ReadOnly))
646 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
648 LOG(VB_GENERAL, LOG_ERR,
LOC +
649 QString(
"Location: '%1' @ %2 column: %3" 651 .arg(qPrintable(themefile)).arg(errorLine).arg(errorColumn)
652 .arg(qPrintable(errorMsg)));
659 QDomElement docElem = doc.documentElement();
660 QDomNode n = docElem.firstChild();
663 QDomElement e = n.toElement();
666 if (e.tagName() ==
"window")
668 QString
name = e.attribute(
"name",
"");
669 if (
name == windowname)
681 const QString &windowname,
684 bool onlyLoadWindows =
true;
685 bool showWarnings =
true;
688 QStringList::const_iterator it = searchpath.begin();
689 for (; it != searchpath.end(); ++it)
691 QString themefile = *it + xmlfile;
692 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Loading window %1 from %2").arg(windowname).arg(themefile));
693 if (
doLoad(windowname, parent, themefile,
694 onlyLoadWindows, showWarnings))
700 LOG(VB_FILE, LOG_ERR,
LOC +
"No theme file " + themefile);
704 LOG(VB_GENERAL, LOG_ERR,
LOC +
705 QString(
"Unable to load window '%1' from '%2'")
706 .arg(windowname).arg(xmlfile));
713 const QString &filename,
720 if (!f.open(QIODevice::ReadOnly))
727 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
729 LOG(VB_GENERAL, LOG_ERR,
LOC +
730 QString(
"Location: '%1' @ %2 column: %3" 732 .arg(qPrintable(filename)).arg(errorLine).arg(errorColumn)
733 .arg(qPrintable(errorMsg)));
740 QDomElement docElem = doc.documentElement();
741 QDomNode n = docElem.firstChild();
744 QDomElement e = n.toElement();
747 if (e.tagName() ==
"include")
751 if (!include.isEmpty())
755 if (onlywindows && e.tagName() ==
"window")
757 QString
name = e.attribute(
"name",
"");
758 QString include = e.attribute(
"include",
"");
762 "Window needs a name");
766 if (!include.isEmpty())
769 if (
name == windowname)
778 QString
type = e.tagName();
779 if (
type ==
"font" ||
type ==
"fontdef")
783 filename, e, parent, global, showWarnings);
787 QString
name = e.attribute(
"name");
792 else if (
type ==
"imagetype" ||
793 type ==
"textarea" ||
795 type ==
"textedit" ||
797 type ==
"buttonlist" ||
798 type ==
"buttonlist2" ||
799 type ==
"buttontree" ||
801 type ==
"checkbox" ||
802 type ==
"statetype" ||
805 type ==
"progressbar" ||
806 type ==
"scrollbar" ||
807 type ==
"webbrowser" ||
808 type ==
"guidegrid" ||
816 QMap<QString, QString> dependsMap;
819 nullptr, showWarnings, dependsMap);
826 "Unknown widget type");
840 bool loadOnlyWindows =
false;
841 bool showWarnings =
true;
844 QMap<QString, QString> dependsMap;
845 QStringList::const_iterator it = searchpath.begin();
846 for (; it != searchpath.end(); ++it)
848 QString themefile = *it +
"base.xml";
850 loadOnlyWindows, showWarnings))
852 LOG(VB_GUI, LOG_INFO,
LOC +
853 QString(
"Loaded base theme from '%1'").arg(themefile));
856 showWarnings =
false;
861 LOG(VB_GUI | VB_FILE, LOG_WARNING,
LOC +
862 QString(
"No theme file '%1'").arg(themefile));
871 LOG(VB_GUI, LOG_INFO,
LOC +
872 QString(
"Asked to load base file from '%1'").arg(baseTheme));
876 LOG(VB_GUI, LOG_INFO,
LOC +
877 QString(
"Base file already loaded '%1'").arg(baseTheme));
882 bool loadOnlyWindows =
false;
883 bool showWarnings =
true;
887 QStringList::const_iterator it = searchpath.begin();
888 for (; it != searchpath.end(); ++it)
890 QString themefile = *it + baseTheme;
892 loadOnlyWindows, showWarnings))
894 LOG(VB_GUI, LOG_INFO,
LOC +
895 QString(
"Loaded base theme from '%1'").arg(themefile));
898 showWarnings =
false;
903 LOG(VB_GUI | VB_FILE, LOG_WARNING,
LOC +
904 QString(
"No theme file '%1'").arg(themefile));
920 LOG(VB_GENERAL, LOG_ERR,
LOC +
921 QString(
"Unable to load window '%1' from base") .arg(windowname));
928 LOG(VB_GENERAL, LOG_ERR,
LOC +
929 QString(
"UI Object '%1' is not a ScreenType") .arg(windowname));
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)
A simple text clock widget.
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...
static int parseAlignment(const QString &text)
All purpose text widget, displays a text string.
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.
Image widget, displays a single image or multiple images in sequence.
void SetXMLLocation(const QString &filename, int where)
QSize NormSize(const QSize &size)
void ConnectDependants(bool recurse=false)
The base class on which all widgets and screens are based.
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 bool CopyWindowFromBase(const QString &windowname, MythScreenType *win)
void SetXMLName(const QString &name)
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.
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
QMap< QString, QString > GetDependsMap() const
Video widget, displays raw image data.
static MythUIType * GetGlobalObjectStore(void)
static QStringList loadedBaseFiles
A widget for rendering primitive shapes and lines.
MythUIHelper * GetMythUI()
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
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_)
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)
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...
Screen in which all other widgets are contained and rendered.
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
static bool parseBool(const QString &text)
A narrow purpose widget used to represent cut positions and regions when editing a video.
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.