a b/src/qtgui/widgets/qxtconfirmationmessage.cpp
1
#include "qxtconfirmationmessage.h"
2
/****************************************************************************
3
** Copyright (c) 2006 - 2011, the LibQxt project.
4
** See the Qxt AUTHORS file for a list of authors and copyright holders.
5
** All rights reserved.
6
**
7
** Redistribution and use in source and binary forms, with or without
8
** modification, are permitted provided that the following conditions are met:
9
**     * Redistributions of source code must retain the above copyright
10
**       notice, this list of conditions and the following disclaimer.
11
**     * Redistributions in binary form must reproduce the above copyright
12
**       notice, this list of conditions and the following disclaimer in the
13
**       documentation and/or other materials provided with the distribution.
14
**     * Neither the name of the LibQxt project nor the
15
**       names of its contributors may be used to endorse or promote products
16
**       derived from this software without specific prior written permission.
17
**
18
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
**
29
** <http://libqxt.org>  <foundation@libqxt.org>
30
*****************************************************************************/
31
32
33
#include <QCoreApplication>
34
#include <QDialogButtonBox>
35
#include <QPushButton>
36
#include <QGridLayout>
37
#include <QCheckBox>
38
39
static const QLatin1String DEFAULT_ORGANIZATION("QxtWidgets");
40
static const QLatin1String DEFAULT_APPLICATION("QxtConfirmationMessage");
41
42
class QxtConfirmationMessagePrivate : public QxtPrivate<QxtConfirmationMessage>
43
{
44
public:
45
    QXT_DECLARE_PUBLIC(QxtConfirmationMessage)
46
    void init(const QString& message = QString());
47
48
    QString key() const;
49
    QString applicationName() const;
50
    QString organizationName() const;
51
52
    int showAgain();
53
    void doNotShowAgain(int result);
54
    void reset();
55
56
    bool remember;
57
    QCheckBox* confirm;
58
    QString overrideApp;
59
    QString overrideKey;
60
    QString overrideOrg;
61
62
    static QString path;
63
    static QSettings::Scope scope;
64
    static QSettings::Format format;
65
};
66
67
QString QxtConfirmationMessagePrivate::path;
68
QSettings::Scope QxtConfirmationMessagePrivate::scope = QSettings::UserScope;
69
QSettings::Format QxtConfirmationMessagePrivate::format = QSettings::NativeFormat;
70
71
void QxtConfirmationMessagePrivate::init(const QString& message)
72
{
73
    remember = false;
74
    confirm = new QCheckBox(&qxt_p());
75
    if (!message.isNull())
76
        confirm->setText(message);
77
    else
78
        confirm->setText(QxtConfirmationMessage::tr("Do not show again."));
79
80
    QGridLayout* grid = qobject_cast<QGridLayout*>(qxt_p().layout());
81
    QDialogButtonBox* buttons = qxt_p().findChild<QDialogButtonBox*>();
82
    if (grid && buttons)
83
    {
84
        const int idx = grid->indexOf(buttons);
85
        int row, column, rowSpan, columnSpan = 0;
86
        grid->getItemPosition(idx, &row, &column, &rowSpan, &columnSpan);
87
        QLayoutItem* buttonsItem = grid->takeAt(idx);
88
        grid->addWidget(confirm, row, column, rowSpan, columnSpan, Qt::AlignLeft | Qt::AlignTop);
89
        grid->addItem(buttonsItem, ++row, column, rowSpan, columnSpan);
90
    }
91
}
92
93
QString QxtConfirmationMessagePrivate::key() const
94
{
95
    QString value = overrideKey;
96
    if (value.isEmpty())
97
    {
98
        const QString all = qxt_p().windowTitle() + qxt_p().text() + qxt_p().informativeText();
99
        const QByteArray data = all.toLocal8Bit();
100
        value = QString::number(qChecksum(data.constData(), data.length()));
101
    }
102
    return value;
103
}
104
105
QString QxtConfirmationMessagePrivate::applicationName() const
106
{
107
    QString name = overrideApp;
108
    if (name.isEmpty())
109
        name = QCoreApplication::applicationName();
110
    if (name.isEmpty())
111
        name = DEFAULT_APPLICATION;
112
    return name;
113
}
114
115
QString QxtConfirmationMessagePrivate::organizationName() const
116
{
117
    QString name = overrideOrg;
118
    if (name.isEmpty())
119
        name = QCoreApplication::organizationName();
120
    if (name.isEmpty())
121
        name = DEFAULT_ORGANIZATION;
122
    return name;
123
}
124
125
int QxtConfirmationMessagePrivate::showAgain()
126
{
127
    QSettings settings(format, scope, organizationName(), applicationName());
128
    if (!path.isEmpty())
129
        settings.beginGroup(path);
130
    return settings.value(key(), -1).toInt();
131
}
132
133
void QxtConfirmationMessagePrivate::doNotShowAgain(int result)
134
{
135
    QSettings settings(format, scope, organizationName(), applicationName());
136
    if (!path.isEmpty())
137
        settings.beginGroup(path);
138
    settings.setValue(key(), result);
139
}
140
141
void QxtConfirmationMessagePrivate::reset()
142
{
143
    QSettings settings(format, scope, organizationName(), applicationName());
144
    if (!path.isEmpty())
145
        settings.beginGroup(path);
146
    settings.remove(key());
147
}
148
149
/*!
150
    \class QxtConfirmationMessage
151
    \inmodule QxtWidgets
152
    \brief The QxtConfirmationMessage class provides a confirmation message.
153
154
    QxtConfirmationMessage is a confirmation message with checkable
155
    \bold {"Do not show again."} option. A checked and accepted confirmation
156
    message is no more shown until reseted.
157
158
    Example usage:
159
    \code
160
    void MainWindow::closeEvent(QCloseEvent* event)
161
    {
162
        static const QString text(tr("Are you sure you want to quit?"));
163
        if (QxtConfirmationMessage::confirm(this, tr("Confirm"), text) == QMessageBox::No)
164
            event->ignore();
165
    }
166
    \endcode
167
168
    \image qxtconfirmationmessage.png "QxtConfirmationMessage in action."
169
170
    \bold {Note:} QCoreApplication::organizationName and QCoreApplication::applicationName
171
    are used for storing settings. In case these properties are empty, \bold "QxtWidgets" and
172
    \bold "QxtConfirmationMessage" are used, respectively.
173
 */
