<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program 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 General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: <EMAIL>                             *
******************************************************************************/
#include "RealGUI.h"
#include "ImageQt.h"
#ifndef SOFA_GUI_QT_NO_RECORDER
#include "sofa/gui/qt/QSofaRecorder.h"
#endif
#include "sofa/gui/qt/QSofaStatWidget.h"
#include "sofa/gui/qt/GenGraphForm.h"
#include "sofa/gui/qt/QSofaListView.h"
#include <algorithm>

#include <sofa/simulation/common/PropagateEventVisitor.h>
#include <sofa/component/visualmodel/VisualModelImpl.h>
#include <sofa/simulation/common/Visitor.h>
#include <sofa/simulation/common/xml/XML.h>
#include <sofa/simulation/common/InitVisitor.h>
#include <sofa/simulation/common/UpdateContextVisitor.h>
#include <sofa/simulation/common/DeleteVisitor.h>
#include <sofa/simulation/common/DeactivatedNodeVisitor.h>
#include <sofa/component/visualmodel/VisualStyle.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/helper/AdvancedTimer.h>

#include <sofa/core/visual/VisualParams.h>

#ifdef SOFA_QT4
#include <QWidget>
#include <QDockWidget>
#include <QStackedWidget>
#include <QLayout>
#include <Q3ListViewItem>
#include <Q3ListView>
#include <QStatusBar>
#include <QRadioButton>
#include <QCheckBox>
#include <QSplitter>
#include <Q3TextEdit>
#include <QCursor>
#include <QAction>
#include <QMessageBox>
#include <QTabWidget>
#include <QToolTip>
#include <QButtonGroup>
#include <QRadioButton>
#include <QInputDialog>
#include <Q3DockWindow>
#include <Q3DockArea>
#else
#include <qwidget.h>
#include <qwidgetstack.h>
#include <qlayout.h>
#include <qlistview.h>
#include <qstatusbar.h>
#include <qheader.h>
#include <qimage.h>
#include <qsplitter.h>
#include <qtextedit.h>
#include <qcursor.h>
#include <qapplication.h>
#include <qaction.h>
#include <qmessagebox.h>
#include <qtabwidget.h>
#include <qtooltip.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qinputdialog.h>
#include <qmime.h>
#include <qdockwindow.h>
#include <qdockarea.h>
#endif



namespace sofa
{

namespace gui
{

namespace qt
{



SOFA_LINK_CLASS(ImageQt);


#ifdef SOFA_QT4
typedef Q3ListView QListView;
typedef Q3DockWindow QDockWindow;
typedef QStackedWidget QWidgetStack;
typedef Q3TextEdit QTextEdit;
#endif


using sofa::core::objectmodel::BaseObject;
using namespace sofa::helper::system::thread;
using namespace sofa::simulation;
using namespace sofa::core::visual;


///////////////////////////////////////////////////////////
//////////////////// SofaGUI Interface ////////////////////
///////////////////////////////////////////////////////////
extern QApplication* application; // = NULL;
extern RealGUI* gui;

#ifdef SOFA_QT4
/// Custom QApplication class handling FileOpen events for MacOS
class QSOFAApplication : public QApplication
{
public:
    QSOFAApplication(int &argc, char ** argv)
        : QApplication(argc,argv)
    {
    }

protected:
    bool event(QEvent *event)
    {
        switch (event->type())
        {
        case QEvent::FileOpen:
        {
            std::string filename = static_cast<QFileOpenEvent *>(event)->file().ascii();
            if (filename != std::string(static_cast<RealGUI*>(mainWidget())->windowFilePath().ascii()))
                static_cast<RealGUI*>(mainWidget())->fileOpen(static_cast<QFileOpenEvent *>(event)->file().ascii());
            return true;
        }
        default:
            return QApplication::event(event);
        }
    }
};
#else
typedef QApplication QSOFAApplication;
#endif

RealGUI* gui = NULL;
QApplication* application = NULL;

const char* progname="";


int RealGUI::InitGUI ( const char* /*name*/, const std::vector<std::string>& /* options */ )
{
    if ( ImageQt::Init() )
    {
        return 0;
    }
    else
    {
        return 1;
    }
}


SofaGUI* RealGUI::CreateGUI ( const char* name, const std::vector<std::string>& options, sofa::simulation::Node::SPtr root, const char* filename )
{
    CreateApplication();

    // create interface
    gui = new RealGUI ( name, options );
    if ( root )
    {
        gui->setScene ( root, filename );
        gui->setWindowFilePath(QString(filename));
    }

    InitApplication(gui);

    return gui;
}

void RealGUI::CreateApplication(int /*_argc*/, char** /*_argv*/)
{
    int  *argc = new int;
    char **argv=new char*[2];
    *argc = 1;
    argv[0] = strdup ( SofaGUI::GetProgramName() );
    argv[1]=NULL;
    application = new QSOFAApplication ( *argc,argv );
}

void RealGUI::InitApplication( RealGUI* _gui)
{
    application->setMainWidget ( _gui );

    QString pathIcon=(sofa::helper::system::DataRepository.getFirstPath() + std::string( "/icons/SOFA.png" )).c_str();
#ifdef SOFA_QT4
    application->setWindowIcon(QIcon(pathIcon));
#else
    gui->setIcon(QPixmap(pathIcon));
#endif

    // show the gui
    _gui->show();

}

int RealGUI::mainLoop()
{
    int retcode;
    if (windowFilePath().isNull())
    {
        retcode = application->exec();
    }
    else
    {
        const std::string &filename=windowFilePath().ascii();
        const std::string &extension=sofa::helper::system::SetDirectory::GetExtension(filename.c_str());
        if (extension == "simu") fileOpenSimu(filename);
        retcode = application->exec();
    }
    return exitApplication(retcode);
}

void RealGUI::redraw()
{
    emit newStep();
}

int RealGUI::closeGUI()
{

    delete this;
    return 0;
}

Node* RealGUI::currentSimulation()
{
    return viewer->getScene();
}

RealGUI::RealGUI ( const char* viewername, const std::vector<std::string>& options )
    : viewerName ( viewername ),
#ifdef SOFA_GUI_INTERACTION
      interactionButton( NULL ),
#endif
      viewer ( NULL ),
      simulationGraph(NULL),
      mCreateViewersOpt(false),
      m_dumpState(false),
      m_dumpStateStream(NULL),
      m_exportGnuplot(false),
      _animationOBJ(false),
      _animationOBJcounter(0),
      m_displayComputationTime(false),
      m_fullScreen(false),

