File: diffviewsctrl.h

package info (click to toggle)
kdevelop 4%3A25.04.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 73,508 kB
  • sloc: cpp: 291,803; python: 4,322; javascript: 3,518; sh: 1,316; ansic: 703; xml: 414; php: 95; lisp: 66; makefile: 31; sed: 12
file content (226 lines) | stat: -rw-r--r-- 7,788 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
    SPDX-FileCopyrightText: 2020 Jonathan Verner <jonathan@temno.eu>

    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

#ifndef DIFF_VIEWS_CTRL_H
#define DIFF_VIEWS_CTRL_H

#include "repostatusmodel.h"

#include <KTextEditor/Attribute>

#include <QObject>

class GitPlugin;
class QAction;

namespace KDevelop
{
class IDocument;
class IProject;
class VcsJob;
class VcsDiff;
}

namespace KTextEditor
{
class Document;
class View;
}

/**
 * A class which handles displaying & updating tabs showing
 * staged/unstaged changes.
 */
class DiffViewsCtrl : public QObject
{
    Q_OBJECT
public:
    DiffViewsCtrl(QObject* parent = nullptr);
    ~DiffViewsCtrl();

    /* Enum values to be passed to the updateDiff method */
    enum UpdateDiffParams { Activate, NoActivate };

public Q_SLOTS:

    /**
     * Updates the diff view showing the changes to url and,
     * optionally, activates the view.
     *
     * @param url the url of the file to update the diff for
     * @param area the area (determines what type of changes are shown,
     * e.g. if area == Index, the diff shows the staged changes)
     * @param p if equal to Activate (default), activates the tab,
     * if equal to NoActivate, the tab is not activated (e.g. when it is
     * refreshed because of changes in an active document).
     *
     * @note: The tab is not opened immediately, rather a job to compute the
     * diff is scheduled and the tab is opened by the @method diffReady
     * when the job producing the diff finishes.
     *
     * @note: If p is equal to NoActivate and there is no tab already
     * showing the diff, the function returns without doing anything.
     */
    void updateDiff(const QUrl& url, const RepoStatusModel::Areas area, const UpdateDiffParams p = Activate);

    /**
     * Updates all diff views which are shown for a project.
     * The diff views which become empty are closed.
     *
     * @param proj the project to update diff views for
     */
    void updateProjectDiffs(KDevelop::IProject* proj);

    /**
     * Updates all diff views which are shown for a given url.
     * The diff views which become empty are closed.
     *
     * @param url the url to update diff views for
     */
    void updateUrlDiffs(const QUrl& url);


private Q_SLOTS:
    /**
     * A handler called to open a document tab with a diff when
     * the job producing the diff finishes.
     *
     * @param diffJob the job producing the diff
     */
    void diffReady(KDevelop::VcsJob* diffJob);

private:
    /* Describes an action on selected lines/hunk in a diff */
    enum ApplyAction {
        Stage,
        Unstage,
        Revert,
    };

    /**
     * A helper function which applies an action to the currently
     * selected lines/hunk in the active diff view.
     *
     * @param act the action to apply (stage, unstage, revert)
     *
     * @note: If the view has a non-empty selection, the action will
     *        be applied to the selected lines; if the selection is
     *        empty, it will be applied to the hunk which contains
     *        the current cursor position.
     * @note: No confirmation dialog is shown before doing the
     *        potentially dangerous revert action.
     */
    void applySelected(ApplyAction act);

    /**
     * Reverts the selected lines/diff in the currently active
     * document tab showing a diff.
     *
     * @note: This is a helper method for showing a confirmation
     * dialog before reverting, since reverting is an irreversible
     * and dangerous action. The actual work is done using the
     * @ref:applySelected method.
     */
    void revertSelected();

    /**
     * Opens the source document at the line corresponding
     * to the current line in the currently shown diff
     */
    void gotoSrcLine();

    /**
     * A helper function which sets up the actions appropriate for a diff view.
     *
     * The function also creates a context menu for the view,
     * adds the appropriate actions to it and sets up a
     * connection to update the action's texts based on whether
     * a hunk or lines are selected in the active
     * view when the menu is shown.
     *
     * @param view the view to add the actions to
     * @param diffType the type of diff view (staged/unstaged). Allowed
     *                 values are @ref RepoStatusModel::Index and
     *                 @ref RepoStatusModel::WorkTree
     */
    void setupDiffActions(KTextEditor::View* view, const RepoStatusModel::Areas diffType) const;

    QAction *m_stageSelectedAct,    /**< Action to stage selected hunk/lines */
            *m_unstageSelectedAct,  /**< Action to unstage selected hunk/lines */
            *m_revertSelectedAct,   /**< Action to revert selected hunk/lines */
            *m_gotoSrcLineAct;      /**< Action to goto a line in the source file */

    /**
     * A structure for holding information about a tab
     * showing a diff.
     *
     * @note: A valid instance **must** have non null doc, ktDoc, vcs & project
     * project members.
     */
    class ViewData
    {
    public:
        RepoStatusModel::Areas area
            = RepoStatusModel::None; /**< The type of diff shown (staged/unstaged changes to a file; summary of
                                        staged/unstaged changes for a projects) */
        KDevelop::IDocument* doc = nullptr; /**< The associated IDocument */
        KTextEditor::Document* ktDoc = nullptr; /**< The associated KTextEditor::Document */
        KTextEditor::View* actView
            = nullptr; /**< The associated KTextEditor::View, if the tab is currently active; nullptr otherwise */
        GitPlugin* vcs = nullptr; /**< A reference to the git plugin */
        KDevelop::IProject* project = nullptr; /**< A pointer to the project plugin */
        QUrl url; /**< The url of the source file (for which changes are shown), or of the project (if showing a summary
                     of changes) */

        /**
         * Returns true if the instance is valid.
         */
        bool isValid() const;
    };

    /**
     * A helper function to get a ViewData structure for an url.
     *
     * It first tries to find a suitable structure in m_views and, if not
     * found, it creates a new one, caches it in m_views and sets up a connection
     * to remove it from the cache when the document is closed (e.g. by the user)
     * and to update the shown diff when the document is saved.
     *
     * @param url the file with the changes
     * @param area the type of the diff (staged/unstaged)
     */
    const ViewData createView(const QUrl& url, RepoStatusModel::Areas area);

    /**
     * Returns a ViewData structure for the currently active view.
     *
     * @note: If there is no active view or it has no associated ViewData structure,
     * the returned structure has the actView member set to nullptr.
     */
    const ViewData activeView();

    /**
     * A helper function to construct the key into the `m_views` map.
     *
     * @param url the url of the file being diffed
     * @param area the type of diff (i.e. staged (Index) / unstaged (WorkTree) changes)
     */
    static const QString viewKey(const QUrl& url, RepoStatusModel::Areas area);

    /**
     * A map holding ViewData structures for opened diff windows.
     * A diff window is opened only once per file / diff type (staged, unstaged) and
     * is later reused.
     *
     * The keys are formed by concatenating the url of the document
     * being diffed with ':' followed by the RepoStatusModel::Areas
     * enum value identifying what type of diff it is (i.e. showing
     * staged/unstaged changes).
     */
    std::map<QString, ViewData> m_views;
};

#endif // DIFF_VIEWS_CTRL_H