174
175
/*!
176
    Constructs a new QxtConfirmationMessage with \a parent.
177
 */
178
QxtConfirmationMessage::QxtConfirmationMessage(QWidget* parent)
179
        : QMessageBox(parent)
180
{
181
    QXT_INIT_PRIVATE(QxtConfirmationMessage);
182
    qxt_d().init();
183
}
184
185
/*!
186
    Constructs a new QxtConfirmationMessage with \a icon, \a title, \a text, \a confirmation, \a buttons, \a parent and \a flags.
187
 */
188
QxtConfirmationMessage::QxtConfirmationMessage(QMessageBox::Icon icon, const QString& title, const QString& text, const QString& confirmation,
189
        QMessageBox::StandardButtons buttons, QWidget* parent, Qt::WindowFlags flags)
190
        : QMessageBox(icon, title, text, buttons, parent, flags)
191
{
192
    QXT_INIT_PRIVATE(QxtConfirmationMessage);
193
    qxt_d().init(confirmation);
194
}
195
196
/*!
197
    Destructs the confirmation message.
198
 */
199
QxtConfirmationMessage::~QxtConfirmationMessage()
200
{
201
}
202
203
/*!
204
    Opens an confirmation message box with the specified \a title, \a text and \a confirmation.
205
    The standard \a buttons are added to the message box. \a defaultButton specifies 
206
    the button used when Enter is pressed. \a defaultButton must refer to a button that
207
    was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox
208
    chooses a suitable default automatically.
209
210
    Returns the identity of the standard button that was clicked.
211
    If Esc was pressed instead, the escape button is returned.
212
213
    If \a parent is \c 0, the message box is an application modal dialog box.
214
    If \a parent is a widget, the message box is window modal relative to \a parent.
215
 */
