1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "svnclientwidget.h"
6#include "reposwidget.h"
7#include "checkoutdialog.h"
8#include "common/common.h"
9
10#include "QPinnableTabWidget.h"
11#include "GitQlientStyles.h"
12#include "QLogger.h"
13
14#include <QMenu>
15#include <QEvent>
16#include <QPushButton>
17#include <QFileInfo>
18#include <QMessageBox>
19#include <QLabel>
20#include <QProcess>
21#include <QFileDialog>
22
23SvnClientWidget::SvnClientWidget(QWidget *parent, Qt::WindowFlags flags)
24 : QMainWindow (parent, flags)
25 , mRepos(new QPinnableTabWidget())
26{
27 mRepos = new QPinnableTabWidget();
28 const auto homeMenu = new QPushButton();
29 const auto menu = new QMenu(homeMenu);
30 menu->installEventFilter(this);
31
32 homeMenu->setIcon(QIcon(":/icons/burger_menu"));
33 homeMenu->setIconSize(QSize(17, 17));
34 homeMenu->setToolTip("Options");
35 homeMenu->setMenu(menu);
36 homeMenu->setObjectName("MainMenuBtn");
37
38 const auto clone = menu->addAction(QAction::tr("Checkout repository"));
39 ActionManager::getInstance()->registerAction(clone, "SVN.Checkout.Repository",
40 tr("Checkout repository"), QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::SHIFT | Qt::Key::Key_C),
41 ":/collaborators/images/checkout.png");
42 connect(clone, &QAction::triggered, this, &SvnClientWidget::showCheckoutDialog);
43
44 const auto open = menu->addAction(QAction::tr("Open repository"));
45 ActionManager::getInstance()->registerAction(open, "SVN.Open.Repository",
46 tr("Open repository"), QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::SHIFT | Qt::Key::Key_R),
47 ":/collaborators/images/open_repository.png");
48 connect(open, &QAction::triggered, this, &SvnClientWidget::showOpenLocalRepos);
49
50 mRepos->setObjectName("GitQlientTab");
51 mRepos->setStyleSheet(GitQlientStyles::getStyles());
52 mRepos->setCornerWidget(homeMenu, Qt::TopLeftCorner);
53 setCentralWidget(mRepos);
54}
55
56void SvnClientWidget::addRepoTab(const QString &repoPath, const QString &user, const QString &passwd)
57{
58 if (!isSvnDir(repoPath)) {
59 ContextDialog::ok(QDialog::tr("Open path failed, current repos not svn subdir"));
60 return;
61 }
62 addNewRepoTab(repoPath, user, passwd);
63}
64
65void SvnClientWidget::addNewRepoTab(const QString &repoPathArg, const QString &user, const QString &passwd)
66{
67 const auto repoPath = QFileInfo(repoPathArg).canonicalFilePath();
68
69 if (!mCurrentRepos.contains(repoPath)) {
70 const auto repoName = repoPath.contains("/") ? repoPath.split("/").last() : "";
71 auto reposWidget = new ReposWidget;
72 reposWidget->setName(user);
73 reposWidget->setPasswd(passwd);
74 reposWidget->setReposPath(repoPathArg);
75 const int index = mRepos->addTab(reposWidget, repoName);
76 mRepos->setTabIcon(index, QIcon(QString(":/icons/local")));
77 }
78}
79
80void SvnClientWidget::showCheckoutDialog()
81{
82 CheckoutDialog dialog;
83 dialog.connect(&dialog, &CheckoutDialog::checkoutRepos, this, &SvnClientWidget::doCheckoutRepos);
84 dialog.exec();
85}
86
87void SvnClientWidget::showOpenLocalRepos()
88{
89 QUrl url = QFileDialog::getExistingDirectoryUrl(nullptr, tr("select local reops"));
90 if (!url.isEmpty()) {
91 addRepoTab(url.toLocalFile());
92 }
93}
94
95void SvnClientWidget::doCheckoutRepos(const QString &remote, const QString &local, const QString &user, const QString &passwd)
96{
97 auto dialog = qobject_cast<CheckoutDialog*>(sender());
98 if (svnProgram().isEmpty()) {
99 return;
100 }
101 QProcess process;
102 QEventLoop eventLoop;
103 connect(&process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
104 [&]() {
105 eventLoop.exit();
106 });
107
108 process.setProgram(svnProgram());
109 process.setArguments({"checkout", remote, local, "--username", user, "--password", passwd});
110 process.start();
111 process.waitForStarted();
112 StatusWidget *status = new StatusWidget(StatusWidget::Simple, dialog);
113 status->setRunningColor(QColor(Qt::gray));
114 status->move(200, 130);
115 status->show();
116 status->start();
117 eventLoop.exec();
118 status->stop();
119 delete status;
120 if (process.exitCode() != 0 || process.exitStatus() != QProcess::ExitStatus::NormalExit) {
121 ContextDialog::ok(process.readAllStandardError());
122 return;
123 }
124
125 auto okCb = [=](bool checked){
126 Q_UNUSED(checked)
127 addRepoTab(local, user, passwd);
128 };
129
130 ContextDialog::okCancel(QString("checkout repos successful, now to open with user %0?").arg(user),
131 "Message", QMessageBox::Icon::Question, okCb);
132}
133
134bool SvnClientWidget::isSvnDir(const QString &repoPath)
135{
136 QDir dir(repoPath + QDir::separator() + ".svn");
137 return dir.exists();
138}
139
140bool SvnClientWidget::eventFilter(QObject *obj, QEvent *event)
141{
142 const auto menu = qobject_cast<QMenu *>(obj);
143 if (menu && event->type() == QEvent::Show) {
144 auto localPos = menu->parentWidget()->pos();
145 auto pos = mapToGlobal(localPos);
146 menu->show();
147 pos.setY(pos.y() + menu->parentWidget()->height());
148 menu->move(pos);
149 return true;
150 }
151
152 return false;
153}
154