10 #include <QDomDocument>
13 #include <QLinearGradient>
14 #include <QRadialGradient>
17 #include "libmythbase/mythconfig.h"
50 #define LOC QString("XMLParseBase: ")
54 for (QDomNode dname = element.firstChild(); !dname.isNull();
55 dname = dname.nextSibling())
57 QDomText
t = dname.toText();
66 QString s = text.toLower();
67 return (s ==
"yes" || s ==
"true" || (s.toInt() != 0));
78 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
79 QStringList values = text.split(
',', QString::SkipEmptyParts);
81 QStringList values = text.split(
',', Qt::SkipEmptyParts);
83 if (values.size() == 2)
103 QStringList
tmp = text.split(
",");
108 x =
tmp[0].toInt(&x_ok);
109 y =
tmp[1].toInt(&y_ok);
114 if (x == -1 || y == -1)
122 retval = QSize(x, y);
139 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
140 QStringList values = text.split(
',', QString::SkipEmptyParts);
142 QStringList values = text.split(
',', Qt::SkipEmptyParts);
144 if (values.size() == 4)
145 retval =
MythRect(values[0], values[1], values[2], values[3]);
146 if (values.size() == 5)
147 retval =
MythRect(values[0], values[1], values[2], values[3],
163 int alignment = Qt::AlignLeft | Qt::AlignTop;
165 QStringList values = text.split(
',');
167 QStringList::Iterator it;
168 for ( it = values.begin(); it != values.end(); ++it )
172 align = align.trimmed();
173 align = align.toLower();
175 if (align ==
"center" || align ==
"allcenter")
177 alignment &= ~(Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask);
178 alignment |= Qt::AlignCenter;
181 if (align ==
"justify")
183 alignment &= ~Qt::AlignHorizontal_Mask;
184 alignment |= Qt::AlignJustify;
186 else if (align ==
"left")
188 alignment &= ~Qt::AlignHorizontal_Mask;
189 alignment |= Qt::AlignLeft;
191 else if (align ==
"hcenter")
193 alignment &= ~Qt::AlignHorizontal_Mask;
194 alignment |= Qt::AlignHCenter;
196 else if (align ==
"right")
198 alignment &= ~Qt::AlignHorizontal_Mask;
199 alignment |= Qt::AlignRight;
201 else if (align ==
"top")
203 alignment &= ~Qt::AlignVertical_Mask;
204 alignment |= Qt::AlignTop;
206 else if (align ==
"vcenter")
208 alignment &= ~Qt::AlignVertical_Mask;
209 alignment |= Qt::AlignVCenter;
211 else if (align ==
"bottom")
213 alignment &= ~Qt::AlignVertical_Mask;
214 alignment |= Qt::AlignBottom;
229 QString gradientStart = element.attribute(
"start",
"");
230 QString gradientEnd = element.attribute(
"end",
"");
231 int gradientAlpha = element.attribute(
"alpha",
"255").toInt();
232 QString direction = element.attribute(
"direction",
"vertical");
234 QGradientStops stops;
236 if (!gradientStart.isEmpty())
238 auto startColor = QColor(gradientStart);
239 startColor.setAlpha(gradientAlpha);
240 QGradientStop stop(0.0, startColor);
244 for (QDomNode child = element.firstChild(); !child.isNull();
245 child = child.nextSibling())
247 QDomElement childElem = child.toElement();
248 if (childElem.tagName() ==
"stop")
250 float position = childElem.attribute(
"position",
"0").toFloat();
251 QString color = childElem.attribute(
"color",
"");
252 int alpha = childElem.attribute(
"alpha",
"-1").toInt();
254 alpha = gradientAlpha;
255 auto stopColor = QColor(color);
256 stopColor.setAlpha(alpha);
257 QGradientStop stop((position / 100), stopColor);
262 if (!gradientEnd.isEmpty())
264 auto endColor = QColor(gradientEnd);
265 endColor.setAlpha(gradientAlpha);
266 QGradientStop stop(1.0, endColor);
270 if (direction ==
"radial")
272 QRadialGradient gradient;
273 gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
277 gradient.setCenter(
x1,y1);
278 gradient.setFocalPoint(
x1,y1);
279 gradient.setRadius(radius);
280 gradient.setStops(stops);
281 brush = QBrush(gradient);
285 QLinearGradient gradient;
286 gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
291 if (direction ==
"vertical")
298 else if (direction ==
"diagonal")
313 gradient.setStart(
x1, y1);
314 gradient.setFinalStop(
x2, y2);
315 gradient.setStops(stops);
316 brush = QBrush(gradient);
328 text.replace(
"\\n", QString(
"<newline>"));
332 QStringList lines = text.split(
'\n');
333 QStringList::iterator lineIt;
335 for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
337 (*lineIt) = (*lineIt).trimmed();
340 text = lines.join(
" ");
342 text.replace(QString(
"<newline>"), QString(
"\n"));
368 QDomElement &element,
374 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Parent is NULL");
378 QMap<QString, QString> dependsMap;
379 for (QDomNode child = element.firstChild(); !child.isNull();
380 child = child.nextSibling())
382 QDomElement info = child.toElement();
385 QString
type = info.tagName();
386 if (
type ==
"fontdef")
390 filename, info, parent, global, showWarnings);
394 QString name = info.attribute(
"name");
400 else if (
type ==
"imagetype" ||
401 type ==
"procedural" ||
402 type ==
"textarea" ||
404 type ==
"textedit" ||
406 type ==
"buttonlist" ||
407 type ==
"buttonlist2" ||
408 type ==
"buttontree" ||
410 type ==
"checkbox" ||
411 type ==
"statetype" ||
413 type ==
"progressbar" ||
414 type ==
"scrollbar" ||
415 type ==
"webbrowser" ||
416 type ==
"guidegrid" ||
437 QDomElement &element,
const QString &
type,
441 QMap<QString, QString> &parentDependsMap)
443 QString name = element.attribute(
"name",
"");
447 "This element requires a name");
454 if (parent && parent->
GetChild(name))
468 QString inherits = element.attribute(
"from",
"");
469 if (!inherits.isEmpty())
484 QString(
"Couldn't find object '%1' to inherit '%2' from")
485 .arg(inherits, name));
490 if (
type ==
"imagetype")
492 else if (
type ==
"procedural")
494 else if (
type ==
"textarea")
496 else if (
type ==
"group")
498 else if (
type ==
"textedit")
500 else if (
type ==
"button")
502 else if (
type ==
"buttonlist2" ||
type ==
"buttonlist")
504 else if (
type ==
"buttontree")
506 else if (
type ==
"spinbox")
508 else if (
type ==
"checkbox")
510 else if (
type ==
"statetype")
512 else if (
type ==
"clock")
514 else if (
type ==
"progressbar")
516 else if (
type ==
"scrollbar") {
519 }
else if (
type ==
"webbrowser") {
522 }
else if (
type ==
"guidegrid") {
524 }
else if (
type ==
"shape") {
526 }
else if (
type ==
"editbar") {
528 }
else if (
type ==
"video") {
534 "Unknown widget type.");
541 "Failed to instantiate widget type.");
545 if (olduitype && parent)
547 if (
typeid(*olduitype) !=
typeid(*uitype))
550 QString(
"Duplicate name: '%1' in parent '%2'")
551 .arg(name, parent->objectName()));
563 if (
typeid(*base) !=
typeid(*uitype))
566 QString(
"Type of new widget '%1' doesn't match old '%2'")
567 .arg(name, inherits));
576 QString dependee = element.attribute(
"depends",
"");
577 if (!dependee.isEmpty())
578 parentDependsMap.insert(name, dependee);
587 for (QDomNode child = element.firstChild(); !child.isNull();
588 child = child.nextSibling())
590 QDomElement info = child.toElement();
593 if (info.tagName() ==
"fontdef")
597 filename, info, parent, global, showWarnings);
601 QString name2 = info.attribute(
"name");
607 else if (info.tagName() ==
"imagetype" ||
608 info.tagName() ==
"procedural" ||
609 info.tagName() ==
"textarea" ||
610 info.tagName() ==
"group" ||
611 info.tagName() ==
"textedit" ||
612 info.tagName() ==
"button" ||
613 info.tagName() ==
"buttonlist" ||
614 info.tagName() ==
"buttonlist2" ||
615 info.tagName() ==
"buttontree" ||
616 info.tagName() ==
"spinbox" ||
617 info.tagName() ==
"checkbox" ||
618 info.tagName() ==
"statetype" ||
619 info.tagName() ==
"clock" ||
620 info.tagName() ==
"progressbar" ||
621 info.tagName() ==
"scrollbar" ||
622 info.tagName() ==
"webbrowser" ||
623 info.tagName() ==
"guidegrid" ||
624 info.tagName() ==
"shape" ||
625 info.tagName() ==
"editbar" ||
626 info.tagName() ==
"video")
629 uitype, screen, showWarnings, dependsMap);
645 const QString &windowname)
648 for (
const auto & dir : qAsConst(searchpath))
650 QString themefile = dir + xmlfile;
653 if (!f.open(QIODevice::ReadOnly))
661 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
663 LOG(VB_GENERAL, LOG_ERR,
LOC +
664 QString(
"Location: '%1' @ %2 column: %3"
666 .arg(qPrintable(themefile)).arg(errorLine).arg(errorColumn)
667 .arg(qPrintable(errorMsg)));
674 QDomElement docElem = doc.documentElement();
675 QDomNode n = docElem.firstChild();
678 QDomElement e = n.toElement();
681 if (e.tagName() ==
"window")
683 QString name = e.attribute(
"name",
"");
684 if (name == windowname)
696 const QString &windowname,
699 bool onlyLoadWindows =
true;
700 bool showWarnings =
true;
703 for (
const auto & dir : qAsConst(searchpath))
705 QString themefile = dir + xmlfile;
706 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Loading window %1 from %2").arg(windowname, themefile));
707 if (
doLoad(windowname, parent, themefile,
708 onlyLoadWindows, showWarnings))
712 LOG(VB_FILE, LOG_ERR,
LOC +
"No theme file " + themefile);
715 LOG(VB_GENERAL, LOG_ERR,
LOC +
716 QString(
"Unable to load window '%1' from '%2'")
717 .arg(windowname, xmlfile));
725 bool onlyLoadWindows,
731 if (!f.open(QIODevice::ReadOnly))
738 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
740 LOG(VB_GENERAL, LOG_ERR,
LOC +
741 QString(
"Location: '%1' @ %2 column: %3"
743 .arg(qPrintable(
filename)).arg(errorLine).arg(errorColumn)
744 .arg(qPrintable(errorMsg)));
751 QDomElement docElem = doc.documentElement();
752 QDomNode n = docElem.firstChild();
755 QDomElement e = n.toElement();
758 if (e.tagName() ==
"include")
762 if (!include.isEmpty())
766 if (onlyLoadWindows && e.tagName() ==
"window")
768 QString name = e.attribute(
"name",
"");
769 QString include = e.attribute(
"include",
"");
773 "Window needs a name");
777 if (!include.isEmpty())
780 if (name == windowname)
787 if (!onlyLoadWindows)
789 QString
type = e.tagName();
790 if (
type ==
"font" ||
type ==
"fontdef")
794 filename, e, parent, global, showWarnings);
798 QString name = e.attribute(
"name");
803 else if (
type ==
"imagetype" ||
804 type ==
"procedural" ||
805 type ==
"textarea" ||
807 type ==
"textedit" ||
809 type ==
"buttonlist" ||
810 type ==
"buttonlist2" ||
811 type ==
"buttontree" ||
813 type ==
"checkbox" ||
814 type ==
"statetype" ||
817 type ==
"progressbar" ||
818 type ==
"scrollbar" ||
819 type ==
"webbrowser" ||
820 type ==
"guidegrid" ||
828 QMap<QString, QString> dependsMap;
831 nullptr, showWarnings, dependsMap);
838 "Unknown widget type");
844 return !onlyLoadWindows;
850 bool loadOnlyWindows =
false;
851 bool showWarnings =
true;
854 for (
const auto & dir : qAsConst(searchpath))
856 QString themefile = dir +
"base.xml";
858 loadOnlyWindows, showWarnings))
860 LOG(VB_GUI, LOG_INFO,
LOC +
861 QString(
"Loaded base theme from '%1'").arg(themefile));
864 showWarnings =
false;
869 LOG(VB_GUI | VB_FILE, LOG_WARNING,
LOC +
870 QString(
"No theme file '%1'").arg(themefile));
879 LOG(VB_GUI, LOG_INFO,
LOC +
880 QString(
"Asked to load base file from '%1'").arg(baseTheme));
884 LOG(VB_GUI, LOG_INFO,
LOC +
885 QString(
"Base file already loaded '%1'").arg(baseTheme));
890 bool loadOnlyWindows =
false;
891 bool showWarnings =
true;
894 for (
const auto & dir : qAsConst(searchpath))
896 QString themefile = dir + baseTheme;
898 loadOnlyWindows, showWarnings))
900 LOG(VB_GUI, LOG_INFO,
LOC +
901 QString(
"Loaded base theme from '%1'").arg(themefile));
904 showWarnings =
false;
909 LOG(VB_GUI | VB_FILE, LOG_WARNING,
LOC +
910 QString(
"No theme file '%1'").arg(themefile));
926 LOG(VB_GENERAL, LOG_ERR,
LOC +
927 QString(
"Unable to load window '%1' from base") .arg(windowname));
934 LOG(VB_GENERAL, LOG_ERR,
LOC +
935 QString(
"UI Object '%1' is not a ScreenType") .arg(windowname));