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 QStringList values = text.split(
',', Qt::SkipEmptyParts);
79 if (values.size() == 2)
99 QStringList
tmp = text.split(
",");
104 x =
tmp[0].toInt(&x_ok);
105 y =
tmp[1].toInt(&y_ok);
110 if (x == -1 || y == -1)
118 retval = QSize(x, y);
135 QStringList values = text.split(
',', Qt::SkipEmptyParts);
136 if (values.size() == 4)
137 retval =
MythRect(values[0], values[1], values[2], values[3]);
138 if (values.size() == 5)
139 retval =
MythRect(values[0], values[1], values[2], values[3],
155 int alignment = Qt::AlignLeft | Qt::AlignTop;
157 QStringList values = text.split(
',');
159 QStringList::Iterator it;
160 for ( it = values.begin(); it != values.end(); ++it )
164 align = align.trimmed();
165 align = align.toLower();
167 if (align ==
"center" || align ==
"allcenter")
169 alignment &= ~(Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask);
170 alignment |= Qt::AlignCenter;
173 if (align ==
"justify")
175 alignment &= ~Qt::AlignHorizontal_Mask;
176 alignment |= Qt::AlignJustify;
178 else if (align ==
"left")
180 alignment &= ~Qt::AlignHorizontal_Mask;
181 alignment |= Qt::AlignLeft;
183 else if (align ==
"hcenter")
185 alignment &= ~Qt::AlignHorizontal_Mask;
186 alignment |= Qt::AlignHCenter;
188 else if (align ==
"right")
190 alignment &= ~Qt::AlignHorizontal_Mask;
191 alignment |= Qt::AlignRight;
193 else if (align ==
"top")
195 alignment &= ~Qt::AlignVertical_Mask;
196 alignment |= Qt::AlignTop;
198 else if (align ==
"vcenter")
200 alignment &= ~Qt::AlignVertical_Mask;
201 alignment |= Qt::AlignVCenter;
203 else if (align ==
"bottom")
205 alignment &= ~Qt::AlignVertical_Mask;
206 alignment |= Qt::AlignBottom;
221 QString gradientStart = element.attribute(
"start",
"");
222 QString gradientEnd = element.attribute(
"end",
"");
223 int gradientAlpha = element.attribute(
"alpha",
"255").toInt();
224 QString direction = element.attribute(
"direction",
"vertical");
226 QGradientStops stops;
228 if (!gradientStart.isEmpty())
230 auto startColor = QColor(gradientStart);
231 startColor.setAlpha(gradientAlpha);
232 QGradientStop stop(0.0, startColor);
236 for (QDomNode child = element.firstChild(); !child.isNull();
237 child = child.nextSibling())
239 QDomElement childElem = child.toElement();
240 if (childElem.tagName() ==
"stop")
242 float position = childElem.attribute(
"position",
"0").toFloat();
243 QString color = childElem.attribute(
"color",
"");
244 int alpha = childElem.attribute(
"alpha",
"-1").toInt();
246 alpha = gradientAlpha;
247 auto stopColor = QColor(color);
248 stopColor.setAlpha(alpha);
249 QGradientStop stop((position / 100), stopColor);
254 if (!gradientEnd.isEmpty())
256 auto endColor = QColor(gradientEnd);
257 endColor.setAlpha(gradientAlpha);
258 QGradientStop stop(1.0, endColor);
262 if (direction ==
"radial")
264 QRadialGradient gradient;
265 gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
269 gradient.setCenter(
x1,y1);
270 gradient.setFocalPoint(
x1,y1);
271 gradient.setRadius(radius);
272 gradient.setStops(stops);
273 brush = QBrush(gradient);
277 QLinearGradient gradient;
278 gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
283 if (direction ==
"vertical")
290 else if (direction ==
"diagonal")
305 gradient.setStart(
x1, y1);
306 gradient.setFinalStop(
x2, y2);
307 gradient.setStops(stops);
308 brush = QBrush(gradient);
320 text.replace(
"\\n", QString(
"<newline>"));
324 QStringList lines = text.split(
'\n');
325 QStringList::iterator lineIt;
327 for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
329 (*lineIt) = (*lineIt).trimmed();
332 text = lines.join(
" ");
334 text.replace(QString(
"<newline>"), QString(
"\n"));
360 QDomElement &element,
366 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Parent is NULL");
370 QMap<QString, QString> dependsMap;
371 for (QDomNode child = element.firstChild(); !child.isNull();
372 child = child.nextSibling())
374 QDomElement info = child.toElement();
377 QString
type = info.tagName();
378 if (
type ==
"fontdef")
382 filename, info, parent, global, showWarnings);
386 QString name = info.attribute(
"name");
392 else if (
type ==
"imagetype" ||
393 type ==
"procedural" ||
394 type ==
"textarea" ||
396 type ==
"textedit" ||
398 type ==
"buttonlist" ||
399 type ==
"buttonlist2" ||
400 type ==
"buttontree" ||
402 type ==
"checkbox" ||
403 type ==
"statetype" ||
405 type ==
"progressbar" ||
406 type ==
"scrollbar" ||
407 type ==
"webbrowser" ||
408 type ==
"guidegrid" ||
429 QDomElement &element,
const QString &
type,
433 QMap<QString, QString> &parentDependsMap)
435 QString name = element.attribute(
"name",
"");
439 "This element requires a name");
446 if (parent && parent->
GetChild(name))
460 QString inherits = element.attribute(
"from",
"");
461 if (!inherits.isEmpty())
476 QString(
"Couldn't find object '%1' to inherit '%2' from")
477 .arg(inherits, name));
482 if (
type ==
"imagetype")
484 else if (
type ==
"procedural")
486 else if (
type ==
"textarea")
488 else if (
type ==
"group")
490 else if (
type ==
"textedit")
492 else if (
type ==
"button")
494 else if (
type ==
"buttonlist2" ||
type ==
"buttonlist")
496 else if (
type ==
"buttontree")
498 else if (
type ==
"spinbox")
500 else if (
type ==
"checkbox")
502 else if (
type ==
"statetype")
504 else if (
type ==
"clock")
506 else if (
type ==
"progressbar")
508 else if (
type ==
"scrollbar") {
511 }
else if (
type ==
"webbrowser") {
514 }
else if (
type ==
"guidegrid") {
516 }
else if (
type ==
"shape") {
518 }
else if (
type ==
"editbar") {
520 }
else if (
type ==
"video") {
526 "Unknown widget type.");
533 "Failed to instantiate widget type.");
537 if (olduitype && parent)
539 if (
typeid(*olduitype) !=
typeid(*uitype))
542 QString(
"Duplicate name: '%1' in parent '%2'")
543 .arg(name, parent->objectName()));
555 if (
typeid(*base) !=
typeid(*uitype))
558 QString(
"Type of new widget '%1' doesn't match old '%2'")
559 .arg(name, inherits));
568 QString dependee = element.attribute(
"depends",
"");
569 if (!dependee.isEmpty())
570 parentDependsMap.insert(name, dependee);
579 for (QDomNode child = element.firstChild(); !child.isNull();
580 child = child.nextSibling())
582 QDomElement info = child.toElement();
585 if (info.tagName() ==
"fontdef")
589 filename, info, parent, global, showWarnings);
593 QString name2 = info.attribute(
"name");
599 else if (info.tagName() ==
"imagetype" ||
600 info.tagName() ==
"procedural" ||
601 info.tagName() ==
"textarea" ||
602 info.tagName() ==
"group" ||
603 info.tagName() ==
"textedit" ||
604 info.tagName() ==
"button" ||
605 info.tagName() ==
"buttonlist" ||
606 info.tagName() ==
"buttonlist2" ||
607 info.tagName() ==
"buttontree" ||
608 info.tagName() ==
"spinbox" ||
609 info.tagName() ==
"checkbox" ||
610 info.tagName() ==
"statetype" ||
611 info.tagName() ==
"clock" ||
612 info.tagName() ==
"progressbar" ||
613 info.tagName() ==
"scrollbar" ||
614 info.tagName() ==
"webbrowser" ||
615 info.tagName() ==
"guidegrid" ||
616 info.tagName() ==
"shape" ||
617 info.tagName() ==
"editbar" ||
618 info.tagName() ==
"video")
621 uitype, screen, showWarnings, dependsMap);
637 const QString &windowname)
640 for (
const auto & dir : std::as_const(searchpath))
642 QString themefile = dir + xmlfile;
645 if (!f.open(QIODevice::ReadOnly))
653 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
655 LOG(VB_GENERAL, LOG_ERR,
LOC +
656 QString(
"Location: '%1' @ %2 column: %3"
658 .arg(qPrintable(themefile)).arg(errorLine).arg(errorColumn)
659 .arg(qPrintable(errorMsg)));
666 QDomElement docElem = doc.documentElement();
667 QDomNode n = docElem.firstChild();
670 QDomElement e = n.toElement();
673 if (e.tagName() ==
"window")
675 QString name = e.attribute(
"name",
"");
676 if (name == windowname)
688 const QString &windowname,
691 bool onlyLoadWindows =
true;
692 bool showWarnings =
true;
695 for (
const auto & dir : std::as_const(searchpath))
697 QString themefile = dir + xmlfile;
698 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Loading window %1 from %2").arg(windowname, themefile));
699 if (
doLoad(windowname, parent, themefile,
700 onlyLoadWindows, showWarnings))
704 LOG(VB_FILE, LOG_ERR,
LOC +
"No theme file " + themefile);
707 LOG(VB_GENERAL, LOG_ERR,
LOC +
708 QString(
"Unable to load window '%1' from '%2'")
709 .arg(windowname, xmlfile));
717 bool onlyLoadWindows,
723 if (!f.open(QIODevice::ReadOnly))
730 if (!doc.setContent(&f,
false, &errorMsg, &errorLine, &errorColumn))
732 LOG(VB_GENERAL, LOG_ERR,
LOC +
733 QString(
"Location: '%1' @ %2 column: %3"
735 .arg(qPrintable(
filename)).arg(errorLine).arg(errorColumn)
736 .arg(qPrintable(errorMsg)));
743 QDomElement docElem = doc.documentElement();
744 QDomNode n = docElem.firstChild();
747 QDomElement e = n.toElement();
750 if (e.tagName() ==
"include")
754 if (!include.isEmpty())
758 if (onlyLoadWindows && e.tagName() ==
"window")
760 QString name = e.attribute(
"name",
"");
761 QString include = e.attribute(
"include",
"");
765 "Window needs a name");
769 if (!include.isEmpty())
772 if (name == windowname)
779 if (!onlyLoadWindows)
781 QString
type = e.tagName();
782 if (
type ==
"font" ||
type ==
"fontdef")
786 filename, e, parent, global, showWarnings);
790 QString name = e.attribute(
"name");
795 else if (
type ==
"imagetype" ||
796 type ==
"procedural" ||
797 type ==
"textarea" ||
799 type ==
"textedit" ||
801 type ==
"buttonlist" ||
802 type ==
"buttonlist2" ||
803 type ==
"buttontree" ||
805 type ==
"checkbox" ||
806 type ==
"statetype" ||
809 type ==
"progressbar" ||
810 type ==
"scrollbar" ||
811 type ==
"webbrowser" ||
812 type ==
"guidegrid" ||
820 QMap<QString, QString> dependsMap;
823 nullptr, showWarnings, dependsMap);
830 "Unknown widget type");
836 return !onlyLoadWindows;
842 bool loadOnlyWindows =
false;
843 bool showWarnings =
true;
846 for (
const auto & dir : std::as_const(searchpath))
848 QString themefile = dir +
"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;
886 for (
const auto & dir : std::as_const(searchpath))
888 QString themefile = dir + baseTheme;
890 loadOnlyWindows, showWarnings))
892 LOG(VB_GUI, LOG_INFO,
LOC +
893 QString(
"Loaded base theme from '%1'").arg(themefile));
896 showWarnings =
false;
901 LOG(VB_GUI | VB_FILE, LOG_WARNING,
LOC +
902 QString(
"No theme file '%1'").arg(themefile));
918 LOG(VB_GENERAL, LOG_ERR,
LOC +
919 QString(
"Unable to load window '%1' from base") .arg(windowname));
926 LOG(VB_GENERAL, LOG_ERR,
LOC +
927 QString(
"UI Object '%1' is not a ScreenType") .arg(windowname));