File indexing completed on 2024-09-01 13:31:33
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"