File indexing completed on 2024-04-28 09:40:14

0001 /***************************************************************************
0002  *   Copyright (C) 2008-2011 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 "Updater.h"
0022 #include "ui_Updater.h"
0023 
0024 #include "UpdateDetails.h"
0025 #include "DistroUpgrade.h"
0026 #include "CheckableHeader.h"
0027 
0028 #include <QMenu>
0029 //#include <KGenericFactory>
0030 #include <KPixmapSequence>
0031 #include <KAboutData>
0032 #include <KIconLoader>
0033 #include <KConfigGroup>
0034 
0035 #include <ApplicationsDelegate.h>
0036 #include <PkStrings.h>
0037 #include <PkIcons.h>
0038 #include <PackageModel.h>
0039 #include <ApplicationSortFilterModel.h>
0040 
0041 #include <QDBusConnection>
0042 
0043 #include <KConfig>
0044 #include <KFormat>
0045 #include <KMessageBox>
0046 #include <QLoggingCategory>
0047 
0048 #include <Daemon>
0049 
0050 Q_DECLARE_LOGGING_CATEGORY(APPER)
0051 
0052 Updater::Updater(Transaction::Roles roles, QWidget *parent) :
0053     QWidget(parent),
0054     ui(new Ui::Updater),
0055     m_roles(roles)
0056 {
0057     ui->setupUi(this);
0058     updatePallete();
0059 //    connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
0060 //            this, SLOT(updatePallete()));
0061 
0062     m_updatesModel = new PackageModel(this);
0063     m_updatesModel->setCheckable(true);
0064     auto proxyModel = new ApplicationSortFilterModel(this);
0065     proxyModel->setSourceModel(m_updatesModel);
0066     ui->packageView->setModel(proxyModel);
0067 
0068     m_delegate = new ApplicationsDelegate(ui->packageView);
0069     m_delegate->setCheckable(true);
0070     ui->packageView->setItemDelegate(m_delegate);
0071     ui->packageView->sortByColumn(PackageModel::NameCol, Qt::AscendingOrder);
0072     connect(m_updatesModel, &PackageModel::changed, this, &Updater::checkEnableUpdateButton);
0073 
0074     //initialize the model, delegate, client and  connect it's signals
0075     m_header = new CheckableHeader(Qt::Horizontal, this);
0076     connect(m_header, &CheckableHeader::toggled, m_updatesModel, &PackageModel::setAllChecked);
0077     m_header->setCheckBoxVisible(false);
0078     m_header->setDefaultAlignment(Qt::AlignCenter);
0079     ui->packageView->setHeaderHidden(false);
0080     ui->packageView->setHeader(m_header);
0081 
0082     // This must be set AFTER the model is set, otherwise it doesn't work
0083     m_header->setSectionResizeMode(PackageModel::NameCol, QHeaderView::Stretch);
0084     m_header->setSectionResizeMode(PackageModel::VersionCol, QHeaderView::ResizeToContents);
0085     m_header->setSectionResizeMode(PackageModel::CurrentVersionCol, QHeaderView::ResizeToContents);
0086     m_header->setSectionResizeMode(PackageModel::ArchCol, QHeaderView::ResizeToContents);
0087     m_header->setSectionResizeMode(PackageModel::OriginCol, QHeaderView::ResizeToContents);
0088     m_header->setSectionResizeMode(PackageModel::SizeCol, QHeaderView::ResizeToContents);
0089     m_header->setStretchLastSection(false);
0090 
0091     // Setup the busy cursor
0092     m_busySeq = new KPixmapSequenceOverlayPainter(this);
0093     m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("process-working"), KIconLoader::SizeSmallMedium));
0094     m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
0095     m_busySeq->setWidget(ui->packageView->viewport());
0096 
0097     // hide distro Upgrade container and line
0098     ui->distroUpgrade->hide();
0099 
0100     KConfig config(QLatin1String("apper"));
0101     KConfigGroup viewGroup(&config, "UpdateView");
0102 
0103     // versions
0104     ui->packageView->header()->setSectionHidden(PackageModel::VersionCol, true);
0105     m_showPackageVersion = new QAction(i18n("Show Versions"), this);
0106     m_showPackageVersion->setCheckable(true);
0107     connect(m_showPackageVersion, &QAction::toggled, this, &Updater::showVersions);
0108     m_showPackageVersion->setChecked(viewGroup.readEntry("ShowVersions", true));
0109 
0110     // versions
0111     ui->packageView->header()->setSectionHidden(PackageModel::CurrentVersionCol, true);
0112     m_showPackageCurrentVersion = new QAction(i18n("Show Current Versions"), this);
0113     m_showPackageCurrentVersion->setCheckable(true);
0114     connect(m_showPackageCurrentVersion, &QAction::toggled, this, &Updater::showCurrentVersions);
0115     m_showPackageCurrentVersion->setChecked(viewGroup.readEntry("ShowCurrentVersions", false));
0116 
0117     // Arch
0118     ui->packageView->header()->setSectionHidden(PackageModel::ArchCol, true);
0119     m_showPackageArch = new QAction(i18n("Show Architectures"), this);
0120     m_showPackageArch->setCheckable(true);
0121     connect(m_showPackageArch, &QAction::toggled, this, &Updater::showArchs);
0122     m_showPackageArch->setChecked(viewGroup.readEntry("ShowArchs", false));
0123 
0124     // Origin
0125     ui->packageView->header()->setSectionHidden(PackageModel::OriginCol, true);
0126     m_showPackageOrigin = new QAction(i18n("Show Origins"), this);
0127     m_showPackageOrigin->setCheckable(true);
0128     connect(m_showPackageOrigin, &QAction::toggled, this, &Updater::showOrigins);
0129     m_showPackageOrigin->setChecked(viewGroup.readEntry("ShowOrigins", false));
0130 
0131     // Sizes
0132     ui->packageView->header()->setSectionHidden(PackageModel::SizeCol, true);
0133     m_showPackageSize = new QAction(i18n("Show Sizes"), this);
0134     m_showPackageSize->setCheckable(true);
0135     connect(m_showPackageSize, &QAction::toggled, this, &Updater::showSizes);
0136     m_showPackageSize->setChecked(viewGroup.readEntry("ShowSizes", true));
0137 }
0138 
0139 Updater::~Updater()
0140 {
0141     delete ui;
0142 }
0143 
0144 void Updater::showVersions(bool enabled)
0145 {
0146     KConfig config(QLatin1String("apper"));
0147     KConfigGroup viewGroup(&config, "UpdateView");
0148     viewGroup.writeEntry("ShowVersions", enabled);
0149     ui->packageView->header()->setSectionHidden(PackageModel::VersionCol, !enabled);
0150 }
0151 
0152 void Updater::showCurrentVersions(bool enabled)
0153 {
0154     KConfig config(QLatin1String("apper"));
0155     KConfigGroup viewGroup(&config, "UpdateView");
0156     viewGroup.writeEntry("ShowCurrentVersions", enabled);
0157     ui->packageView->header()->setSectionHidden(PackageModel::CurrentVersionCol, !enabled);
0158     if (enabled) {
0159         m_updatesModel->fetchCurrentVersions();
0160     }
0161 }
0162 
0163 void Updater::showArchs(bool enabled)
0164 {
0165     KConfig config(QLatin1String("apper"));
0166     KConfigGroup viewGroup(&config, "UpdateView");
0167     viewGroup.writeEntry("ShowArchs", enabled);
0168     ui->packageView->header()->setSectionHidden(PackageModel::ArchCol, !enabled);
0169 }
0170 
0171 void Updater::showOrigins(bool enabled)
0172 {
0173     KConfig config(QLatin1String("apper"));
0174     KConfigGroup viewGroup(&config, "UpdateView");
0175     viewGroup.writeEntry("showOrigins", enabled);
0176     ui->packageView->header()->setSectionHidden(PackageModel::OriginCol, !enabled);
0177 }
0178 
0179 void Updater::showSizes(bool enabled)
0180 {
0181     KConfig config(QLatin1String("apper"));
0182     KConfigGroup viewGroup(&config, "UpdateView");
0183     viewGroup.writeEntry("ShowSizes", enabled);
0184     ui->packageView->header()->setSectionHidden(PackageModel::SizeCol, !enabled);
0185     if (enabled) {
0186         m_updatesModel->fetchSizes();
0187     }
0188 }
0189 
0190 void Updater::updatePallete()
0191 {
0192     QPalette pal;
0193     pal.setColor(QPalette::Window, pal.base().color());
0194     pal.setColor(QPalette::WindowText, pal.text().color());
0195     ui->backgroundFrame->setPalette(pal);
0196 }
0197 
0198 void Updater::on_packageView_clicked(const QModelIndex &index)
0199 {
0200     QString pkgId = index.data(PackageModel::IdRole).toString();
0201     auto pkgInfo = index.data(PackageModel::InfoRole).value<Transaction::Info>();
0202     ui->updateDetails->setPackage(pkgId, pkgInfo);
0203 }
0204 
0205 //TODO: We should add some kind of configuration to let users show unstable distributions
0206 //That way, by default, users only see stable ones.
0207 void Updater::distroUpgrade(PackageKit::Transaction::DistroUpgrade type, const QString &name, const QString &description)
0208 {
0209     // TODO name should be used to do a upgrade to a different type
0210     Q_UNUSED(name)
0211     if (type != Transaction::DistroUpgradeStable) {
0212         // Ignore unstable distros upgrades for now
0213         return;
0214     }
0215 
0216     ui->distroUpgrade->setName(description);
0217     ui->distroUpgrade->animatedShow();
0218 }
0219 
0220 bool Updater::hasChanges() const
0221 {
0222     return m_updatesModel->hasChanges();
0223 }
0224 
0225 void Updater::checkEnableUpdateButton()
0226 {
0227     qCDebug(APPER) << "updates has changes" << hasChanges();
0228     emit changed(hasChanges());
0229     int selectedSize = m_updatesModel->selectedPackagesToInstall().size();
0230     int updatesSize = m_updatesModel->rowCount();
0231     if (selectedSize == 0) {
0232         m_header->setCheckState(Qt::Unchecked);
0233     } else if (selectedSize == updatesSize) {
0234         m_header->setCheckState(Qt::Checked);
0235     } else {
0236         m_header->setCheckState(Qt::PartiallyChecked);
0237     }
0238 
0239     unsigned long dwSize = m_updatesModel->downloadSize();
0240     if (dwSize) {
0241         emit downloadSize(i18n("Estimated download size: %1",
0242                                KFormat().formatByteSize(dwSize)));
0243     } else {
0244         emit downloadSize(QString());
0245     }
0246     // if we don't have any upates let's disable the button
0247     m_header->setCheckBoxVisible(m_updatesModel->rowCount() != 0);
0248     ui->packageView->setHeaderHidden(m_updatesModel->rowCount() == 0);
0249 }
0250 
0251 void Updater::load()
0252 {
0253     // set focus on the updates view
0254     ui->packageView->setFocus(Qt::OtherFocusReason);
0255     emit downloadSize(QString());
0256     // If the model already has some packages
0257     // let's just clear the selection
0258     if (m_updatesModel->rowCount()) {
0259         m_updatesModel->setAllChecked(false);
0260     } else {
0261         getUpdates();
0262     }
0263 }
0264 
0265 void Updater::getUpdatesFinished()
0266 {
0267     m_updatesT = nullptr;
0268     m_updatesModel->clearSelectedNotPresent();
0269     checkEnableUpdateButton();
0270     if (m_updatesModel->rowCount() == 0) {
0271         // Set the info page
0272         ui->stackedWidget->setCurrentIndex(1);
0273         uint lastTime = Daemon::global()->getTimeSinceAction(Transaction::RoleRefreshCache);
0274         ui->titleL->setText(PkStrings::lastCacheRefreshTitle(lastTime));
0275         ui->descriptionL->setText(PkStrings::lastCacheRefreshSubTitle(lastTime));
0276         ui->iconL->setPixmap(QIcon::fromTheme(PkIcons::lastCacheRefreshIconName(lastTime)).pixmap(128, 128));
0277     }
0278 }
0279 
0280 QStringList Updater::packagesToUpdate() const
0281 {
0282     return m_updatesModel->selectedPackagesToInstall();
0283 }
0284 
0285 void Updater::getUpdates()
0286 {
0287     if (m_updatesT) {
0288         // There is a getUpdates running ignore this call
0289         return;
0290     }
0291 
0292     if (ui->stackedWidget->currentIndex() != 0) {
0293         ui->stackedWidget->setCurrentIndex(0);
0294     }
0295 
0296     // clears the model
0297     ui->packageView->setHeaderHidden(true);
0298     m_updatesModel->clear();
0299     ui->updateDetails->hide();
0300     m_updatesT = Daemon::getUpdates();
0301     connect(m_updatesT, &Transaction::package, m_updatesModel, &PackageModel::addSelectedPackage);
0302     connect(m_updatesT, &Transaction::errorCode, this, &Updater::errorCode);
0303     connect(m_updatesT, &Transaction::finished, m_busySeq, &KPixmapSequenceOverlayPainter::stop);
0304     connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::finished);
0305 
0306     // This is required to estimate download size
0307     connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::fetchSizes);
0308 
0309     if (m_showPackageCurrentVersion->isChecked()) {
0310         connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::fetchCurrentVersions);
0311     }
0312     connect(m_updatesT, &Transaction::finished, this, &Updater::getUpdatesFinished);
0313     m_busySeq->start();
0314 
0315     // Hide the distribution upgrade information
0316     ui->distroUpgrade->animatedHide();
0317 
0318     if (m_roles & Transaction::RoleGetDistroUpgrades) {
0319         // Check for distribution Upgrades
0320         Transaction *t = Daemon::getDistroUpgrades();
0321         connect(m_updatesT, &Transaction::distroUpgrade, this, &Updater::distroUpgrade);
0322         connect(m_updatesT, &Transaction::finished, t, &Transaction::deleteLater);
0323     }
0324 }
0325 
0326 void Updater::on_packageView_customContextMenuRequested(const QPoint &pos)
0327 {
0328     auto menu = new QMenu(this);
0329     menu->addAction(m_showPackageVersion);
0330     menu->addAction(m_showPackageCurrentVersion);
0331     menu->addAction(m_showPackageArch);
0332     menu->addAction(m_showPackageOrigin);
0333     menu->addAction(m_showPackageSize);
0334     QAction *action;
0335     action = menu->addAction(i18n("Check for new updates"));
0336     action->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
0337     connect(action, &QAction::triggered, this, &Updater::refreshCache);
0338     menu->exec(ui->packageView->viewport()->mapToGlobal(pos));
0339     delete menu;
0340 }
0341 
0342 void Updater::errorCode(PackageKit::Transaction::Error error, const QString &details)
0343 {
0344     KMessageBox::detailedError(this,
0345                                PkStrings::errorMessage(error),
0346                                details,
0347                                PkStrings::error(error),
0348                                KMessageBox::Notify);
0349 }
0350 
0351 #include "moc_Updater.cpp"