00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "GraphModeler.h"
00028 #include "AddPreset.h"
00029
00030 #include <sofa/simulation/tree/Simulation.h>
00031 #include <sofa/gui/qt/FileManagement.h>
00032 #include <sofa/helper/system/FileRepository.h>
00033 #include <sofa/helper/system/SetDirectory.h>
00034 #include <sofa/simulation/common/TransformationVisitor.h>
00035
00036 #include <sofa/component/visualmodel/VisualModelImpl.h>
00037
00038 #ifdef SOFA_QT4
00039 #include <Q3Header>
00040 #include <Q3PopupMenu>
00041 #include <QMessageBox>
00042 #else
00043 #include <qheader.h>
00044 #include <qpopupmenu.h>
00045 #include <qmessagebox.h>
00046 #endif
00047
00048 namespace sofa
00049 {
00050
00051 namespace gui
00052 {
00053
00054 namespace qt
00055 {
00056
00057
00058 #ifndef SOFA_QT4
00059 typedef QPopupMenu Q3PopupMenu;
00060 #endif
00061
00062 GNode *GraphModeler::addGNode(GNode *parent, GNode *child, bool saveHistory)
00063 {
00064 GNode *lastRoot = getRoot();
00065 if (!child)
00066 {
00067 child = new GNode();
00068 if (!parent)
00069 child->setName("Root");
00070 }
00071
00072
00073 graphListener->addChild(parent, child);
00074
00075 if (parent != NULL)
00076 parent->addChild(child);
00077 else
00078 {
00079
00080 firstChild()->setExpandable(true);
00081 firstChild()->setOpen(true);
00082 historyOperation.clear();
00083 currentStateHistory=historyOperation.end();
00084 }
00085
00086 if (saveHistory)
00087 {
00088 Operation adding(graphListener->items[child], child, Operation::ADD_OBJECT);
00089 historyOperation.push_front(adding);
00090 }
00091 if (!parent) deleteComponent(graphListener->items[lastRoot]);
00092 return child;
00093 }
00094
00095 BaseObject *GraphModeler::addComponent(GNode *parent, ClassInfo* entry, std::string templateName, bool saveHistory)
00096 {
00097 BaseObject *object=NULL;;
00098 if (!parent || !entry) return object;
00099
00100
00101
00102 xml::ObjectElement description("Default", entry->className.c_str() );
00103
00104 if (!templateName.empty()) description.setAttribute("template", templateName.c_str());
00105
00106
00107 ClassCreator* c;
00108
00109 if (entry->creatorMap.size() <= 1)
00110 c=entry->creatorMap.begin()->second;
00111 else
00112 {
00113 if (templateName.empty())
00114 {
00115 c=entry->creatorMap.find(entry->defaultTemplate)->second; templateName=entry->defaultTemplate;
00116 }
00117 else
00118 c=entry->creatorMap.find(templateName)->second;
00119 }
00120
00121 if (c->canCreate(parent->getContext(), &description))
00122 {
00123 object = c->createInstance(parent->getContext(), NULL);
00124 graphListener->addObject(parent, object);
00125 if (saveHistory)
00126 {
00127 Operation adding(graphListener->items[object], object, Operation::ADD_OBJECT);
00128 historyOperation.push_front(adding);
00129 }
00130 }
00131 else
00132 {
00133 BaseObject* reference = parent->getContext()->getMechanicalState();
00134
00135 if (!reference)
00136 {
00137 const QString caption("Creation Impossible");
00138 const QString warning=QString("No MechanicalState found in your Node ") + QString(parent->getName().c_str());
00139 if ( QMessageBox::warning ( this, caption,warning, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape, QMessageBox::Ignore ) == QMessageBox::Cancel )
00140 return object;
00141 }
00142 else if (entry->className.find("Mapping") != std::string::npos) ;
00143 else
00144 {
00145 const QString caption("Creation Impossible");
00146 const QString warning=
00147 QString("Your component won't be created: \n \t * <")
00148 + QString(reference->getTemplateName().c_str()) + QString("> DOFs are used in the Node ") + QString(parent->getName().c_str()) + QString("\n\t * <")
00149 + QString(templateName.c_str()) + QString("> is the type of your ") + QString(entry->className.c_str());
00150 if ( QMessageBox::warning ( this, caption,warning, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape, QMessageBox::Ignore ) == QMessageBox::Cancel )
00151 return object;
00152 }
00153 object = c->createInstance(parent->getContext(), NULL);
00154 graphListener->addObject(parent, object);
00155 }
00156 return object;
00157 }
00158
00159
00160
00161
00162 void GraphModeler::dropEvent(QDropEvent* event)
00163 {
00164 QPushButton *push = (QPushButton *)event->source();
00165 if (push) push->setDown(false);
00166
00167 QString text;
00168 Q3TextDrag::decode(event, text);
00169
00170 std::string filename(text.ascii());
00171 std::string test = filename; test.resize(4);
00172
00173 if (test == "file")
00174 {
00175 #ifdef WIN32
00176 filename = filename.substr(8);
00177 #else
00178 filename = filename.substr(7);
00179 #endif
00180
00181 if (filename[filename.size()-1] == '\n')
00182 {
00183 filename.resize(filename.size()-1);
00184 filename[filename.size()-1]='\0';
00185 }
00186
00187 emit(fileOpen(filename));
00188 }
00189 else
00190 {
00191
00192 if (library.find(event->source()) != library.end())
00193 {
00194 std::string templateName = text.ascii();
00195 addComponent(getGNode(event->pos()), library.find(event->source())->second.first, templateName );
00196 }
00197 else
00198 {
00199 if (text == QString("GNode"))
00200 {
00201 GNode* node=getGNode(event->pos());
00202 if (node) addGNode(node);
00203 }
00204 }
00205 }
00206 }
00207
00208
00209
00210
00211 BaseObject *GraphModeler::getObject(Q3ListViewItem *item)
00212 {
00213 std::map<core::objectmodel::Base*, Q3ListViewItem* >::iterator it;
00214 for (it = graphListener->items.begin();it != graphListener->items.end();it++)
00215 {
00216 if (it->second == item)
00217 {
00218 return dynamic_cast< BaseObject *>(it->first);
00219 }
00220 }
00221 return NULL;
00222 }
00223
00224
00225 GNode *GraphModeler::getGNode(const QPoint &pos)
00226 {
00227 Q3ListViewItem *item = itemAt(pos);
00228 if (!item) return NULL;
00229 return getGNode(item);
00230 }
00231
00232
00233
00234 GNode *GraphModeler::getGNode(Q3ListViewItem *item)
00235 {
00236 if (!item) return NULL;
00237 sofa::core::objectmodel::Base *object;
00238 std::map<core::objectmodel::Base*, Q3ListViewItem* >::iterator it;
00239 for (it = graphListener->items.begin();it != graphListener->items.end();it++)
00240 {
00241 if (it->second == item)
00242 {
00243 object = it->first;
00244 break;
00245 }
00246 }
00247 if (it == graphListener->items.end()) return NULL;
00248
00249 if (dynamic_cast<GNode*>(it->first)) return dynamic_cast<GNode*>(it->first);
00250 else
00251 {
00252 item = item->parent();
00253 for (it = graphListener->items.begin();it != graphListener->items.end();it++)
00254 {
00255 if (it->second == item)
00256 {
00257 object = it->first;
00258 break;
00259 }
00260 }
00261 if (it == graphListener->items.end()) return NULL;
00262 if (dynamic_cast<GNode*>(it->first)) return dynamic_cast<GNode*>(it->first);
00263 else return NULL;
00264 }
00265 }
00266
00267
00268 void GraphModeler::openModifyObject()
00269 {
00270 Q3ListViewItem *item = currentItem();
00271 openModifyObject(item);
00272 }
00273
00274 void GraphModeler::openModifyObject(Q3ListViewItem *item)
00275 {
00276 if (!item) return;
00277
00278 std::map<core::objectmodel::Base*, Q3ListViewItem* >::iterator it;
00279 for (it = graphListener->items.begin();it != graphListener->items.end();it++)
00280 {
00281 if (it->second == item)
00282 {
00283 break;
00284 }
00285 }
00286 if (it == graphListener->items.end()) return;
00287
00288
00289
00290 current_Id_modifyDialog = it->first;
00291 std::map< void*, QDialog* >::iterator testWindow = map_modifyObjectWindow.find( current_Id_modifyDialog);
00292 if ( testWindow != map_modifyObjectWindow.end())
00293 {
00294
00295 (*testWindow).second->raise();
00296 return;
00297 }
00298
00299 ModifyObjectModeler *dialogModify = new ModifyObjectModeler ( current_Id_modifyDialog, it->first, item,this,item->text(0));
00300 map_modifyObjectWindow.insert( std::make_pair(current_Id_modifyDialog, dialogModify));
00301
00302
00303 map_modifyDialogOpened.insert ( std::make_pair ( current_Id_modifyDialog, it->first ) );
00304
00305 dialogModify->show();
00306 dialogModify->raise();
00307
00308
00309 }
00310
00311 void GraphModeler::doubleClick(Q3ListViewItem *item)
00312 {
00313 if (!item) return;
00314 item->setOpen ( !item->isOpen() );
00315 openModifyObject(item);
00316
00317 }
00318 void GraphModeler::rightClick(Q3ListViewItem *item, const QPoint &point, int index)
00319 {
00320 if (!item) return;
00321 bool isNode=getObject(item)==NULL;
00322
00323 Q3PopupMenu *contextMenu = new Q3PopupMenu ( this, "ContextMenu" );
00324 if (isNode)
00325 {
00326 contextMenu->insertItem("Collapse", this, SLOT( collapseNode()));
00327 contextMenu->insertItem("Expand" , this, SLOT( expandNode()));
00328 contextMenu->insertSeparator ();
00329 contextMenu->insertItem("Load" , this, SLOT( loadNode()));
00330 contextMenu->insertItem(QIconSet(), tr( "Preset"), preset);
00331 contextMenu->insertItem("Save" , this, SLOT( saveNode()));
00332 }
00333 int index_menu = contextMenu->insertItem("Delete" , this, SLOT( deleteComponent()));
00334
00335 if (isNode)
00336 {
00337 if ( !isNodeErasable ( getGNode(item) ) )
00338 contextMenu->setItemEnabled ( index_menu,false );
00339 }
00340 else
00341 {
00342 if ( !isObjectErasable ( getObject(item) ))
00343 contextMenu->setItemEnabled ( index_menu,false );
00344 }
00345
00346 contextMenu->insertItem("Modify" , this, SLOT( openModifyObject()));
00347 contextMenu->popup ( point, index );
00348
00349 }
00350
00351
00352 void GraphModeler::collapseNode()
00353 {
00354 collapseNode(currentItem());
00355 }
00356
00357 void GraphModeler::collapseNode(Q3ListViewItem* item)
00358 {
00359 if (!item) return;
00360
00361 Q3ListViewItem* child;
00362 child = item->firstChild();
00363 while ( child != NULL )
00364 {
00365 child->setOpen ( false );
00366 child = child->nextSibling();
00367 }
00368 item->setOpen ( true );
00369 }
00370
00371 void GraphModeler::expandNode()
00372 {
00373 expandNode(currentItem());
00374 }
00375
00376 void GraphModeler::expandNode(Q3ListViewItem* item)
00377 {
00378 if (!item) return;
00379
00380 item->setOpen ( true );
00381 if ( item != NULL )
00382 {
00383 Q3ListViewItem* child;
00384 child = item->firstChild();
00385 while ( child != NULL )
00386 {
00387 item = child;
00388 child->setOpen ( true );
00389 expandNode(item);
00390 child = child->nextSibling();
00391 }
00392 }
00393 }
00394
00395 GNode *GraphModeler::loadNode()
00396 {
00397 return loadNode(currentItem());
00398 }
00399
00400 GNode *GraphModeler::loadNode(Q3ListViewItem* item, std::string filename)
00401 {
00402 if (!item) return NULL;
00403 GNode *node = getGNode(item);
00404 if (filename.empty())
00405 {
00406 QString s = getOpenFileName ( this, NULL,"Scenes (*.scn *.xml *.simu *.pscn)", "open file dialog", "Choose a file to open" );
00407 if (s.length() >0)
00408 {
00409 filename = s.ascii();
00410 }
00411 else return NULL;
00412 }
00413 xml::BaseElement* newXML=NULL;
00414
00415 newXML = xml::loadFromFile (filename.c_str() );
00416 if (newXML == NULL) return NULL;
00417 if (!newXML->init()) std::cerr<< "Objects initialization failed.\n";
00418 GNode *newNode = dynamic_cast<GNode*> ( newXML->getObject() );
00419 if (newNode) addGNode(node,newNode);
00420 return newNode;
00421 }
00422
00423 void GraphModeler::loadPreset(std::string presetName)
00424 {
00425
00426
00427 xml::BaseElement* newXML = xml::loadFromFile (presetName.c_str() );
00428 if (newXML == NULL) return;
00429
00430 xml::BaseElement::child_iterator<> it(newXML->begin());
00431 bool elementPresent[3]={false,false,false};
00432 for (; it!=newXML->end();++it)
00433 {
00434 if (it->getType() == std::string("MeshLoader") || it->getType() == std::string("SparseGrid")) elementPresent[0] = true;
00435 else if (it->getName() == std::string("VisualNode") || it->getType() == std::string("OglModel")) elementPresent[1] = true;
00436 else if (it->getName() == std::string("CollisionNode")) elementPresent[2] = true;
00437 }
00438
00439 if (!DialogAdd)
00440 {
00441 DialogAdd = new AddPreset(this,"AddPreset", elementPresent);
00442 DialogAdd->setPath(sofa::helper::system::DataRepository.getFirstPath());
00443 }
00444
00445 DialogAdd->setPresetFile(presetName);
00446 GNode *node=getGNode(currentItem());
00447 DialogAdd->setParentNode(node);
00448
00449 DialogAdd->show();
00450 DialogAdd->raise();
00451 }
00452
00453
00454 void GraphModeler::loadPreset(GNode *parent, std::string presetFile,
00455 std::string *filenames,
00456 std::string *translation,
00457 std::string *rotation,
00458 std::string scale)
00459 {
00460
00461
00462 xml::BaseElement* newXML=NULL;
00463
00464 newXML = xml::loadFromFile (presetFile.c_str() );
00465 if (newXML == NULL) return;
00466
00467 bool collisionNodeFound=false;
00468 xml::BaseElement *meshMecha=NULL;
00469 xml::BaseElement::child_iterator<> it(newXML->begin());
00470 for (; it!=newXML->end();++it)
00471 {
00472
00473 if (it->getType() == std::string("MechanicalObject"))
00474 {
00475 updatePresetNode(*it, std::string(), translation, rotation, scale);
00476 }
00477 if (it->getType() == std::string("MeshLoader") || it->getType() == std::string("SparseGrid"))
00478 {
00479 updatePresetNode(*it, filenames[0], translation, rotation, scale);
00480 meshMecha = it;
00481 }
00482 if (it->getType() == std::string("OglModel"))
00483 {
00484 updatePresetNode(*it, filenames[1], translation, rotation, scale);
00485 }
00486
00487 if (it->getName() == std::string("VisualNode"))
00488 {
00489 xml::BaseElement* visualXML = it;
00490
00491 xml::BaseElement::child_iterator<> it_visual(visualXML->begin());
00492 for (;it_visual!=visualXML->end();++it_visual)
00493 {
00494 if (it_visual->getType() == std::string("OglModel"))
00495 {
00496 updatePresetNode(*it_visual, filenames[1], translation, rotation, scale);
00497 }
00498 }
00499 }
00500 if (it->getName() == std::string("CollisionNode"))
00501 {
00502 collisionNodeFound=true;
00503 xml::BaseElement* collisionXML = it;
00504
00505 xml::BaseElement::child_iterator<> it_collision(collisionXML->begin());
00506 for (;it_collision!=collisionXML->end();++it_collision)
00507 {
00508
00509 if (it_collision->getType() == std::string("MechanicalObject"))
00510 {
00511 updatePresetNode(*it_collision, std::string(), translation, rotation, scale);
00512 }
00513 if (it_collision->getType() == std::string("MeshLoader"))
00514 {
00515 updatePresetNode(*it_collision, filenames[2], translation, rotation, scale);
00516 }
00517 }
00518 }
00519 }
00520
00521
00522
00523 if (!newXML->init()) std::cerr<< "Objects initialization failed.\n";
00524 GNode *presetNode = dynamic_cast<GNode*> ( newXML->getObject() );
00525 if (presetNode) addGNode(parent,presetNode);
00526 }
00527
00528 void GraphModeler::updatePresetNode(xml::BaseElement &elem, std::string meshFile, std::string *translation, std::string *rotation, std::string scale)
00529 {
00530 if (elem.presenceAttribute(std::string("filename"))) elem.setAttribute(std::string("filename"), meshFile.c_str());
00531
00532 if (elem.presenceAttribute(std::string("dx"))) elem.setAttribute(std::string("dx"), translation[0].c_str());
00533 if (elem.presenceAttribute(std::string("dy"))) elem.setAttribute(std::string("dy"), translation[1].c_str());
00534 if (elem.presenceAttribute(std::string("dz"))) elem.setAttribute(std::string("dz"), translation[2].c_str());
00535
00536 if (elem.presenceAttribute(std::string("rx"))) elem.setAttribute(std::string("rx"), rotation[0].c_str());
00537 if (elem.presenceAttribute(std::string("ry"))) elem.setAttribute(std::string("ry"), rotation[1].c_str());
00538 if (elem.presenceAttribute(std::string("rz"))) elem.setAttribute(std::string("rz"), rotation[2].c_str());
00539
00540 if (elem.presenceAttribute(std::string("scale"))) elem.setAttribute(std::string("scale"), scale.c_str());
00541 }
00542
00543
00544 void GraphModeler::saveNode()
00545 {
00546 saveNode(currentItem());
00547 }
00548
00549 void GraphModeler::saveNode(Q3ListViewItem* item)
00550 {
00551 if (!item) return;
00552 GNode *node = getGNode(item);
00553 if (!node) return;
00554
00555 QString s = sofa::gui::qt::getSaveFileName ( this, NULL, "Scenes (*.scn *.xml)", "save file dialog", "Choose where the scene will be saved" );
00556 if ( s.length() >0 )
00557 getSimulation()->printXML(node, s.ascii());
00558 }
00559
00560 void GraphModeler::clearGraph()
00561 {
00562 deleteComponent(firstChild());
00563 }
00564
00565 void GraphModeler::deleteComponent(Q3ListViewItem* item, bool saveHistory)
00566 {
00567 if (!item) return;
00568
00569 GNode *parent = getGNode(item->parent());
00570 bool isNode = getObject(item)==NULL;
00571 if (!isNode && isObjectErasable(getObject(item)))
00572 {
00573 BaseObject* object = getObject(item);
00574 graphListener->removeObject(getGNode(item), getObject(item));
00575
00576 if (saveHistory)
00577 {
00578 Operation removal(item, getObject(item),Operation::DELETE_OBJECT);
00579 historyOperation.push_front(removal);
00580 }
00581
00582 parent->removeObject(object);
00583 delete object;
00584 }
00585 else
00586 {
00587 if (!isNodeErasable(getGNode(item))) return;
00588 GNode *node = getGNode(item);
00589 graphListener->removeChild(parent, node);
00590
00591 if (saveHistory)
00592 {
00593 Operation removal(item, getGNode(item),Operation::DELETE_OBJECT);
00594 historyOperation.push_front(removal);
00595 }
00596 if (!parent && childCount() == 0) addGNode(NULL);
00597
00598 getSimulation()->unload (node);
00599 }
00600
00601 }
00602 void GraphModeler::deleteComponent()
00603 {
00604 Q3ListViewItem *item = currentItem();
00605 deleteComponent(item);
00606 }
00607
00608 void GraphModeler::modifyUnlock ( void *Id )
00609 {
00610 map_modifyDialogOpened.erase( Id );
00611 map_modifyObjectWindow.erase( Id );
00612 }
00613
00614
00615
00616
00617 void GraphModeler::editUndo()
00618 {
00619 std::cout << "Undo \n";
00620 std::cout << historyOperation.size() << " size of the history\n";
00621 if (currentStateHistory == historyOperation.begin()) return;
00622 currentStateHistory--;
00623 }
00624
00625 void GraphModeler::editRedo()
00626 {
00627 std::cout << "Redo \n";
00628 }
00629
00630 void GraphModeler::keyPressEvent ( QKeyEvent * e )
00631 {
00632 switch ( e->key() )
00633 {
00634 case Qt::Key_Delete :
00635 {
00636 deleteComponent();
00637 break;
00638 }
00639 default:
00640 {
00641 e->ignore();
00642 break;
00643 }
00644 }
00645 }
00646
00647
00648 bool GraphModeler::isNodeErasable ( core::objectmodel::Base* element )
00649 {
00650 std::map< void*, core::objectmodel::Base*>::iterator it;
00651 for (it = map_modifyDialogOpened.begin(); it != map_modifyDialogOpened.end();it++)
00652 {
00653
00654 if (dynamic_cast< BaseObject* >(it->second))
00655 {
00656 if (getGNode(graphListener->items[it->second]) == element) return false;
00657 }
00658 else if (it->second == element) return false;
00659
00660 }
00661
00662 std::map< core::objectmodel::Base*, Q3ListViewItem*>::iterator it_item;
00663 it_item = graphListener->items.find(element);
00664
00665 Q3ListViewItem *child = it_item->second->firstChild();
00666 while (child != NULL)
00667 {
00668 for (it_item = graphListener->items.begin(); it_item != graphListener->items.end();it_item++)
00669 {
00670 if (it_item->second == child)
00671 {
00672 if (!isNodeErasable(it_item->first)) return false;
00673 break;
00674 }
00675 }
00676 child = child->nextSibling();
00677 }
00678 return true;
00679 }
00680
00681 bool GraphModeler::isObjectErasable ( core::objectmodel::Base* element )
00682 {
00683 std::map< void*, core::objectmodel::Base*>::iterator it;
00684 for (it = map_modifyDialogOpened.begin(); it != map_modifyDialogOpened.end();it++)
00685 {
00686 if (it->second == element) return false;
00687 }
00688
00689 return true;
00690 }
00691
00692 }
00693 }
00694 }