| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2020 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the examples of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** BSD License Usage |
| 18 | ** Alternatively, you may use this file under the terms of the BSD license |
| 19 | ** as follows: |
| 20 | ** |
| 21 | ** "Redistribution and use in source and binary forms, with or without |
| 22 | ** modification, are permitted provided that the following conditions are |
| 23 | ** met: |
| 24 | ** * Redistributions of source code must retain the above copyright |
| 25 | ** notice, this list of conditions and the following disclaimer. |
| 26 | ** * Redistributions in binary form must reproduce the above copyright |
| 27 | ** notice, this list of conditions and the following disclaimer in |
| 28 | ** the documentation and/or other materials provided with the |
| 29 | ** distribution. |
| 30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 31 | ** contributors may be used to endorse or promote products derived |
| 32 | ** from this software without specific prior written permission. |
| 33 | ** |
| 34 | ** |
| 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 46 | ** |
| 47 | ** $QT_END_LICENSE$ |
| 48 | ** |
| 49 | ****************************************************************************/ |
| 50 | |
| 51 | #include "widgetgallery.h" |
| 52 | |
| 53 | #include <QApplication> |
| 54 | #include <QCheckBox> |
| 55 | #include <QComboBox> |
| 56 | #include <QCommandLinkButton> |
| 57 | #include <QDateTimeEdit> |
| 58 | #include <QDial> |
| 59 | #include <QDialogButtonBox> |
| 60 | #include <QFileSystemModel> |
| 61 | #include <QGridLayout> |
| 62 | #include <QGroupBox> |
| 63 | #include <QMenu> |
| 64 | #include <QLabel> |
| 65 | #include <QLineEdit> |
| 66 | #include <QListWidget> |
| 67 | #include <QPlainTextEdit> |
| 68 | #include <QProgressBar> |
| 69 | #include <QPushButton> |
| 70 | #include <QRadioButton> |
| 71 | #include <QScrollBar> |
| 72 | #include <QShortcut> |
| 73 | #include <QSpinBox> |
| 74 | #include <QStandardItemModel> |
| 75 | #include <QStyle> |
| 76 | #include <QStyleFactory> |
| 77 | #include <QTextBrowser> |
| 78 | #include <QTreeView> |
| 79 | #include <QTableWidget> |
| 80 | #include <QTextEdit> |
| 81 | #include <QToolBox> |
| 82 | #include <QToolButton> |
| 83 | |
| 84 | #include <QIcon> |
| 85 | #include <QDesktopServices> |
| 86 | #include <QScreen> |
| 87 | #include <QWindow> |
| 88 | |
| 89 | #include <QDebug> |
| 90 | #include <QLibraryInfo> |
| 91 | #include <QSysInfo> |
| 92 | #include <QTextStream> |
| 93 | #include <QTimer> |
| 94 | |
| 95 | static inline QString className(const QObject *o) |
| 96 | { |
| 97 | return QString::fromUtf8(o->metaObject()->className()); |
| 98 | } |
| 99 | |
| 100 | static inline void setClassNameToolTip(QWidget *w) |
| 101 | { |
| 102 | w->setToolTip(className(w)); |
| 103 | } |
| 104 | |
| 105 | static QString helpUrl(const QString &page) |
| 106 | { |
| 107 | QString result; |
| 108 | QTextStream(&result) << "https://doc.qt.io/qt-" << QT_VERSION_MAJOR |
| 109 | << '/' << page << ".html" ; |
| 110 | return result; |
| 111 | } |
| 112 | |
| 113 | static inline QString helpUrl(const QWidget *w) |
| 114 | { |
| 115 | return helpUrl(className(w).toLower()); |
| 116 | } |
| 117 | |
| 118 | static void launchHelp(const QWidget *w) |
| 119 | { |
| 120 | QDesktopServices::openUrl(helpUrl(w)); |
| 121 | } |
| 122 | |
| 123 | static void launchModuleHelp() |
| 124 | { |
| 125 | QDesktopServices::openUrl(helpUrl(QLatin1String("qtwidgets-index" ))); |
| 126 | } |
| 127 | |
| 128 | template <class Widget> |
| 129 | Widget *createWidget(const char *name, QWidget *parent = nullptr) |
| 130 | { |
| 131 | auto result = new Widget(parent); |
| 132 | result->setObjectName(QLatin1String(name)); |
| 133 | setClassNameToolTip(result); |
| 134 | return result; |
| 135 | } |
| 136 | |
| 137 | template <class Widget, class Parameter> |
| 138 | Widget *createWidget1(const Parameter &p1, const char *name, QWidget *parent = nullptr) |
| 139 | { |
| 140 | auto result = new Widget(p1, parent); |
| 141 | result->setObjectName(QLatin1String(name)); |
| 142 | setClassNameToolTip(result); |
| 143 | return result; |
| 144 | } |
| 145 | |
| 146 | QTextStream &operator<<(QTextStream &str, const QRect &r) |
| 147 | { |
| 148 | str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() |
| 149 | << Qt::noforcesign; |
| 150 | return str; |
| 151 | } |
| 152 | |
| 153 | static QString highDpiScaleFactorRoundingPolicy() |
| 154 | { |
| 155 | QString result; |
| 156 | QDebug(&result) << QGuiApplication::highDpiScaleFactorRoundingPolicy(); |
| 157 | if (result.endsWith(QLatin1Char(')'))) |
| 158 | result.chop(1); |
| 159 | const int lastSep = result.lastIndexOf(QLatin1String("::" )); |
| 160 | if (lastSep != -1) |
| 161 | result.remove(0, lastSep + 2); |
| 162 | return result; |
| 163 | } |
| 164 | |
| 165 | WidgetGallery::WidgetGallery(QWidget *parent) |
| 166 | : QDialog(parent) |
| 167 | , progressBar(createProgressBar()) |
| 168 | { |
| 169 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); |
| 170 | |
| 171 | auto styleComboBox = createWidget<QComboBox>("styleComboBox" ); |
| 172 | const QString defaultStyleName = QApplication::style()->objectName(); |
| 173 | QStringList styleNames = QStyleFactory::keys(); |
| 174 | for (int i = 1, size = styleNames.size(); i < size; ++i) { |
| 175 | if (defaultStyleName.compare(styleNames.at(i), Qt::CaseInsensitive) == 0) { |
| 176 | styleNames.swapItemsAt(0, i); |
| 177 | break; |
| 178 | } |
| 179 | } |
| 180 | styleComboBox->addItems(styleNames); |
| 181 | |
| 182 | auto styleLabel = createWidget1<QLabel>(tr("&Style:" ), "styleLabel" ); |
| 183 | styleLabel->setBuddy(styleComboBox); |
| 184 | |
| 185 | auto helpLabel = createWidget1<QLabel>(tr("Press F1 over a widget to see Documentation" ), "helpLabel" ); |
| 186 | |
| 187 | auto disableWidgetsCheckBox = createWidget1<QCheckBox>(tr("&Disable widgets" ), "disableWidgetsCheckBox" ); |
| 188 | |
| 189 | auto buttonsGroupBox = createButtonsGroupBox(); |
| 190 | auto itemViewTabWidget = createItemViewTabWidget(); |
| 191 | auto simpleInputWidgetsGroupBox = createSimpleInputWidgetsGroupBox(); |
| 192 | auto textToolBox = createTextToolBox(); |
| 193 | |
| 194 | connect(styleComboBox, &QComboBox::textActivated, |
| 195 | this, &WidgetGallery::changeStyle); |
| 196 | connect(disableWidgetsCheckBox, &QCheckBox::toggled, |
| 197 | buttonsGroupBox, &QWidget::setDisabled); |
| 198 | connect(disableWidgetsCheckBox, &QCheckBox::toggled, |
| 199 | textToolBox, &QWidget::setDisabled); |
| 200 | connect(disableWidgetsCheckBox, &QCheckBox::toggled, |
| 201 | itemViewTabWidget, &QWidget::setDisabled); |
| 202 | connect(disableWidgetsCheckBox, &QCheckBox::toggled, |
| 203 | simpleInputWidgetsGroupBox, &QWidget::setDisabled); |
| 204 | |
| 205 | auto topLayout = new QHBoxLayout; |
| 206 | topLayout->addWidget(styleLabel); |
| 207 | topLayout->addWidget(styleComboBox); |
| 208 | topLayout->addStretch(1); |
| 209 | topLayout->addWidget(helpLabel); |
| 210 | topLayout->addStretch(1); |
| 211 | topLayout->addWidget(disableWidgetsCheckBox); |
| 212 | |
| 213 | auto dialogButtonBox = createWidget1<QDialogButtonBox>(QDialogButtonBox::Help | QDialogButtonBox::Close, |
| 214 | "dialogButtonBox" ); |
| 215 | connect(dialogButtonBox, &QDialogButtonBox::helpRequested, this, launchModuleHelp); |
| 216 | connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); |
| 217 | |
| 218 | auto mainLayout = new QGridLayout(this); |
| 219 | mainLayout->addLayout(topLayout, 0, 0, 1, 2); |
| 220 | mainLayout->addWidget(buttonsGroupBox, 1, 0); |
| 221 | mainLayout->addWidget(simpleInputWidgetsGroupBox, 1, 1); |
| 222 | mainLayout->addWidget(itemViewTabWidget, 2, 0); |
| 223 | mainLayout->addWidget(textToolBox, 2, 1); |
| 224 | mainLayout->addWidget(progressBar, 3, 0, 1, 2); |
| 225 | mainLayout->addWidget(dialogButtonBox, 4, 0, 1, 2); |
| 226 | |
| 227 | setWindowTitle(tr("Widget Gallery Qt %1" ).arg(QT_VERSION_STR)); |
| 228 | |
| 229 | new QShortcut(QKeySequence::HelpContents, this, this, &WidgetGallery::helpOnCurrentWidget); |
| 230 | } |
| 231 | |
| 232 | void WidgetGallery::setVisible(bool visible) |
| 233 | { |
| 234 | QDialog::setVisible(visible); |
| 235 | if (visible) { |
| 236 | connect(windowHandle(), &QWindow::screenChanged, this, &WidgetGallery::updateSystemInfo); |
| 237 | updateSystemInfo(); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | void WidgetGallery::changeStyle(const QString &styleName) |
| 242 | { |
| 243 | QApplication::setStyle(QStyleFactory::create(styleName)); |
| 244 | } |
| 245 | |
| 246 | void WidgetGallery::advanceProgressBar() |
| 247 | { |
| 248 | int curVal = progressBar->value(); |
| 249 | int maxVal = progressBar->maximum(); |
| 250 | progressBar->setValue(curVal + (maxVal - curVal) / 100); |
| 251 | } |
| 252 | |
| 253 | QGroupBox *WidgetGallery::createButtonsGroupBox() |
| 254 | { |
| 255 | auto result = createWidget1<QGroupBox>(tr("Buttons" ), "buttonsGroupBox" ); |
| 256 | |
| 257 | auto defaultPushButton = createWidget1<QPushButton>(tr("Default Push Button" ), "defaultPushButton" ); |
| 258 | defaultPushButton->setDefault(true); |
| 259 | |
| 260 | auto togglePushButton = createWidget1<QPushButton>(tr("Toggle Push Button" ), "togglePushButton" ); |
| 261 | togglePushButton->setCheckable(true); |
| 262 | togglePushButton->setChecked(true); |
| 263 | |
| 264 | auto flatPushButton = createWidget1<QPushButton>(tr("Flat Push Button" ), "flatPushButton" ); |
| 265 | flatPushButton->setFlat(true); |
| 266 | |
| 267 | auto toolButton = createWidget<QToolButton>("toolButton" ); |
| 268 | toolButton->setText(tr("Tool Button" )); |
| 269 | |
| 270 | auto = createWidget<QToolButton>("menuButton" ); |
| 271 | menuToolButton->setText(tr("Menu Button" )); |
| 272 | auto = new QMenu(menuToolButton); |
| 273 | menuToolButton->setPopupMode(QToolButton::InstantPopup); |
| 274 | toolMenu->addAction("Option" ); |
| 275 | toolMenu->addSeparator(); |
| 276 | auto action = toolMenu->addAction("Checkable Option" ); |
| 277 | action->setCheckable(true); |
| 278 | menuToolButton->setMenu(toolMenu); |
| 279 | auto toolLayout = new QHBoxLayout; |
| 280 | toolLayout->addWidget(toolButton); |
| 281 | toolLayout->addWidget(menuToolButton); |
| 282 | |
| 283 | auto commandLinkButton = createWidget1<QCommandLinkButton>(tr("Command Link Button" ), "commandLinkButton" ); |
| 284 | commandLinkButton->setDescription(tr("Description" )); |
| 285 | |
| 286 | auto buttonLayout = new QVBoxLayout; |
| 287 | buttonLayout->addWidget(defaultPushButton); |
| 288 | buttonLayout->addWidget(togglePushButton); |
| 289 | buttonLayout->addWidget(flatPushButton); |
| 290 | buttonLayout->addLayout(toolLayout); |
| 291 | buttonLayout->addWidget(commandLinkButton); |
| 292 | buttonLayout->addStretch(1); |
| 293 | |
| 294 | auto radioButton1 = createWidget1<QRadioButton>(tr("Radio button 1" ), "radioButton1" ); |
| 295 | auto radioButton2 = createWidget1<QRadioButton>(tr("Radio button 2" ), "radioButton2" ); |
| 296 | auto radioButton3 = createWidget1<QRadioButton>(tr("Radio button 3" ), "radioButton3" ); |
| 297 | radioButton1->setChecked(true); |
| 298 | |
| 299 | auto checkBox = createWidget1<QCheckBox>(tr("Tri-state check box" ), "checkBox" ); |
| 300 | checkBox->setTristate(true); |
| 301 | checkBox->setCheckState(Qt::PartiallyChecked); |
| 302 | |
| 303 | auto checkableLayout = new QVBoxLayout; |
| 304 | checkableLayout->addWidget(radioButton1); |
| 305 | checkableLayout->addWidget(radioButton2); |
| 306 | checkableLayout->addWidget(radioButton3); |
| 307 | checkableLayout->addWidget(checkBox); |
| 308 | checkableLayout->addStretch(1); |
| 309 | |
| 310 | auto mainLayout = new QHBoxLayout(result); |
| 311 | mainLayout->addLayout(buttonLayout); |
| 312 | mainLayout->addLayout(checkableLayout); |
| 313 | mainLayout->addStretch(); |
| 314 | return result; |
| 315 | } |
| 316 | |
| 317 | static QWidget *embedIntoHBoxLayout(QWidget *w, int margin = 5) |
| 318 | { |
| 319 | auto result = new QWidget; |
| 320 | auto layout = new QHBoxLayout(result); |
| 321 | layout->setContentsMargins(margin, margin, margin, margin); |
| 322 | layout->addWidget(w); |
| 323 | return result; |
| 324 | } |
| 325 | |
| 326 | QToolBox *WidgetGallery::createTextToolBox() |
| 327 | { |
| 328 | auto result = createWidget<QToolBox>("toolBox" ); |
| 329 | |
| 330 | const QString plainText = tr("Twinkle, twinkle, little star,\n" |
| 331 | "How I wonder what you are.\n" |
| 332 | "Up above the world so high,\n" |
| 333 | "Like a diamond in the sky.\n" |
| 334 | "Twinkle, twinkle, little star,\n" |
| 335 | "How I wonder what you are!\n" ); |
| 336 | // Create centered/italic HTML rich text |
| 337 | QString richText = QLatin1String("<html><head/><body><i>" ); |
| 338 | for (const auto &line : QStringView{ plainText }.split(QLatin1Char('\n'))) |
| 339 | richText += QString::fromLatin1("<center>%1</center>" ).arg(line); |
| 340 | richText += QLatin1String("</i></body></html>" ); |
| 341 | |
| 342 | auto textEdit = createWidget1<QTextEdit>(richText, "textEdit" ); |
| 343 | auto plainTextEdit = createWidget1<QPlainTextEdit>(plainText, "plainTextEdit" ); |
| 344 | |
| 345 | systemInfoTextBrowser = createWidget<QTextBrowser>("systemInfoTextBrowser" ); |
| 346 | |
| 347 | result->addItem(embedIntoHBoxLayout(textEdit), tr("Text Edit" )); |
| 348 | result->addItem(embedIntoHBoxLayout(plainTextEdit), tr("Plain Text Edit" )); |
| 349 | result->addItem(embedIntoHBoxLayout(systemInfoTextBrowser), tr("Text Browser" )); |
| 350 | return result; |
| 351 | } |
| 352 | |
| 353 | QTabWidget *WidgetGallery::createItemViewTabWidget() |
| 354 | { |
| 355 | auto result = createWidget<QTabWidget>("bottomLeftTabWidget" ); |
| 356 | result->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); |
| 357 | |
| 358 | auto treeView = createWidget<QTreeView>("treeView" ); |
| 359 | auto fileSystemModel = new QFileSystemModel(treeView); |
| 360 | fileSystemModel->setRootPath(QDir::rootPath()); |
| 361 | treeView->setModel(fileSystemModel); |
| 362 | |
| 363 | auto tableWidget = createWidget<QTableWidget>("tableWidget" ); |
| 364 | tableWidget->setRowCount(10); |
| 365 | tableWidget->setColumnCount(10); |
| 366 | |
| 367 | auto listModel = new QStandardItemModel(0, 1, result); |
| 368 | listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-128.png" )), |
| 369 | tr("Directory" ))); |
| 370 | listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/computer-32.png" )), |
| 371 | tr("Computer" ))); |
| 372 | |
| 373 | auto listView = createWidget<QListView>("listView" ); |
| 374 | listView->setModel(listModel); |
| 375 | |
| 376 | auto iconModeListView = createWidget<QListView>("iconModeListView" ); |
| 377 | iconModeListView->setViewMode(QListView::IconMode); |
| 378 | iconModeListView->setModel(listModel); |
| 379 | |
| 380 | result->addTab(embedIntoHBoxLayout(treeView), tr("&Tree View" )); |
| 381 | result->addTab(embedIntoHBoxLayout(tableWidget), tr("T&able" )); |
| 382 | result->addTab(embedIntoHBoxLayout(listView), tr("&List" )); |
| 383 | result->addTab(embedIntoHBoxLayout(iconModeListView), tr("&Icon Mode List" )); |
| 384 | return result; |
| 385 | } |
| 386 | |
| 387 | QGroupBox *WidgetGallery::createSimpleInputWidgetsGroupBox() |
| 388 | { |
| 389 | auto result = createWidget1<QGroupBox>(tr("Simple Input Widgets" ), "bottomRightGroupBox" ); |
| 390 | result->setCheckable(true); |
| 391 | result->setChecked(true); |
| 392 | |
| 393 | auto lineEdit = createWidget1<QLineEdit>("s3cRe7" , "lineEdit" ); |
| 394 | lineEdit->setClearButtonEnabled(true); |
| 395 | lineEdit->setEchoMode(QLineEdit::Password); |
| 396 | |
| 397 | auto spinBox = createWidget<QSpinBox>("spinBox" , result); |
| 398 | spinBox->setValue(50); |
| 399 | |
| 400 | auto dateTimeEdit = createWidget<QDateTimeEdit>("dateTimeEdit" , result); |
| 401 | dateTimeEdit->setDateTime(QDateTime::currentDateTime()); |
| 402 | |
| 403 | auto slider = createWidget<QSlider>("slider" , result); |
| 404 | slider->setOrientation(Qt::Horizontal); |
| 405 | slider->setValue(40); |
| 406 | |
| 407 | auto scrollBar = createWidget<QScrollBar>("scrollBar" , result); |
| 408 | scrollBar->setOrientation(Qt::Horizontal); |
| 409 | setClassNameToolTip(scrollBar); |
| 410 | scrollBar->setValue(60); |
| 411 | |
| 412 | auto dial = createWidget<QDial>("dial" , result); |
| 413 | dial->setValue(30); |
| 414 | dial->setNotchesVisible(true); |
| 415 | |
| 416 | auto layout = new QGridLayout(result); |
| 417 | layout->addWidget(lineEdit, 0, 0, 1, 2); |
| 418 | layout->addWidget(spinBox, 1, 0, 1, 2); |
| 419 | layout->addWidget(dateTimeEdit, 2, 0, 1, 2); |
| 420 | layout->addWidget(slider, 3, 0); |
| 421 | layout->addWidget(scrollBar, 4, 0); |
| 422 | layout->addWidget(dial, 3, 1, 2, 1); |
| 423 | layout->setRowStretch(5, 1); |
| 424 | return result; |
| 425 | } |
| 426 | |
| 427 | QProgressBar *WidgetGallery::createProgressBar() |
| 428 | { |
| 429 | auto result = createWidget<QProgressBar>("progressBar" ); |
| 430 | result->setRange(0, 10000); |
| 431 | result->setValue(0); |
| 432 | |
| 433 | auto timer = new QTimer(this); |
| 434 | connect(timer, &QTimer::timeout, this, &WidgetGallery::advanceProgressBar); |
| 435 | timer->start(1000); |
| 436 | return result; |
| 437 | } |
| 438 | |
| 439 | void WidgetGallery::updateSystemInfo() |
| 440 | { |
| 441 | QString systemInfo; |
| 442 | QTextStream str(&systemInfo); |
| 443 | str << "<html><head/><body><h3>Build</h3><p>" << QLibraryInfo::build() << "</p>" |
| 444 | << "<h3>Operating System</h3><p>" << QSysInfo::prettyProductName() << "</p>" |
| 445 | << "<h3>Screens</h3><p>High DPI scale factor rounding policy: " |
| 446 | << highDpiScaleFactorRoundingPolicy() << "</p><ol>" ; |
| 447 | const auto screens = QGuiApplication::screens(); |
| 448 | for (auto screen : screens) { |
| 449 | const bool current = screen == this->screen(); |
| 450 | str << "<li>" ; |
| 451 | if (current) |
| 452 | str << "<i>" ; |
| 453 | str << '"' << screen->name() << "\" " << screen->geometry() << ", " |
| 454 | << screen->logicalDotsPerInchX() << "DPI, DPR=" |
| 455 | << screen->devicePixelRatio(); |
| 456 | if (current) |
| 457 | str << "</i>" ; |
| 458 | str << "</li>" ; |
| 459 | } |
| 460 | str << "</ol></body></html>" ; |
| 461 | systemInfoTextBrowser->setHtml(systemInfo); |
| 462 | } |
| 463 | |
| 464 | void WidgetGallery::helpOnCurrentWidget() |
| 465 | { |
| 466 | // Skip over internal widgets |
| 467 | for (auto w = QApplication::widgetAt(QCursor::pos(screen())); w; w = w->parentWidget()) { |
| 468 | const QString name = w->objectName(); |
| 469 | if (!name.isEmpty() && !name.startsWith(QLatin1String("qt_" ))) { |
| 470 | launchHelp(w); |
| 471 | break; |
| 472 | } |
| 473 | } |
| 474 | } |
| 475 | |