2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QApplication>
11 #include <QMouseEvent>
16 FileList::FileList(QWidget
* p
) : QListWidget(p
), d(NULL
), git(NULL
), st(NULL
) {}
18 void FileList::setup(Domain
* dm
, Git
* g
) {
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
) {
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
*) {
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());
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
103 st
->setFileName(fileName
);
105 st
->setSelectItem(true);
109 void FileList::on_customContextMenuRequested(const QPoint
&) {
111 int row
= currentRow();
112 if (row
== -1 || (row
== 0 && st
->isMerge())) // header clicked
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))
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
);
148 drag
->start(); // blocking until drop event
150 d
->setDragging(false);
152 QListWidget::mouseMoveEvent(e
);
155 void FileList::insertFiles(const RevFile
* files
) {
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
);
167 color
= color
.lighter();
168 addItem(header
, color
);
170 if (files
->count() == 0)
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
))
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
194 else if (files
->statusCmp(i
, RevFile::DELETED
))
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
))
203 // ...new file is shown with extended info
204 if (files
->statusCmp(i
, RevFile::NEW
)) {
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
);
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
233 if (st
->fileName().isEmpty())
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
);
244 setCurrentItem(l
.first());
245 l
.first()->setSelected(st
->selectItem());