1 | #include "BranchesWidget.h" |
2 | |
3 | #include <AddSubtreeDlg.h> |
4 | #include <BranchTreeWidget.h> |
5 | #include <BranchesViewDelegate.h> |
6 | #include <BranchesWidgetMinimal.h> |
7 | #include <ClickableFrame.h> |
8 | #include <GitBase.h> |
9 | #include <GitCache.h> |
10 | #include <GitConfig.h> |
11 | #include <GitQlientBranchItemRole.h> |
12 | #include <GitQlientSettings.h> |
13 | #include <GitStashes.h> |
14 | #include <GitSubmodules.h> |
15 | #include <GitSubtree.h> |
16 | #include <GitTags.h> |
17 | #include <StashesContextMenu.h> |
18 | #include <SubmodulesContextMenu.h> |
19 | |
20 | #include <QApplication> |
21 | #include <QHeaderView> |
22 | #include <QLabel> |
23 | #include <QLineEdit> |
24 | #include <QListWidget> |
25 | #include <QMenu> |
26 | #include <QMessageBox> |
27 | #include <QPushButton> |
28 | #include <QToolButton> |
29 | #include <QVBoxLayout> |
30 | |
31 | #include <QLogger.h> |
32 | |
33 | using namespace QLogger; |
34 | using namespace GitQlient; |
35 | |
36 | namespace |
37 | { |
38 | QTreeWidgetItem *getChild(QTreeWidgetItem *parent, const QString &childName) |
39 | { |
40 | QTreeWidgetItem *child = nullptr; |
41 | |
42 | if (parent) |
43 | { |
44 | const auto childrenCount = parent->childCount(); |
45 | |
46 | for (auto i = 0; i < childrenCount; ++i) |
47 | if (parent->child(i)->text(0) == childName) |
48 | child = parent->child(i); |
49 | } |
50 | |
51 | return child; |
52 | } |
53 | } |
54 | |
55 | BranchesWidget::BranchesWidget(const QSharedPointer<GitCache> &cache, const QSharedPointer<GitBase> &git, |
56 | QWidget *parent) |
57 | : QFrame(parent) |
58 | , mCache(cache) |
59 | , mGit(git) |
60 | , mGitTags(new GitTags(mGit, mCache)) |
61 | , mLocalBranchesTree(new BranchTreeWidget(mCache, mGit)) |
62 | , mRemoteBranchesTree(new BranchTreeWidget(mCache, mGit)) |
63 | , mTagsTree(new RefTreeWidget()) |
64 | , mStashesList(new QListWidget()) |
65 | , mStashesCount(new QLabel(tr("(0)" ))) |
66 | , mStashesArrow(new QLabel()) |
67 | , mSubmodulesCount(new QLabel("(0)" )) |
68 | , mSubmodulesArrow(new QLabel()) |
69 | , mSubmodulesList(new QListWidget()) |
70 | , mSubtreeCount(new QLabel("(0)" )) |
71 | , mSubtreeArrow(new QLabel()) |
72 | , mSubtreeList(new QListWidget()) |
73 | , mMinimize(new QPushButton()) |
74 | , mMinimal(new BranchesWidgetMinimal(mCache, mGit)) |
75 | { |
76 | connect(mCache.get(), &GitCache::signalCacheUpdated, this, &BranchesWidget::showBranches); |
77 | connect(mCache.get(), &GitCache::signalCacheUpdated, this, &BranchesWidget::processTags); |
78 | |
79 | setAttribute(Qt::WA_DeleteOnClose); |
80 | |
81 | mLocalBranchesTree->setLocalRepo(true); |
82 | mLocalBranchesTree->setMouseTracking(true); |
83 | mLocalBranchesTree->setItemDelegate(mLocalDelegate = new BranchesViewDelegate()); |
84 | mLocalBranchesTree->setColumnCount(1); |
85 | mLocalBranchesTree->setObjectName("LocalBranches" ); |
86 | |
87 | const auto = mLocalBranchesTree->headerItem(); |
88 | localHeader->setText(0, tr("Local" )); |
89 | |
90 | mRemoteBranchesTree->setColumnCount(1); |
91 | mRemoteBranchesTree->setMouseTracking(true); |
92 | mRemoteBranchesTree->setItemDelegate(mRemotesDelegate = new BranchesViewDelegate()); |
93 | |
94 | const auto = mRemoteBranchesTree->headerItem(); |
95 | remoteHeader->setText(0, tr("Remote" )); |
96 | |
97 | const auto = mTagsTree->headerItem(); |
98 | tagHeader->setText(0, tr("Tags" )); |
99 | |
100 | mTagsTree->setColumnCount(1); |
101 | mTagsTree->setMouseTracking(true); |
102 | mTagsTree->setItemDelegate(mTagsDelegate = new BranchesViewDelegate(true)); |
103 | mTagsTree->setContextMenuPolicy(Qt::CustomContextMenu); |
104 | |
105 | GitQlientSettings settings(mGit->getGitDir()); |
106 | |
107 | /* STASHES START */ |
108 | if (const auto visible = settings.localValue("StashesHeader" , true).toBool(); !visible) |
109 | { |
110 | const auto icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
111 | mStashesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
112 | mStashesList->setVisible(visible); |
113 | } |
114 | else |
115 | mStashesArrow->setPixmap(QIcon(":/icons/remove" ).pixmap(QSize(15, 15))); |
116 | |
117 | const auto = new ClickableFrame(); |
118 | const auto = new QHBoxLayout(stashHeaderFrame); |
119 | stashHeaderLayout->setContentsMargins(10, 0, 0, 0); |
120 | stashHeaderLayout->setSpacing(10); |
121 | stashHeaderLayout->addWidget(new QLabel(tr("Stashes" ))); |
122 | stashHeaderLayout->addWidget(mStashesCount); |
123 | stashHeaderLayout->addStretch(); |
124 | stashHeaderLayout->addWidget(mStashesArrow); |
125 | |
126 | mStashesList->setMouseTracking(true); |
127 | mStashesList->setContextMenuPolicy(Qt::CustomContextMenu); |
128 | |
129 | const auto stashLayout = new QVBoxLayout(); |
130 | stashLayout->setContentsMargins(QMargins()); |
131 | stashLayout->setSpacing(0); |
132 | stashLayout->addWidget(stashHeaderFrame); |
133 | stashLayout->addSpacing(5); |
134 | stashLayout->addWidget(mStashesList); |
135 | |
136 | const auto stashFrame = new QFrame(); |
137 | stashFrame->setObjectName("sectionFrame" ); |
138 | stashFrame->setLayout(stashLayout); |
139 | |
140 | /* STASHES END */ |
141 | |
142 | /* SUBMODULES START */ |
143 | if (const auto visible = settings.localValue("SubmodulesHeader" , true).toBool(); !visible) |
144 | { |
145 | const auto icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
146 | mSubmodulesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
147 | mSubmodulesList->setVisible(visible); |
148 | } |
149 | else |
150 | mSubmodulesArrow->setPixmap(QIcon(":/icons/remove" ).pixmap(QSize(15, 15))); |
151 | |
152 | const auto = new ClickableFrame(); |
153 | const auto = new QHBoxLayout(submoduleHeaderFrame); |
154 | submoduleHeaderLayout->setContentsMargins(10, 0, 0, 0); |
155 | submoduleHeaderLayout->setSpacing(10); |
156 | submoduleHeaderLayout->addWidget(new QLabel(tr("Submodules" ))); |
157 | submoduleHeaderLayout->addWidget(mSubmodulesCount); |
158 | submoduleHeaderLayout->addStretch(); |
159 | submoduleHeaderLayout->addWidget(mSubmodulesArrow); |
160 | |
161 | mSubmodulesList->setMouseTracking(true); |
162 | mSubmodulesList->setContextMenuPolicy(Qt::CustomContextMenu); |
163 | connect(mSubmodulesList, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *item) { |
164 | emit signalOpenSubmodule(mGit->getWorkingDir().append("/" ).append(item->text())); |
165 | }); |
166 | |
167 | const auto submoduleLayout = new QVBoxLayout(); |
168 | submoduleLayout->setContentsMargins(QMargins()); |
169 | submoduleLayout->setSpacing(0); |
170 | submoduleLayout->addWidget(submoduleHeaderFrame); |
171 | submoduleLayout->addSpacing(5); |
172 | submoduleLayout->addWidget(mSubmodulesList); |
173 | |
174 | const auto submoduleFrame = new QFrame(); |
175 | submoduleFrame->setObjectName("sectionFrame" ); |
176 | submoduleFrame->setLayout(submoduleLayout); |
177 | |
178 | /* SUBMODULES END */ |
179 | |
180 | /* SUBTREE START */ |
181 | if (const auto visible = settings.localValue("SubtreeHeader" , true).toBool(); !visible) |
182 | { |
183 | const auto icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
184 | mSubtreeArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
185 | mSubtreeList->setVisible(visible); |
186 | } |
187 | else |
188 | mSubtreeArrow->setPixmap(QIcon(":/icons/remove" ).pixmap(QSize(15, 15))); |
189 | |
190 | const auto = new ClickableFrame(); |
191 | const auto = new QHBoxLayout(subtreeHeaderFrame); |
192 | subtreeHeaderLayout->setContentsMargins(10, 0, 0, 0); |
193 | subtreeHeaderLayout->setSpacing(10); |
194 | subtreeHeaderLayout->addWidget(new QLabel(tr("Subtrees" ))); |
195 | subtreeHeaderLayout->addWidget(mSubtreeCount); |
196 | subtreeHeaderLayout->addStretch(); |
197 | subtreeHeaderLayout->addWidget(mSubtreeArrow); |
198 | |
199 | mSubtreeList->setMouseTracking(true); |
200 | mSubtreeList->setContextMenuPolicy(Qt::CustomContextMenu); |
201 | |
202 | const auto subtreeLayout = new QVBoxLayout(); |
203 | subtreeLayout->setContentsMargins(QMargins()); |
204 | subtreeLayout->setSpacing(0); |
205 | subtreeLayout->addWidget(subtreeHeaderFrame); |
206 | subtreeLayout->addSpacing(5); |
207 | subtreeLayout->addWidget(mSubtreeList); |
208 | |
209 | const auto subtreeFrame = new QFrame(); |
210 | subtreeFrame->setObjectName("sectionFrame" ); |
211 | subtreeFrame->setLayout(subtreeLayout); |
212 | |
213 | /* SUBTREE END */ |
214 | |
215 | const auto searchBranch = new QLineEdit(); |
216 | searchBranch->setPlaceholderText(tr("Prese ENTER to search a branch or tag..." )); |
217 | searchBranch->setObjectName("SearchInput" ); |
218 | connect(searchBranch, &QLineEdit::returnPressed, this, &BranchesWidget::onSearchBranch); |
219 | |
220 | mMinimize->setIcon(QIcon(":/icons/ahead" )); |
221 | mMinimize->setToolTip(tr("Show minimalist view" )); |
222 | mMinimize->setObjectName("BranchesWidgetOptionsButton" ); |
223 | connect(mMinimize, &QPushButton::clicked, this, &BranchesWidget::minimalView); |
224 | |
225 | const auto mainControlsLayout = new QHBoxLayout(); |
226 | mainControlsLayout->setContentsMargins(QMargins()); |
227 | mainControlsLayout->setSpacing(5); |
228 | mainControlsLayout->addWidget(mMinimize); |
229 | mainControlsLayout->addWidget(searchBranch); |
230 | |
231 | const auto separator1 = new QFrame(); |
232 | separator1->setObjectName("separator" ); |
233 | |
234 | const auto separator2 = new QFrame(); |
235 | separator2->setObjectName("separator" ); |
236 | |
237 | const auto panelsLayout = new QVBoxLayout(); |
238 | panelsLayout->setContentsMargins(QMargins()); |
239 | panelsLayout->setSpacing(0); |
240 | panelsLayout->addWidget(mLocalBranchesTree); |
241 | panelsLayout->addWidget(separator1); |
242 | panelsLayout->addWidget(mRemoteBranchesTree); |
243 | panelsLayout->addWidget(separator2); |
244 | panelsLayout->addWidget(mTagsTree); |
245 | panelsLayout->addWidget(stashFrame); |
246 | panelsLayout->addWidget(submoduleFrame); |
247 | panelsLayout->addWidget(subtreeFrame); |
248 | |
249 | const auto panelsFrame = new QFrame(); |
250 | panelsFrame->setObjectName("panelsFrame" ); |
251 | panelsFrame->setLayout(panelsLayout); |
252 | |
253 | const auto vLayout = new QVBoxLayout(); |
254 | vLayout->setContentsMargins(0, 0, 0, 0); |
255 | vLayout->setSpacing(0); |
256 | vLayout->addLayout(mainControlsLayout); |
257 | vLayout->addSpacing(5); |
258 | vLayout->addWidget(panelsFrame); |
259 | |
260 | mFullBranchFrame = new QFrame(); |
261 | |
262 | const auto mainBranchLayout = new QHBoxLayout(mFullBranchFrame); |
263 | mainBranchLayout->setContentsMargins(QMargins()); |
264 | mainBranchLayout->setSpacing(0); |
265 | mainBranchLayout->addLayout(vLayout); |
266 | |
267 | const auto mainLayout = new QGridLayout(this); |
268 | mainLayout->setContentsMargins(QMargins()); |
269 | mainLayout->setSpacing(0); |
270 | mainLayout->addWidget(mFullBranchFrame, 0, 0, 3, 1); |
271 | mainLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), 0, 1); |
272 | mainLayout->addWidget(mMinimal, 1, 1); |
273 | mainLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 1); |
274 | |
275 | const auto isMinimalVisible = settings.localValue("MinimalBranchesView" , false).toBool(); |
276 | mFullBranchFrame->setVisible(!isMinimalVisible); |
277 | mMinimal->setVisible(isMinimalVisible); |
278 | connect(mMinimal, &BranchesWidgetMinimal::showFullBranchesView, this, &BranchesWidget::fullView); |
279 | connect(mMinimal, &BranchesWidgetMinimal::commitSelected, this, &BranchesWidget::signalSelectCommit); |
280 | connect(mMinimal, &BranchesWidgetMinimal::stashSelected, this, &BranchesWidget::onStashSelected); |
281 | |
282 | /* |
283 | connect(mLocalBranchesTree, &BranchTreeWidget::signalRefreshPRsCache, mCache.get(), |
284 | &GitCache::refreshPRsCache); |
285 | */ |
286 | connect(mLocalBranchesTree, &BranchTreeWidget::signalSelectCommit, this, &BranchesWidget::signalSelectCommit); |
287 | connect(mLocalBranchesTree, &BranchTreeWidget::signalSelectCommit, mRemoteBranchesTree, |
288 | &BranchTreeWidget::clearSelection); |
289 | connect(mLocalBranchesTree, &BranchTreeWidget::signalFetchPerformed, mGitTags.data(), &GitTags::getRemoteTags); |
290 | connect(mLocalBranchesTree, &BranchTreeWidget::fullReload, this, &BranchesWidget::fullReload); |
291 | connect(mLocalBranchesTree, &BranchTreeWidget::logReload, this, &BranchesWidget::logReload); |
292 | connect(mLocalBranchesTree, &BranchTreeWidget::signalMergeRequired, this, &BranchesWidget::signalMergeRequired); |
293 | connect(mLocalBranchesTree, &BranchTreeWidget::mergeSqushRequested, this, &BranchesWidget::mergeSqushRequested); |
294 | connect(mLocalBranchesTree, &BranchTreeWidget::signalPullConflict, this, &BranchesWidget::signalPullConflict); |
295 | |
296 | connect(mRemoteBranchesTree, &BranchTreeWidget::signalSelectCommit, this, &BranchesWidget::signalSelectCommit); |
297 | connect(mRemoteBranchesTree, &BranchTreeWidget::signalSelectCommit, mLocalBranchesTree, |
298 | &BranchTreeWidget::clearSelection); |
299 | connect(mRemoteBranchesTree, &BranchTreeWidget::signalFetchPerformed, mGitTags.data(), &GitTags::getRemoteTags); |
300 | connect(mRemoteBranchesTree, &BranchTreeWidget::fullReload, this, &BranchesWidget::fullReload); |
301 | connect(mRemoteBranchesTree, &BranchTreeWidget::logReload, this, &BranchesWidget::logReload); |
302 | connect(mRemoteBranchesTree, &BranchTreeWidget::signalMergeRequired, this, &BranchesWidget::signalMergeRequired); |
303 | connect(mRemoteBranchesTree, &BranchTreeWidget::mergeSqushRequested, this, &BranchesWidget::mergeSqushRequested); |
304 | |
305 | connect(mTagsTree, &QTreeWidget::itemClicked, this, &BranchesWidget::onTagClicked); |
306 | connect(mTagsTree, &QListWidget::customContextMenuRequested, this, &BranchesWidget::showTagsContextMenu); |
307 | connect(mStashesList, &QListWidget::itemClicked, this, &BranchesWidget::onStashClicked); |
308 | connect(mStashesList, &QListWidget::customContextMenuRequested, this, &BranchesWidget::showStashesContextMenu); |
309 | connect(mSubmodulesList, &QListWidget::customContextMenuRequested, this, &BranchesWidget::showSubmodulesContextMenu); |
310 | connect(mSubtreeList, &QListWidget::customContextMenuRequested, this, &BranchesWidget::showSubtreesContextMenu); |
311 | connect(stashHeaderFrame, &ClickableFrame::clicked, this, &BranchesWidget::onStashesHeaderClicked); |
312 | connect(submoduleHeaderFrame, &ClickableFrame::clicked, this, &BranchesWidget::onSubmodulesHeaderClicked); |
313 | connect(subtreeHeaderFrame, &ClickableFrame::clicked, this, &BranchesWidget::onSubtreesHeaderClicked); |
314 | } |
315 | |
316 | BranchesWidget::~BranchesWidget() |
317 | { |
318 | delete mLocalDelegate; |
319 | delete mRemotesDelegate; |
320 | delete mTagsDelegate; |
321 | } |
322 | |
323 | bool BranchesWidget::isMinimalViewActive() const |
324 | { |
325 | GitQlientSettings settings(mGit->getGitDir()); |
326 | return settings.localValue("MinimalBranchesView" , false).toBool(); |
327 | } |
328 | |
329 | void BranchesWidget::showBranches() |
330 | { |
331 | QLog_Info("UI" , QString("Loading branches data" )); |
332 | |
333 | clear(); |
334 | mMinimal->clearActions(); |
335 | |
336 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
337 | |
338 | auto branches = mCache->getBranches(References::Type::LocalBranch); |
339 | |
340 | if (!branches.empty()) |
341 | { |
342 | QLog_Info("UI" , QString("Fetched {%1} local branches" ).arg(branches.count())); |
343 | QLog_Info("UI" , QString("Processing local branches..." )); |
344 | |
345 | for (const auto &pair : qAsConst(branches)) |
346 | { |
347 | for (const auto &branch : pair.second) |
348 | { |
349 | if (!branch.contains("HEAD->" )) |
350 | { |
351 | processLocalBranch(pair.first, branch); |
352 | mMinimal->configureLocalMenu(pair.first, branch); |
353 | } |
354 | } |
355 | } |
356 | |
357 | QLog_Info("UI" , QString("... local branches processed" )); |
358 | } |
359 | |
360 | branches.clear(); |
361 | branches.squeeze(); |
362 | branches = mCache->getBranches(References::Type::RemoteBranches); |
363 | |
364 | if (!branches.empty()) |
365 | { |
366 | QLog_Info("UI" , QString("Fetched {%1} remote branches" ).arg(branches.count())); |
367 | QLog_Info("UI" , QString("Processing remote branches..." )); |
368 | |
369 | for (const auto &pair : qAsConst(branches)) |
370 | { |
371 | for (const auto &branch : pair.second) |
372 | { |
373 | if (!branch.contains("HEAD->" )) |
374 | { |
375 | processRemoteBranch(pair.first, branch); |
376 | mMinimal->configureRemoteMenu(pair.first, branch); |
377 | } |
378 | } |
379 | } |
380 | |
381 | branches.clear(); |
382 | branches.squeeze(); |
383 | |
384 | QLog_Info("UI" , QString("... remote branches processed" )); |
385 | } |
386 | |
387 | processStashes(); |
388 | processSubmodules(); |
389 | processSubtrees(); |
390 | |
391 | QApplication::restoreOverrideCursor(); |
392 | |
393 | adjustBranchesTree(mLocalBranchesTree); |
394 | } |
395 | |
396 | void BranchesWidget::refreshCurrentBranchLink() |
397 | { |
398 | mLocalBranchesTree->reloadCurrentBranchLink(); |
399 | } |
400 | |
401 | void BranchesWidget::clear() |
402 | { |
403 | blockSignals(true); |
404 | mLocalBranchesTree->clear(); |
405 | mRemoteBranchesTree->clear(); |
406 | blockSignals(false); |
407 | } |
408 | |
409 | void BranchesWidget::fullView() |
410 | { |
411 | mFullBranchFrame->setVisible(true); |
412 | mMinimal->setVisible(false); |
413 | |
414 | emit minimalViewStateChanged(false); |
415 | |
416 | GitQlientSettings settings(mGit->getGitDir()); |
417 | settings.setLocalValue("MinimalBranchesView" , mMinimal->isVisible()); |
418 | } |
419 | |
420 | void BranchesWidget::returnToSavedView() |
421 | { |
422 | GitQlientSettings settings(mGit->getGitDir()); |
423 | const auto savedState = settings.localValue("MinimalBranchesView" , false).toBool(); |
424 | |
425 | if (savedState != mMinimal->isVisible()) |
426 | { |
427 | mFullBranchFrame->setVisible(!savedState); |
428 | mMinimal->setVisible(savedState); |
429 | |
430 | emit minimalViewStateChanged(savedState); |
431 | } |
432 | } |
433 | |
434 | void BranchesWidget::minimalView() |
435 | { |
436 | forceMinimalView(); |
437 | |
438 | GitQlientSettings settings(mGit->getGitDir()); |
439 | settings.setLocalValue("MinimalBranchesView" , mMinimal->isVisible()); |
440 | } |
441 | |
442 | void BranchesWidget::forceMinimalView() |
443 | { |
444 | mFullBranchFrame->setVisible(false); |
445 | mMinimal->setVisible(true); |
446 | |
447 | emit minimalViewStateChanged(true); |
448 | } |
449 | |
450 | void BranchesWidget::onPanelsVisibilityChaned() |
451 | { |
452 | GitQlientSettings settings(mGit->getGitDir()); |
453 | |
454 | auto visible = settings.localValue("StashesHeader" , true).toBool(); |
455 | auto icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
456 | mStashesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
457 | mStashesList->setVisible(visible); |
458 | |
459 | visible = settings.localValue("SubmodulesHeader" , true).toBool(); |
460 | icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
461 | mSubmodulesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
462 | mSubmodulesList->setVisible(visible); |
463 | |
464 | visible = settings.localValue("SubtreeHeader" , true).toBool(); |
465 | icon = QIcon(!visible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
466 | mSubtreeArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
467 | mSubtreeList->setVisible(visible); |
468 | } |
469 | |
470 | void BranchesWidget::processLocalBranch(const QString &sha, QString branch) |
471 | { |
472 | QLog_Debug("UI" , QString("Adding local branch {%1}" ).arg(branch)); |
473 | |
474 | auto isCurrentBranch = false; |
475 | |
476 | if (branch == mGit->getCurrentBranch()) |
477 | isCurrentBranch = true; |
478 | |
479 | const auto fullBranchName = branch; |
480 | |
481 | QVector<QTreeWidgetItem *> parents; |
482 | QTreeWidgetItem *parent = nullptr; |
483 | auto folders = branch.split("/" ); |
484 | branch = folders.takeLast(); |
485 | |
486 | for (const auto &folder : qAsConst(folders)) |
487 | { |
488 | QTreeWidgetItem *child = nullptr; |
489 | |
490 | if (parent) |
491 | { |
492 | child = getChild(parent, folder); |
493 | parents.append(child); |
494 | } |
495 | else |
496 | { |
497 | for (auto i = 0; i < mLocalBranchesTree->topLevelItemCount(); ++i) |
498 | { |
499 | if (mLocalBranchesTree->topLevelItem(i)->text(0) == folder) |
500 | { |
501 | child = mLocalBranchesTree->topLevelItem(i); |
502 | parents.append(child); |
503 | } |
504 | } |
505 | } |
506 | |
507 | if (!child) |
508 | { |
509 | const auto item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(); |
510 | item->setText(0, folder); |
511 | |
512 | if (!parent) |
513 | mLocalBranchesTree->addTopLevelItem(item); |
514 | |
515 | parent = item; |
516 | parents.append(parent); |
517 | } |
518 | else |
519 | { |
520 | parent = child; |
521 | parents.append(child); |
522 | } |
523 | } |
524 | |
525 | auto item = new QTreeWidgetItem(parent); |
526 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); |
527 | item->setText(0, branch); |
528 | item->setData(0, GitQlient::IsCurrentBranchRole, isCurrentBranch); |
529 | item->setData(0, GitQlient::FullNameRole, fullBranchName); |
530 | item->setData(0, GitQlient::LocalBranchRole, true); |
531 | item->setData(0, GitQlient::ShaRole, sha); |
532 | item->setData(0, Qt::ToolTipRole, fullBranchName); |
533 | item->setData(0, GitQlient::IsLeaf, true); |
534 | |
535 | if (isCurrentBranch) |
536 | { |
537 | item->setSelected(true); |
538 | |
539 | for (const auto parent : parents) |
540 | { |
541 | mLocalBranchesTree->setCurrentItem(item); |
542 | mLocalBranchesTree->expandItem(parent); |
543 | const auto indexToScroll = mLocalBranchesTree->currentIndex(); |
544 | mLocalBranchesTree->scrollTo(indexToScroll); |
545 | } |
546 | } |
547 | |
548 | parents.clear(); |
549 | parents.squeeze(); |
550 | |
551 | mLocalBranchesTree->addTopLevelItem(item); |
552 | |
553 | QLog_Debug("UI" , QString("Finish gathering local branch information" )); |
554 | } |
555 | |
556 | void BranchesWidget::processRemoteBranch(const QString &sha, QString branch) |
557 | { |
558 | const auto fullBranchName = branch; |
559 | auto folders = branch.split("/" ); |
560 | branch = folders.takeLast(); |
561 | |
562 | QTreeWidgetItem *parent = nullptr; |
563 | |
564 | for (const auto &folder : qAsConst(folders)) |
565 | { |
566 | QTreeWidgetItem *child = nullptr; |
567 | |
568 | if (parent) |
569 | child = getChild(parent, folder); |
570 | else |
571 | { |
572 | for (auto i = 0; i < mRemoteBranchesTree->topLevelItemCount(); ++i) |
573 | { |
574 | if (mRemoteBranchesTree->topLevelItem(i)->text(0) == folder) |
575 | child = mRemoteBranchesTree->topLevelItem(i); |
576 | } |
577 | } |
578 | |
579 | if (!child) |
580 | { |
581 | const auto item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(); |
582 | item->setText(0, folder); |
583 | |
584 | if (!parent) |
585 | { |
586 | item->setData(0, GitQlient::IsRoot, true); |
587 | mRemoteBranchesTree->addTopLevelItem(item); |
588 | } |
589 | |
590 | parent = item; |
591 | } |
592 | else |
593 | parent = child; |
594 | } |
595 | |
596 | QLog_Trace("UI" , QString("Adding remote branch {%1}" ).arg(branch)); |
597 | |
598 | const auto item = new QTreeWidgetItem(parent); |
599 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); |
600 | item->setText(0, branch); |
601 | item->setData(0, GitQlient::FullNameRole, fullBranchName); |
602 | item->setData(0, GitQlient::LocalBranchRole, false); |
603 | item->setData(0, GitQlient::ShaRole, sha); |
604 | item->setData(0, Qt::ToolTipRole, fullBranchName); |
605 | item->setData(0, GitQlient::IsLeaf, true); |
606 | } |
607 | |
608 | void BranchesWidget::processTags() |
609 | { |
610 | mTagsTree->clear(); |
611 | |
612 | const auto localTags = mCache->getTags(References::Type::LocalTag); |
613 | auto remoteTags = mCache->getTags(References::Type::RemoteTag); |
614 | |
615 | for (auto iter = localTags.cbegin(); iter != localTags.cend(); ++iter) |
616 | { |
617 | QTreeWidgetItem *parent = nullptr; |
618 | auto fullTagName = iter.key(); |
619 | auto folders = fullTagName.split("/" ); |
620 | auto tagName = folders.takeLast(); |
621 | |
622 | for (const auto &folder : qAsConst(folders)) |
623 | { |
624 | QTreeWidgetItem *child = nullptr; |
625 | |
626 | if (parent) |
627 | child = getChild(parent, folder); |
628 | else |
629 | { |
630 | for (auto i = 0; i < mTagsTree->topLevelItemCount(); ++i) |
631 | { |
632 | if (mTagsTree->topLevelItem(i)->text(0) == folder) |
633 | child = mTagsTree->topLevelItem(i); |
634 | } |
635 | } |
636 | |
637 | if (!child) |
638 | { |
639 | const auto item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(); |
640 | item->setText(0, folder); |
641 | |
642 | if (!parent) |
643 | mTagsTree->addTopLevelItem(item); |
644 | |
645 | parent = item; |
646 | } |
647 | else |
648 | parent = child; |
649 | } |
650 | |
651 | const auto item = new QTreeWidgetItem(parent); |
652 | |
653 | if (!remoteTags.contains(fullTagName)) |
654 | { |
655 | tagName += " (local)" ; |
656 | item->setData(0, LocalBranchRole, false); |
657 | } |
658 | else |
659 | { |
660 | item->setData(0, LocalBranchRole, true); |
661 | remoteTags.remove(fullTagName); |
662 | } |
663 | |
664 | QLog_Trace("UI" , QString("Adding tag {%1}" ).arg(tagName)); |
665 | |
666 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); |
667 | item->setText(0, tagName); |
668 | item->setData(0, GitQlient::FullNameRole, fullTagName); |
669 | item->setData(0, GitQlient::ShaRole, iter.value()); |
670 | item->setData(0, Qt::ToolTipRole, fullTagName); |
671 | item->setData(0, GitQlient::IsLeaf, true); |
672 | |
673 | mTagsTree->addTopLevelItem(item); |
674 | } |
675 | |
676 | for (auto iter = remoteTags.cbegin(); iter != remoteTags.cend(); ++iter) |
677 | { |
678 | QTreeWidgetItem *parent = nullptr; |
679 | auto fullTagName = iter.key(); |
680 | auto folders = fullTagName.split("/" ); |
681 | auto tagName = folders.takeLast(); |
682 | |
683 | for (const auto &folder : qAsConst(folders)) |
684 | { |
685 | QTreeWidgetItem *child = nullptr; |
686 | |
687 | if (parent) |
688 | child = getChild(parent, folder); |
689 | else |
690 | { |
691 | for (auto i = 0; i < mTagsTree->topLevelItemCount(); ++i) |
692 | { |
693 | if (mTagsTree->topLevelItem(i)->text(0) == folder) |
694 | child = mTagsTree->topLevelItem(i); |
695 | } |
696 | } |
697 | |
698 | if (!child) |
699 | { |
700 | const auto item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(); |
701 | item->setText(0, folder); |
702 | |
703 | if (!parent) |
704 | mTagsTree->addTopLevelItem(item); |
705 | |
706 | parent = item; |
707 | } |
708 | else |
709 | parent = child; |
710 | } |
711 | |
712 | QLog_Trace("UI" , QString("Adding tag {%1}" ).arg(tagName)); |
713 | |
714 | const auto item = new QTreeWidgetItem(parent); |
715 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); |
716 | item->setText(0, tagName); |
717 | item->setData(0, GitQlient::FullNameRole, fullTagName); |
718 | item->setData(0, GitQlient::ShaRole, iter.value()); |
719 | item->setData(0, Qt::ToolTipRole, fullTagName); |
720 | item->setData(0, GitQlient::IsLeaf, true); |
721 | |
722 | mTagsTree->addTopLevelItem(item); |
723 | } |
724 | |
725 | mTagsTree->update(); |
726 | } |
727 | |
728 | void BranchesWidget::processStashes() |
729 | { |
730 | mStashesList->clear(); |
731 | |
732 | QScopedPointer<GitStashes> git(new GitStashes(mGit)); |
733 | const auto stashes = git->getStashes(); |
734 | |
735 | QLog_Info("UI" , QString("Fetching {%1} stashes" ).arg(stashes.count())); |
736 | |
737 | for (const auto &stash : stashes) |
738 | { |
739 | const auto stashId = stash.split(":" ).first(); |
740 | const auto stashDesc = stash.split("}: " ).last(); |
741 | const auto item = new QListWidgetItem(stashDesc); |
742 | item->setData(Qt::UserRole, stashId); |
743 | mStashesList->addItem(item); |
744 | mMinimal->configureStashesMenu(stashId, stashDesc); |
745 | } |
746 | |
747 | mStashesCount->setText(QString("(%1)" ).arg(stashes.count())); |
748 | } |
749 | |
750 | void BranchesWidget::processSubmodules() |
751 | { |
752 | mSubmodulesList->clear(); |
753 | |
754 | QScopedPointer<GitSubmodules> git(new GitSubmodules(mGit)); |
755 | const auto submodules = git->getSubmodules(); |
756 | |
757 | QLog_Info("UI" , QString("Fetching {%1} submodules" ).arg(submodules.count())); |
758 | |
759 | for (const auto &submodule : submodules) |
760 | { |
761 | mSubmodulesList->addItem(submodule); |
762 | mMinimal->configureSubmodulesMenu(submodule); |
763 | } |
764 | |
765 | mSubmodulesCount->setText('(' + QString::number(submodules.count()) + ')'); |
766 | } |
767 | |
768 | void BranchesWidget::processSubtrees() |
769 | { |
770 | mSubtreeList->clear(); |
771 | |
772 | QScopedPointer<GitSubtree> git(new GitSubtree(mGit)); |
773 | |
774 | const auto ret = git->list(); |
775 | |
776 | if (ret.success) |
777 | { |
778 | const auto rawData = ret.output; |
779 | const auto commits = rawData.split("\n\n" ); |
780 | auto count = 0; |
781 | |
782 | for (auto &subtreeRawData : commits) |
783 | { |
784 | if (!subtreeRawData.isEmpty()) |
785 | { |
786 | QString name; |
787 | QString sha; |
788 | auto fields = subtreeRawData.split("\n" ); |
789 | |
790 | for (auto &field : fields) |
791 | { |
792 | if (field.contains("git-subtree-dir:" )) |
793 | name = field.remove("git-subtree-dir:" ).trimmed(); |
794 | else if (field.contains("git-subtree-split" )) |
795 | sha = field.remove("git-subtree-split:" ).trimmed(); |
796 | } |
797 | |
798 | mSubtreeList->addItem(name); |
799 | ++count; |
800 | } |
801 | } |
802 | |
803 | mSubtreeCount->setText('(' + QString::number(count) + ')'); |
804 | } |
805 | } |
806 | |
807 | void BranchesWidget::adjustBranchesTree(BranchTreeWidget *treeWidget) |
808 | { |
809 | for (auto i = 1; i < treeWidget->columnCount(); ++i) |
810 | treeWidget->resizeColumnToContents(i); |
811 | |
812 | treeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch); |
813 | |
814 | for (auto i = 1; i < treeWidget->columnCount(); ++i) |
815 | treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); |
816 | |
817 | treeWidget->header()->setStretchLastSection(false); |
818 | } |
819 | |
820 | void BranchesWidget::(const QPoint &p) |
821 | { |
822 | const auto item = mTagsTree->itemAt(p); |
823 | |
824 | if (!item) |
825 | return; |
826 | |
827 | const auto tagName = item->data(0, GitQlient::FullNameRole).toString(); |
828 | |
829 | if (!tagName.isEmpty()) |
830 | { |
831 | const auto isRemote = item->data(0, LocalBranchRole).toBool(); |
832 | const auto = new QMenu(this); |
833 | const auto removeTagAction = menu->addAction(tr("Remove tag" )); |
834 | connect(removeTagAction, &QAction::triggered, this, [this, tagName, isRemote]() { |
835 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
836 | QScopedPointer<GitTags> git(new GitTags(mGit)); |
837 | const auto ret = git->removeTag(tagName, isRemote); |
838 | QApplication::restoreOverrideCursor(); |
839 | |
840 | if (ret.success) |
841 | mGitTags->getRemoteTags(); |
842 | }); |
843 | |
844 | const auto pushTagAction = menu->addAction(tr("Push tag" )); |
845 | pushTagAction->setEnabled(!isRemote); |
846 | connect(pushTagAction, &QAction::triggered, this, [this, tagName]() { |
847 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
848 | QScopedPointer<GitTags> git(new GitTags(mGit)); |
849 | const auto ret = git->pushTag(tagName); |
850 | QApplication::restoreOverrideCursor(); |
851 | |
852 | if (ret.success) |
853 | mGitTags->getRemoteTags(); |
854 | }); |
855 | |
856 | menu->exec(mTagsTree->viewport()->mapToGlobal(p)); |
857 | } |
858 | } |
859 | |
860 | void BranchesWidget::(const QPoint &p) |
861 | { |
862 | QLog_Info("UI" , QString("Requesting context menu for stashes" )); |
863 | |
864 | const auto index = mStashesList->indexAt(p); |
865 | |
866 | if (index.isValid()) |
867 | { |
868 | const auto = new StashesContextMenu(mGit, index.data(Qt::UserRole).toString(), this); |
869 | connect(menu, &StashesContextMenu::signalUpdateView, this, &BranchesWidget::fullReload); |
870 | connect(menu, &StashesContextMenu::signalContentRemoved, this, &BranchesWidget::fullReload); |
871 | menu->exec(mStashesList->viewport()->mapToGlobal(p)); |
872 | } |
873 | } |
874 | |
875 | void BranchesWidget::(const QPoint &p) |
876 | { |
877 | QLog_Info("UI" , QString("Requesting context menu for submodules" )); |
878 | |
879 | const auto = new SubmodulesContextMenu(mGit, mSubmodulesList->indexAt(p), this); |
880 | connect(menu, &SubmodulesContextMenu::openSubmodule, this, &BranchesWidget::signalOpenSubmodule); |
881 | connect(menu, &SubmodulesContextMenu::infoUpdated, this, &BranchesWidget::fullReload); |
882 | |
883 | menu->exec(mSubmodulesList->viewport()->mapToGlobal(p)); |
884 | } |
885 | |
886 | void BranchesWidget::(const QPoint &p) |
887 | { |
888 | QLog_Info("UI" , QString("Requesting context menu for subtrees" )); |
889 | |
890 | QModelIndex index = mSubtreeList->indexAt(p); |
891 | |
892 | const auto = new QMenu(this); |
893 | |
894 | if (index.isValid()) |
895 | { |
896 | connect(menu->addAction(tr("Pull" )), &QAction::triggered, this, [this, index]() { |
897 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
898 | |
899 | const auto prefix = index.data().toString(); |
900 | const auto subtreeData = getSubtreeData(prefix); |
901 | |
902 | QScopedPointer<GitSubtree> git(new GitSubtree(mGit)); |
903 | const auto ret = git->pull(subtreeData.first, subtreeData.second, prefix); |
904 | QApplication::restoreOverrideCursor(); |
905 | |
906 | if (ret.success) |
907 | emit fullReload(); |
908 | else |
909 | QMessageBox::warning(this, tr("Error when pulling" ), ret.output); |
910 | }); |
911 | /* |
912 | connect(menu->addAction(tr("Merge")), &QAction::triggered, this, [this, index]() { |
913 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
914 | |
915 | const auto subtreeData = getSubtreeData(index.data().toString()); |
916 | |
917 | QScopedPointer<GitSubtree> git(new GitSubtree(mGit)); |
918 | const auto ret = git->pull(subtreeData.first, subtreeData.second); |
919 | QApplication::restoreOverrideCursor(); |
920 | |
921 | if (ret.success) |
922 | emit signalBranchesUpdated(); |
923 | }); |
924 | */ |
925 | connect(menu->addAction(tr("Push" )), &QAction::triggered, this, [this, index]() { |
926 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
927 | |
928 | const auto prefix = index.data().toString(); |
929 | const auto subtreeData = getSubtreeData(prefix); |
930 | |
931 | QScopedPointer<GitSubtree> git(new GitSubtree(mGit)); |
932 | const auto ret = git->push(subtreeData.first, subtreeData.second, prefix); |
933 | QApplication::restoreOverrideCursor(); |
934 | |
935 | if (ret.success) |
936 | emit fullReload(); |
937 | else |
938 | QMessageBox::warning(this, tr("Error when pushing" ), ret.output); |
939 | }); |
940 | |
941 | const auto addSubtree = menu->addAction(tr("Configure" )); |
942 | connect(addSubtree, &QAction::triggered, this, [this, index]() { |
943 | const auto prefix = index.data().toString(); |
944 | const auto subtreeData = getSubtreeData(prefix); |
945 | AddSubtreeDlg addDlg(prefix, subtreeData.first, subtreeData.second, mGit); |
946 | const auto ret = addDlg.exec(); |
947 | if (ret == QDialog::Accepted) |
948 | emit fullReload(); |
949 | }); |
950 | // menu->addAction(tr("Split")); |
951 | } |
952 | else |
953 | { |
954 | const auto addSubtree = menu->addAction(tr("Add subtree" )); |
955 | connect(addSubtree, &QAction::triggered, this, [this]() { |
956 | AddSubtreeDlg addDlg(mGit); |
957 | const auto ret = addDlg.exec(); |
958 | if (ret == QDialog::Accepted) |
959 | emit fullReload(); |
960 | }); |
961 | } |
962 | |
963 | menu->exec(mSubtreeList->viewport()->mapToGlobal(p)); |
964 | } |
965 | |
966 | void BranchesWidget::() |
967 | { |
968 | const auto stashesAreVisible = mStashesList->isVisible(); |
969 | const auto icon = QIcon(stashesAreVisible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
970 | mStashesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
971 | mStashesList->setVisible(!stashesAreVisible); |
972 | |
973 | GitQlientSettings settings(mGit->getGitDir()); |
974 | settings.setLocalValue("StashesHeader" , !stashesAreVisible); |
975 | |
976 | emit panelsVisibilityChanged(); |
977 | } |
978 | |
979 | void BranchesWidget::() |
980 | { |
981 | const auto submodulesAreVisible = mSubmodulesList->isVisible(); |
982 | const auto icon = QIcon(submodulesAreVisible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
983 | mSubmodulesArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
984 | mSubmodulesList->setVisible(!submodulesAreVisible); |
985 | |
986 | GitQlientSettings settings(mGit->getGitDir()); |
987 | settings.setLocalValue("SubmodulesHeader" , !submodulesAreVisible); |
988 | |
989 | emit panelsVisibilityChanged(); |
990 | } |
991 | |
992 | void BranchesWidget::() |
993 | { |
994 | const auto subtreesAreVisible = mSubtreeList->isVisible(); |
995 | const auto icon = QIcon(subtreesAreVisible ? QString(":/icons/add" ) : QString(":/icons/remove" )); |
996 | mSubtreeArrow->setPixmap(icon.pixmap(QSize(15, 15))); |
997 | mSubtreeList->setVisible(!subtreesAreVisible); |
998 | |
999 | GitQlientSettings settings(mGit->getGitDir()); |
1000 | settings.setLocalValue("SubtreeHeader" , !subtreesAreVisible); |
1001 | |
1002 | emit panelsVisibilityChanged(); |
1003 | } |
1004 | |
1005 | void BranchesWidget::onTagClicked(QTreeWidgetItem *item) |
1006 | { |
1007 | if (item && item->data(0, IsLeaf).toBool()) |
1008 | emit signalSelectCommit(item->data(0, ShaRole).toString()); |
1009 | } |
1010 | |
1011 | void BranchesWidget::onStashClicked(QListWidgetItem *item) |
1012 | { |
1013 | onStashSelected(item->data(Qt::UserRole).toString()); |
1014 | } |
1015 | |
1016 | void BranchesWidget::onStashSelected(const QString &stashId) |
1017 | { |
1018 | QScopedPointer<GitTags> git(new GitTags(mGit)); |
1019 | const auto sha = git->getTagCommit(stashId).output; |
1020 | |
1021 | emit signalSelectCommit(sha); |
1022 | } |
1023 | |
1024 | void BranchesWidget::onSearchBranch() |
1025 | { |
1026 | const auto lineEdit = qobject_cast<QLineEdit *>(sender()); |
1027 | |
1028 | const auto text = lineEdit->text(); |
1029 | |
1030 | if (mLastSearch != text) |
1031 | { |
1032 | mLastSearch = text; |
1033 | mLastIndex = mLocalBranchesTree->focusOnBranch(mLastSearch); |
1034 | mLastTreeSearched = mLocalBranchesTree; |
1035 | |
1036 | if (mLastIndex == -1) |
1037 | { |
1038 | mLastIndex = mRemoteBranchesTree->focusOnBranch(mLastSearch); |
1039 | mLastTreeSearched = mRemoteBranchesTree; |
1040 | |
1041 | if (mLastIndex == -1) |
1042 | { |
1043 | mLastIndex = mTagsTree->focusOnBranch(mLastSearch); |
1044 | mLastTreeSearched = mTagsTree; |
1045 | |
1046 | if (mLastIndex == -1) |
1047 | mLastTreeSearched = mLocalBranchesTree; |
1048 | } |
1049 | } |
1050 | } |
1051 | else |
1052 | { |
1053 | if (mLastTreeSearched == mLocalBranchesTree) |
1054 | { |
1055 | if (mLastIndex != -1) |
1056 | { |
1057 | mLastIndex = mLocalBranchesTree->focusOnBranch(mLastSearch, mLastIndex); |
1058 | mLastTreeSearched = mLocalBranchesTree; |
1059 | } |
1060 | |
1061 | if (mLastIndex == -1) |
1062 | { |
1063 | mLastIndex = mRemoteBranchesTree->focusOnBranch(mLastSearch); |
1064 | mLastTreeSearched = mRemoteBranchesTree; |
1065 | } |
1066 | |
1067 | if (mLastIndex == -1) |
1068 | { |
1069 | mLastIndex = mTagsTree->focusOnBranch(mLastSearch); |
1070 | mLastTreeSearched = mTagsTree; |
1071 | } |
1072 | } |
1073 | else if (mLastTreeSearched == mRemoteBranchesTree) |
1074 | { |
1075 | if (mLastIndex == -1) |
1076 | { |
1077 | mLastIndex = mRemoteBranchesTree->focusOnBranch(mLastSearch); |
1078 | mLastTreeSearched = mRemoteBranchesTree; |
1079 | } |
1080 | |
1081 | if (mLastIndex == -1) |
1082 | { |
1083 | mLastIndex = mTagsTree->focusOnBranch(mLastSearch); |
1084 | mLastTreeSearched = mTagsTree; |
1085 | } |
1086 | } |
1087 | else if (mLastIndex != -1) |
1088 | { |
1089 | mLastIndex = mTagsTree->focusOnBranch(mLastSearch, mLastIndex); |
1090 | mLastTreeSearched = mTagsTree; |
1091 | |
1092 | if (mLastIndex == -1) |
1093 | mLastTreeSearched = mLocalBranchesTree; |
1094 | } |
1095 | } |
1096 | } |
1097 | |
1098 | QPair<QString, QString> BranchesWidget::getSubtreeData(const QString &prefix) |
1099 | { |
1100 | GitQlientSettings settings(mGit->getGitDir()); |
1101 | bool end = false; |
1102 | QString url; |
1103 | QString ref; |
1104 | |
1105 | for (auto i = 0; !end; ++i) |
1106 | { |
1107 | const auto repo = settings.localValue(QString("Subtrees/%1.prefix" ).arg(i), "" ); |
1108 | |
1109 | if (repo.toString() == prefix) |
1110 | { |
1111 | auto tmpUrl = settings.localValue(QString("Subtrees/%1.url" ).arg(i)).toString(); |
1112 | auto tmpRef = settings.localValue(QString("Subtrees/%1.ref" ).arg(i)).toString(); |
1113 | |
1114 | if (tmpUrl.isEmpty() || tmpRef.isEmpty()) |
1115 | { |
1116 | const auto resp |
1117 | = QMessageBox::question(this, tr("Subtree configuration not found!" ), |
1118 | tr("The subtree configuration was not found. It could be that it was created " |
1119 | "outside GitQlient.<br>To operate with this subtree, it needs to be " |
1120 | "configured.<br><br><b>Do you want to configure it now?<b>" )); |
1121 | |
1122 | if (resp == QMessageBox::Yes) |
1123 | { |
1124 | AddSubtreeDlg stDlg(prefix, mGit, this); |
1125 | const auto ret = stDlg.exec(); |
1126 | |
1127 | if (ret == QDialog::Accepted) |
1128 | { |
1129 | tmpUrl = settings.localValue(QString("Subtrees/%1.url" ).arg(i)).toString(); |
1130 | tmpRef = settings.localValue(QString("Subtrees/%1.ref" ).arg(i)).toString(); |
1131 | |
1132 | if (tmpUrl.isEmpty() || tmpRef.isEmpty()) |
1133 | QMessageBox::critical(this, tr("Unexpected error!" ), |
1134 | tr("An unidentified error happened while using subtrees. Please contact the " |
1135 | "creator of GitQlient for support." )); |
1136 | else |
1137 | { |
1138 | url = tmpUrl; |
1139 | ref = tmpRef; |
1140 | } |
1141 | } |
1142 | } |
1143 | |
1144 | end = true; |
1145 | } |
1146 | else |
1147 | { |
1148 | url = tmpUrl; |
1149 | ref = tmpRef; |
1150 | end = true; |
1151 | } |
1152 | } |
1153 | else if (repo.toString().isEmpty()) |
1154 | { |
1155 | const auto resp |
1156 | = QMessageBox::question(this, tr("Subtree configuration not found!" ), |
1157 | tr("The subtree configuration was not found. It could be that it was created " |
1158 | "outside GitQlient.<br>To operate with this subtree, it needs to be " |
1159 | "configured.<br><br><b>Do you want to configure it now?<b>" )); |
1160 | |
1161 | if (resp == QMessageBox::Yes) |
1162 | { |
1163 | AddSubtreeDlg stDlg(prefix, mGit, this); |
1164 | const auto ret = stDlg.exec(); |
1165 | |
1166 | if (ret == QDialog::Accepted) |
1167 | { |
1168 | const auto tmpUrl = settings.localValue(QString("Subtrees/%1.url" ).arg(i)).toString(); |
1169 | const auto tmpRef = settings.localValue(QString("Subtrees/%1.ref" ).arg(i)).toString(); |
1170 | |
1171 | if (tmpUrl.isEmpty() || tmpRef.isEmpty()) |
1172 | QMessageBox::critical(this, tr("Unexpected error!" ), |
1173 | tr("An unidentified error happened while using subtrees. Please contact the " |
1174 | "creator of GitQlient for support." )); |
1175 | else |
1176 | { |
1177 | url = tmpUrl; |
1178 | ref = tmpRef; |
1179 | } |
1180 | } |
1181 | } |
1182 | |
1183 | end = true; |
1184 | } |
1185 | } |
1186 | |
1187 | return qMakePair(url, ref); |
1188 | } |
1189 | |