      currentTab ( NULL ),
#ifndef SOFA_GUI_QT_NO_RECORDER
      recorder(NULL),
#else
      fpsLabel(NULL),
      timeLabel(NULL),
#endif
      statWidget(NULL),
      timerStep(NULL),
      backgroundImage(NULL),
      left_stack(NULL),
      pluginManager_dialog(NULL),
      recentlyOpenedFilesManager("config/Sofa.ini"),
      saveReloadFile(false),
      frameCounter(0),
#ifdef SOFA_GUI_INTERACTION
      m_interactionActived(false),
#endif
      displayFlag(NULL),
#ifdef SOFA_DUMP_VISITOR_INFO
      windowTraceVisitor(NULL),
      handleTraceVisitor(NULL),
#endif
      descriptionScene(NULL),
      htmlPage(NULL),
      animationState(false)
{

    // parse the options
    mCreateViewersOpt = true;
    for (unsigned int i=0; i<options.size(); ++i)
    {
        if (options[i] == "noViewers")
        {
            mCreateViewersOpt = false;
            std::cerr<<"=========================== No Viewers ====================="<<std::endl;
        }
    }

#ifdef SOFA_GUI_INTERACTION
    interactionButton = new QPushButton(optionTabs);
    interactionButton->setObjectName(QString::fromUtf8("interactionButton"));
    interactionButton->setCheckable(true);
    interactionButton->setStyleSheet("background-color: cyan;");

    gridLayout->addWidget(interactionButton, 3, 0, 1, 1);
    gridLayout->removeWidget(screenshotButton);
    gridLayout->addWidget(screenshotButton, 3, 1, 1,1);

    interactionButton->setText(QApplication::translate("GUI", "&Interaction", 0, QApplication::UnicodeUTF8));
    interactionButton->setShortcut(QApplication::translate("GUI", "Alt+i", 0, QApplication::UnicodeUTF8));
#ifndef QT_NO_TOOLTIP
    interactionButton->setProperty("toolTip", QVariant(QApplication::translate("GUI", "Start interaction mode", 0, QApplication::UnicodeUTF8)));
#endif // QT_NO_TOOLTIP	
#endif

    connect(this, SIGNAL(quit()), this, SLOT(fileExit()));

    //--------
    pluginManager_dialog = new SofaPluginManager();
    pluginManager_dialog->hide();

    this->connect( pluginManager_dialog, SIGNAL( libraryAdded() ),  this, SLOT( updateViewerList() ));
    this->connect( pluginManager_dialog, SIGNAL( libraryRemoved() ),  this, SLOT( updateViewerList() ));

    informationOnPickCallBack = InformationOnPickCallBack(this);

#ifdef SOFA_QT4
    fileMenu->removeAction(Action);
#endif
    //Configure Recently Opened Menu
    const int indexRecentlyOpened=fileMenu->count()-2;
    QMenu *recentMenu = recentlyOpenedFilesManager.createWidget(this);
    fileMenu->insertItem(QPixmap(),recentMenu,indexRecentlyOpened,indexRecentlyOpened);
    connect(recentMenu, SIGNAL(activated(int)), this, SLOT(fileRecentlyOpened(int)));

    left_stack = new QWidgetStack ( splitter2 );
    connect ( startButton, SIGNAL ( toggled ( bool ) ), this , SLOT ( playpauseGUI ( bool ) ) );
#ifdef SOFA_GUI_INTERACTION
    connect ( interactionButton, SIGNAL ( toggled ( bool ) ), this , SLOT ( interactionGUI ( bool ) ) );
#endif
    connect ( ResetSceneButton, SIGNAL ( clicked() ), this, SLOT ( resetScene() ) );
    connect ( dtEdit, SIGNAL ( textChanged ( const QString& ) ), this, SLOT ( setDt ( const QString& ) ) );
    connect ( stepButton, SIGNAL ( clicked() ), this, SLOT ( step() ) );
    connect ( dumpStateCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( dumpState ( bool ) ) );
    connect ( displayComputationTimeCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( displayComputationTime ( bool ) ) );
    connect ( exportGnuplotFilesCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportGnuplot ( bool ) ) );
#ifdef SOFA_DUMP_VISITOR_INFO
    connect ( exportVisitorCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportVisitor ( bool ) ) );
#endif


    pathDumpVisitor = sofa::helper::system::SetDirectory::GetParentDir(sofa::helper::system::DataRepository.getFirstPath().c_str()) + std::string( "/dumpVisitor.xml" );

    connect ( tabs, SIGNAL ( currentChanged ( QWidget* ) ), this, SLOT ( currentTabChanged ( QWidget* ) ) );

    //Create a Dock Window to receive the Sofa Recorder
#ifndef SOFA_GUI_QT_NO_RECORDER
    QDockWindow *dockRecorder=new QDockWindow(this);
    dockRecorder->setResizeEnabled(true);
    this->moveDockWindow( dockRecorder, Qt::DockBottom);
    this->leftDock() ->setAcceptDockWindow(dockRecorder,false);
    this->rightDock()->setAcceptDockWindow(dockRecorder,false);

    recorder = new QSofaRecorder(dockRecorder);
    dockRecorder->setWidget(recorder);

    connect(startButton, SIGNAL(  toggled ( bool ) ), recorder, SLOT( TimerStart(bool) ) );
#else
    //Status Bar Configuration
    fpsLabel = new QLabel ( "9999.9 FPS", statusBar() );
    fpsLabel->setMinimumSize ( fpsLabel->sizeHint() );
    fpsLabel->clear();

    timeLabel = new QLabel ( "Time: 999.9999 s", statusBar() );
    timeLabel->setMinimumSize ( timeLabel->sizeHint() );
    timeLabel->clear();
    statusBar()->addWidget ( fpsLabel );
    statusBar()->addWidget ( timeLabel );
#endif

    statWidget = new QSofaStatWidget(TabStats);
    TabStats->layout()->add(statWidget);

    simulationGraph = new QSofaListView(SIMULATION,TabGraph,"SimuGraph");
    if (mCreateViewersOpt) createViewers(viewername);

    currentTabChanged ( tabs->currentPage() );

    //ADD GUI for Background
    //------------------------------------------------------------------------
    //Informations
    QWidget *colour = new QWidget(TabPage);
    QHBoxLayout *colourLayout = new QHBoxLayout(colour);
    colourLayout->addWidget(new QLabel(QString("Colour "),colour));

    for (unsigned int i=0; i<3; ++i)
    {
        std::ostringstream s;
        s<<"background" <<i;
        background[i] = new WDoubleLineEdit(colour,s.str().c_str());
        background[i]->setMinValue( 0.0f);
        background[i]->setMaxValue( 1.0f);
        background[i]->setValue( 1.0f);

        colourLayout->addWidget(background[i]);
        connect( background[i], SIGNAL( returnPressed() ), this, SLOT( updateBackgroundColour() ) );
    }

    QWidget *image = new QWidget(TabPage);
    QHBoxLayout *imageLayout = new QHBoxLayout(image);
    imageLayout->addWidget(new QLabel(QString("Image "),image));

    backgroundImage = new QLineEdit(image,"backgroundImage");
    if (mCreateViewersOpt)
        backgroundImage->setText( QString(viewer->getBackgroundImage().c_str()) );
    else
        backgroundImage->setText( QString() ); //by default if we havn't yet a viewer
    imageLayout->addWidget(backgroundImage);
    connect( backgroundImage, SIGNAL( returnPressed() ), this, SLOT( updateBackgroundImage() ) );


    ((QVBoxLayout*)(TabPage->layout()))->insertWidget(1,colour);
    ((QVBoxLayout*)(TabPage->layout()))->insertWidget(2,image);

    //---------------------------------------------------------------------------------------------------
#ifdef SOFA_PML
    pmlreader = NULL;
    lmlreader = NULL;
#endif

    ((QVBoxLayout*)TabGraph->layout())->addWidget(simulationGraph);
    connect ( ExportGraphButton, SIGNAL ( clicked() ), simulationGraph, SLOT ( Export() ) );
#ifdef SOFA_QT4
    tabs->removeTab(tabs->indexOf(TabVisualGraph));
#endif


#ifndef SOFA_DUMP_VISITOR_INFO
    //Remove option to see visitor trace
    this->exportVisitorCheckbox->hide();
#else
    //Main window containing a QListView only
    windowTraceVisitor = new WindowVisitor;
    windowTraceVisitor->graphView->setSorting(-1);
    windowTraceVisitor->hide();
    connect(windowTraceVisitor, SIGNAL(WindowVisitorClosed(bool)), this->exportVisitorCheckbox, SLOT(setChecked(bool)));
    handleTraceVisitor = new GraphVisitor(windowTraceVisitor);
#endif
    //--------
    descriptionScene = new QDialog(this);
    descriptionScene->resize(400,400);
    QVBoxLayout *descriptionLayout = new QVBoxLayout(descriptionScene);
    htmlPage = new QTextBrowser(descriptionScene);
    descriptionLayout->addWidget(htmlPage);
#ifdef SOFA_QT4
    connect(htmlPage, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(changeHtmlPage(const QUrl&)));
#else
    // QMimeSourceFactory::defaultFactory()->setExtensionType("html", "text/utf8");
    htmlPage->mimeSourceFactory()->setExtensionType("html", "text/utf8");;
    connect(htmlPage, SIGNAL(sourceChanged(const QString&)), this, SLOT(changeHtmlPage(const QString&)));
#endif
    SofaMouseManager::getInstance()->hide();
    SofaVideoRecorderManager::getInstance()->hide();

    //Center the application
    const QRect screen = QApplication::desktop()->availableGeometry(QApplication::desktop()->primaryScreen());
    this->move(  ( screen.width()- this->width()  ) / 2,  ( screen.height() - this->height()) / 2  );

