File indexing completed on 2024-05-12 15:27:00

0001 /***************************************************************************
0002     File                 : macros.h
0003     Project              : LabPlot
0004     Description          : Various preprocessor macros
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2008 Tilman Benkert (thzs@gmx.net)
0007     Copyright            : (C) 2013-2015 Alexander Semke (alexander.semke@web.de)
0008     Copyright            : (C) 2016-2020 Stefan Gerlach (stefan.gerlach@uni.kn)
0009 
0010  ***************************************************************************/
0011 
0012 /***************************************************************************
0013  *                                                                         *
0014  *  This program is free software; you can redistribute it and/or modify   *
0015  *  it under the terms of the GNU General Public License as published by   *
0016  *  the Free Software Foundation; either version 2 of the License, or      *
0017  *  (at your option) any later version.                                    *
0018  *                                                                         *
0019  *  This program is distributed in the hope that it will be useful,        *
0020  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0021  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0022  *  GNU General Public License for more details.                           *
0023  *                                                                         *
0024  *   You should have received a copy of the GNU General Public License     *
0025  *   along with this program; if not, write to the Free Software           *
0026  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0027  *   Boston, MA  02110-1301  USA                                           *
0028  *                                                                         *
0029  ***************************************************************************/
0030 
0031 #ifndef MACROS_H
0032 #define MACROS_H
0033 
0034 // SET_NUMBER_LOCALE
0035 #include <KSharedConfig>
0036 #include <KConfigGroup>
0037 
0038 #include <QApplication>
0039 #include <QMetaEnum>
0040 
0041 // C++ style warning (works on Windows)
0042 #include <iostream>
0043 #define WARN(x) std::cout << x << std::endl;
0044 
0045 #ifndef NDEBUG
0046 #include <QDebug>
0047 #define QDEBUG(x) qDebug() << x;
0048 // C++ style debugging (works on Windows)
0049 #include <iomanip>
0050 #define DEBUG(x) std::cout << x << std::endl;
0051 #else
0052 #define QDEBUG(x) {}
0053 #define DEBUG(x) {}
0054 #endif
0055 
0056 #if QT_VERSION < 0x050700
0057 template <class T>
0058 constexpr std::add_const_t<T>& qAsConst(T& t) noexcept {
0059     return t;
0060 }
0061 #endif
0062 
0063 #define WAIT_CURSOR QApplication::setOverrideCursor(QCursor(Qt::WaitCursor))
0064 #define RESET_CURSOR QApplication::restoreOverrideCursor()
0065 
0066 #define UTF8_QSTRING(str) QString::fromUtf8(str)
0067 #define STDSTRING(qstr) qstr.toUtf8().constData()
0068 
0069 #define ENUM_TO_STRING(class, enum, value) \
0070     (class::staticMetaObject.enumerator(class::staticMetaObject.indexOfEnumerator(#enum)).valueToKey(static_cast<int>(value)))
0071 #define ENUM_COUNT(class, enum) \
0072     (class::staticMetaObject.enumerator(class::staticMetaObject.indexOfEnumerator(#enum)).keyCount())
0073 
0074 // define number locale from setting (using system locale when QLocale::AnyLanguage)
0075 #define SET_NUMBER_LOCALE \
0076 QLocale::Language numberLocaleLanguage = static_cast<QLocale::Language>(KSharedConfig::openConfig()->group("Settings_General").readEntry( QLatin1String("DecimalSeparatorLocale"), static_cast<int>(QLocale::Language::AnyLanguage) )); \
0077 QLocale numberLocale(numberLocaleLanguage == QLocale::AnyLanguage ? QLocale() : numberLocaleLanguage); \
0078 if (numberLocale.language() == QLocale::Language::C) \
0079     numberLocale.setNumberOptions(QLocale::DefaultNumberOptions);
0080 
0081 //////////////////////// LineEdit Access ///////////////////////////////
0082 #define SET_INT_FROM_LE(var, le) { \
0083     bool ok; \
0084     SET_NUMBER_LOCALE \
0085     const int tmp = numberLocale.toInt((le)->text(), &ok); \
0086     if (ok) \
0087         var = tmp; \
0088 }
0089 
0090 #define SET_DOUBLE_FROM_LE(var, le) { \
0091     bool ok; \
0092     SET_NUMBER_LOCALE \
0093     const double tmp = numberLocale.toDouble((le)->text(), &ok); \
0094     if (ok) \
0095         var = tmp; \
0096 }
0097 
0098 //////////////////////// Accessor ///////////////////////////////
0099 
0100 #define BASIC_ACCESSOR(type, var, method, Method) \
0101     type method() const { return var; }; \
0102     void set ## Method(const type value) { var = value; }
0103 #define CLASS_ACCESSOR(type, var, method, Method) \
0104     type method() const { return var; }; \
0105     void set ## Method(const type & value) { var = value; }
0106 
0107 #define BASIC_D_ACCESSOR_DECL(type, method, Method) \
0108     type method() const; \
0109     void set ## Method(const type value);
0110 
0111 #define BASIC_D_ACCESSOR_IMPL(classname, type, method, Method, var) \
0112     void classname::set ## Method(const type value) \
0113     { \
0114         d->var = value; \
0115     } \
0116     type classname::method() const \
0117     { \
0118         return d->var; \
0119     }
0120 
0121 #define BASIC_D_READER_IMPL(classname, type, method, var) \
0122     type classname::method() const \
0123     { \
0124         return d->var; \
0125     }
0126 
0127 #define BASIC_SHARED_D_READER_IMPL(classname, type, method, var) \
0128     type classname::method() const \
0129     { \
0130         Q_D(const classname); \
0131         return d->var; \
0132     }
0133 
0134 #define CLASS_D_ACCESSOR_DECL(type, method, Method) \
0135     type method() const; \
0136     void set ## Method(const type & value);
0137 
0138 #define CLASS_D_ACCESSOR_IMPL(classname, type, method, Method, var) \
0139     void classname::set ## Method(const type & value) \
0140     { \
0141         d->var = value; \
0142     } \
0143     type classname::method() const \
0144     { \
0145         return d->var; \
0146     }
0147 
0148 #define CLASS_D_READER_IMPL(classname, type, method, var) \
0149     type classname::method() const \
0150     { \
0151         return d->var; \
0152     }
0153 
0154 #define CLASS_SHARED_D_READER_IMPL(classname, type, method, var) \
0155     type classname::method() const \
0156     { \
0157         Q_D(const classname); \
0158         return d->var; \
0159     }
0160 
0161 #define POINTER_D_ACCESSOR_DECL(type, method, Method) \
0162     type *method() const; \
0163     void set ## Method(type *ptr);
0164 
0165 #define FLAG_D_ACCESSOR_DECL(Method) \
0166     bool is ## Method() const; \
0167     bool has ## Method() const; \
0168     void set ## Method(const bool value = true); \
0169     void enable ## Method(const bool value = true);
0170 
0171 #define FLAG_D_ACCESSOR_IMPL(classname, Method, var) \
0172     void classname::set ## Method(const bool value) \
0173     { \
0174         d->var = value; \
0175     } \
0176     void classname::enable ## Method(const bool value) \
0177     { \
0178         d->var = value; \
0179     } \
0180     bool classname::is ## Method() const \
0181     { \
0182         return d->var; \
0183     } \
0184     bool classname::has ## Method() const \
0185     { \
0186         return d->var; \
0187     }
0188 
0189 //////////////////////// Standard Setter /////////////////////
0190 
0191 #define STD_SETTER_CMD_IMPL(class_name, cmd_name, value_type, field_name) \
0192 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0193     public: \
0194         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0195             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0196 };
0197 
0198 #define STD_SETTER_CMD_IMPL_F(class_name, cmd_name, value_type, field_name, finalize_method) \
0199 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0200     public: \
0201         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0202             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0203         virtual void finalize() override { m_target->finalize_method(); } \
0204 };
0205 
0206 // setter class with finalize() and signal emitting.
0207 #define STD_SETTER_CMD_IMPL_S(class_name, cmd_name, value_type, field_name) \
0208 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0209     public: \
0210         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0211             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0212         virtual void finalize() override { emit m_target->q->field_name##Changed(m_target->*m_field); } \
0213 };
0214 
0215 #define STD_SETTER_CMD_IMPL_F_S(class_name, cmd_name, value_type, field_name, finalize_method) \
0216 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0217     public: \
0218         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0219             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0220         virtual void finalize() override { m_target->finalize_method(); emit m_target->q->field_name##Changed(m_target->*m_field); } \
0221 };
0222 
0223 // setter class with finalize() and signal emitting for changing several properties in one single step (embedded in beginMacro/endMacro)
0224 #define STD_SETTER_CMD_IMPL_M_F_S(class_name, cmd_name, value_type, field_name, finalize_method) \
0225 class class_name ## cmd_name ## Cmd: public StandardMacroSetterCmd<class_name::Private, value_type> { \
0226     public: \
0227         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0228             : StandardMacroSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0229         virtual void finalize() override { m_target->finalize_method(); emit m_target->q->field_name##Changed(m_target->*m_field); } \
0230         virtual void finalizeUndo() override { emit m_target->q->field_name##Changed(m_target->*m_field); } \
0231 };
0232 
0233 #define STD_SETTER_CMD_IMPL_I(class_name, cmd_name, value_type, field_name, init_method) \
0234 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0235     public: \
0236         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0237             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0238         virtual void initialize() { m_target->init_method(); } \
0239 };
0240 
0241 #define STD_SETTER_CMD_IMPL_IF(class_name, cmd_name, value_type, field_name, init_method, finalize_method) \
0242 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \
0243     public: \
0244         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0245             : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \
0246         virtual void initialize() { m_target->init_method(); } \
0247         virtual void finalize() { m_target->finalize_method(); } \
0248 };
0249 
0250 #define STD_SWAP_METHOD_SETTER_CMD_IMPL(class_name, cmd_name, value_type, method_name) \
0251 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \
0252     public: \
0253         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0254             : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \
0255 };
0256 
0257 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_F(class_name, cmd_name, value_type, method_name, finalize_method) \
0258 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \
0259     public: \
0260         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0261             : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \
0262         virtual void finalize() override { m_target->finalize_method(); } \
0263 };
0264 
0265 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_I(class_name, cmd_name, value_type, method_name, init_method) \
0266 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \
0267     public: \
0268         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0269             : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \
0270         virtual void initialize() { m_target->init_method(); } \
0271 };
0272 
0273 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_IF(class_name, cmd_name, value_type, method_name, init_method, finalize_method) \
0274 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \
0275     public: \
0276         class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \
0277             : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \
0278         virtual void initialize() { m_target->init_method(); } \
0279         virtual void finalize() { m_target->finalize_method(); } \
0280 };
0281 
0282 
0283 //////////////////////// XML - serialization/deserialization /////
0284 
0285 //QColor
0286 #define WRITE_QCOLOR(color)                                                 \
0287 do {                                                                        \
0288 writer->writeAttribute( "color_r", QString::number(color.red()) );          \
0289 writer->writeAttribute( "color_g", QString::number(color.green()) );        \
0290 writer->writeAttribute( "color_b", QString::number(color.blue()) );         \
0291 } while (0)
0292 
0293 #define READ_QCOLOR(color)                                                  \
0294 do {                                                                        \
0295 str = attribs.value("color_r").toString();                                  \
0296 if(str.isEmpty())                                                           \
0297     reader->raiseWarning(attributeWarning.subs("color_r").toString());              \
0298 else                                                                        \
0299     color.setRed( str.toInt() );                                            \
0300                                                                             \
0301 str = attribs.value("color_g").toString();                                  \
0302 if(str.isEmpty())                                                           \
0303     reader->raiseWarning(attributeWarning.subs("color_g").toString());              \
0304 else                                                                        \
0305     color.setGreen( str.toInt() );                                          \
0306                                                                             \
0307 str = attribs.value("color_b").toString();                                  \
0308 if(str.isEmpty())                                                           \
0309     reader->raiseWarning(attributeWarning.subs("color_b").toString());              \
0310 else                                                                        \
0311     color.setBlue( str.toInt() );                                           \
0312 } while(0)
0313 
0314 //QPen
0315 #define WRITE_QPEN(pen)                                                     \
0316 do {                                                                        \
0317 writer->writeAttribute( "style", QString::number(pen.style()) );            \
0318 writer->writeAttribute( "color_r", QString::number(pen.color().red()) );    \
0319 writer->writeAttribute( "color_g", QString::number(pen.color().green()) );  \
0320 writer->writeAttribute( "color_b", QString::number(pen.color().blue()) );   \
0321 writer->writeAttribute( "width", QString::number(pen.widthF()) );           \
0322 } while (0)
0323 
0324 #define READ_QPEN(pen)                                                      \
0325 do {                                                                        \
0326 str = attribs.value("style").toString();                                    \
0327 if(str.isEmpty())                                                           \
0328     reader->raiseWarning(attributeWarning.subs("style").toString());                    \
0329 else                                                                        \
0330     pen.setStyle( (Qt::PenStyle)str.toInt() );                              \
0331                                                                             \
0332 QColor color;                                                               \
0333 str = attribs.value("color_r").toString();                                  \
0334 if(str.isEmpty())                                                           \
0335     reader->raiseWarning(attributeWarning.subs("color_r").toString());              \
0336 else                                                                        \
0337     color.setRed( str.toInt() );                                            \
0338                                                                             \
0339 str = attribs.value("color_g").toString();                                  \
0340 if(str.isEmpty())                                                           \
0341     reader->raiseWarning(attributeWarning.subs("color_g").toString());              \
0342 else                                                                        \
0343     color.setGreen( str.toInt() );                                          \
0344                                                                             \
0345 str = attribs.value("color_b").toString();                                  \
0346 if(str.isEmpty())                                                           \
0347     reader->raiseWarning(attributeWarning.subs("color_b").toString());              \
0348 else                                                                        \
0349     color.setBlue( str.toInt() );                                           \
0350                                                                             \
0351 pen.setColor(color);                                                        \
0352                                                                             \
0353 str = attribs.value("width").toString();                                    \
0354 if(str.isEmpty())                                                           \
0355     reader->raiseWarning(attributeWarning.subs("width").toString());                    \
0356 else                                                                        \
0357     pen.setWidthF( str.toDouble() );                                        \
0358 } while(0)
0359 
0360 //QFont
0361 #define WRITE_QFONT(font)                                                   \
0362 do {                                                                        \
0363 writer->writeAttribute( "fontFamily", font.family() );                      \
0364 writer->writeAttribute( "fontSize", QString::number(font.pixelSize()) );    \
0365 writer->writeAttribute( "fontPointSize", QString::number(font.pointSize()));\
0366 writer->writeAttribute( "fontWeight", QString::number(font.weight()) );     \
0367 writer->writeAttribute( "fontItalic", QString::number(font.italic()) );     \
0368 } while(0)
0369 
0370 #define READ_QFONT(font)                                                    \
0371 do {                                                                        \
0372 str = attribs.value("fontFamily").toString();                               \
0373 if(str.isEmpty())                                                           \
0374     reader->raiseWarning(attributeWarning.subs("fontFamily").toString());               \
0375 else                                                                        \
0376     font.setFamily( str );                                                  \
0377                                                                             \
0378 str = attribs.value("fontSize").toString();                                 \
0379 if(str.isEmpty())                                                           \
0380     reader->raiseWarning(attributeWarning.subs("fontSize").toString());             \
0381 else {                                                                      \
0382     int size = str.toInt();                                                 \
0383     if (size != -1)                                                         \
0384         font.setPixelSize(size);                                            \
0385 }                                                                           \
0386                                                                             \
0387 str = attribs.value("fontPointSize").toString();                            \
0388 if(str.isEmpty())                                                           \
0389     reader->raiseWarning(attributeWarning.subs("fontPointSize").toString());            \
0390 else {                                                                      \
0391     int size = str.toInt();                                                 \
0392     if (size != -1)                                                         \
0393         font.setPointSize(size);                                            \
0394 }                                                                           \
0395                                                                             \
0396 str = attribs.value("fontWeight").toString();                               \
0397 if(str.isEmpty())                                                           \
0398     reader->raiseWarning(attributeWarning.subs("fontWeight").toString());               \
0399 else                                                                        \
0400     font.setWeight( str.toInt() );                                          \
0401                                                                             \
0402 str = attribs.value("fontItalic").toString();                               \
0403 if(str.isEmpty())                                                           \
0404     reader->raiseWarning(attributeWarning.subs("fontItalic").toString());               \
0405 else                                                                        \
0406     font.setItalic( str.toInt() );                                          \
0407 } while(0)
0408 
0409 //QBrush
0410 #define WRITE_QBRUSH(brush)                                                     \
0411 do {                                                                            \
0412 writer->writeAttribute("brush_style", QString::number(brush.style()) );         \
0413 writer->writeAttribute("brush_color_r", QString::number(brush.color().red()));  \
0414 writer->writeAttribute("brush_color_g", QString::number(brush.color().green()));\
0415 writer->writeAttribute("brush_color_b", QString::number(brush.color().blue())); \
0416 } while(0)
0417 
0418 #define READ_QBRUSH(brush)                                                  \
0419 do {                                                                        \
0420 str = attribs.value("brush_style").toString();                              \
0421 if(str.isEmpty())                                                           \
0422     reader->raiseWarning(attributeWarning.subs("brush_style").toString());          \
0423 else                                                                        \
0424     brush.setStyle( (Qt::BrushStyle)str.toInt() );                          \
0425                                                                             \
0426 QColor color;                                                               \
0427 str = attribs.value("brush_color_r").toString();                            \
0428 if(str.isEmpty())                                                           \
0429     reader->raiseWarning(attributeWarning.subs("brush_color_r").toString());            \
0430 else                                                                        \
0431     color.setRed( str.toInt() );                                            \
0432                                                                             \
0433 str = attribs.value("brush_color_g").toString();                            \
0434 if(str.isEmpty())                                                           \
0435     reader->raiseWarning(attributeWarning.subs("brush_color_g").toString());            \
0436 else                                                                        \
0437     color.setGreen( str.toInt() );                                          \
0438                                                                             \
0439 str = attribs.value("brush_color_b").toString();                            \
0440 if(str.isEmpty())                                                           \
0441     reader->raiseWarning(attributeWarning.subs("brush_color_b").toString());            \
0442 else                                                                        \
0443     color.setBlue( str.toInt() );                                           \
0444                                                                             \
0445 brush.setColor(color);                                                      \
0446 } while(0)
0447 
0448 
0449 
0450 //Column
0451 #define WRITE_COLUMN(column, columnName)                                            \
0452 do {                                                                                \
0453 if (column){                                                                        \
0454     writer->writeAttribute( #columnName, column->path() );                          \
0455 } else {                                                                            \
0456     writer->writeAttribute( #columnName, QString() );                                       \
0457 }                                                                                   \
0458 } while(0)
0459 
0460 //column names can be empty in case no columns were used before save
0461 //the actual pointers to the x- and y-columns are restored in Project::load()
0462 #define READ_COLUMN(columnName)                                                     \
0463 do {                                                                                \
0464     str = attribs.value(#columnName).toString();                                    \
0465     d->columnName ##Path = str;                                                     \
0466 } while(0)
0467 
0468 #define READ_INT_VALUE(name, var, type) \
0469 str = attribs.value(name).toString(); \
0470 if (str.isEmpty()) \
0471     reader->raiseWarning(attributeWarning.subs(name).toString()); \
0472 else \
0473     d->var = (type)str.toInt();
0474 
0475 #define READ_DOUBLE_VALUE(name, var) \
0476 str = attribs.value(name).toString(); \
0477 if (str.isEmpty()) \
0478     reader->raiseWarning(attributeWarning.subs(name).toString()); \
0479 else \
0480     d->var = str.toDouble();
0481 
0482 #define READ_STRING_VALUE(name, var) \
0483 str = attribs.value(name).toString(); \
0484 if (str.isEmpty()) \
0485     reader->raiseWarning(attributeWarning.subs(name).toString()); \
0486 else \
0487     d->var = str;
0488 
0489 //used in Project::load()
0490 #define RESTORE_COLUMN_POINTER(obj, col, Col)                                       \
0491 do {                                                                                \
0492 if (!obj->col ##Path().isEmpty()) {                                                 \
0493     for (Column* column : columns) {                                                \
0494         if (!column) continue;                                                      \
0495         if (column->path() == obj->col ##Path()) {                                  \
0496             obj->set## Col(column);                                                 \
0497             break;                                                                  \
0498         }                                                                           \
0499     }                                                                               \
0500 }                                                                                   \
0501 } while(0)
0502 
0503 
0504 
0505 #define WRITE_PATH(obj, name)                                                       \
0506 do {                                                                                \
0507 if (obj){                                                                           \
0508     writer->writeAttribute( #name, obj->path() );                                   \
0509 } else {                                                                            \
0510     writer->writeAttribute( #name, QString() );                                         \
0511 }                                                                                   \
0512 } while(0)
0513 
0514 #define READ_PATH(name)                                                             \
0515 do {                                                                                \
0516     str = attribs.value(#name).toString();                                          \
0517     d->name ##Path = str;                                                           \
0518 } while(0)
0519 
0520 #define RESTORE_POINTER(obj, name, Name, Type, list)                                \
0521 do {                                                                                \
0522 if (!obj->name ##Path().isEmpty()) {                                                \
0523     for (AbstractAspect* aspect : list) {                                           \
0524         if (aspect->path() == obj->name ##Path()) {                                 \
0525             auto a = dynamic_cast<Type*>(aspect);                                   \
0526             if (!a) continue;                                                       \
0527             obj->set## Name(a);                                                     \
0528             break;                                                                  \
0529         }                                                                           \
0530     }                                                                               \
0531 }                                                                                   \
0532 } while(0)
0533 
0534 #endif // MACROS_H