diff options
author | Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> | 2015-07-17 14:21:55 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> | 2015-07-29 11:10:34 +0000 |
commit | a98e3ba6238788e5b94dfda7d63a9df380b905af (patch) | |
tree | 9e6352d74a1f03ebbd7e96c3e2ccde5e8945a461 | |
parent | 08a732b69e951b8f1ca53d2e047c432407f42d67 (diff) | |
download | qttools-a98e3ba6238788e5b94dfda7d63a9df380b905af.tar.gz qttools-a98e3ba6238788e5b94dfda7d63a9df380b905af.tar.bz2 qttools-a98e3ba6238788e5b94dfda7d63a9df380b905af.zip |
Qt Designer: Add customizable property tooltips.
- Introduce tag propertytooltip to property specifications
in the ui XML snippet returned by
QDesignerCustomWidgetInterface::domXml()
- Pass the text to the property editor and set as description tooltip
on the property.
- As an added benefit, show the type in the normal tooltip.
- Demonstrate using TicTacToe example.
[ChangeLog][Qt Designer] Added customizable property tooltips.
Task-number: QTBUG-45442
Change-Id: I371bbbb3a6f2bc0f433193b5eb45658211ca67de
Reviewed-by: Jarek Kobus <jaroslaw.kobus@theqtcompany.com>
-rw-r--r-- | examples/designer/taskmenuextension/tictactoeplugin.cpp | 1 | ||||
-rw-r--r-- | src/designer/data/ui4.xsd | 5 | ||||
-rw-r--r-- | src/designer/src/components/propertyeditor/propertyeditor.cpp | 59 | ||||
-rw-r--r-- | src/designer/src/designer/doc/src/designer-manual.qdoc | 13 | ||||
-rw-r--r-- | src/designer/src/lib/shared/pluginmanager.cpp | 69 | ||||
-rw-r--r-- | src/designer/src/lib/shared/pluginmanager_p.h | 2 | ||||
-rw-r--r-- | src/designer/src/lib/uilib/ui4.cpp | 86 | ||||
-rw-r--r-- | src/designer/src/lib/uilib/ui4_p.h | 40 |
8 files changed, 228 insertions, 47 deletions
diff --git a/examples/designer/taskmenuextension/tictactoeplugin.cpp b/examples/designer/taskmenuextension/tictactoeplugin.cpp index 770a44a2..6e0c7b02 100644 --- a/examples/designer/taskmenuextension/tictactoeplugin.cpp +++ b/examples/designer/taskmenuextension/tictactoeplugin.cpp @@ -127,6 +127,7 @@ QString TicTacToePlugin::domXml() const <customwidget>\ <class>TicTacToe</class>\ <propertyspecifications>\ + <tooltip name=\"state\">Tic Tac Toe state</tooltip>\ <stringpropertyspecification name=\"state\" notr=\"true\" type=\"singleline\"/>\ </propertyspecifications>\ </customwidget>\ diff --git a/src/designer/data/ui4.xsd b/src/designer/data/ui4.xsd index 62a69429..e5474a65 100644 --- a/src/designer/data/ui4.xsd +++ b/src/designer/data/ui4.xsd @@ -579,10 +579,15 @@ <xs:complexType name="PropertySpecifications"> <xs:sequence maxOccurs="unbounded"> + <xs:element name="tooltip" type="PropertyToolTip" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="stringpropertyspecification" type="StringPropertySpecification" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> + <xs:complexType name="PropertyToolTip"> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + <xs:complexType name="StringPropertySpecification"> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="type" type="xs:string" use="required" /> diff --git a/src/designer/src/components/propertyeditor/propertyeditor.cpp b/src/designer/src/components/propertyeditor/propertyeditor.cpp index 75ecf70b..91e70236 100644 --- a/src/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/src/designer/src/components/propertyeditor/propertyeditor.cpp @@ -56,9 +56,8 @@ #include <qdesigner_propertycommand_p.h> #include <metadatabase_p.h> #include <iconloader_p.h> -#ifdef Q_OS_WIN -# include <widgetfactory_p.h> -#endif +#include <widgetfactory_p.h> + #include <QtWidgets/QAction> #include <QtWidgets/QLineEdit> #include <QtWidgets/QMenu> @@ -909,22 +908,36 @@ QString PropertyEditor::realClassName(QObject *object) const return className; } -static QString msgUnsupportedType(const QString &propertyName, unsigned type) +static const char *typeName(int type) +{ + if (type == qMetaTypeId<PropertySheetStringValue>()) + type = QVariant::String; + if (type < int(QVariant::UserType)) + return QVariant::typeToName(static_cast<QVariant::Type>(type)); + if (type == qMetaTypeId<PropertySheetIconValue>()) + return "QIcon"; + if (type == qMetaTypeId<PropertySheetPixmapValue>()) + return "QPixmap"; + if (type == qMetaTypeId<PropertySheetKeySequenceValue>()) + return "QKeySequence"; + if (type == qMetaTypeId<PropertySheetFlagValue>()) + return "QFlags"; + if (type == qMetaTypeId<PropertySheetEnumValue>()) + return "enum"; + if (type == QVariant::Invalid) + return "invalid"; + if (type == QVariant::UserType) + return "user type"; + return Q_NULLPTR; +} + +static QString msgUnsupportedType(const QString &propertyName, int type) { QString rc; QTextStream str(&rc); - str << "The property \"" << propertyName << "\" of type " << type; - if (type == QVariant::Invalid) { - str << " (invalid) "; - } else { - if (type < QVariant::UserType) { - if (const char *typeName = QVariant::typeToName(static_cast<QVariant::Type>(type))) - str << " (" << typeName << ") "; - } else { - str << " (user type) "; - } - } - str << " is not supported yet!"; + const char *typeS = typeName(type); + str << "The property \"" << propertyName << "\" of type (" + << (typeS ? typeS : "unknown") << ") is not supported yet!"; return rc; } @@ -998,6 +1011,9 @@ void PropertyEditor::setObject(QObject *object) m_groups.clear(); if (m_propertySheet) { + const QString className = WidgetFactory::classNameOf(formWindow->core(), m_object); + const QDesignerCustomWidgetData customData = formWindow->core()->pluginManager()->customWidgetData(className); + QtProperty *lastProperty = 0; QtProperty *lastGroup = 0; const int propertyCount = m_propertySheet->count(); @@ -1048,6 +1064,17 @@ void PropertyEditor::setObject(QObject *object) if (property != 0) { const bool dynamicProperty = (dynamicSheet && dynamicSheet->isDynamicProperty(i)) || (sheet && sheet->isDefaultDynamicProperty(i)); + QString descriptionToolTip; + if (!dynamicProperty && !customData.isNull()) + descriptionToolTip = customData.propertyToolTip(propertyName); + if (descriptionToolTip.isEmpty()) { + if (const char *typeS = typeName(type)) { + descriptionToolTip = propertyName + QLatin1String(" (") + + QLatin1String(typeS) + QLatin1Char(')'); + } + } + if (!descriptionToolTip.isEmpty()) + property->setDescriptionToolTip(descriptionToolTip); switch (type) { case QVariant::Palette: setupPaletteProperty(property); diff --git a/src/designer/src/designer/doc/src/designer-manual.qdoc b/src/designer/src/designer/doc/src/designer-manual.qdoc index 66545646..418a6853 100644 --- a/src/designer/src/designer/doc/src/designer-manual.qdoc +++ b/src/designer/src/designer/doc/src/designer-manual.qdoc @@ -2405,8 +2405,9 @@ pixmap property in the property editor. <class>widgets::MyWidget</class> <addpagemethod>addPage</addpagemethod> <propertyspecifications> - <stringpropertyspecification name="fileName" notr="true" type="singleline" - <stringpropertyspecification name="text" type="richtext" + <stringpropertyspecification name="fileName" notr="true" type="singleline"/> + <stringpropertyspecification name="text" type="richtext"/> + <tooltip name="text">Explanatory text to be shown in Property Editor</tooltip> </propertyspecifications> </customwidget> </customwidgets> @@ -2443,9 +2444,13 @@ pixmap property in the property editor. for them. The \c{<propertyspecifications>} element can contain a list of property meta information. - Currently, properties of type string are supported. For these properties, the - \c{<stringpropertyspecification>} tag can be used. This tag has the following attributes: + The tag \c{<tooltip>} may be used to specify a tool tip to be shown in Property Editor + when hovering over the property. The property name is given in the attribute \c name and + the element text is the tooltip. This functionality was added in Qt 5.6. + + For properties of type string, the \c{<stringpropertyspecification>} tag can be used. + This tag has the following attributes: \table \header diff --git a/src/designer/src/lib/shared/pluginmanager.cpp b/src/designer/src/lib/shared/pluginmanager.cpp index 856e07cf..0b1932d6 100644 --- a/src/designer/src/lib/shared/pluginmanager.cpp +++ b/src/designer/src/lib/shared/pluginmanager.cpp @@ -67,6 +67,7 @@ static const char *extendsElementC = "extends"; static const char *addPageMethodC = "addpagemethod"; static const char *propertySpecsC = "propertyspecifications"; static const char *stringPropertySpecC = "stringpropertyspecification"; +static const char propertyToolTipC[] = "tooltip"; static const char *stringPropertyNameAttrC = "name"; static const char *stringPropertyTypeAttrC = "type"; static const char *stringPropertyNoTrAttrC = "notr"; @@ -142,6 +143,7 @@ public: // Type of a string property typedef QPair<qdesigner_internal::TextPropertyValidationMode, bool> StringPropertyType; typedef QHash<QString, StringPropertyType> StringPropertyTypeMap; + typedef QHash<QString, QString> PropertyToolTipMap; explicit QDesignerCustomWidgetSharedData(const QString &thePluginPath) : pluginPath(thePluginPath) {} void clearXML(); @@ -155,6 +157,7 @@ public: QString xmlExtends; StringPropertyTypeMap xmlStringPropertyTypeMap; + PropertyToolTipMap propertyToolTipMap; }; void QDesignerCustomWidgetSharedData::clearXML() @@ -235,6 +238,11 @@ bool QDesignerCustomWidgetData::xmlStringPropertyType(const QString &name, Strin return true; } +QString QDesignerCustomWidgetData::propertyToolTip(const QString &name) const +{ + return m_d->propertyToolTipMap.value(name); +} + // Wind a QXmlStreamReader until it finds an element. Returns index or one of FindResult enum FindResult { FindError = -2, ElementNotFound = -1 }; @@ -290,12 +298,13 @@ static qdesigner_internal::TextPropertyValidationMode typeStringToType(const QSt return qdesigner_internal::ValidationRichText; } -static bool parsePropertySpecs(QXmlStreamReader &sr, - QDesignerCustomWidgetSharedData::StringPropertyTypeMap *rc, - QString *errorMessage) +static bool parsePropertySpecs(QXmlStreamReader &sr, + QDesignerCustomWidgetSharedData *data, + QString *errorMessage) { const QString propertySpecs = QLatin1String(propertySpecsC); const QString stringPropertySpec = QLatin1String(stringPropertySpecC); + const QString propertyToolTip = QLatin1String(propertyToolTipC); const QString stringPropertyTypeAttr = QLatin1String(stringPropertyTypeAttrC); const QString stringPropertyNoTrAttr = QLatin1String(stringPropertyNoTrAttrC); const QString stringPropertyNameAttr = QLatin1String(stringPropertyNameAttrC); @@ -303,31 +312,39 @@ static bool parsePropertySpecs(QXmlStreamReader &sr, while (!sr.atEnd()) { switch(sr.readNext()) { case QXmlStreamReader::StartElement: { - if (sr.name() != stringPropertySpec) { + if (sr.name() == stringPropertySpec) { + const QXmlStreamAttributes atts = sr.attributes(); + const QString name = atts.value(stringPropertyNameAttr).toString(); + const QString type = atts.value(stringPropertyTypeAttr).toString(); + const QString notrS = atts.value(stringPropertyNoTrAttr).toString(); //Optional + + if (type.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyTypeAttr); + return false; + } + if (name.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyNameAttr); + return false; + } + bool typeOk; + const bool noTr = notrS == QStringLiteral("true") || notrS == QStringLiteral("1"); + QDesignerCustomWidgetSharedData::StringPropertyType v(typeStringToType(type, &typeOk), !noTr); + if (!typeOk) { + *errorMessage = QDesignerPluginManager::tr("'%1' is not a valid string property specification.").arg(type); + return false; + } + data->xmlStringPropertyTypeMap.insert(name, v); + } else if (sr.name() == propertyToolTip) { + const QString name = sr.attributes().value(stringPropertyNameAttr).toString(); + if (name.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyNameAttr); + return false; + } + data->propertyToolTipMap.insert(name, sr.readElementText().trimmed()); + } else { *errorMessage = QDesignerPluginManager::tr("An invalid property specification ('%1') was encountered. Supported types: %2").arg(sr.name().toString(), stringPropertySpec); return false; } - const QXmlStreamAttributes atts = sr.attributes(); - const QString name = atts.value(stringPropertyNameAttr).toString(); - const QString type = atts.value(stringPropertyTypeAttr).toString(); - const QString notrS = atts.value(stringPropertyNoTrAttr).toString(); //Optional - - if (type.isEmpty()) { - *errorMessage = msgAttributeMissing(stringPropertyTypeAttr); - return false; - } - if (name.isEmpty()) { - *errorMessage = msgAttributeMissing(stringPropertyNameAttr); - return false; - } - bool typeOk; - const bool noTr = notrS == QStringLiteral("true") || notrS == QStringLiteral("1"); - QDesignerCustomWidgetSharedData::StringPropertyType v(typeStringToType(type, &typeOk), !noTr); - if (!typeOk) { - *errorMessage = QDesignerPluginManager::tr("'%1' is not a valid string property specification.").arg(type); - return false; - } - rc->insert(name, v); } break; case QXmlStreamReader::EndElement: // Outer </stringproperties> @@ -429,7 +446,7 @@ QDesignerCustomWidgetData::ParseResult } break; case 2: // <stringproperties> - if (!parsePropertySpecs(sr, &m_d->xmlStringPropertyTypeMap, errorMessage)) { + if (!parsePropertySpecs(sr, m_d.data(), errorMessage)) { *errorMessage = msgXmlError(name, *errorMessage); return ParseError; } diff --git a/src/designer/src/lib/shared/pluginmanager_p.h b/src/designer/src/lib/shared/pluginmanager_p.h index af173476..08d6f4cd 100644 --- a/src/designer/src/lib/shared/pluginmanager_p.h +++ b/src/designer/src/lib/shared/pluginmanager_p.h @@ -93,6 +93,8 @@ public: QString xmlDisplayName() const; // Type of a string property bool xmlStringPropertyType(const QString &name, StringPropertyType *type) const; + // Custom tool tip of property + QString propertyToolTip(const QString &name) const; private: QSharedDataPointer<QDesignerCustomWidgetSharedData> m_d; diff --git a/src/designer/src/lib/uilib/ui4.cpp b/src/designer/src/lib/uilib/ui4.cpp index 46354922..96c91afe 100644 --- a/src/designer/src/lib/uilib/ui4.cpp +++ b/src/designer/src/lib/uilib/ui4.cpp @@ -8776,6 +8776,8 @@ void DomSlots::setElementSlot(const QStringList& a) void DomPropertySpecifications::clear(bool clear_all) { + qDeleteAll(m_tooltip); + m_tooltip.clear(); qDeleteAll(m_stringpropertyspecification); m_stringpropertyspecification.clear(); @@ -8793,6 +8795,8 @@ DomPropertySpecifications::DomPropertySpecifications() DomPropertySpecifications::~DomPropertySpecifications() { + qDeleteAll(m_tooltip); + m_tooltip.clear(); qDeleteAll(m_stringpropertyspecification); m_stringpropertyspecification.clear(); } @@ -8804,6 +8808,12 @@ void DomPropertySpecifications::read(QXmlStreamReader &reader) switch (reader.readNext()) { case QXmlStreamReader::StartElement : { const QString tag = reader.name().toString().toLower(); + if (tag == QLatin1String("tooltip")) { + DomPropertyToolTip *v = new DomPropertyToolTip(); + v->read(reader); + m_tooltip.append(v); + continue; + } if (tag == QLatin1String("stringpropertyspecification")) { DomStringPropertySpecification *v = new DomStringPropertySpecification(); v->read(reader); @@ -8830,6 +8840,10 @@ void DomPropertySpecifications::write(QXmlStreamWriter &writer, const QString &t { writer.writeStartElement(tagName.isEmpty() ? QString::fromUtf8("propertyspecifications") : tagName.toLower()); + for (int i = 0; i < m_tooltip.size(); ++i) { + DomPropertyToolTip* v = m_tooltip[i]; + v->write(writer, QStringLiteral("tooltip")); + } for (int i = 0; i < m_stringpropertyspecification.size(); ++i) { DomStringPropertySpecification* v = m_stringpropertyspecification[i]; v->write(writer, QStringLiteral("stringpropertyspecification")); @@ -8840,12 +8854,84 @@ void DomPropertySpecifications::write(QXmlStreamWriter &writer, const QString &t writer.writeEndElement(); } +void DomPropertySpecifications::setElementTooltip(const QList<DomPropertyToolTip*>& a) +{ + m_children |= Tooltip; + m_tooltip = a; +} + void DomPropertySpecifications::setElementStringpropertyspecification(const QList<DomStringPropertySpecification*>& a) { m_children |= Stringpropertyspecification; m_stringpropertyspecification = a; } +void DomPropertyToolTip::clear(bool clear_all) +{ + + if (clear_all) { + m_text.clear(); + m_has_attr_name = false; + } + + m_children = 0; +} + +DomPropertyToolTip::DomPropertyToolTip() +{ + m_children = 0; + m_has_attr_name = false; +} + +DomPropertyToolTip::~DomPropertyToolTip() +{ +} + +void DomPropertyToolTip::read(QXmlStreamReader &reader) +{ + + foreach (const QXmlStreamAttribute &attribute, reader.attributes()) { + QStringRef name = attribute.name(); + if (name == QLatin1String("name")) { + setAttributeName(attribute.value().toString()); + continue; + } + reader.raiseError(QStringLiteral("Unexpected attribute ") + name.toString()); + } + + for (bool finished = false; !finished && !reader.hasError();) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement : { + const QString tag = reader.name().toString().toLower(); + reader.raiseError(QStringLiteral("Unexpected element ") + tag); + } + break; + case QXmlStreamReader::EndElement : + finished = true; + break; + case QXmlStreamReader::Characters : + if (!reader.isWhitespace()) + m_text.append(reader.text().toString()); + break; + default : + break; + } + } +} + +void DomPropertyToolTip::write(QXmlStreamWriter &writer, const QString &tagName) const +{ + writer.writeStartElement(tagName.isEmpty() ? QString::fromUtf8("propertytooltip") : tagName.toLower()); + + if (hasAttributeName()) + writer.writeAttribute(QStringLiteral("name"), attributeName()); + + if (!m_text.isEmpty()) + writer.writeCharacters(m_text); + + writer.writeEndElement(); +} + void DomStringPropertySpecification::clear(bool clear_all) { diff --git a/src/designer/src/lib/uilib/ui4_p.h b/src/designer/src/lib/uilib/ui4_p.h index 60685c91..1e5bcbf0 100644 --- a/src/designer/src/lib/uilib/ui4_p.h +++ b/src/designer/src/lib/uilib/ui4_p.h @@ -144,6 +144,7 @@ class DomWidgetData; class DomDesignerData; class DomSlots; class DomPropertySpecifications; +class DomPropertyToolTip; class DomStringPropertySpecification; /******************************************************************************* @@ -3541,6 +3542,9 @@ public: // attribute accessors // child element accessors + inline QList<DomPropertyToolTip*> elementTooltip() const { return m_tooltip; } + void setElementTooltip(const QList<DomPropertyToolTip*>& a); + inline QList<DomStringPropertySpecification*> elementStringpropertyspecification() const { return m_stringpropertyspecification; } void setElementStringpropertyspecification(const QList<DomStringPropertySpecification*>& a); @@ -3551,15 +3555,49 @@ private: // attribute data // child element data uint m_children; + QList<DomPropertyToolTip*> m_tooltip; QList<DomStringPropertySpecification*> m_stringpropertyspecification; enum Child { - Stringpropertyspecification = 1 + Tooltip = 1, + Stringpropertyspecification = 2 }; DomPropertySpecifications(const DomPropertySpecifications &other); void operator = (const DomPropertySpecifications&other); }; +class QDESIGNER_UILIB_EXPORT DomPropertyToolTip { +public: + DomPropertyToolTip(); + ~DomPropertyToolTip(); + + void read(QXmlStreamReader &reader); + void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; + inline QString text() const { return m_text; } + inline void setText(const QString &s) { m_text = s; } + + // attribute accessors + inline bool hasAttributeName() const { return m_has_attr_name; } + inline QString attributeName() const { return m_attr_name; } + inline void setAttributeName(const QString& a) { m_attr_name = a; m_has_attr_name = true; } + inline void clearAttributeName() { m_has_attr_name = false; } + + // child element accessors +private: + QString m_text; + void clear(bool clear_all = true); + + // attribute data + QString m_attr_name; + bool m_has_attr_name; + + // child element data + uint m_children; + + DomPropertyToolTip(const DomPropertyToolTip &other); + void operator = (const DomPropertyToolTip&other); +}; + class QDESIGNER_UILIB_EXPORT DomStringPropertySpecification { public: DomStringPropertySpecification(); |