diff options
Diffstat (limited to 'src/widgets')
157 files changed, 2173 insertions, 939 deletions
diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp index 6cdc06d702..63c6fbb9bb 100644 --- a/src/widgets/accessible/complexwidgets.cpp +++ b/src/widgets/accessible/complexwidgets.cpp @@ -120,7 +120,14 @@ public: return rec; } - bool isValid() const override { return m_parent.data() && m_parent->count() > m_index; } + bool isValid() const override { + if (m_parent) { + if (static_cast<QWidget *>(m_parent.data())->d_func()->data.in_destructor) + return false; + return m_parent->count() > m_index; + } + return false; + } QAccessibleInterface *childAt(int, int) const override { return 0; } int childCount() const override { return 0; } @@ -199,7 +206,7 @@ QAccessibleTabBar::QAccessibleTabBar(QWidget *w) QAccessibleTabBar::~QAccessibleTabBar() { - foreach (QAccessible::Id id, m_childInterfaces) + for (QAccessible::Id id : qAsConst(m_childInterfaces)) QAccessible::deleteAccessibleInterface(id); } diff --git a/src/widgets/accessible/complexwidgets_p.h b/src/widgets/accessible/complexwidgets_p.h index 96db2dab70..e7a32c7264 100644 --- a/src/widgets/accessible/complexwidgets_p.h +++ b/src/widgets/accessible/complexwidgets_p.h @@ -90,8 +90,6 @@ public: int indexOfChild(const QAccessibleInterface *child) const override; bool isValid() const override; QAccessibleInterface *childAt(int x, int y) const override; - -//protected: QAbstractScrollArea *abstractScrollArea() const; private: diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp index 4d37400dc9..51cfaa7f5e 100644 --- a/src/widgets/accessible/itemviews.cpp +++ b/src/widgets/accessible/itemviews.cpp @@ -110,12 +110,12 @@ QAccessibleTable::QAccessibleTable(QWidget *w) bool QAccessibleTable::isValid() const { - return (view() && !qobject_cast<QWidget*>(view())->d_func()->data.in_destructor); + return view() && !qt_widget_private(view())->data.in_destructor; } QAccessibleTable::~QAccessibleTable() { - Q_FOREACH (QAccessible::Id id, childToId) + for (QAccessible::Id id : qAsConst(childToId)) QAccessible::deleteAccessibleInterface(id); } @@ -221,7 +221,7 @@ QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const return cells; const QModelIndexList selectedIndexes = view()->selectionModel()->selectedIndexes(); cells.reserve(selectedIndexes.size()); - Q_FOREACH (const QModelIndex &index, selectedIndexes) + for (const QModelIndex &index : selectedIndexes) cells.append(child(logicalIndex(index))); return cells; } @@ -233,7 +233,7 @@ QList<int> QAccessibleTable::selectedColumns() const QList<int> columns; const QModelIndexList selectedColumns = view()->selectionModel()->selectedColumns(); columns.reserve(selectedColumns.size()); - Q_FOREACH (const QModelIndex &index, selectedColumns) + for (const QModelIndex &index : selectedColumns) columns.append(index.column()); return columns; @@ -246,7 +246,7 @@ QList<int> QAccessibleTable::selectedRows() const QList<int> rows; const QModelIndexList selectedRows = view()->selectionModel()->selectedRows(); rows.reserve(selectedRows.size()); - Q_FOREACH (const QModelIndex &index, selectedRows) + for (const QModelIndex &index : selectedRows) rows.append(index.row()); return rows; @@ -553,7 +553,7 @@ void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event) switch (event->modelChangeType()) { case QAccessibleTableModelChangeEvent::ModelReset: - Q_FOREACH (QAccessible::Id id, childToId) + for (QAccessible::Id id : qAsConst(childToId)) QAccessible::deleteAccessibleInterface(id); childToId.clear(); break; @@ -973,7 +973,7 @@ void QAccessibleTableCell::unselectCell() { QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); - if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) + if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection)) return; QAccessibleTableInterface *cellTable = table()->tableInterface(); @@ -1091,7 +1091,8 @@ void QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text) bool QAccessibleTableCell::isValid() const { - return view && view->model() && m_index.isValid(); + return view && !qt_widget_private(view)->data.in_destructor + && view->model() && m_index.isValid(); } QAccessibleInterface *QAccessibleTableCell::parent() const @@ -1180,7 +1181,8 @@ void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &) bool QAccessibleTableHeaderCell::isValid() const { - return view && view->model() && (index >= 0) + return view && !qt_widget_private(view)->data.in_destructor + && view->model() && (index >= 0) && ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount())); } diff --git a/src/widgets/accessible/qaccessiblemenu.cpp b/src/widgets/accessible/qaccessiblemenu.cpp index 8b3353f625..507584eb02 100644 --- a/src/widgets/accessible/qaccessiblemenu.cpp +++ b/src/widgets/accessible/qaccessiblemenu.cpp @@ -117,10 +117,9 @@ QAccessibleInterface *QAccessibleMenu::child(int index) const QAccessibleInterface *QAccessibleMenu::parent() const { if (QAction *menuAction = menu()->menuAction()) { - QList<QWidget *> parentCandidates; - parentCandidates << menu()->parentWidget(); - parentCandidates << menuAction->associatedWidgets(); - foreach (QWidget *w, parentCandidates) { + const QList<QWidget*> parentCandidates = + QList<QWidget*>() << menu()->parentWidget() << menuAction->associatedWidgets(); + for (QWidget *w : parentCandidates) { if (qobject_cast<QMenu*>(w) #if QT_CONFIG(menubar) || qobject_cast<QMenuBar*>(w) diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp index 872ddcded5..0d87cc486d 100644 --- a/src/widgets/accessible/qaccessiblewidgets.cpp +++ b/src/widgets/accessible/qaccessiblewidgets.cpp @@ -569,7 +569,7 @@ QCalendarWidget *QAccessibleCalendarWidget::calendarWidget() const QAbstractItemView *QAccessibleCalendarWidget::calendarView() const { - foreach (QObject *child, calendarWidget()->children()) { + for (QObject *child : calendarWidget()->children()) { if (child->objectName() == QLatin1String("qt_calendar_calendarview")) return static_cast<QAbstractItemView *>(child); } @@ -578,7 +578,7 @@ QAbstractItemView *QAccessibleCalendarWidget::calendarView() const QWidget *QAccessibleCalendarWidget::navigationBar() const { - foreach (QObject *child, calendarWidget()->children()) { + for (QObject *child : calendarWidget()->children()) { if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) return static_cast<QWidget *>(child); } diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 99946d341d..4aa680af61 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -2123,7 +2123,6 @@ void QColorDialog::setVisible(bool visible) } /*! - \overload \since 4.5 Opens the dialog and connects its colorSelected() signal to the slot specified @@ -2162,6 +2161,7 @@ QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QStr return dlg.selectedColor(); } +#if QT_DEPRECATED_SINCE(5, 12) /*! \obsolete @@ -2169,7 +2169,7 @@ QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QStr and an alpha channel (transparency) value. The color+alpha is initially set to \a initial. The dialog is a child of \a parent. - If \a ok is non-null, \e *\a ok is set to true if the user clicked + If \a ok is non-null, \e {*ok} is set to true if the user clicked \uicontrol{OK}, and to false if the user clicked Cancel. If the user clicks Cancel, the \a initial value is returned. @@ -2187,6 +2187,7 @@ QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent) *ok = color.isValid(); return result; } +#endif /*! Destroys the color dialog. diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h index 6451ff9bde..cdbe0e7fb4 100644 --- a/src/widgets/dialogs/qcolordialog.h +++ b/src/widgets/dialogs/qcolordialog.h @@ -92,8 +92,9 @@ public: const QString &title = QString(), ColorDialogOptions options = ColorDialogOptions()); - // obsolete - static QRgb getRgba(QRgb rgba = 0xffffffff, bool *ok = nullptr, QWidget *parent = nullptr); +#if QT_DEPRECATED_SINCE(5, 12) + QT_DEPRECATED_X("Use getColor()") static QRgb getRgba(QRgb rgba = 0xffffffff, bool *ok = nullptr, QWidget *parent = nullptr); +#endif static int customCount(); static QColor customColor(int index); diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp index f5db4481ee..06f0393b4c 100644 --- a/src/widgets/dialogs/qdialog.cpp +++ b/src/widgets/dialogs/qdialog.cpp @@ -100,6 +100,10 @@ static inline int themeDialogType(const QDialog *dialog) if (qobject_cast<const QErrorMessage *>(dialog)) return QPlatformTheme::MessageDialog; #endif +#if !QT_CONFIG(filedialog) && !QT_CONFIG(colordialog) && !QT_CONFIG(fontdialog) && \ + !QT_CONFIG(messagebox) && !QT_CONFIG(errormessage) + Q_UNUSED(dialog); +#endif return -1; } @@ -514,6 +518,13 @@ void QDialog::open() interaction with the parent window is blocked while the dialog is open. By default, the dialog is application modal. + \note Avoid using this function; instead, use \c{open()}. Unlike exec(), + open() is asynchronous, and does not spin an additional event loop. This + prevents a series of dangerous bugs from happening (e.g. deleting the + dialog's parent while the dialog is open via exec()). When using open() you + can connect to the finished() signal of QDialog to be notified when the + dialog is closed. + \sa open(), show(), result(), setWindowModality() */ @@ -560,9 +571,12 @@ int QDialog::exec() } /*! - Closes the dialog and sets its result code to \a r. If this dialog - is shown with exec(), done() causes the local event loop to finish, - and exec() to return \a r. + Closes the dialog and sets its result code to \a r. The finished() signal + will emit \a r; if \a r is QDialog::Accepted or QDialog::Rejected, the + accepted() or the rejected() signals will also be emitted, respectively. + + If this dialog is shown with exec(), done() also causes the local event loop + to finish, and exec() to return \a r. As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set. If the dialog is the application's diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 778e8556c7..5c6c03d3aa 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -519,7 +519,7 @@ void QFileDialog::changeEvent(QEvent *e) QFileDialogPrivate::QFileDialogPrivate() : -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) proxyModel(0), #endif model(0), @@ -665,7 +665,7 @@ void QFileDialogPrivate::retranslateStrings() QList<QAction*> actions = qFileDialogUi->treeView->header()->actions(); QAbstractItemModel *abstractModel = model; -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) if (proxyModel) abstractModel = proxyModel; #endif @@ -804,8 +804,6 @@ QFileDialog::Options QFileDialog::options() const } /*! - \overload - \since 4.5 This function connects one of its signals to the slot specified by \a receiver @@ -1049,10 +1047,15 @@ void QFileDialog::selectFile(const QString &filename) return; if (!d->usingWidgets()) { - QUrl url = QUrl::fromLocalFile(filename); + QUrl url; if (QFileInfo(filename).isRelative()) { - QDir dir(d->options->initialDirectory().toLocalFile()); - url = QUrl::fromLocalFile(dir.absoluteFilePath(filename)); + url = d->options->initialDirectory(); + QString path = url.path(); + if (!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); + url.setPath(path + filename); + } else { + url = QUrl::fromLocalFile(filename); } d->selectFile_sys(url); d->options->setInitiallySelectedFiles(QList<QUrl>() << url); @@ -1110,7 +1113,7 @@ Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path) const QString homePath = QDir::homePath(); #else const QByteArray userName = path.midRef(1, separatorPosition - 1).toLocal8Bit(); -# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) +# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM) passwd pw; passwd *tmpPw; char buf[200]; @@ -2108,9 +2111,7 @@ QString QFileDialog::labelText(DialogLabel label) const strings. If you want multiple filters, separate them with ';;', for example: - \code - "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" - \endcode + \snippet code/src_gui_dialogs_qfiledialog.cpp 14 The \a options argument holds various options about how to run the dialog, see the QFileDialog::Option enum for more information on the flags you can @@ -2223,9 +2224,7 @@ QUrl QFileDialog::getOpenFileUrl(QWidget *parent, \a selectedFilter and \a filter may be empty strings. If you need multiple filters, separate them with ';;', for instance: - \code - "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" - \endcode + \snippet code/src_gui_dialogs_qfiledialog.cpp 14 The dialog's caption is set to \a caption. If \a caption is not specified then a default caption will be used. @@ -2339,9 +2338,7 @@ QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent, parameters \a dir, \a selectedFilter, and \a filter may be empty strings. Multiple filters are separated with ';;'. For instance: - \code - "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" - \endcode + \snippet code/src_gui_dialogs_qfiledialog.cpp 14 The \a options argument holds various options about how to run the dialog, see the QFileDialog::Option enum for more information on the flags you can @@ -2815,7 +2812,7 @@ bool QFileDialogPrivate::restoreWidgetState(QStringList &history, int splitterPo QList<QAction*> actions = headerView->actions(); QAbstractItemModel *abstractModel = model; -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) if (proxyModel) abstractModel = proxyModel; #endif @@ -2984,7 +2981,7 @@ void QFileDialogPrivate::createWidgets() q, SLOT(_q_showHeader(QAction*)));; QAbstractItemModel *abstractModel = model; -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) if (proxyModel) abstractModel = proxyModel; #endif @@ -3065,7 +3062,7 @@ void QFileDialogPrivate::_q_showHeader(QAction *action) qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked()); } -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) /*! \since 4.3 @@ -3143,7 +3140,7 @@ QAbstractProxyModel *QFileDialog::proxyModel() const Q_D(const QFileDialog); return d->proxyModel; } -#endif // QT_NO_PROXYMODEL +#endif // QT_CONFIG(proxymodel) /*! \internal diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h index b9a49d3d18..a4d289a77a 100644 --- a/src/widgets/dialogs/qfiledialog.h +++ b/src/widgets/dialogs/qfiledialog.h @@ -178,7 +178,7 @@ public: void setSupportedSchemes(const QStringList &schemes); QStringList supportedSchemes() const; -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) void setProxyModel(QAbstractProxyModel *model); QAbstractProxyModel *proxyModel() const; #endif diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h index 17290381d3..3a93a53911 100644 --- a/src/widgets/dialogs/qfiledialog_p.h +++ b/src/widgets/dialogs/qfiledialog_p.h @@ -227,7 +227,7 @@ public: void _q_fileRenamed(const QString &path, const QString &oldName, const QString &newName); // layout -#ifndef QT_NO_PROXYMODEL +#if QT_CONFIG(proxymodel) QAbstractProxyModel *proxyModel; #endif @@ -346,17 +346,17 @@ private: }; QModelIndex QFileDialogPrivate::mapToSource(const QModelIndex &index) const { -#ifdef QT_NO_PROXYMODEL - return index; -#else +#if QT_CONFIG(proxymodel) return proxyModel ? proxyModel->mapToSource(index) : index; +#else + return index; #endif } QModelIndex QFileDialogPrivate::mapFromSource(const QModelIndex &index) const { -#ifdef QT_NO_PROXYMODEL - return index; -#else +#if QT_CONFIG(proxymodel) return proxyModel ? proxyModel->mapFromSource(index) : index; +#else + return index; #endif } diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 3a30cb5b2a..8b3549c3f5 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -48,6 +48,9 @@ #endif #include <qapplication.h> #include <QtCore/qcollator.h> +#if QT_CONFIG(regularexpression) +# include <QtCore/qregularexpression.h> +#endif #include <algorithm> @@ -1580,7 +1583,7 @@ bool QFileSystemModel::nameFilterDisables() const void QFileSystemModel::setNameFilters(const QStringList &filters) { // Prep the regexp's ahead of time -#ifndef QT_NO_REGEXP +#if QT_CONFIG(regularexpression) Q_D(QFileSystemModel); if (!d->bypassFilters.isEmpty()) { @@ -1601,11 +1604,7 @@ void QFileSystemModel::setNameFilters(const QStringList &filters) } } - d->nameFilters.clear(); - const Qt::CaseSensitivity caseSensitive = - (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive; - for (const auto &filter : filters) - d->nameFilters << QRegExp(filter, caseSensitive, QRegExp::Wildcard); + d->nameFilters = filters; d->forceSort = true; d->delayedSort(); #endif @@ -1616,16 +1615,12 @@ void QFileSystemModel::setNameFilters(const QStringList &filters) */ QStringList QFileSystemModel::nameFilters() const { +#if QT_CONFIG(regularexpression) Q_D(const QFileSystemModel); - QStringList filters; -#ifndef QT_NO_REGEXP - const int numNameFilters = d->nameFilters.size(); - filters.reserve(numNameFilters); - for (int i = 0; i < numNameFilters; ++i) { - filters << d->nameFilters.at(i).pattern(); - } + return d->nameFilters; +#else + return QStringList(); #endif - return filters; } /*! @@ -2026,15 +2021,21 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co */ bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const { -#ifndef QT_NO_REGEXP +#if QT_CONFIG(regularexpression) if (nameFilters.isEmpty()) return true; // Check the name regularexpression filters if (!(node->isDir() && (filters & QDir::AllDirs))) { + const QRegularExpression::PatternOptions options = + (filters & QDir::CaseSensitive) ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption; + for (const auto &nameFilter : nameFilters) { - QRegExp copy = nameFilter; - if (copy.exactMatch(node->fileName)) + const QString wildcard = QRegularExpression::wildcardToRegularExpression(nameFilter); + QRegularExpression rx(QRegularExpression::anchoredPattern(wildcard), options); + QRegularExpressionMatch match = rx.match(node->fileName); + if (match.hasMatch()) return true; } return false; diff --git a/src/widgets/dialogs/qfilesystemmodel_p.h b/src/widgets/dialogs/qfilesystemmodel_p.h index a2a02e2d41..9c432e1ae6 100644 --- a/src/widgets/dialogs/qfilesystemmodel_p.h +++ b/src/widgets/dialogs/qfilesystemmodel_p.h @@ -294,8 +294,6 @@ public: void _q_fileSystemChanged(const QString &path, const QVector<QPair<QString, QFileInfo> > &); void _q_resolvedName(const QString &fileName, const QString &resolvedName); - static int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs); - QDir rootDir; #if QT_CONFIG(filesystemwatcher) # ifdef Q_OS_WIN @@ -317,8 +315,8 @@ public: //It enable a sort which is not recursive, it means //we sort only what we see. bool disableRecursiveSort; -#ifndef QT_NO_REGEXP - QList<QRegExp> nameFilters; +#if QT_CONFIG(regularexpression) + QStringList nameFilters; #endif QHash<QString, QString> resolvedSymLinks; diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp index 5f912c582f..477c6bd540 100644 --- a/src/widgets/dialogs/qfontdialog.cpp +++ b/src/widgets/dialogs/qfontdialog.cpp @@ -931,7 +931,6 @@ QFontDialog::FontDialogOptions QFontDialog::options() const /*! \since 4.5 - \overload Opens the dialog and connects its fontSelected() signal to the slot specified by \a receiver and \a member. diff --git a/src/widgets/dialogs/qinputdialog.cpp b/src/widgets/dialogs/qinputdialog.cpp index 5c6e0f45a5..5a7d6edddf 100644 --- a/src/widgets/dialogs/qinputdialog.cpp +++ b/src/widgets/dialogs/qinputdialog.cpp @@ -1070,7 +1070,6 @@ QString QInputDialog::cancelButtonText() const /*! \since 4.5 - \overload This function connects one of its signals to the slot specified by \a receiver and \a member. The specific signal depends on the arguments that are specified @@ -1180,7 +1179,7 @@ void QInputDialog::done(int result) \a inputMethodHints is the input method hints that will be used in the edit widget if an input method is active. - If \a ok is nonnull \e *\a ok will be set to true if the user pressed + If \a ok is nonnull \e {*ok} will be set to true if the user pressed \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent is \a parent. The dialog will be modal and uses the specified widget \a flags. @@ -1228,7 +1227,7 @@ QString QInputDialog::getText(QWidget *parent, const QString &title, const QStri \a inputMethodHints is the input method hints that will be used in the edit widget if an input method is active. - If \a ok is nonnull \e *\a ok will be set to true if the user pressed + If \a ok is nonnull \e {*ok} will be set to true if the user pressed \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent is \a parent. The dialog will be modal and uses the specified widget \a flags. @@ -1436,7 +1435,7 @@ double QInputDialog::getDouble(QWidget *parent, const QString &title, const QStr If \a editable is true the user can enter their own text; otherwise, the user may only select one of the existing items. - If \a ok is nonnull \e *\a ok will be set to true if the user pressed + If \a ok is nonnull \e {*ok} will be set to true if the user pressed \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent is \a parent. The dialog will be modal and uses the widget \a flags. diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index 6de952a1d3..99157747dd 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -64,6 +64,7 @@ #include <QtGui/qfont.h> #include <QtGui/qfontmetrics.h> #include <QtGui/qclipboard.h> +#include "private/qabstractbutton_p.h" #include <private/qdesktopwidget_p.h> #ifdef Q_OS_WIN @@ -492,9 +493,17 @@ void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button) void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role) { - Q_UNUSED(role); Q_Q(QMessageBox); - q->done(button); + if (button > QPlatformDialogHelper::LastButton) { + // It's a custom button, and the QPushButton in options is just a proxy + // for the button on the platform dialog. Simulate the user clicking it. + clickedButton = static_cast<QAbstractButton *>(options->customButton(button)->button); + Q_ASSERT(clickedButton); + clickedButton->click(); + q->done(role); + } else { + q->done(button); + } } /*! @@ -831,6 +840,8 @@ void QMessageBox::addButton(QAbstractButton *button, ButtonRole role) if (!button) return; removeButton(button); + d->options->addButton(button->text(), static_cast<QPlatformDialogHelper::ButtonRole>(role), + button); d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role); d->customButtonList.append(button); d->autoAddOkButton = false; @@ -1064,7 +1075,7 @@ void QMessageBoxPrivate::detectEscapeButton() or 0 if the user hit the \uicontrol Esc key and no \l{setEscapeButton()}{escape button} was set. - If exec() hasn't been called yet, returns 0. + If exec() hasn't been called yet, returns nullptr. Example: @@ -1082,7 +1093,7 @@ QAbstractButton *QMessageBox::clickedButton() const \since 4.2 Returns the button that should be the message box's - \l{QPushButton::setDefault()}{default button}. Returns 0 + \l{QPushButton::setDefault()}{default button}. Returns nullptr if no default button was set. \sa addButton(), QPushButton::setDefault() @@ -1489,8 +1500,6 @@ void QMessageBox::keyPressEvent(QKeyEvent *e) } /*! - \overload - Opens the dialog and connects its finished() or buttonClicked() signal to the slot specified by \a receiver and \a member. If the slot in \a member has a pointer for its first parameter the connection is to buttonClicked(), @@ -2678,7 +2687,11 @@ void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *) void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *) { Q_Q(QMessageBox); - clickedButton = q->button(QMessageBox::StandardButton(code)); + QAbstractButton *button = q->button(QMessageBox::StandardButton(code)); + // If it was a custom button, a custom ID was used, so we won't get a valid pointer here. + // In that case, clickedButton has already been set in _q_buttonClicked. + if (button) + clickedButton = button; } /*! @@ -2730,7 +2743,7 @@ QPixmap QMessageBox::standardIcon(Icon icon) Shows the message box as a \l{QDialog#Modal Dialogs}{modal dialog}, blocking until the user closes it. - When using a QMessageBox with standard buttons, this functions returns a + When using a QMessageBox with standard buttons, this function returns a \l StandardButton value indicating the standard button that was clicked. When using QMessageBox with custom buttons, this function returns an opaque value; use clickedButton() to determine which button was clicked. diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp index a276e28a0c..4bf78e2115 100644 --- a/src/widgets/dialogs/qprogressdialog.cpp +++ b/src/widgets/dialogs/qprogressdialog.cpp @@ -865,7 +865,6 @@ void QProgressDialog::forceShow() /*! \since 4.5 - \overload Opens the dialog and connects its canceled() signal to the slot specified by \a receiver and \a member. diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp index 5ef304c9f1..aa9ad7f290 100644 --- a/src/widgets/dialogs/qwizard_win.cpp +++ b/src/widgets/dialogs/qwizard_win.cpp @@ -606,8 +606,8 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q // Set up the DC const LOGFONT captionLogFont = getCaptionLogFont(hTheme); const HFONT hCaptionFont = CreateFontIndirect(&captionLogFont); - HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp); - HFONT hOldFont = (HFONT)SelectObject(dcMem, (HGDIOBJ) hCaptionFont); + auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp)); + auto hOldFont = reinterpret_cast<HFONT>(SelectObject(dcMem, (HGDIOBJ) hCaptionFont)); // Draw the text! DTTOPTS dto; @@ -654,7 +654,7 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc) dib.bmiHeader.biCompression = BI_RGB; bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0); - HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp); + auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp)); BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY); SelectObject(dcMem, (HGDIOBJ) hOldBmp); diff --git a/src/widgets/dialogs/qwizard_win_p.h b/src/widgets/dialogs/qwizard_win_p.h index 7ca4899a1f..d302dedaa3 100644 --- a/src/widgets/dialogs/qwizard_win_p.h +++ b/src/widgets/dialogs/qwizard_win_p.h @@ -71,22 +71,23 @@ class QVistaBackButton : public QAbstractButton public: QVistaBackButton(QWidget *widget); - QSize sizeHint() const; - inline QSize minimumSizeHint() const + QSize sizeHint() const override; + inline QSize minimumSizeHint() const override { return sizeHint(); } - void enterEvent(QEvent *event); - void leaveEvent(QEvent *event); - void paintEvent(QPaintEvent *event); + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + void paintEvent(QPaintEvent *event) override; }; class QWizard; class QVistaHelper : public QObject { + Q_DISABLE_COPY(QVistaHelper) public: QVistaHelper(QWizard *wizard); - ~QVistaHelper(); + ~QVistaHelper() override; enum TitleBarChangeType { NormalTitleBar, ExtendedTitleBar }; void updateCustomMargins(bool vistaMargins); bool setDWMTitleBar(TitleBarChangeType type); @@ -133,7 +134,7 @@ private: void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; static int instanceCount; static VistaState cachedVistaState; diff --git a/src/widgets/doc/images/gridlayout.png b/src/widgets/doc/images/qgridlayout.png Binary files differindex ae76c0487b..ae76c0487b 100644 --- a/src/widgets/doc/images/gridlayout.png +++ b/src/widgets/doc/images/qgridlayout.png diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp index 58f0ae560f..06cca37111 100644 --- a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp +++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp @@ -140,3 +140,7 @@ QFileDialog dialog(this); dialog.setMimeTypeFilters(mimeTypeFilters); dialog.exec(); //! [13] + +//! [14] +"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" +//! [14] diff --git a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp index 8d8c63db9e..ebca9d5368 100644 --- a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp +++ b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp @@ -271,3 +271,18 @@ QRect deviceRect = xform.mapRect(rect).toAlignedRect(); view->viewport()->scroll(dx, dy, deviceRect); //! [19] +//! [20] +item->setTransform(QTransform().rotate(angle), true); +//! [20] + +//! [21] +setTransform(QTransform::fromScale(sx, sy), true); +//! [21] + +//! [22] +setTransform(QTransform().shear(sh, sv), true); +//! [22] + +//! [23] +setTransform(QTransform::fromTranslate(dx, dy), true); +//! [23] diff --git a/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp b/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp index eadf753ded..a2ac780a82 100644 --- a/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp +++ b/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp @@ -84,3 +84,51 @@ formLayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint); formLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop); formLayout->setLabelAlignment(Qt::AlignLeft); //! [2] + +//! [3] +QFormLayout *flay = ...; +QPointer<QLineEdit> le = new QLineEdit; +flay->insertRow(2, "User:", le); +// later: +flay->removeRow(2); // le == nullptr at this point +//! [3] + +//! [4] +QFormLayout *flay = ...; +QPointer<QLineEdit> le = new QLineEdit; +flay->insertRow(2, "User:", le); +// later: +flay->removeRow(le); // le == nullptr at this point +//! [4] + +//! [5] +QFormLayout *flay = ...; +QPointer<QVBoxLayout> vbl = new QVBoxLayout; +flay->insertRow(2, "User:", vbl); +// later: +flay->removeRow(layout); // vbl == nullptr at this point +//! [5] + +//! [6] +QFormLayout *flay = ...; +QPointer<QLineEdit> le = new QLineEdit; +flay->insertRow(2, "User:", le); +// later: +QFormLayout::TakeRowResult result = flay->takeRow(2); +//! [6] + +//! [7] +QFormLayout *flay = ...; +QPointer<QLineEdit> le = new QLineEdit; +flay->insertRow(2, "User:", le); +// later: +QFormLayout::TakeRowResult result = flay->takeRow(widget); +//! [7] + +//! [8] +QFormLayout *flay = ...; +QPointer<QVBoxLayout> vbl = new QVBoxLayout; +flay->insertRow(2, "User:", vbl); +// later: +QFormLayout::TakeRowResult result = flay->takeRow(widget); +//! [8] diff --git a/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp b/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp new file mode 100644 index 0000000000..2b3d825266 --- /dev/null +++ b/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] + QWidget *w = ...; + QScroller::grabGesture(w, QScroller::LeftMouseButtonGesture); +//! [0] + +//! [1] + QWidget *w = ...; + QScroller *scroller = QScroller::scroller(w); + scroller->scrollTo(QPointF(100, 100)); +//! [1] diff --git a/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp b/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp new file mode 100644 index 0000000000..8ebaaf3991 --- /dev/null +++ b/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] + void MainWindow::createMenus() + { + fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(newAct); + fileMenu->addAction(openAct); + fileMenu->addAction(saveAct); +//! [0] + +//! [1] + void MainWindow::createToolBars() + { + fileToolBar = addToolBar(tr("File")); + fileToolBar->addAction(newAct); +//! [1] + +//! [2] + resizeDocks({blueWidget, yellowWidget}, {20 , 40}, Qt::Horizontal); +//! [2] diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc index be6a068d65..43f9dda49a 100644 --- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc +++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc @@ -520,7 +520,7 @@ user had manually called the corresponding QWidget::setPalette() and QWidget::setFont() methods on all of the QWidgets targeted by the style sheet. If this would have caused propagation in C++, it will cause - propagation in style sheets and visa versa. + propagation in style sheets and vice versa. \section1 Widgets Inside C++ Namespaces diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout.h b/src/widgets/graphicsview/qgraphicsanchorlayout.h index e392be1568..9bea43dd8e 100644 --- a/src/widgets/graphicsview/qgraphicsanchorlayout.h +++ b/src/widgets/graphicsview/qgraphicsanchorlayout.h @@ -70,7 +70,6 @@ private: Q_DECLARE_PRIVATE(QGraphicsAnchor) friend class QGraphicsAnchorLayoutPrivate; - friend struct AnchorData; }; class Q_WIDGETS_EXPORT QGraphicsAnchorLayout : public QGraphicsLayout diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp index 71027f00a2..008560d856 100644 --- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp @@ -167,7 +167,7 @@ AnchorData::~AnchorData() if (graphicsAnchor) { // Remove reference to ourself to avoid double removal in // QGraphicsAnchorPrivate dtor. - graphicsAnchor->d_func()->data = 0; + QGraphicsAnchorPrivate::get(graphicsAnchor)->data = nullptr; delete graphicsAnchor; } @@ -215,7 +215,7 @@ void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) } else { // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor Q_ASSERT(graphicsAnchor); - QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func(); + QGraphicsAnchorPrivate *anchorPrivate = QGraphicsAnchorPrivate::get(graphicsAnchor); // Policy, min and max sizes are straightforward policy = anchorPrivate->sizePolicy; @@ -2526,7 +2526,7 @@ QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) // Check if this constraint have some overlap with current // trunk variables... - foreach (QSimplexVariable *ad, trunkVariables) { + for (QSimplexVariable *ad : qAsConst(trunkVariables)) { if (c->variables.contains(ad)) { match = true; break; diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h index 6b2408b2eb..699ca32bfe 100644 --- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h @@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE respectively. */ +namespace QtGraphicsAnchorLayout { /*! \internal @@ -326,6 +327,9 @@ public: QSet<AnchorData *> positives; QSet<AnchorData *> negatives; }; +} // namespace QtGraphicsAnchorLayout +using namespace QtGraphicsAnchorLayout; + Q_DECLARE_TYPEINFO(GraphPath, Q_MOVABLE_TYPE); class QGraphicsAnchorLayoutPrivate; @@ -346,6 +350,9 @@ public: void setSizePolicy(QSizePolicy::Policy policy); + static QGraphicsAnchorPrivate *get(QGraphicsAnchor *q) + { return q->d_func(); } + QGraphicsAnchorLayoutPrivate *layoutPrivate; AnchorData *data; diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index fdf21fb499..e81eab4c46 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -1598,7 +1598,7 @@ QGraphicsItem::~QGraphicsItem() #ifndef QT_NO_GESTURES if (d_ptr->isObject && !d_ptr->gestureContext.isEmpty()) { QGraphicsObject *o = static_cast<QGraphicsObject *>(this); - if (QGestureManager *manager = QGestureManager::instance()) { + if (QGestureManager *manager = QGestureManager::instance(QGestureManager::DontForceCreation)) { const auto types = d_ptr->gestureContext.keys(); // FIXME: iterate over the map directly? for (Qt::GestureType type : types) manager->cleanupCachedGestures(o, type); @@ -4666,9 +4666,7 @@ void QGraphicsItem::resetTransform() Use - \code - item->setTransform(QTransform().rotate(angle), true); - \endcode + \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 20 instead. @@ -4689,9 +4687,7 @@ void QGraphicsItem::resetTransform() Use - \code - setTransform(QTransform::fromScale(sx, sy), true); - \endcode + \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 21 instead. @@ -4712,9 +4708,7 @@ void QGraphicsItem::resetTransform() Use - \code - setTransform(QTransform().shear(sh, sv), true); - \endcode + \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 22 instead. @@ -4730,9 +4724,7 @@ void QGraphicsItem::resetTransform() Use setPos() or setTransformOriginPoint() instead. For identical behavior, use - \code - setTransform(QTransform::fromTranslate(dx, dy), true); - \endcode + \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 23 Translates the current item transformation by (\a dx, \a dy). @@ -7310,7 +7302,7 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) selectedItems = d_ptr->scene->selectedItems(); initialPositions = d_ptr->scene->d_func()->movingItemsInitialPositions; if (initialPositions.isEmpty()) { - foreach (QGraphicsItem *item, selectedItems) + for (QGraphicsItem *item : qAsConst(selectedItems)) initialPositions[item] = item->pos(); initialPositions[this] = pos(); } diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h index 9fc6c0794a..d586a22544 100644 --- a/src/widgets/graphicsview/qgraphicsitem_p.h +++ b/src/widgets/graphicsview/qgraphicsitem_p.h @@ -500,7 +500,9 @@ public: quint32 filtersDescendantEvents : 1; quint32 sceneTransformTranslateOnly : 1; quint32 notifyBoundingRectChanged : 1; - +#ifdef Q_OS_WASM + unsigned char :0; //this aligns 64bit field for wasm see QTBUG-65259 +#endif // New 32 bits quint32 notifyInvalidated : 1; quint32 mouseSetsFocus : 1; diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 37c631483a..bba992144d 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -297,6 +297,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() painterStateProtection(true), sortCacheEnabled(false), allItemsIgnoreTouchEvents(true), + focusOnTouch(true), minimumRenderSize(0.0), selectionChanging(0), rectAdjust(2), @@ -2393,6 +2394,7 @@ void QGraphicsScene::clear() d->allItemsIgnoreHoverEvents = true; d->allItemsUseDefaultCursor = true; d->allItemsIgnoreTouchEvents = true; + d->focusOnTouch = true; } /*! @@ -3215,7 +3217,8 @@ void QGraphicsScene::update(const QRectF &rect) view->d_func()->updateRectF(rect); } } else { - d->updatedRects << rect; + if (!d->updatedRects.contains(rect)) + d->updatedRects << rect; } } @@ -4331,7 +4334,8 @@ static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion & pix->fill(Qt::transparent); pixmapPainter.begin(pix); } else { - subPix = QPixmap(br.size()); + subPix = QPixmap(br.size() * pix->devicePixelRatio()); + subPix.setDevicePixelRatio(pix->devicePixelRatio()); subPix.fill(Qt::transparent); pixmapPainter.begin(&subPix); pixmapPainter.translate(-br.topLeft()); @@ -4409,6 +4413,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte return; } + const qreal devicePixelRatio = painter->device()->devicePixelRatio(); const qreal oldPainterOpacity = painter->opacity(); qreal newPainterOpacity = oldPainterOpacity; QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0; @@ -4428,6 +4433,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Fetch the off-screen transparent buffer and exposed area info. QPixmapCache::Key pixmapKey; QPixmap pix; + bool pixmapFound; QGraphicsItemCache *itemCache = itemd->extraItemCache(); if (cacheMode == QGraphicsItem::ItemCoordinateCache) { @@ -4442,18 +4448,20 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Render using item coordinate cache mode. if (cacheMode == QGraphicsItem::ItemCoordinateCache) { QSize pixmapSize; - bool fixedCacheSize = false; + bool fixedCacheSize = itemCache->fixedSize.isValid(); QRect br = brect.toAlignedRect(); - if ((fixedCacheSize = itemCache->fixedSize.isValid())) { + if (fixedCacheSize) { pixmapSize = itemCache->fixedSize; } else { pixmapSize = br.size(); } + pixmapSize *= devicePixelRatio; + // Create or recreate the pixmap. int adjust = itemCache->fixedSize.isValid() ? 0 : 2; QSize adjustSize(adjust*2, adjust*2); - br.adjust(-adjust, -adjust, adjust, adjust); + br.adjust(-adjust / devicePixelRatio, -adjust / devicePixelRatio, adjust / devicePixelRatio, adjust / devicePixelRatio); if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) { pix = QPixmap(pixmapSize + adjustSize); itemCache->boundingRect = br; @@ -4476,7 +4484,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Fit the item's bounding rect into the pixmap's coordinates. QTransform itemToPixmap; if (fixedCacheSize) { - const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height()); + const QPointF scale((pixmapSize.width() / devicePixelRatio) / brect.width(), + (pixmapSize.height() / devicePixelRatio) / brect.height()); itemToPixmap.scale(scale.x(), scale.y()); } itemToPixmap.translate(-br.x(), -br.y()); @@ -4498,6 +4507,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte styleOptionTmp.exposedRect = exposedRect; // Render. + pix.setDevicePixelRatio(devicePixelRatio); _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), &styleOptionTmp, painterStateProtection); @@ -4595,21 +4605,22 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Copy / "scroll" the old pixmap onto the new ole and calculate // scrolled exposure. - if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) { + if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size() / devicePixelRatio) { QPoint diff = newCacheIndent - deviceData->cacheIndent; - QPixmap newPix(deviceRect.size()); + QPixmap newPix(deviceRect.size() * devicePixelRatio); // ### Investigate removing this fill (test with Plasma and // graphicssystem raster). newPix.fill(Qt::transparent); if (!pix.isNull()) { + newPix.setDevicePixelRatio(devicePixelRatio); QPainter newPixPainter(&newPix); newPixPainter.drawPixmap(-diff, pix); newPixPainter.end(); } QRegion exposed; - exposed += newPix.rect(); + exposed += QRect(QPoint(0,0), newPix.size() / devicePixelRatio); if (!pix.isNull()) - exposed -= QRect(-diff, pix.size()); + exposed -= QRect(-diff, pix.size() / devicePixelRatio); scrollExposure = exposed; pix = newPix; @@ -4621,9 +4632,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte deviceData->cacheIndent = QPoint(); // Auto-adjust the pixmap size. - if (deviceRect.size() != pix.size()) { + if (deviceRect.size() != pix.size() / devicePixelRatio) { // exposed needs to cover the whole pixmap - pix = QPixmap(deviceRect.size()); + pix = QPixmap(deviceRect.size() * devicePixelRatio); pixModified = true; itemCache->allExposed = true; itemCache->exposed.clear(); @@ -4667,6 +4678,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1); // Render the exposed areas. + pix.setDevicePixelRatio(devicePixelRatio); _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), &styleOptionTmp, painterStateProtection); @@ -5844,6 +5856,41 @@ void QGraphicsScene::setMinimumRenderSize(qreal minSize) update(); } +/*! + \property QGraphicsScene::focusOnTouch + \since 5.12 + \brief whether items gain focus when receiving a \e {touch begin} event. + + The usual behavior is to transfer focus only when an item is clicked. Often + a tap on a touchpad is interpreted as equivalent to a mouse click by the + operating system, generating a synthesized click event in response. However, + at least on macOS you can configure this behavior. + + By default, QGraphicsScene also transfers focus when you touch on a trackpad + or similar. If the operating system is configured to not generate a + synthetic mouse click on tapping the trackpad, this is surprising. If the + operating system does generate synthetic mouse clicks on tapping the + trackpad, the focus transfer on starting a touch gesture is unnecessary. + + With focusOnTouch switched off, QGraphicsScene behaves as one would expect + on macOS. + + The default value is \c true, ensuring that the default behavior is just as + in Qt versions prior to 5.12. Set to \c false to prevent touch events from + triggering focus changes. +*/ +bool QGraphicsScene::focusOnTouch() const +{ + Q_D(const QGraphicsScene); + return d->focusOnTouch; +} + +void QGraphicsScene::setFocusOnTouch(bool enabled) +{ + Q_D(QGraphicsScene); + d->focusOnTouch = enabled; +} + void QGraphicsScenePrivate::addView(QGraphicsView *view) { views << view; @@ -6023,39 +6070,41 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve { Q_Q(QGraphicsScene); - if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.constFirst() != origin) { - const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first(); - cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(), - firstTouchPoint.scenePos(), - static_cast<QWidget *>(touchEvent->target())); - } + if (focusOnTouch) { + if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.constFirst() != origin) { + const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first(); + cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(), + firstTouchPoint.scenePos(), + static_cast<QWidget *>(touchEvent->target())); + } - // Set focus on the topmost enabled item that can take focus. - bool setFocus = false; + // Set focus on the topmost enabled item that can take focus. + bool setFocus = false; - foreach (QGraphicsItem *item, cachedItemsUnderMouse) { - if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { - if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { + foreach (QGraphicsItem *item, cachedItemsUnderMouse) { + if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { + if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { + setFocus = true; + if (item != q->focusItem()) + q->setFocusItem(item, Qt::MouseFocusReason); + break; + } + } + if (item->isPanel()) + break; + if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) + break; + if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) { + // Make sure we don't clear focus. setFocus = true; - if (item != q->focusItem()) - q->setFocusItem(item, Qt::MouseFocusReason); break; } } - if (item->isPanel()) - break; - if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) - break; - if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) { - // Make sure we don't clear focus. - setFocus = true; - break; - } - } - // If nobody could take focus, clear it. - if (!stickyFocus && !setFocus) - q->setFocusItem(0, Qt::MouseFocusReason); + // If nobody could take focus, clear it. + if (!stickyFocus && !setFocus) + q->setFocusItem(0, Qt::MouseFocusReason); + } bool res = false; bool eventAccepted = touchEvent->isAccepted(); @@ -6391,7 +6440,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) ev.setWidget(event->widget()); sendEvent(receiver.data(), &ev); QSet<QGesture *> ignoredGestures; - foreach (QGesture *g, gestures) { + for (QGesture *g : qAsConst(gestures)) { if (!ev.isAccepted() && !ev.isAccepted(g)) { // if the gesture was ignored by its target, we will update the // targetItems list with a possible target items (items that diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h index 8efbcd273e..287e551db7 100644 --- a/src/widgets/graphicsview/qgraphicsscene.h +++ b/src/widgets/graphicsview/qgraphicsscene.h @@ -106,6 +106,7 @@ class Q_WIDGETS_EXPORT QGraphicsScene : public QObject Q_PROPERTY(bool sortCacheEnabled READ isSortCacheEnabled WRITE setSortCacheEnabled) Q_PROPERTY(bool stickyFocus READ stickyFocus WRITE setStickyFocus) Q_PROPERTY(qreal minimumRenderSize READ minimumRenderSize WRITE setMinimumRenderSize) + Q_PROPERTY(bool focusOnTouch READ focusOnTouch WRITE setFocusOnTouch) public: enum ItemIndexMethod { @@ -253,6 +254,9 @@ public: qreal minimumRenderSize() const; void setMinimumRenderSize(qreal minSize); + bool focusOnTouch() const; + void setFocusOnTouch(bool enabled); + public Q_SLOTS: void update(const QRectF &rect = QRectF()); void invalidate(const QRectF &rect = QRectF(), SceneLayers layers = AllLayers); diff --git a/src/widgets/graphicsview/qgraphicsscene_p.h b/src/widgets/graphicsview/qgraphicsscene_p.h index 2f5d7c54bb..a2d13436fc 100644 --- a/src/widgets/graphicsview/qgraphicsscene_p.h +++ b/src/widgets/graphicsview/qgraphicsscene_p.h @@ -114,7 +114,8 @@ public: quint32 painterStateProtection : 1; quint32 sortCacheEnabled : 1; // for compatibility quint32 allItemsIgnoreTouchEvents : 1; - quint32 padding : 15; + quint32 focusOnTouch : 1; + quint32 padding : 14; qreal minimumRenderSize; diff --git a/src/widgets/graphicsview/qgraphicssceneevent.cpp b/src/widgets/graphicsview/qgraphicssceneevent.cpp index f7f09486e9..398ef1aaf5 100644 --- a/src/widgets/graphicsview/qgraphicssceneevent.cpp +++ b/src/widgets/graphicsview/qgraphicssceneevent.cpp @@ -259,8 +259,9 @@ #include "qgraphicssceneevent.h" -#ifndef QT_NO_DEBUG +#ifndef QT_NO_DEBUG_STREAM #include <QtCore/qdebug.h> +#include <private/qdebug_p.h> #endif #include <QtCore/qmap.h> #include <QtCore/qpoint.h> @@ -1730,4 +1731,99 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos) d->newPos = pos; } +#ifndef QT_NO_DEBUG_STREAM +template <class Event> +static inline void formatPositions(QDebug &debug, const Event *event) +{ + debug << ", pos="; + QtDebugUtils::formatQPoint(debug, event->pos()); + debug << ", scenePos="; + QtDebugUtils::formatQPoint(debug, event->scenePos()); + debug << ", screenPos="; + QtDebugUtils::formatQPoint(debug, event->screenPos()); +} + +QDebug operator<<(QDebug debug, const QGraphicsSceneEvent *event) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + if (!event) { + debug << "QGraphicsSceneEvent(0)"; + return debug; + } + + const QEvent::Type type = event->type(); + switch (type) { + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseDoubleClick: { + const QGraphicsSceneMouseEvent *me = static_cast<const QGraphicsSceneMouseEvent *>(event); + const Qt::MouseButton button = me->button(); + const Qt::MouseButtons buttons = me->buttons(); + debug << "QGraphicsSceneMouseEvent("; + QtDebugUtils::formatQEnum(debug, type); + if (type != QEvent::GraphicsSceneMouseMove) { + debug << ", "; + QtDebugUtils::formatQEnum(debug, button); + } + if (buttons && button != buttons) { + debug << ", buttons="; + QtDebugUtils::formatQFlags(debug, buttons); + } + QtDebugUtils::formatNonNullQFlags(debug, ", ", me->modifiers()); + formatPositions(debug, me); + QtDebugUtils::formatNonNullQEnum(debug, ", ", me->source()); + QtDebugUtils::formatNonNullQFlags(debug, ", flags=", me->flags()); + debug << ')'; + } + break; + case QEvent::GraphicsSceneContextMenu: { + const QGraphicsSceneContextMenuEvent *ce = static_cast<const QGraphicsSceneContextMenuEvent *>(event); + debug << "QGraphicsSceneContextMenuEvent(reason=" << ce->reason(); + QtDebugUtils::formatNonNullQFlags(debug, ", ", ce->modifiers()); + formatPositions(debug, ce); + debug << ')'; + } + break; + case QEvent::GraphicsSceneHoverEnter: + case QEvent::GraphicsSceneHoverMove: + case QEvent::GraphicsSceneHoverLeave: + debug << "QGraphicsSceneHoverEvent("; + formatPositions(debug, static_cast<const QGraphicsSceneHoverEvent *>(event)); + debug << ')'; + break; + case QEvent::GraphicsSceneHelp: + break; + case QEvent::GraphicsSceneDragEnter: + case QEvent::GraphicsSceneDragMove: + case QEvent::GraphicsSceneDragLeave: + case QEvent::GraphicsSceneDrop: { + const QGraphicsSceneDragDropEvent *de = static_cast<const QGraphicsSceneDragDropEvent *>(event); + debug << "QGraphicsSceneDragDropEvent(proposedAction="; + QtDebugUtils::formatQEnum(debug, de->proposedAction()); + debug << ", possibleActions="; + QtDebugUtils::formatQFlags(debug, de->possibleActions()); + debug << ", source=" << de->source(); + QtDebugUtils::formatNonNullQFlags(debug, ", buttons=", de->buttons()); + QtDebugUtils::formatNonNullQFlags(debug, ", ", de->modifiers()); + formatPositions(debug, de); + } + break; + case QEvent::GraphicsSceneWheel: { + const QGraphicsSceneWheelEvent *we = static_cast<const QGraphicsSceneWheelEvent *>(event); + debug << "QGraphicsSceneWheelEvent("; + QtDebugUtils::formatNonNullQFlags(debug, ", buttons=", we->buttons()); + QtDebugUtils::formatNonNullQFlags(debug, ", ", we->modifiers()); + formatPositions(debug, we); + debug << ')'; + } + break; + default: + break; + } + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + QT_END_NAMESPACE diff --git a/src/widgets/graphicsview/qgraphicssceneevent.h b/src/widgets/graphicsview/qgraphicssceneevent.h index 77b53e401d..9d940be2c0 100644 --- a/src/widgets/graphicsview/qgraphicssceneevent.h +++ b/src/widgets/graphicsview/qgraphicssceneevent.h @@ -320,6 +320,10 @@ public: void setNewPos(const QPointF &pos); }; +#ifndef QT_NO_DEBUG_STREAM +Q_WIDGETS_EXPORT QDebug operator<<(QDebug, const QGraphicsSceneEvent *); +#endif + QT_END_NAMESPACE #endif diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index f79ee41e10..24647dd74c 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -2703,7 +2703,7 @@ void QGraphicsView::updateScene(const QList<QRectF> &rects) dirtyViewportRects << xrect; } - foreach (const QRect &rect, dirtyViewportRects) { + for (const QRect &rect : qAsConst(dirtyViewportRects)) { // Add the exposed rect to the update region. In rect update // mode, we only count the bounding rect of items. if (!boundingRectUpdate) { @@ -3483,7 +3483,9 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Recreate the background pixmap, and flag the whole background as // exposed. if (d->mustResizeBackgroundPixmap) { - d->backgroundPixmap = QPixmap(viewport()->size()); + const qreal dpr = d->viewport->devicePixelRatioF(); + d->backgroundPixmap = QPixmap(viewport()->size() * dpr); + d->backgroundPixmap.setDevicePixelRatio(dpr); QBrush bgBrush = viewport()->palette().brush(viewport()->backgroundRole()); if (!bgBrush.isOpaque()) d->backgroundPixmap.fill(Qt::transparent); @@ -3679,14 +3681,20 @@ void QGraphicsView::scrollContentsBy(int dx, int dy) && X11->use_xrender #endif ) { + // Below, QPixmap::scroll() works in device pixels, while the delta values + // and backgroundPixmapExposed are in device independent pixels. + const qreal dpr = d->backgroundPixmap.devicePixelRatio(); + const qreal inverseDpr = qreal(1) / dpr; + // Scroll the background pixmap QRegion exposed; if (!d->backgroundPixmap.isNull()) - d->backgroundPixmap.scroll(dx, dy, d->backgroundPixmap.rect(), &exposed); + d->backgroundPixmap.scroll(dx * dpr, dy * dpr, d->backgroundPixmap.rect(), &exposed); // Invalidate the background pixmap d->backgroundPixmapExposed.translate(dx, dy); - d->backgroundPixmapExposed += exposed; + const QRegion exposedScaled = QTransform::fromScale(inverseDpr, inverseDpr).map(exposed); + d->backgroundPixmapExposed += exposedScaled; } // Always replay on scroll. diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index c9f321c3f6..7bc0ece4b3 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -599,18 +599,21 @@ QString QAbstractItemDelegatePrivate::textForRole(Qt::ItemDataRole role, const Q case QVariant::DateTime: text = locale.toString(value.toDateTime(), formatType); break; - default: { - if (value.canConvert<QJsonValue>()) { - const QJsonValue val = value.toJsonValue(); - if (val.isBool()) - text = QVariant(val.toBool()).toString(); - else if (val.isDouble()) - text = locale.toString(val.toDouble(), 'g', precision); - else if (val.isString()) - text = val.toString(); - } else { - text = value.toString(); + case QVariant::Type(QMetaType::QJsonValue): { + const QJsonValue val = value.toJsonValue(); + if (val.isBool()) { + text = QVariant(val.toBool()).toString(); + break; + } + if (val.isDouble()) { + text = locale.toString(val.toDouble(), 'g', precision); + break; } + // val is a string (or null) here + Q_FALLTHROUGH(); + } + default: { + text = value.toString(); if (role == Qt::DisplayRole) text.replace(QLatin1Char('\n'), QChar::LineSeparator); break; diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 2d30b2650a..7bfa51337d 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -1853,11 +1853,13 @@ bool QHeaderView::restoreState(const QByteArray &state) */ void QHeaderView::reset() { + Q_D(QHeaderView); QAbstractItemView::reset(); // it would be correct to call clear, but some apps rely // on the header keeping the sections, even after calling reset //d->clear(); initializeSections(); + d->invalidateCachedSizeHint(); } /*! @@ -2868,6 +2870,7 @@ bool QHeaderView::viewportEvent(QEvent *e) } return true; } #endif // QT_CONFIG(statustip) + case QEvent::Resize: case QEvent::FontChange: case QEvent::StyleChange: d->invalidateCachedSizeHint(); @@ -2962,8 +2965,10 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical margin += style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this) + style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); - if (d->textElideMode != Qt::ElideNone) - opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin); + if (d->textElideMode != Qt::ElideNone) { + const QRect textRect = style()->subElementRect(QStyle::SE_HeaderLabel, &opt, this); + opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode, textRect.width() - margin); + } QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation, Qt::ForegroundRole); @@ -3363,7 +3368,9 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position) sectionIndicator->resize(w, h); #endif - QPixmap pm(w, h); + const qreal pixmapDevicePixelRatio = q->devicePixelRatioF(); + QPixmap pm(QSize(w, h) * pixmapDevicePixelRatio); + pm.setDevicePixelRatio(pixmapDevicePixelRatio); pm.fill(QColor(0, 0, 0, 45)); QRect rect(0, 0, w, h); @@ -3828,6 +3835,7 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize) void QHeaderViewPrivate::setDefaultSectionSize(int size) { Q_Q(QHeaderView); + size = qBound(q->minimumSectionSize(), size, q->maximumSectionSize()); executePostedLayout(); invalidateCachedSizeHint(); defaultSectionSize = size; @@ -4083,7 +4091,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) } int sectionItemsLengthTotal = 0; - foreach (const SectionItem §ion, newSectionItems) + for (const SectionItem §ion : qAsConst(newSectionItems)) sectionItemsLengthTotal += section.size; if (sectionItemsLengthTotal != lengthIn) return false; diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index 91122283a4..dff4cc4593 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -103,7 +103,10 @@ public: QItemEditorFactory *f; bool clipPainting; - QRect textLayoutBounds(const QStyleOptionViewItem &options) const; + QRect displayRect(const QModelIndex &index, const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const; + QRect textLayoutBounds(const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const; QSizeF doTextLayout(int lineWidth) const; mutable QTextLayout textLayout; mutable QTextOption textOption; @@ -121,21 +124,53 @@ public: } tmp; }; -QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItem &option) const +QRect QItemDelegatePrivate::displayRect(const QModelIndex &index, const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const +{ + Q_Q(const QItemDelegate); + const QVariant value = index.data(Qt::DisplayRole); + if (!value.isValid() || value.isNull()) + return QRect(); + + const QString text = valueToText(value, option); + const QVariant fontVal = index.data(Qt::FontRole); + const QFont fnt = qvariant_cast<QFont>(fontVal).resolve(option.font); + return q->textRectangle(nullptr, + textLayoutBounds(option, decorationRect, checkRect), + fnt, text); +} + +// similar to QCommonStylePrivate::viewItemSize(Qt::DisplayRole) +QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const { QRect rect = option.rect; + const QWidget *w = widget(option); + QStyle *style = w ? w->style() : QApplication::style(); const bool wrapText = option.features & QStyleOptionViewItem::WrapText; + // see QItemDelegate::drawDisplay + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, w) + 1; switch (option.decorationPosition) { case QStyleOptionViewItem::Left: case QStyleOptionViewItem::Right: - rect.setWidth(wrapText && rect.isValid() ? rect.width() : (QFIXED_MAX)); + rect.setWidth(wrapText && rect.isValid() ? rect.width() - 2 * textMargin : (QFIXED_MAX)); break; case QStyleOptionViewItem::Top: case QStyleOptionViewItem::Bottom: - rect.setWidth(wrapText ? option.decorationSize.width() : (QFIXED_MAX)); + rect.setWidth(wrapText ? option.decorationSize.width() - 2 * textMargin : (QFIXED_MAX)); break; } + if (wrapText) { + if (!decorationRect.isNull()) + rect.setWidth(rect.width() - decorationRect.width() - 2 * textMargin); + if (!checkRect.isNull()) + rect.setWidth(rect.width() - checkRect.width() - 2 * textMargin); + // adjust height to be sure that the text fits + const QSizeF size = doTextLayout(rect.width()); + rect.setHeight(qCeil(size.height())); + } + return rect; } @@ -395,14 +430,6 @@ void QItemDelegate::paint(QPainter *painter, decorationRect = QRect(); } - QString text; - QRect displayRect; - value = index.data(Qt::DisplayRole); - if (value.isValid() && !value.isNull()) { - text = d->valueToText(value, opt); - displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text); - } - QRect checkRect; Qt::CheckState checkState = Qt::Unchecked; value = index.data(Qt::CheckStateRole); @@ -411,6 +438,14 @@ void QItemDelegate::paint(QPainter *painter, checkRect = doCheck(opt, opt.rect, value); } + QString text; + QRect displayRect; + value = index.data(Qt::DisplayRole); + if (value.isValid() && !value.isNull()) { + text = d->valueToText(value, opt); + displayRect = d->displayRect(index, opt, decorationRect, checkRect); + } + // do the layout doLayout(opt, &checkRect, &decorationRect, &displayRect, false); @@ -440,12 +475,13 @@ void QItemDelegate::paint(QPainter *painter, QSize QItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_D(const QItemDelegate); QVariant value = index.data(Qt::SizeHintRole); if (value.isValid()) return qvariant_cast<QSize>(value); QRect decorationRect = rect(option, index, Qt::DecorationRole); - QRect displayRect = rect(option, index, Qt::DisplayRole); QRect checkRect = rect(option, index, Qt::CheckStateRole); + QRect displayRect = d->displayRect(index, option, decorationRect, checkRect); doLayout(option, &checkRect, &decorationRect, &displayRect, true); @@ -1000,8 +1036,8 @@ QPixmap *QItemDelegate::selected(const QPixmap &pixmap, const QPalette &palette, /*! \internal + Only used (and usable) for Qt::DecorationRole and Qt::CheckStateRole */ - QRect QItemDelegate::rect(const QStyleOptionViewItem &option, const QModelIndex &index, int role) const { @@ -1032,7 +1068,9 @@ QRect QItemDelegate::rect(const QStyleOptionViewItem &option, const QString text = d->valueToText(value, option); value = index.data(Qt::FontRole); QFont fnt = qvariant_cast<QFont>(value).resolve(option.font); - return textRectangle(0, d->textLayoutBounds(option), fnt, text); } + return textRectangle(nullptr, + d->textLayoutBounds(option, QRect(), QRect()), + fnt, text); } } } return QRect(); diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index a7174a92e8..e5769940d4 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1631,6 +1631,32 @@ bool QListView::isSelectionRectVisible() const } /*! + \property QListView::itemAlignment + \brief the alignment of each item in its cell + \since 5.12 + + This is only supported in ListMode with TopToBottom flow + and with wrapping enabled. + The default alignment is 0, which means that an item fills + its cell entirely. +*/ +void QListView::setItemAlignment(Qt::Alignment alignment) +{ + Q_D(QListView); + if (d->itemAlignment == alignment) + return; + d->itemAlignment = alignment; + if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping()) + d->doDelayedItemsLayout(); +} + +Qt::Alignment QListView::itemAlignment() const +{ + Q_D(const QListView); + return d->itemAlignment; +} + +/*! \reimp */ bool QListView::event(QEvent *e) @@ -1656,7 +1682,8 @@ QListViewPrivate::QListViewPrivate() column(0), uniformItemSizes(false), batchSize(100), - showElasticBand(false) + showElasticBand(false), + itemAlignment(Qt::Alignment()) { } @@ -2366,6 +2393,7 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c options.rect.setSize(contentsSize); QSize size = (uniformItemSizes() && cachedItemSize().isValid()) ? cachedItemSize() : itemSize(options, index); + QSize cellSize = size; QPoint pos; if (flow() == QListView::LeftToRight) { @@ -2378,12 +2406,22 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c int right = (segment + 1 >= segmentPositions.count() ? contentsSize.width() : segmentPositions.at(segment + 1)); - size.setWidth(right - pos.x()); + cellSize.setWidth(right - pos.x()); } else { // make the items as wide as the viewport - size.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing())); + cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing())); } } + if (dd->itemAlignment & Qt::AlignHorizontal_Mask) { + size.setWidth(qMin(size.width(), cellSize.width())); + if (dd->itemAlignment & Qt::AlignRight) + pos.setX(pos.x() + cellSize.width() - size.width()); + if (dd->itemAlignment & Qt::AlignHCenter) + pos.setX(pos.x() + (cellSize.width() - size.width()) / 2); + } else { + size.setWidth(cellSize.width()); + } + return QListViewItem(QRect(pos, size), index.row()); } @@ -2562,8 +2600,18 @@ QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const if (isHidden(row)) continue; QModelIndex index = modelIndex(row); - if (index.isValid()) - ret += index; + if (index.isValid()) { + if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) { + ret += index; + } else { + const auto viewItem = indexToListViewItem(index); + const int iw = viewItem.width(); + const int startPos = qMax(segStartPosition, segmentPositions.at(seg)); + const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition); + if (endPos >= viewItem.x && startPos < viewItem.x + iw) + ret += index; + } + } #if 0 // for debugging else qWarning("intersectingSet: row %d was invalid", row); @@ -2603,7 +2651,7 @@ int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wr positions = segmentPositions; else if (!flowPositions.isEmpty()) { positions.reserve(scrollValueMap.size()); - foreach (int itemShown, scrollValueMap) + for (int itemShown : scrollValueMap) positions.append(flowPositions.at(itemShown)); } if (positions.isEmpty() || bounds <= length) @@ -2767,6 +2815,8 @@ bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions) drag->setHotSpot(dd->pressedPosition - rect.topLeft()); Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction); draggedItems.clear(); + // for internal moves the action was set to Qt::CopyAction in + // filterDropEvent() to avoid the deletion here if (action == Qt::MoveAction) dd->clearOrRemove(); } @@ -2784,7 +2834,7 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e) if (qq->acceptDrops()) { const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled; const QVector<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1))); - foreach (const QModelIndex &index, dropIndices) + for (const QModelIndex &index : dropIndices) if ((index.flags() & dropableFlags) == dropableFlags) return false; } @@ -2803,6 +2853,8 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e) dd->stopAutoScroll(); draggedItems.clear(); dd->emitIndexesMoved(indexes); + // do not delete item on internal move, see filterStartDrag() + e->setDropAction(Qt::CopyAction); e->accept(); // we have handled the event // if the size has not grown, we need to check if it has shrinked if (contentsSize != contents) { diff --git a/src/widgets/itemviews/qlistview.h b/src/widgets/itemviews/qlistview.h index 9fc4035999..8a5d5e02ae 100644 --- a/src/widgets/itemviews/qlistview.h +++ b/src/widgets/itemviews/qlistview.h @@ -65,6 +65,7 @@ class Q_WIDGETS_EXPORT QListView : public QAbstractItemView Q_PROPERTY(int batchSize READ batchSize WRITE setBatchSize) Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) Q_PROPERTY(bool selectionRectVisible READ isSelectionRectVisible WRITE setSelectionRectVisible) + Q_PROPERTY(Qt::Alignment itemAlignment READ itemAlignment WRITE setItemAlignment) public: enum Movement { Static, Free, Snap }; @@ -125,6 +126,9 @@ public: void setSelectionRectVisible(bool show); bool isSelectionRectVisible() const; + void setItemAlignment(Qt::Alignment alignment); + Qt::Alignment itemAlignment() const; + QRect visualRect(const QModelIndex &index) const override; void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; QModelIndex indexAt(const QPoint &p) const override; diff --git a/src/widgets/itemviews/qlistview_p.h b/src/widgets/itemviews/qlistview_p.h index ca947292e3..181386d4d0 100644 --- a/src/widgets/itemviews/qlistview_p.h +++ b/src/widgets/itemviews/qlistview_p.h @@ -431,6 +431,8 @@ public: QRect elasticBand; bool showElasticBand; + + Qt::Alignment itemAlignment; }; // inline implementations diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index 4f1c7fe80a..72e0a67a64 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -48,9 +48,6 @@ QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug (?) -typedef bool(*LessThan)(const QPair<QListWidgetItem*,int>&,const QPair<QListWidgetItem*,int>&); - class QListWidgetMimeData : public QMimeData { Q_OBJECT @@ -301,7 +298,7 @@ void QListModel::sort(int column, Qt::SortOrder order) sorting[i].second = i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::sort(sorting.begin(), sorting.end(), compare); QModelIndexList fromIndexes; QModelIndexList toIndexes; @@ -338,7 +335,7 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en sorting[i].second = start + i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes = persistentIndexList(); @@ -1847,7 +1844,7 @@ QMimeData *QListWidget::mimeData(const QList<QListWidgetItem*> items) const // if non empty, it's called from the model's own mimeData if (cachedIndexes.isEmpty()) { cachedIndexes.reserve(items.count()); - foreach (QListWidgetItem *item, items) + for (QListWidgetItem *item : items) cachedIndexes << indexFromItem(item); QMimeData *result = d->listModel()->internalMimeData(); diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 1938fd8e92..9725a768de 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -74,7 +74,7 @@ void QSpanCollection::addSpan(QSpanCollection::Span *span) //the previouslist is the list of spans that sarts _before_ the row of the span. // and which may intersect this row. const SubIndex previousList = it_y.value(); - foreach(Span *s, previousList) { + for (Span *s : previousList) { //If a subspans intersect the row, we need to split it into subspans if(s->bottom() >= span->top()) sub_index.insert(-s->left(), s); @@ -798,6 +798,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, const QStyleOptionViewItem &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn) { + Q_Q(const QTableView); bool alternateBase = false; QRegion region = viewport->rect(); @@ -816,7 +817,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, visibleSpans = set.toList(); } - foreach (QSpanCollection::Span *span, visibleSpans) { + for (QSpanCollection::Span *span : qAsConst(visibleSpans)) { int row = span->top(); int col = span->left(); QModelIndex index = model->index(row, col, root); @@ -831,6 +832,18 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, alternateBase = alternatingColors && (span->top() & 1); opt.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase); drawCell(painter, opt, index); + if (showGrid) { + // adjust the clip rect to be able to paint the top & left grid lines + // if the headers are not visible, see paintEvent() + if (horizontalHeader->visualIndex(row) == 0) + rect.setTop(rect.top() + 1); + if (verticalHeader->visualIndex(row) == 0) { + if (q->isLeftToRight()) + rect.setLeft(rect.left() + 1); + else + rect.setRight(rect.right() - 1); + } + } region -= rect; for (int r = span->top(); r <= span->bottom(); ++r) { const int vr = visualRow(r); @@ -1163,7 +1176,6 @@ void QTableView::doItemsLayout() { Q_D(QTableView); QAbstractItemView::doItemsLayout(); - d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); if (!d->verticalHeader->updatesEnabled()) d->verticalHeader->setUpdatesEnabled(true); } @@ -1321,10 +1333,10 @@ void QTableView::scrollContentsBy(int dx, int dy) //we need to update the first line of the previous top item in the view //because it has the grid drawn if the header is invisible. //It is strictly related to what's done at then end of the paintEvent - if (dy > 0 && d->horizontalHeader->isHidden() && d->verticalScrollMode == ScrollPerItem) { + if (dy > 0 && d->horizontalHeader->isHidden()) { d->viewport->update(0, dy, d->viewport->width(), dy); } - if (dx > 0 && d->verticalHeader->isHidden() && d->horizontalScrollMode == ScrollPerItem) { + if (dx > 0 && d->verticalHeader->isHidden()) { d->viewport->update(dx, 0, dx, d->viewport->height()); } } @@ -1504,10 +1516,26 @@ void QTableView::paintEvent(QPaintEvent *event) //draw the top & left grid lines if the headers are not visible. //We do update this line when subsequent scroll happen (see scrollContentsBy) - if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem) - painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0); - if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem) - painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom()); + if (horizontalHeader->isHidden() && top == 0) { + const int row = verticalHeader->logicalIndex(top); + if (!verticalHeader->isSectionHidden(row)) { + const int rowY = rowViewportPosition(row) + offset.y(); + if (rowY == dirtyArea.top()) + painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY); + } + } + if (verticalHeader->isHidden() && left == 0) { + const int col = horizontalHeader->logicalIndex(left); + if (!horizontalHeader->isSectionHidden(col)) { + int colX = columnViewportPosition(col) + offset.x(); + if (!isLeftToRight()) + colX += columnWidth(left) - 1; + if (isLeftToRight() && colX == dirtyArea.left()) + painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); + if (!isLeftToRight() && colX == dirtyArea.right()) + painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); + } + } painter.setPen(old); } } @@ -1788,8 +1816,12 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi break; case MovePageUp: { int newRow = rowAt(visualRect(current).bottom() - d->viewport->height()); - if (newRow == -1) - newRow = d->logicalRow(0); + if (newRow == -1) { + int visualRow = 0; + while (visualRow < bottom && isRowHidden(d->logicalRow(visualRow))) + ++visualRow; + newRow = d->logicalRow(visualRow); + } return d->model->index(newRow, current.column(), d->root); } case MovePageDown: { @@ -2194,6 +2226,7 @@ void QTableView::updateGeometries() verticalScrollBar()->setRange(0, verticalLength - vsize.height()); verticalScrollBar()->d_func()->itemviewChangeSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2)); } + d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); d->geometryRecursionBlock = false; QAbstractItemView::updateGeometries(); diff --git a/src/widgets/itemviews/qtablewidget.cpp b/src/widgets/itemviews/qtablewidget.cpp index 9d5a2aa1bd..2d539e10ba 100644 --- a/src/widgets/itemviews/qtablewidget.cpp +++ b/src/widgets/itemviews/qtablewidget.cpp @@ -225,7 +225,7 @@ QTableWidgetItem *QTableModel::takeItem(int row, int column) itm->view = 0; itm->d->id = -1; tableItems[i] = 0; - QModelIndex ind = index(itm); + const QModelIndex ind = index(row, column); emit dataChanged(ind, ind); } return itm; @@ -453,17 +453,20 @@ bool QTableModel::setItemData(const QModelIndex &index, const QMap<int, QVariant QTableWidget *view = qobject_cast<QTableWidget*>(QObject::parent()); QTableWidgetItem *itm = item(index); if (itm) { - itm->view = 0; // prohibits item from calling itemChanged() - bool changed = false; + itm->view = nullptr; // prohibits item from calling itemChanged() + QVector<int> rolesVec; for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it) { - if (itm->data(it.key()) != it.value()) { - itm->setData(it.key(), it.value()); - changed = true; + const int role = (it.key() == Qt::EditRole ? Qt::DisplayRole : it.key()); + if (itm->data(role) != it.value()) { + itm->setData(role, it.value()); + rolesVec += role; + if (role == Qt::DisplayRole) + rolesVec += Qt::EditRole; } } itm->view = view; - if (changed) - itemChanged(itm); + if (!rolesVec.isEmpty()) + itemChanged(itm, rolesVec); return true; } @@ -506,7 +509,7 @@ void QTableModel::sort(int column, Qt::SortOrder order) unsortable.append(row); } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sortable.begin(), sortable.end(), compare); QVector<QTableWidgetItem*> sorted_table(tableItems.count()); @@ -558,7 +561,7 @@ void QTableModel::ensureSorted(int column, Qt::SortOrder order, sorting.append(QPair<QTableWidgetItem*,int>(itm, row)); } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes, newPersistentIndexes; QVector<QTableWidgetItem*> newTable = tableItems; @@ -771,7 +774,7 @@ void QTableModel::clearContents() endResetModel(); } -void QTableModel::itemChanged(QTableWidgetItem *item) +void QTableModel::itemChanged(QTableWidgetItem *item, const QVector<int> &roles) { if (!item) return; @@ -787,7 +790,7 @@ void QTableModel::itemChanged(QTableWidgetItem *item) } else { QModelIndex idx = index(item); if (idx.isValid()) - emit dataChanged(idx, idx); + emit dataChanged(idx, idx, roles); } } @@ -1386,8 +1389,13 @@ void QTableWidgetItem::setData(int role, const QVariant &value) } if (!found) values.append(QWidgetItemData(role, value)); - if (QTableModel *model = (view ? qobject_cast<QTableModel*>(view->model()) : 0)) - model->itemChanged(this); + if (QTableModel *model = (view ? qobject_cast<QTableModel*>(view->model()) : nullptr)) + { + const QVector<int> roles((role == Qt::DisplayRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); + model->itemChanged(this, roles); + } } /*! @@ -2595,7 +2603,7 @@ QMimeData *QTableWidget::mimeData(const QList<QTableWidgetItem*> items) const // if non empty, it's called from the model's own mimeData if (cachedIndexes.isEmpty()) { cachedIndexes.reserve(items.count()); - foreach (QTableWidgetItem *item, items) + for (QTableWidgetItem *item : items) cachedIndexes << indexFromItem(item); QMimeData *result = d->tableModel()->internalMimeData(); diff --git a/src/widgets/itemviews/qtablewidget.h b/src/widgets/itemviews/qtablewidget.h index 7322e3aed7..9de27d164f 100644 --- a/src/widgets/itemviews/qtablewidget.h +++ b/src/widgets/itemviews/qtablewidget.h @@ -302,6 +302,7 @@ Q_SIGNALS: void itemActivated(QTableWidgetItem *item); void itemEntered(QTableWidgetItem *item); + // ### Qt 6: add changed roles void itemChanged(QTableWidgetItem *item); void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous); diff --git a/src/widgets/itemviews/qtablewidget_p.h b/src/widgets/itemviews/qtablewidget_p.h index 6412477be0..9899272fce 100644 --- a/src/widgets/itemviews/qtablewidget_p.h +++ b/src/widgets/itemviews/qtablewidget_p.h @@ -62,9 +62,6 @@ QT_REQUIRE_CONFIG(tablewidget); QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug -typedef bool(*LessThan)(const QPair<QTableWidgetItem*,int>&,const QPair<QTableWidgetItem*,int>&); - class QTableWidgetMimeData : public QMimeData { Q_OBJECT @@ -160,7 +157,7 @@ public: void clear(); void clearContents(); - void itemChanged(QTableWidgetItem *item); + void itemChanged(QTableWidgetItem *item, const QVector<int> &roles = QVector<int>()); QTableWidgetItem *createItem() const; const QTableWidgetItem *itemPrototype() const; diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 7f99a2c6cb..f3647f656a 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -131,11 +131,12 @@ QT_BEGIN_NAMESPACE of the sibling that follows the parent. \row \li Left \li Hides the children of the current item (if present) by collapsing a branch. - \row \li Minus \li Same as LeftArrow. + \row \li Minus \li Same as Left. \row \li Right \li Reveals the children of the current item (if present) by expanding a branch. - \row \li Plus \li Same as RightArrow. - \row \li Asterisk \li Expands all children of the current item (if present). + \row \li Plus \li Same as Right. + \row \li Asterisk \li Expands the current item and all its children + (if present). \row \li PageUp \li Moves the cursor up one page. \row \li PageDown \li Moves the cursor down one page. \row \li Home \li Moves the cursor to an item in the same column of the first @@ -632,11 +633,8 @@ bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const Q_D(const QTreeView); if (d->spanningIndexes.isEmpty() || !d->model) return false; - QModelIndex index = d->model->index(row, 0, parent); - for (int i = 0; i < d->spanningIndexes.count(); ++i) - if (d->spanningIndexes.at(i) == index) - return true; - return false; + const QModelIndex index = d->model->index(row, 0, parent); + return d->spanningIndexes.contains(index); } /*! @@ -653,20 +651,14 @@ void QTreeView::setFirstColumnSpanned(int row, const QModelIndex &parent, bool s Q_D(QTreeView); if (!d->model) return; - QModelIndex index = d->model->index(row, 0, parent); + const QModelIndex index = d->model->index(row, 0, parent); if (!index.isValid()) return; - if (span) { - QPersistentModelIndex persistent(index); - if (!d->spanningIndexes.contains(persistent)) - d->spanningIndexes.append(persistent); - } else { - QPersistentModelIndex persistent(index); - int i = d->spanningIndexes.indexOf(persistent); - if (i >= 0) - d->spanningIndexes.remove(i); - } + if (span) + d->spanningIndexes.insert(index); + else + d->spanningIndexes.remove(index); d->executePostedLayout(); int i = d->viewIndex(index); @@ -1420,7 +1412,7 @@ QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList if (spanningIndexes.isEmpty()) return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r); QModelIndexList list; - foreach (const QModelIndex &idx, indexes) { + for (const QModelIndex &idx : indexes) { if (idx.column() > 0 && q->isFirstColumnSpanned(idx.row(), idx.parent())) continue; list << idx; @@ -2000,19 +1992,21 @@ void QTreeView::keyPressEvent(QKeyEvent *event) if (d->isIndexValid(current) && d->model && d->itemsExpandable) { switch (event->key()) { case Qt::Key_Asterisk: { + // do layouting only once after expanding is done + d->doDelayedItemsLayout(); QStack<QModelIndex> parents; parents.push(current); - while (!parents.isEmpty()) { - QModelIndex parent = parents.pop(); - for (int row = 0; row < d->model->rowCount(parent); ++row) { - QModelIndex child = d->model->index(row, 0, parent); - if (!d->isIndexValid(child)) - break; - parents.push(child); - expand(child); - } + while (!parents.isEmpty()) { + QModelIndex parent = parents.pop(); + for (int row = 0; row < d->model->rowCount(parent); ++row) { + QModelIndex child = d->model->index(row, 0, parent); + if (!d->isIndexValid(child)) + break; + parents.push(child); + expand(child); } - expand(current); + } + expand(current); break; } case Qt::Key_Plus: expand(current); @@ -2495,7 +2489,6 @@ void QTreeView::scrollContentsBy(int dx, int dy) int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy) int currentViewIndex = currentScrollbarValue; // the first visible item int previousViewIndex = previousScrollbarValue; - const QVector<QTreeViewItem> viewItems = d->viewItems; dy = 0; if (previousViewIndex < currentViewIndex) { // scrolling down for (int i = previousViewIndex; i < currentViewIndex; ++i) { @@ -3732,9 +3725,14 @@ void QTreeViewPrivate::updateScrollBars() int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const { + Q_Q(const QTreeView); executePostedLayout(); - int x = pos.x(); - int column = header->logicalIndexAt(x); + bool spanned = false; + if (!spanningIndexes.isEmpty()) { + const QModelIndex index = q->indexAt(pos); + spanned = q->isFirstColumnSpanned(index.row(), index.parent()); + } + const int column = spanned ? 0 : header->logicalIndexAt(pos.x()); if (!isTreePosition(column)) return -1; // no logical index at x diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h index 061bd1fc57..0a0e7aae87 100644 --- a/src/widgets/itemviews/qtreeview_p.h +++ b/src/widgets/itemviews/qtreeview_p.h @@ -249,7 +249,7 @@ public: void updateIndentationFromStyle(); // used for spanning rows - QVector<QPersistentModelIndex> spanningIndexes; + QSet<QPersistentModelIndex> spanningIndexes; // used for updating resized columns int columnResizeTimerID; diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp index 654c241079..a0af27115d 100644 --- a/src/widgets/itemviews/qtreewidget.cpp +++ b/src/widgets/itemviews/qtreewidget.cpp @@ -52,9 +52,6 @@ QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug (?) -typedef bool(*LessThan)(const QPair<QTreeWidgetItem*,int>&,const QPair<QTreeWidgetItem*,int>&); - class QTreeModelLessThan { public: @@ -610,7 +607,7 @@ void QTreeModel::ensureSorted(int column, Qt::SortOrder order, sorting[i].second = start + i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes; @@ -777,7 +774,7 @@ bool QTreeModel::isChanging() const if column is -1 then all columns have changed */ -void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column) +void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column, const QVector<int> &roles) { if (signalsBlocked()) return; @@ -800,7 +797,7 @@ void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column) topLeft = index(item, column); bottomRight = topLeft; } - emit dataChanged(topLeft, bottomRight); + emit dataChanged(topLeft, bottomRight, roles); } void QTreeModel::beginInsertItems(QTreeWidgetItem *parent, int row, int count) @@ -850,7 +847,7 @@ void QTreeModel::sortItems(QList<QTreeWidgetItem*> *items, int column, Qt::SortO } // do the sorting - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList fromList; @@ -1015,6 +1012,14 @@ void QTreeModel::timerEvent(QTimerEvent *ev) \sa isHidden() */ +void QTreeWidgetItem::setHidden(bool ahide) +{ + if (view) { + view->setItemHidden(this, ahide); + d->hidden = ahide; + } +} + /*! \fn bool QTreeWidgetItem::isHidden() const \since 4.2 @@ -1024,6 +1029,11 @@ void QTreeModel::timerEvent(QTimerEvent *ev) \sa setHidden() */ +bool QTreeWidgetItem::isHidden() const +{ + return (view ? d->hidden : false); +} + /*! \fn void QTreeWidgetItem::setExpanded(bool expand) \since 4.2 @@ -1651,6 +1661,25 @@ void QTreeWidgetItem::setFlags(Qt::ItemFlags flags) itemChanged(); } +void QTreeWidgetItemPrivate::updateHiddenStatus(QTreeWidgetItem *item, bool inserting) +{ + QTreeModel *model = (item->view ? qobject_cast<QTreeModel*>(item->view->model()) : 0); + if (!model) + return; + QStack<QTreeWidgetItem *> parents; + parents.push(item); + while (!parents.isEmpty()) { + QTreeWidgetItem *parent = parents.pop(); + QModelIndex index = model->index(parent, 0); + if (parent->d->hidden) + item->view->setRowHidden(index.row(), index.parent(), inserting); + for (int i = 0; i < parent->children.count(); ++i) { + QTreeWidgetItem *child = parent->children.at(i); + parents.push(child); + } + } +} + void QTreeWidgetItemPrivate::propagateDisabled(QTreeWidgetItem *item) { Q_ASSERT(item); @@ -1766,11 +1795,14 @@ void QTreeWidgetItem::setData(int column, int role, const QVariant &value) } if (model) { - model->emitDataChanged(this, column); + const QVector<int> roles((role == Qt::DisplayRole || role == Qt::EditRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); + model->emitDataChanged(this, column, roles); if (role == Qt::CheckStateRole) { QTreeWidgetItem *p; for (p = par; p && (p->itemFlags & Qt::ItemIsAutoTristate); p = p->par) - model->emitDataChanged(p, column); + model->emitDataChanged(p, column, roles); } } } @@ -1937,6 +1969,7 @@ void QTreeWidgetItem::insertChild(int index, QTreeWidgetItem *child) stack.push(i->children.at(c)); } children.insert(index, child); + d->updateHiddenStatus(child, true); model->endInsertItems(); model->skipPendingSort = wasSkipSort; } else { @@ -1974,6 +2007,7 @@ QTreeWidgetItem *QTreeWidgetItem::takeChild(int index) } if (index >= 0 && index < children.count()) { if (model) model->beginRemoveItems(this, index, 1); + d->updateHiddenStatus(children.at(index), false); QTreeWidgetItem *item = children.takeAt(index); item->par = 0; QStack<QTreeWidgetItem*> stack; @@ -2052,6 +2086,7 @@ void QTreeWidgetItem::insertChildren(int index, const QList<QTreeWidgetItem*> &c this->children.insert(index + n, child); if (child->par) d->propagateDisabled(child); + d->updateHiddenStatus(child, true); } if (model) model->endInsertItems(); } @@ -3099,6 +3134,8 @@ bool QTreeWidget::isItemHidden(const QTreeWidgetItem *item) const */ void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) { + if (!item) + return; Q_D(QTreeWidget); if (item == d->treeModel()->headerItem) { header()->setHidden(hide); @@ -3106,6 +3143,7 @@ void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) const QModelIndex index = d->index(item); setRowHidden(index.row(), index.parent(), hide); } + item->d->hidden = hide; } /*! diff --git a/src/widgets/itemviews/qtreewidget.h b/src/widgets/itemviews/qtreewidget.h index a31af0428a..975f208702 100644 --- a/src/widgets/itemviews/qtreewidget.h +++ b/src/widgets/itemviews/qtreewidget.h @@ -82,8 +82,8 @@ public: inline void setSelected(bool select); inline bool isSelected() const; - inline void setHidden(bool hide); - inline bool isHidden() const; + void setHidden(bool hide); + bool isHidden() const; inline void setExpanded(bool expand); inline bool isExpanded() const; @@ -339,6 +339,7 @@ Q_SIGNALS: void itemDoubleClicked(QTreeWidgetItem *item, int column); void itemActivated(QTreeWidgetItem *item, int column); void itemEntered(QTreeWidgetItem *item, int column); + // ### Qt 6: add changed roles void itemChanged(QTreeWidgetItem *item, int column); void itemExpanded(QTreeWidgetItem *item); void itemCollapsed(QTreeWidgetItem *item); @@ -409,12 +410,6 @@ inline void QTreeWidgetItem::setSelected(bool aselect) inline bool QTreeWidgetItem::isSelected() const { return (view ? view->isItemSelected(this) : false); } -inline void QTreeWidgetItem::setHidden(bool ahide) -{ if (view) view->setItemHidden(this, ahide); } - -inline bool QTreeWidgetItem::isHidden() const -{ return (view ? view->isItemHidden(this) : false); } - inline void QTreeWidgetItem::setExpanded(bool aexpand) { if (view) view->setItemExpanded(this, aexpand); } diff --git a/src/widgets/itemviews/qtreewidget_p.h b/src/widgets/itemviews/qtreewidget_p.h index f4625842ef..adc2c2c421 100644 --- a/src/widgets/itemviews/qtreewidget_p.h +++ b/src/widgets/itemviews/qtreewidget_p.h @@ -139,7 +139,7 @@ public: protected: QTreeModel(QTreeModelPrivate &, QTreeWidget *parent = 0); - void emitDataChanged(QTreeWidgetItem *item, int column); + void emitDataChanged(QTreeWidgetItem *item, int column, const QVector<int> &roles); void beginInsertItems(QTreeWidgetItem *parent, int row, int count); void endInsertItems(); void beginRemoveItems(QTreeWidgetItem *parent, int row, int count); @@ -187,13 +187,16 @@ class QTreeWidgetItemPrivate { public: QTreeWidgetItemPrivate(QTreeWidgetItem *item) - : q(item), disabled(false), selected(false), rowGuess(-1), policy(QTreeWidgetItem::DontShowIndicatorWhenChildless) {} + : q(item), disabled(false), selected(false), hidden(false), rowGuess(-1), + policy(QTreeWidgetItem::DontShowIndicatorWhenChildless) {} void propagateDisabled(QTreeWidgetItem *item); + void updateHiddenStatus(QTreeWidgetItem *item, bool inserting); void sortChildren(int column, Qt::SortOrder order, bool climb); QTreeWidgetItem *q; QVariantList display; uint disabled : 1; uint selected : 1; + uint hidden : 1; int rowGuess; QTreeWidgetItem::ChildIndicatorPolicy policy; }; diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index 1bdcecbc81..c2f6e4ce75 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -35,7 +35,8 @@ HEADERS += \ kernel/qgesturemanager_p.h \ kernel/qdesktopwidget_p.h \ kernel/qwidgetwindow_p.h \ - kernel/qwindowcontainer_p.h + kernel/qwindowcontainer_p.h \ + kernel/qtestsupport_widgets.h SOURCES += \ kernel/qaction.cpp \ @@ -60,7 +61,8 @@ SOURCES += \ kernel/qdesktopwidget.cpp \ kernel/qwidgetsvariant.cpp \ kernel/qwidgetwindow.cpp \ - kernel/qwindowcontainer.cpp + kernel/qwindowcontainer.cpp \ + kernel/qtestsupport_widgets.cpp macx: { HEADERS += kernel/qmacgesturerecognizer_p.h diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index ba315d4338..45b98e9475 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -110,6 +110,8 @@ #include <qpa/qplatformwindow.h> +#include <qtwidgets_tracepoints_p.h> + //#define ALIEN_DEBUG static void initResources() @@ -1025,17 +1027,17 @@ QString QApplication::styleSheet() const void QApplication::setStyleSheet(const QString& styleSheet) { QApplicationPrivate::styleSheet = styleSheet; - QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplicationPrivate::app_style); + QStyleSheetStyle *styleSheetStyle = qt_styleSheet(QApplicationPrivate::app_style); if (styleSheet.isEmpty()) { // application style sheet removed - if (!proxy) + if (!styleSheetStyle) return; // there was no stylesheet before - setStyle(proxy->base); - } else if (proxy) { // style sheet update, just repolish - proxy->repolish(qApp); + setStyle(styleSheetStyle->base); + } else if (styleSheetStyle) { // style sheet update, just repolish + styleSheetStyle->repolish(qApp); } else { // stylesheet set the first time - QStyleSheetStyle *newProxy = new QStyleSheetStyle(QApplicationPrivate::app_style); - QApplicationPrivate::app_style->setParent(newProxy); - setStyle(newProxy); + QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(QApplicationPrivate::app_style); + QApplicationPrivate::app_style->setParent(newStyleSheetStyle); + setStyle(newStyleSheetStyle); } } @@ -1145,11 +1147,11 @@ void QApplication::setStyle(QStyle *style) QStyle *old = QApplicationPrivate::app_style; // save #ifndef QT_NO_STYLE_STYLESHEET - if (!QApplicationPrivate::styleSheet.isEmpty() && !qobject_cast<QStyleSheetStyle *>(style)) { + if (!QApplicationPrivate::styleSheet.isEmpty() && !qt_styleSheet(style)) { // we have a stylesheet already and a new style is being set - QStyleSheetStyle *newProxy = new QStyleSheetStyle(style); - style->setParent(newProxy); - QApplicationPrivate::app_style = newProxy; + QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(style); + style->setParent(newStyleSheetStyle); + QApplicationPrivate::app_style = newStyleSheetStyle; } else #endif // QT_NO_STYLE_STYLESHEET QApplicationPrivate::app_style = style; @@ -1199,8 +1201,8 @@ void QApplication::setStyle(QStyle *style) } #ifndef QT_NO_STYLE_STYLESHEET - if (QStyleSheetStyle *oldProxy = qobject_cast<QStyleSheetStyle *>(old)) { - oldProxy->deref(); + if (QStyleSheetStyle *oldStyleSheetStyle = qt_styleSheet(old)) { + oldStyleSheetStyle->deref(); } else #endif if (old && old->parent() == qApp) { @@ -1343,7 +1345,6 @@ void QApplication::setGlobalStrut(const QSize& strut) /*! \fn QPalette QApplication::palette(const QWidget* widget) - \overload If a \a widget is passed, the default palette for the widget's class is returned. This may or may not be the application palette. In most cases @@ -2627,7 +2628,7 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *nativeWidget, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, - bool spontaneous) + bool spontaneous, bool onlyDispatchEnterLeave) { Q_ASSERT(receiver); Q_ASSERT(event); @@ -2688,11 +2689,17 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, // We need this quard in case someone opens a modal dialog / popup. If that's the case // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. const bool wasLeaveAfterRelease = leaveAfterRelease != 0; - bool result; - if (spontaneous) - result = QApplication::sendSpontaneousEvent(receiver, event); - else - result = QApplication::sendEvent(receiver, event); + bool result = true; + // This code is used for sending the synthetic enter/leave events for cases where it is needed + // due to other events causing the widget under the mouse to change. However in those cases + // we do not want to send the mouse event associated with this call, so this enables us to + // not send the unneeded mouse event + if (!onlyDispatchEnterLeave) { + if (spontaneous) + result = QApplication::sendSpontaneousEvent(receiver, event); + else + result = QApplication::sendEvent(receiver, event); + } if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { @@ -2767,9 +2774,10 @@ void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) if (widget->data->in_destructor && qt_button_down == widget) qt_button_down = 0; - // Send enter/leave events followed by a mouse move on the entered widget. + // A mouse move is not actually sent, but we utilize the sendMouseEvent() call to send the + // enter/leave events as appropriate QMouseEvent e(QEvent::MouseMove, pos, windowPos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); - sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver); + sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver, true, true); #else // !QT_NO_CURSOR Q_UNUSED(widget); #endif // QT_NO_CURSOR @@ -2947,8 +2955,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) d->checkReceiverThread(receiver); #endif - if (receiver->isWindowType()) - QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e); + if (receiver->isWindowType()) { + if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e)) + return true; // Platform plugin ate the event + } if(e->spontaneous()) { // Capture the current mouse and keyboard states. Doing so here is @@ -3288,6 +3298,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(), wheel->modifiers(), phase, wheel->source(), wheel->inverted()); + we.setTimestamp(wheel->timestamp()); bool eventAccepted; do { we.spont = spontaneous && w == receiver; @@ -3324,6 +3335,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) const QPoint &relpos = QApplicationPrivate::wheel_widget->mapFromGlobal(wheel->globalPos()); QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(), wheel->modifiers(), wheel->phase(), wheel->source()); + we.setTimestamp(wheel->timestamp()); we.spont = true; we.ignore(); d->notify_helper(QApplicationPrivate::wheel_widget, &we); @@ -3375,6 +3387,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) tablet->tangentialPressure(), tablet->rotation(), tablet->z(), tablet->modifiers(), tablet->uniqueId(), tablet->button(), tablet->buttons()); te.spont = e->spontaneous(); + te.setAccepted(false); res = d->notify_helper(w, w == receiver ? tablet : &te); eventAccepted = ((w == receiver) ? tablet : &te)->isAccepted(); e->spont = false; @@ -3649,7 +3662,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) break; w = w->parentWidget(); } - foreach (QGesture *g, allGestures) + for (QGesture *g : qAsConst(allGestures)) gestureEvent->setAccepted(g, false); gestureEvent->m_accept = false; // to make sure we check individual gestures } else { @@ -3696,11 +3709,19 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) { + // These tracepoints (and the whole function, actually) are very similar + // to the ones in QCoreApplicationPrivate::notify_helper; the reason for their + // duplication is because tracepoint symbols are not exported by QtCore. + // If you adjust the tracepoints here, consider adjusting QCoreApplicationPrivate too. + Q_TRACE(QApplication_notify_entry, receiver, e, e->type()); + // send to all application event filters if (threadRequiresCoreApplication() && receiver->d_func()->threadData->thread == mainThread() - && sendThroughApplicationEventFilters(receiver, e)) + && sendThroughApplicationEventFilters(receiver, e)) { + Q_TRACE(QApplication_notify_event_filtered, receiver, e, e->type()); return true; + } if (receiver->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(receiver); @@ -3720,11 +3741,18 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) } // send to all receiver event filters - if (sendThroughObjectEventFilters(receiver, e)) + if (sendThroughObjectEventFilters(receiver, e)) { + Q_TRACE(QApplication_notify_event_filtered, receiver, e, e->type()); return true; + } + + Q_TRACE(QApplication_notify_before_delivery, receiver, e, e->type()); // deliver the event - bool consumed = receiver->event(e); + const bool consumed = receiver->event(e); + + Q_TRACE(QApplication_notify_after_delivery, receiver, e, e->type(), consumed); + QCoreApplicationPrivate::setEventSpontaneous(e, false); return consumed; } @@ -4493,12 +4521,12 @@ void QApplicationPrivate::notifyDragStarted(const QDrag *drag) #endif // QT_CONFIG(draganddrop) #ifndef QT_NO_GESTURES -QGestureManager* QGestureManager::instance() +QGestureManager* QGestureManager::instance(InstanceCreation ic) { QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); if (!qAppPriv) return 0; - if (!qAppPriv->gestureManager) + if (!qAppPriv->gestureManager && ic == ForceCreation) qAppPriv->gestureManager = new QGestureManager(qApp); return qAppPriv->gestureManager; } diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 488ca6cbfd..2d9468cc21 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -226,7 +226,7 @@ public: QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, - bool spontaneous = true); + bool spontaneous = true, bool onlyDispatchEnterLeave = false); void sendSyntheticEnterLeave(QWidget *widget); static QWindow *windowForWidget(const QWidget *widget) diff --git a/src/widgets/kernel/qformlayout.cpp b/src/widgets/kernel/qformlayout.cpp index 595ff3eb6e..66e8858e21 100644 --- a/src/widgets/kernel/qformlayout.cpp +++ b/src/widgets/kernel/qformlayout.cpp @@ -1435,13 +1435,7 @@ static void clearAndDestroyQLayoutItem(QLayoutItem *item) up one row and the freed vertical space is redistributed amongst the remaining rows. You can use this function to undo a previous addRow() or insertRow(): - \code - QFormLayout *flay = ...; - QPointer<QLineEdit> le = new QLineEdit; - flay->insertRow(2, "User:", le); - // later: - flay->removeRow(2); // le == nullptr at this point - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 3 If you want to remove the row from the layout without deleting the widgets, use takeRow() instead. @@ -1467,13 +1461,7 @@ void QFormLayout::removeRow(int row) up one row and the freed vertical space is redistributed amongst the remaining rows. You can use this function to undo a previous addRow() or insertRow(): - \code - QFormLayout *flay = ...; - QPointer<QLineEdit> le = new QLineEdit; - flay->insertRow(2, "User:", le); - // later: - flay->removeRow(le); // le == nullptr at this point - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 4 If you want to remove the row from the layout without deleting the widgets, use takeRow() instead. @@ -1499,13 +1487,7 @@ void QFormLayout::removeRow(QWidget *widget) up one row and the freed vertical space is redistributed amongst the remaining rows. You can use this function to undo a previous addRow() or insertRow(): - \code - QFormLayout *flay = ...; - QPointer<QVBoxLayout> vbl = new QVBoxLayout; - flay->insertRow(2, "User:", vbl); - // later: - flay->removeRow(layout); // vbl == nullptr at this point - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 5 If you want to remove the row from the form layout without deleting the inserted layout, use takeRow() instead. @@ -1532,13 +1514,7 @@ void QFormLayout::removeRow(QLayout *layout) up one row and the freed vertical space is redistributed amongst the remaining rows. You can use this function to undo a previous addRow() or insertRow(): - \code - QFormLayout *flay = ...; - QPointer<QLineEdit> le = new QLineEdit; - flay->insertRow(2, "User:", le); - // later: - QFormLayout::TakeRowResult result = flay->takeRow(2); - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 6 If you want to remove the row from the layout and delete the widgets, use removeRow() instead. @@ -1583,13 +1559,7 @@ QFormLayout::TakeRowResult QFormLayout::takeRow(int row) After this call, rowCount() is decremented by one. All following rows are shifted up one row and the freed vertical space is redistributed amongst the remaining rows. - \code - QFormLayout *flay = ...; - QPointer<QLineEdit> le = new QLineEdit; - flay->insertRow(2, "User:", le); - // later: - QFormLayout::TakeRowResult result = flay->takeRow(widget); - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 7 If you want to remove the row from the layout and delete the widgets, use removeRow() instead. @@ -1628,13 +1598,7 @@ QFormLayout::TakeRowResult QFormLayout::takeRow(QWidget *widget) After this call, rowCount() is decremented by one. All following rows are shifted up one row and the freed vertical space is redistributed amongst the remaining rows. - \code - QFormLayout *flay = ...; - QPointer<QVBoxLayout> vbl = new QVBoxLayout; - flay->insertRow(2, "User:", vbl); - // later: - QFormLayout::TakeRowResult result = flay->takeRow(widget); - \endcode + \snippet code/src_gui_kernel_qformlayout.cpp 8 If you want to remove the row from the form layout and delete the inserted layout, use removeRow() instead. diff --git a/src/widgets/kernel/qgesture.cpp b/src/widgets/kernel/qgesture.cpp index 7f8bf18e90..fc715687c6 100644 --- a/src/widgets/kernel/qgesture.cpp +++ b/src/widgets/kernel/qgesture.cpp @@ -916,7 +916,7 @@ QGesture *QGestureEvent::gesture(Qt::GestureType type) const QList<QGesture *> QGestureEvent::activeGestures() const { QList<QGesture *> gestures; - foreach (QGesture *gesture, m_gestures) { + for (QGesture *gesture : m_gestures) { if (gesture->state() != Qt::GestureCanceled) gestures.append(gesture); } @@ -929,7 +929,7 @@ QList<QGesture *> QGestureEvent::activeGestures() const QList<QGesture *> QGestureEvent::canceledGestures() const { QList<QGesture *> gestures; - foreach (QGesture *gesture, m_gestures) { + for (QGesture *gesture : m_gestures) { if (gesture->state() == Qt::GestureCanceled) gestures.append(gesture); } diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 5bf66d68e3..c4188044cf 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -773,7 +773,7 @@ void QGestureManager::recycle(QGesture *gesture) bool QGestureManager::gesturePending(QObject *o) { - const QGestureManager *gm = QGestureManager::instance(); + const QGestureManager *gm = QGestureManager::instance(DontForceCreation); return gm && gm->m_gestureOwners.key(o); } diff --git a/src/widgets/kernel/qgesturemanager_p.h b/src/widgets/kernel/qgesturemanager_p.h index 3df80bab55..3a5c9822eb 100644 --- a/src/widgets/kernel/qgesturemanager_p.h +++ b/src/widgets/kernel/qgesturemanager_p.h @@ -81,7 +81,9 @@ public: bool filterEvent(QGraphicsObject *receiver, QEvent *event); #endif // QT_CONFIG(graphicsview) - static QGestureManager* instance(); // declared in qapplication.cpp + enum InstanceCreation { ForceCreation, DontForceCreation }; + + static QGestureManager *instance(InstanceCreation ic = ForceCreation); // declared in qapplication.cpp static bool gesturePending(QObject *o); void cleanupCachedGestures(QObject *target, Qt::GestureType type); diff --git a/src/widgets/kernel/qgridlayout.cpp b/src/widgets/kernel/qgridlayout.cpp index db8ef89477..f1c6c96a6d 100644 --- a/src/widgets/kernel/qgridlayout.cpp +++ b/src/widgets/kernel/qgridlayout.cpp @@ -1029,7 +1029,7 @@ QRect QGridLayoutPrivate::cellRect(int row, int col) const This illustration shows a fragment of a dialog with a five-column, three-row grid (the grid is shown overlaid in magenta): - \image gridlayout.png A grid layout + \image qgridlayout.png A grid layout Columns 0, 2 and 4 in this dialog fragment are made up of a QLabel, a QLineEdit, and a QListBox. Columns 1 and 3 are diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index 9ce1c1c2d4..eac5674161 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -109,10 +109,11 @@ static int menuBarHeightForWidth(QWidget *menubar, int w) /*! Constructs a new top-level QLayout, with parent \a parent. - \a parent may not be 0. + \a parent may not be a \c nullptr. - There can be only one top-level layout for a widget. It is - returned by QWidget::layout(). + The layout is set directly as the top-level layout for + \a parent. There can be only one top-level layout for a + widget. It is returned by QWidget::layout(). */ QLayout::QLayout(QWidget *parent) : QObject(*new QLayoutPrivate, parent) @@ -1246,6 +1247,26 @@ int QLayout::indexOf(QWidget *widget) const } /*! + \since 5.12 + Searches for layout item \a layoutItem in this layout (not including child + layouts). + + Returns the index of \a layoutItem, or -1 if \a layoutItem is not found. +*/ +int QLayout::indexOf(QLayoutItem *layoutItem) const +{ + int i = 0; + QLayoutItem *item = itemAt(i); + while (item) { + if (item == layoutItem) + return i; + ++i; + item = itemAt(i); + } + return -1; +} + +/*! \enum QLayout::SizeConstraint The possible values are: diff --git a/src/widgets/kernel/qlayout.h b/src/widgets/kernel/qlayout.h index bcc33a0811..616f4e7164 100644 --- a/src/widgets/kernel/qlayout.h +++ b/src/widgets/kernel/qlayout.h @@ -122,6 +122,7 @@ public: virtual QLayoutItem *itemAt(int index) const = 0; virtual QLayoutItem *takeAt(int index) = 0; virtual int indexOf(QWidget *) const; + QT6_VIRTUAL int indexOf(QLayoutItem *) const; virtual int count() const = 0; bool isEmpty() const override; QSizePolicy::ControlTypes controlTypes() const override; diff --git a/src/widgets/kernel/qmacgesturerecognizer_p.h b/src/widgets/kernel/qmacgesturerecognizer_p.h index e381a6cc2f..739fc201b7 100644 --- a/src/widgets/kernel/qmacgesturerecognizer_p.h +++ b/src/widgets/kernel/qmacgesturerecognizer_p.h @@ -66,9 +66,9 @@ class QMacSwipeGestureRecognizer : public QGestureRecognizer public: QMacSwipeGestureRecognizer(); - QGesture *create(QObject *target); - QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); - void reset(QGesture *gesture); + QGesture *create(QObject *target) override; + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event) override; + void reset(QGesture *gesture) override; }; class QMacPinchGestureRecognizer : public QGestureRecognizer @@ -76,9 +76,9 @@ class QMacPinchGestureRecognizer : public QGestureRecognizer public: QMacPinchGestureRecognizer(); - QGesture *create(QObject *target); - QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); - void reset(QGesture *gesture); + QGesture *create(QObject *target) override; + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event) override; + void reset(QGesture *gesture) override; }; class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer @@ -86,9 +86,9 @@ class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer public: QMacPanGestureRecognizer(); - QGesture *create(QObject *target); - QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); - void reset(QGesture *gesture); + QGesture *create(QObject *target) override; + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event) override; + void reset(QGesture *gesture) override; protected: void timerEvent(QTimerEvent *ev) override; private: diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index c96b6812c4..ed0fe0ed91 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -906,9 +906,19 @@ void QOpenGLWidgetPrivate::invalidateFbo() const int gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0 const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT +#ifdef Q_OS_WASM + // webgl does not allow separate depth and stencil attachments + // QTBUG-69913 + const int gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT + + const GLenum attachments[] = { + gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment, gl_depth_stencil_attachment + }; +#else const GLenum attachments[] = { gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment }; +#endif f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments); } else { f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -938,7 +948,8 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer() q->makeCurrent(); } - QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatioF(), false, false); + const bool hasAlpha = q->format().hasAlpha(); + QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatioF(), hasAlpha, hasAlpha); res.setDevicePixelRatio(q->devicePixelRatioF()); // While we give no guarantees of what is going to be left bound, prefer the diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp index fde039c75e..a680ff7913 100644 --- a/src/widgets/kernel/qshortcut.cpp +++ b/src/widgets/kernel/qshortcut.cpp @@ -149,8 +149,16 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge bool visible = w->isVisible(); #if QT_CONFIG(menubar) if (QMenuBar *menuBar = qobject_cast<QMenuBar *>(w)) { - if (menuBar->isNativeMenuBar()) - visible = true; + if (auto *pmb = menuBar->platformMenuBar()) { + if (menuBar->parentWidget()) { + visible = true; + } else { + if (auto *ww = qobject_cast<QWidgetWindow *>(pmb->parentWindow())) + w = ww->widget(); // Good enough since we only care about the window + else + return false; // This is not a QWidget window. We won't deliver + } + } } #endif diff --git a/src/widgets/kernel/qtestsupport_widgets.cpp b/src/widgets/kernel/qtestsupport_widgets.cpp new file mode 100644 index 0000000000..b227e6ff5d --- /dev/null +++ b/src/widgets/kernel/qtestsupport_widgets.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestsupport_widgets.h" + +#include "qwidget.h" + +#include <QtGui/qwindow.h> +#include <QtGui/qtestsupport_gui.h> + +QT_BEGIN_NAMESPACE + +/*! \fn bool qWaitForWindowActive(QWidget *widget, int timeout) + \relates QTest + \since 5.0 + + Waits for \a timeout milliseconds or until the \a widget's window is active. + + Returns \c true if \c widget's window is active within \a timeout milliseconds, otherwise returns \c false. + + \sa QTest::qWaitForWindowExposed(), QWidget::isActiveWindow() +*/ +Q_WIDGETS_EXPORT Q_REQUIRED_RESULT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout) +{ + if (QWindow *window = widget->window()->windowHandle()) + return QTest::qWaitForWindowActive(window, timeout); + return false; +} + +/*! \fn bool qWaitForWindowExposed(QWidget *widget, int timeout) + \relates QTest + \since 5.0 + + Waits for \a timeout milliseconds or until the \a widget's window is exposed. + Returns \c true if \c widget's window is exposed within \a timeout milliseconds, otherwise returns \c false. + + This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some + time after being asked to show itself on the screen. + + Note that a window that is mapped to screen may still not be considered exposed if the window client + area is completely covered by other windows, or if the window is otherwise not visible. This function + will then time out when waiting for such a window. + + A specific configuration where this happens is when using QGLWidget as a viewport widget on macOS: + The viewport widget gets the expose event, not the parent widget. + + \sa QTest::qWaitForWindowActive() +*/ +Q_WIDGETS_EXPORT Q_REQUIRED_RESULT bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout) +{ + if (QWindow *window = widget->window()->windowHandle()) + return QTest::qWaitForWindowExposed(window, timeout); + return false; +} + +/*! \fn bool qWaitForWindowShown(QWidget *widget, int timeout) + \relates QTest + \since 5.0 + \deprecated + + Waits for \a timeout milliseconds or until the \a widget's window is exposed. + Returns \c true if \c widget's window is exposed within \a timeout milliseconds, otherwise returns \c false. + + This function does the same as qWaitForWindowExposed(). + + Example: + + \code + QWidget widget; + widget.show(); + QTest::qWaitForWindowShown(&widget); + \endcode + + \sa QTest::qWaitForWindowActive(), QTest::qWaitForWindowExposed() +*/ + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qtestsupport_widgets.h b/src/widgets/kernel/qtestsupport_widgets.h new file mode 100644 index 0000000000..ca1406b0b2 --- /dev/null +++ b/src/widgets/kernel/qtestsupport_widgets.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTSUPPORT_WIDGETS_H +#define QTESTSUPPORT_WIDGETS_H + +#include "qtwidgetsglobal.h" + +QT_BEGIN_NAMESPACE + +class QWidget; + +namespace QTest { +Q_WIDGETS_EXPORT Q_REQUIRED_RESULT bool qWaitForWindowActive(QWidget *widget, int timeout = 5000); +Q_WIDGETS_EXPORT Q_REQUIRED_RESULT bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000); + +#if QT_DEPRECATED_SINCE(5, 0) +QT_DEPRECATED Q_REQUIRED_RESULT inline static bool qWaitForWindowShown(QWidget *widget, int timeout = 5000) +{ return QTest::qWaitForWindowExposed(widget, timeout); } +#endif +} + +QT_END_NAMESPACE + +#endif diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index ed7184302a..2e6575c163 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -123,11 +123,11 @@ class QTipLabel : public QLabel { Q_OBJECT public: - QTipLabel(const QString &text, QWidget *w, int msecDisplayTime); + QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime); ~QTipLabel(); static QTipLabel *instance; - void updateSize(); + void updateSize(const QPoint &pos); bool eventFilter(QObject *, QEvent *) override; @@ -135,7 +135,7 @@ public: bool fadingOut; - void reuseTip(const QString &text, int msecDisplayTime); + void reuseTip(const QString &text, int msecDisplayTime, const QPoint &pos); void hideTip(); void hideTipImmediately(); void setTipRect(QWidget *w, const QRect &r); @@ -171,7 +171,7 @@ private: QTipLabel *QTipLabel::instance = 0; -QTipLabel::QTipLabel(const QString &text, QWidget *w, int msecDisplayTime) +QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime) #ifndef QT_NO_STYLE_STYLESHEET : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), styleSheetParent(0), widget(0) #else @@ -192,7 +192,7 @@ QTipLabel::QTipLabel(const QString &text, QWidget *w, int msecDisplayTime) setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); setMouseTracking(true); fadingOut = false; - reuseTip(text, msecDisplayTime); + reuseTip(text, msecDisplayTime, pos); } void QTipLabel::restartExpireTimer(int msecDisplayTime) @@ -204,7 +204,7 @@ void QTipLabel::restartExpireTimer(int msecDisplayTime) hideTimer.stop(); } -void QTipLabel::reuseTip(const QString &text, int msecDisplayTime) +void QTipLabel::reuseTip(const QString &text, int msecDisplayTime, const QPoint &pos) { #ifndef QT_NO_STYLE_STYLESHEET if (styleSheetParent){ @@ -214,20 +214,35 @@ void QTipLabel::reuseTip(const QString &text, int msecDisplayTime) } #endif - setWordWrap(Qt::mightBeRichText(text)); + setWordWrap(true); setText(text); - updateSize(); + updateSize(pos); restartExpireTimer(msecDisplayTime); } -void QTipLabel::updateSize() +void QTipLabel::updateSize(const QPoint &pos) { QFontMetrics fm(font()); QSize extra(1, 0); // Make it look good with the default ToolTip font on Mac, which has a small descent. if (fm.descent() == 2 && fm.ascent() >= 11) ++extra.rheight(); - resize(sizeHint() + extra); + QSize sh = sizeHint(); + if (wordWrap()) { + QScreen *screen = QGuiApplication::screenAt(pos); + if (!screen) + screen = QGuiApplication::primaryScreen(); + if (screen) { + const qreal screenWidth = screen->geometry().width(); + if (sh.width() > screenWidth) { + // Try to use widely accepted 75chars max length or 80% of the screen width else. + // See https://en.wikipedia.org/wiki/Line_length + sh.setWidth(qMin(fm.averageCharWidth() * 75, static_cast<int>(screenWidth * .8))); + sh.setHeight(heightForWidth(sh.width())); + } + } + } + resize(sh + extra); } void QTipLabel::paintEvent(QPaintEvent *ev) @@ -254,13 +269,13 @@ void QTipLabel::resizeEvent(QResizeEvent *e) void QTipLabel::mouseMoveEvent(QMouseEvent *e) { - if (rect.isNull()) - return; - QPoint pos = e->globalPos(); - if (widget) - pos = widget->mapFromGlobal(pos); - if (!rect.contains(pos)) - hideTip(); + if (!rect.isNull()) { + QPoint pos = e->globalPos(); + if (widget) + pos = widget->mapFromGlobal(pos); + if (!rect.contains(pos)) + hideTip(); + } QLabel::mouseMoveEvent(e); } @@ -381,7 +396,7 @@ int QTipLabel::getTipScreen(const QPoint &pos, QWidget *w) void QTipLabel::placeTip(const QPoint &pos, QWidget *w) { #ifndef QT_NO_STYLE_STYLESHEET - if (testAttribute(Qt::WA_StyleSheet) || (w && qobject_cast<QStyleSheetStyle *>(w->style()))) { + if (testAttribute(Qt::WA_StyleSheet) || (w && qt_styleSheet(w->style()))) { //the stylesheet need to know the real parent QTipLabel::instance->setProperty("_q_stylesheet_parent", QVariant::fromValue(w)); //we force the style to be the QStyleSheetStyle, and force to clear the cache as well. @@ -394,7 +409,7 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w) QTipLabel::instance, SLOT(styleSheetParentDestroyed())); // QTBUG-64550: A font inherited by the style sheet might change the size, // particular on Windows, where the tip is not parented on a window. - QTipLabel::instance->updateSize(); + QTipLabel::instance->updateSize(pos); } } #endif //QT_NO_STYLE_STYLESHEET @@ -497,7 +512,7 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons if (w) localPos = w->mapFromGlobal(pos); if (QTipLabel::instance->tipChanged(localPos, text, w)){ - QTipLabel::instance->reuseTip(text, msecDisplayTime); + QTipLabel::instance->reuseTip(text, msecDisplayTime, pos); QTipLabel::instance->setTipRect(w, rect); QTipLabel::instance->placeTip(pos, w); } @@ -511,10 +526,10 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons // raised when the tooltip will be shown QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED - new QTipLabel(text, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w)), msecDisplayTime); + new QTipLabel(text, pos, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w)), msecDisplayTime); QT_WARNING_POP #else - new QTipLabel(text, w, msecDisplayTime); // sets QTipLabel::instance to itself + new QTipLabel(text, pos, w, msecDisplayTime); // sets QTipLabel::instance to itself #endif QTipLabel::instance->setTipRect(w, rect); QTipLabel::instance->placeTip(pos, w); diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp index 96d0cf61c4..1fa83d3238 100644 --- a/src/widgets/kernel/qwhatsthis.cpp +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -48,7 +48,9 @@ #include "qscreen.h" #include "qpainter.h" #include "qtimer.h" +#if QT_CONFIG(action) #include "qaction.h" +#endif // QT_CONFIG(action) #include "qcursor.h" #include "qbitmap.h" #include "qtextdocument.h" @@ -366,7 +368,9 @@ class QWhatsThisPrivate : public QObject ~QWhatsThisPrivate(); static QWhatsThisPrivate *instance; bool eventFilter(QObject *, QEvent *) override; +#if QT_CONFIG(action) QPointer<QAction> action; +#endif // QT_CONFIG(action) static void say(QWidget *, const QString &, int x = 0, int y = 0); static void notifyToplevels(QEvent *e); bool leaveOnMouseRelease; @@ -408,8 +412,10 @@ QWhatsThisPrivate::QWhatsThisPrivate() QWhatsThisPrivate::~QWhatsThisPrivate() { +#if QT_CONFIG(action) if (action) action->setChecked(false); +#endif // QT_CONFIG(action) #ifndef QT_NO_CURSOR QApplication::restoreOverrideCursor(); #endif @@ -485,6 +491,7 @@ bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e) return true; } +#if QT_CONFIG(action) class QWhatsThisAction: public QAction { Q_OBJECT @@ -516,6 +523,7 @@ void QWhatsThisAction::actionTriggered() QWhatsThisPrivate::instance->action = this; } } +#endif // QT_CONFIG(action) /*! This function switches the user interface into "What's This?" @@ -672,10 +680,12 @@ void QWhatsThis::hideText() The returned QAction provides a convenient way to let users enter "What's This?" mode. */ +#if QT_CONFIG(action) QAction *QWhatsThis::createAction(QObject *parent) { return new QWhatsThisAction(parent); } +#endif // QT_CONFIG(action) QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwhatsthis.h b/src/widgets/kernel/qwhatsthis.h index 1f0f82b2a2..59c0b01c9b 100644 --- a/src/widgets/kernel/qwhatsthis.h +++ b/src/widgets/kernel/qwhatsthis.h @@ -48,7 +48,9 @@ QT_REQUIRE_CONFIG(whatsthis); QT_BEGIN_NAMESPACE +#if QT_CONFIG(action) class QAction; +#endif // QT_CONFIG(action) class Q_WIDGETS_EXPORT QWhatsThis { @@ -62,7 +64,9 @@ public: static void showText(const QPoint &pos, const QString &text, QWidget *w = nullptr); static void hideText(); +#if QT_CONFIG(action) static QAction *createAction(QObject *parent = nullptr); +#endif // QT_CONFIG(action) }; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 1e249dc191..8c680560d4 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1138,7 +1138,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) q->data = &data; -#ifndef QT_NO_THREAD +#if QT_CONFIG(thread) if (!parent) { Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget", "Widgets must be created in the GUI thread."); @@ -1572,7 +1572,7 @@ QWidget::~QWidget() #endif #ifndef QT_NO_GESTURES - if (QGestureManager *manager = QGestureManager::instance()) { + if (QGestureManager *manager = QGestureManager::instance(QGestureManager::DontForceCreation)) { // \forall Qt::GestureType type : ungrabGesture(type) (inlined) for (auto it = d->gestureContext.keyBegin(), end = d->gestureContext.keyEnd(); it != end; ++it) manager->cleanupCachedGestures(this, *it); @@ -1580,9 +1580,6 @@ QWidget::~QWidget() d->gestureContext.clear(); #endif - // force acceptDrops false before winId is destroyed. - d->registerDropSite(false); - #ifndef QT_NO_ACTION // remove all actions from this widget for (int i = 0; i < d->actions.size(); ++i) { @@ -1849,7 +1846,7 @@ void QWidgetPrivate::deleteExtra() deleteSysExtra(); #ifndef QT_NO_STYLE_STYLESHEET // dereference the stylesheet style - if (QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle *>(extra->style)) + if (QStyleSheetStyle *proxy = qt_styleSheet(extra->style)) proxy->deref(); #endif if (extra->topextra) { @@ -1905,19 +1902,21 @@ void QWidgetPrivate::deleteTLSysExtra() } /* - Returns \c true if there are widgets above this which overlap with + Returns \c region of widgets above this which overlap with \a rect, which is in parent's coordinate system (same as crect). */ -bool QWidgetPrivate::isOverlapped(const QRect &rect) const +QRegion QWidgetPrivate::overlappedRegion(const QRect &rect, bool breakAfterFirst) const { Q_Q(const QWidget); const QWidget *w = q; QRect r = rect; + QPoint p; + QRegion region; while (w) { if (w->isWindow()) - return false; + break; QWidgetPrivate *pd = w->parentWidget()->d_func(); bool above = false; for (int i = 0; i < pd->children.size(); ++i) { @@ -1929,19 +1928,23 @@ bool QWidgetPrivate::isOverlapped(const QRect &rect) const continue; } - if (qRectIntersects(sibling->d_func()->effectiveRectFor(sibling->data->crect), r)) { + const QRect siblingRect = sibling->d_func()->effectiveRectFor(sibling->data->crect); + if (qRectIntersects(siblingRect, r)) { const QWExtra *siblingExtra = sibling->d_func()->extra; if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect && !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) { continue; } - return true; + region += siblingRect.translated(-p); + if (breakAfterFirst) + break; } } w = w->parentWidget(); r.translate(pd->data.crect.topLeft()); + p += pd->data.crect.topLeft(); } - return false; + return region; } void QWidgetPrivate::syncBackingStore() @@ -2398,7 +2401,8 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrus #endif } else if (brush.gradient() - && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) { + && (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode + || brush.gradient()->coordinateMode() == QGradient::ObjectMode)) { painter->save(); painter->setClipRegion(rgn); painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush); @@ -2659,7 +2663,7 @@ void QWidget::setStyleSheet(const QString& styleSheet) return; d->createExtra(); - QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle *>(d->extra->style); + QStyleSheetStyle *proxy = qt_styleSheet(d->extra->style); d->extra->styleSheet = styleSheet; if (styleSheet.isEmpty()) { // stylesheet removed if (!proxy) @@ -2724,12 +2728,12 @@ void QWidget::setStyle(QStyle *style) setAttribute(Qt::WA_SetStyle, style != 0); d->createExtra(); #ifndef QT_NO_STYLE_STYLESHEET - if (QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle *>(style)) { + if (QStyleSheetStyle *styleSheetStyle = qt_styleSheet(style)) { //if for some reason someone try to set a QStyleSheetStyle, ref it //(this may happen for exemple in QButtonDialogBox which propagates its style) - proxy->ref(); + styleSheetStyle->ref(); d->setStyle_helper(style, false); - } else if (qobject_cast<QStyleSheetStyle *>(d->extra->style) || !qApp->styleSheet().isEmpty()) { + } else if (qt_styleSheet(d->extra->style) || !qApp->styleSheet().isEmpty()) { // if we have an application stylesheet or have a proxy already, propagate d->setStyle_helper(new QStyleSheetStyle(style), true); } else @@ -2737,48 +2741,22 @@ void QWidget::setStyle(QStyle *style) d->setStyle_helper(style, false); } -void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool -#if 0 // Used to be included in Qt4 for Q_WS_MAC - metalHack -#endif - ) +void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate) { Q_Q(QWidget); - QStyle *oldStyle = q->style(); -#ifndef QT_NO_STYLE_STYLESHEET - QPointer<QStyle> origStyle; -#endif + QStyle *oldStyle = q->style(); -#if 0 // Used to be included in Qt4 for Q_WS_MAC - // the metalhack boolean allows Qt/Mac to do a proper re-polish depending - // on how the Qt::WA_MacBrushedMetal attribute is set. It is only ever - // set when changing that attribute and passes the widget's CURRENT style. - // therefore no need to do a reassignment. - if (!metalHack) -#endif - { - createExtra(); + createExtra(); #ifndef QT_NO_STYLE_STYLESHEET - origStyle = extra->style.data(); + QPointer<QStyle> origStyle = extra->style; #endif - extra->style = newStyle; - } + extra->style = newStyle; // repolish - if (q->windowType() != Qt::Desktop) { - if (polished) { - oldStyle->unpolish(q); -#if 0 // Used to be included in Qt4 for Q_WS_MAC - if (metalHack) - macUpdateMetalAttribute(); -#endif - q->style()->polish(q); -#if 0 // Used to be included in Qt4 for Q_WS_MAC - } else if (metalHack) { - macUpdateMetalAttribute(); -#endif - } + if (polished && q->windowType() != Qt::Desktop) { + oldStyle->unpolish(q); + q->style()->polish(q); } if (propagate) { @@ -2792,8 +2770,8 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool } #ifndef QT_NO_STYLE_STYLESHEET - if (!qobject_cast<QStyleSheetStyle*>(newStyle)) { - if (const QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(origStyle.data())) { + if (!qt_styleSheet(newStyle)) { + if (const QStyleSheetStyle* cssStyle = qt_styleSheet(origStyle)) { cssStyle->clearWidgetFont(q); } } @@ -2804,7 +2782,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool #ifndef QT_NO_STYLE_STYLESHEET // dereference the old stylesheet style - if (QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle *>(origStyle.data())) + if (QStyleSheetStyle *proxy = qt_styleSheet(origStyle)) proxy->deref(); #endif } @@ -2815,7 +2793,9 @@ void QWidgetPrivate::inheritStyle() #ifndef QT_NO_STYLE_STYLESHEET Q_Q(QWidget); - QStyleSheetStyle *proxy = extra ? qobject_cast<QStyleSheetStyle *>(extra->style) : 0; + QStyle *extraStyle = extra ? (QStyle*)extra->style : nullptr; + + QStyleSheetStyle *proxy = qt_styleSheet(extraStyle); if (!q->styleSheet().isEmpty()) { Q_ASSERT(proxy); @@ -2823,16 +2803,16 @@ void QWidgetPrivate::inheritStyle() return; } - QStyle *origStyle = proxy ? proxy->base : (extra ? (QStyle*)extra->style : 0); + QStyle *origStyle = proxy ? proxy->base : extraStyle; QWidget *parent = q->parentWidget(); QStyle *parentStyle = (parent && parent->d_func()->extra) ? (QStyle*)parent->d_func()->extra->style : 0; // If we have stylesheet on app or parent has stylesheet style, we need // to be running a proxy - if (!qApp->styleSheet().isEmpty() || qobject_cast<QStyleSheetStyle *>(parentStyle)) { + if (!qApp->styleSheet().isEmpty() || qt_styleSheet(parentStyle)) { QStyle *newStyle = parentStyle; if (q->testAttribute(Qt::WA_SetStyle)) newStyle = new QStyleSheetStyle(origStyle); - else if (QStyleSheetStyle *newProxy = qobject_cast<QStyleSheetStyle *>(parentStyle)) + else if (QStyleSheetStyle *newProxy = qt_styleSheet(parentStyle)) newProxy->ref(); setStyle_helper(newStyle, true); @@ -2841,7 +2821,7 @@ void QWidgetPrivate::inheritStyle() // So, we have no stylesheet on parent/app and we have an empty stylesheet // we just need our original style back - if (origStyle == (extra ? (QStyle*)extra->style : 0)) // is it any different? + if (origStyle == extraStyle) // is it any different? return; // We could have inherited the proxy from our parent (which has a custom style) @@ -3480,11 +3460,6 @@ void QWidget::setAcceptDrops(bool on) } -void QWidgetPrivate::registerDropSite(bool on) -{ - Q_UNUSED(on); -} - /*! Disables widget input events if \a disable is true; otherwise enables input events. @@ -4514,16 +4489,14 @@ void QWidget::setForegroundRole(QPalette::ColorRole role) and these styles typically do not follow the palette. Because of this, assigning roles to a widget's palette is not guaranteed to change the appearance of the widget. Instead, you may choose to apply a \l - styleSheet. You can refer to our Knowledge Base article - \l{http://qt.nokia.com/developer/knowledgebase/22}{here} for more - information. + styleSheet. \warning Do not use this function in conjunction with \l{Qt Style Sheets}. When using style sheets, the palette of a widget can be customized using the "color", "background-color", "selection-color", "selection-background-color" and "alternate-background-color". - \sa QApplication::palette(), QWidget::font() + \sa QApplication::palette(), QWidget::font(), \l {Qt Style Sheets} */ const QPalette &QWidget::palette() const { @@ -4690,9 +4663,8 @@ void QWidget::setFont(const QFont &font) #ifndef QT_NO_STYLE_STYLESHEET const QStyleSheetStyle* style; - if (d->extra && (style = qobject_cast<const QStyleSheetStyle*>(d->extra->style))) { + if (d->extra && (style = qt_styleSheet(d->extra->style))) style->saveWidgetFont(this, font); - } #endif setAttribute(Qt::WA_SetFont, font.resolve() != 0); @@ -4788,7 +4760,7 @@ void QWidgetPrivate::updateFont(const QFont &font) Q_Q(QWidget); #ifndef QT_NO_STYLE_STYLESHEET const QStyleSheetStyle* cssStyle; - cssStyle = extra ? qobject_cast<const QStyleSheetStyle*>(extra->style) : 0; + cssStyle = extra ? qt_styleSheet(extra->style) : 0; const bool useStyleSheetPropagationInWidgetStyles = QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); #endif @@ -6620,9 +6592,12 @@ QWidget *QWidgetPrivate::deepestFocusProxy() const void QWidgetPrivate::setFocus_sys() { Q_Q(QWidget); - // Embedded native widget may have taken the focus; get it back to toplevel if that is the case + // Embedded native widget may have taken the focus; get it back to toplevel + // if that is the case (QTBUG-25852) const QWidget *topLevel = q->window(); - if (topLevel->windowType() != Qt::Popup) { + // Do not activate in case the popup menu opens another application (QTBUG-70810). + if (QGuiApplication::applicationState() == Qt::ApplicationActive + && topLevel->windowType() != Qt::Popup) { if (QWindow *nativeWindow = q->window()->windowHandle()) { if (nativeWindow != QGuiApplication::focusWindow() && q->testAttribute(Qt::WA_WState_Created)) { @@ -6981,8 +6956,10 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second) determineLastFocusChild(second, lastFocusChildOfSecond); // If the tab order is already correct, exit early - if (lastFocusChildOfFirst->d_func()->focus_next == second) + if (lastFocusChildOfFirst == second || + lastFocusChildOfFirst->d_func()->focus_next == second) { return; + } // Note that we need to handle two different sections in the tab chain; The section // that 'first' belongs to (firstSection), where we are about to insert 'second', and @@ -7381,7 +7358,8 @@ QByteArray QWidget::saveGeometry() const // Version history: // - Qt 4.2 - 4.8.6, 5.0 - 5.3 : Version 1.0 // - Qt 4.8.6 - today, 5.4 - today: Version 2.0, save screen width in addition to check for high DPI scaling. - quint16 majorVersion = 2; + // - Qt 5.12 - today : Version 3.0, save QWidget::geometry() + quint16 majorVersion = 3; quint16 minorVersion = 0; const int screenNumber = QDesktopWidgetPrivate::screenNumber(this); stream << magicNumber @@ -7397,7 +7375,8 @@ QByteArray QWidget::saveGeometry() const << qint32(screenNumber) << quint8(windowState() & Qt::WindowMaximized) << quint8(windowState() & Qt::WindowFullScreen) - << qint32(QDesktopWidgetPrivate::screenGeometry(screenNumber).width()); // 1.1 onwards + << qint32(QDesktopWidgetPrivate::screenGeometry(screenNumber).width()) // added in 2.0 + << geometry(); // added in 3.0 return array; } @@ -7437,7 +7416,7 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) if (storedMagicNumber != magicNumber) return false; - const quint16 currentMajorVersion = 2; + const quint16 currentMajorVersion = 3; quint16 majorVersion = 0; quint16 minorVersion = 0; @@ -7448,7 +7427,8 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) // (Allow all minor versions.) QRect restoredFrameGeometry; - QRect restoredNormalGeometry; + QRect restoredGeometry; + QRect restoredNormalGeometry; qint32 restoredScreenNumber; quint8 maximized; quint8 fullScreen; @@ -7462,6 +7442,10 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) if (majorVersion > 1) stream >> restoredScreenWidth; + if (majorVersion > 2) + stream >> restoredGeometry; + + // ### Qt 6 - Perhaps it makes sense to dumb down the restoreGeometry() logic, see QTBUG-69104 if (restoredScreenNumber >= QDesktopWidgetPrivate::numScreens()) restoredScreenNumber = QDesktopWidgetPrivate::primaryScreen(); @@ -7548,14 +7532,11 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) setWindowState(ws); d_func()->topData()->normalGeometry = restoredNormalGeometry; } else { - QPoint offset; -#if 0 // Used to be included in Qt4 for Q_WS_X11 - if (isFullScreen()) - offset = d_func()->topData()->fullScreenOffset; -#endif setWindowState(windowState() & ~(Qt::WindowMaximized | Qt::WindowFullScreen)); - move(restoredFrameGeometry.topLeft() + offset); - resize(restoredNormalGeometry.size()); + if (majorVersion > 2) + setGeometry(restoredGeometry); + else + setGeometry(restoredNormalGeometry); } return true; } @@ -10107,20 +10088,24 @@ void QWidget::hideEvent(QHideEvent *) which are passed in the \a message parameter. In your reimplementation of this function, if you want to stop the - event being handled by Qt, return true and set \a result. - If you return false, this native event is passed back to Qt, - which translates the event into a Qt event and sends it to the widget. + event being handled by Qt, return true and set \a result. The \a result + parameter has meaning only on Windows. If you return false, this native + event is passed back to Qt, which translates the event into a Qt event + and sends it to the widget. - \note Events are only delivered to this event handler if the widget is - has a native Window handle. + \note Events are only delivered to this event handler if the widget + has a native window handle. \note This function superseedes the event filter functions x11Event(), winEvent() and macEvent() of Qt 4. + \sa QAbstractNativeEventFilter + \table \header \li Platform \li Event Type Identifier \li Message Type \li Result Type \row \li Windows \li "windows_generic_MSG" \li MSG * \li LRESULT \row \li macOS \li "NSEvent" \li NSEvent * \li + \row \li XCB \li "xcb_generic_event_t" \li xcb_generic_event_t * \li \endtable */ @@ -11214,7 +11199,6 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) break; } case Qt::WA_DropSiteRegistered: { - d->registerDropSite(on); for (int i = 0; i < d->children.size(); ++i) { QWidget *w = qobject_cast<QWidget *>(d->children.at(i)); if (w && !w->isWindow() && !w->testAttribute(Qt::WA_AcceptDrops) && w->testAttribute(Qt::WA_DropSiteRegistered) != on) diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index 9f9f167002..9d5fe89c70 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -714,6 +714,7 @@ private: friend class QWidgetWindow; friend class QAccessibleWidget; friend class QAccessibleTable; + friend class QAccessibleTabButton; #ifndef QT_NO_GESTURES friend class QGestureManager; friend class QWinNativePanGestureRecognizer; diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index e8b550b1cd..c2fc27a9ad 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -395,7 +395,7 @@ public: void setLocale_helper(const QLocale &l, bool forceUpdate = false); void resolveLocale(); - void setStyle_helper(QStyle *newStyle, bool propagate, bool metalHack = false); + void setStyle_helper(QStyle *newStyle, bool propagate); void inheritStyle(); void setUpdatesEnabled_helper(bool ); @@ -453,7 +453,7 @@ public: // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). void invalidateBuffer(const QRegion &); void invalidateBuffer(const QRect &); - bool isOverlapped(const QRect&) const; + QRegion overlappedRegion(const QRect &rect, bool breakAfterFirst = false) const; void syncBackingStore(); void syncBackingStore(const QRegion ®ion); @@ -483,7 +483,6 @@ public: void _q_showIfNotHidden(); void setEnabled_helper(bool); - void registerDropSite(bool); static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); void updateFrameStrut(); diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 3b093283cd..53769ef9ed 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -59,6 +59,7 @@ #include <private/qgraphicseffect_p.h> #endif #include <QtGui/private/qwindow_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <qpa/qplatformbackingstore.h> @@ -759,7 +760,7 @@ void QWidgetBackingStore::updateLists(QWidget *cur) QList<QObject*> children = cur->children(); for (int i = 0; i < children.size(); ++i) { QWidget *child = qobject_cast<QWidget*>(children.at(i)); - if (!child) + if (!child || child->isWindow()) continue; updateLists(child); @@ -793,6 +794,25 @@ QWidgetBackingStore::~QWidgetBackingStore() delete dirtyOnScreenWidgets; } +static QVector<QRect> getSortedRectsToScroll(const QRegion ®ion, int dx, int dy) +{ + QVector<QRect> rects; + std::copy(region.begin(), region.end(), std::back_inserter(rects)); + if (rects.count() > 1) { + std::sort(rects.begin(), rects.end(), [=](const QRect &r1, const QRect &r2) { + if (r1.y() == r2.y()) { + if (dx > 0) + return r1.x() > r2.x(); + return r1.x() < r2.x(); + } + if (dy > 0) + return r1.y() > r2.y(); + return r1.y() < r2.y(); + }); + } + return rects; +} + //parent's coordinates; move whole rect; update parent and widget //assume the screen blt has already been done, so we don't need to refresh that part void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) @@ -820,12 +840,12 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) const QRect parentRect(rect & clipR); const bool nativeWithTextureChild = textureChildSeen && q->internalWinId(); - bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild + const bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild #if QT_CONFIG(graphicsview) // No accelerate move for proxy widgets. && !tlw->d_func()->extra->proxyWidget #endif - && !isOverlapped(sourceRect) && !isOverlapped(destRect); + ; if (!accelerateMove) { QRegion parentR(effectiveRectFor(parentRect)); @@ -841,18 +861,39 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) QWidgetBackingStore *wbs = x->backingStoreTracker.data(); QRegion childExpose(newRect & clipR); + QRegion overlappedExpose; - if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) - childExpose -= destRect; + if (sourceRect.isValid()) { + overlappedExpose = (overlappedRegion(sourceRect) | overlappedRegion(destRect)) & clipR; + + const qreal factor = QHighDpiScaling::factor(q->windowHandle()); + if (overlappedExpose.isEmpty() || qFloor(factor) == factor) { + const QVector<QRect> rectsToScroll + = getSortedRectsToScroll(QRegion(sourceRect) - overlappedExpose, dx, dy); + for (QRect rect : rectsToScroll) { + if (wbs->bltRect(rect, dx, dy, pw)) { + childExpose -= rect.translated(dx, dy); + } + } + } + + childExpose -= overlappedExpose; + } if (!pw->updatesEnabled()) return; const bool childUpdatesEnabled = q->updatesEnabled(); - if (childUpdatesEnabled && !childExpose.isEmpty()) { - childExpose.translate(-data.crect.topLeft()); - wbs->markDirty(childExpose, q); - isMoved = true; + if (childUpdatesEnabled) { + if (!overlappedExpose.isEmpty()) { + overlappedExpose.translate(-data.crect.topLeft()); + invalidateBuffer(overlappedExpose); + } + if (!childExpose.isEmpty()) { + childExpose.translate(-data.crect.topLeft()); + wbs->markDirty(childExpose, q); + isMoved = true; + } } QRegion parentExpose(parentRect); @@ -888,13 +929,12 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_SCROLL") == 0; - QRect scrollRect = rect & clipRect(); - bool overlapped = false; - bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent) - && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); + const QRect clipR = clipRect(); + const QRect scrollRect = rect & clipR; + const bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent); if (!accelerateScroll) { - if (overlapped) { + if (!overlappedRegion(scrollRect.translated(data.crect.topLeft()), true).isEmpty()) { QRegion region(scrollRect); subtractOpaqueSiblings(region); invalidateBuffer(region); @@ -906,12 +946,23 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; const QRect sourceRect = destRect.translated(-dx, -dy); + const QRegion overlappedExpose = (overlappedRegion(scrollRect.translated(data.crect.topLeft()))) + .translated(-data.crect.topLeft()) & clipR; QRegion childExpose(scrollRect); - if (sourceRect.isValid()) { - if (wbs->bltRect(sourceRect, dx, dy, q)) - childExpose -= destRect; + + const qreal factor = QHighDpiScaling::factor(q->windowHandle()); + if (overlappedExpose.isEmpty() || qFloor(factor) == factor) { + const QVector<QRect> rectsToScroll + = getSortedRectsToScroll(QRegion(sourceRect) - overlappedExpose, dx, dy); + for (const QRect &rect : rectsToScroll) { + if (wbs->bltRect(rect, dx, dy, q)) { + childExpose -= rect.translated(dx, dy); + } + } } + childExpose -= overlappedExpose; + if (inDirtyList) { if (rect == q->rect()) { dirty.translate(dx, dy); @@ -928,6 +979,8 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) if (!q->updatesEnabled()) return; + if (!overlappedExpose.isEmpty()) + invalidateBuffer(overlappedExpose); if (!childExpose.isEmpty()) { wbs->markDirty(childExpose, q); isScrolled = true; @@ -991,7 +1044,7 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) } } - if (QWidgetPrivate::get(tlw)->textureChildSeen) { + if (QWidgetPrivate::get(widget)->textureChildSeen) { // No render-to-texture widgets in the (sub-)tree due to hidden or native // children. Returning null results in using the normal backingstore flush path // without OpenGL-based compositing. This is very desirable normally. However, diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 1f3057b008..7292c795b8 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -311,8 +311,10 @@ bool QWidgetWindow::event(QEvent *event) #if QT_CONFIG(draganddrop) case QEvent::DragEnter: + handleDragEnterEvent(static_cast<QDragEnterEvent *>(event)); + return true; case QEvent::DragMove: - handleDragEnterMoveEvent(static_cast<QDragMoveEvent *>(event)); + handleDragMoveEvent(static_cast<QDragMoveEvent *>(event)); return true; case QEvent::DragLeave: handleDragLeaveEvent(static_cast<QDragLeaveEvent *>(event)); @@ -841,6 +843,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event) QPoint mapped = widget->mapFrom(rootWidget, pos); QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); + translated.setTimestamp(event->timestamp()); QGuiApplication::forwardEvent(widget, &translated, event); } @@ -848,62 +851,80 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event) #if QT_CONFIG(draganddrop) -void QWidgetWindow::handleDragEnterMoveEvent(QDragMoveEvent *event) +static QWidget *findDnDTarget(QWidget *parent, const QPoint &pos) { - Q_ASSERT(event->type() ==QEvent::DragMove || !m_dragTarget); // Find a target widget under mouse that accepts drops (QTBUG-22987). - QWidget *widget = m_widget->childAt(event->pos()); + QWidget *widget = parent->childAt(pos); if (!widget) - widget = m_widget; + widget = parent; for ( ; widget && !widget->isWindow() && !widget->acceptDrops(); widget = widget->parentWidget()) ; if (widget && !widget->acceptDrops()) - widget = 0; - // Target widget unchanged: DragMove - if (widget && widget == m_dragTarget.data()) { - Q_ASSERT(event->type() == QEvent::DragMove); - const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); - QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); - translated.setDropAction(event->dropAction()); - if (event->isAccepted()) { // Handling 'DragEnter' should suffice for the application. - translated.accept(); - translated.setDropAction(event->dropAction()); - } - QGuiApplication::forwardEvent(widget, &translated, event); - if (translated.isAccepted()) { - event->accept(); - } else { - event->ignore(); - } - event->setDropAction(translated.dropAction()); - return; - } - // Target widget changed: Send DragLeave to previous, DragEnter to new if there is any - if (m_dragTarget.data()) { - QDragLeaveEvent le; - QGuiApplication::forwardEvent(m_dragTarget.data(), &le, event); - m_dragTarget = 0; - } + widget = nullptr; + return widget; +} + +void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget) +{ + Q_ASSERT(m_dragTarget == nullptr); + if (!widget) + widget = findDnDTarget(m_widget, event->pos()); if (!widget) { - event->ignore(); - return; + event->ignore(); + return; } m_dragTarget = widget; + const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); - QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); - QGuiApplication::forwardEvent(widget, &translated, event); - if (translated.isAccepted()) { - event->accept(); - } else { + QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(), + event->mouseButtons(), event->keyboardModifiers()); + translated.setDropAction(event->dropAction()); + translated.setAccepted(event->isAccepted()); + QGuiApplication::forwardEvent(m_dragTarget, &translated, event); + event->setAccepted(translated.isAccepted()); + event->setDropAction(translated.dropAction()); +} + +void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event) +{ + auto *widget = findDnDTarget(m_widget, event->pos()); + if (!widget) { event->ignore(); + if (m_dragTarget) { // Send DragLeave to previous + QDragLeaveEvent leaveEvent; + QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event); + m_dragTarget = nullptr; + } + } else { + const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); + QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(), + event->mouseButtons(), event->keyboardModifiers()); + translated.setDropAction(event->dropAction()); + translated.setAccepted(event->isAccepted()); + + if (widget == m_dragTarget) { // Target widget unchanged: Send DragMove + QGuiApplication::forwardEvent(m_dragTarget, &translated, event); + } else { + if (m_dragTarget) { // Send DragLeave to previous + QDragLeaveEvent leaveEvent; + QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event); + m_dragTarget = nullptr; + } + // Send DragEnter to new widget. + handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget); + // The drag enter event is always immediately followed by a drag move event, + // see QDragEnterEvent documentation. + QGuiApplication::forwardEvent(m_dragTarget, &translated, event); + } + event->setAccepted(translated.isAccepted()); + event->setDropAction(translated.dropAction()); } - event->setDropAction(translated.dropAction()); } void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event) { if (m_dragTarget) - QGuiApplication::forwardEvent(m_dragTarget.data(), event); - m_dragTarget = 0; + QGuiApplication::forwardEvent(m_dragTarget, event); + m_dragTarget = nullptr; } void QWidgetWindow::handleDropEvent(QDropEvent *event) @@ -913,13 +934,12 @@ void QWidgetWindow::handleDropEvent(QDropEvent *event) event->ignore(); return; } - const QPoint mapped = m_dragTarget.data()->mapFromGlobal(m_widget->mapToGlobal(event->pos())); + const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); - QGuiApplication::forwardEvent(m_dragTarget.data(), &translated, event); - if (translated.isAccepted()) - event->accept(); + QGuiApplication::forwardEvent(m_dragTarget, &translated, event); + event->setAccepted(translated.isAccepted()); event->setDropAction(translated.dropAction()); - m_dragTarget = 0; + m_dragTarget = nullptr; } #endif // QT_CONFIG(draganddrop) @@ -957,7 +977,10 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) } if (exposed) { + // QTBUG-39220, QTBUG-58575: set all (potentially fully obscured parent widgets) mapped. m_widget->setAttribute(Qt::WA_Mapped); + for (QWidget *p = m_widget->parentWidget(); p && !p->testAttribute(Qt::WA_Mapped); p = p->parentWidget()) + p->setAttribute(Qt::WA_Mapped); if (!event->region().isNull()) wPriv->syncBackingStore(event->region()); } else { @@ -1021,6 +1044,7 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(), event->rotation(), event->z(), event->modifiers(), event->uniqueId(), event->button(), event->buttons()); ev.setTimestamp(event->timestamp()); + ev.setAccepted(false); QGuiApplication::forwardEvent(widget, &ev, event); event->setAccepted(ev.isAccepted()); } diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index ead099390e..0728135467 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -96,7 +96,8 @@ protected: void handleWheelEvent(QWheelEvent *); #endif #if QT_CONFIG(draganddrop) - void handleDragEnterMoveEvent(QDragMoveEvent *); + void handleDragEnterEvent(QDragEnterEvent *, QWidget *widget = nullptr); + void handleDragMoveEvent(QDragMoveEvent *); void handleDragLeaveEvent(QDragLeaveEvent *); void handleDropEvent(QDropEvent *); #endif diff --git a/src/widgets/qtwidgets.tracepoints b/src/widgets/qtwidgets.tracepoints new file mode 100644 index 0000000000..01a1383670 --- /dev/null +++ b/src/widgets/qtwidgets.tracepoints @@ -0,0 +1,4 @@ +QApplication_notify_entry(QObject *receiver, QEvent *event, int type) +QApplication_notify_event_filtered(QObject *receiver, QEvent *event, int type) +QApplication_notify_before_delivery(QObject *receiver, QEvent *event, int type) +QApplication_notify_after_delivery(QObject *receiver, QEvent *event, int type, bool consumed) diff --git a/src/widgets/styles/images/titlebar-contexthelp-16.png b/src/widgets/styles/images/titlebar-contexthelp-16.png Binary files differnew file mode 100644 index 0000000000..2cead19910 --- /dev/null +++ b/src/widgets/styles/images/titlebar-contexthelp-16.png diff --git a/src/widgets/styles/images/titlebar-contexthelp-32.png b/src/widgets/styles/images/titlebar-contexthelp-32.png Binary files differnew file mode 100644 index 0000000000..1cd4843d5e --- /dev/null +++ b/src/widgets/styles/images/titlebar-contexthelp-32.png diff --git a/src/widgets/styles/images/titlebar-contexthelp-48.png b/src/widgets/styles/images/titlebar-contexthelp-48.png Binary files differnew file mode 100644 index 0000000000..9b170687be --- /dev/null +++ b/src/widgets/styles/images/titlebar-contexthelp-48.png diff --git a/src/widgets/styles/images/titlebar-max-16.png b/src/widgets/styles/images/titlebar-max-16.png Binary files differnew file mode 100644 index 0000000000..101a7eac2b --- /dev/null +++ b/src/widgets/styles/images/titlebar-max-16.png diff --git a/src/widgets/styles/images/titlebar-max-32.png b/src/widgets/styles/images/titlebar-max-32.png Binary files differnew file mode 100644 index 0000000000..529c54f61d --- /dev/null +++ b/src/widgets/styles/images/titlebar-max-32.png diff --git a/src/widgets/styles/images/titlebar-max-48.png b/src/widgets/styles/images/titlebar-max-48.png Binary files differnew file mode 100644 index 0000000000..cfa0b67edf --- /dev/null +++ b/src/widgets/styles/images/titlebar-max-48.png diff --git a/src/widgets/styles/images/titlebar-min-16.png b/src/widgets/styles/images/titlebar-min-16.png Binary files differnew file mode 100644 index 0000000000..95e714b522 --- /dev/null +++ b/src/widgets/styles/images/titlebar-min-16.png diff --git a/src/widgets/styles/images/titlebar-min-32.png b/src/widgets/styles/images/titlebar-min-32.png Binary files differnew file mode 100644 index 0000000000..0b9afedecf --- /dev/null +++ b/src/widgets/styles/images/titlebar-min-32.png diff --git a/src/widgets/styles/images/titlebar-min-48.png b/src/widgets/styles/images/titlebar-min-48.png Binary files differnew file mode 100644 index 0000000000..b59a336d36 --- /dev/null +++ b/src/widgets/styles/images/titlebar-min-48.png diff --git a/src/widgets/styles/images/titlebar-shade-16.png b/src/widgets/styles/images/titlebar-shade-16.png Binary files differnew file mode 100644 index 0000000000..cc870a1e5c --- /dev/null +++ b/src/widgets/styles/images/titlebar-shade-16.png diff --git a/src/widgets/styles/images/titlebar-shade-32.png b/src/widgets/styles/images/titlebar-shade-32.png Binary files differnew file mode 100644 index 0000000000..b785b8e216 --- /dev/null +++ b/src/widgets/styles/images/titlebar-shade-32.png diff --git a/src/widgets/styles/images/titlebar-shade-48.png b/src/widgets/styles/images/titlebar-shade-48.png Binary files differnew file mode 100644 index 0000000000..42b75b4a0c --- /dev/null +++ b/src/widgets/styles/images/titlebar-shade-48.png diff --git a/src/widgets/styles/images/titlebar-unshade-16.png b/src/widgets/styles/images/titlebar-unshade-16.png Binary files differnew file mode 100644 index 0000000000..ef19de6c2f --- /dev/null +++ b/src/widgets/styles/images/titlebar-unshade-16.png diff --git a/src/widgets/styles/images/titlebar-unshade-32.png b/src/widgets/styles/images/titlebar-unshade-32.png Binary files differnew file mode 100644 index 0000000000..9f74bb0ac7 --- /dev/null +++ b/src/widgets/styles/images/titlebar-unshade-32.png diff --git a/src/widgets/styles/images/titlebar-unshade-48.png b/src/widgets/styles/images/titlebar-unshade-48.png Binary files differnew file mode 100644 index 0000000000..bd17c3cf48 --- /dev/null +++ b/src/widgets/styles/images/titlebar-unshade-48.png diff --git a/src/widgets/styles/images/toolbar-ext-h-16.png b/src/widgets/styles/images/toolbar-ext-h-16.png Binary files differnew file mode 100644 index 0000000000..c6bd1b1784 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-16.png diff --git a/src/widgets/styles/images/toolbar-ext-h-32.png b/src/widgets/styles/images/toolbar-ext-h-32.png Binary files differnew file mode 100644 index 0000000000..99c62698f2 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-32.png diff --git a/src/widgets/styles/images/toolbar-ext-h-8.png b/src/widgets/styles/images/toolbar-ext-h-8.png Binary files differnew file mode 100644 index 0000000000..340a374bce --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-8.png diff --git a/src/widgets/styles/images/toolbar-ext-h-rtl-16.png b/src/widgets/styles/images/toolbar-ext-h-rtl-16.png Binary files differnew file mode 100644 index 0000000000..31c72892b4 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-rtl-16.png diff --git a/src/widgets/styles/images/toolbar-ext-h-rtl-32.png b/src/widgets/styles/images/toolbar-ext-h-rtl-32.png Binary files differnew file mode 100644 index 0000000000..bfc333daac --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-rtl-32.png diff --git a/src/widgets/styles/images/toolbar-ext-h-rtl-8.png b/src/widgets/styles/images/toolbar-ext-h-rtl-8.png Binary files differnew file mode 100644 index 0000000000..538e408310 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-h-rtl-8.png diff --git a/src/widgets/styles/images/toolbar-ext.png b/src/widgets/styles/images/toolbar-ext-macstyle.png Binary files differindex 37bd403ff8..37bd403ff8 100644 --- a/src/widgets/styles/images/toolbar-ext.png +++ b/src/widgets/styles/images/toolbar-ext-macstyle.png diff --git a/src/widgets/styles/images/toolbar-ext@2x.png b/src/widgets/styles/images/toolbar-ext-macstyle@2x.png Binary files differindex 6fc729efb0..6fc729efb0 100644 --- a/src/widgets/styles/images/toolbar-ext@2x.png +++ b/src/widgets/styles/images/toolbar-ext-macstyle@2x.png diff --git a/src/widgets/styles/images/toolbar-ext-v-10.png b/src/widgets/styles/images/toolbar-ext-v-10.png Binary files differnew file mode 100644 index 0000000000..2a6d0e4c70 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-v-10.png diff --git a/src/widgets/styles/images/toolbar-ext-v-20.png b/src/widgets/styles/images/toolbar-ext-v-20.png Binary files differnew file mode 100644 index 0000000000..adc27f52b5 --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-v-20.png diff --git a/src/widgets/styles/images/toolbar-ext-v-5.png b/src/widgets/styles/images/toolbar-ext-v-5.png Binary files differnew file mode 100644 index 0000000000..21c670446c --- /dev/null +++ b/src/widgets/styles/images/toolbar-ext-v-5.png diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 735ae6b080..66f5f4876e 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -938,55 +938,53 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt viewItemTextLayout(textLayout, textRect.width()); - QString elidedText; - qreal height = 0; - qreal width = 0; - int elidedIndex = -1; - const int lineCount = textLayout.lineCount(); - for (int j = 0; j < lineCount; ++j) { - const QTextLine line = textLayout.lineAt(j); - if (j + 1 <= lineCount - 1) { - const QTextLine nextLine = textLayout.lineAt(j + 1); - if ((nextLine.y() + nextLine.height()) > textRect.height()) { - int start = line.textStart(); - int length = line.textLength() + nextLine.textLength(); - const QStackTextEngine engine(textLayout.text().mid(start, length), option->font); - elidedText = engine.elidedText(option->textElideMode, textRect.width()); - height += line.height(); - width = textRect.width(); - elidedIndex = j; - break; - } - } - if (line.naturalTextWidth() > textRect.width()) { - int start = line.textStart(); - int length = line.textLength(); - const QStackTextEngine engine(textLayout.text().mid(start, length), option->font); - elidedText = engine.elidedText(option->textElideMode, textRect.width()); - height += line.height(); - width = textRect.width(); - elidedIndex = j; - break; - } - width = qMax<qreal>(width, line.width()); - height += line.height(); - } - + const QRectF boundingRect = textLayout.boundingRect(); const QRect layoutRect = QStyle::alignedRect(option->direction, option->displayAlignment, - QSize(int(width), int(height)), textRect); + boundingRect.size().toSize(), textRect); const QPointF position = layoutRect.topLeft(); + const int lineCount = textLayout.lineCount(); + + qreal height = 0; for (int i = 0; i < lineCount; ++i) { const QTextLine line = textLayout.lineAt(i); - if (i == elidedIndex) { - qreal x = position.x() + line.x(); - qreal y = position.y() + line.y() + line.ascent(); + height += line.height(); + + // above visible rect + if (height + layoutRect.top() <= textRect.top()) + continue; + + const int start = line.textStart(); + const int length = line.textLength(); + + const bool drawElided = line.naturalTextWidth() > textRect.width(); + bool elideLastVisibleLine = false; + if (!drawElided && i + 1 < lineCount) { + const QTextLine nextLine = textLayout.lineAt(i + 1); + const int nextHeight = height + nextLine.height() / 2; + // elide when less than the next half line is visible + if (nextHeight + layoutRect.top() > textRect.height() + textRect.top()) + elideLastVisibleLine = true; + } + + if (drawElided || elideLastVisibleLine) { + QString text = textLayout.text().mid(start, length); + if (elideLastVisibleLine) + text += QChar(0x2026); + const QStackTextEngine engine(text, option->font); + const QString elidedText = engine.elidedText(option->textElideMode, textRect.width()); + const QPointF pos(position.x() + line.x(), + position.y() + line.y() + line.ascent()); p->save(); p->setFont(option->font); - p->drawText(QPointF(x, y), elidedText); + p->drawText(pos, elidedText); p->restore(); - break; + } else { + line.draw(p, position); } - line.draw(p, position); + + // below visible text, can stop + if (height + layoutRect.top() >= textRect.bottom()) + break; } } @@ -1675,8 +1673,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, alignment |= Qt::AlignLeft | Qt::AlignVCenter; } tr.translate(shiftX, shiftY); + const QString text = toolbutton->fontMetrics.elidedText(toolbutton->text, Qt::ElideMiddle, tr.width()); proxy()->drawItemText(p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette, - toolbutton->state & State_Enabled, toolbutton->text, + toolbutton->state & State_Enabled, text, QPalette::ButtonText); } else { rect.translate(shiftX, shiftY); @@ -2863,8 +2862,8 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, case SE_TabBarScrollLeftButton: { const bool vertical = opt->rect.width() < opt->rect.height(); const Qt::LayoutDirection ld = widget->layoutDirection(); - const int buttonWidth = qMax(pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width()); - const int buttonOverlap = pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, widget); + const int buttonWidth = qMax(proxy()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width()); + const int buttonOverlap = proxy()->pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, widget); r = vertical ? QRect(0, opt->rect.height() - (buttonWidth * 2) + buttonOverlap, opt->rect.width(), buttonWidth) : QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - (buttonWidth * 2) + buttonOverlap, 0, buttonWidth, opt->rect.height())); @@ -2872,7 +2871,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, case SE_TabBarScrollRightButton: { const bool vertical = opt->rect.width() < opt->rect.height(); const Qt::LayoutDirection ld = widget->layoutDirection(); - const int buttonWidth = qMax(pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width()); + const int buttonWidth = qMax(proxy()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width()); r = vertical ? QRect(0, opt->rect.height() - buttonWidth, opt->rect.width(), buttonWidth) : QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - buttonWidth, 0, buttonWidth, opt->rect.height())); @@ -3087,7 +3086,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, //have all the information we need (ie. the layout's margin) const QToolBar *tb = qobject_cast<const QToolBar*>(widget); const int margin = tb && tb->layout() ? tb->layout()->margin() : 2; - const int handleExtent = pixelMetric(QStyle::PM_ToolBarHandleExtent, opt, tb); + const int handleExtent = proxy()->pixelMetric(QStyle::PM_ToolBarHandleExtent, opt, tb); if (tbopt->state & QStyle::State_Horizontal) { r = QRect(margin, margin, handleExtent, tbopt->rect.height() - 2*margin); r = QStyle::visualRect(tbopt->direction, tbopt->rect, r); @@ -4942,8 +4941,8 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_SpinBox: if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { // Add button + frame widths - int buttonWidth = 20; - int fw = vopt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, vopt, widget) : 0; + const int buttonWidth = (vopt->subControls & (QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown)) != 0 ? 20 : 0; + const int fw = vopt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, vopt, widget) : 0; sz += QSize(buttonWidth + 2*fw, 2*fw); } break; @@ -5312,6 +5311,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget case SH_SpinBox_ButtonsInsideFrame: ret = true; break; + case SH_SpinBox_StepModifier: + ret = Qt::ControlModifier; + break; default: ret = 0; break; @@ -5724,14 +5726,14 @@ static inline QString iconPngSuffix() { return QStringLiteral(".png"); } static void addIconFiles(const QString &prefix, const int sizes[], size_t count, QIcon &icon) { - for (size_t i = 0; i < count; ++i) { - const int size = sizes[i]; - icon.addFile(prefix + QString::number(size) + iconPngSuffix(), QSize(size, size)); - } + for (size_t i = 0; i < count; ++i) + icon.addFile(prefix + QString::number(sizes[i]) + iconPngSuffix()); } static const int dockTitleIconSizes[] = {10, 16, 20, 32, 48, 64}; - +static const int titleBarSizes[] = {16, 32, 48}; +static const int toolBarExtHSizes[] = {8, 16, 32}; +static const int toolBarExtVSizes[] = {5, 10, 20}; #endif // imageformat_png /*! @@ -6046,6 +6048,27 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG + case SP_TitleBarMinButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-min-"), + titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon); + break; + case SP_TitleBarMaxButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-max-"), + titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon); + break; + case SP_TitleBarShadeButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-shade-"), + titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon); + + break; + case SP_TitleBarUnshadeButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-unshade-"), + titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon); + break; + case SP_TitleBarContextHelpButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-contexthelp-"), + titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon); + break; case SP_FileDialogNewFolder: icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-16.png"), QSize(16, 16)); icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-32.png"), QSize(32, 32)); @@ -6254,6 +6277,17 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption addIconFiles(iconResourcePrefix() + QStringLiteral("normalizedockup-"), dockTitleIconSizes, sizeof(dockTitleIconSizes)/sizeof(dockTitleIconSizes[0]), icon); break; + case SP_ToolBarHorizontalExtensionButton: { + QString prefix = iconResourcePrefix() + QStringLiteral("toolbar-ext-h-"); + if (rtl) + prefix += QStringLiteral("rtl-"); + addIconFiles(prefix, toolBarExtHSizes, sizeof(toolBarExtHSizes)/sizeof(toolBarExtHSizes[0]), icon); + } + break; + case SP_ToolBarVerticalExtensionButton: + addIconFiles(iconResourcePrefix() + QStringLiteral("toolbar-ext-v-"), + toolBarExtVSizes, sizeof(toolBarExtVSizes)/sizeof(toolBarExtVSizes[0]), icon); + break; #endif // QT_NO_IMAGEFORMAT_PNG default: icon.addPixmap(proxy()->standardPixmap(standardIcon, option, widget)); diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 73a6554f1a..8006be8c27 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -2001,6 +2001,13 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, Determnines if the spin box buttons are inside the line edit frame. This enum value has been introduced in Qt 5.11. + \value SH_SpinBox_StepModifier + Determines which Qt::KeyboardModifier increases the step rate of + QAbstractSpinBox. Possible values are Qt::NoModifier, + Qt::ControlModifier (default) or Qt::ShiftModifier. Qt::NoModifier + disables this feature. + This enum value has been introduced in Qt 5.12. + \sa styleHint() */ diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index cef569d514..9192dae864 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -741,6 +741,7 @@ public: SH_Widget_Animation_Duration, SH_ComboBox_AllowWheelScrolling, SH_SpinBox_ButtonsInsideFrame, + SH_SpinBox_StepModifier, // Add new style hint values here SH_CustomBase = 0xf0000000 diff --git a/src/widgets/styles/qstyle.qrc b/src/widgets/styles/qstyle.qrc index 2dc3207e6d..d3511ee754 100644 --- a/src/widgets/styles/qstyle.qrc +++ b/src/widgets/styles/qstyle.qrc @@ -140,13 +140,37 @@ <file>images/normalizedockup-32.png</file> <file>images/normalizedockup-48.png</file> <file>images/normalizedockup-64.png</file> + <file>images/toolbar-ext-h-8.png</file> + <file>images/toolbar-ext-h-16.png</file> + <file>images/toolbar-ext-h-32.png</file> + <file>images/toolbar-ext-h-rtl-8.png</file> + <file>images/toolbar-ext-h-rtl-16.png</file> + <file>images/toolbar-ext-h-rtl-32.png</file> + <file>images/toolbar-ext-v-5.png</file> + <file>images/toolbar-ext-v-10.png</file> + <file>images/toolbar-ext-v-20.png</file> + <file>images/titlebar-contexthelp-16.png</file> + <file>images/titlebar-contexthelp-32.png</file> + <file>images/titlebar-contexthelp-48.png</file> + <file>images/titlebar-max-16.png</file> + <file>images/titlebar-max-32.png</file> + <file>images/titlebar-max-48.png</file> + <file>images/titlebar-min-16.png</file> + <file>images/titlebar-min-32.png</file> + <file>images/titlebar-min-48.png</file> + <file>images/titlebar-shade-16.png</file> + <file>images/titlebar-shade-32.png</file> + <file>images/titlebar-shade-48.png</file> + <file>images/titlebar-unshade-16.png</file> + <file>images/titlebar-unshade-32.png</file> + <file>images/titlebar-unshade-48.png</file> </qresource> <qresource prefix="/qt-project.org/styles/macstyle"> <file alias="images/closedock-16.png">images/closedock-macstyle-16.png</file> <file alias="images/closedock-down-16.png">images/closedock-down-macstyle-16.png</file> <file alias="images/dockdock-16.png">images/dockdock-macstyle-16.png</file> <file alias="images/dockdock-down-16.png">images/dockdock-down-macstyle-16.png</file> - <file>images/toolbar-ext.png</file> - <file>images/toolbar-ext@2x.png</file> + <file alias="images/toolbar-ext.png">images/toolbar-ext-macstyle.png</file> + <file alias="images/toolbar-ext@2x.png">images/toolbar-ext-macstyle@2x.png</file> </qresource> </RCC> diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp index 8679d96eda..0b910d46df 100644 --- a/src/widgets/styles/qstylehelper.cpp +++ b/src/widgets/styles/qstylehelper.cpp @@ -403,14 +403,6 @@ QColor backgroundColor(const QPalette &pal, const QWidget* widget) return pal.color(QPalette::Base); } -QWindow *styleObjectWindow(QObject *so) -{ - if (so) - return so->property("_q_styleObjectWindow").value<QWindow *>(); - - return 0; -} - WidgetSizePolicy widgetSizePolicy(const QWidget *widget, const QStyleOption *opt) { while (widget) { diff --git a/src/widgets/styles/qstylehelper_p.h b/src/widgets/styles/qstylehelper_p.h index 260860bf4d..d79dfe4288 100644 --- a/src/widgets/styles/qstylehelper_p.h +++ b/src/widgets/styles/qstylehelper_p.h @@ -90,7 +90,6 @@ namespace QStyleHelper Q_WIDGETS_EXPORT bool hasAncestor(QObject *obj, QAccessible::Role role); #endif Q_WIDGETS_EXPORT QColor backgroundColor(const QPalette &pal, const QWidget* widget = 0); - Q_WIDGETS_EXPORT QWindow *styleObjectWindow(QObject *so); enum WidgetSizePolicy { SizeLarge = 0, SizeSmall = 1, SizeMini = 2, SizeDefault = -1 }; diff --git a/src/widgets/styles/qstyleoption.cpp b/src/widgets/styles/qstyleoption.cpp index e7fa26e2d4..97631a5841 100644 --- a/src/widgets/styles/qstyleoption.cpp +++ b/src/widgets/styles/qstyleoption.cpp @@ -1842,10 +1842,12 @@ QStyleOptionMenuItem::QStyleOptionMenuItem(int version) /*! \variable QStyleOptionMenuItem::tabWidth - \brief the tab width for the menu item + \brief the reserved width for the menu item's shortcut - The tab width is the distance between the text of the menu item - and the shortcut. The default value is 0. + QMenu sets it to the width occupied by the widest shortcut among + all visible items within the menu. + + The default value is 0. */ diff --git a/src/widgets/styles/qstyleoption.h b/src/widgets/styles/qstyleoption.h index 9fbaf34a86..8ae07efc81 100644 --- a/src/widgets/styles/qstyleoption.h +++ b/src/widgets/styles/qstyleoption.h @@ -366,7 +366,7 @@ public: QString text; QIcon icon; int maxIconWidth; - int tabWidth; + int tabWidth; // ### Qt 6: rename to reservedShortcutWidth QFont font; QStyleOptionMenuItem(); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index ceede9e72f..71c7f5449a 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -117,6 +117,8 @@ #include <QtWidgets/qtoolbar.h> #endif +#include <QtGui/qscreen.h> + QT_BEGIN_NAMESPACE using namespace QCss; @@ -532,6 +534,8 @@ public: const QStyleSheetGeometryData *geometry() const { return geo; } const QStyleSheetPositionData *position() const { return p; } + bool hasModification() const; + bool hasPalette() const { return pal != 0; } bool hasBackground() const { return bg != 0 && (!bg->pixmap.isNull() || bg->brush.style() != Qt::NoBrush); } bool hasGradientBackground() const { return bg && bg->brush.style() >= Qt::LinearGradientPattern @@ -952,8 +956,10 @@ QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject Attachment attachment = Attachment_Scroll; origin = Origin_Padding; Origin clip = Origin_Border; - if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip)) - bg = new QStyleSheetBackgroundData(brush, QPixmap(uri), repeat, alignment, origin, attachment, clip); + if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip)) { + bg = new QStyleSheetBackgroundData(brush, QStyleSheetStyle::loadPixmap(uri, object), + repeat, alignment, origin, attachment, clip); + } QBrush sfg, fg; QBrush sbg, abg; @@ -992,7 +998,7 @@ QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject bd->bi = new QStyleSheetBorderImageData; QStyleSheetBorderImageData *bi = bd->bi; - bi->pixmap = QPixmap(uri); + bi->pixmap = QStyleSheetStyle::loadPixmap(uri, object); for (int i = 0; i < 4; i++) bi->cuts[i] = cuts[i]; bi->horizStretch = horizStretch; @@ -1043,7 +1049,7 @@ QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject if (const QWidget *widget = qobject_cast<const QWidget *>(object)) { QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle); if (!style) - style = qobject_cast<QStyleSheetStyle *>(widget->style()); + style = qt_styleSheet(widget->style()); if (style) fixupBorder(style->nativeFrameWidth(widget)); } @@ -1215,30 +1221,33 @@ void QRenderRule::drawBackgroundImage(QPainter *p, const QRect &rect, QPoint off if (background()->attachment == Attachment_Fixed) off = QPoint(0, 0); + QSize bgpSize = bgp.size() / bgp.devicePixelRatio(); + int bgpHeight = bgpSize.height(); + int bgpWidth = bgpSize.width(); QRect r = originRect(rect, background()->origin); - QRect aligned = QStyle::alignedRect(Qt::LeftToRight, background()->position, bgp.size(), r); + QRect aligned = QStyle::alignedRect(Qt::LeftToRight, background()->position, bgpSize, r); QRect inter = aligned.translated(-off).intersected(r); switch (background()->repeat) { case Repeat_Y: p->drawTiledPixmap(inter.x(), r.y(), inter.width(), r.height(), bgp, inter.x() - aligned.x() + off.x(), - bgp.height() - int(aligned.y() - r.y()) % bgp.height() + off.y()); + bgpHeight - int(aligned.y() - r.y()) % bgpHeight + off.y()); break; case Repeat_X: p->drawTiledPixmap(r.x(), inter.y(), r.width(), inter.height(), bgp, - bgp.width() - int(aligned.x() - r.x())%bgp.width() + off.x(), + bgpWidth - int(aligned.x() - r.x())%bgpWidth + off.x(), inter.y() - aligned.y() + off.y()); break; case Repeat_XY: p->drawTiledPixmap(r, bgp, - QPoint(bgp.width() - int(aligned.x() - r.x())% bgp.width() + off.x(), - bgp.height() - int(aligned.y() - r.y())%bgp.height() + off.y())); + QPoint(bgpWidth - int(aligned.x() - r.x())% bgpWidth + off.x(), + bgpHeight - int(aligned.y() - r.y())%bgpHeight + off.y())); break; case Repeat_None: default: p->drawPixmap(inter.x(), inter.y(), bgp, inter.x() - aligned.x() + off.x(), - inter.y() - aligned.y() + off.y(), inter.width(), inter.height()); + inter.y() - aligned.y() + off.y(), bgp.width() , bgp.height()); break; } @@ -1446,6 +1455,21 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q p->setBrush(cg, QPalette::AlternateBase, pal->alternateBackground); } +bool QRenderRule::hasModification() const +{ + return hasPalette() || + hasBackground() || + hasGradientBackground() || + !hasNativeBorder() || + !hasNativeOutline() || + hasBox() || + hasPosition() || + hasGeometry() || + hasImage() || + hasFont || + !styleHints.isEmpty(); +} + /////////////////////////////////////////////////////////////////////////////// // Style rules #define OBJECT_PTR(x) (static_cast<QObject *>(x.ptr)) @@ -1504,7 +1528,7 @@ public: return className; } else if (name == QLatin1String("style")) { QWidget *w = qobject_cast<QWidget *>(obj); - QStyleSheetStyle *proxy = w ? qobject_cast<QStyleSheetStyle *>(w->style()) : 0; + QStyleSheetStyle *proxy = w ? qt_styleSheet(w->style()) : 0; if (proxy) { QString styleName = QString::fromLatin1(proxy->baseStyle()->metaObject()->className()); cache[name] = styleName; @@ -1925,11 +1949,11 @@ QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: - extraClass |= PseudoClass_Left; + extraClass |= PseudoClass_Right; break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: - extraClass |= PseudoClass_Right; + extraClass |= PseudoClass_Left; break; default: break; @@ -1962,11 +1986,11 @@ QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: - extraClass |= PseudoClass_Left; + extraClass |= PseudoClass_Right; break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: - extraClass |= PseudoClass_Right; + extraClass |= PseudoClass_Left; break; default: break; @@ -2736,7 +2760,7 @@ QStyle *QStyleSheetStyle::baseStyle() const { if (base) return base; - if (QStyleSheetStyle *me = qobject_cast<QStyleSheetStyle *>(QApplication::style())) + if (QStyleSheetStyle *me = qt_styleSheet(QApplication::style())) return me->base; return QApplication::style(); } @@ -2825,6 +2849,9 @@ void QStyleSheetStyle::polish(QWidget *w) #endif QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Any); + + w->setAttribute(Qt::WA_StyleSheetTarget, rule.hasModification()); + if (rule.hasDrawable() || rule.hasBox()) { if (w->metaObject() == &QWidget::staticMetaObject #if QT_CONFIG(itemviews) @@ -2908,6 +2935,7 @@ void QStyleSheetStyle::unpolish(QWidget *w) styleSheetCaches->styleSheetCache.remove(w); unsetPalette(w); setGeometry(w); + w->setAttribute(Qt::WA_StyleSheetTarget, false); w->setAttribute(Qt::WA_StyleSheet, false); QObject::disconnect(w, 0, this, 0); #if QT_CONFIG(scrollarea) @@ -3672,6 +3700,17 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q bool dis = !(opt->state & QStyle::State_Enabled), act = opt->state & QStyle::State_Selected; + int checkableOffset = 0; + if (checkable) { + QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); + QStyleOptionMenuItem newMi = mi; + newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); + checkableOffset = newMi.rect.width(); + if (subSubRule.hasDrawable() || checked) + drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); + } + + int iconOffset = 0; if (!mi.icon.isNull()) { QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; if (act && !dis) @@ -3691,20 +3730,22 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q iconRule.geo->height = pixh; } QRect iconRect = positionRect(w, subRule, iconRule, PseudoElement_MenuIcon, opt->rect, opt->direction); + if (opt->direction == Qt::LeftToRight) + iconRect.moveLeft(iconRect.left() + checkableOffset); + else + iconRect.moveRight(iconRect.right() - checkableOffset); iconRule.drawRule(p, iconRect); QRect pmr(0, 0, pixw, pixh); pmr.moveCenter(iconRect.center()); p->drawPixmap(pmr.topLeft(), pixmap); - } else if (checkable) { - QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); - if (subSubRule.hasDrawable() || checked) { - QStyleOptionMenuItem newMi = mi; - newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); - drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); - } + iconOffset = iconRule.geo->width; } QRect textRect = subRule.contentsRect(opt->rect); + if (opt->direction == Qt::LeftToRight) + textRect.setLeft(textRect.left() + checkableOffset + iconOffset); + else + textRect.setRight(textRect.right() - checkableOffset - iconOffset); textRect.setWidth(textRect.width() - mi.tabWidth); QStringRef s(&mi.text); p->setPen(mi.palette.buttonText().color()); @@ -3838,17 +3879,10 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if(hasStyleRule(w, PseudoElement_HeaderViewSection)) { QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection); if (!subRule.hasNativeBorder() || !subRule.baseStyleCanDraw() - || subRule.hasBackground() || subRule.hasPalette() || subRule.hasFont) { + || subRule.hasBackground() || subRule.hasPalette() || subRule.hasFont || subRule.hasBorder()) { ParentStyle::drawControl(ce, opt, p, w); return; } - if (subRule.hasFont) { - const QFont oldFont = p->font(); - p->setFont(subRule.font.resolve(p->font())); - baseStyle()->drawControl(ce, opt, p, w); - p->setFont(oldFont); - return; - } } break; case CE_HeaderSection: @@ -4821,13 +4855,12 @@ int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const return 0; break; - case PM_TabBarScrollButtonWidth: { + case PM_TabBarScrollButtonWidth: subRule = renderRule(w, opt, PseudoElement_TabBarScroller); if (subRule.hasContentsSize()) { QSize sz = subRule.size(); - return sz.width() != -1 ? sz.width() : sz.height(); + return (sz.width() != -1 ? sz.width() : sz.height()) / 2; } - } break; case PM_TabBarTabShiftHorizontal: @@ -5050,6 +5083,16 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op int width = csz.width(); if (mi->text.contains(QLatin1Char('\t'))) width += 12; //as in QCommonStyle + bool checkable = mi->checkType != QStyleOptionMenuItem::NotCheckable; + if (checkable) { + QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); + QRect checkmarkRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); + width += checkmarkRect.width(); + } + if (!mi->icon.isNull()) { + QPixmap pixmap = mi->icon.pixmap(pixelMetric(PM_SmallIconSize)); + width += pixmap.width(); + } return subRule.boxSize(subRule.adjustSize(QSize(width, csz.height()))); } } @@ -5200,7 +5243,7 @@ static QLatin1String propertyNameForStandardPixmap(QStyle::StandardPixmap sp) case QStyle::SP_DialogCloseButton: return QLatin1String("dialog-close-icon"); case QStyle::SP_DialogApplyButton: return QLatin1String("dialog-apply-icon"); case QStyle::SP_DialogResetButton: return QLatin1String("dialog-reset-icon"); - case QStyle::SP_DialogDiscardButton: return QLatin1String("discard-icon"); + case QStyle::SP_DialogDiscardButton: return QLatin1String("dialog-discard-icon"); case QStyle::SP_DialogYesButton: return QLatin1String("dialog-yes-icon"); case QStyle::SP_DialogNoButton: return QLatin1String("dialog-no-icon"); case QStyle::SP_ArrowUp: return QLatin1String("uparrow-icon"); @@ -5876,6 +5919,12 @@ QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, c } break; + case SE_TabBarScrollLeftButton: + case SE_TabBarScrollRightButton: + if (hasStyleRule(w, PseudoElement_TabBarScroller)) + return ParentStyle::subElementRect(se, opt, w); + break; + case SE_TabBarTearIndicator: { QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTear); if (subRule.hasContentsSize()) { @@ -6067,6 +6116,28 @@ bool QStyleSheetStyle::isNaturalChild(const QObject *obj) return false; } +QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context) +{ + qreal ratio = -1.0; + if (const QWidget *widget = qobject_cast<const QWidget *>(context)) { + if (QScreen *screen = QApplication::screenAt(widget->mapToGlobal(QPoint(0, 0)))) + ratio = screen->devicePixelRatio(); + } + + if (ratio < 0) { + if (const QApplication *app = qApp) + ratio = app->devicePixelRatio(); + else + ratio = 1.0; + } + + qreal sourceDevicePixelRatio = 1.0; + QString resolvedFileName = qt_findAtNxFile(fileName, ratio, &sourceDevicePixelRatio); + QPixmap pixmap(resolvedFileName); + pixmap.setDevicePixelRatio(sourceDevicePixelRatio); + return pixmap; +} + QT_END_NAMESPACE #include "moc_qstylesheetstyle_p.cpp" diff --git a/src/widgets/styles/qstylesheetstyle_p.h b/src/widgets/styles/qstylesheetstyle_p.h index 042abf5c22..d4edb83525 100644 --- a/src/widgets/styles/qstylesheetstyle_p.h +++ b/src/widgets/styles/qstylesheetstyle_p.h @@ -167,6 +167,7 @@ private: static Qt::Alignment resolveAlignment(Qt::LayoutDirection, Qt::Alignment); static bool isNaturalChild(const QObject *obj); + static QPixmap loadPixmap(const QString &fileName, const QObject *context); bool initObject(const QObject *obj) const; public: static int numinstances; @@ -215,6 +216,13 @@ template <typename T> class QTypeInfo<QStyleSheetStyleCaches::Tampered<T>> : QTypeInfoMerger<QStyleSheetStyleCaches::Tampered<T>, T> {}; + +// Returns a QStyleSheet from the given style. +inline QStyleSheetStyle* qt_styleSheet(QStyle *style) +{ + return qobject_cast<QStyleSheetStyle *>(style); +} + QT_END_NAMESPACE #endif // QT_NO_STYLE_STYLESHEET #endif // QSTYLESHEETSTYLE_P_H diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 80ce8419f8..12ca5201c1 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -842,17 +842,19 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, : opt->palette.text().color()); if (opt->state & State_NoChange) p->setBrush(opt->palette.brush(QPalette::Button)); - p->drawRect(opt->rect.x() + 1, opt->rect.y() + 1, 11, 11); + p->drawRect(opt->rect.x() + 1, opt->rect.y() + 1, opt->rect.width() - 2, opt->rect.height() - 2); } #endif // QT_CONFIG(itemviews) if (!(opt->state & State_Off)) { QPointF points[6]; - points[0] = { opt->rect.x() + QStyleHelper::dpiScaled(3.5), opt->rect.y() + QStyleHelper::dpiScaled(5.5) }; - points[1] = { points[0].x(), points[0].y() + QStyleHelper::dpiScaled(2) }; - points[2] = { points[1].x() + QStyleHelper::dpiScaled(2), points[1].y() + QStyleHelper::dpiScaled(2) }; - points[3] = { points[2].x() + QStyleHelper::dpiScaled(4), points[2].y() - QStyleHelper::dpiScaled(4) }; - points[4] = { points[3].x(), points[3].y() - QStyleHelper::dpiScaled(2) }; - points[5] = { points[4].x() - QStyleHelper::dpiScaled(4), points[4].y() + QStyleHelper::dpiScaled(4) }; + qreal scaleh = opt->rect.width() / 12.0; + qreal scalev = opt->rect.height() / 12.0; + points[0] = { opt->rect.x() + 3.5 * scaleh, opt->rect.y() + 5.5 * scalev }; + points[1] = { points[0].x(), points[0].y() + 2 * scalev }; + points[2] = { points[1].x() + 2 * scaleh, points[1].y() + 2 * scalev }; + points[3] = { points[2].x() + 4 * scaleh, points[2].y() - 4 * scalev }; + points[4] = { points[3].x(), points[3].y() - 2 * scalev }; + points[5] = { points[4].x() - 4 * scaleh, points[4].y() + 4 * scalev }; p->setPen(QPen(opt->palette.text().color(), 0)); p->setBrush(opt->palette.text().color()); p->drawPolygon(points, 6); @@ -1150,9 +1152,6 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, opt, widget), mode); const int pixw = pixmap.width() / pixmap.devicePixelRatio(); const int pixh = pixmap.height() / pixmap.devicePixelRatio(); - if (act && !dis && !checked) - qDrawShadePanel(p, vCheckRect, menuitem->palette, false, 1, - &menuitem->palette.brush(QPalette::Button)); QRect pmr(0, 0, pixw, pixh); pmr.moveCenter(vCheckRect.center()); p->setPen(menuitem->palette.text().color()); diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index 22fb0a511d..0daa4a4b41 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -144,6 +144,7 @@ #include "qcompleter_p.h" #include "QtWidgets/qscrollbar.h" +#include "QtCore/qdir.h" #include "QtCore/qstringlistmodel.h" #if QT_CONFIG(dirmodel) #include "QtWidgets/qdirmodel.h" @@ -181,10 +182,10 @@ int QCompletionModel::columnCount(const QModelIndex &) const void QCompletionModel::setSourceModel(QAbstractItemModel *source) { - bool hadModel = (sourceModel() != 0); + bool hadModel = (sourceModel() != nullptr); if (hadModel) - QObject::disconnect(sourceModel(), 0, this, 0); + QObject::disconnect(sourceModel(), nullptr, this, nullptr); QAbstractProxyModel::setSourceModel(source); @@ -401,7 +402,7 @@ QVariant QCompletionModel::data(const QModelIndex& index, int role) const void QCompletionModel::modelDestroyed() { - QAbstractProxyModel::setSourceModel(0); // switch to static empty model + QAbstractProxyModel::setSourceModel(nullptr); // switch to static empty model invalidate(); } @@ -470,13 +471,13 @@ QMatchData QCompletionEngine::filterHistory() return QMatchData(); #if QT_CONFIG(dirmodel) - const bool isDirModel = (qobject_cast<QDirModel *>(source) != 0); + const bool isDirModel = (qobject_cast<QDirModel *>(source) != nullptr); #else const bool isDirModel = false; #endif Q_UNUSED(isDirModel) #if QT_CONFIG(filesystemmodel) - const bool isFsModel = (qobject_cast<QFileSystemModel *>(source) != 0); + const bool isFsModel = (qobject_cast<QFileSystemModel *>(source) != nullptr); #else const bool isFsModel = false; #endif @@ -827,9 +828,18 @@ QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex& /////////////////////////////////////////////////////////////////////////////// QCompleterPrivate::QCompleterPrivate() -: widget(0), proxy(0), popup(0), filterMode(Qt::MatchStartsWith), cs(Qt::CaseSensitive), - role(Qt::EditRole), column(0), maxVisibleItems(7), sorting(QCompleter::UnsortedModel), - wrap(true), eatFocusOut(true), hiddenBecauseNoMatch(false) + : widget(nullptr), + proxy(nullptr), + popup(nullptr), + filterMode(Qt::MatchStartsWith), + cs(Qt::CaseSensitive), + role(Qt::EditRole), + column(0), + maxVisibleItems(7), + sorting(QCompleter::UnsortedModel), + wrap(true), + eatFocusOut(true), + hiddenBecauseNoMatch(false) { } @@ -1000,7 +1010,7 @@ QCompleter::QCompleter(QAbstractItemModel *model, QObject *parent) d->init(model); } -#ifndef QT_NO_STRINGLISTMODEL +#if QT_CONFIG(stringlistmodel) /*! Constructs a QCompleter object with the given \a parent that uses the specified \a list as a source of possible completions. @@ -1011,7 +1021,7 @@ QCompleter::QCompleter(const QStringList& list, QObject *parent) Q_D(QCompleter); d->init(new QStringListModel(list, this)); } -#endif // QT_NO_STRINGLISTMODEL +#endif // QT_CONFIG(stringlistmodel) /*! Destroys the completer object. @@ -1145,7 +1155,7 @@ void QCompleter::setCompletionMode(QCompleter::CompletionMode mode) d->widget->removeEventFilter(this); if (d->popup) { d->popup->deleteLater(); - d->popup = 0; + d->popup = nullptr; } } else { if (d->widget) @@ -1221,8 +1231,8 @@ void QCompleter::setPopup(QAbstractItemView *popup) Q_D(QCompleter); Q_ASSERT(popup != 0); if (d->popup) { - QObject::disconnect(d->popup->selectionModel(), 0, this, 0); - QObject::disconnect(d->popup, 0, this, 0); + QObject::disconnect(d->popup->selectionModel(), nullptr, this, nullptr); + QObject::disconnect(d->popup, nullptr, this, nullptr); } if (d->popup != popup) delete d->popup; @@ -1494,7 +1504,7 @@ void QCompleter::complete(const QRect& rect) return; } - Q_ASSERT(d->widget != 0); + Q_ASSERT(d->widget); if ((d->mode == QCompleter::PopupCompletion && !idx.isValid()) || (d->mode == QCompleter::UnfilteredPopupCompletion && d->proxy->rowCount() == 0)) { if (d->popup) @@ -1804,10 +1814,10 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const bool isDirModel = false; bool isFsModel = false; #if QT_CONFIG(dirmodel) - isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0; + isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != nullptr; #endif #if QT_CONFIG(filesystemmodel) - isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0; + isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != nullptr; #endif if (!isDirModel && !isFsModel) return sourceModel->data(index, d->role).toString(); @@ -1854,13 +1864,13 @@ QStringList QCompleter::splitPath(const QString& path) const bool isFsModel = false; #if QT_CONFIG(dirmodel) Q_D(const QCompleter); - isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0; + isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != nullptr; #endif #if QT_CONFIG(filesystemmodel) #if !QT_CONFIG(dirmodel) Q_D(const QCompleter); #endif - isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0; + isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != nullptr; #endif if ((!isDirModel && !isFsModel) || path.isEmpty()) diff --git a/src/widgets/util/qcompleter.h b/src/widgets/util/qcompleter.h index de79302e15..5620b55589 100644 --- a/src/widgets/util/qcompleter.h +++ b/src/widgets/util/qcompleter.h @@ -84,10 +84,10 @@ public: QCompleter(QObject *parent = nullptr); QCompleter(QAbstractItemModel *model, QObject *parent = nullptr); -#ifndef QT_NO_STRINGLISTMODEL +#if QT_CONFIG(stringlistmodel) QCompleter(const QStringList& completions, QObject *parent = nullptr); #endif - ~QCompleter(); + ~QCompleter() override; void setWidget(QWidget *widget); QWidget *widget() const; diff --git a/src/widgets/util/qscroller.cpp b/src/widgets/util/qscroller.cpp index ea8168b55c..e229a885a8 100644 --- a/src/widgets/util/qscroller.cpp +++ b/src/widgets/util/qscroller.cpp @@ -249,18 +249,11 @@ private: scrolling speed and takes care of updates. QScroller can be triggered by a flick gesture - \code - QWidget *w = ...; - QScroller::grabGesture(w, QScroller::LeftMouseButtonGesture); - \endcode + \snippet code/src_widgets_util_qscroller.cpp 0 or directly like this: - \code - QWidget *w = ...; - QScroller *scroller = QScroller::scroller(w); - scroller->scrollTo(QPointF(100, 100)); - \endcode + \snippet code/src_widgets_util_qscroller.cpp 1 The scrolled QObjects receive a QScrollPrepareEvent whenever the scroller needs to update its geometry information and a QScrollEvent whenever the content of the object should @@ -1894,7 +1887,7 @@ qreal QScrollerPrivate::nextSnapPos(qreal p, int dir, Qt::Orientation orientatio if (orientation == Qt::Horizontal) { // the snap points in the list - foreach (qreal snapPos, snapPositionsX) { + for (qreal snapPos : snapPositionsX) { qreal snapPosDist = snapPos - p; if ((dir > 0 && snapPosDist < 0) || (dir < 0 && snapPosDist > 0)) @@ -1941,7 +1934,7 @@ qreal QScrollerPrivate::nextSnapPos(qreal p, int dir, Qt::Orientation orientatio } else { // (orientation == Qt::Vertical) // the snap points in the list - foreach (qreal snapPos, snapPositionsY) { + for (qreal snapPos : snapPositionsY) { qreal snapPosDist = snapPos - p; if ((dir > 0 && snapPosDist < 0) || (dir < 0 && snapPosDist > 0)) diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp index 86c824afdb..d15f5e5955 100644 --- a/src/widgets/util/qsystemtrayicon.cpp +++ b/src/widgets/util/qsystemtrayicon.cpp @@ -523,6 +523,8 @@ QBalloonTip::QBalloonTip(const QIcon &icon, const QString &title, closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); closeButton->setFixedSize(closeButtonSize, closeButtonSize); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); +#else + Q_UNUSED(closeButtonSize); #endif #if QT_CONFIG(label) diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index df93e15f80..86532456c7 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -63,8 +63,6 @@ #include <private/qguiapplication_p.h> #include <qdebug.h> -#include <QtPlatformHeaders/qxcbwindowfunctions.h> -#include <QtPlatformHeaders/qxcbintegrationfunctions.h> #ifndef QT_NO_SYSTEMTRAYICON QT_BEGIN_NAMESPACE @@ -98,10 +96,7 @@ private slots: void systemTrayWindowChanged(QScreen *screen); private: - bool addToTray(); - QSystemTrayIcon *q; - QPixmap background; }; QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) @@ -117,55 +112,13 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) const QSize size(22, 22); // Gnome, standard size setGeometry(QRect(QPoint(0, 0), size)); setMinimumSize(size); - - // We need two different behaviors depending on whether the X11 visual for the system tray - // (a) exists and (b) supports an alpha channel, i.e. is 32 bits. - // If we have a visual that has an alpha channel, we can paint this widget with a transparent - // background and it will work. - // However, if there's no alpha channel visual, in order for transparent tray icons to work, - // we do not have a transparent background on the widget, but set the BackPixmap property of our - // window to ParentRelative (so that it inherits the background of its X11 parent window), call - // xcb_clear_region before painting (so that the inherited background is visible) and then grab - // the just-drawn background from the X11 server. - bool hasAlphaChannel = QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannel(); - setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel); - if (!hasAlphaChannel) { - createWinId(); - QXcbWindowFunctions::setParentRelativeBackPixmap(windowHandle()); - - // XXX: This is actually required, but breaks things ("QWidget::paintEngine: Should no - // longer be called"). Why is this needed? When the widget is drawn, we use tricks to grab - // the tray icon's background from the server. If the tray icon isn't visible (because - // another window is on top of it), the trick fails and instead uses the content of that - // other window as the background. - // setAttribute(Qt::WA_PaintOnScreen); - } - - addToTray(); -} - -bool QSystemTrayIconSys::addToTray() -{ - if (!locateSystemTray()) - return false; - - createWinId(); + setAttribute(Qt::WA_TranslucentBackground); setMouseTracking(true); - - if (!QXcbWindowFunctions::requestSystemTrayWindowDock(windowHandle())) - return false; - - if (!background.isNull()) - background = QPixmap(); - show(); - return true; } void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *) { - if (locateSystemTray()) { - addToTray(); - } else { + if (!locateSystemTray()) { QBalloonTip::hideBalloon(); hide(); // still no luck destroy(); @@ -174,7 +127,7 @@ void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *) QRect QSystemTrayIconSys::globalGeometry() const { - return QXcbWindowFunctions::systemTrayWindowGlobalGeometry(windowHandle()); + return QRect(mapToGlobal(QPoint(0, 0)), size()); } void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev) @@ -227,22 +180,6 @@ void QSystemTrayIconSys::paintEvent(QPaintEvent *) const QRect rect(QPoint(0, 0), geometry().size()); QPainter painter(this); - // If we have Qt::WA_TranslucentBackground set, during widget creation - // we detected the systray visual supported an alpha channel - if (testAttribute(Qt::WA_TranslucentBackground)) { - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(rect, Qt::transparent); - } else { - // clearRegion() was called on XEMBED_EMBEDDED_NOTIFY, so we hope that got done by now. - // Grab the tray background pixmap, before rendering the icon for the first time. - if (background.isNull()) { - background = QGuiApplication::primaryScreen()->grabWindow(winId(), - 0, 0, rect.size().width(), rect.size().height()); - } - // Then paint over the icon area with the background before compositing the icon on top. - painter.drawPixmap(QPoint(0, 0), background); - } - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); q->icon().paint(&painter, rect); } @@ -285,6 +222,7 @@ void QSystemTrayIconPrivate::install_sys() sys = new QSystemTrayIconSys(q); QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), sys, SLOT(systemTrayWindowChanged(QScreen*))); + sys->show(); } } diff --git a/src/widgets/util/qundostack.cpp b/src/widgets/util/qundostack.cpp index b371e903a6..e928b9fe37 100644 --- a/src/widgets/util/qundostack.cpp +++ b/src/widgets/util/qundostack.cpp @@ -742,6 +742,17 @@ void QUndoStack::resetClean() } /*! + \since 5.12 + \property QUndoStack::clean + \brief the clean status of this stack. + + This property indicates whether or not the stack is clean. For example, a + stack is clean when a document has been saved. + + \sa isClean(), setClean(), resetClean(), cleanIndex() +*/ + +/*! If the stack is in the clean state, returns \c true; otherwise returns \c false. \sa setClean(), cleanIndex() @@ -940,6 +951,17 @@ void QUndoStack::setIndex(int idx) } /*! + \since 5.12 + \property QUndoStack::canUndo + \brief whether this stack can undo. + + This property indicates whether or not there is a command that can be + undone. + + \sa canUndo(), index(), canRedo() +*/ + +/*! Returns \c true if there is a command available for undo; otherwise returns \c false. This function returns \c false if the stack is empty, or if the bottom command @@ -959,6 +981,17 @@ bool QUndoStack::canUndo() const } /*! + \since 5.12 + \property QUndoStack::canRedo + \brief whether this stack can redo. + + This property indicates whether or not there is a command that can be + redone. + + \sa canRedo(), index(), canUndo() +*/ + +/*! Returns \c true if there is a command available for redo; otherwise returns \c false. This function returns \c false if the stack is empty or if the top command @@ -978,6 +1011,17 @@ bool QUndoStack::canRedo() const } /*! + \since 5.12 + \property QUndoStack::undoText + \brief the undo text of the next command that is undone. + + This property holds the text of the command which will be undone in the + next call to undo(). + + \sa undoText(), QUndoCommand::actionText(), redoText() +*/ + +/*! Returns the text of the command which will be undone in the next call to undo(). \sa QUndoCommand::actionText(), redoText() @@ -994,6 +1038,17 @@ QString QUndoStack::undoText() const } /*! + \since 5.12 + \property QUndoStack::redoText + \brief the redo text of the next command that is redone. + + This property holds the text of the command which will be redone in the + next call to redo(). + + \sa redoText(), QUndoCommand::actionText(), undoText() +*/ + +/*! Returns the text of the command which will be redone in the next call to redo(). \sa QUndoCommand::actionText(), undoText() diff --git a/src/widgets/util/qundostack.h b/src/widgets/util/qundostack.h index 4be24eadab..b5716b2e9b 100644 --- a/src/widgets/util/qundostack.h +++ b/src/widgets/util/qundostack.h @@ -90,6 +90,11 @@ class Q_WIDGETS_EXPORT QUndoStack : public QObject Q_DECLARE_PRIVATE(QUndoStack) Q_PROPERTY(bool active READ isActive WRITE setActive) Q_PROPERTY(int undoLimit READ undoLimit WRITE setUndoLimit) + Q_PROPERTY(bool canUndo READ canUndo NOTIFY canUndoChanged) + Q_PROPERTY(bool canRedo READ canRedo NOTIFY canRedoChanged) + Q_PROPERTY(QString undoText READ undoText NOTIFY undoTextChanged) + Q_PROPERTY(QString redoText READ redoText NOTIFY redoTextChanged) + Q_PROPERTY(bool clean READ isClean NOTIFY cleanChanged) public: explicit QUndoStack(QObject *parent = nullptr); diff --git a/src/widgets/widgets.pro b/src/widgets/widgets.pro index e028a691c8..e556cb8b10 100644 --- a/src/widgets/widgets.pro +++ b/src/widgets/widgets.pro @@ -6,6 +6,9 @@ CONFIG += $$MODULE_CONFIG DEFINES += QT_NO_USING_NAMESPACE msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x65000000 +TRACEPOINT_PROVIDER = $$PWD/qtwidgets.tracepoints +CONFIG += qt_tracepoints + QMAKE_DOCS = $$PWD/doc/qtwidgets.qdocconf #platforms diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index f059980c5c..4e1aa51b4b 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE \li \l alignment: The alignment of the text in the QAbstractSpinBox. \li \l wrapping: Whether the QAbstractSpinBox wraps from the - minimum value to the maximum value and vica versa. + minimum value to the maximum value and vice versa. \endlist @@ -100,6 +100,16 @@ QT_BEGIN_NAMESPACE integer value to signify how many steps were taken. E.g. Pressing Qt::Key_Down will trigger a call to stepBy(-1). + When the user triggers a step whilst holding the Qt::ControlModifier, + QAbstractSpinBox steps by 10 instead of making a single step. This + step modifier affects wheel events, key events and interaction with + the spinbox buttons. Note that on macOS, Control corresponds to the + Command key. + + Since Qt 5.12, QStyle::SH_SpinBox_StepModifier can be used to select + which Qt::KeyboardModifier increases the step rate. Qt::NoModifier + disables this feature. + QAbstractSpinBox also provide a virtual function stepEnabled() to determine whether stepping up/down is allowed at any point. This function returns a bitset of StepEnabled. @@ -117,6 +127,13 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QAbstractSpinBox::StepType + + \value DefaultStepType + \value AdaptiveDecimalStepType +*/ + +/*! \fn void QAbstractSpinBox::editingFinished() This signal is emitted editing is finished. This happens when the @@ -268,7 +285,7 @@ void QAbstractSpinBox::setSpecialValueText(const QString &specialValueText) \brief whether the spin box is circular. If wrapping is true stepping up from maximum() value will take you - to the minimum() value and vica versa. Wrapping only make sense if + to the minimum() value and vice versa. Wrapping only make sense if you have minimum() and maximum() values set. \snippet code/src_gui_widgets_qabstractspinbox.cpp 0 @@ -640,7 +657,15 @@ void QAbstractSpinBox::stepBy(int steps) e = AlwaysEmit; } if (!dontstep) { - d->setValue(d->bound(d->value + (d->singleStep * steps), old, steps), e); + QVariant singleStep; + switch (d->stepType) { + case QAbstractSpinBox::StepType::AdaptiveDecimalStepType: + singleStep = d->calculateAdaptiveDecimalStep(steps); + break; + default: + singleStep = d->singleStep; + } + d->setValue(d->bound(d->value + (singleStep * steps), old, steps), e); } else if (e == AlwaysEmit) { d->emitSignals(e, old); } @@ -826,9 +851,13 @@ void QAbstractSpinBox::changeEvent(QEvent *event) style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, 0, this); if (d->edit) d->edit->setFrame(!style()->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, nullptr, this)); + d->stepModifier = static_cast<Qt::KeyboardModifier>(style()->styleHint(QStyle::SH_SpinBox_StepModifier, nullptr, this)); d->reset(); d->updateEditFieldGeometry(); break; + case QEvent::LocaleChange: + d->updateEdit(); + break; case QEvent::EnabledChange: if (!isEnabled()) { d->reset(); @@ -1008,6 +1037,8 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) const bool up = (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_Up); if (!(stepEnabled() & (up ? StepUpEnabled : StepDownEnabled))) return; + if (!isPgUpOrDown && (event->modifiers() & d->stepModifier)) + steps *= 10; if (!up) steps *= -1; if (style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) { @@ -1134,11 +1165,24 @@ void QAbstractSpinBox::keyReleaseEvent(QKeyEvent *event) void QAbstractSpinBox::wheelEvent(QWheelEvent *event) { Q_D(QAbstractSpinBox); +#ifdef Q_OS_MACOS + // If the event comes from a real mouse wheel, rather than a track pad + // (Qt::MouseEventSynthesizedBySystem), the shift modifier changes the + // scroll orientation to horizontal. + // Convert horizontal events back to vertical whilst shift is held. + if ((event->modifiers() & Qt::ShiftModifier) + && event->source() == Qt::MouseEventNotSynthesized) { + d->wheelDeltaRemainder += event->angleDelta().x(); + } else { + d->wheelDeltaRemainder += event->angleDelta().y(); + } +#else d->wheelDeltaRemainder += event->angleDelta().y(); +#endif const int steps = d->wheelDeltaRemainder / 120; d->wheelDeltaRemainder -= steps * 120; if (stepEnabled() & (steps > 0 ? StepUpEnabled : StepDownEnabled)) - stepBy(event->modifiers() & Qt::ControlModifier ? steps * 10 : steps); + stepBy(event->modifiers() & d->stepModifier ? steps * 10 : steps); event->accept(); } #endif @@ -1238,18 +1282,19 @@ void QAbstractSpinBox::timerEvent(QTimerEvent *event) } if (doStep) { + const bool increaseStepRate = QGuiApplication::keyboardModifiers() & d->stepModifier; const StepEnabled st = stepEnabled(); if (d->buttonState & Up) { if (!(st & StepUpEnabled)) { d->reset(); } else { - stepBy(1); + stepBy(increaseStepRate ? 10 : 1); } } else if (d->buttonState & Down) { if (!(st & StepDownEnabled)) { d->reset(); } else { - stepBy(-1); + stepBy(increaseStepRate ? -10 : -1); } } return; @@ -1377,8 +1422,9 @@ QAbstractSpinBoxPrivate::QAbstractSpinBoxPrivate() cachedState(QValidator::Invalid), pendingEmit(false), readOnly(false), wrapping(false), ignoreCursorPositionChanged(false), frame(true), accelerate(false), keyboardTracking(true), cleared(false), ignoreUpdateEdit(false), correctionMode(QAbstractSpinBox::CorrectToPreviousValue), - acceleration(0), hoverControl(QStyle::SC_None), buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0), - showGroupSeparator(0), wheelDeltaRemainder(0) + stepModifier(Qt::ControlModifier), acceleration(0), hoverControl(QStyle::SC_None), + buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0), showGroupSeparator(0), + wheelDeltaRemainder(0) { } @@ -1629,7 +1675,10 @@ void QAbstractSpinBoxPrivate::updateState(bool up, bool fromKeyboard /* = false : QAbstractSpinBox::StepDownEnabled))) { spinClickThresholdTimerId = q->startTimer(spinClickThresholdTimerInterval); buttonState = (up ? Up : Down) | (fromKeyboard ? Keyboard : Mouse); - q->stepBy(up ? 1 : -1); + int steps = up ? 1 : -1; + if (QGuiApplication::keyboardModifiers() & stepModifier) + steps *= 10; + q->stepBy(steps); #ifndef QT_NO_ACCESSIBILITY QAccessibleValueChangeEvent event(q, value); QAccessible::updateAccessibility(&event); @@ -1898,6 +1947,11 @@ void QAbstractSpinBoxPrivate::clearCache() const cachedState = QValidator::Acceptable; } +QVariant QAbstractSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + Q_UNUSED(steps) + return singleStep; +} // --- QSpinBoxValidator --- diff --git a/src/widgets/widgets/qabstractspinbox.h b/src/widgets/widgets/qabstractspinbox.h index 83bf83d779..87d46c7326 100644 --- a/src/widgets/widgets/qabstractspinbox.h +++ b/src/widgets/widgets/qabstractspinbox.h @@ -127,6 +127,13 @@ public: virtual void fixup(QString &input) const; virtual void stepBy(int steps); + + enum StepType { + DefaultStepType, + AdaptiveDecimalStepType + }; + Q_ENUM(StepType) + public Q_SLOTS: void stepUp(); void stepDown(); diff --git a/src/widgets/widgets/qabstractspinbox_p.h b/src/widgets/widgets/qabstractspinbox_p.h index 8f312fa900..fce88e43f4 100644 --- a/src/widgets/widgets/qabstractspinbox_p.h +++ b/src/widgets/widgets/qabstractspinbox_p.h @@ -122,6 +122,8 @@ public: static int variantCompare(const QVariant &arg1, const QVariant &arg2); static QVariant variantBound(const QVariant &min, const QVariant &value, const QVariant &max); + virtual QVariant calculateAdaptiveDecimalStep(int steps) const; + QLineEdit *edit; QString prefix, suffix, specialValueText; QVariant value, minimum, maximum, singleStep; @@ -143,6 +145,8 @@ public: uint cleared : 1; uint ignoreUpdateEdit : 1; QAbstractSpinBox::CorrectionMode correctionMode; + QAbstractSpinBox::StepType stepType = QAbstractSpinBox::StepType::DefaultStepType; + Qt::KeyboardModifier stepModifier = Qt::ControlModifier; int acceleration; QStyle::SubControl hoverControl; QRect hoverRect; diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 04a44e1f37..e20a0892b4 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -3160,7 +3160,6 @@ void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e) #endif // We've restricted the next couple of lines, because by not calling // viewContainer(), we avoid creating the QComboBoxPrivateContainer. - viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval()); viewContainer()->initialClickPosition = q->mapToGlobal(e->pos()); #ifdef QT_KEYPAD_NAVIGATION } @@ -3169,8 +3168,10 @@ void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e) // The code below ensures that regular mousepress and pick item still works // If it was not called the viewContainer would ignore event since it didn't have // a mousePressEvent first. - if (viewContainer()) + if (viewContainer()) { + viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval()); viewContainer()->maybeIgnoreMouseButtonRelease = false; + } } else { #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && lineEdit) { diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index 75289e9d1f..54504d124b 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -2629,8 +2629,9 @@ void QDockAreaLayout::removePlaceHolder(const QString &name) QList<int> index = indexOfPlaceHolder(name); if (!index.isEmpty()) remove(index); - foreach (QDockWidgetGroupWindow *dwgw, mainWindow->findChildren<QDockWidgetGroupWindow *>( - QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) { index = dwgw->layoutInfo()->indexOfPlaceHolder(name); if (!index.isEmpty()) { dwgw->layoutInfo()->remove(index); @@ -3065,8 +3066,9 @@ QRect QDockAreaLayout::constrainedRect(QRect rect, QWidget* widget) bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget) { QDockAreaLayoutItem *item = 0; - foreach (QDockWidgetGroupWindow *dwgw, mainWindow->findChildren<QDockWidgetGroupWindow *>( - QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) { QList<int> index = dwgw->layoutInfo()->indexOfPlaceHolder(dockWidget->objectName()); if (!index.isEmpty()) { dockWidget->setParent(dwgw); @@ -3175,7 +3177,7 @@ void QDockAreaLayout::resizeDocks(const QList<QDockWidget *> &docks, if (!info->tabbed && info->o == o) { info->item_list[path.constLast()].size = size; int totalSize = 0; - foreach (const QDockAreaLayoutItem &item, info->item_list) { + for (const QDockAreaLayoutItem &item : qAsConst(info->item_list)) { if (!item.skip()) { if (totalSize != 0) totalSize += sep; @@ -3293,6 +3295,8 @@ int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &or delta = pick(o, dest - origin); delta = separatorMoveHelper(list, sep_index, delta, sep); + fallbackToSizeHints = false; + if (index == QInternal::LeftDock || index == QInternal::RightDock) setGrid(0, &list); else diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp index 84cb78a474..6c871aae2c 100644 --- a/src/widgets/widgets/qdockwidget.cpp +++ b/src/widgets/widgets/qdockwidget.cpp @@ -45,6 +45,7 @@ #include <qdrawutil.h> #include <qevent.h> #include <qfontmetrics.h> +#include <qproxystyle.h> #include <qwindow.h> #include <qscreen.h> #include <qmainwindow.h> @@ -166,6 +167,10 @@ static inline bool isWindowsStyle(const QStyle *style) if (style->inherits("QStyleSheetStyle")) effectiveStyle = static_cast<const QStyleSheetStyle *>(style)->baseStyle(); #endif +#if !defined(QT_NO_STYLE_PROXY) + if (style->inherits("QProxyStyle")) + effectiveStyle = static_cast<const QProxyStyle *>(style)->baseStyle(); +#endif return effectiveStyle->inherits("QWindowsStyle"); } @@ -691,7 +696,6 @@ void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const // If we are in a floating tab, init from the parent because the attributes and the geometry // of the title bar should be taken from the floating window. option->initFrom(floatingTab && !isFloating() ? parentWidget() : this); - option->fontMetrics = QFontMetrics(d->font); option->rect = dwlayout->titleArea(); option->title = d->fixedWindowTitle; option->closable = hasFeature(this, QDockWidget::DockWidgetClosable); @@ -1468,6 +1472,7 @@ void QDockWidget::closeEvent(QCloseEvent *event) void QDockWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event) + Q_D(QDockWidget); QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout()); @@ -1488,7 +1493,11 @@ void QDockWidget::paintEvent(QPaintEvent *event) // the title may wish to extend out to all sides (eg. Vista style) QStyleOptionDockWidget titleOpt; initStyleOption(&titleOpt); - p.setFont(d_func()->font); + if (font() == QApplication::font("QDockWidget")) { + titleOpt.fontMetrics = QFontMetrics(d->font); + p.setFont(d->font); + } + p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt); } } diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp index 5d09e14073..60f88df9af 100644 --- a/src/widgets/widgets/qlabel.cpp +++ b/src/widgets/widgets/qlabel.cpp @@ -288,7 +288,7 @@ void QLabel::setText(const QString &text) return; QWidgetTextControl *oldControl = d->control; - d->control = 0; + d->control = nullptr; d->clearContents(); d->text = text; @@ -303,7 +303,7 @@ void QLabel::setText(const QString &text) d->ensureTextControl(); } else { delete d->control; - d->control = 0; + d->control = nullptr; } if (d->isRichText) { @@ -714,7 +714,7 @@ void QLabel::setTextInteractionFlags(Qt::TextInteractionFlags flags) d->ensureTextControl(); } else { delete d->control; - d->control = 0; + d->control = nullptr; } if (d->control) @@ -1021,13 +1021,13 @@ void QLabel::paintEvent(QPaintEvent *) QStyleOption opt; opt.initFrom(this); #ifndef QT_NO_STYLE_STYLESHEET - if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style)) { + if (QStyleSheetStyle* cssStyle = qt_styleSheet(style)) cssStyle->styleSheetPalette(this, &opt, &opt.palette); - } #endif if (d->control) { #ifndef QT_NO_SHORTCUT - const bool underline = (bool)style->styleHint(QStyle::SH_UnderlineShortcut, 0, this, 0); + const bool underline = static_cast<bool>(style->styleHint(QStyle::SH_UnderlineShortcut, + nullptr, this, nullptr)); if (d->shortcutId != 0 && underline != d->shortcutCursor.charFormat().fontUnderline()) { QTextCharFormat fmt; @@ -1294,20 +1294,20 @@ void QLabel::setMovie(QMovie *movie) void QLabelPrivate::clearContents() { delete control; - control = 0; + control = nullptr; isTextLabel = false; hasShortcut = false; #ifndef QT_NO_PICTURE delete picture; - picture = 0; + picture = nullptr; #endif delete scaledpixmap; - scaledpixmap = 0; + scaledpixmap = nullptr; delete cachedimage; - cachedimage = 0; + cachedimage = nullptr; delete pixmap; - pixmap = 0; + pixmap = nullptr; text.clear(); Q_Q(QLabel); @@ -1321,7 +1321,7 @@ void QLabelPrivate::clearContents() QObject::disconnect(movie, SIGNAL(resized(QSize)), q, SLOT(_q_movieResized(QSize))); QObject::disconnect(movie, SIGNAL(updated(QRect)), q, SLOT(_q_movieUpdated(QRect))); } - movie = 0; + movie = nullptr; #endif #ifndef QT_NO_CURSOR if (onAnchor) { @@ -1428,9 +1428,9 @@ void QLabel::setScaledContents(bool enable) d->scaledcontents = enable; if (!enable) { delete d->scaledpixmap; - d->scaledpixmap = 0; + d->scaledpixmap = nullptr; delete d->cachedimage; - d->cachedimage = 0; + d->cachedimage = nullptr; } update(contentsRect()); } @@ -1629,7 +1629,7 @@ QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos) } if (linkToCopy.isEmpty() && !control) - return 0; + return nullptr; return control->createStandardContextMenu(p, q_func()); } diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index ca6aacc16c..242a4405ca 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -437,8 +437,6 @@ bool QLineEdit::hasFrame() const #if QT_CONFIG(action) /*! - \overload - Adds the \a action to the list of actions at the \a position. \since 5.2 @@ -497,6 +495,8 @@ void QLineEdit::setClearButtonEnabled(bool enable) d->removeAction(clearAction); delete clearAction; } +#else + Q_UNUSED(enable); #endif // QT_CONFIG(action) } @@ -680,7 +680,8 @@ QSize QLineEdit::sizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm(font()); - int h = qMax(fm.height(), 14) + 2*d->verticalMargin + const int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this); + int h = qMax(fm.height(), iconSize - 2) + 2*d->verticalMargin + d->topTextMargin + d->bottomTextMargin + d->topmargin + d->bottommargin; int w = fm.horizontalAdvance(QLatin1Char('x')) * 17 + 2*d->horizontalMargin @@ -1676,6 +1677,21 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) */ /*! + \fn void QLineEdit::inputRejected() + + This signal is emitted when the user presses a key that is not + considered to be acceptable input. For example, if a key press + results in a validator's validate() call to return Invalid. + Another case is when trying to enter in more characters beyond the + maximum length of the line edit. + + Note: This signal will still be emitted in a case where part of + the text is accepted but not all of it is. For example, if there + is a maximum length set and the clipboard text is longer than the + maximum length when it is pasted. +*/ + +/*! Converts the given key press \a event into a line edit action. If Return or Enter is pressed and the current text is valid (or @@ -1946,8 +1962,7 @@ void QLineEdit::paintEvent(QPaintEvent *) if (!d->placeholderText.isEmpty()) { const Qt::LayoutDirection layoutDir = d->placeholderText.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight; const Qt::Alignment alignPhText = QStyle::visualAlignment(layoutDir, QFlag(d->alignment)); - QColor col = pal.text().color(); - col.setAlpha(128); + const QColor col = pal.placeholderText().color(); QPen oldpen = p.pen(); p.setPen(col); Qt::LayoutDirection oldLayoutDir = p.layoutDirection(); @@ -2002,7 +2017,7 @@ void QLineEdit::paintEvent(QPaintEvent *) // draw text, selections and cursors #ifndef QT_NO_STYLE_STYLESHEET - if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style())) { + if (QStyleSheetStyle* cssStyle = qt_styleSheet(style())) { cssStyle->styleSheetPalette(this, &panel, &pal); } #endif diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h index 6c70a8f44a..de82927f74 100644 --- a/src/widgets/widgets/qlineedit.h +++ b/src/widgets/widgets/qlineedit.h @@ -207,6 +207,7 @@ Q_SIGNALS: void returnPressed(); void editingFinished(); void selectionChanged(); + void inputRejected(); protected: void mousePressEvent(QMouseEvent *) override; diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index cccb44c4ef..df8d534afa 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -218,6 +218,7 @@ void QLineEditPrivate::init(const QString& txt) QObject::connect(control, SIGNAL(updateNeeded(QRect)), q, SLOT(_q_updateNeeded(QRect))); + QObject::connect(control, SIGNAL(inputRejected()), q, SIGNAL(inputRejected())); QStyleOptionFrame opt; q->initStyleOption(&opt); @@ -350,11 +351,9 @@ void QLineEditIconButton::paintEvent(QPaintEvent *) QWindow *window = nullptr; if (const QWidget *nativeParent = nativeParentWidget()) window = nativeParent->windowHandle(); - // Note isDown should really use the active state but in most styles - // this has no proper feedback QIcon::Mode state = QIcon::Disabled; if (isEnabled()) - state = isDown() ? QIcon::Selected : QIcon::Normal; + state = isDown() ? QIcon::Active : QIcon::Normal; const QLineEditPrivate *lep = lineEditPrivate(); const int iconWidth = lep ? lep->sideWidgetParameters().iconSize : 16; const QSize iconSize(iconWidth, iconWidth); @@ -444,7 +443,7 @@ QLineEditPrivate::SideWidgetParameters QLineEditPrivate::sideWidgetParameters() { Q_Q(const QLineEdit); SideWidgetParameters result; - result.iconSize = q->height() < 34 ? 16 : 32; + result.iconSize = q->style()->pixelMetric(QStyle::PM_SmallIconSize, 0, q); result.margin = result.iconSize / 4; result.widgetWidth = result.iconSize + 6; result.widgetHeight = result.iconSize + 2; @@ -468,6 +467,8 @@ void QLineEditPrivate::setClearButtonEnabled(bool enabled) break; } } +#else + Q_UNUSED(enabled); #endif } @@ -485,6 +486,8 @@ void QLineEditPrivate::positionSideWidgets() #if QT_CONFIG(action) if (e.action->isVisible()) widgetGeometry.moveLeft(widgetGeometry.left() + delta); +#else + Q_UNUSED(delta); #endif } widgetGeometry.moveLeft(contentRect.width() - p.widgetWidth - p.margin); @@ -598,6 +601,8 @@ void QLineEditPrivate::removeAction(QAction *action) if (!hasSideWidgets()) // Last widget, remove connection QObject::disconnect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); q->update(); +#else + Q_UNUSED(action); #endif // QT_CONFIG(action) } diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp index 2014bdabf3..411b482c11 100644 --- a/src/widgets/widgets/qmainwindow.cpp +++ b/src/widgets/widgets/qmainwindow.cpp @@ -249,14 +249,7 @@ void QMainWindowPrivate::init() An example of how to create menus follows: - \code - void MainWindow::createMenus() - { - fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(newAct); - fileMenu->addAction(openAct); - fileMenu->addAction(saveAct); - \endcode + \snippet code/src_widgets_widgets_qmainwindow.cpp 0 The \c createPopupMenu() function creates popup menus when the main window receives context menu events. The default @@ -283,12 +276,7 @@ void QMainWindowPrivate::init() An example of toolbar creation follows: - \code - void MainWindow::createToolBars() - { - fileToolBar = addToolBar(tr("File")); - fileToolBar->addAction(newAct); - \endcode + \snippet code/src_widgets_widgets_qmainwindow.cpp 1 \section2 Creating Dock Widgets @@ -1227,9 +1215,8 @@ Qt::DockWidgetArea QMainWindow::dockWidgetArea(QDockWidget *dockwidget) const to the relative weight of the sizes. Example: - \code - resizeDocks({blueWidget, yellowWidget}, {20 , 40}, Qt::Horizontal); - \endcode + \snippet code/src_widgets_widgets_qmainwindow.cpp 2 + If the blue and the yellow widget are nested on the same level they will be resized such that the yellowWidget is twice as big as the blueWidget @@ -1312,8 +1299,12 @@ bool QMainWindow::restoreState(const QByteArray &state, int version) bool QMainWindow::event(QEvent *event) { Q_D(QMainWindow); + +#if QT_CONFIG(dockwidget) if (d->layout && d->layout->windowEvent(event)) return true; +#endif + switch (event->type()) { #if QT_CONFIG(toolbar) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 43c22910f9..053bfbf024 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -426,7 +426,8 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty() } // Make sure to reparent the possibly floating or hidden QDockWidgets to the parent - foreach (QDockWidget *dw, findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly)) { + const auto dockWidgets = findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidget *dw : dockWidgets) { bool wasFloating = dw->isFloating(); bool wasHidden = dw->isHidden(); dw->setParent(parentWidget()); @@ -445,7 +446,8 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty() dw->show(); } #if QT_CONFIG(tabbar) - foreach (QTabBar *tb, findChildren<QTabBar *>(QString(), Qt::FindDirectChildrenOnly)) + const auto tabBars = findChildren<QTabBar *>(QString(), Qt::FindDirectChildrenOnly); + for (QTabBar *tb : tabBars) tb->setParent(parentWidget()); #endif deleteLater(); @@ -1037,10 +1039,10 @@ void QMainWindowLayoutState::saveState(QDataStream &stream) const #if QT_CONFIG(dockwidget) dockAreaLayout.saveState(stream); #if QT_CONFIG(tabbar) - QList<QDockWidgetGroupWindow *> floatingTabs = + const QList<QDockWidgetGroupWindow *> floatingTabs = mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly); - foreach (QDockWidgetGroupWindow *floating, floatingTabs) { + for (QDockWidgetGroupWindow *floating : floatingTabs) { if (floating->layoutInfo()->isEmpty()) continue; stream << uchar(QDockAreaLayout::FloatingDockWidgetTabMarker) << floating->geometry(); @@ -1528,9 +1530,9 @@ void QMainWindowLayout::setDocumentMode(bool enabled) _documentMode = enabled; // Update the document mode for all tab bars - foreach (QTabBar *bar, usedTabBars) + for (QTabBar *bar : qAsConst(usedTabBars)) bar->setDocumentMode(_documentMode); - foreach (QTabBar *bar, unusedTabBars) + for (QTabBar *bar : qAsConst(unusedTabBars)) bar->setDocumentMode(_documentMode); } #endif // QT_CONFIG(tabbar) @@ -1809,8 +1811,9 @@ QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget) QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget); if (info) return info; - foreach (QDockWidgetGroupWindow *dwgw, - parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) { info = dwgw->layoutInfo()->info(widget); if (info) return info; @@ -2077,8 +2080,9 @@ bool QMainWindowLayout::plug(QLayoutItem *widgetItem) layoutState.remove(previousPath); previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget); // Let's remove the widget from any possible group window - foreach (QDockWidgetGroupWindow *dwgw, - parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) { if (dwgw == currentHoveredFloat) continue; QList<int> path = dwgw->layoutInfo()->indexOf(widget); @@ -2106,8 +2110,9 @@ bool QMainWindowLayout::plug(QLayoutItem *widgetItem) #if QT_CONFIG(dockwidget) // Let's remove the widget from any possible group window - foreach (QDockWidgetGroupWindow *dwgw, - parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) { QList<int> path = dwgw->layoutInfo()->indexOf(widget); if (!path.isEmpty()) dwgw->layoutInfo()->remove(path); @@ -2249,7 +2254,8 @@ void QMainWindowLayout::animationFinished(QWidget *widget) #if QT_CONFIG(dockwidget) parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); #if QT_CONFIG(tabbar) - foreach (QTabBar *tab_bar, usedTabBars) + const auto usedTabBarsCopy = usedTabBars; // list potentially modified by animations + for (QTabBar *tab_bar : usedTabBarsCopy) tab_bar->show(); #endif // QT_CONFIG(tabbar) #endif // QT_CONFIG(dockwidget) @@ -2533,7 +2539,8 @@ void QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos) // Check if we are over another floating dock widget QVarLengthArray<QWidget *, 10> candidates; - foreach (QObject *c, parentWidget()->children()) { + const auto siblings = parentWidget()->children(); + for (QObject *c : siblings) { QWidget *w = qobject_cast<QWidget*>(c); if (!w) continue; @@ -2543,7 +2550,8 @@ void QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos) candidates << w; if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) { // Sometimes, there are floating QDockWidget that have a QDockWidgetGroupWindow as a parent. - foreach (QObject *c, group->children()) { + const auto groupChildren = group->children(); + for (QObject *c : groupChildren) { if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) { if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized()) candidates << dw; @@ -2671,14 +2679,14 @@ void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animat { #if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars(); - foreach (QDockWidgetGroupWindow *dwgw, - parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly)) { + const auto groups = + parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly); + for (QDockWidgetGroupWindow *dwgw : groups) used += dwgw->layoutInfo()->usedTabBars(); - } - QSet<QTabBar*> retired = usedTabBars - used; + const QSet<QTabBar*> retired = usedTabBars - used; usedTabBars = used; - foreach (QTabBar *tab_bar, retired) { + for (QTabBar *tab_bar : retired) { tab_bar->hide(); while (tab_bar->count() > 0) tab_bar->removeTab(0); @@ -2686,10 +2694,10 @@ void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animat } if (sep == 1) { - QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets(); - QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps; + const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets(); + const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps; usedSeparatorWidgets = usedSeps; - foreach (QWidget *sepWidget, retiredSeps) { + for (QWidget *sepWidget : retiredSeps) { unusedSeparatorWidgets.append(sepWidget); } } @@ -2731,7 +2739,7 @@ bool QMainWindowLayout::restoreState(QDataStream &stream) #if QT_CONFIG(dockwidget) if (parentWidget()->isVisible()) { #if QT_CONFIG(tabbar) - foreach (QTabBar *tab_bar, usedTabBars) + for (QTabBar *tab_bar : qAsConst(usedTabBars)) tab_bar->show(); #endif diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index 4ccfb1786e..72cbec2350 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -92,6 +92,7 @@ public: QPoint hoverPos; #if QT_CONFIG(dockwidget) + #if QT_CONFIG(cursor) QCursor separatorCursor(const QList<int> &path); void adjustCursor(const QPoint &pos); @@ -108,13 +109,15 @@ public: bool startSeparatorMove(const QPoint &pos); bool separatorMove(const QPoint &pos); bool endSeparatorMove(const QPoint &pos); + bool windowEvent(QEvent *e); #endif // QT_CONFIG(dockwidget) - bool windowEvent(QEvent *e); }; -#if QT_CONFIG(dockwidget) && QT_CONFIG(cursor) +#if QT_CONFIG(dockwidget) + +#if QT_CONFIG(cursor) template <typename Layout> QCursor QMainWindowLayoutSeparatorHelper<Layout>::separatorCursor(const QList<int> &path) { @@ -187,14 +190,13 @@ void QMainWindowLayoutSeparatorHelper<Layout>::adjustCursor(const QPoint &pos) } } } -#endif // QT_CONFIG(cursor) && QT_CONFIG(dockwidget) +#endif // QT_CONFIG(cursor) template <typename Layout> bool QMainWindowLayoutSeparatorHelper<Layout>::windowEvent(QEvent *event) { QWidget *w = window(); switch (event->type()) { -#if QT_CONFIG(dockwidget) case QEvent::Paint: { QPainter p(w); QRegion r = static_cast<QPaintEvent *>(event)->region(); @@ -290,14 +292,12 @@ bool QMainWindowLayoutSeparatorHelper<Layout>::windowEvent(QEvent *event) return true; } break; -#endif // QT_CONFIG(dockwidget) default: break; } return false; } -#if QT_CONFIG(dockwidget) template <typename Layout> bool QMainWindowLayoutSeparatorHelper<Layout>::startSeparatorMove(const QPoint &pos) { diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp index 45c01dec80..f32cd26478 100644 --- a/src/widgets/widgets/qmdiarea.cpp +++ b/src/widgets/widgets/qmdiarea.cpp @@ -471,8 +471,8 @@ QVector<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const ylist.erase(std::unique(ylist.begin(), ylist.end()), ylist.end()); result.reserve(ylist.size() * xlist.size()); - foreach (int y, ylist) - foreach (int x, xlist) + for (int y : qAsConst(ylist)) + for (int x : qAsConst(xlist)) result << QRect(QPoint(x, y), size); return result; } @@ -954,7 +954,7 @@ void QMdiAreaPrivate::rearrange(Rearranger *rearranger) } } - if (active && rearranger->type() == Rearranger::RegularTiler) { + if (active && rearranger->type() == Rearranger::RegularTiler && !tileCalledFromResizeEvent) { // Move active window in front if necessary. That's the case if we // have any windows with staysOnTopHint set. int indexToActive = widgets.indexOf((QWidget *)active); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 363647aee0..c79e88f094 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -1741,8 +1741,6 @@ QMenu::~QMenu() } /*! - \overload - This convenience function creates a new action with \a text. The function adds the newly created action to the menu's list of actions, and returns it. @@ -2433,7 +2431,7 @@ void QMenu::popup(const QPoint &p, QAction *atAction) atAction = d->defaultAction; // TODO: This works for first level menus, not yet sub menus } else { - foreach (QAction *action, d->actions) + for (QAction *action : qAsConst(d->actions)) if (action->isEnabled()) { atAction = action; break; diff --git a/src/widgets/widgets/qmenu.h b/src/widgets/widgets/qmenu.h index 86d927e919..628f818b5e 100644 --- a/src/widgets/widgets/qmenu.h +++ b/src/widgets/widgets/qmenu.h @@ -46,7 +46,7 @@ #include <QtGui/qicon.h> #include <QtWidgets/qaction.h> -#ifdef Q_OS_OSX +#if defined(Q_OS_MACOS) || defined(Q_CLANG_QDOC) Q_FORWARD_DECLARE_OBJC_CLASS(NSMenu); #endif @@ -81,7 +81,7 @@ public: QAction *addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut = 0); QAction *addAction(const QIcon &icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut = 0); -#ifdef Q_QDOC +#ifdef Q_CLANG_QDOC template<typename PointerToMemberFunction> QAction *addAction(const QString &text, const QObject *receiver, PointerToMemberFunction method, const QKeySequence &shortcut = 0); template<typename Functor> @@ -151,7 +151,7 @@ public: connect(result, &QAction::triggered, std::move(slot)); return result; } -#endif // !Q_QDOC +#endif // !Q_CLANG_QDOC QAction *addMenu(QMenu *menu); QMenu *addMenu(const QString &title); @@ -211,7 +211,7 @@ public: QPlatformMenu *platformMenu(); void setPlatformMenu(QPlatformMenu *platformMenu); -#ifdef Q_OS_OSX +#if defined(Q_OS_MACOS) || defined(Q_CLANG_QDOC) NSMenu* toNSMenu(); void setAsDockMenu(); #endif diff --git a/src/widgets/widgets/qmenu_mac.mm b/src/widgets/widgets/qmenu_mac.mm index 0d680fb4dc..0872da803d 100644 --- a/src/widgets/widgets/qmenu_mac.mm +++ b/src/widgets/widgets/qmenu_mac.mm @@ -73,6 +73,7 @@ inline QPlatformNativeInterface::NativeResourceForIntegrationFunction resolvePla /*! + \fn NSMenu *QMenu::toNSMenu() \since 5.2 Returns the native NSMenu for this menu. Available on \macos only. @@ -94,6 +95,7 @@ NSMenu *QMenu::toNSMenu() /*! + \fn void QMenu::setAsDockMenu() \since 5.2 Set this menu to be the dock menu available by option-clicking @@ -149,6 +151,7 @@ void QMenuPrivate::moveWidgetToPlatformItem(QWidget *widget, QPlatformMenuItem* #if QT_CONFIG(menubar) /*! + \fn NSMenu *QMenuBar::toNSMenu() \since 5.2 Returns the native NSMenu for this menu bar. Available on \macos only. diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 6df53dc4e4..ce74a4c2ff 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -749,8 +749,6 @@ QMenuBar::~QMenuBar() } /*! - \overload - This convenience function creates a new action with \a text. The function adds the newly created action to the menu's list of actions, and returns it. diff --git a/src/widgets/widgets/qmenubar.h b/src/widgets/widgets/qmenubar.h index 2f071e7e3b..cf6663f94a 100644 --- a/src/widgets/widgets/qmenubar.h +++ b/src/widgets/widgets/qmenubar.h @@ -67,7 +67,7 @@ public: QAction *addAction(const QString &text); QAction *addAction(const QString &text, const QObject *receiver, const char* member); -#ifdef Q_QDOC +#ifdef Q_CLANG_QDOC template<typename Obj, typename PointerToMemberFunctionOrFunctor> QAction *addAction(const QString &text, const Obj *receiver, PointerToMemberFunctionOrFunctor method); template<typename Functor> @@ -91,7 +91,7 @@ public: connect(result, &QAction::triggered, std::move(slot)); return result; } -#endif // !Q_QDOC +#endif // !Q_CLANG_QDOC QAction *addMenu(QMenu *menu); QMenu *addMenu(const QString &title); @@ -121,7 +121,7 @@ public: void setCornerWidget(QWidget *w, Qt::Corner corner = Qt::TopRightCorner); QWidget *cornerWidget(Qt::Corner corner = Qt::TopRightCorner) const; -#ifdef Q_OS_OSX +#if defined(Q_OS_MACOS) || defined(Q_CLANG_QDOC) NSMenu* toNSMenu(); #endif diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index a4c463fb5b..d6f6a364a8 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -48,6 +48,7 @@ #include <qdrag.h> #endif #include <qclipboard.h> +#include <qmath.h> #if QT_CONFIG(menu) #include <qmenu.h> #endif @@ -293,6 +294,7 @@ void QPlainTextDocumentLayout::documentChanged(int from, int charsRemoved, int c QTextBlock changeStartBlock = doc->findBlock(from); QTextBlock changeEndBlock = doc->findBlock(qMax(0, from + charsChanged - 1)); + bool blockVisibilityChanged = false; if (changeStartBlock == changeEndBlock && newBlockCount == d->blockCount) { QTextBlock block = changeStartBlock; @@ -310,14 +312,18 @@ void QPlainTextDocumentLayout::documentChanged(int from, int charsRemoved, int c QTextBlock block = changeStartBlock; do { block.clearLayout(); + const int lineCount = block.isVisible() ? 1 : 0; + if (block.lineCount() != lineCount) { + blockVisibilityChanged = true; + block.setLineCount(lineCount); + } if (block == changeEndBlock) break; block = block.next(); } while(block.isValid()); } - if (newBlockCount != d->blockCount) { - + if (newBlockCount != d->blockCount || blockVisibilityChanged) { int changeEnd = changeEndBlock.blockNumber(); int blockDiff = newBlockCount - d->blockCount; int oldChangeEnd = changeEnd - blockDiff; @@ -382,6 +388,8 @@ void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block) line.setLineWidth(availableWidth); line.setPosition(QPointF(margin, height)); height += line.height(); + if (line.leading() < 0) + height += qCeil(line.leading()); blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin); } tl->endLayout(); @@ -1927,8 +1935,7 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e) painter.setClipRect(er); if (d->placeholderVisible) { - QColor col = d->control->palette().text().color(); - col.setAlpha(128); + const QColor col = d->control->palette().placeholderText().color(); painter.setPen(col); painter.setClipRect(e->rect()); const int margin = int(document()->documentMargin()); @@ -2336,8 +2343,6 @@ void QPlainTextEdit::wheelEvent(QWheelEvent *e) #endif /*! - \fn QPlainTextEdit::zoomIn(int range) - Zooms in on the text by making the base font size \a range points larger and recalculating all font sizes to be the new size. This does not change the size of any images. @@ -2350,10 +2355,6 @@ void QPlainTextEdit::zoomIn(int range) } /*! - \fn QPlainTextEdit::zoomOut(int range) - - \overload - Zooms out on the text by making the base font size \a range points smaller and recalculating all font sizes to be the new size. This does not change the size of any images. @@ -2631,8 +2632,8 @@ void QPlainTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); QEvent event(QEvent::ReadOnlyChange); QApplication::sendEvent(this, &event); } diff --git a/src/widgets/widgets/qspinbox.cpp b/src/widgets/widgets/qspinbox.cpp index 561215ec85..dcf3906dd7 100644 --- a/src/widgets/widgets/qspinbox.cpp +++ b/src/widgets/widgets/qspinbox.cpp @@ -45,6 +45,8 @@ #include <qvalidator.h> #include <qdebug.h> +#include <algorithm> +#include <cmath> #include <float.h> QT_BEGIN_NAMESPACE @@ -75,6 +77,8 @@ public: } int displayIntegerBase; + + QVariant calculateAdaptiveDecimalStep(int steps) const override; }; class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate @@ -100,6 +104,8 @@ public: // When fiddling with the decimals property, we may lose precision in these properties. double actualMin; double actualMax; + + QVariant calculateAdaptiveDecimalStep(int steps) const override; }; @@ -415,6 +421,47 @@ void QSpinBox::setRange(int minimum, int maximum) } /*! + Sets the step type for the spin box to \a stepType, which is single + step or adaptive decimal step. + + Adaptive decimal step means that the step size will continuously be + adjusted to one power of ten below the current \l value. So when + the value is 1100, the step is set to 100, so stepping up once + increases it to 1200. For 1200 stepping up takes it to 1300. For + negative values, stepping down from -1100 goes to -1200. + + Step direction is taken into account to handle edges cases, so + that stepping down from 100 takes the value to 99 instead of 90. + Thus a step up followed by a step down -- or vice versa -- always + lands on the starting value; 99 -> 100 -> 99. + + Setting this will cause the spin box to disregard the value of + \l singleStep, although it is preserved so that \l singleStep + comes into effect if adaptive decimal step is later turned off. + + \since 5.12 +*/ + +void QSpinBox::setStepType(QAbstractSpinBox::StepType stepType) +{ + Q_D(QSpinBox); + d->stepType = stepType; +} + +/*! + \property QSpinBox::stepType + \brief The step type. + + The step type can be single step or adaptive decimal step. +*/ + +QAbstractSpinBox::StepType QSpinBox::stepType() const +{ + Q_D(const QSpinBox); + return d->stepType; +} + +/*! \property QSpinBox::displayIntegerBase \brief the base used to display the value of the spin box @@ -847,6 +894,50 @@ void QDoubleSpinBox::setRange(double minimum, double maximum) } /*! + Sets the step type for the spin box to \a stepType, which is single + step or adaptive decimal step. + + Adaptive decimal step means that the step size will continuously be + adjusted to one power of ten below the current \l value. So when + the value is 1100, the step is set to 100, so stepping up once + increases it to 1200. For 1200 stepping up takes it to 1300. For + negative values, stepping down from -1100 goes to -1200. + + It also works for any decimal values, 0.041 is increased to 0.042 + by stepping once. + + Step direction is taken into account to handle edges cases, so + that stepping down from 100 takes the value to 99 instead of 90. + Thus a step up followed by a step down -- or vice versa -- always + lands on the starting value; 99 -> 100 -> 99. + + Setting this will cause the spin box to disregard the value of + \l singleStep, although it is preserved so that \l singleStep + comes into effect if adaptive decimal step is later turned off. + + \since 5.12 +*/ + +void QDoubleSpinBox::setStepType(StepType stepType) +{ + Q_D(QDoubleSpinBox); + d->stepType = stepType; +} + +/*! + \property QDoubleSpinBox::stepType + \brief The step type. + + The step type can be single step or adaptive decimal step. +*/ + +QAbstractSpinBox::StepType QDoubleSpinBox::stepType() const +{ + Q_D(const QDoubleSpinBox); + return d->stepType; +} + +/*! \property QDoubleSpinBox::decimals \brief the precision of the spin box, in decimals @@ -1078,6 +1169,22 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, return cachedValue; } +QVariant QSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + const int intValue = value.toInt(); + const int absValue = qAbs(intValue); + + if (absValue < 100) + return 1; + + const bool valueNegative = intValue < 0; + const bool stepsNegative = steps < 0; + const int signCompensation = (valueNegative == stepsNegative) ? 0 : 1; + + const int log = static_cast<int>(std::log10(absValue - signCompensation)) - 1; + return static_cast<int>(std::pow(10, log)); +} + // --- QDoubleSpinBoxPrivate --- /*! @@ -1303,6 +1410,27 @@ QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const return q->textFromValue(f.toDouble()); } +QVariant QDoubleSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + const double doubleValue = value.toDouble(); + const double minStep = std::pow(10, -decimals); + double absValue = qAbs(doubleValue); + + if (absValue < minStep) + return minStep; + + const bool valueNegative = doubleValue < 0; + const bool stepsNegative = steps < 0; + if (valueNegative != stepsNegative) + absValue /= 1.01; + + const double shift = std::pow(10, 1 - std::floor(std::log10(absValue))); + const double absRounded = round(absValue * shift) / shift; + const double log = floorf(std::log10(absRounded)) - 1; + + return std::max(minStep, std::pow(10, log)); +} + /*! \reimp */ bool QSpinBox::event(QEvent *event) { diff --git a/src/widgets/widgets/qspinbox.h b/src/widgets/widgets/qspinbox.h index 73489c9a68..d2eac903fb 100644 --- a/src/widgets/widgets/qspinbox.h +++ b/src/widgets/widgets/qspinbox.h @@ -58,6 +58,7 @@ class Q_WIDGETS_EXPORT QSpinBox : public QAbstractSpinBox Q_PROPERTY(int minimum READ minimum WRITE setMinimum) Q_PROPERTY(int maximum READ maximum WRITE setMaximum) Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep) + Q_PROPERTY(StepType stepType READ stepType WRITE setStepType) Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true) Q_PROPERTY(int displayIntegerBase READ displayIntegerBase WRITE setDisplayIntegerBase) @@ -86,6 +87,9 @@ public: void setRange(int min, int max); + StepType stepType() const; + void setStepType(StepType stepType); + int displayIntegerBase() const; void setDisplayIntegerBase(int base); @@ -121,6 +125,7 @@ class Q_WIDGETS_EXPORT QDoubleSpinBox : public QAbstractSpinBox Q_PROPERTY(double minimum READ minimum WRITE setMinimum) Q_PROPERTY(double maximum READ maximum WRITE setMaximum) Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep) + Q_PROPERTY(StepType stepType READ stepType WRITE setStepType) Q_PROPERTY(double value READ value WRITE setValue NOTIFY valueChanged USER true) public: explicit QDoubleSpinBox(QWidget *parent = nullptr); @@ -147,6 +152,9 @@ public: void setRange(double min, double max); + StepType stepType() const; + void setStepType(StepType stepType); + int decimals() const; void setDecimals(int prec); diff --git a/src/widgets/widgets/qsplashscreen.cpp b/src/widgets/widgets/qsplashscreen.cpp index 44b9f7d9a1..277d2fd99f 100644 --- a/src/widgets/widgets/qsplashscreen.cpp +++ b/src/widgets/widgets/qsplashscreen.cpp @@ -327,7 +327,13 @@ void QSplashScreen::drawContents(QPainter *painter) cursor.select(QTextCursor::Document); QTextBlockFormat fmt; fmt.setAlignment(Qt::Alignment(d->currAlign)); + fmt.setLayoutDirection(layoutDirection()); cursor.mergeBlockFormat(fmt); + const QSizeF txtSize = doc.size(); + if (d->currAlign & Qt::AlignBottom) + r.setTop(r.height() - txtSize.height()); + else if (d->currAlign & Qt::AlignVCenter) + r.setTop(r.height() / 2 - txtSize.height() / 2); painter->save(); painter->translate(r.topLeft()); doc.drawContents(painter); diff --git a/src/widgets/widgets/qsplitter.cpp b/src/widgets/widgets/qsplitter.cpp index 6ee49aa9f0..9e38c8f18a 100644 --- a/src/widgets/widgets/qsplitter.cpp +++ b/src/widgets/widgets/qsplitter.cpp @@ -826,7 +826,7 @@ QSplitterLayoutStruct *QSplitterPrivate::findWidget(QWidget *w) const if (list.at(i)->widget == w) return list.at(i); } - return 0; + return nullptr; } @@ -855,7 +855,7 @@ void QSplitterPrivate::insertWidget_helper(int index, QWidget *widget, bool show QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w) { Q_Q(QSplitter); - QSplitterLayoutStruct *sls = 0; + QSplitterLayoutStruct *sls = nullptr; int i; int last = list.count(); for (i = 0; i < list.size(); ++i) { @@ -872,12 +872,9 @@ QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w) if (sls) { list.move(i,index); } else { - QSplitterHandle *newHandle = 0; sls = new QSplitterLayoutStruct; - QString tmp = QLatin1String("qt_splithandle_"); - tmp += w->objectName(); - newHandle = q->createHandle(); - newHandle->setObjectName(tmp); + QSplitterHandle *newHandle = q->createHandle(); + newHandle->setObjectName(QLatin1String("qt_splithandle_") + w->objectName()); sls->handle = newHandle; sls->widget = w; w->lower(); @@ -1248,7 +1245,7 @@ QSplitterHandle *QSplitter::handle(int index) const { Q_D(const QSplitter); if (index < 0 || index >= d->list.size()) - return 0; + return nullptr; return d->list.at(index)->handle; } @@ -1262,7 +1259,7 @@ QWidget *QSplitter::widget(int index) const { Q_D(const QSplitter); if (index < 0 || index >= d->list.size()) - return 0; + return nullptr; return d->list.at(index)->widget; } @@ -1463,7 +1460,7 @@ void QSplitter::moveSplitter(int pos, int index) void QSplitter::getRange(int index, int *min, int *max) const { Q_D(const QSplitter); - d->getRange(index, min, 0, 0, max); + d->getRange(index, min, nullptr, nullptr, max); } diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp index 98e15c8f17..68453e1842 100644 --- a/src/widgets/widgets/qtabbar.cpp +++ b/src/widgets/widgets/qtabbar.cpp @@ -74,6 +74,23 @@ QT_BEGIN_NAMESPACE +namespace { +class CloseButton : public QAbstractButton +{ + Q_OBJECT + +public: + explicit CloseButton(QWidget *parent = 0); + + QSize sizeHint() const override; + QSize minimumSizeHint() const override + { return sizeHint(); } + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + void paintEvent(QPaintEvent *event) override; +}; +} + QMovableTabWidget::QMovableTabWidget(QWidget *parent) : QWidget(parent) { @@ -2686,7 +2703,7 @@ void QTabBarPrivate::Tab::TabBarAnimation::updateCurrentValue(const QVariant &cu priv->moveTab(priv->tabList.indexOf(*tab), current.toInt()); } -void QTabBarPrivate::Tab::TabBarAnimation::updateState(QAbstractAnimation::State, QAbstractAnimation::State newState) +void QTabBarPrivate::Tab::TabBarAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State) { if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(*tab)); } @@ -2695,5 +2712,4 @@ void QTabBarPrivate::Tab::TabBarAnimation::updateState(QAbstractAnimation::State QT_END_NAMESPACE #include "moc_qtabbar.cpp" - -#include "moc_qtabbar_p.cpp" +#include "qtabbar.moc" diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h index 04f07c7cec..9b798e89c9 100644 --- a/src/widgets/widgets/qtabbar_p.h +++ b/src/widgets/widgets/qtabbar_p.h @@ -146,7 +146,7 @@ public: void updateCurrentValue(const QVariant ¤t) override; - void updateState(State, State newState) override; + void updateState(State newState, State) override; private: //these are needed for the callbacks Tab *tab; @@ -273,21 +273,6 @@ public: }; -class CloseButton : public QAbstractButton -{ - Q_OBJECT - -public: - explicit CloseButton(QWidget *parent = 0); - - QSize sizeHint() const override; - QSize minimumSizeHint() const override - { return sizeHint(); } - void enterEvent(QEvent *event) override; - void leaveEvent(QEvent *event) override; - void paintEvent(QPaintEvent *event) override; -}; - QT_END_NAMESPACE #endif diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp index df847e4894..8a848554e3 100644 --- a/src/widgets/widgets/qtabwidget.cpp +++ b/src/widgets/widgets/qtabwidget.cpp @@ -511,8 +511,6 @@ QString QTabWidget::tabText(int index) const } /*! - \overload - Sets the \a icon for the tab at position \a index. */ void QTabWidget::setTabIcon(int index, const QIcon &icon) diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp index fa4dd14c92..46b973bae7 100644 --- a/src/widgets/widgets/qtextbrowser.cpp +++ b/src/widgets/widgets/qtextbrowser.cpp @@ -163,10 +163,13 @@ QString QTextBrowserPrivate::findFile(const QUrl &name) const fileName = name.toLocalFile(); } + if (fileName.isEmpty()) + return fileName; + if (QFileInfo(fileName).isAbsolute()) return fileName; - foreach (QString path, searchPaths) { + for (QString path : qAsConst(searchPaths)) { if (!path.endsWith(QLatin1Char('/'))) path.append(QLatin1Char('/')); path.append(fileName); @@ -1089,6 +1092,8 @@ QVariant QTextBrowser::loadResource(int /*type*/, const QUrl &name) QByteArray data; QString fileName = d->findFile(d->resolveUrl(name)); + if (fileName.isEmpty()) + return QVariant(); QFile f(fileName); if (f.open(QFile::ReadOnly)) { data = f.readAll(); diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 5790b1e32e..e3a45680ef 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -1518,8 +1518,7 @@ void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e) layout->setViewport(QRect()); if (!placeholderText.isEmpty() && doc->isEmpty() && !control->isPreediting()) { - QColor col = control->palette().text().color(); - col.setAlpha(128); + const QColor col = control->palette().placeholderText().color(); p->setPen(col); const int margin = int(doc->documentMargin()); p->drawText(viewport->rect().adjusted(margin, margin, -margin, -margin), Qt::AlignTop | Qt::TextWordWrap, placeholderText); @@ -2311,8 +2310,6 @@ void QTextEdit::scrollToAnchor(const QString &name) } /*! - \fn QTextEdit::zoomIn(int range) - Zooms in on the text by making the base font size \a range points larger and recalculating all font sizes to be the new size. This does not change the size of any images. @@ -2325,10 +2322,6 @@ void QTextEdit::zoomIn(int range) } /*! - \fn QTextEdit::zoomOut(int range) - - \overload - Zooms out on the text by making the base font size \a range points smaller and recalculating all font sizes to be the new size. This does not change the size of any images. diff --git a/src/widgets/widgets/qtoolbar.cpp b/src/widgets/widgets/qtoolbar.cpp index 4e90bce69d..4af71c126e 100644 --- a/src/widgets/widgets/qtoolbar.cpp +++ b/src/widgets/widgets/qtoolbar.cpp @@ -743,8 +743,6 @@ void QToolBar::clear() } /*! - \overload - Creates a new action with the given \a text. This action is added to the end of the toolbar. */ diff --git a/src/widgets/widgets/qtoolbarlayout_p.h b/src/widgets/widgets/qtoolbarlayout_p.h index b813cd5e2c..a788d30450 100644 --- a/src/widgets/widgets/qtoolbarlayout_p.h +++ b/src/widgets/widgets/qtoolbarlayout_p.h @@ -97,7 +97,7 @@ public: void insertAction(int index, QAction *action); int indexOf(QAction *action) const; - int indexOf(QWidget *widget) const override { return QLayout::indexOf(widget); } + using QLayout::indexOf; // bring back the hidden members bool layoutActions(const QSize &size); QSize expandedSize(const QSize &size) const; diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index c4a928410b..cf2d885b52 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -711,10 +711,12 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); if (m_validInput) { if (m_text != textCopy) { - internalSetText(textCopy, cursorCopy, false); + internalSetText(textCopy, cursorCopy, edited); return true; } m_cursor = cursorCopy; + } else { + emit inputRejected(); } } #endif @@ -762,6 +764,8 @@ void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edite if (m_maskData) { m_text = maskString(0, txt, true); m_text += clearString(m_text.length(), m_maxLength - m_text.length()); + if (edited && oldText == m_text) + emit inputRejected(); } else { m_text = txt.isEmpty() ? txt : txt.left(m_maxLength); } @@ -839,6 +843,8 @@ void QWidgetLineControl::internalInsert(const QString &s) addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); if (m_maskData) { QString ms = maskString(m_cursor, s); + if (ms.isEmpty() && !s.isEmpty()) + emit inputRejected(); #ifndef QT_NO_ACCESSIBILITY QAccessibleTextInsertEvent insertEvent(accessibleObject(), m_cursor, ms); QAccessible::updateAccessibility(&insertEvent); @@ -867,6 +873,8 @@ void QWidgetLineControl::internalInsert(const QString &s) addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1)); m_textDirty = true; } + if (s.length() > remaining) + emit inputRejected(); } } diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index ca70e2c02f..3e33bc0605 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -545,6 +545,7 @@ Q_SIGNALS: void accepted(); void editingFinished(); void updateNeeded(const QRect &); + void inputRejected(); #ifdef QT_KEYPAD_NAVIGATION void editFocusChange(bool); diff --git a/src/widgets/widgets/qwidgetresizehandler.cpp b/src/widgets/widgets/qwidgetresizehandler.cpp index 45010d1768..7ed6f6d78d 100644 --- a/src/widgets/widgets/qwidgetresizehandler.cpp +++ b/src/widgets/widgets/qwidgetresizehandler.cpp @@ -192,6 +192,7 @@ bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee) keyPressEvent(static_cast<QKeyEvent *>(ee)); break; case QEvent::ShortcutOverride: + buttonDown &= ((QGuiApplication::mouseButtons() & Qt::LeftButton) != Qt::NoButton); if (buttonDown) { ee->accept(); return true; |