2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QApplication>
13 FileList::FileList(QWidget
* p
) : QListWidget(p
), d(NULL
), git(NULL
), st(NULL
) {}
15 void FileList::setup(Domain
* dm
, Git
* g
) {
21 setFont(QGit::STD_FONT
);
23 connect(this, SIGNAL(customContextMenuRequested(const QPoint
&)),
24 this, SLOT(on_customContextMenuRequested(const QPoint
&)));
26 connect(this, SIGNAL(currentItemChanged(QListWidgetItem
*, QListWidgetItem
*)),
27 this, SLOT(on_currentItemChanged(QListWidgetItem
*, QListWidgetItem
*)));
30 void FileList::addItem(const QString
& label
, const QColor
& clr
) {
32 QListWidgetItem
* item
= new QListWidgetItem(label
, this);
33 item
->setForeground(clr
);
36 QString
FileList::currentText() {
38 QListWidgetItem
* item
= currentItem();
39 return (item
? item
->data(Qt::DisplayRole
).toString() : "");
42 void FileList::on_changeFont(const QFont
& f
) {
47 void FileList::focusInEvent(QFocusEvent
*) {
49 // Workaround a Qt4.2 bug
51 // When an item is clicked and FileList still doesn't have the
52 // focus we could have a double currentItemChanged() signal,
53 // the first with current set to first item, the second with
54 // current correctly set to the clicked one.
55 // Oddly enough overriding this virtual function we remove
56 // the spurious first signal if any.
58 // Unluckily in case the clicked one is the first in list we
59 // have only one event and we could miss an update in that case,
60 // so try to handle that
61 if (!st
->isMerge() && row(currentItem()) == 0)
62 on_currentItemChanged(currentItem(), currentItem());
65 void FileList::on_currentItemChanged(QListWidgetItem
* current
, QListWidgetItem
*) {
70 if (st
->isMerge() && row(current
) == 0) { // header clicked
72 // In a listbox without current item, as soon as the box
73 // gains focus the first item becomes the current item
74 // and a spurious currentChanged() signal is sent.
75 // In case of a merge the signal arrives here and fakes
76 // the user clicking on the header.
78 // The problem arise when user clicks on a merge header,
79 // then list box gains focus and current item becomes null
80 // because the content of the list is cleared and updated.
82 // If now tab is changed list box loose the focus and,
83 // upon changing back again the tab the signal triggers
84 // because Qt gives back the focus to the listbox.
86 // The workaround here is to give the focus away as soon
87 // as the user clicks on the merge header. Note that a
88 // lb->clearFocus() is not enough, we really need to
89 // reassign the focus to someone else.
90 d
->tabPage()->setFocus();
91 st
->setAllMergeFiles(!st
->allMergeFiles());
94 QString
fileName(currentText());
95 git
->removeExtraFileInfo(&fileName
);
96 // if we are called by updateFileList() fileName is already updated
97 if (st
->fileName() == fileName
) // avoid loops
100 st
->setFileName(fileName
);
102 st
->setSelectItem(true);
106 void FileList::on_customContextMenuRequested(const QPoint
&) {
108 int row
= currentRow();
109 if (row
== -1 || (row
== 0 && st
->isMerge())) // header clicked
112 emit
contextMenu(currentText(), QGit::POPUP_FILE_EV
);
115 void FileList::mousePressEvent(QMouseEvent
* e
) {
117 if (currentItem() && e
->button() == Qt::LeftButton
) {
118 d
->setReadyToDrag(true);
119 dragFileName
= currentText();
121 QListWidget::mousePressEvent(e
);
124 void FileList::mouseReleaseEvent(QMouseEvent
* e
) {
126 d
->setReadyToDrag(false); // in case of just click without moving
127 QListWidget::mouseReleaseEvent(e
);
130 void FileList::mouseMoveEvent(QMouseEvent
* e
) {
132 if (d
->isReadyToDrag()) {
134 if (!d
->setDragging(true))
137 if (dragFileName
.isEmpty())
138 dbs("ASSERT in FileList::mouseMoveEvent() empty drag name");
140 QDrag
* drag
= new QDrag(this);
141 QMimeData
* mimeData
= new QMimeData
;
142 mimeData
->setText(dragFileName
);
143 drag
->setMimeData(mimeData
);
145 drag
->start(); // blocking until drop event
147 d
->setDragging(false);
149 QListWidget::mouseMoveEvent(e
);
152 void FileList::insertFiles(const RevFile
* files
) {
159 const QString
header((st
->allMergeFiles()) ?
160 "Click to view only interesting files" : "Click to view all merge files");
161 addItem(header
, Qt::blue
);
163 if (files
->count() == 0)
166 bool isMergeParents
= !files
->mergeParent
.isEmpty();
167 int prevPar
= (isMergeParents
? files
->mergeParent
.first() : 1);
168 setUpdatesEnabled(false);
169 for (int i
= 0; i
< files
->count(); ++i
) {
171 if (files
->statusCmp(i
, RevFile::UNKNOWN
))
174 QColor clr
= Qt::black
;
175 if (isMergeParents
&& files
->mergeParent
.at(i
) != prevPar
) {
176 prevPar
= files
->mergeParent
.at(i
);
177 new QListWidgetItem("", this);
178 new QListWidgetItem("", this);
180 QString
extSt(files
->extendedStatus(i
));
181 if (extSt
.isEmpty()) {
182 if (files
->statusCmp(i
, RevFile::NEW
))
184 else if (files
->statusCmp(i
, RevFile::DELETED
))
188 // in case of rename deleted file is not shown and...
189 if (files
->statusCmp(i
, RevFile::DELETED
))
192 // ...new file is shown with extended info
193 if (files
->statusCmp(i
, RevFile::NEW
)) {
198 addItem(git
->filePath(*files
, i
), clr
);
200 setUpdatesEnabled(true);
203 void FileList::update(const RevFile
* files
, bool newFiles
) {
205 QPalette pl
= QApplication::palette();
206 if (!st
->diffToSha().isEmpty())
207 pl
.setColor(QPalette::Base
, QGit::LIGHT_BLUE
);
213 QString
fileName(currentText());
214 git
->removeExtraFileInfo(&fileName
); // could be a renamed/copied file
216 if (!fileName
.isEmpty() && (fileName
== st
->fileName())) {
217 currentItem()->setSelected(st
->selectItem()); // just a refresh
222 if (st
->fileName().isEmpty())
225 QList
<QListWidgetItem
*> l
= findItems(st
->fileName(), Qt::MatchExactly
);
226 if (l
.isEmpty()) { // could be a renamed/copied file, try harder
228 fileName
= st
->fileName();
229 git
->addExtraFileInfo(&fileName
, st
->sha(), st
->diffToSha(), st
->allMergeFiles());
230 l
= findItems(fileName
, Qt::MatchExactly
);
233 setCurrentItem(l
.first());
234 l
.first()->setSelected(st
->selectItem());