| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 2020 Ahmad Samir <a.samirh78@gmail.com> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
| 6 | */ |
| 7 | |
| 8 | #include "kmessagedialog.h" |
| 9 | #include "kmessagebox_p.h" |
| 10 | |
| 11 | #include "loggingcategory.h" |
| 12 | |
| 13 | #include <QApplication> |
| 14 | #include <QCheckBox> |
| 15 | #include <QDebug> |
| 16 | #include <QDialogButtonBox> |
| 17 | #include <QHBoxLayout> |
| 18 | #include <QLabel> |
| 19 | #include <QListWidget> |
| 20 | #include <QPushButton> |
| 21 | #include <QScreen> |
| 22 | #include <QScrollArea> |
| 23 | #include <QScrollBar> |
| 24 | #include <QShowEvent> |
| 25 | #include <QStyle> |
| 26 | #include <QStyleOption> |
| 27 | #include <QTextBrowser> |
| 28 | #include <QVBoxLayout> |
| 29 | #include <QWindow> |
| 30 | |
| 31 | #include <KCollapsibleGroupBox> |
| 32 | #include <KSqueezedTextLabel> |
| 33 | |
| 34 | static const Qt::TextInteractionFlags s_textFlags = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard; |
| 35 | |
| 36 | // TODO KF6 remove QObject inheritance again |
| 37 | class KMessageDialogPrivate : public QObject |
| 38 | { |
| 39 | Q_OBJECT |
| 40 | |
| 41 | public: |
| 42 | explicit KMessageDialogPrivate(KMessageDialog::Type type, KMessageDialog *qq) |
| 43 | : m_type(type) |
| 44 | , q(qq) |
| 45 | { |
| 46 | } |
| 47 | |
| 48 | KMessageDialog::Type m_type; |
| 49 | KMessageDialog *const q; |
| 50 | |
| 51 | QVBoxLayout *m_topLayout = nullptr; |
| 52 | QWidget *m_mainWidget = nullptr; |
| 53 | QLabel *m_iconLabel = nullptr; |
| 54 | QLabel *m_messageLabel = nullptr; |
| 55 | QListWidget *m_listWidget = nullptr; |
| 56 | QLabel *m_detailsLabel = nullptr; |
| 57 | QTextBrowser *m_detailsTextEdit = nullptr; |
| 58 | KCollapsibleGroupBox *m_detailsGroup = nullptr; |
| 59 | QCheckBox *m_dontAskAgainCB = nullptr; |
| 60 | QDialogButtonBox *m_buttonBox = nullptr; |
| 61 | QMetaObject::Connection m_buttonBoxConnection; |
| 62 | bool m_notifyEnabled = true; |
| 63 | }; |
| 64 | |
| 65 | KMessageDialog::KMessageDialog(KMessageDialog::Type type, const QString &text, QWidget *parent) |
| 66 | : QDialog(parent) |
| 67 | , d(new KMessageDialogPrivate(type, this)) |
| 68 | { |
| 69 | // Dialog top-level layout |
| 70 | d->m_topLayout = new QVBoxLayout(this); |
| 71 | d->m_topLayout->setSizeConstraint(QLayout::SetFixedSize); |
| 72 | |
| 73 | // Main widget |
| 74 | d->m_mainWidget = new QWidget(this); |
| 75 | d->m_topLayout->addWidget(d->m_mainWidget); |
| 76 | |
| 77 | // Layout for the main widget |
| 78 | auto *mainLayout = new QVBoxLayout(d->m_mainWidget); |
| 79 | QStyle *widgetStyle = d->m_mainWidget->style(); |
| 80 | // Provide extra spacing |
| 81 | mainLayout->setSpacing(widgetStyle->pixelMetric(metric: QStyle::PM_LayoutVerticalSpacing) * 2); |
| 82 | mainLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
| 83 | |
| 84 | auto *hLayout = new QHBoxLayout{}; |
| 85 | mainLayout->addLayout(layout: hLayout, stretch: 5); |
| 86 | |
| 87 | // Icon |
| 88 | auto *iconLayout = new QVBoxLayout{}; |
| 89 | hLayout->addLayout(layout: iconLayout, stretch: 0); |
| 90 | |
| 91 | d->m_iconLabel = new QLabel(d->m_mainWidget); |
| 92 | d->m_iconLabel->setVisible(false); |
| 93 | iconLayout->addWidget(d->m_iconLabel); |
| 94 | hLayout->addSpacing(size: widgetStyle->pixelMetric(metric: QStyle::PM_LayoutHorizontalSpacing)); |
| 95 | |
| 96 | const QRect desktop = screen()->geometry(); |
| 97 | const auto desktopWidth = desktop.width(); |
| 98 | // Main message text |
| 99 | d->m_messageLabel = new QLabel(text, d->m_mainWidget); |
| 100 | if (d->m_messageLabel->sizeHint().width() > (desktopWidth * 0.5)) { |
| 101 | // Enable automatic wrapping of messages which are longer than 50% of screen width |
| 102 | d->m_messageLabel->setWordWrap(true); |
| 103 | // Use a squeezed label if text is still too wide |
| 104 | const bool usingSqueezedLabel = d->m_messageLabel->sizeHint().width() > (desktopWidth * 0.85); |
| 105 | if (usingSqueezedLabel) { |
| 106 | delete d->m_messageLabel; |
| 107 | d->m_messageLabel = new KSqueezedTextLabel(text, d->m_mainWidget); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | d->m_messageLabel->setTextInteractionFlags(s_textFlags); |
| 112 | |
| 113 | const bool usingScrollArea = (desktop.height() / 3) < d->m_messageLabel->sizeHint().height(); |
| 114 | if (usingScrollArea) { |
| 115 | QScrollArea *messageScrollArea = new QScrollArea(d->m_mainWidget); |
| 116 | messageScrollArea->setWidget(d->m_messageLabel); |
| 117 | messageScrollArea->setFrameShape(QFrame::NoFrame); |
| 118 | messageScrollArea->setWidgetResizable(true); |
| 119 | hLayout->addWidget(messageScrollArea, stretch: 5); |
| 120 | } else { |
| 121 | hLayout->addWidget(d->m_messageLabel, stretch: 5); |
| 122 | } |
| 123 | |
| 124 | // List widget, will be populated by setListWidgetItems() |
| 125 | d->m_listWidget = new QListWidget(d->m_mainWidget); |
| 126 | mainLayout->addWidget(d->m_listWidget, stretch: usingScrollArea ? 10 : 50); |
| 127 | d->m_listWidget->setVisible(false); |
| 128 | |
| 129 | // DontAskAgain checkbox, will be set up by setDontAskAgainText() |
| 130 | d->m_dontAskAgainCB = new QCheckBox(d->m_mainWidget); |
| 131 | mainLayout->addWidget(d->m_dontAskAgainCB); |
| 132 | d->m_dontAskAgainCB->setVisible(false); |
| 133 | |
| 134 | // Details widget, text will be added by setDetails() |
| 135 | auto *detailsHLayout = new QHBoxLayout{}; |
| 136 | d->m_topLayout->addLayout(layout: detailsHLayout); |
| 137 | |
| 138 | d->m_detailsGroup = new KCollapsibleGroupBox(); |
| 139 | d->m_detailsGroup->setVisible(false); |
| 140 | d->m_detailsGroup->setTitle(QApplication::translate(context: "KMessageDialog" , key: "Details" )); |
| 141 | QVBoxLayout *detailsLayout = new QVBoxLayout(d->m_detailsGroup); |
| 142 | |
| 143 | d->m_detailsLabel = new QLabel(); |
| 144 | d->m_detailsLabel->setTextInteractionFlags(s_textFlags); |
| 145 | d->m_detailsLabel->setWordWrap(true); |
| 146 | detailsLayout->addWidget(d->m_detailsLabel); |
| 147 | |
| 148 | d->m_detailsTextEdit = new QTextBrowser{}; |
| 149 | d->m_detailsTextEdit->setMinimumHeight(d->m_detailsTextEdit->fontMetrics().lineSpacing() * 11); |
| 150 | detailsLayout->addWidget(d->m_detailsTextEdit, stretch: 50); |
| 151 | |
| 152 | detailsHLayout->addWidget(d->m_detailsGroup); |
| 153 | |
| 154 | // Button box |
| 155 | d->m_buttonBox = new QDialogButtonBox(this); |
| 156 | d->m_topLayout->addWidget(d->m_buttonBox); |
| 157 | |
| 158 | // Default buttons |
| 159 | if ((d->m_type == KMessageDialog::Information) || (d->m_type != KMessageDialog::Error)) { |
| 160 | // set Ok button |
| 161 | setButtons(); |
| 162 | } else if (d->m_type == KMessageDialog::WarningContinueCancel) { |
| 163 | // set Continue & Cancel buttons |
| 164 | setButtons(primaryAction: KStandardGuiItem::cont(), secondaryAction: KGuiItem(), cancelAction: KStandardGuiItem::cancel()); |
| 165 | } |
| 166 | |
| 167 | setNotifyEnabled(true); |
| 168 | |
| 169 | // If the dialog is rejected, e.g. by pressing Esc, done() signal connected to the button box |
| 170 | // won't be emitted |
| 171 | connect(sender: this, signal: &QDialog::rejected, context: this, slot: [this]() { |
| 172 | done(KMessageDialog::Cancel); |
| 173 | }); |
| 174 | } |
| 175 | |
| 176 | // This method has been copied from KWindowSystem to avoid depending on it |
| 177 | static void setMainWindow(QDialog *dialog, WId mainWindowId) |
| 178 | { |
| 179 | #ifdef Q_OS_OSX |
| 180 | if (!QWidget::find(mainWindowId)) { |
| 181 | return; |
| 182 | } |
| 183 | #endif |
| 184 | // Set the WA_NativeWindow attribute to force the creation of the QWindow. |
| 185 | // Without this QWidget::windowHandle() returns 0. |
| 186 | dialog->setAttribute(Qt::WA_NativeWindow, on: true); |
| 187 | QWindow *subWindow = dialog->windowHandle(); |
| 188 | Q_ASSERT(subWindow); |
| 189 | |
| 190 | QWindow *mainWindow = QWindow::fromWinId(id: mainWindowId); |
| 191 | if (!mainWindow) { |
| 192 | // foreign windows not supported on all platforms |
| 193 | return; |
| 194 | } |
| 195 | // mainWindow is not the child of any object, so make sure it gets deleted at some point |
| 196 | QObject::connect(sender: dialog, signal: &QObject::destroyed, context: mainWindow, slot: &QObject::deleteLater); |
| 197 | subWindow->setTransientParent(mainWindow); |
| 198 | } |
| 199 | |
| 200 | KMessageDialog::KMessageDialog(KMessageDialog::Type type, const QString &text, WId parent_id) |
| 201 | : KMessageDialog(type, text) |
| 202 | { |
| 203 | QWidget *parent = QWidget::find(parent_id); |
| 204 | setParent(parent); |
| 205 | if (!parent && parent_id) { |
| 206 | setMainWindow(dialog: this, mainWindowId: parent_id); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | KMessageDialog::~KMessageDialog() |
| 211 | { |
| 212 | removeEventFilter(obj: d.get()); |
| 213 | } |
| 214 | |
| 215 | void KMessageDialog::setCaption(const QString &caption) |
| 216 | { |
| 217 | if (!caption.isEmpty()) { |
| 218 | setWindowTitle(caption); |
| 219 | return; |
| 220 | } |
| 221 | |
| 222 | QString title; |
| 223 | switch (d->m_type) { // Get a title based on the dialog Type |
| 224 | case KMessageDialog::QuestionTwoActions: |
| 225 | case KMessageDialog::QuestionTwoActionsCancel: |
| 226 | title = QApplication::translate(context: "KMessageDialog" , key: "Question" ); |
| 227 | break; |
| 228 | case KMessageDialog::WarningTwoActions: |
| 229 | case KMessageDialog::WarningTwoActionsCancel: |
| 230 | case KMessageDialog::WarningContinueCancel: |
| 231 | title = QApplication::translate(context: "KMessageDialog" , key: "Warning" ); |
| 232 | break; |
| 233 | case KMessageDialog::Information: |
| 234 | title = QApplication::translate(context: "KMessageDialog" , key: "Information" ); |
| 235 | break; |
| 236 | case KMessageDialog::Error: { |
| 237 | title = QApplication::translate(context: "KMessageDialog" , key: "Error" ); |
| 238 | break; |
| 239 | } |
| 240 | default: |
| 241 | break; |
| 242 | } |
| 243 | |
| 244 | setWindowTitle(title); |
| 245 | } |
| 246 | |
| 247 | void KMessageDialog::setIcon(const QIcon &icon) |
| 248 | { |
| 249 | QIcon effectiveIcon(icon); |
| 250 | if (effectiveIcon.isNull()) { // Fallback to an icon based on the dialog Type |
| 251 | QStyle *style = this->style(); |
| 252 | switch (d->m_type) { |
| 253 | case KMessageDialog::QuestionTwoActions: |
| 254 | case KMessageDialog::QuestionTwoActionsCancel: |
| 255 | effectiveIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxQuestion, option: nullptr, widget: this); |
| 256 | break; |
| 257 | case KMessageDialog::WarningTwoActions: |
| 258 | case KMessageDialog::WarningTwoActionsCancel: |
| 259 | case KMessageDialog::WarningContinueCancel: |
| 260 | effectiveIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxWarning, option: nullptr, widget: this); |
| 261 | break; |
| 262 | case KMessageDialog::Information: |
| 263 | effectiveIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxInformation, option: nullptr, widget: this); |
| 264 | break; |
| 265 | case KMessageDialog::Error: |
| 266 | effectiveIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical, option: nullptr, widget: this); |
| 267 | break; |
| 268 | default: |
| 269 | break; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | if (effectiveIcon.isNull()) { |
| 274 | qCWarning(KWidgetsAddonsLog) << "Neither the requested icon nor a generic one based on the " |
| 275 | "dialog type could be found." ; |
| 276 | return; |
| 277 | } |
| 278 | |
| 279 | d->m_iconLabel->setVisible(true); |
| 280 | |
| 281 | QStyleOption option; |
| 282 | option.initFrom(w: d->m_mainWidget); |
| 283 | QStyle *widgetStyle = d->m_mainWidget->style(); |
| 284 | const int size = widgetStyle->pixelMetric(metric: QStyle::PM_MessageBoxIconSize, option: &option, widget: d->m_mainWidget); |
| 285 | d->m_iconLabel->setPixmap(effectiveIcon.pixmap(extent: size)); |
| 286 | } |
| 287 | |
| 288 | void KMessageDialog::setListWidgetItems(const QStringList &strlist) |
| 289 | { |
| 290 | const bool isEmpty = strlist.isEmpty(); |
| 291 | d->m_listWidget->setVisible(!isEmpty); |
| 292 | if (isEmpty) { |
| 293 | return; |
| 294 | } |
| 295 | |
| 296 | // Enable automatic wrapping since the listwidget already has a good initial width |
| 297 | d->m_messageLabel->setWordWrap(true); |
| 298 | d->m_listWidget->addItems(labels: strlist); |
| 299 | |
| 300 | QStyleOptionViewItem styleOption; |
| 301 | styleOption.initFrom(w: d->m_listWidget); |
| 302 | QFontMetrics fm(styleOption.font); |
| 303 | int listWidth = d->m_listWidget->width(); |
| 304 | for (const QString &str : strlist) { |
| 305 | listWidth = qMax(a: listWidth, b: fm.boundingRect(text: str).width()); |
| 306 | } |
| 307 | const int borderWidth = (d->m_listWidget->width() - d->m_listWidget->viewport()->width() // |
| 308 | + d->m_listWidget->verticalScrollBar()->height()); |
| 309 | listWidth += borderWidth; |
| 310 | const auto deskWidthPortion = screen()->geometry().width() * 0.85; |
| 311 | if (listWidth > deskWidthPortion) { // Limit the list widget size to 85% of screen width |
| 312 | listWidth = qRound(d: deskWidthPortion); |
| 313 | } |
| 314 | d->m_listWidget->setMinimumWidth(listWidth); |
| 315 | d->m_listWidget->setSelectionMode(QListWidget::NoSelection); |
| 316 | d->m_messageLabel->setSizePolicy(hor: QSizePolicy::Preferred, ver: QSizePolicy::Minimum); |
| 317 | } |
| 318 | |
| 319 | void KMessageDialog::setDetails(const QString &details) |
| 320 | { |
| 321 | d->m_detailsGroup->setVisible(!details.isEmpty()); |
| 322 | |
| 323 | if (details.length() < 512) { // random number KMessageBox uses. |
| 324 | d->m_detailsLabel->setText(details); |
| 325 | d->m_detailsLabel->show(); |
| 326 | |
| 327 | d->m_detailsTextEdit->setText(QString()); |
| 328 | d->m_detailsTextEdit->hide(); |
| 329 | } else { |
| 330 | d->m_detailsLabel->setText(QString()); |
| 331 | d->m_detailsLabel->hide(); |
| 332 | |
| 333 | d->m_detailsTextEdit->setText(details); |
| 334 | d->m_detailsTextEdit->show(); |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | void KMessageDialog::setButtons(const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const KGuiItem &cancelAction) |
| 339 | { |
| 340 | switch (d->m_type) { |
| 341 | case KMessageDialog::QuestionTwoActions: { |
| 342 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); |
| 343 | auto *buttonYes = d->m_buttonBox->button(which: QDialogButtonBox::Yes); |
| 344 | KGuiItem::assign(button: buttonYes, item: primaryAction); |
| 345 | buttonYes->setFocus(); |
| 346 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction); |
| 347 | break; |
| 348 | } |
| 349 | case KMessageDialog::QuestionTwoActionsCancel: { |
| 350 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); |
| 351 | auto *buttonYes = d->m_buttonBox->button(which: QDialogButtonBox::Yes); |
| 352 | KGuiItem::assign(button: buttonYes, item: primaryAction); |
| 353 | buttonYes->setFocus(); |
| 354 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction); |
| 355 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::Cancel), item: cancelAction); |
| 356 | break; |
| 357 | } |
| 358 | case KMessageDialog::WarningTwoActions: { |
| 359 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); |
| 360 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction); |
| 361 | |
| 362 | auto *noBtn = d->m_buttonBox->button(which: QDialogButtonBox::No); |
| 363 | KGuiItem::assign(button: noBtn, item: secondaryAction); |
| 364 | noBtn->setDefault(true); |
| 365 | noBtn->setFocus(); |
| 366 | break; |
| 367 | } |
| 368 | case KMessageDialog::WarningTwoActionsCancel: { |
| 369 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); |
| 370 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction); |
| 371 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction); |
| 372 | |
| 373 | auto *cancelButton = d->m_buttonBox->button(which: QDialogButtonBox::Cancel); |
| 374 | KGuiItem::assign(button: cancelButton, item: cancelAction); |
| 375 | cancelButton->setDefault(true); |
| 376 | cancelButton->setFocus(); |
| 377 | break; |
| 378 | } |
| 379 | case KMessageDialog::WarningContinueCancel: { |
| 380 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::Cancel); |
| 381 | |
| 382 | KGuiItem::assign(button: d->m_buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction); |
| 383 | |
| 384 | auto *cancelButton = d->m_buttonBox->button(which: QDialogButtonBox::Cancel); |
| 385 | KGuiItem::assign(button: cancelButton, item: cancelAction); |
| 386 | cancelButton->setDefault(true); |
| 387 | cancelButton->setFocus(); |
| 388 | break; |
| 389 | } |
| 390 | case KMessageDialog::Information: |
| 391 | case KMessageDialog::Error: { |
| 392 | d->m_buttonBox->setStandardButtons(QDialogButtonBox::Ok); |
| 393 | auto *okButton = d->m_buttonBox->button(which: QDialogButtonBox::Ok); |
| 394 | KGuiItem::assign(button: okButton, item: KStandardGuiItem::ok()); |
| 395 | okButton->setFocus(); |
| 396 | break; |
| 397 | } |
| 398 | default: |
| 399 | break; |
| 400 | } |
| 401 | |
| 402 | // Button connections |
| 403 | if (!d->m_buttonBoxConnection) { |
| 404 | d->m_buttonBoxConnection = connect(sender: d->m_buttonBox, signal: &QDialogButtonBox::clicked, context: this, slot: [this](QAbstractButton *button) { |
| 405 | QDialogButtonBox::StandardButton code = d->m_buttonBox->standardButton(button); |
| 406 | const int result = (code == QDialogButtonBox::Ok) ? KMessageDialog::Ok |
| 407 | : (code == QDialogButtonBox::Cancel) ? KMessageDialog::Cancel |
| 408 | : (code == QDialogButtonBox::Yes) ? KMessageDialog::PrimaryAction |
| 409 | : (code == QDialogButtonBox::No) ? KMessageDialog::SecondaryAction |
| 410 | : |
| 411 | /* else */ -1; |
| 412 | if (result != -1) { |
| 413 | done(result); |
| 414 | } |
| 415 | }); |
| 416 | } |
| 417 | } |
| 418 | |
| 419 | void KMessageDialog::setDontAskAgainText(const QString &dontAskAgainText) |
| 420 | { |
| 421 | d->m_dontAskAgainCB->setVisible(!dontAskAgainText.isEmpty()); |
| 422 | d->m_dontAskAgainCB->setText(dontAskAgainText); |
| 423 | } |
| 424 | |
| 425 | void KMessageDialog::setDontAskAgainChecked(bool isChecked) |
| 426 | { |
| 427 | if (d->m_dontAskAgainCB->text().isEmpty()) { |
| 428 | qCWarning(KWidgetsAddonsLog) << "setDontAskAgainChecked() method was called on a dialog that doesn't " |
| 429 | "appear to have a checkbox; you need to use setDontAskAgainText() " |
| 430 | "to add a checkbox to the dialog first." ; |
| 431 | return; |
| 432 | } |
| 433 | |
| 434 | d->m_dontAskAgainCB->setChecked(isChecked); |
| 435 | } |
| 436 | |
| 437 | bool KMessageDialog::isDontAskAgainChecked() const |
| 438 | { |
| 439 | if (d->m_dontAskAgainCB->text().isEmpty()) { |
| 440 | qCWarning(KWidgetsAddonsLog) << "isDontAskAgainChecked() method was called on a dialog that doesn't " |
| 441 | "appear to have a checkbox; you need to use setDontAskAgainText() " |
| 442 | "to add a checkbox to the dialog first." ; |
| 443 | return false; |
| 444 | } |
| 445 | |
| 446 | return d->m_dontAskAgainCB->isChecked(); |
| 447 | } |
| 448 | |
| 449 | void KMessageDialog::setOpenExternalLinks(bool isAllowed) |
| 450 | { |
| 451 | d->m_messageLabel->setOpenExternalLinks(isAllowed); |
| 452 | d->m_detailsLabel->setOpenExternalLinks(isAllowed); |
| 453 | d->m_detailsTextEdit->setOpenExternalLinks(isAllowed); |
| 454 | } |
| 455 | |
| 456 | bool KMessageDialog::isNotifyEnabled() const |
| 457 | { |
| 458 | return d->m_notifyEnabled; |
| 459 | } |
| 460 | |
| 461 | void KMessageDialog::setNotifyEnabled(bool enable) |
| 462 | { |
| 463 | d->m_notifyEnabled = enable; |
| 464 | } |
| 465 | |
| 466 | void KMessageDialog::showEvent(QShowEvent *event) |
| 467 | { |
| 468 | if (d->m_notifyEnabled && !event->spontaneous()) { |
| 469 | // TODO include m_listWidget items |
| 470 | beep(type: d->m_type, text: d->m_messageLabel->text(), dialog: topLevelWidget()); |
| 471 | } |
| 472 | QDialog::showEvent(event); |
| 473 | } |
| 474 | |
| 475 | void KMessageDialog::beep(Type type, const QString &text, QWidget *widget) |
| 476 | { |
| 477 | #ifndef Q_OS_WIN // FIXME problems with KNotify on Windows |
| 478 | QMessageBox::Icon notifyType = QMessageBox::NoIcon; |
| 479 | switch (type) { |
| 480 | case KMessageDialog::QuestionTwoActions: |
| 481 | case KMessageDialog::QuestionTwoActionsCancel: |
| 482 | notifyType = QMessageBox::Question; |
| 483 | break; |
| 484 | case KMessageDialog::WarningTwoActions: |
| 485 | case KMessageDialog::WarningTwoActionsCancel: |
| 486 | case KMessageDialog::WarningContinueCancel: |
| 487 | notifyType = QMessageBox::Warning; |
| 488 | break; |
| 489 | case KMessageDialog::Information: |
| 490 | notifyType = QMessageBox::Information; |
| 491 | break; |
| 492 | case KMessageDialog::Error: |
| 493 | notifyType = QMessageBox::Critical; |
| 494 | break; |
| 495 | } |
| 496 | |
| 497 | KMessageBox::notifyInterface()->sendNotification(notificationType: notifyType, message: text, parent: widget); |
| 498 | #endif |
| 499 | } |
| 500 | |
| 501 | #include "kmessagedialog.moc" |
| 502 | #include "moc_kmessagedialog.cpp" |
| 503 | |