File indexing completed on 2024-05-12 16:02:08

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->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, this, SLOT(adjustPosition()));
0442 }
0443 
0444 int KoDialog::marginHint()
0445 {
0446     return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin);
0447 }
0448 
0449 int KoDialog::spacingHint()
0450 {
0451     return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
0452 }
0453 
0454 int KoDialog::groupSpacingHint()
0455 {
0456     return QApplication::fontMetrics().lineSpacing();
0457 }
0458 
0459 QString KoDialog::makeStandardCaption(const QString &userCaption,
0460                                       QWidget *window,
0461                                       CaptionFlags flags)
0462 {
0463     Q_UNUSED(window);
0464     QString caption = qApp->applicationDisplayName();
0465     QString captionString = userCaption.isEmpty() ? caption : userCaption;
0466 
0467     // If the document is modified, add '[modified]'.
0468     if (flags & ModifiedCaption) {
0469         captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
0470     }
0471 
0472     if (!userCaption.isEmpty()) {
0473         // Add the application name if:
0474         // User asked for it, it's not a duplication  and the app name (caption()) is not empty
0475         if (flags & AppNameCaption &&
0476                 !caption.isEmpty() &&
0477                 !userCaption.endsWith(caption)) {
0478             // TODO: check to see if this is a transient/secondary window before trying to add the app name
0479             //       on platforms that need this
0480             captionString += i18nc("Document/application separator in titlebar", " – ") + caption;
0481         }
0482     }
0483 
0484     return captionString;
0485 }
0486 
0487 void KoDialog::setCaption(const QString &_caption)
0488 {
0489     const QString caption = makeStandardCaption(_caption, this);
0490     setPlainCaption(caption);
0491 }
0492 
0493 void KoDialog::setCaption(const QString &caption, bool modified)
0494 {
0495     CaptionFlags flags = HIGCompliantCaption;
0496 
0497     // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath
0498     if (modified) {
0499         flags |= ModifiedCaption;
0500     }
0501 
0502     setPlainCaption(makeStandardCaption(caption, this, flags));
0503 }
0504 
0505 void KoDialog::setPlainCaption(const QString &caption)
0506 {
0507     if (QWidget *win = window()) {
0508         win->setWindowTitle(caption);
0509     }
0510 }
0511 
0512 void KoDialog::resizeLayout(QWidget *widget, int margin, int spacing)   //static
0513 {
0514     if (widget->layout()) {
0515         resizeLayout(widget->layout(), margin, spacing);
0516     }
0517 
0518     if (widget->children().count() > 0) {
0519         const QList<QObject *> list = widget->children();
0520         foreach (QObject *object, list) {
0521             if (object->isWidgetType()) {
0522                 resizeLayout((QWidget *)object, margin, spacing);
0523             }
0524         }
0525     }
0526 }
0527 
0528 void KoDialog::resizeLayout(QLayout *layout, int margin, int spacing)   //static
0529 {
0530     QLayoutItem *child;
0531     int pos = 0;
0532 
0533     while ((child = layout->itemAt(pos))) {
0534         if (child->layout()) {
0535             resizeLayout(child->layout(), margin, spacing);
0536         }
0537 
0538         ++pos;
0539     }
0540 
0541     if (layout->layout()) {
0542         layout->layout()->setMargin(margin);
0543         layout->layout()->setSpacing(spacing);
0544     }
0545 }
0546 
0547 void KoDialog::showButtonSeparator(bool state)
0548 {
0549     Q_D(KoDialog);
0550     if ((d->mActionSeparator != 0) == state) {
0551         return;
0552     }
0553     if (state) {
0554         if (d->mActionSeparator) {
0555             return;
0556         }
0557 
0558         d->mActionSeparator = new KSeparator(this);
0559         d->mActionSeparator->setOrientation(d->mButtonOrientation);
0560     } else {
0561         delete d->mActionSeparator;
0562         d->mActionSeparator = 0;
0563     }
0564 
0565     d->setupLayout();
0566 }
0567 
0568 void KoDialog::setInitialSize(const QSize &size)
0569 {
0570     d_func()->mMinSize = size;
0571     adjustSize();
0572 }
0573 
0574 void KoDialog::incrementInitialSize(const QSize &size)
0575 {
0576     d_func()->mIncSize = size;
0577     adjustSize();
0578 }
0579 
0580 QPushButton *KoDialog::button(ButtonCode id) const
0581 {
0582     Q_D(const KoDialog);
0583     return d->mButtonList.value(id, 0);
0584 }
0585 
0586 void KoDialog::enableButton(ButtonCode id, bool state)
0587 {
0588     QPushButton *button = this->button(id);
0589     if (button) {
0590         button->setEnabled(state);
0591     }
0592 }
0593 
0594 bool KoDialog::isButtonEnabled(ButtonCode id) const
0595 {
0596     QPushButton *button = this->button(id);
0597     if (button) {
0598         return button->isEnabled();
0599     }
0600 
0601     return false;
0602 }
0603 
0604 void KoDialog::enableButtonOk(bool state)
0605 {
0606     enableButton(Ok, state);
0607 }
0608 
0609 void KoDialog::enableButtonApply(bool state)
0610 {
0611     enableButton(Apply, state);
0612 }
0613 
0614 void KoDialog::enableButtonCancel(bool state)
0615 {
0616     enableButton(Cancel, state);
0617 }
0618 
0619 void KoDialog::showButton(ButtonCode id, bool state)
0620 {
0621     QPushButton *button = this->button(id);
0622     if (button) {
0623         state ? button->show() : button->hide();
0624     }
0625 }
0626 
0627 void KoDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item)
0628 {
0629     QPushButton *button = this->button(id);
0630     if (!button) {
0631         return;
0632     }
0633 
0634     KGuiItem::assign(button, item);
0635 }
0636 
0637 void KoDialog::setButtonText(ButtonCode id, const QString &text)
0638 {
0639     Q_D(KoDialog);
0640     if (!d->mSettingDetails && (id == Details)) {
0641         d->mDetailsButtonText = text;
0642         setDetailsWidgetVisible(d->mDetailsVisible);
0643         return;
0644     }
0645 
0646     QPushButton *button = this->button(id);
0647     if (button) {
0648         button->setText(text);
0649     }
0650 }
0651 
0652 QString KoDialog::buttonText(ButtonCode id) const
0653 {
0654     QPushButton *button = this->button(id);
0655     if (button) {
0656         return button->text();
0657     } else {
0658         return QString();
0659     }
0660 }
0661 
0662 void KoDialog::setButtonIcon(ButtonCode id, const QIcon &icon)
0663 {
0664     QPushButton *button = this->button(id);
0665     if (button) {
0666         button->setIcon(icon);
0667     }
0668 }
0669 
0670 QIcon KoDialog::buttonIcon(ButtonCode id) const
0671 {
0672     QPushButton *button = this->button(id);
0673     if (button) {
0674         return button->icon();
0675     } else {
0676         return QIcon();
0677     }
0678 }
0679 
0680 void KoDialog::setButtonToolTip(ButtonCode id, const QString &text)
0681 {
0682     QPushButton *button = this->button(id);
0683     if (button) {
0684         if (text.isEmpty()) {
0685             button->setToolTip(QString());
0686         } else {
0687             button->setToolTip(text);
0688         }
0689     }
0690 }
0691 
0692 QString KoDialog::buttonToolTip(ButtonCode id) const
0693 {
0694     QPushButton *button = this->button(id);
0695     if (button) {
0696         return button->toolTip();
0697     } else {
0698         return QString();
0699     }
0700 }
0701 
0702 void KoDialog::setButtonWhatsThis(ButtonCode id, const QString &text)
0703 {
0704     QPushButton *button = this->button(id);
0705     if (button) {
0706         if (text.isEmpty()) {
0707             button->setWhatsThis(QString());
0708         } else {
0709             button->setWhatsThis(text);
0710         }
0711     }
0712 }
0713 
0714 QString KoDialog::buttonWhatsThis(ButtonCode id) const
0715 {
0716     QPushButton *button = this->button(id);
0717     if (button) {
0718         return button->whatsThis();
0719     } else {
0720         return QString();
0721     }
0722 }
0723 
0724 void KoDialog::setButtonFocus(ButtonCode id)
0725 {
0726     QPushButton *button = this->button(id);
0727     if (button) {
0728         button->setFocus();
0729     }
0730 }
0731 
0732 void KoDialog::setDetailsWidget(QWidget *detailsWidget)
0733 {
0734     Q_D(KoDialog);
0735     if (d->mDetailsWidget == detailsWidget) {
0736         return;
0737     }
0738     delete d->mDetailsWidget;
0739     d->mDetailsWidget = detailsWidget;
0740 
0741     if (d->mDetailsWidget->parentWidget() != this) {
0742         d->mDetailsWidget->setParent(this);
0743     }
0744 
0745     d->mDetailsWidget->hide();
0746     d->setupLayout();
0747 
0748     if (!d->mSettingDetails) {
0749         setDetailsWidgetVisible(d->mDetailsVisible);
0750     }
0751 }
0752 
0753 bool KoDialog::isDetailsWidgetVisible() const
0754 {
0755     return d_func()->mDetailsVisible;
0756 }
0757 
0758 void KoDialog::setDetailsWidgetVisible(bool visible)
0759 {
0760     Q_D(KoDialog);
0761     if (d->mDetailsButtonText.isEmpty()) {
0762         d->mDetailsButtonText = i18n("&Details");
0763     }
0764 
0765     d->mSettingDetails = true;
0766     d->mDetailsVisible = visible;
0767     if (d->mDetailsVisible) {
0768         emit aboutToShowDetails();
0769         setButtonText(Details, d->mDetailsButtonText + " <<");
0770         if (d->mDetailsWidget) {
0771             if (layout()) {
0772                 layout()->setEnabled(false);
0773             }
0774 
0775             d->mDetailsWidget->show();
0776 
0777             adjustSize();
0778 
0779             if (layout()) {
0780                 layout()->activate();
0781                 layout()->setEnabled(true);
0782             }
0783         }
0784     } else {
0785         setButtonText(Details, d->mDetailsButtonText + " >>");
0786         if (d->mDetailsWidget) {
0787             d->mDetailsWidget->hide();
0788         }
0789 
0790         if (layout()) {
0791             layout()->activate();
0792             adjustSize();
0793         }
0794 
0795     }
0796 
0797     d->mSettingDetails = false;
0798 }
0799 
0800 void KoDialog::delayedDestruct()
0801 {
0802     if (isVisible()) {
0803         hide();
0804     }
0805 
0806     deleteLater();
0807 }
0808 
0809 void KoDialog::slotButtonClicked(int button)
0810 {
0811     Q_D(KoDialog);
0812     emit buttonClicked(static_cast<KoDialog::ButtonCode>(button));
0813 
0814     switch (button) {
0815     case Ok:
0816         emit okClicked();
0817         accept();
0818         break;
0819     case Apply:
0820         emit applyClicked();
0821         break;
0822     case Try:
0823         emit tryClicked();
0824         break;
0825     case User3:
0826         emit user3Clicked();
0827         break;
0828     case User2:
0829         emit user2Clicked();
0830         break;
0831     case User1:
0832         emit user1Clicked();
0833         break;
0834     case Yes:
0835         emit yesClicked();
0836         done(Yes);
0837         break;
0838     case No:
0839         emit noClicked();
0840         done(No);
0841         break;
0842     case Cancel:
0843         emit cancelClicked();
0844         reject();
0845         break;
0846     case Close:
0847         emit closeClicked();
0848         done(Close); // KDE5: call reject() instead; more QDialog-like.
0849         break;
0850     case Help:
0851         emit helpClicked();
0852         if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) {
0853             KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
0854         }
0855         break;
0856     case Default:
0857         emit defaultClicked();
0858         break;
0859     case Reset:
0860         emit resetClicked();
0861         break;
0862     case Details:
0863         setDetailsWidgetVisible(!d->mDetailsVisible);
0864         break;
0865     }
0866 
0867     // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now.
0868     if (d->mDeferredDelete) {
0869         d->mDeferredDelete = false;
0870         delayedDestruct();
0871     }
0872 }
0873 
0874 void KoDialog::enableLinkedHelp(bool state)
0875 {
0876     Q_D(KoDialog);
0877     if ((d->mUrlHelp != 0) == state) {
0878         return;
0879     }
0880     if (state) {
0881         if (d->mUrlHelp) {
0882             return;
0883         }
0884 
0885         d->mUrlHelp = new KUrlLabel(this);
0886         d->mUrlHelp->setText(helpLinkText());
0887         d->mUrlHelp->setFloatEnabled(true);
0888         d->mUrlHelp->setUnderline(true);
0889         d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint());
0890         connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked()));
0891 
0892         d->mUrlHelp->show();
0893     } else {
0894         delete d->mUrlHelp;
0895         d->mUrlHelp = 0;
0896     }
0897 
0898     d->setupLayout();
0899 }
0900 
0901 void KoDialog::setHelp(const QString &anchor, const QString &appname)
0902 {
0903     Q_D(KoDialog);
0904     d->mAnchor  = anchor;
0905     d->mHelpApp = appname;
0906 }
0907 
0908 void KoDialog::setHelpLinkText(const QString &text)
0909 {
0910     Q_D(KoDialog);
0911     d->mHelpLinkText = text;
0912     if (d->mUrlHelp) {
0913         d->mUrlHelp->setText(helpLinkText());
0914     }
0915 }
0916 
0917 QString KoDialog::helpLinkText() const
0918 {
0919     Q_D(const KoDialog);
0920     return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText);
0921 }
0922 
0923 void KoDialog::hideEvent(QHideEvent *event)
0924 {
0925     emit hidden();
0926 
0927     if (!event->spontaneous()) {
0928         emit finished();
0929     }
0930 }
0931 
0932 void KoDialog::closeEvent(QCloseEvent *event)
0933 {
0934     Q_D(KoDialog);
0935     QPushButton *button = this->button(d->mEscapeButton);
0936     if (button && !isHidden()) {
0937         button->animateClick();
0938 
0939         if (testAttribute(Qt::WA_DeleteOnClose)) {
0940             // Don't let QWidget::close do a deferred delete just yet, wait for the click first
0941             d->mDeferredDelete = true;
0942             setAttribute(Qt::WA_DeleteOnClose, false);
0943         }
0944     } else {
0945         QDialog::closeEvent(event);
0946     }
0947 }
0948 
0949 void KoDialog::adjustPosition()
0950 {
0951     QWidget *w = parentWidget();
0952 
0953     QPoint p(0, 0);
0954     int extraw = 0, extrah = 0, scrn = 0;
0955     if (w)
0956         w = w->window();
0957     QRect desk;
0958     if (w) {
0959         scrn = qApp->desktop()->screenNumber(w);
0960     } else if (qApp->desktop()->isVirtualDesktop()) {
0961         scrn = qApp->desktop()->screenNumber(QCursor::pos());
0962     } else {
0963         scrn = qApp->desktop()->screenNumber(this);
0964     }
0965     desk = qApp->desktop()->availableGeometry(scrn);
0966 
0967     QWidgetList list = QApplication::topLevelWidgets();
0968     for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
0969         QWidget * current = list.at(i);
0970         if (current->isVisible()) {
0971             int framew = current->geometry().x() - current->x();
0972             int frameh = current->geometry().y() - current->y();
0973 
0974             extraw = qMax(extraw, framew);
0975             extrah = qMax(extrah, frameh);
0976         }
0977     }
0978 
0979     // sanity check for decoration frames. With embedding, we
0980     // might get extraordinary values
0981     if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) {
0982         extrah = 40;
0983         extraw = 10;
0984     }
0985 
0986 
0987     if (w) {
0988         // Use pos() if the widget is embedded into a native window
0989         QPoint pp;
0990         if (w->windowHandle() && w->windowHandle()->property("_q_embedded_native_parent_handle").value<WId>())
0991             pp = w->pos();
0992         else
0993             pp = w->mapToGlobal(QPoint(0,0));
0994         p = QPoint(pp.x() + w->width()/2,
0995                    pp.y() + w->height()/ 2);
0996     } else {
0997         // p = middle of the desktop
0998         p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
0999     }
1000 
1001     // p = origin of this
1002     p = QPoint(p.x()-width()/2 - extraw,
1003                p.y()-height()/2 - extrah);
1004 
1005 
1006     if (p.x() + extraw + width() > desk.x() + desk.width())
1007         p.setX(desk.x() + desk.width() - width() - extraw);
1008     if (p.x() < desk.x())
1009         p.setX(desk.x());
1010 
1011     if (p.y() + extrah + height() > desk.y() + desk.height())
1012         p.setY(desk.y() + desk.height() - height() - extrah);
1013     if (p.y() < desk.y())
1014         p.setY(desk.y());
1015 
1016     // QTBUG-52735: Manually set the correct target screen since scaling in a
1017     // subsequent call to QWindow::resize() may otherwise use the wrong factor
1018     // if the screen changed notification is still in an event queue.
1019     if (scrn >= 0) {
1020         if (QWindow *window = windowHandle())
1021             window->setScreen(QGuiApplication::screens().at(scrn));
1022     }
1023     setGeometry(p.x(), p.y(), width(), height());
1024 }
1025 
1026 
1027 
1028 #include "moc_KoDialog.cpp"