/* * Copyright 2008-2009 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 . */ /** * \file sigmod/Macros.h * \todo Replace macros with protected methods of Object */ #ifndef SIGMOD_MACROS #define SIGMOD_MACROS #ifdef MAKE_SIGMOD_LIB #include "XmlReader.h" #define LOAD_ID() \ int newId = id; \ if ((id == -1) && xml.hasAttribute("id")) \ newId = xml.attribute("id", "-1").toInt(); \ setId(newId) #define LOAD_BEGIN() clear() #define LOAD(variable) loadValue(xml.firstChildElement(#variable), &m_##variable) #define LOAD_ENUM(variable, type) loadEnum(xml.firstChildElement(#variable), &m_##variable, type##Str) #define LOAD_ARRAY(variable) loadArray(xml.firstChildElement(#variable), &m_##variable) #define LOAD_LIST(variable) loadList(xml.firstChildElement(#variable), &m_##variable) #define LOAD_MAP(variable, valueName) loadMap(xml.firstChildElement(#variable), &m_##variable, #valueName) #define LOAD_MATRIX(variable) loadMatrix(xml.firstChildElement(#variable), &m_##variable) #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() \ QDomDocument doc; \ QDomElement xml = doc.createElement(className()); \ xml.setAttribute("id", id()) #define SAVE(variable) xml.appendChild(saveValue(#variable, m_##variable)) #define SAVE_ENUM(variable, type) xml.appendChild(saveEnum(#variable, m_##variable, type##Str)) #define SAVE_ARRAY(variable) xml.appendChild(saveArray(#variable, m_##variable)) #define SAVE_LIST(variable) xml.appendChild(saveList(#variable, m_##variable)) #define SAVE_MAP(variable, valueName) xml.appendChild(saveMap(#variable, m_##variable, #valueName)) #define SAVE_MATRIX(variable) xml.appendChild(saveMatrix(#variable, m_##variable)) #define SAVE_Rules(variable) xml.appendChild(m_##variable->save()) #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_SUB(class, variable) \ foreach (class* subclass, rhs.m_##variable) \ m_##variable.append(new class(*subclass, this, subclass->id())) #define TEST_BEGIN() \ connect(this, SIGNAL(warning(QString)), SIGNAL(valWarning(QString))); \ connect(this, SIGNAL(error(QString)), SIGNAL(valError(QString))); \ emit(valMessage(QString("++%1 (%2)").arg(className()).arg(id()))) #define TEST_END() \ emit(valMessage(QString("--%1 (%2)").arg(className()).arg(id()))); \ disconnect(this, SIGNAL(warning(QString)), this, SIGNAL(valWarning(QString))); \ disconnect(this, SIGNAL(error(QString)), this, SIGNAL(valError(QString))) #define TEST(variable) variable##Check(m_##variable) #define TEST_ARRAY_INDEX(variable, index) variable##Check(index, m_##variable[index]) #define TEST_ARRAY_INDEX_OFF(variable, index, offset) variable##Check(index, m_##variable[index - offset]) #define TEST_LIST(variable) \ foreach (int variable, m_##variable) \ variable##Check(variable) #define TEST_MAP(variable) \ const QList variable##_keys = m_##variable.keys(); \ foreach (int variable, variable##_keys) \ variable##Check(variable, m_##variable[variable]) #define TEST_MATRIX(variable) \ for (int i = 0; i < m_##variable.height(); ++i) \ { \ for (int j = 0; j < m_##variable.width(); ++j) \ variable##Check(i, j, m_##variable(i, j)); \ } #define TEST_CHILD(object) \ connect(object, SIGNAL(valMessage(QString)), this, SIGNAL(valMessage(QString))); \ connect(object, SIGNAL(valWarning(QString)), this, SIGNAL(valWarning(QString))); \ connect(object, SIGNAL(valError(QString)), this, SIGNAL(valError(QString))); \ object->validate(); \ disconnect(object, SIGNAL(valMessage(QString)), this, SIGNAL(valMessage(QString))); \ disconnect(object, SIGNAL(valWarning(QString)), this, SIGNAL(valWarning(QString))); \ disconnect(object, SIGNAL(valError(QString)), this, SIGNAL(valError(QString))) #define TEST_SUB_BEGIN(type, variable) \ foreach (type* object, m_##variable) \ { \ TEST_CHILD(object) #define TEST_SUB(name, value) TEST_SUB_RAW(value, name, value) #define TEST_SUB_RAW(checking, name, value) \ if (checking##Checker.contains(object->value())) \ emit(error(subclass(name, object->id()))); \ checking##Checker.insert(object->value()) #define TEST_SUB_END() } #define TS(variable) \ if (variable##Check(variable) && (m_##variable != variable)) \ { \ m_##variable = variable; \ emit(changed()); \ } #define TS_ARRAY(variable, index, offset, value) \ if (variable##Check(index, value) && (m_##variable[index - offset] != value)) \ { \ m_##variable[index - offset] = value; \ emit(changed()); \ } #define TS_MATRIX(variable, row, column, value) \ if (variable##Check(value) && (m_##variable(row, column) != value)) \ { \ m_##variable(row, column) = value; \ emit(changed()); \ } #define TS_LIST_BEGIN(variable) \ if (state && variable##Check(variable) && !m_##variable.contains(variable)) \ { #define TS_LIST_INTERNAL(variable) \ m_##variable.append(variable); \ emit(changed()) #define TS_LIST_INTERNAL_LIMIT(variable, limit, limitError) \ if (m_##variable.size() < limit) \ { \ m_##variable.append(variable); \ emit(changed()); \ } \ else \ ERROR(limitError) #define TS_LIST_END(variable) \ } \ else if (!state && m_##variable.contains(variable)) \ { \ m_##variable.removeOne(variable); \ emit(changed()); \ } #define TS_LIST(variable) \ TS_LIST_BEGIN(variable) \ TS_LIST_INTERNAL(variable); \ TS_LIST_END(variable) #define TS_LIST_LIMIT(variable, limit, limitError) \ TS_LIST_BEGIN(variable) \ TS_LIST_INTERNAL_LIMIT(variable, limit, limitError); \ TS_LIST_END(variable) #define WARNING(msg) emit(warning(msg)) #define ERROR(msg) emit(error(msg)) #define EBOUNDS(variable, min, max) EBOUNDS_MOD(variable, (min), (max), variable) #define EBOUNDS_IDX(variable) emit(error(bounds(#variable, variable))) #define EBOUNDS_MOD(variable, min, max, value) emit(error(bounds(#variable, (min), (max), value))) #define TBOUNDS(variable, min, max) TBOUNDS_MOD(variable, min, max, variable) #define TBOUNDS_MOD(variable, min, max, value) \ { \ const __typeof(min) variable##_min = (min); \ const __typeof(max) variable##_max = (max); \ if ((value < variable##_min) || (variable##_max < value)) \ { \ EBOUNDS_MOD(variable, variable##_min, variable##_max, value); \ return false; \ } \ } #define IBOUNDS(variable, pointer, subclass) \ if (!pointer->subclass##ById(variable)) \ { \ EBOUNDS_IDX(variable); \ return false; \ } #define SETTER(class, type, capital, variable) \ void class::set##capital(const type variable) \ { \ TS(variable); \ } #define SETTER_ARRAY(class, type, capital, variable, valueName, indexType, indexName, offset) \ void class::set##capital(const indexType indexName, const type valueName) \ { \ TS_ARRAY(variable, indexName, offset, valueName); \ } #define SETTER_MATRIX(class, type, capital, variable, valueName) \ void class::set##capital(const int row, const int column, const type valueName) \ { \ TS_MATRIX(variable, row, column, valueName); \ } #define SETTER_LIST(class, capital, variable) \ void class::set##capital(const int variable, const bool state) \ { \ TS_LIST(variable); \ } #define SETTER_LIST_LIMIT(class, capital, variable, limit, limitError) \ void class::set##capital(const int variable, const bool state) \ { \ TS_LIST_LIMIT(variable, limit, limitError); \ } #define SETTER_MAP(class, capital, variable, valueName) \ void class::set##capital(const int variable, const int valueName) \ { \ if (valueName && variable##Check(variable, valueName) && (!m_##variable.contains(variable) || (valueName != m_##variable[variable]))) \ { \ m_##variable[variable] = valueName; \ emit(changed()); \ } \ else if (!valueName && m_##variable.contains(variable)) \ { \ m_##variable.remove(variable); \ emit(changed()); \ } \ } #define GETTER(class, type, variable) \ type class::variable() const \ { \ return m_##variable; \ } #define GETTER_ARRAY(class, type, variable, valueName, indexType, indexName, offset) \ type class::variable(const indexType indexName) const \ { \ if (variable##Check(indexName, m_##variable[indexName - offset])) \ return m_##variable[indexName - offset]; \ return type(); \ } #define GETTER_LIST(class, variable) \ bool class::variable(const int variable) const \ { \ return m_##variable.contains(variable); \ } \ \ QList class::variable() const \ { \ return m_##variable; \ } #define GETTER_MAP(class, variable) \ int class::variable(const int variable) const \ { \ if (m_##variable.contains(variable)) \ return m_##variable[variable]; \ return int(); \ } \ \ QMap class::variable() const \ { \ return m_##variable; \ } #define CHECK_BEGIN(class, type, variable) \ bool class::variable##Check(const type variable) const \ { #define CHECK_BEGIN_ARRAY(class, type, variable, valueName, indexType, indexName) \ bool class::variable##Check(const indexType indexName, const type valueName) const \ { #define CHECK_END() \ return true; \ } #define CHECK(class, type, variable) \ CHECK_BEGIN(class, type, variable) \ Q_UNUSED(variable) \ CHECK_END() #define CHECK_INDEX(class, type, variable, pointer, subclass) \ CHECK_BEGIN(class, type, variable) \ IBOUNDS(variable, pointer, subclass) \ CHECK_END() #define CHECK_BOUNDS(class, type, variable, min, max) \ CHECK_BEGIN(class, type, variable) \ TBOUNDS(variable, (min), (max)) \ CHECK_END() #define SUBCLASS_RAW(class, subclass, capital, short, variable) \ const subclass* class::short(const int index) const \ { \ if (index < short##Count()) \ return m_##variable.at(index); \ return NULL; \ } \ \ subclass* class::short(const int index) \ { \ if (index < short##Count()) \ return m_##variable[index]; \ return NULL; \ } \ \ const subclass* class::short##ById(const int id) const \ { \ return short(short##Index(id)); \ } \ \ subclass* class::short##ById(const int id) \ { \ return short(short##Index(id)); \ } \ \ int class::short##Index(const int id) const \ { \ for (int i = 0; i < short##Count(); ++i) \ { \ if (m_##variable[i]->id() == id) \ return i; \ } \ return INT_MAX; \ } \ \ int class::short##Count() const \ { \ return m_##variable.size(); \ } \ \ subclass* class::new##capital() \ { \ return new##capital(new subclass(this, new##capital##Id())); \ } \ \ subclass* class::new##capital(const QDomElement& xml) \ { \ return new##capital(new subclass(xml, this, new##capital##Id())); \ } \ \ subclass* class::new##capital(const subclass& short) \ { \ return new##capital(new subclass(short, this, new##capital##Id())); \ } \ \ subclass* class::new##capital(subclass* short) \ { \ m_##variable.append(short); \ return short; \ } \ \ void class::delete##capital(const int index) \ { \ if (index < short##Count()) \ { \ delete m_##variable[index]; \ m_##variable.removeAt(index); \ } \ } \ \ void class::delete##capital##ById(const int id) \ { \ delete##capital(short##Index(id)); \ } \ \ int class::new##capital##Id() const \ { \ int i = 0; \ while ((i < short##Count()) && (short##Index(i) != INT_MAX)) \ ++i; \ return i; \ } #define SUBCLASS(class, capital, short, variable) SUBCLASS_RAW(class, class##capital, capital, short, variable) #define SSUBCLASS(class, capital, short, variable) SUBCLASS_RAW(class, capital, capital, short, variable) #define SUBCLASS_CLEAR(variable) \ qDeleteAll(m_##variable); \ m_##variable.clear() #endif #endif