File indexing completed on 2024-04-28 05:11:02

0001 /*
0002     This file is part of Akregator.
0003 
0004     SPDX-FileCopyrightText: 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0007 */
0008 
0009 #include "mainwindow.h"
0010 #include "akregator_part.h"
0011 #include "akregatorconfig.h"
0012 #include "trayicon.h"
0013 #include <Libkdepim/ProgressManager>
0014 #include <Libkdepim/ProgressStatusBarWidget>
0015 #include <Libkdepim/StatusbarProgressWidget>
0016 #include <PimCommon/BroadcastStatus>
0017 
0018 #include <KActionCollection>
0019 #include <KConfig>
0020 #include <KEditToolBar>
0021 #include <KLocalizedString>
0022 #include <KMessageBox>
0023 #include <KPluginFactory>
0024 #include <KPluginMetaData>
0025 #include <KSharedConfig>
0026 #include <KShortcutsDialog>
0027 #include <KSqueezedTextLabel>
0028 #include <KStandardAction>
0029 #include <KToggleFullScreenAction>
0030 #include <KToolBar>
0031 #include <KXMLGUIFactory>
0032 #include <QApplication>
0033 #include <QFontDatabase>
0034 #include <QMenuBar>
0035 #include <QStatusBar>
0036 #include <QTimer>
0037 #include <QToolButton>
0038 
0039 using namespace Akregator;
0040 
0041 MainWindow::MainWindow(QWidget *parent)
0042     : KParts::MainWindow(parent)
0043     , m_part()
0044     , m_statusLabel(new KSqueezedTextLabel(this))
0045 {
0046     // set the shell's ui resource file
0047     setXMLFile(QStringLiteral("akregator_shell.rc"));
0048 
0049     KStandardAction::keyBindings(this, &MainWindow::optionsConfigureKeys, actionCollection()); // options_configure_keybinding
0050     KStandardAction::configureToolbars(this, &MainWindow::optionsConfigureToolbars, actionCollection()); // options_configure_toolbars
0051 
0052     toolBar()->show();
0053     statusBar()->show();
0054 
0055     const int statH = fontMetrics().height() + 2;
0056     m_statusLabel->setTextFormat(Qt::RichText);
0057     m_statusLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
0058     m_statusLabel->setMinimumWidth(0);
0059     m_statusLabel->setFixedHeight(statH);
0060     statusBar()->addWidget(m_statusLabel, 1);
0061 
0062     KStandardAction::quit(qApp, &QApplication::quit, actionCollection());
0063     mShowMenuBarAction = KStandardAction::showMenubar(this, &MainWindow::slotToggleMenubar, actionCollection());
0064     mShowMenuBarAction->setChecked(Settings::showMenuBar());
0065     slotToggleMenubar(true);
0066 
0067     if (menuBar()) {
0068         mHamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
0069         mHamburgerMenu->setShowMenuBarAction(mShowMenuBarAction);
0070         mHamburgerMenu->setMenuBar(menuBar());
0071         connect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, [this]() {
0072             updateHamburgerMenu();
0073             // Immediately disconnect. We only need to run this once, but on demand.
0074             // NOTE: The nullptr at the end disconnects all connections between
0075             // q and mHamburgerMenu's aboutToShowMenu signal.
0076             disconnect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, nullptr);
0077         });
0078     }
0079 
0080     mShowFullScreenAction = KStandardAction::fullScreen(nullptr, nullptr, this, actionCollection());
0081     actionCollection()->setDefaultShortcut(mShowFullScreenAction, Qt::Key_F11);
0082     connect(mShowFullScreenAction, &QAction::toggled, this, &MainWindow::slotFullScreen);
0083 
0084     setStandardToolBarMenuEnabled(true);
0085     createStandardStatusBarAction();
0086 
0087     connect(PimCommon::BroadcastStatus::instance(), &PimCommon::BroadcastStatus::statusMsg, this, &MainWindow::slotSetStatusBarText);
0088 
0089     connect(qApp, &QCoreApplication::aboutToQuit, this, &MainWindow::slotOnShutdown);
0090 }
0091 
0092 void MainWindow::slotFullScreen(bool t)
0093 {
0094     KToggleFullScreenAction::setFullScreen(this, t);
0095     QMenuBar *mb = menuBar();
0096     if (t) {
0097         auto b = new QToolButton(mb);
0098         b->setDefaultAction(mShowFullScreenAction);
0099         b->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Ignored));
0100         b->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0101         mb->setCornerWidget(b, Qt::TopRightCorner);
0102         b->setVisible(true);
0103         b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
0104     } else {
0105         QWidget *w = mb->cornerWidget(Qt::TopRightCorner);
0106         if (w) {
0107             w->deleteLater();
0108         }
0109     }
0110 }
0111 
0112 void MainWindow::slotToggleMenubar(bool dontShowWarning)
0113 {
0114     if (menuBar()) {
0115         if (mShowMenuBarAction->isChecked()) {
0116             menuBar()->show();
0117         } else {
0118             if (!dontShowWarning && (!toolBar()->isVisible() || !toolBar()->actions().contains(mHamburgerMenu))) {
0119                 const QString accel = mShowMenuBarAction->shortcut().toString();
0120                 KMessageBox::information(this,
0121                                          i18n("<qt>This will hide the menu bar completely."
0122                                               " You can show it again by typing %1.</qt>",
0123                                               accel),
0124                                          i18nc("@title:window", "Hide menu bar"),
0125                                          QStringLiteral("HideMenuBarWarning"));
0126             }
0127             menuBar()->hide();
0128         }
0129         Settings::setShowMenuBar(mShowMenuBarAction->isChecked());
0130     }
0131 }
0132 
0133 void MainWindow::updateHamburgerMenu()
0134 {
0135     auto menu = new QMenu(this);
0136     menu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Quit)));
0137     mHamburgerMenu->setMenu(menu);
0138 }
0139 
0140 bool MainWindow::loadPart()
0141 {
0142     if (m_part) {
0143         return true;
0144     }
0145     // this routine will find and load our Part.  it finds the Part by
0146     // name which is a bad idea usually.. but it's alright in this
0147     // case since our Part is made for this Shell
0148     const KPluginMetaData md(QStringLiteral("akregatorpart"));
0149     const auto result = KPluginFactory::instantiatePlugin<KParts::Part>(md, this);
0150     if (result) {
0151         m_part = static_cast<Akregator::Part *>(result.plugin);
0152     } else {
0153         KMessageBox::error(this, i18n("Could not find the Akregator part; please check your installation.\n%1", result.errorString));
0154         return false;
0155     }
0156 
0157     m_part->setObjectName(QLatin1StringView("akregator_part"));
0158     setCentralWidget(m_part->widget());
0159 
0160     connect(m_part.data(), &Part::setWindowCaption, this, qOverload<const QString &>(&KMainWindow::setCaption));
0161 
0162     createGUI(m_part);
0163     setAutoSaveSettings();
0164     return true;
0165 }
0166 
0167 void MainWindow::setupProgressWidgets()
0168 {
0169     auto progressStatusBarWidget = new KPIM::ProgressStatusBarWidget(statusBar(), this);
0170     m_statusbarProgress = progressStatusBarWidget->littleProgress();
0171     statusBar()->addPermanentWidget(m_statusbarProgress, 0);
0172 
0173     // The progress widget blocks a large part of the status bar, but is empty
0174     // most of the time. Hide it when unused, allowing a longer status label.
0175     m_hideProgressTimer = new QTimer(this);
0176     m_hideProgressTimer->setSingleShot(true);
0177     connect(m_hideProgressTimer, &QTimer::timeout, m_statusbarProgress, &QWidget::hide);
0178 
0179     connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemAdded, this, &MainWindow::updateStatusbarProgressVisibility);
0180     connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemCompleted, this, &MainWindow::updateStatusbarProgressVisibility);
0181     m_statusbarProgress->hide();
0182 }
0183 
0184 void MainWindow::updateStatusbarProgressVisibility()
0185 {
0186     if (KPIM::ProgressManager::instance()->isEmpty()) {
0187         m_hideProgressTimer->start(5000);
0188     } else {
0189         m_hideProgressTimer->stop();
0190         m_statusbarProgress->show();
0191     }
0192 }
0193 
0194 MainWindow::~MainWindow() = default;
0195 
0196 void MainWindow::saveProperties(KConfigGroup &config)
0197 {
0198     if (!m_part) {
0199         if (!loadPart()) {
0200             return;
0201         }
0202     }
0203 
0204     m_part->saveProperties(config);
0205     config.writeEntry("docked", isHidden());
0206 }
0207 
0208 void MainWindow::readProperties(const KConfigGroup &config)
0209 {
0210     if (!m_part) {
0211         if (!loadPart()) {
0212             return;
0213         }
0214     }
0215     m_part->readProperties(config);
0216     setVisible(!Settings::showTrayIcon() || !config.readEntry("docked", false));
0217 }
0218 
0219 // TODO: move to part?
0220 void MainWindow::optionsConfigureKeys()
0221 {
0222     KShortcutsDialog dlg(this);
0223 
0224     dlg.addCollection(actionCollection());
0225     if (m_part) {
0226         dlg.addCollection(m_part->actionCollection());
0227     }
0228 
0229     if (dlg.configure()) {
0230         if (m_part) {
0231             // FIXME
0232             // m_part->updateQuickSearchLineText();
0233         }
0234     }
0235 }
0236 
0237 // TODO: move to part?
0238 void MainWindow::optionsConfigureToolbars()
0239 {
0240     KConfigGroup grp(KSharedConfig::openConfig().data()->group(autoSaveGroup()));
0241     saveMainWindowSettings(grp);
0242     QPointer<KEditToolBar> dlg = new KEditToolBar(factory());
0243     connect(dlg.data(), &KEditToolBar::newToolBarConfig, this, &MainWindow::applyNewToolbarConfig);
0244     dlg->exec();
0245     delete dlg;
0246 }
0247 
0248 // TODO: move to part?
0249 void MainWindow::applyNewToolbarConfig()
0250 {
0251     applyMainWindowSettings(KSharedConfig::openConfig()->group(autoSaveGroup()));
0252 }
0253 
0254 void MainWindow::slotQuit()
0255 {
0256     qApp->quit();
0257 }
0258 
0259 void MainWindow::slotOnShutdown()
0260 {
0261     delete m_part;
0262 }
0263 
0264 bool MainWindow::queryClose()
0265 {
0266     if (qApp->isSavingSession()) {
0267         return true;
0268     }
0269     if (!TrayIcon::getInstance()) {
0270         delete m_part; // delete that here instead of dtor to ensure nested khtmlparts are deleted before singleton objects like KHTMLPageCache
0271         return true;
0272     }
0273 
0274     hide();
0275     return false;
0276 }
0277 
0278 void MainWindow::slotClearStatusText()
0279 {
0280     m_statusLabel->setText(QString());
0281 }
0282 
0283 void MainWindow::slotSetStatusBarText(const QString &text)
0284 {
0285     m_statusLabel->setText(text);
0286 }
0287 
0288 #include "moc_mainwindow.cpp"