File indexing completed on 2024-04-28 05:34:57
0001 /* 0002 SPDX-FileCopyrightText: 2006 Lukas Tinkl <ltinkl@suse.cz> 0003 SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@suse.cz> 0004 SPDX-FileCopyrightText: 2009 Ivo Anjo <knuckles@gmail.com> 0005 SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "freespacenotifier.h" 0011 0012 #include <KNotification> 0013 #include <KNotificationJobUiDelegate> 0014 0015 #include <KIO/ApplicationLauncherJob> 0016 #include <KIO/FileSystemFreeSpaceJob> 0017 #include <KIO/OpenUrlJob> 0018 0019 #include <chrono> 0020 0021 #include "settings.h" 0022 0023 FreeSpaceNotifier::FreeSpaceNotifier(const QString &path, const KLocalizedString ¬ificationText, QObject *parent) 0024 : QObject(parent) 0025 , m_path(path) 0026 , m_notificationText(notificationText) 0027 { 0028 connect(&m_timer, &QTimer::timeout, this, &FreeSpaceNotifier::checkFreeDiskSpace); 0029 m_timer.start(std::chrono::minutes(1)); 0030 } 0031 0032 FreeSpaceNotifier::~FreeSpaceNotifier() 0033 { 0034 if (m_notification) { 0035 m_notification->close(); 0036 } 0037 } 0038 0039 void FreeSpaceNotifier::checkFreeDiskSpace() 0040 { 0041 if (!FreeSpaceNotifierSettings::enableNotification()) { 0042 // do nothing if notifying is disabled; 0043 // also stop the timer that probably got us here in the first place 0044 m_timer.stop(); 0045 return; 0046 } 0047 0048 auto *job = KIO::fileSystemFreeSpace(QUrl::fromLocalFile(m_path)); 0049 connect(job, &KJob::result, this, [this, job]() { 0050 if (job->error()) { 0051 return; 0052 } 0053 0054 const int limit = FreeSpaceNotifierSettings::minimumSpace(); // MiB 0055 const qint64 avail = job->availableSize() / (1024 * 1024); // to MiB 0056 0057 if (avail >= limit) { 0058 if (m_notification) { 0059 m_notification->close(); 0060 } 0061 return; 0062 } 0063 0064 const int availPercent = int(100 * job->availableSize() / job->size()); 0065 const QString text = m_notificationText.subs(avail).subs(availPercent).toString(); 0066 0067 // Make sure the notification text is always up to date whenever we checked free space 0068 if (m_notification) { 0069 m_notification->setText(text); 0070 } 0071 0072 // User freed some space, warn if it goes low again 0073 if (m_lastAvail > -1 && avail > m_lastAvail) { 0074 m_lastAvail = avail; 0075 return; 0076 } 0077 0078 // Always warn the first time or when available space dropped to half of the previous time 0079 const bool warn = (m_lastAvail < 0 || avail < m_lastAvail / 2); 0080 if (!warn) { 0081 return; 0082 } 0083 0084 m_lastAvail = avail; 0085 0086 if (!m_notification) { 0087 m_notification = new KNotification(QStringLiteral("freespacenotif")); 0088 m_notification->setComponentName(QStringLiteral("freespacenotifier")); 0089 m_notification->setText(text); 0090 0091 auto filelight = filelightService(); 0092 if (filelight) { 0093 auto filelightAction = m_notification->addAction(i18n("Open in Filelight")); 0094 connect(filelightAction, &KNotificationAction::activated, this, [this] { 0095 exploreDrive(); 0096 }); 0097 } else { 0098 // Do we really want the user opening Root in a file manager? 0099 auto fileManagerAction = m_notification->addAction(i18n("Open in File Manager")); 0100 connect(fileManagerAction, &KNotificationAction::activated, this, [this] { 0101 exploreDrive(); 0102 }); 0103 } 0104 0105 // TODO once we have "configure" action support in KNotification, wire it up instead of a button 0106 auto configureAction = m_notification->addAction(i18n("Configure Warning…")); 0107 connect(configureAction, &KNotificationAction::activated, this, [this] { 0108 Q_EMIT configureRequested(); 0109 }); 0110 0111 connect(m_notification, &KNotification::closed, this, &FreeSpaceNotifier::onNotificationClosed); 0112 m_notification->sendEvent(); 0113 } 0114 }); 0115 } 0116 0117 KService::Ptr FreeSpaceNotifier::filelightService() const 0118 { 0119 return KService::serviceByDesktopName(QStringLiteral("org.kde.filelight")); 0120 } 0121 0122 void FreeSpaceNotifier::exploreDrive() 0123 { 0124 auto service = filelightService(); 0125 if (!service) { 0126 auto *job = new KIO::OpenUrlJob({QUrl::fromLocalFile(m_path)}); 0127 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0128 job->start(); 0129 return; 0130 } 0131 0132 auto *job = new KIO::ApplicationLauncherJob(service); 0133 job->setUrls({QUrl::fromLocalFile(m_path)}); 0134 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0135 job->start(); 0136 } 0137 0138 void FreeSpaceNotifier::onNotificationClosed() 0139 { 0140 // warn again if constantly below limit for too long 0141 if (!m_lastAvailTimer) { 0142 m_lastAvailTimer = new QTimer(this); 0143 connect(m_lastAvailTimer, &QTimer::timeout, this, &FreeSpaceNotifier::resetLastAvailable); 0144 } 0145 m_lastAvailTimer->start(std::chrono::hours(1)); 0146 } 0147 0148 void FreeSpaceNotifier::resetLastAvailable() 0149 { 0150 m_lastAvail = -1; 0151 m_lastAvailTimer->deleteLater(); 0152 m_lastAvailTimer = nullptr; 0153 }