2 Description: files tree view
4 Author: Marco Costalba (C) 2005-2007
6 Copyright: See COPYING file that comes with this distribution
9 #include <QApplication>
10 #include <QTreeWidgetItemIterator>
16 QString
FileItem::fullName() const {
18 QTreeWidgetItem
* p
= parent();
19 QString
s(p
? text(0) : ""); // root directory has no fullName
20 while (p
&& p
->parent()) {
21 s
.prepend(p
->text(0) + '/');
27 void FileItem::setBold(bool b
) {
29 if (font(0).bold() == b
)
37 DirItem::DirItem(DirItem
* p
, SCRef ts
, SCRef nm
) : FileItem(p
, nm
), treeSha(ts
) {}
38 DirItem::DirItem(QTreeWidget
* p
, SCRef ts
, SCRef nm
) : FileItem(p
, nm
), treeSha(ts
) {}
40 void TreeView::setup(Domain
* dm
, Git
* g
) {
45 ignoreCurrentChanged
= false;
48 // set built-in pixmaps
49 folderClosed
= QGit::mimePix(".#folder_closed");
50 folderOpen
= QGit::mimePix(".#folder_open");
51 fileDefault
= QGit::mimePix(".#default");
53 connect(this, SIGNAL(itemExpanded(QTreeWidgetItem
*)),
54 this, SLOT(on_itemExpanded(QTreeWidgetItem
*)));
56 connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem
*)),
57 this, SLOT(on_itemCollapsed(QTreeWidgetItem
*)));
59 connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem
*, QTreeWidgetItem
*)),
60 this, SLOT(on_currentItemChanged(QTreeWidgetItem
*, QTreeWidgetItem
*)));
62 connect(this, SIGNAL(customContextMenuRequested(const QPoint
&)),
63 this, SLOT(on_customContextMenuRequested(const QPoint
&)));
66 void TreeView::on_currentItemChanged(QTreeWidgetItem
* item
, QTreeWidgetItem
*) {
69 SCRef fn
= ((FileItem
*)item
)->fullName();
70 if (!ignoreCurrentChanged
&& fn
!= st
->fileName()) {
72 st
->setSelectItem(true);
78 void TreeView::on_customContextMenuRequested(const QPoint
& pos
) {
80 QTreeWidgetItem
* item
= itemAt(pos
);
82 emit
contextMenu(fullName(item
), QGit::POPUP_TREE_EV
);
85 void TreeView::clear() {
91 bool TreeView::isModified(SCRef path
, bool isDir
) {
94 return modifiedDirs
.contains(path
);
96 return modifiedFiles
.contains(path
);
99 bool TreeView::isDir(SCRef fileName
) {
101 // if currentItem is NULL or is different from fileName
102 // return false, because treeview is not updated while
103 // not visible, so could be out of sync.
104 FileItem
* item
= static_cast<FileItem
*>(currentItem());
105 if (item
== NULL
|| item
->fullName() != fileName
)
108 return dynamic_cast<DirItem
*>(item
);
111 const QString
TreeView::fullName(QTreeWidgetItem
* item
) {
113 FileItem
* f
= static_cast<FileItem
*>(item
);
114 return (item
? f
->fullName() : "");
117 void TreeView::getTreeSelectedItems(QStringList
& selectedItems
) {
119 selectedItems
.clear();
120 QList
<QTreeWidgetItem
*> ls
= QTreeWidget::selectedItems();
121 FOREACH (QList
<QTreeWidgetItem
*>, it
, ls
) {
122 FileItem
* f
= static_cast<FileItem
*>(*it
);
123 selectedItems
.append(f
->fullName());
127 void TreeView::setTree(SCRef treeSha
) {
129 if (topLevelItemCount() == 0)
130 // get working dir info only once after each TreeView::clear()
131 git
->getWorkDirFiles(modifiedFiles
, modifiedDirs
, RevFile::ANY
);
133 QTreeWidget::clear();
136 if (!treeSha
.isEmpty()) {
137 // insert a new dir at the beginning of the list
138 DirItem
* root
= new DirItem(this, treeSha
, rootName
);
139 expandItem(root
); // be interesting
143 bool TreeView::getTree(SCRef treeSha
, Git::TreeInfo
& ti
, bool wd
, SCRef treePath
) {
145 // calls qApp->processEvents()
146 treeIsValid
= git
->getTree(treeSha
, ti
, wd
, treePath
);
150 void TreeView::on_itemCollapsed(QTreeWidgetItem
* item
) {
152 item
->setData(0, Qt::DecorationRole
, *folderClosed
);
155 void TreeView::on_itemExpanded(QTreeWidgetItem
* itm
) {
157 DirItem
* item
= dynamic_cast<DirItem
*>(itm
);
161 item
->setData(0, Qt::DecorationRole
, *folderOpen
);
163 bool alreadyWaiting
= false;
164 if (QApplication::overrideCursor())
165 alreadyWaiting
= (QApplication::overrideCursor()->shape() == Qt::WaitCursor
);
168 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor
));
170 if (item
->childCount() < 2) {
172 QTreeWidgetItem
* dummy
= item
->child(0);
173 if (dummy
&& dummy
->text(0).isEmpty())
174 delete dummy
; // remove dummy child
177 if (!getTree(item
->treeSha
, ti
, isWorkingDir
, item
->fullName()))
182 Git::TreeInfo::const_iterator
it(ti
.constBegin());
183 while (it
!= ti
.constEnd()) {
185 const Git::TreeEntry
& te
= *it
;
187 if (te
.type
== "tree") {
188 DirItem
* dir
= new DirItem(item
, te
.sha
, te
.name
);
189 dir
->setData(0, Qt::DecorationRole
, *folderClosed
);
190 dir
->setBold(isModified(dir
->fullName(), true));
191 new DirItem(dir
, "", ""); // dummy child to show expand sign
193 FileItem
* file
= new FileItem(item
, te
.name
);
194 file
->setData(0, Qt::DecorationRole
, *QGit::mimePix(te
.name
));
195 file
->setBold(isModified(file
->fullName()));
202 QApplication::restoreOverrideCursor();
205 void TreeView::updateTree() {
207 if (st
->sha().isEmpty())
210 // qt emits currentChanged() signal when populating
211 // the list view, so we should ignore while here
212 ignoreCurrentChanged
= true;
213 QApplication::setOverrideCursor(Qt::WaitCursor
);
215 isWorkingDir
= (st
->sha() == QGit::ZERO_SHA
);
217 DirItem
* root
= static_cast<DirItem
*>(topLevelItem(0));
218 if (root
&& treeIsValid
)
219 newTree
= (root
->treeSha
!= st
->sha());
224 && st
->sha() != QGit::ZERO_SHA
225 && root
->treeSha
!= QGit::ZERO_SHA
) {
226 // root->treeSha could reference a different sha from current
227 // one in case the tree is the same, i.e. has the same files.
228 // so we prefer to use the previous state sha to call isSameFiles()
229 // and benefit from the early skip logic.
230 // In case previous sha is the same of current it means an update
231 // call has been forced, in that case we use the 'real' root->treeSha
232 if (st
->sha(true) != st
->sha(false))
233 newTree
= !git
->isSameFiles(st
->sha(false), st
->sha(true));
235 newTree
= !git
->isSameFiles(root
->treeSha
, st
->sha(true));
238 if (newTree
) // ok, we really need to update the tree
241 FileItem
* f
= static_cast<FileItem
*>(currentItem());
242 if (f
&& f
->fullName() == st
->fileName()) {
248 if (st
->fileName().isEmpty()) {
252 setUpdatesEnabled(false);
253 const QStringList
lst(st
->fileName().split("/"));
255 QTreeWidgetItemIterator
item(this);
256 ++item
; // first item is repository name
257 FOREACH_SL (it
, lst
) {
258 while (*item
&& treeIsValid
) {
260 if ((*item
)->text(0) == *it
) {
262 // could be a different subdirectory with the
263 // same name that appears before in tree view
264 // to be sure we need to check the names
265 SCRef fn
= ((FileItem
*)*item
)->fullName();
266 if (st
->fileName().startsWith(fn
)) {
268 if (dynamic_cast<DirItem
*>(*item
)) {
272 break; // from while loop only
278 // check if st->fileName() has been deleted by a patch older than this tree
279 if (*item
&& treeIsValid
) {
281 setCurrentItem(*item
); // calls on_currentChanged()
284 setUpdatesEnabled(true);
285 QTreeWidget::update();
289 void TreeView::restoreStuff() {
291 ignoreCurrentChanged
= false;
292 QApplication::restoreOverrideCursor();