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 <sofa/gui/qt/RealGUI.h>
00028
00029
00030 #include <sofa/component/collision/TriangleModel.h>
00031 #include <sofa/component/collision/LineModel.h>
00032 #include <sofa/component/collision/PointModel.h>
00033 #include <sofa/component/collision/SphereModel.h>
00034
00035 #include <sofa/helper/system/FileRepository.h>
00036 #include <sofa/core/objectmodel/BaseContext.h>
00037
00038 #ifdef SOFA_QT4
00039 #include <QWidget>
00040 #include <QStackedWidget>
00041 #include <QLayout>
00042 #include <Q3ListViewItem>
00043 #include <Q3ListView>
00044 #include <QStatusBar>
00045 #include <QRadioButton>
00046 #include <QCheckBox>
00047 #include <QSplitter>
00048 #include <Q3TextEdit>
00049 #include <QCursor>
00050 #include <QAction>
00051 #include <QMessageBox>
00052 #include <QFileDialog>
00053 #include <Q3FileDialog>
00054 #include <QTabWidget>
00055 #include <Q3PopupMenu>
00056 #include <QToolTip>
00057 #include <QButtonGroup>
00058 #include <QRadioButton>
00059 #include <QInputDialog>
00060 #else
00061 #include <qwidget.h>
00062 #include <qwidgetstack.h>
00063 #include <qlayout.h>
00064 #include <qlistview.h>
00065 #include <qstatusbar.h>
00066 #include <qfiledialog.h>
00067 #include <qheader.h>
00068 #include <qimage.h>
00069 #include <qsplitter.h>
00070 #include <qtextedit.h>
00071 #include <qcursor.h>
00072 #include <qapplication.h>
00073 #include <qaction.h>
00074 #include <qmessagebox.h>
00075 #include <qtabwidget.h>
00076 #include <qpopupmenu.h>
00077 #include <qtooltip.h>
00078 #include <qbuttongroup.h>
00079 #include <qradiobutton.h>
00080 #include <qinputdialog.h>
00081 #endif
00082
00083
00084 namespace sofa
00085 {
00086
00087 namespace gui
00088 {
00089
00090 namespace qt
00091 {
00092
00093
00094 #ifdef SOFA_QT4
00095 typedef Q3ListView QListView;
00096 typedef Q3ListViewItem QListViewItem;
00097 #endif
00098
00099 using sofa::simulation::tree::GNode;
00100 using namespace sofa::simulation::tree;
00101 using sofa::core::objectmodel::BaseContext;
00102
00103 void RealGUI::clearGraph()
00104 {
00105 GNode *groot = viewer->getScene();
00106
00107 graphView->setSorting ( -1 );
00108
00109 graphView->header()->hide();
00110
00111 graphListener = new GraphListenerQListView ( graphView );
00112 graphListener->addChild ( NULL, groot );
00113
00114
00115 graphCreateStats(groot);
00116
00117
00118 for ( std::map<core::objectmodel::Base*, Q3ListViewItem* >::iterator it = graphListener->items.begin() ; it != graphListener->items.end() ; ++ it )
00119 {
00120 if ( GNode *current_node = dynamic_cast< GNode *> ( ( *it ).first ) )
00121 {
00122 list_object_initial.push_back ( current_node );
00123 list_object_initial.push_back ( dynamic_cast< GNode *> ( current_node->getParent() ) );
00124 }
00125 }
00126
00127
00128 if ( currentTab != TabGraph )
00129 {
00130 graphListener->freeze ( groot );
00131 }
00132
00133 simulation::tree::Simulation *s = simulation::tree::getSimulation();
00134
00135
00136 if (s->instruments.size() != 0)
00137 {
00138 tabInstrument = new QWidget();
00139 tabs->addTab(tabInstrument, QString("Instrument"));
00140
00141 QVBoxLayout *layout = new QVBoxLayout( tabInstrument, 0, 1, "tabInstrument");
00142
00143 QButtonGroup *list_instrument = new QButtonGroup(tabInstrument);
00144 list_instrument->setExclusive(true);
00145
00146 #ifdef SOFA_QT4
00147 connect ( list_instrument, SIGNAL ( buttonClicked(int) ), this, SLOT ( changeInstrument(int) ) );
00148 #else
00149 connect ( list_instrument, SIGNAL ( clicked(int) ), this, SLOT ( changeInstrument(int) ) );
00150 #endif
00151
00152 QRadioButton *button = new QRadioButton(tabInstrument);button->setText("None");
00153 #ifdef SOFA_QT4
00154 list_instrument->addButton(button, 0);
00155 #else
00156 list_instrument->insert(button);
00157 #endif
00158 layout->addWidget(button);
00159
00160 for (unsigned int i=0;i<s->instruments.size();i++)
00161 {
00162 QRadioButton *button = new QRadioButton(tabInstrument); button->setText(QString( s->instruments[i]->getName().c_str() ) );
00163 #ifdef SOFA_QT4
00164 list_instrument->addButton(button, i+1);
00165 #else
00166 list_instrument->insert(button);
00167 #endif
00168 layout->addWidget(button);
00169 if (i==0)
00170 {
00171 button->setChecked(true); changeInstrument(1);
00172 }
00173 else
00174 s->instruments[i]->setActive(false);
00175
00176 }
00177 #ifdef SOFA_QT4
00178 layout->addStretch(1);
00179 #endif
00180 #ifndef SOFA_QT4
00181 layout->addWidget(list_instrument);
00182 #endif
00183 }
00184 }
00185
00186
00187
00188
00189 void RealGUI::graphCollapse()
00190 {
00191 bool isAnimated = startButton->isOn ();
00192
00193 playpauseGUI ( false );
00194 if ( item_clicked != NULL )
00195 {
00196 QListViewItem* child;
00197 child = item_clicked->firstChild();
00198 while ( child != NULL )
00199 {
00200 child->setOpen ( false );
00201 child = child->nextSibling();
00202 }
00203 item_clicked->setOpen ( true );
00204 }
00205
00206 playpauseGUI ( isAnimated );
00207 }
00208
00209 void RealGUI::graphExpand()
00210 {
00211 bool isAnimated = startButton->isOn();
00212 playpauseGUI ( false );
00213 item_clicked->setOpen ( true );
00214 QListViewItem *item_clicked_back = item_clicked;
00215 if ( item_clicked != NULL )
00216 {
00217 QListViewItem* child;
00218 child = item_clicked->firstChild();
00219 while ( child != NULL )
00220 {
00221 item_clicked = child;
00222
00223 child->setOpen ( true );
00224 graphExpand();
00225 child = child->nextSibling();
00226 }
00227 }
00228 item_clicked = item_clicked_back;
00229 playpauseGUI ( isAnimated );
00230 }
00231
00232 void RealGUI::modifyUnlock ( void *Id )
00233 {
00234 graphCreateStats(viewer->getScene());
00235
00236 map_modifyDialogOpened.erase( Id );
00237 map_modifyObjectWindow.erase( Id );
00238 }
00239
00240
00241
00242
00243
00244 bool RealGUI::graphCreateStats( Node *node)
00245 {
00246 sofa::helper::vector< sofa::core::CollisionModel* > list_collisionModels;
00247 node->get< sofa::core::CollisionModel >( &list_collisionModels, BaseContext::SearchDown);
00248
00249 if (items_stats.size() != 0)
00250 {
00251 delete items_stats[0].second;
00252 items_stats.clear();
00253 }
00254 GUI::StatsCounter->clear();
00255
00256 graphAddCollisionModelsStat(list_collisionModels);
00257
00258 graphSummary();
00259 return true;
00260 }
00261
00262
00263 void RealGUI::graphAddCollisionModelsStat(sofa::helper::vector< sofa::core::CollisionModel* > &v)
00264 {
00265 std::map< BaseContext*, QListViewItem* > listStats;
00266 for (unsigned int i=0;i<v.size();i++)
00267 {
00268 if ( !v[i]->isActive()) continue;
00269 std::map< BaseContext*, QListViewItem* >::iterator it = listStats.find(v[i]->getContext());
00270 QListViewItem *item;
00271 if (it != listStats.end())
00272 {
00273 item = new QListViewItem((*it).second);
00274 }
00275 else
00276 {
00277 QListViewItem *node = new QListViewItem(GUI::StatsCounter);
00278 node->setText(0,QString(v[i]->getContext()->getName().c_str()));
00279 QPixmap* pix = sofa::gui::qt::getPixmap(dynamic_cast< sofa::simulation::tree::GNode*>(v[i]->getContext()));
00280 if (pix) node->setPixmap(0,*pix);
00281 listStats.insert(std::make_pair(v[i]->getContext(), node));
00282 item = new QListViewItem(node);
00283 node->setOpen(true);
00284 }
00285 item->setText(0,v[i]->getName().c_str());
00286
00287 if (dynamic_cast< sofa::component::collision::TriangleModel* >(v[i])) item->setText(1, "Triangle");
00288 else if (dynamic_cast< sofa::component::collision::LineModel* >(v[i])) item->setText(1, "Line");
00289 else if (dynamic_cast< sofa::component::collision::PointModel* >(v[i])) item->setText(1, "Point");
00290 else if (dynamic_cast< sofa::component::collision::TSphereModel<defaulttype::Vec3fTypes>* >(v[i]) ||
00291 dynamic_cast< sofa::component::collision::TSphereModel<defaulttype::Vec3dTypes>* >(v[i]) )
00292 item->setText(1, "Sphere");
00293 else continue;
00294 item->setText(0,v[i]->getName().c_str());
00295 item->setText(2,QString::number(v[i]->getSize()));
00296 items_stats.push_back(std::make_pair(v[i], item));
00297 }
00298 }
00299
00300
00301
00302 void RealGUI::graphSummary()
00303 {
00304 unsigned int counter[4]={0,0,0,0};
00305 for (unsigned int i=0; i < items_stats.size();i++)
00306 {
00307 if (!dynamic_cast< Node *>(items_stats[i].first))
00308 {
00309 if ( std::string(items_stats[i].second->text(1).ascii()) == "Triangle")
00310 {
00311 counter[0]+=atoi(items_stats[i].second->text(2));
00312 }
00313 else if ( std::string(items_stats[i].second->text(1).ascii()) == "Line")
00314 {
00315 counter[1]+=atoi(items_stats[i].second->text(2));
00316 }
00317 else if ( std::string(items_stats[i].second->text(1).ascii()) == "Point")
00318 {
00319 counter[2]+=atoi(items_stats[i].second->text(2));
00320 }
00321 else if ( std::string(items_stats[i].second->text(1).ascii()) == "Sphere")
00322 {
00323 counter[3]+=atoi(items_stats[i].second->text(2));
00324 }
00325 }
00326 }
00327 std::string textStats("Collision Elements present: <ul>");
00328 if (counter[0] != 0)
00329 {
00330 char buf[100];
00331 sprintf ( buf, "<li>Triangles: %d</li>", counter[0] );
00332 textStats += buf;
00333 }
00334
00335 if (counter[1] != 0)
00336 {
00337 char buf[100];
00338 sprintf ( buf, "<li>Lines: %d</li>", counter[1] );
00339 textStats += buf;
00340 }
00341
00342 if (counter[2] != 0)
00343 {
00344 char buf[100];
00345 sprintf ( buf, "<li>Points: %d</li>", counter[2] );
00346 textStats += buf;
00347 }
00348
00349 if (counter[3] != 0)
00350 {
00351 char buf[100];
00352 sprintf ( buf, "<li>Spheres: %d</li>", counter[3] );
00353 textStats += buf;
00354 }
00355
00356 textStats += "</ul>";
00357 statsLabel->setText( textStats.c_str());
00358 statsLabel->update();
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 void RealGUI::DoubleClickeItemInSceneView ( QListViewItem *item )
00368 {
00369
00370
00371 if ( item == NULL )
00372 return;
00373
00374 item_clicked = item;
00375
00376
00377 item_clicked->setOpen ( !item_clicked->isOpen() );
00378 graphModify();
00379 }
00380
00381
00382
00383 void RealGUI::RightClickedItemInSceneView ( QListViewItem *item, const QPoint& point, int index )
00384 {
00385 if ( dialog == NULL )
00386 {
00387
00388 dialog = new AddObject ( &list_object, this );
00389 dialog->setPath ( viewer->getSceneFileName() );
00390 dialog->hide();
00391 }
00392
00393
00394
00395 item_clicked=item;
00396
00397
00398 node_clicked = NULL;
00399 if ( item_clicked == NULL ) return;
00400
00401
00402
00403 std::map<core::objectmodel::Base*, QListViewItem* >::iterator graph_iterator;
00404
00405 for (graph_iterator = graphListener->items.begin(); graph_iterator != graphListener->items.end(); graph_iterator++)
00406 {
00407 if ( (*graph_iterator).second == item) {node_clicked = dynamic_cast< GNode* >( (*graph_iterator).first); break;}
00408 }
00409
00410
00411
00412 QPopupMenu *contextMenu = new QPopupMenu ( graphView, "ContextMenu" );
00413
00414
00415
00416 if ( node_clicked != NULL )
00417 {
00418 contextMenu->insertItem ( "Collapse", this, SLOT ( graphCollapse() ) );
00419 contextMenu->insertItem ( "Expand", this, SLOT ( graphExpand() ) );
00420 contextMenu->insertSeparator ();
00421
00422 if (node_clicked->isActive())
00423 contextMenu->insertItem ( "Desactivate", this, SLOT ( graphDesactivateNode() ) );
00424 else
00425 contextMenu->insertItem ( "Activate", this, SLOT ( graphActivateNode() ) );
00426 contextMenu->insertSeparator ();
00427
00428
00429 contextMenu->insertItem ( "Save Node", this, SLOT ( graphSaveObject() ) );
00430 contextMenu->insertItem ( "Add Node", this, SLOT ( graphAddObject() ) );
00431 int index_menu = contextMenu->insertItem ( "Remove Node", this, SLOT ( graphRemoveObject() ) );
00432
00433
00434 if ( !isErasable ( node_clicked ) )
00435 contextMenu->setItemEnabled ( index_menu,false );
00436
00437 }
00438 contextMenu->insertItem ( "Modify", this, SLOT ( graphModify() ) );
00439 contextMenu->popup ( point, index );
00440
00441 }
00442
00443
00444
00445 void RealGUI::graphSaveObject()
00446 {
00447 bool isAnimated = startButton->isOn();
00448
00449 playpauseGUI ( false );
00450
00451 if ( node_clicked != NULL )
00452 {
00453 fileSaveAs(node_clicked);
00454 item_clicked = NULL;
00455 }
00456 playpauseGUI ( isAnimated );
00457 }
00458
00459 void RealGUI::graphAddObject()
00460 {
00461
00462 bool isAnimated = startButton->isOn();
00463
00464 playpauseGUI ( false );
00465
00466 if ( node_clicked != NULL )
00467 {
00468 dialog->show();
00469 dialog->raise();
00470
00471 item_clicked = NULL;
00472 }
00473 playpauseGUI ( isAnimated );
00474 }
00475
00476
00477 void RealGUI::graphRemoveObject()
00478 {
00479
00480 bool isAnimated = startButton->isOn();
00481
00482 playpauseGUI ( false );
00483 if ( node_clicked != NULL )
00484 {
00485 if ( node_clicked == getSimulation()->getContext() )
00486 {
00487
00488 GNode *groot = new GNode ( "Root" );
00489
00490 groot->setShowVisualModels ( 1 );
00491 groot->setShowCollisionModels ( 0 );
00492 groot->setShowBoundingCollisionModels ( 0 );
00493 groot->setShowBehaviorModels ( 0 );
00494 groot->setShowMappings ( 0 );
00495 groot->setShowMechanicalMappings ( 0 );
00496 groot->setShowForceFields ( 0 );
00497 groot->setShowInteractionForceFields ( 0 );
00498 groot->setShowWireFrame ( 0 );
00499 groot->setShowNormals ( 0 );
00500
00501
00502 viewer->setScene ( groot, viewer->getSceneFileName().c_str() );
00503 graphListener->removeChild ( NULL, node_clicked );
00504 graphListener->addChild ( NULL, groot );
00505 }
00506 else
00507 {
00508 node_clicked->getParent()->removeChild ( node_clicked );
00509 graphListener->removeChild ( NULL, node_clicked );
00510 list_object_removed.push_back ( node_clicked );
00511 }
00512
00513 viewer->resetView();
00514 viewer->getQWidget()->update();
00515 node_clicked = NULL;
00516 item_clicked = NULL;
00517 }
00518 playpauseGUI ( isAnimated );
00519
00520 graphCreateStats(viewer->getScene());
00521 }
00522
00523
00524 void RealGUI::graphModify()
00525 {
00526
00527 bool isAnimated = startButton->isOn();
00528
00529 playpauseGUI ( false );
00530 if ( item_clicked != NULL )
00531 {
00532 core::objectmodel::Base* node=NULL;
00533 for ( std::map<core::objectmodel::Base*, QListViewItem* >::iterator it = graphListener->items.begin() ; it != graphListener->items.end() ; ++ it )
00534 {
00535 if ( ( *it ).second == item_clicked )
00536 {
00537 node = ( *it ).first;
00538 break;
00539 }
00540 }
00541
00542
00543 current_Id_modifyDialog = node;
00544 std::map< void*, QDialog* >::iterator testWindow = map_modifyObjectWindow.find( current_Id_modifyDialog);
00545 if ( testWindow != map_modifyObjectWindow.end())
00546 {
00547
00548 (*testWindow).second->raise();
00549 playpauseGUI ( isAnimated );
00550 return;
00551 }
00552
00553
00554 ModifyObject *dialogModify = new ModifyObject ( current_Id_modifyDialog, node, item_clicked,this,item_clicked->text(0));
00555
00556 map_modifyObjectWindow.insert( std::make_pair(current_Id_modifyDialog, dialogModify));
00557
00558
00559 if ( dynamic_cast<Node *> ( node ) )
00560 map_modifyDialogOpened.insert ( std::make_pair ( current_Id_modifyDialog, node ) );
00561 else
00562 {
00563
00564 for ( std::map<core::objectmodel::Base*, QListViewItem* >::iterator it = graphListener->items.begin() ; it != graphListener->items.end() ; ++ it )
00565 {
00566 if ( ( *it ).second == item_clicked->parent() )
00567 {
00568 map_modifyDialogOpened.insert ( std::make_pair ( current_Id_modifyDialog, ( *it ).first ) );
00569 break;
00570 }
00571 }
00572 }
00573
00574 dialogModify->show();
00575 dialogModify->raise();
00576
00577 connect ( this, SIGNAL ( newScene() ), dialogModify, SLOT ( closeNow() ) );
00578 connect ( this, SIGNAL ( newStep() ), dialogModify, SLOT ( updateTables() ) );
00579 item_clicked = NULL;
00580 }
00581 playpauseGUI ( isAnimated );
00582 }
00583
00584
00585
00586 void RealGUI::graphDesactivateNode()
00587 {
00588 item_clicked->setText(0, QString("Desactivated ") + item_clicked->text(0));
00589 item_clicked->setOpen(false);
00590
00591 std::string pixmap_filename("textures/media-record.png");
00592 if ( sofa::helper::system::DataRepository.findFile ( pixmap_filename ) )
00593 pixmap_filename = sofa::helper::system::DataRepository.getFile ( pixmap_filename );
00594
00595 item_clicked->setPixmap(0,QPixmap(QImage(pixmap_filename.c_str())));
00596 node_clicked->setActive(false);
00597 viewer->getQWidget()->update();
00598 node_clicked->reinit();
00599
00600 graphCreateStats(viewer->getScene());
00601 }
00602
00603 void RealGUI::graphActivateNode()
00604 {
00605 QString desact_text = item_clicked->text(0);
00606 desact_text.remove(QString("Desactivated "), true);
00607 item_clicked->setText(0,desact_text);
00608 QPixmap *p = getPixmap(node_clicked);
00609 item_clicked->setPixmap(0,*p);
00610 node_clicked->setActive(true);
00611 viewer->getQWidget()->update();
00612 node_clicked->init();
00613
00614 graphCreateStats(viewer->getScene());
00615 }
00616
00617
00618
00619 void RealGUI::currentTabChanged ( QWidget* widget )
00620 {
00621 if ( widget == currentTab ) return;
00622 GNode* groot = viewer==NULL ? NULL : viewer->getScene();
00623 if ( widget == TabGraph )
00624 {
00625 if ( groot && graphListener )
00626 {
00627
00628 graphListener->unfreeze ( groot );
00629 }
00630 }
00631 else if ( currentTab == TabGraph )
00632 {
00633 if ( groot && graphListener )
00634 {
00635
00636 graphListener->freeze ( groot );
00637 }
00638 }
00639 else if (widget == TabStats)
00640 graphCreateStats(viewer->getScene());
00641
00642 currentTab = widget;
00643 }
00644
00645
00646
00647
00648
00649 bool RealGUI::isErasable ( core::objectmodel::Base* element )
00650 {
00651 std::map< void*, core::objectmodel::Base*>::iterator it;
00652 for (it = map_modifyDialogOpened.begin(); it != map_modifyDialogOpened.end();it++)
00653 {
00654 if (it->second == element) return false;
00655 }
00656
00657 std::map< core::objectmodel::Base*, QListViewItem*>::iterator it_item;
00658 it_item = graphListener->items.find(element);
00659
00660 QListViewItem *child = it_item->second->firstChild();
00661 while (child != NULL)
00662 {
00663 for (it_item = graphListener->items.begin(); it_item != graphListener->items.end();it_item++)
00664 {
00665 if (it_item->second == child)
00666 {
00667 if (!isErasable(it_item->first)) return false;
00668 break;
00669 }
00670 }
00671 child = child->nextSibling();
00672 }
00673 return true;
00674 }
00675
00676
00677
00678 }
00679
00680 }
00681
00682 }