File indexing completed on 2024-04-21 14:55:52

0001 /*  This file is part of the KDE Libraries
0002  *  Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net)
0003  *  Additions 1999-2000 by Espen Sand (espen@kde.org)
0004  *                      by Holger Freyther <freyther@kde.org>
0005  *            2005-2009 by Olivier Goffart (ogoffart at kde.org)
0006  *
0007  *  This library is free software; you can redistribute it and/or
0008  *  modify it under the terms of the GNU Library General Public
0009  *  License as published by the Free Software Foundation; either
0010  *  version 2 of the License, or (at your option) any later version.
0011  *
0012  *  This library is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  *  Library General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU Library General Public License
0018  *  along with this library; see the file COPYING.LIB.  If not, write to
0019  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  *  Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #include "kdialog.h"
0024 #include "kdialog_p.h"
0025 #include <kglobal.h> // remove KGlobal::caption once done by QPA
0026 
0027 #include <QApplication>
0028 #include <QDesktopWidget>
0029 #include <QDialogButtonBox>
0030 #include <QHBoxLayout>
0031 #include <QHideEvent>
0032 #include <QPointer>
0033 #include <QStyle>
0034 #include <QTimer>
0035 #include <QVBoxLayout>
0036 #include <QWhatsThis>
0037 #include <QDebug>
0038 
0039 #include <kconfig.h>
0040 #include <klocalizedstring.h>
0041 #include <kpushbutton.h>
0042 #include <kseparator.h>
0043 #include <kstandardguiitem.h>
0044 #include <khelpclient.h>
0045 #include <kurllabel.h>
0046 #include <kwindowconfig.h>
0047 
0048 #include <config-kdelibs4support.h>
0049 
0050 #if HAVE_X11
0051 #include <qx11info_x11.h>
0052 #include <netwm.h>
0053 #endif
0054 
0055 static bool sAllowEmbeddingInGraphicsView = false;
0056 
0057 void KDialogPrivate::setupLayout()
0058 {
0059     Q_Q(KDialog);
0060     if (!dirty) {
0061         QMetaObject::invokeMethod(q, "queuedLayoutUpdate", Qt::QueuedConnection);
0062         dirty = true;
0063     }
0064 }
0065 
0066 void KDialogPrivate::queuedLayoutUpdate()
0067 {
0068     if (!dirty) {
0069         return;
0070     }
0071 
0072     dirty = false;
0073 
0074     Q_Q(KDialog);
0075 
0076     // Don't lose the focus widget when re-creating the layout.
0077     // Testcase: KOrganizer's "Select Categories" dialog
0078     QPointer<QWidget> focusWidget = mMainWidget ? mMainWidget->focusWidget() : nullptr;
0079 
0080     if (q->layout() && q->layout() != mTopLayout) {
0081         qWarning() << q->metaObject()->className() << "created with a layout; don't do that, KDialog takes care of it, use mainWidget or setMainWidget instead";
0082         delete q->layout();
0083     }
0084 
0085     delete mTopLayout;
0086 
0087     if (mButtonOrientation == Qt::Horizontal) {
0088         mTopLayout = new QVBoxLayout(q);
0089     } else {
0090         mTopLayout = new QHBoxLayout(q);
0091     }
0092 
0093     if (mUrlHelp) {
0094         mTopLayout->addWidget(mUrlHelp, 0, Qt::AlignRight);
0095     }
0096 
0097     if (mMainWidget) {
0098         mTopLayout->addWidget(mMainWidget, 10);
0099     }
0100 
0101     if (mDetailsWidget) {
0102         mTopLayout->addWidget(mDetailsWidget);
0103     }
0104 
0105     if (mActionSeparator) {
0106         mTopLayout->addWidget(mActionSeparator);
0107     }
0108 
0109     if (mButtonBox) {
0110         mButtonBox->setOrientation(mButtonOrientation);
0111         mTopLayout->addWidget(mButtonBox);
0112     }
0113 
0114     if (focusWidget) {
0115         focusWidget->setFocus();
0116     }
0117 }
0118 
0119 void KDialogPrivate::appendButton(KDialog::ButtonCode key, const KGuiItem &item)
0120 {
0121     Q_Q(KDialog);
0122 
0123     QDialogButtonBox::ButtonRole role = QDialogButtonBox::InvalidRole;
0124     switch (key) {
0125     case KDialog::Help:
0126     case KDialog::Details:
0127         role = QDialogButtonBox::HelpRole;
0128         break;
0129     case KDialog::Default:
0130     case KDialog::Reset:
0131         role = QDialogButtonBox::ResetRole;
0132         break;
0133     case KDialog::Ok:
0134         role = QDialogButtonBox::AcceptRole;
0135         break;
0136     case KDialog::Apply:
0137         role = QDialogButtonBox::ApplyRole;
0138         break;
0139     case KDialog::Try:
0140     case KDialog::Yes:
0141         role = QDialogButtonBox::YesRole;
0142         break;
0143     case KDialog::Close:
0144     case KDialog::Cancel:
0145         role = QDialogButtonBox::RejectRole;
0146         break;
0147     case KDialog::No:
0148         role = QDialogButtonBox::NoRole;
0149         break;
0150     case KDialog::User1:
0151     case KDialog::User2:
0152     case KDialog::User3:
0153         role = QDialogButtonBox::ActionRole;
0154         break;
0155     default:
0156         role = QDialogButtonBox::InvalidRole;
0157         break;
0158     }
0159 
0160     if (role == QDialogButtonBox::InvalidRole) {
0161         return;
0162     }
0163 
0164     KPushButton *button = new KPushButton;
0165     KGuiItem::assign(button, item);
0166     mButtonBox->addButton(button, role);
0167 
0168     mButtonList.insert(key, button);
0169     mButtonSignalMapper.setMapping(button, key);
0170 
0171     QObject::connect(button, SIGNAL(clicked()),
0172                      &mButtonSignalMapper, SLOT(map()));
0173 
0174     if (key == mDefaultButton) {
0175         // Now that it exists, set it as default
0176         q->setDefaultButton(mDefaultButton);
0177     }
0178 }
0179 
0180 void KDialogPrivate::init(KDialog *q)
0181 {
0182     q_ptr = q;
0183 
0184     dirty = false;
0185 
0186     q->setButtons(KDialog::Ok | KDialog::Cancel);
0187     q->setDefaultButton(KDialog::Ok);
0188 
0189     q->connect(&mButtonSignalMapper, SIGNAL(mapped(int)), q, SLOT(slotButtonClicked(int)));
0190 
0191     q->setPlainCaption(KGlobal::caption()); // set appropriate initial window title for case it gets not set later
0192 }
0193 
0194 void KDialogPrivate::helpLinkClicked()
0195 {
0196     q_ptr->slotButtonClicked(KDialog::Help);
0197 }
0198 
0199 KDialog::KDialog(QWidget *parent, Qt::WindowFlags flags)
0200     : QDialog(parent, sAllowEmbeddingInGraphicsView ? flags : flags | Qt::BypassGraphicsProxyWidget), d_ptr(new KDialogPrivate)
0201 {
0202     d_ptr->init(this);
0203 }
0204 
0205 KDialog::KDialog(KDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags)
0206     : QDialog(parent, sAllowEmbeddingInGraphicsView ? flags : flags | Qt::BypassGraphicsProxyWidget), d_ptr(&dd)
0207 {
0208     d_ptr->init(this);
0209 }
0210 
0211 KDialog::~KDialog()
0212 {
0213     delete d_ptr;
0214 }
0215 
0216 void KDialog::setButtons(ButtonCodes buttonMask)
0217 {
0218     Q_D(KDialog);
0219     if (d->mButtonBox) {
0220         d->mButtonList.clear();
0221 
0222         delete d->mButtonBox;
0223         d->mButtonBox = nullptr;
0224     }
0225 
0226     if (buttonMask & Cancel) {
0227         buttonMask &= ~Close;
0228     }
0229 
0230     if (buttonMask & Apply) {
0231         buttonMask &= ~Try;
0232     }
0233 
0234     if (buttonMask & Details) {
0235         buttonMask &= ~Default;
0236     }
0237 
0238     if (buttonMask == None) {
0239         d->setupLayout();
0240         return; // When we want no button box
0241     }
0242 
0243     d->mEscapeButton = (buttonMask & Cancel) ? Cancel : Close;
0244     d->mButtonBox = new QDialogButtonBox(this);
0245 
0246     if (buttonMask & Help) {
0247         d->appendButton(Help, KStandardGuiItem::help());
0248     }
0249     if (buttonMask & Default) {
0250         d->appendButton(Default, KStandardGuiItem::defaults());
0251     }
0252     if (buttonMask & Reset) {
0253         d->appendButton(Reset, KStandardGuiItem::reset());
0254     }
0255     if (buttonMask & User3) {
0256         d->appendButton(User3, KGuiItem());
0257     }
0258     if (buttonMask & User2) {
0259         d->appendButton(User2, KGuiItem());
0260     }
0261     if (buttonMask & User1) {
0262         d->appendButton(User1, KGuiItem());
0263     }
0264     if (buttonMask & Ok) {
0265         d->appendButton(Ok, KStandardGuiItem::ok());
0266     }
0267     if (buttonMask & Apply) {
0268         d->appendButton(Apply, KStandardGuiItem::apply());
0269     }
0270     if (buttonMask & Try) {
0271         d->appendButton(Try, KGuiItem(i18n("&Try")));
0272     }
0273     if (buttonMask & Cancel) {
0274         d->appendButton(Cancel, KStandardGuiItem::cancel());
0275     }
0276     if (buttonMask & Close) {
0277         d->appendButton(Close, KStandardGuiItem::close());
0278     }
0279     if (buttonMask & Yes) {
0280         d->appendButton(Yes, KStandardGuiItem::yes());
0281     }
0282     if (buttonMask & No) {
0283         d->appendButton(No, KStandardGuiItem::no());
0284     }
0285     if (buttonMask & Details) {
0286         d->appendButton(Details, KGuiItem(QString(), "help-about"));
0287         setDetailsWidgetVisible(false);
0288     }
0289 
0290     d->setupLayout();
0291 }
0292 
0293 void KDialog::setButtonsOrientation(Qt::Orientation orientation)
0294 {
0295     Q_D(KDialog);
0296     if (d->mButtonOrientation != orientation) {
0297         d->mButtonOrientation = orientation;
0298 
0299         if (d->mActionSeparator) {
0300             d->mActionSeparator->setOrientation(d->mButtonOrientation);
0301         }
0302 
0303         if (d->mButtonOrientation == Qt::Vertical) {
0304             enableLinkedHelp(false);    // 2000-06-18 Espen: No support for this yet.
0305         }
0306     }
0307 }
0308 
0309 void KDialog::setEscapeButton(ButtonCode id)
0310 {
0311     d_func()->mEscapeButton = id;
0312 }
0313 
0314 void KDialog::setDefaultButton(ButtonCode newDefaultButton)
0315 {
0316     Q_D(KDialog);
0317 
0318     if (newDefaultButton == None) {
0319         newDefaultButton = NoDefault;    // #148969
0320     }
0321 
0322     const KDialog::ButtonCode oldDefault = defaultButton();
0323 
0324     bool oldDefaultHadFocus = false;
0325 
0326     if (oldDefault != NoDefault) {
0327         QPushButton *old = button(oldDefault);
0328         if (old) {
0329             oldDefaultHadFocus = (focusWidget() == old);
0330             old->setDefault(false);
0331         }
0332     }
0333 
0334     if (newDefaultButton != NoDefault) {
0335         QPushButton *b = button(newDefaultButton);
0336         if (b) {
0337             b->setDefault(true);
0338             if (focusWidget() == nullptr || oldDefaultHadFocus) {
0339                 // No widget had focus yet, or the old default button had
0340                 // -> ok to give focus to the new default button, so that it's
0341                 // really default (Enter triggers it).
0342                 // But we don't do this if the kdialog user gave focus to a
0343                 // specific widget in the dialog.
0344                 b->setFocus();
0345             }
0346         }
0347     }
0348     d->mDefaultButton = newDefaultButton;
0349     Q_ASSERT(defaultButton() == newDefaultButton);
0350 }
0351 
0352 KDialog::ButtonCode KDialog::defaultButton() const
0353 {
0354     Q_D(const KDialog);
0355     QHashIterator<int, KPushButton *> it(d->mButtonList);
0356     while (it.hasNext()) {
0357         it.next();
0358         if (it.value()->isDefault()) {
0359             return (ButtonCode)it.key();
0360         }
0361     }
0362 
0363     return d->mDefaultButton;
0364 }
0365 
0366 void KDialog::setMainWidget(QWidget *widget)
0367 {
0368     Q_D(KDialog);
0369     if (d->mMainWidget == widget) {
0370         return;
0371     }
0372     d->mMainWidget = widget;
0373     if (d->mMainWidget && d->mMainWidget->layout()) {
0374         // Avoid double-margin problem
0375         d->mMainWidget->layout()->setContentsMargins(0, 0, 0, 0);
0376     }
0377     d->setupLayout();
0378 }
0379 
0380 QWidget *KDialog::mainWidget()
0381 {
0382     Q_D(KDialog);
0383     if (!d->mMainWidget) {
0384         setMainWidget(new QWidget(this));
0385     }
0386     return d->mMainWidget;
0387 }
0388 
0389 QSize KDialog::sizeHint() const
0390 {
0391     Q_D(const KDialog);
0392 
0393     if (!d->mMinSize.isEmpty()) {
0394         return d->mMinSize.expandedTo(minimumSizeHint()) + d->mIncSize;
0395     } else {
0396         if (d->dirty) {
0397             const_cast<KDialogPrivate *>(d)->queuedLayoutUpdate();
0398         }
0399         return QDialog::sizeHint() + d->mIncSize;
0400     }
0401 }
0402 
0403 QSize KDialog::minimumSizeHint() const
0404 {
0405     Q_D(const KDialog);
0406 
0407     if (d->dirty) {
0408         const_cast<KDialogPrivate *>(d)->queuedLayoutUpdate();
0409     }
0410     return QDialog::minimumSizeHint() + d->mIncSize;
0411 }
0412 
0413 //
0414 // Grab QDialogs keypresses if non-modal.
0415 //
0416 void KDialog::keyPressEvent(QKeyEvent *event)
0417 {
0418     Q_D(KDialog);
0419     if (event->modifiers() == 0) {
0420         if (event->key() == Qt::Key_F1) {
0421             QPushButton *button = this->button(Help);
0422 
0423             if (button) {
0424                 button->animateClick();
0425                 event->accept();
0426                 return;
0427             }
0428         }
0429 
0430         if (event->key() == Qt::Key_Escape) {
0431             QPushButton *button = this->button(d->mEscapeButton);
0432 
0433             if (button) {
0434                 button->animateClick();
0435                 event->accept();
0436                 return;
0437             }
0438 
0439         }
0440     } else if (event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier) {
0441         QWhatsThis::enterWhatsThisMode();
0442         event->accept();
0443         return;
0444     } else if (event->modifiers() == Qt::ControlModifier &&
0445                (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
0446         // accept the dialog when Ctrl-Return is pressed
0447         QPushButton *button = this->button(Ok);
0448 
0449         if (button) {
0450             button->animateClick();
0451             event->accept();
0452             return;
0453         }
0454     }
0455 
0456     QDialog::keyPressEvent(event);
0457 }
0458 
0459 int KDialog::marginHint()
0460 {
0461     return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin);
0462 }
0463 
0464 int KDialog::spacingHint()
0465 {
0466     return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
0467 }
0468 
0469 int KDialog::groupSpacingHint()
0470 {
0471     return QApplication::fontMetrics().lineSpacing();
0472 }
0473 
0474 QString KDialog::makeStandardCaption(const QString &userCaption,
0475                                      QWidget *window,
0476                                      CaptionFlags flags)
0477 {
0478     Q_UNUSED(window);
0479     QString caption = KGlobal::caption();
0480     QString captionString = userCaption.isEmpty() ? caption : userCaption;
0481 
0482     // If the document is modified, add '[modified]'.
0483     if (flags & ModifiedCaption) {
0484         captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
0485     }
0486 
0487     if (!userCaption.isEmpty()) {
0488         // Add the application name if:
0489         // User asked for it, it's not a duplication  and the app name (caption()) is not empty
0490         if (flags & AppNameCaption &&
0491                 !caption.isEmpty() &&
0492                 !userCaption.endsWith(caption)) {
0493             // TODO: check to see if this is a transient/secondary window before trying to add the app name
0494             //       on platforms that need this
0495             captionString += i18nc("Document/application separator in titlebar", " – ") + caption;
0496         }
0497     }
0498 
0499     return captionString;
0500 }
0501 
0502 void KDialog::setCaption(const QString &_caption)
0503 {
0504     const QString caption = makeStandardCaption(_caption, this);
0505     setPlainCaption(caption);
0506 }
0507 
0508 void KDialog::setCaption(const QString &caption, bool modified)
0509 {
0510     CaptionFlags flags = HIGCompliantCaption;
0511 
0512     // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath
0513     if (modified) {
0514         flags |= ModifiedCaption;
0515     }
0516 
0517     setPlainCaption(makeStandardCaption(caption, this, flags));
0518 }
0519 
0520 void KDialog::setPlainCaption(const QString &caption)
0521 {
0522     if (QWidget *win = window()) {
0523         win->setWindowTitle(caption);
0524 #if HAVE_X11
0525         if (QGuiApplication::platformName() == QStringLiteral("xcb")) {
0526             NETWinInfo info(QX11Info::connection(), win->winId(), QX11Info::appRootWindow(), NET::Properties{}, NET::Properties2{});
0527             info.setName(caption.toUtf8().constData());
0528         }
0529 #endif
0530     }
0531 }
0532 
0533 void KDialog::resizeLayout(QWidget *widget, int margin, int spacing)   //static
0534 {
0535     if (widget->layout()) {
0536         resizeLayout(widget->layout(), margin, spacing);
0537     }
0538 
0539     if (widget->children().count() > 0) {
0540         const QList<QObject *> list = widget->children();
0541         foreach (QObject *object, list) {
0542             if (object->isWidgetType()) {
0543                 resizeLayout((QWidget *)object, margin, spacing);
0544             }
0545         }
0546     }
0547 }
0548 
0549 void KDialog::resizeLayout(QLayout *layout, int margin, int spacing)   //static
0550 {
0551     QLayoutItem *child;
0552     int pos = 0;
0553 
0554     while ((child = layout->itemAt(pos))) {
0555         if (child->layout()) {
0556             resizeLayout(child->layout(), margin, spacing);
0557         }
0558 
0559         ++pos;
0560     }
0561 
0562     if (layout->layout()) {
0563         layout->layout()->setMargin(margin);
0564         layout->layout()->setSpacing(spacing);
0565     }
0566 }
0567 
0568 static QRect screenRect(QWidget *widget, int screen)
0569 {
0570     QDesktopWidget *desktop = QApplication::desktop();
0571     KConfig gc("kdeglobals", KConfig::NoGlobals);
0572     KConfigGroup cg(&gc, "Windows");
0573     if (desktop->isVirtualDesktop() &&
0574             cg.readEntry("XineramaEnabled", true) &&
0575             cg.readEntry("XineramaPlacementEnabled", true)) {
0576 
0577         if (screen < 0 || screen >= desktop->numScreens()) {
0578             if (screen == -1) {
0579                 screen = desktop->primaryScreen();
0580             } else if (screen == -3) {
0581                 screen = desktop->screenNumber(QCursor::pos());
0582             } else {
0583                 screen = desktop->screenNumber(widget);
0584             }
0585         }
0586 
0587         return desktop->availableGeometry(screen);
0588     } else {
0589         return desktop->geometry();
0590     }
0591 }
0592 
0593 void KDialog::centerOnScreen(QWidget *widget, int screen)
0594 {
0595     if (!widget) {
0596         return;
0597     }
0598 
0599 #if HAVE_X11
0600     if (QGuiApplication::platformName() == QStringLiteral("xcb")
0601             && !(widget->windowFlags() & Qt::X11BypassWindowManagerHint) && widget->windowType() != Qt::Popup
0602             && NETRootInfo(QX11Info::connection(), NET::Supported).isSupported(NET::WM2FullPlacement)) {
0603         return; // the WM can handle placement much better
0604     }
0605 #endif
0606 
0607     QRect rect = screenRect(widget, screen);
0608 
0609     widget->move(rect.center().x() - widget->width() / 2,
0610                  rect.center().y() - widget->height() / 2);
0611 }
0612 
0613 bool KDialog::avoidArea(QWidget *widget, const QRect &area, int screen)
0614 {
0615     if (!widget) {
0616         return false;
0617     }
0618 
0619     QRect fg = widget->frameGeometry();
0620     if (!fg.intersects(area)) {
0621         return true;    // nothing to do.
0622     }
0623 
0624     const QRect scr = screenRect(widget, screen);
0625     QRect avoid(area);   // let's add some margin
0626     avoid.translate(-5, -5);
0627     avoid.setRight(avoid.right() + 10);
0628     avoid.setBottom(avoid.bottom() + 10);
0629 
0630     if (qMax(fg.top(), avoid.top()) <= qMin(fg.bottom(), avoid.bottom())) {
0631         // We need to move the widget up or down
0632         int spaceAbove = qMax(0, avoid.top() - scr.top());
0633         int spaceBelow = qMax(0, scr.bottom() - avoid.bottom());
0634         if (spaceAbove > spaceBelow)   // where's the biggest side?
0635             if (fg.height() <= spaceAbove) { // big enough?
0636                 fg.setY(avoid.top() - fg.height());
0637             } else {
0638                 return false;
0639             }
0640         else if (fg.height() <= spaceBelow) { // big enough?
0641             fg.setY(avoid.bottom());
0642         } else {
0643             return false;
0644         }
0645     }
0646 
0647     if (qMax(fg.left(), avoid.left()) <= qMin(fg.right(), avoid.right())) {
0648         // We need to move the widget left or right
0649         const int spaceLeft = qMax(0, avoid.left() - scr.left());
0650         const int spaceRight = qMax(0, scr.right() - avoid.right());
0651         if (spaceLeft > spaceRight)   // where's the biggest side?
0652             if (fg.width() <= spaceLeft) { // big enough?
0653                 fg.setX(avoid.left() - fg.width());
0654             } else {
0655                 return false;
0656             }
0657         else if (fg.width() <= spaceRight) { // big enough?
0658             fg.setX(avoid.right());
0659         } else {
0660             return false;
0661         }
0662     }
0663 
0664     widget->move(fg.x(), fg.y());
0665 
0666     return true;
0667 }
0668 
0669 void KDialog::showButtonSeparator(bool state)
0670 {
0671     Q_D(KDialog);
0672     if ((d->mActionSeparator != nullptr) == state) {
0673         return;
0674     }
0675     if (state) {
0676         if (d->mActionSeparator) {
0677             return;
0678         }
0679 
0680         d->mActionSeparator = new KSeparator(this);
0681         d->mActionSeparator->setOrientation(d->mButtonOrientation);
0682     } else {
0683         delete d->mActionSeparator;
0684         d->mActionSeparator = nullptr;
0685     }
0686 
0687     d->setupLayout();
0688 }
0689 
0690 void KDialog::setInitialSize(const QSize &size)
0691 {
0692     d_func()->mMinSize = size;
0693     adjustSize();
0694 }
0695 
0696 void KDialog::incrementInitialSize(const QSize &size)
0697 {
0698     d_func()->mIncSize = size;
0699     adjustSize();
0700 }
0701 
0702 QPushButton *KDialog::button(ButtonCode id) const
0703 {
0704     Q_D(const KDialog);
0705     return d->mButtonList.value(id, nullptr);
0706 }
0707 
0708 void KDialog::enableButton(ButtonCode id, bool state)
0709 {
0710     QPushButton *button = this->button(id);
0711     if (button) {
0712         button->setEnabled(state);
0713     }
0714 }
0715 
0716 bool KDialog::isButtonEnabled(ButtonCode id) const
0717 {
0718     QPushButton *button = this->button(id);
0719     if (button) {
0720         return button->isEnabled();
0721     }
0722 
0723     return false;
0724 }
0725 
0726 void KDialog::enableButtonOk(bool state)
0727 {
0728     enableButton(Ok, state);
0729 }
0730 
0731 void KDialog::enableButtonApply(bool state)
0732 {
0733     enableButton(Apply, state);
0734 }
0735 
0736 void KDialog::enableButtonCancel(bool state)
0737 {
0738     enableButton(Cancel, state);
0739 }
0740 
0741 void KDialog::showButton(ButtonCode id, bool state)
0742 {
0743     QPushButton *button = this->button(id);
0744     if (button) {
0745         state ? button->show() : button->hide();
0746     }
0747 }
0748 
0749 void KDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item)
0750 {
0751     QPushButton *button = this->button(id);
0752     if (!button) {
0753         return;
0754     }
0755 
0756     KGuiItem::assign(button, item);
0757 }
0758 
0759 void KDialog::setButtonMenu(ButtonCode id, QMenu *menu, ButtonPopupMode popupmode)
0760 {
0761     KPushButton *button = static_cast<KPushButton *>(this->button(id));
0762     if (button) {
0763         if (popupmode == InstantPopup) {
0764             button->setMenu(menu);
0765         } else {
0766             button->setDelayedMenu(menu);
0767         }
0768     }
0769 }
0770 
0771 void KDialog::setButtonText(ButtonCode id, const QString &text)
0772 {
0773     Q_D(KDialog);
0774     if (!d->mSettingDetails && (id == Details)) {
0775         d->mDetailsButtonText = text;
0776         setDetailsWidgetVisible(d->mDetailsVisible);
0777         return;
0778     }
0779 
0780     QPushButton *button = this->button(id);
0781     if (button) {
0782         button->setText(text);
0783     }
0784 }
0785 
0786 QString KDialog::buttonText(ButtonCode id) const
0787 {
0788     QPushButton *button = this->button(id);
0789     if (button) {
0790         return button->text();
0791     } else {
0792         return QString();
0793     }
0794 }
0795 
0796 void KDialog::setButtonIcon(ButtonCode id, const QIcon &icon)
0797 {
0798     QPushButton *button = this->button(id);
0799     if (button) {
0800         button->setIcon(icon);
0801     }
0802 }
0803 
0804 QIcon KDialog::buttonIcon(ButtonCode id) const
0805 {
0806     QPushButton *button = this->button(id);
0807     if (button) {
0808         return button->icon();
0809     } else {
0810         return QIcon();
0811     }
0812 }
0813 
0814 void KDialog::setButtonToolTip(ButtonCode id, const QString &text)
0815 {
0816     QPushButton *button = this->button(id);
0817     if (button) {
0818         if (text.isEmpty()) {
0819             button->setToolTip(QString());
0820         } else {
0821             button->setToolTip(text);
0822         }
0823     }
0824 }
0825 
0826 QString KDialog::buttonToolTip(ButtonCode id) const
0827 {
0828     QPushButton *button = this->button(id);
0829     if (button) {
0830         return button->toolTip();
0831     } else {
0832         return QString();
0833     }
0834 }
0835 
0836 void KDialog::setButtonWhatsThis(ButtonCode id, const QString &text)
0837 {
0838     QPushButton *button = this->button(id);
0839     if (button) {
0840         if (text.isEmpty()) {
0841             button->setWhatsThis(QString());
0842         } else {
0843             button->setWhatsThis(text);
0844         }
0845     }
0846 }
0847 
0848 QString KDialog::buttonWhatsThis(ButtonCode id) const
0849 {
0850     QPushButton *button = this->button(id);
0851     if (button) {
0852         return button->whatsThis();
0853     } else {
0854         return QString();
0855     }
0856 }
0857 
0858 void KDialog::setButtonFocus(ButtonCode id)
0859 {
0860     QPushButton *button = this->button(id);
0861     if (button) {
0862         button->setFocus();
0863     }
0864 }
0865 
0866 void KDialog::setDetailsWidget(QWidget *detailsWidget)
0867 {
0868     Q_D(KDialog);
0869     if (d->mDetailsWidget == detailsWidget) {
0870         return;
0871     }
0872     delete d->mDetailsWidget;
0873     d->mDetailsWidget = detailsWidget;
0874 
0875     if (d->mDetailsWidget->parentWidget() != this) {
0876         d->mDetailsWidget->setParent(this);
0877     }
0878 
0879     d->mDetailsWidget->hide();
0880     d->setupLayout();
0881 
0882     if (!d->mSettingDetails) {
0883         setDetailsWidgetVisible(d->mDetailsVisible);
0884     }
0885 }
0886 
0887 bool KDialog::isDetailsWidgetVisible() const
0888 {
0889     return d_func()->mDetailsVisible;
0890 }
0891 
0892 void KDialog::setDetailsWidgetVisible(bool visible)
0893 {
0894     Q_D(KDialog);
0895     if (d->mDetailsButtonText.isEmpty()) {
0896         d->mDetailsButtonText = i18n("&Details");
0897     }
0898 
0899     d->mSettingDetails = true;
0900     d->mDetailsVisible = visible;
0901     if (d->mDetailsVisible) {
0902         emit aboutToShowDetails();
0903         setButtonText(Details, d->mDetailsButtonText + " <<");
0904         if (d->mDetailsWidget) {
0905             if (layout()) {
0906                 layout()->setEnabled(false);
0907             }
0908 
0909             d->mDetailsWidget->show();
0910 
0911             adjustSize();
0912 
0913             if (layout()) {
0914                 layout()->activate();
0915                 layout()->setEnabled(true);
0916             }
0917         }
0918     } else {
0919         setButtonText(Details, d->mDetailsButtonText + " >>");
0920         if (d->mDetailsWidget) {
0921             d->mDetailsWidget->hide();
0922         }
0923 
0924         if (layout()) {
0925             layout()->activate();
0926             adjustSize();
0927         }
0928 
0929     }
0930 
0931     d->mSettingDetails = false;
0932 }
0933 
0934 void KDialog::delayedDestruct()
0935 {
0936     if (isVisible()) {
0937         hide();
0938     }
0939 
0940     deleteLater();
0941 }
0942 
0943 void KDialog::slotButtonClicked(int button)
0944 {
0945     Q_D(KDialog);
0946     emit buttonClicked(static_cast<KDialog::ButtonCode>(button));
0947 
0948     switch (button) {
0949     case Ok:
0950         emit okClicked();
0951         accept();
0952         break;
0953     case Apply:
0954         emit applyClicked();
0955         break;
0956     case Try:
0957         emit tryClicked();
0958         break;
0959     case User3:
0960         emit user3Clicked();
0961         break;
0962     case User2:
0963         emit user2Clicked();
0964         break;
0965     case User1:
0966         emit user1Clicked();
0967         break;
0968     case Yes:
0969         emit yesClicked();
0970         done(Yes);
0971         break;
0972     case No:
0973         emit noClicked();
0974         done(No);
0975         break;
0976     case Cancel:
0977         emit cancelClicked();
0978         reject();
0979         break;
0980     case Close:
0981         emit closeClicked();
0982         done(Close); // KDE5: call reject() instead; more QDialog-like.
0983         break;
0984     case Help:
0985         emit helpClicked();
0986         if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) {
0987             KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
0988         }
0989         break;
0990     case Default:
0991         emit defaultClicked();
0992         break;
0993     case Reset:
0994         emit resetClicked();
0995         break;
0996     case Details:
0997         setDetailsWidgetVisible(!d->mDetailsVisible);
0998         break;
0999     }
1000 
1001     // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now.
1002     if (d->mDeferredDelete) {
1003         d->mDeferredDelete = false;
1004         delayedDestruct();
1005     }
1006 }
1007 
1008 void KDialog::enableLinkedHelp(bool state)
1009 {
1010     Q_D(KDialog);
1011     if ((d->mUrlHelp != nullptr) == state) {
1012         return;
1013     }
1014     if (state) {
1015         if (d->mUrlHelp) {
1016             return;
1017         }
1018 
1019         d->mUrlHelp = new KUrlLabel(this);
1020         d->mUrlHelp->setText(helpLinkText());
1021         d->mUrlHelp->setFloatEnabled(true);
1022         d->mUrlHelp->setUnderline(true);
1023         d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint());
1024         connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked()));
1025 
1026         d->mUrlHelp->show();
1027     } else {
1028         delete d->mUrlHelp;
1029         d->mUrlHelp = nullptr;
1030     }
1031 
1032     d->setupLayout();
1033 }
1034 
1035 void KDialog::setHelp(const QString &anchor, const QString &appname)
1036 {
1037     Q_D(KDialog);
1038     d->mAnchor  = anchor;
1039     d->mHelpApp = appname;
1040 }
1041 
1042 void KDialog::setHelpLinkText(const QString &text)
1043 {
1044     Q_D(KDialog);
1045     d->mHelpLinkText = text;
1046     if (d->mUrlHelp) {
1047         d->mUrlHelp->setText(helpLinkText());
1048     }
1049 }
1050 
1051 QString KDialog::helpLinkText() const
1052 {
1053     Q_D(const KDialog);
1054     return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText);
1055 }
1056 
1057 void KDialog::updateGeometry()
1058 {
1059 }
1060 
1061 void KDialog::hideEvent(QHideEvent *event)
1062 {
1063     emit hidden();
1064 
1065     if (!event->spontaneous()) {
1066         emit finished();
1067     }
1068 }
1069 
1070 void KDialog::closeEvent(QCloseEvent *event)
1071 {
1072     Q_D(KDialog);
1073     QPushButton *button = this->button(d->mEscapeButton);
1074     if (button && !isHidden()) {
1075         button->animateClick();
1076 
1077         if (testAttribute(Qt::WA_DeleteOnClose)) {
1078             // Don't let QWidget::close do a deferred delete just yet, wait for the click first
1079             d->mDeferredDelete = true;
1080             setAttribute(Qt::WA_DeleteOnClose, false);
1081         }
1082     } else {
1083         QDialog::closeEvent(event);
1084     }
1085 }
1086 
1087 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
1088 void KDialog::restoreDialogSize(const KConfigGroup &cfg)
1089 {
1090     KWindowConfig::restoreWindowSize(windowHandle(), cfg);
1091 }
1092 #endif
1093 
1094 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
1095 void KDialog::saveDialogSize(KConfigGroup &config, KConfigGroup::WriteConfigFlags options) const
1096 {
1097     KWindowConfig::saveWindowSize(windowHandle(), config, options);
1098 }
1099 #endif
1100 
1101 void KDialog::setAllowEmbeddingInGraphicsView(bool allowEmbedding)
1102 {
1103     sAllowEmbeddingInGraphicsView = allowEmbedding;
1104 }
1105 
1106 #include "moc_kdialog.cpp"