summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-07-17 14:21:55 +0200
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-07-29 11:10:34 +0000
commita98e3ba6238788e5b94dfda7d63a9df380b905af (patch)
tree9e6352d74a1f03ebbd7e96c3e2ccde5e8945a461
parent08a732b69e951b8f1ca53d2e047c432407f42d67 (diff)
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.cpp1
-rw-r--r--src/designer/data/ui4.xsd5
-rw-r--r--src/designer/src/components/propertyeditor/propertyeditor.cpp59
-rw-r--r--src/designer/src/designer/doc/src/designer-manual.qdoc13
-rw-r--r--src/designer/src/lib/shared/pluginmanager.cpp69
-rw-r--r--src/designer/src/lib/shared/pluginmanager_p.h2
-rw-r--r--src/designer/src/lib/uilib/ui4.cpp86
-rw-r--r--src/designer/src/lib/uilib/ui4_p.h40
8 files changed, 228 insertions, 47 deletions
diff --git a/examples/designer/taskmenuextension/tictactoeplugin.cpp b/examples/designer/taskmenuextension/tictactoeplugin.cpp
index 770a44a24..6e0c7b02d 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 62a69429f..e5474a65c 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 75ecf70b5..91e702362 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 665456468..418a68532 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 856e07cf4..0b1932d6d 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 af1734767..08d6f4cd7 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 46354922a..96c91afe9 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 60685c911..1e5bcbf0a 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();