/* * Copyright 2007-2008 Ben Boeckel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __POKEMOD_OBJECT__ #define __POKEMOD_OBJECT__ // Qt includes #include #include #include // C includes #include class Object : public QObject { Q_OBJECT public: Object(const Object& object); Object(const QString& className, const Object* parent, const int id); virtual ~Object() { } const Object* parent() const; const Object* pokemod() const; int id() const; QString className() const; static QDomDocument xml(const Object* object) { QDomDocument xml(object->className()); xml.appendChild(object->save()); return xml; } signals: void warning(const QString& message) const; void error(const QString& message) const; void changed() const; public slots: virtual void validate() = 0; virtual void load(const QDomElement& xml, int id = INT_MAX) = 0; virtual QDomElement save() const = 0; protected: void setId(const int id); static QString unused(const QString& variable); static QString bounds(const QString& variable); static QString size(const QString& variable); static QString subclass(const QString& subclass, const int id); static QString subclass(const QString& subclass, const QString& name); virtual void clear(); private: int m_id; const QString m_className; const Object* m_parent; }; #define LOAD_NODE(variable) xml.firstChildElement(variable) #define LOAD_DATA(node) node.firstChild().toText().data() #define LOAD_ID() \ if (id == INT_MAX) \ id = xml.attribute("id", "2147483647").toInt(); \ setId(id); \ clear() #define LOAD(type, variable) m_##variable = LOAD_##type(LOAD_NODE(#variable)) #define LOAD_bool(node) ((LOAD_DATA(node) == "true") ? true : false) #define LOAD_int(node) LOAD_DATA(node).toInt() #define LOAD_QString LOAD_DATA #define LOAD_Fraction(node) Fraction(node.attribute("numerator", "1").toInt(), node.attribute("denominator", "1").toInt()) #define LOAD_Point(node) Point(node.attribute("x", "0").toInt(), node.attribute("y", "0").toInt()) // FIXME: QPixmap::fromData static member would be nice #define LOAD_QPixmap(node) QPixmap::fromImage(QImage::fromData(QByteArray::fromBase64(LOAD_DATA(node).toUtf8()))) #define LOAD_QByteArray(node) QByteArray::fromBase64(LOAD_DATA(node).toUtf8()) #define LOAD_Rules(node) new Rules(node, this) #define LOAD_Script(node) Script(node.attribute("interpreter", ""), LOAD_DATA(node)) #define LOAD_ARRAY(type, variable, size) \ QDomElement xml_##variable = LOAD_NODE(#variable).firstChildElement("element"); \ while (!xml_##variable.isNull()) \ { \ int index = xml_##variable.attribute("index", "-1").toInt(); \ if (0 <= index) \ m_##variable[index] = LOAD_##type(xml_##variable); \ xml_##variable = xml_##variable.nextSiblingElement("element"); \ } #define LOAD_LIST(type, variable) \ QDomElement xml_##variable = LOAD_NODE(#variable); \ xml_##variable = LOAD_NODE(#variable).firstChildElement("element"); \ while (!xml_##variable.isNull()) \ { \ int element = LOAD_int(xml_##variable); \ if (!m_##variable.contains(element)) \ m_##variable.append(element); \ xml_##variable = xml_##variable.nextSiblingElement("element"); \ } #define LOAD_MATRIX(setter, type, variable) \ QDomElement xml_##variable = LOAD_NODE(#variable); \ int height_##variable = xml_##variable.attribute("height", "1").toInt(); \ int width_##variable = xml_##variable.attribute("width", "1").toInt(); \ m_##variable.resize(width_##variable, height_##variable); \ xml_##variable = LOAD_NODE(#variable).firstChildElement("element"); \ while (!xml_##variable.isNull()) \ { \ int row = xml_##variable.attribute("row", "-1").toInt(); \ int column = xml_##variable.attribute("column", "-1").toInt(); \ if ((0 <= row) && (0 <= column)) \ setter(row, column, LOAD_##type(xml_##variable)); \ xml_##variable = xml_##variable.nextSiblingElement("element"); \ } #define LOAD_SUB(setter, class) \ QDomElement xml_##class = xml.firstChildElement(#class); \ while (!xml_##class.isNull()) \ { \ setter(xml_##class); \ xml_##class = xml_##class.nextSiblingElement(#class); \ } #define SAVE_CREATE() \ QDomElement xml = QDomDocument().createElement(className()); \ xml.setAttribute("id", id()) #define SAVE_VALUE(element, value) element.appendChild(QDomDocument().createTextNode(value)) #define SAVE(type, variable) \ QDomElement xml_##variable = QDomDocument().createElement(#variable); \ SAVE_##type(variable, variable()); \ xml.appendChild(xml_##variable) #define SAVE_bool(variable, value) SAVE_VALUE(xml_##variable, value ? "true" : "false") #define SAVE_int(variable, value) SAVE_VALUE(xml_##variable, QString::number(value)) #define SAVE_QString(variable, value) SAVE_VALUE(xml_##variable, value) #define SAVE_Fraction(variable, value) \ Fraction frac_##variable = value; \ xml_##variable.setAttribute("numerator", frac_##variable.numerator()); \ xml_##variable.setAttribute("denominator", frac_##variable.denominator()) #define SAVE_Point(variable, value) \ Point point_##variable = value; \ xml_##variable.setAttribute("x", point_##variable.x()); \ xml_##variable.setAttribute("y", point_##variable.y()) #define SAVE_QPixmap(variable, value) \ QByteArray bytes_##variable; \ QBuffer* buffer_##variable = new QBuffer(&bytes_##variable); \ buffer_##variable->open(QIODevice::WriteOnly); \ value.save(buffer_##variable, "PNG"); \ SAVE_VALUE(xml_##variable, bytes_##variable.toBase64()); \ delete buffer_##variable #define SAVE_QByteArray(variable, value) SAVE_VALUE(xml_##variable, value.toBase64()) #define SAVE_Rules(variable) xml.appendChild(m_##variable->save()) #define SAVE_Script(variable, value) \ Script script_##variable = value; \ xml_##variable.setAttribute("interpreter", script_##variable.interpreter()); \ SAVE_VALUE(xml_##variable, script_##variable.script()) #define SAVE_ARRAY(type, variable, size) \ QDomElement xml_array_##variable = QDomDocument().createElement(#variable); \ for (int i = 0; i < size; ++i) \ { \ QDomElement xml_##variable = QDomDocument().createElement("element"); \ xml_##variable.setAttribute("index", QString::number(i)); \ SAVE_##type(variable, variable(i)); \ xml_array_##variable.appendChild(xml_##variable); \ } \ xml.appendChild(xml_array_##variable) #define SAVE_LIST(type, variable) \ QDomElement xml_list_##variable = QDomDocument().createElement(#variable); \ xml_list_##variable.setAttribute("size", m_##variable.size()); \ for (int i = 0; i < m_##variable.size(); ++i) \ { \ QDomElement xml_##variable = QDomDocument().createElement("element"); \ SAVE_##type(variable, m_##variable[i]); \ xml_list_##variable.appendChild(xml_##variable); \ } \ xml.appendChild(xml_list_##variable) #define SAVE_MATRIX(type, variable) \ QDomElement xml_matrix_##variable = QDomDocument().createElement(#variable); \ xml_matrix_##variable.setAttribute("height", m_##variable.height()); \ xml_matrix_##variable.setAttribute("width", m_##variable.width()); \ for (int i = 0; i < m_##variable.height(); ++i) \ { \ for (int j = 0; j < m_##variable.width(); ++j) \ { \ QDomElement xml_##variable = QDomDocument().createElement("element"); \ xml_##variable.setAttribute("row", QString::number(i)); \ xml_##variable.setAttribute("column", QString::number(j)); \ SAVE_##type(variable, variable(i, j)); \ xml_matrix_##variable.appendChild(xml_##variable); \ } \ } \ xml.appendChild(xml_matrix_##variable) #define SAVE_SUB(class, variable) \ foreach (class* sub, m_##variable) \ xml.appendChild(sub->save()) #define COPY(variable) m_##variable = rhs.m_##variable #define COPY_Rules(variable) *m_##variable= *rhs.m_##variable #define COPY_ARRAY(variable, size) \ for (int i = 0; i < size; ++i) \ COPY(variable[i]) #define COPY_SUB(class, variable) \ foreach (class* subclass, rhs.m_##variable) \ m_##variable.append(new class(*subclass, this, subclass->id())) #define TEST(setter, variable) setter(m_##variable) #define TEST_ARRAY(setter, variable, size) \ for (int i = 0; i < size; ++i) \ setter(i, variable(i)) #define TEST_LIST(setter, variable) \ foreach (int variable, m_##variable) \ setter(variable, true) #define TEST_MATRIX(setter, variable) \ for (int i = 0; i < m_##variable.height(); ++i) \ { \ for (int j = 0; j < m_##variable.width(); ++j) \ setter(i, j, variable(i, j)); \ } \ #define CHECK(variable) CHECK_ARRAY(variable, variable) #define CHECK_ARRAY(variable, value) \ if (m_##variable == value) \ return; \ else \ { \ m_##variable = value; \ emit(changed()); \ } #endif