1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** 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.LGPL3 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-3.0.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 (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickdialog_p.h"
41#include <QQuickItem>
42#include <QQmlEngine>
43#include <QStandardPaths>
44#include <private/qguiapplication_p.h>
45
46QT_BEGIN_NAMESPACE
47
48/*!
49 \qmltype Dialog
50 \instantiates QQuickDialog1
51 \inqmlmodule QtQuick.Dialogs
52 \ingroup qtquickdialogs
53 \brief A generic QtQuick dialog wrapper with standard buttons.
54 \since 5.3
55
56 The purpose of Dialog is to wrap arbitrary content into a \e {dialog window}
57 including a row of platform-tailored buttons.
58
59 \note On Android, it is recommended to use \l {QQuickDialog}{Qt Quick Controls 2 Dialog}.
60
61 The \l contentItem is the default property (the only allowed child
62 element), and items declared inside the Dialog will actually be children of
63 another Item inside the \c contentItem. The row of \l standardButtons will
64 also be inside \c contentItem below the declared content, and Dialog will
65 attempt to size itself to fit the content and the buttons.
66
67 Alternatively it is possible to bind \l contentItem to a custom Item, in
68 which case there will be no buttons, no margins, and the custom content
69 will fill the whole dialog. This is much like creating a \l Window,
70 except that on platforms which do not support showing multiple windows,
71 the window borders will be simulated and it will be shown in same scene.
72
73 \note do not attempt to bind the width or height of the dialog to the width
74 or height of its content, because Dialog already tries to size itself
75 to the content. If your goal is to change or eliminate the margins, you
76 must override \l contentItem. If your goal is simply to show a window
77 (whether modal or not), and your platform supports it, it is simpler to use
78 \l Window instead.
79*/
80
81/*!
82 \qmlsignal Dialog::accepted()
83
84 This signal is emitted when the user has pressed any button which has the
85 \l {QMessageBox::}{AcceptRole}: \gui OK, \gui Open, \gui Save,
86 \gui {Save All}, \gui Retry or \gui Ignore.
87
88 The corresponding handler is \c onAccepted.
89*/
90
91/*!
92 \qmlsignal Dialog::rejected()
93
94 This signal is emitted when the user has dismissed the dialog, by closing
95 the dialog window, by pressing a \gui Cancel, \gui Close or \gui Abort
96 button on the dialog, or by pressing the back button or the escape key.
97
98 The corresponding handler is \c onRejected.
99*/
100
101/*!
102 \qmlsignal Dialog::discard()
103
104 This signal is emitted when the user has pressed the \gui Discard button.
105
106 The corresponding handler is \c onDiscard.
107*/
108
109/*!
110 \qmlsignal Dialog::help()
111
112 This signal is emitted when the user has pressed the \gui Help button.
113 Depending on platform, the dialog may not be automatically dismissed
114 because the help that your application provides may need to be relevant to
115 the text shown in this dialog in order to assist the user in making a
116 decision. However on other platforms it's not possible to show a dialog and
117 a help window at the same time. If you want to be sure that the dialog will
118 close, you can set \l visible to \c false in your handler.
119
120 The corresponding handler is \c onHelp.
121*/
122
123/*!
124 \qmlsignal Dialog::yes()
125
126 This signal is emitted when the user has pressed any button which has
127 the \l {QMessageBox::YesRole} {YesRole}: \gui Yes or \gui {Yes to All}.
128
129 The corresponding handler is \c onYes.
130*/
131
132/*!
133 \qmlsignal Dialog::no()
134
135 This signal is emitted when the user has pressed any button which has
136 the \l {QMessageBox::NoRole} {NoRole}: \gui No or \gui {No to All}.
137
138 The corresponding handler is \c onNo.
139*/
140
141/*!
142 \qmlsignal Dialog::apply()
143
144 This signal is emitted when the user has pressed the \gui Apply button.
145
146 The corresponding handler is \c onApply.
147*/
148
149/*!
150 \qmlsignal Dialog::reset()
151
152 This signal is emitted when the user has pressed any button which has
153 the \l {QMessageBox::ResetRole} {ResetRole}: \gui Reset or \gui {Restore Defaults}.
154
155 The corresponding handler is \c onReset.
156*/
157
158/*!
159 \qmlsignal Dialog::actionChosen(var action)
160
161 This signal is emitted when the user has pressed any button or a key
162 associated with some role (such as the Enter or Escape keys). The \a
163 action parameter carries information about the event:
164
165 \list
166 \li StandardButton button - The role of the button which was pressed. If a
167 key was pressed instead, this will be \c StandardButton.Ok if accepted
168 and \c StandardButton.Cancel if rejected.
169 \li Qt.Key key - The key which was pressed, or \c 0 if none
170 \li bool accepted - Set this to \c false to stop the event from triggering
171 its predefined action
172 \endlist
173
174 By handling this signal and setting the \c action.accepted field to \c
175 false, it's possible to implement some validation on the dialog contents
176 before accepting it, for example.
177
178 The corresponding handler is \c onActionChosen.
179
180 \since QtQuick.Controls 1.8
181*/
182
183/*!
184 \qmlproperty bool Dialog::visible
185
186 This property holds whether the dialog is visible. By default this is
187 \c false.
188
189 \sa modality
190*/
191
192/*! \qmlproperty StandardButton Dialog::clickedButton
193
194 This property holds the button pressed by the user. Its value is
195 one of the flags set for the standardButtons property.
196*/
197
198/*!
199 \qmlproperty Qt::WindowModality Dialog::modality
200
201 Whether the dialog should be shown modal with respect to the window
202 containing the dialog's parent Item, modal with respect to the whole
203 application, or non-modal.
204
205 By default it is \c Qt.WindowModal.
206
207 Modality does not mean that there are any blocking calls to wait for the
208 dialog to be accepted or rejected: only that the user will be prevented
209 from interacting with the parent window or the application windows
210 until the dialog is dismissed.
211*/
212
213/*!
214 \qmlmethod void Dialog::open()
215
216 Shows the dialog to the user. It is equivalent to setting \l visible to
217 \c true.
218*/
219
220/*!
221 \qmlmethod void Dialog::close()
222
223 Closes the dialog.
224*/
225
226/*!
227 \qmlproperty string Dialog::title
228
229 The title of the dialog window.
230*/
231
232/*!
233 \class QQuickDialog1
234 \inmodule QtQuick.Dialogs
235 \internal
236
237 The QQuickDialog1 class represents a container for arbitrary
238 dialog contents.
239
240 \since 5.3
241*/
242
243/*!
244 Constructs a dialog wrapper with parent window \a parent.
245*/
246QQuickDialog1::QQuickDialog1(QObject *parent)
247 : QQuickAbstractDialog(parent)
248 , m_enabledButtons(Ok)
249 , m_clickedButton(NoButton)
250{
251}
252
253
254/*!
255 Destroys the dialog wrapper.
256*/
257QQuickDialog1::~QQuickDialog1()
258{
259}
260
261QJSValue QQuickDialog1::__standardButtonsLeftModel()
262{
263 updateStandardButtons();
264 return m_standardButtonsLeftModel;
265}
266
267QJSValue QQuickDialog1::__standardButtonsRightModel()
268{
269 updateStandardButtons();
270 return m_standardButtonsRightModel;
271}
272
273void QQuickDialog1::setVisible(bool v)
274{
275 if (v)
276 m_clickedButton = NoButton;
277 QQuickAbstractDialog::setVisible(v);
278}
279
280void QQuickDialog1::updateStandardButtons()
281{
282 if (m_standardButtonsRightModel.isUndefined()) {
283 QJSEngine *engine = qmlEngine(this);
284 // Managed objects so no need to destroy any existing ones
285 m_standardButtonsLeftModel = engine->newArray();
286 m_standardButtonsRightModel = engine->newArray();
287 int i = 0;
288
289 QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
290 QPlatformDialogHelper::ButtonLayout layoutPolicy =
291 static_cast<QPlatformDialogHelper::ButtonLayout>(theme->themeHint(hint: QPlatformTheme::DialogButtonBoxLayout).toInt());
292 const int *buttonLayout = QPlatformDialogHelper::buttonLayout(orientation: Qt::Horizontal, policy: layoutPolicy);
293 QJSValue *model = &m_standardButtonsLeftModel;
294 for (int r = 0; buttonLayout[r] != QPlatformDialogHelper::EOL; ++r) {
295 quint32 role = (buttonLayout[r] & ~QPlatformDialogHelper::Reverse);
296 // Keep implementation in sync with that in QDialogButtonBoxPrivate::layoutButtons()
297 // to the extent that QtQuick supports the same features
298 switch (role) {
299 case QPlatformDialogHelper::Stretch:
300 model = &m_standardButtonsRightModel;
301 i = 0;
302 break;
303 // TODO maybe: case QPlatformDialogHelper::AlternateRole:
304 default: {
305 for (int e = QPlatformDialogHelper::LowestBit; e <= QPlatformDialogHelper::HighestBit; ++e) {
306 quint32 standardButton = 1 << e;
307 quint32 standardButtonRole = QPlatformDialogHelper::buttonRole(
308 button: static_cast<QPlatformDialogHelper::StandardButton>(standardButton));
309 if ((m_enabledButtons & standardButton) && standardButtonRole == role) {
310 QJSValue o = engine->newObject();
311 o.setProperty(name: "text", value: theme->standardButtonText(button: standardButton));
312 o.setProperty(name: "standardButton", value: standardButton);
313 o.setProperty(name: "role", value: role);
314 model->setProperty(arrayIndex: i++, value: o);
315 }
316 }
317 } break;
318 }
319 }
320 }
321}
322
323void QQuickDialog1::setTitle(const QString &arg)
324{
325 if (m_title != arg) {
326 m_title = arg;
327 if (m_dialogWindow)
328 m_dialogWindow->setTitle(m_title);
329 emit titleChanged();
330 }
331}
332
333void QQuickDialog1::setStandardButtons(StandardButtons buttons)
334{
335 m_enabledButtons = buttons;
336 m_standardButtonsLeftModel = QJSValue();
337 m_standardButtonsRightModel = QJSValue();
338 emit standardButtonsChanged();
339}
340
341/*!
342 \qmlproperty QObject Dialog::contentItem
343
344 The QML object which implements the dialog contents. Should be an \l Item.
345
346 For example the following dialog will show custom content and no buttons:
347
348 \qml
349 import QtQuick 2.3
350 import QtQuick.Controls 1.2
351 import QtQuick.Dialogs 1.2
352
353 Dialog {
354 visible: true
355 title: "Blue sky dialog"
356
357 contentItem: Rectangle {
358 color: "lightskyblue"
359 implicitWidth: 400
360 implicitHeight: 100
361 Text {
362 text: "Hello blue sky!"
363 color: "navy"
364 anchors.centerIn: parent
365 }
366 }
367 }
368 \endqml
369*/
370
371void QQuickDialog1::click(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role)
372{
373 m_clickedButton = static_cast<StandardButton>(button);
374 emit buttonClicked();
375 switch (role) {
376 case QPlatformDialogHelper::AcceptRole:
377 emit accepted();
378 setVisible(false);
379 break;
380 case QPlatformDialogHelper::RejectRole:
381 emit rejected();
382 setVisible(false);
383 break;
384 case QPlatformDialogHelper::DestructiveRole:
385 emit discard();
386 setVisible(false);
387 break;
388 case QPlatformDialogHelper::HelpRole:
389 emit help();
390 break;
391 case QPlatformDialogHelper::YesRole:
392 emit yes();
393 setVisible(false);
394 break;
395 case QPlatformDialogHelper::NoRole:
396 emit no();
397 setVisible(false);
398 break;
399 case QPlatformDialogHelper::ApplyRole:
400 emit apply();
401 break;
402 case QPlatformDialogHelper::ResetRole:
403 emit reset();
404 break;
405 default:
406 qWarning(msg: "unhandled Dialog button %d with role %d", (int)button, (int)role);
407 }
408}
409
410void QQuickDialog1::click(QQuickAbstractDialog::StandardButton button)
411{
412 click(button: static_cast<QPlatformDialogHelper::StandardButton>(button),
413 role: static_cast<QPlatformDialogHelper::ButtonRole>(
414 QPlatformDialogHelper::buttonRole(button: static_cast<QPlatformDialogHelper::StandardButton>(button))));
415}
416
417void QQuickDialog1::accept() {
418 // enter key is treated like OK
419 if (m_clickedButton == NoButton)
420 m_clickedButton = Ok;
421 QQuickAbstractDialog::accept();
422}
423
424void QQuickDialog1::reject() {
425 // escape key is treated like cancel
426 if (m_clickedButton == NoButton)
427 m_clickedButton = Cancel;
428 QQuickAbstractDialog::reject();
429}
430
431/*!
432 \qmlproperty StandardButtons Dialog::standardButtons
433
434 Dialog has a row of buttons along the bottom, each of which has a
435 \l {QMessageBox::ButtonRole} {ButtonRole} that determines which signal
436 will be emitted when the button is pressed. You can also find out which
437 specific button was pressed after the fact via the \l clickedButton
438 property. You can control which buttons are available by setting
439 standardButtons to a bitwise-or combination of the following flags:
440
441 \value StandardButton.Ok
442 An \gui OK button defined with the
443 \l {QMessageBox::}{AcceptRole}.
444 \value StandardButton.Open
445 An \gui Open button defined with the
446 \l {QMessageBox::}{AcceptRole}.
447 \value StandardButton.Save
448 A \gui Save button defined with the
449 \l {QMessageBox::}{AcceptRole}.
450 \value StandardButton.Cancel
451 A \gui Cancel button defined with the
452 \l {QMessageBox::}{RejectRole}.
453 \value StandardButton.Close
454 A \gui Close button defined with the
455 \l {QMessageBox::}{RejectRole}.
456 \value StandardButton.Discard
457 A \gui Discard or \gui {Don't Save} button,
458 depending on the platform, defined with the
459 \l {QMessageBox::}{DestructiveRole}.
460 \value StandardButton.Apply
461 An \gui Apply button defined with the
462 \l {QMessageBox::}{ApplyRole}.
463 \value StandardButton.Reset
464 A \gui Reset button defined with the
465 \l {QMessageBox::}{ResetRole}.
466 \value StandardButton.RestoreDefaults
467 A \gui {Restore Defaults} button defined with the
468 \l {QMessageBox::}{ResetRole}.
469 \value StandardButton.Help
470 A \gui Help button defined with the
471 \l {QMessageBox::}{HelpRole}.
472 \value StandardButton.SaveAll
473 A \gui {Save All} button defined with the
474 \l {QMessageBox::}{AcceptRole}.
475 \value StandardButton.Yes
476 A \gui Yes button defined with the
477 \l {QMessageBox::}{YesRole}.
478 \value StandardButton.YesToAll
479 A \gui {Yes to All} button defined with the
480 \l {QMessageBox::}{YesRole}.
481 \value StandardButton.No
482 A \gui No button defined with the
483 \l {QMessageBox::}{NoRole}.
484 \value StandardButton.NoToAll
485 A \gui {No to All} button defined with the
486 \l {QMessageBox::}{NoRole}.
487 \value StandardButton.Abort
488 An \gui Abort button defined with the
489 \l {QMessageBox::}{RejectRole}.
490 \value StandardButton.Retry
491 A \gui Retry button defined with the
492 \l {QMessageBox::}{AcceptRole}.
493 \value StandardButton.Ignore
494 An \gui Ignore button defined with the
495 \l {QMessageBox::}{AcceptRole}.
496
497 For example the following dialog will show a calendar with the ability to
498 save or cancel a date:
499
500 \qml
501 import QtQuick 2.3
502 import QtQuick.Controls 1.2
503 import QtQuick.Dialogs 1.2
504
505 Dialog {
506 id: dateDialog
507 visible: true
508 title: "Choose a date"
509 standardButtons: StandardButton.Save | StandardButton.Cancel
510
511 onAccepted: console.log("Saving the date " +
512 calendar.selectedDate.toLocaleDateString())
513
514 Calendar {
515 id: calendar
516 onDoubleClicked: dateDialog.click(StandardButton.Save)
517 }
518 }
519 \endqml
520
521 The default is \c StandardButton.Ok.
522
523 The enum values are the same as in \l QMessageBox::StandardButtons.
524*/
525
526QT_END_NAMESPACE
527

source code of qtquickcontrols/src/dialogs/qquickdialog.cpp