File indexing completed on 2024-03-24 05:47:52
0001 /*************************************************************************** 0002 * Copyright (C) 2009-2018 by Daniel Nicoletti * 0003 * dantti12@gmail.com * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; see the file COPYING. If not, write to * 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0018 * Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "UpdateDetails.h" 0022 0023 #include <Daemon> 0024 #include <PkStrings.h> 0025 0026 #include <KMessageBox> 0027 #include <KPixmapSequence> 0028 #include <KLocalizedString> 0029 #include <KFormat> 0030 0031 #include <QAbstractAnimation> 0032 #include <QGraphicsOpacityEffect> 0033 #include <QStringBuilder> 0034 #include <KIconLoader> 0035 0036 #include <Transaction> 0037 0038 #include <QLoggingCategory> 0039 0040 #define FINAL_HEIGHT 160 0041 0042 Q_DECLARE_LOGGING_CATEGORY(APPER) 0043 0044 UpdateDetails::UpdateDetails(QWidget *parent) 0045 : QWidget(parent) 0046 { 0047 setupUi(this); 0048 hideTB->setIcon(QIcon::fromTheme(QLatin1String("window-close"))); 0049 connect(hideTB, &QToolButton::clicked, this, &UpdateDetails::hide); 0050 0051 m_busySeq = new KPixmapSequenceOverlayPainter(this); 0052 m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("process-working"), KIconLoader::SizeSmallMedium)); 0053 m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 0054 m_busySeq->setWidget(this); 0055 0056 QWidget *actionsViewport = descriptionKTB->viewport(); 0057 QPalette palette = actionsViewport->palette(); 0058 palette.setColor(actionsViewport->backgroundRole(), Qt::transparent); 0059 palette.setColor(actionsViewport->foregroundRole(), palette.color(QPalette::WindowText)); 0060 actionsViewport->setPalette(palette); 0061 0062 auto effect = new QGraphicsOpacityEffect(descriptionKTB); 0063 effect->setOpacity(0); 0064 descriptionKTB->setGraphicsEffect(effect); 0065 m_fadeDetails = new QPropertyAnimation(effect, "opacity", this); 0066 m_fadeDetails->setDuration(500); 0067 m_fadeDetails->setStartValue(qreal(0)); 0068 m_fadeDetails->setEndValue(qreal(1)); 0069 connect(m_fadeDetails, &QPropertyAnimation::finished, this, &UpdateDetails::display); 0070 0071 0072 auto anim1 = new QPropertyAnimation(this, "maximumSize", this); 0073 anim1->setDuration(500); 0074 anim1->setEasingCurve(QEasingCurve::OutQuart); 0075 anim1->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); 0076 anim1->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); 0077 auto anim2 = new QPropertyAnimation(this, "minimumSize", this); 0078 anim2->setDuration(500); 0079 anim2->setEasingCurve(QEasingCurve::OutQuart); 0080 anim2->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); 0081 anim2->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); 0082 0083 m_expandPanel = new QParallelAnimationGroup(this); 0084 m_expandPanel->addAnimation(anim1); 0085 m_expandPanel->addAnimation(anim2); 0086 connect(m_expandPanel, &QParallelAnimationGroup::finished, this, &UpdateDetails::display); 0087 0088 } 0089 0090 UpdateDetails::~UpdateDetails() 0091 { 0092 } 0093 0094 void UpdateDetails::setPackage(const QString &packageId, Transaction::Info updateInfo) 0095 { 0096 if (m_packageId == packageId) { 0097 return; 0098 } 0099 m_show = true; 0100 m_packageId = packageId; 0101 m_updateInfo = updateInfo; 0102 m_currentDescription.clear(); 0103 if (m_transaction) { 0104 disconnect(m_transaction, &Transaction::updateDetail, this, &UpdateDetails::updateDetail); 0105 disconnect(m_transaction, &Transaction::finished, this, &UpdateDetails::display); 0106 } 0107 0108 m_transaction = Daemon::getUpdateDetail(m_packageId); 0109 connect(m_transaction, &Transaction::updateDetail, this, &UpdateDetails::updateDetail); 0110 connect(m_transaction, &Transaction::finished, this, &UpdateDetails::display); 0111 0112 if (maximumSize().height() == 0) { 0113 // Expand the panel 0114 m_expandPanel->setDirection(QAbstractAnimation::Forward); 0115 m_expandPanel->start(); 0116 } else if (m_fadeDetails->currentValue().toReal() != 0) { 0117 // Hide the old description 0118 m_fadeDetails->setDirection(QAbstractAnimation::Backward); 0119 m_fadeDetails->start(); 0120 } 0121 m_busySeq->start(); 0122 } 0123 0124 void UpdateDetails::hide() 0125 { 0126 m_show = false; 0127 m_packageId.clear(); 0128 if (maximumSize().height() == FINAL_HEIGHT && 0129 m_fadeDetails->currentValue().toReal() == 1) { 0130 m_fadeDetails->setDirection(QAbstractAnimation::Backward); 0131 m_fadeDetails->start(); 0132 } else if (maximumSize().height() == FINAL_HEIGHT && 0133 m_fadeDetails->currentValue().toReal() == 0) { 0134 m_expandPanel->setDirection(QAbstractAnimation::Backward); 0135 m_expandPanel->start(); 0136 } 0137 } 0138 0139 void UpdateDetails::display() 0140 { 0141 qCDebug(APPER) << sender(); 0142 0143 // set transaction to 0 as if PK crashes 0144 // UpdateDetails won't be emmited 0145 m_transaction = nullptr; 0146 0147 if (!m_show) { 0148 hide(); 0149 return; 0150 } 0151 0152 if (maximumSize().height() == FINAL_HEIGHT && 0153 !m_currentDescription.isEmpty() && 0154 m_fadeDetails->currentValue().toReal() == 0) { 0155 descriptionKTB->setHtml(m_currentDescription); 0156 0157 m_fadeDetails->setDirection(QAbstractAnimation::Forward); 0158 m_fadeDetails->start(); 0159 } else if (m_currentDescription.isEmpty()) { 0160 updateDetailFinished(); 0161 } 0162 } 0163 0164 void UpdateDetails::updateDetail(const QString &packageID, 0165 const QStringList &updates, 0166 const QStringList &obsoletes, 0167 const QStringList &vendorUrls, 0168 const QStringList &bugzillaUrls, 0169 const QStringList &cveUrls, 0170 PackageKit::Transaction::Restart restart, 0171 const QString &updateText, 0172 const QString &changelog, 0173 PackageKit::Transaction::UpdateState state, 0174 const QDateTime &issued, 0175 const QDateTime &updated) 0176 { 0177 //format and show description 0178 QString description; 0179 0180 // update type (ie Security Update) 0181 if (m_updateInfo == Transaction::InfoEnhancement) { 0182 description += QLatin1String("<p>") + 0183 i18n("This update will add new features and expand functionality.") + 0184 QLatin1String("</p>"); 0185 } else if (m_updateInfo == Transaction::InfoBugfix) { 0186 description += QLatin1String("<p>") + 0187 i18n("This update will fix bugs and other non-critical problems.") + 0188 QLatin1String("</p>"); 0189 } else if (m_updateInfo == Transaction::InfoImportant) { 0190 description += QLatin1String("<p>") + 0191 i18n("This update is important as it may solve critical problems.") + 0192 QLatin1String("</p>"); 0193 } else if (m_updateInfo == Transaction::InfoSecurity) { 0194 description += QLatin1String("<p>") + 0195 i18n("This update is needed to fix a security vulnerability with this package.") + 0196 QLatin1String("</p>"); 0197 } else if (m_updateInfo == Transaction::InfoBlocked) { 0198 description += QLatin1String("<p>") + 0199 i18n("This update is blocked.") + 0200 QLatin1String("</p>"); 0201 } 0202 0203 // Issued and Updated 0204 if (!issued.isNull() && !updated.isNull()) { 0205 description += QLatin1String("<p>") + 0206 i18n("This notification was issued on %1 and last updated on %2.", 0207 QLocale::system().toString(issued, QLocale::ShortFormat), 0208 QLocale::system().toString(updated, QLocale::ShortFormat)) + 0209 QLatin1String("</p>"); 0210 } else if (!issued.isNull()) { 0211 description += QLatin1String("<p>") + 0212 i18n("This notification was issued on %1.", 0213 QLocale::system().toString(issued, QLocale::ShortFormat)) + 0214 QLatin1String("</p>"); 0215 } 0216 0217 // Description 0218 if (!updateText.isEmpty()) { 0219 QString _updateText = updateText; 0220 _updateText.replace(QLatin1Char('\n'), QLatin1String("<br/>")); 0221 _updateText.replace(QLatin1Char(' '), QLatin1String(" ")); 0222 description += QLatin1String("<p>") + _updateText + QLatin1String("</p>"); 0223 } 0224 0225 // links 0226 // Vendor 0227 if (!vendorUrls.isEmpty()) { 0228 description += QLatin1String("<p>") + 0229 i18np("For more information about this update please visit this website:", 0230 "For more information about this update please visit these websites:", 0231 vendorUrls.size()) + QLatin1String("<br/>") + 0232 getLinkList(vendorUrls) + 0233 QLatin1String("</p>"); 0234 } 0235 0236 // Bugzilla 0237 if (!bugzillaUrls.isEmpty()) { 0238 description += QLatin1String("<p>") + 0239 i18np("For more information about bugs fixed by this update please visit this website:", 0240 "For more information about bugs fixed by this update please visit these websites:", 0241 bugzillaUrls.size()) + QLatin1String("<br>") + 0242 getLinkList(bugzillaUrls) + 0243 QLatin1String("</p>"); 0244 } 0245 0246 // CVE 0247 if (!cveUrls.isEmpty()) { 0248 description += QLatin1String("<p>") + 0249 i18np("For more information about this security update please visit this website:", 0250 "For more information about this security update please visit these websites:", 0251 cveUrls.size()) + QLatin1String("<br>") + 0252 getLinkList(cveUrls) + 0253 QLatin1String("</p>"); 0254 } 0255 0256 // Notice (about the need for a reboot) 0257 if (restart == Transaction::RestartSystem) { 0258 description += QLatin1String("<p>") + 0259 i18n("The computer will have to be restarted after the update for the changes to take effect.") + 0260 QLatin1String("</p>"); 0261 } else if (restart == Transaction::RestartSession) { 0262 description += QLatin1String("<p>") + 0263 i18n("You will need to log out and back in after the update for the changes to take effect.") + 0264 QLatin1String("</p>"); 0265 } 0266 0267 // State 0268 if (state == Transaction::UpdateStateUnstable) { 0269 description += QLatin1String("<p>") + 0270 i18n("The classification of this update is unstable which means it is not designed for production use.") + 0271 QLatin1String("</p>"); 0272 } else if (state == Transaction::UpdateStateTesting) { 0273 description += QLatin1String("<p>") + 0274 i18n("This is a test update, and is not designed for normal use. Please report any problems or regressions you encounter.") + 0275 QLatin1String("</p>"); 0276 } 0277 0278 // only show changelog if we didn't have any update text 0279 if (updateText.isEmpty() && !changelog.isEmpty()) { 0280 QString _changelog = changelog; 0281 _changelog.replace(QLatin1Char('\n'), QLatin1String("<br/>")); 0282 _changelog.replace(QLatin1Char(' '), QLatin1String(" ")); 0283 description += QLatin1String("<p>") + 0284 i18n("The developer logs will be shown as no description is available for this update:") + 0285 QLatin1String("<br>") + 0286 _changelog + 0287 QLatin1String("</p>"); 0288 } 0289 0290 // Updates (lists of packages that are updated) 0291 if (!updates.isEmpty()) { 0292 description += QLatin1String("<p>") + i18n("Updates:") + QLatin1String("<br>"); 0293 QStringList _updates; 0294 for (const QString &pid : updates) { 0295 _updates += QString::fromUtf8("\xE2\x80\xA2 ") + Transaction::packageName(pid) + QLatin1String(" - ") + Transaction::packageVersion(pid); 0296 } 0297 description += _updates.join(QLatin1String("<br>")) + QLatin1String("</p>"); 0298 } 0299 0300 // Obsoletes (lists of packages that are obsoleted) 0301 if (obsoletes.size()) { 0302 description += QLatin1String("<p></b>") + i18n("Obsoletes:") + QLatin1String("</b><br/>"); 0303 QStringList _obsoletes; 0304 for (const QString &pid : obsoletes) { 0305 _obsoletes += QString::fromUtf8("\xE2\x80\xA2 ") + Transaction::packageName(pid) + QLatin1String(" - ") + Transaction::packageVersion(pid); 0306 } 0307 description += _obsoletes.join(QLatin1String("<br>/")) + QLatin1String("</p>"); 0308 } 0309 0310 // Repository (this is the repository the package comes from) 0311 if (!Transaction::packageData(packageID).isEmpty()) { 0312 description += QLatin1String("<p>") + i18n("Repository: %1", Transaction::packageData(packageID)) + QLatin1String("</p>"); 0313 } 0314 0315 m_currentDescription = description; 0316 m_busySeq->stop(); 0317 } 0318 0319 QString UpdateDetails::getLinkList(const QStringList &urls) const 0320 { 0321 QString ret; 0322 for (const QString &url : urls) { 0323 if (!ret.isEmpty()) { 0324 ret += QLatin1String("<br>"); 0325 } 0326 ret += QString::fromUtf8(" \xE2\x80\xA2 <a href=\"") % url % QLatin1String("\">") % url % QLatin1String("</a>"); 0327 } 0328 return ret; 0329 } 0330 0331 void UpdateDetails::updateDetailFinished() 0332 { 0333 if (descriptionKTB->document()->toPlainText().isEmpty()) { 0334 descriptionKTB->setPlainText(i18n("No update description was found.")); 0335 } 0336 } 0337 0338 #include "moc_UpdateDetails.cpp"