1#include "InitScreen.h"
2
3#include <GeneralConfigDlg.h>
4#include <CreateRepoDlg.h>
5#include <ProgressDlg.h>
6#include <GitQlientSettings.h>
7#include <GitBase.h>
8#include <GitConfig.h>
9#include <ButtonLink.hpp>
10
11#include <QPushButton>
12#include <QGridLayout>
13#include <QFileDialog>
14#include <QButtonGroup>
15#include <QStackedWidget>
16#include <QStyle>
17#include <QLabel>
18#include <QApplication>
19#include <QMessageBox>
20#include <QtGlobal>
21#include <QDesktopServices>
22#include <GitQlientStyles.h>
23
24#include <QLogger.h>
25
26using namespace QLogger;
27
28InitScreen::InitScreen(QWidget *parent)
29 : QFrame(parent)
30 , mOpenRepo(new QPushButton(tr("OPEN")))
31 , mCloneRepo(new QPushButton(tr("CLONE")))
32 , mInitRepo(new QPushButton(tr("NEW")))
33{
34 setAttribute(Qt::WA_DeleteOnClose);
35
36 setStyleSheet(GitQlientStyles::getStyles());
37
38 mOpenRepo->setObjectName("bigButton");
39 mCloneRepo->setObjectName("bigButton");
40 mInitRepo->setObjectName("bigButton");
41
42 // Adding buttons to open or init repos
43 const auto repoOptionsFrame = new QFrame();
44 const auto repoOptionsLayout = new QHBoxLayout(repoOptionsFrame);
45 repoOptionsLayout->setSpacing(0);
46 repoOptionsLayout->setContentsMargins(QMargins());
47 repoOptionsLayout->addWidget(mOpenRepo);
48 repoOptionsLayout->addStretch();
49 repoOptionsLayout->addWidget(mCloneRepo);
50 repoOptionsLayout->addStretch();
51 repoOptionsLayout->addWidget(mInitRepo);
52
53 const auto projectsFrame = new QFrame();
54 mRecentProjectsLayout = new QVBoxLayout(projectsFrame);
55 mRecentProjectsLayout->setContentsMargins(QMargins());
56 mRecentProjectsLayout->addWidget(createRecentProjectsPage());
57
58 const auto mostUsedProjectsFrame = new QFrame();
59 mUsedProjectsLayout = new QVBoxLayout(mostUsedProjectsFrame);
60 mUsedProjectsLayout->setContentsMargins(QMargins());
61 mUsedProjectsLayout->addWidget(createUsedProjectsPage());
62
63 const auto widgetsLayout = new QHBoxLayout();
64 widgetsLayout->setSpacing(10);
65 widgetsLayout->setContentsMargins(0, 10, 0, 10);
66 widgetsLayout->addWidget(projectsFrame);
67 widgetsLayout->addStretch();
68 widgetsLayout->addWidget(mostUsedProjectsFrame);
69
70 const auto title = new QLabel(tr("GitQlient %1").arg(VER));
71 title->setObjectName("title");
72
73 const auto gitqlientIcon = new QLabel();
74 QIcon stagedIcon(":/icons/GitQlientLogoSVG");
75 gitqlientIcon->setPixmap(stagedIcon.pixmap(96, 96));
76
77 const auto configBtn = new QPushButton();
78 configBtn->setIcon(QIcon(":/icons/config"));
79 connect(configBtn, &QPushButton::clicked, this, &InitScreen::openConfigDlg);
80
81 const auto titleLayout = new QHBoxLayout();
82 titleLayout->setContentsMargins(QMargins());
83 titleLayout->setSpacing(10);
84 titleLayout->addStretch();
85 titleLayout->addWidget(gitqlientIcon);
86 titleLayout->addWidget(title);
87 titleLayout->addStretch();
88 titleLayout->addWidget(configBtn);
89
90 const auto lineTitle = new QFrame();
91 lineTitle->setObjectName("orangeHSeparator");
92
93 const auto lineTitle2 = new QFrame();
94 lineTitle2->setObjectName("orangeHSeparator");
95
96 const auto version = new ButtonLink(tr("About GitQlient..."));
97 connect(version, &ButtonLink::clicked, this, &InitScreen::showAbout);
98 version->setToolTip(QString("%1").arg(SHA_VER));
99
100 const auto goToRepo = new ButtonLink(tr("Source code"));
101 connect(goToRepo, &ButtonLink::clicked, this,
102 []() { QDesktopServices::openUrl(QUrl("https://www.github.com/francescmm/GitQlient")); });
103 goToRepo->setToolTip(tr("Get the source code in GitHub"));
104
105 const auto goToBlog = new ButtonLink(tr("Report an issue"));
106 connect(goToBlog, &ButtonLink::clicked, this,
107 []() { QDesktopServices::openUrl(QUrl("https://github.com/francescmm/GitQlient/issues/new/choose")); });
108 goToBlog->setToolTip(tr("Report an issue in GitHub"));
109
110 const auto promoLayout = new QHBoxLayout();
111 promoLayout->setContentsMargins(QMargins());
112 promoLayout->setSpacing(0);
113 promoLayout->addWidget(version);
114 promoLayout->addStretch();
115 promoLayout->addWidget(goToRepo);
116 promoLayout->addStretch();
117 promoLayout->addWidget(goToBlog);
118
119 const auto centerFrame = new QFrame();
120 centerFrame->setObjectName("InitWidget");
121 const auto centerLayout = new QVBoxLayout(centerFrame);
122 centerLayout->setSpacing(10);
123 centerLayout->setContentsMargins(QMargins());
124 centerLayout->addLayout(titleLayout);
125 centerLayout->addWidget(lineTitle);
126 centerLayout->addWidget(repoOptionsFrame);
127 centerLayout->addLayout(widgetsLayout);
128 centerLayout->addWidget(lineTitle2);
129 centerLayout->addLayout(promoLayout);
130 centerLayout->addStretch();
131
132 const auto layout = new QGridLayout(this);
133 layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, 0);
134 layout->addWidget(centerFrame, 1, 1);
135 layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), 2, 2);
136
137 connect(mOpenRepo, &QPushButton::clicked, this, &InitScreen::openRepo);
138 connect(mCloneRepo, &QPushButton::clicked, this, &InitScreen::cloneRepo);
139 connect(mInitRepo, &QPushButton::clicked, this, &InitScreen::initRepo);
140
141 const auto gitBase(QSharedPointer<GitBase>::create(""));
142 mGit = QSharedPointer<GitConfig>::create(gitBase);
143
144 connect(mGit.data(), &GitConfig::signalCloningProgress, this, &InitScreen::updateProgressDialog,
145 Qt::DirectConnection);
146 connect(mGit.data(), &GitConfig::signalCloningFailure, this, &InitScreen::showError, Qt::DirectConnection);
147}
148
149void InitScreen::openRepo()
150{
151 const QString dirName(QFileDialog::getExistingDirectory(this, "Choose the directory of a Git project"));
152
153 if (!dirName.isEmpty())
154 {
155 QDir d(dirName);
156 emit signalOpenRepo(d.absolutePath());
157 }
158}
159
160void InitScreen::cloneRepo()
161{
162 CreateRepoDlg cloneDlg(CreateRepoDlgType::CLONE, mGit, this);
163 connect(&cloneDlg, &CreateRepoDlg::signalOpenWhenFinish, this, [this](const QString &path) { mPathToOpen = path; });
164
165 if (cloneDlg.exec() == QDialog::Accepted)
166 {
167 mProgressDlg = new ProgressDlg(tr("Loading repository..."), QString(), 100, false);
168 connect(mProgressDlg, &ProgressDlg::destroyed, this, [this]() { mProgressDlg = nullptr; });
169 mProgressDlg->show();
170 }
171}
172
173void InitScreen::initRepo()
174{
175 CreateRepoDlg cloneDlg(CreateRepoDlgType::INIT, mGit, this);
176 connect(&cloneDlg, &CreateRepoDlg::signalOpenWhenFinish, this, &InitScreen::signalOpenRepo);
177 cloneDlg.exec();
178}
179
180QWidget *InitScreen::createRecentProjectsPage()
181{
182 delete mInnerWidget;
183 mInnerWidget = new QFrame();
184
185 auto title = new QLabel(tr("Recent"));
186 title->setStyleSheet("font-size: 14pt;");
187
188 const auto innerLayout = new QVBoxLayout(mInnerWidget);
189 innerLayout->setContentsMargins(QMargins());
190 innerLayout->setSpacing(10);
191 innerLayout->addWidget(title);
192
193 const auto projects = GitQlientSettings().getRecentProjects();
194
195 for (auto project : projects)
196 {
197 const auto projectName = project.mid(project.lastIndexOf("/") + 1);
198 const auto labelText = QString("%1<br><em>%2</em>").arg(projectName, project);
199 const auto clickableFrame = new ButtonLink(labelText, this);
200 connect(clickableFrame, &ButtonLink::clicked, this, [this, project]() { emit signalOpenRepo(project); });
201 innerLayout->addWidget(clickableFrame);
202 }
203
204 innerLayout->addStretch();
205
206 const auto clear = new ButtonLink(tr("Clear list"));
207 clear->setVisible(!projects.isEmpty());
208 connect(clear, &ButtonLink::clicked, this, [this]() {
209 GitQlientSettings().clearRecentProjects();
210
211 mRecentProjectsLayout->addWidget(createRecentProjectsPage());
212 });
213
214 const auto lineTitle = new QFrame();
215 lineTitle->setObjectName("separator");
216
217 innerLayout->addWidget(lineTitle);
218 innerLayout->addWidget(clear);
219
220 return mInnerWidget;
221}
222
223QWidget *InitScreen::createUsedProjectsPage()
224{
225 delete mMostUsedInnerWidget;
226 mMostUsedInnerWidget = new QFrame();
227
228 auto title = new QLabel(tr("Most used"));
229 title->setStyleSheet("font-size: 14pt;");
230
231 const auto innerLayout = new QVBoxLayout(mMostUsedInnerWidget);
232 innerLayout->setContentsMargins(QMargins());
233 innerLayout->setSpacing(10);
234 innerLayout->addWidget(title);
235
236 const auto projects = GitQlientSettings().getMostUsedProjects();
237
238 for (auto project : projects)
239 {
240 const auto projectName = project.mid(project.lastIndexOf("/") + 1);
241 const auto labelText = QString("%1<br><em>%2</em>").arg(projectName, project);
242 const auto clickableFrame = new ButtonLink(labelText);
243 connect(clickableFrame, &ButtonLink::clicked, this, [this, project]() { emit signalOpenRepo(project); });
244 innerLayout->addWidget(clickableFrame);
245 }
246
247 innerLayout->addStretch();
248
249 const auto clear = new ButtonLink(tr("Clear list"));
250 clear->setVisible(!projects.isEmpty());
251 connect(clear, &ButtonLink::clicked, this, [this]() {
252 GitQlientSettings().clearMostUsedProjects();
253
254 mUsedProjectsLayout->addWidget(createUsedProjectsPage());
255 });
256
257 const auto lineTitle = new QFrame();
258 lineTitle->setObjectName("separator");
259
260 innerLayout->addWidget(lineTitle);
261 innerLayout->addWidget(clear);
262
263 return mMostUsedInnerWidget;
264}
265
266void InitScreen::updateProgressDialog(QString stepDescription, int value)
267{
268 if (value >= 0)
269 {
270 mProgressDlg->setValue(value);
271
272 if (stepDescription.contains("done", Qt::CaseInsensitive))
273 {
274 mProgressDlg->close();
275 emit signalOpenRepo(mPathToOpen);
276
277 mPathToOpen = "";
278 }
279 }
280
281 mProgressDlg->setLabelText(stepDescription);
282 mProgressDlg->repaint();
283}
284
285void InitScreen::showError(int, QString description)
286{
287 if (mProgressDlg)
288 mProgressDlg->deleteLater();
289
290 QMessageBox::critical(this, tr("Error!"), description);
291}
292
293void InitScreen::showAbout()
294{
295 const QString aboutMsg = tr(
296 "GitQlient, pronounced as git+client (/gɪtˈklaɪənt/) is a multi-platform Git client. "
297 "With GitQlient you will be able to add commits, branches and manage all the options Git provides. <br><br>"
298 "Once a fork of QGit, GitQlient has followed is own path. "
299 "You can download the code from <a href='https://github.com/francescmm/GitQlient'>GitHub</a>. If you find any "
300 "bug or problem, please report it in <a href='https://github.com/francescmm/GitQlient/issues'>the issues "
301 "page</a> so I can fix it as soon as possible.<br><br>"
302 "If you want to integrate GitQlient into QtCreator, I also provide a plugin that you can download from "
303 "<a href='https://github.com/francescmm/GitQlient/releases'>here</a>. Just make sure you pick the right "
304 "version and follow the instructions in the main page of the repo.<br><br>"
305 "GitQlient can be compiled from Qt 5.12 on.<br><br>"
306 "Copyright &copy; 2019 - 2020 GitQlient (Francesc Martínez)");
307
308 QMessageBox::about(this, tr("About GitQlient v%1").arg(VER), aboutMsg);
309}
310
311void InitScreen::openConfigDlg()
312{
313 GeneralConfigDlg dlg;
314 dlg.exec();
315}
316
317void InitScreen::onRepoOpened()
318{
319 mRecentProjectsLayout->addWidget(createRecentProjectsPage());
320 mUsedProjectsLayout->addWidget(createUsedProjectsPage());
321}
322