/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2009 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$ * * $Author$ * * $Date$ * * * \*===========================================================================*/ #include "DataControlPlugin.hh" #include #include #include #include #include #include "Menu.hh" #include //****************************************************************************** /** \brief Slot for Remove action in ContextMenu * */ void DataControlPlugin::slotPopupRemove ( ) { QItemSelectionModel* selection = view_->selectionModel(); if (selection == 0) return; // Get all selected rows QModelIndexList indexList = selection->selectedRows(); QMessageBox msgBox; msgBox.setText(tr("Do you really want to remove the selected objects?")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); QString text; for ( int i = 0 ; i < indexList.size() ; ++i) text += model_->itemName( indexList[i] ) + "\n"; msgBox.setDetailedText(text); if ( msgBox.exec() == QMessageBox::No) return; for ( int i = 0 ; i < indexList.size() ; ++i) { int id = model_->itemId( indexList[i] ); if ( id != -1 ) emit deleteObject( id ); } emit updateView(); } //****************************************************************************** /** \brief Slot for Ungroup action in ContextMenu * */ void DataControlPlugin::slotUngroup ( ) { QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); //get the object int id = model_->itemId( indexList[0] ); BaseObject* group = 0; if ( id > 0 && PluginFunctions::getObject(id, group ) ){ //iterate over children for (int i=group->childCount()-1; i >= 0; i--){ BaseObject* child = group->child(i); // then change the parent child->setParent(group->parent()); } //delete the group emit deleteObject( group->id() ); } } //****************************************************************************** /** \brief Slot for Copy action in ContextMenu * */ void DataControlPlugin::slotCopy() { QItemSelectionModel* selection = view_->selectionModel(); if (selection == 0) return; // Get all selected rows QModelIndexList indexList = selection->selectedRows(); for ( int i = 0 ; i < indexList.size() ; ++i) { int id = model_->itemId( indexList[i] ); if ( id > 0){ int newObject; emit copyObject( id, newObject ); } } emit updateView(); } //****************************************************************************** /** \brief Slot for Group action in ContextMenu * */ void DataControlPlugin::slotGroup() { QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); //check if all objects have the same parent //abort if the parents differ int id = model_->itemId( indexList[0] ); BaseObject* obj0 = 0; if (id == -1 || !PluginFunctions::getObject(id, obj0) ){ std::cerr << "Group Objects: Unable to get object" << std::endl; return; } bool visible = obj0->visible(); bool target = obj0->target(); bool source = obj0->source(); BaseObject* parent = obj0->parent(); for ( int i = 1 ; i < indexList.size() ; ++i) { //get an object id = model_->itemId( indexList[i] ); BaseObject* item = 0; PluginFunctions::getObject(id, item ); //compare parent if ( parent != item->parent() ){ emit log(tr("Cannot group Objects with different parents")); return; } //remember if at least on child was target/source visible |= item->visible(); target |= item->target(); source |= item->source(); } //create new group if (parent == 0) parent = PluginFunctions::objectRoot(); GroupObject* groupItem = new GroupObject( tr("newGroup"), dynamic_cast< GroupObject* >(parent)); groupItem->setName(tr("newGroup ") + QString::number(groupItem->id())); parent->appendChild( dynamic_cast< BaseObject* >( groupItem ) ); groupItem->setParent( parent ); emit emptyObjectAdded( groupItem->id() ); //append new children to group for ( int i = 0 ; i < indexList.size() ; ++i) { //get an object id = model_->itemId( indexList[i] ); BaseObject* item = 0; PluginFunctions::getObject(id, item ); //and move it into the group item->setParent( dynamic_cast< BaseObject* >( groupItem ) ); } //update target/source state groupItem->visible(visible); groupItem->target(target); groupItem->source(source); } //****************************************************************************** /** \brief ContextMenu requested - creates the contextMenu * * @param _pos Position where it was requested */ void DataControlPlugin::slotCustomContextMenuRequested ( const QPoint & _pos ) { popupIndex_ = view_->indexAt(_pos); if (!popupIndex_.isValid()) return; TreeItem* item = model_->getItem(popupIndex_); QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); Menu menu(0); QAction* action; QIcon icon; if ( selectedRows > 1 ) { action = menu.addAction("Copy",this,SLOT ( slotCopy() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-copy.png"); action->setIcon(icon); menu.addAction(tr("Group"),this,SLOT ( slotGroup() )); menu.addSeparator(); menu.addAction(tr("Remove"),this,SLOT ( slotPopupRemove() )); }else // check if the item is a group item if ( item->isGroup() ) { action = menu.addAction(tr("Zoom to objects"),this,SLOT ( slotZoomTo() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"zoom-in.png"); action->setIcon(icon); menu.addAction(tr("Ungroup"),this,SLOT ( slotUngroup() )); menu.addSeparator(); action = menu.addAction(tr("Rename"),this,SLOT ( slotRename() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-rename.png"); action->setIcon(icon); menu.addSeparator(); action = menu.addAction(tr("Remove"),this,SLOT ( slotPopupRemove() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-delete-item.png"); action->setIcon(icon); } else { if(item->dataType() == DATA_LIGHT) { action = menu.addAction(tr("Copy"),this,SLOT ( slotCopy() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-copy.png"); action->setIcon(icon); action = menu.addAction(tr("Rename"),this,SLOT ( slotRename() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-rename.png"); action->setIcon(icon); action = menu.addAction(tr("Remove"),this,SLOT ( slotPopupRemove() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-delete-item.png"); action->setIcon(icon); menu.addSeparator(); action = menu.addAction(tr("Switch On/Off"),this,SLOT ( slotSwitchLight() )); icon = typeIcon(DATA_LIGHT); action->setIcon(icon); action = menu.addAction(tr("Edit Light"),this,SLOT ( slotEditLight() )); icon = typeIcon(DATA_LIGHT); action->setIcon(icon); } else { action = menu.addAction(tr("Zoom to object"),this,SLOT ( slotZoomTo() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"zoom-in.png"); action->setIcon(icon); action = menu.addAction(tr("Copy"),this,SLOT ( slotCopy() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-copy.png"); action->setIcon(icon); action = menu.addAction(tr("Rename"),this,SLOT ( slotRename() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-rename.png"); action->setIcon(icon); action = menu.addAction(tr("Material Properties"),this,SLOT ( slotMaterialProperties() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-material.png"); action->setIcon(icon); menu.addAction(tr("Group"),this,SLOT ( slotGroup() )); menu.addSeparator(); action = menu.addAction(tr("Remove"),this,SLOT ( slotPopupRemove() )); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-delete-item.png"); action->setIcon(icon); } } menu.exec(view_->mapToGlobal( _pos) ); } //****************************************************************************** /** \brief Generate a ContextMenu for the header of the TreeView * * @param _pos Position where the Menu has to be created */ void DataControlPlugin::slotHeaderCustomContextMenuRequested ( const QPoint & _pos ) { headerPopupType_ = viewHeader_->logicalIndexAt( _pos ); QMenu menu(0); QIcon icon; //get all used types QVector types; for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) if ( !types.contains( o_it->dataType() ) ) types.push_back( o_it->dataType() ); QAction* action; switch (headerPopupType_) { // case 0 : // std::cerr << "0"; // break; //Show / Hide case 1 : icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"drawModes.png"); action = menu.addAction(icon,tr("Show all"),this,SLOT ( showAll() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(icon, tr("Show all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( showAll() )); action->setData( QVariant( types[i].value() ) ); } menu.addSeparator(); action = menu.addAction(tr("Hide all"),this,SLOT ( hideAll() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(tr("Hide all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( hideAll() )); action->setData( QVariant( types[i].value() ) ); } break; // Source case 2 : action = menu.addAction(tr("Select all"),this,SLOT ( setAllSource() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(icon, tr("Select all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( setAllSource() )); action->setData( QVariant( types[i].value() ) ); } menu.addSeparator(); action = menu.addAction(tr("Deselect all"),this,SLOT ( clearAllSource() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(icon, tr("Deselect all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( clearAllSource() )); action->setData( QVariant( types[i].value() ) ); } break; // Target case 3 : action = menu.addAction(tr("Select all"),this,SLOT ( setAllTarget() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(icon, tr("Select all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( setAllTarget() )); action->setData( QVariant( types[i].value() ) ); } menu.addSeparator(); action = menu.addAction(tr("Deselect all"),this,SLOT ( clearAllTarget() )); action->setData( QVariant() ); if (types.count() > 1) for (int i=0; i < types.count(); i++){ action = menu.addAction(icon, tr("Deselect all of type '") + dataTypeName(types[i]) + "'",this,SLOT ( clearAllTarget() )); action->setData( QVariant( types[i].value() ) ); } break; default : // std::cerr << "def"; break; } menu.exec(viewHeader_->mapToGlobal( _pos ) ); } //****************************************************************************** /** \brief show a rename dialog for object names * */ void DataControlPlugin::slotRename(){ QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); if (selectedRows == 1){ int id = model_->itemId( indexList[0]); BaseObject* item = 0; if ( id != -1 && PluginFunctions::getObject(id,item) ){ bool ok; QString newName = QInputDialog::getText(0, tr("Rename"), tr("Enter a new name:"), QLineEdit::Normal, item->name(), &ok); if (ok && !newName.isEmpty()){ item->setName(newName); } } } } //****************************************************************************** /** \brief show the material properties dialog * */ void DataControlPlugin::slotMaterialProperties(){ BaseObject* item = 0; //check if it was called from object contextMenu or from the toolBox QAction* action = dynamic_cast< QAction* > ( sender() ); if ( action ){ bool ok = false; int id = action->data().toInt(&ok); if ( ok && id > 0 ) PluginFunctions::getObject(id,item); } if ( item == 0 ){ // the slot was called from toolbox QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); if (selectedRows == 1){ int id = model_->itemId( indexList[0] ); if ( id > 0 ) PluginFunctions::getObject(id,item); } } if ( item != 0 ){ BaseObjectData* itemData = dynamic_cast< BaseObjectData* > (item); ACG::QtWidgets::QtMaterialDialog* dialog = new ACG::QtWidgets::QtMaterialDialog( 0, itemData->materialNode() ); dialog->setWindowFlags(dialog->windowFlags() | Qt::WindowStaysOnTopHint); connect(dialog, SIGNAL(signalNodeChanged(ACG::SceneGraph::BaseNode*)), this, SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)) ); dialog->setWindowIcon( QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"datacontrol-material.png")); dialog->show(); } } //****************************************************************************** /** \brief Called when the material properties were changed inside the material dialog * * @param unused */ void DataControlPlugin::slotNodeChanged( ACG::SceneGraph::BaseNode* /*_node*/ ){ emit updateView(); } //****************************************************************************** /** * \brief Switch light source on or off */ void DataControlPlugin::slotSwitchLight() { QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); if (selectedRows == 1) { LightObject* light = 0; int id = model_->itemId( indexList[0]); if (id == -1 || !PluginFunctions::getObject( id, light ) ) return; if(light == 0) return; light->lightSource()->enabled() ? light->lightSource()->disable() : light->lightSource()->enable(); emit updatedObject(id, UPDATE_ALL); } } //****************************************************************************** /** * \brief Switch light source on or off */ void DataControlPlugin::slotEditLight() { QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); if (selectedRows == 1) { LightObject* light = 0; int id = model_->itemId( indexList[0]); if (id == -1 || !PluginFunctions::getObject( id, light ) ) return; if(light == 0) return; LightWidget* widget = new LightWidget( light->lightNode() ); widget->show(); } } //****************************************************************************** /** \brief Zoom to an object * */ void DataControlPlugin::slotZoomTo(){ QItemSelectionModel* selection = view_->selectionModel(); // Get all selected rows QModelIndexList indexList = selection->selectedRows ( 0 ); int selectedRows = indexList.size(); if (selectedRows == 1){ BaseObject* item = 0; int id = model_->itemId( indexList[0]); if (id == -1 || !PluginFunctions::getObject( id, item) ) return; if ( item->isGroup() ) { //zoom to all objects in this group QList< BaseObject* > children = item->getLeafs(); //compute boundingBox bool firstRound = true; ACG::Vec3d bbmin; ACG::Vec3d bbmax; for (int i=0; i < children.size(); i++){ BaseObjectData* child = dynamic_cast< BaseObjectData* > (children[i]); if (child){ if ( !child->visible() ){ child->show(); } ACG::Vec3d cur_min; ACG::Vec3d cur_max; child->getBoundingBox(cur_min, cur_max); if (firstRound){ bbmin = cur_min; bbmax = cur_max; firstRound = false; }else{ bbmin[0] = std::min( bbmin[0], cur_min[0]); bbmin[1] = std::min( bbmin[1], cur_min[1]); bbmin[2] = std::min( bbmin[2], cur_min[2]); bbmax[0] = std::max( bbmax[0], cur_max[0]); bbmax[1] = std::max( bbmax[0], cur_max[1]); bbmax[2] = std::max( bbmax[0], cur_max[2]); } } } //zoom to objects ACG::Vec3d bbcenter = (bbmax + bbmin) * 0.5; double bbradius = (bbmax - bbmin).norm(); ACG::Vec3d eye = bbcenter + (PluginFunctions::eyePos() - bbcenter).normalize() * bbradius ; PluginFunctions::flyTo(eye, bbcenter ); }else{ //zoom to object BaseObjectData* obj = dynamic_cast< BaseObjectData* >(item); if ( !obj->visible() ){ obj->show(); } if (obj){ ACG::Vec3d bbmin; ACG::Vec3d bbmax; obj->getBoundingBox(bbmin, bbmax); if ((bbmin[0] > bbmax[0]) || (bbmin[1] > bbmax[1]) || (bbmin[2] > bbmax[2])){ std::cerr << "Error while computing bounding box!"; return; } ACG::Vec3d bbcenter = (bbmax + bbmin) * 0.5; double bbradius = (bbmax - bbmin).norm(); ACG::Vec3d eye = bbcenter + (PluginFunctions::eyePos() - bbcenter).normalize() * bbradius ; PluginFunctions::flyTo(eye, bbcenter ); } } } }