    connect(simulationGraph, SIGNAL( RootNodeChanged(sofa::simulation::Node*, const char*) ), this, SLOT ( NewRootNode(sofa::simulation::Node* , const char*) ) );
    connect(simulationGraph, SIGNAL( NodeRemoved() ), this, SLOT( Update() ) );
    connect(simulationGraph, SIGNAL( Lock(bool) ), this, SLOT( LockAnimation(bool) ) );
    connect(simulationGraph, SIGNAL( RequestSaving(sofa::simulation::Node*) ), this, SLOT( fileSaveAs(sofa::simulation::Node*) ) );
    connect(simulationGraph, SIGNAL( RequestExportOBJ(sofa::simulation::Node*, bool) ), this, SLOT( exportOBJ(sofa::simulation::Node*, bool) ) );
    connect(simulationGraph, SIGNAL( RequestActivation(sofa::simulation::Node*, bool) ), this, SLOT( ActivateNode(sofa::simulation::Node*, bool) ) );
    connect(simulationGraph, SIGNAL( Updated() ), this, SLOT( redraw() ) );
    connect(simulationGraph, SIGNAL( NodeAdded() ), this, SLOT( Update() ) );
    connect(this, SIGNAL( newScene() ), simulationGraph, SLOT( CloseAllDialogs() ) );
    connect(this, SIGNAL( newStep() ), simulationGraph, SLOT( UpdateOpenedDialogs() ) );

#ifndef SOFA_GUI_QT_NO_RECORDER
    if (recorder)
        connect( recorder, SIGNAL( RecordSimulation(bool) ), startButton, SLOT( setOn(bool) ) );
    if (recorder && mCreateViewersOpt)
        connect( recorder, SIGNAL( NewTime() ), viewer->getQWidget(), SLOT( update() ) );
#endif
    timerStep = new QTimer(this);
    connect ( timerStep, SIGNAL ( timeout() ), this, SLOT ( step() ) );

    animationState = false;

#ifdef SOFA_GUI_INTERACTION
    m_interactionActived = false;
    if(mCreateViewersOpt)
        viewer->getQWidget()->installEventFilter(this);
#endif
}

void RealGUI::fileRecentlyOpened(int id)
{
    fileOpen(recentlyOpenedFilesManager.getFilename((unsigned int)id));
}

void RealGUI::setPixmap(std::string pixmap_filename, QPushButton* b)
{
    if ( sofa::helper::system::DataRepository.findFile ( pixmap_filename ) )
        pixmap_filename = sofa::helper::system::DataRepository.getFile ( pixmap_filename );

#ifdef SOFA_QT4
    b->setPixmap(QPixmap(QPixmap::fromImage(QImage(pixmap_filename.c_str()))));
#else
    b->setPixmap(QPixmap(QImage(pixmap_filename.c_str())));
#endif
}

RealGUI::~RealGUI()
{
    viewer->setScene(NULL); // has been deleted
#ifdef SOFA_PML
    if ( pmlreader )
    {
        delete pmlreader;
        pmlreader = NULL;
    }
    if ( lmlreader )
    {
        delete lmlreader;
        lmlreader = NULL;
    }
#endif
    if( displayFlag != NULL )
    {
        delete displayFlag;
    }
#ifdef SOFA_DUMP_VISITOR_INFO
    delete windowTraceVisitor;
    delete handleTraceVisitor;
#endif
    removeViewer();
}

void RealGUI::init()
{
    frameCounter = 0;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;

    gnuplot_directory = "";
    m_fullScreen = false;
}

void RealGUI::removeViewer()
{
    if(viewer->isThreaded())
        viewer->stopViewerThread();

    if(mCreateViewersOpt)
    {
        delete viewer;
        viewer = NULL;
    }
}

//createViewers
void RealGUI::createViewers(const char* viewerName)
{
    viewer::SofaViewerArgument arg;
    arg.name = "viewer";
    arg.parent = left_stack;

    if( viewer != NULL )
        removeViewer();

    viewerMap.clear();
    if ( viewerName[0] )
    {
        helper::vector< helper::SofaViewerFactory::Key > keys;
        helper::SofaViewerFactory::getInstance()->uniqueKeys(std::back_inserter(keys));
        helper::vector< helper::SofaViewerFactory::Key >::const_iterator iter;

        for ( iter = keys.begin(); iter != keys.end(); ++iter )
        {
            QAction* action = new QAction(this);
            action->setText( helper::SofaViewerFactory::getInstance()->getViewerName(*iter) );
            action->setMenuText(  helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*iter) );
            action->setToggleAction(true);
            action->addTo(View);
            viewerMap[*iter] = action;
            action->setEnabled(true);
            connect(action, SIGNAL( activated() ), this, SLOT( changeViewer() ) );

            if( strcmp(iter->c_str(), viewerName )== 0 )
            {
                viewer = helper::SofaViewerFactory::CreateObject(*iter, arg);
                action->setOn(true);
            }
            else
            {
                action->setOn(false);
            }
        }
    }

    if( viewer == NULL )
    {
        std::cerr << "ERROR(QtGUI): unknown or disabled viewer name "<<viewerName<<std::endl;
        application->exit();
    }
    if(viewer->isEmbedded())
        left_stack->addWidget ( viewer->getQWidget() );
    initViewer();
}

//initViewer
void RealGUI::initViewer()
{
    if(viewer == NULL)
    {
        std::cerr<<"ERROR when initViewer, the viewer is NULL"<<std::endl;
        return;
    }
    frameCounter = 0;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;
    gnuplot_directory = "";

    if(viewer->isEmbedded())
    {
#ifdef SOFA_QT4
        left_stack->setCurrentWidget ( viewer->getQWidget() );
        viewer->getQWidget()->setFocusPolicy ( Qt::StrongFocus );
#else
        int id_viewer = left_stack->addWidget ( viewer->getQWidget() );
        left_stack->raiseWidget ( id_viewer );
        viewer->getQWidget()->setFocusPolicy ( QWidget::StrongFocus );
        viewer->getQWidget()->setCursor ( QCursor ( 2 ) );
#endif
        viewer->getQWidget()->setSizePolicy ( QSizePolicy ( ( QSizePolicy::SizeType ) 7, ( QSizePolicy::SizeType ) 7, 100, 1, viewer->getQWidget()->sizePolicy().hasHeightForWidth() ) );
        viewer->getQWidget()->setMinimumSize ( QSize ( 0, 0 ) );
        viewer->getQWidget()->setMouseTracking ( TRUE );
    }
    viewer->configureViewerTab(tabs);

    connect ( ResetViewButton, SIGNAL ( clicked() ), this, SLOT ( resetView() ) );
    connect ( SaveViewButton, SIGNAL ( clicked() ), this, SLOT ( saveView() ) );
    connect ( screenshotButton, SIGNAL ( clicked() ), this, SLOT ( screenshot() ) );
    connect ( sizeW, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeW ( int ) ) );
    connect ( sizeH, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeH ( int ) ) );
    if(viewer->isEmbedded())
    {
        connect ( viewer->getQWidget(), SIGNAL ( resizeW ( int ) ), sizeW, SLOT ( setValue ( int ) ) );
        connect ( viewer->getQWidget(), SIGNAL ( resizeH ( int ) ), sizeH, SLOT ( setValue ( int ) ) );
        connect ( viewer->getQWidget(), SIGNAL ( quit (  ) ), this, SLOT ( fileExit (  ) ) );
        connect(simulationGraph, SIGNAL(focusChanged(sofa::core::objectmodel::BaseObject*)),
                viewer->getQWidget(), SLOT(fitObjectBBox(sofa::core::objectmodel::BaseObject*)) );
        connect(simulationGraph, SIGNAL( focusChanged(sofa::core::objectmodel::BaseNode*) ),
                viewer->getQWidget(), SLOT( fitNodeBBox(sofa::core::objectmodel::BaseNode*) ) );
    }

    // splitter2 separates horizontally the OptionTab widget and the viewer widget
    QSplitter *splitter_ptr = dynamic_cast<QSplitter *> ( splitter2 );
    if(viewer->isEmbedded())
    {
        splitter_ptr->moveToLast ( left_stack ); // Use addWidget(widget) instead.
        splitter_ptr->setOpaqueResize ( false );
#ifdef SOFA_QT4
        // rescale factor for the space occuped by the widget index
        splitter_ptr->setStretchFactor( 0, 0); // OptionTab
        splitter_ptr->setStretchFactor( 1, 10); // Viewer
        QList<int> list;
#else
        QValueList<int> list;
#endif
        list.push_back ( 250 ); // OptionTab
        list.push_back ( 640 ); // Viewer
        splitter_ptr->setSizes ( list );
    }
    else
    {
        splitter_ptr->setOpaqueResize ( false );
#ifdef SOFA_QT4
        // rescale factor for the space occuped by the widget index
        splitter_ptr->setStretchFactor( 0, 0); // OptionTab
        splitter_ptr->setStretchFactor( 1, 0); // Viewer
        QList<int> list;
#else
        QValueList<int> list;
#endif
        list.push_back ( 250 ); // OptionTab
        list.push_back ( 0 );  // Viewer
        splitter_ptr->setSizes ( list );
    }

    // setGUI
    textEdit1->setText ( viewer->helpString() );
    if(viewer->isEmbedded())
        connect ( this, SIGNAL( newStep()), viewer->getQWidget(), SLOT( update()));

    if(viewer->isEmbedded())
    {
        viewer->getQWidget()->setFocus();
        viewer->getQWidget()->show();
        updateViewerParameters();
    }

    SofaMouseManager::getInstance()->setPickHandler(viewer->getPickHandler());
    if( !viewer->isThreaded() ) // How to pass info from viewer thread to gui application thread?
        viewer->getPickHandler()->addCallBack(&informationOnPickCallBack );

    guiName=viewerName;
}

