Select Git revision
DataControlPlugin.cc
-
Jan Möbius authored
git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@9595 383ad7c9-94d9-4d36-a494-682f7c89f535
Jan Möbius authoredgit-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@9595 383ad7c9-94d9-4d36-a494-682f7c89f535
DataControlPlugin.cc 23.05 KiB
/*===========================================================================*\
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $Author$ *
* $Date$ *
* *
\*===========================================================================*/
#include <QtGui>
#include "DataControlPlugin.hh"
#include <QLayout>
#include <QGridLayout>
#include <QItemSelectionModel>
#include <iostream>
#include <ACG/GL/GLState.hh>
#include <QStringList>
#include <ACG/Scenegraph/BaseNode.hh>
#include <ACG/QtWidgets/QtMaterialDialog.hh>
#include <QModelIndexList>
#include <queue>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
#include <OpenFlipper/common/GlobalOptions.hh>
#include <ObjectTypes/Light/Light.hh>
//******************************************************************************
const ACG::Vec4f base_color (0.0,0.0,0.5,1.0);
const ACG::Vec4f source_color (0.5,0.0,0.0,1.0);
const ACG::Vec4f target_color (0.0,0.5,0.2,1.0);
//******************************************************************************
/** \brief Plugin initialization
*
*/
void DataControlPlugin::pluginsInitialized() {
//set the slot descriptions
setDescriptions();
QMenu* contextMenu = new QMenu("Object");
//Target Objects
QIcon icon = QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-hide-object.png");
QAction* hideAction = new QAction(icon, tr("&Hide"), this);
hideAction->setStatusTip(tr("Hide object"));
connect(hideAction, SIGNAL(triggered()), this, SLOT(slotContextMenuHide()) );
contextMenu->addAction(hideAction);
//Target Objects
icon = QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-target-object.png");
targetAction_ = new QAction(icon, tr("&Target"), this);
targetAction_->setCheckable(true);
targetAction_->setStatusTip(tr("Set object as target"));
connect(targetAction_, SIGNAL(triggered()), this, SLOT(slotContextMenuTarget()) );
contextMenu->addAction(targetAction_);
//Source Objects
icon = QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-source-object.png");
sourceAction_ = new QAction(icon, tr("&Source"), this);
sourceAction_->setCheckable(true);
sourceAction_->setStatusTip(tr("Set object as source"));
connect(sourceAction_, SIGNAL(triggered()), this, SLOT(slotContextMenuSource()) );
contextMenu->addAction(sourceAction_);
contextMenu->addSeparator();
//Remove Objects
icon = QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-delete-item.png");
removeAction_ = new QAction(icon, tr("&Remove"), this);
removeAction_->setCheckable(false);
removeAction_->setStatusTip(tr("Remove object"));
connect(removeAction_, SIGNAL(triggered()), this, SLOT(slotContextMenuRemove()) );
contextMenu->addAction(removeAction_);
emit addContextMenuItem(contextMenu->menuAction() , DATA_ALL , CONTEXTOBJECTMENU);
icon = QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-material.png");
QAction* material = new QAction(icon, tr("Material Properties"), 0);
connect (material, SIGNAL( triggered() ), this, SLOT ( slotMaterialProperties() ));
emit addContextMenuItem(material , DATA_ALL , CONTEXTOBJECTMENU);
PluginFunctions::setDefaultViewObjectMarker (&objectMarker);
PluginFunctions::setViewObjectMarker (&objectMarker);
connect(tool_->lightSources, SIGNAL(stateChanged(int)), this, SLOT(slotShowLightSources(int)));
slotShowLightSources(tool_->lightSources->checkState());
}
//******************************************************************************
void DataControlPlugin::initializePlugin()
{
locked = false;
tool_ = new DatacontrolToolboxWidget();
connect( tool_ , SIGNAL( keyEvent( QKeyEvent* ) ),
this , SLOT(slotKeyEvent ( QKeyEvent* ) ));
QSize size(300, 300);
tool_->resize(size);
model_ = new TreeModel( );
view_ = tool_->treeView;
tool_->treeView->setModel(model_);
view_->QTreeView::resizeColumnToContents(1);
view_->QTreeView::resizeColumnToContents(2);
view_->QTreeView::resizeColumnToContents(3);
connect( model_,SIGNAL(dataChangedInside(int,int,const QVariant&) ),
this, SLOT( slotDataChanged(int,int,const QVariant&)) );
connect( model_,SIGNAL( moveBaseObject(int,int) ),
this, SLOT( slotMoveBaseObject(int,int) ) );
connect( view_,SIGNAL(customContextMenuRequested ( const QPoint & ) ),
this,SLOT(slotCustomContextMenuRequested ( const QPoint & ) ));
connect( tool_->notSelected, SIGNAL(stateChanged ( int ) ),
this, SLOT (slotBoundingBoxChange ( ) ));
connect( tool_->sourceSelected, SIGNAL(stateChanged ( int ) ),
this, SLOT (slotBoundingBoxChange ( ) ));
connect( tool_->targetSelected, SIGNAL(stateChanged ( int ) ),
this, SLOT (slotBoundingBoxChange ( ) ));
viewHeader_ = tool_->treeView->header();
viewHeader_->setContextMenuPolicy(Qt::CustomContextMenu);
// connect the slot for the context menu
connect( viewHeader_, SIGNAL(customContextMenuRequested ( const QPoint & ) ),
this, SLOT(slotHeaderCustomContextMenuRequested ( const QPoint & ) ));
emit addToolbox("Data Control", tool_);
onlyDown_ = 0;
onlyUp_ = 0;
}
//******************************************************************************
/** \brief update drawing of objects when the active object changed
*
*/
void DataControlPlugin::slotObjectSelectionChanged( int _identifier )
{
BaseObjectData* obj = 0;
if ( PluginFunctions::getObject( _identifier, obj) )
updateBoundingBox (obj);
// if onlyUp_ > 0 --> _identifier is a group and the selection
// does not have to be applied
if (onlyUp_ == 0)
model_->objectChanged( _identifier );
//check for changes in the tree
BaseObject* object = 0;
if ( PluginFunctions::getObject( _identifier, object) ){
// if we are allowed to propagate up
if ( onlyDown_ == 0 ){
onlyUp_++;
propagateUpwards(object->parent(), 2); // 2 = source-target
onlyUp_--;
}
// if we are allowed to propagate down
if ( onlyUp_ == 0 ){
onlyDown_++;
if ( object->isGroup() )
propagateDownwards(object, 2); // 2 = source-target
onlyDown_--;
}
}
}
//******************************************************************************
/** \brief Update the model if the visibility of an object changed
*
* @param _identifier id of an object
*/
void DataControlPlugin::slotVisibilityChanged( int _identifier ){
// if onlyUp_ > 0 --> _identifier is a group and the selection
// does not have to be applied
if (onlyUp_ == 0){
//inform the model
model_->objectChanged( _identifier );
}
//check for changes in the tree
BaseObject* obj = 0;
if ( PluginFunctions::getObject( _identifier, obj) ){
// if we are allowed to propagate up
if ( onlyDown_ == 0 ){
onlyUp_++;
propagateUpwards(obj->parent(), 1); // 1 = visibilty
onlyUp_--;
}
// if we are allowed to propagate down
if ( onlyUp_ == 0 ){
onlyDown_++;
if ( obj->isGroup() )
propagateDownwards(obj, 1); // 1 = visibilty
onlyDown_--;
}
}
BaseObjectData* object = 0;
if ( PluginFunctions::getObject( _identifier, object) )
updateBoundingBox (object);
}
//******************************************************************************
/** \brief Update the model if properties of an object changed
*
* @param _identifier id of an object
*/
void DataControlPlugin::slotObjectPropertiesChanged( int _identifier ){
model_->objectChanged( _identifier );
}
//******************************************************************************
/** \brief Update the model if an object was deleted
*
* @param _identifier id of an object
*/
void DataControlPlugin::slotObjectUpdated( int _identifier , const UpdateType _type ){
}
//******************************************************************************
/** \brief Update the model if a file has been opened
*
* @param _id id of an object
*/
void DataControlPlugin::fileOpened(int _id){
BaseObject* obj = 0;
if ( PluginFunctions::getObject(_id, obj) )
model_->objectAdded(obj);
slotShowLightSources(tool_->lightSources->checkState());
}
//******************************************************************************
/** \brief Update the model if an empty object has been added
*
* @param _id id of an object
*/
void DataControlPlugin::addedEmptyObject(int _id){
fileOpened(_id);
}
//******************************************************************************
/** \brief an object was deleted. delete it internally
*
* @param _id id of the object
*/
void DataControlPlugin::objectDeleted(int _id){
model_->objectDeleted(_id);
}
//******************************************************************************
/** \brief a key event occurred
*
* @param _event the event that occurred
*/
void DataControlPlugin::slotKeyEvent( QKeyEvent* _event )
{
if ( _event->modifiers() == Qt::ControlModifier ) {
switch (_event->key()) {
case Qt::Key_A :
setAllTarget();
return;
default:
return;
}
}
switch (_event->key()) {
case Qt::Key_Delete :
slotPopupRemove();
return;
default:
return;
}
}
//******************************************************************************
/** \brief emit the right updates when the model changed
*
* @param topLeft index in the model
* @param _column hmm
*/
void DataControlPlugin::slotDataChanged ( int _id, int _column, const QVariant& _value)
{
//get the corresponding baseObject
BaseObject* obj = 0;
if ( !PluginFunctions::getObject( _id, obj) )
return;
switch ( _column ) {
// Name
case 0:
obj->setName( _value.toString() );
break;
// show/hide
case 1:
obj->visible( _value.toBool() );
break;
// source
case 2:
obj->source( _value.toBool() );
break;
// target
case 3:
obj->target( _value.toBool() );
break;
default:
break;
}
}
//******************************************************************************
/** \brief Gets called when an object was moved via drag n drop
*
* @param _id id of the object
* @param _parentId id of the new parent
*/
void DataControlPlugin::slotMoveBaseObject(int _id, int _newParentId){
BaseObject* obj = 0;
if ( !PluginFunctions::getObject(_id, obj) )
return;
BaseObject* parent = 0;
if ( !PluginFunctions::getObject(_newParentId, parent) )
return;
BaseObject* oldParent = obj->parent();
//set new parent
obj->setParent( parent );
//if oldParent is an empty group -> delete it
if ( oldParent != PluginFunctions::objectRoot() && oldParent->childCount() == 0 )
emit deleteObject( oldParent->id() );
}
//******************************************************************************
void DataControlPlugin::slotShowLightSources( int _state ) {
int rows = model_->rowCount();
for(int i = 0; i < rows; ++i) {
TreeItem* item = model_->getItem(model_->index(i,0));
if(item->dataType() == DATA_LIGHT) {
view_->setRowHidden(i, model_->parent(model_->index(i,0)), !(_state == Qt::Checked));
}
}
}
//******************************************************************************
/** \brief Load Groups from ini file
*
* @param _ini an ini file
*/
void DataControlPlugin::loadIniFileOptionsLast( INIFile& _ini ) {
if ( _ini.section_exists( "BoundingBox" ) )
{
bool value;
if (_ini.get_entry(value, "BoundingBox","notSelected"))
tool_->notSelected->setChecked (value);
if (_ini.get_entry(value, "BoundingBox","sourceSelected"))
tool_->sourceSelected->setChecked (value);
if (_ini.get_entry(value, "BoundingBox","targetSelected"))
tool_->targetSelected->setChecked (value);
}
if ( !_ini.section_exists( "Groups" ) )
return;
// Names of all groups
QStringList groupNames;
// names of the primary groups
QStringList rootGroup;
// Get the list of group names to the file
_ini.get_entry(groupNames,"Groups","groups");
// Get the primary group names to the file
_ini.get_entry(rootGroup,"Groups","rootGroup");
//list of groups
QVector< BaseObject* > groups;
// Go over one level of the groups
while ( rootGroup.size() > 0 ) {
QString current = rootGroup[0];
rootGroup.removeFirst();
QStringList groupChildren;
QStringList elementChildren;
_ini.get_entry(elementChildren ,current,"children");
_ini.get_entry(groupChildren ,current,"subgroups");
// if we get a parent item, scan the tree for it or use the root node otherwise
BaseObject* parentItem;
QString parentName;
if ( _ini.get_entry(parentName,current,"parent") ) {
parentItem = PluginFunctions::objectRoot()->childExists(parentName);
if ( parentItem == 0 )
parentItem = PluginFunctions::objectRoot();
} else
parentItem = PluginFunctions::objectRoot();
rootGroup << groupChildren;
// check if this group already exists
BaseObject* group = PluginFunctions::objectRoot()->childExists( current );
// group does not exist
if ( !group ) {
group = dynamic_cast< BaseObject* >( new GroupObject( current, dynamic_cast< GroupObject* >(parentItem ) ) );
emit emptyObjectAdded( group->id() );
// in the groups vector we only need the lowest groups
// because they are used recursively
int p = groups.indexOf( group->parent() );
if ( p > -1 )
groups.remove( p );
groups.push_back( group );
}
// process children
for ( int i = 0 ; i < elementChildren.size() ; ++i ) {
BaseObject* childItem = PluginFunctions::objectRoot()->childExists( elementChildren[i] );
if ( childItem ) {
childItem->setParent(group);
}
}
}
}
//******************************************************************************
/** \brief Save groups to ini file
*
* @param _ini an ini file
*/
void DataControlPlugin::saveIniFileOptions( INIFile& _ini ) {
if ( !_ini.section_exists( "Groups" ) )
_ini.add_section("Groups");
std::queue< BaseObject* > children;
children.push( PluginFunctions::objectRoot() );
std::vector< BaseObject* > groups;
// Get all groups from the tree
while ( children.size() > 0 ) {
BaseObject* item = children.front();
children.pop();
for ( int i = 0 ; i < item->childCount(); ++i )
if ( item->child(i)->dataType(DATA_GROUP))
children.push( item->child(i) );
if ( item->dataType(DATA_GROUP) && (item != PluginFunctions::objectRoot() ) )
groups.push_back(item);
}
// Names of all groups
QStringList groupNames;
// names of the primary groups
QStringList rootGroup;
for ( uint i = 0 ; i < groups.size() ; ++i ) {
groupNames.push_back( groups[i]->name() );
if ( !_ini.section_exists( groups[i]->name() ) )
_ini.add_section(groups[i]->name());
_ini.add_entry(groups[i]->name(),"groupname",groups[i]->name());
// write the name of the parent
if ( ( groups[i]->parent() != 0 ) && ( groups[i]->parent() != PluginFunctions::objectRoot() ) )
_ini.add_entry(groups[i]->name(),"parent",groups[i]->parent()->name());
if ( groups[i]->parent() == PluginFunctions::objectRoot() )
rootGroup.push_back( groups[i]->name() );
// Write a list of this groups children
QStringList groupchildren;
QStringList elementchildren;
for ( int j = 0 ; j < groups[i]->childCount(); ++j ) {
if ( groups[i]->child(j)->dataType(DATA_GROUP) )
groupchildren.push_back( groups[i]->child(j)->name() );
else
elementchildren.push_back( groups[i]->child(j)->name() );
}
_ini.add_entry(groups[i]->name(),"subgroups",groupchildren);
_ini.add_entry(groups[i]->name(),"children",elementchildren);
}
// Write the list of group names to the file
_ini.add_entry("Groups","groups",groupNames);
// Write the primary group names to the file
_ini.add_entry("Groups","rootGroup",rootGroup);
if ( !_ini.section_exists( "BoundingBox" ) )
_ini.add_section("BoundingBox");
_ini.add_entry("BoundingBox","notSelected",tool_->notSelected->isChecked ());
_ini.add_entry("BoundingBox","sourceSelected",tool_->sourceSelected->isChecked ());
_ini.add_entry("BoundingBox","targetSelected",tool_->targetSelected->isChecked ());
}
//******************************************************************************
/** \brief Recursively update a column up to the root of the tree
*
* @param _obj object to start with
*/
void DataControlPlugin::propagateUpwards(BaseObject* _obj, int _column ){
if ( _obj == PluginFunctions::objectRoot() || (!_obj->isGroup()) )
return;
QList< BaseObject* > children = _obj->getLeafs();
bool changed = false;
bool value = false;
bool value2 = false;
switch ( _column ){
case 1: //VISIBILTY
for (int i=0; i < children.size(); i++)
value |= children[i]->visible();
_obj->visible( value );
changed = true;
break;
case 2: //SOURCE-TARGET
for (int i=0; i < children.size(); i++){
value |= children[i]->source();
value2 |= children[i]->target();
}
if (_obj->source() != value){
_obj->source( value );
changed = true;
}
if (_obj->target() != value2){
_obj->target( value2 );
changed = true;
}
break;
default:
break;
}
if ( changed )
propagateUpwards( _obj->parent(), _column );
}
//******************************************************************************
/** \brief Recursively update a column up to the root of the tree
*
* @param _obj object to start with
*/
void DataControlPlugin::propagateDownwards(BaseObject* _obj, int _column ){
for (int i=0; i < _obj->childCount(); i++){
BaseObject* current = _obj->child(i);
bool changed = false;
switch ( _column ){
case 1: //VISIBILTY
if ( current->visible() != _obj->visible() ){
current->visible( _obj->visible() );
changed = true;
}
break;
case 2: //SOURCE-TARGET
if ( current->source() != _obj->source() ){
current->source( _obj->source() );
changed = true;
}
if ( current->target() != _obj->target() ){
current->target( _obj->target() );
changed = true;
}
break;
default:
break;
}
if ( changed && current->isGroup() ){
propagateDownwards(current, _column);
}
}
}
//******************************************************************************
/** \brief Bounding box visibility selection changed
*/
void DataControlPlugin::slotBoundingBoxChange( )
{
for (PluginFunctions::ObjectIterator o_it; o_it != PluginFunctions::objectsEnd(); ++o_it) {
updateBoundingBox (o_it);
}
emit updateView();
}
//******************************************************************************
/** \brief Update state of bounding box node
*
* @param _obj object
*/
void DataControlPlugin::updateBoundingBox(BaseObjectData* _obj)
{
if (tool_->notSelected->isChecked () ||
(_obj->source () && tool_->sourceSelected->isChecked ()) ||
(_obj->target () && tool_->targetSelected->isChecked ()))
{
_obj->boundingBoxNode()->set_status( ACG::SceneGraph::BaseNode::Active );
ACG::Vec4f color = base_color;
if (_obj->source () && tool_->sourceSelected->isChecked ())
color += source_color;
if (_obj->target () && tool_->targetSelected->isChecked ())
color += target_color;
_obj->boundingBoxNode()->set_base_color (color);
}
else
_obj->boundingBoxNode()->set_status( ACG::SceneGraph::TranslationManipulatorNode::HideNode );
}
//******************************************************************************
/** \brief Save settings before application is closed
*
* @param _ini reference to ini file
*/
void DataControlPlugin::saveOnExit(INIFile& _ini){
if ( !_ini.section_exists( "BoundingBox" ) )
_ini.add_section("BoundingBox");
_ini.add_entry("BoundingBox","notSelected",tool_->notSelected->isChecked ());
_ini.add_entry("BoundingBox","sourceSelected",tool_->sourceSelected->isChecked ());
_ini.add_entry("BoundingBox","targetSelected",tool_->targetSelected->isChecked ());
}
Q_EXPORT_PLUGIN2( datacontrolplugin , DataControlPlugin );