File indexing completed on 2024-04-28 04:38:49
0001 /* 0002 SPDX-FileCopyrightText: 2020 Jonathan Verner <jonathan@temno.eu> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #ifndef DIFF_VIEWS_CTRL_H 0008 #define DIFF_VIEWS_CTRL_H 0009 0010 #include "repostatusmodel.h" 0011 0012 #include <KTextEditor/Attribute> 0013 0014 #include <QObject> 0015 0016 class GitPlugin; 0017 class QAction; 0018 0019 namespace KDevelop 0020 { 0021 class IDocument; 0022 class IProject; 0023 class VcsJob; 0024 class VcsDiff; 0025 } 0026 0027 namespace KTextEditor 0028 { 0029 class Document; 0030 class View; 0031 } 0032 0033 /** 0034 * A class which handles displaying & updating tabs showing 0035 * staged/unstaged changes. 0036 */ 0037 class DiffViewsCtrl : public QObject 0038 { 0039 Q_OBJECT 0040 public: 0041 DiffViewsCtrl(QObject* parent = nullptr); 0042 ~DiffViewsCtrl(); 0043 0044 /* Enum values to be passed to the updateDiff method */ 0045 enum UpdateDiffParams { Activate, NoActivate }; 0046 0047 public Q_SLOTS: 0048 0049 /** 0050 * Updates the diff view showing the changes to url and, 0051 * optionally, activates the view. 0052 * 0053 * @param url the url of the file to update the diff for 0054 * @param area the area (determines what type of changes are shown, 0055 * e.g. if area == Index, the diff shows the staged changes) 0056 * @param p if equal to Activate (default), activates the tab, 0057 * if equal to NoActivate, the tab is not activated (e.g. when it is 0058 * refreshed because of changes in an active document). 0059 * 0060 * @note: The tab is not opened immediately, rather a job to compute the 0061 * diff is scheduled and the tab is opened by the @method diffReady 0062 * when the job producing the diff finishes. 0063 * 0064 * @note: If p is equal to NoActivate and there is no tab already 0065 * showing the diff, the function returns without doing anything. 0066 */ 0067 void updateDiff(const QUrl& url, const RepoStatusModel::Areas area, const UpdateDiffParams p = Activate); 0068 0069 /** 0070 * Updates all diff views which are shown for a project. 0071 * The diff views which become empty are closed. 0072 * 0073 * @param proj the project to update diff views for 0074 */ 0075 void updateProjectDiffs(KDevelop::IProject* proj); 0076 0077 /** 0078 * Updates all diff views which are shown for a given url. 0079 * The diff views which become empty are closed. 0080 * 0081 * @param url the url to update diff views for 0082 */ 0083 void updateUrlDiffs(const QUrl& url); 0084 0085 0086 private Q_SLOTS: 0087 /** 0088 * A handler called to open a document tab with a diff when 0089 * the job producing the diff finishes. 0090 * 0091 * @param diffJob the job producing the diff 0092 */ 0093 void diffReady(KDevelop::VcsJob* diffJob); 0094 0095 private: 0096 /* Describes an action on selected lines/hunk in a diff */ 0097 enum ApplyAction { 0098 Stage, 0099 Unstage, 0100 Revert, 0101 }; 0102 0103 /** 0104 * A helper function which applies an action to the currently 0105 * selected lines/hunk in the active diff view. 0106 * 0107 * @param act the action to apply (stage, unstage, revert) 0108 * 0109 * @note: If the view has a non-empty selection, the action will 0110 * be applied to the selected lines; if the selection is 0111 * empty, it will be applied to the hunk which contains 0112 * the current cursor position. 0113 * @note: No confirmation dialog is shown before doing the 0114 * potentially dangerous revert action. 0115 */ 0116 void applySelected(ApplyAction act); 0117 0118 /** 0119 * Reverts the selected lines/diff in the currently active 0120 * document tab showing a diff. 0121 * 0122 * @note: This is a helper method for showing a confirmation 0123 * dialog before reverting, since reverting is an irreversible 0124 * and dangerous action. The actual work is done using the 0125 * @ref:applySelected method. 0126 */ 0127 void revertSelected(); 0128 0129 /** 0130 * Opens the source document at the line corresponding 0131 * to the current line in the currently shown diff 0132 */ 0133 void gotoSrcLine(); 0134 0135 /** 0136 * A helper function which sets up the actions appropriate for a diff view. 0137 * 0138 * The function also creates a context menu for the view, 0139 * adds the appropriate actions to it and sets up a 0140 * connection to update the action's texts based on whether 0141 * a hunk or lines are selected in the active 0142 * view when the menu is shown. 0143 * 0144 * @param view the view to add the actions to 0145 * @param diffType the type of diff view (staged/unstaged). Allowed 0146 * values are @ref RepoStatusModel::Index and 0147 * @ref RepoStatusModel::WorkTree 0148 */ 0149 void setupDiffActions(KTextEditor::View* view, const RepoStatusModel::Areas diffType) const; 0150 0151 QAction *m_stageSelectedAct, /**< Action to stage selected hunk/lines */ 0152 *m_unstageSelectedAct, /**< Action to unstage selected hunk/lines */ 0153 *m_revertSelectedAct, /**< Action to revert selected hunk/lines */ 0154 *m_gotoSrcLineAct; /**< Action to goto a line in the source file */ 0155 0156 /** 0157 * A structure for holding information about a tab 0158 * showing a diff. 0159 * 0160 * @note: A valid instance **must** have non null doc, ktDoc, vcs & project 0161 * project members. 0162 */ 0163 class ViewData 0164 { 0165 public: 0166 RepoStatusModel::Areas area 0167 = RepoStatusModel::None; /**< The type of diff shown (staged/unstaged changes to a file; summary of 0168 staged/unstaged changes for a projects) */ 0169 KDevelop::IDocument* doc = nullptr; /**< The associated IDocument */ 0170 KTextEditor::Document* ktDoc = nullptr; /**< The associated KTextEditor::Document */ 0171 KTextEditor::View* actView 0172 = nullptr; /**< The associated KTextEditor::View, if the tab is currently active; nullptr otherwise */ 0173 GitPlugin* vcs = nullptr; /**< A reference to the git plugin */ 0174 KDevelop::IProject* project = nullptr; /**< A pointer to the project plugin */ 0175 QUrl url; /**< The url of the source file (for which changes are shown), or of the project (if showing a summary 0176 of changes) */ 0177 0178 /** 0179 * Returns true if the instance is valid. 0180 */ 0181 bool isValid() const; 0182 }; 0183 0184 /** 0185 * A helper function to get a ViewData structure for an url. 0186 * 0187 * It first tries to find a suitable structure in m_views and, if not 0188 * found, it creates a new one, caches it in m_views and sets up a connection 0189 * to remove it from the cache when the document is closed (e.g. by the user) 0190 * and to update the shown diff when the document is saved. 0191 * 0192 * @param url the file with the changes 0193 * @param area the type of the diff (staged/unstaged) 0194 */ 0195 const ViewData createView(const QUrl& url, RepoStatusModel::Areas area); 0196 0197 /** 0198 * Returns a ViewData structure for the currently active view. 0199 * 0200 * @note: If there is no active view or it has no associated ViewData structure, 0201 * the returned structure has the actView member set to nullptr. 0202 */ 0203 const ViewData activeView(); 0204 0205 /** 0206 * A helper function to construct the key into the `m_views` map. 0207 * 0208 * @param url the url of the file being diffed 0209 * @param area the type of diff (i.e. staged (Index) / unstaged (WorkTree) changes) 0210 */ 0211 static const QString viewKey(const QUrl& url, RepoStatusModel::Areas area); 0212 0213 /** 0214 * A map holding ViewData structures for opened diff windows. 0215 * A diff window is opened only once per file / diff type (staged, unstaged) and 0216 * is later reused. 0217 * 0218 * The keys are formed by concatenating the url of the document 0219 * being diffed with ':' followed by the RepoStatusModel::Areas 0220 * enum value identifying what type of diff it is (i.e. showing 0221 * staged/unstaged changes). 0222 */ 0223 std::map<QString, ViewData> m_views; 0224 }; 0225 0226 #endif // DIFF_VIEWS_CTRL_H