widgetgallery.cpp Example File

gallery/widgetgallery.cpp
 /****************************************************************************
 **
 ** Copyright (C) 2020 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the examples of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:BSD$
 ** Commercial License Usage
 ** Licensees holding valid commercial Qt licenses may use this file in
 ** accordance with the commercial license agreement provided with the
 ** Software or, alternatively, in accordance with the terms contained in
 ** a written agreement between you and The Qt Company. For licensing terms
 ** and conditions see https://www.qt.io/terms-conditions. For further
 ** information use the contact form at https://www.qt.io/contact-us.
 **
 ** BSD License Usage
 ** Alternatively, you may use this file under the terms of the BSD license
 ** as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of The Qt Company Ltd nor the names of its
 **     contributors may be used to endorse or promote products derived
 **     from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 **
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 #include "widgetgallery.h"

 #include <QApplication>
 #include <QCheckBox>
 #include <QComboBox>
 #include <QCommandLinkButton>
 #include <QDateTimeEdit>
 #include <QDial>
 #include <QDialogButtonBox>
 #include <QFileSystemModel>
 #include <QGridLayout>
 #include <QGroupBox>
 #include <QMenu>
 #include <QLabel>
 #include <QLineEdit>
 #include <QListWidget>
 #include <QPlainTextEdit>
 #include <QProgressBar>
 #include <QPushButton>
 #include <QRadioButton>
 #include <QScrollBar>
 #include <QShortcut>
 #include <QSpinBox>
 #include <QStandardItemModel>
 #include <QStyle>
 #include <QStyleFactory>
 #include <QTextBrowser>
 #include <QTreeView>
 #include <QTableWidget>
 #include <QTextEdit>
 #include <QToolBox>
 #include <QToolButton>

 #include <QIcon>
 #include <QDesktopServices>
 #include <QScreen>
 #include <QWindow>

 #include <QDebug>
 #include <QLibraryInfo>
 #include <QSysInfo>
 #include <QTextStream>
 #include <QTimer>

 static inline QString className(const QObject *o)
 {
      return QString::fromUtf8(o->metaObject()->className());
 }

 static inline void setClassNameToolTip(QWidget *w)
 {
     w->setToolTip(className(w));
 }

 static QString helpUrl(const QString &page)
 {
     QString result;
     QTextStream(&result) << "https://doc.qt.io/qt-" << QT_VERSION_MAJOR
         << '/' << page << ".html";
     return result;
 }

 static inline QString helpUrl(const QWidget *w)
 {
     return helpUrl(className(w).toLower());
 }

 static void launchHelp(const QWidget *w)
 {
      QDesktopServices::openUrl(helpUrl(w));
 }

 static void launchModuleHelp()
 {
     QDesktopServices::openUrl(helpUrl(QLatin1String("qtwidgets-index")));
 }

 template <class Widget>
 Widget *createWidget(const char *name, QWidget *parent = nullptr)
 {
     auto result = new Widget(parent);
     result->setObjectName(QLatin1String(name));
     setClassNameToolTip(result);
     return result;
 }

 template <class Widget, class Parameter>
 Widget *createWidget1(const Parameter &p1, const char *name, QWidget *parent = nullptr)
 {
     auto result = new Widget(p1, parent);
     result->setObjectName(QLatin1String(name));
     setClassNameToolTip(result);
     return result;
 }

 QTextStream &operator<<(QTextStream &str, const QRect &r)
 {
     str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y()
         << Qt::noforcesign;
     return str;
 }

 static QString highDpiScaleFactorRoundingPolicy()
 {
     QString result;
     QDebug(&result) << QGuiApplication::highDpiScaleFactorRoundingPolicy();
     if (result.endsWith(QLatin1Char(')')))
         result.chop(1);
     const int lastSep = result.lastIndexOf(QLatin1String("::"));
     if (lastSep != -1)
         result.remove(0, lastSep + 2);
     return result;
 }

 WidgetGallery::WidgetGallery(QWidget *parent)
     : QDialog(parent)
     , progressBar(createProgressBar())
 {
     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

     auto styleComboBox = createWidget<QComboBox>("styleComboBox");
     const QString defaultStyleName = QApplication::style()->objectName();
     QStringList styleNames = QStyleFactory::keys();
     for (int i = 1, size = styleNames.size(); i < size; ++i) {
         if (defaultStyleName.compare(styleNames.at(i), Qt::CaseInsensitive) == 0) {
             styleNames.swapItemsAt(0, i);
             break;
         }
     }
     styleComboBox->addItems(styleNames);

     auto styleLabel = createWidget1<QLabel>(tr("&Style:"), "styleLabel");
     styleLabel->setBuddy(styleComboBox);

     auto helpLabel = createWidget1<QLabel>(tr("Press F1 over a widget to see Documentation"), "helpLabel");

     auto disableWidgetsCheckBox = createWidget1<QCheckBox>(tr("&Disable widgets"), "disableWidgetsCheckBox");

     auto buttonsGroupBox = createButtonsGroupBox();
     auto itemViewTabWidget = createItemViewTabWidget();
     auto simpleInputWidgetsGroupBox = createSimpleInputWidgetsGroupBox();
     auto textToolBox = createTextToolBox();

     connect(styleComboBox, &QComboBox::textActivated,
             this, &WidgetGallery::changeStyle);
     connect(disableWidgetsCheckBox, &QCheckBox::toggled,
             buttonsGroupBox, &QWidget::setDisabled);
     connect(disableWidgetsCheckBox, &QCheckBox::toggled,
             textToolBox, &QWidget::setDisabled);
     connect(disableWidgetsCheckBox, &QCheckBox::toggled,
             itemViewTabWidget, &QWidget::setDisabled);
     connect(disableWidgetsCheckBox, &QCheckBox::toggled,
             simpleInputWidgetsGroupBox, &QWidget::setDisabled);

     auto topLayout = new QHBoxLayout;
     topLayout->addWidget(styleLabel);
     topLayout->addWidget(styleComboBox);
     topLayout->addStretch(1);
     topLayout->addWidget(helpLabel);
     topLayout->addStretch(1);
     topLayout->addWidget(disableWidgetsCheckBox);

     auto dialogButtonBox = createWidget1<QDialogButtonBox>(QDialogButtonBox::Help | QDialogButtonBox::Close,
                                                            "dialogButtonBox");
     connect(dialogButtonBox, &QDialogButtonBox::helpRequested, this, launchModuleHelp);
     connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

     auto mainLayout = new QGridLayout(this);
     mainLayout->addLayout(topLayout, 0, 0, 1, 2);
     mainLayout->addWidget(buttonsGroupBox, 1, 0);
     mainLayout->addWidget(simpleInputWidgetsGroupBox, 1, 1);
     mainLayout->addWidget(itemViewTabWidget, 2, 0);
     mainLayout->addWidget(textToolBox, 2, 1);
     mainLayout->addWidget(progressBar, 3, 0, 1, 2);
     mainLayout->addWidget(dialogButtonBox, 4, 0, 1, 2);

     setWindowTitle(tr("Widget Gallery Qt %1").arg(QT_VERSION_STR));

     new QShortcut(QKeySequence::HelpContents, this, this, &WidgetGallery::helpOnCurrentWidget);
 }

 void  WidgetGallery::setVisible(bool visible)
 {
     QDialog::setVisible(visible);
     if (visible) {
         connect(windowHandle(), &QWindow::screenChanged, this, &WidgetGallery::updateSystemInfo);
         updateSystemInfo();
     }
 }

 void WidgetGallery::changeStyle(const QString &styleName)
 {
     QApplication::setStyle(QStyleFactory::create(styleName));
 }

 void WidgetGallery::advanceProgressBar()
 {
     int curVal = progressBar->value();
     int maxVal = progressBar->maximum();
     progressBar->setValue(curVal + (maxVal - curVal) / 100);
 }

 QGroupBox *WidgetGallery::createButtonsGroupBox()
 {
     auto result = createWidget1<QGroupBox>(tr("Buttons"), "buttonsGroupBox");

     auto defaultPushButton = createWidget1<QPushButton>(tr("Default Push Button"), "defaultPushButton");
     defaultPushButton->setDefault(true);

     auto togglePushButton = createWidget1<QPushButton>(tr("Toggle Push Button"), "togglePushButton");
     togglePushButton->setCheckable(true);
     togglePushButton->setChecked(true);

     auto flatPushButton = createWidget1<QPushButton>(tr("Flat Push Button"), "flatPushButton");
     flatPushButton->setFlat(true);

     auto toolButton = createWidget<QToolButton>("toolButton");
     toolButton->setText(tr("Tool Button"));

     auto menuToolButton = createWidget<QToolButton>("menuButton");
     menuToolButton->setText(tr("Menu Button"));
     auto toolMenu = new QMenu(menuToolButton);
     menuToolButton->setPopupMode(QToolButton::InstantPopup);
     toolMenu->addAction("Option");
     toolMenu->addSeparator();
     auto action = toolMenu->addAction("Checkable Option");
     action->setCheckable(true);
     menuToolButton->setMenu(toolMenu);
     auto toolLayout = new QHBoxLayout;
     toolLayout->addWidget(toolButton);
     toolLayout->addWidget(menuToolButton);

     auto commandLinkButton = createWidget1<QCommandLinkButton>(tr("Command Link Button"), "commandLinkButton");
     commandLinkButton->setDescription(tr("Description"));

     auto buttonLayout = new QVBoxLayout;
     buttonLayout->addWidget(defaultPushButton);
     buttonLayout->addWidget(togglePushButton);
     buttonLayout->addWidget(flatPushButton);
     buttonLayout->addLayout(toolLayout);
     buttonLayout->addWidget(commandLinkButton);
     buttonLayout->addStretch(1);

     auto radioButton1 = createWidget1<QRadioButton>(tr("Radio button 1"), "radioButton1");
     auto radioButton2 = createWidget1<QRadioButton>(tr("Radio button 2"), "radioButton2");
     auto radioButton3 = createWidget1<QRadioButton>(tr("Radio button 3"), "radioButton3");
     radioButton1->setChecked(true);

     auto checkBox =  createWidget1<QCheckBox>(tr("Tri-state check box"), "checkBox");
     checkBox->setTristate(true);
     checkBox->setCheckState(Qt::PartiallyChecked);

     auto checkableLayout = new QVBoxLayout;
     checkableLayout->addWidget(radioButton1);
     checkableLayout->addWidget(radioButton2);
     checkableLayout->addWidget(radioButton3);
     checkableLayout->addWidget(checkBox);
     checkableLayout->addStretch(1);

     auto mainLayout = new QHBoxLayout(result);
     mainLayout->addLayout(buttonLayout);
     mainLayout->addLayout(checkableLayout);
     mainLayout->addStretch();
     return result;
 }

 static QWidget *embedIntoHBoxLayout(QWidget *w, int margin = 5)
 {
     auto result = new QWidget;
     auto layout = new QHBoxLayout(result);
     layout->setContentsMargins(margin, margin, margin, margin);
     layout->addWidget(w);
     return result;
 }

 QToolBox *WidgetGallery::createTextToolBox()
 {
     auto result = createWidget<QToolBox>("toolBox");

     const QString plainText = tr("Twinkle, twinkle, little star,\n"
                             "How I wonder what you are.\n"
                             "Up above the world so high,\n"
                             "Like a diamond in the sky.\n"
                             "Twinkle, twinkle, little star,\n"
                             "How I wonder what you are!\n");
     // Create centered/italic HTML rich text
     QString richText = QLatin1String("<html><head/><body><i>");
     for (const auto &line : plainText.splitRef(QLatin1Char('\n')))
         richText += QLatin1String("<center>") + line + QLatin1String("</center>");
     richText += QLatin1String("</i></body></html>");

     auto textEdit = createWidget1<QTextEdit>(richText, "textEdit");
     auto plainTextEdit = createWidget1<QPlainTextEdit>(plainText, "plainTextEdit");

     systemInfoTextBrowser = createWidget<QTextBrowser>("systemInfoTextBrowser");

     result->addItem(embedIntoHBoxLayout(textEdit), tr("Text Edit"));
     result->addItem(embedIntoHBoxLayout(plainTextEdit), tr("Plain Text Edit"));
     result->addItem(embedIntoHBoxLayout(systemInfoTextBrowser), tr("Text Browser"));
     return result;
 }

 QTabWidget *WidgetGallery::createItemViewTabWidget()
 {
     auto result = createWidget<QTabWidget>("bottomLeftTabWidget");
     result->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);

     auto treeView = createWidget<QTreeView>("treeView");
     auto fileSystemModel = new QFileSystemModel(treeView);
     fileSystemModel->setRootPath(QDir::rootPath());
     treeView->setModel(fileSystemModel);

     auto tableWidget = createWidget<QTableWidget>("tableWidget");
     tableWidget->setRowCount(10);
     tableWidget->setColumnCount(10);

     auto listModel = new QStandardItemModel(0, 1, result);
     listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-128.png")),
                                            tr("Directory")));
     listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/computer-32.png")),
                                            tr("Computer")));

     auto listView = createWidget<QListView>("listView");
     listView->setModel(listModel);

     auto iconModeListView = createWidget<QListView>("iconModeListView");
     iconModeListView->setViewMode(QListView::IconMode);
     iconModeListView->setModel(listModel);

     result->addTab(embedIntoHBoxLayout(treeView), tr("&Tree View"));
     result->addTab(embedIntoHBoxLayout(tableWidget), tr("T&able"));
     result->addTab(embedIntoHBoxLayout(listView), tr("&List"));
     result->addTab(embedIntoHBoxLayout(iconModeListView), tr("&Icon Mode List"));
     return result;
 }

 QGroupBox *WidgetGallery::createSimpleInputWidgetsGroupBox()
 {
     auto result = createWidget1<QGroupBox>(tr("Simple Input Widgets"), "bottomRightGroupBox");
     result->setCheckable(true);
     result->setChecked(true);

     auto lineEdit = createWidget1<QLineEdit>("s3cRe7", "lineEdit");
     lineEdit->setClearButtonEnabled(true);
     lineEdit->setEchoMode(QLineEdit::Password);

     auto spinBox = createWidget<QSpinBox>("spinBox", result);
     spinBox->setValue(50);

     auto dateTimeEdit = createWidget<QDateTimeEdit>("dateTimeEdit", result);
     dateTimeEdit->setDateTime(QDateTime::currentDateTime());

     auto slider = createWidget<QSlider>("slider", result);
     slider->setOrientation(Qt::Horizontal);
     slider->setValue(40);

     auto scrollBar = createWidget<QScrollBar>("scrollBar", result);
     scrollBar->setOrientation(Qt::Horizontal);
     setClassNameToolTip(scrollBar);
     scrollBar->setValue(60);

     auto dial = createWidget<QDial>("dial", result);
     dial->setValue(30);
     dial->setNotchesVisible(true);

     auto layout = new QGridLayout(result);
     layout->addWidget(lineEdit, 0, 0, 1, 2);
     layout->addWidget(spinBox, 1, 0, 1, 2);
     layout->addWidget(dateTimeEdit, 2, 0, 1, 2);
     layout->addWidget(slider, 3, 0);
     layout->addWidget(scrollBar, 4, 0);
     layout->addWidget(dial, 3, 1, 2, 1);
     layout->setRowStretch(5, 1);
     return result;
 }

 QProgressBar *WidgetGallery::createProgressBar()
 {
     auto result = createWidget<QProgressBar>("progressBar");
     result->setRange(0, 10000);
     result->setValue(0);

     auto timer = new QTimer(this);
     connect(timer, &QTimer::timeout, this, &WidgetGallery::advanceProgressBar);
     timer->start(1000);
     return result;
 }

 void WidgetGallery::updateSystemInfo()
 {
     QString systemInfo;
     QTextStream str(&systemInfo);
     str << "<html><head/><body><h3>Build</h3><p>" << QLibraryInfo::build() << "</p>"
         << "<h3>Operating System</h3><p>" << QSysInfo::prettyProductName() << "</p>"
         << "<h3>Screens</h3><p>High DPI scale factor rounding policy: "
         << highDpiScaleFactorRoundingPolicy() << "</p><ol>";
     const auto screens = QGuiApplication::screens();
     for (auto screen : screens) {
         const bool current = screen == this->screen();
         str << "<li>";
         if (current)
             str << "<i>";
         str << '"' << screen->name() << "\" " << screen->geometry() << ", "
             << screen->logicalDotsPerInchX() << "DPI, DPR="
             << screen->devicePixelRatio();
         if (current)
             str << "</i>";
         str << "</li>";
     }
     str << "</ol></body></html>";
     systemInfoTextBrowser->setHtml(systemInfo);
 }

 void WidgetGallery::helpOnCurrentWidget()
 {
     // Skip over internal widgets
     for (auto w = QApplication::widgetAt(QCursor::pos(screen())); w; w = w->parentWidget()) {
         const QString name = w->objectName();
         if (!name.isEmpty() && !name.startsWith(QLatin1String("qt_"))) {
             launchHelp(w);
             break;
         }
     }
 }