Logo Search packages:      
Sourcecode: qgit version File versions  Download package

treeview.cpp

/****************************************************************************
** $Id: qt/dirview.cpp   3.3.4   edited Oct 28 2003 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
** Heavily modified by Marco Costalba
*****************************************************************************/
#include <qapplication.h>
#include <qcursor.h>
#include <qpainter.h>
#include <qaction.h>
#include <qlabel.h>
#include "git.h"
#include "domain.h"
#include "mainimpl.h"
#include "treeview.h"

QPixmap* DirItem::folderClosed = NULL;
QPixmap* DirItem::folderOpen = NULL;
QPixmap* TreeView::fileDefault = NULL;

// ******************************* FileItem ****************************

void FileItem::setPixmap(QPixmap* p) {

      pix = p;
      setup();
      widthChanged(0);
      invalidateHeight();
      repaint();
}

const QPixmap* FileItem::pixmap(int i) const {

      return (i > 0 ? NULL : pix);
}

QString FileItem::text(int column) const {

      return (column == 0 ? name : "");
}

QString FileItem::fullName() {

      QString s; // root directory has no name
      if (p) {
            s = p->fullName();
            if (!s.isEmpty())
                  s.append("/");

            s.append(name);
      }
      return s;
}

void FileItem::paintCell(QPainter* p, const QColorGroup& cg, int col, int wdt, int ali) {

      p->save();
      if (isModified) {
            QFont f(p->font());
            f.setBold(true);
            p->setFont(f);
      }
      QListViewItem::paintCell(p, cg, col, wdt, ali);
      p->restore();
}


// ******************************* DirItem ****************************

using namespace QGit;

DirItem::DirItem(DirItem* par, SCRef ts, SCRef nm, TreeView* t) :
         FileItem(par, nm), treeSha(ts), tv(t), isWorkingDir(par->isWorkingDir) {

            setPixmap(folderClosed);
      }

DirItem::DirItem(QListView* par, SCRef ts, SCRef nm, TreeView* t) :
         FileItem(par, nm), treeSha(ts), tv(t), isWorkingDir(ts == ZERO_SHA) {}

void DirItem::setup() {

      setExpandable(true);
      QListViewItem::setup();
}

void TreeView::getTree(SCRef treeSha, SList names, SList shas,
                       SList types, bool wd, SCRef treePath) {

      git->getTree(treeSha, names, shas, types, wd, treePath); // calls processEvents()
}

void DirItem::setOpen(bool o) {

      if (o)
            setPixmap(folderOpen);
      else
            setPixmap(folderClosed);

      bool alreadyWaiting = false;
      if (QApplication::overrideCursor())
            alreadyWaiting = (QApplication::overrideCursor()->shape() == Qt::WaitCursor);

      if (!alreadyWaiting)
            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

      if (o && !childCount()) {

            QStringList names, types, shas;
            tv->getTree(treeSha, names, shas, types, isWorkingDir, fullName());

            if (!names.empty()) {
                  QStringList::const_iterator it(names.constBegin());
                  QStringList::const_iterator itSha(shas.constBegin());
                  QStringList::const_iterator itTypes(types.constBegin());
                  while (it != names.constEnd()) {

                        if (*itTypes == "tree") {
                              DirItem* item = new DirItem(this, *itSha, *it, tv);
                              item->setModified(tv->isModified(item->fullName(), true));
                        } else {
                              FileItem* item = new FileItem(this, *it);
                              item->setPixmap(tv->mimePix(*it));
                              item->setModified(tv->isModified(item->fullName()));
                        }
                        ++it;
                        ++itSha;
                        ++itTypes;
                  }
            }
      }
      QListViewItem::setOpen(o);
      if (!alreadyWaiting)
            QApplication::restoreOverrideCursor();
}

// ******************************* TreeView ****************************

