00001 #include <typeinfo>
00002
00003 #include <qfile.h>
00004
00005 #include "xmlparsebase.h"
00006 #include "mythmainwindow.h"
00007
00008 #include "mythcontext.h"
00009
00010
00011 #include "mythscreentype.h"
00012 #include "mythuiimage.h"
00013 #include "mythuitext.h"
00014 #include "mythuiclock.h"
00015 #include "mythlistbutton.h"
00016 #include "mythuibutton.h"
00017
00018 QString XMLParseBase::getFirstText(QDomElement &element)
00019 {
00020 for (QDomNode dname = element.firstChild(); !dname.isNull();
00021 dname = dname.nextSibling())
00022 {
00023 QDomText t = dname.toText();
00024 if (!t.isNull())
00025 return t.data();
00026 }
00027 return "";
00028 }
00029
00030 bool XMLParseBase::parseBool(const QString &text)
00031 {
00032 QString s = text.lower();
00033 return (s == "yes" || s == "true" || s.toInt());
00034 }
00035
00036 bool XMLParseBase::parseBool(QDomElement &element)
00037 {
00038 return parseBool(getFirstText(element));
00039 }
00040
00041 QPoint XMLParseBase::parsePoint(const QString &text, bool normalize)
00042 {
00043 int x, y;
00044 QPoint retval;
00045 if (sscanf(text.data(), "%d,%d", &x, &y) == 2)
00046 retval = QPoint(x, y);
00047
00048 if (normalize)
00049 retval = GetMythMainWindow()->NormPoint(retval);
00050
00051 return retval;
00052 }
00053
00054 QPoint XMLParseBase::parsePoint(QDomElement &element, bool normalize)
00055 {
00056 return parsePoint(getFirstText(element), normalize);
00057 }
00058
00059 QSize XMLParseBase::parseSize(const QString &text, bool normalize)
00060 {
00061 int x, y;
00062 QSize retval;
00063 if (sscanf(text.data(), "%d,%d", &x, &y) == 2)
00064 {
00065 if (x == -1 || y == -1)
00066 {
00067 QRect uiSize = GetMythMainWindow()->GetUIScreenRect();
00068 x = uiSize.width();
00069 y = uiSize.height();
00070 normalize = false;
00071 }
00072
00073 retval = QSize(x, y);
00074 }
00075
00076 if (normalize)
00077 retval = GetMythMainWindow()->NormSize(retval);
00078
00079 return retval;
00080 }
00081
00082 QSize XMLParseBase::parseSize(QDomElement &element, bool normalize)
00083 {
00084 return parseSize(getFirstText(element), normalize);
00085 }
00086
00087 QRect XMLParseBase::parseRect(const QString &text, bool normalize)
00088 {
00089 int x, y, w, h;
00090 QRect retval;
00091 if (sscanf(text.data(), "%d,%d,%d,%d", &x, &y, &w, &h) == 4)
00092 retval = QRect(x, y, w, h);
00093
00094 if (normalize)
00095 retval = GetMythMainWindow()->NormRect(retval);
00096
00097 return retval;
00098 }
00099
00100 QRect XMLParseBase::parseRect(QDomElement &element, bool normalize)
00101 {
00102 return parseRect(getFirstText(element), normalize);
00103 }
00104
00105 static MythUIType *globalObjectStore = NULL;
00106
00107 MythUIType *XMLParseBase::GetGlobalObjectStore(void)
00108 {
00109 if (!globalObjectStore)
00110 globalObjectStore = new MythUIType(NULL, "global store");
00111 return globalObjectStore;
00112 }
00113
00114 void XMLParseBase::ClearGlobalObjectStore(void)
00115 {
00116 delete globalObjectStore;
00117 globalObjectStore = NULL;
00118 GetGlobalObjectStore();
00119 }
00120
00121 MythUIType *XMLParseBase::ParseChildren(QDomElement &element,
00122 MythUIType *parent)
00123 {
00124 MythUIType *ret = NULL;
00125 for (QDomNode child = element.firstChild(); !child.isNull();
00126 child = child.nextSibling())
00127 {
00128 QDomElement info = child.toElement();
00129 if (!info.isNull())
00130 {
00131 QString type = info.tagName();
00132 if (type == "font")
00133 {
00134 MythFontProperties *font;
00135 bool global = (GetGlobalObjectStore() == parent);
00136 font = MythFontProperties::ParseFromXml(info, global);
00137 if (!global && font)
00138 {
00139 QString name = info.attribute("name");
00140 parent->AddFont(name, font);
00141 }
00142
00143 if (font)
00144 delete font;
00145 }
00146 else if (type == "imagetype" ||
00147 type == "textarea" ||
00148 type == "button" ||
00149 type == "buttonlist" ||
00150 type == "statetype" ||
00151 type == "clock")
00152 {
00153 ret = ParseUIType(info, type, parent);
00154 }
00155 }
00156 }
00157
00158 return ret;
00159 }
00160
00161 MythUIType *XMLParseBase::ParseUIType(QDomElement &element, const QString &type,
00162 MythUIType *parent,
00163 MythScreenType *screen)
00164 {
00165 QString name = element.attribute("name", "");
00166 if (name.isNull() || name.isEmpty())
00167 {
00168 VERBOSE(VB_IMPORTANT, "element has no name");
00169 return NULL;
00170 }
00171
00172 if (parent && parent->GetChild(name))
00173 {
00174
00175
00176 if (parent == GetGlobalObjectStore())
00177 return NULL;
00178
00179 VERBOSE(VB_IMPORTANT, QString("duplicate name: %1 in parent %2")
00180 .arg(name).arg(parent->name()));
00181 return NULL;
00182 }
00183
00184
00185
00186 MythUIType *uitype = NULL;
00187 MythUIType *base = NULL;
00188
00189 QString inherits = element.attribute("from", "");
00190 if (!inherits.isEmpty())
00191 {
00192 if (parent)
00193 base = parent->GetChild(inherits);
00194
00195
00196 if (screen && !base)
00197 base = screen->GetChild(inherits);
00198
00199 if (!base)
00200 base = GetGlobalObjectStore()->GetChild(inherits);
00201
00202 if (!base)
00203 {
00204 VERBOSE(VB_IMPORTANT, QString("Couldn't find object '%1' to "
00205 "inherit '%2' from")
00206 .arg(inherits).arg(name));
00207 return NULL;
00208 }
00209 }
00210
00211 if (type == "imagetype")
00212 uitype = new MythUIImage(parent, name);
00213 else if (type == "textarea")
00214 uitype = new MythUIText(parent, name);
00215 else if (type == "button")
00216 {
00217 if (base)
00218 uitype = new MythUIButton(parent, name, false);
00219 else
00220 uitype = new MythUIButton(parent, name);
00221 }
00222 else if (type == "buttonlist")
00223 uitype = new MythListButton(parent, name);
00224 else if (type == "statetype")
00225 uitype = new MythUIStateType(parent, name);
00226 else if (type == "window" && parent == GetGlobalObjectStore())
00227 uitype = new MythScreenType(parent, name);
00228 else if (type == "clock")
00229 uitype = new MythUIClock(parent, name);
00230 else
00231 {
00232 VERBOSE(VB_IMPORTANT, QString("Unknown widget type: %1").arg(type));
00233 return NULL;
00234 }
00235
00236 if (base)
00237 {
00238 if (typeid(base) != typeid(uitype))
00239 {
00240 VERBOSE(VB_IMPORTANT, QString("Type of new object '%1' doesn't "
00241 "match old '%2'")
00242 .arg(name).arg(inherits));
00243 delete uitype;
00244 }
00245 uitype->CopyFrom(base);
00246 }
00247
00248 for (QDomNode child = element.firstChild(); !child.isNull();
00249 child = child.nextSibling())
00250 {
00251 QDomElement info = child.toElement();
00252 if (!info.isNull())
00253 {
00254 if (uitype->ParseElement(info))
00255 {
00256 }
00257 else if (info.tagName() == "font")
00258 {
00259 MythFontProperties *font;
00260 bool global = (GetGlobalObjectStore() == parent);
00261 font = MythFontProperties::ParseFromXml(info, global);
00262 if (!global && font)
00263 {
00264 QString name = info.attribute("name");
00265 uitype->AddFont(name, font);
00266 }
00267
00268 if (font)
00269 delete font;
00270 }
00271 else if (info.tagName() == "imagetype" ||
00272 info.tagName() == "textarea" ||
00273 info.tagName() == "button" ||
00274 info.tagName() == "buttonlist" ||
00275 info.tagName() == "statetype" ||
00276 info.tagName() == "clock")
00277 {
00278 ParseUIType(info, info.tagName(), uitype, screen);
00279 }
00280 }
00281 }
00282
00283 uitype->Finalize();
00284 return uitype;
00285 }
00286
00287 bool XMLParseBase::LoadWindowFromXML(const QString &xmlfile,
00288 const QString &windowname,
00289 MythUIType *parent)
00290 {
00291 QValueList<QString> searchpath = gContext->GetThemeSearchPath();
00292 QValueList<QString>::iterator i;
00293 for (i = searchpath.begin(); i != searchpath.end(); i++)
00294 {
00295 QString themefile = *i + xmlfile;
00296 if (doLoad(windowname, parent, themefile))
00297 {
00298 VERBOSE(VB_GENERAL, QString("Loading from: %1").arg(themefile));
00299 return true;
00300 }
00301 }
00302
00303 return false;
00304 }
00305
00306 bool XMLParseBase::doLoad(const QString &windowname,
00307 MythUIType *parent,
00308 const QString &filename,
00309 bool onlywindows)
00310 {
00311 QDomDocument doc;
00312 QFile f(filename);
00313
00314 if (!f.open(IO_ReadOnly))
00315 {
00316
00317 return false;
00318 }
00319
00320 QString errorMsg;
00321 int errorLine = 0;
00322 int errorColumn = 0;
00323
00324 if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
00325 {
00326 cerr << "Error parsing: " << filename << endl;
00327 cerr << "at line: " << errorLine << " column: " << errorColumn << endl;
00328 cerr << errorMsg << endl;
00329 f.close();
00330 return false;
00331 }
00332
00333 f.close();
00334
00335 QDomElement docElem = doc.documentElement();
00336 QDomNode n = docElem.firstChild();
00337 while (!n.isNull())
00338 {
00339 QDomElement e = n.toElement();
00340 if (!e.isNull())
00341 {
00342 if (onlywindows && e.tagName() == "window")
00343 {
00344 QString name = e.attribute("name", "");
00345 if (name.isNull() || name.isEmpty())
00346 {
00347 cerr << "Window needs a name\n";
00348 return false;
00349 }
00350
00351 if (name == windowname)
00352 {
00353 ParseChildren(e, parent);
00354 return true;
00355 }
00356 }
00357
00358 if (!onlywindows)
00359 {
00360 QString type = e.tagName();
00361 if (type == "font")
00362 {
00363 MythFontProperties *font;
00364 bool global = (GetGlobalObjectStore() == parent);
00365 font = MythFontProperties::ParseFromXml(e, global);
00366 if (!global && font)
00367 {
00368 QString name = e.attribute("name");
00369 parent->AddFont(name, font);
00370 }
00371 if (font)
00372 delete font;
00373 }
00374 else if (type == "imagetype" ||
00375 type == "textarea" ||
00376 type == "button" ||
00377 type == "buttonlist" ||
00378 type == "statetype" ||
00379 type == "window" ||
00380 type == "clock")
00381 {
00382 ParseUIType(e, type, parent);
00383 }
00384 }
00385 }
00386 n = n.nextSibling();
00387 }
00388
00389 if (onlywindows)
00390 return false;
00391 return true;
00392 }
00393
00394 bool XMLParseBase::LoadBaseTheme(void)
00395 {
00396 QValueList<QString> searchpath = gContext->GetThemeSearchPath();
00397 QValueList<QString>::iterator i;
00398 for (i = searchpath.begin(); i != searchpath.end(); i++)
00399 {
00400 QString themefile = *i + "base.xml";
00401 if (doLoad(QString::null, GetGlobalObjectStore(), themefile, false))
00402 {
00403 VERBOSE(VB_GENERAL, QString("Loading from: %1").arg(themefile));
00404 }
00405 }
00406
00407 return false;
00408 }
00409
00410 bool XMLParseBase::CopyWindowFromBase(const QString &windowname,
00411 MythScreenType *win)
00412 {
00413 MythUIType *ui = GetGlobalObjectStore()->GetChild(windowname);
00414 if (!ui)
00415 return false;
00416
00417 MythScreenType *st = dynamic_cast<MythScreenType *>(ui);
00418 if (!st)
00419 return false;
00420
00421 win->CopyFrom(st);
00422 return true;
00423 }