diff --git a/Apper/Apper.cpp b/Apper/Apper.cpp index f0d1578..63dd492 100644 --- a/Apper/Apper.cpp +++ b/Apper/Apper.cpp @@ -1,239 +1,239 @@ /*************************************************************************** * 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 "Apper.h" #include "BackendDetails.h" #include "MainUi.h" //#include //#include //#include #include #include //#include //#include //#include #include #include #include #include #include #include #include #include #include Apper::Apper(int& argc, char** argv) : QApplication(argc, argv), m_pkUi(0), m_running(0) { setQuitOnLastWindowClosed(false); auto service = new KDBusService(KDBusService::Unique); connect(this, &Apper::aboutToQuit, service, &KDBusService::deleteLater); connect(service, &KDBusService::activateRequested, this, &Apper::activate); } Apper::~Apper() { } void Apper::appClose() { //check whether we can close if (!m_running && !m_pkUi) { quit(); } } void Apper::kcmFinished() { // kcm is finished we set to 0 to be able to quit m_pkUi->deleteLater(); m_pkUi = 0; appClose(); } void Apper::decreaseAndKillRunning() { m_running--; sender()->deleteLater(); appClose(); } void Apper::activate(const QStringList& arguments, const QString& workingDirectory) { Q_UNUSED(workingDirectory); QCommandLineParser parser; parser.addVersionOption(); parser.addHelpOption(); QCommandLineOption updatesOpt(QStringList() << QLatin1String("updates"), i18n("Show updates")); parser.addOption(updatesOpt); QCommandLineOption settingsOpt(QStringList() << QLatin1String("settings"), i18n("Show settings")); parser.addOption(settingsOpt); QCommandLineOption backendOpt(QStringList() << QLatin1String("backend-details"), i18n("Show backend details")); parser.addOption(backendOpt); QCommandLineOption mimeTypeOpt(QStringList() << QLatin1String("install-mime-type"), i18n("Mime type installer"), QLatin1String("mime-type")); parser.addOption(mimeTypeOpt); QCommandLineOption nameOpt(QStringList() << QLatin1String("install-package-name"), i18n("Package name installer"), QLatin1String("name")); parser.addOption(nameOpt); QCommandLineOption fileOpt(QStringList() << QLatin1String("file"), i18n("Single file installer"), QLatin1String("file")); parser.addOption(fileOpt); QCommandLineOption resourceOpt(QStringList() << QLatin1String("resource"), i18n("Font resource installer"), QLatin1String("lang")); parser.addOption(resourceOpt); QCommandLineOption catalogOpt(QStringList() << QLatin1String("install-catalog"), i18n("Catalog installer"), QLatin1String("file")); parser.addOption(catalogOpt); QCommandLineOption removeOpt(QStringList() << QLatin1String("remove-package-by-file"), i18n("Single package remover"), QLatin1String("filename")); parser.addOption(removeOpt); parser.addPositionalArgument(QLatin1String("[package]"), i18n("Package file to install")); KAboutData::applicationData().setupCommandLine(&parser); parser.process(arguments); KAboutData::applicationData().processCommandLine(&parser); auto args = parser.positionalArguments(); if (args.count()) { // grab the list of files // QStringList urls; // for (int i = 0; i < args.count(); i++) { // urls << args[i]; // } // TODO remote files are copied to /tmp // what will happen if we call the other process to // install and this very one closes? will the files // in /tmp be deleted? invoke(QLatin1String("InstallPackageFiles"), args); return; } if (parser.isSet(updatesOpt)) { QTimer::singleShot(0, this, &Apper::showUpdates); return; } if (parser.isSet(settingsOpt)) { QTimer::singleShot(0, this, &Apper::showSettings); return; } if (parser.isSet(mimeTypeOpt)) { invoke(QLatin1String("InstallMimeTypes"), parser.values(mimeTypeOpt)); return; } if (parser.isSet(nameOpt)) { invoke(QLatin1String("InstallPackageNames"), parser.values(nameOpt)); return; } if (parser.isSet(QLatin1String("install-provide-file"))) { invoke(QLatin1String("InstallProvideFiles"), parser.values(QLatin1String("install-provide-file"))); return; } if (parser.isSet(catalogOpt)) { invoke(QLatin1String("InstallCatalogs"), parser.values(catalogOpt)); return; } if (parser.isSet(removeOpt)) { invoke(QLatin1String("RemovePackageByFiles"), parser.values(removeOpt)); return; } if (parser.isSet(backendOpt)) { auto helper = new BackendDetails; connect(helper, &BackendDetails::rejected, this, &Apper::decreaseAndKillRunning); QTimer::singleShot(0, helper, &BackendDetails::show); m_running++; return; } // If we are here, we neet to show/activate the main UI QTimer::singleShot(0, this, &Apper::showUi); } void Apper::showUi() { if (!m_pkUi) { m_pkUi = new MainUi(); connect(m_pkUi, &MainUi::finished, this, &Apper::kcmFinished); } // Show all m_pkUi->showAll(); m_pkUi->show(); // KWindowSystem::forceActiveWindow(m_pkUi->winId()); } void Apper::showUpdates() { if (!m_pkUi) { m_pkUi = new MainUi(); connect(m_pkUi, &MainUi::finished, this, &Apper::kcmFinished); } m_pkUi->showUpdates(); m_pkUi->show(); // KWindowSystem::forceActiveWindow(m_pkUi->winId()); } void Apper::showSettings() { if (!m_pkUi) { m_pkUi = new MainUi(); connect(m_pkUi, &MainUi::finished, this, &Apper::kcmFinished); } m_pkUi->showSettings(); m_pkUi->show(); // KWindowSystem::forceActiveWindow(m_pkUi->winId()); } void Apper::invoke(const QString &method_name, const QStringList &args) { QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.PackageKit"), QLatin1String("/org/freedesktop/PackageKit"), QLatin1String("org.freedesktop.PackageKit.Modify"), method_name); message << uint(0); message << args; message << QString(); // This call must block otherwise this application closes before // smarticon is activated QDBusConnection::sessionBus().call(message, QDBus::BlockWithGui); QTimer::singleShot(0, this, &Apper::appClose); } -#include "Apper.moc" +#include "moc_Apper.cpp" diff --git a/Apper/ApperKCM.cpp b/Apper/ApperKCM.cpp index 2058a74..bb3ac39 100644 --- a/Apper/ApperKCM.cpp +++ b/Apper/ApperKCM.cpp @@ -1,920 +1,920 @@ /*************************************************************************** * Copyright (C) 2008-2018 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 #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 ApperKCM::ApperKCM(QWidget *parent) : QWidget(parent), ui(new Ui::ApperKCM), m_findIcon(QIcon::fromTheme(QLatin1String("edit-find"))), m_cancelIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))) { ui->setupUi(this); // store the actions supported by the backend connect(Daemon::global(), &Daemon::changed, this, &ApperKCM::daemonChanged); // Set the current locale Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name() + QLatin1String(".UTF-8")); // Browse TAB ui->backTB->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))); // create our toolbar auto toolBar = new QToolBar(this); ui->gridLayout_2->addWidget(toolBar); toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); connect(ui->browseView, &BrowseView::categoryActivated, this, &ApperKCM::on_homeView_activated); auto 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, &KToolBarPopupAction::triggered, this, &ApperKCM::genericActionKTriggered); } // Create the groups model m_groupsModel = new CategoryModel(this); ui->browseView->setCategoryModel(m_groupsModel); connect(m_groupsModel, &CategoryModel::finished, this, &ApperKCM::setupHomeModel); ui->homeView->setSpacing(10); 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, &FiltersMenu::filtersChanged, this, &ApperKCM::search); ui->filtersTB->setIcon(QIcon::fromTheme(QLatin1String("view-filter"))); ApplicationSortFilterModel *proxy = ui->browseView->proxy(); proxy->setApplicationFilter(m_filtersMenu->filterApplications()); connect(m_filtersMenu, QOverload::of(&FiltersMenu::filterApplications), proxy, &ApplicationSortFilterModel::setApplicationFilter); //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); auto 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); auto changesDelegate = new ChangesDelegate(ui->changesView); changesDelegate->setExtendPixmapWidth(0); ui->changesView->setItemDelegate(changesDelegate); // Connect this signal to keep track of changes connect(m_browseModel, &PackageModel::changed, this, &ApperKCM::checkChanged); // packageUnchecked from changes model connect(m_changesModel, &PackageModel::packageUnchecked, m_changesModel, &PackageModel::removePackage); connect(m_changesModel, &PackageModel::packageUnchecked, m_browseModel, &PackageModel::uncheckPackageDefault); ui->reviewMessage->setIcon(QIcon::fromTheme(QLatin1String("edit-redo"))); ui->reviewMessage->setText(i18n("Some software changes were made")); auto reviewAction = new QAction(i18n("Review"), this); connect(reviewAction, &QAction::triggered, this, &ApperKCM::showReviewPages); ui->reviewMessage->addAction(reviewAction); auto discardAction = new QAction(i18n("Discard"), this); connect(discardAction, &QAction::triggered, m_browseModel, &PackageModel::uncheckAll); ui->reviewMessage->addAction(discardAction); auto applyAction = new QAction(i18n("Apply"), this); connect(applyAction, &QAction::triggered, this, &ApperKCM::save); ui->reviewMessage->addAction(applyAction); ui->reviewMessage->setCloseButtonVisible(false); ui->reviewMessage->hide(); connect(ui->reviewMessage, &KMessageWidget::showAnimationFinished, this, [this] () { if (!ui->reviewMessage->property("HasChanges").toBool()) { ui->reviewMessage->animatedHide(); } }); connect(ui->reviewMessage, &KMessageWidget::hideAnimationFinished, this, [this] () { if (ui->reviewMessage->property("HasChanges").toBool()) { ui->reviewMessage->animatedShow(); } }); auto menu = new QMenu(this); ui->settingsTB->setMenu(menu); ui->settingsTB->setIcon(QIcon::fromTheme(QLatin1String("preferences-other"))); auto signalMapper = new QSignalMapper(this); connect(signalMapper, QOverload::of(&QSignalMapper::mapped), this, &ApperKCM::setPage); QAction *action; action = menu->addAction(QIcon::fromTheme(QLatin1String("view-history")), i18n("History")); signalMapper->setMapping(action, QLatin1String("history")); connect(action, &QAction::triggered, signalMapper, QOverload<>::of(&QSignalMapper::map)); action = menu->addAction(QIcon::fromTheme(QLatin1String("preferences-other")), i18n("Settings")); signalMapper->setMapping(action, QLatin1String("settings")); connect(action, &QAction::triggered, signalMapper, QOverload<>::of(&QSignalMapper::map)); auto helpMenu = new KHelpMenu(this, KAboutData::applicationData()); 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(QLatin1String("document-open"))); ui->actionFindDescription->setIcon(QIcon::fromTheme(QLatin1String("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(); } if (hasChanges) { if (!ui->reviewMessage->isHideAnimationRunning() && !ui->reviewMessage->isShowAnimationRunning()) { ui->reviewMessage->animatedShow(); } } else { if (!ui->reviewMessage->isHideAnimationRunning() && !ui->reviewMessage->isShowAnimationRunning()) { ui->reviewMessage->animatedHide(); } } ui->reviewMessage->setProperty("HasChanges", 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 auto 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(QLatin1Char('@')) || (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(QLatin1String("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) { auto 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, &Settings::changed, this, &ApperKCM::checkChanged); connect(m_settingsPage, &Settings::refreshCache, this, &ApperKCM::refreshCache); ui->stackedWidget->addWidget(m_settingsPage); connect(ui->generalSettingsPB, &QPushButton::toggled, m_settingsPage, &Settings::showGeneralSettings); connect(ui->repoSettingsPB, &QPushButton::toggled, m_settingsPage, &Settings::showRepoSettings); } checkChanged(); // ui->buttonBox->clear(); // ui->buttonBox->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Reset); // 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 == nullptr) { m_updaterPage = new Updater(m_roles, this); connect(m_updaterPage, &Updater::refreshCache, this, &ApperKCM::refreshCache); connect(m_updaterPage, &Updater::downloadSize, ui->downloadL, &QLabel::setText); // connect(m_updaterPage, &Updater::changed, this, &ApperKCM::checkChanged); ui->stackedWidget->addWidget(m_updaterPage); ui->checkUpdatesPB->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); connect(ui->checkUpdatesPB, &QPushButton::clicked, this, &ApperKCM::refreshCache); ui->updatePB->setIcon(QIcon::fromTheme(QLatin1String("system-software-update"))); connect(ui->updatePB, &QPushButton::clicked, this, &ApperKCM::save); connect(m_updaterPage, &Updater::changed, ui->updatePB, &QPushButton::setEnabled); } 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, &QLineEdit::textChanged, m_history, &TransactionHistory::setFilterRegExp); 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; } 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::showReviewPages() { 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, &Transaction::finished, ui->browseView->busyCursor(), &KPixmapSequenceOverlayPainter::stop); disconnect(m_searchTransaction, &Transaction::finished, this, &ApperKCM::finished); disconnect(m_searchTransaction, &Transaction::finished, m_browseModel, &PackageModel::finished); disconnect(m_searchTransaction, &Transaction::finished, m_browseModel, &PackageModel::fetchSizes); disconnect(m_searchTransaction, &Transaction::package, m_browseModel, &PackageModel::addNotSelectedPackage); disconnect(m_searchTransaction, &Transaction::errorCode, this, &ApperKCM::errorCode); } } 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(QLatin1Char('@')) || 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, &Transaction::finished, ui->browseView, &BrowseView::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, &Transaction::finished, ui->browseView->busyCursor(), &KPixmapSequenceOverlayPainter::stop); connect(m_searchTransaction, &Transaction::finished, this, &ApperKCM::finished); connect(m_searchTransaction, &Transaction::finished, m_browseModel, &PackageModel::finished); if (ui->browseView->isShowingSizes()) { connect(m_searchTransaction, &Transaction::finished, m_browseModel, &PackageModel::fetchSizes); } connect(m_searchTransaction, &Transaction::package, m_browseModel, &PackageModel::addNotSelectedPackage); connect(m_searchTransaction, &Transaction::errorCode, this, &ApperKCM::errorCode); // 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(); auto transactionW = new PkTransactionWidget(this); connect(transactionW, &PkTransactionWidget::titleChangedProgress, this, &ApperKCM::caption); 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, &PkTransactionWidget::titleChanged, ui->titleL, &QLabel::setText); QEventLoop loop; connect(transaction, &PkTransaction::finished, &loop, &QEventLoop::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(QLatin1String("settings")); } else { setPage(QLatin1String("updates")); } QTimer::singleShot(0, this, &ApperKCM::checkChanged); } void ApperKCM::save() { QWidget *currentWidget = ui->stackedWidget->currentWidget(); if (currentWidget == m_settingsPage) { m_settingsPage->save(); } else { ui->reviewMessage->hide(); auto transactionW = new PkTransactionWidget(this); connect(transactionW, &PkTransactionWidget::titleChangedProgress, this, &ApperKCM::caption); QPointer transaction = new PkTransaction(transactionW); ui->stackedWidget->addWidget(transactionW); ui->stackedWidget->setCurrentWidget(transactionW); ui->stackedWidgetBar->setCurrentIndex(BAR_TITLE); ui->backTB->setEnabled(false); connect(transactionW, &PkTransactionWidget::titleChanged, ui->titleL, &QLabel::setText); emit changed(false); QEventLoop loop; connect(transaction, &PkTransaction::finished, &loop, &QEventLoop::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(QLatin1String("updates")); } else { // install then remove packages search(); } QTimer::singleShot(0, this, &ApperKCM::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" +#include "moc_ApperKCM.cpp" diff --git a/Apper/BackendDetails.cpp b/Apper/BackendDetails.cpp index 7846904..224a2b7 100644 --- a/Apper/BackendDetails.cpp +++ b/Apper/BackendDetails.cpp @@ -1,110 +1,110 @@ /*************************************************************************** * Copyright (C) 2009-2018 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 "BackendDetails.h" #include "ui_BackendDetails.h" #include #include #include using namespace PackageKit; BackendDetails::BackendDetails(QWidget *parent) : QDialog(parent), ui(new Ui::BackendDetails) { ui->setupUi(this); setWindowTitle(i18n("Backend Details")); setWindowIcon(QIcon::fromTheme(QLatin1String("help-about"))); // update information about PackageKit backend connect(Daemon::global(), &Daemon::changed, this, &BackendDetails::daemonChanged); if (Daemon::global()->isRunning()) { daemonChanged(); } } BackendDetails::~BackendDetails() { delete ui; } void BackendDetails::daemonChanged() { // PackageKit QString versionMajor = QString::number(Daemon::global()->versionMajor()); QString versionMinor = QString::number(Daemon::global()->versionMinor()); QString versionMicro = QString::number(Daemon::global()->versionMicro()); ui->pkVersionL->setText(versionMajor % QLatin1Char('.') % versionMinor % QLatin1Char('.') % versionMicro); // GENERAL - Setup backend name and author ui->nameL->setText(Daemon::global()->backendName()); ui->descriptionL->setText(Daemon::global()->backendDescription()); ui->authorL->setText(Daemon::global()->backendAuthor()); ui->distroL->setText(Daemon::global()->distroID()); // METHODS - Setup backend supported methods Transaction::Roles actions = Daemon::global()->roles();// TODO this is async now ui->getUpdatesCB->setChecked(actions & Transaction::RoleGetUpdates); ui->getDistroUpgradesCB->setChecked(actions & Transaction::RoleGetDistroUpgrades); ui->refreshCacheCB->setChecked(actions & Transaction::RoleRefreshCache); ui->searchNameCB->setChecked(actions & Transaction::RoleSearchName); ui->searchDetailsCB->setChecked(actions & Transaction::RoleSearchDetails); ui->searchGroupCB->setChecked(actions & Transaction::RoleSearchGroup); ui->searchFileCB->setChecked(actions & Transaction::RoleSearchFile); ui->cancelCB->setChecked(actions & Transaction::RoleCancel); ui->resolveCB->setChecked(actions & Transaction::RoleResolve); ui->updatePackageCB->setChecked(actions & Transaction::RoleUpdatePackages); ui->installPackageCB->setChecked(actions & Transaction::RoleInstallPackages); ui->removePackageCB->setChecked(actions & Transaction::RoleRemovePackages); ui->getDependsCB->setChecked(actions & Transaction::RoleDependsOn); ui->getRequiresCB->setChecked(actions & Transaction::RoleRequiredBy); ui->getUpdateDetailCB->setChecked(actions & Transaction::RoleGetUpdateDetail); ui->getDescriptionCB->setChecked(actions & Transaction::RoleGetDetails); ui->getFilesCB->setChecked(actions & Transaction::RoleRefreshCache); ui->installFileCB->setChecked(actions & Transaction::RoleInstallFiles); ui->getRepositoryListCB->setChecked(actions & Transaction::RoleGetRepoList); ui->repositoryEnableCB->setChecked(actions & Transaction::RoleRepoEnable); ui->repositorySetEnableCB->setChecked(actions & Transaction::RoleRepoSetData); ui->whatProvidesCB->setChecked(actions & Transaction::RoleWhatProvides); ui->getPackagesCB->setChecked(actions & Transaction::RoleGetPackages); ui->repairSystemCB->setChecked(actions & Transaction::RoleRepairSystem); // FILTERS - Setup filters Transaction::Filters filters = Daemon::global()->filters(); ui->installedCB->setChecked(filters & Transaction::FilterInstalled); ui->guiCB->setChecked(filters & Transaction::FilterGui); ui->developmentCB->setChecked(filters & Transaction::FilterDevel); ui->freeCB->setChecked(filters & Transaction::FilterFree); ui->visibleCB->setChecked(filters & Transaction::FilterVisible); ui->supportedCB->setChecked(filters & Transaction::FilterSupported); ui->newestCB->setChecked(filters & Transaction::FilterNewest); ui->archCB->setChecked(filters & Transaction::FilterNotArch); } -#include "BackendDetails.moc" +#include "moc_BackendDetails.cpp" diff --git a/Apper/BrowseView.cpp b/Apper/BrowseView.cpp index 8bff591..9979d19 100644 --- a/Apper/BrowseView.cpp +++ b/Apper/BrowseView.cpp @@ -1,336 +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, &QListView::clicked, this, &BrowseView::categoryActivated); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("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(QLatin1String("document-export"))); importInstalledPB->setIcon(QIcon::fromTheme(QLatin1String("document-import"))); KConfig config(QLatin1String("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, &QAction::toggled, this, &BrowseView::showVersions); 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, &QAction::toggled, this, &BrowseView::showArchs); 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, &QAction::toggled, this, &BrowseView::showOrigins); 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, &QAction::toggled, this, &BrowseView::showSizes); m_showPackageSizes->setChecked(viewGroup.readEntry("ShowPackageSizes", false)); // Ensure the index is visible when the packageDetails appears connect(packageDetails, &PackageDetails::ensureVisible, this, &BrowseView::ensureVisible); } 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(QLatin1String("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(QLatin1String("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(QLatin1String("apper")); KConfigGroup viewGroup(&config, "BrowseView"); viewGroup.writeEntry("ShowApplicationOrigins", enabled); packageView->header()->setSectionHidden(PackageModel::OriginCol, !enabled); } void BrowseView::showSizes(bool enabled) { KConfig config(QLatin1String("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(QLatin1Char('@'))) { 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(QLatin1Char(';')); } 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(QLatin1String("org.freedesktop.PackageKit"), QLatin1String("/org/freedesktop/PackageKit"), QLatin1String("org.freedesktop.PackageKit.Modify"), QLatin1String("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 "moc_BrowseView.cpp" diff --git a/Apper/CategoryModel.cpp b/Apper/CategoryModel.cpp index 9edb14a..1a629c6 100644 --- a/Apper/CategoryModel.cpp +++ b/Apper/CategoryModel.cpp @@ -1,419 +1,421 @@ /*************************************************************************** * 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 "CategoryModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER) using namespace PackageKit; CategoryModel::CategoryModel(QObject *parent) : QStandardItemModel(parent) { QStandardItem *item; item = new QStandardItem(i18n("Installed Software")); item->setDragEnabled(false); item->setData(Transaction::RoleGetPackages, SearchRole); item->setData(i18n("Lists"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(0, KCategorizedSortFilterProxyModel::CategorySortRole); item->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-apply"))); appendRow(item); item = new QStandardItem(i18n("Updates")); item->setDragEnabled(false); item->setData(Transaction::RoleGetUpdates, SearchRole); item->setData(i18n("Lists"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(0, KCategorizedSortFilterProxyModel::CategorySortRole); item->setIcon(QIcon::fromTheme(QLatin1String("system-software-update"))); appendRow(item); #ifdef HAVE_APPSTREAM // Get the groups #ifdef AS_CATEGORIES_PATH fillWithServiceGroups(); #else fillWithStandardGroups(); #endif // AS_CATEGORIES_PATH // category("", // "servers", // "Servers", // "const QString &summary", // "computer"); // category("servers", // "@coomputer", // "Lighttpd", // "const QString &summary", // "emblem-new"); // category("servers", // "@coomputer2", // "Apache", // "const QString &summary", // "dialog-cancel"); #else #endif //HAVE_APPSTREAM QTimer::singleShot(0, this, SIGNAL(finished())); } CategoryModel::~CategoryModel() { } void CategoryModel::setRoles(Transaction::Roles roles) { m_roles = roles; removeRows(2, rowCount() - 2); QDBusPendingReply > transactions = Daemon::getTransactionList(); transactions.waitForFinished(); if (m_roles & Transaction::RoleGetCategories && transactions.value().isEmpty()) { Transaction *trans = Daemon::getCategories(); connect(trans, &Transaction::category, this, &CategoryModel::category); connect(trans, &Transaction::finished, this, &CategoryModel::finished); } else { fillWithStandardGroups(); } } QModelIndex CategoryModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) { return QStandardItemModel::index(row, column, parent); } return QStandardItemModel::index(row, column, m_rootIndex); } int CategoryModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return QStandardItemModel::rowCount(parent); } return QStandardItemModel::rowCount(m_rootIndex); } void CategoryModel::setRootIndex(const QModelIndex &index) { beginResetModel(); m_rootIndex = index; endResetModel(); emit finished(); } bool CategoryModel::setParentIndex() { if (m_rootIndex.isValid()) { setRootIndex(m_rootIndex.parent()); // Return the future parent so that Back button can be disabled return m_rootIndex.parent().isValid(); } // if there is no higher level return false return false; } bool CategoryModel::hasParent() const { return m_rootIndex.isValid(); } void CategoryModel::category(const QString &parentId, const QString &categoryId, const QString &name, const QString &summary, const QString &icon) { qCDebug(APPER) << parentId << categoryId << name << summary << icon; auto item = new QStandardItem(name); item->setDragEnabled(false); item->setData(Transaction::RoleSearchGroup, SearchRole); item->setData(categoryId, GroupRole); item->setData(i18n("Categories"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(2, KCategorizedSortFilterProxyModel::CategorySortRole); item->setToolTip(summary); item->setIcon(QIcon(QLatin1String("/usr/share/pixmaps/comps/") + icon + QLatin1String(".png"))); if (parentId.isEmpty()) { appendRow(item); } else { QStandardItem *parent = findCategory(parentId); if (parent) { item->setData(parent->text(), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(2, KCategorizedSortFilterProxyModel::CategorySortRole); parent->appendRow(item); } else { appendRow(item); } } // This is a MUST since the spacing needs to be fixed emit finished(); } QStandardItem* CategoryModel::findCategory(const QString &categoryId, const QModelIndex &parent) const { QStandardItem *ret = nullptr; for (int i = 0; i < rowCount(parent); i++) { QModelIndex group = index(i, 0, parent); if (group.data(SearchRole).toUInt() == Transaction::RoleSearchGroup && group.data(GroupRole).toString() == categoryId) { ret = itemFromIndex(group); } else if (hasChildren(group)) { ret = findCategory(categoryId, group); } if (ret) { break; } } return ret; } void CategoryModel::fillWithStandardGroups() { // Get the groups m_groups = Daemon::global()->groups(); qCDebug(APPER); QStandardItem *item; for (int i = 1; i < 64; ++i) { if (m_groups & i) { Transaction::Group group; group = static_cast(i); if (group != Transaction::GroupUnknown) { item = new QStandardItem(PkStrings::groups(group)); item->setDragEnabled(false); item->setData(Transaction::RoleSearchGroup, SearchRole); item->setData(group, GroupRole); item->setData(i18n("Groups"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(1, KCategorizedSortFilterProxyModel::CategorySortRole); item->setIcon(PkIcons::groupsIcon(group)); if (!(m_roles & Transaction::RoleSearchGroup)) { item->setSelectable(false); } appendRow(item); } } } emit finished(); } void CategoryModel::fillWithServiceGroups() { #ifdef AS_CATEGORIES_PATH KLocale::global()->insertCatalog("gnome-menus"); QFile file(QString(AS_CATEGORIES_PATH) + "/categories.xml"); if (!file.open(QIODevice::ReadOnly)) { qCDebug(APPER) << "Failed to open file"; fillWithStandardGroups(); return; } QXmlStreamReader xml(&file); while(xml.readNextStartElement() && !xml.hasError()) { // Read next element. if(xml.tokenType() == QXmlStreamReader::StartDocument) { // qCDebug(APPER) << "StartDocument"; continue; } if(xml.name() == "Menu") { parseMenu(xml, QString()); } } #endif //AS_CATEGORIES_PATH } void CategoryModel::parseMenu(QXmlStreamReader &xml, const QString &parentIcon, QStandardItem *parent) { QString icon = parentIcon; QStandardItem *item = 0; while(!xml.atEnd() && !(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == QLatin1String("Menu"))) { if(xml.tokenType() == QXmlStreamReader::StartElement) { if (xml.name() == QLatin1String("Menu")) { xml.readNext(); parseMenu(xml, icon, item); } else if (xml.name() == QLatin1String("Name")) { QString name = xml.readElementText(); if (!item) { item = new QStandardItem(i18n(name.toUtf8().data())); item->setDragEnabled(false); } else if (item->text().isEmpty()) { item->setText(i18n(name.toUtf8().data())); } } else if (xml.name() == QLatin1String("Icon")) { if (!item) { item = new QStandardItem; item->setDragEnabled(false); } // only sets the icon if it wasn't set, // the .directory might have a better one QString _icon; _icon = xml.readElementText(); if (item->icon().isNull()) { item->setIcon(PkIcons::getIcon(_icon, icon)); icon = _icon; } } else if (xml.name() == QLatin1String("Categories")) { QList categories; categories = parseCategories(xml); if (!categories.isEmpty()) { if (!item) { item = new QStandardItem; item->setDragEnabled(false); } // If we only have one category inside get the first item if (categories.size() == 1) { item->setData(qVariantFromValue(categories.first()), CategoryRole); } else { CategoryMatcher parser(CategoryMatcher::And); parser.setChild(categories); item->setData(qVariantFromValue(parser), CategoryRole); } item->setData(Transaction::RoleResolve, SearchRole); } } else if (xml.name() == QLatin1String("Directory")) { if (!item) { item = new QStandardItem; item->setDragEnabled(false); } QString directory = xml.readElementText(); const KDesktopFile desktopFile(directory); const KConfigGroup config = desktopFile.desktopGroup(); QString _icon = config.readEntry("Icon"); QString _name = config.readEntry("Name"); if (!_icon.isEmpty()) { item->setIcon(PkIcons::getIcon(_icon, icon)); icon = _icon; } if (!_name.isEmpty()) { item->setText(_name); } } else if (xml.name() == QLatin1String("PkGroups")) { if (!item) { item = new QStandardItem; item->setDragEnabled(false); } QString group = xml.readElementText(); Transaction::Group groupEnum; int groupInt = Daemon::enumFromString(group, "Group"); groupEnum = static_cast(groupInt); if (groupEnum != Transaction::GroupUnknown && m_groups & groupEnum) { item->setData(Transaction::RoleSearchGroup, SearchRole); item->setData(groupEnum, GroupRole); } } } // next... xml.readNext(); } if (item && (!item->data(GroupRole).isNull() || !item->data(CategoryRole).isNull())) { if (item->data(CategoryRole).isNull()) { // Set the group name to get it translated Transaction::Group group; group = item->data(GroupRole).value(); item->setText(PkStrings::groups(group)); } item->setData(i18n("Categories"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(1, KCategorizedSortFilterProxyModel::CategorySortRole); if (parent) { parent->appendRow(item); } else { appendRow(item); } } } QList CategoryModel::parseCategories(QXmlStreamReader &xml) { QString token = xml.name().toString(); QList ret; while(!xml.atEnd() && !(xml.readNext() == QXmlStreamReader::EndElement && xml.name() == token)) { if(xml.tokenType() == QXmlStreamReader::StartElement) { // Where the categories where AND if (xml.name() == QLatin1String("And")) { // We are going to read the next element to save the token name QList parsers; parsers = parseCategories(xml); if (!parsers.isEmpty()) { CategoryMatcher opAND(CategoryMatcher::And); opAND.setChild(parsers); ret << opAND; } } else if (xml.name() == QLatin1String("Or")) { // Where the categories where OR QList parsers; parsers = parseCategories(xml); if (!parsers.isEmpty()) { CategoryMatcher opOR(CategoryMatcher::Or); opOR.setChild(parsers); ret << opOR; } } else if (xml.name() == QLatin1String("Not")) { // USED to negate the categories inside it QList parsers; parsers = parseCategories(xml); if (!parsers.isEmpty()) { CategoryMatcher opNot(CategoryMatcher::Not); opNot.setChild(parsers); ret << opNot; } } else if (xml.name() == QLatin1String("Category")) { // Found the real category, if the join was not means // that applications in this category should NOT be displayed QString name = xml.readElementText(); if (!name.isEmpty()){ ret << CategoryMatcher(CategoryMatcher::Term, name); } } } } return ret; } + +#include "moc_CategoryModel.cpp" diff --git a/Apper/ClickableLabel.cpp b/Apper/ClickableLabel.cpp index 53973c3..06c76b5 100644 --- a/Apper/ClickableLabel.cpp +++ b/Apper/ClickableLabel.cpp @@ -1,35 +1,37 @@ /*************************************************************************** * 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 "moc_ClickableLabel.cpp" diff --git a/Apper/FiltersMenu.cpp b/Apper/FiltersMenu.cpp index 41a527f..75673b1 100644 --- a/Apper/FiltersMenu.cpp +++ b/Apper/FiltersMenu.cpp @@ -1,340 +1,342 @@ /*************************************************************************** * 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(QLatin1String("apper")); KConfigGroup filterMenuGroup(&config, "FilterMenu"); auto menuCollections = new QMenu(i18n("Collections"), this); connect(menuCollections, &QMenu::triggered, this, &FiltersMenu::filtersChanged); QAction *action = addMenu(menuCollections); connect(this, &FiltersMenu::enableCollections, action, &QAction::setVisible); auto 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; auto 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 auto menuInstalled = new QMenu(i18n("Installed"), this); connect(menuInstalled, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableInstalled, addMenu(menuInstalled), &QAction::setVisible); addMenu(menuInstalled); auto installedGroup = new QActionGroup(menuInstalled); installedGroup->setExclusive(true); auto installedTrue = new QAction(i18n("Only installed"), installedGroup); installedTrue->setCheckable(true); m_filtersAction[installedTrue] = Transaction::FilterInstalled; installedGroup->addAction(installedTrue); menuInstalled->addAction(installedTrue); m_actions << installedTrue; auto installedFalse = new QAction(i18n("Only available"), installedGroup); installedFalse->setCheckable(true); m_filtersAction[installedFalse] = Transaction::FilterNotInstalled; installedGroup->addAction(installedFalse); menuInstalled->addAction(installedFalse); m_actions << installedFalse; auto installedNone = new QAction(i18n("No filter"), installedGroup); installedNone->setCheckable(true); installedNone->setChecked(true); installedGroup->addAction(installedNone); menuInstalled->addAction(installedNone); m_actions << installedNone; // Development auto menuDevelopment = new QMenu(i18n("Development"), this); connect(menuDevelopment, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableDevelopment, addMenu(menuDevelopment), &QAction::setVisible); addMenu(menuDevelopment); auto developmentGroup = new QActionGroup(menuDevelopment); developmentGroup->setExclusive(true); auto developmentTrue = new QAction(i18n("Only development"), developmentGroup); developmentTrue->setCheckable(true); m_filtersAction[developmentTrue] = Transaction::FilterDevel; developmentGroup->addAction(developmentTrue); menuDevelopment->addAction(developmentTrue); m_actions << developmentTrue; auto 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; auto developmentNone = new QAction(i18n("No filter"), developmentGroup); developmentNone->setCheckable(true); developmentNone->setChecked(true); developmentGroup->addAction(developmentNone); menuDevelopment->addAction(developmentNone); m_actions << developmentNone; // Graphical auto menuGui = new QMenu(i18n("Graphical"), this); connect(menuGui, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableGraphical, addMenu(menuGui), &QAction::setVisible); addMenu(menuGui); auto guiGroup = new QActionGroup(menuGui); guiGroup->setExclusive(true); auto guiTrue = new QAction(i18n("Only graphical"), guiGroup); guiTrue->setCheckable(true); m_filtersAction[guiTrue] = Transaction::FilterGui; guiGroup->addAction(guiTrue); menuGui->addAction(guiTrue); m_actions << guiTrue; auto guiFalse = new QAction(i18n("Only text"), guiGroup); guiFalse->setCheckable(true); m_filtersAction[guiFalse] = Transaction::FilterNotGui; guiGroup->addAction(guiFalse); menuGui->addAction(guiFalse); m_actions << guiFalse; auto guiNone = new QAction(i18n("No filter"), guiGroup); guiNone->setCheckable(true); guiNone->setChecked(true); guiGroup->addAction(guiNone); menuGui->addAction(guiNone); m_actions << guiNone; // Free auto menuFree = new QMenu(i18nc("Filter for free packages", "Free"), this); connect(menuFree, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableFree, addMenu(menuFree), &QAction::setVisible); addMenu(menuFree); auto freeGroup = new QActionGroup(menuFree); freeGroup->setExclusive(true); auto 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; auto 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; auto freeNone = new QAction(i18n("No filter"), freeGroup); freeNone->setCheckable(true); freeNone->setChecked(true); freeGroup->addAction(freeNone); menuFree->addAction(freeNone); m_actions << freeNone; // Supported auto menuSupported = new QMenu(i18nc("Filter for supported packages", "Supported"), this); connect(menuSupported, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableSupported, addMenu(menuSupported), &QAction::setVisible); addMenu(menuSupported); auto supportedGroup = new QActionGroup(menuSupported); supportedGroup->setExclusive(true); auto 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; auto 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; auto supportedNone = new QAction(i18n("No filter"), supportedGroup); supportedNone->setCheckable(true); supportedNone->setChecked(true); supportedGroup->addAction(supportedNone); menuSupported->addAction(supportedNone); m_actions << supportedNone; // Source auto menuSource = new QMenu(i18nc("Filter for source packages", "Source"), this); connect(menuSource, &QMenu::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableSource, addMenu(menuSource), &QAction::setVisible); addMenu(menuSource); auto sourceGroup = new QActionGroup(menuSource); sourceGroup->setExclusive(true); auto sourceTrue = new QAction(i18n("Only sourcecode"), sourceGroup); sourceTrue->setCheckable(true); m_filtersAction[sourceTrue] = Transaction::FilterSource; sourceGroup->addAction(sourceTrue); menuSource->addAction(sourceTrue); m_actions << sourceTrue; auto 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; auto 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, &FiltersMenu::enableBasenameNewestArchSeparator, addSeparator(), &QAction::setVisible); auto basename = new QAction(i18n("Hide Subpackages"), this); connect(basename, &QAction::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableBasename, basename, &QAction::setVisible); basename->setCheckable(true); basename->setToolTip(i18n("Only show one package, not subpackages")); m_filtersAction[basename] = Transaction::FilterBasename; m_actions << basename; auto newest = new QAction(i18n("Only Newest Packages"), this); connect(newest, &QAction::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableNewest, newest, &QAction::setVisible); 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; auto native = new QAction(i18n("Only Native Packages"), this); connect(native, &QAction::triggered, this, &FiltersMenu::filtersChanged); connect(this, &FiltersMenu::enableArch, native, &QAction::setVisible); 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(QLatin1String("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; const QVector actions = m_actions; for (QAction * const action : actions) { if (action->isChecked()) { if (m_filtersAction.contains(action)) { filters |= m_filtersAction[action]; filterSet = true; } } } if (!filterSet) { filters = Transaction::FilterNone; } return filters; } + +#include "moc_FiltersMenu.cpp" diff --git a/Apper/GraphicsOpacityDropShadowEffect.cpp b/Apper/GraphicsOpacityDropShadowEffect.cpp index 32d0ec2..c45384d 100644 --- a/Apper/GraphicsOpacityDropShadowEffect.cpp +++ b/Apper/GraphicsOpacityDropShadowEffect.cpp @@ -1,51 +1,53 @@ /*************************************************************************** * 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 "moc_GraphicsOpacityDropShadowEffect.cpp" diff --git a/Apper/MainUi.cpp b/Apper/MainUi.cpp index 45f9a95..161cef5 100644 --- a/Apper/MainUi.cpp +++ b/Apper/MainUi.cpp @@ -1,89 +1,89 @@ /*************************************************************************** * Copyright (C) 2009-2018 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 "MainUi.h" #include #include #include #include #include #include #include #include "ApperKCM.h" Q_DECLARE_LOGGING_CATEGORY(APPER) MainUi::MainUi(QWidget *parent) : QMainWindow(parent), m_apperModule(0) { setWindowIcon(QIcon::fromTheme(QLatin1String("system-software-install"))); setWindowTitle(i18n("Apper")); KConfig config(QLatin1String("apper")); KConfigGroup configGroup(&config, "MainUi"); restoreGeometry(configGroup.readEntry("geometry", QByteArray())); restoreState(configGroup.readEntry("state", QByteArray())); m_apperModule = new ApperKCM(this); setCentralWidget(m_apperModule); connect(m_apperModule, &ApperKCM::caption, this, &MainUi::setWindowTitle); } MainUi::~MainUi() { } void MainUi::showAll() { if (m_apperModule) { m_apperModule->setProperty("page", QLatin1String("home")); } } void MainUi::showUpdates() { if (m_apperModule) { m_apperModule->setProperty("page", QLatin1String("updates")); } } void MainUi::showSettings() { if (m_apperModule) { m_apperModule->setProperty("page", QLatin1String("settings")); } } void MainUi::closeEvent(QCloseEvent *event) { KConfig config(QLatin1String("apper")); KConfigGroup configGroup(&config, "MainUi"); configGroup.writeEntry("geometry", saveGeometry()); configGroup.writeEntry("state", saveState()); QMainWindow::closeEvent(event); emit finished(); } -#include "MainUi.moc" +#include "moc_MainUi.cpp" diff --git a/Apper/PackageDetails.cpp b/Apper/PackageDetails.cpp index 75a3919..7acc0b5 100644 --- a/Apper/PackageDetails.cpp +++ b/Apper/PackageDetails.cpp @@ -1,800 +1,802 @@ /*************************************************************************** * Copyright (C) 2009-2018 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(QLatin1String("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(QLatin1String("help-about"))); connect(m_actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(actionActivated(QAction*))); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("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() { delete ui; } 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() { const QUrl url = screenshot(Transaction::packageName(m_packageID)); if (!url.isEmpty()) { auto 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(QLatin1Char('\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(QLatin1Char('\n'), QLatin1String("
"))); ui->descriptionL->show(); } else { ui->descriptionL->clear(); } if (!m_details.url().isEmpty()) { ui->homepageL->setText(QLatin1String("") + m_details.url() + QLatin1String("")); 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(QLatin1String("")) .arg(KIconLoader::global()->iconPath(QLatin1String("kde"), KIconLoader::Small))); path.append(QString(QLatin1String(" %1  %3")) .arg(QString::fromUtf8("âžœ")) .arg(KIconLoader::global()->iconPath(QLatin1String("applications-other"), KIconLoader::Small)) .arg(i18n("Applications"))); for (int i = 0; i < ret.size(); i++) { path.append(QString(QLatin1String(" %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() != QLatin1String("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()) + QLatin1String(" - ") + 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 QString();//AppStream::instance()->thumbnail(pkgName); #endif } QUrl PackageDetails::screenshot(const QString &pkgName) const { #ifndef HAVE_APPSTREAM Q_UNUSED(pkgName) return QUrl(); #else return AppStreamHelper::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. const QList apps = AppStreamHelper::instance()->applications(Transaction::packageName(m_packageID)); for (const AppStream::Component &app : apps) { if (!app.description().isEmpty()) { m_detailsDescription = app.description(); break; } } #endif } void PackageDetails::finished() { if (m_busySeq) { m_busySeq->stop(); } m_transaction = 0; auto 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 "moc_PackageDetails.cpp" diff --git a/Apper/ScreenShotViewer.cpp b/Apper/ScreenShotViewer.cpp index 8d7a32f..92777de 100644 --- a/Apper/ScreenShotViewer.cpp +++ b/Apper/ScreenShotViewer.cpp @@ -1,107 +1,109 @@ /*************************************************************************** * Copyright (C) 2009-2018 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 QUrl &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(QLatin1String("layer-visible-on"))); auto tempFile = new QTemporaryFile; // tempFile->setPrefix("appgetfull"); // tempFile->setSuffix(".png"); tempFile->open(); KIO::FileCopyJob *job = KIO::file_copy(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(KIconLoader::global()->loadPixmapSequence(QLatin1String("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, &QPropertyAnimation::finished, this, &ScreenShotViewer::fadeIn); anim1->start(); } else { m_screenshotL->setText(i18n("Could not find screen shot.")); } } void ScreenShotViewer::fadeIn() { auto effect = new QGraphicsOpacityEffect(m_screenshotL); effect->setOpacity(0); auto 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 "moc_ScreenShotViewer.cpp" diff --git a/Apper/Settings/OriginModel.cpp b/Apper/Settings/OriginModel.cpp index 45a15e7..c49caab 100644 --- a/Apper/Settings/OriginModel.cpp +++ b/Apper/Settings/OriginModel.cpp @@ -1,103 +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({ 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, &Transaction::errorCode, this, &OriginModel::errorCode); connect(transaction, &Transaction::finished, this, &OriginModel::setRepoFinished); } 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; } auto 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 "moc_OriginModel.cpp" diff --git a/Apper/Settings/Settings.cpp b/Apper/Settings/Settings.cpp index d06ac0c..2175ea7 100644 --- a/Apper/Settings/Settings.cpp +++ b/Apper/Settings/Settings.cpp @@ -1,351 +1,353 @@ /*************************************************************************** * 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 Q_DECLARE_LOGGING_CATEGORY(APPER) using namespace PackageKit; Settings::Settings(Transaction::Roles roles, QWidget *parent) : QWidget(parent), ui(new Ui::Settings), m_roles(roles) { ui->setupUi(this); auto action = new QAction(i18n("Refresh Cache"), this); connect(action, &QAction::triggered, this, &Settings::refreshCache); connect(action, &QAction::triggered, ui->messageWidget, &KMessageWidget::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, &OriginModel::refreshRepoList, this, &Settings::refreshRepoModel); connect(m_originModel, &OriginModel::refreshRepoList, ui->messageWidget, &KMessageWidget::animatedShow); auto 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, &QCheckBox::stateChanged, this, &Settings::checkChanges); connect(ui->appLauncherCB, &QCheckBox::stateChanged, this, &Settings::checkChanges); connect(ui->distroIntervalCB, QOverload::of(&KComboBox::currentIndexChanged), this, &Settings::checkChanges); connect(ui->intervalCB, QOverload::of(&KComboBox::currentIndexChanged), this, &Settings::checkChanges); connect(ui->checkUpdatesBatteryCB, &QCheckBox::stateChanged, this, &Settings::checkChanges); connect(ui->checkUpdatesMobileCB, &QCheckBox::stateChanged, this, &Settings::checkChanges); connect(ui->autoCB, QOverload::of(&KComboBox::currentIndexChanged), this, &Settings::checkChanges); connect(ui->installUpdatesBatteryCB, &QCheckBox::stateChanged, this, &Settings::checkChanges); connect(ui->installUpdatesMobileCB, &QCheckBox::stateChanged, this, &Settings::checkChanges); // Setup buttons QPushButton *apply = ui->buttonBox->button(QDialogButtonBox::Apply); apply->setEnabled(false); connect(apply, &QPushButton::clicked, this, &Settings::save); connect(this, &Settings::changed, apply, &QPushButton::setEnabled); QPushButton *reset = ui->buttonBox->button(QDialogButtonBox::Reset); // reset->setEnabled(false); connect(reset, &QPushButton::clicked, this, &Settings::defaults); // connect(this, &Settings::changed, reset, &QPushButton::setDisabled); // Setup the busy cursor m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("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 = Daemon::getRepoList(state == Qt::Checked ? Transaction::FilterNone : Transaction::FilterNotDevel); connect(transaction, &Transaction::repoDetail, m_originModel, &OriginModel::addOriginItem); connect(transaction, &Transaction::finished, m_originModel, &OriginModel::finished); connect(transaction, &Transaction::finished, m_busySeq, &KPixmapSequenceOverlayPainter::stop); connect(transaction, &Transaction::finished, this, &Settings::checkChanges); m_busySeq->start(); KConfig config(QLatin1String("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(QLatin1String("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(QLatin1String("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... ui->intervalCB->addItem(KFormat().formatSpelloutDuration(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; for (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() { qCDebug(APPER) << "Saving settings"; KConfig config(QLatin1String("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()); emit changed(false); } void Settings::defaults() { qCDebug(APPER) << "Restoring default settings"; 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 "moc_Settings.cpp" diff --git a/Apper/TransactionFilterModel.cpp b/Apper/TransactionFilterModel.cpp index f0c2192..38c512e 100644 --- a/Apper/TransactionFilterModel.cpp +++ b/Apper/TransactionFilterModel.cpp @@ -1,46 +1,48 @@ /*************************************************************************** * 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 { const QVariant leftData = sourceModel()->data(left, Qt::UserRole); const QVariant rightData = sourceModel()->data(right, Qt::UserRole); if (leftData.type() == QVariant::DateTime) { return leftData.toDateTime() < rightData.toDateTime(); } else { return QSortFilterProxyModel::lessThan(left, right); } } + +#include "moc_TransactionFilterModel.cpp" diff --git a/Apper/TransactionHistory.cpp b/Apper/TransactionHistory.cpp index 238c556..c1624b0 100644 --- a/Apper/TransactionHistory.cpp +++ b/Apper/TransactionHistory.cpp @@ -1,86 +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")); + QAction *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", KFormat().formatSpelloutDuration(time)); timeCacheLabel->setText(text); } + +#include "moc_TransactionHistory.cpp" diff --git a/Apper/TransactionModel.cpp b/Apper/TransactionModel.cpp index 2d9c1b7..0aadd7a 100644 --- a/Apper/TransactionModel.cpp +++ b/Apper/TransactionModel.cpp @@ -1,155 +1,157 @@ /*************************************************************************** * 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 "TransactionModel.h" #include #include #include #include #include #include using namespace PackageKit; TransactionModel::TransactionModel(QObject *parent) : QStandardItemModel(parent) { setSortRole(Qt::DisplayRole); clear(); } void TransactionModel::clear() { QStandardItemModel::clear(); setHorizontalHeaderItem(0, new QStandardItem(i18n("Date"))); setHorizontalHeaderItem(1, new QStandardItem(i18n("Action"))); setHorizontalHeaderItem(2, new QStandardItem(i18n("Details"))); setHorizontalHeaderItem(3, new QStandardItem(i18nc("Machine user who issued the transaction", "Username"))); setHorizontalHeaderItem(4, new QStandardItem(i18n("Application"))); } void TransactionModel::addTransaction(PackageKit::Transaction *trans) { auto dateI = new QStandardItem; auto roleI = new QStandardItem; auto detailsI = new QStandardItem; auto userI = new QStandardItem; auto appI = new QStandardItem; dateI->setText(QLocale::system().toString(trans->timespec().date())); // this is for the filterSort model dateI->setData(trans->timespec(), Qt::UserRole); dateI->setEditable(false); roleI->setText(PkStrings::actionPast(trans->role())); roleI->setIcon(PkIcons::actionIcon(trans->role())); roleI->setEditable(false); detailsI->setText(getDetailsLocalized(trans->data())); detailsI->setEditable(false); KUser user(trans->uid()); QString display; if (!user.property(KUser::FullName).toString().isEmpty()) { display = user.property(KUser::FullName).toString() + QLatin1String(" (") + user.loginName() + QLatin1Char(')'); } else { display = user.loginName(); } userI->setText(display); userI->setEditable(false); appI->setText(trans->cmdline()); appI->setEditable(false); appendRow({ dateI, roleI, detailsI, userI, appI }); delete trans; } QString TransactionModel::getDetailsLocalized(const QString &data) const { QStringList lines = data.split(QLatin1Char('\n')); QStringList ret; QString text; text = getTypeLine(lines, Transaction::StatusInstall); if (!text.isNull()) { ret << text; } text = getTypeLine(lines, Transaction::StatusRemove); if (!text.isNull()) { ret << text; } text = getTypeLine(lines, Transaction::StatusUpdate); if (!text.isNull()) { ret << text; } return ret.join(QLatin1Char('\n')); } QString TransactionModel::getTypeLine(const QStringList &lines, Transaction::Status status) const { QStringList text; for (const QString &line : lines) { const QStringList sections = line.split(QLatin1Char('\t')); if (sections.size() > 1) { switch (status) { case Transaction::StatusInstall: if (sections.at(0) != QLatin1String("installing")) { continue; } break; case Transaction::StatusRemove: if (sections.at(0) != QLatin1String("removing")) { continue; } break; case Transaction::StatusUpdate: if (sections.at(0) != QLatin1String("updating")) { continue; } break; default: continue; } QStringList packageData = sections.at(1).split(QLatin1Char(';')); if (packageData.size()) { text << packageData.at(0); } } } if (text.size()) { // TODO make the status BOLD return PkStrings::statusPast(status) + QLatin1String(": ") + text.join(QLatin1String(", ")); } else { return QString(); } } + +#include "moc_TransactionModel.cpp" diff --git a/Apper/Updater/CheckableHeader.cpp b/Apper/Updater/CheckableHeader.cpp index 09f7bd4..af899fd 100644 --- a/Apper/Updater/CheckableHeader.cpp +++ b/Apper/Updater/CheckableHeader.cpp @@ -1,176 +1,178 @@ /*************************************************************************** * 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 "moc_CheckableHeader.cpp" diff --git a/Apper/Updater/DistroUpgrade.cpp b/Apper/Updater/DistroUpgrade.cpp index da0f870..4e76f65 100644 --- a/Apper/Updater/DistroUpgrade.cpp +++ b/Apper/Updater/DistroUpgrade.cpp @@ -1,115 +1,117 @@ /*************************************************************************** * 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 += QLatin1Char(' ') + i18n("It is recommended to plug in your computer before proceeding."); } else if (hasBattery) { warning += QLatin1Char(' ') + 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, &QProcess::errorOccurred, this, &DistroUpgrade::distroUpgradeError); connect(m_distroUpgradeProcess, QOverload::of(&QProcess::finished), this, &DistroUpgrade::distroUpgradeFinished); QStringList env = QProcess::systemEnvironment(); env << QLatin1String("DESKTOP=kde"); m_distroUpgradeProcess->setEnvironment(env); m_distroUpgradeProcess->start(QLatin1String("/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 "moc_DistroUpgrade.cpp" diff --git a/Apper/Updater/UpdateDetails.cpp b/Apper/Updater/UpdateDetails.cpp index f0511f5..e0e1a68 100644 --- a/Apper/Updater/UpdateDetails.cpp +++ b/Apper/Updater/UpdateDetails.cpp @@ -1,336 +1,338 @@ /*************************************************************************** * Copyright (C) 2009-2018 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) { setupUi(this); hideTB->setIcon(QIcon::fromTheme(QLatin1String("window-close"))); connect(hideTB, &QToolButton::clicked, this, &UpdateDetails::hide); m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("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); auto 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, &QPropertyAnimation::finished, this, &UpdateDetails::display); auto 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)); auto 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, &QParallelAnimationGroup::finished, this, &UpdateDetails::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, &Transaction::updateDetail, this, &UpdateDetails::updateDetail); disconnect(m_transaction, &Transaction::finished, this, &UpdateDetails::display); } m_transaction = Daemon::getUpdateDetail(m_packageId); connect(m_transaction, &Transaction::updateDetail, this, &UpdateDetails::updateDetail); connect(m_transaction, &Transaction::finished, this, &UpdateDetails::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 += QLatin1String("

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

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

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

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

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

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

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

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

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

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

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

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

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

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

") + _updateText + QLatin1String("

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

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

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

") + 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()) + QLatin1String("
") + getLinkList(bugzillaUrls) + QLatin1String("

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

") + 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()) + QLatin1String("
") + getLinkList(cveUrls) + QLatin1String("

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

"); } m_currentDescription = description; m_busySeq->stop(); } QString UpdateDetails::getLinkList(const QStringList &urls) const { QString ret; for (const QString &url : urls) { if (!ret.isEmpty()) { ret += QLatin1String("
"); } 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 "moc_UpdateDetails.cpp" diff --git a/Apper/Updater/Updater.cpp b/Apper/Updater/Updater.cpp index bb79e47..d5376f8 100644 --- a/Apper/Updater/Updater.cpp +++ b/Apper/Updater/Updater.cpp @@ -1,349 +1,351 @@ /*************************************************************************** * 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 Q_DECLARE_LOGGING_CATEGORY(APPER) Updater::Updater(Transaction::Roles roles, QWidget *parent) : QWidget(parent), ui(new Ui::Updater), m_roles(roles) { ui->setupUi(this); updatePallete(); // connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), // this, SLOT(updatePallete())); m_updatesModel = new PackageModel(this); m_updatesModel->setCheckable(true); auto 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, &PackageModel::changed, this, &Updater::checkEnableUpdateButton); //initialize the model, delegate, client and connect it's signals m_header = new CheckableHeader(Qt::Horizontal, this); connect(m_header, &CheckableHeader::toggled, m_updatesModel, &PackageModel::setAllChecked); 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(KIconLoader::global()->loadPixmapSequence(QLatin1String("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(QLatin1String("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, &QAction::toggled, this, &Updater::showVersions); 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, &QAction::toggled, this, &Updater::showCurrentVersions); 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, &QAction::toggled, this, &Updater::showArchs); 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, &QAction::toggled, this, &Updater::showOrigins); 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, &QAction::toggled, this, &Updater::showSizes); m_showPackageSize->setChecked(viewGroup.readEntry("ShowSizes", true)); } Updater::~Updater() { delete ui; } void Updater::showVersions(bool enabled) { KConfig config(QLatin1String("apper")); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowVersions", enabled); ui->packageView->header()->setSectionHidden(PackageModel::VersionCol, !enabled); } void Updater::showCurrentVersions(bool enabled) { KConfig config(QLatin1String("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(QLatin1String("apper")); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("ShowArchs", enabled); ui->packageView->header()->setSectionHidden(PackageModel::ArchCol, !enabled); } void Updater::showOrigins(bool enabled) { KConfig config(QLatin1String("apper")); KConfigGroup viewGroup(&config, "UpdateView"); viewGroup.writeEntry("showOrigins", enabled); ui->packageView->header()->setSectionHidden(PackageModel::OriginCol, !enabled); } void Updater::showSizes(bool enabled) { KConfig config(QLatin1String("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(); auto 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() { qCDebug(APPER) << "updates has changes" << hasChanges(); 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, &Transaction::package, m_updatesModel, &PackageModel::addSelectedPackage); connect(m_updatesT, &Transaction::errorCode, this, &Updater::errorCode); connect(m_updatesT, &Transaction::finished, m_busySeq, &KPixmapSequenceOverlayPainter::stop); connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::finished); // This is required to estimate download size connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::fetchSizes); if (m_showPackageCurrentVersion->isChecked()) { connect(m_updatesT, &Transaction::finished, m_updatesModel, &PackageModel::fetchCurrentVersions); } connect(m_updatesT, &Transaction::finished, this, &Updater::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(m_updatesT, &Transaction::distroUpgrade, this, &Updater::distroUpgrade); connect(m_updatesT, &Transaction::finished, t, &Transaction::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(QLatin1String("view-refresh"))); connect(action, &QAction::triggered, this, &Updater::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 "moc_Updater.cpp" diff --git a/PkSession/AbstractIsRunning.cpp b/PkSession/AbstractIsRunning.cpp index 2dc5c15..df48fe5 100644 --- a/PkSession/AbstractIsRunning.cpp +++ b/PkSession/AbstractIsRunning.cpp @@ -1,59 +1,61 @@ /*************************************************************************** * Copyright (C) 2009-2018 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 "AbstractIsRunning.h" #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) using namespace PackageKit; AbstractIsRunning::AbstractIsRunning(QObject *parent) : QObject(parent) { } AbstractIsRunning::~AbstractIsRunning() { } void AbstractIsRunning::increaseRunning() { m_running++; qCDebug(APPER_SESSION) << "Increase running" << m_running; } void AbstractIsRunning::decreaseRunning() { m_running--; qCDebug(APPER_SESSION) << "Decrease running" << m_running; if (!isRunning()) { qCDebug(APPER_SESSION) << "All tasks completed"; emit close(); } } bool AbstractIsRunning::isRunning() const { return m_running > 0; } + +#include "moc_AbstractIsRunning.cpp" diff --git a/PkSession/IntroDialog.cpp b/PkSession/IntroDialog.cpp index 36dc9ce..51ebab4 100644 --- a/PkSession/IntroDialog.cpp +++ b/PkSession/IntroDialog.cpp @@ -1,80 +1,80 @@ /*************************************************************************** * 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 "IntroDialog.h" #include "ui_IntroDialog.h" #include #include #include #include #include #include #include #include #include "FilesModel.h" IntroDialog::IntroDialog(QWidget *parent) : QWidget(parent), ui(new Ui::IntroDialog) { ui->setupUi(this); } IntroDialog::~IntroDialog() { delete ui; } void IntroDialog::setModel(QAbstractItemModel *model) { ui->listView->setModel(model); connect(model, &QAbstractItemModel::dataChanged, this, &IntroDialog::selectionChanged); } void IntroDialog::acceptDrops(const QString &toolTip) { ui->listView->setDragDropMode(QListView::DropOnly); ui->listView->setToolTip(toolTip); } bool IntroDialog::canContinue() const { return ui->listView->model()->rowCount(); } void IntroDialog::selectionChanged() { // if the model has more than one item it can continue emit continueChanged(canContinue()); } void IntroDialog::setDescription(const QString &description) { ui->descriptionL->setText(description); } -#include "IntroDialog.moc" +#include "moc_IntroDialog.cpp" diff --git a/PkSession/PkInstallCatalogs.cpp b/PkSession/PkInstallCatalogs.cpp index c492094..1188aed 100644 --- a/PkSession/PkInstallCatalogs.cpp +++ b/PkSession/PkInstallCatalogs.cpp @@ -1,274 +1,274 @@ /*************************************************************************** * 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 "PkInstallCatalogs.h" #include "IntroDialog.h" #include "FilesModel.h" #include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) PkInstallCatalogs::PkInstallCatalogs(uint xid, const QStringList &files, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent), m_interaction(interaction), m_message(message) { setWindowTitle(i18n("Install Packages Catalogs")); // Find out how many packages PackageKit is able to resolve QFile file(QLatin1String("/etc/PackageKit/PackageKit.conf")); QRegExp rx(QLatin1String("\\s*MaximumItemsToResolve=(\\d+)"), Qt::CaseSensitive); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); while (!in.atEnd()) { if (rx.indexIn(in.readLine()) != -1) { m_maxResolve = rx.capturedTexts()[1].toInt(); break; } } } const QStringList mimes{ QLatin1String("application/x-catalog"), QLatin1String("text/plain") }; m_introDialog = new IntroDialog(this); m_introDialog->acceptDrops(i18n("You can drop more catalogs in here")); m_model = new FilesModel(files, mimes, this); connect(m_model, &FilesModel::rowsInserted, this, &PkInstallCatalogs::modelChanged); m_introDialog->setModel(m_model); setMainWidget(m_introDialog); modelChanged(); } PkInstallCatalogs::~PkInstallCatalogs() { } void PkInstallCatalogs::modelChanged() { const QStringList files = m_model->files(); enableButtonOk(!files.isEmpty()); QString description; if (files.isEmpty()) { description = i18n("No supported catalog was found"); } else { description = i18np("Do you want to install this catalog?", "Do you want to install these catalogs?", files.size()); } m_introDialog->setDescription(description); QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("An application wants to install a catalog", "An application wants to install catalogs", files.size()); } else { title = i18np("The application %2 wants to install a catalog", "The application %2 wants to install catalogs", files.size(), parentTitle); } setTitle(title); } void PkInstallCatalogs::search() { const QString distroId = Daemon::global()->distroID(); const QStringList parts = distroId.split(QLatin1Char(';')); if (parts.size() != 3) { sendErrorFinished(Failed, QLatin1String("invalid distribution id, please fill a bug against you distribution backend")); return; } const QString distro = parts.at(0); const QString version = parts.at(1); const QString arch = parts.at(2); QStringList rxActions; Transaction::Roles roles = Daemon::global()->roles(); if (roles & Transaction::RoleResolve) { rxActions << QLatin1String("InstallPackages"); } if (roles & Transaction::RoleWhatProvides) { rxActions << QLatin1String("InstallProvides"); } if (roles & Transaction::RoleSearchFile) { rxActions << QLatin1String("InstallFiles"); } if (rxActions.isEmpty()) { if (showWarning()) { // TODO display a nicer message informing of already installed ones setInfo(i18n("Not supported"), i18n("Your backend does not support any of the needed " "methods to install a catalog")); } sendErrorFinished(Failed, QLatin1String("not supported by backend")); return; } // matches at the beginning of line installPackages or InstallProvides or installFiles and capture it // matches an optional set of parenthesis // matches *%1* and or *%2* and or *%3* // matches after '=' but ';' at the end QString pattern; pattern = QString( QLatin1String("^(%1)(?:\\((?:.*%2[^;]*(?:;(?:.*%3[^;]*(?:;(?:.*%4[^;]*)?)?)?)?)?\\))?=(.*[^;$])")) .arg(rxActions.join(QLatin1Char('|')), distro, version, arch); QRegExp rx(pattern, Qt::CaseInsensitive); QStringList filesFailedToOpen; const QStringList files = m_model->files(); if (!files.isEmpty()) { for (const QString &file : files) { QFile catalog(file); if (catalog.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&catalog); while (!in.atEnd()) { if (rx.indexIn(in.readLine()) != -1) { if (rx.cap(1).compare(QLatin1String("InstallPackages"), Qt::CaseInsensitive) == 0) { m_installPackages.append(rx.cap(2).split(QLatin1Char(';'))); } else if (rx.cap(1).compare(QLatin1String("InstallProvides"), Qt::CaseInsensitive) == 0) { m_installProvides.append(rx.cap(2).split(QLatin1Char(';'))); } else if (rx.cap(1).compare(QLatin1String("InstallFiles"), Qt::CaseInsensitive) == 0) { m_installFiles.append(rx.cap(2).split(QLatin1Char(';'))); } } } } else { filesFailedToOpen << file; } } } else { setInfo(i18n("Catalog not found"), i18n("Could not find a catalog to install")); return; } if (showWarning() && filesFailedToOpen.size()) { // TODO display a nicer message informing of already installed ones KMessageBox::sorry(this, i18np("Catalog %2 failed to open", "Catalogs %2 failed to open", filesFailedToOpen.size(), filesFailedToOpen.join(QLatin1Char(','))), i18n("Failed to open")); } if (m_installPackages.isEmpty() && m_installProvides.isEmpty() && m_installFiles.isEmpty()) { setInfo(i18n("Catalog is Empty"), i18n("Could not find any package to install in this catalog")); } else { // Start resolving searchFinished(PkTransaction::Success); } } void PkInstallCatalogs::searchFinished(PkTransaction::ExitStatus status) { if (status == PkTransaction::Success) { if (!m_installPackages.isEmpty()) { // Continue resolving Install Packages QStringList resolve; int count = 0; while (!m_installPackages.isEmpty() && count < m_maxResolve) { // Remove the items from the list so next call we have less resolve.append(m_installPackages.takeFirst()); ++count; } qCDebug(APPER_SESSION) << "m_installPackages" << m_maxResolve << m_installPackages.size() << resolve.size(); auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::resolve(resolve, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleResolve, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage); } else if (!m_installProvides.isEmpty()) { // Continue resolving Install Provides QStringList provides; int count = 0; while (!m_installProvides.isEmpty() && count < m_maxResolve) { // Remove the items from the list so next call we have less provides.append(m_installProvides.takeFirst()); ++count; } qCDebug(APPER_SESSION) << "m_installProvides" << m_maxResolve << m_installProvides.size() << provides.size(); auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(provides, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage); } else if (!m_installFiles.isEmpty()) { // Continue resolving Install Packages QStringList files; int count = 0; while (!m_installFiles.isEmpty() && count < m_maxResolve) { // Remove the items from the list so next call we have less files.append(m_installFiles.takeFirst()); ++count; } qCDebug(APPER_SESSION) << "m_installFiles" << m_maxResolve << m_installFiles.size() << files.size(); auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::searchFiles(files, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleSearchFile, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage); } else { // we are done resolving SessionTask::searchFinished(status); } } else { // we got an error... SessionTask::searchFinished(status); } } -#include "PkInstallCatalogs.moc" +#include "moc_PkInstallCatalogs.cpp" diff --git a/PkSession/PkInstallFontconfigResources.cpp b/PkSession/PkInstallFontconfigResources.cpp index 422153c..cbd9262 100644 --- a/PkSession/PkInstallFontconfigResources.cpp +++ b/PkSession/PkInstallFontconfigResources.cpp @@ -1,164 +1,164 @@ /*************************************************************************** * 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 "PkInstallFontconfigResources.h" #include "IntroDialog.h" #include #include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) PkInstallFontconfigResources::PkInstallFontconfigResources(uint xid, const QStringList &resources, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent) { setWindowTitle(i18n("Installs new Fonts")); auto introDialog = new IntroDialog(this); auto model = new QStandardItemModel(this); introDialog->setModel(model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallFontconfigResources::enableButtonOk); setMainWidget(introDialog); // This will only validate fields QStringList errors; QStringList iso639; for (const QString &font : resources) { // TODO never return in here // TODO add name field from /usr/share/xml/iso-codes/iso_639.xml into model if (!font.startsWith(QLatin1String(":lang="))) { errors << QString(QLatin1String("not recognised prefix: '%1'")).arg(font); qCWarning(APPER_SESSION) << QString(QLatin1String("not recognised prefix: '%1'")).arg(font); continue; } int size = font.size(); if (size < 7 || size > 20) { errors << QString(QLatin1String("lang tag malformed: '%1'")).arg(font); qCWarning(APPER_SESSION) << QString(QLatin1String("lang tag malformed: '%1'")).arg(font); continue; } m_resources << font; iso639 << font.mid(6); } if (m_resources.isEmpty()) { setError(i18n("Could interpret request"), i18n("Please verify if the request was valid")); sendErrorFinished(InternalError, errors.join(QLatin1Char('\n'))); return; } enableButtonOk(true); // Search for the iso 639 names to present it nicely to the user QStringList niceNames; QFile file(QLatin1String("/usr/share/xml/iso-codes/iso_639.xml")); file.open(QFile::ReadOnly); QXmlQuery query; query.bindVariable(QLatin1String("path"), &file); for (const QString &font : iso639) { QString queryTxt; queryTxt = QString(QLatin1String("declare variable $path external;" "doc($path)/iso_639_entries/" "iso_639_entry[@iso_639_2B_code=\"%1\" or " "@iso_639_2T_code=\"%1\" or " "@iso_639_1_code=\"%1\"]/string(@name)")).arg(font); query.setQuery(queryTxt); QStringList result; query.evaluateTo(&result); niceNames.append(result); } // kDebug() << "result" << niceNames << iso639; for (const QString &name : niceNames) { auto item = new QStandardItem(name); item->setIcon(QIcon::fromTheme(QLatin1String("fonts-package")).pixmap(32, 32)); item->setFlags(Qt::ItemIsEnabled); model->appendRow(item); } QString description; description = i18np("An additional font is required to view this document correctly.\n" "Do you want to search for a suitable package now?", "Additional fonts are required to view this document correctly.\n" "Do you want to search for suitable packages now?", m_resources.size()); introDialog->setDescription(description); QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("A program wants to install a font", "A program wants to install fonts", m_resources.size()); } else { title = i18np("The application %2 wants to install a font", "The application %2 wants to install fonts", m_resources.size(), parentTitle); } setTitle(title); } PkInstallFontconfigResources::~PkInstallFontconfigResources() { } void PkInstallFontconfigResources::search() { auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(m_resources, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallFontconfigResources::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallFontconfigResources::addPackage); } void PkInstallFontconfigResources::notFound() { QString msg = i18n("Failed to find font"); if (showWarning()) { setInfo(msg, i18n("No new fonts could be found for this document")); } sendErrorFinished(NoPackagesFound, msg); } void PkInstallFontconfigResources::searchFailed() { QString msg = i18n("Failed to find font"); if (showWarning()) { setError(msg, i18n("Failed to search for provides")); } sendErrorFinished(Failed, QLatin1String("failed to search for provides")); } -#include "PkInstallFontconfigResources.moc" +#include "moc_PkInstallFontconfigResources.cpp" diff --git a/PkSession/PkInstallGStreamerResources.cpp b/PkSession/PkInstallGStreamerResources.cpp index ac1da44..368bf2b 100644 --- a/PkSession/PkInstallGStreamerResources.cpp +++ b/PkSession/PkInstallGStreamerResources.cpp @@ -1,147 +1,147 @@ /*************************************************************************** * 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 "PkInstallGStreamerResources.h" #include "IntroDialog.h" #include #include #include #include #include PkInstallGStreamerResources::PkInstallGStreamerResources(uint xid, const QStringList &resources, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent) { setWindowTitle(i18n("Install GStreamer Resources")); auto introDialog = new IntroDialog(this); auto model = new QStandardItemModel(this); introDialog->setModel(model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallGStreamerResources::enableButtonOk); setMainWidget(introDialog); bool encoder = false; bool decoder = false; // Resources are strings like "ID3 tag|gstreamer0.10(decoder-application/x-id3)()(64bit)" for (const QString &codec : resources) { if (codec.contains(QLatin1String("|gstreamer0.10(decoder"))) { decoder = true; } else if (codec.contains(QLatin1String("|gstreamer0.10(encoder"))) { encoder = true; } auto item = new QStandardItem(codec.section(QLatin1Char('|'), 0, 0)); item->setIcon(QIcon::fromTheme(QLatin1String("x-kde-nsplugin-generated")).pixmap(32, 32)); item->setFlags(Qt::ItemIsEnabled); model->appendRow(item); m_resources << codec.section(QLatin1Char('|'), 1, -1); } QString description; description = i18np("The following plugin is required. " "Do you want to search for this now?", "The following plugins are required. " "Do you want to search for these now?", m_resources.size()); enableButtonOk(true); QString title; // this will come from DBus interface if (parentTitle.isNull()) { if (decoder && !encoder) { // TRANSLATORS: a random program which we can't get the name wants to decode something title = i18np("A program requires an additional plugin to decode this file", "A program requires additional plugins to decode this file", m_resources.size()); } else if (!decoder && encoder) { // TRANSLATORS: a random program which we can't get the name wants to encode something title = i18np("A program requires an additional plugin to encode this file", "A program requires additional plugins to encode this file", m_resources.size()); } else { // TRANSLATORS: a random program which we can't get the name wants to do something (unknown) title = i18np("A program requires an additional plugin for this operation", "A program requires additional plugins for this operation", m_resources.size()); } } else { if (decoder && !encoder) { // TRANSLATORS: a program wants to decode something (unknown) -- string is a program name, e.g. "Movie Player" title = i18np("%2 requires an additional plugin to decode this file", "%2 requires additional plugins to decode this file", m_resources.size(), parentTitle); } else if (!decoder && encoder) { // TRANSLATORS: a program wants to encode something (unknown) -- string is a program name, e.g. "Movie Player" title = i18np("%2 requires an additional plugin to encode this file", "%2 requires additional plugins to encode this file", m_resources.size(), parentTitle); } else { // TRANSLATORS: a program wants to do something (unknown) -- string is a program name, e.g. "Movie Player" title = i18np("%2 requires an additional plugin for this operation", "%2 requires additional plugins for this operation", m_resources.size(), parentTitle); } } introDialog->setDescription(description); setTitle(title); } PkInstallGStreamerResources::~PkInstallGStreamerResources() { } void PkInstallGStreamerResources::search() { auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(m_resources, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallGStreamerResources::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallGStreamerResources::addPackage); } void PkInstallGStreamerResources::notFound() { if (showWarning()) { QString mgs = i18n("No results found"); setInfo(mgs, i18n("Could not find plugin " "in any configured software source")); } sendErrorFinished(NoPackagesFound, QLatin1String("failed to find codec")); } -#include "PkInstallGStreamerResources.moc" +#include "moc_PkInstallGStreamerResources.cpp" diff --git a/PkSession/PkInstallMimeTypes.cpp b/PkSession/PkInstallMimeTypes.cpp index 26764ec..782d7a1 100644 --- a/PkSession/PkInstallMimeTypes.cpp +++ b/PkSession/PkInstallMimeTypes.cpp @@ -1,106 +1,106 @@ /*************************************************************************** * 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 "PkInstallMimeTypes.h" #include "IntroDialog.h" #include "FilesModel.h" #include #include #include #include PkInstallMimeTypes::PkInstallMimeTypes(uint xid, const QStringList &mime_types, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent), m_mimeTypes(mime_types) { setWindowTitle(i18n("Install Support for File Types")); auto introDialog = new IntroDialog(this); m_model = new FilesModel(QStringList(), mime_types, this); introDialog->setModel(m_model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallMimeTypes::enableButtonOk); setMainWidget(introDialog); QString description; if (m_model->rowCount()) { description = i18np("Do you want to search for a program that can open this file type?", "Do you want to search for a program that can open these file types?", m_model->rowCount()); enableButtonOk(true); } else { description = i18n("No valid file types were provided"); } introDialog->setDescription(description); QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("A program is requiring support to open this kind of files", "A program is requiring support to open these kinds of files", m_model->rowCount()); } else { title = i18np("The application %2 is requiring support to open this kind of files", "The application %2 is requiring support to open these kinds of files", m_model->rowCount(), parentTitle); } setTitle(title); } PkInstallMimeTypes::~PkInstallMimeTypes() { } void PkInstallMimeTypes::search() { QStringList mimeTypes = m_model->files(); auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(mimeTypes, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallMimeTypes::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallMimeTypes::addPackage); } void PkInstallMimeTypes::notFound() { QString msg = i18n("Could not find software"); if (showWarning()) { setInfo(msg, i18n("No new applications can be found " "to handle this type of file")); } sendErrorFinished(NoPackagesFound, QLatin1String("nothing was found to handle mime type")); } //setTitle(i18np("Application that can open this type of file", // "Applications that can open this type of file", // m_foundPackages.size())); -#include "PkInstallMimeTypes.moc" +#include "moc_PkInstallMimeTypes.cpp" diff --git a/PkSession/PkInstallPackageFiles.cpp b/PkSession/PkInstallPackageFiles.cpp index ab28eb7..c592290 100644 --- a/PkSession/PkInstallPackageFiles.cpp +++ b/PkSession/PkInstallPackageFiles.cpp @@ -1,126 +1,126 @@ /*************************************************************************** * Copyright (C) 2008-2018 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 "PkInstallPackageFiles.h" #include "IntroDialog.h" #include "FilesModel.h" #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) PkInstallPackageFiles::PkInstallPackageFiles(uint xid, const QStringList &files, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent) { setWindowTitle(i18n("Install Packages Files")); if (Daemon::global()->roles() & Transaction::RoleInstallFiles) { m_introDialog = new IntroDialog(this); m_introDialog->acceptDrops(i18n("You can drop more files in here")); m_model = new FilesModel(files, Daemon::global()->mimeTypes(), this); m_introDialog->setModel(m_model); connect(m_model, &FilesModel::rowsInserted, this, &PkInstallPackageFiles::modelChanged); setMainWidget(m_introDialog); modelChanged(); } else { setError(i18n("Not Supported"), i18n("Your current backend does not support installing files")); } } PkInstallPackageFiles::~PkInstallPackageFiles() { } void PkInstallPackageFiles::modelChanged() { const QStringList files = m_model->files(); enableButtonOk(!files.isEmpty()); QString description; if (files.isEmpty()) { description = i18n("No supported files were provided"); } else { description = i18np("Press Continue if you want to install this file", "Press Continue if you want to install these files", files.size()); } m_introDialog->setDescription(description); QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("An application wants to install a package", "An application wants to install packages", files.size()); } else { title = i18np("The application %2 wants to install a package", "The application %2 wants to install packages", files.size(), parentTitle); } setTitle(title); } void PkInstallPackageFiles::commit() { auto transaction = new PkTransaction(this); setTransaction(Transaction::RoleInstallFiles, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallPackageFiles::transactionFinished, Qt::UniqueConnection); transaction->installFiles(m_model->files()); } void PkInstallPackageFiles::transactionFinished(PkTransaction::ExitStatus status) { qCDebug(APPER_SESSION) << "Finished."; switch (status) { case PkTransaction::Success : if (showFinished()) { setFinish(i18n("Installation Complete"), i18np("File was installed successfully", "Files were installed successfully", m_model->files().count())); } finishTaskOk(); break; case PkTransaction::Cancelled : sendErrorFinished(Cancelled, QLatin1String("Aborted")); break; case PkTransaction::Failed : if (showWarning()) { setError(i18n("Failed to install files"), i18n("Could not install files")); } sendErrorFinished(Failed, i18n("Could not install files")); break; } } -#include "PkInstallPackageFiles.moc" +#include "moc_PkInstallPackageFiles.cpp" diff --git a/PkSession/PkInstallPackageNames.cpp b/PkSession/PkInstallPackageNames.cpp index 1af0641..1f34f76 100644 --- a/PkSession/PkInstallPackageNames.cpp +++ b/PkSession/PkInstallPackageNames.cpp @@ -1,133 +1,133 @@ /*************************************************************************** * 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 "PkInstallPackageNames.h" #include #include #include #include #include #include "IntroDialog.h" PkInstallPackageNames::PkInstallPackageNames(uint xid, const QStringList &packages, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent), m_packages(packages), m_message(message) { setWindowTitle(i18n("Install Packages by Name")); auto introDialog = new IntroDialog(this); auto model = new QStandardItemModel(this); introDialog->setModel(model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallPackageNames::enableButtonOk); setMainWidget(introDialog); for (const QString &package : packages) { QStandardItem *item = new QStandardItem(package); item->setIcon(QIcon::fromTheme(QLatin1String("package-x-generic")).pixmap(32, 32)); item->setFlags(Qt::ItemIsEnabled); model->appendRow(item); } if (m_packages.isEmpty()) { introDialog->setDescription(i18n("No package names were provided")); } else { QString description; description = i18np("Do you want to search for and install this package now?", "Do you want to search for and install these packages now?", m_packages.size()); introDialog->setDescription(description); enableButtonOk(true); } QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("An application wants to install a package", "An application wants to install packages", m_packages.size()); } else { title = i18np("The application %2 wants to install a package", "The application %2 wants to install packages", m_packages.size(), parentTitle); } setTitle(title); } PkInstallPackageNames::~PkInstallPackageNames() { } void PkInstallPackageNames::search() { auto transaction = new PkTransaction(this); transaction->setupTransaction(Daemon::resolve(m_packages, Transaction::FilterArch | Transaction::FilterNewest)); setTransaction(Transaction::RoleResolve, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallPackageNames::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallPackageNames::addPackage); } void PkInstallPackageNames::notFound() { if (m_alreadyInstalled.size()) { if (showWarning()) { setInfo(i18n("Failed to install packages"), i18np("The package %2 is already installed", "The packages %2 are already installed", m_alreadyInstalled.size(), m_alreadyInstalled.join(QLatin1Char(',')))); } sendErrorFinished(Failed, QLatin1String("package already found")); } else { if (showWarning()) { setInfo(i18n("Could not find %1", m_packages.join(QLatin1String(", "))), i18np("The package could not be found in any software source", "The packages could not be found in any software source", m_packages.size())); } sendErrorFinished(NoPackagesFound, QLatin1String("no package found")); } } void PkInstallPackageNames::searchFailed() { sendErrorFinished(Failed, QLatin1String("failed to resolve package name")); } void PkInstallPackageNames::addPackage(Transaction::Info info, const QString &packageID, const QString &summary) { if (info != Transaction::InfoInstalled) { SessionTask::addPackage(info, packageID, summary); } else { m_alreadyInstalled << Transaction::packageName(packageID); } } -#include "PkInstallPackageNames.moc" +#include "moc_PkInstallPackageNames.cpp" diff --git a/PkSession/PkInstallPlasmaResources.cpp b/PkSession/PkInstallPlasmaResources.cpp index d0e6883..ea65e9a 100644 --- a/PkSession/PkInstallPlasmaResources.cpp +++ b/PkSession/PkInstallPlasmaResources.cpp @@ -1,112 +1,112 @@ /*************************************************************************** * Copyright (C) 2009-2011 by Daniel Nicoletti * * dantti12@gmail.com * * Copyright (C) 2011 Kevin Kofler * * * * 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 "PkInstallPlasmaResources.h" #include "IntroDialog.h" #include #include #include #include #include PkInstallPlasmaResources::PkInstallPlasmaResources(uint xid, const QStringList &resources, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent) { setWindowTitle(i18n("Install Plasma Resources")); auto introDialog = new IntroDialog(this); auto model = new QStandardItemModel(this); introDialog->setModel(model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallPlasmaResources::enableButtonOk); setMainWidget(introDialog); // Resources are strings like "dataengine-weather" for (const QString &service : resources) { QString prettyService = service; if (service.startsWith(QLatin1String("dataengine-"))) { prettyService = i18n("%1 data engine", service.mid(11)); } else if (service.startsWith(QLatin1String("scriptengine-"))) { prettyService = i18n("%1 script engine", service.mid(13)); } auto item = new QStandardItem(prettyService); item->setIcon(QIcon::fromTheme(QLatin1String("application-x-plasma")).pixmap(32, 32)); item->setFlags(Qt::ItemIsEnabled); model->appendRow(item); m_resources << service; } if (m_resources.isEmpty()) { introDialog->setDescription(i18n("No supported resources were provided")); } else { QString description = i18np("The following service is required. " "Do you want to search for this now?", "The following services are required. " "Do you want to search for these now?", m_resources.size()); introDialog->setDescription(description); enableButtonOk(true); } QString title = i18np("Plasma requires an additional service for this operation", "Plasma requires additional services for this operation", m_resources.size()); setTitle(title); } PkInstallPlasmaResources::~PkInstallPlasmaResources() { } void PkInstallPlasmaResources::search() { auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(m_resources, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallPlasmaResources::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallPlasmaResources::addPackage); } void PkInstallPlasmaResources::notFound() { QString msg = i18n("Failed to search for Plasma service"); if (showWarning()) { setInfo(msg, i18n("Could not find service " "in any configured software source")); } sendErrorFinished(NoPackagesFound, msg); } -#include "PkInstallPlasmaResources.moc" +#include "moc_PkInstallPlasmaResources.cpp" diff --git a/PkSession/PkInstallPrinterDrivers.cpp b/PkSession/PkInstallPrinterDrivers.cpp index 02e16a7..7fce234 100644 --- a/PkSession/PkInstallPrinterDrivers.cpp +++ b/PkSession/PkInstallPrinterDrivers.cpp @@ -1,89 +1,89 @@ /************************************************************************** * 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 "PkInstallPrinterDrivers.h" #include #include #include #include #include PkInstallPrinterDrivers::PkInstallPrinterDrivers(uint xid, const QStringList &resources, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent), m_resources(resources) { setWindowTitle(i18n("Install Printer Drivers")); // TODO confirm operation QStringList search; for (const QString &deviceid : resources) { QString mfg, mdl; const QStringList fields = deviceid.split(QLatin1Char(';')); for (const QString &field : fields) { const QString keyvalue = field.trimmed(); if (keyvalue.startsWith(QLatin1String("MFG:"))) { mfg = keyvalue.mid(4); } else if (keyvalue.startsWith(QLatin1String("MDL:"))) { mdl = keyvalue.mid(4); } } if (!mfg.isEmpty() && !mdl.isEmpty()) { QString prov; QTextStream out(&prov); out << mfg.toLower().replace(QLatin1Char(' '), QLatin1Char('_')) << QLatin1Char(';') << mdl.toLower().replace(QLatin1Char(' '), QLatin1Char('_')) << QLatin1Char(';'); search << prov; } } auto transaction = new PkTransaction(this); Transaction *t; t = Daemon::whatProvides(search, Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest); transaction->setupTransaction(t); setTransaction(Transaction::RoleWhatProvides, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallPrinterDrivers::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallPrinterDrivers::addPackage); } PkInstallPrinterDrivers::~PkInstallPrinterDrivers() { } void PkInstallPrinterDrivers::notFound() { if (showWarning()) { setInfo(i18n("Failed to search for printer driver"), i18n("Could not find printer driver " "in any configured software source")); } sendErrorFinished(NoPackagesFound, QLatin1String("failed to find printer driver")); } -#include "PkInstallPrinterDrivers.moc" +#include "moc_PkInstallPrinterDrivers.cpp" diff --git a/PkSession/PkInstallProvideFiles.cpp b/PkSession/PkInstallProvideFiles.cpp index e02c762..25501d4 100644 --- a/PkSession/PkInstallProvideFiles.cpp +++ b/PkSession/PkInstallProvideFiles.cpp @@ -1,118 +1,118 @@ /*************************************************************************** * 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 "PkInstallProvideFiles.h" #include "IntroDialog.h" #include "FilesModel.h" #include #include #include #include PkInstallProvideFiles::PkInstallProvideFiles(uint xid, const QStringList &files, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent), m_args(files) { setWindowTitle(i18n("Install Packages that Provides Files")); auto introDialog = new IntroDialog(this); auto model = new FilesModel(files, QStringList(), this); introDialog->setModel(model); connect(introDialog, &IntroDialog::continueChanged, this, &PkInstallProvideFiles::enableButtonOk); setMainWidget(introDialog); if (m_args.isEmpty()) { introDialog->setDescription(i18n("No files were provided")); } else { QString description; description = i18np("Do you want to search for this now?", "Do you want to search for these now?", m_args.size()); introDialog->setDescription(description); enableButtonOk(true); } QString title; // this will come from DBus interface if (parentTitle.isNull()) { title = i18np("A program wants to install a file", "A program wants to install files", m_args.size()); } else { title = i18np("The application %2 is asking to install a file", "The application %2 is asking to install files", m_args.size(), parentTitle); } setTitle(title); } PkInstallProvideFiles::~PkInstallProvideFiles() { } void PkInstallProvideFiles::search() { auto transaction = new PkTransaction(this); transaction->setupTransaction(Daemon::searchFiles(m_args, Transaction::FilterArch | Transaction::FilterNewest)); setTransaction(Transaction::RoleSearchFile, transaction); connect(transaction, &PkTransaction::finished, this, &PkInstallProvideFiles::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkInstallProvideFiles::addPackage); } void PkInstallProvideFiles::notFound() { if (m_alreadyInstalled.size()) { if (showWarning()) { setInfo(i18n("Failed to install file"), i18n("The %1 package already provides this file", m_alreadyInstalled)); } sendErrorFinished(Failed, QLatin1String("already provided")); } else { if (showWarning()) { setInfo(i18n("Failed to find package"), i18np("The file could not be found in any packages", "The files could not be found in any packages", m_args.size())); } sendErrorFinished(NoPackagesFound, QLatin1String("no files found")); } } void PkInstallProvideFiles::addPackage(Transaction::Info info, const QString &packageID, const QString &summary) { if (info != Transaction::InfoInstalled) { SessionTask::addPackage(info, packageID, summary); } else { m_alreadyInstalled = Transaction::packageName(packageID); } } -#include "PkInstallProvideFiles.moc" +#include "moc_PkInstallProvideFiles.cpp" diff --git a/PkSession/PkInterface.cpp b/PkSession/PkInterface.cpp index 57de96b..d0e641d 100644 --- a/PkSession/PkInterface.cpp +++ b/PkSession/PkInterface.cpp @@ -1,193 +1,195 @@ /*************************************************************************** * 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 "PkInterface.h" #include "packagekitadaptor.h" #include //#include #include "SessionTask.h" #include "PkInstallPackageNames.h" #include "PkInstallMimeTypes.h" #include "PkInstallGStreamerResources.h" #include "PkInstallFontconfigResources.h" #include "PkInstallPlasmaResources.h" #include "PkInstallPackageFiles.h" #include "PkInstallProvideFiles.h" #include "PkInstallCatalogs.h" #include "PkRemovePackageByFiles.h" #include "PkInstallPrinterDrivers.h" #include "PkIsInstalled.h" #include "PkSearchFile.h" #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) using namespace PackageKit; PkInterface::PkInterface(QObject *parent) : AbstractIsRunning(parent) { if (!Daemon::isRunning()) { QTimer timer; timer.setInterval(5000); QEventLoop loop; connect(Daemon::global(), &Daemon::isRunningChanged, &loop, &QEventLoop::quit); connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); if (!Daemon::isRunning()) { qCWarning(APPER_SESSION) << "Packagekit didn't start"; qApp->quit(); return; } } qCDebug(APPER_SESSION) << "Creating Helper"; (void) new ModifyAdaptor(this); (void) new QueryAdaptor(this); if (!QDBusConnection::sessionBus().registerService(QLatin1String("org.freedesktop.PackageKit"))) { qCDebug(APPER_SESSION) << "unable to register service to dbus"; return; } if (!QDBusConnection::sessionBus().registerObject(QLatin1String("/org/freedesktop/PackageKit"), this)) { qCDebug(APPER_SESSION) << "unable to register object to dbus"; return; } } PkInterface::~PkInterface() { } void PkInterface::InstallCatalogs(uint xid, const QStringList &files, const QString &interaction) { qCDebug(APPER_SESSION) << xid << files << interaction; show(new PkInstallCatalogs(xid, files, interaction, message())); } void PkInterface::InstallFontconfigResources(uint xid, const QStringList &resources, const QString &interaction) { qCDebug(APPER_SESSION) << xid << resources << interaction; show(new PkInstallFontconfigResources(xid, resources, interaction, message())); } void PkInterface::InstallGStreamerResources(uint xid, const QStringList &resources, const QString &interaction) { qCDebug(APPER_SESSION) << xid << resources << interaction; show(new PkInstallGStreamerResources(xid, resources, interaction, message())); } void PkInterface::InstallMimeTypes(uint xid, const QStringList &mime_types, const QString &interaction) { qCDebug(APPER_SESSION) << xid << mime_types << interaction; show(new PkInstallMimeTypes(xid, mime_types, interaction, message())); } void PkInterface::InstallPackageFiles(uint xid, const QStringList &files, const QString &interaction) { qCDebug(APPER_SESSION) << xid << files << interaction; show(new PkInstallPackageFiles(xid, files, interaction, message())); } void PkInterface::InstallPackageNames(uint xid, const QStringList &packages, const QString &interaction) { qCDebug(APPER_SESSION) << xid << packages << interaction; show(new PkInstallPackageNames(xid, packages, interaction, message())); } void PkInterface::InstallProvideFiles(uint xid, const QStringList &files, const QString &interaction) { qCDebug(APPER_SESSION) << xid << files << interaction; show(new PkInstallProvideFiles(xid, files, interaction, message())); } void PkInterface::RemovePackageByFiles(uint xid, const QStringList &files, const QString &interaction) { qCDebug(APPER_SESSION) << xid << files << interaction; show(new PkRemovePackageByFiles(xid, files, interaction, message())); } void PkInterface::InstallPrinterDrivers(uint xid, const QStringList &resources, const QString &interaction) { qCDebug(APPER_SESSION) << xid << resources << interaction; show(new PkInstallPrinterDrivers(xid, resources, interaction, message())); } void PkInterface::InstallPlasmaResources(uint xid, const QStringList &resources, const QString &interaction) { qCDebug(APPER_SESSION) << xid << resources << interaction; show(new PkInstallPlasmaResources(xid, resources, interaction, message())); } void PkInterface::InstallResources(uint xid, const QString &type, const QStringList &resources, const QString &interaction) { if (type == QLatin1String("codec")) { InstallGStreamerResources(xid, resources, interaction); } else if (type == QLatin1String("mimetype")) { InstallMimeTypes(xid, resources, interaction); } else if (type == QLatin1String("font")) { InstallFontconfigResources(xid, resources, interaction); } else if (type == QLatin1String("postscript-driver")) { InstallPrinterDrivers(xid, resources, interaction); } else if (type == QLatin1String("plasma-service")) { InstallPlasmaResources(xid, resources, interaction); } else { sendErrorReply(QStringLiteral("org.freedesktop.PackageKit.Failed"), QStringLiteral("Unsupported resource type")); } } //Query bool PkInterface::IsInstalled(const QString &package_name, const QString &interaction) { show(new PkIsInstalled(package_name, interaction, message())); // This is discarted return false; } bool PkInterface::SearchFile(const QString &file_name, const QString &interaction, QString &package_name) { Q_UNUSED(package_name) show(new PkSearchFile(file_name, interaction, message())); // This is discarted return false; } void PkInterface::show(SessionTask *widget) { increaseRunning(); setDelayedReply(true); connect(widget, &SessionTask::finished, this, &PkInterface::decreaseRunning); if (widget->parentWId()) { // Check before showing if the widget has // a parent, otherwise it should not be modal // to not lock the application widget->setWindowModality(Qt::WindowModal); } widget->show(); // KWindowSystem::forceActiveWindow(widget->winId()); // KWindowSystem::setMainWindow(widget, widget->parentWId()); } + +#include "moc_PkInterface.cpp" diff --git a/PkSession/PkIsInstalled.cpp b/PkSession/PkIsInstalled.cpp index 11c698b..1505634 100644 --- a/PkSession/PkIsInstalled.cpp +++ b/PkSession/PkIsInstalled.cpp @@ -1,67 +1,67 @@ /*************************************************************************** * 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 "PkIsInstalled.h" #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) PkIsInstalled::PkIsInstalled(const QString &package_name, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(0, interaction, message, parent), m_packageName(package_name), m_message(message) { setWindowTitle(i18n("Querying if a Package is Installed")); auto transaction = new PkTransaction(this); transaction->setupTransaction(Daemon::resolve(m_packageName, Transaction::FilterInstalled)); setTransaction(Transaction::RoleResolve, transaction); connect(transaction, &PkTransaction::finished, this, &PkIsInstalled::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkIsInstalled::addPackage); } PkIsInstalled::~PkIsInstalled() { } void PkIsInstalled::searchFinished(PkTransaction::ExitStatus status) { qCDebug(APPER_SESSION); if (status == PkTransaction::Success) { QDBusMessage reply = m_message.createReply(); reply << (bool) foundPackagesSize(); sendMessageFinished(reply); } else if (status == PkTransaction::Cancelled) { sendErrorFinished(Cancelled, i18n("User canceled the transaction")); } else { sendErrorFinished(InternalError, i18n("An unknown error happened")); } } -#include "PkIsInstalled.moc" +#include "moc_PkIsInstalled.cpp" diff --git a/PkSession/PkRemovePackageByFiles.cpp b/PkSession/PkRemovePackageByFiles.cpp index 6280a48..1d4a295 100644 --- a/PkSession/PkRemovePackageByFiles.cpp +++ b/PkSession/PkRemovePackageByFiles.cpp @@ -1,148 +1,148 @@ /*************************************************************************** * 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 "PkRemovePackageByFiles.h" #include "IntroDialog.h" #include "FilesModel.h" #include #include #include #include #include PkRemovePackageByFiles::PkRemovePackageByFiles(uint xid, const QStringList &files, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(xid, interaction, message, parent) { setWindowTitle(i18n("Remove Packages that Provides Files")); m_introDialog = new IntroDialog(this); m_introDialog->acceptDrops(i18n("You can drop more files in here")); m_model = new FilesModel(files, QStringList(), this); connect(m_model, &FilesModel::rowsInserted, this, &PkRemovePackageByFiles::modelChanged); m_introDialog->setModel(m_model); setMainWidget(m_introDialog); modelChanged(); } PkRemovePackageByFiles::~PkRemovePackageByFiles() { } void PkRemovePackageByFiles::modelChanged() { QStringList files = m_model->files(); enableButtonOk(!files.isEmpty()); QString description; if (files.isEmpty()) { description = i18n("No supported files were provided"); } else { if (m_model->onlyApplications()) { description = i18np("Do you want to remove the following application?", "Do you want to remove the following applications?", files.size()); } else { description = i18np("Do you want to search for a package providing this file?", "Do you want to search for a package providing these files?", files.size()); } } m_introDialog->setDescription(description); QString title; // this will come from DBus interface if (!files.isEmpty() && parentTitle.isNull()) { if (m_model->onlyApplications()) { title = i18np("An application is asking to remove an application", "An application is asking to remove applications", files.size()); } else { title = i18np("An application is asking to remove a file", "An application is asking to remove files", files.size()); } } else if (!files.isEmpty()) { if (m_model->onlyApplications()) { title = i18np("The application %2 is asking to remove an application", "The application %2 is asking to remove applications", files.size(), parentTitle); } else { title = i18np("The application %2 is asking to remove a file", "The application %2 is asking to remove files", files.size(), parentTitle); } } else { title = i18n("No application was found"); } setTitle(title); } void PkRemovePackageByFiles::search() { m_files = m_model->files(); searchFinished(PkTransaction::Success); } void PkRemovePackageByFiles::searchFinished(PkTransaction::ExitStatus status) { if (status == PkTransaction::Success) { if (!m_files.isEmpty()) { QString file = m_files.takeFirst(); auto transaction = new PkTransaction(this); transaction->setupTransaction(Daemon::searchFiles(file, Transaction::FilterInstalled)); setTransaction(Transaction::RoleSearchFile, transaction); connect(transaction, &PkTransaction::finished, this, &PkRemovePackageByFiles::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkRemovePackageByFiles::addPackage); } else { // we are done resolving SessionTask::searchFinished(status); } } else { // we got an error... SessionTask::searchFinished(status); } } void PkRemovePackageByFiles::notFound() { if (showWarning()) { QStringList files = m_model->files(); setInfo(i18n("Could not find %1", files.join(QLatin1String(", "))), i18np("The file could not be found in any installed package", "The files could not be found in any installed package", files.size())); } sendErrorFinished(NoPackagesFound, QLatin1String("no package found")); } -#include "PkRemovePackageByFiles.moc" +#include "moc_PkRemovePackageByFiles.cpp" diff --git a/PkSession/PkSearchFile.cpp b/PkSession/PkSearchFile.cpp index 8922675..02dc894 100644 --- a/PkSession/PkSearchFile.cpp +++ b/PkSession/PkSearchFile.cpp @@ -1,86 +1,86 @@ /*************************************************************************** * 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 "PkSearchFile.h" #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) PkSearchFile::PkSearchFile(const QString &file_name, const QString &interaction, const QDBusMessage &message, QWidget *parent) : SessionTask(0, interaction, message, parent), m_fileName(file_name), m_message(message) { setWindowTitle(i18n("Search Packages that Provides Files")); // Check for a leading slash '/' return with an error if it's not there.. if (!m_fileName.startsWith(QLatin1Char('/'))) { sendErrorFinished(Failed, QLatin1String("Only full file name path is supported")); return; } auto transaction = new PkTransaction(this); transaction->setupTransaction(Daemon::searchFiles(m_fileName, Transaction::FilterNewest)); setTransaction(Transaction::RoleSearchFile, transaction); connect(transaction, &PkTransaction::finished, this, &PkSearchFile::searchFinished, Qt::UniqueConnection); connect(transaction, &PkTransaction::package, this, &PkSearchFile::addPackage); } PkSearchFile::~PkSearchFile() { } void PkSearchFile::searchSuccess() { QModelIndex index = model()->index(0, 0); bool installed = false; QString packageID; if (index.isValid()) { Transaction::Info info; info = index.data(PackageModel::InfoRole).value(); installed = info == Transaction::InfoInstalled; packageID = index.data(PackageModel::IdRole).toString(); } QDBusMessage reply = m_message.createReply(); reply << installed; reply << Transaction::packageName(packageID); qCDebug(APPER_SESSION) << reply; sendMessageFinished(reply); } void PkSearchFile::notFound() { QString msg(i18n("The file name could not be found in any software source")); setError(i18n("Could not find %1", m_fileName), msg); sendErrorFinished(NoPackagesFound, msg); } -#include "PkSearchFile.moc" +#include "moc_PkSearchFile.cpp" diff --git a/PkSession/PkSession.cpp b/PkSession/PkSession.cpp index 742c80f..9c701bb 100644 --- a/PkSession/PkSession.cpp +++ b/PkSession/PkSession.cpp @@ -1,94 +1,96 @@ /*************************************************************************** * 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 "PkSession.h" #include "PkInterface.h" #include #include #include #include #define MINUTE 60000 Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) using namespace PackageKit; PkSession::PkSession(QObject* parent) : QObject(parent) , m_pkInterface(new PkInterface(this)) { connect(m_pkInterface, &PkInterface::close, this, &PkSession::prepareToClose); Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name() + QLatin1String(".UTF-8")); // this enables not quitting when closing a transaction ui qApp->setQuitOnLastWindowClosed(false); // create the close timer and connect it's signal m_closeT = new QTimer(this); connect(m_closeT, &QTimer::timeout, this, &PkSession::close); prepareToClose(); } void PkSession::prepareToClose() { if (isRunning()) { qCDebug(APPER_SESSION) << "Stoping Timer"; m_closeT->stop(); } else { qCDebug(APPER_SESSION) << "Starting Timer: " << MINUTE; m_closeT->start(MINUTE); } } bool PkSession::isRunning() { if (m_pkInterface && m_pkInterface->isRunning()) { qCDebug(APPER_SESSION) << m_pkInterface; return true; } return false; } void PkSession::close() { // This will run when the timer times out, we will check // again just to be sure. if (!isRunning()) { qCDebug(APPER_SESSION) << "Closed by Timer"; qApp->quit(); } } int PkSession::newInstance() { return 0; } PkSession::~PkSession() { } + +#include "moc_PkSession.cpp" diff --git a/PkSession/ReviewChanges.cpp b/PkSession/ReviewChanges.cpp index bd70757..646dbaf 100644 --- a/PkSession/ReviewChanges.cpp +++ b/PkSession/ReviewChanges.cpp @@ -1,78 +1,78 @@ /*************************************************************************** * 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 "ReviewChanges.h" #include "ui_ReviewChanges.h" #include #include #include #include #include ReviewChanges::ReviewChanges(PackageModel *model, QWidget *parent) : QWidget(parent), ui(new Ui::ReviewChanges), m_model(model) { ui->setupUi(this); //initialize the model, delegate, client and connect it's signals ui->packageView->viewport()->setAttribute(Qt::WA_Hover); auto changedProxy = new KCategorizedSortFilterProxyModel(this); changedProxy->setSourceModel(m_model); changedProxy->setCategorizedModel(true); changedProxy->sort(0); changedProxy->setDynamicSortFilter(true); changedProxy->setSortCaseSensitivity(Qt::CaseInsensitive); changedProxy->setSortRole(PackageModel::SortRole); ui->packageView->setModel(changedProxy); setWindowTitle(i18np("The following package was found", "The following packages were found", m_model->rowCount())); auto delegate = new ChangesDelegate(ui->packageView); delegate->setExtendPixmapWidth(0); ui->packageView->setItemDelegate(delegate); connect(m_model, &PackageModel::dataChanged, this, &ReviewChanges::selectionChanged); } ReviewChanges::~ReviewChanges() { delete ui; } PackageModel *ReviewChanges::model() const { return m_model; } void ReviewChanges::selectionChanged() { emit hasSelectedPackages(!m_model->selectedPackagesToInstall().isEmpty() || !m_model->selectedPackagesToRemove().isEmpty()); } -#include "ReviewChanges.moc" +#include "moc_ReviewChanges.cpp" diff --git a/PkSession/SessionTask.cpp b/PkSession/SessionTask.cpp index 8c44560..81d5ae3 100644 --- a/PkSession/SessionTask.cpp +++ b/PkSession/SessionTask.cpp @@ -1,668 +1,668 @@ /*************************************************************************** * 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 "SessionTask.h" #include "ui_SessionTask.h" #include "IntroDialog.h" #include "InfoWidget.h" #include "ReviewChanges.h" #include "ApplicationLauncher.h" #include #include #include #include #include #include #include #include #include #include #include //#include #include //#include #include //#include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) using namespace PackageKit; SessionTask::SessionTask(uint xid, const QString &interaction, const QDBusMessage &message, QWidget *parent) : QDialog(parent), m_xid(xid), m_message(message), ui(new Ui::SessionTask) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); m_model = new PackageModel(this); // connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), // this, SLOT(updatePallete())); updatePallete(); setWindowIcon(QIcon::fromTheme(QLatin1String("system-software-install"))); QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok); okButton->setText(i18n("Continue")); okButton->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); enableButtonOk(false); connect(okButton, &QPushButton::clicked, this, &SessionTask::slotContinueClicked); QPushButton *cancelButton = ui->buttonBox->button(QDialogButtonBox::Cancel); connect(cancelButton, &QPushButton::clicked, this, &SessionTask::slotCancelClicked); Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name() + QLatin1String(".UTF-8")); // Defaults to always m_interactions = ConfirmSearch | ConfirmDeps | ConfirmInstall | Progress | Finished | Warning; m_timeout = 0; parseInteraction(interaction); QString cmdline; uint pid; // TODO as we are running on the session it might // be useless to check the PID on the system if ((pid = getPidSession()) != UINT_MAX) { cmdline = getCmdLine(pid); } else if ((pid = getPidSystem()) != UINT_MAX) { cmdline = getCmdLine(pid); } if (!cmdline.isNull()) { setExec(cmdline); } setMinimumSize(QSize(430,280)); // KConfig config("apper"); // KConfigGroup configGroup(&config, "SessionInstaller"); // restoreDialogSize(configGroup); } SessionTask::~SessionTask() { // KConfig config("apper"); // KConfigGroup configGroup(&config, "SessionInstaller"); // saveDialogSize(configGroup); delete ui; } void SessionTask::addPackage(Transaction::Info info, const QString &packageID, const QString &summary) { m_model->addSelectedPackage(info, packageID, summary); } void SessionTask::searchFinished(PkTransaction::ExitStatus status) { if (m_pkTransaction) { // Disconnect so it can be connected to commitFinished latter disconnect(m_pkTransaction->transaction(), &PkTransaction::finished, this, &SessionTask::searchFinished); } if (status == PkTransaction::Success) { m_model->finished(); if (m_model->rowCount() == 0) { notFound(); showCloseButton(); } else { searchSuccess(); } } else if (status == PkTransaction::Cancelled) { cancelClicked(); } else { searchFailed(); showCloseButton(); } } void SessionTask::commitFinished(PkTransaction::ExitStatus status) { if (m_pkTransaction) { // Disconnect so it can be connected to something else latter disconnect(m_pkTransaction->transaction(), &PkTransaction::finished, this, &SessionTask::searchFinished); } if (status == PkTransaction::Success) { if (!m_removePackages.isEmpty()) { removePackages(); } else { commitSuccess(); showCloseButton(); } } else if (status == PkTransaction::Cancelled) { cancelClicked(); } else { commitFailed(); showCloseButton(); } } void SessionTask::updatePallete() { QPalette pal; // pal.setColor(QPalette::Window, KGlobalSettings::activeTitleColor()); // pal.setColor(QPalette::WindowText, KGlobalSettings::activeTextColor()); ui->backgroundFrame->setPalette(pal); } void SessionTask::setDialog(QDialog *dialog) { // Store the current values QWidget *widget = ui->stackedWidget->currentWidget(); if (qobject_cast(dialog)) { // TODO if there is a removal after instalation // this will break it, but we don't have // this case yet... commitSuccess(dialog); } else { // Set the new ones setMainWidget(dialog); // setTitle(dialog->windowTitle()); // must come after connect(this, &SessionTask::continueClicked, dialog, &QDialog::accept); // connect(this, &SessionTask::continueClicked, dia, &QDialog::accept); // connect(this, SIGNAL(okClicked()), // dialog->mainWidget(), SLOT(deleteLater())); // connect(this, SIGNAL(okClicked()), // dialog, SLOT(deleteLater())); // Make sure we see the last widget and title auto mapper = new QSignalMapper(this); mapper->setMapping(this, widget); connect(this, &SessionTask::continueClicked, mapper, QOverload<>::of(&QSignalMapper::map)); connect(mapper, QOverload::of(&QSignalMapper::mapped), this, &SessionTask::setMainWidget); enableButtonOk(true); } } void SessionTask::setMainWidget(QWidget *widget) { if (widget != mainWidget()) { ui->stackedWidget->addWidget(widget); ui->stackedWidget->setCurrentWidget(widget); setTitle(widget->windowTitle()); } } QWidget* SessionTask::mainWidget() { return ui->stackedWidget->currentWidget(); } void SessionTask::setInfo(const QString &title, const QString &text, const QString &details) { auto info = new InfoWidget(this); info->setWindowTitle(title); info->setDescription(text); info->setDetails(details); setMainWidget(info); // setButtons(KDialog::Close); // button(KDialog::Close)->setFocus(); if (qobject_cast(sender())) { // if we have a sender this method was caller by PkTransaction // be carefull because QSignalMapper from KDialog also calls this method sender()->disconnect(); sendErrorFinished(Failed, text); } } void SessionTask::setError(const QString &title, const QString &text, const QString &details) { auto info = new InfoWidget(this); info->setWindowTitle(title); info->setDescription(text); info->setIcon(QIcon::fromTheme(QLatin1String("dialog-error"))); info->setDetails(details); setMainWidget(info); // setButtons(KDialog::Close); // button(KDialog::Close)->setFocus(); if (qobject_cast(sender())) { // if we have a sender this method was caller by PkTransaction // be carefull because QSignalMapper from KDialog also calls this method sender()->disconnect(); sendErrorFinished(Failed, text); } } void SessionTask::setFinish(const QString &title, const QString &text, QWidget *widget) { auto info = new InfoWidget(this); info->setWindowTitle(title); info->setDescription(text); info->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-apply"))); info->addWidget(widget); setMainWidget(info); // setButtons(KDialog::Close); // button(KDialog::Close)->setFocus(); } void SessionTask::setTitle(const QString &title) { ui->titleL->setText(title); } void SessionTask::setExec(const QString &exec) { if (pathIsTrusted(exec)) { // Get from X11 the window title // KWindowInfo info = KWindowSystem::windowInfo(m_xid, NET::WMVisibleName); // parentTitle = info.visibleName(); } else { parentTitle = exec; } } bool SessionTask::pathIsTrusted(const QString &exec) { // special case the plugin helper -- it's trusted return exec == QLatin1String("/usr/libexec/gst-install-plugins-helper") || exec == QLatin1String("/usr/libexec/pk-gstreamer-install") || exec == QLatin1String("/usr/bin/gstreamer-codec-install") || exec == QLatin1String("/usr/lib/packagekit/pk-gstreamer-install") || exec == QLatin1String("/usr/bin/plasma-desktop") || exec == QLatin1String("/usr/bin/apper"); } QString SessionTask::getCmdLine(uint pid) { QFile file(QString(QLatin1String("/proc/%1/cmdline")).arg(pid)); QString line; if (file.open(QFile::ReadOnly)) { char buf[1024]; qint64 lineLength = file.readLine(buf, sizeof(buf)); if (lineLength != -1) { // the line is available in buf line = QString::fromLocal8Bit(buf); if (!line.contains(QLatin1String("(deleted)"))) { return line; } } } return QString(); } uint SessionTask::getPidSystem() { QDBusMessage msg; msg = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.DBus"), QLatin1String("/org/freedesktop/DBus/Bus"), QLatin1String("org.freedesktop.DBus"), QLatin1String("GetConnectionUnixProcessID")); msg << m_message.service(); QDBusMessage reply = QDBusConnection::systemBus().call(msg); if (reply.type() != QDBusMessage::ReplyMessage) { qCWarning(APPER_SESSION) << "Message did not receive a reply"; } if (reply.arguments().size() == 1) { return reply.arguments().at(0).toUInt(); } return UINT_MAX; } uint SessionTask::getPidSession() { QDBusMessage msg; msg = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.DBus"), QLatin1String("/org/freedesktop/DBus/Bus"), QLatin1String("org.freedesktop.DBus"), QLatin1String("GetConnectionUnixProcessID")); msg << m_message.service(); QDBusMessage reply = QDBusConnection::sessionBus().call(msg); if (reply.type() != QDBusMessage::ReplyMessage) { qCWarning(APPER_SESSION) << "Message did not receive a reply"; } if (reply.arguments().size() == 1) { return reply.arguments().at(0).toUInt(); } return UINT_MAX; } void SessionTask::search() { qCDebug(APPER_SESSION) << "virtual method called, falling back to commit()"; commit(); } void SessionTask::commit() { qCDebug(APPER_SESSION) << "virtual method called"; if (m_reviewChanges) { QStringList installPackages = m_reviewChanges->model()->selectedPackagesToInstall(); m_removePackages = m_reviewChanges->model()->selectedPackagesToRemove(); if (installPackages.isEmpty() && m_removePackages.isEmpty()) { setInfo(i18n("There are no packages to Install or Remove"), i18n("This action should not happen")); sendErrorFinished(Failed, QLatin1String("to install or remove due to empty lists")); } else if (!installPackages.isEmpty()) { // Install Packages auto transaction = new PkTransaction(this); setTransaction(Transaction::RoleInstallPackages, transaction); connect(transaction, &PkTransaction::finished, this, &SessionTask::commitFinished, Qt::UniqueConnection); transaction->installPackages(installPackages); } else { // Remove them removePackages(); } } } void SessionTask::removePackages() { // Remove Packages auto transaction = new PkTransaction(this); setTransaction(Transaction::RoleRemovePackages, transaction); connect(transaction, &PkTransaction::finished, this, &SessionTask::commitFinished, Qt::UniqueConnection); transaction->removePackages(m_removePackages); m_removePackages.clear(); } void SessionTask::notFound() { qCDebug(APPER_SESSION) << "virtual method called"; if (showWarning()) { setInfo(i18n("Could not find"), i18n("No packages were found that meet the request")); } sendErrorFinished(NoPackagesFound, QLatin1String("no package found")); } void SessionTask::searchFailed() { qCDebug(APPER_SESSION) << "virtual method called"; setInfo(i18n("Failed to find"), i18n("No packages were found that meet the request")); sendErrorFinished(Failed, QLatin1String("failed to search")); } void SessionTask::searchSuccess() { qCDebug(APPER_SESSION) << "virtual method called"; enableButtonOk(true); m_reviewChanges = new ReviewChanges(m_model, this); connect(m_reviewChanges, &ReviewChanges::hasSelectedPackages, this, &SessionTask::enableButtonOk); setMainWidget(m_reviewChanges); } void SessionTask::commitFailed() { qCDebug(APPER_SESSION) << "virtual method called"; // This should not be used to display stuff as the transaction should // emit error() or info() // setInfo(i18n("Failed to commit transaction"), // PkStrings::errsearchFailedorMessage(m_pkTransaction->error())); sendErrorFinished(Failed, i18n("Transaction did not finish with success")); } void SessionTask::commitSuccess(QWidget *widget) { qCDebug(APPER_SESSION) << "virtual method called"; setFinish(i18n("Task completed"), i18n("All operations were committed successfully"), widget); finishTaskOk(); } void SessionTask::showCloseButton() { ui->buttonBox->setStandardButtons(QDialogButtonBox::Close); QPushButton *closeBt = ui->buttonBox->button(QDialogButtonBox::Close); closeBt->setDefault(true); connect(closeBt, &QPushButton::clicked, this, &SessionTask::accept); } void SessionTask::sendErrorFinished(DBusError error, const QString &msg) { QString dbusError; switch (error) { case Failed: dbusError = QLatin1String("org.freedesktop.PackageKit.Failed"); break; case InternalError: dbusError = QLatin1String("org.freedesktop.PackageKit.InternalError"); break; case NoPackagesFound: dbusError = QLatin1String("org.freedesktop.PackageKit.NoPackagesFound"); break; case Forbidden: dbusError = QLatin1String("org.freedesktop.PackageKit.Forbidden"); break; case Cancelled: dbusError = QLatin1String("org.freedesktop.PackageKit.Cancelled"); break; } QDBusMessage reply = m_message.createErrorReply(dbusError, msg); QDBusConnection::sessionBus().send(reply); } bool SessionTask::sendMessageFinished(const QDBusMessage &message) { // emit finished(); return QDBusConnection::sessionBus().send(message); } uint SessionTask::parentWId() const { return m_xid; } void SessionTask::slotContinueClicked() { if (qobject_cast(mainWidget())) { enableButtonOk(false); search(); } else if (qobject_cast(mainWidget())) { enableButtonOk(false); commit(); } else { // emit okClicked(); } } void SessionTask::slotCancelClicked() { emit cancelClicked(); sendErrorFinished(Cancelled, QLatin1String("Aborted by the user")); reject(); } void SessionTask::enableButtonOk(bool enable) { QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(enable); if (enable) { // When enabling the Continue button put focus on it okButton->setFocus(); } } void SessionTask::parseInteraction(const QString &interaction) { QStringList interactions = interaction.split(QLatin1Char(',')); // Enable or disable all options if (interactions.contains(QLatin1String("always"))) { m_interactions = ConfirmSearch | ConfirmDeps | ConfirmInstall | Progress | Finished | Warning; } else if (interactions.contains(QLatin1String("never"))) { m_interactions = 0; } // show custom options if (interactions.contains(QLatin1String("show-confirm-search"))) { m_interactions |= ConfirmSearch; } if (interactions.contains(QLatin1String("show-confirm-deps"))) { m_interactions |= ConfirmDeps; } if (interactions.contains(QLatin1String("show-confirm-install"))) { m_interactions |= ConfirmInstall; } if (interactions.contains(QLatin1String("show-progress"))) { m_interactions |= Progress; } if (interactions.contains(QLatin1String("show-finished"))) { m_interactions |= Finished; } if (interactions.contains(QLatin1String("show-warning"))) { m_interactions |= Warning; } // hide custom options if (interactions.contains(QLatin1String("hide-confirm-search"))) { m_interactions &= ~ConfirmSearch; } if (interactions.contains(QLatin1String("hide-confirm-deps"))) { m_interactions &= ~ConfirmDeps; } if (interactions.contains(QLatin1String("hide-confirm-install"))) { m_interactions &= ~ConfirmInstall; } if (interactions.contains(QLatin1String("hide-progress"))) { m_interactions &= ~Progress; } if (interactions.contains(QLatin1String("hide-finished"))) { m_interactions &= ~Finished; } if (interactions.contains(QLatin1String("hide-warning"))) { m_interactions &= ~Warning; } int index; QRegExp rx(QLatin1String("^timeout=(\\d+)$")); index = interactions.indexOf(rx); if (index != -1) { if (rx.indexIn(interactions.at(index)) != -1) { m_timeout = rx.cap(1).toUInt(); } } } bool SessionTask::foundPackages() const { return m_model->rowCount(); } int SessionTask::foundPackagesSize() const { return m_model->rowCount(); } PackageModel *SessionTask::model() const { return m_model; } void SessionTask::setTransaction(Transaction::Role role, PkTransaction *t) { if (m_pkTransaction == 0) { m_pkTransaction = new PkTransactionWidget(this); m_pkTransaction->hideCancelButton(); ui->stackedWidget->addWidget(m_pkTransaction); connect(m_pkTransaction, &PkTransactionWidget::titleChanged, this, &SessionTask::setTitle); connect(this, &SessionTask::cancelClicked, m_pkTransaction, &PkTransactionWidget::cancel); connect(m_pkTransaction, &PkTransactionWidget::dialog, this, &SessionTask::setDialog); connect(m_pkTransaction, &PkTransactionWidget::sorry, this, &SessionTask::setInfo); connect(m_pkTransaction, &PkTransactionWidget::error, this, &SessionTask::setError); } if (t) { m_pkTransaction->setTransaction(t, role); // setTitle(m_pkTransaction->title()); } // avoid changing the current widget if (mainWidget() != m_pkTransaction) { ui->stackedWidget->setCurrentWidget(m_pkTransaction); } } void SessionTask::finishTaskOk() { sendMessageFinished(m_message.createReply()); } SessionTask::Interactions SessionTask::interactions() const { return m_interactions; } uint SessionTask::timeout() const { return m_timeout; } bool SessionTask::showConfirmSearch() const { return m_interactions & ConfirmSearch; } bool SessionTask::showConfirmDeps() const { return m_interactions & ConfirmDeps; } bool SessionTask::showConfirmInstall() const { return m_interactions & ConfirmInstall; } bool SessionTask::showProgress() const { return m_interactions & Progress; } bool SessionTask::showFinished() const { return m_interactions & Finished; } bool SessionTask::showWarning() const { return m_interactions & Warning; } -#include "SessionTask.moc" +#include "moc_SessionTask.cpp" diff --git a/apperd/ApperdThread.cpp b/apperd/ApperdThread.cpp index 0b4eba4..3e77149 100644 --- a/apperd/ApperdThread.cpp +++ b/apperd/ApperdThread.cpp @@ -1,330 +1,332 @@ /*************************************************************************** * Copyright (C) 2012 by Daniel Nicoletti * * * * 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 "ApperdThread.h" #include "RefreshCacheTask.h" #include "Updater.h" #include "DistroUpgrade.h" #include "TransactionWatcher.h" #include "DBusInterface.h" #include "RebootListener.h" #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_DAEMON) #define FIVE_MIN 360000 #define ONE_MIN 72000 /* * What we need: * - Refresh the package cache periodicaly (implies listenning to PK's updates changed) * - Update or Display Package Updates * - Display Distro Upgrades * - Start Sentinel to keep an eye on running transactions */ using namespace PackageKit; //using namespace Solid; ApperdThread::ApperdThread(QObject *parent) : QObject(parent), m_proxyChanged(true), m_AptRebootListener(new AptRebootListener(this)) { } ApperdThread::~ApperdThread() { } void ApperdThread::init() { // connect(PowerManagement::notifier(), SIGNAL(appShouldConserveResourcesChanged(bool)), // this, SLOT(appShouldConserveResourcesChanged())); // This timer keeps polling to see if it has // to refresh the cache m_qtimer = new QTimer(this); m_qtimer->setInterval(FIVE_MIN); connect(m_qtimer, &QTimer::timeout, this, &ApperdThread::poll); m_qtimer->start(); //check if any changes to the file occour //this also prevents from reading when a checkUpdate happens auto confWatch = new KDirWatch(this); confWatch->addFile(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/apper")); connect(confWatch, SIGNAL(dirty(QString)), this, SLOT(configFileChanged())); connect(confWatch, SIGNAL(created(QString)), this, SLOT(configFileChanged())); connect(confWatch, SIGNAL(deleted(QString)), this, SLOT(configFileChanged())); confWatch->startScan(); // Watch for changes in the KDE proxy settings auto proxyWatch = new KDirWatch(this); confWatch->addFile(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/kioslaverc")); connect(proxyWatch, SIGNAL(dirty(QString)), this, SLOT(proxyChanged())); connect(proxyWatch, SIGNAL(created(QString)), this, SLOT(proxyChanged())); connect(proxyWatch, SIGNAL(deleted(QString)), this, SLOT(proxyChanged())); proxyWatch->startScan(); Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name() + QLatin1String(".UTF-8")); connect(Daemon::global(), &Daemon::updatesChanged, this, &ApperdThread::updatesChanged); m_interface = new DBusInterface(this); m_refreshCache = new RefreshCacheTask(this); connect(m_interface, &DBusInterface::refreshCache, m_refreshCache, &RefreshCacheTask::refreshCache); m_updater = new Updater(this); m_distroUpgrade = new DistroUpgrade(this); // read the current settings configFileChanged(); // In case PackageKit is not running watch for it's registration to configure proxy auto watcher = new QDBusServiceWatcher(QLatin1String("org.freedesktop.PackageKit"), QDBusConnection::systemBus(), QDBusServiceWatcher::WatchForRegistration, this); connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &ApperdThread::setProxy); // if PackageKit is running check to see if there are running transactons already bool packagekitIsRunning = nameHasOwner(QLatin1String("org.freedesktop.PackageKit"), QDBusConnection::systemBus()); m_transactionWatcher = new TransactionWatcher(packagekitIsRunning, this); // connect the watch transaction coming from the updater icon to our watcher connect(m_interface, &DBusInterface::watchTransaction, m_transactionWatcher, &TransactionWatcher::watchTransactionInteractive); // listen to Debian/Apt reboot signals from other sources (apt) connect(m_AptRebootListener, &AptRebootListener::requestReboot, m_transactionWatcher, &TransactionWatcher::showRebootNotificationApt); QTimer::singleShot(2 /*minutes*/ * 60 /*seconds*/ * 1000 /*msec*/, m_AptRebootListener, SLOT(checkForReboot())); if (packagekitIsRunning) { // PackageKit is running set the session Proxy setProxy(); // If packagekit is already running go check // for updates updatesChanged(); } else { // Initial check for updates QTimer::singleShot(ONE_MIN, this, SLOT(updatesChanged())); } } // This is called every 5 minutes void ApperdThread::poll() { if (m_lastRefreshCache.isNull()) { // This value wasn't set // convert this to QDateTime m_lastRefreshCache = getTimeSinceRefreshCache(); } // If check for updates is active if (m_configs[QLatin1String(CFG_INTERVAL)].value() != Enum::Never) { // Find out how many seconds passed since last refresh cache qint64 msecsSinceLastRefresh = (QDateTime::currentDateTime().toMSecsSinceEpoch() - m_lastRefreshCache.toMSecsSinceEpoch()) / 1000; // If lastRefreshCache is null it means that the cache was never refreshed if (m_lastRefreshCache.isNull() || msecsSinceLastRefresh > m_configs[QLatin1String(CFG_INTERVAL)].value()) { bool ignoreBattery = m_configs[QLatin1String(CFG_CHECK_UP_BATTERY)].value(); bool ignoreMobile = m_configs[QLatin1String(CFG_CHECK_UP_MOBILE)].value(); if (isSystemReady(ignoreBattery, ignoreMobile)) { m_refreshCache->refreshCache(); } // Invalidate the last time the cache was refreshed m_lastRefreshCache = QDateTime(); } } } void ApperdThread::configFileChanged() { KConfig config(QLatin1String("apper")); KConfigGroup checkUpdateGroup(&config, "CheckUpdate"); m_configs[QLatin1String(CFG_CHECK_UP_BATTERY)] = checkUpdateGroup.readEntry(CFG_CHECK_UP_BATTERY, DEFAULT_CHECK_UP_BATTERY); m_configs[QLatin1String(CFG_CHECK_UP_MOBILE)] = checkUpdateGroup.readEntry(CFG_CHECK_UP_MOBILE, DEFAULT_CHECK_UP_MOBILE); m_configs[QLatin1String(CFG_INSTALL_UP_BATTERY)] = checkUpdateGroup.readEntry(CFG_INSTALL_UP_BATTERY, DEFAULT_INSTALL_UP_BATTERY); m_configs[QLatin1String(CFG_INSTALL_UP_MOBILE)] = checkUpdateGroup.readEntry(CFG_INSTALL_UP_MOBILE, DEFAULT_INSTALL_UP_MOBILE); m_configs[QLatin1String(CFG_AUTO_UP)] = checkUpdateGroup.readEntry(CFG_AUTO_UP, Enum::AutoUpdateDefault); m_configs[QLatin1String(CFG_INTERVAL)] = checkUpdateGroup.readEntry(CFG_INTERVAL, Enum::TimeIntervalDefault); m_configs[QLatin1String(CFG_DISTRO_UPGRADE)] = checkUpdateGroup.readEntry(CFG_DISTRO_UPGRADE, Enum::DistroUpgradeDefault); m_updater->setConfig(m_configs); m_distroUpgrade->setConfig(m_configs); KDirWatch *confWatch = qobject_cast(sender()); if (confWatch) { // Check for updates again since the config changed updatesChanged(); } } void ApperdThread::proxyChanged() { // We must reparse the configuration since the values are all cached KProtocolManager::reparseConfiguration(); QHash proxyConfig; if (KProtocolManager::proxyType() == KProtocolManager::ManualProxy) { proxyConfig[QLatin1String("http")] = KProtocolManager::proxyFor(QLatin1String("http")); proxyConfig[QLatin1String("https")] = KProtocolManager::proxyFor(QLatin1String("https")); proxyConfig[QLatin1String("ftp")] = KProtocolManager::proxyFor(QLatin1String("ftp")); proxyConfig[QLatin1String("socks")] = KProtocolManager::proxyFor(QLatin1String("socks")); } // Check if the proxy settings really changed to avoid setting them twice if (proxyConfig != m_proxyConfig) { m_proxyConfig = proxyConfig; m_proxyChanged = true; setProxy(); } } void ApperdThread::setProxy() { if (!m_proxyChanged) { return; } // If we were called by the watcher it is because PackageKit is running bool packagekitIsRunning = true; auto watcher = qobject_cast(sender()); if (!watcher) { packagekitIsRunning = nameHasOwner(QLatin1String("org.freedesktop.PackageKit"), QDBusConnection::systemBus()); } if (packagekitIsRunning) { // Apply the proxy changes only if packagekit is running // use value() to not insert items on the hash Daemon::global()->setProxy(m_proxyConfig.value(QLatin1String("http")), m_proxyConfig.value(QLatin1String("https")), m_proxyConfig.value(QLatin1String("ftp")), m_proxyConfig.value(QLatin1String("socks")), QString(), QString()); m_proxyChanged = false; } } void ApperdThread::updatesChanged() { // update the last time the cache was refreshed QDateTime lastCacheRefresh; lastCacheRefresh = getTimeSinceRefreshCache(); if (lastCacheRefresh != m_lastRefreshCache) { m_lastRefreshCache = lastCacheRefresh; } bool ignoreBattery = m_configs[QLatin1String(CFG_INSTALL_UP_BATTERY)].value(); bool ignoreMobile = m_configs[QLatin1String(CFG_INSTALL_UP_MOBILE)].value(); // Make sure the user sees the updates m_updater->checkForUpdates(isSystemReady(ignoreBattery, ignoreMobile)); m_distroUpgrade->checkDistroUpgrades(); } void ApperdThread::appShouldConserveResourcesChanged() { bool ignoreBattery = m_configs[QLatin1String(CFG_INSTALL_UP_BATTERY)].value(); bool ignoreMobile = m_configs[QLatin1String(CFG_INSTALL_UP_MOBILE)].value(); if (isSystemReady(ignoreBattery, ignoreMobile)) { m_updater->setSystemReady(); } } QDateTime ApperdThread::getTimeSinceRefreshCache() const { uint value = Daemon::global()->getTimeSinceAction(Transaction::RoleRefreshCache); // When the refresh cache value was not yet defined UINT_MAX is returned if (value == UINT_MAX) { return QDateTime(); } else { // Calculate the last time the cache was refreshed by // subtracting the seconds from the current time return QDateTime::currentDateTime().addSecs(value * -1); } } bool ApperdThread::nameHasOwner(const QString &name, const QDBusConnection &connection) { QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.DBus"), QLatin1String("/"), QLatin1String("org.freedesktop.DBus"), QLatin1String("NameHasOwner")); message << qVariantFromValue(name); QDBusReply reply = connection.call(message); return reply.value(); } bool ApperdThread::isSystemReady(bool ignoreBattery, bool ignoreMobile) const { // First check if we should conserve resources // check how applications should behave (e.g. on battery power) // if (!ignoreBattery && Solid::PowerManagement::appShouldConserveResources()) { qCDebug(APPER_DAEMON) << "System is not ready, application should conserve resources"; // This was fixed for KDElibs 4.8.5 return false; // } // TODO it would be nice is Solid provided this // so we wouldn't be waking up PackageKit for this Solid task. Daemon::Network network = Daemon::global()->networkState(); // test whether network is connected if (network == Daemon::NetworkOffline || network == Daemon::NetworkUnknown) { qCDebug(APPER_DAEMON) << "System is not ready, network state" << network; return false; } // check how applications should behave (e.g. on battery power) if (!ignoreMobile && network == Daemon::NetworkMobile) { qCDebug(APPER_DAEMON) << "System is not ready, network state" << network; return false; } return true; } + +#include "moc_ApperdThread.cpp" diff --git a/apperd/DBusInterface.cpp b/apperd/DBusInterface.cpp index 8409211..2d7c3e9 100644 --- a/apperd/DBusInterface.cpp +++ b/apperd/DBusInterface.cpp @@ -1,121 +1,123 @@ /*************************************************************************** * Copyright (C) 2008-2011 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; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "DBusInterface.h" #include "apperdadaptor.h" #include #ifdef HAVE_DEBCONFKDE #include #include #include using namespace PackageKit; #endif #include Q_DECLARE_LOGGING_CATEGORY(APPER_DAEMON) DBusInterface::DBusInterface(QObject *parent) : QObject(parent) { qCDebug(APPER_DAEMON) << "Creating Helper"; (void) new ApperdAdaptor(this); if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.apperd"))) { qCDebug(APPER_DAEMON) << "another helper is already running"; return; } if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), this)) { qCDebug(APPER_DAEMON) << "unable to register service interface to dbus"; return; } } DBusInterface::~DBusInterface() { qCDebug(APPER_DAEMON) << "-------------DBusInterface-------------" << QThread::currentThreadId(); } void DBusInterface::RefreshCache() { emit refreshCache(); } void DBusInterface::SetupDebconfDialog(const QString &tid, const QString &socketPath, uint xidParent) { #ifdef HAVE_DEBCONFKDE qCDebug(APPER_DAEMON) << tid << socketPath << xidParent; DebconfGui *gui; if (m_debconfGuis.contains(socketPath)) { gui = m_debconfGuis[socketPath]; } else { // Create the Transaction object to delete // the DebconfGui class when the transaction finishes auto transaction = new Transaction(QDBusObjectPath(tid)); transaction->setProperty("socketPath", socketPath); connect(transaction, &Transaction::finished, this, &DBusInterface::transactionFinished); // Setup the Debconf dialog gui = new DebconfGui(socketPath); gui->setWindowModality(Qt::WindowModal); gui->setWindowFlags(Qt::Dialog); m_debconfGuis[socketPath] = gui; connect(gui, SIGNAL(activated()), this, SLOT(debconfActivate())); connect(gui, SIGNAL(deactivated()), gui, SLOT(hide())); } gui->setProperty("xidParent", xidParent); #else Q_UNUSED(tid) Q_UNUSED(socketPath) Q_UNUSED(xidParent) qCDebug(APPER_DAEMON) << "Not compiled with Debconf support - ignoring"; #endif //HAVE_DEBCONFKDE } void DBusInterface::WatchTransaction(const QDBusObjectPath &tid) { emit watchTransaction(tid); } void DBusInterface::debconfActivate() { #ifdef HAVE_DEBCONFKDE // Correct the parent qCDebug(APPER_DAEMON); DebconfGui *gui = qobject_cast(sender()); uint xidParent = gui->property("xidParent").toUInt(); KWindowSystem::setMainWindow(gui, xidParent); gui->show(); #endif } void DBusInterface::transactionFinished() { #ifdef HAVE_DEBCONFKDE QString socketPath = sender()->property("socketPath").toString(); if (m_debconfGuis.contains(socketPath)) { // remove the gui from the list and also delete it m_debconfGuis.take(socketPath)->deleteLater(); } #endif // HAVE_DEBCONFKDE } + +#include "moc_DBusInterface.cpp" diff --git a/apperd/RebootListener.cpp b/apperd/RebootListener.cpp index b7c50b5..fe4e58e 100644 --- a/apperd/RebootListener.cpp +++ b/apperd/RebootListener.cpp @@ -1,59 +1,58 @@ /* Copyright (c) 2010 Sune Vuorela * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "RebootListener.h" #include #include #include #include #include static const QString reboot_required_path = QStringLiteral("/run/reboot-required"); AptRebootListener::AptRebootListener(QObject *parent): QObject(parent) { m_watcher = new KDirWatch(this); m_watcher->addFile(reboot_required_path); connect(m_watcher, &KDirWatch::created, this, &AptRebootListener::slotDirectoryChanged); m_timer = new QTimer(this); m_timer->setSingleShot(true); m_timer->setInterval(500); connect(m_timer, &QTimer::timeout, this, &AptRebootListener::requestReboot); } void AptRebootListener::checkForReboot() { if (QFile::exists(reboot_required_path)) { m_timer->start(); } } - void AptRebootListener::slotDirectoryChanged(const QString &path) { if (path == reboot_required_path) { m_timer->start(); } } -#include +#include "moc_RebootListener.cpp" diff --git a/apperd/RefreshCacheTask.cpp b/apperd/RefreshCacheTask.cpp index ba30ba1..4bd1d17 100644 --- a/apperd/RefreshCacheTask.cpp +++ b/apperd/RefreshCacheTask.cpp @@ -1,85 +1,87 @@ /*************************************************************************** * Copyright (C) 2012 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 "RefreshCacheTask.h" #include #include #include #include #include RefreshCacheTask::RefreshCacheTask(QObject *parent) : QObject(parent), m_transaction(0), m_notification(0), m_lastError(Transaction::ErrorUnknown), m_cacheAge(3600) { } void RefreshCacheTask::refreshCache() { // kDebug(); if (!m_transaction) { // Refresh Cache is false otherwise it will rebuild // the whole cache on Fedora Daemon::setHints (QLatin1String("cache-age=") + QString::number(m_cacheAge)); m_transaction = Daemon::refreshCache(false); connect(m_transaction, &Transaction::finished, this, &RefreshCacheTask::refreshCacheFinished); connect(m_transaction, &Transaction::errorCode, this, &RefreshCacheTask::errorCode); } } void RefreshCacheTask::refreshCacheFinished(PackageKit::Transaction::Exit status, uint runtime) { Q_UNUSED(runtime) m_transaction = 0; if (status == Transaction::ExitSuccess) { m_lastError = Transaction::ErrorUnknown; m_lastErrorString.clear(); } } void RefreshCacheTask::errorCode(Transaction::Error error, const QString &errorMessage) { if (m_notification || (m_lastError == error && m_lastErrorString == errorMessage)) { return; } m_notification = new KNotification(QLatin1String("TransactionFailed"), KNotification::Persistent, this); m_notification->setComponentName(QLatin1String("apperd")); connect(m_notification, &KNotification::closed, this, &RefreshCacheTask::notificationClosed); QIcon icon = QIcon::fromTheme(QLatin1String("dialog-cancel")); // use of QSize does the right thing m_notification->setPixmap(icon.pixmap(QSize(KPK_ICON_SIZE, KPK_ICON_SIZE))); m_notification->setTitle(PkStrings::error(error)); m_notification->setText(errorMessage); m_notification->sendEvent(); } void RefreshCacheTask::notificationClosed() { m_notification->deleteLater(); m_notification = 0; } + +#include "moc_RefreshCacheTask.cpp" diff --git a/apperd/TransactionJob.cpp b/apperd/TransactionJob.cpp index 2b18e50..bc0d2f8 100644 --- a/apperd/TransactionJob.cpp +++ b/apperd/TransactionJob.cpp @@ -1,190 +1,190 @@ /*************************************************************************** * 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 "TransactionJob.h" #include #include #include //#include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_DAEMON) TransactionJob::TransactionJob(Transaction *transaction, QObject *parent) : KJob(parent), m_transaction(transaction), m_status(transaction->status()), m_role(transaction->role()), m_flags(transaction->transactionFlags()), m_percentage(0), m_speed(0), m_downloadSizeRemainingTotal(0), m_finished(false) { setCapabilities(Killable); connect(transaction, &Transaction::roleChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::statusChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::downloadSizeRemainingChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::transactionFlagsChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::percentageChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::speedChanged, this, &TransactionJob::updateJob); connect(transaction, &Transaction::finished, this, &TransactionJob::finished); connect(transaction, &Transaction::package, this, &TransactionJob::package); connect(transaction, &Transaction::repoDetail, this, &TransactionJob::repoDetail); } TransactionJob::~TransactionJob() { } void TransactionJob::finished(PackageKit::Transaction::Exit exit) { if (m_finished) { return; } // emit the description so the Speed: xxx KiB/s // don't get confused to a destination URL emit description(this, PkStrings::action(m_role, m_flags)); if (exit == Transaction::ExitCancelled || exit == Transaction::ExitFailed) { setError(KilledJobError); } m_finished = true; emitResult(); } void TransactionJob::package(Transaction::Info info, const QString &packageID, const QString &summary) { Q_UNUSED(summary) if (!packageID.isEmpty()) { bool changed = false; if (info == Transaction::InfoFinished) { changed = m_packages.removeOne(Transaction::packageName(packageID)); } else if (!m_packages.contains(Transaction::packageName(packageID))) { m_packages << Transaction::packageName(packageID); changed = true; } if (changed) { m_details = m_packages.join(QLatin1String(", ")); emitDescription(); } } } void TransactionJob::repoDetail(const QString &repoId, const QString &repoDescription) { Q_UNUSED(repoId) QString first = PkStrings::status(m_status); emit description(this, PkStrings::action(m_role, m_flags), qMakePair(first, repoDescription)); } void TransactionJob::emitDescription() { QString details = m_details; if (details.isEmpty()) { details = QLatin1String("..."); } QString first = PkStrings::status(m_status); emit description(this, PkStrings::action(m_role, m_flags), qMakePair(first, details)); } void TransactionJob::updateJob() { Transaction::Role role = m_transaction->role(); Transaction::TransactionFlags flags = m_transaction->transactionFlags(); if (m_role != role || m_flags != flags) { m_role = role; m_flags = flags; emitDescription(); } // Status & Speed Transaction::Status status = m_transaction->status(); if (m_status != status) { m_status = status; emitDescription(); } uint percentage = m_transaction->percentage(); if (percentage <= 100) { emitPercent(percentage, 100); } else if (m_percentage != 0) { percentage = 0; emitPercent(0, 0); } m_percentage = percentage; uint speed = m_transaction->speed(); if (m_speed != speed) { m_speed = speed; emitSpeed(m_speed); } if (m_downloadSizeRemainingTotal == 0) { m_downloadSizeRemainingTotal = m_transaction->downloadSizeRemaining(); } if (m_downloadSizeRemainingTotal) { qulonglong processed; processed = m_downloadSizeRemainingTotal - m_transaction->downloadSizeRemaining(); emitPercent(processed, m_downloadSizeRemainingTotal); } } void TransactionJob::start() { m_role = Transaction::RoleUnknown; m_speed = 0; m_downloadSizeRemainingTotal = 0; m_details = Transaction::packageName(m_transaction->lastPackage()); updateJob(); } bool TransactionJob::isFinished() const { return m_finished; } Transaction *TransactionJob::transaction() const { return m_transaction; } bool TransactionJob::doKill() { // emit the description so the Speed: xxx KiB/s // don't get confused to a destination URL emit description(this, PkStrings::action(m_role, m_flags)); QDBusPendingReply<> reply = m_transaction->cancel(); reply.waitForFinished(); qCDebug(APPER_DAEMON) << "Transaction cancel operation result" << m_transaction->tid().path() << reply.error(); emit canceled(); return !reply.isError() && m_transaction->role() == Transaction::RoleCancel; } -#include "TransactionJob.moc" +#include "moc_TransactionJob.cpp" diff --git a/apperd/TransactionWatcher.cpp b/apperd/TransactionWatcher.cpp index b1823ac..57c0038 100644 --- a/apperd/TransactionWatcher.cpp +++ b/apperd/TransactionWatcher.cpp @@ -1,343 +1,345 @@ /*************************************************************************** * 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 "TransactionWatcher.h" #include "TransactionJob.h" #include #include #include #include #include #include #include //#include //#include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_DAEMON) TransactionWatcher::TransactionWatcher(bool packagekitIsRunning, QObject *parent) : QObject(parent), m_inhibitCookie(-1) { m_tracker = new KUiServerJobTracker(this); // keep track of new transactions connect(Daemon::global(), &Daemon::transactionListChanged, this, &TransactionWatcher::transactionListChanged); // if PackageKit is running check to see if there are running transactons already if (packagekitIsRunning) { // here we check whether a transaction job should be created or not QStringList tids; const QList paths = Daemon::global()->getTransactionList(); for (const QDBusObjectPath &path : paths) { tids << path.path(); } transactionListChanged(tids); } } TransactionWatcher::~TransactionWatcher() { // release any cookie that we might have suppressSleep(false, m_inhibitCookie); } void TransactionWatcher::watchTransactionInteractive(const QDBusObjectPath &tid) { watchTransaction(tid); } void TransactionWatcher::transactionListChanged(const QStringList &tids) { if (tids.isEmpty()) { // release any cookie that we might have suppressSleep(false, m_inhibitCookie); } else { for (const QString &tid : tids) { watchTransaction(QDBusObjectPath(tid), false); } } } void TransactionWatcher::watchTransaction(const QDBusObjectPath &tid, bool interactive) { Transaction *transaction; if (!m_transactions.contains(tid)) { // Check if the current transaction is still the same transaction = new Transaction(tid); connect(transaction, &Transaction::roleChanged, this, &TransactionWatcher::transactionReady); connect(transaction, &Transaction::finished, this, &TransactionWatcher::finished); // Store the transaction id m_transactions[tid] = transaction; } else { transaction = m_transactions[tid]; if (transaction->role() != Transaction::RoleUnknown) { // force the first changed or create a TransactionJob transactionChanged(transaction, interactive); } } } void TransactionWatcher::transactionReady() { auto transaction = qobject_cast(sender()); Transaction::Role role = transaction->role(); Transaction::TransactionFlags flags = transaction->transactionFlags(); if (!(flags & Transaction::TransactionFlagOnlyDownload || flags & Transaction::TransactionFlagSimulate) && (role == Transaction::RoleInstallPackages || role == Transaction::RoleInstallFiles || role == Transaction::RoleRemovePackages || role == Transaction::RoleUpdatePackages)) { // AVOID showing messages and restart requires when // the user was just simulating an instalation connect(transaction, &Transaction::requireRestart, this, &TransactionWatcher::requireRestart); // Don't let the system sleep while doing some sensible actions suppressSleep(true, m_inhibitCookie, PkStrings::action(role, flags)); } connect(transaction, &Transaction::isCallerActiveChanged, this, [this, transaction] () { transactionChanged(transaction); }); } void TransactionWatcher::showRebootNotificationApt() { // Create the notification about this transaction auto notify = new KNotification(QLatin1String("RestartRequired"), 0, KNotification::Persistent); connect(notify, QOverload::of(&KNotification::activated), this, &TransactionWatcher::logout); notify->setComponentName(QLatin1String("apperd")); QString text(QLatin1String("") + i18n("The system update has completed") + QLatin1String("")); text.append(QLatin1String("
") + PkStrings::restartType(Transaction::RestartSystem)); notify->setPixmap(PkIcons::restartIcon(Transaction::RestartSystem).pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); notify->setText(text); // TODO RestartApplication should be handled differently QStringList actions; actions << i18n("Restart"); notify->setActions(actions); notify->sendEvent(); } void TransactionWatcher::finished(PackageKit::Transaction::Exit exit) { // check if the transaction emitted any require restart auto transaction = qobject_cast(sender()); QDBusObjectPath tid = transaction->tid(); transaction->disconnect(this); m_transactions.remove(tid); m_transactionJob.remove(tid); if (exit == Transaction::ExitSuccess && !transaction->property("restartType").isNull()) { Transaction::Restart type = transaction->property("restartType").value(); QStringList restartPackages = transaction->property("restartPackages").toStringList(); // Create the notification about this transaction auto notify = new KNotification(QLatin1String("RestartRequired"), 0, KNotification::Persistent); connect(notify, QOverload::of(&KNotification::activated), this, &TransactionWatcher::logout); notify->setComponentName(QLatin1String("apperd")); notify->setProperty("restartType", qVariantFromValue(type)); notify->setPixmap(PkIcons::restartIcon(type).pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); notify->setTitle(PkStrings::restartType(type)); // Create a readable text with package names that required the restart if (!restartPackages.isEmpty()) { restartPackages.removeDuplicates(); restartPackages.sort(); QString text; text = i18np("Package: %2", "Packages: %2", restartPackages.size(), restartPackages.join(QLatin1String(", "))); notify->setText(text); } // TODO RestartApplication should be handled differently QStringList actions; actions << i18n("Restart"); notify->setActions(actions); notify->sendEvent(); } } void TransactionWatcher::transactionChanged(Transaction *transaction, bool interactive) { if (!transaction) { transaction = qobject_cast(sender()); } QDBusObjectPath tid = transaction->tid(); if (!interactive) { interactive = !transaction->isCallerActive(); } // If the if (!m_transactionJob.contains(tid) && interactive) { auto job = new TransactionJob(transaction, this); connect(transaction, &Transaction::errorCode, this, &TransactionWatcher::errorCode); connect(job, &TransactionJob::canceled, this, &TransactionWatcher::watchedCanceled); m_tracker->registerJob(job); m_transactionJob[tid] = job; job->start(); } } void TransactionWatcher::errorCode(PackageKit::Transaction::Error err, const QString &details) { auto notify = new KNotification(QLatin1String("TransactionError"), 0, KNotification::Persistent); notify->setComponentName(QLatin1String("apperd")); notify->setTitle(PkStrings::error(err)); notify->setText(PkStrings::errorMessage(err)); notify->setProperty("ErrorType", QVariant::fromValue(err)); notify->setProperty("Details", details); QStringList actions; actions << i18n("Details"); notify->setActions(actions); notify->setPixmap(QIcon::fromTheme(QLatin1String("dialog-error")).pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); connect(notify, QOverload::of(&KNotification::activated), this, &TransactionWatcher::errorActivated); notify->sendEvent(); } void TransactionWatcher::errorActivated(uint action) { auto notify = qobject_cast(sender()); // if the user clicked "Details" if (action == 1) { Transaction::Error error = notify->property("ErrorType").value(); QString details = notify->property("Details").toString(); KMessageBox::detailedSorry(0, PkStrings::errorMessage(error), details.replace(QLatin1Char('\n'), QLatin1String("
")), PkStrings::error(error), KMessageBox::Notify); } notify->close(); } void TransactionWatcher::requireRestart(PackageKit::Transaction::Restart type, const QString &packageID) { auto transaction = qobject_cast(sender()); if (transaction->property("restartType").isNull()) { transaction->setProperty("restartType", qVariantFromValue(type)); } else { Transaction::Restart oldType; oldType = transaction->property("restartType").value(); int old = PackageImportance::restartImportance(oldType); int newer = PackageImportance::restartImportance(type); // Check to see which one is more important if (newer > old) { transaction->setProperty("restartType", qVariantFromValue(type)); } } if (!Transaction::packageName(packageID).isEmpty()) { QStringList restartPackages = transaction->property("restartPackages").toStringList(); restartPackages << Transaction::packageName(packageID); transaction->setProperty("restartPackages", restartPackages); } } void TransactionWatcher::logout() { auto notify = qobject_cast(sender()); Transaction::Restart restartType; restartType = notify->property("restartType").value(); KWorkSpace::ShutdownType shutdownType; switch (restartType) { case Transaction::RestartSystem: case Transaction::RestartSecuritySystem: // The restart type was system shutdownType = KWorkSpace::ShutdownTypeReboot; break; case Transaction::RestartSession: case Transaction::RestartSecuritySession: // The restart type was session shutdownType = KWorkSpace::ShutdownTypeLogout; break; default: qCWarning(APPER_DAEMON) << "Unknown restart type:" << restartType; return; } // We call KSM server to restart or logout our system KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmYes, shutdownType, KWorkSpace::ShutdownModeInteractive); } void TransactionWatcher::watchedCanceled() { auto job = qobject_cast(sender()); if (job->isFinished()) { job->deleteLater(); return; } Transaction::Role role = job->transaction()->role(); if (role != Transaction::RoleCancel && role != Transaction::RoleUnknown) { m_tracker->unregisterJob(job); m_tracker->registerJob(job); job->start(); } } void TransactionWatcher::suppressSleep(bool enable, int &inhibitCookie, const QString &reason) { if (inhibitCookie == -1) { return; } if (enable) { qCDebug(APPER_DAEMON) << "Begin Suppressing Sleep"; // inhibitCookie = Solid::PowerManagement::beginSuppressingSleep(reason); if (inhibitCookie == -1) { qCDebug(APPER_DAEMON) << "Sleep suppression denied!"; } } else { qCDebug(APPER_DAEMON) << "Stop Suppressing Sleep"; // if (!Solid::PowerManagement::stopSuppressingSleep(inhibitCookie)) { qCDebug(APPER_DAEMON) << "Stop failed: invalid cookie."; // } inhibitCookie = -1; } } + +#include "moc_TransactionWatcher.cpp" diff --git a/apperd/Updater.cpp b/apperd/Updater.cpp index ee5195a..99fb34c 100644 --- a/apperd/Updater.cpp +++ b/apperd/Updater.cpp @@ -1,323 +1,325 @@ /*************************************************************************** * Copyright (C) 2008 by Trever Fischer * * wm161@wm161.net * * 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 "ApperdThread.h" #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_LOGGING_CATEGORY(APPER_DAEMON) #define UPDATES_ICON "system-software-update" using namespace PackageKit; Updater::Updater(QObject* parent) : QObject(parent), m_getUpdatesT(0) { // in case registration fails due to another user or application running // keep an eye on it so we can register when available auto watcher = new QDBusServiceWatcher(QLatin1String("org.kde.ApperUpdaterIcon"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &Updater::serviceOwnerChanged); m_hasAppletIconified = ApperdThread::nameHasOwner(QLatin1String("org.kde.ApperUpdaterIcon"), QDBusConnection::sessionBus()); } Updater::~Updater() { } void Updater::setConfig(const QVariantHash &configs) { m_configs = configs; } void Updater::setSystemReady() { // System ready changed, maybe we can auto // install some updates m_systemReady = true; getUpdateFinished(); } void Updater::checkForUpdates(bool systemReady) { m_systemReady = systemReady; // Skip the check if one is already running or // the plasmoid is in Icon form and the auto update type is None if (m_getUpdatesT) { return; } m_updateList.clear(); m_importantList.clear(); m_securityList.clear(); m_getUpdatesT = Daemon::getUpdates(); connect(m_getUpdatesT, &Transaction::package, this, &Updater::packageToUpdate); connect(m_getUpdatesT, &Transaction::finished, this, &Updater::getUpdateFinished); } void Updater::packageToUpdate(Transaction::Info info, const QString &packageID, const QString &summary) { Q_UNUSED(summary) switch (info) { case Transaction::InfoBlocked: // Blocked updates are not instalable updates so there is no // reason to show/count them return; case Transaction::InfoImportant: m_importantList << packageID; break; case Transaction::InfoSecurity: m_securityList << packageID; break; default: break; } m_updateList << packageID; } void Updater::getUpdateFinished() { m_getUpdatesT = 0; if (!m_updateList.isEmpty()) { auto transaction = qobject_cast(sender()); bool different = false; if (m_oldUpdateList.size() != m_updateList.size()) { different = true; } else { // The lists have the same size let's make sure // all the packages are the same const QStringList updates = m_updateList; for (const QString &packageId : updates) { if (!m_oldUpdateList.contains(packageId)) { different = true; break; } } } // sender is not a transaction when we systemReady has changed // if the lists are the same don't show // a notification or try to upgrade again if (transaction && !different) { return; } uint updateType = m_configs[QLatin1String(CFG_AUTO_UP)].value(); if (m_systemReady && updateType == Enum::All) { // update all bool ret; ret = updatePackages(m_updateList, false, QLatin1String("plasmagik"), i18n("Updates are being automatically installed.")); if (ret) { return; } } else if (m_systemReady && updateType == Enum::Security && !m_securityList.isEmpty()) { // Defaults to security bool ret; ret = updatePackages(m_securityList, false, QLatin1String(UPDATES_ICON), i18n("Security updates are being automatically installed.")); if (ret) { return; } } else if (m_systemReady && updateType == Enum::DownloadOnly) { // Download all updates bool ret; ret = updatePackages(m_updateList, true, QLatin1String("download"), i18n("Updates are being automatically downloaded.")); if (ret) { return; } } else if (!m_systemReady && (updateType == Enum::All || updateType == Enum::DownloadOnly || (updateType == Enum::Security && !m_securityList.isEmpty()))) { qCDebug(APPER_DAEMON) << "Not auto updating or downloading, as we might be on battery or mobile connection"; } // If an erro happened to create the auto update // transaction show the update list if (transaction) { // The transaction is not valid if the systemReady changed showUpdatesPopup(); } } else { m_oldUpdateList.clear(); } } void Updater::autoUpdatesFinished(PkTransaction::ExitStatus status) { auto notify = new KNotification(QLatin1String("UpdatesComplete")); notify->setComponentName(QLatin1String("apperd")); if (status == PkTransaction::Success) { if (sender()->property("DownloadOnly").toBool()) { // We finished downloading show the updates to the user showUpdatesPopup(); } else { QIcon icon = QIcon::fromTheme(QLatin1String("task-complete")); // use of QSize does the right thing notify->setPixmap(icon.pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); notify->setText(i18n("System update was successful.")); notify->sendEvent(); } } else { QIcon icon = QIcon::fromTheme(QLatin1String("dialog-cancel")); // use of QSize does the right thing notify->setPixmap(icon.pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); notify->setText(i18n("The software update failed.")); notify->sendEvent(); // show updates popup showUpdatesPopup(); } } void Updater::reviewUpdates() { if (m_hasAppletIconified) { QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.kde.ApperUpdaterIcon"), QLatin1String("/"), QLatin1String("org.kde.ApperUpdaterIcon"), QLatin1String("ReviewUpdates")); QDBusMessage reply = QDBusConnection::sessionBus().call(message); if (reply.type() == QDBusMessage::ReplyMessage) { return; } qCWarning(APPER_DAEMON) << "Message did not receive a reply"; } // This must be called from the main thread... KToolInvocation::startServiceByDesktopName(QLatin1String("apper_updates")); } void Updater::installUpdates() { bool ret; ret = updatePackages(m_updateList, false); if (ret) { return; } reviewUpdates(); } void Updater::serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(service) Q_UNUSED(oldOwner) m_hasAppletIconified = !newOwner.isEmpty(); } void Updater::showUpdatesPopup() { m_oldUpdateList = m_updateList; auto notify = new KNotification(QLatin1String("ShowUpdates"), 0, KNotification::Persistent); notify->setComponentName(QLatin1String("apperd")); connect(notify, &KNotification::action1Activated, this, &Updater::reviewUpdates); connect(notify, &KNotification::action2Activated, this, &Updater::installUpdates); notify->setTitle(i18np("There is one new update", "There are %1 new updates", m_updateList.size())); QString text; const QStringList updates = m_updateList; for (const QString &packageId : updates) { const QString packageName = Transaction::packageName(packageId); if (text.length() + packageName.length() > 150) { text.append(QLatin1String(" ...")); break; } else if (!text.isNull()) { text.append(QLatin1String(", ")); } text.append(packageName); } notify->setText(text); QStringList actions; actions << i18n("Review"); if (m_hasAppletIconified) { actions << i18n("Install"); } notify->setActions(actions); // use of QSize does the right thing notify->setPixmap(QIcon::fromTheme(QLatin1String("system-software-update")).pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE)); notify->sendEvent(); } bool Updater::updatePackages(const QStringList &packages, bool downloadOnly, const QString &icon, const QString &msg) { m_oldUpdateList = m_updateList; // Defaults to security auto transaction = new PkTransaction; transaction->setProperty("DownloadOnly", downloadOnly); transaction->enableJobWatcher(true); transaction->updatePackages(packages, downloadOnly); connect(transaction, &PkTransaction::finished, this, &Updater::autoUpdatesFinished); if (!icon.isNull()) { KNotification *notify; if (downloadOnly) { notify = new KNotification(QLatin1String("DownloadingUpdates")); } else { notify = new KNotification(QLatin1String("AutoInstallingUpdates")); } notify->setComponentName(QLatin1String("apperd")); notify->setText(msg); // use of QSize does the right thing notify->setPixmap(QIcon::fromTheme(icon).pixmap(QSize(KPK_ICON_SIZE, KPK_ICON_SIZE))); notify->sendEvent(); } return true; } + +#include "moc_Updater.cpp" diff --git a/apperd/apperd.cpp b/apperd/apperd.cpp index 02d2c5a..7deb287 100644 --- a/apperd/apperd.cpp +++ b/apperd/apperd.cpp @@ -1,55 +1,51 @@ /*************************************************************************** * 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 "apperd.h" #include "ApperdThread.h" -#include #include Q_LOGGING_CATEGORY(APPER_DAEMON, "apper.daemon") -K_PLUGIN_FACTORY(ApperFactory, registerPlugin();) -K_EXPORT_PLUGIN(ApperFactory("apperd", "apper")) - ApperD::ApperD(QObject *parent, const QList &) : KDEDModule(parent) { // m_thread = new QThread(this); m_apperThread = new ApperdThread; // m_apperThread->moveToThread(m_thread); // m_thread->start(); // Make all our init code run on the thread since // the DBus calls were made blocking QTimer::singleShot(0, m_apperThread, SLOT(init())); } ApperD::~ApperD() { // delete the apper thread code, don't use delete later since it has moved // to the stopped thread m_apperThread->deleteLater(); // m_thread->quit(); // m_thread->wait(); // delete m_thread; } -#include "apperd.moc" +#include "moc_apperd.cpp" diff --git a/apperd/apperd.h b/apperd/apperd.h index 3ba0ec2..30b6f23 100644 --- a/apperd/apperd.h +++ b/apperd/apperd.h @@ -1,42 +1,45 @@ /*************************************************************************** * 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 APPERD_H #define APPERD_H #include +#include #include class ApperdThread; class ApperD : public KDEDModule { Q_OBJECT public: ApperD(QObject *parent, const QList&); ~ApperD(); private: QThread *m_thread; ApperdThread *m_apperThread; }; +K_PLUGIN_FACTORY(ApperFactory, registerPlugin();) + #endif diff --git a/libapper/ApplicationSortFilterModel.cpp b/libapper/ApplicationSortFilterModel.cpp index 7e46acc..0c5549f 100644 --- a/libapper/ApplicationSortFilterModel.cpp +++ b/libapper/ApplicationSortFilterModel.cpp @@ -1,104 +1,106 @@ /*************************************************************************** * Copyright (C) 2012 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 "ApplicationSortFilterModel.h" #include "PackageModel.h" //#include ApplicationSortFilterModel::ApplicationSortFilterModel(QObject *parent) : QSortFilterProxyModel(parent), m_info(Transaction::InfoUnknown), m_applicationsOnly(false) { setDynamicSortFilter(true); setSortCaseSensitivity(Qt::CaseInsensitive); setSortRole(PackageModel::SortRole); } PackageModel *ApplicationSortFilterModel::sourcePkgModel() const { return qobject_cast(sourceModel()); } void ApplicationSortFilterModel::setSourcePkgModel(PackageModel *packageModel) { setSourceModel(packageModel); } Transaction::Info ApplicationSortFilterModel::infoFilter() const { return m_info; } bool ApplicationSortFilterModel::applicationFilter() const { return m_applicationsOnly; } void ApplicationSortFilterModel::setInfoFilter(Transaction::Info info) { m_info = info; invalidate(); } void ApplicationSortFilterModel::setApplicationFilter(bool enable) { m_applicationsOnly = enable; invalidate(); } bool ApplicationSortFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { QModelIndex index = sourceModel()->index(source_row, 0, source_parent); // If we are filtering by Info check if the info matches if (m_info != Transaction::InfoUnknown && m_info != index.data(PackageModel::InfoRole).value()) { return false; } // If we are filtering by Applications check if it is an application if (m_applicationsOnly && index.data(PackageModel::IsPackageRole).toBool()) { return false; } // Return true if no filter was applied return true; } bool ApplicationSortFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool leftIsPackage = left.data(PackageModel::IsPackageRole).toBool(); bool rightIsPackage = left.data(PackageModel::IsPackageRole).toBool(); if (leftIsPackage != rightIsPackage) { // If the right item is a package the left should move right return rightIsPackage; } return QSortFilterProxyModel::lessThan(left, right); } void ApplicationSortFilterModel::sortNow() { sort(0); } + +#include "moc_ApplicationSortFilterModel.cpp" diff --git a/libapper/ApplicationSortFilterModel.h b/libapper/ApplicationSortFilterModel.h index 2004e70..b3fa6fe 100644 --- a/libapper/ApplicationSortFilterModel.h +++ b/libapper/ApplicationSortFilterModel.h @@ -1,64 +1,62 @@ /*************************************************************************** - * Copyright (C) 2012 by Daniel Nicoletti * + * Copyright (C) 2012-2018 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 APPLICATIONSORTFILTERMODEL_H #define APPLICATIONSORTFILTERMODEL_H #include #include -//#include - using namespace PackageKit; class PackageModel; class Q_DECL_EXPORT ApplicationSortFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(PackageModel* sourcePkgModel READ sourcePkgModel WRITE setSourcePkgModel NOTIFY changed) Q_PROPERTY(Transaction::Info infoFilter READ infoFilter WRITE setInfoFilter NOTIFY changed) Q_PROPERTY(bool applicationFilter READ applicationFilter WRITE setApplicationFilter NOTIFY changed) public: explicit ApplicationSortFilterModel(QObject *parent = 0); PackageModel* sourcePkgModel() const; void setSourcePkgModel(PackageModel *packageModel); Transaction::Info infoFilter() const; bool applicationFilter() const; public Q_SLOTS: void setInfoFilter(Transaction::Info info); void setApplicationFilter(bool enable); void sortNow(); Q_SIGNALS: void changed(); private: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const; Transaction::Info m_info; bool m_applicationsOnly; }; #endif // APPLICATIONSORTFILTERMODEL_H diff --git a/libapper/PackageModel.cpp b/libapper/PackageModel.cpp index f343946..1ff2a04 100644 --- a/libapper/PackageModel.cpp +++ b/libapper/PackageModel.cpp @@ -1,919 +1,921 @@ /*************************************************************************** * Copyright (C) 2008-2018 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 #include #endif #define ICON_SIZE 22 #define OVERLAY_SIZE 16 using namespace PackageKit; Q_DECLARE_LOGGING_CATEGORY(APPER_LIB) PackageModel::PackageModel(QObject *parent) : QAbstractItemModel(parent), m_finished(false), m_checkable(false), m_fetchSizesTransaction(0), m_fetchInstalledVersionsTransaction(0) { m_installedEmblem = PkIcons::getIcon(QLatin1String("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) { 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) { const QString packageName = Transaction::packageName(packageID); applications = AppStreamHelper::instance()->applications(packageName); for (const AppStream::Component &app : applications) { InternalPackage iPackage; iPackage.info = info; iPackage.packageID = packageID; iPackage.pkgName = packageName; iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.isPackage = false; if (app.name().isEmpty()) { iPackage.displayName = packageName; } else { iPackage.displayName = app.name(); } if (app.summary().isEmpty()) { iPackage.summary = summary; } else { iPackage.summary = app.summary(); } const QList icons = app.icons(); for (const AppStream::Icon &icon : icons) { if (icon.url().isEmpty()) { iPackage.icon = icon.name(); } else { iPackage.icon = icon.url().toLocalFile(); } break; } 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.pkgName = Transaction::packageName(packageID); iPackage.displayName = iPackage.pkgName; iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.summary = summary; #ifdef HAVE_APPSTREAM iPackage.icon = AppStreamHelper::instance()->genericIcon(iPackage.pkgName); if (m_checkable) { // in case of updates model only check if it's an app applications = AppStreamHelper::instance()->applications(iPackage.pkgName); if (!applications.isEmpty()) { iPackage.isPackage = false; } } #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(QLatin1String("/"))) { 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 package.pkgName; 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::checkAll() { m_checkedPackages.clear(); for (const InternalPackage &package : qAsConst(m_packages)) { checkPackage(package, false); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); emit changed(!m_checkedPackages.isEmpty()); } 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() { auto it = m_checkedPackages.begin(); while (it != m_checkedPackages.end()) { const InternalPackage &package = it.value(); bool notFound = true; for (const InternalPackage &iPackage : qAsConst(m_packages)) { if (iPackage.packageID == package.packageID) { notFound = false; break; } } if (notFound) { // Uncheck the package If it's not in the model m_checkedPackages.erase(it); uncheckPackageLogic(package.packageID); } else { ++it; } } } bool PackageModel::checkable() const { return m_checkable; } void PackageModel::uncheckInstalledPackages() { auto it = m_checkedPackages.begin(); while (it != m_checkedPackages.end()) { const InternalPackage &package = it.value(); if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { const QString pkgId = it.key(); it = m_checkedPackages.erase(it); uncheckPackageLogic(pkgId, true); } else { ++it; } } } void PackageModel::uncheckAvailablePackages() { auto it = m_checkedPackages.begin(); while (it != m_checkedPackages.end()) { const InternalPackage &package = it.value(); if (package.info == Transaction::InfoAvailable || package.info == Transaction::InfoCollectionAvailable) { const QString pkgId = it.key(); it = m_checkedPackages.erase(it); uncheckPackageLogic(pkgId, true); } else { ++it; } } } void PackageModel::finished() { auto 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.. disconnect(trans, &Transaction::finished, this, &PackageModel::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; for (const InternalPackage &p : qAsConst(m_packages)) { pkgs << p.packageID; } if (!pkgs.isEmpty()) { m_fetchSizesTransaction = Daemon::getDetails(pkgs); connect(m_fetchSizesTransaction, &Transaction::details, this, &PackageModel::updateSize); connect(m_fetchSizesTransaction, &Transaction::finished, this, &PackageModel::fetchSizesFinished); } } void PackageModel::fetchSizesFinished() { auto trans = qobject_cast(sender()); if (trans) { // When pkd dies this method is called twice // pk-qt2 bug.. disconnect(trans, &Transaction::finished, this, &PackageModel::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; for (const InternalPackage &p : qAsConst(m_packages)) { pkgs << p.pkgName; } if (!pkgs.isEmpty()) { m_fetchInstalledVersionsTransaction = Daemon::resolve(pkgs, Transaction::FilterInstalled);; connect(m_fetchInstalledVersionsTransaction, &Transaction::package, this, &PackageModel::updateCurrentVersion); connect(m_fetchInstalledVersionsTransaction, &Transaction::finished, this, &PackageModel::fetchCurrentVersionsFinished); } } void PackageModel::fetchCurrentVersionsFinished() { auto trans = qobject_cast(sender()); if (trans) { // When pkd dies this method is called twice // pk-qt2 bug.. disconnect(trans, &Transaction::finished, this, &PackageModel::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) == m_packages[i].pkgName && 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, &Transaction::package, this, &PackageModel::addSelectedPackage); } else { connect(m_getUpdatesTransaction, &Transaction::package, this, &PackageModel::addNotSelectedPackage); } // 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, &Transaction::finished, this, &PackageModel::fetchSizes); if (fetchCurrentVersions) { connect(m_getUpdatesTransaction, &Transaction::finished, this, &PackageModel::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 { for (const InternalPackage &package : qAsConst(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; for (const InternalPackage &package : qAsConst(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::uncheckAll() { auto it = m_checkedPackages.begin(); while (it != m_checkedPackages.end()) { const QString pkgId = it.key(); it = m_checkedPackages.erase(it); uncheckPackageLogic(pkgId, true, false); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); emit changed(!m_checkedPackages.isEmpty()); } void PackageModel::uncheckPackageDefault(const QString &packageID) { uncheckPackage(packageID); } void PackageModel::uncheckPackage(const QString &packageID, bool forceEmitUnchecked, bool emitDataChanged) { auto it = m_checkedPackages.find(packageID); if (it != m_checkedPackages.end()) { m_checkedPackages.erase(it); uncheckPackageLogic(packageID, forceEmitUnchecked, emitDataChanged); } } void PackageModel::uncheckPackageLogic(const QString &packageID, bool forceEmitUnchecked, bool emitDataChanged) { 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 { return m_checkedPackages.contains(pid); } void PackageModel::setAllChecked(bool checked) { if (checked) { checkAll(); } else { uncheckAll(); } } QStringList PackageModel::selectedPackagesToInstall() const { QStringList list; for (const InternalPackage &package : qAsConst(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; for (const InternalPackage &package : qAsConst(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; for (const InternalPackage &package : qAsConst(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; for (const InternalPackage &package : qAsConst(m_packages)) { list << package.packageID; } return list; } unsigned long PackageModel::downloadSize() const { unsigned long size = 0; for (const InternalPackage &package : qAsConst(m_checkedPackages)) { size += package.size; } return size; } bool PackageModel::allSelected() const { for (const InternalPackage &package : qAsConst(m_packages)) { if (!containsChecked(package.packageID)) { return false; } } return true; } void PackageModel::setCheckable(bool checkable) { m_checkable = checkable; } + +#include "moc_PackageModel.cpp"