diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-03-25 13:17:07 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-03-27 16:42:34 +0100 |
commit | f29b73d0026db64d7b2d1ca049461b784c98cecc (patch) | |
tree | b01f3d5204060868371cb4e133bd4fbf58092465 | |
parent | 927a76c9246109f14b51bd9a3cf224d6f987e10d (diff) |
axviewer test: Add a metaobject dump
Task-number: QTBUG-82945
Change-Id: If9c84743779acdd199fd67ec2c2f4fc72f58129a
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r-- | tests/manual/axviewer/main.cpp | 221 |
1 files changed, 220 insertions, 1 deletions
diff --git a/tests/manual/axviewer/main.cpp b/tests/manual/axviewer/main.cpp index 6dd5f27..4828009 100644 --- a/tests/manual/axviewer/main.cpp +++ b/tests/manual/axviewer/main.cpp @@ -31,15 +31,25 @@ #include <QtWidgets/QAction> #include <QtWidgets/QApplication> +#include <QtWidgets/QDialog> +#include <QtWidgets/QDialogButtonBox> #include <QtWidgets/QMainWindow> #include <QtWidgets/QMenu> #include <QtWidgets/QMenuBar> +#include <QtWidgets/QPlainTextEdit> #include <QtWidgets/QStatusBar> #include <QtWidgets/QToolBar> +#include <QtWidgets/QVBoxLayout> + +#include <QtGui/QFontDatabase> +#include <QtGui/QScreen> #include <QtCore/QCommandLineOption> #include <QtCore/QCommandLineParser> #include <QtCore/QDebug> +#include <QtCore/QMetaMethod> +#include <QtCore/QMetaObject> +#include <QtCore/QPair> #include <QtCore/QStringList> #include <QtCore/QSysInfo> @@ -61,6 +71,195 @@ static inline bool isOptionSet(int argc, char *argv[], const char *option) [option] (const char *arg) { return !qstrcmp(arg, option); }); } +using rightAlignNumber = QPair<int, int>; // Use as str << rightAlignNumber(value, width) + +QTextStream &operator<<(QTextStream &str, const rightAlignNumber &r) +{ + auto oldWidth = str.fieldWidth(); + str.setFieldWidth(r.second); + auto oldAlignment = str.fieldAlignment(); + str.setFieldAlignment(QTextStream::AlignRight); + str << r.first; + str.setFieldAlignment(oldAlignment); + str.setFieldWidth(oldWidth); + return str; +} + +QTextStream &operator<<(QTextStream &str, const QMetaEnum &me) +{ + const int keyCount = me.keyCount(); + str << me.name() << ' ' << keyCount << " keys"; + if (me.isFlag()) + str << " [flag]"; + if (me.isScoped()) + str << " [scoped]"; + const int maxLogCount = std::min(6, keyCount); + str << " {"; + for (int k = 0; k < maxLogCount; ++k) { + if (k) + str << ", "; + str << me.key(k) << " = " << me.value(k); + } + if (maxLogCount < keyCount) + str << ",..."; + str << '}'; + return str; +} + +QTextStream &operator<<(QTextStream &str, const QMetaClassInfo &mc) +{ + str << '"' << mc.name() << "\": \"" << mc.value() << '"'; + return str; +} + +QTextStream &operator<<(QTextStream &str, const QMetaProperty &mp) +{ + str << mp.typeName() << ' ' << mp.name(); + if (mp.isWritable()) + str << " [writable]"; + if (mp.isResettable()) + str << " [resettable]"; + if (mp.isDesignable()) + str << " [designable]"; + if (mp.isStored()) + str << " [stored]"; + if (mp.isUser()) + str << " [user]"; + if (mp.isConstant()) + str << " [constant]"; + if (mp.isFinal()) + str << " [final]"; + if (mp.isRequired()) + str << " [required]"; + if (mp.isFlagType()) + str << " [flag]"; + if (mp.isEnumType()) + str << " [enum " << mp.enumerator().name() << ']'; + if (mp.hasNotifySignal()) + str << " [notify " << mp.notifySignal().name() << ']'; + return str; +} + +QTextStream &operator<<(QTextStream &str, const QMetaMethod &m) +{ + switch (m.access()) { + case QMetaMethod::Private: + str << "private "; + break; + case QMetaMethod::Protected: + str << "protected "; + break; + case QMetaMethod::Public: + break; + } + str << m.typeName() << ' ' << m.methodSignature(); + switch (m.methodType()) { + case QMetaMethod::Method: + break; + case QMetaMethod::Signal: + str << " [signal]"; + break; + case QMetaMethod::Slot: + str << " [slot]"; + break; + case QMetaMethod::Constructor: + str << " [ct]"; + break; + } + if (auto attributes = m.attributes()) { + str << " attributes: " << Qt::hex << Qt::showbase << attributes + << Qt::dec << Qt::noshowbase; + } + if (const int count = m.parameterCount()) { + str << " Parameters: "; + const auto parameterNames = m.parameterNames(); + const auto parameterTypes = m.parameterTypes(); + for (int p = 0; p < count; ++p) { + if (p) + str << ", "; + str << parameterTypes.at(p) << ' ' << parameterNames.at(p); + } + } + return str; +} + +static void formatMetaObject(QTextStream &str, const QMetaObject *mo, const QByteArray &indent) +{ + str << indent << "--- " << mo->className() << " ---\n"; + + const int classInfoOffset = mo->classInfoOffset(); + const int classInfoCount = mo->classInfoCount(); + if (classInfoOffset < classInfoCount) { + str << indent << " Class Info of " << mo->className() << ": " + << classInfoOffset << ".." << classInfoCount << '\n'; + for (int i = classInfoOffset; i < classInfoCount; ++i) { + str << indent << " " << rightAlignNumber(i, 3) << ' ' + << mo->classInfo(i) << '\n'; + } + } + + const int enumOffset = mo->enumeratorOffset(); + const int enumCount = mo->enumeratorCount(); + if (enumOffset < enumCount) { + str << indent << " Enums of " << mo->className() << ": " << enumOffset + << ".." << enumCount << '\n'; + for (int e = enumOffset; e < enumCount; ++e) + str << indent << " " << rightAlignNumber(e, 3) << ' ' << mo->enumerator(e) << '\n'; + } + + const int methodOffset = mo->methodOffset(); + const int methodCount = mo->methodCount(); + if (methodOffset < methodCount) { + str << indent << " Methods of " << mo->className() << ": " << methodOffset + << ".." << methodCount << '\n'; + for (int m = methodOffset; m < methodCount; ++m) + str << indent << " " << rightAlignNumber(m, 3) << ' ' << mo->method(m) << '\n'; + } + + const int propertyOffset = mo->propertyOffset(); + const int propertyCount = mo-> propertyCount(); + if (propertyOffset < propertyCount) { + str << indent << " Properties of " << mo->className() << ": " << propertyOffset + << ".." << propertyCount << '\n'; + for (int p = propertyOffset; p < propertyCount; ++p) + str << indent << " " << rightAlignNumber(p, 3) << ' ' << mo->property(p) << '\n'; + } +} + +QTextStream &operator<<(QTextStream &str, const QMetaObject &o) +{ + QVector<const QMetaObject *> klasses; + for (auto s = &o; s; s = s->superClass()) + klasses.prepend(s); + + QByteArray indent; + for (auto k : klasses) { + formatMetaObject(str, k, indent); + indent += " "; + } + return str; +} + +class TextDialog : public QDialog +{ +public: + explicit TextDialog(const QString &text, QWidget *parent = nullptr); +}; + +TextDialog::TextDialog(const QString &text, QWidget *parent) : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + auto layout = new QVBoxLayout(this); + auto pe = new QPlainTextEdit(text, this); + pe->setReadOnly(true); + pe->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + layout->addWidget(pe); + + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this); + layout->addWidget(buttonBox); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + class MainWindow : public QMainWindow { Q_OBJECT @@ -68,6 +267,9 @@ public: MainWindow(); bool setControl(const QString &clsid); +public slots: + void showMetaObject(); + private: QAxWidget *m_axWidget; }; @@ -91,7 +293,9 @@ MainWindow::MainWindow() toolbar->setObjectName(QLatin1String("ToolBar")); addToolBar(Qt::TopToolBarArea, toolbar); - QAction *action; + QAction *action = fileMenu->addAction("Dump MetaObject", + this, &MainWindow::showMetaObject); + toolbar->addAction(action); #ifdef QT_DIAG_LIB action = fileMenu->addAction("Dump Widgets", this, [] () { QtDiag::dumpAllWidgets(); }); @@ -117,6 +321,21 @@ bool MainWindow::setControl(const QString &clsid) return result; } +void MainWindow::showMetaObject() +{ + auto mo = m_axWidget->metaObject(); + QString dump; + { + QTextStream str(&dump); + str << *mo; + } + auto dialog = new TextDialog(dump, this); + dialog->setWindowTitle(QLatin1String("MetaObject of ") + QLatin1String(mo->className())); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->resize(screen()->geometry().size() * 2 / 3); + dialog->show(); +} + int main(int argc, char* argv[]) { if (isOptionSet(argc, argv, "-s")) |