diff --git a/ApperKCM/ApperKCM.cpp b/ApperKCM/ApperKCM.cpp index 695eb9c..295d7b8 100644 --- a/ApperKCM/ApperKCM.cpp +++ b/ApperKCM/ApperKCM.cpp @@ -1,946 +1,948 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "ApperKCM.h" #include "ui_ApperKCM.h" #include //#include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #ifdef HAVE_APPSTREAM #include #endif #include #include #include "FiltersMenu.h" #include "BrowseView.h" #include "CategoryModel.h" #include "TransactionHistory.h" #include "Settings/Settings.h" #include "Updater/Updater.h" Q_LOGGING_CATEGORY(APPER, "apper") #define BAR_SEARCH 0 #define BAR_UPDATE 1 #define BAR_SETTINGS 2 #define BAR_TITLE 3 //KCONFIGGROUP_DECLARE_ENUM_QOBJECT(Transaction, Filter) K_PLUGIN_FACTORY(ApperFactory, registerPlugin();) K_EXPORT_PLUGIN(ApperFactory("kcm_apper", "apper")) ApperKCM::ApperKCM(QWidget *parent, const QVariantList &args) : KCModule(parent, args), ui(new Ui::ApperKCM), m_currentAction(0), m_groupsProxyModel(0), m_settingsPage(0), m_updaterPage(0), m_searchTransaction(0), m_findIcon(QIcon::fromTheme("edit-find")), m_cancelIcon(QIcon::fromTheme("dialog-cancel")), m_forceRefreshCache(false), m_cacheAge(600), m_history(0), m_searchRole(Transaction::RoleUnknown) { KAboutData *aboutData; aboutData = new KAboutData("kcm_apper", "apper", APPER_VERSION, i18n("KDE interface for managing software"), KAboutLicense::LicenseKey::GPL); aboutData->addAuthor(i18n("(C) 2008-2013 Daniel Nicoletti"), QString(), "dantti12@gmail.com", "http://dantti.wordpress.com"); aboutData->addAuthor(i18n("Matthias Klumpp"), QString(), QStringLiteral("matthias@tenstral.net")); setAboutData(aboutData); setButtons(Apply); // store the actions supported by the backend connect(Daemon::global(), SIGNAL(changed()), this, SLOT(daemonChanged())); // Set the current locale //TODO FIXME // QString locale(KLocale::global()->language() % QLatin1Char('.') % KLocale::global()->encoding()); -// Daemon::global()->setHints(QLatin1String("locale=") % locale); + Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name()); + + qCDebug(APPER) << Q_FUNC_INFO << QLocale::system().name(); ui->setupUi(this); // Browse TAB ui->backTB->setIcon(QIcon::fromTheme("go-previous")); // create our toolbar QToolBar *toolBar = new QToolBar(this); ui->gridLayout_2->addWidget(toolBar); toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); connect(ui->browseView, SIGNAL(categoryActivated(QModelIndex)), this, SLOT(on_homeView_activated(QModelIndex))); QMenu *findMenu = new QMenu(this); // find is just a generic name in case we don't have any search method m_genericActionK = new KToolBarPopupAction(m_findIcon, i18n("Find"), this); toolBar->addAction(m_genericActionK); // Add actions that the backend supports findMenu->addAction(ui->actionFindName); setCurrentAction(ui->actionFindName); findMenu->addAction(ui->actionFindDescription); if (!m_currentAction) { setCurrentAction(ui->actionFindDescription); } findMenu->addAction(ui->actionFindFile); if (!m_currentAction) { setCurrentAction(ui->actionFindFile); } // If no action was set we can't use this search if (m_currentAction == 0) { m_genericActionK->setEnabled(false); ui->searchKLE->setEnabled(false); } else { // Check to see if we need the KToolBarPopupAction setCurrentActionCancel(false); if (findMenu->actions().size() > 1) { m_currentAction->setVisible(false); m_genericActionK->setMenu(findMenu); } else { m_currentAction->setVisible(true); toolBar->removeAction(m_genericActionK); toolBar->addAction(m_currentAction); } connect(m_genericActionK, SIGNAL(triggered()), this, SLOT(genericActionKTriggered())); } // Create the groups model m_groupsModel = new CategoryModel(this); ui->browseView->setCategoryModel(m_groupsModel); connect(m_groupsModel, SIGNAL(finished()), this, SLOT(setupHomeModel())); // ui->homeView->setSpacing(QDialog::spacingHint()); ui->homeView->viewport()->setAttribute(Qt::WA_Hover); KFileItemDelegate *delegate = new KFileItemDelegate(this); delegate->setWrapMode(QTextOption::WordWrap); ui->homeView->setItemDelegate(delegate); // install the backend filters ui->filtersTB->setMenu(m_filtersMenu = new FiltersMenu(this)); connect(m_filtersMenu, SIGNAL(filtersChanged()), this, SLOT(search())); ui->filtersTB->setIcon(QIcon::fromTheme("view-filter")); ApplicationSortFilterModel *proxy = ui->browseView->proxy(); proxy->setApplicationFilter(m_filtersMenu->filterApplications()); connect(m_filtersMenu, SIGNAL(filterApplications(bool)), proxy, SLOT(setApplicationFilter(bool))); //initialize the model, delegate, client and connect it's signals m_browseModel = ui->browseView->model(); // CHANGES TAB ui->changesView->viewport()->setAttribute(Qt::WA_Hover); m_changesModel = new PackageModel(this); KCategorizedSortFilterProxyModel *changedProxy = new KCategorizedSortFilterProxyModel(this); changedProxy->setSourceModel(m_changesModel); changedProxy->setDynamicSortFilter(true); changedProxy->setCategorizedModel(true); changedProxy->setSortCaseSensitivity(Qt::CaseInsensitive); changedProxy->setSortRole(PackageModel::SortRole); changedProxy->sort(0); ui->changesView->setModel(changedProxy); ChangesDelegate *changesDelegate = new ChangesDelegate(ui->changesView); changesDelegate->setExtendPixmapWidth(0); ui->changesView->setItemDelegate(changesDelegate); // Connect this signal to keep track of changes connect(m_browseModel, SIGNAL(changed(bool)), this, SLOT(checkChanged())); // packageUnchecked from changes model connect(m_changesModel, SIGNAL(packageUnchecked(QString)), m_changesModel, SLOT(removePackage(QString))); connect(m_changesModel, SIGNAL(packageUnchecked(QString)), m_browseModel, SLOT(uncheckPackage(QString))); ui->changesPB->setIcon(QIcon::fromTheme("edit-redo")); auto menu = new QMenu(this); ui->settingsTB->setMenu(menu); ui->settingsTB->setIcon(QIcon::fromTheme("preferences-other")); auto signalMapper = new QSignalMapper(this); QAction *action; action = menu->addAction(QIcon::fromTheme("view-history"), i18n("History")); signalMapper->setMapping(action, "history"); connect(action, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(setPage(QString))); action = menu->addAction(QIcon::fromTheme("preferences-other"), i18n("Settings")); signalMapper->setMapping(action, "settings"); connect(action, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(setPage(QString))); // Only show help menu if not on System Settings if (!args.isEmpty()) { // adds the help menu //! KHelpMenu *helpMenu = new KHelpMenu(this, KGlobal::mainComponent().aboutData()); //! menu->addMenu(helpMenu->menu()); } // Make sure the search bar is visible ui->stackedWidgetBar->setCurrentIndex(BAR_SEARCH); } void ApperKCM::setupHomeModel() { KCategorizedSortFilterProxyModel *oldProxy = m_groupsProxyModel; m_groupsProxyModel = new KCategorizedSortFilterProxyModel(this); m_groupsProxyModel->setSourceModel(m_groupsModel); m_groupsProxyModel->setCategorizedModel(true); m_groupsProxyModel->sort(0); ui->homeView->setModel(m_groupsProxyModel); if (oldProxy) { oldProxy->deleteLater(); } } void ApperKCM::genericActionKTriggered() { m_currentAction->trigger(); } void ApperKCM::setCurrentAction(QAction *action) { // just load the new action if it changes this // also ensures that our menu has more than one action if (m_currentAction != action) { // hides the item from the list action->setVisible(false); // ensures the current action was created if (m_currentAction) { // show the item back in the list m_currentAction->setVisible(true); } m_currentAction = action; // copy data from the curront action m_genericActionK->setText(m_currentAction->text()); m_genericActionK->setIcon(m_currentAction->icon()); } } void ApperKCM::setCurrentActionEnabled(bool state) { if (m_currentAction) { m_currentAction->setEnabled(state); } m_genericActionK->setEnabled(state); } void ApperKCM::setCurrentActionCancel(bool cancel) { if (cancel) { // every action should like cancel ui->actionFindName->setText(i18n("&Cancel")); ui->actionFindFile->setText(i18n("&Cancel")); ui->actionFindDescription->setText(i18n("&Cancel")); m_genericActionK->setText(i18n("&Cancel")); // set cancel icons ui->actionFindFile->setIcon(m_cancelIcon); ui->actionFindDescription->setIcon(m_cancelIcon); ui->actionFindName->setIcon(m_cancelIcon); m_genericActionK->setIcon(m_cancelIcon); } else { ui->actionFindName->setText(i18n("Find by &name")); ui->actionFindFile->setText(i18n("Find by f&ile name")); ui->actionFindDescription->setText(i18n("Find by &description")); // Define actions icon ui->actionFindFile->setIcon(QIcon::fromTheme("document-open")); ui->actionFindDescription->setIcon(QIcon::fromTheme("document-edit")); ui->actionFindName->setIcon(m_findIcon); m_genericActionK->setIcon(m_findIcon); if (m_currentAction) { m_genericActionK->setText(m_currentAction->text()); } else { // This might happen when the backend can // only search groups m_genericActionK->setText(i18n("Find")); } } } void ApperKCM::checkChanged() { bool hasChanges = false; if (ui->stackedWidget->currentWidget() == ui->pageHome || ui->stackedWidget->currentWidget() == ui->pageChanges || ui->stackedWidget->currentWidget() == ui->pageBrowse) { hasChanges = m_browseModel->hasChanges(); if (!hasChanges && ui->stackedWidget->currentWidget() == ui->pageChanges) { search(); } ui->changesPB->setEnabled(hasChanges); } else if (ui->stackedWidget->currentWidget() == m_updaterPage) { hasChanges = m_updaterPage->hasChanges(); } else if (ui->stackedWidget->currentWidget() == m_settingsPage) { hasChanges = m_settingsPage->hasChanges(); } emit changed(hasChanges); } void ApperKCM::errorCode(PackageKit::Transaction::Error error, const QString &details) { if (error != Transaction::ErrorTransactionCancelled) { KMessageBox::detailedSorry(this, PkStrings::errorMessage(error), details, PkStrings::error(error), KMessageBox::Notify); } } ApperKCM::~ApperKCM() { delete ui; } void ApperKCM::daemonChanged() { Transaction::Roles roles = Daemon::roles(); if (m_roles == roles) { return; } m_roles = roles; // Add actions that the backend supports ui->actionFindName->setEnabled(roles & Transaction::RoleSearchName); ui->actionFindDescription->setEnabled(roles & Transaction::RoleSearchDetails); ui->actionFindFile->setEnabled(roles & Transaction::RoleSearchFile); ui->browseView->init(roles); m_groupsModel->setRoles(roles); m_filtersMenu->setFilters(Daemon::filters()); } void ApperKCM::on_actionFindName_triggered() { setCurrentAction(ui->actionFindName); if (!ui->searchKLE->text().isEmpty()) { // cache the search m_searchRole = Transaction::RoleSearchName; m_searchString = ui->searchKLE->text(); // create the main transaction search(); } } void ApperKCM::on_actionFindDescription_triggered() { setCurrentAction(ui->actionFindDescription); if (!ui->searchKLE->text().isEmpty()) { // cache the search m_searchRole = Transaction::RoleSearchDetails; m_searchString = ui->searchKLE->text(); // create the main transaction search(); } } void ApperKCM::on_actionFindFile_triggered() { setCurrentAction(ui->actionFindFile); if (!ui->searchKLE->text().isEmpty()) { // cache the search m_searchRole = Transaction::RoleSearchFile; m_searchString = ui->searchKLE->text(); // create the main transaction search(); } } void ApperKCM::on_homeView_activated(const QModelIndex &index) { if (index.isValid()) { const QSortFilterProxyModel *proxy; proxy = qobject_cast(index.model()); // If the cast failed it's the index came from browseView if (proxy) { m_searchParentCategory = proxy->mapToSource(index); } else { m_searchParentCategory = index; } // cache the search m_searchRole = static_cast(index.data(CategoryModel::SearchRole).toUInt()); qCDebug(APPER) << m_searchRole << index.data(CategoryModel::CategoryRole).toString(); if (m_searchRole == Transaction::RoleResolve) { #ifdef HAVE_APPSTREAM CategoryMatcher parser = index.data(CategoryModel::CategoryRole).value(); m_searchCategory = AppStream::instance()->findPkgNames(parser); #endif // HAVE_APPSTREAM } else if (m_searchRole == Transaction::RoleSearchGroup) { if (index.data(CategoryModel::GroupRole).type() == QVariant::String) { QString category = index.data(CategoryModel::GroupRole).toString(); if (category.startsWith('@') || (category.startsWith(QLatin1String("repo:")) && category.size() > 5)) { m_searchGroupCategory = category; } else { m_groupsModel->setRootIndex(m_searchParentCategory); ui->backTB->setEnabled(true); return; } } else { m_searchGroupCategory.clear(); int groupRole = index.data(CategoryModel::GroupRole).toInt(); m_searchGroup = static_cast(groupRole); m_searchString = index.data().toString(); // Store the nice name to change the title } } else if (m_searchRole == Transaction::RoleGetUpdates) { setPage("updates"); return; } // create the main transaction search(); } } bool ApperKCM::canChangePage() { bool changed; // Check if we can change the current page if (ui->stackedWidget->currentWidget() == m_updaterPage) { changed = m_updaterPage->hasChanges(); } else if (ui->stackedWidget->currentWidget() == m_settingsPage) { changed = m_settingsPage->hasChanges(); } else { changed = m_browseModel->hasChanges(); } // if there are no changes don't ask the user if (!changed) { return true; } const int queryUser = KMessageBox::warningYesNoCancel( this, i18n("The settings of the current module have changed.\n" "Do you want to apply the changes or discard them?"), i18n("Apply Settings"), KStandardGuiItem::apply(), KStandardGuiItem::discard(), KStandardGuiItem::cancel()); switch (queryUser) { case KMessageBox::Yes: save(); return true; case KMessageBox::No: load(); return true; case KMessageBox::Cancel: return false; default: return false; } } QString ApperKCM::page() const { return QString(); } void ApperKCM::setPage(const QString &page) { PkTransaction *transaction = qobject_cast(ui->stackedWidget->currentWidget()); if (transaction) { return; } if (page == QLatin1String("settings")) { if (ui->stackedWidget->currentWidget() != m_settingsPage) { if (!canChangePage()) { return; } if (m_settingsPage == 0) { m_settingsPage = new Settings(m_roles, this); connect(m_settingsPage, SIGNAL(changed(bool)), this, SLOT(checkChanged())); connect(m_settingsPage, SIGNAL(refreshCache()), SLOT(refreshCache())); ui->stackedWidget->addWidget(m_settingsPage); connect(ui->generalSettingsPB, SIGNAL(toggled(bool)), m_settingsPage, SLOT(showGeneralSettings())); connect(ui->repoSettingsPB, SIGNAL(toggled(bool)), m_settingsPage, SLOT(showRepoSettings())); } checkChanged(); setButtons(KCModule::Default | KCModule::Apply); emit changed(true); // THIS IS DUMB setButtons only take effect after changed goes true emit changed(false); ui->generalSettingsPB->setChecked(true); ui->stackedWidgetBar->setCurrentIndex(BAR_SETTINGS); ui->stackedWidget->setCurrentWidget(m_settingsPage); m_settingsPage->load(); ui->titleL->clear(); ui->backTB->setEnabled(true); emit caption(i18n("Settings")); } } else if (page == QLatin1String("updates")) { if (ui->stackedWidget->currentWidget() != m_updaterPage) { if (!canChangePage()) { return; } if (m_updaterPage == 0) { m_updaterPage = new Updater(m_roles, this); connect(m_updaterPage, SIGNAL(refreshCache()), this, SLOT(refreshCache())); connect(m_updaterPage, SIGNAL(downloadSize(QString)), ui->downloadL, SLOT(setText(QString))); connect(m_updaterPage, SIGNAL(changed(bool)), this, SLOT(checkChanged())); ui->stackedWidget->addWidget(m_updaterPage); ui->checkUpdatesPB->setIcon(QIcon::fromTheme("view-refresh")); connect(ui->checkUpdatesPB, SIGNAL(clicked(bool)), this, SLOT(refreshCache())); } checkChanged(); ui->stackedWidget->setCurrentWidget(m_updaterPage); m_updaterPage->load(); ui->stackedWidgetBar->setCurrentIndex(BAR_UPDATE); ui->backTB->setEnabled(true); emit caption(i18n("Updates")); } } else if (page == QLatin1String("home")) { if (ui->stackedWidget->currentWidget() == m_updaterPage || ui->stackedWidget->currentWidget() == m_settingsPage) { on_backTB_clicked(); } } else if (page == QLatin1String("history")) { m_history = new TransactionHistory(this); ui->searchKLE->clear(); connect(ui->searchKLE, SIGNAL(textChanged(QString)), m_history, SLOT(setFilterRegExp(QString))); ui->stackedWidget->addWidget(m_history); ui->stackedWidget->setCurrentWidget(m_history); ui->backTB->setEnabled(true); ui->filtersTB->setEnabled(false); ui->widget->setEnabled(false); emit caption(i18n("History")); } } void ApperKCM::on_backTB_clicked() { bool canGoBack = false; if (ui->stackedWidget->currentWidget() == ui->pageBrowse) { if (!ui->browseView->goBack()) { return; } else if (m_groupsModel->hasParent()) { canGoBack = true; } } else if (ui->stackedWidget->currentWidget() == m_history) { ui->filtersTB->setEnabled(true); ui->widget->setEnabled(true); m_history->deleteLater(); m_history = 0; } else if (ui->stackedWidget->currentWidget() == ui->pageHome) { if (m_groupsModel->setParentIndex()) { // if we are able to set a new parent item // do not disable back button return; } } else if (ui->stackedWidget->currentWidget() == m_updaterPage) { if (!canChangePage()) { return; } ui->stackedWidgetBar->setCurrentIndex(BAR_SEARCH); checkChanged(); } else if (ui->stackedWidget->currentWidget() == m_settingsPage) { if (!canChangePage()) { return; } setButtons(Apply); emit changed(true); // THIS IS DUMB setButtons only take effect after changed goes true ui->stackedWidgetBar->setCurrentIndex(BAR_SEARCH); checkChanged(); } ui->homeView->selectionModel()->clear(); ui->stackedWidget->setCurrentWidget(ui->pageHome); ui->backTB->setEnabled(canGoBack); // reset the search role m_searchRole = Transaction::RoleUnknown; emit caption(); } void ApperKCM::on_changesPB_clicked() { m_changesModel->clear(); m_changesModel->addSelectedPackagesFromModel(m_browseModel); ui->stackedWidget->setCurrentWidget(ui->pageChanges); ui->backTB->setEnabled(true); emit caption(i18n("Pending Changes")); } void ApperKCM::disconnectTransaction() { if (m_searchTransaction) { // Disconnect everything so that the model don't store // wrong data m_searchTransaction->cancel(); disconnect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), ui->browseView->busyCursor(), SLOT(stop())); disconnect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(finished())); disconnect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_browseModel, SLOT(finished())); disconnect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_browseModel, SLOT(fetchSizes())); disconnect(m_searchTransaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_browseModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); disconnect(m_searchTransaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), this, SLOT(errorCode(PackageKit::Transaction::Error,QString))); } } void ApperKCM::search() { ui->browseView->cleanUi(); if (ui->stackedWidgetBar->currentIndex() != BAR_SEARCH) { ui->stackedWidgetBar->setCurrentIndex(BAR_SEARCH); } disconnectTransaction(); // search switch (m_searchRole) { case Transaction::RoleSearchName: m_searchTransaction = Daemon::searchNames(m_searchString, m_filtersMenu->filters()); emit caption(m_searchString); break; case Transaction::RoleSearchDetails: m_searchTransaction = Daemon::searchDetails(m_searchString, m_filtersMenu->filters()); emit caption(m_searchString); break; case Transaction::RoleSearchFile: m_searchTransaction = Daemon::searchFiles(m_searchString, m_filtersMenu->filters()); emit caption(m_searchString); break; case Transaction::RoleSearchGroup: if (m_searchGroupCategory.isEmpty()) { m_searchTransaction = Daemon::searchGroup(m_searchGroup, m_filtersMenu->filters()); // m_searchString has the group nice name emit caption(m_searchString); } else { ui->browseView->setParentCategory(m_searchParentCategory); emit caption(m_searchParentCategory.data().toString()); #ifndef HAVE_APPSTREAM if (m_searchGroupCategory.startsWith('@') || m_searchGroupCategory.startsWith(QLatin1String("repo:"))) { m_searchTransaction = Daemon::searchGroup(m_searchGroupCategory, m_filtersMenu->filters()); } #endif // else the transaction is useless } break; case Transaction::RoleGetPackages: // we want all the installed ones ui->browseView->disableExportInstalledPB(); m_searchTransaction = Daemon::getPackages(Transaction::FilterInstalled | m_filtersMenu->filters()); connect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), ui->browseView, SLOT(enableExportInstalledPB())); emit caption(i18n("Installed Software")); break; case Transaction::RoleResolve: #ifdef HAVE_APPSTREAM if (!m_searchCategory.isEmpty()) { ui->browseView->setParentCategory(m_searchParentCategory); // WARNING the resolve might fail if the backend // has a low limit MaximumItemsToResolve m_searchTransaction = Daemon::resolve(m_searchCategory, m_filtersMenu->filters()); emit caption(m_searchParentCategory.data().toString()); } else { ui->browseView->setParentCategory(m_searchParentCategory); KMessageBox::sorry(this, i18n("Could not find an application that matched this category")); emit caption(); disconnectTransaction(); m_searchTransaction = 0; return; } break; #endif default: qCWarning(APPER) << "Search type not defined yet"; emit caption(); disconnectTransaction(); m_searchTransaction = 0; return; } connect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), ui->browseView->busyCursor(), SLOT(stop())); connect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(finished())); connect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_browseModel, SLOT(finished())); if (ui->browseView->isShowingSizes()) { connect(m_searchTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_browseModel, SLOT(fetchSizes())); } connect(m_searchTransaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_browseModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); connect(m_searchTransaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), this, SLOT(errorCode(PackageKit::Transaction::Error,QString))); // cleans the models m_browseModel->clear(); ui->browseView->showInstalledPanel(m_searchRole == Transaction::RoleGetPackages); ui->browseView->busyCursor()->start(); ui->backTB->setEnabled(true); setCurrentActionCancel(true); setCurrentActionEnabled(m_searchTransaction->allowCancel()); ui->stackedWidget->setCurrentWidget(ui->pageBrowse); } void ApperKCM::changed() { Transaction *trans = qobject_cast(sender()); setCurrentActionEnabled(trans->allowCancel()); } void ApperKCM::refreshCache() { emit changed(false); QWidget *currentWidget = ui->stackedWidget->currentWidget(); PkTransactionWidget *transactionW = new PkTransactionWidget(this); connect(transactionW, SIGNAL(titleChangedProgress(QString)), this, SIGNAL(caption(QString))); QPointer transaction = new PkTransaction(transactionW); Daemon::setHints (QLatin1String("cache-age=")+QString::number(m_cacheAge)); transaction->refreshCache(m_forceRefreshCache); transactionW->setTransaction(transaction, Transaction::RoleRefreshCache); ui->stackedWidget->addWidget(transactionW); ui->stackedWidget->setCurrentWidget(transactionW); ui->stackedWidgetBar->setCurrentIndex(BAR_TITLE); ui->backTB->setEnabled(false); connect(transactionW, SIGNAL(titleChanged(QString)), ui->titleL, SLOT(setText(QString))); QEventLoop loop; connect(transaction, SIGNAL(finished(PkTransaction::ExitStatus)), &loop, SLOT(quit())); // wait for the end of transaction if (!transaction->isFinished()) { loop.exec(); if (!transaction) { // Avoid crashing return; } // If the refresh failed force next refresh Cache call m_forceRefreshCache = transaction->exitStatus() == PkTransaction::Failed; } if (m_updaterPage) { m_updaterPage->getUpdates(); } if (currentWidget == m_settingsPage) { setPage("settings"); } else { setPage("updates"); } QTimer::singleShot(0, this, SLOT(checkChanged())); } void ApperKCM::save() { QWidget *currentWidget = ui->stackedWidget->currentWidget(); if (currentWidget == m_settingsPage) { m_settingsPage->save(); } else { PkTransactionWidget *transactionW = new PkTransactionWidget(this); connect(transactionW, SIGNAL(titleChangedProgress(QString)), this, SIGNAL(caption(QString))); QPointer transaction = new PkTransaction(transactionW); ui->stackedWidget->addWidget(transactionW); ui->stackedWidget->setCurrentWidget(transactionW); ui->stackedWidgetBar->setCurrentIndex(BAR_TITLE); ui->backTB->setEnabled(false); connect(transactionW, SIGNAL(titleChanged(QString)), ui->titleL, SLOT(setText(QString))); emit changed(false); QEventLoop loop; connect(transaction, SIGNAL(finished(PkTransaction::ExitStatus)), &loop, SLOT(quit())); if (currentWidget == m_updaterPage) { transaction->updatePackages(m_updaterPage->packagesToUpdate()); transactionW->setTransaction(transaction, Transaction::RoleUpdatePackages); // wait for the end of transaction if (!transaction->isFinished()) { loop.exec(); if (!transaction) { // Avoid crashing return; } } } else { // install then remove packages QStringList installPackages = m_browseModel->selectedPackagesToInstall(); if (!installPackages.isEmpty()) { transaction->installPackages(installPackages); transactionW->setTransaction(transaction, Transaction::RoleInstallPackages); // wait for the end of transaction if (!transaction->isFinished()) { loop.exec(); if (!transaction) { // Avoid crashing return; } } if (transaction->exitStatus() == PkTransaction::Success) { m_browseModel->uncheckAvailablePackages(); } } QStringList removePackages = m_browseModel->selectedPackagesToRemove(); if (!removePackages.isEmpty()) { transaction->removePackages(removePackages); transactionW->setTransaction(transaction, Transaction::RoleRemovePackages); // wait for the end of transaction if (!transaction->isFinished()) { loop.exec(); if (!transaction) { // Avoid crashing return; } } if (transaction->exitStatus() == PkTransaction::Success) { m_browseModel->uncheckInstalledPackages(); } } } transaction->deleteLater(); if (currentWidget == m_updaterPage) { m_updaterPage->getUpdates(); setPage("updates"); } else { // install then remove packages search(); } QTimer::singleShot(0, this, SLOT(checkChanged())); } } void ApperKCM::load() { if (ui->stackedWidget->currentWidget() == m_updaterPage) { m_updaterPage->load(); } else if (ui->stackedWidget->currentWidget() == m_settingsPage) { m_settingsPage->load(); } else { // set focus on the search lineEdit ui->searchKLE->setFocus(Qt::OtherFocusReason); m_browseModel->setAllChecked(false); } } void ApperKCM::defaults() { if (ui->stackedWidget->currentWidget() == m_settingsPage) { m_settingsPage->defaults(); } } void ApperKCM::finished() { // if m_currentAction is false means that our // find button should be disable as there aren't any // search methods setCurrentActionEnabled(m_currentAction); setCurrentActionCancel(false); m_searchTransaction = 0; } void ApperKCM::keyPressEvent(QKeyEvent *event) { if (ui->searchKLE->hasFocus() && ui->stackedWidget->currentWidget() != m_history && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { // special tab handling here m_currentAction->trigger(); return; } KCModule::keyPressEvent(event); } void ApperKCM::closeEvent(QCloseEvent *event) { // PkTransaction *transaction = qobject_cast(stackedWidget->currentWidget()); // if (transaction) { event->ignore(); // } else { // event->accept(); // } } #include "ApperKCM.moc" diff --git a/ApperKCM/BrowseView.cpp b/ApperKCM/BrowseView.cpp index 9adb034..5cf1e6e 100644 --- a/ApperKCM/BrowseView.cpp +++ b/ApperKCM/BrowseView.cpp @@ -1,340 +1,338 @@ /*************************************************************************** * Copyright (C) 2009-2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "BrowseView.h" #include "PackageDetails.h" #include "CategoryModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace PackageKit; BrowseView::BrowseView(QWidget *parent) : QWidget(parent) { setupUi(this); connect(categoryView, SIGNAL(clicked(QModelIndex)), this, SIGNAL(categoryActivated(QModelIndex))); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(packageView->viewport()); m_model = new PackageModel(this); m_proxy = new ApplicationSortFilterModel(this); m_proxy->setSourceModel(m_model); packageView->setModel(m_proxy); packageView->sortByColumn(PackageModel::NameCol, Qt::AscendingOrder); packageView->header()->setDefaultAlignment(Qt::AlignCenter); packageView->header()->setStretchLastSection(false); packageView->header()->setSectionResizeMode(PackageModel::NameCol, QHeaderView::Stretch); packageView->header()->setSectionResizeMode(PackageModel::VersionCol, QHeaderView::ResizeToContents); packageView->header()->setSectionResizeMode(PackageModel::ArchCol, QHeaderView::ResizeToContents); packageView->header()->setSectionResizeMode(PackageModel::OriginCol, QHeaderView::ResizeToContents); packageView->header()->setSectionResizeMode(PackageModel::SizeCol, QHeaderView::ResizeToContents); packageView->header()->setSectionResizeMode(PackageModel::ActionCol, QHeaderView::ResizeToContents); // Hide current Version since it's useless for us packageView->header()->setSectionHidden(PackageModel::CurrentVersionCol, true); ApplicationsDelegate *delegate = new ApplicationsDelegate(packageView); packageView->setItemDelegate(delegate); exportInstalledPB->setIcon(QIcon::fromTheme("document-export")); importInstalledPB->setIcon(QIcon::fromTheme("document-import")); KConfig config("apper"); KConfigGroup viewGroup(&config, "BrowseView"); // Version packageView->header()->setSectionHidden(PackageModel::VersionCol, true); m_showPackageVersion = new QAction(i18n("Show Versions"), this); m_showPackageVersion->setCheckable(true); connect(m_showPackageVersion, SIGNAL(toggled(bool)), this, SLOT(showVersions(bool))); m_showPackageVersion->setChecked(viewGroup.readEntry("ShowApplicationVersions", true)); // Arch packageView->header()->setSectionHidden(PackageModel::ArchCol, true); m_showPackageArch = new QAction(i18n("Show Architectures"), this); m_showPackageArch->setCheckable(true); connect(m_showPackageArch, SIGNAL(toggled(bool)), this, SLOT(showArchs(bool))); m_showPackageArch->setChecked(viewGroup.readEntry("ShowApplicationArchitectures", false)); // Origin packageView->header()->setSectionHidden(PackageModel::OriginCol, true); m_showPackageOrigin = new QAction(i18n("Show Origins"), this); m_showPackageOrigin->setCheckable(true); connect(m_showPackageOrigin, SIGNAL(toggled(bool)), this, SLOT(showOrigins(bool))); m_showPackageOrigin->setChecked(viewGroup.readEntry("ShowApplicationOrigins", false)); // Sizes packageView->header()->setSectionHidden(PackageModel::SizeCol, true); m_showPackageSizes = new QAction(i18n("Show Sizes"), this); m_showPackageSizes->setCheckable(true); connect(m_showPackageSizes, SIGNAL(toggled(bool)), this, SLOT(showSizes(bool))); m_showPackageSizes->setChecked(viewGroup.readEntry("ShowPackageSizes", false)); // Ensure the index is visible when the packageDetails appears connect(packageDetails, SIGNAL(ensureVisible(QModelIndex)), this, SLOT(ensureVisible(QModelIndex))); } void BrowseView::init(Transaction::Roles roles) { packageDetails->init(roles); } BrowseView::~BrowseView() { } bool BrowseView::showPageHeader() const { return false; } PackageModel* BrowseView::model() const { return m_model; } void BrowseView::showVersions(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "BrowseView"); viewGroup.writeEntry("ShowApplicationVersions", enabled); packageView->header()->setSectionHidden(PackageModel::VersionCol, !enabled); packageDetails->hidePackageVersion(enabled); } void BrowseView::showArchs(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "BrowseView"); viewGroup.writeEntry("ShowApplicationArchitectures", enabled); packageView->header()->setSectionHidden(PackageModel::ArchCol, !enabled); packageDetails->hidePackageArch(enabled); } void BrowseView::showOrigins(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "BrowseView"); viewGroup.writeEntry("ShowApplicationOrigins", enabled); packageView->header()->setSectionHidden(PackageModel::OriginCol, !enabled); } void BrowseView::showSizes(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "BrowseView"); viewGroup.writeEntry("ShowPackageSizes", enabled); packageView->header()->setSectionHidden(PackageModel::SizeCol, !enabled); packageDetails->hidePackageArch(enabled); if (enabled) { m_model->fetchSizes(); } } void BrowseView::on_packageView_customContextMenuRequested(const QPoint &pos) { auto menu = new QMenu(this); menu->addAction(m_showPackageVersion); menu->addAction(m_showPackageArch); menu->addAction(m_showPackageOrigin); menu->addAction(m_showPackageSizes); menu->exec(packageView->viewport()->mapToGlobal(pos)); menu->deleteLater(); } void BrowseView::on_packageView_clicked(const QModelIndex &index) { if (index.column() == PackageModel::ActionCol) { return; } QModelIndex origIndex = m_proxy->mapToSource(index); packageDetails->setPackage(origIndex); } void BrowseView::ensureVisible(const QModelIndex &index) { QModelIndex proxIndex = m_proxy->mapFromSource(index); packageView->scrollTo(proxIndex); } void BrowseView::showInstalledPanel(bool visible) { installedF->setVisible(visible); } ApplicationSortFilterModel* BrowseView::proxy() const { return m_proxy; } KPixmapSequenceOverlayPainter* BrowseView::busyCursor() const { return m_busySeq; } void BrowseView::setCategoryModel(QAbstractItemModel *model) { categoryView->setModel(model); } void BrowseView::setParentCategory(const QModelIndex &index) { categoryView->setRootIndex(index); // Make sure the last item is not selected categoryView->selectionModel()->clearSelection(); categoryView->horizontalScrollBar()->setValue(0); // Display the category view if the index has child items categoryF->setVisible(categoryView->model()->rowCount(index)); } bool BrowseView::goBack() { packageDetails->hide(); QModelIndex index = categoryView->rootIndex(); if (index.parent().isValid()) { index = index.parent(); // if it's valid we need to know if it wasn't a PK root category if (index.data(CategoryModel::GroupRole).type() == QVariant::String) { QString category = index.data(CategoryModel::GroupRole).toString(); if (!category.startsWith('@')) { return true; } } setParentCategory(index); emit categoryActivated(index); return false; } return true; } void BrowseView::on_categoryMvLeft_clicked() { categoryView->horizontalScrollBar()->setValue(categoryView->horizontalScrollBar()->value() - 1); } void BrowseView::on_categoryMvRight_clicked() { categoryView->horizontalScrollBar()->setValue(categoryView->horizontalScrollBar()->value() + 1); } void BrowseView::cleanUi() { packageDetails->hide(); categoryF->setVisible(false); } bool BrowseView::isShowingSizes() const { return m_showPackageSizes->isChecked(); } void BrowseView::on_exportInstalledPB_clicked() { // We will assume the installed model // is populated since the user is seeing it. QString fileName; fileName = QFileDialog::getSaveFileName(this, i18n("Export installed packages"), QString(), QStringLiteral("*.catalog")); if (fileName.isEmpty()) { return; } QFile file(fileName); file.open(QIODevice::WriteOnly); QTextStream out(&file); out << "[PackageKit Catalog]\n\n"; out << "InstallPackages(" << Daemon::global()->distroID() << ")="; QStringList packages; for (int i = 0; i < m_model->rowCount(); i++) { packages << m_model->data(m_model->index(i, 0), PackageModel::PackageName).toString(); } out << packages.join(";"); } void BrowseView::on_importInstalledPB_clicked() { QString fileName; fileName = QFileDialog::getOpenFileName(this, i18n("Install packages from catalog"), QString(), QStringLiteral("*.catalog")); if (fileName.isEmpty()) { return; } // send a DBus message to install this catalog QDBusMessage message; message = QDBusMessage::createMethodCall("org.freedesktop.PackageKit", "/org/freedesktop/PackageKit", "org.freedesktop.PackageKit.Modify", "InstallCatalogs"); message << static_cast(effectiveWinId()); message << (QStringList() << fileName); message << QString(); // This call must block otherwise this application closes before // smarticon is activated QDBusMessage reply = QDBusConnection::sessionBus().call(message, QDBus::Block); } void BrowseView::disableExportInstalledPB() { exportInstalledPB->setEnabled(false); } void BrowseView::enableExportInstalledPB() { exportInstalledPB->setEnabled(true); } - -#include "BrowseView.moc" diff --git a/ApperKCM/ClickableLabel.cpp b/ApperKCM/ClickableLabel.cpp index 6d83e93..53973c3 100644 --- a/ApperKCM/ClickableLabel.cpp +++ b/ApperKCM/ClickableLabel.cpp @@ -1,37 +1,35 @@ /*************************************************************************** * Copyright (C) 2009-2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "ClickableLabel.h" #include ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f) { } void ClickableLabel::mouseReleaseEvent(QMouseEvent *event) { QLabel::mousePressEvent(event); emit clicked(); } - -#include "ClickableLabel.moc" diff --git a/ApperKCM/FiltersMenu.cpp b/ApperKCM/FiltersMenu.cpp index 242e3f4..58afea4 100644 --- a/ApperKCM/FiltersMenu.cpp +++ b/ApperKCM/FiltersMenu.cpp @@ -1,359 +1,357 @@ /*************************************************************************** * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include "FiltersMenu.h" #include #include #include FiltersMenu::FiltersMenu(QWidget *parent) : QMenu(parent) { // Loads the filter menu settings KConfig config("apper"); KConfigGroup filterMenuGroup(&config, "FilterMenu"); QMenu *menuCollections = new QMenu(i18n("Collections"), this); connect(menuCollections, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableCollections(bool)), addMenu(menuCollections), SLOT(setVisible(bool))); QActionGroup *collectionGroup = new QActionGroup(menuCollections); collectionGroup->setExclusive(true); QAction *collectionTrue = new QAction(i18n("Only collections"), collectionGroup); collectionTrue->setCheckable(true); m_filtersAction[collectionTrue] = Transaction::FilterCollections; collectionGroup->addAction(collectionTrue); menuCollections->addAction(collectionTrue); m_actions << collectionTrue; QAction *collectionFalse = new QAction(i18n("Exclude collections"), collectionGroup); collectionFalse->setCheckable(true); m_filtersAction[collectionFalse] = Transaction::FilterNotCollections; collectionGroup->addAction(collectionFalse); menuCollections->addAction(collectionFalse); m_actions << collectionFalse; // Installed QMenu *menuInstalled = new QMenu(i18n("Installed"), this); connect(menuInstalled, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableInstalled(bool)), addMenu(menuInstalled), SLOT(setVisible(bool))); addMenu(menuInstalled); QActionGroup *installedGroup = new QActionGroup(menuInstalled); installedGroup->setExclusive(true); QAction *installedTrue = new QAction(i18n("Only installed"), installedGroup); installedTrue->setCheckable(true); m_filtersAction[installedTrue] = Transaction::FilterInstalled; installedGroup->addAction(installedTrue); menuInstalled->addAction(installedTrue); m_actions << installedTrue; QAction *installedFalse = new QAction(i18n("Only available"), installedGroup); installedFalse->setCheckable(true); m_filtersAction[installedFalse] = Transaction::FilterNotInstalled; installedGroup->addAction(installedFalse); menuInstalled->addAction(installedFalse); m_actions << installedFalse; QAction *installedNone = new QAction(i18n("No filter"), installedGroup); installedNone->setCheckable(true); installedNone->setChecked(true); installedGroup->addAction(installedNone); menuInstalled->addAction(installedNone); m_actions << installedNone; // Development QMenu *menuDevelopment = new QMenu(i18n("Development"), this); connect(menuDevelopment, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableDevelopment(bool)), addMenu(menuDevelopment), SLOT(setVisible(bool))); addMenu(menuDevelopment); QActionGroup *developmentGroup = new QActionGroup(menuDevelopment); developmentGroup->setExclusive(true); QAction *developmentTrue = new QAction(i18n("Only development"), developmentGroup); developmentTrue->setCheckable(true); m_filtersAction[developmentTrue] = Transaction::FilterDevel; developmentGroup->addAction(developmentTrue); menuDevelopment->addAction(developmentTrue); m_actions << developmentTrue; QAction *developmentFalse = new QAction(i18n("Only end user files"), developmentGroup); developmentFalse->setCheckable(true); m_filtersAction[developmentFalse] = Transaction::FilterNotDevel; developmentGroup->addAction(developmentFalse); menuDevelopment->addAction(developmentFalse); m_actions << developmentFalse; QAction *developmentNone = new QAction(i18n("No filter"), developmentGroup); developmentNone->setCheckable(true); developmentNone->setChecked(true); developmentGroup->addAction(developmentNone); menuDevelopment->addAction(developmentNone); m_actions << developmentNone; // Graphical QMenu *menuGui = new QMenu(i18n("Graphical"), this); connect(menuGui, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableGraphical(bool)), addMenu(menuGui), SLOT(setVisible(bool))); addMenu(menuGui); QActionGroup *guiGroup = new QActionGroup(menuGui); guiGroup->setExclusive(true); QAction *guiTrue = new QAction(i18n("Only graphical"), guiGroup); guiTrue->setCheckable(true); m_filtersAction[guiTrue] = Transaction::FilterGui; guiGroup->addAction(guiTrue); menuGui->addAction(guiTrue); m_actions << guiTrue; QAction *guiFalse = new QAction(i18n("Only text"), guiGroup); guiFalse->setCheckable(true); m_filtersAction[guiFalse] = Transaction::FilterNotGui; guiGroup->addAction(guiFalse); menuGui->addAction(guiFalse); m_actions << guiFalse; QAction *guiNone = new QAction(i18n("No filter"), guiGroup); guiNone->setCheckable(true); guiNone->setChecked(true); guiGroup->addAction(guiNone); menuGui->addAction(guiNone); m_actions << guiNone; // Free QMenu *menuFree = new QMenu(i18nc("Filter for free packages", "Free"), this); connect(menuFree, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableFree(bool)), addMenu(menuFree), SLOT(setVisible(bool))); addMenu(menuFree); QActionGroup *freeGroup = new QActionGroup(menuFree); freeGroup->setExclusive(true); QAction *freeTrue = new QAction(i18n("Only free software"), freeGroup); freeTrue->setCheckable(true); m_filtersAction[freeTrue] = Transaction::FilterFree; freeGroup->addAction(freeTrue); menuFree->addAction(freeTrue); m_actions << freeTrue; QAction *freeFalse = new QAction(i18n("Only non-free software"), freeGroup); freeFalse->setCheckable(true); m_filtersAction[freeFalse] = Transaction::FilterNotFree; freeGroup->addAction(freeFalse); menuFree->addAction(freeFalse); m_actions << freeFalse; QAction *freeNone = new QAction(i18n("No filter"), freeGroup); freeNone->setCheckable(true); freeNone->setChecked(true); freeGroup->addAction(freeNone); menuFree->addAction(freeNone); m_actions << freeNone; // Supported QMenu *menuSupported = new QMenu(i18nc("Filter for supported packages", "Supported"), this); connect(menuSupported, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableSupported(bool)), addMenu(menuSupported), SLOT(setVisible(bool))); addMenu(menuSupported); QActionGroup *supportedGroup = new QActionGroup(menuSupported); supportedGroup->setExclusive(true); QAction *supportedTrue = new QAction(i18n("Only supported software"), supportedGroup); supportedTrue->setCheckable(true); m_filtersAction[supportedTrue] = Transaction::FilterSupported; supportedGroup->addAction(supportedTrue); menuSupported->addAction(supportedTrue); m_actions << supportedTrue; QAction *supportedFalse = new QAction(i18n("Only non-supported software"), supportedGroup); supportedFalse->setCheckable(true); m_filtersAction[supportedFalse] = Transaction::FilterNotSupported; supportedGroup->addAction(supportedFalse); menuSupported->addAction(supportedFalse); m_actions << supportedFalse; QAction *supportedNone = new QAction(i18n("No filter"), supportedGroup); supportedNone->setCheckable(true); supportedNone->setChecked(true); supportedGroup->addAction(supportedNone); menuSupported->addAction(supportedNone); m_actions << supportedNone; // Source QMenu *menuSource = new QMenu(i18nc("Filter for source packages", "Source"), this); connect(menuSource, SIGNAL(triggered(QAction*)), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableSource(bool)), addMenu(menuSource), SLOT(setVisible(bool))); addMenu(menuSource); QActionGroup *sourceGroup = new QActionGroup(menuSource); sourceGroup->setExclusive(true); QAction *sourceTrue = new QAction(i18n("Only sourcecode"), sourceGroup); sourceTrue->setCheckable(true); m_filtersAction[sourceTrue] = Transaction::FilterSource; sourceGroup->addAction(sourceTrue); menuSource->addAction(sourceTrue); m_actions << sourceTrue; QAction *sourceFalse = new QAction(i18n("Only non-sourcecode"), sourceGroup); sourceFalse->setCheckable(true); m_filtersAction[sourceFalse] = Transaction::FilterNotSource; sourceGroup->addAction(sourceFalse); menuSource->addAction(sourceFalse); m_actions << sourceFalse; QAction *sourceNone = new QAction(i18n("No filter"), sourceGroup); sourceNone->setCheckable(true); sourceNone->setChecked(true); sourceGroup->addAction(sourceNone); menuSource->addAction(sourceNone); m_actions << sourceNone; // Basename, Newest, Arch separator connect(this, SIGNAL(enableBasenameNewestArchSeparator(bool)), addSeparator(), SLOT(setVisible(bool))); QAction *basename = new QAction(i18n("Hide Subpackages"), this); connect(basename, SIGNAL(triggered()), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableBasename(bool)), basename, SLOT(setVisible(bool))); basename->setCheckable(true); basename->setToolTip(i18n("Only show one package, not subpackages")); m_filtersAction[basename] = Transaction::FilterBasename; m_actions << basename; QAction *newest = new QAction(i18n("Only Newest Packages"), this); connect(newest, SIGNAL(triggered()), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableNewest(bool)), newest, SLOT(setVisible(bool))); newest->setCheckable(true); newest->setChecked(filterMenuGroup.readEntry("FilterNewest", true)); newest->setToolTip(i18n("Only show the newest available package")); m_filtersAction[newest] = Transaction::FilterNewest; m_actions << newest; QAction *native = new QAction(i18n("Only Native Packages"), this); connect(native, SIGNAL(triggered()), this, SIGNAL(filtersChanged())); connect(this, SIGNAL(enableArch(bool)), native, SLOT(setVisible(bool))); native->setCheckable(true); native->setChecked(filterMenuGroup.readEntry("FilterNative", true)); native->setToolTip(i18n("Only show packages matching the machine architecture")); m_filtersAction[native] = Transaction::FilterArch; m_actions << native; #ifdef HAVE_APPSTREAM addSeparator(); m_applications = new QAction(i18n("Only Show Applications"), this); m_applications->setCheckable(true); m_applications->setChecked(filterMenuGroup.readEntry("HidePackages", false)); m_applications->setToolTip(i18n("Hide packages that are not applications")); addAction(m_applications); connect(m_applications, SIGNAL(triggered(bool)), this, SIGNAL(filterApplications(bool))); #endif // HAVE_APPSTREAM } FiltersMenu::~FiltersMenu() { KConfig config("apper"); KConfigGroup filterMenuGroup(&config, "FilterMenu"); // For usability we will only save ViewInGroups settings and Newest filter, // - The user might get angry when he does not find any packages because he didn't // see that a filter is set by config // This entry does not depend on the backend it's ok to call this pointer // filterMenuGroup.writeEntry("ViewInGroups", m_filtersMenu->actionGrouped()); // This entry does not depend on the backend it's ok to call this pointer filterMenuGroup.writeEntry("FilterNewest", static_cast(filters() & Transaction::FilterNewest)); // This entry does not depend on the backend it's ok to call this pointer filterMenuGroup.writeEntry("FilterNative", static_cast(filters() & Transaction::FilterArch)); #ifdef HAVE_APPSTREAM filterMenuGroup.writeEntry("HidePackages", m_applications->isChecked()); #endif // HAVE_APPSTREAM } void FiltersMenu::setFilters(Transaction::Filters filters) { emit enableCollections(filters & Transaction::FilterCollections || filters & Transaction::FilterNotCollections); emit enableInstalled(filters & Transaction::FilterInstalled || filters & Transaction::FilterNotInstalled); emit enableDevelopment(filters & Transaction::FilterDevel || filters & Transaction::FilterNotDevel); emit enableGraphical(filters & Transaction::FilterGui || filters & Transaction::FilterNotGui); emit enableFree(filters & Transaction::FilterFree || filters & Transaction::FilterNotFree); emit enableSupported(filters & Transaction::FilterSupported || filters & Transaction::FilterNotSupported); emit enableSource(filters & Transaction::FilterSource || filters & Transaction::FilterNotSource); emit enableBasenameNewestArchSeparator(filters & Transaction::FilterBasename || filters & Transaction::FilterNewest || filters & Transaction::FilterArch); emit enableBasename(filters & Transaction::FilterBasename); emit enableNewest(filters & Transaction::FilterNewest); emit enableArch(filters & Transaction::FilterArch); } bool FiltersMenu::filterApplications() const { #ifdef HAVE_APPSTREAM return m_applications->isChecked(); #else return false; #endif // HAVE_APPSTREAM } Transaction::Filters FiltersMenu::filters() const { Transaction::Filters filters; bool filterSet = false; foreach (QAction * const action, m_actions) { if (action->isChecked()) { if (m_filtersAction.contains(action)) { filters |= m_filtersAction[action]; filterSet = true; } } } if (!filterSet) { filters = Transaction::FilterNone; } return filters; } - -#include "FiltersMenu.moc" diff --git a/ApperKCM/GraphicsOpacityDropShadowEffect.cpp b/ApperKCM/GraphicsOpacityDropShadowEffect.cpp index 289ce74..32d0ec2 100644 --- a/ApperKCM/GraphicsOpacityDropShadowEffect.cpp +++ b/ApperKCM/GraphicsOpacityDropShadowEffect.cpp @@ -1,53 +1,51 @@ /*************************************************************************** * Copyright (C) 2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "GraphicsOpacityDropShadowEffect.h" #include #include GraphicsOpacityDropShadowEffect::GraphicsOpacityDropShadowEffect(QObject *parent) : QGraphicsDropShadowEffect(parent), m_opacity(1) { } GraphicsOpacityDropShadowEffect::~GraphicsOpacityDropShadowEffect() { } qreal GraphicsOpacityDropShadowEffect::opacity() const { return m_opacity; } void GraphicsOpacityDropShadowEffect::setOpacity(qreal opacity) { m_opacity = opacity; update(); } void GraphicsOpacityDropShadowEffect::draw(QPainter *painter) { painter->setOpacity(m_opacity); QGraphicsDropShadowEffect::draw(painter); } - -#include "GraphicsOpacityDropShadowEffect.moc" diff --git a/ApperKCM/PackageDetails.cpp b/ApperKCM/PackageDetails.cpp index b073871..d1d4f06 100644 --- a/ApperKCM/PackageDetails.cpp +++ b/ApperKCM/PackageDetails.cpp @@ -1,804 +1,802 @@ /*************************************************************************** * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "PackageDetails.h" #include "ui_PackageDetails.h" #include "ScreenShotViewer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_APPSTREAM #include #endif #include "GraphicsOpacityDropShadowEffect.h" #define BLUR_RADIUS 15 #define FINAL_HEIGHT 210 using namespace PackageKit; Q_DECLARE_LOGGING_CATEGORY(APPER) Q_DECLARE_METATYPE(KPixmapSequenceOverlayPainter**) PackageDetails::PackageDetails(QWidget *parent) : QWidget(parent), ui(new Ui::PackageDetails), m_busySeq(0), m_display(false), m_hideVersion(false), m_hideArch(false), m_transaction(0), m_hasDetails(false), m_hasFileList(false) { ui->setupUi(this); ui->hideTB->setIcon(QIcon::fromTheme("window-close")); connect(ui->hideTB, SIGNAL(clicked()), this, SLOT(hide())); auto menu = new QMenu(i18n("Display"), this); m_actionGroup = new QActionGroup(this); // we check to see which roles are supported by the backend // if so we ask for information and create the containers descriptionAction = menu->addAction(i18n("Description")); descriptionAction->setCheckable(true); descriptionAction->setData(PackageKit::Transaction::RoleGetDetails); m_actionGroup->addAction(descriptionAction); ui->descriptionW->setWidgetResizable(true); dependsOnAction = menu->addAction(i18n("Depends On")); dependsOnAction->setCheckable(true); dependsOnAction->setData(PackageKit::Transaction::RoleDependsOn); m_actionGroup->addAction(dependsOnAction); // Sets a transparent background QWidget *dependsViewport = ui->dependsOnLV->viewport(); QPalette dependsPalette = dependsViewport->palette(); dependsPalette.setColor(dependsViewport->backgroundRole(), Qt::transparent); dependsPalette.setColor(dependsViewport->foregroundRole(), dependsPalette.color(QPalette::WindowText)); dependsViewport->setPalette(dependsPalette); m_dependsModel = new PackageModel(this); m_dependsProxy = new QSortFilterProxyModel(this); m_dependsProxy->setDynamicSortFilter(true); m_dependsProxy->setSortRole(PackageModel::SortRole); m_dependsProxy->setSourceModel(m_dependsModel); ui->dependsOnLV->setModel(m_dependsProxy); ui->dependsOnLV->sortByColumn(0, Qt::AscendingOrder); ui->dependsOnLV->header()->setDefaultAlignment(Qt::AlignCenter); ui->dependsOnLV->header()->setSectionResizeMode(PackageModel::NameCol, QHeaderView::ResizeToContents); ui->dependsOnLV->header()->setSectionResizeMode(PackageModel::VersionCol, QHeaderView::ResizeToContents); ui->dependsOnLV->header()->setSectionResizeMode(PackageModel::ArchCol, QHeaderView::Stretch); ui->dependsOnLV->header()->hideSection(PackageModel::ActionCol); ui->dependsOnLV->header()->hideSection(PackageModel::CurrentVersionCol); ui->dependsOnLV->header()->hideSection(PackageModel::OriginCol); ui->dependsOnLV->header()->hideSection(PackageModel::SizeCol); requiredByAction = menu->addAction(i18n("Required By")); requiredByAction->setCheckable(true); requiredByAction->setData(PackageKit::Transaction::RoleRequiredBy); m_actionGroup->addAction(requiredByAction); // Sets a transparent background QWidget *requiredViewport = ui->requiredByLV->viewport(); QPalette requiredPalette = requiredViewport->palette(); requiredPalette.setColor(requiredViewport->backgroundRole(), Qt::transparent); requiredPalette.setColor(requiredViewport->foregroundRole(), requiredPalette.color(QPalette::WindowText)); requiredViewport->setPalette(requiredPalette); m_requiresModel = new PackageModel(this); m_requiresProxy = new QSortFilterProxyModel(this); m_requiresProxy->setDynamicSortFilter(true); m_requiresProxy->setSortRole(PackageModel::SortRole); m_requiresProxy->setSourceModel(m_requiresModel); ui->requiredByLV->setModel(m_requiresProxy); ui->requiredByLV->sortByColumn(0, Qt::AscendingOrder); ui->requiredByLV->header()->setDefaultAlignment(Qt::AlignCenter); ui->requiredByLV->header()->setSectionResizeMode(PackageModel::NameCol, QHeaderView::ResizeToContents); ui->requiredByLV->header()->setSectionResizeMode(PackageModel::VersionCol, QHeaderView::ResizeToContents); ui->requiredByLV->header()->setSectionResizeMode(PackageModel::ArchCol, QHeaderView::Stretch); ui->requiredByLV->header()->hideSection(PackageModel::ActionCol); ui->requiredByLV->header()->hideSection(PackageModel::CurrentVersionCol); ui->requiredByLV->header()->hideSection(PackageModel::OriginCol); ui->requiredByLV->header()->hideSection(PackageModel::SizeCol); fileListAction = menu->addAction(i18n("File List")); fileListAction->setCheckable(true); fileListAction->setData(PackageKit::Transaction::RoleGetFiles); m_actionGroup->addAction(fileListAction); // Sets a transparent background QWidget *actionsViewport = ui->filesPTE->viewport(); QPalette palette = actionsViewport->palette(); palette.setColor(actionsViewport->backgroundRole(), Qt::transparent); palette.setColor(actionsViewport->foregroundRole(), palette.color(QPalette::WindowText)); actionsViewport->setPalette(palette); // Set the menu ui->menuTB->setMenu(menu); ui->menuTB->setIcon(QIcon::fromTheme("help-about")); connect(m_actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(actionActivated(QAction*))); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(ui->stackedWidget); // Setup the opacit effect that makes the descriptio transparent // after finished it checks in display() to see if it shouldn't show // up again. The property animation is always the same, the only different thing // is the Forward or Backward property QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(ui->stackedWidget); effect->setOpacity(0); ui->stackedWidget->setGraphicsEffect(effect); m_fadeStacked = new QPropertyAnimation(effect, "opacity", this); m_fadeStacked->setDuration(500); m_fadeStacked->setStartValue(qreal(0)); m_fadeStacked->setEndValue(qreal(1)); connect(m_fadeStacked, SIGNAL(finished()), this, SLOT(display())); // It's is impossible due to some limitation in Qt to set two effects on the same // Widget m_fadeScreenshot = new QPropertyAnimation(effect, "opacity", this); GraphicsOpacityDropShadowEffect *shadow = new GraphicsOpacityDropShadowEffect(ui->screenshotL); shadow->setOpacity(0); shadow->setBlurRadius(BLUR_RADIUS); shadow->setOffset(2); shadow->setColor(QApplication::palette().dark().color()); ui->screenshotL->setGraphicsEffect(shadow); m_fadeScreenshot = new QPropertyAnimation(shadow, "opacity", this); m_fadeScreenshot->setDuration(500); m_fadeScreenshot->setStartValue(qreal(0)); m_fadeScreenshot->setEndValue(qreal(1)); connect(m_fadeScreenshot, SIGNAL(finished()), this, SLOT(display())); // This pannel expanding QPropertyAnimation *anim1 = new QPropertyAnimation(this, "maximumSize", this); anim1->setDuration(500); anim1->setEasingCurve(QEasingCurve::OutQuart); anim1->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); anim1->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); QPropertyAnimation *anim2 = new QPropertyAnimation(this, "minimumSize", this); anim2->setDuration(500); anim2->setEasingCurve(QEasingCurve::OutQuart); anim2->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); anim2->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); m_expandPanel = new QParallelAnimationGroup(this); m_expandPanel->addAnimation(anim1); m_expandPanel->addAnimation(anim2); connect(m_expandPanel, SIGNAL(finished()), this, SLOT(display())); } void PackageDetails::init(PackageKit::Transaction::Roles roles) { // qCDebug(); bool setChecked = true; if (roles & PackageKit::Transaction::RoleGetDetails) { descriptionAction->setEnabled(true); descriptionAction->setChecked(setChecked); setChecked = false; } else { descriptionAction->setEnabled(false); descriptionAction->setChecked(false); } if (roles & PackageKit::Transaction::RoleDependsOn) { dependsOnAction->setEnabled(true); dependsOnAction->setChecked(setChecked); setChecked = false; } else { dependsOnAction->setEnabled(false); dependsOnAction->setChecked(false); } if (roles & PackageKit::Transaction::RoleRequiredBy) { requiredByAction->setEnabled(true); requiredByAction->setChecked(setChecked); setChecked = false; } else { requiredByAction->setEnabled(false); requiredByAction->setChecked(false); } if (roles & PackageKit::Transaction::RoleGetFiles) { fileListAction->setEnabled(true); fileListAction->setChecked(setChecked); setChecked = false; } else { fileListAction->setEnabled(false); fileListAction->setChecked(false); } } PackageDetails::~PackageDetails() { } void PackageDetails::setPackage(const QModelIndex &index) { qCDebug(APPER) << index; QString appId = index.data(PackageModel::ApplicationId).toString(); QString packageID = index.data(PackageModel::IdRole).toString(); // if it's the same package and the same application, return if (packageID == m_packageID && appId == m_appId) { return; } else if (maximumSize().height() == 0) { // Expand the panel m_display = true; m_expandPanel->setDirection(QAbstractAnimation::Forward); m_expandPanel->start(); } else { // Hide the old description fadeOut(PackageDetails::FadeScreenshot | PackageDetails::FadeStacked); } m_index = index; m_appId = appId; m_packageID = packageID; m_hasDetails = false; m_hasFileList = false; m_hasRequires = false; m_hasDepends = false; qCDebug(APPER) << "appId" << appId << "m_package" << m_packageID; QString pkgIconPath = index.data(PackageModel::IconRole).toString(); m_currentIcon = PkIcons::getIcon(pkgIconPath, QString()).pixmap(64, 64); m_appName = index.data(PackageModel::NameRole).toString(); m_currentScreenshot = thumbnail(Transaction::packageName(m_packageID)); qCDebug(APPER) << "current screenshot" << m_currentScreenshot; if (!m_currentScreenshot.isNull()) { if (m_screenshotPath.contains(m_currentScreenshot)) { display(); } else { auto tempFile = new QTemporaryFile; tempFile->open(); KIO::FileCopyJob *job = KIO::file_copy(QUrl(m_currentScreenshot), QUrl(tempFile->fileName()), -1, KIO::Overwrite | KIO::HideProgressInfo); connect(job, &KIO::FileCopyJob::result, this, &PackageDetails::resultJob); } } if (m_actionGroup->checkedAction()) { actionActivated(m_actionGroup->checkedAction()); } } void PackageDetails::on_screenshotL_clicked() { QString url; url = screenshot(Transaction::packageName(m_packageID)); if (!url.isNull()) { ScreenShotViewer *view = new ScreenShotViewer(url); view->setWindowTitle(m_appName); view->show(); } } void PackageDetails::hidePackageVersion(bool hide) { m_hideVersion = hide; } void PackageDetails::hidePackageArch(bool hide) { m_hideArch = hide; } void PackageDetails::actionActivated(QAction *action) { // don't fade the screenshot // if the package changed setPackage() fades both fadeOut(FadeStacked); qCDebug(APPER); // disconnect the transaction // so that we don't get old data if (m_transaction) { disconnect(m_transaction, SIGNAL(details(PackageKit::Details)), this, SLOT(description(PackageKit::Details))); disconnect(m_transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_dependsModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); disconnect(m_transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_requiresModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); disconnect(m_transaction, SIGNAL(files(QString,QStringList)), this, SLOT(files(QString,QStringList))); disconnect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(finished())); m_transaction = 0; } // Check to see if we don't already have the required data uint role = action->data().toUInt(); switch (role) { case PackageKit::Transaction::RoleGetDetails: if (m_hasDetails) { description(m_details); display(); return; } break; case PackageKit::Transaction::RoleDependsOn: if (m_hasDepends) { display(); return; } break; case PackageKit::Transaction::RoleRequiredBy: if (m_hasRequires) { display(); return; } break; case PackageKit::Transaction::RoleGetFiles: if (m_hasFileList) { display(); return; } break; } // we don't have the data qCDebug(APPER) << "New transaction"; switch (role) { case PackageKit::Transaction::RoleGetDetails: m_transaction = Daemon::getDetails(m_packageID); connect(m_transaction, SIGNAL(details(PackageKit::Details)), SLOT(description(PackageKit::Details))); break; case PackageKit::Transaction::RoleDependsOn: m_dependsModel->clear(); m_transaction = Daemon::dependsOn(m_packageID, PackageKit::Transaction::FilterNone, false); connect(m_transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_dependsModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); connect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_dependsModel, SLOT(finished())); break; case PackageKit::Transaction::RoleRequiredBy: m_requiresModel->clear(); m_transaction = Daemon::requiredBy(m_packageID, PackageKit::Transaction::FilterNone, false); connect(m_transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_requiresModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); connect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_requiresModel, SLOT(finished())); break; case PackageKit::Transaction::RoleGetFiles: m_currentFileList.clear(); m_transaction = Daemon::getFiles(m_packageID); connect(m_transaction, SIGNAL(files(QString,QStringList)), this, SLOT(files(QString,QStringList))); break; default: qWarning() << Q_FUNC_INFO << "Oops, unhandled role, please report" << role; return; } connect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(finished())); qCDebug(APPER) <<"transaction running"; m_busySeq->start(); } void PackageDetails::resultJob(KJob *job) { KIO::FileCopyJob *fJob = qobject_cast(job); if (!fJob->error()) { m_screenshotPath[fJob->srcUrl().url()] = fJob->destUrl().toLocalFile(); display(); } } void PackageDetails::hide() { m_display = false; // Clean the old description otherwise if the user selects the same // package the pannel won't expand m_packageID.clear(); m_appId.clear(); if (maximumSize().height() == FINAL_HEIGHT) { if (m_fadeStacked->currentValue().toReal() == 0 && m_fadeScreenshot->currentValue().toReal() == 0) { // Screen shot and description faded let's shrink the pannel m_expandPanel->setDirection(QAbstractAnimation::Backward); m_expandPanel->start(); } else { // Hide current description fadeOut(PackageDetails::FadeScreenshot | PackageDetails::FadeStacked); } } } void PackageDetails::fadeOut(FadeWidgets widgets) { // Fade out only if needed if ((widgets & FadeStacked) && m_fadeStacked->currentValue().toReal() != 0) { m_fadeStacked->setDirection(QAbstractAnimation::Backward); m_fadeStacked->start(); } // Fade out the screenshot only if needed if ((widgets & FadeScreenshot) && m_fadeScreenshot->currentValue().toReal() != 0) { ui->screenshotL->unsetCursor(); m_fadeScreenshot->setDirection(QAbstractAnimation::Backward); m_fadeScreenshot->start(); } } void PackageDetails::display() { // If we shouldn't be showing hide the pannel if (!m_display) { hide(); } else if (maximumSize().height() == FINAL_HEIGHT) { emit ensureVisible(m_index); // Check to see if the stacked widget is transparent if (m_fadeStacked->currentValue().toReal() == 0 && m_actionGroup->checkedAction()) { bool fadeIn = false; switch (m_actionGroup->checkedAction()->data().toUInt()) { case PackageKit::Transaction::RoleGetDetails: if (m_hasDetails) { setupDescription(); fadeIn = true; } break; case PackageKit::Transaction::RoleDependsOn: if (m_hasDepends) { if (ui->stackedWidget->currentWidget() != ui->pageDepends) { ui->stackedWidget->setCurrentWidget(ui->pageDepends); } fadeIn = true; } break; case PackageKit::Transaction::RoleRequiredBy: if (m_hasRequires) { if (ui->stackedWidget->currentWidget() != ui->pageRequired) { ui->stackedWidget->setCurrentWidget(ui->pageRequired); } fadeIn = true; } break; case PackageKit::Transaction::RoleGetFiles: if (m_hasFileList) { ui->filesPTE->clear(); if (m_currentFileList.isEmpty()) { ui->filesPTE->insertPlainText(i18n("No files were found.")); } else { m_currentFileList.sort(); ui->filesPTE->insertPlainText(m_currentFileList.join("\n")); } if (ui->stackedWidget->currentWidget() != ui->pageFiles) { ui->stackedWidget->setCurrentWidget(ui->pageFiles); } ui->filesPTE->verticalScrollBar()->setValue(0); fadeIn = true; } break; } if (fadeIn) { // Fade In m_fadeStacked->setDirection(QAbstractAnimation::Forward); m_fadeStacked->start(); } } // Check to see if we have a screen shot and if we are // transparent, and make sure the details are going // to be shown if (m_fadeScreenshot->currentValue().toReal() == 0 && m_screenshotPath.contains(m_currentScreenshot) && m_fadeStacked->direction() == QAbstractAnimation::Forward) { QPixmap pixmap; pixmap = QPixmap(m_screenshotPath[m_currentScreenshot]) .scaled(160,120, Qt::KeepAspectRatio, Qt::SmoothTransformation); ui->screenshotL->setPixmap(pixmap); ui->screenshotL->setCursor(Qt::PointingHandCursor); // Fade In m_fadeScreenshot->setDirection(QAbstractAnimation::Forward); m_fadeScreenshot->start(); } } } void PackageDetails::setupDescription() { if (ui->stackedWidget->currentWidget() != ui->pageDescription) { ui->stackedWidget->setCurrentWidget(ui->pageDescription); } if (!m_hasDetails) { // Oops we don't have any details ui->descriptionL->setText(i18n("Could not fetch software details")); ui->descriptionL->show(); // Hide stuff so we don't display outdated data ui->homepageL->hide(); ui->pathL->hide(); ui->licenseL->hide(); ui->sizeL->hide(); ui->iconL->clear(); } if (!m_detailsDescription.isEmpty()) { ui->descriptionL->setText(m_detailsDescription.replace('\n', "
")); ui->descriptionL->show(); } else { ui->descriptionL->clear(); } if (!m_details.url().isEmpty()) { ui->homepageL->setText("" + m_details.url() + ""); ui->homepageL->show(); } else { ui->homepageL->hide(); } // Let's try to find the application's path in human user // readable easiest form :D KService::Ptr service = KService::serviceByDesktopName(m_appId); QVector > ret; if (service) { ret = locateApplication(QString(), service->menuId()); } if (ret.isEmpty()) { ui->pathL->hide(); } else { QString path; path.append(QString("") .arg(KIconLoader::global()->iconPath("kde", KIconLoader::Small))); path.append(QString(" %1  %3") .arg(QString::fromUtf8("âžœ")) .arg(KIconLoader::global()->iconPath("applications-other", KIconLoader::Small)) .arg(i18n("Applications"))); for (int i = 0; i < ret.size(); i++) { path.append(QString(" %1  %3") .arg(QString::fromUtf8("âžœ")) .arg(KIconLoader::global()->iconPath(ret.at(i).second, KIconLoader::Small)) .arg(ret.at(i).first)); } ui->pathL->setText(path); ui->pathL->show(); } // if (details->group() != Package::UnknownGroup) { // // description += "" + i18nc("Group of the package", "Group") + ":" // // + PkStrings::groups(details->group()) // // + ""; // } if (!m_details.license().isEmpty() && m_details.license() != "unknown") { // We have a license, check if we have and should show show package version if (!m_hideVersion && !Transaction::packageVersion(m_details.packageId()).isEmpty()) { ui->licenseL->setText(Transaction::packageVersion(m_details.packageId()) + " - " + m_details.license()); } else { ui->licenseL->setText(m_details.license()); } ui->licenseL->show(); } else if (!m_hideVersion) { ui->licenseL->setText(Transaction::packageVersion(m_details.packageId())); ui->licenseL->show(); } else { ui->licenseL->hide(); } if (m_details.size() > 0) { QString size = KFormat().formatByteSize(m_details.size()); if (!m_hideArch && !Transaction::packageArch(m_details.packageId()).isEmpty()) { ui->sizeL->setText(size % QLatin1String(" (") % Transaction::packageArch(m_details.packageId()) % QLatin1Char(')')); } else { ui->sizeL->setText(size); } ui->sizeL->show(); } else if (!m_hideArch && !Transaction::packageArch(m_details.packageId()).isEmpty()) { ui->sizeL->setText(Transaction::packageArch(m_details.packageId())); } else { ui->sizeL->hide(); } if (m_currentIcon.isNull()) { ui->iconL->clear(); } else { ui->iconL->setPixmap(m_currentIcon); } } QVector > PackageDetails::locateApplication(const QString &_relPath, const QString &menuId) const { QVector > ret; KServiceGroup::Ptr root = KServiceGroup::group(_relPath); if (!root || !root->isValid()) { return ret; } KServiceGroup::List list = root->entries(false /* sorted */, true /* exclude no display entries */, false /* allow separators */); //! TODO: Port to KF5 properly Q_UNUSED(menuId) #if 0 for (KServiceGroup::List::ConstIterator it = list.begin(); it != list.end(); it++) { KSycocaEntry::Ptr = (*it); if (p->isType(KST_KService)) { KService *service = static_cast(p.get()); if (service->noDisplay()) { continue; } // qCDebug(APPER) << menuId << service->menuId(); if (service->menuId() == menuId) { QPair pair; pair.first = service->name(); pair.second = service->icon(); ret << pair; // qCDebug(APPER) << "FOUND!"; return ret; } } else if (p->isType(KST_KServiceGroup)) { KServiceGroup *serviceGroup = static_cast(p.get()); if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0) { continue; } QVector > found; found = locateApplication(serviceGroup->relPath(), menuId); if (!found.isEmpty()) { QPair pair; pair.first = serviceGroup->caption(); pair.second = serviceGroup->icon(); ret << pair; ret << found; return ret; } } else { kWarning(250) << "KServiceGroup: Unexpected object in list!"; continue; } } #endif return ret; } QString PackageDetails::thumbnail(const QString &pkgName) const { #ifndef HAVE_APPSTREAM Q_UNUSED(pkgName) return QString(); #else return AppStream::instance()->thumbnail(pkgName); #endif } QString PackageDetails::screenshot(const QString &pkgName) const { #ifndef HAVE_APPSTREAM Q_UNUSED(pkgName) return QString(); #else return AppStream::instance()->screenshot(pkgName); #endif } void PackageDetails::description(const PackageKit::Details &details) { qCDebug(APPER) << details; m_details = details; m_detailsDescription = details.description(); m_hasDetails = true; #ifdef HAVE_APPSTREAM // check if we have application details from Appstream data // FIXME: The whole AppStream handling sucks badly, since it was added later // and on to of the package-based model. So we can't respect the "multiple apps // in one package" case here. QList apps; apps = AppStream::instance()->applications(Transaction::packageName(m_packageID)); foreach (const AppStream::Application &app, apps) { if (!app.description.isEmpty()) { m_detailsDescription = app.description; break; } } #endif } void PackageDetails::finished() { if (m_busySeq) { m_busySeq->stop(); } m_transaction = 0; PackageKit::Transaction *transaction; transaction = qobject_cast(sender()); qCDebug(APPER); if (transaction) { qCDebug(APPER) << transaction->role() << PackageKit::Transaction::RoleGetDetails; if (transaction->role() == PackageKit::Transaction::RoleGetDetails) { m_hasDetails = true; } else if (transaction->role() == PackageKit::Transaction::RoleGetFiles) { m_hasFileList = true; } else if (transaction->role() == PackageKit::Transaction::RoleRequiredBy) { m_hasRequires = true; } else if (transaction->role() == PackageKit::Transaction::RoleDependsOn) { m_hasDepends = true; } else { return; } display(); } } void PackageDetails::files(const QString &packageID, const QStringList &files) { Q_UNUSED(packageID) m_currentFileList = files; } - -#include "PackageDetails.moc" diff --git a/ApperKCM/ScreenShotViewer.cpp b/ApperKCM/ScreenShotViewer.cpp index 381e076..70c62f5 100644 --- a/ApperKCM/ScreenShotViewer.cpp +++ b/ApperKCM/ScreenShotViewer.cpp @@ -1,109 +1,107 @@ /*************************************************************************** * Copyright (C) 2009-2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "ScreenShotViewer.h" #include #include #include #include #include #include #include #include #include #include "ClickableLabel.h" ScreenShotViewer::ScreenShotViewer(const QString &url, QWidget *parent) : QScrollArea(parent) { m_screenshotL = new ClickableLabel(this); m_screenshotL->setCursor(Qt::PointingHandCursor); m_screenshotL->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); m_screenshotL->resize(250, 200); resize(250, 200); setFrameShape(NoFrame); setFrameShadow(Plain); setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); setWidget(m_screenshotL); setWindowIcon(QIcon::fromTheme("layer-visible-on")); auto tempFile = new QTemporaryFile; // tempFile->setPrefix("appgetfull"); // tempFile->setSuffix(".png"); tempFile->open(); KIO::FileCopyJob *job = KIO::file_copy(QUrl(url), QUrl(tempFile->fileName()), -1, KIO::Overwrite | KIO::HideProgressInfo); connect(job, &KIO::FileCopyJob::result, this, &ScreenShotViewer::resultJob); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(m_screenshotL); m_busySeq->start(); connect(m_screenshotL, SIGNAL(clicked()), this, SLOT(deleteLater())); } ScreenShotViewer::~ScreenShotViewer() { } void ScreenShotViewer::resultJob(KJob *job) { m_busySeq->stop(); auto fJob = qobject_cast(job); if (!fJob->error()) { m_screenshot = QPixmap(fJob->destUrl().toLocalFile()); QPropertyAnimation *anim1 = new QPropertyAnimation(this, "size"); anim1->setDuration(500); anim1->setStartValue(size()); anim1->setEndValue(m_screenshot.size()); anim1->setEasingCurve(QEasingCurve::OutCubic); connect(anim1, SIGNAL(finished()), this, SLOT(fadeIn())); anim1->start(); } else { m_screenshotL->setText(i18n("Could not find screen shot.")); } } void ScreenShotViewer::fadeIn() { QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(m_screenshotL); effect->setOpacity(0); QPropertyAnimation *anim = new QPropertyAnimation(effect, "opacity"); anim->setDuration(500); anim->setStartValue(qreal(0)); anim->setEndValue(qreal(1)); m_screenshotL->setGraphicsEffect(effect); m_screenshotL->setPixmap(m_screenshot); m_screenshotL->adjustSize(); anim->start(); } - -#include "ScreenShotViewer.moc" diff --git a/ApperKCM/Settings/OriginModel.cpp b/ApperKCM/Settings/OriginModel.cpp index c0aed2f..623ed1f 100644 --- a/ApperKCM/Settings/OriginModel.cpp +++ b/ApperKCM/Settings/OriginModel.cpp @@ -1,107 +1,105 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "OriginModel.h" #include #include #include #include #include using namespace PackageKit; OriginModel::OriginModel(QObject *parent) : QStandardItemModel(parent), m_finished(true) { setHorizontalHeaderLabels(QStringList() << i18n("Origin of Packages")); } OriginModel::~OriginModel() { } bool OriginModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::CheckStateRole && index.isValid()) { Transaction *transaction = Daemon::repoEnable(index.data(RepoId).toString(), value.toBool()); connect(transaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), SLOT(errorCode(PackageKit::Transaction::Error,QString))); connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), SLOT(setRepoFinished(PackageKit::Transaction::Exit))); } return false; } QVariantHash OriginModel::changes() const { QVariantHash ret; for (int i = 0; i < rowCount(); ++i) { QStandardItem *repo = item(i); bool currentState = repo->checkState(); if (currentState != repo->data(RepoInitialState).toBool()) { ret[repo->data(RepoId).toString()] = currentState; } } return ret; } void OriginModel::addOriginItem(const QString &repo_id, const QString &details, bool enabled) { if (m_finished) { // if we received a finished signal this is a new query removeRows(0, rowCount()); m_finished = false; } QStandardItem *item = new QStandardItem(details); item->setCheckable(true); item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); item->setData(repo_id, RepoId); item->setData(enabled, RepoInitialState); appendRow(item); } void OriginModel::finished() { m_finished = true; } void OriginModel::errorCode(PackageKit::Transaction::Error error, const QString &details) { if (error != Transaction::ErrorTransactionCancelled) { KMessageBox::detailedSorry(0, PkStrings::errorMessage(error), details, PkStrings::error(error), KMessageBox::Notify); } } void OriginModel::setRepoFinished(Transaction::Exit exit) { if (exit == Transaction::ExitSuccess) { emit refreshRepoList(); } sender()->deleteLater(); } - -#include "OriginModel.moc" diff --git a/ApperKCM/Settings/Settings.cpp b/ApperKCM/Settings/Settings.cpp index bb4363e..32cca18 100644 --- a/ApperKCM/Settings/Settings.cpp +++ b/ApperKCM/Settings/Settings.cpp @@ -1,343 +1,341 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "Settings.h" #include "ui_Settings.h" #include "OriginModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace PackageKit; Settings::Settings(Transaction::Roles roles, QWidget *parent) : QWidget(parent), ui(new Ui::Settings), m_roles(roles) { ui->setupUi(this); QAction *action = new QAction(i18n("Refresh Cache"), this); connect(action, SIGNAL(triggered()), SIGNAL(refreshCache())); connect(action, SIGNAL(triggered()), ui->messageWidget, SLOT(animatedHide())); ui->messageWidget->addAction(action); ui->messageWidget->setText(i18n("A repository was changed, it's highly recommended to refresh the cache")); ui->messageWidget->hide(); if (!(m_roles & Transaction::RoleRefreshCache)) { ui->intervalL->setEnabled(false); ui->intervalCB->setEnabled(false); } if (!(m_roles & Transaction::RoleGetDistroUpgrades)) { ui->distroIntervalCB->setEnabled(false); } m_originModel = new OriginModel(this); connect(m_originModel, SIGNAL(refreshRepoList()), SLOT(refreshRepoModel())); connect(m_originModel, SIGNAL(refreshRepoList()), ui->messageWidget, SLOT(animatedShow())); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(m_originModel); ui->originTV->setModel(proxy); ui->originTV->header()->setDefaultAlignment(Qt::AlignCenter); // This is needed to keep the oring right ui->originTV->header()->setSortIndicator(0, Qt::AscendingOrder); proxy->sort(0); if (!(m_roles & Transaction::RoleGetRepoList)) { // Disables the group box ui->originTV->setEnabled(false); ui->showOriginsCB->setEnabled(false); } ui->distroIntervalCB->addItem(i18nc("Inform about distribution upgrades", "Never"), Enum::DistroNever); ui->distroIntervalCB->addItem(i18nc("Inform about distribution upgrades", "Only stable"), Enum::DistroStable); // Ignore unstable distros upgrades for now #ifndef false ui->distroIntervalCB->addItem(i18nc("Inform about distribution upgrades", "Stable and development"), Enum::DistroDevelopment); #endif ui->intervalCB->addItem(i18nc("Hourly refresh the package cache", "Hourly"), Enum::Hourly); ui->intervalCB->addItem(i18nc("Daily refresh the package cache", "Daily"), Enum::Daily); ui->intervalCB->addItem(i18nc("Weekly refresh the package cache", "Weekly"), Enum::Weekly); ui->intervalCB->addItem(i18nc("Monthly refresh the package cache", "Monthly"), Enum::Monthly); ui->intervalCB->addItem(i18nc("Never refresh package cache", "Never"), Enum::Never); ui->autoCB->addItem(i18nc("No updates will be automatically installed", "None"), Enum::None); ui->autoCB->addItem(i18n("Download only"), Enum::DownloadOnly); ui->autoCB->addItem(i18n("Security only"), Enum::Security); ui->autoCB->addItem(i18n("All updates"), Enum::All); connect(ui->autoConfirmCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); connect(ui->appLauncherCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); connect(ui->distroIntervalCB, SIGNAL(currentIndexChanged(int)), this, SLOT(checkChanges())); connect(ui->intervalCB, SIGNAL(currentIndexChanged(int)), this, SLOT(checkChanges())); connect(ui->checkUpdatesBatteryCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); connect(ui->checkUpdatesMobileCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); connect(ui->autoCB, SIGNAL(currentIndexChanged(int)), this, SLOT(checkChanges())); connect(ui->installUpdatesBatteryCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); connect(ui->installUpdatesMobileCB, SIGNAL(stateChanged(int)), this, SLOT(checkChanges())); // Setup the busy cursor m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(ui->originTV->viewport()); #ifndef EDIT_ORIGNS_DESKTOP_NAME ui->editOriginsPB->hide(); #endif //EDIT_ORIGNS_DESKTOP_NAME } Settings::~Settings() { delete ui; } void Settings::on_editOriginsPB_clicked() { #ifdef EDIT_ORIGNS_DESKTOP_NAME KToolInvocation::startServiceByDesktopName(EDIT_ORIGNS_DESKTOP_NAME); #endif //EDIT_ORIGNS_DESKTOP_NAME } void Settings::refreshRepoModel() { on_showOriginsCB_stateChanged(ui->showOriginsCB->checkState()); } // TODO update the repo list connecting to repo changed signal void Settings::on_showOriginsCB_stateChanged(int state) { Transaction *transaction; transaction = Daemon::getRepoList(state == Qt::Checked ? Transaction::FilterNone : Transaction::FilterNotDevel); connect(transaction, SIGNAL(repoDetail(QString,QString,bool)), m_originModel, SLOT(addOriginItem(QString,QString,bool))); connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_originModel, SLOT(finished())); connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_busySeq, SLOT(stop())); connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(checkChanges())); m_busySeq->start(); KConfig config("apper"); KConfigGroup originsDialog(&config, "originsDialog"); bool showDevel = originsDialog.readEntry("showDevel", false); if (showDevel != ui->showOriginsCB->isChecked()) { originsDialog.writeEntry("showDevel", ui->showOriginsCB->isChecked()); } } bool Settings::hasChanges() const { KConfig config("apper"); KConfigGroup requirementsDialog(&config, "requirementsDialog"); KConfigGroup transaction(&config, "Transaction"); KConfigGroup checkUpdateGroup(&config, "CheckUpdate"); if (ui->distroIntervalCB->itemData(ui->distroIntervalCB->currentIndex()).toUInt() != static_cast(checkUpdateGroup.readEntry(CFG_DISTRO_UPGRADE, Enum::DistroUpgradeDefault)) || ui->intervalCB->itemData(ui->intervalCB->currentIndex()).toUInt() != static_cast(checkUpdateGroup.readEntry(CFG_INTERVAL, Enum::TimeIntervalDefault)) || ui->checkUpdatesBatteryCB->isChecked() != checkUpdateGroup.readEntry(CFG_CHECK_UP_BATTERY, DEFAULT_CHECK_UP_BATTERY) || ui->checkUpdatesMobileCB->isChecked() != checkUpdateGroup.readEntry(CFG_CHECK_UP_MOBILE, DEFAULT_CHECK_UP_MOBILE) || ui->autoCB->itemData(ui->autoCB->currentIndex()).toUInt() != static_cast(checkUpdateGroup.readEntry(CFG_AUTO_UP, Enum::AutoUpdateDefault)) || ui->installUpdatesBatteryCB->isChecked() != checkUpdateGroup.readEntry(CFG_INSTALL_UP_BATTERY, DEFAULT_INSTALL_UP_BATTERY) || ui->installUpdatesMobileCB->isChecked() != checkUpdateGroup.readEntry(CFG_INSTALL_UP_MOBILE, DEFAULT_INSTALL_UP_MOBILE) || ui->autoConfirmCB->isChecked() != !requirementsDialog.readEntry("autoConfirm", false) || ui->appLauncherCB->isChecked() != transaction.readEntry("ShowApplicationLauncher", true)) { return true; } return false; } void Settings::checkChanges() { emit changed(hasChanges()); // Check if interval update is never bool enabled = ui->intervalCB->itemData(ui->intervalCB->currentIndex()).toUInt() != Enum::Never; ui->checkUpdatesBatteryCB->setEnabled(enabled); ui->checkUpdatesMobileCB->setEnabled(enabled); ui->autoInsL->setEnabled(enabled); ui->autoCB->setEnabled(enabled); if (enabled) { enabled = ui->autoCB->itemData(ui->autoCB->currentIndex()).toUInt() != Enum::None; } ui->installUpdatesMobileCB->setEnabled(enabled); ui->installUpdatesBatteryCB->setEnabled(enabled); } void Settings::load() { KConfig config("apper"); KConfigGroup requirementsDialog(&config, "requirementsDialog"); ui->autoConfirmCB->setChecked(!requirementsDialog.readEntry("autoConfirm", false)); KConfigGroup transaction(&config, "Transaction"); ui->appLauncherCB->setChecked(transaction.readEntry("ShowApplicationLauncher", true)); KConfigGroup checkUpdateGroup(&config, "CheckUpdate"); uint distroUpgrade = checkUpdateGroup.readEntry(CFG_DISTRO_UPGRADE, Enum::DistroUpgradeDefault); int ret = ui->distroIntervalCB->findData(distroUpgrade); if (ret == -1) { ui->distroIntervalCB->setCurrentIndex(ui->distroIntervalCB->findData(Enum::DistroUpgradeDefault)); } else { ui->distroIntervalCB->setCurrentIndex(ret); } uint interval = checkUpdateGroup.readEntry(CFG_INTERVAL, Enum::TimeIntervalDefault); ret = ui->intervalCB->findData(interval); if (ret == -1) { // this is if someone change the file by hand... KFormat f; // ui->intervalCB->addItem(KLocale::global()->prettyFormatDuration(interval * 1000), interval); ui->intervalCB->addItem(f.formatDuration(interval * 1000), interval); ui->intervalCB->setCurrentIndex(ui->intervalCB->count() - 1); } else { ui->intervalCB->setCurrentIndex(ret); } ui->checkUpdatesBatteryCB->setChecked(checkUpdateGroup.readEntry(CFG_CHECK_UP_BATTERY, DEFAULT_CHECK_UP_BATTERY)); ui->checkUpdatesMobileCB->setChecked(checkUpdateGroup.readEntry(CFG_CHECK_UP_MOBILE, DEFAULT_CHECK_UP_MOBILE)); uint autoUpdate = checkUpdateGroup.readEntry(CFG_AUTO_UP, Enum::AutoUpdateDefault); ret = ui->autoCB->findData(autoUpdate); if (ret == -1) { // this is if someone change the file by hand... ui->autoCB->setCurrentIndex(ui->autoCB->findData(Enum::AutoUpdateDefault)); } else { ui->autoCB->setCurrentIndex(ret); } ui->installUpdatesBatteryCB->setChecked(checkUpdateGroup.readEntry(CFG_INSTALL_UP_BATTERY, DEFAULT_INSTALL_UP_BATTERY)); ui->installUpdatesMobileCB->setChecked(checkUpdateGroup.readEntry(CFG_INSTALL_UP_MOBILE, DEFAULT_INSTALL_UP_MOBILE)); // Load origns list if (m_roles & Transaction::RoleGetRepoList) { KConfigGroup originsDialog(&config, "originsDialog"); bool showDevel = originsDialog.readEntry("showDevel", false); ui->showOriginsCB->setChecked(showDevel); refreshRepoModel(); ui->originTV->setEnabled(true); } else { ui->originTV->setEnabled(false); } // hide battery options if we are on a desktop computer const QList listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString()); bool notFound = true; foreach (const Solid::Device &device, listBattery) { const Solid::Battery *battery = device.as(); if (battery && battery->type() == Solid::Battery::PrimaryBattery) { notFound = false; break; } } if (notFound) { ui->checkUpdatesBatteryCB->hide(); ui->installUpdatesBatteryCB->hide(); } } void Settings::save() { KConfig config("apper"); KConfigGroup requirementsDialog(&config, "requirementsDialog"); requirementsDialog.writeEntry("autoConfirm", !ui->autoConfirmCB->isChecked()); KConfigGroup transaction(&config, "Transaction"); transaction.writeEntry("ShowApplicationLauncher", ui->appLauncherCB->isChecked()); KConfigGroup checkUpdateGroup(&config, "CheckUpdate"); checkUpdateGroup.writeEntry("distroUpgrade", ui->distroIntervalCB->itemData(ui->distroIntervalCB->currentIndex()).toUInt()); checkUpdateGroup.writeEntry("interval", ui->intervalCB->itemData(ui->intervalCB->currentIndex()).toUInt()); checkUpdateGroup.writeEntry("checkUpdatesOnBattery", ui->checkUpdatesBatteryCB->isChecked()); checkUpdateGroup.writeEntry("checkUpdatesOnMobile", ui->checkUpdatesMobileCB->isChecked()); checkUpdateGroup.writeEntry("autoUpdate", ui->autoCB->itemData(ui->autoCB->currentIndex()).toUInt()); checkUpdateGroup.writeEntry("installUpdatesOnBattery", ui->installUpdatesBatteryCB->isChecked()); checkUpdateGroup.writeEntry("installUpdatesOnMobile", ui->installUpdatesMobileCB->isChecked()); } void Settings::defaults() { ui->autoConfirmCB->setChecked(true); ui->appLauncherCB->setChecked(true); ui->distroIntervalCB->setCurrentIndex(ui->distroIntervalCB->findData(Enum::DistroUpgradeDefault)); ui->intervalCB->setCurrentIndex(ui->intervalCB->findData(Enum::TimeIntervalDefault)); ui->autoCB->setCurrentIndex(ui->autoCB->findData(Enum::AutoUpdateDefault) ); checkChanges(); } void Settings::showGeneralSettings() { ui->stackedWidget->setCurrentIndex(0); } void Settings::showRepoSettings() { ui->stackedWidget->setCurrentIndex(1); } - -#include "Settings.moc" diff --git a/ApperKCM/TransactionFilterModel.cpp b/ApperKCM/TransactionFilterModel.cpp index 663b72b..477ab6b 100644 --- a/ApperKCM/TransactionFilterModel.cpp +++ b/ApperKCM/TransactionFilterModel.cpp @@ -1,48 +1,46 @@ /*************************************************************************** * Copyright (C) 2009 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "TransactionFilterModel.h" #include #include TransactionFilterModel::TransactionFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { } TransactionFilterModel::~TransactionFilterModel() { } bool TransactionFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { QVariant leftData = sourceModel()->data(left, Qt::UserRole); QVariant rightData = sourceModel()->data(right, Qt::UserRole); if (leftData.type() == QVariant::DateTime) { return leftData.toDateTime() < rightData.toDateTime(); } else { return QSortFilterProxyModel::lessThan(left, right); } } - -#include "TransactionFilterModel.moc" diff --git a/ApperKCM/TransactionHistory.cpp b/ApperKCM/TransactionHistory.cpp index 2afc8ea..ef62a34 100644 --- a/ApperKCM/TransactionHistory.cpp +++ b/ApperKCM/TransactionHistory.cpp @@ -1,89 +1,87 @@ /*************************************************************************** * Copyright (C) 2009-2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "TransactionHistory.h" #include "TransactionFilterModel.h" #include "TransactionModel.h" #include #include #include #include #include #include #include #include TransactionHistory::TransactionHistory(QWidget *parent) : QWidget(parent) { setupUi(this); m_transactionModel = new TransactionModel(this); m_proxyModel = new TransactionFilterModel(this); m_proxyModel->setSourceModel(m_transactionModel); m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_proxyModel->setFilterKeyColumn(-1); treeView->setModel(m_proxyModel); treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); // Get the data refreshList(); } TransactionHistory::~TransactionHistory() { } void TransactionHistory::setFilterRegExp(const QString ®exp) { m_proxyModel->setFilterRegExp(regexp); } void TransactionHistory::on_treeView_customContextMenuRequested(const QPoint &pos) { auto menu = new QMenu(this); QAction *action; action = menu->addAction(i18n("Refresh transactions list")); connect(action, &QAction::triggered, this, &TransactionHistory::refreshList); menu->exec(treeView->viewport()->mapToGlobal(pos)); delete menu; } void TransactionHistory::refreshList() { // Refresh transaction list m_transactionModel->clear(); Transaction *transaction = Daemon::getOldTransactions(0); connect(transaction, &Transaction::transaction, m_transactionModel, &TransactionModel::addTransaction); // Refresh time QString text; uint time = Daemon::global()->getTimeSinceAction(Transaction::RoleRefreshCache) * 1000; // text = i18n("Time since last cache refresh: %1", KLocale::global()->prettyFormatDuration(time)); text = i18n("Time since last cache refresh: %1", KFormat().formatDuration(time)); timeCacheLabel->setText(text); } - -#include "TransactionHistory.moc" diff --git a/ApperKCM/Updater/CheckableHeader.cpp b/ApperKCM/Updater/CheckableHeader.cpp index 521630f..09f7bd4 100644 --- a/ApperKCM/Updater/CheckableHeader.cpp +++ b/ApperKCM/Updater/CheckableHeader.cpp @@ -1,178 +1,176 @@ /*************************************************************************** * Copyright (C) 2010-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "CheckableHeader.h" #include #include #include #include #define UNIVERSAL_PADDING 3 CheckableHeader::CheckableHeader(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent), m_state(Qt::Unchecked), m_visible(true) { } void CheckableHeader::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { const QStyle *style = QApplication::style(); painter->save(); QHeaderView::paintSection(painter, rect, logicalIndex); painter->restore(); if (logicalIndex == 0 && m_visible) { QStyleOptionButton option; option.state = QStyle::State_None; option.rect = rect; if (QApplication::isRightToLeft()) { option.rect.setRight(rect.right() - UNIVERSAL_PADDING); } else { option.rect.setLeft(rect.left() + UNIVERSAL_PADDING); } option.rect.setLeft(rect.left() + UNIVERSAL_PADDING); switch (m_state) { case Qt::Unchecked : option.state |= QStyle::State_Off; break; case Qt::PartiallyChecked : option.state |= QStyle::State_NoChange; break; case Qt::Checked : option.state |= QStyle::State_On; break; } // Get the cursor position to check if it has focus QPoint pos = mapFromGlobal(QCursor::pos()); QRect rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option); if (insideCheckBox(rect, pos)) { option.state |= QStyle::State_HasFocus; } // draw item data as CheckBox painter->save(); style->drawControl(QStyle::CE_CheckBox, &option, painter); painter->restore(); } } bool CheckableHeader::insideCheckBox(const QRect &rect, const QPoint &pos) const { // kDebug() << rect << pos; if ((pos.x() >= rect.x() && (pos.x() <= rect.x() + rect.width())) && (pos.y() >= rect.y() && (pos.y() <= rect.y() + rect.height()))) { return true; } return false; } QSize CheckableHeader::sizeHint() const { const QStyle *style = QApplication::style(); QStyleOptionButton option; QRect rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option); QSize size = QHeaderView::sizeHint(); // kDebug() << size << rect; if (size.height() < (rect.height() + 2 * UNIVERSAL_PADDING)) { size.setHeight(rect.height() + 2 * UNIVERSAL_PADDING); } return size; } QSize CheckableHeader::sectionSizeFromContents(int logicalIndex) const { QSize size = QHeaderView::sectionSizeFromContents(logicalIndex); if (logicalIndex == 0) { const QStyle *style = QApplication::style(); QStyleOptionButton option; QRect rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option); QString text = model()->headerData(0, Qt::Horizontal).toString(); QFontMetrics metric = QFontMetrics(QFont()); int textSize = metric.width(text); int minimunSize = textSize + 2 * (rect.width() + 2 * (UNIVERSAL_PADDING + 1)); if (size.width() < minimunSize) { size.setWidth(minimunSize); } } return size; } void CheckableHeader::mouseMoveEvent(QMouseEvent *event) { headerDataChanged(Qt::Horizontal, 0, 0); QHeaderView::mouseMoveEvent(event); } void CheckableHeader::leaveEvent(QEvent *event) { headerDataChanged(Qt::Horizontal, 0, 0); QHeaderView::leaveEvent(event); // kDebug(); } void CheckableHeader::mousePressEvent(QMouseEvent *event) { if (!m_visible) { return; } const QStyle *style = QApplication::style(); QStyleOptionButton option; option.rect.setSize(sizeHint()); option.rect.setWidth(viewport()->width()); QRect rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option); QPoint pos = mapFromGlobal(QCursor::pos()); // kDebug() << rect << pos; if (insideCheckBox(rect, pos)) { if (m_state == Qt::Checked) { m_state = Qt::Unchecked; } else { m_state = Qt::Checked; } emit toggled(m_state); headerDataChanged(Qt::Horizontal, 0, 0); } else { QHeaderView::mousePressEvent(event); } } void CheckableHeader::setCheckState(Qt::CheckState state) { m_state = state; } void CheckableHeader::setCheckBoxVisible(bool visible) { m_visible = visible; headerDataChanged(Qt::Horizontal, 0, 0); } - -#include "CheckableHeader.moc" diff --git a/ApperKCM/Updater/DistroUpgrade.cpp b/ApperKCM/Updater/DistroUpgrade.cpp index d9eb12a..fecd75c 100644 --- a/ApperKCM/Updater/DistroUpgrade.cpp +++ b/ApperKCM/Updater/DistroUpgrade.cpp @@ -1,118 +1,116 @@ /*************************************************************************** * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "DistroUpgrade.h" #include #include #include #include #include //#include #include #include DistroUpgrade::DistroUpgrade(QWidget *parent) : KMessageWidget(parent) { auto action = new QAction(i18n("Upgrade"), this); connect(action, &QAction::triggered, this, &DistroUpgrade::startDistroUpgrade); addAction(action); } DistroUpgrade::~DistroUpgrade() { } void DistroUpgrade::setName(const QString &name) { setText(i18n("Distribution upgrade available: %1", name)); } void DistroUpgrade::startDistroUpgrade() { //! QList powerPlugs = Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter); bool pluggedIn = true; bool hasBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery).size()>0; //! foreach(const Solid::Device &dev, powerPlugs) { //! if (!dev.as()->isPlugged()) { //! pluggedIn = false; //! } //! } QString warning = i18n("You are about to upgrade your distribution to the latest version. " "This is usually a very lengthy process and takes a lot longer than " "simply upgrading your packages."); if (!pluggedIn) { warning += ' ' + i18n("It is recommended to plug in your computer before proceeding."); } else if (hasBattery) { warning += ' ' + i18n("It is recommended that you keep your computer plugged in while the upgrade is being performed."); } if (KMessageBox::warningContinueCancel(this,warning) == KMessageBox::Continue) { m_distroUpgradeProcess = new QProcess; connect(m_distroUpgradeProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(distroUpgradeError(QProcess::ProcessError))); connect(m_distroUpgradeProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(distroUpgradeFinished(int,QProcess::ExitStatus))); QStringList env = QProcess::systemEnvironment(); env << "DESKTOP=kde"; m_distroUpgradeProcess->setEnvironment(env); m_distroUpgradeProcess->start("/usr/share/PackageKit/pk-upgrade-distro.sh"); } } void DistroUpgrade::distroUpgradeFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitStatus == QProcess::NormalExit && exitCode == 0) { KMessageBox::information(this, i18n("Distribution upgrade complete.")); } else if (exitStatus == QProcess::NormalExit) { KMessageBox::sorry(this, i18n("Distribution upgrade process exited with code %1.", exitCode)); } m_distroUpgradeProcess->deleteLater(); m_distroUpgradeProcess = 0; } void DistroUpgrade::distroUpgradeError(QProcess::ProcessError error) { QString text; switch(error) { case QProcess::FailedToStart: KMessageBox::sorry(this, i18n("The distribution upgrade process failed to start.")); break; case QProcess::Crashed: KMessageBox::sorry(this, i18n("The distribution upgrade process crashed some time after starting successfully.")); break; default: KMessageBox::sorry(this, i18n("The distribution upgrade process failed with an unknown error.")); break; } } - -#include "DistroUpgrade.moc" diff --git a/ApperKCM/Updater/UpdateDetails.cpp b/ApperKCM/Updater/UpdateDetails.cpp index e04028d..27cc5a9 100644 --- a/ApperKCM/Updater/UpdateDetails.cpp +++ b/ApperKCM/Updater/UpdateDetails.cpp @@ -1,346 +1,344 @@ /*************************************************************************** * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "UpdateDetails.h" #include #include #include #include #include #include #include #include #include #include #include #include #define FINAL_HEIGHT 160 Q_DECLARE_LOGGING_CATEGORY(APPER) UpdateDetails::UpdateDetails(QWidget *parent) : QWidget(parent), m_show(false), m_transaction(0) { setupUi(this); hideTB->setIcon(QIcon::fromTheme("window-close")); connect(hideTB, SIGNAL(clicked()), this, SLOT(hide())); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(this); QWidget *actionsViewport = descriptionKTB->viewport(); QPalette palette = actionsViewport->palette(); palette.setColor(actionsViewport->backgroundRole(), Qt::transparent); palette.setColor(actionsViewport->foregroundRole(), palette.color(QPalette::WindowText)); actionsViewport->setPalette(palette); QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(descriptionKTB); effect->setOpacity(0); descriptionKTB->setGraphicsEffect(effect); m_fadeDetails = new QPropertyAnimation(effect, "opacity", this); m_fadeDetails->setDuration(500); m_fadeDetails->setStartValue(qreal(0)); m_fadeDetails->setEndValue(qreal(1)); connect(m_fadeDetails, SIGNAL(finished()), this, SLOT(display())); QPropertyAnimation *anim1 = new QPropertyAnimation(this, "maximumSize", this); anim1->setDuration(500); anim1->setEasingCurve(QEasingCurve::OutQuart); anim1->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); anim1->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); QPropertyAnimation *anim2 = new QPropertyAnimation(this, "minimumSize", this); anim2->setDuration(500); anim2->setEasingCurve(QEasingCurve::OutQuart); anim2->setStartValue(QSize(QWIDGETSIZE_MAX, 0)); anim2->setEndValue(QSize(QWIDGETSIZE_MAX, FINAL_HEIGHT)); m_expandPanel = new QParallelAnimationGroup(this); m_expandPanel->addAnimation(anim1); m_expandPanel->addAnimation(anim2); connect(m_expandPanel, SIGNAL(finished()), this, SLOT(display())); } UpdateDetails::~UpdateDetails() { } void UpdateDetails::setPackage(const QString &packageId, Transaction::Info updateInfo) { if (m_packageId == packageId) { return; } m_show = true; m_packageId = packageId; m_updateInfo = updateInfo; m_currentDescription.clear(); if (m_transaction) { disconnect(m_transaction, SIGNAL(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime)), this, SLOT(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime))); disconnect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(display())); } m_transaction = Daemon::getUpdateDetail(m_packageId); connect(m_transaction, SIGNAL(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime)), this, SLOT(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime))); connect(m_transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(display())); if (maximumSize().height() == 0) { // Expand the panel m_expandPanel->setDirection(QAbstractAnimation::Forward); m_expandPanel->start(); } else if (m_fadeDetails->currentValue().toReal() != 0) { // Hide the old description m_fadeDetails->setDirection(QAbstractAnimation::Backward); m_fadeDetails->start(); } m_busySeq->start(); } void UpdateDetails::hide() { m_show = false; m_packageId.clear(); if (maximumSize().height() == FINAL_HEIGHT && m_fadeDetails->currentValue().toReal() == 1) { m_fadeDetails->setDirection(QAbstractAnimation::Backward); m_fadeDetails->start(); } else if (maximumSize().height() == FINAL_HEIGHT && m_fadeDetails->currentValue().toReal() == 0) { m_expandPanel->setDirection(QAbstractAnimation::Backward); m_expandPanel->start(); } } void UpdateDetails::display() { qCDebug(APPER) << sender(); // set transaction to 0 as if PK crashes // UpdateDetails won't be emmited m_transaction = 0; if (!m_show) { hide(); return; } if (maximumSize().height() == FINAL_HEIGHT && !m_currentDescription.isEmpty() && m_fadeDetails->currentValue().toReal() == 0) { descriptionKTB->setHtml(m_currentDescription); m_fadeDetails->setDirection(QAbstractAnimation::Forward); m_fadeDetails->start(); } else if (m_currentDescription.isEmpty()) { updateDetailFinished(); } } void UpdateDetails::updateDetail(const QString &packageID, const QStringList &updates, const QStringList &obsoletes, const QStringList &vendorUrls, const QStringList &bugzillaUrls, const QStringList &cveUrls, PackageKit::Transaction::Restart restart, const QString &updateText, const QString &changelog, PackageKit::Transaction::UpdateState state, const QDateTime &issued, const QDateTime &updated) { //format and show description QString description; // update type (ie Security Update) if (m_updateInfo == Transaction::InfoEnhancement) { description += "

" + i18n("This update will add new features and expand functionality.") + "

"; } else if (m_updateInfo == Transaction::InfoBugfix) { description += "

" + i18n("This update will fix bugs and other non-critical problems.") + "

"; } else if (m_updateInfo == Transaction::InfoImportant) { description += "

" + i18n("This update is important as it may solve critical problems.") + "

"; } else if (m_updateInfo == Transaction::InfoSecurity) { description += "

" + i18n("This update is needed to fix a security vulnerability with this package.") + "

"; } else if (m_updateInfo == Transaction::InfoBlocked) { description += "

" + i18n("This update is blocked.") + "

"; } // Issued and Updated if (!issued.isNull() && !updated.isNull()) { description += "

" + i18n("This notification was issued on %1 and last updated on %2.", QLocale::system().toString(issued, QLocale::ShortFormat), QLocale::system().toString(updated, QLocale::ShortFormat)) + "

"; } else if (!issued.isNull()) { description += "

" + i18n("This notification was issued on %1.", QLocale::system().toString(issued, QLocale::ShortFormat)) + "

"; } // Description if (!updateText.isEmpty()) { QString _updateText = updateText; _updateText.replace('\n', "
"); _updateText.replace(' ', " "); description += "

" + _updateText + "

"; } // links // Vendor if (!vendorUrls.isEmpty()) { description += "

" + i18np("For more information about this update please visit this website:", "For more information about this update please visit these websites:", vendorUrls.size()) + "
" + getLinkList(vendorUrls) + "

"; } // Bugzilla if (!bugzillaUrls.isEmpty()) { description += "

" + i18np("For more information about bugs fixed by this update please visit this website:", "For more information about bugs fixed by this update please visit these websites:", bugzillaUrls.size()) + "
" + getLinkList(bugzillaUrls) + "

"; } // CVE if (!cveUrls.isEmpty()) { description += "

" + i18np("For more information about this security update please visit this website:", "For more information about this security update please visit these websites:", cveUrls.size()) + "
" + getLinkList(cveUrls) + "

"; } // Notice (about the need for a reboot) if (restart == Transaction::RestartSystem) { description += "

" + i18n("The computer will have to be restarted after the update for the changes to take effect.") + "

"; } else if (restart == Transaction::RestartSession) { description += "

" + i18n("You will need to log out and back in after the update for the changes to take effect.") + "

"; } // State if (state == Transaction::UpdateStateUnstable) { description += "

" + i18n("The classification of this update is unstable which means it is not designed for production use.") + "

"; } else if (state == Transaction::UpdateStateTesting) { description += "

" + i18n("This is a test update, and is not designed for normal use. Please report any problems or regressions you encounter.") + "

"; } // only show changelog if we didn't have any update text if (updateText.isEmpty() && !changelog.isEmpty()) { QString _changelog = changelog; _changelog.replace('\n', "
"); _changelog.replace(' ', " "); description += "

" + i18n("The developer logs will be shown as no description is available for this update:") + "
" + _changelog + "

"; } // Updates (lists of packages that are updated) if (!updates.isEmpty()) { description += "

" + i18n("Updates:") + "
"; QStringList _updates; foreach (const QString &pid, updates) { _updates += QString::fromUtf8("\xE2\x80\xA2 ") + Transaction::packageName(pid) + " - " + Transaction::packageVersion(pid); } description += _updates.join("
") + "

"; } // Obsoletes (lists of packages that are obsoleted) if (obsoletes.size()) { description += "

" + i18n("Obsoletes:") + "
"; QStringList _obsoletes; foreach (const QString &pid, obsoletes) { _obsoletes += QString::fromUtf8("\xE2\x80\xA2 ") + Transaction::packageName(pid) + " - " + Transaction::packageVersion(pid); } description += _obsoletes.join("
/") + "

"; } // Repository (this is the repository the package comes from) if (!Transaction::packageData(packageID).isEmpty()) { description += "

" + i18n("Repository: %1", Transaction::packageData(packageID)) + "

"; } m_currentDescription = description; m_busySeq->stop(); } QString UpdateDetails::getLinkList(const QStringList &urls) const { QString ret; foreach (const QString &url, urls) { if (!ret.isEmpty()) { ret += "
"; } ret += QString::fromUtf8(" \xE2\x80\xA2 ") % url % QLatin1String(""); } return ret; } void UpdateDetails::updateDetailFinished() { if (descriptionKTB->document()->toPlainText().isEmpty()) { descriptionKTB->setPlainText(i18n("No update description was found.")); } } - -#include "UpdateDetails.moc" diff --git a/ApperKCM/Updater/Updater.cpp b/ApperKCM/Updater/Updater.cpp index 791c8cc..1f15212 100644 --- a/ApperKCM/Updater/Updater.cpp +++ b/ApperKCM/Updater/Updater.cpp @@ -1,361 +1,359 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "Updater.h" #include "ui_Updater.h" #include "UpdateDetails.h" #include "DistroUpgrade.h" #include "CheckableHeader.h" #include //#include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include Updater::Updater(Transaction::Roles roles, QWidget *parent) : QWidget(parent), ui(new Ui::Updater), m_roles(roles), m_selected(true), m_updatesT(0) { ui->setupUi(this); updatePallete(); // connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), // this, SLOT(updatePallete())); m_updatesModel = new PackageModel(this); m_updatesModel->setCheckable(true); ApplicationSortFilterModel *proxyModel = new ApplicationSortFilterModel(this); proxyModel->setSourceModel(m_updatesModel); ui->packageView->setModel(proxyModel); m_delegate = new ApplicationsDelegate(ui->packageView); m_delegate->setCheckable(true); ui->packageView->setItemDelegate(m_delegate); ui->packageView->sortByColumn(PackageModel::NameCol, Qt::AscendingOrder); connect(m_updatesModel, SIGNAL(changed(bool)), this, SLOT(checkEnableUpdateButton())); //initialize the model, delegate, client and connect it's signals m_header = new CheckableHeader(Qt::Horizontal, this); connect(m_header, SIGNAL(toggled(bool)), m_updatesModel, SLOT(setAllChecked(bool))); m_header->setCheckBoxVisible(false); m_header->setDefaultAlignment(Qt::AlignCenter); ui->packageView->setHeaderHidden(false); ui->packageView->setHeader(m_header); // This must be set AFTER the model is set, otherwise it doesn't work m_header->setSectionResizeMode(PackageModel::NameCol, QHeaderView::Stretch); m_header->setSectionResizeMode(PackageModel::VersionCol, QHeaderView::ResizeToContents); m_header->setSectionResizeMode(PackageModel::CurrentVersionCol, QHeaderView::ResizeToContents); m_header->setSectionResizeMode(PackageModel::ArchCol, QHeaderView::ResizeToContents); m_header->setSectionResizeMode(PackageModel::OriginCol, QHeaderView::ResizeToContents); m_header->setSectionResizeMode(PackageModel::SizeCol, QHeaderView::ResizeToContents); m_header->setStretchLastSection(false); // Setup the busy cursor m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(ui->packageView->viewport()); // hide distro Upgrade container and line ui->distroUpgrade->hide(); KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); // versions ui->packageView->header()->setSectionHidden(PackageModel::VersionCol, true); m_showPackageVersion = new QAction(i18n("Show Versions"), this); m_showPackageVersion->setCheckable(true); connect(m_showPackageVersion, SIGNAL(toggled(bool)), this, SLOT(showVersions(bool))); m_showPackageVersion->setChecked(viewGroup.readEntry("ShowVersions", true)); // versions ui->packageView->header()->setSectionHidden(PackageModel::CurrentVersionCol, true); m_showPackageCurrentVersion = new QAction(i18n("Show Current Versions"), this); m_showPackageCurrentVersion->setCheckable(true); connect(m_showPackageCurrentVersion, SIGNAL(toggled(bool)), this, SLOT(showCurrentVersions(bool))); m_showPackageCurrentVersion->setChecked(viewGroup.readEntry("ShowCurrentVersions", false)); // Arch ui->packageView->header()->setSectionHidden(PackageModel::ArchCol, true); m_showPackageArch = new QAction(i18n("Show Architectures"), this); m_showPackageArch->setCheckable(true); connect(m_showPackageArch, SIGNAL(toggled(bool)), this, SLOT(showArchs(bool))); m_showPackageArch->setChecked(viewGroup.readEntry("ShowArchs", false)); // Origin ui->packageView->header()->setSectionHidden(PackageModel::OriginCol, true); m_showPackageOrigin = new QAction(i18n("Show Origins"), this); m_showPackageOrigin->setCheckable(true); connect(m_showPackageOrigin, SIGNAL(toggled(bool)), this, SLOT(showOrigins(bool))); m_showPackageOrigin->setChecked(viewGroup.readEntry("ShowOrigins", false)); // Sizes ui->packageView->header()->setSectionHidden(PackageModel::SizeCol, true); m_showPackageSize = new QAction(i18n("Show Sizes"), this); m_showPackageSize->setCheckable(true); connect(m_showPackageSize, SIGNAL(toggled(bool)), this, SLOT(showSizes(bool))); m_showPackageSize->setChecked(viewGroup.readEntry("ShowSizes", true)); } Updater::~Updater() { delete ui; } void Updater::showVersions(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowVersions", enabled); ui->packageView->header()->setSectionHidden(PackageModel::VersionCol, !enabled); } void Updater::showCurrentVersions(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowCurrentVersions", enabled); ui->packageView->header()->setSectionHidden(PackageModel::CurrentVersionCol, !enabled); if (enabled) { m_updatesModel->fetchCurrentVersions(); } } void Updater::showArchs(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowArchs", enabled); ui->packageView->header()->setSectionHidden(PackageModel::ArchCol, !enabled); } void Updater::showOrigins(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("showOrigins", enabled); ui->packageView->header()->setSectionHidden(PackageModel::OriginCol, !enabled); } void Updater::showSizes(bool enabled) { KConfig config("apper"); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowSizes", enabled); ui->packageView->header()->setSectionHidden(PackageModel::SizeCol, !enabled); if (enabled) { m_updatesModel->fetchSizes(); } } void Updater::updatePallete() { QPalette pal; pal.setColor(QPalette::Window, pal.base().color()); pal.setColor(QPalette::WindowText, pal.text().color()); ui->backgroundFrame->setPalette(pal); } void Updater::on_packageView_clicked(const QModelIndex &index) { QString pkgId = index.data(PackageModel::IdRole).toString(); Transaction::Info pkgInfo = index.data(PackageModel::InfoRole).value(); ui->updateDetails->setPackage(pkgId, pkgInfo); } //TODO: We should add some kind of configuration to let users show unstable distributions //That way, by default, users only see stable ones. void Updater::distroUpgrade(PackageKit::Transaction::DistroUpgrade type, const QString &name, const QString &description) { // TODO name should be used to do a upgrade to a different type Q_UNUSED(name) if (type != Transaction::DistroUpgradeStable) { // Ignore unstable distros upgrades for now return; } ui->distroUpgrade->setName(description); ui->distroUpgrade->animatedShow(); } bool Updater::hasChanges() const { return m_updatesModel->hasChanges(); } void Updater::checkEnableUpdateButton() { emit changed(hasChanges()); int selectedSize = m_updatesModel->selectedPackagesToInstall().size(); int updatesSize = m_updatesModel->rowCount(); if (selectedSize == 0) { m_header->setCheckState(Qt::Unchecked); } else if (selectedSize == updatesSize) { m_header->setCheckState(Qt::Checked); } else { m_header->setCheckState(Qt::PartiallyChecked); } unsigned long dwSize = m_updatesModel->downloadSize(); if (dwSize) { emit downloadSize(i18n("Estimated download size: %1", KFormat().formatByteSize(dwSize))); } else { emit downloadSize(QString()); } // if we don't have any upates let's disable the button m_header->setCheckBoxVisible(m_updatesModel->rowCount() != 0); ui->packageView->setHeaderHidden(m_updatesModel->rowCount() == 0); } void Updater::load() { // set focus on the updates view ui->packageView->setFocus(Qt::OtherFocusReason); emit downloadSize(QString()); // If the model already has some packages // let's just clear the selection if (m_updatesModel->rowCount()) { m_updatesModel->setAllChecked(false); } else { getUpdates(); } } void Updater::getUpdatesFinished() { m_updatesT = 0; m_updatesModel->clearSelectedNotPresent(); checkEnableUpdateButton(); if (m_updatesModel->rowCount() == 0) { // Set the info page ui->stackedWidget->setCurrentIndex(1); uint lastTime = Daemon::global()->getTimeSinceAction(Transaction::RoleRefreshCache); ui->titleL->setText(PkStrings::lastCacheRefreshTitle(lastTime)); ui->descriptionL->setText(PkStrings::lastCacheRefreshSubTitle(lastTime)); ui->iconL->setPixmap(QIcon::fromTheme(PkIcons::lastCacheRefreshIconName(lastTime)).pixmap(128, 128)); } } QStringList Updater::packagesToUpdate() const { return m_updatesModel->selectedPackagesToInstall(); } void Updater::getUpdates() { if (m_updatesT) { // There is a getUpdates running ignore this call return; } if (ui->stackedWidget->currentIndex() != 0) { ui->stackedWidget->setCurrentIndex(0); } // clears the model ui->packageView->setHeaderHidden(true); m_updatesModel->clear(); ui->updateDetails->hide(); m_updatesT = Daemon::getUpdates(); connect(m_updatesT, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), m_updatesModel, SLOT(addSelectedPackage(PackageKit::Transaction::Info,QString,QString))); connect(m_updatesT, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), this, SLOT(errorCode(PackageKit::Transaction::Error,QString))); connect(m_updatesT, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_busySeq, SLOT(stop())); connect(m_updatesT, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_updatesModel, SLOT(finished())); // This is required to estimate download size connect(m_updatesT, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_updatesModel, SLOT(fetchSizes())); if (m_showPackageCurrentVersion->isChecked()) { connect(m_updatesT, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), m_updatesModel, SLOT(fetchCurrentVersions())); } connect(m_updatesT, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(getUpdatesFinished())); m_busySeq->start(); // Hide the distribution upgrade information ui->distroUpgrade->animatedHide(); if (m_roles & Transaction::RoleGetDistroUpgrades) { // Check for distribution Upgrades Transaction *t = Daemon::getDistroUpgrades(); connect(t, SIGNAL(distroUpgrade(PackageKit::Transaction::DistroUpgrade,QString,QString)), this, SLOT(distroUpgrade(PackageKit::Transaction::DistroUpgrade,QString,QString))); connect(t, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), t, SLOT(deleteLater())); } } void Updater::on_packageView_customContextMenuRequested(const QPoint &pos) { auto menu = new QMenu(this); menu->addAction(m_showPackageVersion); menu->addAction(m_showPackageCurrentVersion); menu->addAction(m_showPackageArch); menu->addAction(m_showPackageOrigin); menu->addAction(m_showPackageSize); QAction *action; action = menu->addAction(i18n("Check for new updates")); action->setIcon(QIcon::fromTheme("view-refresh")); connect(action, SIGNAL(triggered(bool)), this, SIGNAL(refreshCache())); menu->exec(ui->packageView->viewport()->mapToGlobal(pos)); delete menu; } void Updater::errorCode(PackageKit::Transaction::Error error, const QString &details) { KMessageBox::detailedSorry(this, PkStrings::errorMessage(error), details, PkStrings::error(error), KMessageBox::Notify); } - -#include "Updater.moc" diff --git a/CMakeLists.txt b/CMakeLists.txt index 637f050..2cd4ea0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,149 +1,148 @@ project(Apper) cmake_minimum_required(VERSION 3.0) set(APPER_VERSION 1.0.0) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) include(FindPkgConfig) include(KDEInstallDirs) include(KDECompilerSettings) include(KDECMakeSettings) include(FeatureSummary) include(ECMInstallIcons) find_package(Qt5 5.2.0 CONFIG REQUIRED Core DBus Widgets Quick Sql XmlPatterns) # Load the frameworks we need find_package(KF5 REQUIRED COMPONENTS Config DocTools GuiAddons I18n KCMUtils DBusAddons KIO Notifications IconThemes ) find_package(LibKWorkspace REQUIRED) find_package(KDED REQUIRED) find_package(PackageKitQt5 1.0.0 REQUIRED) # # Options # # The various parts of Apper that can be built, or not. option(BUILD_APPER "Build the Apper application" ON) option(BUILD_APPERKCM "Build the Apper KDE Control Module" ON) option(BUILD_APPERD "Build the Apper daemon" ON) option(BUILD_DECLARATIVE "Build the Qt Quick plugins" ON) option(BUILD_PKSESSION "Build the PkSession helper application" ON) option(BUILD_PLASMOID "Build the update notifier plasmoid" ON) # Only for Debian based systems option(DEBCONF_SUPPORT "Build Apper with debconf support" OFF) # Yum does not support this option(AUTOREMOVE "Build Apper with auto remove enabled" OFF) set(HAVE_AUTOREMOVE ${AUTOREMOVE}) message(STATUS "Building Apper with auto remove: " ${AUTOREMOVE}) # AppStream application management support option(APPSTREAM "Build Apper with AppStream support" OFF) set(HAVE_APPSTREAM ${APPSTREAM}) message(STATUS "Building Apper with AppStream support: " ${APPSTREAM}) # Enable support for Limba packages option(LIMBA "Build Apper with Limba bundle support" OFF) set(HAVE_LIMBA ${LIMBA}) message(STATUS "Building Apper with Limba support: " ${LIMBA}) option(MAINTAINER "Enable maintainer mode" OFF) if(DEBCONF_SUPPORT) # Tries to find the package, when it finds it, set HAVE_DEBCONFKDE find_package(DebconfKDE REQUIRED) message(STATUS "Building with Debconf support") set(HAVE_DEBCONF ${DEBCONF_SUPPORT}) endif(DEBCONF_SUPPORT) # command to edit the packages origins set(EDIT_ORIGNS_DESKTOP_NAME "" CACHE STRING "Edit origins desktop name") if (EDIT_ORIGNS_DESKTOP_NAME) message(STATUS "Edit origins desktop name: " ${EDIT_ORIGNS_DESKTOP_NAME}) endif(EDIT_ORIGNS_DESKTOP_NAME) # Generate config.h configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # # Add definitions # set(MAINTAINER_CFLAGS "") if(MAINTAINER) set(MAINTAINER_CFLAGS "-Werror -Wall -Wcast-align -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self -Wno-deprecated-declarations") if (CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9) set(MAINTAINER_CFLAGS ${MAINTAINER_CFLAGS} "-fdiagnostics-color=auto") endif() endif() endif(MAINTAINER) add_definitions(${MAINTAINER_CFLAGS}) -add_definitions("-std=gnu++11") add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_STRICT_ITERATORS -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_USE_FAST_OPERATOR_PLUS ) # # Global includes # include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${PackageKitQt5_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libapper) # # Subcomponents # add_subdirectory(libapper) if(BUILD_APPERKCM) add_subdirectory(ApperKCM) endif(BUILD_APPERKCM) if(BUILD_APPER) add_subdirectory(Apper) endif(BUILD_APPER) if(BUILD_PKSESSION) add_subdirectory(PkSession) endif(BUILD_PKSESSION) if(BUILD_APPERD) add_subdirectory(apperd) endif(BUILD_APPERD) if(BUILD_DECLARATIVE) add_subdirectory(declarative-plugins) endif(BUILD_DECLARATIVE) if(BUILD_PLASMOID) add_subdirectory(plasmoid) endif(BUILD_PLASMOID) if(LIMBA) add_subdirectory(AppSetup) endif() add_subdirectory(doc) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/libapper/PackageModel.cpp b/libapper/PackageModel.cpp index cd6c9ce..4d4c8f7 100644 --- a/libapper/PackageModel.cpp +++ b/libapper/PackageModel.cpp @@ -1,876 +1,881 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * Copyright (C) 2008 by Trever Fischer * * wm161@wm161.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include "PackageModel.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_APPSTREAM #include #endif #define ICON_SIZE 22 #define OVERLAY_SIZE 16 using namespace PackageKit; PackageModel::PackageModel(QObject *parent) : QAbstractItemModel(parent), m_finished(false), m_checkable(false), m_fetchSizesTransaction(0), m_fetchInstalledVersionsTransaction(0) { m_installedEmblem = PkIcons::getIcon("dialog-ok-apply", QString()).pixmap(16, 16); m_roles[SortRole] = "rSort"; m_roles[NameRole] = "rName"; m_roles[SummaryRole] = "rSummary"; m_roles[VersionRole] = "rVersion"; m_roles[ArchRole] = "rArch"; m_roles[IconRole] = "rIcon"; m_roles[IdRole] = "rId"; m_roles[CheckStateRole] = "rChecked"; m_roles[InfoRole] = "rInfo"; m_roles[ApplicationId] = "rApplicationId"; m_roles[IsPackageRole] = "rIsPackageRole"; m_roles[PackageName] = "rPackageName"; m_roles[InfoIconRole] = "rInfoIcon"; } void PackageModel::addSelectedPackagesFromModel(PackageModel *model) { - QList packages = model->internalSelectedPackages(); - foreach (const InternalPackage &package, packages) { + const QList packages = model->internalSelectedPackages(); + for (const InternalPackage &package : packages) { addPackage(package.info, package.packageID, package.summary, true); } finished(); } +void PackageModel::addNotSelectedPackage(Transaction::Info info, const QString &packageID, const QString &summary) +{ + addPackage(info, packageID, summary); +} + void PackageModel::addPackage(Transaction::Info info, const QString &packageID, const QString &summary, bool selected) { if (m_finished) { qDebug() << Q_FUNC_INFO << "we are finished calling clear"; clear(); } switch(info) { case Transaction::InfoBlocked: case Transaction::InfoFinished: case Transaction::InfoCleanup: return; default: break; } #ifdef HAVE_APPSTREAM QList applications; if (!m_checkable) { applications = AppStream::instance()->applications(Transaction::packageName(packageID)); foreach (const AppStream::Application &app, applications) { InternalPackage iPackage; iPackage.info = info; iPackage.packageID = packageID; iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.isPackage = false; if (app.name.isEmpty()) { iPackage.displayName = Transaction::packageName(packageID); } else { iPackage.displayName = app.name; } if (app.summary.isEmpty()) { iPackage.summary = summary; } else { iPackage.summary = app.summary; } iPackage.icon = app.icon_url; iPackage.appId = app.id; iPackage.size = 0; if (selected) { checkPackage(iPackage, false); } m_packages.append(iPackage); } } if (applications.isEmpty()) { #endif //HAVE_APPSTREAM InternalPackage iPackage; iPackage.info = info; iPackage.packageID = packageID; iPackage.displayName = Transaction::packageName(packageID); iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.summary = summary; iPackage.size = 0; #ifdef HAVE_APPSTREAM iPackage.icon = AppStream::instance()->genericIcon(Transaction::packageName(packageID)); if (iPackage.icon.isEmpty()) iPackage.icon = Transaction::packageIcon(packageID); if (m_checkable) { // in case of updates model only check if it's an app applications = AppStream::instance()->applications(Transaction::packageName(packageID)); if (!applications.isEmpty() || !Transaction::packageIcon(packageID).isEmpty()) { iPackage.isPackage = false; } else { iPackage.isPackage = true; } } else { iPackage.isPackage = true; } #else iPackage.isPackage = true; #endif // HAVE_APPSTREAM if (selected) { checkPackage(iPackage, false); } m_packages.append(iPackage); #ifdef HAVE_APPSTREAM } #endif // HAVE_APPSTREAM } void PackageModel::addSelectedPackage(Transaction::Info info, const QString &packageID, const QString &summary) { addPackage(info, packageID, summary, true); } QVariant PackageModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant ret; if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case NameCol: if (m_checkable) { ret = PkStrings::packageQuantity(true, m_packages.size(), m_checkedPackages.size()); } else { ret = i18n("Name"); } break; case VersionCol: ret = i18n("Version"); break; case CurrentVersionCol: ret = i18n("Installed Version"); break; case ArchCol: ret = i18n("Arch"); break; case OriginCol: ret = i18n("Origin"); break; case SizeCol: ret = i18n("Size"); break; case ActionCol: ret = i18n("Action"); break; } } return ret; } int PackageModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !m_finished) { return 0; } return m_packages.size(); } QModelIndex PackageModel::index(int row, int column, const QModelIndex &parent) const { // kDebug() << parent.isValid() << m_packageCount << row << column; // Check to see if the index isn't out of list if (!parent.isValid() && m_packages.size() > row) { return createIndex(row, column); } return QModelIndex(); } QModelIndex PackageModel::parent(const QModelIndex &index) const { Q_UNUSED(index) return QModelIndex(); } QHash PackageModel::roleNames() const { return m_roles; } QVariant PackageModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const InternalPackage &package = m_packages[index.row()]; if (index.column() == NameCol) { switch (role) { case Qt::CheckStateRole: if (!m_checkable) { return QVariant(); } if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case CheckStateRole: if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case IsPackageRole: return package.isPackage; case Qt::DisplayRole: return package.displayName; case Qt::DecorationRole: { QPixmap icon = QPixmap(44, ICON_SIZE); icon.fill(Qt::transparent); if (!package.icon.isNull()) { QPixmap pixmap; if (package.icon.startsWith("/")) { pixmap = QPixmap(); pixmap.load(package.icon); pixmap = pixmap.scaledToHeight(ICON_SIZE); } else { pixmap = KIconLoader::global()->loadIcon(package.icon, KIconLoader::NoGroup, ICON_SIZE, KIconLoader::DefaultState, QStringList(), 0L, true); } if (!pixmap.isNull()) { QPainter painter(&icon); painter.drawPixmap(QPoint(2, 0), pixmap); } } if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { QPainter painter(&icon); QPoint startPoint; // bottom right corner startPoint = QPoint(44 - OVERLAY_SIZE, 4); painter.drawPixmap(startPoint, m_installedEmblem); } else if (m_checkable) { QIcon emblemIcon = PkIcons::packageIcon(package.info); QPainter painter(&icon); QPoint startPoint; // bottom right corner startPoint = QPoint(44 - OVERLAY_SIZE, 4); painter.drawPixmap(startPoint, emblemIcon.pixmap(OVERLAY_SIZE, OVERLAY_SIZE)); } return icon; } case PackageName: return Transaction::packageName(package.packageID); case Qt::ToolTipRole: if (m_checkable) { return PkStrings::info(package.info); } else { return i18n("Version: %1\nArchitecture: %2", package.version, package.arch); } } } else if (role == Qt::DisplayRole) { if (index.column() == VersionCol) { return package.version; } else if (index.column() == CurrentVersionCol) { return package.currentVersion; } else if (index.column() == ArchCol) { return package.arch; } else if (index.column() == OriginCol) { return package.repo; } else if (index.column() == SizeCol) { KFormat f; return package.size ? f.formatByteSize(package.size) : QString(); } } else if (index.column() == SizeCol && role == Qt::TextAlignmentRole) { return static_cast(Qt::AlignRight | Qt::AlignVCenter); } switch (role) { case IconRole: return package.icon; case SortRole: return QString(package.displayName % QLatin1Char(' ') % package.version % QLatin1Char(' ') % package.arch); case CheckStateRole: if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case IdRole: return package.packageID; case NameRole: return package.displayName; case SummaryRole: return package.summary; case VersionRole: return package.version; case ArchRole: return package.arch; case OriginCol: return package.repo; case InfoRole: return qVariantFromValue(package.info); case KCategorizedSortFilterProxyModel::CategoryDisplayRole: if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { return i18n("To be Removed"); } else { return i18n("To be Installed"); } case KCategorizedSortFilterProxyModel::CategorySortRole: // USING 0 here seems to let things unsorted return package.isPackage ? 1 : 0; // Packages comes after applications case ApplicationId: return package.appId; case InfoIconRole: return PkIcons::packageIcon(package.info); default: return QVariant(); } return QVariant(); } bool PackageModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::CheckStateRole && m_packages.size() > index.row()) { if (value.toBool()) { checkPackage(m_packages[index.row()]); } else { uncheckPackage(m_packages[index.row()].packageID); } emit changed(!m_checkedPackages.isEmpty()); return true; } return false; } Qt::ItemFlags PackageModel::flags(const QModelIndex &index) const { if (index.column() == NameCol) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | QAbstractItemModel::flags(index); } return QAbstractItemModel::flags(index); } int PackageModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); if (m_checkable) { // when the model is checkable the action column is not shown return ActionCol; } else { return ActionCol + 1; } } void PackageModel::removePackage(const QString &packageID) { int i = 0; while (i < m_packages.size()) { InternalPackage iPackage = m_packages[i]; if (iPackage.packageID == packageID && iPackage.info != Transaction::InfoUntrusted) { beginRemoveRows(QModelIndex(), i, i); m_packages.remove(i); endRemoveRows(); // since we removed one entry we don't // need to increase the counter continue; } ++i; } } void PackageModel::clear() { qDebug() << Q_FUNC_INFO; beginRemoveRows(QModelIndex(), 0, m_packages.size()); m_finished = false; m_packages.clear(); m_fetchSizesTransaction = 0; m_fetchInstalledVersionsTransaction = 0; if (m_getUpdatesTransaction) { m_getUpdatesTransaction->disconnect(this); m_getUpdatesTransaction->cancel(); } endRemoveRows(); } void PackageModel::clearSelectedNotPresent() { foreach (const InternalPackage &package, m_checkedPackages) { bool notFound = true; foreach (const InternalPackage &iPackage, m_packages) { if (iPackage.packageID == package.packageID) { notFound = false; break; } } if (notFound) { // Uncheck the package If it's not in the model uncheckPackage(package.packageID); } } } bool PackageModel::checkable() const { return m_checkable; } void PackageModel::uncheckInstalledPackages() { foreach (const InternalPackage &package, m_checkedPackages) { if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { uncheckPackage(package.packageID, true); } } } void PackageModel::uncheckAvailablePackages() { foreach (const InternalPackage &package, m_checkedPackages) { if (package.info == Transaction::InfoAvailable || package.info == Transaction::InfoCollectionAvailable) { uncheckPackage(package.packageID, true); } } } void PackageModel::finished() { Transaction *trans = qobject_cast(sender()); qDebug() << Q_FUNC_INFO << trans << sender(); if (trans /*== m_getUpdatesTransaction*/) { // m_getUpdatesTransaction = 0; // When pkd dies this method is called twice // pk-qt2 bug.. trans->disconnect(this, SLOT(finished())); } // The whole structure is about to change if (!m_packages.isEmpty()) { beginInsertRows(QModelIndex(), 0, m_packages.size() - 1); m_finished = true; endInsertRows(); } emit changed(!m_checkedPackages.isEmpty()); } void PackageModel::fetchSizes() { if (m_fetchSizesTransaction) { return; } // get package size QStringList pkgs; foreach (const InternalPackage &p, m_packages) { pkgs << p.packageID; } if (!pkgs.isEmpty()) { m_fetchSizesTransaction = Daemon::getDetails(pkgs); connect(m_fetchSizesTransaction, SIGNAL(details(PackageKit::Details)), SLOT(updateSize(PackageKit::Details))); connect(m_fetchSizesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(fetchSizesFinished())); } } void PackageModel::fetchSizesFinished() { Transaction *trans = qobject_cast(sender()); if (trans) { // When pkd dies this method is called twice // pk-qt2 bug.. trans->disconnect(this, SLOT(fetchSizesFinished())); } // emit this after all is changed otherwise on large models it will // be hell slow... emit dataChanged(createIndex(0, SizeCol), createIndex(m_packages.size(), SizeCol)); emit changed(!m_checkedPackages.isEmpty()); } void PackageModel::updateSize(const PackageKit::Details &details) { // if size is 0 don't waste time looking for the package qulonglong size = details.size(); if (size == 0) { return; } for (int i = 0; i < m_packages.size(); ++i) { const QString &packageId = details.packageId(); if (packageId == m_packages[i].packageID) { m_packages[i].size = size; if (m_checkable) { // updates the checked packages as well if (m_checkedPackages.contains(packageId)) { // Avoid checking packages that aren't checked m_checkedPackages[packageId].size = size; } break; } #ifdef HAVE_APPSTREAM if (m_checkable) { // checkable models don't have duplicated package ids // so don't waste time scanning all list break; } #else // Without AppStream we don't have duplicated package ids break; #endif // HAVE_APPSTREAM } } } void PackageModel::fetchCurrentVersions() { if (m_fetchInstalledVersionsTransaction) { return; } // get package current version QStringList pkgs; foreach (const InternalPackage &p, m_packages) { pkgs << Transaction::packageName(p.packageID); } if (!pkgs.isEmpty()) { m_fetchInstalledVersionsTransaction = Daemon::resolve(pkgs, Transaction::FilterInstalled);; connect(m_fetchInstalledVersionsTransaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), this, SLOT(updateCurrentVersion(PackageKit::Transaction::Info,QString,QString))); connect(m_fetchInstalledVersionsTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(fetchCurrentVersionsFinished())); } } void PackageModel::fetchCurrentVersionsFinished() { Transaction *trans = qobject_cast(sender()); if (trans) { // When pkd dies this method is called twice // pk-qt2 bug.. trans->disconnect(this, SLOT(fetchCurrentVersionsFinished())); } // emit this after all is changed otherwise on large models it will // be hell slow... emit dataChanged(createIndex(0, CurrentVersionCol), createIndex(m_packages.size(), CurrentVersionCol)); emit changed(!m_checkedPackages.isEmpty()); } void PackageModel::updateCurrentVersion(Transaction::Info info, const QString &packageID, const QString &summary) { Q_UNUSED(info) Q_UNUSED(summary) // if current version is empty don't waste time looking if (!Transaction::packageVersion(packageID).isEmpty()) { for (int i = 0; i < m_packages.size(); ++i) { if (Transaction::packageName(packageID) == Transaction::packageName(m_packages[i].packageID) && Transaction::packageArch(packageID) == m_packages[i].arch) { m_packages[i].currentVersion = Transaction::packageVersion(packageID); if (m_checkable) { // updates the checked packages as well if (m_checkedPackages.contains(m_packages[i].packageID)) { // Avoid checking packages that aren't checked m_checkedPackages[m_packages[i].packageID].currentVersion = Transaction::packageVersion(packageID); } break; } } } } } void PackageModel::getUpdates(bool fetchCurrentVersions, bool selected) { clear(); m_getUpdatesTransaction = Daemon::getUpdates(); if (selected) { connect(m_getUpdatesTransaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), this, SLOT(addSelectedPackage(PackageKit::Transaction::Info,QString,QString))); } else { connect(m_getUpdatesTransaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), this, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); } connect(m_getUpdatesTransaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), this, SLOT(errorCode(PackageKit::Transaction::Error,QString))); // connect(m_getUpdatesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), // m_busySeq, SLOT(stop())); // connect(m_getUpdatesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), // this, SLOT(finished())); // This is required to estimate download size connect(m_getUpdatesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(fetchSizes())); if (fetchCurrentVersions) { connect(m_getUpdatesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(fetchCurrentVersions())); } connect(m_getUpdatesTransaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), this, SLOT(getUpdatesFinished())); // get all updates } void PackageModel::toggleSelection(const QString &packageID) { if (containsChecked(packageID)) { uncheckPackage(packageID, true); } else { foreach (const InternalPackage &package, m_packages) { if (package.packageID == packageID) { checkPackage(package); break; } } } } QString PackageModel::selectionStateText() const { return headerData(NameCol, Qt::Horizontal).toString(); } bool PackageModel::hasChanges() const { return !m_checkedPackages.isEmpty(); } int PackageModel::countInfo(PackageKit::Transaction::Info info) const { int ret = 0; foreach (const InternalPackage &package, m_packages) { if (package.info == info) { ++ret; } } return ret; } void PackageModel::checkPackage(const InternalPackage &package, bool emitDataChanged) { QString pkgId = package.packageID; if (!containsChecked(pkgId)) { m_checkedPackages[pkgId] = package; // A checkable model does not have duplicated entries if (emitDataChanged || !m_checkable || !m_packages.isEmpty()) { // This is a slow operation so in case the user // is unchecking all of the packages there is // no need to emit data changed for every item for (int i = 0; i < m_packages.size(); ++i) { if (m_packages[i].packageID == pkgId) { QModelIndex index = createIndex(i, 0); emit dataChanged(index, index); } } // The model might not be displayed yet if (m_finished) { emit changed(!m_checkedPackages.isEmpty()); } } } } void PackageModel::uncheckPackage(const QString &packageID, bool forceEmitUnchecked, bool emitDataChanged) { if (containsChecked(packageID)) { m_checkedPackages.remove(packageID); if (forceEmitUnchecked || sender() == 0) { // The package might be removed by rmSelectedPackage // If we don't copy it the browse model won't uncheck there // right package emit packageUnchecked(packageID); } if (emitDataChanged || !m_checkable) { // This is a slow operation so in case the user // is unchecking all of the packages there is // no need to emit data changed for every item for (int i = 0; i < m_packages.size(); ++i) { if (m_packages[i].packageID == packageID) { QModelIndex index = createIndex(i, 0); emit dataChanged(index, index); } } // The model might not be displayed yet if (m_finished) { emit changed(!m_checkedPackages.isEmpty()); } } } } QList PackageModel::internalSelectedPackages() const { QList ret; QHash::const_iterator i = m_checkedPackages.constBegin(); while (i != m_checkedPackages.constEnd()) { ret << i.value(); ++i; } return ret; } bool PackageModel::containsChecked(const QString &pid) const { if (m_checkedPackages.isEmpty()) { return false; } return m_checkedPackages.contains(pid); } void PackageModel::setAllChecked(bool checked) { if (checked) { m_checkedPackages.clear(); foreach (const InternalPackage &package, m_packages) { checkPackage(package, false); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); } else { // This is a very slow operation, which in here we try to optimize foreach (const InternalPackage &package, m_checkedPackages) { uncheckPackage(package.packageID, true, false); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); } emit changed(!m_checkedPackages.isEmpty()); } QStringList PackageModel::selectedPackagesToInstall() const { QStringList list; foreach (const InternalPackage &package, m_checkedPackages) { if (package.info != Transaction::InfoInstalled && package.info != Transaction::InfoCollectionInstalled) { // append the packages are not installed list << package.packageID; } } return list; } QStringList PackageModel::selectedPackagesToRemove() const { QStringList list; foreach (const InternalPackage &package, m_checkedPackages) { if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { // check what packages are installed and marked to be removed list << package.packageID; } } return list; } QStringList PackageModel::packagesWithInfo(Transaction::Info info) const { QStringList list; foreach (const InternalPackage &package, m_packages) { if (package.info == info) { // Append to the list if the package matches the info value list << package.packageID; } } return list; } QStringList PackageModel::packageIDs() const { QStringList list; foreach (const InternalPackage &package, m_packages) { list << package.packageID; } return list; } unsigned long PackageModel::downloadSize() const { unsigned long size = 0; foreach (const InternalPackage &package, m_checkedPackages) { size += package.size; } return size; } bool PackageModel::allSelected() const { foreach (const InternalPackage &package, m_packages) { if (!containsChecked(package.packageID)) { return false; } } return true; } void PackageModel::setCheckable(bool checkable) { m_checkable = checkable; } diff --git a/libapper/PackageModel.h b/libapper/PackageModel.h index 4dc46a3..0075cb1 100644 --- a/libapper/PackageModel.h +++ b/libapper/PackageModel.h @@ -1,155 +1,156 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef PACKAGE_MODEL_H #define PACKAGE_MODEL_H #include #include #include #include
class Q_DECL_EXPORT PackageModel : public QAbstractItemModel { Q_OBJECT Q_PROPERTY(bool checkable READ checkable WRITE setCheckable NOTIFY changed) Q_PROPERTY(QString selectionStateText READ selectionStateText NOTIFY changed) public: enum { NameCol = 0, VersionCol, CurrentVersionCol, ArchCol, OriginCol, SizeCol, ActionCol }; enum { SortRole = Qt::UserRole, NameRole, SummaryRole, VersionRole, ArchRole, IconRole, IdRole, CheckStateRole, InfoRole, ApplicationId, IsPackageRole, PackageName, InfoIconRole }; typedef struct { QString displayName; QString version; QString arch; QString repo; QString packageID; QString summary; PackageKit::Transaction::Info info; QString icon; QString appId; QString currentVersion; bool isPackage; double size; } InternalPackage; explicit PackageModel(QObject *parent = 0); Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Q_INVOKABLE bool allSelected() const; Q_INVOKABLE QStringList selectedPackagesToInstall() const; Q_INVOKABLE QStringList selectedPackagesToRemove() const; Q_INVOKABLE QStringList packagesWithInfo(PackageKit::Transaction::Info info) const; Q_INVOKABLE QStringList packageIDs() const; unsigned long downloadSize() const; Q_INVOKABLE void clear(); /** * This removes all selected packages that are not in the model */ Q_INVOKABLE void clearSelectedNotPresent(); bool checkable() const; void setCheckable(bool checkable); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; virtual QHash roleNames() const override; public Q_SLOTS: void addSelectedPackagesFromModel(PackageModel *model); + void addNotSelectedPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void addPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary, bool selected = false); void addSelectedPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void removePackage(const QString &packageID); void setAllChecked(bool checked); void checkPackage(const PackageModel::InternalPackage &package, bool emitDataChanged = true); void uncheckPackage(const QString &packageID, bool forceEmitUnchecked = false, bool emitDataChanged = true); bool hasChanges() const; int countInfo(PackageKit::Transaction::Info info) const; void uncheckInstalledPackages(); void uncheckAvailablePackages(); void finished(); void fetchSizes(); void fetchSizesFinished(); void updateSize(const PackageKit::Details &details); void fetchCurrentVersions(); void fetchCurrentVersionsFinished(); void updateCurrentVersion(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void getUpdates(bool fetchCurrentVersions, bool selected); void toggleSelection(const QString &packageID); QString selectionStateText() const; Q_SIGNALS: void changed(bool value); void packageUnchecked(const QString &packageID); private: QList internalSelectedPackages() const; bool containsChecked(const QString &pid) const; bool m_finished = true; bool m_checkable; QPixmap m_installedEmblem; QVector m_packages; QHash m_checkedPackages; PackageKit::Transaction *m_getUpdatesTransaction = 0; PackageKit::Transaction *m_fetchSizesTransaction; PackageKit::Transaction *m_fetchInstalledVersionsTransaction; QHash m_roles; }; #endif diff --git a/libapper/PkIcons.cpp b/libapper/PkIcons.cpp index 2421aa7..ed038a3 100644 --- a/libapper/PkIcons.cpp +++ b/libapper/PkIcons.cpp @@ -1,338 +1,340 @@ /*************************************************************************** * Copyright (C) 2008 by Trever Fischer * * wm161@wm161.net * * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include "PkIcons.h" #include #include Q_LOGGING_CATEGORY(APPER_LIB, "apper.lib") //#include using namespace PackageKit; bool PkIcons::init = false; QHash PkIcons::cache = QHash(); void PkIcons::configure() { QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() + QStringList{"xdgdata-pixmap", "/usr/share/app-info/icons/", "/usr/share/app-install/icons/"}); // KStandardDirs:: KGlobal::dirs()->addResourceDir("xdgdata-pixmap", "/usr/share/app-info/icons/", "/usr/share/app-install/icons/"); // KIconLoader::global()->reconfigure("apper"); PkIcons::init = true; } QIcon PkIcons::getIcon(const QString &name) { if (!PkIcons::init) { PkIcons::configure(); } return QIcon::fromTheme(name); } QIcon PkIcons::getIcon(const QString &name, const QString &defaultName) { if (!PkIcons::init) { PkIcons::configure(); } if (name.isEmpty()) { return QIcon(); } bool isNull; isNull = KIconLoader::global()->iconPath(name, KIconLoader::NoGroup, true).isEmpty(); if (isNull && !defaultName.isNull()) { return QIcon::fromTheme(defaultName); } else if (isNull) { return QIcon(); } return QIcon::fromTheme(name); } QString PkIcons::statusIconName(Transaction::Status status) { if (!PkIcons::init) { PkIcons::configure(); } switch (status) { case Transaction::StatusUnknown : return "help-browser"; case Transaction::StatusCancel : case Transaction::StatusCleanup : return "package-clean-up"; case Transaction::StatusCommit : return "package-working";//TODO needs a better icon case Transaction::StatusDepResolve : return "package-info"; case Transaction::StatusDownloadChangelog : case Transaction::StatusDownloadFilelist : case Transaction::StatusDownloadGroup : case Transaction::StatusDownloadPackagelist : return "refresh-cache"; case Transaction::StatusDownload : return "package-download"; case Transaction::StatusDownloadRepository : case Transaction::StatusDownloadUpdateinfo : return "refresh-cache"; case Transaction::StatusFinished : return "package-clean-up"; case Transaction::StatusGeneratePackageList : return "refresh-cache"; case Transaction::StatusWaitingForLock : return "dialog-password"; case Transaction::StatusWaitingForAuth : return "dialog-password";//IMPROVE ME case Transaction::StatusInfo : return "package-info"; case Transaction::StatusInstall : return "kpk-package-add"; case Transaction::StatusLoadingCache : return "refresh-cache"; case Transaction::StatusObsolete : return "package-clean-up"; case Transaction::StatusQuery : return "search-package"; case Transaction::StatusRefreshCache : return "refresh-cache"; case Transaction::StatusRemove : return "package-removed"; case Transaction::StatusRepackaging : return "package-clean-up"; case Transaction::StatusRequest : return "search-package"; case Transaction::StatusRunning : return "package-working"; case Transaction::StatusScanApplications : return "search-package"; case Transaction::StatusSetup : return "package-working"; case Transaction::StatusSigCheck : case Transaction::StatusTestCommit : return "package-info";//TODO needs a better icon case Transaction::StatusUpdate : return "package-update"; case Transaction::StatusWait : return "package-wait"; case Transaction::StatusScanProcessList : return "package-info"; case Transaction::StatusCheckExecutableFiles : return "package-info"; case Transaction::StatusCheckLibraries : return "package-info"; case Transaction::StatusCopyFiles : return "package-info"; + case Transaction::StatusRunHook : return "package-info"; } qCDebug(APPER_LIB) << "status icon unrecognised: " << status; return "help-browser"; } QIcon PkIcons::statusIcon(Transaction::Status status) { return QIcon::fromTheme(PkIcons::statusIconName(status)); } QString PkIcons::statusAnimation(Transaction::Status status) { if (!PkIcons::init) { PkIcons::configure(); } switch (status) { case Transaction::StatusUnknown : return "help-browser"; case Transaction::StatusCancel : case Transaction::StatusCleanup : return "pk-cleaning-up"; case Transaction::StatusCommit : case Transaction::StatusDepResolve : return "pk-testing"; case Transaction::StatusDownloadChangelog : case Transaction::StatusDownloadFilelist : case Transaction::StatusDownloadGroup : case Transaction::StatusDownloadPackagelist : return "pk-refresh-cache"; case Transaction::StatusDownload : return "pk-downloading"; case Transaction::StatusDownloadRepository : case Transaction::StatusDownloadUpdateinfo : return "pk-refresh-cache"; case Transaction::StatusFinished : return "pk-cleaning-up"; case Transaction::StatusGeneratePackageList : return "pk-searching"; case Transaction::StatusWaitingForLock : return "pk-waiting"; case Transaction::StatusInfo : return "package-working"; case Transaction::StatusInstall : return "pk-installing"; case Transaction::StatusLoadingCache : return "pk-refresh-cache"; case Transaction::StatusObsolete : return "pk-cleaning-up"; case Transaction::StatusQuery : return "pk-searching"; case Transaction::StatusRefreshCache : return "pk-refresh-cache"; case Transaction::StatusRemove : return "package-removed";//TODO do the animation case Transaction::StatusRepackaging : return "pk-searching"; case Transaction::StatusRequest : return "process-working"; case Transaction::StatusRunning : return "pk-testing"; case Transaction::StatusScanApplications : return "pk-searching"; case Transaction::StatusSetup : return "pk-searching"; case Transaction::StatusSigCheck : return "package-info"; case Transaction::StatusTestCommit : return "pk-testing"; case Transaction::StatusUpdate : return "pk-installing"; case Transaction::StatusWait : return "pk-waiting"; case Transaction::StatusWaitingForAuth : return "dialog-password"; case Transaction::StatusScanProcessList : return "utilities-system-monitor"; default : qCDebug(APPER_LIB) << "status icon unrecognised: " << status; return "help-browser"; } } QString PkIcons::actionIconName(Transaction::Role role) { if (!PkIcons::init) { PkIcons::configure(); } switch (role) { case Transaction::RoleUnknown : return "applications-other"; case Transaction::RoleAcceptEula : return "package-info"; case Transaction::RoleCancel : return "process-stop"; case Transaction::RoleDownloadPackages : return "package-download"; case Transaction::RoleGetCategories : return "package-info"; case Transaction::RoleDependsOn : return "package-info"; case Transaction::RoleGetDetails : return "package-info"; case Transaction::RoleGetDetailsLocal : return "package-info"; case Transaction::RoleGetDistroUpgrades : return "distro-upgrade"; case Transaction::RoleGetFiles : return "search-package"; case Transaction::RoleGetFilesLocal : return "search-package"; case Transaction::RoleGetOldTransactions : return "package-info"; case Transaction::RoleGetPackages : return "package-packages"; case Transaction::RoleGetRepoList : return "package-orign"; case Transaction::RoleRequiredBy : return "package-info"; case Transaction::RoleGetUpdateDetail : return "package-info"; case Transaction::RoleGetUpdates : return "package-info"; case Transaction::RoleInstallFiles : return "package-installed"; case Transaction::RoleInstallPackages : return "package-installed"; case Transaction::RoleInstallSignature : return "package-installed"; case Transaction::RoleRefreshCache : return "refresh-cache"; case Transaction::RoleRemovePackages : return "package-removed"; case Transaction::RoleRepoEnable : return "package-orign"; case Transaction::RoleRepoSetData : return "package-orign"; case Transaction::RoleRepoRemove : return "package-orign"; case Transaction::RoleResolve : return "search-package"; case Transaction::RoleSearchDetails : return "search-package"; case Transaction::RoleSearchFile : return "search-package"; case Transaction::RoleSearchGroup : return "search-package"; case Transaction::RoleSearchName : return "search-package"; case Transaction::RoleUpdatePackages : return "package-update"; case Transaction::RoleWhatProvides : return "search-package"; case Transaction::RoleRepairSystem : return "package-rollback"; + case Transaction::StatusRunHook : return "package-info"; } qCDebug(APPER_LIB) << "action unrecognised: " << role; return "applications-other"; } QIcon PkIcons::actionIcon(Transaction::Role role) { return QIcon::fromTheme(actionIconName(role)); } QIcon PkIcons::groupsIcon(Transaction::Group group) { if (!PkIcons::init) { PkIcons::configure(); } switch (group) { case Transaction::GroupUnknown : return QIcon::fromTheme("unknown"); case Transaction::GroupAccessibility : return QIcon::fromTheme("preferences-desktop-accessibility"); case Transaction::GroupAccessories : return QIcon::fromTheme("applications-accessories"); case Transaction::GroupAdminTools : return QIcon::fromTheme("dialog-password"); case Transaction::GroupCommunication : return QIcon::fromTheme("network-workgroup");//FIXME case Transaction::GroupDesktopGnome : return QIcon::fromTheme("kpk-desktop-gnome"); case Transaction::GroupDesktopKde : return QIcon::fromTheme("kde"); case Transaction::GroupDesktopOther : return QIcon::fromTheme("user-desktop"); case Transaction::GroupDesktopXfce : return QIcon::fromTheme("kpk-desktop-xfce"); case Transaction::GroupDocumentation : return QIcon::fromTheme("accessories-dictionary");//FIXME case Transaction::GroupEducation : return QIcon::fromTheme("applications-education"); case Transaction::GroupElectronics : return QIcon::fromTheme("media-flash"); case Transaction::GroupFonts : return QIcon::fromTheme("preferences-desktop-font"); case Transaction::GroupGames : return QIcon::fromTheme("applications-games"); case Transaction::GroupGraphics : return QIcon::fromTheme("applications-graphics"); case Transaction::GroupInternet : return QIcon::fromTheme("applications-internet"); case Transaction::GroupLegacy : return QIcon::fromTheme("media-floppy"); case Transaction::GroupLocalization : return QIcon::fromTheme("applications-education-language"); case Transaction::GroupMaps : return QIcon::fromTheme("Maps");//FIXME case Transaction::GroupCollections : return QIcon::fromTheme("package-orign"); case Transaction::GroupMultimedia : return QIcon::fromTheme("applications-multimedia"); case Transaction::GroupNetwork : return QIcon::fromTheme("network-wired"); case Transaction::GroupOffice : return QIcon::fromTheme("applications-office"); case Transaction::GroupOther : return QIcon::fromTheme("applications-other"); case Transaction::GroupPowerManagement : return QIcon::fromTheme("battery"); case Transaction::GroupProgramming : return QIcon::fromTheme("applications-development"); case Transaction::GroupPublishing : return QIcon::fromTheme("accessories-text-editor"); case Transaction::GroupRepos : return QIcon::fromTheme("application-x-compressed-tar"); case Transaction::GroupScience : return QIcon::fromTheme("applications-science"); case Transaction::GroupSecurity : return QIcon::fromTheme("security-high"); case Transaction::GroupServers : return QIcon::fromTheme("network-server"); case Transaction::GroupSystem : return QIcon::fromTheme("applications-system"); case Transaction::GroupVirtualization : return QIcon::fromTheme("cpu"); case Transaction::GroupVendor : return QIcon::fromTheme("application-certificate"); case Transaction::GroupNewest : return QIcon::fromTheme("dialog-information"); } qCDebug(APPER_LIB) << "group unrecognised: " << group; return QIcon::fromTheme("unknown"); } QIcon PkIcons::packageIcon(Transaction::Info info) { if (!PkIcons::init) { PkIcons::configure(); } switch (info) { case Transaction::InfoBugfix : return QIcon::fromTheme("script-error"); case Transaction::InfoEnhancement : return QIcon::fromTheme("ktip"); case Transaction::InfoImportant : return QIcon::fromTheme("security-medium"); case Transaction::InfoLow : return QIcon::fromTheme("security-high"); case Transaction::InfoSecurity : return QIcon::fromTheme("security-low"); case Transaction::InfoNormal : return QIcon::fromTheme("emblem-new"); case Transaction::InfoBlocked : return QIcon::fromTheme("dialog-cancel"); case Transaction::InfoAvailable : return QIcon::fromTheme("package-download"); case Transaction::InfoInstalled : return QIcon::fromTheme("package-installed"); default : return QIcon::fromTheme("package"); } } QString PkIcons::restartIconName(Transaction::Restart type) { if (!PkIcons::init) { PkIcons::configure(); } // These names MUST be standard icons, otherwise KStatusNotifierItem // will not be able to load them switch (type) { case Transaction::RestartSecuritySystem : case Transaction::RestartSystem : return "system-reboot"; case Transaction::RestartSecuritySession : case Transaction::RestartSession : return "system-log-out"; case Transaction::RestartApplication : return "process-stop"; case Transaction::RestartNone : case Transaction::RestartUnknown : break; } return ""; } QIcon PkIcons::restartIcon(Transaction::Restart type) { return PkIcons::getIcon(restartIconName(type)); } QIcon PkIcons::getPreloadedIcon(const QString &name) { if (!PkIcons::init) { PkIcons::configure(); } qCDebug(APPER_LIB) << KIconLoader::global()->iconPath(name, KIconLoader::NoGroup, true); QIcon icon; icon.addPixmap(QIcon::fromTheme(name).pixmap(48, 48)); return icon; } QString PkIcons::lastCacheRefreshIconName(uint lastTime) { unsigned long fifteen = 60 * 60 * 24 * 15; unsigned long tirty = 60 * 60 * 24 * 30; if (lastTime != UINT_MAX && lastTime < fifteen) { return QLatin1String("security-high"); } else if (lastTime != UINT_MAX && lastTime > fifteen && lastTime < tirty) { return QLatin1String("security-medium"); } return QLatin1String("security-low"); } #include "moc_PkIcons.cpp" diff --git a/libapper/PkTransaction.cpp b/libapper/PkTransaction.cpp index 486a8e7..58a8c42 100644 --- a/libapper/PkTransaction.cpp +++ b/libapper/PkTransaction.cpp @@ -1,803 +1,778 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include "PkTransaction.h" #include #include #include #include #include #include #include #include #include #include #include #include "Enum.h" #include "PkStrings.h" #include "RepoSig.h" #include "LicenseAgreement.h" #include "PkIcons.h" #include "ApplicationLauncher.h" #include "PackageModel.h" #include "Requirements.h" #include "PkTransactionProgressModel.h" #include "PkTransactionWidget.h" Q_DECLARE_LOGGING_CATEGORY(APPER_LIB) class PkTransactionPrivate { public: bool allowDeps; bool jobWatcher; bool handlingActionRequired; bool showingError; //This might replace the above qulonglong downloadSizeRemaining; PkTransaction::ExitStatus exitStatus; Transaction::Status status; Transaction::TransactionFlags flags; Transaction::Role originalRole; Transaction::Error error; Transaction::Role role; QStringList packages; ApplicationLauncher *launcher; QStringList files; QStringList newPackages; PackageModel *simulateModel; PkTransactionProgressModel *progressModel; QWidget *parentWindow; QDBusObjectPath tid; Transaction *transaction; }; PkTransaction::PkTransaction(QObject *parent) : QObject(parent), d(new PkTransactionPrivate) { // for sanity we are finished till some transaction is set d->allowDeps = false; d->jobWatcher = false; d->handlingActionRequired = false; d->showingError = false; d->downloadSizeRemaining = 0; d->exitStatus = Success; d->status = Transaction::StatusUnknown; // for sanity we are trusted till an error is given and the user accepts d->flags = Transaction::TransactionFlagOnlyTrusted; d->originalRole = Transaction::RoleUnknown; d->role = Transaction::RoleUnknown; d->error = Transaction::ErrorUnknown; d->launcher = 0; d->simulateModel = 0; d->progressModel = new PkTransactionProgressModel(this); d->parentWindow = qobject_cast(parent); d->transaction = 0; } PkTransaction::~PkTransaction() { // DO NOT disconnect the transaction here, // it might not exist when this happen delete d; } void PkTransaction::installFiles(const QStringList &files) { // if (Daemon::global()->roles() & Transaction::RoleInstallFiles) { d->originalRole = Transaction::RoleInstallFiles; d->files = files; d->flags = Transaction::TransactionFlagOnlyTrusted | Transaction::TransactionFlagSimulate; setupTransaction(Daemon::installFiles(files, d->flags)); // } else { // showError(i18n("Current backend does not support installing files."), i18n("Error")); // } } void PkTransaction::installPackages(const QStringList &packages) { // if (Daemon::global()->roles() & Transaction::RoleInstallPackages) { d->originalRole = Transaction::RoleInstallPackages; d->packages = packages; d->flags = Transaction::TransactionFlagOnlyTrusted | Transaction::TransactionFlagSimulate; setupTransaction(Daemon::installPackages(d->packages, d->flags)); // } else { // showError(i18n("Current backend does not support installing packages."), i18n("Error")); // } } void PkTransaction::removePackages(const QStringList &packages) { // if (Daemon::global()->roles() & Transaction::RoleRemovePackages) { d->originalRole = Transaction::RoleRemovePackages; d->allowDeps = true; // *was* false, Default to avoid dependencies removal unless simulate says so, except for https://bugs.kde.org/show_bug.cgi?id=315063 d->packages = packages; d->flags = Transaction::TransactionFlagOnlyTrusted | Transaction::TransactionFlagSimulate; setupTransaction(Daemon::removePackages(d->packages, d->allowDeps, AUTOREMOVE, d->flags)); // } else { // showError(i18n("The current backend does not support removing packages."), i18n("Error")); // } } void PkTransaction::updatePackages(const QStringList &packages, bool downloadOnly) { // if (Daemon::global()->roles() & Transaction::RoleUpdatePackages) { d->originalRole = Transaction::RoleUpdatePackages; d->packages = packages; if (downloadOnly) { // Don't simulate if we are just downloading d->flags = Transaction::TransactionFlagOnlyDownload; } else { d->flags = Transaction::TransactionFlagOnlyTrusted | Transaction::TransactionFlagSimulate; } setupTransaction(Daemon::updatePackages(d->packages, d->flags)); // } else { // showError(i18n("The current backend does not support updating packages."), i18n("Error")); // } } void PkTransaction::refreshCache(bool force) { setupTransaction(Daemon::refreshCache(force)); } void PkTransaction::installPackages() { setupTransaction(Daemon::installPackages(d->packages, d->flags)); } void PkTransaction::installFiles() { setupTransaction(Daemon::installFiles(d->files, d->flags)); } void PkTransaction::removePackages() { setupTransaction(Daemon::removePackages(d->packages, d->allowDeps, AUTOREMOVE, d->flags)); } void PkTransaction::updatePackages() { setupTransaction(Daemon::updatePackages(d->packages, d->flags)); } void PkTransaction::requeueTransaction() { Requirements *requires = qobject_cast(sender()); if (requires) { // As we have requires allow deps removal d->allowDeps = true; if (!requires->trusted()) { // Set only trusted to false, to do as the user asked setTrusted(false); } } // Delete the simulate model if (d->simulateModel) { d->simulateModel->deleteLater(); d->simulateModel = 0; } // We are not handling any required action yet for the requeued transaction. // Without this a second license agreement f.e. does not get shown, // see http://bugs.kde.org/show_bug.cgi?id=326619 d->handlingActionRequired = false; switch (d->originalRole) { case Transaction::RoleRemovePackages: removePackages(); break; case Transaction::RoleInstallPackages: installPackages(); break; case Transaction::RoleInstallFiles: installFiles(); break; case Transaction::RoleUpdatePackages: updatePackages(); break; default : setExitStatus(Failed); return; } } void PkTransaction::slotErrorCode(Transaction::Error error, const QString &details) { qCDebug(APPER_LIB) << "errorCode: " << error << details; d->error = error; if (d->handlingActionRequired) { // We are already handling required actions // like eulaRequired() and repoSignatureRequired() return; } switch (error) { case Transaction::ErrorTransactionCancelled: case Transaction::ErrorProcessKill: // these errors should be ignored break; case Transaction::ErrorGpgFailure: case Transaction::ErrorBadGpgSignature: case Transaction::ErrorMissingGpgSignature: case Transaction::ErrorCannotInstallRepoUnsigned: case Transaction::ErrorCannotUpdateRepoUnsigned: { d->handlingActionRequired = true; int ret = KMessageBox::warningYesNo(d->parentWindow, i18n("You are about to install unsigned packages that can compromise your system, " "as it is impossible to verify if the software came from a trusted " "source.\n\nAre you sure you want to proceed with the installation?"), i18n("Installing unsigned software")); if (ret == KMessageBox::Yes) { // Set only trusted to false, to do as the user asked setTrusted(false); requeueTransaction(); } else { setExitStatus(Cancelled); } d->handlingActionRequired = false; return; } default: d->showingError = true; showSorry(PkStrings::error(error), PkStrings::errorMessage(error), QString(details).replace('\n', "
")); // when we receive an error we are done setExitStatus(Failed); } } void PkTransaction::slotEulaRequired(const QString &eulaID, const QString &packageID, const QString &vendor, const QString &licenseAgreement) { if (d->handlingActionRequired) { // if its true means that we alread passed here d->handlingActionRequired = false; return; } else { d->handlingActionRequired = true; } auto eula = new LicenseAgreement(eulaID, packageID, vendor, licenseAgreement, d->parentWindow); connect(eula, SIGNAL(yesClicked()), this, SLOT(acceptEula())); connect(eula, SIGNAL(rejected()), this, SLOT(reject())); showDialog(eula); } void PkTransaction::acceptEula() { LicenseAgreement *eula = qobject_cast(sender()); if (eula) { qCDebug(APPER_LIB) << "Accepting EULA" << eula->id(); setupTransaction(Daemon::acceptEula(eula->id())); } else { qCWarning(APPER_LIB) << "something is broken, slot is bound to LicenseAgreement but signalled from elsewhere."; } } void PkTransaction::slotChanged() { Transaction *transaction = qobject_cast(sender()); d->downloadSizeRemaining = transaction->downloadSizeRemaining(); d->role = transaction->role(); if (!d->jobWatcher) { return; } QDBusObjectPath _tid = transaction->tid(); if (d->tid != _tid && !(d->flags & Transaction::TransactionFlagSimulate)) { d->tid = _tid; // if the transaction changed and // the user wants the watcher send the tid QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.kde.apperd"), QLatin1String("/"), QLatin1String("org.kde.apperd"), QLatin1String("WatchTransaction")); // Use our own cached tid to avoid crashes message << qVariantFromValue(_tid); if (!QDBusConnection::sessionBus().send(message)) { qCWarning(APPER_LIB) << "Failed to put WatchTransaction on the DBus queue"; } } } void PkTransaction::slotMediaChangeRequired(Transaction::MediaType type, const QString &id, const QString &text) { Q_UNUSED(id) d->handlingActionRequired = true; int ret = KMessageBox::questionYesNo(d->parentWindow, PkStrings::mediaMessage(type, text), i18n("A media change is required"), KStandardGuiItem::cont(), KStandardGuiItem::cancel()); d->handlingActionRequired = false; // if the user clicked continue we got yes if (ret == KMessageBox::Yes) { requeueTransaction(); } else { setExitStatus(Cancelled); } } void PkTransaction::slotRepoSignature(const QString &packageID, const QString &repoName, const QString &keyUrl, const QString &keyUserid, const QString &keyId, const QString &keyFingerprint, const QString &keyTimestamp, Transaction::SigType type) { if (d->handlingActionRequired) { // if its true means that we alread passed here d->handlingActionRequired = false; return; } else { d->handlingActionRequired = true; } - RepoSig *repoSig = new RepoSig(packageID, repoName, keyUrl, keyUserid, keyId, keyFingerprint, keyTimestamp, type, d->parentWindow); + auto repoSig = new RepoSig(packageID, repoName, keyUrl, keyUserid, keyId, keyFingerprint, keyTimestamp, type, d->parentWindow); connect(repoSig, SIGNAL(yesClicked()), this, SLOT(installSignature())); connect(repoSig, SIGNAL(rejected()), this, SLOT(reject())); showDialog(repoSig); } void PkTransaction::installSignature() { RepoSig *repoSig = qobject_cast(sender()); if (repoSig) { qCDebug(APPER_LIB) << "Installing Signature" << repoSig->keyID(); setupTransaction(Daemon::installSignature(repoSig->sigType(), repoSig->keyID(), repoSig->packageID())); } else { qCWarning(APPER_LIB) << "something is broken, slot is bound to RepoSig but signalled from elsewhere."; } } void PkTransaction::slotFinished(Transaction::Exit status) { // Clear the model to don't keep trash when reusing the transaction d->progressModel->clear(); Requirements *requires = 0; Transaction::Role _role = qobject_cast(sender())->role(); d->transaction = 0; // Will be deleted later qCDebug(APPER_LIB) << status << _role; switch (_role) { case Transaction::RoleInstallSignature: case Transaction::RoleAcceptEula: if (status == Transaction::ExitSuccess) { // if the required action was performed with success // requeue our main transaction requeueTransaction(); return; } break; default: break; } switch(status) { case Transaction::ExitSuccess: // Check if we are just simulating if (d->flags & Transaction::TransactionFlagSimulate) { // Disable the simulate flag d->flags ^= Transaction::TransactionFlagSimulate; d->simulateModel->finished(); // Remove the transaction packages foreach (const QString &packageID, d->packages) { d->simulateModel->removePackage(packageID); } d->newPackages = d->simulateModel->packagesWithInfo(Transaction::InfoInstalling); if (_role == Transaction::RoleInstallPackages) { d->newPackages << d->packages; d->newPackages.removeDuplicates(); } requires = new Requirements(d->simulateModel, d->parentWindow); requires->setDownloadSizeRemaining(d->downloadSizeRemaining); - connect(requires, SIGNAL(accepted()), this, SLOT(requeueTransaction())); - connect(requires, SIGNAL(rejected()), this, SLOT(reject())); + connect(requires, &Requirements::accepted, this, &PkTransaction::requeueTransaction); + connect(requires, &Requirements::rejected, this, &PkTransaction::reject); if (requires->shouldShow()) { showDialog(requires); } else { requires->deleteLater(); // Since we removed the Simulate Flag this will procced // with the actual action requeueTransaction(); } } else { KConfig config("apper"); KConfigGroup transactionGroup(&config, "Transaction"); bool showApp = transactionGroup.readEntry("ShowApplicationLauncher", true); if (showApp && !d->newPackages.isEmpty() && (_role == Transaction::RoleInstallPackages || _role == Transaction::RoleInstallFiles || _role == Transaction::RoleRemovePackages || _role == Transaction::RoleUpdatePackages)) { // When installing files or updates that involves new packages // try to resolve the available packages at simulation time // to maybe show the user the new applications that where installed if (d->launcher) { delete d->launcher; } d->launcher = new ApplicationLauncher(d->parentWindow); connect(this, SIGNAL(files(QString,QStringList)), d->launcher, SLOT(files(QString,QStringList))); setupTransaction(Daemon::getFiles(d->newPackages)); d->newPackages.clear(); return; // avoid the exit code } else if (_role == Transaction::RoleGetFiles && d->launcher && d->launcher->hasApplications()) { // if we have a launcher and the laucher has applications // show them to the user showDialog(d->launcher); - connect(d->launcher, SIGNAL(finished()), SLOT(setExitStatus())); + connect(d->launcher, &ApplicationLauncher::finished, this, &PkTransaction::setExitStatus); return; } setExitStatus(Success); } break; case Transaction::ExitNeedUntrusted: case Transaction::ExitKeyRequired: case Transaction::ExitEulaRequired: case Transaction::ExitMediaChangeRequired: qCDebug(APPER_LIB) << "finished KeyRequired or EulaRequired: " << status; if (!d->handlingActionRequired) { qCDebug(APPER_LIB) << "Not Handling Required Action"; setExitStatus(Failed); } break; case Transaction::ExitCancelled: // Avoid crash in case we are showing an error if (!d->showingError) { setExitStatus(Cancelled); } break; case Transaction::ExitFailed: if (!d->handlingActionRequired && !d->showingError) { qCDebug(APPER_LIB) << "Yep, we failed."; setExitStatus(Failed); } break; default : qCDebug(APPER_LIB) << "finished default" << status; setExitStatus(Failed); break; } } PkTransaction::ExitStatus PkTransaction::exitStatus() const { return d->exitStatus; } bool PkTransaction::isFinished() const { qCDebug(APPER_LIB) << d->transaction->status() << d->transaction->role(); return d->transaction->status() == Transaction::StatusFinished; } PackageModel *PkTransaction::simulateModel() const { return d->simulateModel; } uint PkTransaction::percentage() const { if (d->transaction) { return d->transaction->percentage(); } return 0; } uint PkTransaction::remainingTime() const { if (d->transaction) { return d->transaction->remainingTime(); } return 0; } uint PkTransaction::speed() const { if (d->transaction) { return d->transaction->speed(); } return 0; } qulonglong PkTransaction::downloadSizeRemaining() const { if (d->transaction) { return d->transaction->downloadSizeRemaining(); } return 0; } Transaction::Status PkTransaction::status() const { if (d->transaction) { return d->transaction->status(); } return Transaction::StatusUnknown; } Transaction::Role PkTransaction::role() const { if (d->transaction) { return d->transaction->role(); } return Transaction::RoleUnknown; } bool PkTransaction::allowCancel() const { if (d->transaction) { return d->transaction->allowCancel(); } return false; } Transaction::TransactionFlags PkTransaction::transactionFlags() const { if (d->transaction) { return d->transaction->transactionFlags(); } return Transaction::TransactionFlagNone; } void PkTransaction::getUpdateDetail(const QString &packageID) { setupTransaction(Daemon::getUpdateDetail(packageID)); } void PkTransaction::getUpdates() { setupTransaction(Daemon::getUpdates()); } void PkTransaction::cancel() { if (d->transaction) { d->transaction->cancel(); } } void PkTransaction::setTrusted(bool trusted) { if (trusted) { d->flags |= Transaction::TransactionFlagOnlyTrusted; } else { d->flags ^= Transaction::TransactionFlagOnlyTrusted; } } -void PkTransaction::setExitStatus(PkTransaction::ExitStatus status) +void PkTransaction::setExitStatus(int status) { qCDebug(APPER_LIB) << status; if (d->launcher) { d->launcher->deleteLater(); d->launcher = 0; } - d->exitStatus = status; + d->exitStatus = static_cast(status); if (!d->handlingActionRequired || !d->showingError) { - emit finished(status); + emit finished(d->exitStatus); } } void PkTransaction::reject() { setExitStatus(Cancelled); } void PkTransaction::setupTransaction(Transaction *transaction) { // Clear the model to don't keep trash when reusing the transaction d->progressModel->clear(); d->transaction = transaction; if (!(transaction->transactionFlags() & Transaction::TransactionFlagSimulate) && transaction->role() != Transaction::RoleGetUpdates && transaction->role() != Transaction::RoleGetUpdateDetail) { - connect(transaction, SIGNAL(repoDetail(QString,QString,bool)), - d->progressModel, SLOT(currentRepo(QString,QString,bool))); - connect(transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), - d->progressModel, SLOT(currentPackage(PackageKit::Transaction::Info,QString,QString))); - connect(transaction, SIGNAL(itemProgress(QString,PackageKit::Transaction::Status,uint)), - d->progressModel, SLOT(itemProgress(QString,PackageKit::Transaction::Status,uint))); + connect(transaction, &Transaction::repoDetail, d->progressModel, &PkTransactionProgressModel::currentRepo); + connect(transaction, &Transaction::package, d->progressModel, &PkTransactionProgressModel::currentPackage); + connect(transaction, &Transaction::itemProgress, d->progressModel, &PkTransactionProgressModel::itemProgress); } - connect(transaction, SIGNAL(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime)), - SIGNAL(updateDetail(QString,QStringList,QStringList,QStringList,QStringList,QStringList,PackageKit::Transaction::Restart,QString,QString,PackageKit::Transaction::UpdateState,QDateTime,QDateTime))); - connect(transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), - SIGNAL(package(PackageKit::Transaction::Info,QString,QString))); - connect(transaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), - SIGNAL(errorCode(PackageKit::Transaction::Error,QString))); + connect(transaction, &Transaction::updateDetail, this, &PkTransaction::updateDetail); + connect(transaction, &Transaction::package, this, &PkTransaction::package); + connect(transaction, &Transaction::errorCode, this, &PkTransaction::errorCode); // Required actions - connect(transaction, SIGNAL(allowCancelChanged()), - SIGNAL(allowCancelChanged())); - connect(transaction, SIGNAL(downloadSizeRemainingChanged()), - SIGNAL(downloadSizeRemainingChanged())); - connect(transaction, SIGNAL(elapsedTimeChanged()), - SIGNAL(elapsedTimeChanged())); - connect(transaction, SIGNAL(isCallerActiveChanged()), - SIGNAL(isCallerActiveChanged())); - connect(transaction, SIGNAL(lastPackageChanged()), - SIGNAL(lastPackageChanged())); - connect(transaction, SIGNAL(percentageChanged()), - SIGNAL(percentageChanged())); - connect(transaction, SIGNAL(remainingTimeChanged()), - SIGNAL(remainingTimeChanged())); - connect(transaction, SIGNAL(roleChanged()), - SIGNAL(roleChanged())); - connect(transaction, SIGNAL(speedChanged()), - SIGNAL(speedChanged())); - connect(transaction, SIGNAL(statusChanged()), - SIGNAL(statusChanged())); - connect(transaction, SIGNAL(transactionFlagsChanged()), - SIGNAL(transactionFlagsChanged())); - connect(transaction, SIGNAL(uidChanged()), - SIGNAL(uidChanged())); - - connect(transaction, SIGNAL(downloadSizeRemainingChanged()), - SLOT(slotChanged())); - connect(transaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)), - SLOT(slotErrorCode(PackageKit::Transaction::Error,QString))); - connect(transaction, SIGNAL(eulaRequired(QString,QString,QString,QString)), - SLOT(slotEulaRequired(QString,QString,QString,QString))); - connect(transaction, SIGNAL(mediaChangeRequired(PackageKit::Transaction::MediaType,QString,QString)), - SLOT(slotMediaChangeRequired(PackageKit::Transaction::MediaType,QString,QString))); - connect(transaction, SIGNAL(repoSignatureRequired(QString,QString,QString,QString,QString,QString,QString,PackageKit::Transaction::SigType)), - SLOT(slotRepoSignature(QString,QString,QString,QString,QString,QString,QString,PackageKit::Transaction::SigType))); - - connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)), - SLOT(slotFinished(PackageKit::Transaction::Exit))); + connect(transaction, &Transaction::allowCancelChanged, this, &PkTransaction::allowCancelChanged); + connect(transaction, &Transaction::downloadSizeRemainingChanged, this, &PkTransaction::downloadSizeRemainingChanged); + connect(transaction, &Transaction::elapsedTimeChanged, this, &PkTransaction::elapsedTimeChanged); + connect(transaction, &Transaction::isCallerActiveChanged, this, &PkTransaction::isCallerActiveChanged); + connect(transaction, &Transaction::lastPackageChanged, this, &PkTransaction::lastPackageChanged); + connect(transaction, &Transaction::percentageChanged, this, &PkTransaction::percentageChanged); + connect(transaction, &Transaction::remainingTimeChanged, this, &PkTransaction::remainingTimeChanged); + connect(transaction, &Transaction::roleChanged, this, &PkTransaction::roleChanged); + connect(transaction, &Transaction::speedChanged, this, &PkTransaction::speedChanged); + connect(transaction, &Transaction::statusChanged, this, &PkTransaction::statusChanged); + connect(transaction, &Transaction::transactionFlagsChanged, this, &PkTransaction::transactionFlagsChanged); + connect(transaction, &Transaction::uidChanged, this, &PkTransaction::uidChanged); + + connect(transaction, &Transaction::downloadSizeRemainingChanged, this, &PkTransaction::slotChanged); + connect(transaction, &Transaction::errorCode, this, &PkTransaction::slotErrorCode); + connect(transaction, &Transaction::eulaRequired, this, &PkTransaction::slotEulaRequired); + connect(transaction, &Transaction::mediaChangeRequired, this, &PkTransaction::slotMediaChangeRequired); + connect(transaction, &Transaction::repoSignatureRequired, this, &PkTransaction::slotRepoSignature); + + connect(transaction, &Transaction::finished, this, &PkTransaction::slotFinished); if (d->flags & Transaction::TransactionFlagSimulate) { d->simulateModel = new PackageModel(this); - connect(d->transaction, SIGNAL(package(PackageKit::Transaction::Info,QString,QString)), - d->simulateModel, SLOT(addPackage(PackageKit::Transaction::Info,QString,QString))); + connect(d->transaction, &Transaction::package, d->simulateModel, &PackageModel::addNotSelectedPackage); } #ifdef HAVE_DEBCONFKDE QString _tid = transaction->tid().path(); QString socket; // Build a socket path like /tmp/1761_edeceabd_data_debconf socket = QLatin1String("/tmp") % _tid % QLatin1String("_debconf"); QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.kde.apperd"), QLatin1String("/"), QLatin1String("org.kde.apperd"), QLatin1String("SetupDebconfDialog")); // Use our own cached tid to avoid crashes message << qVariantFromValue(_tid); message << qVariantFromValue(socket); if (d->parentWindow) { message << qVariantFromValue(static_cast(d->parentWindow->effectiveWinId())); } else { message << qVariantFromValue(0u); } if (!QDBusConnection::sessionBus().send(message)) { qCWarning(APPER_LIB) << "Failed to put SetupDebconfDialog message in DBus queue"; } transaction->setHints(QLatin1String("frontend-socket=") % socket); #endif //HAVE_DEBCONFKDE } void PkTransaction::showDialog(QDialog *dlg) { auto widget = qobject_cast(d->parentWindow); if (!widget || widget->isCancelVisible()) { dlg->setModal(d->parentWindow); dlg->show(); } else { dlg->setProperty("embedded", true); emit dialog(dlg); } } void PkTransaction::showError(const QString &title, const QString &description, const QString &details) { PkTransactionWidget *widget = qobject_cast(d->parentWindow); if (!widget || widget->isCancelVisible()) { if (details.isEmpty()) { if (d->parentWindow) { KMessageBox::error(d->parentWindow, description, title); } else { KMessageBox::errorWId(0, description, title); } } else { KMessageBox::detailedError(d->parentWindow, description, details, title); } } else { emit errorMessage(title, description, details); } } void PkTransaction::showSorry(const QString &title, const QString &description, const QString &details) { PkTransactionWidget *widget = qobject_cast(d->parentWindow); if (!widget || widget->isCancelVisible()) { if (details.isEmpty()) { KMessageBox::sorry(d->parentWindow, description, title); } else { KMessageBox::detailedSorry(d->parentWindow, description, details, title); } } else { emit sorry(title, description, details); } } QString PkTransaction::title() const { return PkStrings::action(d->originalRole, d->flags); } Transaction::Role PkTransaction::cachedRole() const { return d->role; } Transaction::TransactionFlags PkTransaction::flags() const { return d->flags; } PkTransactionProgressModel *PkTransaction::progressModel() const { return d->progressModel; } void PkTransaction::enableJobWatcher(bool enable) { d->jobWatcher = enable; } #include "moc_PkTransaction.cpp" diff --git a/libapper/PkTransaction.h b/libapper/PkTransaction.h index 35e0013..19d2595 100644 --- a/libapper/PkTransaction.h +++ b/libapper/PkTransaction.h @@ -1,171 +1,171 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef PK_TRANSACTION_H #define PK_TRANSACTION_H #include //#include #include #include using namespace PackageKit; class PackageModel; class PkTransactionPrivate; class PkTransactionProgressModel; class Q_DECL_EXPORT PkTransaction : public QObject { Q_OBJECT Q_ENUMS(ExitStatus) public: typedef enum { Success, Failed, Cancelled } ExitStatus; explicit PkTransaction(QObject *parent = 0); ~PkTransaction(); void setupTransaction(Transaction *transaction); Q_INVOKABLE void installPackages(const QStringList &packages); Q_INVOKABLE void installFiles(const QStringList &files); Q_INVOKABLE void removePackages(const QStringList &packages); Q_INVOKABLE void updatePackages(const QStringList &packages, bool downloadOnly = false); Q_INVOKABLE void refreshCache(bool force); QString title() const; Transaction::Role cachedRole() const; Transaction::TransactionFlags flags() const; Q_INVOKABLE PkTransactionProgressModel* progressModel() const; Q_INVOKABLE void enableJobWatcher(bool enable); PkTransaction::ExitStatus exitStatus() const; bool isFinished() const; PackageModel* simulateModel() const; Q_PROPERTY(uint percentage READ percentage NOTIFY percentageChanged) uint percentage() const; Q_PROPERTY(uint remainingTime READ remainingTime NOTIFY remainingTimeChanged) uint remainingTime() const; Q_PROPERTY(uint speed READ speed NOTIFY speedChanged) uint speed() const; Q_PROPERTY(qulonglong downloadSizeRemaining READ downloadSizeRemaining NOTIFY downloadSizeRemainingChanged) qulonglong downloadSizeRemaining() const; Q_PROPERTY(PackageKit::Transaction::Status status READ status NOTIFY statusChanged) Transaction::Status status() const; Q_PROPERTY(PackageKit::Transaction::Role role READ role NOTIFY roleChanged) Transaction::Role role() const; Q_PROPERTY(bool allowCancel READ allowCancel NOTIFY allowCancelChanged) bool allowCancel() const; Q_PROPERTY(PackageKit::Transaction::TransactionFlags transactionFlags READ transactionFlags NOTIFY transactionFlagsChanged) Transaction::TransactionFlags transactionFlags() const; public Q_SLOTS: void getUpdateDetail(const QString &packageID); void getUpdates(); void cancel(); void setTrusted(bool trusted); /** * When mediaChangeRequired(), eulaRequired() or repoSignatureRequired() * and the action is performed this method should be called */ void requeueTransaction(); Q_SIGNALS: void package(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void updateDetail(const QString &packageID, const QStringList &updates, const QStringList &obsoletes, const QStringList &vendorUrls, const QStringList &bugzillaUrls, const QStringList &cveUrls, PackageKit::Transaction::Restart restart, const QString &updateText, const QString &changelog, PackageKit::Transaction::UpdateState state, const QDateTime &issued, const QDateTime &updated); void errorCode(PackageKit::Transaction::Error error, const QString &details); void finished(PkTransaction::ExitStatus status); void titleChanged(const QString &title); void sorry(const QString &title, const QString &text, const QString &details); void errorMessage(const QString &title, const QString &text, const QString &details); void dialog(QDialog *widget); void allowCancelChanged(); void isCallerActiveChanged(); void downloadSizeRemainingChanged(); void elapsedTimeChanged(); void lastPackageChanged(); void percentageChanged(); void remainingTimeChanged(); void roleChanged(); void speedChanged(); void statusChanged(); void transactionFlagsChanged(); void uidChanged(); private Q_SLOTS: void installPackages(); void installFiles(); void removePackages(); void updatePackages(); void installSignature(); void acceptEula(); void slotChanged(); void slotFinished(PackageKit::Transaction::Exit status); void slotErrorCode(PackageKit::Transaction::Error error, const QString &details); void slotEulaRequired(const QString &eulaID, const QString &packageID, const QString &vendor, const QString &licenseAgreement); void slotMediaChangeRequired(PackageKit::Transaction::MediaType type, const QString &id, const QString &text); void slotRepoSignature(const QString &packageID, const QString &repoName, const QString &keyUrl, const QString &keyUserid, const QString &keyId, const QString &keyFingerprint, const QString &keyTimestamp, PackageKit::Transaction::SigType type); - void setExitStatus(PkTransaction::ExitStatus status = PkTransaction::Success); + void setExitStatus(int status = PkTransaction::Success); void reject(); private: void showDialog(QDialog *dialog); void showError(const QString &title, const QString &description, const QString &details = QString()); void showSorry(const QString &title, const QString &description, const QString &details = QString()); PkTransactionPrivate *d; }; #endif