4 This file is part of GammaRay, the Qt application inspection and
7 Copyright (C) 2010-2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8 Author: Volker Krause <volker.krause@kdab.com>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "metatypedeclarations.h"
27 #include <QtCore/qobject.h>
28 #include <QtCore/QStringList>
32 #include <qsizepolicy.h>
33 #include <qmetaobject.h>
34 #include <qtextformat.h>
35 #include <QGraphicsItem>
36 #include <QGraphicsWidget>
43 using namespace GammaRay
;
46 class ProtectedExposer
: public QObject
49 using QObject::staticQtMetaObject
;
53 QString
Util::displayString(const QObject
*object
)
56 return "QObject(0x0)";
58 if (object
->objectName().isEmpty()) {
59 return QString::fromLatin1("%1 (%2)").
60 arg(addressToString(object
)).
61 arg(object
->metaObject()->className());
63 return object
->objectName();
66 QString
Util::addressToUid(const void *p
)
68 return QString::number(reinterpret_cast<qlonglong
>(p
), 16);
71 static QString
sizePolicyToString(QSizePolicy::Policy policy
)
73 const int index
= QSizePolicy::staticMetaObject
.indexOfEnumerator("Policy");
74 const QMetaEnum metaEnum
= QSizePolicy::staticMetaObject
.enumerator(index
);
75 return QString::fromLatin1(metaEnum
.valueToKey(policy
));
78 QString
GammaRay::Util::variantToString(const QVariant
&value
)
80 switch (value
.type()) {
82 return QString::fromUtf8("%1 x %2 → %3 x %4")
83 .arg(value
.toLine().x1()).arg(value
.toLine().y1())
84 .arg(value
.toLine().x2()).arg(value
.toLine().y2());
87 return QString::fromUtf8("%1 x %2 → %3 x %4")
88 .arg(value
.toLineF().x1()).arg(value
.toLineF().y1())
89 .arg(value
.toLineF().x2()).arg(value
.toLineF().y2());
92 return QString::fromLatin1("%1x%2").
93 arg(value
.toPoint().x()).
94 arg(value
.toPoint().y());
96 case QVariant::PointF
:
97 return QString::fromLatin1("%1x%2").
98 arg(value
.toPointF().x()).
99 arg(value
.toPointF().y());
102 return QString::fromLatin1("%1x%2 %3x%4").
103 arg(value
.toRect().x()).
104 arg(value
.toRect().y()).
105 arg(value
.toRect().width()).
106 arg(value
.toRect().height());
108 case QVariant::RectF
:
109 return QString::fromLatin1("%1x%2 %3x%4").
110 arg(value
.toRectF().x()).
111 arg(value
.toRectF().y()).
112 arg(value
.toRectF().width()).
113 arg(value
.toRectF().height());
115 case QVariant::Region
:
117 const QRegion region
= value
.value
<QRegion
>();
118 if (region
.isEmpty()) {
119 return QLatin1String("<empty>");
121 if (region
.rectCount() == 1) {
122 return variantToString(region
.rects().first());
124 return QString::fromLatin1("<%1 rects>").arg(region
.rectCount());
129 return QString::fromLatin1("%1x%2").
130 arg(value
.toSize().width()).
131 arg(value
.toSize().height());
133 case QVariant::SizeF
:
134 return QString::fromLatin1("%1x%2").
135 arg(value
.toSizeF().width()).
136 arg(value
.toSizeF().height());
138 case QVariant::SizePolicy
:
139 return QString::fromLatin1("%1 x %2").
140 arg(sizePolicyToString(value
.value
<QSizePolicy
>().horizontalPolicy())).
141 arg(sizePolicyToString(value
.value
<QSizePolicy
>().verticalPolicy()));
143 case QVariant::StringList
:
144 return value
.toStringList().join(", ");
146 case QVariant::Transform
:
148 const QTransform t
= value
.value
<QTransform
>();
149 return QString::fromLatin1("[%1 %2 %3, %4 %5 %6, %7 %8 %9]").
150 arg(t
.m11()).arg(t
.m12()).arg(t
.m13()).
151 arg(t
.m21()).arg(t
.m22()).arg(t
.m23()).
152 arg(t
.m31()).arg(t
.m32()).arg(t
.m33());
158 // types with dynamic type ids
159 if (value
.type() == qMetaTypeId
<QTextLength
>()) {
160 const QTextLength l
= value
.value
<QTextLength
>();
163 case QTextLength::VariableLength
:
164 typeStr
= QObject::tr("variable");
166 case QTextLength::FixedLength
:
167 typeStr
= QObject::tr("fixed");
169 case QTextLength::PercentageLength
:
170 typeStr
= QObject::tr("percentage");
173 return QString::fromLatin1("%1 (%2)").arg(l
.rawValue()).arg(typeStr
);
176 if (value
.userType() == qMetaTypeId
<QPainterPath
>()) {
177 const QPainterPath path
= value
.value
<QPainterPath
>();
178 if (path
.isEmpty()) {
179 return QObject::tr("<empty>");
181 return QObject::tr("<%1 elements>").arg(path
.elementCount());
184 if (value
.type() == qMetaTypeId
<QWidget
*>()) {
185 return displayString(value
.value
<QWidget
*>());
188 if (value
.userType() == qMetaTypeId
<QGraphicsEffect
*>()) {
189 return addressToString(value
.value
<QGraphicsEffect
*>());
191 if (value
.userType() == qMetaTypeId
<QGraphicsItem
*>()) {
192 return addressToString(value
.value
<QGraphicsItem
*>());
194 if (value
.userType() == qMetaTypeId
<QGraphicsItemGroup
*>()) {
195 return addressToString(value
.value
<QGraphicsItemGroup
*>());
197 if (value
.userType() == qMetaTypeId
<QGraphicsObject
*>()) {
198 return displayString(value
.value
<QGraphicsObject
*>());
200 if (value
.userType() == qMetaTypeId
<QGraphicsWidget
*>()) {
201 return displayString(value
.value
<QGraphicsWidget
*>());
203 if (value
.userType() == qMetaTypeId
<const QStyle
*>()) {
204 return displayString(value
.value
<const QStyle
*>());
208 const QString enumStr
= enumToString(value
);
209 if (!enumStr
.isEmpty()) {
213 return value
.toString();
216 QVariant
Util::decorationForVariant(const QVariant
&value
)
218 switch (value
.type()) {
219 case QVariant::Brush
:
221 const QBrush b
= value
.value
<QBrush
>();
222 if (b
.style() != Qt::NoBrush
) {
224 p
.fill(QColor(0, 0, 0, 0));
225 QPainter
painter(&p
);
227 painter
.drawRect(0, 0, p
.width() - 1, p
.height() - 1);
231 case QVariant::Color
:
233 const QColor c
= value
.value
<QColor
>();
236 QPainter
painter(&p
);
237 painter
.setBrush(QBrush(c
));
238 painter
.drawRect(0, 0, p
.width() - 1, p
.height() - 1);
242 case QVariant::Cursor
:
244 const QCursor c
= value
.value
<QCursor
>();
245 if (!c
.pixmap().isNull()) {
246 return c
.pixmap().scaled(16, 16, Qt::KeepAspectRatio
, Qt::FastTransformation
);
255 const QPen pen
= value
.value
<QPen
>();
256 if (pen
.style() != Qt::NoPen
) {
258 p
.fill(QColor(0, 0, 0, 0));
259 QPainter
painter(&p
);
261 painter
.translate(0, 8 - pen
.width() / 2);
262 painter
.drawLine(0, 0, p
.width(), 0);
266 case QVariant::Pixmap
:
268 const QPixmap p
= value
.value
<QPixmap
>();
269 return QVariant::fromValue(p
.scaled(16, 16, Qt::KeepAspectRatio
, Qt::FastTransformation
));
277 QString
Util::addressToString(const void *p
)
279 return (QLatin1String("0x") + QString::number(reinterpret_cast<qlonglong
>(p
), 16));
282 QString
Util::enumToString(const QVariant
&value
, const char *typeName
, QObject
*object
)
284 QByteArray
enumTypeName(typeName
);
285 if (enumTypeName
.isEmpty()) {
286 enumTypeName
= value
.typeName();
289 // strip of class name and namespace
290 const int pos
= enumTypeName
.lastIndexOf("::");
292 enumTypeName
= enumTypeName
.mid(pos
+ 2);
295 const QMetaObject
*mo
= &ProtectedExposer::staticQtMetaObject
;
296 int enumIndex
= mo
->indexOfEnumerator(enumTypeName
);
297 if (enumIndex
< 0 && object
) {
298 mo
= object
->metaObject();
299 enumIndex
= mo
->indexOfEnumerator(enumTypeName
);
305 const QMetaEnum me
= mo
->enumerator(enumIndex
);
309 return me
.valueToKeys(value
.toInt());
312 bool Util::descendantOf(QObject
*ascendant
, QObject
*obj
)
314 QObject
*parent
= obj
->parent();
318 if (parent
== ascendant
) {
321 return descendantOf(ascendant
, parent
);
325 static QString
stringifyProperty(QObject
*obj
, const QString
&propName
)
327 const QVariant value
= obj
->property(propName
.toLatin1());
328 const QMetaProperty mp
=
329 obj
->metaObject()->property(
330 obj
->metaObject()->indexOfProperty(propName
.toLatin1()));
332 const QString enumStr
= Util::enumToString(value
, mp
.typeName(), obj
);
333 if (!enumStr
.isEmpty()) {
337 return Util::variantToString(value
);
340 static QVariant
iconForObject(const QMetaObject
*mo
, QObject
*obj
)
342 const QString basePath
= QString::fromLatin1(":/gammaray/classes/%1/").arg(mo
->className());
343 const QDir
dir(basePath
);
345 // see if we find one with exactly matching properties
346 foreach (const QString
&entry
,
347 dir
.entryList(QStringList() << QLatin1String("*.png"), QDir::Files
)) {
348 if (entry
== QLatin1String("default.png")) {
351 QString
propString(entry
);
353 const QStringList props
= propString
.split(QLatin1String(";"));
354 if (props
.isEmpty()) {
357 bool allMatch
= true;
358 foreach (const QString
&prop
, props
) {
359 const QStringList keyValue
= prop
.split(QLatin1Char('='));
360 if (keyValue
.size() != 2) {
363 if (stringifyProperty(obj
, keyValue
.first()) != keyValue
.last()) {
369 return QIcon(basePath
+ entry
);
372 return QIcon(basePath
+ QLatin1String("default.png"));
373 } else if (mo
->superClass()) {
374 return iconForObject(mo
->superClass(), obj
);
380 QVariant
Util::iconForObject(QObject
*obj
)
383 return GammaRay::iconForObject(obj
->metaObject(), obj
);