diff options
| author | Aleix Pol <aleixpol@kde.org> | 2015-11-06 15:21:53 (GMT) |
|---|---|---|
| committer | Aleix Pol <aleixpol@kde.org> | 2015-11-06 15:21:53 (GMT) |
| commit | c56fba86f6850effca3c146f75e66b0154ad5994 (patch) | |
| tree | ec48fb16d33797790752c8f47d6dc7635cf974d3 | |
| parent | 4d83be1a3faa1672deb93d3a8731906cf27cdf2b (diff) | |
Preparation for the split
Move the required classes within libMuonApt into muon
| -rw-r--r-- | muon/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | muon/DetailsTabs/TechnicalDetailsTab.cpp | 2 | ||||
| -rw-r--r-- | muon/FilterWidget/ArchitectureFilter.cpp | 2 | ||||
| -rw-r--r-- | muon/FilterWidget/CategoryFilter.cpp | 2 | ||||
| -rw-r--r-- | muon/FilterWidget/StatusFilter.cpp | 2 | ||||
| -rw-r--r-- | muon/MainWindow.cpp | 4 | ||||
| -rw-r--r-- | muon/ManagerWidget.cpp | 2 | ||||
| -rw-r--r-- | muon/PackageModel/PackageDelegate.cpp | 2 | ||||
| -rw-r--r-- | muon/PackageModel/PackageWidget.cpp | 2 | ||||
| -rw-r--r-- | muon/TransactionWidget.cpp | 2 | ||||
| -rw-r--r-- | muon/muonapt/ChangesDialog.cpp | 118 | ||||
| -rw-r--r-- | muon/muonapt/ChangesDialog.h | 45 | ||||
| -rw-r--r-- | muon/muonapt/HistoryView/HistoryProxyModel.cpp | 87 | ||||
| -rw-r--r-- | muon/muonapt/HistoryView/HistoryProxyModel.h | 52 | ||||
| -rw-r--r-- | muon/muonapt/HistoryView/HistoryView.cpp | 233 | ||||
| -rw-r--r-- | muon/muonapt/HistoryView/HistoryView.h | 79 | ||||
| -rw-r--r-- | muon/muonapt/MuonStrings.cpp | 337 | ||||
| -rw-r--r-- | muon/muonapt/MuonStrings.h | 64 | ||||
| -rw-r--r-- | muon/muonapt/QAptActions.cpp | 535 | ||||
| -rw-r--r-- | muon/muonapt/QAptActions.h | 110 |
20 files changed, 1682 insertions, 12 deletions
diff --git a/muon/CMakeLists.txt b/muon/CMakeLists.txt index 0e67ae9..b321bb1 100644 --- a/muon/CMakeLists.txt +++ b/muon/CMakeLists.txt @@ -33,6 +33,15 @@ set(muon_SRCS config/ManagerSettingsDialog.cpp config/GeneralSettingsPage.cpp settings/SettingsPageBase.cpp + + muonapt/ChangesDialog.cpp + muonapt/MuonStrings.cpp + muonapt/QAptActions.cpp + muonapt/HistoryView/HistoryView.h + muonapt/HistoryView/HistoryProxyModel.h + muonapt/HistoryView/HistoryView.cpp + muonapt/HistoryView/HistoryProxyModel.cpp + ) kconfig_add_kcfg_files(muon_SRCS GENERATE_MOC config/MuonSettings.kcfgc) @@ -40,8 +49,9 @@ install(FILES config/muon.kcfg DESTINATION ${KCFG_INSTALL_DIR}) add_executable(muon ${muon_SRCS}) -target_link_libraries(muon MuonApt - DebconfKDE::Main +target_compile_definitions(muon PRIVATE -DCMAKE_INSTALL_FULL_LIBEXECDIR_KF5=\"${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}\") + +target_link_libraries(muon DebconfKDE::Main KF5::KIOWidgets KF5::KDELibs4Support KF5::DBusAddons diff --git a/muon/DetailsTabs/TechnicalDetailsTab.cpp b/muon/DetailsTabs/TechnicalDetailsTab.cpp index 9b38b27..e387cb8 100644 --- a/muon/DetailsTabs/TechnicalDetailsTab.cpp +++ b/muon/DetailsTabs/TechnicalDetailsTab.cpp @@ -37,7 +37,7 @@ #include <QApt/Package> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" TechnicalDetailsTab::TechnicalDetailsTab(QWidget *parent) : DetailsTab(parent) diff --git a/muon/FilterWidget/ArchitectureFilter.cpp b/muon/FilterWidget/ArchitectureFilter.cpp index 84d3ec5..9e7bad0 100644 --- a/muon/FilterWidget/ArchitectureFilter.cpp +++ b/muon/FilterWidget/ArchitectureFilter.cpp @@ -27,7 +27,7 @@ #include <QApt/Backend> // Libmuon includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" ArchitectureFilter::ArchitectureFilter(QObject *parent, QApt::Backend *backend) : FilterModel(parent) diff --git a/muon/FilterWidget/CategoryFilter.cpp b/muon/FilterWidget/CategoryFilter.cpp index 76dbb7d..8971e1e 100644 --- a/muon/FilterWidget/CategoryFilter.cpp +++ b/muon/FilterWidget/CategoryFilter.cpp @@ -30,7 +30,7 @@ #include <QApt/Backend> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" CategoryFilter::CategoryFilter(QObject *parent, QApt::Backend *backend) : FilterModel(parent) diff --git a/muon/FilterWidget/StatusFilter.cpp b/muon/FilterWidget/StatusFilter.cpp index 28d86c1..4989a5b 100644 --- a/muon/FilterWidget/StatusFilter.cpp +++ b/muon/FilterWidget/StatusFilter.cpp @@ -27,7 +27,7 @@ #include <QApt/Package> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" StatusFilter::StatusFilter(QObject *parent) : FilterModel(parent) diff --git a/muon/MainWindow.cpp b/muon/MainWindow.cpp index 4427f34..de068d8 100644 --- a/muon/MainWindow.cpp +++ b/muon/MainWindow.cpp @@ -45,7 +45,7 @@ #include <QApt/Transaction> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" #include "TransactionWidget.h" #include "FilterWidget/FilterWidget.h" #include "ManagerWidget.h" @@ -53,7 +53,7 @@ #include "MuonSettings.h" #include "StatusWidget.h" #include "config/ManagerSettingsDialog.h" -#include "../libmuonapt/QAptActions.h" +#include "muonapt/QAptActions.h" MainWindow::MainWindow() : KXmlGuiWindow() diff --git a/muon/ManagerWidget.cpp b/muon/ManagerWidget.cpp index f4c0004..930c4af 100644 --- a/muon/ManagerWidget.cpp +++ b/muon/ManagerWidget.cpp @@ -35,7 +35,7 @@ #include <QApt/Backend> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" #include "DetailsWidget.h" #include "PackageModel/PackageModel.h" #include "PackageModel/PackageProxyModel.h" diff --git a/muon/PackageModel/PackageDelegate.cpp b/muon/PackageModel/PackageDelegate.cpp index fbbe4d9..f39cd78 100644 --- a/muon/PackageModel/PackageDelegate.cpp +++ b/muon/PackageModel/PackageDelegate.cpp @@ -29,7 +29,7 @@ #include <KIconLoader> // Own -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" #include "PackageModel.h" PackageDelegate::PackageDelegate(QObject *parent) diff --git a/muon/PackageModel/PackageWidget.cpp b/muon/PackageModel/PackageWidget.cpp index 335c8d1..bf10d14 100644 --- a/muon/PackageModel/PackageWidget.cpp +++ b/muon/PackageModel/PackageWidget.cpp @@ -48,7 +48,7 @@ #include <QApt/MarkingErrorInfo> // Own includes -#include "../libmuonapt/ChangesDialog.h" +#include "muonapt/ChangesDialog.h" #include "DetailsWidget.h" #include "MuonSettings.h" #include "PackageModel.h" diff --git a/muon/TransactionWidget.cpp b/muon/TransactionWidget.cpp index 556fa8f..fd25646 100644 --- a/muon/TransactionWidget.cpp +++ b/muon/TransactionWidget.cpp @@ -41,7 +41,7 @@ #include <DebconfGui.h> // Own includes -#include "../libmuonapt/MuonStrings.h" +#include "muonapt/MuonStrings.h" #include "DownloadModel/DownloadDelegate.h" #include "DownloadModel/DownloadModel.h" diff --git a/muon/muonapt/ChangesDialog.cpp b/muon/muonapt/ChangesDialog.cpp new file mode 100644 index 0000000..8bfe5a4 --- /dev/null +++ b/muon/muonapt/ChangesDialog.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright © 2011 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "ChangesDialog.h" + +// Qt includes +#include <QtWidgets/QLabel> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QTreeView> +#include <QtWidgets/QVBoxLayout> + +// KDE includes +#include <KLocalizedString> +#include <KStandardGuiItem> + +// Own includes +#include "muonapt/MuonStrings.h" + +ChangesDialog::ChangesDialog(QWidget *parent, const QApt::StateChanges &changes) + : QDialog(parent) +{ + setWindowTitle(i18nc("@title:window", "Confirm Additional Changes")); + QVBoxLayout *layout = new QVBoxLayout(this); + setLayout(layout); + + QLabel *headerLabel = new QLabel(this); + headerLabel->setText(i18nc("@info", "<h2>Mark additional changes?</h2>")); + + int count = countChanges(changes); + QLabel *label = new QLabel(this); + label->setText(i18np("This action requires a change to another package:", + "This action requires changes to other packages:", + count)); + + QTreeView *packageView = new QTreeView(this); + packageView->setHeaderHidden(true); + packageView->setRootIsDecorated(false); + + QWidget *bottomBox = new QWidget(this); + QHBoxLayout *bottomLayout = new QHBoxLayout(bottomBox); + bottomLayout->setSpacing(0); + bottomLayout->setMargin(0); + bottomBox->setLayout(bottomLayout); + + QWidget *bottomSpacer = new QWidget(bottomBox); + bottomSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + + QPushButton *okButton = new QPushButton(bottomBox); + KGuiItem okItem = KStandardGuiItem::ok(); + okButton->setText(okItem.text()); + okButton->setIcon(okItem.icon()); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + + QPushButton *cancelButton = new QPushButton(bottomBox); + KGuiItem cancelItem = KStandardGuiItem::cancel(); + cancelButton->setText(cancelItem.text()); + cancelButton->setIcon(cancelItem.icon()); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + bottomLayout->addWidget(bottomSpacer); + bottomLayout->addWidget(okButton); + bottomLayout->addWidget(cancelButton); + + m_model = new QStandardItemModel(this); + packageView->setModel(m_model); + addPackages(changes); + packageView->expandAll(); + packageView->setEditTriggers(QAbstractItemView::NoEditTriggers); + + layout->addWidget(headerLabel); + layout->addWidget(label); + layout->addWidget(packageView); + layout->addWidget(bottomBox); +} + +void ChangesDialog::addPackages(const QApt::StateChanges &changes) +{ + for (auto i = changes.constBegin(); i != changes.constEnd(); ++i) { + QStandardItem *root = new QStandardItem; + root->setText(MuonStrings::global()->packageStateName(i.key())); + + QFont font = root->font(); + font.setBold(true); + root->setFont(font); + + Q_FOREACH (QApt::Package *package, *i) { + root->appendRow(new QStandardItem(QIcon::fromTheme("muon"), package->name())); + } + + m_model->appendRow(root); + } +} + +int ChangesDialog::countChanges(const QApt::StateChanges &changes) +{ + int count = 0; + foreach (const QApt::PackageList& pkgs, changes) { + count += pkgs.size(); + } + return count; +} diff --git a/muon/muonapt/ChangesDialog.h b/muon/muonapt/ChangesDialog.h new file mode 100644 index 0000000..ed17c46 --- /dev/null +++ b/muon/muonapt/ChangesDialog.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright © 2011 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef CHANGESDIALOG_H +#define CHANGESDIALOG_H + +// Qt includes +#include <QStandardItemModel> +#include <QDialog> + +// QApt includes +#include <QApt/Package> + +class QStandardItemModel; + +class ChangesDialog : public QDialog +{ +public: + ChangesDialog(QWidget *parent, const QApt::StateChanges &changes); + +private: + QStandardItemModel *m_model; + + void addPackages(const QApt::StateChanges &changes); + int countChanges(const QApt::StateChanges &changes); +}; + +#endif // CHANGESDIALOG_H diff --git a/muon/muonapt/HistoryView/HistoryProxyModel.cpp b/muon/muonapt/HistoryView/HistoryProxyModel.cpp new file mode 100644 index 0000000..96f9fac --- /dev/null +++ b/muon/muonapt/HistoryView/HistoryProxyModel.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "HistoryProxyModel.h" + +#include <QStandardItemModel> +#include <QStandardItem> + +HistoryProxyModel::HistoryProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) + , m_stateFilter((QApt::Package::State)0) +{ +} + +HistoryProxyModel::~HistoryProxyModel() +{ +} + +void HistoryProxyModel::search(const QString &searchText) +{ + m_searchText = searchText; + invalidate(); +} + +void HistoryProxyModel::setStateFilter(QApt::Package::State state) +{ + m_stateFilter = state; + invalidate(); +} + +bool HistoryProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); + for(int i = 0 ; i < sourceModel()->rowCount(sourceIndex); i++) { + if (filterAcceptsRow(i, sourceIndex)) { + return true; + } + } + + //Our "main"-method + QStandardItem *item = static_cast<QStandardItemModel *>(sourceModel())->itemFromIndex(sourceModel()->index(sourceRow, 0, sourceParent)); + + if (!item) { + return false; + } + + if (!m_stateFilter == 0) { + if ((bool)(item->data(HistoryActionRole).toInt() & m_stateFilter) == false) { + return false; + } + } + + if (!m_searchText.isEmpty()) { + if ((bool)(item->data(Qt::DisplayRole).toString().contains(m_searchText)) == false) { + return false; + } + } + + return true; +} + +bool HistoryProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + QStandardItemModel *parentModel = static_cast<QStandardItemModel *>(sourceModel()); + + QStandardItem *leftItem = parentModel->itemFromIndex(left); + QStandardItem *rightItem = parentModel->itemFromIndex(right); + + return (leftItem->data(HistoryDateRole).toDateTime() > rightItem->data(HistoryDateRole).toDateTime()); +} diff --git a/muon/muonapt/HistoryView/HistoryProxyModel.h b/muon/muonapt/HistoryView/HistoryProxyModel.h new file mode 100644 index 0000000..a5fc1e7 --- /dev/null +++ b/muon/muonapt/HistoryView/HistoryProxyModel.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef HISTORYPROXYMODEL_H +#define HISTORYPROXYMODEL_H + +#include <QSortFilterProxyModel> + +#include <QApt/Package> + +class HistoryProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + enum { + HistoryDateRole = Qt::UserRole + 1, + HistoryActionRole = Qt::UserRole + 2 + }; + HistoryProxyModel(QObject *parent); + ~HistoryProxyModel(); + + void search(const QString &searchText); + void setStateFilter(QApt::Package::State state); + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + +protected: + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + +private: + QString m_searchText; + QApt::Package::State m_stateFilter; +}; + +#endif diff --git a/muon/muonapt/HistoryView/HistoryView.cpp b/muon/muonapt/HistoryView/HistoryView.cpp new file mode 100644 index 0000000..33d5e5d --- /dev/null +++ b/muon/muonapt/HistoryView/HistoryView.cpp @@ -0,0 +1,233 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "HistoryView.h" + +#include <QtCore/QTimer> +#include <QtWidgets/QLabel> +#include <QListView> +#include <QtWidgets/QTreeView> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QComboBox> +#include <QStandardItemModel> + +#include <KLocalizedString> + +#include <QApt/History> + +#include "HistoryProxyModel.h" + +HistoryView::HistoryView(QWidget *parent) + : QWidget(parent) +{ + setLayout(new QVBoxLayout(this)); + m_history = new QApt::History(this); + + QWidget *headerWidget = new QWidget(this); + QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget); + + QLabel *headerLabel = new QLabel(headerWidget); + headerLabel->setText(xi18nc("@info", "<title>History</title>")); + + QWidget *headerSpacer = new QWidget(headerWidget); + headerSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + m_searchEdit = new QLineEdit(headerWidget); + m_searchEdit->setPlaceholderText(i18nc("@label Line edit click message", "Search")); + m_searchEdit->setClearButtonEnabled(true); + + m_searchTimer = new QTimer(this); + m_searchTimer->setInterval(300); + m_searchTimer->setSingleShot(true); + connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(startSearch())); + connect(m_searchEdit, SIGNAL(textChanged(QString)), m_searchTimer, SLOT(start())); + + m_filterBox = new QComboBox(headerWidget); + m_filterBox->insertItem(AllChangesItem, QIcon::fromTheme("bookmark-new-list"), + i18nc("@item:inlistbox Filters all changes in the history view", + "All changes"), + 0); + m_filterBox->insertItem(InstallationsItem, QIcon::fromTheme("download"), + i18nc("@item:inlistbox Filters installations in the history view", + "Installations"), + QApt::Package::ToInstall); + m_filterBox->insertItem(UpdatesItem, QIcon::fromTheme("system-software-update"), + i18nc("@item:inlistbox Filters updates in the history view", + "Updates"), + QApt::Package::ToUpgrade); + m_filterBox->insertItem(RemovalsItem, QIcon::fromTheme("edit-delete"), + i18nc("@item:inlistbox Filters removals in the history view", + "Removals"), + (QApt::Package::State)(QApt::Package::ToRemove | QApt::Package::ToPurge)); + connect(m_filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setStateFilter(int))); + + headerLayout->addWidget(headerLabel); + headerLayout->addWidget(headerSpacer); + headerLayout->addWidget(m_searchEdit); + headerLayout->addWidget(m_filterBox); + + m_historyModel = new QStandardItemModel(this); + m_historyModel->setColumnCount(1); + m_historyModel->setHeaderData(0, Qt::Horizontal, i18nc("@title:column", "Date")); + m_historyView = new QTreeView(this); + + QIcon itemIcon(QIcon::fromTheme("applications-other")); + + QHash<QString, QString> categoryHash; + + QHash<PastActions, QString> actionHash; + actionHash[InstalledAction] = i18nc("@info:status describes a past-tense action", "Installed"); + actionHash[UpgradedAction] = i18nc("@info:status describes a past-tense action", "Upgraded"); + actionHash[DowngradedAction] = i18nc("@status describes a past-tense action", "Downgraded"); + actionHash[RemovedAction] = i18nc("@status describes a past-tense action", "Removed"); + actionHash[PurgedAction] = i18nc("@status describes a past-tense action", "Purged"); + + Q_FOREACH (const QApt::HistoryItem &item, m_history->historyItems()) { + QDateTime startDateTime = item.startDate(); + QString formattedTime = startDateTime.toString(); + QString category; + + QString date = startDateTime.date().toString(); + if (categoryHash.contains(date)) { + category = categoryHash.value(date); + } else { + category = startDateTime.date().toString(Qt::DefaultLocaleShortDate); + categoryHash[date] = category; + } + + QStandardItem *parentItem = 0; + + if (!m_categoryHash.contains(category)) { + parentItem = new QStandardItem; + parentItem->setEditable(false); + parentItem->setText(category); + parentItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + + m_historyModel->appendRow(parentItem); + m_categoryHash[category] = parentItem; + } else { + parentItem = m_categoryHash.value(category); + } + + foreach (const QString &package, item.installedPackages()) { + QStandardItem *historyItem = new QStandardItem; + historyItem->setEditable(false); + historyItem->setIcon(itemIcon); + + QString action = actionHash.value(InstalledAction); + QString text = i18nc("@item example: muon installed at 16:00", "%1 %2 at %3", + package, action, formattedTime); + historyItem->setText(text); + historyItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + historyItem->setData(QApt::Package::ToInstall, HistoryProxyModel::HistoryActionRole); + + parentItem->appendRow(historyItem); + } + + foreach (const QString &package, item.upgradedPackages()) { + QStandardItem *historyItem = new QStandardItem; + historyItem->setEditable(false); + historyItem->setIcon(itemIcon); + + QString action = actionHash.value(UpgradedAction); + QString text = i18nc("@item example: muon installed at 16:00", "%1 %2 at %3", + package, action, formattedTime); + historyItem->setText(text); + historyItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + historyItem->setData(QApt::Package::ToUpgrade, HistoryProxyModel::HistoryActionRole); + + parentItem->appendRow(historyItem); + } + + foreach (const QString &package, item.downgradedPackages()) { + QStandardItem *historyItem = new QStandardItem; + historyItem->setEditable(false); + historyItem->setIcon(itemIcon); + + QString action = actionHash.value(DowngradedAction); + QString text = i18nc("@item example: muon installed at 16:00", "%1 %2 at %3", + package, action, formattedTime); + historyItem->setText(text); + historyItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + historyItem->setData(QApt::Package::ToDowngrade, HistoryProxyModel::HistoryActionRole); + + parentItem->appendRow(historyItem); + } + + foreach (const QString &package, item.removedPackages()) { + QStandardItem *historyItem = new QStandardItem; + historyItem->setEditable(false); + historyItem->setIcon(itemIcon); + + QString action = actionHash.value(RemovedAction); + QString text = i18nc("@item example: muon installed at 16:00", "%1 %2 at %3", + package, action, formattedTime); + historyItem->setText(text); + historyItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + historyItem->setData(QApt::Package::ToRemove, HistoryProxyModel::HistoryActionRole); + + parentItem->appendRow(historyItem); + } + + foreach (const QString &package, item.purgedPackages()) { + QStandardItem *historyItem = new QStandardItem; + historyItem->setEditable(false); + historyItem->setIcon(itemIcon); + + QString action = actionHash.value(PurgedAction); + QString text = i18nc("@item example: muon installed at 16:00", "%1 %2 at %3", + package, action, formattedTime); + historyItem->setText(text); + historyItem->setData(startDateTime, HistoryProxyModel::HistoryDateRole); + historyItem->setData(QApt::Package::ToPurge, HistoryProxyModel::HistoryActionRole); + + parentItem->appendRow(historyItem); + } + } + + m_historyView->setMouseTracking(true); + m_historyView->setVerticalScrollMode(QListView::ScrollPerPixel); + + m_proxyModel = new HistoryProxyModel(this); + m_proxyModel->setSourceModel(m_historyModel); + m_proxyModel->sort(0); + + m_historyView->setModel(m_proxyModel); + + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); +} + +QSize HistoryView::sizeHint() const +{ + return QWidget::sizeHint().expandedTo(QSize(500, 500)); +} + +void HistoryView::setStateFilter(int index) +{ + QApt::Package::State state = (QApt::Package::State)m_filterBox->itemData(index).toInt(); + m_proxyModel->setStateFilter(state); +} + +void HistoryView::startSearch() +{ + m_proxyModel->search(m_searchEdit->text()); +} + diff --git a/muon/muonapt/HistoryView/HistoryView.h b/muon/muonapt/HistoryView/HistoryView.h new file mode 100644 index 0000000..f63b85b --- /dev/null +++ b/muon/muonapt/HistoryView/HistoryView.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef HISTORYVIEW_H +#define HISTORYVIEW_H + +#include <QtCore/QHash> + +#include <QWidget> + +class QStandardItem; +class QStandardItemModel; +class QTimer; +class QTreeView; +class QLineEdit; +class QComboBox; + +namespace QApt { + class History; +} + +class HistoryProxyModel; + +class HistoryView : public QWidget +{ + Q_OBJECT +public: + enum ComboItems { + AllChangesItem = 0, + InstallationsItem = 1, + UpdatesItem = 2, + RemovalsItem = 3 + }; + enum PastActions { + InvalidAction = 0, + InstalledAction = 1, + UpgradedAction = 2, + DowngradedAction = 3, + RemovedAction = 4, + PurgedAction = 5 + }; + HistoryView(QWidget *parent); + + QSize sizeHint() const; + +private: + QApt::History *m_history; + QStandardItemModel *m_historyModel; + HistoryProxyModel *m_proxyModel; + QHash<QString, QStandardItem *> m_categoryHash; + + QLineEdit *m_searchEdit; + QTimer *m_searchTimer; + QComboBox *m_filterBox; + QTreeView *m_historyView; + +private Q_SLOTS: + void setStateFilter(int index); + void startSearch(); +}; + +#endif diff --git a/muon/muonapt/MuonStrings.cpp b/muon/muonapt/MuonStrings.cpp new file mode 100644 index 0000000..1138610 --- /dev/null +++ b/muon/muonapt/MuonStrings.cpp @@ -0,0 +1,337 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "MuonStrings.h" + +#include <KLocalizedString> +#include <QDebug> + +#include <QApt/Transaction> + +Q_GLOBAL_STATIC_WITH_ARGS(MuonStrings, globalMuonStrings, (0)) + +using namespace QApt; + +MuonStrings *MuonStrings::global() +{ + return globalMuonStrings; +} + +MuonStrings::MuonStrings(QObject *parent) + : QObject(parent) + , m_groupHash(groupHash()) + , m_stateHash(stateHash()) + , m_archHash(archHash()) +{ +} + +QHash<QString, QString> MuonStrings::groupHash() +{ + QHash<QString, QString> hash; + hash["admin"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"admin\"", + "System Administration"); + hash["base"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"base\"", + "Base System"); + hash["cli-mono"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"cli-mono\"", + "Mono/CLI Infrastructure"); + hash["comm"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"comm\"", + "Communication"); + hash["database"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"database\"", + "Databases"); + hash["devel"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"devel\"", + "Development"); + hash["doc"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"doc\"", + "Documentation"); + hash["debug"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"debug\"", + "Debug"); + hash["editors"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"editors\"", + "Editors"); + hash["electronics"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"electronics\"", + "Electronics"); + hash["embedded"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"embedded\"", + "Embedded Devices"); + hash["fonts"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"fonts\"", + "Fonts"); + hash["games"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"games\"", + "Games and Amusement"); + hash["gnome"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"gnome\"", + "GNOME Desktop Environment"); + hash["graphics"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"graphics\"", + "Graphics"); + hash["gnu-r"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"gnu-r\"", + "GNU R Statistical System"); + hash["gnustep"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"gnustep\"", + "Gnustep Desktop Environment"); + hash["hamradio"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"hamradio\"", + "Amateur Radio"); + hash["haskell"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"haskell\"", + "Haskell Programming Language"); + hash["httpd"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"httpd\"", + "Web Servers"); + hash["interpreters"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"interpreters\"", + "Interpreted Computer Languages"); + hash["java"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"java\"", + "Java Programming Language"); + hash["kde"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"kde\"", + "KDE Software Compilation"); + hash["kernel"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"kernel\"", + "Kernel and Modules"); + hash["libdevel"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"libdevel\"", + "Libraries - Development"); + hash["libs"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"libs\"", + "Libraries"); + hash["lisp"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"lisp\"", + "Lisp Programming Language"); + hash["localization"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"localization\"", + "Localization"); + hash["mail"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"mail\"", + "Email"); + hash["math"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"math\"", + "Mathematics"); + hash["misc"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"misc\"", + "Miscellaneous - Text-based"); + hash["net"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"net\"", + "Networking"); + hash["news"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"news\"", + "Newsgroups"); + hash["ocaml"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"ocaml\"", + "OCaml Programming Language"); + hash["oldlibs"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"oldlibs\"", + "Libraries - Old"); + hash["otherosfs"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"otherosfs\"", + "Cross Platform"); + hash["perl"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"perl\"", + "Perl Programming Language"); + hash["php"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"php\"", + "PHP Programming Language"); + hash["python"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"python\"", + "Python Programming Language"); + hash["ruby"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"ruby\"", + "Ruby Programming Language"); + hash["science"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"science\"", + "Science"); + hash["shells"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"shells\"", + "Shells"); + hash["sound"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"sound\"", + "Multimedia"); + hash["tex"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"tex\"", + "TeX Authoring"); + hash["text"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"text\"", + "Word Processing"); + hash["utils"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"utils\"", + "Utilities"); + hash["vcs"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"vcs\"", + "Version Control Systems"); + hash["video"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"video\"", + "Video Software"); + hash["web"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"web\"", + "Internet"); + hash["x11"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"x11\"", + "Miscellaneous - Graphical"); + hash["xfce"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"xfce\"", + "Xfce Desktop Environment"); + hash["zope"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"zope\"", + "Zope/Plone Environment"); + hash["unknown"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"unknown\"", + "Unknown"); + hash["alien"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"alien\"", + "Converted from RPM by Alien"); + hash["translations"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"translations\"", + "Internationalization and Localization"); + hash["metapackages"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"metapackages\"", + "Meta Packages"); + hash["non-us"] = i18nc("@item:inlistbox Debian package section \"non-US\", for packages that cannot be shipped in the US", + "Restricted On Export"); + hash["non-free"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"non-free\"", + "Non-free"); + hash["contrib"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"contrib\"", + "Contrib"); + hash["education"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"education\"", + "Education"); + hash["introspection"] = i18nc("@item:inlistbox Human-readable name for the Debian package section \"introspection\"", + "GObject Introspection Data"); + return hash; +} + +QString MuonStrings::groupName(const QString &name) const +{ + QString suffix; + + if (name.contains('/')) { + QStringList split = name.split('/'); + suffix = split.at(1); + + return m_groupHash.value(suffix); + } else { + return m_groupHash.value(name); + } +} + +QString MuonStrings::groupKey(const QString &text) const +{ + return m_groupHash.key(text); +} + +QHash<int, QString> MuonStrings::stateHash() +{ + QHash<int, QString> hash; + hash[Package::ToKeep] = i18nc("@info:status Package state", "No Change"); + hash[Package::ToInstall] = i18nc("@info:status Requested action", "Install"); + hash[Package::NewInstall] = i18nc("@info:status Requested action", "Install"); + hash[Package::ToReInstall] = i18nc("@info:status Requested action", "Reinstall"); + hash[Package::ToUpgrade] = i18nc("@info:status Requested action", "Upgrade"); + hash[Package::ToDowngrade] = i18nc("@info:status Requested action", "Downgrade"); + hash[Package::ToRemove] = i18nc("@info:status Requested action", "Remove"); + hash[Package::Held] = i18nc("@info:status Package state" , "Held"); + hash[Package::Installed] = i18nc("@info:status Package state", "Installed"); + hash[Package::Upgradeable] = i18nc("@info:status Package state", "Upgradeable"); + hash[Package::NowBroken] = i18nc("@info:status Package state", "Broken"); + hash[Package::InstallBroken] = i18nc("@info:status Package state", "Install Broken"); + hash[Package::Orphaned] = i18nc("@info:status Package state", "Orphaned"); + hash[Package::Pinned] = i18nc("@info:status Package state", "Locked"); + hash[Package::New] = i18nc("@info:status Package state", "New in repository"); + hash[Package::ResidualConfig] = i18nc("@info:status Package state", "Residual Configuration"); + hash[Package::NotDownloadable] = i18nc("@info:status Package state", "Not Downloadable"); + hash[Package::ToPurge] = i18nc("@info:status Requested action", "Purge"); + hash[Package::IsImportant] = i18nc("@info:status Package state", "Important for base install"); + hash[Package::OverrideVersion] = i18nc("@info:status Package state", "Version overridden"); + hash[Package::IsAuto] = i18nc("@info:status Package state", "Required by other packages"); + hash[Package::IsGarbage] = i18nc("@info:status Package state", "Installed (auto-removable)"); + hash[Package::NowPolicyBroken] = i18nc("@info:status Package state", "Policy Broken"); + hash[Package::InstallPolicyBroken] = i18nc("@info:status Package state", "Policy Broken"); + hash[Package::NotInstalled] = i18nc("@info:status Package state" , "Not Installed"); + hash[Package::IsPinned] = i18nc("@info:status Package locked at a certain version", + "Locked"); + hash[Package::IsManuallyHeld] = i18nc("@info:status Package state", "Manually held back"); + + return hash; +} + +QString MuonStrings::packageStateName(Package::State state) const +{ + return m_stateHash.value(state); +} + +QString MuonStrings::packageChangeStateName(Package::State state) const +{ + int ns = state & (Package::ToKeep | Package::ToInstall | Package::ToReInstall | Package::NewInstall + | Package::ToUpgrade | Package::ToRemove + | Package::ToPurge | Package::ToDowngrade); + return m_stateHash.value(ns); +} + +QHash<QString, QString> MuonStrings::archHash() +{ + QHash<QString, QString> hash; + hash["all"] = i18nc("@item:inlistbox", "Common"); + hash["i386"] = i18nc("@item:inlistbox CPU architecture", "32-bit"); + hash["amd64"] = i18nc("@item:inlistbox CPU architecture", "64-bit"); + hash["powerpc"] = i18nc("@item:inlistbox PU architecture", "Power PC"); + + return hash; +} + +QString MuonStrings::archString(const QString &arch) const +{ + QString str = m_archHash.value(arch); + + if (str.isEmpty()) + str = arch; + + return str; +} + +QString MuonStrings::errorTitle(ErrorCode error) const +{ + switch (error) { + case InitError: + return i18nc("@title:window", "Initialization Error"); + case LockError: + return i18nc("@title:window", "Unable to Obtain Package System Lock"); + case DiskSpaceError: + return i18nc("@title:window", "Low Disk Space"); + case FetchError: + case CommitError: + return i18nc("@title:window", "Failed to Apply Changes"); + case AuthError: + return i18nc("@title:window", "Authentication error"); + case WorkerDisappeared: + return i18nc("@title:window", "Unexpected Error"); + case UntrustedError: + return i18nc("@title:window", "Untrusted Packages"); + case UnknownError: + default: + return i18nc("@title:window", "Unknown Error"); + } +} + +QString MuonStrings::errorText(ErrorCode error, Transaction *trans) const +{ + QString text; + + switch (error) { + case InitError: + text = i18nc("@label", "The package system could not be initialized, your " + "configuration may be broken."); + break; + case LockError: + text = i18nc("@label", + "Another application seems to be using the package " + "system at this time. You must close all other package " + "managers before you will be able to install or remove " + "any packages."); + break; + case DiskSpaceError: + text = i18nc("@label", + "You do not have enough disk space in the directory " + "at %1 to continue with this operation.", trans->errorDetails()); + break; + case FetchError: + text = i18nc("@label", "Could not download packages"); + break; + case CommitError: + text = i18nc("@label", "An error occurred while applying changes:"); + break; + case AuthError: + text = i18nc("@label", + "This operation cannot continue since proper " + "authorization was not provided"); + break; + case WorkerDisappeared: + text = i18nc("@label", "It appears that the QApt worker has either crashed " + "or disappeared. Please report a bug to the QApt maintainers"); + break; + case UntrustedError: + text = i18ncp("@label", + "The following package has not been verified by its author. " + "Downloading untrusted packages has been disallowed " + "by your current configuration.", + "The following packages have not been verified by " + "their authors. " + "Downloading untrusted packages has " + "been disallowed by your current configuration.", + trans->untrustedPackages().size()); + break; + default: + break; + } + + return text; +} diff --git a/muon/muonapt/MuonStrings.h b/muon/muonapt/MuonStrings.h new file mode 100644 index 0000000..1a0f13d --- /dev/null +++ b/muon/muonapt/MuonStrings.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef MUONSTRINGS_H +#define MUONSTRINGS_H + +#include <QtCore/QHash> + +#include <QApt/Package> + +namespace QApt { + class Transaction; +} + +class MuonStrings : public QObject +{ + Q_OBJECT +public: + explicit MuonStrings(QObject *parent); + + static MuonStrings* global(); + + QString groupName(const QString &name) const; + QString groupKey(const QString &text) const; + + /** @returns the state name for a given @p state, for displaying it to the user */ + QString packageStateName(QApt::Package::State state) const; + + /** @returns the state name for the given @p state changes, for displaying it to the user + * This means, the flags that are related to a state change, like ToInstall, ToUpgrade, etc + */ + QString packageChangeStateName(QApt::Package::State state) const; + QString archString(const QString &arch) const; + QString errorTitle(QApt::ErrorCode error) const; + QString errorText(QApt::ErrorCode error, QApt::Transaction *trans) const; + +private: + const QHash<QString, QString> m_groupHash; + const QHash<int, QString> m_stateHash; + const QHash<QString, QString> m_archHash; + + QHash<QString, QString> groupHash(); + QHash<int, QString> stateHash(); + QHash<QString, QString> archHash(); +}; + +#endif diff --git a/muon/muonapt/QAptActions.cpp b/muon/muonapt/QAptActions.cpp new file mode 100644 index 0000000..12d79cd --- /dev/null +++ b/muon/muonapt/QAptActions.cpp @@ -0,0 +1,535 @@ +/*************************************************************************** + * Copyright © 2012 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "QAptActions.h" +#include "MuonStrings.h" +#include "HistoryView/HistoryView.h" + +// Qt includes +#include <QtCore/QDir> +#include <QtCore/QStringBuilder> +#include <QAction> +#include <QDebug> +#include <QDialog> +#include <QFileDialog> +#include <QStandardPaths> +#include <QDialogButtonBox> +#include <QLayout> +#include <QNetworkConfigurationManager> + +// KDE includes +#include <KActionCollection> +#include <KConfigGroup> +#include <KLocalizedString> +#include <KMessageBox> +#include <KProcess> +#include <KStandardAction> +#include <KSharedConfig> +#include <KXmlGuiWindow> +#include <KWindowConfig> + +// QApt includes +#include <QApt/Backend> +#include <QApt/DebFile> +#include <QApt/Transaction> + +QAptActions::QAptActions() + : QObject(nullptr) + , m_backend(nullptr) + , m_actionsDisabled(false) + , m_mainWindow(nullptr) + , m_reloadWhenEditorFinished(false) + , m_historyDialog(nullptr) + , m_distUpgradeAvailable(false) + , m_config(new QNetworkConfigurationManager(this)) +{ + connect(m_config, &QNetworkConfigurationManager::onlineStateChanged, this, &QAptActions::shouldConnect); +} + +QAptActions* QAptActions::self() +{ + static QPointer<QAptActions> self; + if(!self) { + self = new QAptActions; + } + return self; +} + +void QAptActions::setMainWindow(KXmlGuiWindow* w) +{ + setParent(w); + m_mainWindow = w; + + setupActions(); +} + +KXmlGuiWindow* QAptActions::mainWindow() const +{ + return m_mainWindow; +} + +void QAptActions::setBackend(QApt::Backend* backend) +{ + if(backend == m_backend) + return; + m_backend = backend; + if (!m_backend->init()) + initError(); + + connect(m_backend, SIGNAL(packageChanged()), this, SLOT(setActionsEnabled())); + + setOriginalState(m_backend->currentCacheState()); + + setReloadWhenEditorFinished(true); + // Some actions need an initialized backend to be able to set their enabled state + setActionsEnabled(true); + checkDistUpgrade(); +} + +void QAptActions::setupActions() +{ + QAction* undoAction = KStandardAction::undo(this, SLOT(undo()), actionCollection()); + actionCollection()->addAction("undo", undoAction); + m_actions.append(undoAction); + + QAction* redoAction = KStandardAction::redo(this, SLOT(redo()), actionCollection()); + actionCollection()->addAction("redo", redoAction); + m_actions.append(redoAction); + + QAction* revertAction = actionCollection()->addAction("revert"); + revertAction->setIcon(QIcon::fromTheme("document-revert")); + revertAction->setText(i18nc("@action Reverts all potential changes to the cache", "Unmark All")); + connect(revertAction, SIGNAL(triggered()), this, SLOT(revertChanges())); + m_actions.append(revertAction); + + QAction* softwarePropertiesAction = actionCollection()->addAction("software_properties"); + softwarePropertiesAction->setPriority(QAction::LowPriority); + softwarePropertiesAction->setIcon(QIcon::fromTheme("configure")); + softwarePropertiesAction->setText(i18nc("@action Opens the software sources configuration dialog", "Configure Software Sources")); + connect(softwarePropertiesAction, SIGNAL(triggered()), this, SLOT(runSourcesEditor())); + m_actions.append(softwarePropertiesAction); + + QAction* loadSelectionsAction = actionCollection()->addAction("open_markings"); + loadSelectionsAction->setIcon(QIcon::fromTheme("document-open")); + loadSelectionsAction->setText(i18nc("@action", "Read Markings...")); + connect(loadSelectionsAction, SIGNAL(triggered()), this, SLOT(loadSelections())); + m_actions.append(loadSelectionsAction); + + QAction* saveSelectionsAction = actionCollection()->addAction("save_markings"); + saveSelectionsAction->setIcon(QIcon::fromTheme("document-save-as")); + saveSelectionsAction->setText(i18nc("@action", "Save Markings As...")); + connect(saveSelectionsAction, SIGNAL(triggered()), this, SLOT(saveSelections())); + m_actions.append(saveSelectionsAction); + + QAction* createDownloadListAction = actionCollection()->addAction("save_download_list"); + createDownloadListAction->setPriority(QAction::LowPriority); + createDownloadListAction->setIcon(QIcon::fromTheme("document-save-as")); + createDownloadListAction->setText(i18nc("@action", "Save Package Download List...")); + connect(createDownloadListAction, SIGNAL(triggered()), this, SLOT(createDownloadList())); + m_actions.append(createDownloadListAction); + + QAction* downloadListAction = actionCollection()->addAction("download_from_list"); + downloadListAction->setPriority(QAction::LowPriority); + downloadListAction->setIcon(QIcon::fromTheme("download")); + downloadListAction->setText(i18nc("@action", "Download Packages From List...")); + connect(downloadListAction, SIGNAL(triggered()), this, SLOT(downloadPackagesFromList())); + downloadListAction->setEnabled(isConnected()); + connect(this, SIGNAL(shouldConnect(bool)), downloadListAction, SLOT(setEnabled(bool))); + m_actions.append(downloadListAction); + + QAction* loadArchivesAction = actionCollection()->addAction("load_archives"); + loadArchivesAction->setPriority(QAction::LowPriority); + loadArchivesAction->setIcon(QIcon::fromTheme("document-open")); + loadArchivesAction->setText(i18nc("@action", "Add Downloaded Packages")); + connect(loadArchivesAction, SIGNAL(triggered()), this, SLOT(loadArchives())); + m_actions.append(loadArchivesAction); + + QAction* saveInstalledAction = actionCollection()->addAction("save_package_list"); + saveInstalledAction->setPriority(QAction::LowPriority); + saveInstalledAction->setIcon(QIcon::fromTheme("document-save-as")); + saveInstalledAction->setText(i18nc("@action", "Save Installed Packages List...")); + connect(saveInstalledAction, SIGNAL(triggered()), this, SLOT(saveInstalledPackagesList())); + + QAction* historyAction = actionCollection()->addAction("history"); + historyAction->setPriority(QAction::LowPriority); + historyAction->setIcon(QIcon::fromTheme("view-history")); + historyAction->setText(i18nc("@action::inmenu", "History...")); + actionCollection()->setDefaultShortcut(historyAction, QKeySequence(Qt::CTRL + Qt::Key_H)); + connect(historyAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog())); + + QAction *distUpgradeAction = actionCollection()->addAction("dist-upgrade"); + distUpgradeAction->setIcon(QIcon::fromTheme("system-software-update")); + distUpgradeAction->setText(i18nc("@action", "Upgrade")); + distUpgradeAction->setPriority(QAction::HighPriority); + distUpgradeAction->setWhatsThis(i18nc("Notification when a new version of Kubuntu is available", + "A new version of Kubuntu is available.")); + distUpgradeAction->setEnabled(m_distUpgradeAvailable); + connect(distUpgradeAction, SIGNAL(triggered(bool)), SLOT(launchDistUpgrade())); + + m_actions.append(saveInstalledAction); +} + +void QAptActions::setActionsEnabled(bool enabled) +{ + m_actionsDisabled = !enabled; + + Q_FOREACH (QAction *action, m_actions) { + action->setEnabled(enabled); + } + + if (!enabled || !m_mainWindow || !actionCollection()) + return; + + actionCollection()->action("update")->setEnabled(isConnected() && enabled); + + actionCollection()->action("undo")->setEnabled(m_backend && !m_backend->isUndoStackEmpty()); + actionCollection()->action("redo")->setEnabled(m_backend && !m_backend->isRedoStackEmpty()); + actionCollection()->action("revert")->setEnabled(m_backend && !m_backend->isUndoStackEmpty()); + + actionCollection()->action("save_download_list")->setEnabled(isConnected()); + + bool changesPending = m_backend && m_backend->areChangesMarked(); + actionCollection()->action("save_markings")->setEnabled(changesPending); + actionCollection()->action("save_download_list")->setEnabled(changesPending); + actionCollection()->action("dist-upgrade")->setEnabled(m_distUpgradeAvailable); +} + +bool QAptActions::reloadWhenSourcesEditorFinished() const +{ + return m_reloadWhenEditorFinished; +} + +bool QAptActions::isConnected() const +{ + return m_config->isOnline(); +} + +bool QAptActions::saveSelections() +{ + QString filename = QFileDialog::getSaveFileName(m_mainWindow, i18nc("@title:window", "Save Markings As")); + + if (filename.isEmpty()) { + return false; + } + + if (!m_backend->saveSelections(filename)) { + QString text = xi18nc("@label", "The document could not be saved, as it " + "was not possible to write to " + "<filename>%1</filename>\n\nCheck " + "that you have write access to this file " + "or that enough disk space is available.", + filename); + KMessageBox::error(m_mainWindow, text, QString()); + return false; + } + + return true; +} + +bool QAptActions::saveInstalledPackagesList() +{ + QString filename; + + filename = QFileDialog::getSaveFileName(m_mainWindow, + i18nc("@title:window", "Save Installed Packages List As")); + + if (filename.isEmpty()) { + return false; + } + + if (!m_backend->saveInstalledPackagesList(filename)) { + QString text = xi18nc("@label", "The document could not be saved, as it " + "was not possible to write to " + "<filename>%1</filename>\n\nCheck " + "that you have write access to this file " + "or that enough disk space is available.", + filename); + KMessageBox::error(m_mainWindow, text, QString()); + return false; + } + + return true; +} + +bool QAptActions::createDownloadList() +{ + QString filename; + filename = QFileDialog::getSaveFileName(m_mainWindow, + i18nc("@title:window", "Save Download List As")); + + if (filename.isEmpty()) { + return false; + } + + if (!m_backend->saveDownloadList(filename)) { + QString text = xi18nc("@label", "The document could not be saved, as it " + "was not possible to write to " + "<filename>%1</filename>\n\nCheck " + "that you have write access to this file " + "or that enough disk space is available.", + filename); + KMessageBox::error(m_mainWindow, text, QString()); + return false; + } + + return true; +} + +void QAptActions::downloadPackagesFromList() +{ + QString filename = QFileDialog::getOpenFileName(m_mainWindow, i18nc("@title:window", "Open File")); + + if (filename.isEmpty()) { + return; + } + + QString dirName = filename.left(filename.lastIndexOf('/')); + + setActionsEnabled(false); + QApt::Transaction *trans = m_backend->downloadArchives(filename, dirName % QLatin1String("/packages")); + + if (trans) + emit downloadArchives(trans); +} + +void QAptActions::loadSelections() +{ + QString filename = QFileDialog::getOpenFileName(m_mainWindow, i18nc("@title:window", "Open File")); + + if (filename.isEmpty()) { + return; + } + + m_backend->saveCacheState(); + if (!m_backend->loadSelections(filename)) { + QString text = i18nc("@label", "Could not mark changes. Please make sure " + "that the file is a markings file created by " + "either the Muon Package Manager or the " + "Synaptic Package Manager."); + KMessageBox::error(m_mainWindow, text, QString()); + } +} + +void QAptActions::loadArchives() +{ + QString dirName = QFileDialog::getExistingDirectory(m_mainWindow, + i18nc("@title:window", "Choose a Directory")); + + if (dirName.isEmpty()) { + // User canceled + return; + } + + QDir dir(dirName); + QStringList archiveFiles = dir.entryList(QDir::Files, QDir::Name); + + int successCount = 0; + foreach (const QString &archiveFile, archiveFiles) { + const QApt::DebFile debFile(dirName % '/' % archiveFile); + + if (debFile.isValid()) { + if (m_backend->addArchiveToCache(debFile)) { + successCount++; + } + } + } + + if (successCount) { + QString message = i18ncp("@label", + "%1 package was successfully added to the cache", + "%1 packages were successfully added to the cache", + successCount); + KMessageBox::information(m_mainWindow, message, QString()); + } else { + QString message = i18nc("@label", + "No valid packages could be found in this directory. " + "Please make sure the packages are compatible with your " + "computer and are at the latest version."); + KMessageBox::error(m_mainWindow, message, i18nc("@title:window", + "Packages Could Not be Found")); + } +} + +void QAptActions::undo() +{ + m_backend->undo(); +} + +void QAptActions::redo() +{ + m_backend->redo(); +} + +void QAptActions::revertChanges() +{ + m_backend->restoreCacheState(m_originalState); + emit changesReverted(); +} + +void QAptActions::runSourcesEditor() +{ + KProcess *proc = new KProcess(this); + QStringList arguments; + int winID = m_mainWindow->effectiveWinId(); + + const QString kdesu = QFile::decodeName(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/kdesu"); + const QString editor = QStandardPaths::findExecutable("software-properties-kde"); + + arguments << kdesu << "--" << editor << QStringLiteral("--attach") << QString::number(winID); + if (m_reloadWhenEditorFinished) { + arguments << QStringLiteral("--dont-update"); + } + + proc->setProgram(arguments); + m_mainWindow->find(winID)->setEnabled(false); + proc->start(); + connect(proc, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(sourcesEditorFinished(int))); +} + +void QAptActions::sourcesEditorFinished(int exitStatus) +{ + bool reload = (exitStatus != 0); + m_mainWindow->find(m_mainWindow->effectiveWinId())->setEnabled(true); + if (m_reloadWhenEditorFinished && reload) { + actionCollection()->action("update")->trigger(); + } + + emit sourcesEditorClosed(reload); +} + +KActionCollection* QAptActions::actionCollection() +{ + return m_mainWindow->actionCollection(); +} + +void QAptActions::setOriginalState(QApt::CacheState state) +{ + m_originalState = state; +} + +void QAptActions::setReloadWhenEditorFinished(bool reload) +{ + m_reloadWhenEditorFinished = reload; +} + +void QAptActions::initError() +{ + QString details = m_backend->initErrorMessage(); + + MuonStrings *muonStrings = MuonStrings::global(); + + QString title = muonStrings->errorTitle(QApt::InitError); + QString text = muonStrings->errorText(QApt::InitError, nullptr); + + KMessageBox::detailedError(m_mainWindow, text, details, title); + exit(-1); +} + +void QAptActions::displayTransactionError(QApt::ErrorCode error, QApt::Transaction* trans) +{ + if (error == QApt::Success) + return; + + MuonStrings *muonStrings = MuonStrings::global(); + + QString title = muonStrings->errorTitle(error); + QString text = muonStrings->errorText(error, trans); + + switch (error) { + case QApt::InitError: + case QApt::FetchError: + case QApt::CommitError: + KMessageBox::detailedError(QAptActions::self()->mainWindow(), text, trans->errorDetails(), title); + break; + default: + KMessageBox::error(QAptActions::self()->mainWindow(), text, title); + break; + } +} + +void QAptActions::showHistoryDialog() +{ + if (!m_historyDialog) { + m_historyDialog = new QDialog(mainWindow()); + m_historyDialog->setLayout(new QVBoxLayout(m_historyDialog)); + + KConfigGroup dialogConfig(KSharedConfig::openConfig("muonrc"), "HistoryDialog"); + KWindowConfig::restoreWindowSize(m_historyDialog->windowHandle(), dialogConfig); + + + connect(m_historyDialog, SIGNAL(finished()), SLOT(closeHistoryDialog())); + HistoryView *historyView = new HistoryView(m_historyDialog); + m_historyDialog->layout()->addWidget(historyView); + m_historyDialog->setWindowTitle(i18nc("@title:window", "Package History")); + m_historyDialog->setWindowIcon(QIcon::fromTheme("view-history")); + + QDialogButtonBox* box = new QDialogButtonBox(m_historyDialog); + box->setStandardButtons(QDialogButtonBox::Close); + connect(box, SIGNAL(accepted()), m_historyDialog, SLOT(accept())); + connect(box, SIGNAL(rejected()), m_historyDialog, SLOT(reject())); + m_historyDialog->layout()->addWidget(box); + + m_historyDialog->show(); + } else { + m_historyDialog->raise(); + } +} + +void QAptActions::closeHistoryDialog() +{ + KConfigGroup dialogConfig(KSharedConfig::openConfig("muonrc"), "HistoryDialog"); + KWindowConfig::restoreWindowSize(m_historyDialog->windowHandle(), dialogConfig); + m_historyDialog->deleteLater(); + m_historyDialog = nullptr; +} + +void QAptActions::launchDistUpgrade() +{ + const QString kdesu = QFile::decodeName(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/kdesu"); + QProcess::startDetached(kdesu, {"--", "do-release-upgrade", "-m", "desktop", "-f", "DistUpgradeViewKDE"}); +} + +void QAptActions::checkDistUpgrade() +{ + if(!QFile::exists("/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeFetcherKDE.py")) { + qWarning() << "Couldn't find the /usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeFetcherKDE.py file"; + return; + } + QString checkerFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "libmuon/applicationsbackend/releasechecker"); + if(checkerFile.isEmpty()) { + qWarning() << "Couldn't find the releasechecker script" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + return; + } + + KProcess* checkerProcess = new KProcess(this); + checkerProcess->setProgram(QStringList() << "/usr/bin/python3" << checkerFile); + connect(checkerProcess, SIGNAL(finished(int)), this, SLOT(checkerFinished(int))); + connect(checkerProcess, SIGNAL(finished(int)), checkerProcess, SLOT(deleteLater())); + checkerProcess->start(); +} + +void QAptActions::checkerFinished(int res) +{ + m_distUpgradeAvailable = (res == 0); + if (!m_mainWindow) + return; + actionCollection()->action("dist-upgrade")->setEnabled(m_distUpgradeAvailable); +} diff --git a/muon/muonapt/QAptActions.h b/muon/muonapt/QAptActions.h new file mode 100644 index 0000000..33db6e1 --- /dev/null +++ b/muon/muonapt/QAptActions.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright © 2012 Jonathan Thomas <echidnaman@kubuntu.org> * + * * + * 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) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef QAPTACTIONS_H +#define QAPTACTIONS_H + +#include <QtCore/QObject> +#include <QPointer> + +#include <QApt/Globals> + + +class KXmlGuiWindow; +class KDialog; +class KXmlGuiWindow; +class KActionCollection; +class QAction; +class QDialog; +class QNetworkConfigurationManager; + +namespace QApt { + class Backend; + class Transaction; +} + +class QAptActions : public QObject +{ + Q_OBJECT +public: + static QAptActions* self(); + void setMainWindow(KXmlGuiWindow* w); + KXmlGuiWindow* mainWindow() const; + + bool reloadWhenSourcesEditorFinished() const; + bool isConnected() const; + void setOriginalState(QApt::CacheState state); + void setReloadWhenEditorFinished(bool reload); + void initError(); + void displayTransactionError(QApt::ErrorCode error, QApt::Transaction* trans); + KActionCollection* actionCollection(); + + void setCanExit(bool e) { m_canExit = e; } + bool canExit() const { return m_canExit; } + +signals: + void shouldConnect(bool isConnected); + void changesReverted(); + void sourcesEditorClosed(bool reload); + void downloadArchives(QApt::Transaction *trans); + +public slots: + void setBackend(QApt::Backend *backend); + void setupActions(); + + // KAction slots + bool saveSelections(); + bool saveInstalledPackagesList(); + void loadSelections(); + bool createDownloadList(); + void downloadPackagesFromList(); + void loadArchives(); + void undo(); + void redo(); + void revertChanges(); + void runSourcesEditor(); + void sourcesEditorFinished(int exitStatus); + void showHistoryDialog(); + void setActionsEnabled(bool enabled = true); + +private slots: + void closeHistoryDialog(); + void checkDistUpgrade(); + void launchDistUpgrade(); + void checkerFinished(int res); + +private: + QAptActions(); + + QApt::Backend *m_backend; + QApt::CacheState m_originalState; + bool m_actionsDisabled; + KXmlGuiWindow* m_mainWindow; + bool m_reloadWhenEditorFinished; + + QPointer<QDialog> m_historyDialog; + QList<QAction *> m_actions; + bool m_distUpgradeAvailable; + QNetworkConfigurationManager* m_config; + bool m_canExit; + +}; + +#endif // QAPTACTIONS_H |
