diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/widgets/qdialogbuttonbox.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/widgets/qdialogbuttonbox.cpp')
-rw-r--r-- | src/gui/widgets/qdialogbuttonbox.cpp | 1136 |
1 files changed, 1136 insertions, 0 deletions
diff --git a/src/gui/widgets/qdialogbuttonbox.cpp b/src/gui/widgets/qdialogbuttonbox.cpp new file mode 100644 index 0000000..246da95 --- /dev/null +++ b/src/gui/widgets/qdialogbuttonbox.cpp @@ -0,0 +1,1136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qhash.h> +#include <QtGui/qpushbutton.h> +#include <QtGui/qstyle.h> +#include <QtGui/qlayout.h> +#include <QtGui/qdialog.h> +#include <QtGui/qapplication.h> +#include <QtGui/private/qwidget_p.h> + +#include "qdialogbuttonbox.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDialogButtonBox + \since 4.2 + \brief The QDialogButtonBox class is a widget that presents buttons in a + layout that is appropriate to the current widget style. + + \ingroup application + \mainclass + + Dialogs and message boxes typically present buttons in a layout that + conforms to the interface guidelines for that platform. Invariably, + different platforms have different layouts for their dialogs. + QDialogButtonBox allows a developer to add buttons to it and will + automatically use the appropriate layout for the user's desktop + environment. + + Most buttons for a dialog follow certain roles. Such roles include: + + \list + \o Accepting or rejecting the dialog. + \o Asking for help. + \o Performing actions on the dialog itself (such as resetting fields or + applying changes). + \endlist + + There can also be alternate ways of dismissing the dialog which may cause + destructive results. + + Most dialogs have buttons that can almost be considered standard (e.g. + \gui OK and \gui Cancel buttons). It is sometimes convenient to create these + buttons in a standard way. + + There are a couple ways of using QDialogButtonBox. One ways is to create + the buttons (or button texts) yourself and add them to the button box, + specifying their role. + + \snippet examples/dialogs/extension/finddialog.cpp 1 + + Alternatively, QDialogButtonBox provides several standard buttons (e.g. OK, Cancel, Save) + that you can use. They exist as flags so you can OR them together in the constructor. + + \snippet examples/dialogs/tabdialog/tabdialog.cpp 2 + + You can mix and match normal buttons and standard buttons. + + Currently the buttons are laid out in the following way if the button box is horizontal: + \table 100% + \row \o \inlineimage buttonbox-gnomelayout-horizontal.png GnomeLayout Horizontal + \o Button box laid out in horizontal GnomeLayout + \row \o \inlineimage buttonbox-kdelayout-horizontal.png KdeLayout Horizontal + \o Button box laid out in horizontal KdeLayout + \row \o \inlineimage buttonbox-maclayout-horizontal.png MacLayout Horizontal + \o Button box laid out in horizontal MacLayout + \row \o \inlineimage buttonbox-winlayout-horizontal.png WinLayout Horizontal + \o Button box laid out in horizontal WinLayout + \endtable + + The buttons are laid out the following way if the button box is vertical: + + \table 100% + \row \o \inlineimage buttonbox-gnomelayout-vertical.png GnomeLayout Vertical + \o Button box laid out in vertical GnomeLayout + \row \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical + \o Button box laid out in vertical KdeLayout + \row \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical + \o Button box laid out in vertical MacLayout + \row \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical + \o Button box laid out in vertical WinLayout + \endtable + + Additionally, button boxes that contain only buttons with ActionRole or + HelpRole can be considered modeless and have an alternate look on the mac: + + \table 100% + \row \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout + \o modeless horizontal MacLayout + \row \o \inlineimage buttonbox-mac-modeless-vertical.png Screenshot of modeless vertical MacLayout + \o modeless vertical MacLayout + \endtable + + When a button is clicked in the button box, the clicked() signal is emitted + for the actual button is that is pressed. For convenience, if the button + has an AcceptRole, RejectRole, or HelpRole, the accepted(), rejected(), or + helpRequested() signals are emitted respectively. + + If you want a specific button to be default you need to call + QPushButton::setDefault() on it yourself. However, if there is no default + button set and to preserve which button is the default button across + platforms when using the QPushButton::autoDefault property, the first push + button with the accept role is made the default button when the + QDialogButtonBox is shown, + + \sa QMessageBox, QPushButton, QDialog +*/ + +enum { + AcceptRole = QDialogButtonBox::AcceptRole, + RejectRole = QDialogButtonBox::RejectRole, + DestructiveRole = QDialogButtonBox::DestructiveRole, + ActionRole = QDialogButtonBox::ActionRole, + HelpRole = QDialogButtonBox::HelpRole, + YesRole = QDialogButtonBox::YesRole, + NoRole = QDialogButtonBox::NoRole, + ApplyRole = QDialogButtonBox::ApplyRole, + ResetRole = QDialogButtonBox::ResetRole, + + AlternateRole = 0x10000000, + Stretch = 0x20000000, + EOL = 0x40000000, + Reverse = 0x80000000 +}; + +static QDialogButtonBox::ButtonRole roleFor(QDialogButtonBox::StandardButton button) +{ + switch (button) { + case QDialogButtonBox::Ok: + case QDialogButtonBox::Save: + case QDialogButtonBox::Open: + case QDialogButtonBox::SaveAll: + case QDialogButtonBox::Retry: + case QDialogButtonBox::Ignore: + return QDialogButtonBox::AcceptRole; + + case QDialogButtonBox::Cancel: + case QDialogButtonBox::Close: + case QDialogButtonBox::Abort: + return QDialogButtonBox::RejectRole; + + case QDialogButtonBox::Discard: + return QDialogButtonBox::DestructiveRole; + + case QDialogButtonBox::Help: + return QDialogButtonBox::HelpRole; + + case QDialogButtonBox::Apply: + return QDialogButtonBox::ApplyRole; + + case QDialogButtonBox::Yes: + case QDialogButtonBox::YesToAll: + return QDialogButtonBox::YesRole; + + case QDialogButtonBox::No: + case QDialogButtonBox::NoToAll: + return QDialogButtonBox::NoRole; + + case QDialogButtonBox::RestoreDefaults: + case QDialogButtonBox::Reset: + return QDialogButtonBox::ResetRole; + + case QDialogButtonBox::NoButton: // NoButton means zero buttons, not "No" button + ; + } + + return QDialogButtonBox::InvalidRole; +} + +static const int layouts[2][5][14] = +{ + // Qt::Horizontal + { + // WinLayout + { ResetRole, Stretch, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, ActionRole, RejectRole, ApplyRole, + HelpRole, EOL, EOL, EOL }, + + // MacLayout + { HelpRole, ResetRole, ApplyRole, ActionRole, Stretch, DestructiveRole | Reverse, + AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL, EOL }, + + // KdeLayout + { HelpRole, ResetRole, Stretch, YesRole, NoRole, ActionRole, AcceptRole, AlternateRole, + ApplyRole, DestructiveRole, RejectRole, EOL }, + + // GnomeLayout + { HelpRole, ResetRole, Stretch, ActionRole, ApplyRole | Reverse, DestructiveRole | Reverse, + AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL }, + + // Mac modeless + { ResetRole, ApplyRole, ActionRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL } + }, + + // Qt::Vertical + { + // WinLayout + { ActionRole, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, RejectRole, ApplyRole, ResetRole, + HelpRole, Stretch, EOL, EOL, EOL }, + + // MacLayout + { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, Stretch, ActionRole, ApplyRole, + ResetRole, HelpRole, EOL, EOL }, + + // KdeLayout + { AcceptRole, AlternateRole, ApplyRole, ActionRole, YesRole, NoRole, Stretch, ResetRole, + DestructiveRole, RejectRole, HelpRole, EOL }, + + // GnomeLayout + { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, ApplyRole, ActionRole, Stretch, + ResetRole, HelpRole, EOL, EOL, EOL }, + + // Mac modeless + { ActionRole, ApplyRole, ResetRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL } + } +}; + +class QDialogButtonBoxPrivate : public QWidgetPrivate +{ + Q_DECLARE_PUBLIC(QDialogButtonBox) + +public: + QDialogButtonBoxPrivate(Qt::Orientation orient); + + QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles]; + QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash; + + Qt::Orientation orientation; + QDialogButtonBox::ButtonLayout layoutPolicy; + QBoxLayout *buttonLayout; + bool internalRemove; + bool center; + + void createStandardButtons(QDialogButtonBox::StandardButtons buttons); + + void layoutButtons(); + void initLayout(); + void resetLayout(); + QPushButton *createButton(QDialogButtonBox::StandardButton button, bool doLayout = true); + void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, bool doLayout = true); + void _q_handleButtonDestroyed(); + void _q_handleButtonClicked(); + void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse); + void retranslateStrings(); + const char *standardButtonText(QDialogButtonBox::StandardButton sbutton) const; +}; + +QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient) + : orientation(orient), buttonLayout(0), internalRemove(false), center(false) +{ +} + +void QDialogButtonBoxPrivate::initLayout() +{ + Q_Q(QDialogButtonBox); + layoutPolicy = QDialogButtonBox::ButtonLayout(q->style()->styleHint(QStyle::SH_DialogButtonLayout, 0, q)); + bool createNewLayout = buttonLayout == 0 + || (orientation == Qt::Horizontal && qobject_cast<QVBoxLayout *>(buttonLayout) != 0) + || (orientation == Qt::Vertical && qobject_cast<QHBoxLayout *>(buttonLayout) != 0); + if (createNewLayout) { + delete buttonLayout; + if (orientation == Qt::Horizontal) + buttonLayout = new QHBoxLayout(q); + else + buttonLayout = new QVBoxLayout(q); + } + + int left, top, right, bottom; + setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem); + getLayoutItemMargins(&left, &top, &right, &bottom); + buttonLayout->setContentsMargins(-left, -top, -right, -bottom); + + if (!q->testAttribute(Qt::WA_WState_OwnSizePolicy)) { + QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::ButtonBox); + if (orientation == Qt::Vertical) + sp.transpose(); + q->setSizePolicy(sp); + q->setAttribute(Qt::WA_WState_OwnSizePolicy, false); + } + + // ### move to a real init() function + q->setFocusPolicy(Qt::TabFocus); +} + +void QDialogButtonBoxPrivate::resetLayout() +{ + //delete buttonLayout; + initLayout(); + layoutButtons(); +} + +void QDialogButtonBoxPrivate::addButtonsToLayout(const QList<QAbstractButton *> &buttonList, + bool reverse) +{ + int start = reverse ? buttonList.count() - 1 : 0; + int end = reverse ? -1 : buttonList.count(); + int step = reverse ? -1 : 1; + + for (int i = start; i != end; i += step) { + QAbstractButton *button = buttonList.at(i); + buttonLayout->addWidget(button); + button->show(); + } +} + +void QDialogButtonBoxPrivate::layoutButtons() +{ + Q_Q(QDialogButtonBox); + const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item + + for (int i = buttonLayout->count() - 1; i >= 0; --i) { + QLayoutItem *item = buttonLayout->takeAt(i); + if (QWidget *widget = item->widget()) + widget->hide(); + delete item; + } + + int tmpPolicy = layoutPolicy; + + static const int M = 5; + static const int ModalRoles[M] = { AcceptRole, RejectRole, DestructiveRole, YesRole, NoRole }; + if (tmpPolicy == QDialogButtonBox::MacLayout) { + bool hasModalButton = false; + for (int i = 0; i < M; ++i) { + if (!buttonLists[ModalRoles[i]].isEmpty()) { + hasModalButton = true; + break; + } + } + if (!hasModalButton) + tmpPolicy = 4; // Mac modeless + } + + const int *currentLayout = layouts[orientation == Qt::Vertical][tmpPolicy]; + + if (center) + buttonLayout->addStretch(); + + QList<QAbstractButton *> acceptRoleList = buttonLists[AcceptRole]; + + while (*currentLayout != EOL) { + int role = (*currentLayout & ~Reverse); + bool reverse = (*currentLayout & Reverse); + + switch (role) { + case Stretch: + if (!center) + buttonLayout->addStretch(); + break; + case AcceptRole: { + if (acceptRoleList.isEmpty()) + break; + // Only the first one + QAbstractButton *button = acceptRoleList.first(); + buttonLayout->addWidget(button); + button->show(); + } + break; + case AlternateRole: + { + if (acceptRoleList.size() < 2) + break; + QList<QAbstractButton *> list = acceptRoleList; + list.removeFirst(); + addButtonsToLayout(list, reverse); + } + break; + case DestructiveRole: + { + const QList<QAbstractButton *> &list = buttonLists[role]; + + /* + Mac: Insert a gap on the left of the destructive + buttons to ensure that they don't get too close to + the help and action buttons (but only if there are + some buttons to the left of the destructive buttons + (and the stretch, whence buttonLayout->count() > 1 + and not 0)). + */ + if (tmpPolicy == QDialogButtonBox::MacLayout + && !list.isEmpty() && buttonLayout->count() > 1) + buttonLayout->addSpacing(MacGap); + + addButtonsToLayout(list, reverse); + + /* + Insert a gap between the destructive buttons and the + accept and reject buttons. + */ + if (tmpPolicy == QDialogButtonBox::MacLayout && !list.isEmpty()) + buttonLayout->addSpacing(MacGap); + } + break; + case RejectRole: + case ActionRole: + case HelpRole: + case YesRole: + case NoRole: + case ApplyRole: + case ResetRole: + addButtonsToLayout(buttonLists[role], reverse); + } + ++currentLayout; + } + + QWidget *lastWidget = 0; + q->setFocusProxy(0); + for (int i = 0; i < buttonLayout->count(); ++i) { + QLayoutItem *item = buttonLayout->itemAt(i); + if (QWidget *widget = item->widget()) { + if (lastWidget) + QWidget::setTabOrder(lastWidget, widget); + else + q->setFocusProxy(widget); + lastWidget = widget; + } + } + + if (center) + buttonLayout->addStretch(); +} + +QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton, + bool doLayout) +{ + Q_Q(QDialogButtonBox); + const char *buttonText = 0; + int icon = 0; + + switch (sbutton) { + case QDialogButtonBox::Ok: + icon = QStyle::SP_DialogOkButton; + break; + case QDialogButtonBox::Save: + icon = QStyle::SP_DialogSaveButton; + break; + case QDialogButtonBox::Open: + icon = QStyle::SP_DialogOpenButton; + break; + case QDialogButtonBox::Cancel: + icon = QStyle::SP_DialogCancelButton; + break; + case QDialogButtonBox::Close: + icon = QStyle::SP_DialogCloseButton; + break; + case QDialogButtonBox::Apply: + icon = QStyle::SP_DialogApplyButton; + break; + case QDialogButtonBox::Reset: + icon = QStyle::SP_DialogResetButton; + break; + case QDialogButtonBox::Help: + icon = QStyle::SP_DialogHelpButton; + break; + case QDialogButtonBox::Discard: + icon = QStyle::SP_DialogDiscardButton; + break; + case QDialogButtonBox::Yes: + icon = QStyle::SP_DialogYesButton; + break; + case QDialogButtonBox::No: + icon = QStyle::SP_DialogNoButton; + break; + case QDialogButtonBox::YesToAll: + case QDialogButtonBox::NoToAll: + case QDialogButtonBox::SaveAll: + case QDialogButtonBox::Abort: + case QDialogButtonBox::Retry: + case QDialogButtonBox::Ignore: + case QDialogButtonBox::RestoreDefaults: + break; + case QDialogButtonBox::NoButton: + return 0; + ; + } + buttonText = standardButtonText(sbutton); + + QPushButton *button = new QPushButton(QDialogButtonBox::tr(buttonText), q); + QStyle *style = q->style(); + if (style->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons, 0, q) && icon != 0) + button->setIcon(style->standardIcon(QStyle::StandardPixmap(icon), 0, q)); + if (style != QApplication::style()) // Propagate style + button->setStyle(style); + standardButtonHash.insert(button, sbutton); + if (roleFor(sbutton) != QDialogButtonBox::InvalidRole) { + addButton(button, roleFor(sbutton), doLayout); + } else { + qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added"); + } + return button; +} + +void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, + bool doLayout) +{ + Q_Q(QDialogButtonBox); + QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_handleButtonClicked())); + QObject::connect(button, SIGNAL(destroyed()), q, SLOT(_q_handleButtonDestroyed())); + buttonLists[role].append(button); + if (doLayout) + layoutButtons(); +} + +void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardButtons buttons) +{ + uint i = QDialogButtonBox::FirstButton; + while (i <= QDialogButtonBox::LastButton) { + if (i & buttons) { + createButton(QDialogButtonBox::StandardButton(i), false); + } + i = i << 1; + } + layoutButtons(); +} + +const char *QDialogButtonBoxPrivate::standardButtonText(QDialogButtonBox::StandardButton sbutton) const +{ + const char *buttonText = 0; + bool gnomeLayout = (layoutPolicy == QDialogButtonBox::GnomeLayout); + switch (sbutton) { + case QDialogButtonBox::Ok: + buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&OK") : QT_TRANSLATE_NOOP("QDialogButtonBox", "OK"); + break; + case QDialogButtonBox::Save: + buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Save") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Save"); + break; + case QDialogButtonBox::Open: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Open"); + break; + case QDialogButtonBox::Cancel: + buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Cancel") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Cancel"); + break; + case QDialogButtonBox::Close: + buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Close") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Close"); + break; + case QDialogButtonBox::Apply: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Apply"); + break; + case QDialogButtonBox::Reset: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Reset"); + break; + case QDialogButtonBox::Help: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Help"); + break; + case QDialogButtonBox::Discard: + if (layoutPolicy == QDialogButtonBox::MacLayout) + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Don't Save"); + else if (layoutPolicy == QDialogButtonBox::GnomeLayout) + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Close without Saving"); + else + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Discard"); + break; + case QDialogButtonBox::Yes: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&Yes"); + break; + case QDialogButtonBox::YesToAll: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Yes to &All"); + break; + case QDialogButtonBox::No: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&No"); + break; + case QDialogButtonBox::NoToAll: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "N&o to All"); + break; + case QDialogButtonBox::SaveAll: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Save All"); + break; + case QDialogButtonBox::Abort: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Abort"); + break; + case QDialogButtonBox::Retry: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Retry"); + break; + case QDialogButtonBox::Ignore: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Ignore"); + break; + case QDialogButtonBox::RestoreDefaults: + buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Restore Defaults"); + break; + case QDialogButtonBox::NoButton: + ; + } // switch + return buttonText; +} + +void QDialogButtonBoxPrivate::retranslateStrings() +{ + const char *buttonText = 0; + QHash<QPushButton *, QDialogButtonBox::StandardButton>::iterator it = standardButtonHash.begin(); + while (it != standardButtonHash.end()) { + buttonText = standardButtonText(it.value()); + if (buttonText) { + QPushButton *button = it.key(); + button->setText(QDialogButtonBox::tr(buttonText)); + } + ++it; + } +} + +/*! + Constructs an empty, horizontal button box with the given \a parent. + + \sa orientation, addButton() +*/ +QDialogButtonBox::QDialogButtonBox(QWidget *parent) + : QWidget(*new QDialogButtonBoxPrivate(Qt::Horizontal), parent, 0) +{ + d_func()->initLayout(); +} + +/*! + Constructs an empty button box with the given \a orientation and \a parent. + + \sa orientation, addButton() +*/ +QDialogButtonBox::QDialogButtonBox(Qt::Orientation orientation, QWidget *parent) + : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0) +{ + d_func()->initLayout(); +} + +/*! + Constructs a button box with the given \a orientation and \a parent, containing + the standard buttons specified by \a buttons. + + \sa orientation, addButton() +*/ +QDialogButtonBox::QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation, + QWidget *parent) + : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0) +{ + d_func()->initLayout(); + d_func()->createStandardButtons(buttons); +} + +/*! + Destroys the button box. +*/ +QDialogButtonBox::~QDialogButtonBox() +{ +} + +/*! + \enum QDialogButtonBox::ButtonRole + \enum QMessageBox::ButtonRole + + This enum describes the roles that can be used to describe buttons in + the button box. Combinations of these roles are as flags used to + describe different aspects of their behavior. + + \value InvalidRole The button is invalid. + \value AcceptRole Clicking the button causes the dialog to be accepted + (e.g. OK). + \value RejectRole Clicking the button causes the dialog to be rejected + (e.g. Cancel). + \value DestructiveRole Clicking the button causes a destructive change + (e.g. for Discarding Changes) and closes the dialog. + \value ActionRole Clicking the button causes changes to the elements within + the dialog. + \value HelpRole The button can be clicked to request help. + \value YesRole The button is a "Yes"-like button. + \value NoRole The button is a "No"-like button. + \value ApplyRole The button applies current changes. + \value ResetRole The button resets the dialog's fields to default values. + + \omitvalue NRoles + + \sa StandardButton +*/ + +/*! + \enum QDialogButtonBox::StandardButton + + These enums describe flags for standard buttons. Each button has a + defined \l ButtonRole. + + \value Ok An "OK" button defined with the \l AcceptRole. + \value Open A "Open" button defined with the \l AcceptRole. + \value Save A "Save" button defined with the \l AcceptRole. + \value Cancel A "Cancel" button defined with the \l RejectRole. + \value Close A "Close" button defined with the \l RejectRole. + \value Discard A "Discard" or "Don't Save" button, depending on the platform, + defined with the \l DestructiveRole. + \value Apply An "Apply" button defined with the \l ApplyRole. + \value Reset A "Reset" button defined with the \l ResetRole. + \value RestoreDefaults A "Restore Defaults" button defined with the \l ResetRole. + \value Help A "Help" button defined with the \l HelpRole. + \value SaveAll A "Save All" button defined with the \l AcceptRole. + \value Yes A "Yes" button defined with the \l YesRole. + \value YesToAll A "Yes to All" button defined with the \l YesRole. + \value No A "No" button defined with the \l NoRole. + \value NoToAll A "No to All" button defined with the \l NoRole. + \value Abort An "Abort" button defined with the \l RejectRole. + \value Retry A "Retry" button defined with the \l AcceptRole. + \value Ignore An "Ignore" button defined with the \l AcceptRole. + + \value NoButton An invalid button. + + \omitvalue FirstButton + \omitvalue LastButton + + \sa ButtonRole, standardButtons +*/ + +/*! + \enum QDialogButtonBox::ButtonLayout + + This enum describes the layout policy to be used when arranging the buttons + contained in the button box. + + \value WinLayout Use a policy appropriate for applications on Windows. + \value MacLayout Use a policy appropriate for applications on Mac OS X. + \value KdeLayout Use a policy appropriate for applications on KDE. + \value GnomeLayout Use a policy appropriate for applications on GNOME. + + The button layout is specified by the \l{style()}{current style}. +*/ + +/*! + \fn void QDialogButtonBox::clicked(QAbstractButton *button) + + This signal is emitted when a button inside the button box is clicked. The + specific button that was pressed is specified by \a button. + + \sa accepted(), rejected(), helpRequested() +*/ + +/*! + \fn void QDialogButtonBox::accepted() + + This signal is emitted when a button inside the button box is clicked, as long + as it was defined with the \l AcceptRole or \l YesRole. + + \sa rejected(), clicked() helpRequested() +*/ + +/*! + \fn void QDialogButtonBox::rejected() + + This signal is emitted when a button inside the button box is clicked, as long + as it was defined with the \l RejectRole or \l NoRole. + + \sa accepted() helpRequested() clicked() +*/ + +/*! + \fn void QDialogButtonBox::helpRequested() + + This signal is emitted when a button inside the button box is clicked, as long + as it was defined with the \l HelpRole. + + \sa accepted() rejected() clicked() +*/ + +/*! + \property QDialogButtonBox::orientation + \brief the orientation of the button box + + By default, the orientation is horizontal (i.e. the buttons are laid out + side by side). The possible orientations are Qt::Horizontal and + Qt::Vertical. +*/ +Qt::Orientation QDialogButtonBox::orientation() const +{ + return d_func()->orientation; +} + +void QDialogButtonBox::setOrientation(Qt::Orientation orientation) +{ + Q_D(QDialogButtonBox); + if (orientation == d->orientation) + return; + + d->orientation = orientation; + d->resetLayout(); +} + +/*! + Clears the button box, deleting all buttons within it. + + \sa removeButton(), addButton() +*/ +void QDialogButtonBox::clear() +{ + Q_D(QDialogButtonBox); + // Remove the created standard buttons, they should be in the other lists, which will + // do the deletion + d->standardButtonHash.clear(); + for (int i = 0; i < NRoles; ++i) { + QList<QAbstractButton *> &list = d->buttonLists[i]; + while (list.count()) { + QAbstractButton *button = list.takeAt(0); + QObject::disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed())); + delete button; + } + } +} + +/*! + Returns a list of all the buttons that have been added to the button box. + + \sa buttonRole(), addButton(), removeButton() +*/ +QList<QAbstractButton *> QDialogButtonBox::buttons() const +{ + Q_D(const QDialogButtonBox); + QList<QAbstractButton *> finalList; + for (int i = 0; i < NRoles; ++i) { + const QList<QAbstractButton *> &list = d->buttonLists[i]; + for (int j = 0; j < list.count(); ++j) + finalList.append(list.at(j)); + } + return finalList; +} + +/*! + Returns the button role for the specified \a button. This function returns + \l InvalidRole if \a button is 0 or has not been added to the button box. + + \sa buttons(), addButton() +*/ +QDialogButtonBox::ButtonRole QDialogButtonBox::buttonRole(QAbstractButton *button) const +{ + Q_D(const QDialogButtonBox); + for (int i = 0; i < NRoles; ++i) { + const QList<QAbstractButton *> &list = d->buttonLists[i]; + for (int j = 0; j < list.count(); ++j) { + if (list.at(j) == button) + return ButtonRole(i); + } + } + return InvalidRole; +} + +/*! + Removes \a button from the button box without deleting it and sets its parent to zero. + + \sa clear(), buttons(), addButton() +*/ +void QDialogButtonBox::removeButton(QAbstractButton *button) +{ + Q_D(QDialogButtonBox); + + if (!button) + return; + + // Remove it from the standard button hash first and then from the roles + if (QPushButton *pushButton = qobject_cast<QPushButton *>(button)) + d->standardButtonHash.remove(pushButton); + for (int i = 0; i < NRoles; ++i) { + QList<QAbstractButton *> &list = d->buttonLists[i]; + for (int j = 0; j < list.count(); ++j) { + if (list.at(j) == button) { + list.takeAt(j); + if (!d->internalRemove) { + disconnect(button, SIGNAL(clicked()), this, SLOT(_q_handleButtonClicked())); + disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed())); + } + break; + } + } + } + if (!d->internalRemove) + button->setParent(0); +} + +/*! + Adds the given \a button to the button box with the specified \a role. + If the role is invalid, the button is not added. + + If the button has already been added, it is removed and added again with the + new role. + + \sa removeButton(), clear() +*/ +void QDialogButtonBox::addButton(QAbstractButton *button, ButtonRole role) +{ + Q_D(QDialogButtonBox); + if (role <= InvalidRole || role >= NRoles) { + qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added"); + return; + } + removeButton(button); + button->setParent(this); + d->addButton(button, role); +} + +/*! + Creates a push button with the given \a text, adds it to the button box for the + specified \a role, and returns the corresponding push button. If \a role is + invalid, no button is created, and zero is returned. + + \sa removeButton(), clear() +*/ +QPushButton *QDialogButtonBox::addButton(const QString &text, ButtonRole role) +{ + Q_D(QDialogButtonBox); + if (role <= InvalidRole || role >= NRoles) { + qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added"); + return 0; + } + QPushButton *button = new QPushButton(text, this); + d->addButton(button, role); + return button; +} + +/*! + Adds a standard \a button to the button box if it is valid to do so, and returns + a push button. If \a button is invalid, it is not added to the button box, and + zero is returned. + + \sa removeButton(), clear() +*/ +QPushButton *QDialogButtonBox::addButton(StandardButton button) +{ + Q_D(QDialogButtonBox); + return d->createButton(button); +} + +/*! + \property QDialogButtonBox::standardButtons + \brief collection of standard buttons in the button box + + This property controls which standard buttons are used by the button box. + + \sa addButton() +*/ +void QDialogButtonBox::setStandardButtons(StandardButtons buttons) +{ + Q_D(QDialogButtonBox); + // Clear out all the old standard buttons, then recreate them. + qDeleteAll(d->standardButtonHash.keys()); + d->standardButtonHash.clear(); + + d->createStandardButtons(buttons); +} + +QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const +{ + Q_D(const QDialogButtonBox); + StandardButtons standardButtons = NoButton; + QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin(); + while (it != d->standardButtonHash.constEnd()) { + standardButtons |= it.value(); + ++it; + } + return standardButtons; +} + +/*! + Returns the QPushButton corresponding to the standard button \a which, + or 0 if the standard button doesn't exist in this button box. + + \sa standardButton(), standardButtons(), buttons() +*/ +QPushButton *QDialogButtonBox::button(StandardButton which) const +{ + Q_D(const QDialogButtonBox); + return d->standardButtonHash.key(which); +} + +/*! + Returns the standard button enum value corresponding to the given \a button, + or NoButton if the given \a button isn't a standard button. + + \sa button(), buttons(), standardButtons() +*/ +QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const +{ + Q_D(const QDialogButtonBox); + return d->standardButtonHash.value(static_cast<QPushButton *>(button)); +} + +void QDialogButtonBoxPrivate::_q_handleButtonClicked() +{ + Q_Q(QDialogButtonBox); + if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) { + emit q->clicked(button); + + switch (q->buttonRole(button)) { + case AcceptRole: + case YesRole: + emit q->accepted(); + break; + case RejectRole: + case NoRole: + emit q->rejected(); + break; + case HelpRole: + emit q->helpRequested(); + break; + default: + break; + } + } +} + +void QDialogButtonBoxPrivate::_q_handleButtonDestroyed() +{ + Q_Q(QDialogButtonBox); + if (QObject *object = q->sender()) { + QBoolBlocker skippy(internalRemove); + q->removeButton(static_cast<QAbstractButton *>(object)); + } +} + +/*! + \property QDialogButtonBox::centerButtons + \brief whether the buttons in the button box are centered + + By default, this property is false. This behavior is appopriate + for most types of dialogs. A notable exception is message boxes + on most platforms (e.g. Windows), where the button box is + centered horizontally. + + \sa QMessageBox +*/ +void QDialogButtonBox::setCenterButtons(bool center) +{ + Q_D(QDialogButtonBox); + if (d->center != center) { + d->center = center; + d->resetLayout(); + } +} + +bool QDialogButtonBox::centerButtons() const +{ + Q_D(const QDialogButtonBox); + return d->center; +} + +/*! + \reimp +*/ +void QDialogButtonBox::changeEvent(QEvent *event) +{ + typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash; + + Q_D(QDialogButtonBox); + switch (event->type()) { + case QEvent::StyleChange: // Propagate style + if (!d->standardButtonHash.empty()) { + QStyle *newStyle = style(); + const StandardButtonHash::iterator end = d->standardButtonHash.end(); + for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it) + it.key()->setStyle(newStyle); + } + // fallthrough intended +#ifdef Q_WS_MAC + case QEvent::MacSizeChange: +#endif + d->resetLayout(); + QWidget::changeEvent(event); + break; + default: + QWidget::changeEvent(event); + break; + } +} + +/*! + \reimp +*/ +bool QDialogButtonBox::event(QEvent *event) +{ + Q_D(QDialogButtonBox); + if (event->type() == QEvent::Show) { + QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole]; + QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0)); + bool hasDefault = false; + QWidget *dialog = 0; + QWidget *p = this; + while (p && !p->isWindow()) { + p = p->parentWidget(); + if ((dialog = qobject_cast<QDialog *>(p))) + break; + } + + foreach (QPushButton *pb, qFindChildren<QPushButton *>(dialog ? dialog : this)) { + if (pb->isDefault() && pb != firstAcceptButton) { + hasDefault = true; + break; + } + } + if (!hasDefault && firstAcceptButton) + firstAcceptButton->setDefault(true); + }else if (event->type() == QEvent::LanguageChange) { + d->retranslateStrings(); + } + + return QWidget::event(event); +} + +QT_END_NAMESPACE + +#include "moc_qdialogbuttonbox.cpp" |