2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QApplication>
11 #include <QMouseEvent>
17 FileList::FileList(QWidget
* p
) : QListWidget(p
), d(NULL
), git(NULL
), st(NULL
) {}
19 void FileList::setup(Domain
* dm
, Git
* g
) {
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
) {
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
*) {
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());
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
104 st
->setFileName(fileName
);
106 st
->setSelectItem(true);
110 void FileList::on_customContextMenuRequested(const QPoint
&) {
112 int row
= currentRow();
113 if (row
== -1 || (row
== 0 && st
->isMerge())) // header clicked
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)
133 QSize size
= fm
.boundingRect(dragFileName
).size() + QSize(2*spacing
, 2);
135 QPixmap
pixmap(size
);
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
);
142 drag
->setPixmap(pixmap
);
144 // exec blocks until dragging is finished
145 drag
->exec(Qt::CopyAction
, Qt::CopyAction
);
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
) {
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
);
168 color
= color
.lighter();
169 addItem(header
, color
);
171 if (files
->count() == 0)
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
))
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
195 else if (files
->statusCmp(i
, RevFile::DELETED
))
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
))
204 // ...new file is shown with extended info
205 if (files
->statusCmp(i
, RevFile::NEW
)) {
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
);
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
234 if (st
->fileName().isEmpty())
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
);
245 setCurrentItem(l
.first());
246 l
.first()->setSelected(st
->selectItem());