File indexing completed on 2024-03-24 15:40:45

0001 /*
0002     This file is part of the KDE Libraries
0003     SPDX-FileCopyrightText: 1999-2000 Espen Sand <espen@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 // I (espen) prefer that header files are included alphabetically
0009 
0010 #include "khelpmenu.h"
0011 
0012 #include <QAction>
0013 #include <QApplication>
0014 #include <QDesktopServices>
0015 #include <QDialogButtonBox>
0016 #include <QLabel>
0017 #include <QMenu>
0018 #include <QStandardPaths>
0019 #include <QStyle>
0020 #include <QTimer>
0021 #include <QUrl>
0022 #include <QWhatsThis>
0023 #include <QWidget>
0024 
0025 #include "kaboutapplicationdialog.h"
0026 #include "kaboutkdedialog_p.h"
0027 #include "kbugreport.h"
0028 #include "kswitchlanguagedialog_p.h"
0029 
0030 #include <KAboutData>
0031 #include <KAuthorized>
0032 #include <KLocalizedString>
0033 #include <KStandardAction>
0034 
0035 using namespace KDEPrivate;
0036 
0037 class KHelpMenuPrivate
0038 {
0039 public:
0040     KHelpMenuPrivate()
0041         : mAboutData(KAboutData::applicationData())
0042     {
0043     }
0044     ~KHelpMenuPrivate()
0045     {
0046         delete mMenu;
0047         delete mAboutApp;
0048         delete mAboutKDE;
0049         delete mBugReport;
0050         delete mSwitchApplicationLanguage;
0051     }
0052 
0053     void createActions(KHelpMenu *q);
0054 
0055     QMenu *mMenu = nullptr;
0056     QDialog *mAboutApp = nullptr;
0057     KAboutKdeDialog *mAboutKDE = nullptr;
0058     KBugReport *mBugReport = nullptr;
0059     QAction *mDonateAction = nullptr;
0060     KSwitchLanguageDialog *mSwitchApplicationLanguage = nullptr;
0061 
0062     // TODO evaluate if we use static_cast<QWidget*>(parent()) instead of mParent to win that bit of memory
0063     QWidget *mParent = nullptr;
0064     QString mAboutAppText;
0065 
0066     bool mShowWhatsThis = false;
0067     bool mActionsCreated = false;
0068 
0069     QAction *mHandBookAction = nullptr;
0070     QAction *mWhatsThisAction = nullptr;
0071     QAction *mReportBugAction = nullptr;
0072     QAction *mSwitchApplicationLanguageAction = nullptr;
0073     QAction *mAboutAppAction = nullptr;
0074     QAction *mAboutKDEAction = nullptr;
0075 
0076     KAboutData mAboutData;
0077 };
0078 
0079 KHelpMenu::KHelpMenu(QWidget *parent, const QString &aboutAppText, bool showWhatsThis)
0080     : QObject(parent)
0081     , d(new KHelpMenuPrivate)
0082 {
0083     d->mAboutAppText = aboutAppText;
0084     d->mShowWhatsThis = showWhatsThis;
0085     d->mParent = parent;
0086     d->createActions(this);
0087 }
0088 
0089 KHelpMenu::KHelpMenu(QWidget *parent, const KAboutData &aboutData, bool showWhatsThis)
0090     : QObject(parent)
0091     , d(new KHelpMenuPrivate)
0092 {
0093     d->mShowWhatsThis = showWhatsThis;
0094     d->mParent = parent;
0095     d->mAboutData = aboutData;
0096     d->createActions(this);
0097 }
0098 
0099 KHelpMenu::~KHelpMenu()
0100 {
0101     delete d;
0102 }
0103 
0104 void KHelpMenuPrivate::createActions(KHelpMenu *q)
0105 {
0106     if (mActionsCreated) {
0107         return;
0108     }
0109     mActionsCreated = true;
0110 
0111     if (KAuthorized::authorizeAction(QStringLiteral("help_contents"))) {
0112         mHandBookAction = KStandardAction::helpContents(q, &KHelpMenu::appHelpActivated, q);
0113     }
0114     if (mShowWhatsThis && KAuthorized::authorizeAction(QStringLiteral("help_whats_this"))) {
0115         mWhatsThisAction = KStandardAction::whatsThis(q, &KHelpMenu::contextHelpActivated, q);
0116     }
0117 
0118     if (KAuthorized::authorizeAction(QStringLiteral("help_report_bug")) && !mAboutData.bugAddress().isEmpty()) {
0119         mReportBugAction = KStandardAction::reportBug(q, &KHelpMenu::reportBug, q);
0120     }
0121 
0122     if (KAuthorized::authorizeAction(QStringLiteral("help_donate")) && mAboutData.bugAddress() == QLatin1String("submit@bugs.kde.org")) {
0123         mDonateAction = KStandardAction::donate(q, &KHelpMenu::donate, q);
0124     }
0125 
0126     if (KAuthorized::authorizeAction(QStringLiteral("switch_application_language"))) {
0127         mSwitchApplicationLanguageAction = KStandardAction::switchApplicationLanguage(q, &KHelpMenu::switchApplicationLanguage, q);
0128     }
0129 
0130     if (KAuthorized::authorizeAction(QStringLiteral("help_about_app"))) {
0131         mAboutAppAction = KStandardAction::aboutApp(q, &KHelpMenu::aboutApplication, q);
0132     }
0133 
0134     if (KAuthorized::authorizeAction(QStringLiteral("help_about_kde"))) {
0135         mAboutKDEAction = KStandardAction::aboutKDE(q, &KHelpMenu::aboutKDE, q);
0136     }
0137 }
0138 
0139 // Used in the non-xml-gui case, like kfind or ksnapshot's help button.
0140 QMenu *KHelpMenu::menu()
0141 {
0142     if (!d->mMenu) {
0143         d->mMenu = new QMenu(d->mParent);
0144         connect(d->mMenu, &QObject::destroyed, this, &KHelpMenu::menuDestroyed);
0145 
0146         d->mMenu->setTitle(i18n("&Help"));
0147 
0148         d->createActions(this);
0149 
0150         bool need_separator = false;
0151         if (d->mHandBookAction) {
0152             d->mMenu->addAction(d->mHandBookAction);
0153             need_separator = true;
0154         }
0155 
0156         if (d->mWhatsThisAction) {
0157             d->mMenu->addAction(d->mWhatsThisAction);
0158             need_separator = true;
0159         }
0160 
0161         if (d->mReportBugAction) {
0162             if (need_separator) {
0163                 d->mMenu->addSeparator();
0164             }
0165             d->mMenu->addAction(d->mReportBugAction);
0166             need_separator = true;
0167         }
0168 
0169         if (d->mDonateAction) {
0170             if (need_separator) {
0171                 d->mMenu->addSeparator();
0172             }
0173             d->mMenu->addAction(d->mDonateAction);
0174             need_separator = true;
0175         }
0176 
0177         if (d->mSwitchApplicationLanguageAction) {
0178             if (need_separator) {
0179                 d->mMenu->addSeparator();
0180             }
0181             d->mMenu->addAction(d->mSwitchApplicationLanguageAction);
0182             need_separator = true;
0183         }
0184 
0185         if (need_separator) {
0186             d->mMenu->addSeparator();
0187         }
0188 
0189         if (d->mAboutAppAction) {
0190             d->mMenu->addAction(d->mAboutAppAction);
0191         }
0192 
0193         if (d->mAboutKDEAction) {
0194             d->mMenu->addAction(d->mAboutKDEAction);
0195         }
0196     }
0197 
0198     return d->mMenu;
0199 }
0200 
0201 QAction *KHelpMenu::action(MenuId id) const
0202 {
0203     switch (id) {
0204     case menuHelpContents:
0205         return d->mHandBookAction;
0206 
0207     case menuWhatsThis:
0208         return d->mWhatsThisAction;
0209 
0210     case menuReportBug:
0211         return d->mReportBugAction;
0212 
0213     case menuSwitchLanguage:
0214         return d->mSwitchApplicationLanguageAction;
0215 
0216     case menuAboutApp:
0217         return d->mAboutAppAction;
0218 
0219     case menuAboutKDE:
0220         return d->mAboutKDEAction;
0221 
0222     case menuDonate:
0223         return d->mDonateAction;
0224     }
0225 
0226     return nullptr;
0227 }
0228 
0229 void KHelpMenu::appHelpActivated()
0230 {
0231     QDesktopServices::openUrl(QUrl(QStringLiteral("help:/")));
0232 }
0233 
0234 void KHelpMenu::aboutApplication()
0235 {
0236     if (receivers(SIGNAL(showAboutApplication())) > 0) {
0237         Q_EMIT showAboutApplication();
0238     } else { // if (d->mAboutData)
0239         if (!d->mAboutApp) {
0240             d->mAboutApp = new KAboutApplicationDialog(d->mAboutData, d->mParent);
0241             connect(d->mAboutApp, &QDialog::finished, this, &KHelpMenu::dialogFinished);
0242         }
0243         d->mAboutApp->show();
0244     }
0245 #if 0 // KF5: when can this happen?
0246     else {
0247         if (!d->mAboutApp) {
0248             d->mAboutApp = new QDialog(d->mParent, Qt::Dialog);
0249             QString caption = QGuiApplication::applicationDisplayName();
0250             if (caption.isEmpty()) {
0251                 caption = QCoreApplication::applicationName();
0252             }
0253             d->mAboutApp->setWindowTitle(i18n("About %1", caption));
0254             d->mAboutApp->setObjectName(QStringLiteral("about"));
0255             connect(d->mAboutApp, SIGNAL(finished(int)), this, SLOT(dialogFinished()));
0256 
0257             const int spacingHint = d->mAboutApp->style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
0258             const int marginHint = d->mAboutApp->style()->pixelMetric(QStyle::PM_DefaultChildMargin);
0259 
0260             QVBoxLayout *vbox = new QVBoxLayout;
0261             d->mAboutApp->setLayout(vbox);
0262 
0263             QHBoxLayout *hbox = new QHBoxLayout;
0264             hbox->setSpacing(spacingHint * 3);
0265             hbox->setMargin(marginHint * 1);
0266 
0267             const int size = IconSize(KIconLoader::Dialog);
0268             QLabel *label1 = new QLabel(d->mAboutApp);
0269             label1->setPixmap(qApp->windowIcon().pixmap(size, size));
0270             QLabel *label2 = new QLabel(d->mAboutApp);
0271             label2->setText(d->mAboutAppText);
0272 
0273             hbox->addWidget(label1);
0274             hbox->addWidget(label2);
0275 
0276             vbox->addLayout(hbox);
0277 
0278             QDialogButtonBox *buttonBox = new QDialogButtonBox(d->mAboutApp);
0279             buttonBox->setStandardButtons(QDialogButtonBox::Close);
0280             connect(buttonBox, SIGNAL(accepted()), d->mAboutApp, SLOT(accept()));
0281             connect(buttonBox, SIGNAL(rejected()), d->mAboutApp, SLOT(reject()));
0282             vbox->addWidget(buttonBox);
0283         }
0284         d->mAboutApp->show();
0285     }
0286 #endif
0287 }
0288 
0289 void KHelpMenu::aboutKDE()
0290 {
0291     if (!d->mAboutKDE) {
0292         d->mAboutKDE = new KAboutKdeDialog(d->mParent);
0293         connect(d->mAboutKDE, &QDialog::finished, this, &KHelpMenu::dialogFinished);
0294     }
0295     d->mAboutKDE->show();
0296 }
0297 
0298 void KHelpMenu::reportBug()
0299 {
0300     if (!d->mBugReport) {
0301         d->mBugReport = new KBugReport(d->mAboutData, d->mParent);
0302         connect(d->mBugReport, &QDialog::finished, this, &KHelpMenu::dialogFinished);
0303     }
0304     d->mBugReport->show();
0305 }
0306 
0307 void KHelpMenu::switchApplicationLanguage()
0308 {
0309     if (!d->mSwitchApplicationLanguage) {
0310         d->mSwitchApplicationLanguage = new KSwitchLanguageDialog(d->mParent);
0311         connect(d->mSwitchApplicationLanguage, &QDialog::finished, this, &KHelpMenu::dialogFinished);
0312     }
0313     d->mSwitchApplicationLanguage->show();
0314 }
0315 
0316 void KHelpMenu::donate()
0317 {
0318     QDesktopServices::openUrl(QUrl(QLatin1String("https://www.kde.org/donate?app=") + d->mAboutData.componentName()));
0319 }
0320 
0321 void KHelpMenu::dialogFinished()
0322 {
0323     QTimer::singleShot(0, this, &KHelpMenu::timerExpired);
0324 }
0325 
0326 void KHelpMenu::timerExpired()
0327 {
0328     if (d->mAboutKDE && !d->mAboutKDE->isVisible()) {
0329         delete d->mAboutKDE;
0330         d->mAboutKDE = nullptr;
0331     }
0332 
0333     if (d->mBugReport && !d->mBugReport->isVisible()) {
0334         delete d->mBugReport;
0335         d->mBugReport = nullptr;
0336     }
0337 
0338     if (d->mSwitchApplicationLanguage && !d->mSwitchApplicationLanguage->isVisible()) {
0339         delete d->mSwitchApplicationLanguage;
0340         d->mSwitchApplicationLanguage = nullptr;
0341     }
0342 
0343     if (d->mAboutApp && !d->mAboutApp->isVisible()) {
0344         delete d->mAboutApp;
0345         d->mAboutApp = nullptr;
0346     }
0347 }
0348 
0349 void KHelpMenu::menuDestroyed()
0350 {
0351     d->mMenu = nullptr;
0352 }
0353 
0354 void KHelpMenu::contextHelpActivated()
0355 {
0356     QWhatsThis::enterWhatsThisMode();
0357 }
0358 
0359 #include "moc_khelpmenu.cpp"