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
95static inline QString className(const QObject *o)
96{
97 return QString::fromUtf8(str: o->metaObject()->className());
98}
99
100static inline void setClassNameToolTip(QWidget *w)
101{
102 w->setToolTip(className(o: w));
103}
104
105static 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
113static inline QString helpUrl(const QWidget *w)
114{
115 return helpUrl(page: className(o: w).toLower());
116}
117
118static void launchHelp(const QWidget *w)
119{
120 QDesktopServices::openUrl(url: helpUrl(w));
121}
122
123static void launchModuleHelp()
124{
125 QDesktopServices::openUrl(url: helpUrl(page: QLatin1String("qtwidgets-index")));
126}
127
128template <class Widget>
129Widget *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
137template <class Widget, class Parameter>
138Widget *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
146QTextStream &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
153static QString highDpiScaleFactorRoundingPolicy()
154{
155 QString result;
156 QDebug(&result) << QGuiApplication::highDpiScaleFactorRoundingPolicy();
157 if (result.endsWith(c: QLatin1Char(')')))
158 result.chop(n: 1);
159 const int lastSep = result.lastIndexOf(s: QLatin1String("::"));
160 if (lastSep != -1)
161 result.remove(i: 0, len: lastSep + 2);
162 return result;
163}
164
165WidgetGallery::WidgetGallery(QWidget *parent)
166 : QDialog(parent)
167 , progressBar(createProgressBar())
168{
169 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
170
171 auto styleComboBox = createWidget<QComboBox>(name: "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(s: styleNames.at(i), cs: Qt::CaseInsensitive) == 0) {
176 styleNames.swapItemsAt(i: 0, j: i);
177 break;
178 }
179 }
180 styleComboBox->addItems(texts: styleNames);
181
182 auto styleLabel = createWidget1<QLabel>(p1: tr(s: "&Style:"), name: "styleLabel");
183 styleLabel->setBuddy(styleComboBox);
184
185 auto helpLabel = createWidget1<QLabel>(p1: tr(s: "Press F1 over a widget to see Documentation"), name: "helpLabel");
186
187 auto disableWidgetsCheckBox = createWidget1<QCheckBox>(p1: tr(s: "&Disable widgets"), name: "disableWidgetsCheckBox");
188
189 auto buttonsGroupBox = createButtonsGroupBox();
190 auto itemViewTabWidget = createItemViewTabWidget();
191 auto simpleInputWidgetsGroupBox = createSimpleInputWidgetsGroupBox();
192 auto textToolBox = createTextToolBox();
193
194 connect(sender: styleComboBox, signal: &QComboBox::textActivated,
195 receiver: this, slot: &WidgetGallery::changeStyle);
196 connect(sender: disableWidgetsCheckBox, signal: &QCheckBox::toggled,
197 receiver: buttonsGroupBox, slot: &QWidget::setDisabled);
198 connect(sender: disableWidgetsCheckBox, signal: &QCheckBox::toggled,
199 receiver: textToolBox, slot: &QWidget::setDisabled);
200 connect(sender: disableWidgetsCheckBox, signal: &QCheckBox::toggled,
201 receiver: itemViewTabWidget, slot: &QWidget::setDisabled);
202 connect(sender: disableWidgetsCheckBox, signal: &QCheckBox::toggled,
203 receiver: simpleInputWidgetsGroupBox, slot: &QWidget::setDisabled);
204
205 auto topLayout = new QHBoxLayout;
206 topLayout->addWidget(styleLabel);
207 topLayout->addWidget(styleComboBox);
208 topLayout->addStretch(stretch: 1);
209 topLayout->addWidget(helpLabel);
210 topLayout->addStretch(stretch: 1);
211 topLayout->addWidget(disableWidgetsCheckBox);
212
213 auto dialogButtonBox = createWidget1<QDialogButtonBox>(p1: QDialogButtonBox::Help | QDialogButtonBox::Close,
214 name: "dialogButtonBox");
215 connect(sender: dialogButtonBox, signal: &QDialogButtonBox::helpRequested, context: this, slot: launchModuleHelp);
216 connect(sender: dialogButtonBox, signal: &QDialogButtonBox::rejected, receiver: this, slot: &QDialog::reject);
217
218 auto mainLayout = new QGridLayout(this);
219 mainLayout->addLayout(topLayout, row: 0, column: 0, rowSpan: 1, columnSpan: 2);
220 mainLayout->addWidget(buttonsGroupBox, row: 1, column: 0);
221 mainLayout->addWidget(simpleInputWidgetsGroupBox, row: 1, column: 1);
222 mainLayout->addWidget(itemViewTabWidget, row: 2, column: 0);
223 mainLayout->addWidget(textToolBox, row: 2, column: 1);
224 mainLayout->addWidget(progressBar, row: 3, column: 0, rowSpan: 1, columnSpan: 2);
225 mainLayout->addWidget(dialogButtonBox, row: 4, column: 0, rowSpan: 1, columnSpan: 2);
226
227 setWindowTitle(tr(s: "Widget Gallery Qt %1").arg(QT_VERSION_STR));
228
229 new QShortcut(QKeySequence::HelpContents, this, this, &WidgetGallery::helpOnCurrentWidget);
230}
231
232void WidgetGallery::setVisible(bool visible)
233{
234 QDialog::setVisible(visible);
235 if (visible) {
236 connect(sender: windowHandle(), signal: &QWindow::screenChanged, receiver: this, slot: &WidgetGallery::updateSystemInfo);
237 updateSystemInfo();
238 }
239}
240
241void WidgetGallery::changeStyle(const QString &styleName)
242{
243 QApplication::setStyle(QStyleFactory::create(styleName));
244}
245
246void WidgetGallery::advanceProgressBar()
247{
248 int curVal = progressBar->value();
249 int maxVal = progressBar->maximum();
250 progressBar->setValue(curVal + (maxVal - curVal) / 100);
251}
252
253QGroupBox *WidgetGallery::createButtonsGroupBox()
254{
255 auto result = createWidget1<QGroupBox>(p1: tr(s: "Buttons"), name: "buttonsGroupBox");
256
257 auto defaultPushButton = createWidget1<QPushButton>(p1: tr(s: "Default Push Button"), name: "defaultPushButton");
258 defaultPushButton->setDefault(true);
259
260 auto togglePushButton = createWidget1<QPushButton>(p1: tr(s: "Toggle Push Button"), name: "togglePushButton");
261 togglePushButton->setCheckable(true);
262 togglePushButton->setChecked(true);
263
264 auto flatPushButton = createWidget1<QPushButton>(p1: tr(s: "Flat Push Button"), name: "flatPushButton");
265 flatPushButton->setFlat(true);
266
267 auto toolButton = createWidget<QToolButton>(name: "toolButton");
268 toolButton->setText(tr(s: "Tool Button"));
269
270 auto menuToolButton = createWidget<QToolButton>(name: "menuButton");
271 menuToolButton->setText(tr(s: "Menu Button"));
272 auto toolMenu = new QMenu(menuToolButton);
273 menuToolButton->setPopupMode(QToolButton::InstantPopup);
274 toolMenu->addAction(text: "Option");
275 toolMenu->addSeparator();
276 auto action = toolMenu->addAction(text: "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>(p1: tr(s: "Command Link Button"), name: "commandLinkButton");
284 commandLinkButton->setDescription(tr(s: "Description"));
285
286 auto buttonLayout = new QVBoxLayout;
287 buttonLayout->addWidget(defaultPushButton);
288 buttonLayout->addWidget(togglePushButton);
289 buttonLayout->addWidget(flatPushButton);
290 buttonLayout->addLayout(layout: toolLayout);
291 buttonLayout->addWidget(commandLinkButton);
292 buttonLayout->addStretch(stretch: 1);
293
294 auto radioButton1 = createWidget1<QRadioButton>(p1: tr(s: "Radio button 1"), name: "radioButton1");
295 auto radioButton2 = createWidget1<QRadioButton>(p1: tr(s: "Radio button 2"), name: "radioButton2");
296 auto radioButton3 = createWidget1<QRadioButton>(p1: tr(s: "Radio button 3"), name: "radioButton3");
297 radioButton1->setChecked(true);
298
299 auto checkBox = createWidget1<QCheckBox>(p1: tr(s: "Tri-state check box"), name: "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(stretch: 1);
309
310 auto mainLayout = new QHBoxLayout(result);
311 mainLayout->addLayout(layout: buttonLayout);
312 mainLayout->addLayout(layout: checkableLayout);
313 mainLayout->addStretch();
314 return result;
315}
316
317static QWidget *embedIntoHBoxLayout(QWidget *w, int margin = 5)
318{
319 auto result = new QWidget;
320 auto layout = new QHBoxLayout(result);
321 layout->setContentsMargins(left: margin, top: margin, right: margin, bottom: margin);
322 layout->addWidget(w);
323 return result;
324}
325
326QToolBox *WidgetGallery::createTextToolBox()
327{
328 auto result = createWidget<QToolBox>(name: "toolBox");
329
330 const QString plainText = tr(s: "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 : plainText.splitRef(sep: QLatin1Char('\n')))
339 richText += QLatin1String("<center>") + line + QLatin1String("</center>");
340 richText += QLatin1String("</i></body></html>");
341
342 auto textEdit = createWidget1<QTextEdit>(p1: richText, name: "textEdit");
343 auto plainTextEdit = createWidget1<QPlainTextEdit>(p1: plainText, name: "plainTextEdit");
344
345 systemInfoTextBrowser = createWidget<QTextBrowser>(name: "systemInfoTextBrowser");
346
347 result->addItem(item: embedIntoHBoxLayout(w: textEdit), text: tr(s: "Text Edit"));
348 result->addItem(item: embedIntoHBoxLayout(w: plainTextEdit), text: tr(s: "Plain Text Edit"));
349 result->addItem(item: embedIntoHBoxLayout(w: systemInfoTextBrowser), text: tr(s: "Text Browser"));
350 return result;
351}
352
353QTabWidget *WidgetGallery::createItemViewTabWidget()
354{
355 auto result = createWidget<QTabWidget>(name: "bottomLeftTabWidget");
356 result->setSizePolicy(hor: QSizePolicy::Preferred, ver: QSizePolicy::Ignored);
357
358 auto treeView = createWidget<QTreeView>(name: "treeView");
359 auto fileSystemModel = new QFileSystemModel(treeView);
360 fileSystemModel->setRootPath(QDir::rootPath());
361 treeView->setModel(fileSystemModel);
362
363 auto tableWidget = createWidget<QTableWidget>(name: "tableWidget");
364 tableWidget->setRowCount(10);
365 tableWidget->setColumnCount(10);
366
367 auto listModel = new QStandardItemModel(0, 1, result);
368 listModel->appendRow(aitem: new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-128.png")),
369 tr(s: "Directory")));
370 listModel->appendRow(aitem: new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/computer-32.png")),
371 tr(s: "Computer")));
372
373 auto listView = createWidget<QListView>(name: "listView");
374 listView->setModel(listModel);
375
376 auto iconModeListView = createWidget<QListView>(name: "iconModeListView");
377 iconModeListView->setViewMode(QListView::IconMode);
378 iconModeListView->setModel(listModel);
379
380 result->addTab(widget: embedIntoHBoxLayout(w: treeView), tr(s: "&Tree View"));
381 result->addTab(widget: embedIntoHBoxLayout(w: tableWidget), tr(s: "T&able"));
382 result->addTab(widget: embedIntoHBoxLayout(w: listView), tr(s: "&List"));
383 result->addTab(widget: embedIntoHBoxLayout(w: iconModeListView), tr(s: "&Icon Mode List"));
384 return result;
385}
386
387QGroupBox *WidgetGallery::createSimpleInputWidgetsGroupBox()
388{
389 auto result = createWidget1<QGroupBox>(p1: tr(s: "Simple Input Widgets"), name: "bottomRightGroupBox");
390 result->setCheckable(true);
391 result->setChecked(true);
392
393 auto lineEdit = createWidget1<QLineEdit>(p1: "s3cRe7", name: "lineEdit");
394 lineEdit->setClearButtonEnabled(true);
395 lineEdit->setEchoMode(QLineEdit::Password);
396
397 auto spinBox = createWidget<QSpinBox>(name: "spinBox", parent: result);
398 spinBox->setValue(50);
399
400 auto dateTimeEdit = createWidget<QDateTimeEdit>(name: "dateTimeEdit", parent: result);
401 dateTimeEdit->setDateTime(QDateTime::currentDateTime());
402
403 auto slider = createWidget<QSlider>(name: "slider", parent: result);
404 slider->setOrientation(Qt::Horizontal);
405 slider->setValue(40);
406
407 auto scrollBar = createWidget<QScrollBar>(name: "scrollBar", parent: result);
408 scrollBar->setOrientation(Qt::Horizontal);
409 setClassNameToolTip(scrollBar);
410 scrollBar->setValue(60);
411
412 auto dial = createWidget<QDial>(name: "dial", parent: result);
413 dial->setValue(30);
414 dial->setNotchesVisible(true);
415
416 auto layout = new QGridLayout(result);
417 layout->addWidget(lineEdit, row: 0, column: 0, rowSpan: 1, columnSpan: 2);
418 layout->addWidget(spinBox, row: 1, column: 0, rowSpan: 1, columnSpan: 2);
419 layout->addWidget(dateTimeEdit, row: 2, column: 0, rowSpan: 1, columnSpan: 2);
420 layout->addWidget(slider, row: 3, column: 0);
421 layout->addWidget(scrollBar, row: 4, column: 0);
422 layout->addWidget(dial, row: 3, column: 1, rowSpan: 2, columnSpan: 1);
423 layout->setRowStretch(row: 5, stretch: 1);
424 return result;
425}
426
427QProgressBar *WidgetGallery::createProgressBar()
428{
429 auto result = createWidget<QProgressBar>(name: "progressBar");
430 result->setRange(minimum: 0, maximum: 10000);
431 result->setValue(0);
432
433 auto timer = new QTimer(this);
434 connect(sender: timer, signal: &QTimer::timeout, receiver: this, slot: &WidgetGallery::advanceProgressBar);
435 timer->start(msec: 1000);
436 return result;
437}
438
439void 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
464void WidgetGallery::helpOnCurrentWidget()
465{
466 // Skip over internal widgets
467 for (auto w = QApplication::widgetAt(p: QCursor::pos(screen: screen())); w; w = w->parentWidget()) {
468 const QString name = w->objectName();
469 if (!name.isEmpty() && !name.startsWith(s: QLatin1String("qt_"))) {
470 launchHelp(w);
471 break;
472 }
473 }
474}
475

source code of qtbase/examples/widgets/gallery/widgetgallery.cpp