diff --git a/libapper/PackageModel.cpp b/libapper/PackageModel.cpp index 30f5ea4..63c8c89 100644 --- a/libapper/PackageModel.cpp +++ b/libapper/PackageModel.cpp @@ -1,879 +1,898 @@ /*************************************************************************** * 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 #endif #define ICON_SIZE 22 #define OVERLAY_SIZE 16 using namespace PackageKit; PackageModel::PackageModel(QObject *parent) : QAbstractItemModel(parent), m_finished(false), m_checkable(false), m_fetchSizesTransaction(0), m_fetchInstalledVersionsTransaction(0) { m_installedEmblem = PkIcons::getIcon("dialog-ok-apply", QString()).pixmap(16, 16); m_roles[SortRole] = "rSort"; m_roles[NameRole] = "rName"; m_roles[SummaryRole] = "rSummary"; m_roles[VersionRole] = "rVersion"; m_roles[ArchRole] = "rArch"; m_roles[IconRole] = "rIcon"; m_roles[IdRole] = "rId"; m_roles[CheckStateRole] = "rChecked"; m_roles[InfoRole] = "rInfo"; m_roles[ApplicationId] = "rApplicationId"; m_roles[IsPackageRole] = "rIsPackageRole"; m_roles[PackageName] = "rPackageName"; m_roles[InfoIconRole] = "rInfoIcon"; } void PackageModel::addSelectedPackagesFromModel(PackageModel *model) { const QList packages = model->internalSelectedPackages(); for (const InternalPackage &package : packages) { addPackage(package.info, package.packageID, package.summary, true); } finished(); } void PackageModel::addNotSelectedPackage(Transaction::Info info, const QString &packageID, const QString &summary) { addPackage(info, packageID, summary); } void PackageModel::addPackage(Transaction::Info info, const QString &packageID, const QString &summary, bool selected) { if (m_finished) { qDebug() << Q_FUNC_INFO << "we are finished calling clear"; clear(); } switch(info) { case Transaction::InfoBlocked: case Transaction::InfoFinished: case Transaction::InfoCleanup: return; default: break; } #ifdef HAVE_APPSTREAM QList applications; if (!m_checkable) { applications = AppStream::instance()->applications(Transaction::packageName(packageID)); foreach (const AppStream::Application &app, applications) { InternalPackage iPackage; iPackage.info = info; iPackage.packageID = packageID; iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.isPackage = false; if (app.name.isEmpty()) { iPackage.displayName = Transaction::packageName(packageID); } else { iPackage.displayName = app.name; } if (app.summary.isEmpty()) { iPackage.summary = summary; } else { iPackage.summary = app.summary; } iPackage.icon = app.icon_url; iPackage.appId = app.id; iPackage.size = 0; if (selected) { checkPackage(iPackage, false); } m_packages.append(iPackage); } } if (applications.isEmpty()) { #endif //HAVE_APPSTREAM InternalPackage iPackage; iPackage.info = info; iPackage.packageID = packageID; iPackage.displayName = Transaction::packageName(packageID); iPackage.version = Transaction::packageVersion(packageID); iPackage.arch = Transaction::packageArch(packageID); iPackage.repo = Transaction::packageData(packageID); iPackage.summary = summary; iPackage.size = 0; #ifdef HAVE_APPSTREAM iPackage.icon = AppStream::instance()->genericIcon(Transaction::packageName(packageID)); if (iPackage.icon.isEmpty()) iPackage.icon = Transaction::packageIcon(packageID); if (m_checkable) { // in case of updates model only check if it's an app applications = AppStream::instance()->applications(Transaction::packageName(packageID)); if (!applications.isEmpty() || !Transaction::packageIcon(packageID).isEmpty()) { iPackage.isPackage = false; } else { iPackage.isPackage = true; } } else { iPackage.isPackage = true; } #else iPackage.isPackage = true; #endif // HAVE_APPSTREAM if (selected) { checkPackage(iPackage, false); } m_packages.append(iPackage); #ifdef HAVE_APPSTREAM } #endif // HAVE_APPSTREAM } void PackageModel::addSelectedPackage(Transaction::Info info, const QString &packageID, const QString &summary) { addPackage(info, packageID, summary, true); } QVariant PackageModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant ret; if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case NameCol: if (m_checkable) { ret = PkStrings::packageQuantity(true, m_packages.size(), m_checkedPackages.size()); } else { ret = i18n("Name"); } break; case VersionCol: ret = i18n("Version"); break; case CurrentVersionCol: ret = i18n("Installed Version"); break; case ArchCol: ret = i18n("Arch"); break; case OriginCol: ret = i18n("Origin"); break; case SizeCol: ret = i18n("Size"); break; case ActionCol: ret = i18n("Action"); break; } } return ret; } int PackageModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !m_finished) { return 0; } return m_packages.size(); } QModelIndex PackageModel::index(int row, int column, const QModelIndex &parent) const { // kDebug() << parent.isValid() << m_packageCount << row << column; // Check to see if the index isn't out of list if (!parent.isValid() && m_packages.size() > row) { return createIndex(row, column); } return QModelIndex(); } QModelIndex PackageModel::parent(const QModelIndex &index) const { Q_UNUSED(index) return QModelIndex(); } QHash PackageModel::roleNames() const { return m_roles; } QVariant PackageModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const InternalPackage &package = m_packages[index.row()]; if (index.column() == NameCol) { switch (role) { case Qt::CheckStateRole: if (!m_checkable) { return QVariant(); } if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case CheckStateRole: if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case IsPackageRole: return package.isPackage; case Qt::DisplayRole: return package.displayName; case Qt::DecorationRole: { QPixmap icon = QPixmap(44, ICON_SIZE); icon.fill(Qt::transparent); if (!package.icon.isNull()) { QPixmap pixmap; if (package.icon.startsWith("/")) { pixmap = QPixmap(); pixmap.load(package.icon); pixmap = pixmap.scaledToHeight(ICON_SIZE); } else { pixmap = KIconLoader::global()->loadIcon(package.icon, KIconLoader::NoGroup, ICON_SIZE, KIconLoader::DefaultState, QStringList(), 0L, true); } if (!pixmap.isNull()) { QPainter painter(&icon); painter.drawPixmap(QPoint(2, 0), pixmap); } } if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { QPainter painter(&icon); QPoint startPoint; // bottom right corner startPoint = QPoint(44 - OVERLAY_SIZE, 4); painter.drawPixmap(startPoint, m_installedEmblem); } else if (m_checkable) { QIcon emblemIcon = PkIcons::packageIcon(package.info); QPainter painter(&icon); QPoint startPoint; // bottom right corner startPoint = QPoint(44 - OVERLAY_SIZE, 4); painter.drawPixmap(startPoint, emblemIcon.pixmap(OVERLAY_SIZE, OVERLAY_SIZE)); } return icon; } case PackageName: return Transaction::packageName(package.packageID); case Qt::ToolTipRole: if (m_checkable) { return PkStrings::info(package.info); } else { return i18n("Version: %1\nArchitecture: %2", package.version, package.arch); } } } else if (role == Qt::DisplayRole) { if (index.column() == VersionCol) { return package.version; } else if (index.column() == CurrentVersionCol) { return package.currentVersion; } else if (index.column() == ArchCol) { return package.arch; } else if (index.column() == OriginCol) { return package.repo; } else if (index.column() == SizeCol) { KFormat f; return package.size ? f.formatByteSize(package.size) : QString(); } } else if (index.column() == SizeCol && role == Qt::TextAlignmentRole) { return static_cast(Qt::AlignRight | Qt::AlignVCenter); } switch (role) { case IconRole: return package.icon; case SortRole: return QString(package.displayName % QLatin1Char(' ') % package.version % QLatin1Char(' ') % package.arch); case CheckStateRole: if (containsChecked(package.packageID)) { return Qt::Checked; } return Qt::Unchecked; case IdRole: return package.packageID; case NameRole: return package.displayName; case SummaryRole: return package.summary; case VersionRole: return package.version; case ArchRole: return package.arch; case OriginCol: return package.repo; case InfoRole: return qVariantFromValue(package.info); case KCategorizedSortFilterProxyModel::CategoryDisplayRole: if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { return i18n("To be Removed"); } else { return i18n("To be Installed"); } case KCategorizedSortFilterProxyModel::CategorySortRole: // USING 0 here seems to let things unsorted return package.isPackage ? 1 : 0; // Packages comes after applications case ApplicationId: return package.appId; case InfoIconRole: return PkIcons::packageIcon(package.info); default: return QVariant(); } return QVariant(); } bool PackageModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::CheckStateRole && m_packages.size() > index.row()) { if (value.toBool()) { checkPackage(m_packages[index.row()]); } else { uncheckPackage(m_packages[index.row()].packageID); } emit changed(!m_checkedPackages.isEmpty()); return true; } return false; } Qt::ItemFlags PackageModel::flags(const QModelIndex &index) const { if (index.column() == NameCol) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | QAbstractItemModel::flags(index); } return QAbstractItemModel::flags(index); } int PackageModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); if (m_checkable) { // when the model is checkable the action column is not shown return ActionCol; } else { return ActionCol + 1; } } void PackageModel::removePackage(const QString &packageID) { int i = 0; while (i < m_packages.size()) { InternalPackage iPackage = m_packages[i]; if (iPackage.packageID == packageID && iPackage.info != Transaction::InfoUntrusted) { beginRemoveRows(QModelIndex(), i, i); m_packages.remove(i); endRemoveRows(); // since we removed one entry we don't // need to increase the counter continue; } ++i; } } void PackageModel::clear() { qDebug() << Q_FUNC_INFO; beginRemoveRows(QModelIndex(), 0, m_packages.size()); m_finished = false; m_packages.clear(); m_fetchSizesTransaction = 0; m_fetchInstalledVersionsTransaction = 0; if (m_getUpdatesTransaction) { m_getUpdatesTransaction->disconnect(this); m_getUpdatesTransaction->cancel(); } endRemoveRows(); } void PackageModel::clearSelectedNotPresent() { - for (const InternalPackage &package : qAsConst(m_checkedPackages)) { + auto it = m_checkedPackages.begin(); + while (it != m_checkedPackages.end()) { + const InternalPackage &package = it.value(); + bool notFound = true; - const QVector packages = m_packages; - for (const InternalPackage &iPackage : packages) { + 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 - uncheckPackage(package.packageID); + m_checkedPackages.erase(it); + uncheckPackageLogic(package.packageID); + } else { + ++it; } } } bool PackageModel::checkable() const { return m_checkable; } void PackageModel::uncheckInstalledPackages() { - for (const InternalPackage &package : qAsConst(m_checkedPackages)) { + auto it = m_checkedPackages.begin(); + while (it != m_checkedPackages.end()) { + const InternalPackage &package = it.value(); if (package.info == Transaction::InfoInstalled || package.info == Transaction::InfoCollectionInstalled) { - uncheckPackage(package.packageID, true); + it = m_checkedPackages.erase(it); + uncheckPackageLogic(it.key(), true); + } else { + ++it; } } } void PackageModel::uncheckAvailablePackages() { - for (const InternalPackage &package : qAsConst(m_checkedPackages)) { + auto it = m_checkedPackages.begin(); + while (it != m_checkedPackages.end()) { + const InternalPackage &package = it.value(); if (package.info == Transaction::InfoAvailable || package.info == Transaction::InfoCollectionAvailable) { - uncheckPackage(package.packageID, true); + it = m_checkedPackages.erase(it); + uncheckPackageLogic(it.key(), 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(); + 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 << Transaction::packageName(p.packageID); } 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) == Transaction::packageName(m_packages[i].packageID) && Transaction::packageArch(packageID) == m_packages[i].arch) { m_packages[i].currentVersion = Transaction::packageVersion(packageID); if (m_checkable) { // updates the checked packages as well if (m_checkedPackages.contains(m_packages[i].packageID)) { // Avoid checking packages that aren't checked m_checkedPackages[m_packages[i].packageID].currentVersion = Transaction::packageVersion(packageID); } break; } } } } } void PackageModel::getUpdates(bool fetchCurrentVersions, bool selected) { clear(); m_getUpdatesTransaction = Daemon::getUpdates(); if (selected) { connect(m_getUpdatesTransaction, &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::uncheckPackageDefault(const QString &packageID) { uncheckPackage(packageID); } void PackageModel::uncheckPackage(const QString &packageID, bool forceEmitUnchecked, bool emitDataChanged) { - if (containsChecked(packageID)) { - m_checkedPackages.remove(packageID); - if (forceEmitUnchecked || sender() == 0) { - // The package might be removed by rmSelectedPackage - // If we don't copy it the browse model won't uncheck there - // right package - emit packageUnchecked(packageID); - } + auto it = m_checkedPackages.find(packageID); + if (it != m_checkedPackages.end()) { + m_checkedPackages.erase(it); + uncheckPackageLogic(packageID, forceEmitUnchecked, emitDataChanged); + } +} - 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); - } - } +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); + } - // The model might not be displayed yet - if (m_finished) { - emit changed(!m_checkedPackages.isEmpty()); + if (emitDataChanged || !m_checkable) { + // This is a slow operation so in case the user + // is unchecking all of the packages there is + // no need to emit data changed for every item + for (int i = 0; i < m_packages.size(); ++i) { + if (m_packages[i].packageID == packageID) { + QModelIndex index = createIndex(i, 0); + emit dataChanged(index, index); } } + + // The model might not be displayed yet + if (m_finished) { + emit changed(!m_checkedPackages.isEmpty()); + } } } QList PackageModel::internalSelectedPackages() const { QList ret; QHash::const_iterator i = m_checkedPackages.constBegin(); while (i != m_checkedPackages.constEnd()) { ret << i.value(); ++i; } return ret; } bool PackageModel::containsChecked(const QString &pid) const { - if (m_checkedPackages.isEmpty()) { - return false; - } return m_checkedPackages.contains(pid); } void PackageModel::setAllChecked(bool checked) { if (checked) { m_checkedPackages.clear(); for (const InternalPackage &package : qAsConst(m_packages)) { checkPackage(package, false); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); } else { - // This is a very slow operation, which in here we try to optimize - for (const InternalPackage &package : qAsConst(m_checkedPackages)) { - uncheckPackage(package.packageID, true, false); + auto it = m_checkedPackages.begin(); + while (it != m_checkedPackages.end()) { + uncheckPackageLogic(it.key(), true, false); + it = m_checkedPackages.erase(it); } emit dataChanged(createIndex(0, 0), createIndex(m_packages.size(), 0)); } emit changed(!m_checkedPackages.isEmpty()); } 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; } diff --git a/libapper/PackageModel.h b/libapper/PackageModel.h index e2a14ec..77216cf 100644 --- a/libapper/PackageModel.h +++ b/libapper/PackageModel.h @@ -1,157 +1,160 @@ /*************************************************************************** * Copyright (C) 2008-2011 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef PACKAGE_MODEL_H #define PACKAGE_MODEL_H #include #include #include #include
class Q_DECL_EXPORT PackageModel : public QAbstractItemModel { Q_OBJECT Q_PROPERTY(bool checkable READ checkable WRITE setCheckable NOTIFY changed) Q_PROPERTY(QString selectionStateText READ selectionStateText NOTIFY changed) public: enum { NameCol = 0, VersionCol, CurrentVersionCol, ArchCol, OriginCol, SizeCol, ActionCol }; enum { SortRole = Qt::UserRole, NameRole, SummaryRole, VersionRole, ArchRole, IconRole, IdRole, CheckStateRole, InfoRole, ApplicationId, IsPackageRole, PackageName, InfoIconRole }; typedef struct { QString displayName; QString version; QString arch; QString repo; QString packageID; QString summary; PackageKit::Transaction::Info info; QString icon; QString appId; QString currentVersion; bool isPackage; double size; } InternalPackage; explicit PackageModel(QObject *parent = 0); Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Q_INVOKABLE bool allSelected() const; Q_INVOKABLE QStringList selectedPackagesToInstall() const; Q_INVOKABLE QStringList selectedPackagesToRemove() const; Q_INVOKABLE QStringList packagesWithInfo(PackageKit::Transaction::Info info) const; Q_INVOKABLE QStringList packageIDs() const; unsigned long downloadSize() const; Q_INVOKABLE void clear(); /** * This removes all selected packages that are not in the model */ Q_INVOKABLE void clearSelectedNotPresent(); bool checkable() const; void setCheckable(bool checkable); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; virtual QHash roleNames() const override; public Q_SLOTS: void addSelectedPackagesFromModel(PackageModel *model); void addNotSelectedPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void addPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary, bool selected = false); void addSelectedPackage(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void removePackage(const QString &packageID); void setAllChecked(bool checked); void checkPackage(const PackageModel::InternalPackage &package, bool emitDataChanged = true); void uncheckPackageDefault(const QString &packageID); void uncheckPackage(const QString &packageID, bool forceEmitUnchecked = false, bool emitDataChanged = true); + void uncheckPackageLogic(const QString &packageID, + bool forceEmitUnchecked = false, + bool emitDataChanged = true); bool hasChanges() const; int countInfo(PackageKit::Transaction::Info info) const; void uncheckInstalledPackages(); void uncheckAvailablePackages(); void finished(); void fetchSizes(); void fetchSizesFinished(); void updateSize(const PackageKit::Details &details); void fetchCurrentVersions(); void fetchCurrentVersionsFinished(); void updateCurrentVersion(PackageKit::Transaction::Info info, const QString &packageID, const QString &summary); void getUpdates(bool fetchCurrentVersions, bool selected); void toggleSelection(const QString &packageID); QString selectionStateText() const; Q_SIGNALS: void changed(bool value); void packageUnchecked(const QString &packageID); private: QList internalSelectedPackages() const; bool containsChecked(const QString &pid) const; bool m_finished = true; bool m_checkable; QPixmap m_installedEmblem; QVector m_packages; QHash m_checkedPackages; PackageKit::Transaction *m_getUpdatesTransaction = 0; PackageKit::Transaction *m_fetchSizesTransaction; PackageKit::Transaction *m_fetchInstalledVersionsTransaction; QHash m_roles; }; #endif