//changeViewer
void RealGUI::changeViewer()
{
    QObject* obj = const_cast<QObject*>( QObject::sender() );
    if( !obj) return;

    QAction* action = static_cast<QAction*>(obj);

    action->setOn(true);
    std::map< helper::SofaViewerFactory::Key, QAction*  >::const_iterator iter_map;
    for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end() ; ++iter_map )
    {
        if ( (*iter_map).second == action )
        {
            // Cleanup previous viewer
            if ( viewer->getScene() !=NULL )
            {
                viewer->getPickHandler()->unload();
                // Unload viewer components before delete the whole scene
                viewer->unloadSceneView();
                simulation::getSimulation()->unload ( viewer->getScene() );
                //delete viewer->getScene() ;
                viewer->setScene(NULL);
            }
            viewer->removeViewerTab(tabs);
            if(viewer->isEmbedded())
                left_stack->removeWidget(viewer->getQWidget() );

            removeViewer();

            // Need for the next creation
            viewer::SofaViewerArgument arg;
            arg.name = "viewer";
            arg.parent = left_stack; // Set it by default but in case of standalone viewer, we don't use it in tis constructor

            // Create new viewer
            viewer =  helper::SofaViewerFactory::CreateObject( (*iter_map).first, arg);

            if(viewer->isEmbedded())
                left_stack->addWidget( viewer->getQWidget() );

            initViewer();
        }
        else
        {
            (*iter_map).second->setOn(false);
        }
    }

    // Reload the scene
    std::string filename(this->windowFilePath().ascii());
    fileOpen ( filename.c_str() ); // keep the current display flags
}

//updateViewerList
void RealGUI::updateViewerList()
{
    helper::vector< helper::SofaViewerFactory::Key > currentKeys;
    std::map< helper::SofaViewerFactory::Key, QAction*>::const_iterator iter_map;
    for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end() ; ++iter_map )
    {
        currentKeys.push_back((*iter_map).first);
    }
    std::sort(currentKeys.begin(),currentKeys.end());
    helper::vector< helper::SofaViewerFactory::Key > updatedKeys;
    helper::SofaViewerFactory::getInstance()->uniqueKeys(std::back_inserter(updatedKeys));
    std::sort(updatedKeys.begin(),updatedKeys.end());

    helper::vector< helper::SofaViewerFactory::Key > diffKeys;

    std::set_symmetric_difference(currentKeys.begin(),currentKeys.end(),updatedKeys.begin(),updatedKeys.end()
            ,std::back_inserter(diffKeys));

    helper::vector< helper::SofaViewerFactory::Key >::const_iterator it;
    for( it = diffKeys.begin(); it != diffKeys.end(); ++it)
    {

        std::map< helper::SofaViewerFactory::Key, QAction* >::iterator itViewerMap;

        if( (itViewerMap = viewerMap.find(*it)) != viewerMap.end() )
        {
            if( (*itViewerMap).second->isOn() )
            {
                if ( viewer->getScene() !=NULL )
                {
                    viewer->getPickHandler()->unload();
                    viewer->unloadSceneView();
                    simulation::getSimulation()->unload ( viewer->getScene() );
                    //delete viewer->getScene() ;
                    viewer->setScene(NULL);
                }

                viewer->removeViewerTab(tabs);

                if(viewer->isEmbedded())
                    left_stack->removeWidget(viewer->getQWidget() );

                removeViewer();
            }

            (*itViewerMap).second->removeFrom(View);
            viewerMap.erase(itViewerMap);
        }
        else
        {
            QAction* action = new QAction(this);
            action->setText( helper::SofaViewerFactory::getInstance()->getViewerName(*it) );
            action->setMenuText(  helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*it) );
            action->setToggleAction(true);
            action->addTo(View);
            viewerMap[*it] = action;
            action->setEnabled(true);
            connect(action, SIGNAL( activated() ), this, SLOT( changeViewer() ) );
        }
    }

    if( viewer == NULL )
    {
        if(!viewerMap.empty())
        {
            viewer::SofaViewerArgument arg;
            arg.name = "viewer";
            arg.parent = left_stack;
            /* change viewer */
            viewer =  helper::SofaViewerFactory::CreateObject( viewerMap.begin()->first, arg);

            if(viewer->isEmbedded())
                left_stack->addWidget( viewer->getQWidget() );

            initViewer();
        }
    }
}

