From 82c3e9edc2e9990027a65705c31bd618df455d91 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 6 May 2015 12:59:05 +0200 Subject: Manual QScreen test: capture screen changes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Make the subject of the Property watcher settable. - Embed it into a QMainWindow with menu and listen to the screen changed event, setting the new screen with a message about the position. - Remove hash, close obsolete windows by iterating over the top levels looking for the screen. Change-Id: I4ed1122bab7c0cd9676d63995ce85a44719f4ba6 Reviewed-by: Morten Johan Sørvig --- tests/manual/qscreen/main.cpp | 139 +++++++++++++++++++++++++------ tests/manual/qscreen/propertywatcher.cpp | 81 ++++++++++++++---- tests/manual/qscreen/propertywatcher.h | 14 ++-- tests/manual/qscreen/qscreen.pro | 1 + 4 files changed, 188 insertions(+), 47 deletions(-) (limited to 'tests/manual/qscreen') diff --git a/tests/manual/qscreen/main.cpp b/tests/manual/qscreen/main.cpp index 6f672ee422..ef9c2efe19 100644 --- a/tests/manual/qscreen/main.cpp +++ b/tests/manual/qscreen/main.cpp @@ -36,22 +36,117 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include #include -int i = 0; +class ScreenPropertyWatcher : public PropertyWatcher +{ + Q_OBJECT +public: + ScreenPropertyWatcher(QWidget *wp = Q_NULLPTR) : PropertyWatcher(Q_NULLPTR, QString(), wp) + { + // workaround for the fact that virtualSiblings is not a property, + // thus there is no change notification: + // allow the user to update the field manually + connect(this, &PropertyWatcher::updatedAllFields, this, &ScreenPropertyWatcher::updateSiblings); + } + + QScreen *screenSubject() const { return qobject_cast(subject()); } + void setScreenSubject(QScreen *s, const QString &annotation = QString()) + { + setSubject(s, annotation); + updateSiblings(); + } -typedef QHash ScreensHash; -Q_GLOBAL_STATIC(ScreensHash, props); +public slots: + void updateSiblings(); +}; -void updateSiblings(PropertyWatcher* w) +void ScreenPropertyWatcher::updateSiblings() { - QLineEdit *siblingsField = w->findChild("siblings"); - QScreen* screen = (QScreen*)w->subject(); - QStringList siblingsList; - foreach (QScreen *sibling, screen->virtualSiblings()) - siblingsList << sibling->name(); - siblingsField->setText(siblingsList.join(", ")); + const QScreen *screen = screenSubject(); + if (!screen) + return; + const QString objectName = QLatin1String("siblings"); + QLineEdit *siblingsField = findChild(objectName); + if (!siblingsField) { + siblingsField = new QLineEdit(this); + siblingsField->setObjectName(objectName); + siblingsField->setReadOnly(true); + formLayout()->insertRow(0, QLatin1String("virtualSiblings"), siblingsField); + } + QString text; + foreach (const QScreen *sibling, screen->virtualSiblings()) { + if (!text.isEmpty()) + text += QLatin1String(", "); + text += sibling->name(); + } + siblingsField->setText(text); +} + +class ScreenWatcherMainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit ScreenWatcherMainWindow(QScreen *screen); + + QScreen *screenSubject() const { return m_watcher->screenSubject(); } + +protected: + bool event(QEvent *event) Q_DECL_OVERRIDE; + +private: + const QString m_annotation; + ScreenPropertyWatcher *m_watcher; +}; + +static int i = 0; + +ScreenWatcherMainWindow::ScreenWatcherMainWindow(QScreen *screen) + : m_annotation(QLatin1Char('#') + QString::number(i++)) + , m_watcher(new ScreenPropertyWatcher(this)) +{ + setAttribute(Qt::WA_DeleteOnClose); + setCentralWidget(m_watcher); + m_watcher->setScreenSubject(screen, m_annotation); + + QMenu *fileMenu = menuBar()->addMenu(QLatin1String("&File")); + QAction *a = fileMenu->addAction(QLatin1String("Close")); + a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W)); + connect(a, SIGNAL(triggered()), this, SLOT(close())); + a = fileMenu->addAction(QLatin1String("Quit")); + a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + connect(a, SIGNAL(triggered()), qApp, SLOT(quit())); +} + +static inline QString msgScreenChange(const QWidget *w, const QScreen *oldScreen, const QScreen *newScreen) +{ + QString result; + const QRect geometry = w->geometry(); + const QPoint pos = QCursor::pos(); + QTextStream(&result) << "Screen changed \"" << oldScreen->name() << "\" --> \"" + << newScreen->name() << "\" at " << pos.x() << ',' << pos.y() << " geometry: " + << geometry.width() << 'x' << geometry.height() << forcesign << geometry.x() + << geometry.y() << '.'; + return result; +} + +bool ScreenWatcherMainWindow::event(QEvent *event) +{ + if (event->type() == QEvent::ScreenChangeInternal) { + QScreen *newScreen = windowHandle()->screen(); + const QString message = msgScreenChange(this, m_watcher->screenSubject(), newScreen); + qDebug().noquote() << message; + statusBar()->showMessage(message); + m_watcher->setScreenSubject(newScreen, m_annotation); + } + return QMainWindow::event(event); } void screenAdded(QScreen* screen) @@ -59,12 +154,7 @@ void screenAdded(QScreen* screen) screen->setOrientationUpdateMask((Qt::ScreenOrientations)0x0F); qDebug("\nscreenAdded %s siblings %d first %s", qPrintable(screen->name()), screen->virtualSiblings().count(), (screen->virtualSiblings().isEmpty() ? "none" : qPrintable(screen->virtualSiblings().first()->name()))); - PropertyWatcher *w = new PropertyWatcher(screen, QString::number(i++)); - QLineEdit *siblingsField = new QLineEdit(); - siblingsField->setObjectName("siblings"); - siblingsField->setReadOnly(true); - w->layout()->insertRow(0, "virtualSiblings", siblingsField); - updateSiblings(w); + ScreenWatcherMainWindow *w = new ScreenWatcherMainWindow(screen); // This doesn't work. If the multiple screens are part of // a virtual desktop (i.e. they are virtual siblings), then @@ -85,18 +175,17 @@ void screenAdded(QScreen* screen) geom.setHeight(screen->geometry().height() * 9 / 10); geom.moveCenter(screen->geometry().center()); w->setGeometry(geom); - - props->insert(screen, w); - - // workaround for the fact that virtualSiblings is not a property, - // thus there is no change notification: - // allow the user to update the field manually - QObject::connect(w, &PropertyWatcher::updatedAllFields, &updateSiblings); } void screenRemoved(QScreen* screen) { - delete props->take(screen); + const QWidgetList topLevels = QApplication::topLevelWidgets(); + for (int i = topLevels.size() - 1; i >= 0; --i) { + if (ScreenWatcherMainWindow *sw = qobject_cast(topLevels.at(i))) { + if (sw->screenSubject() == screen) + sw->close(); + } + } } int main(int argc, char *argv[]) @@ -109,3 +198,5 @@ int main(int argc, char *argv[]) QObject::connect((const QGuiApplication*)QGuiApplication::instance(), &QGuiApplication::screenRemoved, &screenRemoved); return a.exec(); } + +#include "main.moc" diff --git a/tests/manual/qscreen/propertywatcher.cpp b/tests/manual/qscreen/propertywatcher.cpp index 19668a8d26..b745ef5125 100644 --- a/tests/manual/qscreen/propertywatcher.cpp +++ b/tests/manual/qscreen/propertywatcher.cpp @@ -35,35 +35,82 @@ #include #include #include +#include #include "propertyfield.h" PropertyWatcher::PropertyWatcher(QObject *subject, QString annotation, QWidget *parent) - : QWidget(parent), m_subject(subject), m_layout(new QFormLayout) + : QWidget(parent), m_subject(Q_NULLPTR), m_formLayout(new QFormLayout(this)) { - setWindowTitle(QString("Properties of %1 %2 %3") - .arg(subject->metaObject()->className()).arg(subject->objectName()).arg(annotation)); setMinimumSize(450, 300); + m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + setSubject(subject, annotation); +} + +class UpdatesEnabledBlocker +{ + Q_DISABLE_COPY(UpdatesEnabledBlocker); +public: + explicit UpdatesEnabledBlocker(QWidget *w) : m_widget(w) + { + m_widget->setUpdatesEnabled(false); + } + ~UpdatesEnabledBlocker() + { + m_widget->setUpdatesEnabled(true); + m_widget->update(); + } + +private: + QWidget *m_widget; +}; + +void PropertyWatcher::setSubject(QObject *s, const QString &annotation) +{ + if (s == m_subject) + return; + + UpdatesEnabledBlocker blocker(this); + + if (m_subject) { + disconnect(m_subject, &QObject::destroyed, this, &PropertyWatcher::subjectDestroyed); + for (int i = m_formLayout->count() - 1; i >= 0; --i) { + QLayoutItem *item = m_formLayout->takeAt(i); + delete item->widget(); + delete item; + } + window()->setWindowTitle(QString()); + window()->setWindowIconText(QString()); + } + + m_subject = s; + if (!m_subject) + return; + const QMetaObject* meta = m_subject->metaObject(); + QString title = QLatin1String("Properties ") + QLatin1String(meta->className()); + if (!m_subject->objectName().isEmpty()) + title += QLatin1Char(' ') + m_subject->objectName(); + if (!annotation.isEmpty()) + title += QLatin1Char(' ') + annotation; + window()->setWindowTitle(title); - for (int i = 0; i < meta->propertyCount(); ++i) { - QMetaProperty prop = meta->property(i); + for (int i = 0, count = meta->propertyCount(); i < count; ++i) { + const QMetaProperty prop = meta->property(i); if (prop.isReadable()) { - PropertyField* field = new PropertyField(m_subject, prop); - m_layout->addRow(prop.name(), field); + QLabel *label = new QLabel(prop.name(), this); + PropertyField *field = new PropertyField(m_subject, prop, this); + m_formLayout->addRow(label, field); if (!qstrcmp(prop.name(), "name")) - setWindowIconText(prop.read(subject).toString()); + window()->setWindowIconText(prop.read(m_subject).toString()); + label->setVisible(true); + field->setVisible(true); } } - QPushButton *updateButton = new QPushButton("update"); - connect(updateButton, &QPushButton::clicked, this, &PropertyWatcher::updateAllFields); - m_layout->addRow("", updateButton); - m_layout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - setLayout(m_layout); - connect(subject, &QObject::destroyed, this, &PropertyWatcher::subjectDestroyed); -} + connect(m_subject, &QObject::destroyed, this, &PropertyWatcher::subjectDestroyed); -PropertyWatcher::~PropertyWatcher() -{ + QPushButton *updateButton = new QPushButton(QLatin1String("Update"), this); + connect(updateButton, &QPushButton::clicked, this, &PropertyWatcher::updateAllFields); + m_formLayout->addRow(QString(), updateButton); } void PropertyWatcher::updateAllFields() diff --git a/tests/manual/qscreen/propertywatcher.h b/tests/manual/qscreen/propertywatcher.h index 7dccfe3672..01e448845a 100644 --- a/tests/manual/qscreen/propertywatcher.h +++ b/tests/manual/qscreen/propertywatcher.h @@ -44,10 +44,12 @@ class PropertyWatcher : public QWidget Q_OBJECT public: - PropertyWatcher(QObject* subject, QString annotation = QString(), QWidget *parent = 0); - ~PropertyWatcher(); - QFormLayout *layout() { return m_layout; } - QObject* subject() { return m_subject; } + explicit PropertyWatcher(QObject* subject = Q_NULLPTR, QString annotation = QString(), QWidget *parent = Q_NULLPTR); + + QFormLayout *formLayout() { return m_formLayout; } + + QObject *subject() const { return m_subject; } + void setSubject(QObject *s, const QString &annotation = QString()); public slots: void updateAllFields(); @@ -56,9 +58,9 @@ public slots: signals: void updatedAllFields(PropertyWatcher* sender); -protected: +private: QObject* m_subject; - QFormLayout * m_layout; + QFormLayout * m_formLayout; }; #endif // PROPERTY_WATCHER_H diff --git a/tests/manual/qscreen/qscreen.pro b/tests/manual/qscreen/qscreen.pro index cec8bbf245..5d587db3f4 100644 --- a/tests/manual/qscreen/qscreen.pro +++ b/tests/manual/qscreen/qscreen.pro @@ -1,4 +1,5 @@ QT += core gui widgets +CONFIG += console TARGET = qscreen TEMPLATE = app -- cgit v1.2.3