216
QMessageBox::StandardButton QxtConfirmationMessage::confirm(QWidget* parent,
217
        const QString& title, const QString& text, const QString& confirmation,
218
        QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
219
{
220
    QxtConfirmationMessage msgBox(QMessageBox::NoIcon, title, text, confirmation, QMessageBox::NoButton, parent);
221
    QDialogButtonBox* buttonBox = msgBox.findChild<QDialogButtonBox*>();
222
    Q_ASSERT(buttonBox != 0);
223
224
    uint mask = QMessageBox::FirstButton;
225
    while (mask <= QMessageBox::LastButton)
226
    {
227
        uint sb = buttons & mask;
228
        mask <<= 1;
229
        if (!sb)
230
            continue;
231
        QPushButton* button = msgBox.addButton((QMessageBox::StandardButton)sb);
232
        // Choose the first accept role as the default
233
        if (msgBox.defaultButton())
234
            continue;
235
        if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
236
                || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton)))
237
            msgBox.setDefaultButton(button);
238
    }
239
    if (msgBox.exec() == -1)
240
        return QMessageBox::Cancel;
241
    return msgBox.standardButton(msgBox.clickedButton());
242
}
243
244
/*!
245
    \property QxtConfirmationMessage::confirmationText
246
    \brief the confirmation text
247
248
    The default value is \bold {"Do not show again."}
249
 */
250
QString QxtConfirmationMessage::confirmationText() const
251
{
252
    return qxt_d().confirm->text();
253
}
254
255
void QxtConfirmationMessage::setConfirmationText(const QString& confirmation)
256
{
257
    qxt_d().confirm->setText(confirmation);
258
}
259
260
/*!
261
    \property QxtConfirmationMessage::overrideSettingsApplication
262
    \brief the override application name used for settings
263
264
    QCoreApplication::applicationName is used when no \bold overrideSettingsApplication
265
    has been set. The application name falls back to \bold "QxtConfirmationMessage"
266
    when no QCoreApplication::applicationName has been set.
267
268
    The default value is an empty string.
269
 */
270
QString QxtConfirmationMessage::overrideSettingsApplication() const
271
{
272
    return qxt_d().overrideApp;
273
}
274
275
void QxtConfirmationMessage::setOverrideSettingsApplication(const QString& application)
276
{
277
    qxt_d().overrideApp = application;
278
}
279
280
/*!
281
    \property QxtConfirmationMessage::overrideSettingsKey
282
    \brief the override key used for settings
283
284
    When no \bold overrideSettingsKey has been set, the key is calculated with
285
    qChecksum() based on title, text and confirmation message.
286
287
    The default value is an empty string.
288
 */
289
QString QxtConfirmationMessage::overrideSettingsKey() const
290
{
291
    return qxt_d().overrideKey;
292
}
293
294
void QxtConfirmationMessage::setOverrideSettingsKey(const QString& key)
295
{
296
    qxt_d().overrideKey = key;
297
}
298
299
/*!
300
    \property QxtConfirmationMessage::overrideSettingsOrganization
301
    \brief the override organization name used for settings
302
303
    QCoreApplication::organizationName is used when no \bold overrideSettingsOrganization
304
    has been set. The organization name falls back to \bold "QxtWidgets" when no
305
    QCoreApplication::organizationName has been set.
306
307
    The default value is an empty string.
308
 */