//fileOpen
void RealGUI::fileOpen ( std::string filename, bool temporaryFile )
{
    //std::cout << "GUI: fileOpen " << filename << " ( was " <<   std::string(this->windowFilePath().ascii()) << " )" << std::endl;
    const std::string &extension=sofa::helper::system::SetDirectory::GetExtension(filename.c_str());
    if (extension == "simu")
    {
        return fileOpenSimu(filename);
    }

    startButton->setOn(false);
    descriptionScene->hide();
    htmlPage->clear();

    if ( sofa::helper::system::DataRepository.findFile (filename) )
        filename = sofa::helper::system::DataRepository.getFile ( filename );
    else
        return;
    startDumpVisitor();

    frameCounter = 0;
    sofa::simulation::xml::numDefault = 0;

    update();
    //Hide all the dialogs to modify the graph
    emit ( newScene() );

    if ( viewer->getScene() !=NULL )
    {
        viewer->getPickHandler()->reset();//activateRay(false);
        viewer->getPickHandler()->unload();

        // Unload viewer components before delete the whole scene
        viewer->unloadSceneView();
        simulation::getSimulation()->unload ( viewer->getScene() );
    }
    //Clear the list of modified dialog opened

    // Load the scene
    simulation::Node::SPtr root = simulation::getSimulation()->load ( filename.c_str() );
    simulation::getSimulation()->init ( root.get() );

    if ( root == NULL )
    {
        qFatal ( "Failed to load %s",filename.c_str() );
        stopDumpVisitor();
        return;
    }
    this->setWindowFilePath(filename.c_str());
    setScene ( root, filename.c_str(), temporaryFile );

    configureGUI(root.get());

    setExportGnuplot(exportGnuplotFilesCheckbox->isChecked());
//  displayComputationTime(m_displayComputationTime);  // (FF) This can be set outside of the GUI and should not be changed implicitly by the GUI
    stopDumpVisitor();<commit_msg>r12701/sofa-dev : RealGUI.cpp : the viewer doesn't know anymore the sofa root just beforeload a new scene.<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program 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 General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: <EMAIL>                             *
******************************************************************************/
#include "RealGUI.h"
#include "ImageQt.h"
#ifndef SOFA_GUI_QT_NO_RECORDER
#include "sofa/gui/qt/QSofaRecorder.h"
#endif
#include "sofa/gui/qt/QSofaStatWidget.h"
#include "sofa/gui/qt/GenGraphForm.h"
#include "sofa/gui/qt/QSofaListView.h"
#include <algorithm>

#include <sofa/simulation/common/PropagateEventVisitor.h>
#include <sofa/component/visualmodel/VisualModelImpl.h>
#include <sofa/simulation/common/Visitor.h>
#include <sofa/simulation/common/xml/XML.h>
#include <sofa/simulation/common/InitVisitor.h>
#include <sofa/simulation/common/UpdateContextVisitor.h>
#include <sofa/simulation/common/DeleteVisitor.h>
#include <sofa/simulation/common/DeactivatedNodeVisitor.h>
#include <sofa/component/visualmodel/VisualStyle.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/helper/AdvancedTimer.h>

#include <sofa/core/visual/VisualParams.h>

#ifdef SOFA_QT4
#include <QWidget>
#include <QDockWidget>
#include <QStackedWidget>
#include <QLayout>
#include <Q3ListViewItem>
#include <Q3ListView>
#include <QStatusBar>
#include <QRadioButton>
#include <QCheckBox>
#include <QSplitter>
#include <Q3TextEdit>
#include <QCursor>
#include <QAction>
#include <QMessageBox>
#include <QTabWidget>
#include <QToolTip>
#include <QButtonGroup>
#include <QRadioButton>
#include <QInputDialog>
#include <Q3DockWindow>
#include <Q3DockArea>
#else
#include <qwidget.h>
#include <qwidgetstack.h>
#include <qlayout.h>
#include <qlistview.h>
#include <qstatusbar.h>
#include <qheader.h>
#include <qimage.h>
#include <qsplitter.h>
#include <qtextedit.h>
#include <qcursor.h>
#include <qapplication.h>
#include <qaction.h>
#include <qmessagebox.h>
#include <qtabwidget.h>
#include <qtooltip.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qinputdialog.h>
#include <qmime.h>
#include <qdockwindow.h>
#include <qdockarea.h>
#endif



namespace sofa
{

namespace gui
{

namespace qt
{



SOFA_LINK_CLASS(ImageQt);


#ifdef SOFA_QT4
typedef Q3ListView QListView;
typedef Q3DockWindow QDockWindow;
typedef QStackedWidget QWidgetStack;
typedef Q3TextEdit QTextEdit;
#endif


using sofa::core::objectmodel::BaseObject;
using namespace sofa::helper::system::thread;
using namespace sofa::simulation;
using namespace sofa::core::visual;


///////////////////////////////////////////////////////////
//////////////////// SofaGUI Interface ////////////////////
///////////////////////////////////////////////////////////
extern QApplication* application; // = NULL;
extern RealGUI* gui;

#ifdef SOFA_QT4
/// Custom QApplication class handling FileOpen events for MacOS
class QSOFAApplication : public QApplication
{
public:
    QSOFAApplication(int &argc, char ** argv)
        : QApplication(argc,argv)
    {
    }

protected:
    bool event(QEvent *event)
    {
        switch (event->type())
        {
        case QEvent::FileOpen:
        {
            std::string filename = static_cast<QFileOpenEvent *>(event)->file().ascii();
            if (filename != std::string(static_cast<RealGUI*>(mainWidget())->windowFilePath().ascii()))
                static_cast<RealGUI*>(mainWidget())->fileOpen(static_cast<QFileOpenEvent *>(event)->file().ascii());
            return true;
        }
        default:
            return QApplication::event(event);
        }
    }
};
#else
typedef QApplication QSOFAApplication;
#endif

RealGUI* gui = NULL;
QApplication* application = NULL;

const char* progname="";


int RealGUI::InitGUI ( const char* /*name*/, const std::vector<std::string>& /* options */ )
{
    if ( ImageQt::Init() )
    {
        return 0;
    }
    else
    {
        return 1;
    }
}


SofaGUI* RealGUI::CreateGUI ( const char* name, const std::vector<std::string>& options, sofa::simulation::Node::SPtr root, const char* filename )
{
    CreateApplication();

    // create interface
    gui = new RealGUI ( name, options );
    if ( root )
    {
        gui->setScene ( root, filename );
        gui->setWindowFilePath(QString(filename));
    }

    InitApplication(gui);

    return gui;
}

void RealGUI::CreateApplication(int /*_argc*/, char** /*_argv*/)
{
    int  *argc = new int;
    char **argv=new char*[2];
    *argc = 1;
    argv[0] = strdup ( SofaGUI::GetProgramName() );
    argv[1]=NULL;
    application = new QSOFAApplication ( *argc,argv );
}

void RealGUI::InitApplication( RealGUI* _gui)
{
    application->setMainWidget ( _gui );

    QString pathIcon=(sofa::helper::system::DataRepository.getFirstPath() + std::string( "/icons/SOFA.png" )).c_str();
#ifdef SOFA_QT4
    application->setWindowIcon(QIcon(pathIcon));
#else
    gui->setIcon(QPixmap(pathIcon));
#endif

    // show the gui
    _gui->show();

}

int RealGUI::mainLoop()
{
    int retcode;
    if (windowFilePath().isNull())
    {
        retcode = application->exec();
    }
    else
    {
        const std::string &filename=windowFilePath().ascii();
        const std::string &extension=sofa::helper::system::SetDirectory::GetExtension(filename.c_str());
        if (extension == "simu") fileOpenSimu(filename);
        retcode = application->exec();
    }
    return exitApplication(retcode);
}

void RealGUI::redraw()
{
    emit newStep();
}

int RealGUI::closeGUI()
{

    delete this;
    return 0;
}

Node* RealGUI::currentSimulation()
{
    return viewer->getScene();
}

RealGUI::RealGUI ( const char* viewername, const std::vector<std::string>& options )
    : viewerName ( viewername ),
#ifdef SOFA_GUI_INTERACTION
      interactionButton( NULL ),
#endif
      viewer ( NULL ),
      simulationGraph(NULL),
      mCreateViewersOpt(false),
      m_dumpState(false),
      m_dumpStateStream(NULL),
      m_exportGnuplot(false),
      _animationOBJ(false),
      _animationOBJcounter(0),
      m_displayComputationTime(false),
      m_fullScreen(false),

      currentTab ( NULL ),
#ifndef SOFA_GUI_QT_NO_RECORDER
      recorder(NULL),
#else
      fpsLabel(NULL),
      timeLabel(NULL),
#endif
      statWidget(NULL),
      timerStep(NULL),
      backgroundImage(NULL),
      left_stack(NULL),
      pluginManager_dialog(NULL),
      recentlyOpenedFilesManager("config/Sofa.ini"),
      saveReloadFile(false),
      frameCounter(0),
#ifdef SOFA_GUI_INTERACTION
      m_interactionActived(false),
#endif
      displayFlag(NULL),
#ifdef SOFA_DUMP_VISITOR_INFO
      windowTraceVisitor(NULL),
      handleTraceVisitor(NULL),
#endif
      descriptionScene(NULL),
      htmlPage(NULL),
      animationState(false)
{

    // parse the options
    mCreateViewersOpt = true;
    for (unsigned int i=0; i<options.size(); ++i)
    {
        if (options[i] == "noViewers")
        {
            mCreateViewersOpt = false;
            std::cerr<<"=========================== No Viewers ====================="<<std::endl;
        }
    }

#ifdef SOFA_GUI_INTERACTION
    interactionButton = new QPushButton(optionTabs);
    interactionButton->setObjectName(QString::fromUtf8("interactionButton"));
    interactionButton->setCheckable(true);
    interactionButton->setStyleSheet("background-color: cyan;");

    gridLayout->addWidget(interactionButton, 3, 0, 1, 1);
    gridLayout->removeWidget(screenshotButton);
    gridLayout->addWidget(screenshotButton, 3, 1, 1,1);

    interactionButton->setText(QApplication::translate("GUI", "&Interaction", 0, QApplication::UnicodeUTF8));
    interactionButton->setShortcut(QApplication::translate("GUI", "Alt+i", 0, QApplication::UnicodeUTF8));
#ifndef QT_NO_TOOLTIP
    interactionButton->setProperty("toolTip", QVariant(QApplication::translate("GUI", "Start interaction mode", 0, QApplication::UnicodeUTF8)));
#endif // QT_NO_TOOLTIP	
#endif

    connect(this, SIGNAL(quit()), this, SLOT(fileExit()));

    //--------
    pluginManager_dialog = new SofaPluginManager();
    pluginManager_dialog->hide();

    this->connect( pluginManager_dialog, SIGNAL( libraryAdded() ),  this, SLOT( updateViewerList() ));
    this->connect( pluginManager_dialog, SIGNAL( libraryRemoved() ),  this, SLOT( updateViewerList() ));

    informationOnPickCallBack = InformationOnPickCallBack(this);

#ifdef SOFA_QT4
    fileMenu->removeAction(Action);
#endif
    //Configure Recently Opened Menu
    const int indexRecentlyOpened=fileMenu->count()-2;
    QMenu *recentMenu = recentlyOpenedFilesManager.createWidget(this);
    fileMenu->insertItem(QPixmap(),recentMenu,indexRecentlyOpened,indexRecentlyOpened);
    connect(recentMenu, SIGNAL(activated(int)), this, SLOT(fileRecentlyOpened(int)));

    left_stack = new QWidgetStack ( splitter2 );
    connect ( startButton, SIGNAL ( toggled ( bool ) ), this , SLOT ( playpauseGUI ( bool ) ) );
#ifdef SOFA_GUI_INTERACTION
    connect ( interactionButton, SIGNAL ( toggled ( bool ) ), this , SLOT ( interactionGUI ( bool ) ) );
#endif
    connect ( ResetSceneButton, SIGNAL ( clicked() ), this, SLOT ( resetScene() ) );
    connect ( dtEdit, SIGNAL ( textChanged ( const QString& ) ), this, SLOT ( setDt ( const QString& ) ) );
    connect ( stepButton, SIGNAL ( clicked() ), this, SLOT ( step() ) );
    connect ( dumpStateCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( dumpState ( bool ) ) );
    connect ( displayComputationTimeCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( displayComputationTime ( bool ) ) );
    connect ( exportGnuplotFilesCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportGnuplot ( bool ) ) );
#ifdef SOFA_DUMP_VISITOR_INFO
    connect ( exportVisitorCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportVisitor ( bool ) ) );
#endif


    pathDumpVisitor = sofa::helper::system::SetDirectory::GetParentDir(sofa::helper::system::DataRepository.getFirstPath().c_str()) + std::string( "/dumpVisitor.xml" );

    connect ( tabs, SIGNAL ( currentChanged ( QWidget* ) ), this, SLOT ( currentTabChanged ( QWidget* ) ) );

    //Create a Dock Window to receive the Sofa Recorder
#ifndef SOFA_GUI_QT_NO_RECORDER
    QDockWindow *dockRecorder=new QDockWindow(this);
    dockRecorder->setResizeEnabled(true);
    this->moveDockWindow( dockRecorder, Qt::DockBottom);
    this->leftDock() ->setAcceptDockWindow(dockRecorder,false);
    this->rightDock()->setAcceptDockWindow(dockRecorder,false);

    recorder = new QSofaRecorder(dockRecorder);
    dockRecorder->setWidget(recorder);

    connect(startButton, SIGNAL(  toggled ( bool ) ), recorder, SLOT( TimerStart(bool) ) );
#else
    //Status Bar Configuration
    fpsLabel = new QLabel ( "9999.9 FPS", statusBar() );
    fpsLabel->setMinimumSize ( fpsLabel->sizeHint() );
    fpsLabel->clear();

    timeLabel = new QLabel ( "Time: 999.9999 s", statusBar() );
    timeLabel->setMinimumSize ( timeLabel->sizeHint() );
    timeLabel->clear();
    statusBar()->addWidget ( fpsLabel );
    statusBar()->addWidget ( timeLabel );
#endif

    statWidget = new QSofaStatWidget(TabStats);
    TabStats->layout()->add(statWidget);

    simulationGraph = new QSofaListView(SIMULATION,TabGraph,"SimuGraph");
    if (mCreateViewersOpt) createViewers(viewername);

    currentTabChanged ( tabs->currentPage() );

    //ADD GUI for Background
    //------------------------------------------------------------------------
    //Informations
    QWidget *colour = new QWidget(TabPage);
    QHBoxLayout *colourLayout = new QHBoxLayout(colour);
    colourLayout->addWidget(new QLabel(QString("Colour "),colour));

    for (unsigned int i=0; i<3; ++i)
    {
        std::ostringstream s;
        s<<"background" <<i;
        background[i] = new WDoubleLineEdit(colour,s.str().c_str());
        background[i]->setMinValue( 0.0f);
        background[i]->setMaxValue( 1.0f);
        background[i]->setValue( 1.0f);

        colourLayout->addWidget(background[i]);
        connect( background[i], SIGNAL( returnPressed() ), this, SLOT( updateBackgroundColour() ) );
    }

    QWidget *image = new QWidget(TabPage);
    QHBoxLayout *imageLayout = new QHBoxLayout(image);
    imageLayout->addWidget(new QLabel(QString("Image "),image));

    backgroundImage = new QLineEdit(image,"backgroundImage");
    if (mCreateViewersOpt)
        backgroundImage->setText( QString(viewer->getBackgroundImage().c_str()) );
    else
        backgroundImage->setText( QString() ); //by default if we havn't yet a viewer
    imageLayout->addWidget(backgroundImage);
    connect( backgroundImage, SIGNAL( returnPressed() ), this, SLOT( updateBackgroundImage() ) );


    ((QVBoxLayout*)(TabPage->layout()))->insertWidget(1,colour);
    ((QVBoxLayout*)(TabPage->layout()))->insertWidget(2,image);

    //---------------------------------------------------------------------------------------------------
#ifdef SOFA_PML
    pmlreader = NULL;
    lmlreader = NULL;
#endif

    ((QVBoxLayout*)TabGraph->layout())->addWidget(simulationGraph);
    connect ( ExportGraphButton, SIGNAL ( clicked() ), simulationGraph, SLOT ( Export() ) );
#ifdef SOFA_QT4
    tabs->removeTab(tabs->indexOf(TabVisualGraph));
#endif


#ifndef SOFA_DUMP_VISITOR_INFO
    //Remove option to see visitor trace
    this->exportVisitorCheckbox->hide();
#else
    //Main window containing a QListView only
    windowTraceVisitor = new WindowVisitor;
    windowTraceVisitor->graphView->setSorting(-1);
    windowTraceVisitor->hide();
    connect(windowTraceVisitor, SIGNAL(WindowVisitorClosed(bool)), this->exportVisitorCheckbox, SLOT(setChecked(bool)));
    handleTraceVisitor = new GraphVisitor(windowTraceVisitor);
#endif
    //--------
    descriptionScene = new QDialog(this);
    descriptionScene->resize(400,400);
    QVBoxLayout *descriptionLayout = new QVBoxLayout(descriptionScene);
    htmlPage = new QTextBrowser(descriptionScene);
    descriptionLayout->addWidget(htmlPage);
#ifdef SOFA_QT4
    connect(htmlPage, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(changeHtmlPage(const QUrl&)));
#else
    // QMimeSourceFactory::defaultFactory()->setExtensionType("html", "text/utf8");
    htmlPage->mimeSourceFactory()->setExtensionType("html", "text/utf8");;
    connect(htmlPage, SIGNAL(sourceChanged(const QString&)), this, SLOT(changeHtmlPage(const QString&)));
#endif
    SofaMouseManager::getInstance()->hide();
    SofaVideoRecorderManager::getInstance()->hide();

    //Center the application
    const QRect screen = QApplication::desktop()->availableGeometry(QApplication::desktop()->primaryScreen());
    this->move(  ( screen.width()- this->width()  ) / 2,  ( screen.height() - this->height()) / 2  );

    connect(simulationGraph, SIGNAL( RootNodeChanged(sofa::simulation::Node*, const char*) ), this, SLOT ( NewRootNode(sofa::simulation::Node* , const char*) ) );
    connect(simulationGraph, SIGNAL( NodeRemoved() ), this, SLOT( Update() ) );
    connect(simulationGraph, SIGNAL( Lock(bool) ), this, SLOT( LockAnimation(bool) ) );
    connect(simulationGraph, SIGNAL( RequestSaving(sofa::simulation::Node*) ), this, SLOT( fileSaveAs(sofa::simulation::Node*) ) );
    connect(simulationGraph, SIGNAL( RequestExportOBJ(sofa::simulation::Node*, bool) ), this, SLOT( exportOBJ(sofa::simulation::Node*, bool) ) );
    connect(simulationGraph, SIGNAL( RequestActivation(sofa::simulation::Node*, bool) ), this, SLOT( ActivateNode(sofa::simulation::Node*, bool) ) );
    connect(simulationGraph, SIGNAL( Updated() ), this, SLOT( redraw() ) );
    connect(simulationGraph, SIGNAL( NodeAdded() ), this, SLOT( Update() ) );
    connect(this, SIGNAL( newScene() ), simulationGraph, SLOT( CloseAllDialogs() ) );
    connect(this, SIGNAL( newStep() ), simulationGraph, SLOT( UpdateOpenedDialogs() ) );

#ifndef SOFA_GUI_QT_NO_RECORDER
    if (recorder)
        connect( recorder, SIGNAL( RecordSimulation(bool) ), startButton, SLOT( setOn(bool) ) );
    if (recorder && mCreateViewersOpt)
        connect( recorder, SIGNAL( NewTime() ), viewer->getQWidget(), SLOT( update() ) );
#endif
    timerStep = new QTimer(this);
    connect ( timerStep, SIGNAL ( timeout() ), this, SLOT ( step() ) );

    animationState = false;

#ifdef SOFA_GUI_INTERACTION
    m_interactionActived = false;
    if(mCreateViewersOpt)
        viewer->getQWidget()->installEventFilter(this);
#endif
}

void RealGUI::fileRecentlyOpened(int id)
{
    fileOpen(recentlyOpenedFilesManager.getFilename((unsigned int)id));
}

void RealGUI::setPixmap(std::string pixmap_filename, QPushButton* b)
{
    if ( sofa::helper::system::DataRepository.findFile ( pixmap_filename ) )
        pixmap_filename = sofa::helper::system::DataRepository.getFile ( pixmap_filename );

#ifdef SOFA_QT4
    b->setPixmap(QPixmap(QPixmap::fromImage(QImage(pixmap_filename.c_str()))));
#else
    b->setPixmap(QPixmap(QImage(pixmap_filename.c_str())));
#endif
}

RealGUI::~RealGUI()
{
#ifdef SOFA_PML
    if ( pmlreader )
    {
        delete pmlreader;
        pmlreader = NULL;
    }
    if ( lmlreader )
    {
        delete lmlreader;
        lmlreader = NULL;
    }
#endif
    if( displayFlag != NULL )
    {
        delete displayFlag;
    }
#ifdef SOFA_DUMP_VISITOR_INFO
    delete windowTraceVisitor;
    delete handleTraceVisitor;
#endif
    removeViewer();
}

void RealGUI::init()
{
    frameCounter = 0;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;

    gnuplot_directory = "";
    m_fullScreen = false;
}

void RealGUI::removeViewer()
{
    if(viewer->isThreaded())
        viewer->stopViewerThread();

    if(mCreateViewersOpt)
    {
        delete viewer;
        viewer = NULL;
    }
}

//createViewers
void RealGUI::createViewers(const char* viewerName)
{
    viewer::SofaViewerArgument arg;
    arg.name = "viewer";
    arg.parent = left_stack;

    if( viewer != NULL )
        removeViewer();

    viewerMap.clear();
    if ( viewerName[0] )
    {
        helper::vector< helper::SofaViewerFactory::Key > keys;
        helper::SofaViewerFactory::getInstance()->uniqueKeys(std::back_inserter(keys));
        helper::vector< helper::SofaViewerFactory::Key >::const_iterator iter;

        for ( iter = keys.begin(); iter != keys.end(); ++iter )
        {
            QAction* action = new QAction(this);
            action->setText( helper::SofaViewerFactory::getInstance()->getViewerName(*iter) );
            action->setMenuText(  helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*iter) );
            action->setToggleAction(true);
            action->addTo(View);
            viewerMap[*iter] = action;
            action->setEnabled(true);
            connect(action, SIGNAL( activated() ), this, SLOT( changeViewer() ) );

            if( strcmp(iter->c_str(), viewerName )== 0 )
            {
                viewer = helper::SofaViewerFactory::CreateObject(*iter, arg);
                action->setOn(true);
            }
            else
            {
                action->setOn(false);
            }
        }
    }

    if( viewer == NULL )
    {
        std::cerr << "ERROR(QtGUI): unknown or disabled viewer name "<<viewerName<<std::endl;
        application->exit();
    }
    if(viewer->isEmbedded())
        left_stack->addWidget ( viewer->getQWidget() );
    initViewer();
}

//initViewer
void RealGUI::initViewer()
{
    if(viewer == NULL)
    {
        std::cerr<<"ERROR when initViewer, the viewer is NULL"<<std::endl;
        return;
    }
    frameCounter = 0;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;
    gnuplot_directory = "";

    if(viewer->isEmbedded())
    {
#ifdef SOFA_QT4
        left_stack->setCurrentWidget ( viewer->getQWidget() );
        viewer->getQWidget()->setFocusPolicy ( Qt::StrongFocus );
#else
        int id_viewer = left_stack->addWidget ( viewer->getQWidget() );
        left_stack->raiseWidget ( id_viewer );
        viewer->getQWidget()->setFocusPolicy ( QWidget::StrongFocus );
        viewer->getQWidget()->setCursor ( QCursor ( 2 ) );
#endif
        viewer->getQWidget()->setSizePolicy ( QSizePolicy ( ( QSizePolicy::SizeType ) 7, ( QSizePolicy::SizeType ) 7, 100, 1, viewer->getQWidget()->sizePolicy().hasHeightForWidth() ) );
        viewer->getQWidget()->setMinimumSize ( QSize ( 0, 0 ) );
        viewer->getQWidget()->setMouseTracking ( TRUE );
    }
    viewer->configureViewerTab(tabs);

    connect ( ResetViewButton, SIGNAL ( clicked() ), this, SLOT ( resetView() ) );
    connect ( SaveViewButton, SIGNAL ( clicked() ), this, SLOT ( saveView() ) );
    connect ( screenshotButton, SIGNAL ( clicked() ), this, SLOT ( screenshot() ) );
    connect ( sizeW, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeW ( int ) ) );
    connect ( sizeH, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeH ( int ) ) );
    if(viewer->isEmbedded())
    {
        connect ( viewer->getQWidget(), SIGNAL ( resizeW ( int ) ), sizeW, SLOT ( setValue ( int ) ) );
        connect ( viewer->getQWidget(), SIGNAL ( resizeH ( int ) ), sizeH, SLOT ( setValue ( int ) ) );
        connect ( viewer->getQWidget(), SIGNAL ( quit (  ) ), this, SLOT ( fileExit (  ) ) );
        connect(simulationGraph, SIGNAL(focusChanged(sofa::core::objectmodel::BaseObject*)),
                viewer->getQWidget(), SLOT(fitObjectBBox(sofa::core::objectmodel::BaseObject*)) );
        connect(simulationGraph, SIGNAL( focusChanged(sofa::core::objectmodel::BaseNode*) ),
                viewer->getQWidget(), SLOT( fitNodeBBox(sofa::core::objectmodel::BaseNode*) ) );
    }

    // splitter2 separates horizontally the OptionTab widget and the viewer widget
    QSplitter *splitter_ptr = dynamic_cast<QSplitter *> ( splitter2 );
    if(viewer->isEmbedded())
    {
        splitter_ptr->moveToLast ( left_stack ); // Use addWidget(widget) instead.
        splitter_ptr->setOpaqueResize ( false );
#ifdef SOFA_QT4
        // rescale factor for the space occuped by the widget index
        splitter_ptr->setStretchFactor( 0, 0); // OptionTab
        splitter_ptr->setStretchFactor( 1, 10); // Viewer
        QList<int> list;
#else
        QValueList<int> list;
#endif
        list.push_back ( 250 ); // OptionTab
        list.push_back ( 640 ); // Viewer
        splitter_ptr->setSizes ( list );
    }
    else
    {
        splitter_ptr->setOpaqueResize ( false );
#ifdef SOFA_QT4
        // rescale factor for the space occuped by the widget index
        splitter_ptr->setStretchFactor( 0, 0); // OptionTab
        splitter_ptr->setStretchFactor( 1, 0); // Viewer
        QList<int> list;
#else
        QValueList<int> list;
#endif
        list.push_back ( 250 ); // OptionTab
        list.push_back ( 0 );  // Viewer
        splitter_ptr->setSizes ( list );
    }

    // setGUI
    textEdit1->setText ( viewer->helpString() );
    if(viewer->isEmbedded())
        connect ( this, SIGNAL( newStep()), viewer->getQWidget(), SLOT( update()));

    if(viewer->isEmbedded())
    {
        viewer->getQWidget()->setFocus();
        viewer->getQWidget()->show();
        updateViewerParameters();
    }

    SofaMouseManager::getInstance()->setPickHandler(viewer->getPickHandler());
    if( !viewer->isThreaded() ) // How to pass info from viewer thread to gui application thread?
        viewer->getPickHandler()->addCallBack(&informationOnPickCallBack );

    guiName=viewerName;
}

