From 449b8a93170ecc19f2f438b160d0bc4122999401 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 18 May 2011 14:39:44 +0200 Subject: QUiLoader, QAbstractFormBuilder: Introduce errorString(). Introduce errorString() to be able to obtain load errors in Qt Designer. Remove automatic Qt 3 form conversion from Qt Designer (since uic3 no longer exists) and move all form load error checking logic including language check into QAbstractFormBuilder. Make language accessible in FormBuilderExtra in case Jambi is revived. Reviewed-by: hjk --- tools/uilib/abstractformbuilder.cpp | 112 ++++++++++++++++++++++++++++-------- tools/uilib/abstractformbuilder.h | 2 + tools/uilib/formbuilderextra.cpp | 1 + tools/uilib/formbuilderextra_p.h | 2 + 4 files changed, 94 insertions(+), 23 deletions(-) (limited to 'tools') diff --git a/tools/uilib/abstractformbuilder.cpp b/tools/uilib/abstractformbuilder.cpp index 4d142bd09f..1d44ad5ee6 100644 --- a/tools/uilib/abstractformbuilder.cpp +++ b/tools/uilib/abstractformbuilder.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -177,44 +178,97 @@ QAbstractFormBuilder::~QAbstractFormBuilder() { } +// Return UI file version from attribute 'version="4.0"' +static QPair uiVersion(const QString &attr) +{ + const QStringList versions = attr.split(QLatin1Char('.'), QString::SkipEmptyParts); + if (versions.size() >= 2) { + bool okMajor, okMinor; + const int majorVersion = versions.at(0).toInt(&okMajor); + const int minorVersion = versions.at(1).toInt(&okMinor); + if (okMajor && okMinor) + return QPair(majorVersion, minorVersion); + } + return QPair(-1, -1); +} + +static inline QString msgXmlError(const QXmlStreamReader &reader) +{ + return QCoreApplication::translate("QAbstractFormBuilder", "An error has occurred while reading the UI file at line %1, column %2: %3") + .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()); +} + +// Read and check the version and the (optional) language attribute +// of an element and leave reader positioned at . +static bool inline readUiAttributes(QXmlStreamReader &reader, const QString &language, QString *errorMessage) +{ + const QString uiElement = QLatin1String("ui"); + // Read up to first element + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::Invalid: + *errorMessage = msgXmlError(reader); + return false; + case QXmlStreamReader::StartElement: + if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) { + const QString versionAttribute = QLatin1String("version"); + const QString languageAttribute = QLatin1String("language"); + const QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(versionAttribute)) { + const QString versionString = attributes.value(versionAttribute).toString(); + if (uiVersion(versionString).first < 4) { + *errorMessage = QCoreApplication::translate("QAbstractFormBuilder", "This file was created using Designer from Qt-%1 and cannot be read.") + .arg(versionString); + return false; + } // version error + } // has version + if (attributes.hasAttribute(languageAttribute)) { + // Check on optional language (Jambi) + const QString formLanguage = attributes.value(languageAttribute).toString(); + if (!formLanguage.isEmpty() && formLanguage.compare(language, Qt::CaseInsensitive)) { + *errorMessage = QCoreApplication::translate("QAbstractFormBuilder", "This file cannot be read because it was created using %1.").arg(formLanguage); + return false; + } // language error + } // has language + return true; + } // matched + break; + default: + break; + } + } + // No found. + *errorMessage = QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file: The root element is missing."); + return false; +} + /*! \fn QWidget *QAbstractFormBuilder::load(QIODevice *device, QWidget *parent) Loads an XML representation of a widget from the given \a device, and constructs a new widget with the specified \a parent. - \sa save() + \sa save(), errorString() */ QWidget *QAbstractFormBuilder::load(QIODevice *dev, QWidget *parentWidget) { - QXmlStreamReader reader; - reader.setDevice(dev); - DomUI ui; - bool initialized = false; - - const QString uiElement = QLatin1String("ui"); - while (!reader.atEnd()) { - if (reader.readNext() == QXmlStreamReader::StartElement) { - if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) { - ui.read(reader); - initialized = true; - } else { - reader.raiseError(QCoreApplication::translate("QAbstractFormBuilder", "Unexpected element <%1>").arg(reader.name().toString())); - } - } + QXmlStreamReader reader(dev); + d->m_errorString.clear(); + if (!readUiAttributes(reader, d->m_language, &d->m_errorString)) { + uiLibWarning(d->m_errorString); + return false; } + DomUI ui; + ui.read(reader); if (reader.hasError()) { - uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "An error has occurred while reading the UI file at line %1, column %2: %3") - .arg(reader.lineNumber()).arg(reader.columnNumber()) - .arg(reader.errorString())); - return 0; - } - if (!initialized) { - uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file: The root element is missing.")); + d->m_errorString = msgXmlError(reader); + uiLibWarning(d->m_errorString); return 0; } QWidget *widget = create(&ui, parentWidget); + if (!widget && d->m_errorString.isEmpty()) + d->m_errorString = QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file"); return widget; } @@ -3119,4 +3173,16 @@ bool QAbstractFormBuilder::isScriptingEnabled() const #endif } +/*! + Returns a human-readable description of the last error occurred in load(). + + \since 5.0 + \sa load() +*/ + +QString QAbstractFormBuilder::errorString() const +{ + return d->m_errorString; +} + QT_END_NAMESPACE diff --git a/tools/uilib/abstractformbuilder.h b/tools/uilib/abstractformbuilder.h index 4c22570932..3a1ddccc66 100644 --- a/tools/uilib/abstractformbuilder.h +++ b/tools/uilib/abstractformbuilder.h @@ -127,6 +127,8 @@ public: void setScriptingEnabled(bool enabled); bool isScriptingEnabled() const; + QString errorString() const; + protected: // // load diff --git a/tools/uilib/formbuilderextra.cpp b/tools/uilib/formbuilderextra.cpp index 12e43f1e38..20e8e75327 100644 --- a/tools/uilib/formbuilderextra.cpp +++ b/tools/uilib/formbuilderextra.cpp @@ -87,6 +87,7 @@ QFormBuilderExtra::CustomWidgetData::CustomWidgetData(const DomCustomWidget *dcw QFormBuilderExtra::QFormBuilderExtra() : m_defaultMargin(INT_MIN), m_defaultSpacing(INT_MIN), + m_language(QLatin1String("c++")), m_layoutWidget(false), m_resourceBuilder(0), m_textBuilder(0) diff --git a/tools/uilib/formbuilderextra_p.h b/tools/uilib/formbuilderextra_p.h index a5e2029391..777776039d 100644 --- a/tools/uilib/formbuilderextra_p.h +++ b/tools/uilib/formbuilderextra_p.h @@ -180,6 +180,8 @@ public: int m_defaultMargin; int m_defaultSpacing; QDir m_workingDirectory; + QString m_errorString; + QString m_language; private: void clearResourceBuilder(); -- cgit v1.2.3 From e00b8105bfcf3d4e36275dea6355705ec5fdbc40 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 20 May 2011 10:10:32 +0200 Subject: Designer: Extend container extension. Make it possible to disable adding/removing pages by adding respective bool virtual functions. Useful for implementing containers with fixed, single children like QScrollArea, QDockWidget, which require a container extension to work properly in Qt Designer. Previously, the problem was that the add/remove page context menu actions were enabled for them, leading to crashes und undesired behaviour. Reviewed-by: Jarek Kobus --- tools/uilib/container.h | 7 +++++++ tools/uilib/container.qdoc | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'tools') diff --git a/tools/uilib/container.h b/tools/uilib/container.h index 89df461e02..f0d89faa08 100644 --- a/tools/uilib/container.h +++ b/tools/uilib/container.h @@ -65,6 +65,13 @@ public: virtual void addWidget(QWidget *widget) = 0; virtual void insertWidget(int index, QWidget *widget) = 0; virtual void remove(int index) = 0; + + virtual bool canAddWidget() const + // ### Qt6 remove body, provided in Qt5 for source compatibility to Qt4. + { return true; } + virtual bool canRemove(int index) const + // ### Qt6 remove body, provided in Qt5 for source compatibility to Qt4. + { Q_UNUSED(index); return true; } }; Q_DECLARE_EXTENSION_INTERFACE(QDesignerContainerExtension, "com.trolltech.Qt.Designer.Container") diff --git a/tools/uilib/container.qdoc b/tools/uilib/container.qdoc index d9310515d3..f8e0670811 100644 --- a/tools/uilib/container.qdoc +++ b/tools/uilib/container.qdoc @@ -170,3 +170,30 @@ \sa addWidget(), insertWidget() */ + +/*! + \fn bool QDesignerContainerExtension::canAddWidget() const + + Returns whether a widget can be added. This determines whether + the context menu options to add or insert pages are enabled. + + This should return false for containers that have a single, fixed + page, for example QScrollArea or QDockWidget. + + \since 5.0 + \sa addWidget(), canRemove() +*/ + +/*! + \fn bool QDesignerContainerExtension::canRemove(int index) const + + Returns whether the widget at the given \a index can be removed. + This determines whether the context menu option to remove the current + page is enabled. + + This should return false for containers that have a single, fixed + page, for example QScrollArea or QDockWidget. + + \since 5.0 + \sa remove(), canAddWidget() +*/ -- cgit v1.2.3