TreeView::TreeView(Domain* dm, Git* g, QListView* lv) :
                   QObject(dm), d(dm), git(g), listView(lv) {

      EM_INIT(exTreeCleared, "Resetting tree view");

      st = &(d->st);
      oldRoot = NULL;
      ignoreCurrentChanged = false;

      initMimePix();

      connect(listView, SIGNAL(currentChanged(QListViewItem*)),
              this, SLOT(on_currentChanged(QListViewItem*)));

      connect(listView, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
              this, SLOT(on_contextMenuRequested(QListViewItem*, const QPoint&, int)));
}

void TreeView::initMimePix() {

      MainImpl* m = d->m(); // just a shortcut

      setMimePix("#FOLDER_CLOSED", m->lblFolder->pixmap());
      setMimePix("#FOLDER_OPEN",   m->lblFolderOpen->pixmap());
      setMimePix("#DEFAULT",       m->lblFile->pixmap());
      setMimePix("c",              m->lblC->pixmap());
      setMimePix("cpp",            m->lblCpp->pixmap());
      setMimePix("h",              m->lblH->pixmap());
      setMimePix("txt",            m->lblTxt->pixmap());
      setMimePix("sh",             m->lblSh->pixmap());
      setMimePix("perl",           m->lblPl->pixmap());
      setMimePix("pl",             m->lblPl->pixmap());
      setMimePix("py",             m->lblPy->pixmap());

      m->lblFolder->hide();
      m->lblFolderOpen->hide();
      m->lblFile->hide();
      m->lblC->hide();
      m->lblCpp->hide();
      m->lblH->hide();
      m->lblTxt->hide();
      m->lblSh->hide();
      m->lblPl->hide();
      m->lblPy->hide();
}

void TreeView::on_currentChanged(QListViewItem* item) {

      if (item) {
            SCRef fn = ((FileItem*)item)->fullName();
            if (!ignoreCurrentChanged && fn != st->fileName()) {
                  st->setFileName(fn);
                  st->setSelectItem(true);
                  UPDATE_DOMAIN(d);
            }
      }
}

void TreeView::on_contextMenuRequested(QListViewItem* item, const QPoint&,int) {

      if (item)
            emit contextMenu(fullName(item), POPUP_TREE_EV);
}

void TreeView::clear() {

      EM_RAISE(exTreeCleared);

      oldRoot = NULL;
      rootName = "";
      listView->clear();
}

bool TreeView::isModified(SCRef path, bool isDir) {

      if (isDir)
            return (modifiedDirs.findIndex(path) != -1);

      return (modifiedFiles.findIndex(path) != -1);
}

bool TreeView::isDir(SCRef fileName) {

      // if currentItem is NULL or is different from fileName
      // return false, because treeview is not updated while
      // not visible, so could be out of sync.
      FileItem* item = static_cast<FileItem*>(listView->currentItem());
      if (item == NULL || item->fullName() != fileName)
            return false;

      return dynamic_cast<DirItem*>(item);
}

const QString TreeView::fullName(QListViewItem* item) {

      FileItem* f = static_cast<FileItem*>(item);
      return (item ? f->fullName() : "");
}

void TreeView::getTreeSelectedItems(QStringList& selectedItems) {

      selectedItems.clear();
      QListViewItemIterator it(listView);
      while (it.current()) {
            FileItem* f = static_cast<FileItem*>(it.current());
            if (f->isSelected())
                  selectedItems.append(f->fullName());
            ++it;
      }
}

void TreeView::setMimePix(SCRef ext, QPixmap* pix) {

      // common cases first
      if (ext == "#FOLDER_CLOSED")
            DirItem::folderClosed = pix;

      else if (ext == "#FOLDER_OPEN")
            DirItem::folderOpen = pix;

      else if (ext == "#DEFAULT")
            fileDefault = pix;

      // set added extensions
      if (!mimePixMap.find(ext))
            mimePixMap.insert(ext, pix);
}

QPixmap* TreeView::mimePix(SCRef fileName) {

      SCRef ext = fileName.section('.', -1, -1);
      if (ext.isEmpty())
            return fileDefault;

      QPixmap* pix = mimePixMap.find(ext);
      return (pix ? pix : fileDefault);
}

