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(git
, SIGNAL(newRevsAdded(const FileHistory
*, const QVector
<ShaString
>&)),
50 this, SLOT(on_newRevsAdded(const FileHistory
*, const QVector
<ShaString
>&)));
52 connect(git
, SIGNAL(loadCompleted(const FileHistory
*, const QString
&)),
53 this, SLOT(on_loadCompleted(const FileHistory
*, const QString
&)));
55 connect(m(), SIGNAL(changeFont(const QFont
&)),
56 tab()->listViewLog
, SLOT(on_changeFont(const QFont
&)));
58 connect(m(), SIGNAL(updateRevDesc()), this, SLOT(on_updateRevDesc()));
60 connect(tab()->listViewLog
, SIGNAL(lanesContextMenuRequested(const QStringList
&,
61 const QStringList
&)), this, SLOT(on_lanesContextMenuRequested
62 (const QStringList
&, const QStringList
&)));
64 connect(tab()->listViewLog
, SIGNAL(revisionsDragged(const QStringList
&)),
65 m(), SLOT(revisionsDragged(const QStringList
&)));
67 connect(tab()->listViewLog
, SIGNAL(revisionsDropped(const QStringList
&)),
68 m(), SLOT(revisionsDropped(const QStringList
&)));
70 connect(tab()->listViewLog
, SIGNAL(contextMenu(const QString
&, int)),
71 this, SLOT(on_contextMenu(const QString
&, int)));
73 connect(m()->treeView
, SIGNAL(contextMenu(const QString
&, int)),
74 this, SLOT(on_contextMenu(const QString
&, int)));
76 connect(tab()->fileList
, SIGNAL(contextMenu(const QString
&, int)),
77 this, SLOT(on_contextMenu(const QString
&, int)));
79 connect(m(), SIGNAL(changeFont(const QFont
&)),
80 tab()->fileList
, SLOT(on_changeFont(const QFont
&)));
82 connect(m(), SIGNAL(highlightPatch(const QString
&, bool)),
83 tab()->textEditDiff
, SLOT(on_highlightPatch(const QString
&, bool)));
86 RevsView::~RevsView() {
91 QVector
<QSplitter
*> v
;
92 v
<< tab()->horizontalSplitter
<< tab()->verticalSplitter
;
93 QGit::saveGeometrySetting(QGit::REV_GEOM_KEY
, NULL
, &v
);
95 // manually delete before container is removed in Domain
96 // d'tor to avoid a crash due to spurious events in
97 // SmartBrowse::eventFilter()
98 delete tab()->textBrowserDesc
;
99 delete tab()->textEditDiff
;
101 delete linkedPatchView
;
105 void RevsView::clear(bool complete
) {
107 Domain::clear(complete
);
109 tab()->textBrowserDesc
->clear();
110 tab()->textEditDiff
->clear();
111 tab()->fileList
->clear();
112 m()->treeView
->clear();
113 updateLineEditSHA(true);
115 linkedPatchView
->clear();
118 void RevsView::setEnabled(bool b
) {
120 container
->setEnabled(b
);
122 linkedPatchView
->tabPage()->setEnabled(b
);
125 void RevsView::toggleDiffView() {
127 QStackedWidget
* s
= tab()->stackedPanes
;
128 QTabWidget
* t
= tab()->tabLogDiff
;
130 bool isTabPage
= (s
->currentIndex() == 0);
131 int idx
= (isTabPage
? t
->currentIndex() : s
->currentIndex());
133 bool old
= container
->updatesEnabled();
134 container
->setUpdatesEnabled(false);
137 t
->setCurrentIndex(1 - idx
);
139 s
->setCurrentIndex(3 - idx
);
141 container
->setUpdatesEnabled(old
);
144 void RevsView::setTabLogDiffVisible(bool b
) {
146 QStackedWidget
* s
= tab()->stackedPanes
;
147 QTabWidget
* t
= tab()->tabLogDiff
;
149 bool isTabPage
= (s
->currentIndex() == 0);
150 int idx
= (isTabPage
? t
->currentIndex() : s
->currentIndex());
152 container
->setUpdatesEnabled(false);
154 if (b
&& !isTabPage
) {
156 t
->addTab(tab()->textBrowserDesc
, "Log");
157 t
->addTab(tab()->textEditDiff
, "Diff");
159 t
->setCurrentIndex(idx
- 1);
160 s
->setCurrentIndex(0);
162 if (!b
&& isTabPage
) {
164 s
->addWidget(tab()->textBrowserDesc
);
165 s
->addWidget(tab()->textEditDiff
);
167 // manually remove the two remaining empty pages
168 t
->removeTab(0); t
->removeTab(0);
170 s
->setCurrentIndex(idx
+ 1);
172 container
->setUpdatesEnabled(true);
175 void RevsView::viewPatch(bool newTab
) {
177 if (!newTab
&& linkedPatchView
) {
178 m()->tabWdg
->setCurrentWidget(linkedPatchView
->tabPage());
181 PatchView
* pv
= new PatchView(m(), git
);
182 m()->tabWdg
->addTab(pv
->tabPage(), "&Patch");
183 m()->tabWdg
->setCurrentWidget(pv
->tabPage());
185 if (!newTab
) { // linkedPatchView == NULL
186 linkedPatchView
= pv
;
187 linkDomain(linkedPatchView
);
189 connect(m(), SIGNAL(highlightPatch(const QString
&, bool)),
190 pv
->tab()->textEditDiff
, SLOT(on_highlightPatch(const QString
&, bool)));
192 connect(pv
->tab()->fileList
, SIGNAL(itemDoubleClicked(QListWidgetItem
*)),
193 m(), SLOT(fileList_itemDoubleClicked(QListWidgetItem
*)));
195 connect(m(), SIGNAL(updateRevDesc()), pv
, SLOT(on_updateRevDesc()));
196 connect(m(), SIGNAL(closeAllTabs()), pv
, SLOT(on_closeAllTabs()));
198 UPDATE_DM_MASTER(pv
, false);
201 void RevsView::on_newRevsAdded(const FileHistory
* fh
, const QVector
<ShaString
>&) {
203 if (!git
->isMainHistory(fh
) || !st
.sha().isEmpty())
206 ListView
* lv
= tab()->listViewLog
;
207 if (lv
->model()->rowCount() == 0)
210 st
.setSha(lv
->sha(0));
211 st
.setSelectItem(true);
212 UPDATE(); // give feedback to user as soon as possible
215 void RevsView::on_loadCompleted(const FileHistory
* fh
, const QString
& stats
) {
217 if (!git
->isMainHistory(fh
))
220 UPDATE(); // restore revision after a refresh
221 QApplication::postEvent(this, new MessageEvent(stats
));
224 void RevsView::on_updateRevDesc() {
226 SCRef d
= m()->getRevisionDesc(st
.sha());
227 tab()->textBrowserDesc
->setHtml(d
);
230 bool RevsView::doUpdate(bool force
) {
232 force
= force
|| m()->lineEditSHA
->text().isEmpty();
234 bool found
= tab()->listViewLog
->update();
236 if (!found
&& !st
.sha().isEmpty()) {
238 const QString
tmp("Sorry, revision " + st
.sha() +
239 " has not been found in main view");
240 showStatusBarMessage(tmp
);
242 } else { // sha could be NULL
244 if (st
.isChanged(StateInfo::SHA
) || force
) {
248 showStatusBarMessage(git
->getRevInfo(st
.sha()));
250 if ( testFlag(QGit::MSG_ON_NEW_F
)
251 && tab()->textEditDiff
->isVisible())
254 const RevFile
* files
= NULL
;
255 bool newFiles
= false;
257 if (st
.isChanged(StateInfo::ANY
& ~StateInfo::FILE_NAME
) || force
) {
259 tab()->fileList
->clear();
261 if (linkedPatchView
) // give some feedback while waiting
262 linkedPatchView
->clear();
264 // blocking call, could be slow in case of all merge files
265 files
= git
->getFiles(st
.sha(), st
.diffToSha(), st
.allMergeFiles());
268 tab()->textEditDiff
->update(st
);
270 // call always to allow a simple refresh
271 tab()->fileList
->update(files
, newFiles
);
273 // update the tree at startup or when releasing a no-match toolbar search
274 if (m()->treeView
->isVisible() || st
.sha(false).isEmpty())
275 m()->treeView
->updateTree(); // blocking call
277 if (st
.selectItem()) {
278 bool isDir
= m()->treeView
->isDir(st
.fileName());
279 m()->updateContextActions(st
.sha(), st
.fileName(), isDir
, found
);
281 if (st
.isChanged() || force
) {
282 // activate log or diff tab depending on file selection
283 tab()->tabLogDiff
->setCurrentIndex(st
.fileName().isEmpty() ? 0 : 1);
284 tab()->textEditDiff
->centerOnFileHeader(st
);
287 // at the end update diffs that is the slowest and must be
288 // run after update of file list for 'diff to sha' to work
289 if (linkedPatchView
) {
290 linkedPatchView
->st
= st
;
291 UPDATE_DM_MASTER(linkedPatchView
, force
); // async call
294 return (found
|| st
.sha().isEmpty());
297 void RevsView::updateLineEditSHA(bool clear
) {
299 QLineEdit
* l
= m()->lineEditSHA
;
302 l
->setText(""); // clears history
304 else if (l
->text() != st
.sha()) {
306 if (l
->text().isEmpty())
307 l
->setText(st
.sha()); // first rev clears history
309 // setText() clears undo/redo history so
310 // we use clear() + insert() instead
315 m()->ActBack
->setEnabled(l
->isUndoAvailable());
316 m()->ActForward
->setEnabled(l
->isRedoAvailable());
319 void RevsView::on_lanesContextMenuRequested(SCList parents
, SCList children
) {
322 FOREACH_SL (it
, children
)
323 contextMenu
.addAction("Child: " + git
->getShortLog(*it
));
325 FOREACH_SL (it
, parents
) {
326 QString
log(git
->getShortLog(*it
));
327 contextMenu
.addAction("Parent: " + (log
.isEmpty() ? *it
: log
));
329 QAction
* act
= contextMenu
.exec(QCursor::pos()); // modal exec
333 int cc
= children
.count();
334 int id
= contextMenu
.actions().indexOf(act
);
335 SCRef
target(id
< cc
? children
[id
] : parents
[id
- cc
]);