309
QString QxtConfirmationMessage::overrideSettingsOrganization() const
310
{
311
    return qxt_d().overrideOrg;
312
}
313
314
void QxtConfirmationMessage::setOverrideSettingsOrganization(const QString& organization)
315
{
316
    qxt_d().overrideOrg = organization;
317
}
318
319
/*!
320
    \property QxtConfirmationMessage::rememberOnReject
321
    \brief whether \bold {"Do not show again."} option is stored even
322
    if the message box is rejected (eg. user presses Cancel).
323
324
    The default value is \c false.
325
 */
326
bool QxtConfirmationMessage::rememberOnReject() const
327
{
328
    return qxt_d().remember;
329
}
330
331
void QxtConfirmationMessage::setRememberOnReject(bool remember)
332
{
333
    qxt_d().remember = remember;
334
}
335
336
/*!
337
    Returns The format used for storing settings.
338
339
    The default value is QSettings::NativeFormat.
340
 */
341
QSettings::Format QxtConfirmationMessage::settingsFormat()
342
{
343
    return QxtConfirmationMessagePrivate::format;
344
}
345
346
/*!
347
    Sets the \a format used for storing settings.
348
 */
349
void QxtConfirmationMessage::setSettingsFormat(QSettings::Format format)
350
{
351
    QxtConfirmationMessagePrivate::format = format;
352
}
353
354
/*!
355
    Returns The scope used for storing settings.
356
357
    The default value is QSettings::UserScope.
358
 */
359
QSettings::Scope QxtConfirmationMessage::settingsScope()
360
{
361
    return QxtConfirmationMessagePrivate::scope;
362
}
363
364
/*!
365
    Sets the \a scope used for storing settings.
366
 */
367
void QxtConfirmationMessage::setSettingsScope(QSettings::Scope scope)
368
{
369
    QxtConfirmationMessagePrivate::scope = scope;
370
}
371
372
/*!
373
    Returns the path used for storing settings.
374
375
    The default value is an empty string.
376
 */
377
QString QxtConfirmationMessage::settingsPath()
378
{
379
    return QxtConfirmationMessagePrivate::path;
380
}
381
382
/*!
383
    Sets the \a path used for storing settings.
384
 */
385
void QxtConfirmationMessage::setSettingsPath(const QString& path)
386
{
387
    QxtConfirmationMessagePrivate::path = path;
388
}
389
390
/*!
391
    Shows the confirmation message if necessary. The confirmation message is not
392
    shown in case \bold {"Do not show again."} has been checked while the same
393
    confirmation message was earlierly accepted.
394
395
    A confirmation message is identified by the combination of title,
396
    QMessageBox::text and optional QMessageBox::informativeText.
397
398
    A clicked button with role QDialogButtonBox::AcceptRole or
399
    QDialogButtonBox::YesRole is considered as "accepted".
400
401
    \warning This function does not reimplement but shadows QMessageBox::exec().
402
403
    \sa QWidget::windowTitle, QMessageBox::text, QMessageBox::informativeText
404
 */
405
int QxtConfirmationMessage::exec()
406
{
407
    int res = qxt_d().showAgain();
408
    if (res == -1)
409
        res = QMessageBox::exec();
410
    return res;
411
}
412
413
/*!
414
    \reimp
415
 */
416
void QxtConfirmationMessage::done(int result)
417
{
418
    QDialogButtonBox* buttons = this->findChild<QDialogButtonBox*>();
419
    Q_ASSERT(buttons != 0);
420
421
    int role = buttons->buttonRole(clickedButton());
422
    if (qxt_d().confirm->isChecked() &&
423
            (qxt_d().remember || role != QDialogButtonBox::RejectRole))
424
    {
425
        qxt_d().doNotShowAgain(result);
426
    }
427
    QMessageBox::done(result);
428
}
429
430
/*!
431
    Resets this instance of QxtConfirmationMessage. A reseted confirmation
432
    message is shown again until user checks \bold {"Do not show again."} and
433
    accepts the confirmation message.
434
 */
435
void QxtConfirmationMessage::reset()
436
{
437
    qxt_d().reset();
438
}