Menu item "Checkout" spawns a dialog, thus requires ellipsis
[qgit4/redivivus.git] / src / revsview.cpp
blob3fe871f9456ae6026130942cd3c13d9956778cc5
1 /*
2 Description: qgit revision list view
4 Author: Marco Costalba (C) 2005-2007
6 Copyright: See COPYING file that comes with this distribution
8 */
9 #include <QMenu>
10 #include <QStackedWidget>
11 #include "common.h"
12 #include "git.h"
13 #include "domain.h"
14 #include "treeview.h"
15 #include "listview.h"
16 #include "filelist.h"
17 #include "revdesc.h"
18 #include "patchview.h"
19 #include "smartbrowse.h"
20 #include "mainimpl.h"
21 #include "revsview.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);
38 // restore geometry
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() {
88 if (!parent())
89 return;
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;
102 delete revTab;
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);
114 if (linkedPatchView)
115 linkedPatchView->clear();
118 void RevsView::setEnabled(bool b) {
120 container->setEnabled(b);
121 if (linkedPatchView)
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);
136 if (isTabPage)
137 t->setCurrentIndex(1 - idx);
138 else
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());
179 return;
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()));
197 pv->st = st;
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())
204 return;
206 ListView* lv = tab()->listViewLog;
207 if (lv->model()->rowCount() == 0)
208 return;
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))
218 return;
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) {
246 updateLineEditSHA();
247 on_updateRevDesc();
248 showStatusBarMessage(git->getRevInfo(st.sha()));
250 if ( testFlag(QGit::MSG_ON_NEW_F)
251 && tab()->textEditDiff->isVisible())
252 toggleDiffView();
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());
266 newFiles = true;
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;
301 if (clear)
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
308 else {
309 // setText() clears undo/redo history so
310 // we use clear() + insert() instead
311 l->clear();
312 l->insert(st.sha());
315 m()->ActBack->setEnabled(l->isUndoAvailable());
316 m()->ActForward->setEnabled(l->isRedoAvailable());
319 void RevsView::on_lanesContextMenuRequested(SCList parents, SCList children) {
321 QMenu contextMenu;
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
330 if (!act)
331 return;
333 int cc = children.count();
334 int id = contextMenu.actions().indexOf(act);
335 SCRef target(id < cc ? children[id] : parents[id - cc]);
336 st.setSha(target);
337 UPDATE();