2 Description: qgit revision list view
4 Author: Marco Costalba (C) 2005-2007
6 Copyright: See COPYING file that comes with this distribution
10 #include <QStackedWidget>
18 #include "patchview.h"
19 #include "smartbrowse.h"
23 RevsView::RevsView(MainImpl
* mi
, Git
* g
, bool isMain
) : Domain(mi
, g
, isMain
) {
25 revTab
= new Ui_TabRev();
26 revTab
->setupUi(container
);
28 tab()->listViewLog
->setup(this, g
);
29 tab()->textBrowserDesc
->setup(this);
30 tab()->textEditDiff
->setup(this, git
);
31 tab()->fileList
->setup(this, git
);
32 m()->treeView
->setup(this, git
);
34 setTabLogDiffVisible(QGit::testFlag(QGit::LOG_DIFF_TAB_F
));
36 SmartBrowse
* sb
= new SmartBrowse(this);
39 QVector
<QSplitter
*> v
;
40 v
<< tab()->horizontalSplitter
<< tab()->verticalSplitter
;
41 QGit::restoreGeometrySetting(QGit::REV_GEOM_KEY
, NULL
, &v
);
43 connect(m(), SIGNAL(typeWriterFontChanged()),
44 tab()->textEditDiff
, SLOT(typeWriterFontChanged()));
46 connect(m(), SIGNAL(flagChanged(uint
)),
47 sb
, SLOT(flagChanged(uint
)));
49 connect(m(), SIGNAL(flagChanged(uint
)), SLOT(on_flagChanged(uint
)));
51 connect(git
, SIGNAL(newRevsAdded(const FileHistory
*, const QVector
<ShaString
>&)),
52 this, SLOT(on_newRevsAdded(const FileHistory
*, const QVector
<ShaString
>&)));
54 connect(git
, SIGNAL(loadCompleted(const FileHistory
*, const QString
&)),
55 this, SLOT(on_loadCompleted(const FileHistory
*, const QString
&)));
57 connect(m(), SIGNAL(changeFont(const QFont
&)),
58 tab()->listViewLog
, SLOT(on_changeFont(const QFont
&)));
60 connect(m(), SIGNAL(updateRevDesc()), this, SLOT(on_updateRevDesc()));
62 connect(tab()->listViewLog
, SIGNAL(lanesContextMenuRequested(const QStringList
&,
63 const QStringList
&)), this, SLOT(on_lanesContextMenuRequested
64 (const QStringList
&, const QStringList
&)));
66 connect(tab()->listViewLog
, SIGNAL(applyRevisions(const QStringList
&, const QString
&)),
67 m(), SLOT(applyRevisions(const QStringList
&, const QString
&)));
68 connect(tab()->listViewLog
, SIGNAL(applyPatches(QStringList
)),
69 m(), SLOT(applyPatches(const QStringList
&)));
71 connect(tab()->listViewLog
, SIGNAL(rebase(QString
,QString
,QString
)),
72 m(), SLOT(rebase(QString
,QString
,QString
)));
73 connect(tab()->listViewLog
, SIGNAL(merge(QStringList
,QString
)),
74 m(), SLOT(merge(QStringList
,QString
)));
75 connect(tab()->listViewLog
, SIGNAL(moveRef(QString
,QString
)),
76 m(), SLOT(moveRef(QString
,QString
)));
78 connect(tab()->listViewLog
, SIGNAL(contextMenu(const QString
&, int)),
79 this, SLOT(on_contextMenu(const QString
&, int)));
81 connect(m()->treeView
, SIGNAL(contextMenu(const QString
&, int)),
82 this, SLOT(on_contextMenu(const QString
&, int)));
84 connect(tab()->fileList
, SIGNAL(contextMenu(const QString
&, int)),
85 this, SLOT(on_contextMenu(const QString
&, int)));
87 connect(m(), SIGNAL(changeFont(const QFont
&)),
88 tab()->fileList
, SLOT(on_changeFont(const QFont
&)));
90 connect(m(), SIGNAL(highlightPatch(const QString
&, bool)),
91 tab()->textEditDiff
, SLOT(on_highlightPatch(const QString
&, bool)));
94 RevsView::~RevsView() {
99 QVector
<QSplitter
*> v
;
100 v
<< tab()->horizontalSplitter
<< tab()->verticalSplitter
;
101 QGit::saveGeometrySetting(QGit::REV_GEOM_KEY
, NULL
, &v
);
103 // manually delete before container is removed in Domain
104 // d'tor to avoid a crash due to spurious events in
105 // SmartBrowse::eventFilter()
106 delete tab()->textBrowserDesc
;
107 delete tab()->textEditDiff
;
109 delete linkedPatchView
;
113 void RevsView::clear(bool complete
) {
115 Domain::clear(complete
);
117 tab()->textBrowserDesc
->clear();
118 tab()->textEditDiff
->clear();
119 tab()->fileList
->clear();
120 m()->treeView
->clear();
121 updateLineEditSHA(true);
123 linkedPatchView
->clear();
126 void RevsView::setEnabled(bool b
) {
128 container
->setEnabled(b
);
130 linkedPatchView
->tabPage()->setEnabled(b
);
133 void RevsView::toggleDiffView() {
135 QStackedWidget
* s
= tab()->stackedPanes
;
136 QTabWidget
* t
= tab()->tabLogDiff
;
138 bool isTabPage
= (s
->currentIndex() == 0);
139 int idx
= (isTabPage
? t
->currentIndex() : s
->currentIndex());
141 bool old
= container
->updatesEnabled();
142 container
->setUpdatesEnabled(false);
145 t
->setCurrentIndex(1 - idx
);
147 s
->setCurrentIndex(3 - idx
);
149 container
->setUpdatesEnabled(old
);
152 void RevsView::setTabLogDiffVisible(bool b
) {
154 QStackedWidget
* s
= tab()->stackedPanes
;
155 QTabWidget
* t
= tab()->tabLogDiff
;
157 bool isTabPage
= (s
->currentIndex() == 0);
158 int idx
= (isTabPage
? t
->currentIndex() : s
->currentIndex());
160 container
->setUpdatesEnabled(false);
162 if (b
&& !isTabPage
) {
164 t
->addTab(tab()->textBrowserDesc
, "Log");
165 t
->addTab(tab()->textEditDiff
, "Diff");
167 t
->setCurrentIndex(idx
- 1);
168 s
->setCurrentIndex(0);
170 if (!b
&& isTabPage
) {
172 s
->addWidget(tab()->textBrowserDesc
);
173 s
->addWidget(tab()->textEditDiff
);
175 // manually remove the two remaining empty pages
176 t
->removeTab(0); t
->removeTab(0);
178 s
->setCurrentIndex(idx
+ 1);
180 container
->setUpdatesEnabled(true);
183 void RevsView::viewPatch(bool newTab
) {
185 if (!newTab
&& linkedPatchView
) {
186 m()->tabWdg
->setCurrentWidget(linkedPatchView
->tabPage());
189 PatchView
* pv
= new PatchView(m(), git
);
190 m()->tabWdg
->addTab(pv
->tabPage(), "&Patch");
191 m()->tabWdg
->setCurrentWidget(pv
->tabPage());
193 if (!newTab
) { // linkedPatchView == NULL
194 linkedPatchView
= pv
;
195 linkDomain(linkedPatchView
);
197 connect(m(), SIGNAL(highlightPatch(const QString
&, bool)),
198 pv
->tab()->textEditDiff
, SLOT(on_highlightPatch(const QString
&, bool)));
200 connect(pv
->tab()->fileList
, SIGNAL(itemDoubleClicked(QListWidgetItem
*)),
201 m(), SLOT(fileList_itemDoubleClicked(QListWidgetItem
*)));
203 connect(m(), SIGNAL(updateRevDesc()), pv
, SLOT(on_updateRevDesc()));
204 connect(m(), SIGNAL(closeAllTabs()), pv
, SLOT(on_closeAllTabs()));
206 UPDATE_DM_MASTER(pv
, false);
209 void RevsView::on_newRevsAdded(const FileHistory
* fh
, const QVector
<ShaString
>&) {
211 if (!git
->isMainHistory(fh
) || !st
.sha().isEmpty())
214 ListView
* lv
= tab()->listViewLog
;
215 if (lv
->model()->rowCount() == 0)
218 st
.setSha(lv
->sha(0));
219 st
.setSelectItem(true);
220 UPDATE(); // give feedback to user as soon as possible
223 void RevsView::on_loadCompleted(const FileHistory
* fh
, const QString
& stats
) {
225 if (!git
->isMainHistory(fh
))
228 UPDATE(); // restore revision after a refresh
229 QApplication::postEvent(this, new MessageEvent(stats
));
232 void RevsView::on_updateRevDesc() {
234 SCRef d
= m()->getRevisionDesc(st
.sha());
235 tab()->textBrowserDesc
->setHtml(d
);
238 void RevsView::on_flagChanged(uint flag
) {
240 if (flag
== QGit::ENABLE_DRAGNDROP_F
) {
241 if (QGit::testFlag(QGit::ENABLE_DRAGNDROP_F
)) {
242 tab()->listViewLog
->setSelectionMode(QAbstractItemView::ExtendedSelection
);
244 tab()->listViewLog
->setSelectionMode(QAbstractItemView::SingleSelection
);
249 bool RevsView::doUpdate(bool force
) {
251 force
= force
|| m()->lineEditSHA
->text().isEmpty();
253 bool found
= tab()->listViewLog
->update();
255 if (!found
&& !st
.sha().isEmpty()) {
257 const QString
tmp("Sorry, revision " + st
.sha() +
258 " has not been found in main view");
259 showStatusBarMessage(tmp
);
261 } else { // sha could be NULL
263 if (st
.isChanged(StateInfo::SHA
) || force
) {
267 showStatusBarMessage(git
->getRevInfo(st
.sha()));
269 if ( testFlag(QGit::MSG_ON_NEW_F
)
270 && tab()->textEditDiff
->isVisible())
273 const RevFile
* files
= NULL
;
274 bool newFiles
= false;
276 if (st
.isChanged(StateInfo::ANY
& ~StateInfo::FILE_NAME
) || force
) {
278 tab()->fileList
->clear();
280 if (linkedPatchView
) // give some feedback while waiting
281 linkedPatchView
->clear();
283 // blocking call, could be slow in case of all merge files
284 files
= git
->getFiles(st
.sha(), st
.diffToSha(), st
.allMergeFiles());
287 tab()->textEditDiff
->update(st
);
289 // call always to allow a simple refresh
290 tab()->fileList
->update(files
, newFiles
);
292 // update the tree at startup or when releasing a no-match toolbar search
293 if (m()->treeView
->isVisible() || st
.sha(false).isEmpty())
294 m()->treeView
->updateTree(); // blocking call
296 if (st
.selectItem()) {
297 bool isDir
= m()->treeView
->isDir(st
.fileName());
298 m()->updateContextActions(st
.sha(), st
.fileName(), isDir
, found
);
300 if (st
.isChanged() || force
) {
301 // activate log or diff tab depending on file selection
302 bool sha_changed
= st
.sha(true) != st
.sha(false);
303 tab()->tabLogDiff
->setCurrentIndex(sha_changed
? 0 : 1);
304 tab()->textEditDiff
->centerOnFileHeader(st
);
307 // at the end update diffs that is the slowest and must be
308 // run after update of file list for 'diff to sha' to work
309 if (linkedPatchView
) {
310 linkedPatchView
->st
= st
;
311 UPDATE_DM_MASTER(linkedPatchView
, force
); // async call
314 return (found
|| st
.sha().isEmpty());
317 void RevsView::updateLineEditSHA(bool clear
) {
319 QLineEdit
* l
= m()->lineEditSHA
;
322 l
->setText(""); // clears history
324 else if (l
->text() != st
.sha()) {
325 auto hash
= QGit::testFlag(QGit::ENABLE_SHORTREF_F
)
326 ? st
.sha().left(git
->shortHashLength())
329 if (l
->text().isEmpty())
330 l
->setText(hash
); // first rev clears history
332 // setText() clears undo/redo history so
333 // we use clear() + insert() instead
338 m()->ActBack
->setEnabled(l
->isUndoAvailable());
339 m()->ActForward
->setEnabled(l
->isRedoAvailable());
342 void RevsView::on_lanesContextMenuRequested(SCList parents
, SCList children
) {
345 FOREACH_SL (it
, children
)
346 contextMenu
.addAction("Child: " + git
->getShortLog(*it
));
348 FOREACH_SL (it
, parents
) {
349 QString
log(git
->getShortLog(*it
));
350 contextMenu
.addAction("Parent: " + (log
.isEmpty() ? *it
: log
));
352 QAction
* act
= contextMenu
.exec(QCursor::pos()); // modal exec
356 int cc
= children
.count();
357 int id
= contextMenu
.actions().indexOf(act
);
358 SCRef
target(id
< cc
? children
[id
] : parents
[id
- cc
]);