/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2010 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*--------------------------------------------------------------------------- *
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see . *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $LastChangedBy$ *
* $Date$ *
* *
\*===========================================================================*/
#include
#include
#include "TreeModelObjectSelection.hh"
#include
#include
#include "../OpenFlipper/BasePlugin/PluginFunctions.hh"
//******************************************************************************
/** \brief Constructor
*
* @param _parent parent Object
*/
TreeModelObjectSelection::TreeModelObjectSelection( QObject *_parent) : QAbstractItemModel(_parent)
{
rootItem_ = new TreeItemObjectSelection( -1, "ROOT", DATA_UNKNOWN, 0);
}
//******************************************************************************
/** \brief Destructor
*
*/
TreeModelObjectSelection::~TreeModelObjectSelection()
{
}
//******************************************************************************
/** \brief Return the number of columns
*
* @param unused
* @return return always 2
*/
int TreeModelObjectSelection::columnCount(const QModelIndex &/*_parent*/) const
{
// Id, Name -> 2
return (2);
}
//******************************************************************************
/** \brief Returns the data stored under the given role for the item referred to by the index
*
* @param index a ModelIndex that defines the item in the tree
* @param role defines the kind of data requested
* @return requested data
*/
QVariant TreeModelObjectSelection::data(const QModelIndex &index, int role) const
{
// Skip invalid requests
if (!index.isValid())
return QVariant();
// Get the corresponding tree item
TreeItemObjectSelection *item = static_cast(index.internalPointer());
if ( item == rootItem_ ) {
std::cerr << "Root" << std::endl;
}
// Set the background color of the objects row
if ( role == Qt::BackgroundRole ) {
if ( !item->visible() ) {
return QVariant (QBrush (QColor (192, 192, 192)));
}
}
if (role == Qt::DisplayRole)
{
switch (index.column ())
{
case 0:
return QVariant(item->id());
case 1:
return QVariant(item->name());
default:
return QVariant ();
}
}
else
return QVariant ();
}
//******************************************************************************
/** \brief Returns the item flags for the given index
*
* @param index ModelIndex that defines an item in the tree
* @return flags for the given ModelIndex
*/
Qt::ItemFlags TreeModelObjectSelection::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
Qt::ItemFlags flags = 0;
// Show/Source/Target
if ( index.column() == 0 || index.column() == 1 )
flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
else
flags = Qt::ItemIsEnabled;
return flags;
}
//******************************************************************************
/** \brief Returns the data in the header
*
* @param section the column in the header
* @param orientation header orientation (only horizontal handled)
* @param role the role that defines the type of data
* @return the requested data
*/
QVariant TreeModelObjectSelection::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
if (section == 0)
return QVariant("ID");
else if (section == 1)
return QVariant("Name");
else
return QVariant();
}
return QVariant();
}
//******************************************************************************
/** \brief Returns the index of the item in the model specified by the given row, column and parent index.
*
* @param row the row
* @param column the column
* @param _parent parent item
* @return corresponding ModelIndex
*/
QModelIndex TreeModelObjectSelection::index(int row, int column, const QModelIndex &_parent) const
{
TreeItemObjectSelection *parentItem;
if (!_parent.isValid())
parentItem = rootItem_;
else
parentItem = static_cast(_parent.internalPointer());
TreeItemObjectSelection *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
//******************************************************************************
/** \brief Return index of parent item
*
* @param index a ModelIndex
* @return parent of the given ModelIndex
*/
QModelIndex TreeModelObjectSelection::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItemObjectSelection *childItem = static_cast(index.internalPointer());
TreeItemObjectSelection *parentItem = childItem->parent();
if (parentItem == rootItem_)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
//******************************************************************************
/** \brief Returns the number of rows under given parent
*
* @param _parent parent Item
* @return number of rows that are children of given parent
*/
int TreeModelObjectSelection::rowCount(const QModelIndex &_parent) const
{
TreeItemObjectSelection *parentItem;
if (_parent.column() > 0)
return 0;
if (!_parent.isValid())
parentItem = rootItem_;
else
parentItem = static_cast(_parent.internalPointer());
return parentItem->childCount();
}
//******************************************************************************
/** \brief The object with the given id has been changed. Update the model.
*
* @param _id id of an object
*/
void TreeModelObjectSelection::objectChanged(int _id) {
if ( _id != -1 ){
BaseObject* obj = 0;
PluginFunctions::getObject(_id, obj);
TreeItemObjectSelection* item = rootItem_->childExists(_id);
//if internal and external representation are both valid
if (obj != 0 && item != 0){
//update the name
if ( obj->name() != item->name() ){
item->name( obj->name() );
QModelIndex index = getModelIndex(item,0);
if ( index.isValid() )
emit dataChanged( index, index);
}
//update visibility
if ( obj->visible() != item->visible() || obj->isGroup() ){
item->visible( obj->visible() );
QModelIndex index0 = getModelIndex(item,0);
QModelIndex index1 = getModelIndex(item,3);
if ( index0.isValid() && index1.isValid() ){
//the whole row has to be updated because of the grey background-color
emit dataChanged( index0, index1);
propagateUpwards(item->parent(), 1, obj->visible() );
}
if ( obj->isGroup() )
propagateDownwards(item, 1 );
}
//update parent
if ( obj->parent() == PluginFunctions::objectRoot() && isRoot( item->parent() ) ){
return;
}else if ( obj->parent() == PluginFunctions::objectRoot() && !isRoot( item->parent() ) ){
moveItem(item, rootItem_ );
}else if ( obj->parent()->id() != item->parent()->id() ){
TreeItemObjectSelection* parent = rootItem_->childExists( obj->parent()->id() );
if (parent != 0)
moveItem(item, parent );
}
}
}
}
/** \brief The object with the given id has been added. add it to the internal tree
*
* @param id_ id of the object
*/
void TreeModelObjectSelection::objectAdded(BaseObject* _object){
objectAdded (_object, _object->parent());
}
/** \brief The object with the given id has been added. add it to the internal tree
*
* @param id_ id of the object
*/
void TreeModelObjectSelection::objectAdded(BaseObject* _object, BaseObject* _parent){
if (rootItem_->childExists(_object->id()))
return;
TreeItemObjectSelection* parent = 0;
//find the parent
if ( _parent == PluginFunctions::objectRoot() )
parent = rootItem_;
else
parent = rootItem_->childExists( _parent->id() );
if (!parent)
{
objectAdded(_parent);
parent = rootItem_->childExists( _parent->id() );
}
QModelIndex parentIndex = getModelIndex(parent, 0);
beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); //insert at the bottom
TreeItemObjectSelection* item = new TreeItemObjectSelection( _object->id(), _object->name(), _object->dataType(), parent);
parent->appendChild( item );
endInsertRows();
objectChanged( _object->id() );
}
/** \brief The object with the given id has been deleted. delete it from the internal tree
*
* @param id_ id of the object
*/
void TreeModelObjectSelection::objectDeleted(int _id){
TreeItemObjectSelection* item = rootItem_->childExists(_id);
if ( item != 0 && !isRoot(item) ){
QModelIndex itemIndex = getModelIndex(item, 0);
QModelIndex parentIndex = itemIndex.parent();
beginRemoveRows( parentIndex, itemIndex.row(), itemIndex.row() );
item->parent()->removeChild(item);
item->deleteSubtree();
delete item;
endRemoveRows();
}
}
//******************************************************************************
/** \brief move the item to a new parent
*
* @param _item the item
* @param _parent new parent
*/
void TreeModelObjectSelection::moveItem(TreeItemObjectSelection* _item, TreeItemObjectSelection* _parent ){
QModelIndex itemIndex = getModelIndex(_item, 0);
QModelIndex oldParentIndex = itemIndex.parent();
QModelIndex newParentIndex = getModelIndex(_parent, 0);
//delete everything at the old location
beginRemoveRows( oldParentIndex, itemIndex.row(), itemIndex.row() );
_item->parent()->removeChild(_item);
endRemoveRows();
//insert it at the new location
beginInsertRows(newParentIndex, _parent->childCount(), _parent->childCount() ); //insert at the bottom
_item->setParent( _parent );
_parent->appendChild( _item );
endInsertRows();
emit layoutChanged();
}
//******************************************************************************
/** \brief Return item at given index
*
* @param index a ModelIndex
* @return item at given index
*/
TreeItemObjectSelection* TreeModelObjectSelection::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItemObjectSelection *item = static_cast(index.internalPointer());
if (item) return item;
}
return rootItem_;
}
//******************************************************************************
/** \brief Return item-name at given index
*
* @param index a ModelIndex
* @return name of the item at given index
*/
QString TreeModelObjectSelection::itemName(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItemObjectSelection *item = static_cast(index.internalPointer());
if (item)
return item->name();
}
return "not found";
}
//******************************************************************************
/** \brief Return item-id at given index
*
* @param index a ModelIndex
* @return item-id at given index
*/
int TreeModelObjectSelection::itemId(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItemObjectSelection *item = static_cast(index.internalPointer());
if (item)
return item->id();
}
return -1;
}
//******************************************************************************
/** \brief Return index of given item
*
* Warning: Only use this function if you know that all ModelIndices are created
*
* @param _object an object
* @param _column a column
* @return index of object and column
*/
QModelIndex TreeModelObjectSelection::getModelIndex(TreeItemObjectSelection* _object, int _column ){
// root item gets an invalid QModelIndex
if ( _object == rootItem_ )
return QModelIndex();
QModelIndex index = createIndex(_object->row(), _column, _object);
return index;
}
//******************************************************************************
/** \brief Return index of given item
*
* Warning: Only use this function if you know that all ModelIndices are created
*
* @param _id an object id
* @param _column a column
* @return index of object and column
*/
QModelIndex TreeModelObjectSelection::getModelIndex(int _id, int _column ){
TreeItemObjectSelection *obj = rootItem_->childExists(_id);
if (obj)
return getModelIndex (obj, _column);
return QModelIndex();
}
//******************************************************************************
/** \brief Recursively update a column up to the root of the tree
*
* @param _item item to start with
*/
void TreeModelObjectSelection::propagateUpwards(TreeItemObjectSelection* _item, int _column, bool _value ){
if ( isRoot(_item) || (!_item->isGroup()) )
return;
if (_column == 1){ //visibility
_item->visible( _value );
//the whole row has to be updated because of the grey background-color
QModelIndex index0 = getModelIndex(_item,0);
QModelIndex index1 = getModelIndex(_item,3);
emit dataChanged( index0, index1);
} else {
QModelIndex index = getModelIndex(_item,_column);
emit dataChanged(index, index);
}
propagateUpwards( _item->parent(), _column, _value );
}
//******************************************************************************
/** \brief Recursively update a column up to the root of the tree
*
* @param _item item to start with
*/
void TreeModelObjectSelection::propagateDownwards(TreeItemObjectSelection* _item, int _column ){
for (int i=0; i < _item->childCount(); i++){
TreeItemObjectSelection* current = _item->child(i);
bool changed = false;
switch ( _column ){
case 1: //VISIBILTY
if ( current->visible() != _item->visible() ){
current->visible( _item->visible() );
changed = true;
}
break;
default:
break;
}
if (changed){
QModelIndex index = getModelIndex(current,_column);
emit dataChanged(index, index);
}
if ( current->isGroup() )
propagateDownwards(current, _column);
}
}
//******************************************************************************
/** \brief Set Data at 'index' to 'value'
*
* @param index a ModelIndex defining the positin in the model
* @param value the new value
* @param unused
* @return return if the data was set successfully
*/
bool TreeModelObjectSelection::setData(const QModelIndex &index, const QVariant &value, int /*role*/)
{
emit dataChangedInside( itemId(index), index.column(), value );
return true;
}
//******************************************************************************
/** \brief return if an object is equal to the root object
*
* @param _item the item to be checked
* @return is it the root object?
*/
bool TreeModelObjectSelection::isRoot(TreeItemObjectSelection * _item) {
return ( _item == rootItem_ );
}