1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickdialog_p.h"
5#include "qquickdialog_p_p.h"
6#include "qquickdialogbuttonbox_p.h"
7#include "qquickabstractbutton_p.h"
8#include "qquickpopupitem_p_p.h"
9#include "qquickpopupwindow_p_p.h"
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \qmltype Dialog
15 \inherits Popup
16//! \nativetype QQuickDialog
17 \inqmlmodule QtQuick.Controls
18 \ingroup qtquickcontrols-dialogs
19 \ingroup qtquickcontrols-popups
20 \brief Popup dialog with standard buttons and a title, used for short-term interaction with the user.
21 \since 5.8
22
23 A dialog is a popup mostly used for short-term tasks and brief communications
24 with the user. Similarly to \l ApplicationWindow and \l Page, Dialog is organized
25 into three sections: \l header, \l {Popup::}{contentItem}, and \l footer.
26
27 \image qtquickcontrols-page-wireframe.png
28
29 The \l {Popup::}{padding} properties only affect the contentItem. Use the
30 \l {Popup::}{spacing} property to affect the space between header,
31 contentItem and footer.
32
33 By default, Dialogs have \l {QQuickItem::}{focus}.
34
35 \section1 Dialog Title and Buttons
36
37 Dialog's \l title is displayed by a style-specific title bar that is assigned
38 as a dialog \l header by default.
39
40 Dialog's standard buttons are managed by a \l DialogButtonBox that is assigned
41 as a dialog \l footer by default. The dialog's \l standardButtons property is
42 forwarded to the respective property of the button box. Furthermore, the
43 \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
44 signals of the button box are connected to the respective signals in Dialog.
45
46 \snippet qtquickcontrols-dialog.qml 1
47
48 \section1 Modal Dialogs
49
50 A \l {Popup::}{modal} dialog blocks input to other content beneath
51 the dialog. When a modal dialog is opened, the user must finish
52 interacting with the dialog and close it before they can access any
53 other content in the same window.
54
55 \snippet qtquickcontrols-dialog-modal.qml 1
56
57 \section1 Modeless Dialogs
58
59 A modeless dialog is a dialog that operates independently of other
60 content around the dialog. When a modeless dialog is opened, the user
61 is allowed to interact with both the dialog and the other content in
62 the same window.
63
64 \snippet qtquickcontrols-dialog-modeless.qml 1
65
66 \sa DialogButtonBox, {Popup Controls}
67*/
68
69/*!
70 \qmlsignal QtQuick.Controls::Dialog::accepted()
71
72 This signal is emitted when the dialog has been accepted either
73 interactively or by calling \l accept().
74
75 \note This signal is \e not emitted when closing the dialog with
76 \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
77
78 \sa rejected()
79*/
80
81/*!
82 \qmlsignal QtQuick.Controls::Dialog::rejected()
83
84 This signal is emitted when the dialog has been rejected either
85 interactively or by calling \l reject().
86
87 \note This signal is \e not emitted when closing the dialog with
88 \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
89
90 \sa accepted()
91*/
92
93/*!
94 \since QtQuick.Controls 2.3 (Qt 5.10)
95 \qmlsignal QtQuick.Controls::Dialog::applied()
96
97 This signal is emitted when the \c Dialog.Apply standard button is clicked.
98
99 \sa discarded(), reset()
100*/
101
102/*!
103 \since QtQuick.Controls 2.3 (Qt 5.10)
104 \qmlsignal QtQuick.Controls::Dialog::reset()
105
106 This signal is emitted when the \c Dialog.Reset standard button is clicked.
107
108 \sa discarded(), applied()
109*/
110
111/*!
112 \since QtQuick.Controls 2.3 (Qt 5.10)
113 \qmlsignal QtQuick.Controls::Dialog::discarded()
114
115 This signal is emitted when the \c Dialog.Discard standard button is clicked.
116
117 \sa reset(), applied()
118*/
119
120/*!
121 \since QtQuick.Controls 2.3 (Qt 5.10)
122 \qmlsignal QtQuick.Controls::Dialog::helpRequested()
123
124 This signal is emitted when the \c Dialog.Help standard button is clicked.
125
126 \sa accepted(), rejected()
127*/
128
129QPlatformDialogHelper::ButtonRole QQuickDialogPrivate::buttonRole(QQuickAbstractButton *button)
130{
131 const QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(object: qmlAttachedPropertiesObject<QQuickDialogButtonBox>(obj: button, create: false));
132 return attached ? attached->buttonRole() : QPlatformDialogHelper::InvalidRole;
133}
134
135void QQuickDialogPrivate::handleAccept()
136{
137 Q_Q(QQuickDialog);
138 q->accept();
139}
140
141void QQuickDialogPrivate::handleReject()
142{
143 Q_Q(QQuickDialog);
144 q->reject();
145}
146
147void QQuickDialogPrivate::handleClick(QQuickAbstractButton *button)
148{
149 Q_Q(QQuickDialog);
150 switch (buttonRole(button)) {
151 case QPlatformDialogHelper::ApplyRole:
152 emit q->applied();
153 break;
154 case QPlatformDialogHelper::ResetRole:
155 emit q->reset();
156 break;
157 case QPlatformDialogHelper::DestructiveRole:
158 emit q->discarded();
159 q->close();
160 break;
161 case QPlatformDialogHelper::HelpRole:
162 emit q->helpRequested();
163 break;
164 default:
165 break;
166 }
167}
168
169Qt::WindowFlags QQuickDialogPrivate::popupWindowType() const
170{
171 return Qt::Dialog;
172}
173
174QQuickDialog::QQuickDialog(QObject *parent)
175 : QQuickDialog(*(new QQuickDialogPrivate), parent)
176{
177}
178
179QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
180 : QQuickPopup(dd, parent)
181{
182 Q_D(QQuickDialog);
183
184 // Dialogs should get active focus when opened so that e.g. Cancel closes them.
185 setFocus(true);
186 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::headerChanged, context: this, slot: &QQuickDialog::headerChanged);
187 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::footerChanged, context: this, slot: &QQuickDialog::footerChanged);
188 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::implicitHeaderWidthChanged, context: this, slot: &QQuickDialog::implicitHeaderWidthChanged);
189 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::implicitHeaderHeightChanged, context: this, slot: &QQuickDialog::implicitHeaderHeightChanged);
190 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::implicitFooterWidthChanged, context: this, slot: &QQuickDialog::implicitFooterWidthChanged);
191 QObject::connect(sender: d->popupItem, signal: &QQuickPopupItem::implicitFooterHeightChanged, context: this, slot: &QQuickDialog::implicitFooterHeightChanged);
192}
193
194QQuickDialog::~QQuickDialog()
195{
196 Q_D(QQuickDialog);
197 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::headerChanged, receiver: this, slot: &QQuickDialog::headerChanged);
198 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::footerChanged, receiver: this, slot: &QQuickDialog::footerChanged);
199 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::implicitHeaderWidthChanged, receiver: this, slot: &QQuickDialog::implicitHeaderWidthChanged);
200 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::implicitHeaderHeightChanged, receiver: this, slot: &QQuickDialog::implicitHeaderHeightChanged);
201 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::implicitFooterWidthChanged, receiver: this, slot: &QQuickDialog::implicitFooterWidthChanged);
202 QObject::disconnect(sender: d->popupItem, signal: &QQuickPopupItem::implicitFooterHeightChanged, receiver: this, slot: &QQuickDialog::implicitFooterHeightChanged);
203}
204
205/*!
206 \qmlproperty string QtQuick.Controls::Dialog::title
207
208 This property holds the dialog title.
209
210 The title is displayed in the dialog header.
211
212 \code
213 Dialog {
214 title: qsTr("About")
215
216 Label {
217 text: "Lorem ipsum..."
218 }
219 }
220 \endcode
221*/
222QString QQuickDialog::title() const
223{
224 Q_D(const QQuickDialog);
225 return d->m_title;
226}
227
228void QQuickDialog::setTitle(const QString &title)
229{
230 Q_D(QQuickDialog);
231 if (d->m_title == title)
232 return;
233 d->m_title = title;
234
235 if (d->popupWindow)
236 d->popupWindow->setTitle(title);
237 else
238 d->popupItem->setTitle(title);
239
240 emit titleChanged();
241}
242
243/*!
244 \qmlproperty Item QtQuick.Controls::Dialog::header
245
246 This property holds the dialog header item. The header item is positioned to
247 the top, and resized to the width of the dialog. The default value is \c null.
248
249 \note Assigning a \l DialogButtonBox as a dialog header automatically connects
250 its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
251 signals to the respective signals in Dialog.
252
253 \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
254 header automatically sets the respective \l DialogButtonBox::position,
255 \l ToolBar::position, or \l TabBar::position property to \c Header.
256
257 \sa footer
258*/
259QQuickItem *QQuickDialog::header() const
260{
261 Q_D(const QQuickDialog);
262 return d->popupItem->header();
263}
264
265void QQuickDialog::setHeader(QQuickItem *header)
266{
267 Q_D(QQuickDialog);
268 QQuickItem *oldHeader = d->popupItem->header();
269 if (oldHeader == header)
270 return;
271
272 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: header, QStringLiteral("header"));
273
274 if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object: oldHeader)) {
275 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::accepted, receiverPrivate: d, slot: &QQuickDialogPrivate::handleAccept);
276 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::rejected, receiverPrivate: d, slot: &QQuickDialogPrivate::handleReject);
277 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: d, slot: &QQuickDialogPrivate::handleClick);
278 if (d->buttonBox == buttonBox)
279 d->buttonBox = nullptr;
280 }
281
282 if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object: header)) {
283 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::accepted, receiverPrivate: d, slot: &QQuickDialogPrivate::handleAccept);
284 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::rejected, receiverPrivate: d, slot: &QQuickDialogPrivate::handleReject);
285 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: d, slot: &QQuickDialogPrivate::handleClick);
286 d->buttonBox = buttonBox;
287 buttonBox->setStandardButtons(d->standardButtons);
288 }
289
290 d->popupItem->setHeader(header);
291}
292
293/*!
294 \qmlproperty Item QtQuick.Controls::Dialog::footer
295
296 This property holds the dialog footer item. The footer item is positioned to
297 the bottom, and resized to the width of the dialog. The default value is \c null.
298
299 \note Assigning a \l DialogButtonBox as a dialog footer automatically connects
300 its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
301 signals to the respective signals in Dialog.
302
303 \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
304 footer automatically sets the respective \l DialogButtonBox::position,
305 \l ToolBar::position, or \l TabBar::position property to \c Footer.
306
307 \sa header
308*/
309QQuickItem *QQuickDialog::footer() const
310{
311 Q_D(const QQuickDialog);
312 return d->popupItem->footer();
313}
314
315void QQuickDialog::setFooter(QQuickItem *footer)
316{
317 Q_D(QQuickDialog);
318 QQuickItem *oldFooter = d->popupItem->footer();
319 if (oldFooter == footer)
320 return;
321
322 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: footer, QStringLiteral("footer"));
323
324 if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object: oldFooter)) {
325 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::accepted, receiverPrivate: d, slot: &QQuickDialogPrivate::handleAccept);
326 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::rejected, receiverPrivate: d, slot: &QQuickDialogPrivate::handleReject);
327 QObjectPrivate::disconnect(sender: buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: d, slot: &QQuickDialogPrivate::handleClick);
328 if (d->buttonBox == buttonBox)
329 d->buttonBox = nullptr;
330 }
331 if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object: footer)) {
332 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::accepted, receiverPrivate: d, slot: &QQuickDialogPrivate::handleAccept);
333 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::rejected, receiverPrivate: d, slot: &QQuickDialogPrivate::handleReject);
334 QObjectPrivate::connect(sender: buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: d, slot: &QQuickDialogPrivate::handleClick);
335 d->buttonBox = buttonBox;
336 buttonBox->setStandardButtons(d->standardButtons);
337 }
338
339 d->popupItem->setFooter(footer);
340}
341
342/*!
343 \qmlproperty enumeration QtQuick.Controls::Dialog::standardButtons
344
345 This property holds a combination of standard buttons that are used by the dialog.
346
347 \snippet qtquickcontrols-dialog.qml 1
348
349 The buttons will be positioned in the appropriate order for the user's platform.
350
351 Possible flags:
352 \value Dialog.Ok An "OK" button defined with the \c AcceptRole.
353 \value Dialog.Open An "Open" button defined with the \c AcceptRole.
354 \value Dialog.Save A "Save" button defined with the \c AcceptRole.
355 \value Dialog.Cancel A "Cancel" button defined with the \c RejectRole.
356 \value Dialog.Close A "Close" button defined with the \c RejectRole.
357 \value Dialog.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
358 \value Dialog.Apply An "Apply" button defined with the \c ApplyRole.
359 \value Dialog.Reset A "Reset" button defined with the \c ResetRole.
360 \value Dialog.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
361 \value Dialog.Help A "Help" button defined with the \c HelpRole.
362 \value Dialog.SaveAll A "Save All" button defined with the \c AcceptRole.
363 \value Dialog.Yes A "Yes" button defined with the \c YesRole.
364 \value Dialog.YesToAll A "Yes to All" button defined with the \c YesRole.
365 \value Dialog.No A "No" button defined with the \c NoRole.
366 \value Dialog.NoToAll A "No to All" button defined with the \c NoRole.
367 \value Dialog.Abort An "Abort" button defined with the \c RejectRole.
368 \value Dialog.Retry A "Retry" button defined with the \c AcceptRole.
369 \value Dialog.Ignore An "Ignore" button defined with the \c AcceptRole.
370 \value Dialog.NoButton An invalid button.
371
372 \sa DialogButtonBox
373*/
374QPlatformDialogHelper::StandardButtons QQuickDialog::standardButtons() const
375{
376 Q_D(const QQuickDialog);
377 return d->standardButtons;
378}
379
380void QQuickDialog::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
381{
382 Q_D(QQuickDialog);
383 if (d->standardButtons == buttons)
384 return;
385
386 d->standardButtons = buttons;
387 if (d->buttonBox)
388 d->buttonBox->setStandardButtons(buttons);
389 emit standardButtonsChanged();
390}
391
392/*!
393 \since QtQuick.Controls 2.3 (Qt 5.10)
394 \qmlmethod AbstractButton QtQuick.Controls::Dialog::standardButton(StandardButton button)
395
396 Returns the specified standard \a button, or \c null if it does not exist.
397
398 \sa standardButtons
399*/
400QQuickAbstractButton *QQuickDialog::standardButton(QPlatformDialogHelper::StandardButton button) const
401{
402 Q_D(const QQuickDialog);
403 if (!d->buttonBox)
404 return nullptr;
405 return d->buttonBox->standardButton(button);
406}
407
408/*!
409 \since QtQuick.Controls 2.3 (Qt 5.10)
410 \qmlproperty int QtQuick.Controls::Dialog::result
411
412 This property holds the result code.
413
414 Standard result codes:
415 \value Dialog.Accepted The dialog was accepted.
416 \value Dialog.Rejected The dialog was rejected.
417
418 \sa accept(), reject(), done()
419*/
420int QQuickDialog::result() const
421{
422 Q_D(const QQuickDialog);
423 return d->result;
424}
425
426void QQuickDialog::setResult(int result)
427{
428 Q_D(QQuickDialog);
429 if (d->result == result)
430 return;
431
432 d->result = result;
433 emit resultChanged();
434}
435
436/*!
437 \since QtQuick.Controls 2.5 (Qt 5.12)
438 \qmlproperty real QtQuick.Controls::Dialog::implicitHeaderWidth
439 \readonly
440
441 This property holds the implicit header width.
442
443 The value is equal to \c {header && header.visible ? header.implicitWidth : 0}.
444
445 \sa implicitHeaderHeight, implicitFooterWidth
446*/
447qreal QQuickDialog::implicitHeaderWidth() const
448{
449 Q_D(const QQuickDialog);
450 return d->popupItem->implicitHeaderWidth();
451}
452
453/*!
454 \since QtQuick.Controls 2.5 (Qt 5.12)
455 \qmlproperty real QtQuick.Controls::Dialog::implicitHeaderHeight
456 \readonly
457
458 This property holds the implicit header height.
459
460 The value is equal to \c {header && header.visible ? header.implicitHeight : 0}.
461
462 \sa implicitHeaderWidth, implicitFooterHeight
463*/
464qreal QQuickDialog::implicitHeaderHeight() const
465{
466 Q_D(const QQuickDialog);
467 return d->popupItem->implicitHeaderHeight();
468}
469
470/*!
471 \since QtQuick.Controls 2.5 (Qt 5.12)
472 \qmlproperty real QtQuick.Controls::Dialog::implicitFooterWidth
473 \readonly
474
475 This property holds the implicit footer width.
476
477 The value is equal to \c {footer && footer.visible ? footer.implicitWidth : 0}.
478
479 \sa implicitFooterHeight, implicitHeaderWidth
480*/
481qreal QQuickDialog::implicitFooterWidth() const
482{
483 Q_D(const QQuickDialog);
484 return d->popupItem->implicitFooterWidth();
485}
486
487/*!
488 \since QtQuick.Controls 2.5 (Qt 5.12)
489 \qmlproperty real QtQuick.Controls::Dialog::implicitFooterHeight
490 \readonly
491
492 This property holds the implicit footer height.
493
494 The value is equal to \c {footer && footer.visible ? footer.implicitHeight : 0}.
495
496 \sa implicitFooterWidth, implicitHeaderHeight
497*/
498qreal QQuickDialog::implicitFooterHeight() const
499{
500 Q_D(const QQuickDialog);
501 return d->popupItem->implicitFooterHeight();
502}
503
504void QQuickDialog::setOpacity(qreal opacity)
505{
506 Q_D(QQuickDialog);
507 QQuickPopup::setOpacity(d->popupWindow ? qreal(!qFuzzyIsNull(d: opacity)) : opacity);
508}
509
510/*!
511 \qmlmethod void QtQuick.Controls::Dialog::accept()
512
513 Emits the \l accepted() signal and closes the dialog.
514
515 \sa reject(), done()
516*/
517void QQuickDialog::accept()
518{
519 done(result: Accepted);
520}
521
522/*!
523 \qmlmethod void QtQuick.Controls::Dialog::reject()
524
525 Emits the \l rejected() signal and closes the dialog.
526
527 \sa accept(), done()
528*/
529void QQuickDialog::reject()
530{
531 done(result: Rejected);
532}
533
534/*!
535 \since QtQuick.Controls 2.3 (Qt 5.10)
536 \qmlmethod void QtQuick.Controls::Dialog::done(int result)
537
538 \list 1
539 \li Sets the \a result.
540 \li Emits \l accepted() or \l rejected() depending on
541 whether the result is \c Dialog.Accepted or \c Dialog.Rejected,
542 respectively.
543 \li Emits \l{Popup::}{closed()}.
544 \endlist
545
546 \sa accept(), reject(), result
547*/
548void QQuickDialog::done(int result)
549{
550 setResult(result);
551
552 if (result == Accepted)
553 emit accepted();
554 else if (result == Rejected)
555 emit rejected();
556
557 close();
558}
559
560#if QT_CONFIG(accessibility)
561QAccessible::Role QQuickDialog::accessibleRole() const
562{
563 return QAccessible::Dialog;
564}
565
566void QQuickDialog::accessibilityActiveChanged(bool active)
567{
568 Q_D(QQuickDialog);
569 QQuickPopup::accessibilityActiveChanged(active);
570
571 if (active)
572 maybeSetAccessibleName(name: d->popupItem->title());
573}
574#endif
575
576QT_END_NAMESPACE
577
578#include "moc_qquickdialog_p.cpp"
579

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quicktemplates/qquickdialog.cpp