File indexing completed on 2024-04-14 05:39:37
0001 // SPDX-License-Identifier: GPL-3.0-or-later 0002 /* 0003 Copyright 2017,2019 Martin Koller, kollix@aon.at 0004 0005 This file is part of liquidshell. 0006 0007 liquidshell is free software: you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation, either version 3 of the License, or 0010 (at your option) any later version. 0011 0012 liquidshell is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with liquidshell. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include <PkUpdates.hxx> 0022 #include <PkUpdateList.hxx> 0023 0024 #include <QIcon> 0025 #include <QDateTime> 0026 #include <QPainter> 0027 #include <QDebug> 0028 0029 #include <KLocalizedString> 0030 #include <KIconLoader> 0031 #include <KConfig> 0032 #include <KConfigGroup> 0033 0034 //-------------------------------------------------------------------------------- 0035 0036 PkUpdates::PkUpdates(QWidget *parent) 0037 : SysTrayItem(parent) 0038 { 0039 KConfig config; 0040 KConfigGroup group = config.group("SoftwareUpdates"); 0041 if ( !group.hasKey("enabled") ) // create config entry so that one knows it exists 0042 group.writeEntry("enabled", true); 0043 0044 bool isEnabled = group.readEntry("enabled", true); 0045 0046 if ( !isEnabled ) 0047 { 0048 hide(); 0049 return; 0050 } 0051 0052 setPixmap(currentPixmap = QIcon::fromTheme("system-software-update").pixmap(size())); 0053 connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, [this]() { createToolTip(); }); 0054 0055 // check every hour if the next checkpoint was reached. This ensures that 0056 // we check for updates even when the computer was suspended for a while 0057 // and therefore a normal QTimer timeout for 1 day will not be reached in 1 day 0058 // TODO check again. start() was missing 0059 updateTimer.setInterval(3600 * 1000); 0060 updateTimer.start(); 0061 connect(&updateTimer, &QTimer::timeout, this, &PkUpdates::checkForUpdatesReached); 0062 0063 QString nextCheck = QDateTime::currentDateTime() 0064 .addMSecs(updateTimer.interval()) 0065 .toString(Qt::SystemLocaleShortDate); 0066 setToolTip(i18n("Next check: %1", nextCheck)); 0067 0068 //QTimer::singleShot(0, this, &PkUpdates::checkForUpdatesReached); 0069 } 0070 0071 //-------------------------------------------------------------------------------- 0072 0073 void PkUpdates::checkForUpdatesReached() 0074 { 0075 if ( updateList && updateList->isInstallInProgress() ) 0076 return; 0077 0078 QDateTime current = QDateTime::currentDateTime(); 0079 0080 if ( !nextCheck.isValid() || (current >= nextCheck) ) 0081 { 0082 checkForUpdates(); 0083 nextCheck = current.addDays(1); 0084 } 0085 } 0086 0087 //-------------------------------------------------------------------------------- 0088 0089 void PkUpdates::checkForUpdates() 0090 { 0091 setPixmap(currentPixmap = QIcon::fromTheme("system-software-update").pixmap(size())); 0092 setToolTip(i18n("Checking for updates ...")); 0093 0094 packages.clear(); 0095 setRefreshProgress(0); 0096 0097 PackageKit::Transaction *transaction = PackageKit::Daemon::refreshCache(true); 0098 0099 connect(transaction, &PackageKit::Transaction::errorCode, this, &PkUpdates::transactionError); 0100 connect(transaction, &PackageKit::Transaction::finished, this, &PkUpdates::refreshFinished); 0101 0102 connect(transaction, &PackageKit::Transaction::percentageChanged, this, 0103 [this, transaction]() 0104 { 0105 if ( (transaction->percentage() <= 100) && (transaction->status() != PackageKit::Transaction::StatusFinished) ) 0106 { 0107 setRefreshProgress(transaction->percentage() / 2); // first step: refresh cache, second: get updates 0108 setToolTip(i18n("Checking for updates ... %1%", refreshProgress)); 0109 } 0110 }); 0111 } 0112 0113 //-------------------------------------------------------------------------------- 0114 0115 void PkUpdates::refreshFinished(PackageKit::Transaction::Exit status, uint runtime) 0116 { 0117 Q_UNUSED(runtime) 0118 Q_UNUSED(status) 0119 0120 // don't stop on exit error; it could e.g. only be an error on one of the repos 0121 //if ( status != PackageKit::Transaction::ExitSuccess ) 0122 //return; 0123 0124 ///////////////// 0125 // hmm ... does that do anything on openSuse ? seems not implemented there 0126 /* 0127 { 0128 PackageKit::Transaction *transaction = PackageKit::Daemon::getDistroUpgrades(); 0129 0130 connect(transaction, &PackageKit::Transaction::errorCode, this, &PkUpdates::transactionError); 0131 0132 connect(transaction, &PackageKit::Transaction::distroUpgrade, this, 0133 [this](PackageKit::Transaction::DistroUpgrade type, const QString &name, const QString &description) 0134 { 0135 qDebug() << "distroUpgrade" << type << name << description; 0136 }); 0137 } 0138 */ 0139 ///////////////// 0140 0141 PackageKit::Transaction *transaction = PackageKit::Daemon::getUpdates(); 0142 0143 connect(transaction, &PackageKit::Transaction::package, this, &PkUpdates::package); 0144 connect(transaction, &PackageKit::Transaction::errorCode, this, &PkUpdates::transactionError); 0145 0146 connect(transaction, &PackageKit::Transaction::finished, this, 0147 [this]() 0148 { 0149 if ( updateList ) 0150 updateList->setPackages(packages); 0151 0152 setRefreshProgress(100); 0153 createToolTip(true); 0154 }); 0155 0156 connect(transaction, &PackageKit::Transaction::percentageChanged, this, 0157 [this, transaction]() 0158 { 0159 if ( (transaction->percentage() <= 100) && (transaction->status() != PackageKit::Transaction::StatusFinished) ) 0160 { 0161 setRefreshProgress(50 + (transaction->percentage() / 2)); // second step in checking for updates 0162 setToolTip(i18n("Checking for updates ... %1%", refreshProgress)); 0163 } 0164 }); 0165 } 0166 0167 //-------------------------------------------------------------------------------- 0168 0169 void PkUpdates::package(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary) 0170 { 0171 PackageData pkg; 0172 pkg.id = packageID; 0173 pkg.summary = summary; 0174 0175 packages.insert(info, pkg); 0176 } 0177 0178 //-------------------------------------------------------------------------------- 0179 0180 void PkUpdates::transactionError(PackageKit::Transaction::Error error, const QString &details) 0181 { 0182 Q_UNUSED(error) 0183 0184 setToolTip(i18n("Last check: %1\nError on checking for updates: %2", 0185 QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate), details)); 0186 0187 KNotification::event("update error", i18n("Software Update Error"), details, 0188 QIcon::fromTheme("dialog-error").pixmap(32), this); 0189 0190 setRefreshProgress(100); 0191 } 0192 0193 //-------------------------------------------------------------------------------- 0194 0195 void PkUpdates::createToolTip(bool notify) 0196 { 0197 PackageKit::Transaction::Info info = PackageKit::Transaction::InfoUnknown; 0198 QString tooltip; 0199 0200 int count = 0; 0201 QList<PackageData> list = packages.values(PackageKit::Transaction::InfoSecurity); 0202 0203 if ( list.count() ) 0204 { 0205 info = PackageKit::Transaction::InfoSecurity; 0206 0207 count += list.count(); 0208 tooltip += i18np("%1 <b>security</b> update available", "%1 <b>security</b> updates available", list.count()); 0209 addItems(tooltip, list); 0210 } 0211 0212 list = packages.values(PackageKit::Transaction::InfoImportant); 0213 0214 if ( list.count() ) 0215 { 0216 if ( info == PackageKit::Transaction::InfoUnknown ) 0217 info = PackageKit::Transaction::InfoImportant; 0218 0219 count += list.count(); 0220 tooltip += i18np("%1 <i>important</i> update available", "%1 <i>important</i> updates available", list.count()); 0221 addItems(tooltip, list); 0222 } 0223 0224 list = packages.values(PackageKit::Transaction::InfoBugfix); 0225 0226 if ( list.count() ) 0227 { 0228 if ( info == PackageKit::Transaction::InfoUnknown ) 0229 info = PackageKit::Transaction::InfoBugfix; 0230 0231 count += list.count(); 0232 tooltip += i18np("%1 bugfix update available", "%1 bugfix updates available", list.count()); 0233 addItems(tooltip, list); 0234 } 0235 0236 int others = packages.count() - count; 0237 0238 if ( tooltip.isEmpty() ) 0239 { 0240 if ( others ) 0241 { 0242 setToolTip(i18np("Last check: %1\nNo important updates available\n%2 other", 0243 "Last check: %1\nNo important updates available\n%2 others", 0244 QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate), others)); 0245 0246 if ( QIcon::hasThemeIcon("software-update-available") ) 0247 setPixmap(currentPixmap = QIcon::fromTheme("software-update-available").pixmap(size())); 0248 else 0249 setPixmap(currentPixmap = QIcon::fromTheme("update-low").pixmap(size())); 0250 } 0251 else 0252 { 0253 setToolTip(i18n("Last check: %1\nNo updates available", 0254 QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate))); 0255 0256 setPixmap(currentPixmap = QIcon::fromTheme("update-none").pixmap(size())); 0257 } 0258 } 0259 else 0260 { 0261 if ( others ) 0262 tooltip += i18np("<br>%1 other", "<br>%1 others", others); 0263 0264 tooltip = i18n("<html>Last check: %1<br>%2</html>", 0265 QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate), tooltip); 0266 setToolTip(tooltip); 0267 0268 QString icon; 0269 switch ( info ) 0270 { 0271 case PackageKit::Transaction::InfoSecurity: 0272 { 0273 if ( QIcon::hasThemeIcon("software-update-urgent") ) 0274 icon = "software-update-urgent"; 0275 else 0276 icon = "update-high"; 0277 break; 0278 } 0279 case PackageKit::Transaction::InfoImportant: 0280 { 0281 if ( QIcon::hasThemeIcon("software-update-urgent") ) 0282 icon = "software-update-urgent"; 0283 else 0284 icon = "update-medium"; 0285 break; 0286 } 0287 default: // PackageKit::Transaction::InfoBugfix: // and others 0288 { 0289 if ( QIcon::hasThemeIcon("software-update-available") ) 0290 icon = "software-update-available"; 0291 else 0292 icon = "update-low"; 0293 break; 0294 } 0295 } 0296 setPixmap(currentPixmap = QIcon::fromTheme(icon).pixmap(size())); 0297 0298 if ( notify ) 0299 { 0300 if ( notification ) 0301 notification->close(); // close previous notification if it's still here 0302 0303 notification = KNotification::event("updates available", i18n("Software Updates Available"), tooltip, 0304 QIcon::fromTheme(icon).pixmap(32), this); 0305 } 0306 } 0307 } 0308 0309 //-------------------------------------------------------------------------------- 0310 0311 void PkUpdates::addItems(QString &tooltip, const QList<PackageData> &list) const 0312 { 0313 tooltip += "<ul>"; 0314 0315 int count = std::min(3, list.count()); 0316 if ( list.count() == 4 ) // if there's just one more, show it directly instead of "1 more" 0317 count++; 0318 0319 for (int i = 0; i < count; i++) 0320 tooltip += "<li>" + list[i].summary + "</li>"; 0321 0322 if ( list.count() > 4 ) 0323 tooltip += i18n("<li>%1 more ...</li>", list.count() - count); 0324 0325 tooltip += "</ul>"; 0326 } 0327 0328 //-------------------------------------------------------------------------------- 0329 0330 QWidget *PkUpdates::getDetailsList() 0331 { 0332 if ( !updateList ) 0333 { 0334 updateList = new PkUpdateList(this); 0335 updateList->setPackages(packages); 0336 updateList->setRefreshProgress(refreshProgress); 0337 connect(updateList, &PkUpdateList::refreshRequested, this, &PkUpdates::checkForUpdates); 0338 connect(updateList, &PkUpdateList::packageInstalled, this, &PkUpdates::packageInstalled); 0339 connect(updateList, &PkUpdateList::packageCountToInstall, this, &PkUpdates::packageCountToInstallChanged); 0340 } 0341 0342 return updateList; 0343 } 0344 0345 //-------------------------------------------------------------------------------- 0346 0347 void PkUpdates::packageInstalled(const QString &id) 0348 { 0349 for (PackageList::iterator it = packages.begin(); it != packages.end(); ++it) 0350 { 0351 if ( (*it).id == id ) 0352 { 0353 packages.erase(it); 0354 break; 0355 } 0356 } 0357 createToolTip(); 0358 } 0359 0360 //-------------------------------------------------------------------------------- 0361 0362 void PkUpdates::setRefreshProgress(int progress) 0363 { 0364 refreshProgress = progress; 0365 0366 if ( updateList ) 0367 updateList->setRefreshProgress(refreshProgress); 0368 } 0369 0370 //-------------------------------------------------------------------------------- 0371 0372 void PkUpdates::packageCountToInstallChanged(int num) 0373 { 0374 if ( num == 0 ) 0375 { 0376 setPixmap(currentPixmap); 0377 return; 0378 } 0379 0380 QPixmap pix = currentPixmap; 0381 QPainter painter(&pix); 0382 QFont f = font(); 0383 f.setPixelSize(contentsRect().width() / 2); 0384 f.setBold(true); 0385 painter.setFont(f); 0386 0387 painter.drawText(contentsRect(), Qt::AlignCenter, QString::number(num)); 0388 painter.end(); 0389 0390 setPixmap(pix); 0391 } 0392 0393 //--------------------------------------------------------------------------------