File indexing completed on 2024-05-19 04:29:32

0001 /*  This file is part of the KDE Libraries
0002  *  SPDX-FileCopyrightText: 1998 Thomas Tanghus (tanghus@earthling.net)
0003  *  SPDX-FileCopyrightText: 1999-2000 Espen Sand (espen@kde.org)
0004  *  SPDX-FileCopyrightText: 1999-2000 Holger Freyther <freyther@kde.org>
0005  *  SPDX-FileCopyrightText: 2005-2009 Olivier Goffart (ogoffart at kde.org)
0006  *
0007  *  SPDX-License-Identifier: LGPL-2.0-or-later
0008  */
0009 
0010 #include "KoDialog.h"
0011 #include "KoDialog_p.h"
0012 
0013 #include <QWindow>
0014 #include <QApplication>
0015 #include <QGuiApplication>
0016 #include <QDialogButtonBox>
0017 #include <QHBoxLayout>
0018 #include <QHideEvent>
0019 #include <QPointer>
0020 #include <QStyle>
0021 #include <QTimer>
0022 #include <QVBoxLayout>
0023 #include <QWhatsThis>
0024 #include <QDebug>
0025 #include <QPushButton>
0026 #include <QDesktopWidget>
0027 #include <QTimer>
0028 
0029 #include <kconfig.h>
0030 #include <klocalizedstring.h>
0031 
0032 #include <kseparator.h>
0033 #include <kstandardguiitem.h>
0034 #include <khelpclient.h>
0035 #include <kurllabel.h>
0036 #include <kwindowconfig.h>
0037 
0038 void KoDialogPrivate::setupLayout()
0039 {
0040     Q_Q(KoDialog);
0041     if (!dirty) {
0042         QMetaObject::invokeMethod(q, "queuedLayoutUpdate", Qt::QueuedConnection);
0043         dirty = true;
0044     }
0045 }
0046 
0047 void KoDialogPrivate::queuedLayoutUpdate()
0048 {
0049     if (!dirty) {
0050         return;
0051     }
0052 
0053     dirty = false;
0054 
0055     Q_Q(KoDialog);
0056 
0057     // Don't lose the focus widget when re-creating the layout.
0058     // Testcase: KOrganizer's "Select Categories" dialog
0059     QPointer<QWidget> focusWidget = mMainWidget ? mMainWidget->focusWidget() : 0;
0060 
0061     if (q->layout() && q->layout() != mTopLayout) {
0062         qWarning() << q->metaObject()->className() << "created with a layout; don't do that, KoDialog takes care of it, use mainWidget or setMainWidget instead";
0063         delete q->layout();
0064     }
0065 
0066     delete mTopLayout;
0067 
0068     if (mButtonOrientation == Qt::Horizontal) {
0069         mTopLayout = new QVBoxLayout(q);
0070     } else {
0071         mTopLayout = new QHBoxLayout(q);
0072     }
0073 
0074     if (mUrlHelp) {
0075         mTopLayout->addWidget(mUrlHelp, 0, Qt::AlignRight);
0076     }
0077 
0078     if (mMainWidget) {
0079         mTopLayout->addWidget(mMainWidget, 10);
0080     }
0081 
0082     if (mDetailsWidget) {
0083         mTopLayout->addWidget(mDetailsWidget);
0084     }
0085 
0086     if (mActionSeparator) {
0087         mTopLayout->addWidget(mActionSeparator);
0088     }
0089 
0090     if (mButtonBox) {
0091         mButtonBox->setOrientation(mButtonOrientation);
0092         mTopLayout->addWidget(mButtonBox);
0093     }
0094 
0095     if (focusWidget) {
0096         focusWidget->setFocus();
0097     }
0098 }
0099 
0100 void KoDialogPrivate::appendButton(KoDialog::ButtonCode key, const KGuiItem &item)
0101 {
0102     Q_Q(KoDialog);
0103 
0104     QDialogButtonBox::ButtonRole role = QDialogButtonBox::InvalidRole;
0105     switch (key) {
0106     case KoDialog::Help:
0107     case KoDialog::Details:
0108         role = QDialogButtonBox::HelpRole;
0109         break;
0110     case KoDialog::Default:
0111     case KoDialog::Reset:
0112         role = QDialogButtonBox::ResetRole;
0113         break;
0114     case KoDialog::Ok:
0115         role = QDialogButtonBox::AcceptRole;
0116         break;
0117     case KoDialog::Apply:
0118         role = QDialogButtonBox::ApplyRole;
0119         break;
0120     case KoDialog::Try:
0121     case KoDialog::Yes:
0122         role = QDialogButtonBox::YesRole;
0123         break;
0124     case KoDialog::Close:
0125     case KoDialog::Cancel:
0126         role = QDialogButtonBox::RejectRole;
0127         break;
0128     case KoDialog::No:
0129         role = QDialogButtonBox::NoRole;
0130         break;
0131     case KoDialog::User1:
0132     case KoDialog::User2:
0133     case KoDialog::User3:
0134         role = QDialogButtonBox::ActionRole;
0135         break;
0136     default:
0137         role = QDialogButtonBox::InvalidRole;
0138         break;
0139     }
0140 
0141     if (role == QDialogButtonBox::InvalidRole) {
0142         return;
0143     }
0144 
0145     QPushButton *button = new QPushButton;
0146     KGuiItem::assign(button, item);
0147     mButtonBox->addButton(button, role);
0148 
0149     mButtonList.insert(key, button);
0150 
0151     QObject::connect(button, &QPushButton::clicked, q, [=] { q->slotButtonClicked(key); });
0152 
0153     if (key == mDefaultButton) {
0154         // Now that it exists, set it as default
0155         q->setDefaultButton(mDefaultButton);
0156     }
0157 }
0158 
0159 void KoDialogPrivate::init(KoDialog *q)
0160 {
0161     q_ptr = q;
0162 
0163     dirty = false;
0164 
0165     q->setButtons(KoDialog::Ok | KoDialog::Cancel);
0166     q->setDefaultButton(KoDialog::Ok);
0167 
0168     q->setPlainCaption(qApp->applicationDisplayName()); // set appropriate initial window title for case it gets not set later
0169 }
0170 
0171 void KoDialogPrivate::helpLinkClicked()
0172 {
0173     q_ptr->slotButtonClicked(KoDialog::Help);
0174 }
0175 
0176 KoDialog::KoDialog(QWidget *parent, Qt::WindowFlags flags)
0177     : QDialog(parent ? parent : qApp->activeWindow(), flags)
0178     , d_ptr(new KoDialogPrivate)
0179 {
0180     d_ptr->init(this);
0181 }
0182 
0183 KoDialog::KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags)
0184     : QDialog(parent ? parent : qApp->activeWindow(), flags)
0185     , d_ptr(&dd)
0186 {
0187     d_ptr->init(this);
0188 }
0189 
0190 KoDialog::~KoDialog()
0191 {
0192     delete d_ptr;
0193 }
0194 
0195 void KoDialog::setButtons(ButtonCodes buttonMask)
0196 {
0197     Q_D(KoDialog);
0198     if (d->mButtonBox) {
0199         d->mButtonList.clear();
0200 
0201         delete d->mButtonBox;
0202         d->mButtonBox = 0;
0203     }
0204 
0205     if (buttonMask & Cancel) {
0206         buttonMask &= ~Close;
0207     }
0208 
0209     if (buttonMask & Apply) {
0210         buttonMask &= ~Try;
0211     }
0212 
0213     if (buttonMask & Details) {
0214         buttonMask &= ~Default;
0215     }
0216 
0217     if (buttonMask == None) {
0218         d->setupLayout();
0219         return; // When we want no button box
0220     }
0221 
0222     d->mEscapeButton = (buttonMask & Cancel) ? Cancel : Close;
0223     d->mButtonBox = new QDialogButtonBox(this);
0224 
0225     if (buttonMask & Help) {
0226         d->appendButton(Help, KStandardGuiItem::help());
0227     }
0228     if (buttonMask & Default) {
0229         d->appendButton(Default, KStandardGuiItem::defaults());
0230     }
0231     if (buttonMask & Reset) {
0232         d->appendButton(Reset, KStandardGuiItem::reset());
0233     }
0234     if (buttonMask & User3) {
0235         d->appendButton(User3, KGuiItem());
0236     }
0237     if (buttonMask & User2) {
0238         d->appendButton(User2, KGuiItem());
0239     }
0240     if (buttonMask & User1) {
0241         d->appendButton(User1, KGuiItem());
0242     }
0243     if (buttonMask & Ok) {
0244         d->appendButton(Ok, KStandardGuiItem::ok());
0245     }
0246     if (buttonMask & Apply) {
0247         d->appendButton(Apply, KStandardGuiItem::apply());
0248     }
0249     if (buttonMask & Try) {
0250         d->appendButton(Try, KGuiItem(i18n("&Try")));
0251     }
0252     if (buttonMask & Cancel) {
0253         d->appendButton(Cancel, KStandardGuiItem::cancel());
0254     }
0255     if (buttonMask & Close) {
0256         d->appendButton(Close, KStandardGuiItem::close());
0257     }
0258     if (buttonMask & Yes) {
0259         d->appendButton(Yes, KStandardGuiItem::yes());
0260     }
0261     if (buttonMask & No) {
0262         d->appendButton(No, KStandardGuiItem::no());
0263     }
0264     if (buttonMask & Details) {
0265         d->appendButton(Details, KGuiItem(QString(), "help-about"));
0266         setDetailsWidgetVisible(false);
0267     }
0268 
0269     d->setupLayout();
0270 }
0271 
0272 void KoDialog::setButtonsOrientation(Qt::Orientation orientation)
0273 {
0274     Q_D(KoDialog);
0275     if (d->mButtonOrientation != orientation) {
0276         d->mButtonOrientation = orientation;
0277 
0278         if (d->mActionSeparator) {
0279             d->mActionSeparator->setOrientation(d->mButtonOrientation);
0280         }
0281 
0282         if (d->mButtonOrientation == Qt::Vertical) {
0283             enableLinkedHelp(false);    // 2000-06-18 Espen: No support for this yet.
0284         }
0285     }
0286 }
0287 
0288 void KoDialog::setEscapeButton(ButtonCode id)
0289 {
0290     d_func()->mEscapeButton = id;
0291 }
0292 
0293 void KoDialog::setDefaultButton(ButtonCode newDefaultButton)
0294 {
0295     Q_D(KoDialog);
0296 
0297     if (newDefaultButton == None) {
0298         newDefaultButton = NoDefault;    // #148969
0299     }
0300 
0301     const KoDialog::ButtonCode oldDefault = defaultButton();
0302 
0303     bool oldDefaultHadFocus = false;
0304 
0305     if (oldDefault != NoDefault) {
0306         QPushButton *old = button(oldDefault);
0307         if (old) {
0308             oldDefaultHadFocus = (focusWidget() == old);
0309             old->setDefault(false);
0310         }
0311     }
0312 
0313     if (newDefaultButton != NoDefault) {
0314         QPushButton *b = button(newDefaultButton);
0315         if (b) {
0316             b->setDefault(true);
0317             if (focusWidget() == 0 || oldDefaultHadFocus) {
0318                 // No widget had focus yet, or the old default button had
0319                 // -> ok to give focus to the new default button, so that it's
0320                 // really default (Enter triggers it).
0321                 // But we don't do this if the kdialog user gave focus to a
0322                 // specific widget in the dialog.
0323                 b->setFocus();
0324             }
0325         }
0326     }
0327     d->mDefaultButton = newDefaultButton;
0328     Q_ASSERT(defaultButton() == newDefaultButton);
0329 }
0330 
0331 KoDialog::ButtonCode KoDialog::defaultButton() const
0332 {
0333     Q_D(const KoDialog);
0334     QHashIterator<int, QPushButton *> it(d->mButtonList);
0335     while (it.hasNext()) {
0336         it.next();
0337         if (it.value()->isDefault()) {
0338             return (ButtonCode)it.key();
0339         }
0340     }
0341 
0342     return d->mDefaultButton;
0343 }
0344 
0345 void KoDialog::setMainWidget(QWidget *widget)
0346 {
0347     Q_D(KoDialog);
0348     if (d->mMainWidget == widget) {
0349         return;
0350     }
0351     d->mMainWidget = widget;
0352     if (d->mMainWidget && d->mMainWidget->layout()) {
0353         // Avoid double-margin problem
0354         d->mMainWidget->layout()->setMargin(0);
0355     }
0356     d->setupLayout();
0357 }
0358 
0359 QWidget *KoDialog::mainWidget()
0360 {
0361     Q_D(KoDialog);
0362     if (!d->mMainWidget) {
0363         setMainWidget(new QWidget(this));
0364     }
0365     return d->mMainWidget;
0366 }
0367 
0368 QSize KoDialog::sizeHint() const
0369 {
0370     Q_D(const KoDialog);
0371 
0372     if (!d->mMinSize.isEmpty()) {
0373         return d->mMinSize.expandedTo(minimumSizeHint()) + d->mIncSize;
0374     } else {
0375         if (d->dirty) {
0376             const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate();
0377         }
0378         return QDialog::sizeHint() + d->mIncSize;
0379     }
0380 }
0381 
0382 QSize KoDialog::minimumSizeHint() const
0383 {
0384     Q_D(const KoDialog);
0385 
0386     if (d->dirty) {
0387         const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate();
0388     }
0389     return QDialog::minimumSizeHint() + d->mIncSize;
0390 }
0391 
0392 //
0393 // Grab QDialogs keypresses if non-modal.
0394 //
0395 void KoDialog::keyPressEvent(QKeyEvent *event)
0396 {
0397     Q_D(KoDialog);
0398     if (event->modifiers() == 0) {
0399         if (event->key() == Qt::Key_F1) {
0400             QPushButton *button = this->button(Help);
0401 
0402             if (button) {
0403                 button->animateClick();
0404                 event->accept();
0405                 return;
0406             }
0407         }
0408 
0409         if (event->key() == Qt::Key_Escape) {
0410             QPushButton *button = this->button(d->mEscapeButton);
0411 
0412             if (button) {
0413                 button->animateClick();
0414                 event->accept();
0415                 return;
0416             }
0417 
0418         }
0419     } else if (event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier) {
0420         QWhatsThis::enterWhatsThisMode();
0421         event->accept();
0422         return;
0423     } else if (event->modifiers() == Qt::ControlModifier &&
0424                (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
0425         // accept the dialog when Ctrl-Return is pressed
0426         QPushButton *button = this->button(Ok);
0427 
0428         if (button) {
0429             button->animateClick();
0430             event->accept();
0431             return;
0432         }
0433     }
0434 
0435     QDialog::keyPressEvent(event);
0436 }
0437 
0438 void KoDialog::showEvent(QShowEvent *e)
0439 {
0440     QDialog::showEvent(e);
0441     QTimer::singleShot(5, [&]() {
0442         adjustPosition(parentWidget());
0443     });
0444 }
0445 
0446 int KoDialog::marginHint()
0447 {
0448     return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin);
0449 }
0450 
0451 int KoDialog::spacingHint()
0452 {
0453     return QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0454 }
0455 
0456 int KoDialog::groupSpacingHint()
0457 {
0458     return QApplication::fontMetrics().lineSpacing();
0459 }
0460 
0461 QString KoDialog::makeStandardCaption(const QString &userCaption,
0462                                       QWidget *window,
0463                                       CaptionFlags flags)
0464 {
0465     Q_UNUSED(window);
0466     QString caption = qApp->applicationDisplayName();
0467     QString captionString = userCaption.isEmpty() ? caption : userCaption;
0468 
0469     // If the document is modified, add '[modified]'.
0470     if (flags & ModifiedCaption) {
0471         captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
0472     }
0473 
0474     if (!userCaption.isEmpty()) {
0475         // Add the application name if:
0476         // User asked for it, it's not a duplication  and the app name (caption()) is not empty
0477         if (flags & AppNameCaption &&
0478                 !caption.isEmpty() &&
0479                 !userCaption.endsWith(caption)) {
0480             // TODO: check to see if this is a transient/secondary window before trying to add the app name
0481             //       on platforms that need this
0482             captionString += i18nc("Document/application separator in titlebar", " – ") + caption;
0483         }
0484     }
0485 
0486     return captionString;
0487 }
0488 
0489 void KoDialog::setCaption(const QString &_caption)
0490 {
0491     const QString caption = makeStandardCaption(_caption, this);
0492     setPlainCaption(caption);
0493 }
0494 
0495 void KoDialog::setCaption(const QString &caption, bool modified)
0496 {
0497     CaptionFlags flags = HIGCompliantCaption;
0498 
0499     // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath
0500     if (modified) {
0501         flags |= ModifiedCaption;
0502     }
0503 
0504     setPlainCaption(makeStandardCaption(caption, this, flags));
0505 }
0506 
0507 void KoDialog::setPlainCaption(const QString &caption)
0508 {
0509     if (QWidget *win = window()) {
0510         win->setWindowTitle(caption);
0511     }
0512 }
0513 
0514 void KoDialog::resizeLayout(QWidget *widget, int margin, int spacing)   //static
0515 {
0516     if (widget->layout()) {
0517         resizeLayout(widget->layout(), margin, spacing);
0518     }
0519 
0520     if (widget->children().count() > 0) {
0521         const QList<QObject *> list = widget->children();
0522         foreach (QObject *object, list) {
0523             if (object->isWidgetType()) {
0524                 resizeLayout((QWidget *)object, margin, spacing);
0525             }
0526         }
0527     }
0528 }
0529 
0530 void KoDialog::resizeLayout(QLayout *layout, int margin, int spacing)   //static
0531 {
0532     QLayoutItem *child;
0533     int pos = 0;
0534 
0535     while ((child = layout->itemAt(pos))) {
0536         if (child->layout()) {
0537             resizeLayout(child->layout(), margin, spacing);
0538         }
0539 
0540         ++pos;
0541     }
0542 
0543     if (layout->layout()) {
0544         layout->layout()->setMargin(margin);
0545         layout->layout()->setSpacing(spacing);
0546     }
0547 }
0548 
0549 void KoDialog::showButtonSeparator(bool state)
0550 {
0551     Q_D(KoDialog);
0552     if ((d->mActionSeparator != 0) == state) {
0553         return;
0554     }
0555     if (state) {
0556         if (d->mActionSeparator) {
0557             return;
0558         }
0559 
0560         d->mActionSeparator = new KSeparator(this);
0561         d->mActionSeparator->setOrientation(d->mButtonOrientation);
0562     } else {
0563         delete d->mActionSeparator;
0564         d->mActionSeparator = 0;
0565     }
0566 
0567     d->setupLayout();
0568 }
0569 
0570 void KoDialog::setInitialSize(const QSize &size)
0571 {
0572     d_func()->mMinSize = size;
0573     adjustSize();
0574 }
0575 
0576 void KoDialog::incrementInitialSize(const QSize &size)
0577 {
0578     d_func()->mIncSize = size;
0579     adjustSize();
0580 }
0581 
0582 QPushButton *KoDialog::button(ButtonCode id) const
0583 {
0584     Q_D(const KoDialog);
0585     return d->mButtonList.value(id, 0);
0586 }
0587 
0588 void KoDialog::enableButton(ButtonCode id, bool state)
0589 {
0590     QPushButton *button = this->button(id);
0591     if (button) {
0592         button->setEnabled(state);
0593     }
0594 }
0595 
0596 bool KoDialog::isButtonEnabled(ButtonCode id) const
0597 {
0598     QPushButton *button = this->button(id);
0599     if (button) {
0600         return button->isEnabled();
0601     }
0602 
0603     return false;
0604 }
0605 
0606 void KoDialog::enableButtonOk(bool state)
0607 {
0608     enableButton(Ok, state);
0609 }
0610 
0611 void KoDialog::enableButtonApply(bool state)
0612 {
0613     enableButton(Apply, state);
0614 }
0615 
0616 void KoDialog::enableButtonCancel(bool state)
0617 {
0618     enableButton(Cancel, state);
0619 }
0620 
0621 void KoDialog::showButton(ButtonCode id, bool state)
0622 {
0623     QPushButton *button = this->button(id);
0624     if (button) {
0625         state ? button->show() : button->hide();
0626     }
0627 }
0628 
0629 void KoDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item)
0630 {
0631     QPushButton *button = this->button(id);
0632     if (!button) {
0633         return;
0634     }
0635 
0636     KGuiItem::assign(button, item);
0637 }
0638 
0639 void KoDialog::setButtonText(ButtonCode id, const QString &text)
0640 {
0641     Q_D(KoDialog);
0642     if (!d->mSettingDetails && (id == Details)) {
0643         d->mDetailsButtonText = text;
0644         setDetailsWidgetVisible(d->mDetailsVisible);
0645         return;
0646     }
0647 
0648     QPushButton *button = this->button(id);
0649     if (button) {
0650         button->setText(text);
0651     }
0652 }
0653 
0654 QString KoDialog::buttonText(ButtonCode id) const
0655 {
0656     QPushButton *button = this->button(id);
0657     if (button) {
0658         return button->text();
0659     } else {
0660         return QString();
0661     }
0662 }
0663 
0664 void KoDialog::setButtonIcon(ButtonCode id, const QIcon &icon)
0665 {
0666     QPushButton *button = this->button(id);
0667     if (button) {
0668         button->setIcon(icon);
0669     }
0670 }
0671 
0672 QIcon KoDialog::buttonIcon(ButtonCode id) const
0673 {
0674     QPushButton *button = this->button(id);
0675     if (button) {
0676         return button->icon();
0677     } else {
0678         return QIcon();
0679     }
0680 }
0681 
0682 void KoDialog::setButtonToolTip(ButtonCode id, const QString &text)
0683 {
0684     QPushButton *button = this->button(id);
0685     if (button) {
0686         if (text.isEmpty()) {
0687             button->setToolTip(QString());
0688         } else {
0689             button->setToolTip(text);
0690         }
0691     }
0692 }
0693 
0694 QString KoDialog::buttonToolTip(ButtonCode id) const
0695 {
0696     QPushButton *button = this->button(id);
0697     if (button) {
0698         return button->toolTip();
0699     } else {
0700         return QString();
0701     }
0702 }
0703 
0704 void KoDialog::setButtonWhatsThis(ButtonCode id, const QString &text)
0705 {
0706     QPushButton *button = this->button(id);
0707     if (button) {
0708         if (text.isEmpty()) {
0709             button->setWhatsThis(QString());
0710         } else {
0711             button->setWhatsThis(text);
0712         }
0713     }
0714 }
0715 
0716 QString KoDialog::buttonWhatsThis(ButtonCode id) const
0717 {
0718     QPushButton *button = this->button(id);
0719     if (button) {
0720         return button->whatsThis();
0721     } else {
0722         return QString();
0723     }
0724 }
0725 
0726 void KoDialog::setButtonFocus(ButtonCode id)
0727 {
0728     QPushButton *button = this->button(id);
0729     if (button) {
0730         button->setFocus();
0731     }
0732 }
0733 
0734 void KoDialog::setDetailsWidget(QWidget *detailsWidget)
0735 {
0736     Q_D(KoDialog);
0737     if (d->mDetailsWidget == detailsWidget) {
0738         return;
0739     }
0740     delete d->mDetailsWidget;
0741     d->mDetailsWidget = detailsWidget;
0742 
0743     if (d->mDetailsWidget->parentWidget() != this) {
0744         d->mDetailsWidget->setParent(this);
0745     }
0746 
0747     d->mDetailsWidget->hide();
0748     d->setupLayout();
0749 
0750     if (!d->mSettingDetails) {
0751         setDetailsWidgetVisible(d->mDetailsVisible);
0752     }
0753 }
0754 
0755 bool KoDialog::isDetailsWidgetVisible() const
0756 {
0757     return d_func()->mDetailsVisible;
0758 }
0759 
0760 void KoDialog::setDetailsWidgetVisible(bool visible)
0761 {
0762     Q_D(KoDialog);
0763     if (d->mDetailsButtonText.isEmpty()) {
0764         d->mDetailsButtonText = i18n("&Details");
0765     }
0766 
0767     d->mSettingDetails = true;
0768     d->mDetailsVisible = visible;
0769     if (d->mDetailsVisible) {
0770         emit aboutToShowDetails();
0771         setButtonText(Details, d->mDetailsButtonText + " <<");
0772         if (d->mDetailsWidget) {
0773             if (layout()) {
0774                 layout()->setEnabled(false);
0775             }
0776 
0777             d->mDetailsWidget->show();
0778 
0779             adjustSize();
0780 
0781             if (layout()) {
0782                 layout()->activate();
0783                 layout()->setEnabled(true);
0784             }
0785         }
0786     } else {
0787         setButtonText(Details, d->mDetailsButtonText + " >>");
0788         if (d->mDetailsWidget) {
0789             d->mDetailsWidget->hide();
0790         }
0791 
0792         if (layout()) {
0793             layout()->activate();
0794             adjustSize();
0795         }
0796 
0797     }
0798 
0799     d->mSettingDetails = false;
0800 }
0801 
0802 void KoDialog::delayedDestruct()
0803 {
0804     if (isVisible()) {
0805         hide();
0806     }
0807 
0808     deleteLater();
0809 }
0810 
0811 void KoDialog::slotButtonClicked(int button)
0812 {
0813     Q_D(KoDialog);
0814     emit buttonClicked(static_cast<KoDialog::ButtonCode>(button));
0815 
0816     switch (button) {
0817     case Ok:
0818         emit okClicked();
0819         accept();
0820         break;
0821     case Apply:
0822         emit applyClicked();
0823         break;
0824     case Try:
0825         emit tryClicked();
0826         break;
0827     case User3:
0828         emit user3Clicked();
0829         break;
0830     case User2:
0831         emit user2Clicked();
0832         break;
0833     case User1:
0834         emit user1Clicked();
0835         break;
0836     case Yes:
0837         emit yesClicked();
0838         done(Yes);
0839         break;
0840     case No:
0841         emit noClicked();
0842         done(No);
0843         break;
0844     case Cancel:
0845         emit cancelClicked();
0846         reject();
0847         break;
0848     case Close:
0849         emit closeClicked();
0850         done(Close); // KDE5: call reject() instead; more QDialog-like.
0851         break;
0852     case Help:
0853         emit helpClicked();
0854         if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) {
0855             KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
0856         }
0857         break;
0858     case Default:
0859         emit defaultClicked();
0860         break;
0861     case Reset:
0862         emit resetClicked();
0863         break;
0864     case Details:
0865         setDetailsWidgetVisible(!d->mDetailsVisible);
0866         break;
0867     }
0868 
0869     // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now.
0870     if (d->mDeferredDelete) {
0871         d->mDeferredDelete = false;
0872         delayedDestruct();
0873     }
0874 }
0875 
0876 void KoDialog::enableLinkedHelp(bool state)
0877 {
0878     Q_D(KoDialog);
0879     if ((d->mUrlHelp != 0) == state) {
0880         return;
0881     }
0882     if (state) {
0883         if (d->mUrlHelp) {
0884             return;
0885         }
0886 
0887         d->mUrlHelp = new KUrlLabel(this);
0888         d->mUrlHelp->setText(helpLinkText());
0889         d->mUrlHelp->setFloatEnabled(true);
0890         d->mUrlHelp->setUnderline(true);
0891         d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint());
0892         connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked()));
0893 
0894         d->mUrlHelp->show();
0895     } else {
0896         delete d->mUrlHelp;
0897         d->mUrlHelp = 0;
0898     }
0899 
0900     d->setupLayout();
0901 }
0902 
0903 void KoDialog::setHelp(const QString &anchor, const QString &appname)
0904 {
0905     Q_D(KoDialog);
0906     d->mAnchor  = anchor;
0907     d->mHelpApp = appname;
0908 }
0909 
0910 void KoDialog::setHelpLinkText(const QString &text)
0911 {
0912     Q_D(KoDialog);
0913     d->mHelpLinkText = text;
0914     if (d->mUrlHelp) {
0915         d->mUrlHelp->setText(helpLinkText());
0916     }
0917 }
0918 
0919 QString KoDialog::helpLinkText() const
0920 {
0921     Q_D(const KoDialog);
0922     return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText);
0923 }
0924 
0925 void KoDialog::hideEvent(QHideEvent *event)
0926 {
0927     emit hidden();
0928 
0929     if (!event->spontaneous()) {
0930         emit finished();
0931     }
0932 }
0933 
0934 void KoDialog::closeEvent(QCloseEvent *event)
0935 {
0936     Q_D(KoDialog);
0937     QPushButton *button = this->button(d->mEscapeButton);
0938     if (button && !isHidden()) {
0939         button->animateClick();
0940 
0941         if (testAttribute(Qt::WA_DeleteOnClose)) {
0942             // Don't let QWidget::close do a deferred delete just yet, wait for the click first
0943             d->mDeferredDelete = true;
0944             setAttribute(Qt::WA_DeleteOnClose, false);
0945         }
0946     } else {
0947         QDialog::closeEvent(event);
0948     }
0949 }
0950 
0951 #include "moc_KoDialog.cpp"