File indexing completed on 2024-04-28 04:38:51
0001 /* 0002 SPDX-FileCopyrightText: 2020 Jonathan L. Verner <jonathan.verner@matfyz.cz> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KDEVPLATFORM_PLUGIN_REPO_STATUS_MODEL_H 0008 #define KDEVPLATFORM_PLUGIN_REPO_STATUS_MODEL_H 0009 0010 #include "gitplugin.h" 0011 0012 #include <project/projectchangesmodel.h> 0013 #include <vcs/interfaces/ibasicversioncontrol.h> 0014 0015 class KJob; 0016 0017 namespace KDevelop { 0018 class IProject; 0019 class IDocument; 0020 } 0021 0022 /** 0023 * This implements the model for vcs status of files in a project. 0024 * 0025 * The tree structure of the model is: 0026 * 0027 * - project item 0028 * - index 0029 * - file with staged changes 0030 * - ... 0031 * - worktree 0032 * - file with unstaged changes 0033 * - ... 0034 * - conflicts 0035 * - file with unresolved conflicts 0036 * - ... 0037 * - untrackded 0038 * - untracked file 0039 * - ... 0040 * 0041 * It is modeled on (and part of the code is copied from) the @class ProjectChangesModel 0042 * (see kdevplatform/vcs/interfaces/ibasicversioncontrol.h) 0043 * 0044 * @author Jonathan L. Verner <jonathan.verner@matfyz.cz> 0045 */ 0046 class RepoStatusModel : public QStandardItemModel 0047 { 0048 Q_OBJECT 0049 0050 public: 0051 enum ItemRoles { 0052 UrlRole = Qt::UserRole+1, /**< an url to the item */ 0053 AreaRole, /**< the area where the item belongs (index, worktree, untracked) **/ 0054 NameRole, /**< A human readable name of the item */ 0055 BranchNameRole, /**< the git branch on which the item is located */ 0056 StatusRole, /**< the git status of the item (GitPlugin::ExtendedState) */ 0057 ReadableStatusRole, /**< a human-readable git status of the item */ 0058 ProjectUrlRole, /**< the url of the project */ 0059 }; 0060 0061 /** 0062 * The areas into which files are sorted. A file may be in 0063 * more than one area (e.g. if it has both staged and unstaged 0064 * changes, it will be in Index and WorkTree). The special 0065 * areas ProjectRoot, IndexRoot, WorkTreeRoot, UntrackedRoot and ConflictsRoot 0066 * correspond to the root items. 0067 */ 0068 enum Areas { 0069 ProjectRoot, /**< The root item of the project */ 0070 IndexRoot, /**< The root item of the staged changes */ 0071 WorkTreeRoot, /**< The root item of the unstaged changes */ 0072 UntrackedRoot, /**< The root item of the untracked files */ 0073 ConflictRoot, /**< The root item of the files with unresolved conflicts */ 0074 Index, /**< An item with staged changes */ 0075 WorkTree, /**< An item with unstaged changes */ 0076 Untracked, /**< An untracked item */ 0077 Conflicts, /**< An item with unresolved conflicts */ 0078 None, /**< None of the above */ 0079 }; 0080 0081 /** 0082 * A structure containing the collection of top-level items (i.e. the ones not containing file items) 0083 * corresponding to a project. 0084 */ 0085 struct ProjectItem { 0086 QStandardItem *project, *index, *worktree, *conflicts, *untracked; 0087 bool isValid() const {return project;} 0088 }; 0089 0090 explicit RepoStatusModel(QObject* parent); 0091 ~RepoStatusModel() override; 0092 0093 /** 0094 * Updates the items described by `status`, i.e. moves the 0095 * item(s) corresponding to status.url to the respective areas and 0096 * sets their area role data. 0097 * 0098 * @param pItem the model item for the project that the items belongs to 0099 * @param status the status data 0100 * 0101 * @note the @p pItem must be valid! 0102 */ 0103 void updateState(const ProjectItem& pItem, const KDevelop::VcsStatusInfo& status); 0104 0105 /** 0106 * Runs a job to fetches the statuses of elements (given by `urls`) 0107 * of project `project`. 0108 * 0109 * @param project the project the elements belong to 0110 * @param urls the urls to fetch the status for 0111 * @param mode whether to recurse into subdirectories, if an url is a directory 0112 */ 0113 void fetchStatusesForUrls(KDevelop::IProject* project, const QList<QUrl>& urls, 0114 KDevelop::IBasicVersionControl::RecursionMode mode); 0115 0116 /** 0117 * Returns a list of items corresponding to project roots. 0118 * 0119 * @note we return a const so that the result can be used in for-range 0120 * loops without detaching the container. 0121 */ 0122 const QList<QStandardItem*> projectRoots() const; 0123 0124 /** 0125 * Retrieves the items in a given area of a project. 0126 * 0127 * @param project a project root 0128 * @param area the area to get the items from 0129 * 0130 * @returns a list of items in the given area of the project 0131 * 0132 * @note we return a const so that the result can be used in for-range 0133 * loops without detaching the container. 0134 */ 0135 const QList<QStandardItem*> items(const QStandardItem* project, Areas area) const; 0136 0137 /** 0138 * Returns the ProjectItem structure (containing the project, index, worktree, 0139 * conflicts & untracked items) for project `p`. 0140 * 0141 * @note: Returns a default-constructed ProjectItem{} if @p p is absent from the model. 0142 * This includes the case when @p p is null. 0143 * 0144 * @param p the project 0145 */ 0146 ProjectItem projectItem(const KDevelop::IProject* p) const; 0147 0148 /** 0149 * Returns the ProjectItem structure (containing the project, index, worktree, 0150 * conflicts & untracked items) for the project whose ProjectRoot 0151 * item is `p_item` 0152 * 0153 * @param p_item the ProjectRoot item 0154 */ 0155 ProjectItem projectItem(QStandardItem* p_item) const; 0156 0157 public Q_SLOTS: 0158 0159 /** 0160 * Updates all open projects and removes projects which are not open anymore. 0161 */ 0162 void reloadAll(); 0163 0164 /** 0165 * Updates all items belonging to the projects `p` (and removes the ones 0166 * no longer in the projects). 0167 * 0168 * @param projects the projects to update 0169 */ 0170 void reload(const QList<KDevelop::IProject*>& projects); 0171 0172 /** 0173 * Updates the projects given byl urls `p`. 0174 * 0175 * @param projects the urls of projects to update 0176 */ 0177 void reload(const QList<QUrl>& projects); 0178 0179 /** 0180 * Adds a new project to the model (e.g. when a new project is opened). 0181 * 0182 * @param p the project to add. 0183 */ 0184 void addProject(const KDevelop::IProject* p); 0185 0186 /** 0187 * Removes a project from the model (e.g. when a project is closed). 0188 * 0189 * @param p the project to remove 0190 */ 0191 void removeProject(const KDevelop::IProject* p); 0192 0193 /** 0194 * Processes the result of a job started by `fetchStatusesForUrls` 0195 * 0196 * @param job the KJob to whose results are processed. 0197 */ 0198 void statusReady(KJob* job); 0199 0200 /** 0201 * A handler called to update the status of the item(s) in the model 0202 * when a document is saved 0203 * 0204 * @param doc the document (the item(s) corresponding to this will be 0205 * updated) 0206 */ 0207 void documentSaved(const KDevelop::IDocument* doc); 0208 0209 /** 0210 * A handler called when items are added to a project 0211 */ 0212 void itemsAdded(const QModelIndex& idx, int start, int end); 0213 0214 /** 0215 * A handler called when a job is unregistered. 0216 * 0217 * This is used to monitor when jobs run by the VCS 0218 * (e.g. git add, git commit, etc.) finish so that 0219 * we can schedule an update of the corresponding projects. 0220 */ 0221 void jobUnregistered(KJob*); 0222 0223 /** 0224 * A handler called when the branch is switched in a repo 0225 * to schedule the update of the name of the project. 0226 */ 0227 void repositoryBranchChanged(const QUrl& url); 0228 0229 /** 0230 * A handler for processing the result of a job getting 0231 * the current branch name of a repo. (this job is scheduled 0232 * by the `repositoryBranchChanged` method) 0233 */ 0234 void branchNameReady(KDevelop::VcsJob* job); 0235 0236 private: 0237 /* Functions determining which area(s) a file should be listed in 0238 * depending on its status */ 0239 static bool showInIndex(const GitPlugin::ExtendedState state); 0240 static bool showInWorkTree(const GitPlugin::ExtendedState state); 0241 static bool showInConflicts(const GitPlugin::ExtendedState state); 0242 static bool showInUntracked(const GitPlugin::ExtendedState state); 0243 0244 /** 0245 * Removes all items with url `url` from the model. 0246 * 0247 * @param url the url to remove 0248 * @param parent the parent whose children will be processed (if it is 0249 * null all elements in the model will be processed) 0250 */ 0251 void removeUrl(const QUrl& url, const QStandardItem* parent = nullptr); 0252 0253 /** 0254 * Return the list of all urls for items in project `project` 0255 * 0256 * @param project the project 0257 */ 0258 QList<QUrl> childUrls(const ProjectItem& project) const; 0259 0260 /** 0261 * A helper function to recursively compute all the descendants of 0262 * `parent` and return them as a list. If `parent` is null, all items 0263 * (except the invisible root) are returned 0264 * 0265 * @param parent the node whose children will be returned (if it is 0266 * null all non-root nodes will be returned) 0267 * 0268 * @note we return a const so that the result can be used in for-range 0269 * loops without detaching the container. 0270 */ 0271 const QList<QStandardItem*> allItems(const QStandardItem* parent = nullptr) const; 0272 0273 /** 0274 * A helper function to find the model item corresponding to the project 0275 * @p project 0276 * 0277 * Returns a nullptr if the project is not in the model (e.g. it does not use git) 0278 */ 0279 QStandardItem* findProject(const KDevelop::IProject* project) const; 0280 }; 0281 0282 #endif