void TreeView::setTreeName(SCRef treeName) {

      rootName = treeName;
}

void TreeView::setTree(SCRef treeSha) {

      oldRoot = listView->firstChild();
      if (!oldRoot) {
            git->getWorkDirFiles(MODIFIED, modifiedFiles, modifiedDirs);
            QStringList f, d;
            git->getWorkDirFiles(DELETED, f, d);
            modifiedFiles += f;
            modifiedDirs += d;
            git->getWorkDirFiles(UNKNOWN, f, d);
            modifiedFiles += f;
            modifiedDirs += d;
      }
      if (!treeSha.isEmpty()) {
            // insert a new dir at the beginning of the list
            DirItem* root = new DirItem(listView, treeSha, rootName, this);
            root->setOpen(true); // be interesting
      }
}

void TreeView::update() {

      if (st->sha().isEmpty())
            return;

      // qt emits currentChanged() signal when populating
      // the list view, so we should ignore while here
      ignoreCurrentChanged = true;

      try {
            EM_REGISTER(exTreeCleared);

            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

            bool newTree = true;
            DirItem* root = static_cast<DirItem*>(listView->firstChild());
            if (root)
                  newTree = (root->treeSha != st->sha());

            if (   newTree
                && root
                && st->sha() != ZERO_SHA
                && root->treeSha != ZERO_SHA)
                  // root->treeSha could reference a different sha from current
                  // one in case the tree is the same, i.e. has the same files.
                  // so we must use the state sha to call isSameFiles() and
                  // benefit from the early skip logic
                  newTree = !git->isSameFiles(st->sha(false), st->sha(true));

            if (newTree) // ok, we really need to update the tree
                  setTree(st->sha());
            else {
                  FileItem* f = static_cast<FileItem*>(listView->currentItem());
                  if (f && f->fullName() == st->fileName()) {

                        restoreStuff();
                        return;
                  }
            }
            if (st->fileName().isEmpty()) {

                  if (newTree)
                        deleteOldTree();

                  restoreStuff();
                  return;
            }
            listView->setUpdatesEnabled(false);
            QStringList lst(QStringList::split("/", st->fileName()));
            QListViewItem* item(listView->firstChild());
            item = item->itemBelow(); // first item is repository name
            loopList(it2, lst) {
                  while (item && item != oldRoot) {
                        if (item->text(0) == *it2) {
                              // could be a different subdirectory with the
                              // same name that appears before in tree view
                              // to be sure we need to check the names
                              if (st->fileName().startsWith(((FileItem*)item)->fullName())) {
                                    item->setOpen(true);
                                    break; // from while loop only
                              }
                        }
                        item = item->itemBelow();
                  }
            }
            bool found = (item && item != oldRoot);

            deleteOldTree();

            if (found) {
                  listView->clearSelection();
                  listView->setSelected(item, true);
                  listView->setCurrentItem(item); // calls on_currentChanged()
                  listView->ensureItemVisible(item);
            }
            listView->setUpdatesEnabled(true);
            listView->triggerUpdate();
            restoreStuff();

      } catch (int i) {

            EM_REMOVE(exTreeCleared);

            if (EM_MATCH(i, exTreeCleared, "updating tree")) {

                  QApplication::restoreOverrideCursor();
                  listView->setUpdatesEnabled(true);
                  ignoreCurrentChanged = false;
                  EM_CHECK_PENDING;
                  return;
            }
            const QString info("Exception \'" + EM_DESC(i) + "\' "
                               "not handled in tree view...re-throw");
            dbp("%1", info);
            throw i;
      }
}

void TreeView::restoreStuff() {

      ignoreCurrentChanged = false;
      QApplication::restoreOverrideCursor();
      EM_REMOVE(exTreeCleared);
}

void TreeView::deleteOldTree() {

      while (oldRoot && oldRoot->itemBelow())
            delete oldRoot->itemBelow();

      delete oldRoot;
      oldRoot = NULL;
}

Generated by  Doxygen 1.6.0   Back to index