Silence compilation warnings
[qgit4/redivivus.git] / src / filelist.cpp
blob0196d98bad91825e631832625f6ed284177db598
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 <QPainter>
13 #include "git.h"
14 #include "domain.h"
15 #include "filelist.h"
17 FileList::FileList(QWidget* p) : QListWidget(p), d(NULL), git(NULL), st(NULL) {}
19 void FileList::setup(Domain* dm, Git* g) {
21 d = dm;
22 git = g;
23 st = &(d->st);
25 setFont(QGit::STD_FONT);
27 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
28 this, SLOT(on_customContextMenuRequested(const QPoint&)));
30 connect(this, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
31 this, SLOT(on_currentItemChanged(QListWidgetItem*, QListWidgetItem*)));
34 void FileList::addItem(const QString& label, const QColor& clr) {
36 QListWidgetItem* item = new QListWidgetItem(label, this);
37 item->setForeground(clr);
40 QString FileList::currentText() {
42 QListWidgetItem* item = currentItem();
43 return (item ? item->data(Qt::DisplayRole).toString() : "");
46 void FileList::on_changeFont(const QFont& f) {
48 setFont(f);
51 void FileList::focusInEvent(QFocusEvent*) {
53 // Workaround a Qt4.2 bug
55 // When an item is clicked and FileList still doesn't have the
56 // focus we could have a double currentItemChanged() signal,
57 // the first with current set to first item, the second with
58 // current correctly set to the clicked one.
59 // Oddly enough overriding this virtual function we remove
60 // the spurious first signal if any.
62 // Unluckily in case the clicked one is the first in list we
63 // have only one event and we could miss an update in that case,
64 // so try to handle that
65 if (!st->isMerge() && row(currentItem()) == 0)
66 on_currentItemChanged(currentItem(), currentItem());
69 void FileList::on_currentItemChanged(QListWidgetItem* current, QListWidgetItem*) {
71 if (!current)
72 return;
74 if (st->isMerge() && row(current) == 0) { // header clicked
76 // In a listbox without current item, as soon as the box
77 // gains focus the first item becomes the current item
78 // and a spurious currentChanged() signal is sent.
79 // In case of a merge the signal arrives here and fakes
80 // the user clicking on the header.
82 // The problem arise when user clicks on a merge header,
83 // then list box gains focus and current item becomes null
84 // because the content of the list is cleared and updated.
86 // If now tab is changed list box loose the focus and,
87 // upon changing back again the tab the signal triggers
88 // because Qt gives back the focus to the listbox.
90 // The workaround here is to give the focus away as soon
91 // as the user clicks on the merge header. Note that a
92 // lb->clearFocus() is not enough, we really need to
93 // reassign the focus to someone else.
94 d->tabPage()->setFocus();
95 st->setAllMergeFiles(!st->allMergeFiles());
97 } else {
98 QString fileName(currentText());
99 git->removeExtraFileInfo(&fileName);
100 // if we are called by updateFileList() fileName is already updated
101 if (st->fileName() == fileName) // avoid loops
102 return;
104 st->setFileName(fileName);
106 st->setSelectItem(true);
107 UPDATE_DOMAIN(d);
110 void FileList::on_customContextMenuRequested(const QPoint&) {
112 int row = currentRow();
113 if (row == -1 || (row == 0 && st->isMerge())) // header clicked
114 return;
116 emit contextMenu(currentText(), QGit::POPUP_FILE_EV);
119 bool FileList::startDragging(QMouseEvent* /*e*/) {
120 const QString& dragFileName = currentText();
121 if (dragFileName.isEmpty()) return false;
123 QMimeData* mimeData = new QMimeData;
124 mimeData->setText(dragFileName);
126 QDrag *drag = new QDrag(this);
127 drag->setMimeData(mimeData);
129 // attach some nice pixmap to the drag (to know what is dragged)
130 int spacing = 4;
131 QFont f;
132 QFontMetrics fm(f);
133 QSize size = fm.boundingRect(dragFileName).size() + QSize(2*spacing, 2);
135 QPixmap pixmap(size);
136 QPainter painter;
137 painter.begin(&pixmap);
138 painter.setBrush(QPalette().color(QPalette::Window));
139 painter.drawRect(0,0, size.width()-1, size.height()-1);
140 painter.drawText(spacing, fm.ascent()+1, dragFileName);
141 painter.end();
142 drag->setPixmap(pixmap);
144 // exec blocks until dragging is finished
145 drag->exec(Qt::CopyAction, Qt::CopyAction);
146 return true;
149 void FileList::mouseMoveEvent(QMouseEvent* e) {
150 if (e->buttons() == Qt::LeftButton)
151 if (startDragging(e)) return;
153 QListWidget::mouseMoveEvent(e);
156 void FileList::insertFiles(const RevFile* files) {
158 clear();
159 if (!files)
160 return;
162 if (st->isMerge()) {
163 const QString header((st->allMergeFiles()) ?
164 "Click to view only interesting files" : "Click to view all merge files");
165 const bool useDark = QPalette().color(QPalette::Window).value() > QPalette().color(QPalette::WindowText).value();
166 QColor color (Qt::blue);
167 if (!useDark)
168 color = color.lighter();
169 addItem(header, color);
171 if (files->count() == 0)
172 return;
174 bool isMergeParents = !files->mergeParent.isEmpty();
175 int prevPar = (isMergeParents ? files->mergeParent.first() : 1);
176 setUpdatesEnabled(false);
177 for (int i = 0; i < files->count(); ++i) {
179 if (files->statusCmp(i, RevFile::UNKNOWN))
180 continue;
182 const bool useDark = QPalette().color(QPalette::Window).value() > QPalette().color(QPalette::WindowText).value();
184 QColor clr = palette().color(QPalette::WindowText);
185 if (isMergeParents && files->mergeParent.at(i) != prevPar) {
186 prevPar = files->mergeParent.at(i);
187 new QListWidgetItem("", this);
188 new QListWidgetItem("", this);
190 QString extSt(files->extendedStatus(i));
191 if (extSt.isEmpty()) {
192 if (files->statusCmp(i, RevFile::NEW))
193 clr = useDark ? Qt::darkGreen
194 : Qt::green;
195 else if (files->statusCmp(i, RevFile::DELETED))
196 clr = Qt::red;
197 } else {
198 clr = useDark ? Qt::darkBlue
199 : QColor(Qt::blue).lighter();
200 // in case of rename deleted file is not shown and...
201 if (files->statusCmp(i, RevFile::DELETED))
202 continue;
204 // ...new file is shown with extended info
205 if (files->statusCmp(i, RevFile::NEW)) {
206 addItem(extSt, clr);
207 continue;
210 addItem(git->filePath(*files, i), clr);
212 setUpdatesEnabled(true);
215 void FileList::update(const RevFile* files, bool newFiles) {
217 QPalette pl = QApplication::palette();
218 if (!st->diffToSha().isEmpty())
219 pl.setColor(QPalette::Base, QGit::LIGHT_BLUE);
221 setPalette(pl);
222 if (newFiles)
223 insertFiles(files);
225 QString fileName(currentText());
226 git->removeExtraFileInfo(&fileName); // could be a renamed/copied file
228 if (!fileName.isEmpty() && (fileName == st->fileName())) {
229 currentItem()->setSelected(st->selectItem()); // just a refresh
230 return;
232 clearSelection();
234 if (st->fileName().isEmpty())
235 return;
237 QList<QListWidgetItem*> l = findItems(st->fileName(), Qt::MatchExactly);
238 if (l.isEmpty()) { // could be a renamed/copied file, try harder
240 fileName = st->fileName();
241 git->addExtraFileInfo(&fileName, st->sha(), st->diffToSha(), st->allMergeFiles());
242 l = findItems(fileName, Qt::MatchExactly);
244 if (!l.isEmpty()) {
245 setCurrentItem(l.first());
246 l.first()->setSelected(st->selectItem());