//changeViewer
void RealGUI::changeViewer()
{
    QObject* obj = const_cast<QObject*>( QObject::sender() );
    if( !obj) return;

    QAction* action = static_cast<QAction*>(obj);

    action->setOn(true);
    std::map< helper::SofaViewerFactory::Key, QAction*  >::const_iterator iter_map;
    for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end() ; ++iter_map )
    {
        if ( (*iter_map).second == action )
        {
            // Cleanup previous viewer
            if ( viewer->getScene() !=NULL )
            {
                viewer->getPickHandler()->unload();
                // Unload viewer components before delete the whole scene
                viewer->unloadSceneView();
                simulation::getSimulation()->unload ( viewer->getScene() );
                //delete viewer->getScene() ;
                viewer->setScene(NULL);
            }
            viewer->removeViewerTab(tabs);
            if(viewer->isEmbedded())
                left_stack->removeWidget(viewer->getQWidget() );

            removeViewer();

            // Need for the next creation
            viewer::SofaViewerArgument arg;
            arg.name = "viewer";
            arg.parent = left_stack; // Set it by default but in case of standalone viewer, we don't use it in tis constructor

            // Create new viewer
            viewer =  helper::SofaViewerFactory::CreateObject( (*iter_map).first, arg);

            if(viewer->isEmbedded())
                left_stack->addWidget( viewer->getQWidget() );

            initViewer();
        }
        else
        {
            (*iter_map).second->setOn(false);
        }
    }

    // Reload the scene
    std::string filename(this->windowFilePath().ascii());
    fileOpen ( filename.c_str() ); // keep the current display flags
}

