File indexing completed on 2024-05-05 17:43:52
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, &KIO::FileSystemFreeSpaceJob::result, this, [this](KIO::Job *job, KIO::filesize_t size, KIO::filesize_t available) { 0050 if (job->error()) { 0051 return; 0052 } 0053 0054 const int limit = FreeSpaceNotifierSettings::minimumSpace(); // MiB 0055 const qint64 avail = available / (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 * available / 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 QStringList actions = {i18n("Configure Warning…")}; 0092 0093 auto filelight = filelightService(); 0094 if (filelight) { 0095 actions.prepend(i18n("Open in Filelight")); 0096 } else { 0097 // Do we really want the user opening Root in a file manager? 0098 actions.prepend(i18n("Open in File Manager")); 0099 } 0100 0101 m_notification->setActions(actions); 0102 0103 connect(m_notification, &KNotification::activated, this, [this](uint actionId) { 0104 if (actionId == 1) { 0105 exploreDrive(); 0106 // TODO once we have "configure" action support in KNotification, wire it up instead of a button 0107 } else if (actionId == 2) { 0108 Q_EMIT configureRequested(); 0109 } 0110 }); 0111 0112 connect(m_notification, &KNotification::closed, this, &FreeSpaceNotifier::onNotificationClosed); 0113 m_notification->sendEvent(); 0114 } 0115 }); 0116 } 0117 0118 KService::Ptr FreeSpaceNotifier::filelightService() const 0119 { 0120 return KService::serviceByDesktopName(QStringLiteral("org.kde.filelight")); 0121 } 0122 0123 void FreeSpaceNotifier::exploreDrive() 0124 { 0125 auto service = filelightService(); 0126 if (!service) { 0127 auto *job = new KIO::OpenUrlJob({QUrl::fromLocalFile(m_path)}); 0128 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0129 job->start(); 0130 return; 0131 } 0132 0133 auto *job = new KIO::ApplicationLauncherJob(service); 0134 job->setUrls({QUrl::fromLocalFile(m_path)}); 0135 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0136 job->start(); 0137 } 0138 0139 void FreeSpaceNotifier::onNotificationClosed() 0140 { 0141 // warn again if constantly below limit for too long 0142 if (!m_lastAvailTimer) { 0143 m_lastAvailTimer = new QTimer(this); 0144 connect(m_lastAvailTimer, &QTimer::timeout, this, &FreeSpaceNotifier::resetLastAvailable); 0145 } 0146 m_lastAvailTimer->start(std::chrono::hours(1)); 0147 } 0148 0149 void FreeSpaceNotifier::resetLastAvailable() 0150 { 0151 m_lastAvail = -1; 0152 m_lastAvailTimer->deleteLater(); 0153 m_lastAvailTimer = nullptr; 0154 }