File indexing completed on 2024-04-28 05:49:06

0001 /*
0002     SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #pragma once
0007 
0008 #include <QFutureWatcher>
0009 #include <QPointer>
0010 #include <QProcess>
0011 #include <QTimer>
0012 #include <QWidget>
0013 
0014 #include "git/gitstatus.h"
0015 
0016 class QTreeView;
0017 class QStringListModel;
0018 class GitStatusModel;
0019 class KateProject;
0020 class QItemSelection;
0021 class QMenu;
0022 class QToolButton;
0023 class QTemporaryFile;
0024 class KateProjectPluginView;
0025 class GitWidgetTreeView;
0026 class QStackedWidget;
0027 class QLineEdit;
0028 class KActionCollection;
0029 
0030 namespace KTextEditor
0031 {
0032 class MainWindow;
0033 class View;
0034 class Document;
0035 }
0036 
0037 enum class ClickAction : uint8_t;
0038 enum class StashMode : uint8_t;
0039 
0040 class GitWidget : public QWidget
0041 {
0042     Q_OBJECT
0043 public:
0044     explicit GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow = nullptr, KateProjectPluginView *pluginView = nullptr);
0045     ~GitWidget() override;
0046 
0047     void init();
0048 
0049     bool eventFilter(QObject *o, QEvent *e) override;
0050 
0051     void showEvent(QShowEvent *e) override;
0052 
0053     /**
0054      * Trigger the GitWidget to update itself.
0055      * It is safe to call it repeatedly in a short time, due to delayed update after the last call.
0056      */
0057     void updateStatus();
0058 
0059     KTextEditor::MainWindow *mainWindow();
0060 
0061     // will just proxy the message to the plugin view
0062     void sendMessage(const QString &message, bool warn);
0063 
0064     QString dotGitPath() const
0065     {
0066         return m_activeGitDirPath;
0067     }
0068 
0069     QString indexPath() const
0070     {
0071         if (m_activeGitDirPath == m_topLevelGitPath) {
0072             return m_activeGitDirPath + QStringLiteral(".git/index");
0073         }
0074         // Should we support submodules?
0075         return QString();
0076     }
0077 
0078 private:
0079     /** These ends with "/", always remember this */
0080 
0081     // This variable contains the current active git path
0082     // being tracked by this widget
0083     QString m_activeGitDirPath;
0084     // This variable contains the topLevel git path
0085     QString m_topLevelGitPath;
0086     // This variable contains all submodule paths
0087     QStringList m_submodulePaths;
0088 
0089     /**
0090      * Helper to avoid multiple reloads at a time
0091      * @see slotUpdateStatus
0092      */
0093     QTimer m_updateTrigger;
0094 
0095     QToolButton *m_menuBtn;
0096     QToolButton *m_commitBtn;
0097     QToolButton *m_pushBtn;
0098     QToolButton *m_pullBtn;
0099     QToolButton *m_cancelBtn;
0100     KateProject *m_project;
0101     GitWidgetTreeView *m_treeView;
0102     GitStatusModel *m_model;
0103     QLineEdit *m_filterLineEdit;
0104     QFutureWatcher<GitUtils::GitParsedStatus> m_gitStatusWatcher;
0105     QString m_commitMessage;
0106     KTextEditor::MainWindow *m_mainWin;
0107     QMenu *m_gitMenu;
0108     KateProjectPluginView *m_pluginView;
0109     bool m_initialized = false;
0110 
0111     QWidget *m_mainView;
0112     QStackedWidget *m_stackWidget;
0113 
0114     using CancelHandle = QPointer<QProcess>;
0115     CancelHandle m_cancelHandle;
0116 
0117     void setDotGitPath();
0118     void setSubmodulesPaths();
0119     void setActiveGitDir();
0120     void selectActiveFileInStatus();
0121 
0122     QProcess *gitp(const QStringList &arguments);
0123 
0124     void buildMenu(KActionCollection *ac);
0125     void runGitCmd(const QStringList &args, const QString &i18error);
0126     void runPushPullCmd(const QStringList &args);
0127     void stage(const QStringList &files, bool = false);
0128     void unstage(const QStringList &files);
0129     void discard(const QStringList &files);
0130     void clean(const QStringList &files);
0131     void openAtHEAD(const QString &file);
0132     void showDiff(const QString &file, bool staged);
0133     void launchExternalDiffTool(const QString &file, bool staged);
0134     void commitChanges(const QString &msg, const QString &desc, bool signOff, bool amend = false);
0135     void branchCompareFiles(const QString &from, const QString &to);
0136 
0137     QMenu *stashMenu(KActionCollection *pCollection);
0138     QAction *stashMenuAction(KActionCollection *ac, const QString &name, const QString &text, StashMode m);
0139 
0140     void treeViewContextMenuEvent(QContextMenuEvent *e);
0141     void selectedContextMenu(QContextMenuEvent *e);
0142 
0143     void createStashDialog(StashMode m, const QString &gitPath);
0144 
0145     void enableCancel(QProcess *git);
0146     void hideCancel();
0147 
0148 private Q_SLOTS:
0149     /**
0150      * Does the real update
0151      */
0152     void slotUpdateStatus();
0153 
0154     void parseStatusReady();
0155     void openCommitChangesDialog(bool amend = false);
0156     void handleClick(const QModelIndex &idx, ClickAction clickAction);
0157     void treeViewSingleClicked(const QModelIndex &idx);
0158     void treeViewDoubleClicked(const QModelIndex &idx);
0159 
0160     // signals
0161 public:
0162     Q_SIGNAL void checkoutBranch();
0163 };