//updateViewerList
void RealGUI::updateViewerList()
{
    helper::vector< helper::SofaViewerFactory::Key > currentKeys;
    std::map< helper::SofaViewerFactory::Key, QAction*>::const_iterator iter_map;
    for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end() ; ++iter_map )
    {
        currentKeys.push_back((*iter_map).first);
    }
    std::sort(currentKeys.begin(),currentKeys.end());
    helper::vector< helper::SofaViewerFactory::Key > updatedKeys;
    helper::SofaViewerFactory::getInstance()->uniqueKeys(std::back_inserter(updatedKeys));
    std::sort(updatedKeys.begin(),updatedKeys.end());

    helper::vector< helper::SofaViewerFactory::Key > diffKeys;

    std::set_symmetric_difference(currentKeys.begin(),currentKeys.end(),updatedKeys.begin(),updatedKeys.end()
            ,std::back_inserter(diffKeys));

    helper::vector< helper::SofaViewerFactory::Key >::const_iterator it;
    for( it = diffKeys.begin(); it != diffKeys.end(); ++it)
    {

        std::map< helper::SofaViewerFactory::Key, QAction* >::iterator itViewerMap;

        if( (itViewerMap = viewerMap.find(*it)) != viewerMap.end() )
        {
            if( (*itViewerMap).second->isOn() )
            {
                if ( viewer->getScene() !=NULL )
                {
                    viewer->getPickHandler()->unload();
                    viewer->unloadSceneView();
                    simulation::getSimulation()->unload ( viewer->getScene() );
                    //delete viewer->getScene() ;
                    viewer->setScene(NULL);
                }

                viewer->removeViewerTab(tabs);

                if(viewer->isEmbedded())
                    left_stack->removeWidget(viewer->getQWidget() );

                removeViewer();
            }

            (*itViewerMap).second->removeFrom(View);
            viewerMap.erase(itViewerMap);
        }
        else
        {
            QAction* action = new QAction(this);
            action->setText( helper::SofaViewerFactory::getInstance()->getViewerName(*it) );
            action->setMenuText(  helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*it) );
            action->setToggleAction(true);
            action->addTo(View);
            viewerMap[*it] = action;
            action->setEnabled(true);
            connect(action, SIGNAL( activated() ), this, SLOT( changeViewer() ) );
        }
    }

    if( viewer == NULL )
    {
        if(!viewerMap.empty())
        {
            viewer::SofaViewerArgument arg;
            arg.name = "viewer";
            arg.parent = left_stack;
            /* change viewer */
            viewer =  helper::SofaViewerFactory::CreateObject( viewerMap.begin()->first, arg);

            if(viewer->isEmbedded())
                left_stack->addWidget( viewer->getQWidget() );

            initViewer();
        }
    }
}

