1 /* 2 SPDX-FileCopyrightText: 2020 Jonathan L. Verner <jonathan.verner@matfyz.cz> 3 4 SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7 #ifndef KDEVPLATFORM_PLUGIN_COMMIT_TOOLVIEW_H 8 #define KDEVPLATFORM_PLUGIN_COMMIT_TOOLVIEW_H 9 10 #include "repostatusmodel.h" 11 12 #include <interfaces/iuicontroller.h> 13 14 #include <KTextEditor/Attribute> 15 16 #include <QWidget> 17 18 class ActiveStyledDelegate; 19 class DiffViewsCtrl; 20 class FilterEmptyItemsProxyModel; 21 class RepoStatusModel; 22 class SimpleCommitForm; 23 24 class QAction; 25 class QMenu; 26 class QModelIndex; 27 class QLineEdit; 28 class QTreeView; 29 class QAbstractProxyModel; 30 class QUrl; 31 32 namespace KDevelop { 33 class IBasicVersionControl; 34 class IDocument; 35 class IProject; 36 class VcsJob; 37 } 38 39 namespace KTextEditor { 40 class View; 41 class Document; 42 } 43 44 /** 45 * This implements the git-cola like toolview for preparing commits. 46 * 47 * The view contains a list of projects. Each project contains four 48 * lists: 49 * 50 * - the staged changes list lists all files in the project which 51 * have changes staged for commit; 52 * - the unstaged changes list lists all files in the project which 53 * have changes which are not currently staged for commit; 54 * - the conflicts list lists all files which have unresolved (merge) 55 * conflicts; and 56 * - the untracked list which lists all files not tracked in the VCS 57 * 58 * Clicking on a file in one of the staged/unstaged lists opens a document 59 * tab with the diff showing the changes. The user can then select lines/hunks 60 * from the diff and remove/add them from the staged changes using the context menu. 61 * 62 * Double clicking on a file will, instead, stage/unstage all changes in the file 63 * or mark the conflicts as resolved or add the file to be tracked in VCS. 64 * 65 * Above these lists a lineedit and a textedit may be used to prepare a 66 * commit message. The commit button will commit the staged changes to the 67 * repo. If several projects are listed, the one which is expanded will be 68 * used (only one project is allowed to be expaned to show the lists at a time, 69 * an expaned project is automatically collapsed when a different one is expanded). 70 * 71 * @author Jonathan L. Verner <jonathan.verner@matfyz.cz> 72 */ 73 74 class CommitToolView : public QWidget 75 { 76 Q_OBJECT 77 78 public: 79 enum ShowDiffParams { Activate, NoActivate }; 80 81 /** 82 * @note: m_statusmodel remains the property of the caller whose 83 * responsibility is to delete it (and care must be taken not 84 * to delete it before the CommitToolView is deleted) 85 */ 86 CommitToolView(QWidget* parent, RepoStatusModel* m_statusmodel); 87 88 /** 89 * @returns the currently active project (i.e. the one that 90 * is expanded in the treeview) 91 */ 92 KDevelop::IProject* activeProject() const; 93 94 /** 95 * @returns the index of the currently active project (i.e. the one that 96 * is expanded in the treeview) 97 */ 98 QStandardItem* activeProjectItem() const; 99 100 /** 101 * @returns true if the item pointed to by the repostatusmodel index 102 * idx is the root item of the currently active project. 103 */ 104 bool isActiveProject(const QModelIndex& idx) const; 105 106 Q_SIGNALS: 107 108 /** 109 * This signal is emitted when the view wants to show a diff 110 * 111 * @param url the url to display the changes for 112 * @param area the type of changes to display 113 */ 114 void showDiff(const QUrl& url, const RepoStatusModel::Areas area); 115 116 /** 117 * This signal is emitted when the view wants to show a file 118 * 119 * @param url the url of the file to show 120 */ 121 void showSource(const QUrl& url); 122 123 /** 124 * This signal is emitted when the diff showing changes of type @param area 125 * to the file @param url needs to be updated. 126 */ 127 void updateDiff(const QUrl& url, const RepoStatusModel::Areas area); 128 129 /** 130 * This signal is emitted when all diffs showing changes to files in 131 * project @param project need to be updated. 132 */ 133 void updateProjectDiffs(KDevelop::IProject* project); 134 135 /** 136 * This signal is emitted when all diffs showing changes to the file 137 * @param url need to be updated. 138 * 139 * @note: In contrast to the updateDiff signal, this also includes diffs 140 * showing all changes to the owning project (staged/unstaged) 141 */ 142 void updateUrlDiffs(const QUrl& url); 143 144 public Q_SLOTS: 145 /** 146 * Shows the toolview context menu 147 */ 148 void popupContextMenu(const QPoint& pos); 149 150 /** 151 * A handler called when the user double clicks 152 * an item in the treeview. 153 */ 154 void dblClicked(const QModelIndex& idx); 155 156 /** 157 * A handler called when the user clicks an item 158 * in the treeview. 159 */ 160 void clicked(const QModelIndex& idx); 161 162 /** 163 * A handler called when a user expands an item 164 * in the treeview. 165 */ 166 void activateProject(const QModelIndex& idx); 167 168 /** 169 * Stages the staged changes in the given files. 170 * 171 * @param urls the list of files whose changes to stage 172 */ 173 void stageSelectedFiles(const QList<QUrl>& urls); 174 175 /** 176 * Unstages the staged changes in the given files. 177 * 178 * @param urls the list of files whose changes to unstage 179 */ 180 void unstageSelectedFiles(const QList<QUrl>& urls); 181 182 /** 183 * Reverts the uncommited changes in the given files. 184 * 185 * @param urls the list of files whose changes to revert 186 * 187 * @note: This is an irreversible and dangerous action, 188 * a confirmation dialog is shown before it is applied 189 */ 190 void revertSelectedFiles(const QList<QUrl>& urls); 191 192 /** 193 * Runs git commit on the staged changes. The commit message 194 * is constructed from the data in the commit form. 195 * 196 * @note This function assumes that there are some staged changes. 197 * @note The extended description of the commit is wrapped at 70 columns 198 */ 199 void commitActiveProject(); 200 201 private: 202 203 /* Describes an action on selected lines/hunk in a diff */ 204 enum ApplyAction { 205 Stage, 206 Unstage, 207 Revert, 208 }; 209 210 /** 211 * Updates the toolview layout based on the dock area position: 212 * 213 * When the toolview is placed on the left/right, all the widgets 214 * sit on top of each other; when it is placed on the top/bottom, 215 * the commit area (commit header, button, description textedit) 216 * will sit to the left of the changes view with the search filter. 217 */ 218 219 void doLayOut(const Qt::DockWidgetArea area); 220 221 /** 222 * A helper function which return the VCS plugin which 223 * handles `url`. 224 * 225 * @param url the url for which the plugin is returned 226 * 227 * @note: Returns nullptr if no project/VCS plugin for the 228 * given url exists. 229 */ 230 KDevelop::IBasicVersionControl* vcsPluginForUrl(const QUrl& url) const; 231 232 /** 233 * The model which lists the projects and staged/modified/... files 234 * which are shown in the treeview. 235 */ 236 RepoStatusModel* m_statusmodel; 237 238 /** 239 * The filtered repostatus model 240 */ 241 FilterEmptyItemsProxyModel* m_proxymodel; 242 243 /** The form for composing the commit message and doing the commit. */ 244 SimpleCommitForm* m_commitForm = nullptr; 245 246 /** The treeview listing the projects & their staged/modified/... files */ 247 QTreeView* m_view = nullptr; 248 249 /** The lineedit for filtering the treeview */ 250 QLineEdit* m_filter = nullptr; 251 252 /**************************************** 253 * Various contextmenus & their actions * 254 ****************************************/ 255 256 QMenu 257 /** Menu with a single "Refresh" action (shown for projects in the toolview) */ 258 *m_refreshMenu 259 /** Menu with stage/unstage/revert actions (shown for files in the toolview) */ 260 , *m_toolviewMenu 261 ; 262 QAction *m_refreshModelAct 263 , *m_stageFilesAct 264 , *m_unstageFilesAct 265 , *m_revertFilesAct 266 ; 267 268 /** A style delegate for showing the currently selected project in bold */ 269 ActiveStyledDelegate* m_styleDelegate; 270 }; 271 272 /** 273 * A factory for creating CommitToolViews. 274 */ 275 class CommitToolViewFactory : public KDevelop::IToolViewFactory 276 { 277 public: 278 explicit CommitToolViewFactory(RepoStatusModel* statusModel); 279 ~CommitToolViewFactory(); 280 QWidget* create(QWidget* parent = nullptr) override; 281 Qt::DockWidgetArea defaultPosition() const override; 282 QString id() const override; 283 284 private: 285 RepoStatusModel* m_statusmodel; 286 DiffViewsCtrl* m_diffViewsCtrl; 287 }; 288 289 #endif 290