From e58907b7034650c2a8bb7ba4291f1ed3a15f66d4 Mon Sep 17 00:00:00 2001 From: Renaud Guezennec Date: Thu, 29 Aug 2024 11:13:46 +0200 Subject: [PATCH] Git: show modification states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I94d91e34489e6bb2e23cabe8f0c93dfc01ca7812 Reviewed-by: André Hartmann --- src/plugins/coreplugin/iversioncontrol.cpp | 44 ++++++++++++++++++- src/plugins/coreplugin/iversioncontrol.h | 15 ++++++- src/plugins/git/gitclient.cpp | 28 ++++++++---- src/plugins/git/gitclient.h | 4 +- src/plugins/git/gitplugin.cpp | 6 +-- src/plugins/projectexplorer/projectmodels.cpp | 14 ++++-- src/plugins/projectexplorer/projectnodes.cpp | 8 ++-- src/plugins/projectexplorer/projectnodes.h | 3 +- 8 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/plugins/coreplugin/iversioncontrol.cpp b/src/plugins/coreplugin/iversioncontrol.cpp index 78925435acb..11219d18e7d 100644 --- a/src/plugins/coreplugin/iversioncontrol.cpp +++ b/src/plugins/coreplugin/iversioncontrol.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -63,10 +64,10 @@ FilePaths IVersionControl::additionalToolsPath() const return {}; } -bool IVersionControl::hasModification(const FilePath &path) const +IVersionControl::FileState IVersionControl::modificationState(const FilePath &path) const { Q_UNUSED(path) - return false; + return IVersionControl::FileState::NoModification; } void IVersionControl::monitorDirectory(const Utils::FilePath &path) @@ -225,4 +226,43 @@ bool IVersionControl::handleLink(const FilePath &workingDirectory, const QString return true; } +QColor IVersionControl::vcStateToColor(const IVersionControl::FileState &state) +{ + using CIVF = Core::IVersionControl::FileState; + using UT = Utils::Theme; + switch (state) { + case CIVF::ModifiedState: + return Utils::creatorColor(UT::VcsBase_FileModified_TextColor); + case CIVF::AddedState: + return Utils::creatorColor(UT::VcsBase_FileAdded_TextColor); + case CIVF::RenamedState: + return Utils::creatorColor(UT::VcsBase_FileRenamed_TextColor); + case CIVF::DeletedState: + return Utils::creatorColor(UT::VcsBase_FileDeleted_TextColor); + case CIVF::UnmanagedState: + return Utils::creatorColor(UT::VcsBase_FileUnmerged_TextColor); + default: + return Utils::creatorColor(UT::PaletteText); + } +} + +QString IVersionControl::modificationToText(const IVersionControl::FileState &state) +{ + using CIVF = Core::IVersionControl::FileState; + switch (state) { + case CIVF::AddedState: + return Tr::tr("Version control state: added"); + case CIVF::ModifiedState: + return Tr::tr("Version control state: modified"); + case CIVF::DeletedState: + return Tr::tr("Version control state: deleted"); + case CIVF::RenamedState: + return Tr::tr("Version control state: renamed"); + case CIVF::UnmanagedState: + return Tr::tr("Version control state: untracked"); + default: + return {}; + } +} + } // namespace Core diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index b3e80a79d4c..f04883446aa 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -42,6 +42,16 @@ public: OpenMandatory /*!< Files must always be opened by the VCS */ }; + enum class FileState : quint8 { + NoModification = 0x00, + ModifiedState, + AddedState, + DeletedState, + RenamedState, + UnmanagedState + }; + Q_ENUM(FileState) + IVersionControl(); ~IVersionControl() override; @@ -96,7 +106,7 @@ public: /*! * Returns true if the file has modification compared to version control */ - virtual bool hasModification(const Utils::FilePath &path) const; + virtual Core::IVersionControl::FileState modificationState(const Utils::FilePath &path) const; /*! * Starts monitoring modified files inside path @@ -226,6 +236,9 @@ public: QString refreshTopic(const Utils::FilePath &repository); void setTopicRefresher(const TopicRefresher &topicRefresher); + static QColor vcStateToColor(const IVersionControl::FileState &state); + static QString modificationToText(const IVersionControl::FileState &state); + signals: void repositoryChanged(const Utils::FilePath &repository); void filesChanged(const QStringList &files); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index d16fb48b811..7739782c204 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -882,13 +882,13 @@ FilePaths GitClient::unmanagedFiles(const FilePaths &filePaths) const return res; } -bool GitClient::hasModification(const Utils::FilePath &workingDirectory, +IVersionControl::FileState GitClient::modificationState(const Utils::FilePath &workingDirectory, const Utils::FilePath &fileName) const { const ModificationInfo &info = m_modifInfos[workingDirectory]; int length = workingDirectory.toString().size(); const QString fileNameFromRoot = fileName.absoluteFilePath().path().mid(length + 1); - return info.modifiedFiles.contains(fileNameFromRoot); + return info.modifiedFiles.value(fileNameFromRoot, IVersionControl::FileState::NoModification); } void GitClient::stopMonitoring(const Utils::FilePath &path) @@ -920,6 +920,7 @@ void GitClient::monitorDirectory(const Utils::FilePath &path) void GitClient::updateModificationInfos() { + using IVCF = IVersionControl::FileState; for (const ModificationInfo &infoTemp : std::as_const(m_modifInfos)) { const FilePath path = infoTemp.rootPath; @@ -930,22 +931,31 @@ void GitClient::updateModificationInfos() ModificationInfo &info = m_modifInfos[path]; const QStringList res = result.cleanedStdOut().split("\n", Qt::SkipEmptyParts); - QSet modifiedFiles; + QHash modifiedFiles; for (const QString &line : res) { if (line.size() <= 3) continue; - static const QSet gitStates{'M', 'A'}; + static const QHash gitStates { + {'M', IVCF::ModifiedState}, + {'A', IVCF::AddedState}, + {'R', IVCF::RenamedState}, + {'D', IVCF::DeletedState}, + {'?', IVCF::UnmanagedState}, + }; - if (gitStates.contains(line.at(0)) || gitStates.contains(line.at(1))) - modifiedFiles.insert(line.mid(3).trimmed()); + const IVCF &modification = std::max(gitStates.value(line.at(0), IVCF::NoModification), + gitStates.value(line.at(1), IVCF::NoModification)); + + if (modification != IVCF::NoModification) + modifiedFiles.insert(line.mid(3).trimmed(), modification); } - const QSet oldfiles = info.modifiedFiles; + const QHash oldfiles = info.modifiedFiles; info.modifiedFiles = modifiedFiles; - QStringList newList = modifiedFiles.values(); - QStringList list = oldfiles.values(); + QStringList newList = modifiedFiles.keys(); + QStringList list = oldfiles.keys(); newList.sort(); list.sort(); QStringList statusChangedFiles; diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index e7a91bda0b1..1429469ca79 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -122,7 +122,7 @@ public: struct ModificationInfo { Utils::FilePath rootPath; - QSet modifiedFiles; + QHash modifiedFiles; }; GitClient(); @@ -140,7 +140,7 @@ public: Utils::FilePath findGitDirForRepository(const Utils::FilePath &repositoryDir) const; bool managesFile(const Utils::FilePath &workingDirectory, const QString &fileName) const; Utils::FilePaths unmanagedFiles(const Utils::FilePaths &filePaths) const; - bool hasModification(const Utils::FilePath &workingDirectory, + Core::IVersionControl::FileState modificationState(const Utils::FilePath &workingDirectory, const Utils::FilePath &fileName) const; void monitorDirectory(const Utils::FilePath &path); void stopMonitoring(const Utils::FilePath &path); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index bae1deeb77e..5978c439b7e 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -157,7 +157,7 @@ public: FilePaths unmanagedFiles(const FilePaths &filePaths) const final; bool isConfigured() const final; - bool hasModification(const Utils::FilePath &path) const final; + IVersionControl::FileState modificationState(const Utils::FilePath &path) const final; void monitorDirectory(const Utils::FilePath &path) final; void stopMonitoringDirectory(const Utils::FilePath &path) final; bool supportsOperation(Operation operation) const final; @@ -1763,10 +1763,10 @@ bool GitPluginPrivate::isConfigured() const return !gitClient().vcsBinary({}).isEmpty(); } -bool GitPluginPrivate::hasModification(const Utils::FilePath &path) const +IVersionControl::FileState GitPluginPrivate::modificationState(const Utils::FilePath &path) const { const Utils::FilePath projectDir = gitClient().findRepositoryForDirectory(path.absolutePath()); - return gitClient().hasModification(projectDir, path); + return gitClient().modificationState(projectDir, path); } void GitPluginPrivate::monitorDirectory(const Utils::FilePath &path) diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index c9465812e92..9a47d1d0473 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -215,8 +215,11 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const tooltip += "

