diff --git a/vcs/models/tests/test_models.cpp b/vcs/models/tests/test_models.cpp index 7a353907d6..fc98e03a1a 100644 --- a/vcs/models/tests/test_models.cpp +++ b/vcs/models/tests/test_models.cpp @@ -1,142 +1,142 @@ /*************************************************************************** * Copyright 2011 Andrey Batyiev * * * * 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 . * ***************************************************************************/ #include "test_models.h" #include #include #include #include using namespace KDevelop; void TestModels::initTestCase() { AutoTestShell::init({"dummy"}); TestCore::initialize(); } void TestModels::cleanupTestCase() { TestCore::shutdown(); } void TestModels::testVcsFileChangesModel() { const auto indexForUrl = [](const VcsFileChangesModel* model, const QUrl& url) { return model->match(model->index(0, 0), VcsFileChangesModel::UrlRole, url, 1, Qt::MatchExactly).value(0); }; const auto statusInfo = [](const QModelIndex& idx) { return idx.data(VcsFileChangesModel::VcsStatusInfoRole).value(); }; - VcsFileChangesModel *model = new VcsFileChangesModel(this); + QScopedPointer model(new VcsFileChangesModel); // Newly created model should be empty QVERIFY(model->rowCount() == 0); // Pull some files into QUrl filenames[] = { QUrl::fromLocalFile(QStringLiteral("foo")), QUrl::fromLocalFile(QStringLiteral("bar")), QUrl::fromLocalFile(QStringLiteral("pew")), QUrl::fromLocalFile(QStringLiteral("trash")) }; VcsStatusInfo::State states[] = {VcsStatusInfo::ItemAdded, VcsStatusInfo::ItemModified, VcsStatusInfo::ItemDeleted, VcsStatusInfo::ItemUpToDate}; VcsStatusInfo status; for(int i = 0; i < 3; i++) { status.setUrl(filenames[i]); status.setState(states[i]); model->updateState(status); QCOMPARE(model->rowCount(), (i+1)); } // Pulling up-to-date file doesn't change anything { status.setUrl(filenames[3]); status.setState(states[3]); model->updateState(status); QCOMPARE(model->rowCount(), 3); } // Check that all OK for(int i = 0; i < 3; i++) { - QModelIndex idx = indexForUrl(model, filenames[i]); + QModelIndex idx = indexForUrl(model.data(), filenames[i]); QVERIFY(idx.isValid()); VcsStatusInfo info = statusInfo(idx); QVERIFY(info.url().isValid()); QCOMPARE(info.url(), filenames[i]); QCOMPARE(info.state(), states[i]); } // Pull it all again = nothing changed for(int i = 0; i < 3; i++) { status.setUrl(filenames[i]); status.setState(states[i]); model->updateState(status); QCOMPARE(model->rowCount(), 3); } // Check that all OK for(int i = 0; i < 3; i++) { - QModelIndex item = indexForUrl(model, filenames[i]); + QModelIndex item = indexForUrl(model.data(), filenames[i]); QVERIFY(item.isValid()); VcsStatusInfo info = statusInfo(item); QCOMPARE(info.url(), filenames[i]); QCOMPARE(info.state(), states[i]); } // Remove one file { states[1] = VcsStatusInfo::ItemUpToDate; status.setUrl(filenames[1]); status.setState(states[1]); model->updateState(status); QCOMPARE(model->rowCount(), 2); } // Check them all for(int i = 0; i < 3; i++) { if(states[i] != VcsStatusInfo::ItemUpToDate && states[i] != VcsStatusInfo::ItemUnknown) { - QModelIndex item = indexForUrl(model, filenames[i]); + QModelIndex item = indexForUrl(model.data(), filenames[i]); QVERIFY(item.isValid()); VcsStatusInfo info = statusInfo(item); QCOMPARE(info.url(), filenames[i]); QCOMPARE(info.state(), states[i]); } } // Delete them all model->removeRows(0, model->rowCount()); QCOMPARE(model->rowCount(), 0); // Pull it all again for(int i = 0; i < 3; i++) { status.setUrl(filenames[i]); status.setState(states[i]); model->updateState(status); } QCOMPARE(model->rowCount(), 2); } QTEST_MAIN(TestModels); diff --git a/vcs/models/vcseventmodel.cpp b/vcs/models/vcseventmodel.cpp index b4cd6c4692..56d5f36aa0 100644 --- a/vcs/models/vcseventmodel.cpp +++ b/vcs/models/vcseventmodel.cpp @@ -1,183 +1,183 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "vcseventmodel.h" #include #include #include #include #include #include #include "../vcsevent.h" #include "../vcsrevision.h" #include #include #include #include namespace KDevelop { class VcsEventModelPrivate { public: QList m_events; KDevelop::IBasicVersionControl* m_iface; VcsRevision m_rev; QUrl m_url; bool done; bool fetching; }; VcsEventModel::VcsEventModel( KDevelop::IBasicVersionControl* iface, const VcsRevision& rev, const QUrl& url, QObject* parent ) : QAbstractTableModel( parent ), d(new VcsEventModelPrivate) { d->m_iface = iface; d->m_rev = rev; d->m_url = url; d->done = false; d->fetching = false; } VcsEventModel::~VcsEventModel() { delete d; } int VcsEventModel::rowCount( const QModelIndex& parent) const { return parent.isValid() ? 0 : d->m_events.count(); } int VcsEventModel::columnCount( const QModelIndex& parent) const { return parent.isValid() ? 0 : ColumnCount; } QVariant VcsEventModel::data( const QModelIndex& idx, int role ) const { if( !idx.isValid() || role != Qt::DisplayRole ) return QVariant(); if( idx.row() < 0 || idx.row() >= rowCount() || idx.column() < 0 || idx.column() >= columnCount() ) return QVariant(); KDevelop::VcsEvent ev = d->m_events.at( idx.row() ); switch( idx.column() ) { case RevisionColumn: return QVariant( ev.revision().revisionValue() ); case SummaryColumn: // show the first line only return QVariant( ev.message().section('\n', 0, 0) ); case AuthorColumn: return QVariant( ev.author() ); case DateColumn: return QVariant( QLocale().toString( ev.date() ) ); default: break; } return QVariant(); } QVariant VcsEventModel::headerData( int section, Qt::Orientation orientation, int role ) const { if( section < 0 || section >= columnCount() || orientation != Qt::Horizontal || role != Qt::DisplayRole ) return QVariant(); switch( section ) { case RevisionColumn: return QVariant( i18n("Revision") ); case SummaryColumn: return QVariant( i18n("Message") ); case AuthorColumn: return QVariant( i18n("Author") ); case DateColumn: return QVariant( i18n("Date") ); default: break; } return QVariant(); } void VcsEventModel::addEvents( const QList& list ) { if( list.isEmpty() ) return; beginInsertRows( QModelIndex(), rowCount(), rowCount()+list.count()-1 ); d->m_events += list; endInsertRows(); } KDevelop::VcsEvent VcsEventModel::eventForIndex( const QModelIndex& idx ) const { if( !idx.isValid() || idx.row() < 0 || idx.row() >= rowCount() ) { return KDevelop::VcsEvent(); } return d->m_events.at( idx.row() ); } bool VcsEventModel::canFetchMore(const QModelIndex& parent) const { return !d->done && !d->fetching && !parent.isValid(); } void VcsEventModel::fetchMore(const QModelIndex& parent) { d->fetching = true; Q_ASSERT(!parent.isValid()); Q_UNUSED(parent); VcsJob* job = d->m_iface->log(d->m_url, d->m_rev, qMax(rowCount(), 100)); - connect(this, &VcsEventModel::destroyed, job, [&] { job->kill(); }); + connect(this, &VcsEventModel::destroyed, job, [job] { job->kill(); }); connect(job, &VcsJob::finished, this, &VcsEventModel::jobReceivedResults); ICore::self()->runController()->registerJob( job ); } void VcsEventModel::jobReceivedResults(KJob* job) { QList l = qobject_cast(job)->fetchResults().toList(); if(l.isEmpty() || job->error()!=0) { d->done = true; return; } QList newevents; foreach( const QVariant &v, l ) { if( v.canConvert() ) { newevents << v.value(); } } d->m_rev = newevents.last().revision(); if(!d->m_events.isEmpty()) { newevents.removeFirst(); } d->done = newevents.isEmpty(); addEvents( newevents ); d->fetching = false; } } diff --git a/vcs/models/vcsfilechangesmodel.cpp b/vcs/models/vcsfilechangesmodel.cpp index ac1d4c90ee..8c5f1e4a9d 100644 --- a/vcs/models/vcsfilechangesmodel.cpp +++ b/vcs/models/vcsfilechangesmodel.cpp @@ -1,270 +1,270 @@ /* This file is part of KDevelop Copyright 2010 Aleix Pol Split into separate class Copyright 2011 Andrey Batyiev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vcsfilechangesmodel.h" #include #include #include #include #include #include namespace KDevelop { static QString stateToString(KDevelop::VcsStatusInfo::State state) { switch(state) { case KDevelop::VcsStatusInfo::ItemAdded: return i18nc("file was added to versioncontrolsystem", "Added"); case KDevelop::VcsStatusInfo::ItemDeleted: return i18nc("file was deleted from versioncontrolsystem", "Deleted"); case KDevelop::VcsStatusInfo::ItemHasConflicts: return i18nc("file is confilicting (versioncontrolsystem)", "Has Conflicts"); case KDevelop::VcsStatusInfo::ItemModified: return i18nc("version controlled file was modified", "Modified"); case KDevelop::VcsStatusInfo::ItemUpToDate: return i18nc("file is up to date in versioncontrolsystem", "Up To Date"); case KDevelop::VcsStatusInfo::ItemUnknown: case KDevelop::VcsStatusInfo::ItemUserState: return i18nc("file is not known to versioncontrolsystem", "Unknown"); } return i18nc("Unknown VCS file status, probably a backend error", "?"); } static QIcon stateToIcon(KDevelop::VcsStatusInfo::State state) { switch(state) { case KDevelop::VcsStatusInfo::ItemAdded: return QIcon::fromTheme(QStringLiteral("vcs-added")); case KDevelop::VcsStatusInfo::ItemDeleted: return QIcon::fromTheme(QStringLiteral("vcs-removed")); case KDevelop::VcsStatusInfo::ItemHasConflicts: return QIcon::fromTheme(QStringLiteral("vcs-conflicting")); case KDevelop::VcsStatusInfo::ItemModified: return QIcon::fromTheme(QStringLiteral("vcs-locally-modified")); case KDevelop::VcsStatusInfo::ItemUpToDate: return QIcon::fromTheme(QStringLiteral("vcs-normal")); case KDevelop::VcsStatusInfo::ItemUnknown: case KDevelop::VcsStatusInfo::ItemUserState: return QIcon::fromTheme(QStringLiteral("unknown")); } return QIcon::fromTheme(QStringLiteral("dialog-error")); } VcsFileChangesSortProxyModel::VcsFileChangesSortProxyModel(QObject* parent) : QSortFilterProxyModel(parent) { } bool VcsFileChangesSortProxyModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { const auto leftStatus = source_left.data(VcsFileChangesModel::StateRole).value(); const auto rightStatus = source_right.data(VcsFileChangesModel::StateRole).value(); if (leftStatus != rightStatus) { return leftStatus < rightStatus; } const QString leftPath = source_left.data(VcsFileChangesModel::UrlRole).toString(); const QString rightPath = source_right.data(VcsFileChangesModel::UrlRole).toString(); return QString::localeAwareCompare(leftPath, rightPath) < 0; } class VcsStatusInfoItem : public QStandardItem { public: VcsStatusInfoItem(const VcsStatusInfo& info) : QStandardItem() , m_info(info) {} void setStatus(const VcsStatusInfo& info) { m_info = info; emitDataChanged(); } QVariant data(int role) const override { switch(role) { case Qt::DisplayRole: return stateToString(m_info.state()); case Qt::DecorationRole: return stateToIcon(m_info.state()); case VcsFileChangesModel::VcsStatusInfoRole: return QVariant::fromValue(m_info); case VcsFileChangesModel::UrlRole: return m_info.url(); case VcsFileChangesModel::StateRole: return QVariant::fromValue(m_info.state()); } return {}; } private: VcsStatusInfo m_info; }; class VcsFileChangesModelPrivate { public: bool allowSelection; }; VcsFileChangesModel::VcsFileChangesModel(QObject *parent, bool allowSelection) : QStandardItemModel(parent), d(new VcsFileChangesModelPrivate {allowSelection} ) { setColumnCount(2); setHeaderData(0, Qt::Horizontal, i18n("Filename")); setHeaderData(1, Qt::Horizontal, i18n("Status")); } VcsFileChangesModel::~VcsFileChangesModel() { } int VcsFileChangesModel::updateState(QStandardItem *parent, const KDevelop::VcsStatusInfo &status) { if(status.state()==VcsStatusInfo::ItemUnknown || status.state()==VcsStatusInfo::ItemUpToDate) { removeUrl(status.url()); return -1; } else { QStandardItem* item = fileItemForUrl(parent, status.url()); if(!item) { QString path = ICore::self()->projectController()->prettyFileName(status.url(), KDevelop::IProjectController::FormatPlain); QMimeType mime = status.url().isLocalFile() ? QMimeDatabase().mimeTypeForFile(status.url().toLocalFile(), QMimeDatabase::MatchExtension) : QMimeDatabase().mimeTypeForUrl(status.url()); QIcon icon = QIcon::fromTheme(mime.iconName()); item = new QStandardItem(icon, path); auto itStatus = new VcsStatusInfoItem(status); if(d->allowSelection) { item->setCheckable(true); item->setCheckState(status.state() == VcsStatusInfo::ItemUnknown ? Qt::Unchecked : Qt::Checked); } parent->appendRow({ item, itStatus }); } else { QStandardItem *parent = item->parent(); if(parent == 0) parent = invisibleRootItem(); auto statusInfoItem = static_cast(parent->child(item->row(), 1)); statusInfoItem->setStatus(status); } return item->row(); } } QVariant VcsFileChangesModel::data(const QModelIndex &index, int role) const { - if (role == UrlRole && index.column()==0) { + if (role >= VcsStatusInfoRole && index.column()==0) { return QStandardItemModel::data(index.sibling(index.row(), 1), role); } return QStandardItemModel::data(index, role); } QStandardItem* VcsFileChangesModel::fileItemForUrl(QStandardItem* parent, const QUrl& url) const { for(int i=0, c=parent->rowCount(); ichild(i); if(indexFromItem(item).data(UrlRole).toUrl() == url) { return parent->child(i); } } return 0; } void VcsFileChangesModel::setAllChecked(bool checked) { if(!d->allowSelection) return; QStandardItem* parent = invisibleRootItem(); for(int i = 0, c = parent->rowCount(); i < c; i++) { QStandardItem* item = parent->child(i); item->setCheckState(checked ? Qt::Checked : Qt::Unchecked); } } QList VcsFileChangesModel::checkedUrls(QStandardItem *parent) const { QList ret; for(int i = 0, c = parent->rowCount(); i < c; i++) { QStandardItem* item = parent->child(i); if(!d->allowSelection || item->checkState() == Qt::Checked) { ret << indexFromItem(item).data(UrlRole).toUrl(); } } return ret; } QList VcsFileChangesModel::urls(QStandardItem *parent) const { QList ret; for(int i = 0, c = parent->rowCount(); i < c; i++) { QStandardItem* item = parent->child(i); ret << indexFromItem(item).data(UrlRole).toUrl(); } return ret; } void VcsFileChangesModel::checkUrls(QStandardItem *parent, const QList& urls) const { QSet urlSet(urls.toSet()); if(!d->allowSelection) return; for(int i = 0, c = parent->rowCount(); i < c; i++) { QStandardItem* item = parent->child(i); item->setCheckState(urlSet.contains(indexFromItem(item).data(UrlRole).toUrl()) ? Qt::Checked : Qt::Unchecked); } } void VcsFileChangesModel::setIsCheckbable(bool checkable) { d->allowSelection = checkable; } bool VcsFileChangesModel::isCheckable() const { return d->allowSelection; } bool VcsFileChangesModel::removeUrl(const QUrl& url) { const auto matches = match(index(0, 0), UrlRole, url, 1, Qt::MatchExactly); if (matches.isEmpty()) return false; const auto& idx = matches.first(); return removeRow(idx.row(), idx.parent()); } } diff --git a/vcs/models/vcsfilechangesmodel.h b/vcs/models/vcsfilechangesmodel.h index c4cf6bdb82..efa6b345c7 100644 --- a/vcs/models/vcsfilechangesmodel.h +++ b/vcs/models/vcsfilechangesmodel.h @@ -1,148 +1,148 @@ /* This file is part of KDevelop Copyright 2010 Aleix Pol Split into separate class Copyright 2011 Andrey Batyiev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_VCSFILECHANGESMODEL_H #define KDEVPLATFORM_VCSFILECHANGESMODEL_H #include #include #include #include class QUrl; namespace KDevelop { class VcsStatusInfo; class KDEVPLATFORMVCS_EXPORT VcsFileChangesSortProxyModel : public QSortFilterProxyModel { Q_OBJECT public: VcsFileChangesSortProxyModel(QObject* parent = nullptr); bool lessThan(const QModelIndex& rLeft, const QModelIndex& rRight) const override; }; /** * This class holds and represents information about changes in files. * Also it is possible to provide tree like models by inheriting this class, see protected members. * All stuff should be pulled in by @p updateState. */ class VcsFileChangesModelPrivate; class KDEVPLATFORMVCS_EXPORT VcsFileChangesModel : public QStandardItemModel { Q_OBJECT public: enum ItemRoles { VcsStatusInfoRole = Qt::UserRole+1, UrlRole, StateRole, LastItemRole }; enum Column { PathColumn = 0, StatusColumn = 1 }; /** * Constructor for class. * @param isCheckable if true, model will show checkboxes on items. */ - explicit VcsFileChangesModel(QObject *parent, bool isCheckable = false); + explicit VcsFileChangesModel(QObject *parent = nullptr, bool isCheckable = false); ~VcsFileChangesModel() override; QVariant data(const QModelIndex &index, int role) const override; /** * Returns list of currently checked urls. */ QList checkedUrls() const { return checkedUrls(invisibleRootItem()); } /** * Returns urls of all files * */ QList urls() const { return urls(invisibleRootItem()); } /** * Set the checked urls * */ void setCheckedUrls(const QList& urls) const { return checkUrls(invisibleRootItem(), urls); } /** * Changes the check-state of all files to the given state * */ void setAllChecked(bool checked); void setIsCheckbable(bool checkable); bool isCheckable() const; bool removeUrl(const QUrl& url); public slots: /** * Used to post update of status of some file. Any status except UpToDate * and Unknown will update (or add) item representation. */ void updateState(const KDevelop::VcsStatusInfo &status) { updateState(invisibleRootItem(), status); } protected: /** * Post update of status of some file. * @return changed row or -1 if row is deleted */ int updateState(QStandardItem *parent, const KDevelop::VcsStatusInfo &status); /** * Returns list of currently checked urls. */ QList checkedUrls(QStandardItem *parent) const; /** * Checks the given urls, unchecks all others. * */ void checkUrls(QStandardItem *parent, const QList& urls) const; /** * Returns all urls * */ QList urls(QStandardItem *parent) const; /** * Returns item for particular url. */ QStandardItem* fileItemForUrl(QStandardItem *parent, const QUrl &url) const; private: QScopedPointer const d; }; } Q_DECLARE_METATYPE(KDevelop::VcsStatusInfo::State) #endif // KDEVPLATFORM_VCSFILECHANGESMODEL_H