Version 2.6
[qgit4/redivivus.git] / src / filelist.cpp
blob1a0bf80bf5cf429b42bd6cd5f3490d177544dfe8
1 /*
2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
5 */
6 #include <QDrag>
7 #include <QApplication>
8 #include <QMimeData>
9 #include <QPalette>
10 #include <QMimeData>
11 #include <QMouseEvent>
12 #include "git.h"
13 #include "domain.h"
14 #include "filelist.h"
16 FileList::FileList(QWidget* p) : QListWidget(p), d(NULL), git(NULL), st(NULL) {}
18 void FileList::setup(Domain* dm, Git* g) {
20 d = dm;
21 git = g;
22 st = &(d->st);
24 setFont(QGit::STD_FONT);
26 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
27 this, SLOT(on_customContextMenuRequested(const QPoint&)));
29 connect(this, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
30 this, SLOT(on_currentItemChanged(QListWidgetItem*, QListWidgetItem*)));
33 void FileList::addItem(const QString& label, const QColor& clr) {
35 QListWidgetItem* item = new QListWidgetItem(label, this);
36 item->setForeground(clr);
39 QString FileList::currentText() {
41 QListWidgetItem* item = currentItem();
42 return (item ? item->data(Qt::DisplayRole).toString() : "");
45 void FileList::on_changeFont(const QFont& f) {
47 setFont(f);
50 void FileList::focusInEvent(QFocusEvent*) {
52 // Workaround a Qt4.2 bug
54 // When an item is clicked and FileList still doesn't have the
55 // focus we could have a double currentItemChanged() signal,
56 // the first with current set to first item, the second with
57 // current correctly set to the clicked one.
58 // Oddly enough overriding this virtual function we remove
59 // the spurious first signal if any.
61 // Unluckily in case the clicked one is the first in list we
62 // have only one event and we could miss an update in that case,
63 // so try to handle that
64 if (!st->isMerge() && row(currentItem()) == 0)
65 on_currentItemChanged(currentItem(), currentItem());
68 void FileList::on_currentItemChanged(QListWidgetItem* current, QListWidgetItem*) {
70 if (!current)
71 return;
73 if (st->isMerge() && row(current) == 0) { // header clicked
75 // In a listbox without current item, as soon as the box
76 // gains focus the first item becomes the current item
77 // and a spurious currentChanged() signal is sent.
78 // In case of a merge the signal arrives here and fakes
79 // the user clicking on the header.
81 // The problem arise when user clicks on a merge header,
82 // then list box gains focus and current item becomes null
83 // because the content of the list is cleared and updated.
85 // If now tab is changed list box loose the focus and,
86 // upon changing back again the tab the signal triggers
87 // because Qt gives back the focus to the listbox.
89 // The workaround here is to give the focus away as soon
90 // as the user clicks on the merge header. Note that a
91 // lb->clearFocus() is not enough, we really need to
92 // reassign the focus to someone else.
93 d->tabPage()->setFocus();
94 st->setAllMergeFiles(!st->allMergeFiles());
96 } else {
97 QString fileName(currentText());
98 git->removeExtraFileInfo(&fileName);
99 // if we are called by updateFileList() fileName is already updated
100 if (st->fileName() == fileName) // avoid loops
101 return;
103 st->setFileName(fileName);
105 st->setSelectItem(true);
106 UPDATE_DOMAIN(d);
109 void FileList::on_customContextMenuRequested(const QPoint&) {
111 int row = currentRow();
112 if (row == -1 || (row == 0 && st->isMerge())) // header clicked
113 return;
115 emit contextMenu(currentText(), QGit::POPUP_FILE_EV);
118 void FileList::mousePressEvent(QMouseEvent* e) {
120 if (currentItem() && e->button() == Qt::LeftButton) {
121 d->setReadyToDrag(true);
122 dragFileName = currentText();
124 QListWidget::mousePressEvent(e);
127 void FileList::mouseReleaseEvent(QMouseEvent* e) {
129 d->setReadyToDrag(false); // in case of just click without moving
130 QListWidget::mouseReleaseEvent(e);
133 void FileList::mouseMoveEvent(QMouseEvent* e) {
135 if (d->isReadyToDrag()) {
137 if (!d->setDragging(true))
138 return;
140 if (dragFileName.isEmpty())
141 dbs("ASSERT in FileList::mouseMoveEvent() empty drag name");
143 QDrag* drag = new QDrag(this);
144 QMimeData* mimeData = new QMimeData;
145 mimeData->setText(dragFileName);
146 drag->setMimeData(mimeData);
147 dragFileName = "";
148 drag->start(); // blocking until drop event
150 d->setDragging(false);
152 QListWidget::mouseMoveEvent(e);
155 void FileList::insertFiles(const RevFile* files) {
157 clear();
158 if (!files)
159 return;
161 if (st->isMerge()) {
162 const QString header((st->allMergeFiles()) ?
163 "Click to view only interesting files" : "Click to view all merge files");
164 const bool useDark = QPalette().color(QPalette::Window).value() > QPalette().color(QPalette::WindowText).value();
165 QColor color (Qt::blue);
166 if (!useDark)
167 color = color.lighter();
168 addItem(header, color);
170 if (files->count() == 0)
171 return;
173 bool isMergeParents = !files->mergeParent.isEmpty();
174 int prevPar = (isMergeParents ? files->mergeParent.first() : 1);
175 setUpdatesEnabled(false);
176 for (int i = 0; i < files->count(); ++i) {
178 if (files->statusCmp(i, RevFile::UNKNOWN))
179 continue;
181 const bool useDark = QPalette().color(QPalette::Window).value() > QPalette().color(QPalette::WindowText).value();
183 QColor clr = palette().color(QPalette::WindowText);
184 if (isMergeParents && files->mergeParent.at(i) != prevPar) {
185 prevPar = files->mergeParent.at(i);
186 new QListWidgetItem("", this);
187 new QListWidgetItem("", this);
189 QString extSt(files->extendedStatus(i));
190 if (extSt.isEmpty()) {
191 if (files->statusCmp(i, RevFile::NEW))
192 clr = useDark ? Qt::darkGreen
193 : Qt::green;
194 else if (files->statusCmp(i, RevFile::DELETED))
195 clr = Qt::red;
196 } else {
197 clr = useDark ? Qt::darkBlue
198 : QColor(Qt::blue).lighter();
199 // in case of rename deleted file is not shown and...
200 if (files->statusCmp(i, RevFile::DELETED))
201 continue;
203 // ...new file is shown with extended info
204 if (files->statusCmp(i, RevFile::NEW)) {
205 addItem(extSt, clr);
206 continue;
209 addItem(git->filePath(*files, i), clr);
211 setUpdatesEnabled(true);
214 void FileList::update(const RevFile* files, bool newFiles) {
216 QPalette pl = QApplication::palette();
217 if (!st->diffToSha().isEmpty())
218 pl.setColor(QPalette::Base, QGit::LIGHT_BLUE);
220 setPalette(pl);
221 if (newFiles)
222 insertFiles(files);
224 QString fileName(currentText());
225 git->removeExtraFileInfo(&fileName); // could be a renamed/copied file
227 if (!fileName.isEmpty() && (fileName == st->fileName())) {
228 currentItem()->setSelected(st->selectItem()); // just a refresh
229 return;
231 clearSelection();
233 if (st->fileName().isEmpty())
234 return;
236 QList<QListWidgetItem*> l = findItems(st->fileName(), Qt::MatchExactly);
237 if (l.isEmpty()) { // could be a renamed/copied file, try harder
239 fileName = st->fileName();
240 git->addExtraFileInfo(&fileName, st->sha(), st->diffToSha(), st->allMergeFiles());
241 l = findItems(fileName, Qt::MatchExactly);
243 if (!l.isEmpty()) {
244 setCurrentItem(l.first());
245 l.first()->setSelected(st->selectItem());