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

kbstreeview.cpp

/***************************************************************************
 *   Copyright (C) 2004 by Roberto Virga                                   *
 *   rvirga@users.sf.net                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <qheader.h>
#include <qlayout.h>
#include <qpopupmenu.h>

#include <kiconloader.h>
#include <klocale.h>
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>

#include <kboincspy.h>
#include <kbstree.h>

#include "kbstreeview.h"

KBSTreeView::KBSTreeView(KBSTreeNode *root, QWidget *parent, const char *name)
           : QWidget(parent, name), m_root(root)
{
}

void KBSTreeView::readConfig(KConfig *)
{
}

void KBSTreeView::writeConfig(KConfig *)
{
}

KBSNestedTreeView::KBSNestedTreeView(KBSTreeNode *root, QWidget *parent, const char *name)
                 : KBSTreeView(root, parent, name)
{
  (new QVBoxLayout(this))->setAutoAdd(true);
  
  m_view = new KListView(this);

  m_view->setSorting(-1);  
  m_view->addColumn("items");
  m_view->header()->hide();
  m_view->setRootIsDecorated(true);
  
  connect(m_view, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
  connect(m_view, SIGNAL(executed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *)));
  connect(m_view, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)),
          this, SLOT(slotContextMenu(KListView *, QListViewItem *, const QPoint &)));
    
  connect(m_root, SIGNAL(childInserted(KBSTreeNode *)),
          this, SLOT(updateInsert(KBSTreeNode *)));
  connect(m_root, SIGNAL(childRemoved(KBSTreeNode *)),
          this, SLOT(updateRemove(KBSTreeNode *)));
  
  rebuild();
}

KBSTreeNode *KBSNestedTreeView::selection()
{
  return m_nodes.find(m_view->selectedItem());
}

void KBSNestedTreeView::select(KBSTreeNode *node)
{
  QListViewItem *oldSelection = m_view->selectedItem(),
                *newSelection = viewItem(node);  
  if(oldSelection == newSelection) return;
  
  if(NULL != newSelection)
    m_view->setSelected(newSelection, true);
  else if(NULL != oldSelection)
    m_view->setSelected(oldSelection, false);
}

void KBSNestedTreeView::rebuild()
{
  select(NULL);
  m_view->clear();
  for(QPtrDictIterator<KBSTreeNode> it(m_nodes); it.current() != NULL; ++it)
  {
    disconnect(it.current(), SIGNAL(nodeChanged(KBSTreeNode *)),
               this, SLOT(updateChange(KBSTreeNode *)));
    disconnect(it.current(), SIGNAL(childInserted(KBSTreeNode *)),
               this, SLOT(updateInsert(KBSTreeNode *)));
    disconnect(it.current(), SIGNAL(childRemoved(KBSTreeNode *)),
               this, SLOT(updateRemove(KBSTreeNode *)));
  }
  m_nodes.clear();
    
  for(unsigned i = m_root->children(); i > 0; i--)
    buildTreeView(m_root->child(i-1), new QListViewItem(m_view));
}

void KBSNestedTreeView::updateChange(KBSTreeNode *node)
{
  QListViewItem *item = viewItem(node);
  if(NULL == item) return;

  item->setText(0, node->name());
  item->setPixmap(0, CompositePixmap(node->icons()));
}

void KBSNestedTreeView::updateInsert(KBSTreeNode *node)
{
  KBSTreeNode *parent = static_cast<KBSTreeNode*>(node->parent());
  QListViewItem *item = viewItem(parent);
  
  QListViewItem *before = NULL;
  int pos = parent->childIndex(node);
  if(pos > 0) {
    before = (NULL != item) ? item->firstChild() : m_view->firstChild();
    while(--pos > 0) before = before->nextSibling();
  }
  
  if(NULL != item)
    buildTreeView(node, new QListViewItem(item, before));
  else
    buildTreeView(node, new QListViewItem(m_view, before));
}

void KBSNestedTreeView::updateRemove(KBSTreeNode *node)
{
  if(selection() == node) select(NULL);
  
  for(unsigned i = node->children(); i > 0; --i)
    updateRemove(node->child(i-1));
  
  QListViewItem *item = viewItem(node);  
  m_nodes.remove(item);
  delete item;
  
  disconnect(node, SIGNAL(nodeChanged(KBSTreeNode *)),
             this, SLOT(updateChange(KBSTreeNode *)));
  disconnect(node, SIGNAL(childInserted(KBSTreeNode *)),
             this, SLOT(updateInsert(KBSTreeNode *)));
  disconnect(node, SIGNAL(childRemoved(KBSTreeNode *)),
             this, SLOT(updateRemove(KBSTreeNode *)));
}

QListViewItem *KBSNestedTreeView::viewItem(const KBSTreeNode *node) const
{
  if(NULL == node || node->isRoot()) return NULL;

  KBSTreePath path = node->path();
  QListViewItem *item = m_view->firstChild();
  
  KBSTreePath::const_iterator it = path.constBegin();
  do {
    for(unsigned i = 0; i < *it; i++)
      item = item->nextSibling();
    ++it;
    if(path.constEnd() != it)
      item = item->firstChild();
  } while(path.constEnd() != it);
   
  return item;
}

void KBSNestedTreeView::buildTreeView(const KBSTreeNode *node, QListViewItem *item)
{
  m_nodes.insert(item, node);
  
  item->setText(0, node->name());
  item->setPixmap(0, CompositePixmap(node->icons()));

  connect(node, SIGNAL(nodeChanged(KBSTreeNode *)),
          this, SLOT(updateChange(KBSTreeNode *)));
  connect(node, SIGNAL(childInserted(KBSTreeNode *)),
          this, SLOT(updateInsert(KBSTreeNode *)));
  connect(node, SIGNAL(childRemoved(KBSTreeNode *)),
          this, SLOT(updateRemove(KBSTreeNode *)));
            
  for(unsigned i = node->children(); i > 0; i--)
    buildTreeView(node->child(i-1), new QListViewItem(item));
}  

void KBSNestedTreeView::slotExecuted(QListViewItem *item)
{
  KBSTreeNode *node = m_nodes.find(item);
  if(NULL == node) return;
  
  if(node->children() > 0)
    item->setOpen(!item->isOpen());
  else
    emit activated(node);
}

void KBSNestedTreeView::slotContextMenu(KListView *, QListViewItem *item, const QPoint &pos)
{
  KBSTreeNode *node = m_nodes.find(item);
  if(NULL != node && selection() != node) select(node);
  
  QPopupMenu *popup = static_cast<QPopupMenu*>(kmain->guiFactory()->container("treeview_popup", kmain));
  popup->popup(pos);
}

KBSFlattenedTreeView::KBSFlattenedTreeView(KBSTreeNode *root, QWidget *parent, const char *name)
                    : KBSTreeView(root, parent, name), m_size(KIcon::SizeMedium), m_focus(NULL)
{
  (new QVBoxLayout(this))->setAutoAdd(true);
  
  m_view = new KListBox(this);
    
  connect(m_view, SIGNAL(selectionChanged()),
          this, SIGNAL(selectionChanged()));
  connect(m_view, SIGNAL(executed(QListBoxItem *)),
          this, SLOT(slotExecuted(QListBoxItem *)));
  connect(m_view, SIGNAL(contextMenuRequested(QListBoxItem *, const QPoint &)),
          this, SLOT(slotContextMenuRequested(QListBoxItem *, const QPoint &)));
  
  setupConnections(root, true);
  setFocus(root);
}

KBSTreeNode *KBSFlattenedTreeView::selection()
{
  return treeNode(m_view->selectedItem());
}

void KBSFlattenedTreeView::select(KBSTreeNode *node)
{
  QListBoxItem *selection = m_view->selectedItem();
  
  if(NULL == node)
    if(NULL != selection)
      m_view->setSelected(selection, false);
    else
      return;
  else if(node->isRoot())
    if(m_focus != node)
      setFocus(node);
    else
      select(NULL);
  else if(m_focus == node)
    m_view->setSelected(0, true);
  else
  {
    KBSTreeNode *parent = static_cast<KBSTreeNode*>(node->parent());
    unsigned pos = parent->childIndex(node);
    if(!parent->isRoot()) pos++;
    
    if(m_focus == parent && m_view->isSelected(pos))
      return;
    else if(m_focus != parent)
      setFocus(parent);
    
    m_view->setSelected(pos, true);
  }
}

unsigned KBSFlattenedTreeView::iconSize() const
{
  return m_size;
}

void KBSFlattenedTreeView::setIconSize(unsigned size)
{
  if(size == m_size) return;
  
  m_size = size;  
  rebuild();
}

void KBSFlattenedTreeView::rebuild()
{
  m_view->clear();
  
  if(!m_focus->isRoot())
    m_view->insertItem(SmallIcon("back", m_size), i18n("Back"));
    
  const unsigned children = m_focus->children();
  for(unsigned i = 0; i < children; i++) {
    KBSTreeNode *child = m_focus->child(i);
    m_view->insertItem(CompositePixmap(child->icons(), m_size), child->name());
  }
}

void KBSFlattenedTreeView::updateChange(KBSTreeNode *node)
{
  if(node->isRoot()) return;
  
  KBSTreeNode *parent = static_cast<KBSTreeNode*>(node->parent());
  unsigned pos = parent->childIndex(node);
  if(!m_focus->isRoot()) pos++;
  
  if(m_focus == parent)
  {
    QListBoxItem *selection = m_view->selectedItem();
    
    m_view->changeItem(CompositePixmap(node->icons(), m_size), node->name(), pos);
    
    if(NULL != selection) m_view->setCurrentItem(selection);
  }
}

void KBSFlattenedTreeView::updateInsert(KBSTreeNode *node)
{
  KBSTreeNode *parent = static_cast<KBSTreeNode*>(node->parent());
  
  if(m_focus == parent)
  {
    QListBoxItem *selection = m_view->selectedItem();
    
    unsigned pos = parent->childIndex(node);
    if(!m_focus->isRoot()) pos++;
    
    m_view->insertItem(CompositePixmap(node->icons(), m_size), node->name(), pos);
    
    if(NULL != selection) m_view->setCurrentItem(selection);
  }
  
  setupConnections(node, true);
}

void KBSFlattenedTreeView::updateRemove(KBSTreeNode *node)
{
  KBSTreeNode *selection = this->selection();
  if(NULL != selection && (selection == node || node->isAncestor(selection)))
    select(NULL);
  
  KBSTreeNode *parent = static_cast<KBSTreeNode*>(node->parent());
  
  if(!m_focus->isRoot() && parent->isAncestor(m_focus))
    setFocus(parent);
  if(m_focus == parent)
  {
    unsigned pos = parent->childIndex(node);
    if(!m_focus->isRoot()) pos++;
    
    m_view->removeItem(pos);
  }
  
  setupConnections(node, false);
}

void KBSFlattenedTreeView::slotExecuted(QListBoxItem *item)
{
  int pos = m_view->index(item);
  if(pos < 0) return;
  
  if(!m_focus->isRoot())
    if(0 == pos) {
      KBSTreeNode *child = m_focus;
      setFocus(static_cast<KBSTreeNode*>(m_focus->parent()));
      select(child);
      return;
    } else
      --pos;
  
  KBSTreeNode *node = m_focus->child(pos);
  if(node->children() > 0)
    setFocus(node);
  else {
    select(node);  
    emit activated(node);
  }
}

void KBSFlattenedTreeView::slotContextMenuRequested(QListBoxItem *item, const QPoint &pos)
{
  KBSTreeNode *node = treeNode(item);
  if(NULL != node && selection() != node) select(node);
  
  QPopupMenu *popup = static_cast<QPopupMenu*>(kmain->guiFactory()->container("treeview_popup", kmain));
  popup->exec(pos);
}

KBSTreeNode *KBSFlattenedTreeView::treeNode(QListBoxItem *item) const
{
  if(NULL == item) return NULL;
  
  int pos = m_view->index(item);
  if(pos < 0) return NULL;
  
  if(!m_focus->isRoot())
    if(0 == pos) return m_focus;
    else pos--;
    
  return m_focus->child(pos);
}

void KBSFlattenedTreeView::setupConnections(KBSTreeNode *node, bool set)
{
  if(set) {
    connect(node, SIGNAL(nodeChanged(KBSTreeNode *)), this, SLOT(updateChange(KBSTreeNode *)));
    connect(node, SIGNAL(childInserted(KBSTreeNode *)), this, SLOT(updateInsert(KBSTreeNode *)));
    connect(node, SIGNAL(childRemoved(KBSTreeNode *)), this, SLOT(updateRemove(KBSTreeNode *)));
  } else {
    disconnect(node, SIGNAL(nodeChanged(KBSTreeNode *)), this, SLOT(updateChange(KBSTreeNode *)));
    disconnect(node, SIGNAL(childInserted(KBSTreeNode *)), this, SLOT(updateInsert(KBSTreeNode *)));
    disconnect(node, SIGNAL(childRemoved(KBSTreeNode *)), this, SLOT(updateRemove(KBSTreeNode *)));
  }
  
  for(unsigned i = 0; i < node->children(); ++i)
    setupConnections(node->child(i), set);
}

void KBSFlattenedTreeView::setFocus(KBSTreeNode *node)
{
  if(node == m_focus) return;

  m_focus = node;
  rebuild();
  select(m_focus);
}

#include "kbstreeview.moc"

Generated by  Doxygen 1.6.0   Back to index