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