File indexing completed on 2024-05-12 05:20:43
0001 /* 0002 * kmail: KDE mail client 0003 * SPDX-FileCopyrightText: 1996-1998 Stefan Taferner <taferner@kde.org> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 * 0007 */ 0008 0009 #include "kmmainwin.h" 0010 #include "kmmainwidget.h" 0011 #include "tag/tagactionmanager.h" 0012 #include <Libkdepim/ProgressStatusBarWidget> 0013 #include <Libkdepim/StatusbarProgressWidget> 0014 #include <PimCommon/BroadcastStatus> 0015 #include <PimCommon/NeedUpdateVersionUtils> 0016 #include <PimCommon/NeedUpdateVersionWidget> 0017 0018 #include <KConfigGroup> 0019 #include <KToolBar> 0020 #include <QApplication> 0021 #include <QStatusBar> 0022 #include <QTimer> 0023 0024 #include <KAboutData> 0025 #include <KConfig> 0026 #include <KConfigGui> 0027 #include <KEditToolBar> 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 #include <KStandardAction> 0031 #include <KXMLGUIFactory> 0032 #include <QMenuBar> 0033 #include <QWindow> 0034 0035 #include <QLabel> 0036 #include <QVBoxLayout> 0037 0038 // signal handler for SIGINT & SIGTERM 0039 #ifdef Q_OS_UNIX 0040 #include <KSignalHandler> 0041 #include <signal.h> 0042 #include <unistd.h> 0043 #endif 0044 0045 #include <chrono> 0046 0047 using namespace std::chrono_literals; 0048 0049 KMMainWin::KMMainWin(QWidget *) 0050 : KXmlGuiWindow(nullptr) 0051 , mMessageLabel(new QLabel(i18n("Starting..."))) 0052 0053 { 0054 #ifdef Q_OS_UNIX 0055 /** 0056 * Set up signal handler for SIGINT and SIGTERM 0057 */ 0058 KSignalHandler::self()->watchSignal(SIGINT); 0059 KSignalHandler::self()->watchSignal(SIGTERM); 0060 connect(KSignalHandler::self(), &KSignalHandler::signalReceived, this, [this](int signal) { 0061 if (signal == SIGINT || signal == SIGTERM) { 0062 // Intercept console. 0063 printf("Shutting down...\n"); 0064 slotQuit(); 0065 } 0066 }); 0067 #endif 0068 setObjectName(QLatin1StringView("kmail-mainwindow#")); 0069 0070 resize(700, 500); // The default size 0071 0072 auto mainWidget = new QWidget(this); 0073 auto mainWidgetLayout = new QVBoxLayout(mainWidget); 0074 mainWidgetLayout->setContentsMargins({}); 0075 if (PimCommon::NeedUpdateVersionUtils::checkVersion()) { 0076 const auto status = PimCommon::NeedUpdateVersionUtils::obsoleteVersionStatus(KAboutData::applicationData().version(), QDate::currentDate()); 0077 if (status != PimCommon::NeedUpdateVersionUtils::ObsoleteVersion::NotObsoleteYet) { 0078 auto needUpdateVersionWidget = new PimCommon::NeedUpdateVersionWidget(this); 0079 mainWidgetLayout->addWidget(needUpdateVersionWidget); 0080 qDebug() << " KAboutData::applicationData().version() " << KAboutData::applicationData().version(); 0081 needUpdateVersionWidget->setObsoleteVersion(status); 0082 } 0083 } 0084 0085 mKMMainWidget = new KMMainWidget(this, this, actionCollection()); 0086 mainWidgetLayout->addWidget(mKMMainWidget); 0087 0088 // Don't initialize in constructor. We need this statusbar created 0089 // Bug 460289 0090 mProgressBar = new KPIM::ProgressStatusBarWidget(statusBar(), this); 0091 connect(mKMMainWidget, &KMMainWidget::recreateGui, this, &KMMainWin::slotUpdateGui); 0092 setCentralWidget(mainWidget); 0093 setupStatusBar(); 0094 if (!kmkernel->xmlGuiInstanceName().isEmpty()) { 0095 setComponentName(kmkernel->xmlGuiInstanceName(), i18n("KMail2")); 0096 } 0097 setStandardToolBarMenuEnabled(true); 0098 0099 KStandardAction::configureToolbars(this, &KMMainWin::slotEditToolbars, actionCollection()); 0100 0101 KStandardAction::keyBindings(this, &KMMainWin::slotConfigureShortcuts, actionCollection()); 0102 0103 mShowMenuBarAction = KStandardAction::showMenubar(this, &KMMainWin::slotToggleMenubar, actionCollection()); 0104 if (menuBar()) { 0105 mHamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); 0106 mHamburgerMenu->setShowMenuBarAction(mShowMenuBarAction); 0107 mHamburgerMenu->setMenuBar(menuBar()); 0108 connect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, [this]() { 0109 updateHamburgerMenu(); 0110 // Immediately disconnect. We only need to run this once, but on demand. 0111 // NOTE: The nullptr at the end disconnects all connections between 0112 // q and mHamburgerMenu's aboutToShowMenu signal. 0113 disconnect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, nullptr); 0114 }); 0115 } 0116 0117 KStandardAction::quit(this, &KMMainWin::slotQuit, actionCollection()); 0118 createGUI(QStringLiteral("kmmainwin.rc")); 0119 0120 // must be after createGUI, otherwise e.g toolbar settings are not loaded 0121 setAutoSaveSettings(KMKernel::self()->config()->group(QStringLiteral("Main Window"))); 0122 0123 connect(PimCommon::BroadcastStatus::instance(), &PimCommon::BroadcastStatus::statusMsg, this, &KMMainWin::displayStatusMessage); 0124 0125 connect(mKMMainWidget, &KMMainWidget::captionChangeRequest, this, qOverload<const QString &>(&KMainWindow::setCaption)); 0126 0127 mKMMainWidget->updateQuickSearchLineText(); 0128 mShowMenuBarAction->setChecked(KMailSettings::self()->showMenuBar()); 0129 slotToggleMenubar(true); 0130 connect(guiFactory(), &KXMLGUIFactory::shortcutsSaved, this, &KMMainWin::slotShortcutSaved); 0131 0132 mShowFullScreenAction = KStandardAction::fullScreen(nullptr, nullptr, this, actionCollection()); 0133 actionCollection()->setDefaultShortcut(mShowFullScreenAction, Qt::Key_F11); 0134 connect(mShowFullScreenAction, &QAction::toggled, this, &KMMainWin::slotFullScreen); 0135 KMKernel::self()->setSystemTryAssociatedWindow(windowHandle()); 0136 } 0137 0138 KMMainWin::~KMMainWin() 0139 { 0140 // Avoids a crash if there are any Akonadi jobs running, which may 0141 // attempt to display a status message when they are killed. 0142 disconnect(PimCommon::BroadcastStatus::instance(), &PimCommon::BroadcastStatus::statusMsg, this, nullptr); 0143 } 0144 0145 void KMMainWin::slotFullScreen(bool t) 0146 { 0147 KToggleFullScreenAction::setFullScreen(this, t); 0148 QMenuBar *mb = menuBar(); 0149 if (t) { 0150 auto b = new QToolButton(mb); 0151 b->setDefaultAction(mShowFullScreenAction); 0152 b->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Ignored)); 0153 b->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0154 mb->setCornerWidget(b, Qt::TopRightCorner); 0155 b->setVisible(true); 0156 b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0157 } else { 0158 QWidget *w = mb->cornerWidget(Qt::TopRightCorner); 0159 if (w) { 0160 w->deleteLater(); 0161 } 0162 } 0163 } 0164 0165 void KMMainWin::updateHamburgerMenu() 0166 { 0167 auto menu = new QMenu(this); 0168 menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Open))); 0169 menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::SaveAs))); 0170 menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Print))); 0171 menu->addSeparator(); 0172 menu->addAction(actionCollection()->action(QStringLiteral("check_mail"))); 0173 menu->addAction(actionCollection()->action(QStringLiteral("check_mail_in"))); 0174 menu->addAction(actionCollection()->action(QStringLiteral("send_queued"))); 0175 menu->addAction(actionCollection()->action(QStringLiteral("send_queued_via"))); 0176 menu->addSeparator(); 0177 0178 menu->addAction(actionCollection()->action(QStringLiteral("kmail_configure_kmail"))); 0179 menu->addAction(actionCollection()->action(QStringLiteral("kmail_configure_notifications"))); 0180 menu->addSeparator(); 0181 0182 menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Quit))); 0183 mHamburgerMenu->setMenu(menu); 0184 } 0185 0186 KMMainWidget *KMMainWin::mainKMWidget() const 0187 { 0188 return mKMMainWidget; 0189 } 0190 0191 void KMMainWin::displayStatusMessage(const QString &aText) 0192 { 0193 if (!statusBar() || !mProgressBar->littleProgress()) { 0194 return; 0195 } 0196 const int statusWidth = statusBar()->width() - mProgressBar->littleProgress()->width() - fontMetrics().maxWidth(); 0197 0198 const QString text = fontMetrics().elidedText(QLatin1Char(' ') + aText, Qt::ElideRight, statusWidth); 0199 0200 // ### FIXME: We should disable richtext/HTML (to avoid possible denial of service attacks), 0201 // but this code would double the size of the status bar if the user hovers 0202 // over an <foo@bar.com>-style email address :-( 0203 // text.replace("&", "&"); 0204 // text.replace("<", "<"); 0205 // text.replace(">", ">"); 0206 mMessageLabel->setText(text); 0207 mMessageLabel->setToolTip(aText); 0208 } 0209 0210 void KMMainWin::slotToggleMenubar(bool dontShowWarning) 0211 { 0212 if (menuBar()) { 0213 if (mShowMenuBarAction->isChecked()) { 0214 menuBar()->show(); 0215 } else { 0216 if (!dontShowWarning && (!toolBar()->isVisible() || !toolBar()->actions().contains(mHamburgerMenu))) { 0217 const QString accel = mShowMenuBarAction->shortcut().toString(); 0218 KMessageBox::information(this, 0219 i18n("<qt>This will hide the menu bar completely." 0220 " You can show it again by typing %1.</qt>", 0221 accel), 0222 i18nc("@title:window", "Hide menu bar"), 0223 QStringLiteral("HideMenuBarWarning")); 0224 } 0225 menuBar()->hide(); 0226 } 0227 KMailSettings::self()->setShowMenuBar(mShowMenuBarAction->isChecked()); 0228 } 0229 } 0230 0231 void KMMainWin::slotEditToolbars() 0232 { 0233 KConfigGroup grp = KMKernel::self()->config()->group(QStringLiteral("Main Window")); 0234 saveMainWindowSettings(grp); 0235 QPointer<KEditToolBar> dlg = new KEditToolBar(guiFactory(), this); 0236 connect(dlg.data(), &KEditToolBar::newToolBarConfig, this, &KMMainWin::slotUpdateGui); 0237 0238 dlg->exec(); 0239 delete dlg; 0240 } 0241 0242 void KMMainWin::slotUpdateGui() 0243 { 0244 // remove dynamically created actions before editing 0245 mKMMainWidget->clearFilterActions(); 0246 mKMMainWidget->tagActionManager()->clearActions(); 0247 mKMMainWidget->clearPluginActions(); 0248 0249 createGUI(QStringLiteral("kmmainwin.rc")); 0250 applyMainWindowSettings(KMKernel::self()->config()->group(QStringLiteral("Main Window"))); 0251 0252 // plug dynamically created actions again 0253 mKMMainWidget->initializeFilterActions(false); 0254 mKMMainWidget->tagActionManager()->createActions(); 0255 // FIXME mKMMainWidget->initializePluginActions(); 0256 } 0257 0258 void KMMainWin::setupStatusBar() 0259 { 0260 /* Create a progress dialog and hide it. */ 0261 mMessageLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); 0262 statusBar()->addWidget(mMessageLabel); 0263 0264 QTimer::singleShot(2s, PimCommon::BroadcastStatus::instance(), &PimCommon::BroadcastStatus::reset); 0265 statusBar()->addPermanentWidget(mKMMainWidget->dkimWidgetInfo()); 0266 statusBar()->addPermanentWidget(mKMMainWidget->zoomLabelIndicator()); 0267 statusBar()->addPermanentWidget(mKMMainWidget->vacationScriptIndicator()); 0268 statusBar()->addPermanentWidget(mProgressBar->littleProgress()); 0269 } 0270 0271 void KMMainWin::slotQuit() 0272 { 0273 mReallyClose = true; 0274 close(); 0275 } 0276 0277 //----------------------------------------------------------------------------- 0278 bool KMMainWin::restoreDockedState(int n) 0279 { 0280 // Default restore behavior is to show the window once it is restored. 0281 // Override this if the main window was hidden in the system tray 0282 // when the session was saved. 0283 KConfigGroup config(KConfigGui::sessionConfig(), QString::number(n)); 0284 const bool show = !config.readEntry("docked", false); 0285 0286 return KMainWindow::restore(n, show); 0287 } 0288 0289 void KMMainWin::showAndActivateWindow() 0290 { 0291 show(); 0292 raise(); 0293 activateWindow(); 0294 } 0295 0296 void KMMainWin::saveProperties(KConfigGroup &config) 0297 { 0298 // This is called by the session manager on log-off 0299 // Save the shown/hidden status so we can restore to the same state. 0300 KMainWindow::saveProperties(config); 0301 config.writeEntry("docked", isHidden()); 0302 } 0303 0304 bool KMMainWin::queryClose() 0305 { 0306 if (kmkernel->shuttingDown() || qApp->isSavingSession() || mReallyClose) { 0307 return true; 0308 } 0309 return kmkernel->canQueryClose(); 0310 } 0311 0312 void KMMainWin::slotConfigureShortcuts() 0313 { 0314 guiFactory()->showConfigureShortcutsDialog(); 0315 } 0316 0317 void KMMainWin::slotShortcutSaved() 0318 { 0319 mKMMainWidget->updateQuickSearchLineText(); 0320 } 0321 0322 #include "moc_kmmainwin.cpp"