| 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 | |
| 26 | using namespace QLogger; |
| 27 | |
| 28 | InitScreen::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 | |
| 149 | void 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 | |
| 160 | void 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 | |
| 173 | void InitScreen::initRepo() |
| 174 | { |
| 175 | CreateRepoDlg cloneDlg(CreateRepoDlgType::INIT, mGit, this); |
| 176 | connect(&cloneDlg, &CreateRepoDlg::signalOpenWhenFinish, this, &InitScreen::signalOpenRepo); |
| 177 | cloneDlg.exec(); |
| 178 | } |
| 179 | |
| 180 | QWidget *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 | |
| 223 | QWidget *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 | |
| 266 | void 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 | |
| 285 | void InitScreen::showError(int, QString description) |
| 286 | { |
| 287 | if (mProgressDlg) |
| 288 | mProgressDlg->deleteLater(); |
| 289 | |
| 290 | QMessageBox::critical(this, tr("Error!" ), description); |
| 291 | } |
| 292 | |
| 293 | void 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 © 2019 - 2020 GitQlient (Francesc Martínez)" ); |
| 307 | |
| 308 | QMessageBox::about(this, tr("About GitQlient v%1" ).arg(VER), aboutMsg); |
| 309 | } |
| 310 | |
| 311 | void InitScreen::openConfigDlg() |
| 312 | { |
| 313 | GeneralConfigDlg dlg; |
| 314 | dlg.exec(); |
| 315 | } |
| 316 | |
| 317 | void InitScreen::onRepoOpened() |
| 318 | { |
| 319 | mRecentProjectsLayout->addWidget(createRecentProjectsPage()); |
| 320 | mUsedProjectsLayout->addWidget(createUsedProjectsPage()); |
| 321 | } |
| 322 | |