//fileOpen
void RealGUI::fileOpen ( std::string filename, bool temporaryFile )
{
    //std::cout << "GUI: fileOpen " << filename << " ( was " <<   std::string(this->windowFilePath().ascii()) << " )" << std::endl;
    const std::string &extension=sofa::helper::system::SetDirectory::GetExtension(filename.c_str());
    if (extension == "simu")
    {
        return fileOpenSimu(filename);
    }

    startButton->setOn(false);
    descriptionScene->hide();
    htmlPage->clear();

    if ( sofa::helper::system::DataRepository.findFile (filename) )
        filename = sofa::helper::system::DataRepository.getFile ( filename );
    else
        return;
    startDumpVisitor();

    frameCounter = 0;
    sofa::simulation::xml::numDefault = 0;

    update();
    //Hide all the dialogs to modify the graph
    emit ( newScene() );

    if ( viewer->getScene() !=NULL )
    {
        viewer->getPickHandler()->reset();//activateRay(false);
        viewer->getPickHandler()->unload();

        // Unload viewer components before delete the whole scene
        viewer->unloadSceneView();
        simulation::getSimulation()->unload ( viewer->getScene() );
        viewer->setScene(NULL);
    }
    //Clear the list of modified dialog opened

    // Load the scene
    simulation::Node::SPtr root = simulation::getSimulation()->load ( filename.c_str() );
    simulation::getSimulation()->init ( root.get() );

    if ( root == NULL )
    {
        qFatal ( "Failed to load %s",filename.c_str() );
        stopDumpVisitor();
        return;
    }
    this->setWindowFilePath(filename.c_str());
    setScene ( root, filename.c_str(), temporaryFile );

    configureGUI(root.get());

    setExportGnuplot(exportGnuplotFilesCheckbox->isChecked());
//  displayComputationTime(m_displayComputationTime);  // (FF) This can be set outside of the GUI and should not be changed implicitly by the GUI
    stopDumpVisitor();
{'fraction_non_alphanumeric': 0.15421143136605298, 'fraction_numerical': 0.004590846703582754, 'mean_word_length': 3.014693774146558, 'pattern_counts': {'":': 0, '<': 225, '<?xml version=': 0, '>': 595, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7041354', 'n_tokens_mistral': 19564, 'n_tokens_neox': 18670, 'n_words': 3740}