qtbase-opensource-src/examples/widgets/gallery/widgetgallery.cpp

475 lines
17 KiB
C++

/****************************************************************************
**
** 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;
}
}
}