" + Tr::tr("No kits are enabled for this project. " "Enable kits in the \"Projects\" mode."); } - } else if (fileNode && fileNode->hasModification()) { - tooltip += "

" + Tr::tr("Version control state: modified"); + } else if (fileNode) { + const QString &stateText = + IVersionControl::modificationToText(fileNode->modificationState()); + if (!stateText.isEmpty()) + tooltip += "

" + stateText; } return tooltip; } @@ -243,8 +246,11 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const return font; } case Qt::ForegroundRole: - if (fileNode && fileNode->hasModification()) - return Utils::creatorColor(Utils::Theme::VcsBase_FileModified_TextColor); + if (fileNode) { + Core::IVersionControl::FileState state = fileNode->modificationState(); + if (state != Core::IVersionControl::FileState::NoModification) + return Core::IVersionControl::vcStateToColor(state); + } return node->isEnabled() ? QVariant() : Utils::creatorColor(Utils::Theme::TextColorDisabled); case Project::FilePathRole: diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 6beb3408d5d..61c24645d7a 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -261,17 +261,17 @@ void FileNode::setHasError(bool error) const m_hasError = error; } -bool FileNode::hasModification() const +Core::IVersionControl::FileState FileNode::modificationState() const { if (isGenerated()) - return false; + return Core::IVersionControl::FileState::NoModification; const FilePath file = filePath(); const FilePath dir = file.absolutePath(); if (Core::IVersionControl *vc = Core::VcsManager::findVersionControlForDirectory(dir)) - return vc->hasModification(file); + return vc->modificationState(file); - return false; + return Core::IVersionControl::FileState::NoModification; } bool FileNode::useUnavailableMarker() const diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index b4bd2c3e7a9..623dea202dc 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -202,7 +203,7 @@ public: void setHasError(const bool error); void setHasError(const bool error) const; - bool hasModification() const; + Core::IVersionControl::FileState modificationState() const; QIcon icon() const; void setIcon(const QIcon icon);