treeview.cpp

Go to the documentation of this file.
00001 /*
00002         Description: files tree view
00003 
00004         Author: Marco Costalba (C) 2005-2006
00005 
00006         Copyright: See COPYING file that comes with this distribution
00007 
00008 */
00009 #include <qapplication.h>
00010 #include <qcursor.h>
00011 #include <qpainter.h>
00012 #include <qaction.h>
00013 #include <qlabel.h>
00014 #include "git.h"
00015 #include "domain.h"
00016 #include "mainimpl.h"
00017 #include "treeview.h"
00018 
00019 using namespace QGit;
00020 
00021 QString FileItem::fullName() const {
00022 
00023         QListViewItem* p = parent();
00024         QString s(p ? text(0) : ""); // root directory has no fullName
00025         while (p && p->parent()) {
00026                 s.prepend(p->text(0) + '/');
00027                 p = p->parent();
00028         }
00029         return s;
00030 }
00031 
00032 void FileItem::paintCell(QPainter* p, const QColorGroup& cg, int col, int wdt, int ali) {
00033 
00034         p->save();
00035         if (isModified) {
00036                 QFont f(p->font());
00037                 f.setBold(true);
00038                 p->setFont(f);
00039         }
00040         QListViewItem::paintCell(p, cg, col, wdt, ali);
00041         p->restore();
00042 }
00043 
00044 DirItem::DirItem(DirItem* p, SCRef ts, SCRef nm, TreeView* t) : FileItem(p, nm), treeSha(ts),
00045          tv(t), isWorkingDir(p->isWorkingDir) { setPixmap(0, *tv->folderClosed); }
00046 
00047 DirItem::DirItem(QListView* p, SCRef ts, SCRef nm, TreeView* t) : FileItem(p, nm), treeSha(ts),
00048          tv(t), isWorkingDir(ts == ZERO_SHA) {}
00049 
00050 void DirItem::setup() {
00051 
00052         setExpandable(true);
00053         QListViewItem::setup();
00054 }
00055 
00056 bool TreeView::getTree(SCRef treeSha, SList names, SList shas,
00057                        SList types, bool wd, SCRef treePath) {
00058 
00059         // calls qApp->processEvents()
00060         treeIsValid = git->getTree(treeSha, names, shas, types, wd, treePath);
00061         return treeIsValid;
00062 }
00063 
00064 void DirItem::setOpen(bool b) {
00065 
00066         setPixmap(0, b ? *tv->folderOpen : *tv->folderClosed);
00067 
00068         bool alreadyWaiting = false;
00069         if (QApplication::overrideCursor())
00070                 alreadyWaiting = (QApplication::overrideCursor()->shape() == Qt::WaitCursor);
00071 
00072         if (!alreadyWaiting)
00073                 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
00074 
00075         if (b && !childCount()) {
00076 
00077                 QStringList names, types, shas;
00078                 if (!tv->getTree(treeSha, names, shas, types, isWorkingDir, fullName()))
00079                         return;
00080 
00081                 if (!names.empty()) {
00082                         QStringList::const_iterator it(names.constBegin());
00083                         QStringList::const_iterator itSha(shas.constBegin());
00084                         QStringList::const_iterator itTypes(types.constBegin());
00085                         while (it != names.constEnd()) {
00086 
00087                                 if (*itTypes == "tree") {
00088                                         DirItem* item = new DirItem(this, *itSha, *it, tv);
00089                                         item->setModified(tv->isModified(item->fullName(), true));
00090                                 } else {
00091                                         FileItem* item = new FileItem(this, *it);
00092                                         item->setPixmap(0, *tv->mimePix(*it));
00093                                         item->setModified(tv->isModified(item->fullName()));
00094                                 }
00095                                 ++it;
00096                                 ++itSha;
00097                                 ++itTypes;
00098                         }
00099                 }
00100         }
00101         QListViewItem::setOpen(b);
00102         if (!alreadyWaiting)
00103                 QApplication::restoreOverrideCursor();
00104 }
00105 
00106 // ******************************* TreeView ****************************
00107 
00108 TreeView::TreeView(Domain* dm, Git* g, QListView* lv) : QObject(dm),
00109                    d(dm), git(g), listView(lv), treeIsValid(false) {
00110 
00111         st = &(d->st);
00112         ignoreCurrentChanged = false;
00113 
00114         initMimePix();
00115 
00116         connect(listView, SIGNAL(currentChanged(QListViewItem*)),
00117                 this, SLOT(on_currentChanged(QListViewItem*)));
00118 
00119         connect(listView, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
00120                 this, SLOT(on_contextMenuRequested(QListViewItem*, const QPoint&, int)));
00121 }
00122 
00123 void TreeView::initMimePix() {
00124 
00125         MainImpl* m = d->m(); // just a shortcut
00126 
00127         setMimePix("#FOLDER_CLOSED", m->lblFolder->pixmap());
00128         setMimePix("#FOLDER_OPEN",   m->lblFolderOpen->pixmap());
00129         setMimePix("#DEFAULT",       m->lblFile->pixmap());
00130         setMimePix("c",              m->lblC->pixmap());
00131         setMimePix("cpp",            m->lblCpp->pixmap());
00132         setMimePix("h",              m->lblH->pixmap());
00133         setMimePix("txt",            m->lblTxt->pixmap());
00134         setMimePix("sh",             m->lblSh->pixmap());
00135         setMimePix("perl",           m->lblPl->pixmap());
00136         setMimePix("pl",             m->lblPl->pixmap());
00137         setMimePix("py",             m->lblPy->pixmap());
00138         setMimePix("java",           m->lblJava->pixmap());
00139         setMimePix("jar",            m->lblJava->pixmap());
00140         setMimePix("tar",            m->lblTar->pixmap());
00141         setMimePix("gz",             m->lblTar->pixmap());
00142         setMimePix("tgz",            m->lblTar->pixmap());
00143         setMimePix("zip",            m->lblTar->pixmap());
00144         setMimePix("bz",             m->lblTar->pixmap());
00145         setMimePix("bz2",            m->lblTar->pixmap());
00146         setMimePix("html",           m->lblHtml->pixmap());
00147         setMimePix("xml",            m->lblHtml->pixmap());
00148 
00149         m->lblFolder->hide();
00150         m->lblFolderOpen->hide();
00151         m->lblFile->hide();
00152         m->lblC->hide();
00153         m->lblCpp->hide();
00154         m->lblH->hide();
00155         m->lblTxt->hide();
00156         m->lblSh->hide();
00157         m->lblPl->hide();
00158         m->lblPy->hide();
00159         m->lblJava->hide();
00160         m->lblTar->hide();
00161         m->lblHtml->hide();
00162 }
00163 
00164 void TreeView::on_currentChanged(QListViewItem* item) {
00165 
00166         if (item) {
00167                 SCRef fn = ((FileItem*)item)->fullName();
00168                 if (!ignoreCurrentChanged && fn != st->fileName()) {
00169                         st->setFileName(fn);
00170                         st->setSelectItem(true);
00171                         UPDATE_DOMAIN(d);
00172                 }
00173         }
00174 }
00175 
00176 void TreeView::on_contextMenuRequested(QListViewItem* item, const QPoint&,int) {
00177 
00178         if (item)
00179                 emit contextMenu(fullName(item), POPUP_TREE_EV);
00180 }
00181 
00182 void TreeView::clear() {
00183 
00184         rootName = "";
00185         listView->clear();
00186 }
00187 
00188 bool TreeView::isModified(SCRef path, bool isDir) {
00189 
00190         if (isDir)
00191                 return (modifiedDirs.findIndex(path) != -1);
00192 
00193         return (modifiedFiles.findIndex(path) != -1);
00194 }
00195 
00196 bool TreeView::isDir(SCRef fileName) {
00197 
00198         // if currentItem is NULL or is different from fileName
00199         // return false, because treeview is not updated while
00200         // not visible, so could be out of sync.
00201         FileItem* item = static_cast<FileItem*>(listView->currentItem());
00202         if (item == NULL || item->fullName() != fileName)
00203                 return false;
00204 
00205         return dynamic_cast<DirItem*>(item);
00206 }
00207 
00208 const QString TreeView::fullName(QListViewItem* item) {
00209 
00210         FileItem* f = static_cast<FileItem*>(item);
00211         return (item ? f->fullName() : "");
00212 }
00213 
00214 void TreeView::getTreeSelectedItems(QStringList& selectedItems) {
00215 
00216         selectedItems.clear();
00217         QListViewItemIterator it(listView);
00218         while (it.current()) {
00219                 FileItem* f = static_cast<FileItem*>(it.current());
00220                 if (f->isSelected())
00221                         selectedItems.append(f->fullName());
00222                 ++it;
00223         }
00224 }
00225 
00226 void TreeView::setMimePix(SCRef ext, QPixmap* pix) {
00227 
00228         // set built-in pixmaps
00229         if (ext == "#FOLDER_CLOSED")
00230                 folderClosed = pix;
00231 
00232         else if (ext == "#FOLDER_OPEN")
00233                 folderOpen = pix;
00234 
00235         else if (ext == "#DEFAULT")
00236                 fileDefault = pix;
00237 
00238         // set added extensions
00239         else if (!mimePixMap.find(ext))
00240                 mimePixMap.insert(ext, pix);
00241 }
00242 
00243 const QPixmap* TreeView::mimePix(SCRef fileName) {
00244 
00245         SCRef ext = fileName.section('.', -1, -1);
00246         QPixmap* pix = mimePixMap.find(ext);
00247         return (pix ? pix : fileDefault);
00248 }
00249 
00250 void TreeView::setTree(SCRef treeSha) {
00251 
00252         if (listView->childCount() == 0)
00253                 // get working dir info only once after each TreeView::clear()
00254                 git->getWorkDirFiles(modifiedFiles, modifiedDirs, RevFile::ANY);
00255 
00256         listView->clear();
00257         treeIsValid = true;
00258 
00259         if (!treeSha.isEmpty()) {
00260                 // insert a new dir at the beginning of the list
00261                 DirItem* root = new DirItem(listView, treeSha, rootName, this);
00262                 root->setOpen(true); // be interesting
00263         }
00264 }
00265 
00266 void TreeView::update() {
00267 
00268         if (st->sha().isEmpty())
00269                 return;
00270 
00271         // qt emits currentChanged() signal when populating
00272         // the list view, so we should ignore while here
00273         ignoreCurrentChanged = true;
00274         QApplication::setOverrideCursor(Qt::WaitCursor);
00275 
00276         bool newTree = true;
00277         DirItem* root = static_cast<DirItem*>(listView->firstChild());
00278         if (root && treeIsValid)
00279                 newTree = (root->treeSha != st->sha());
00280 
00281         if (   newTree
00282             && treeIsValid
00283             && root
00284             && st->sha() != ZERO_SHA
00285             && root->treeSha != ZERO_SHA)
00286                 // root->treeSha could reference a different sha from current
00287                 // one in case the tree is the same, i.e. has the same files.
00288                 // so we prefer to use the previous state sha to call isSameFiles()
00289                 // and benefit from the early skip logic.
00290                 // In case previous sha is the same of current it means an update
00291                 // call has been forced, in that case we use the 'real' root->treeSha
00292                 if (st->sha(true) != st->sha(false))
00293                         newTree = !git->isSameFiles(st->sha(false), st->sha(true));
00294                 else
00295                         newTree = !git->isSameFiles(root->treeSha, st->sha(true));
00296 
00297         if (newTree) // ok, we really need to update the tree
00298                 setTree(st->sha());
00299         else {
00300                 FileItem* f = static_cast<FileItem*>(listView->currentItem());
00301                 if (f && f->fullName() == st->fileName()) {
00302 
00303                         restoreStuff();
00304                         return;
00305                 }
00306         }
00307         if (st->fileName().isEmpty()) {
00308                 restoreStuff();
00309                 return;
00310         }
00311         listView->setUpdatesEnabled(false);
00312         const QStringList lst(QStringList::split("/", st->fileName()));
00313         QListViewItem* item = listView->firstChild();
00314         item = item->itemBelow(); // first item is repository name
00315         FOREACH_SL (it, lst) {
00316                 while (item && treeIsValid) {
00317                         if (item->text(0) == *it) {
00318                                 // could be a different subdirectory with the
00319                                 // same name that appears before in tree view
00320                                 // to be sure we need to check the names
00321                                 if (st->fileName().startsWith(((FileItem*)item)->fullName())) {
00322                                         item->setOpen(true);
00323                                         break; // from while loop only
00324                                 }
00325                         }
00326                         item = item->itemBelow();
00327                 }
00328         }
00329         // check if st->fileName() has been deleted by a patch older than this tree
00330         if (item && treeIsValid) {
00331                 listView->clearSelection();
00332                 listView->setSelected(item, true);
00333                 listView->setCurrentItem(item); // calls on_currentChanged()
00334                 listView->ensureItemVisible(item);
00335         }
00336         listView->setUpdatesEnabled(true);
00337         listView->triggerUpdate();
00338         restoreStuff();
00339 }
00340 
00341 void TreeView::restoreStuff() {
00342 
00343         ignoreCurrentChanged = false;
00344         QApplication::restoreOverrideCursor();
00345 }

Generated on Fri Dec 7 21:57:38 2007 for QGit by  doxygen 1.5.3