<commit_before>/*******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 1       *
*                (c) 2006-2007 MGH, INRIA, USTL, UJF, CNRS                     *
*                                                                              *
* 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.                    *
*                                                                              *
* Contact information: <EMAIL>                              *
*                                                                              *
* Authors: <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,     *
* <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,        *
* and <NAME>                                                                 *
*******************************************************************************/

#ifdef SOFA_GUI_QTOGREVIEWER
#include "QtOgreViewer/QtOgreViewer.h"
#endif

#ifdef SOFA_GUI_QTVIEWER
#include "QtViewer/QtViewer.h"
#endif

#ifdef SOFA_GUI_QGLVIEWER
#include "QtGLViewer/QtGLViewer.h"
#endif
#include "RealGUI.h"

#include <sofa/simulation/tree/Simulation.h>
#include <sofa/simulation/tree/MutationListener.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/simulation/automatescheduler/ThreadSimulation.h>
#include <sofa/simulation/automatescheduler/ExecBus.h>
#include <sofa/simulation/automatescheduler/Node.h>

namespace sofa
{
namespace simulation
{
namespace automatescheduler
{
extern simulation::tree::GNode* groot;
}
}
}


#ifdef QT_MODULE_QT3SUPPORT
#include <Q3FileDialog>
#include <QStatusBar>
#include <Q3DockWindow>
#include <Q3ListViewItem>
#include <Q3ListView>
#include <QStackedWidget>
#include <QRadioButton>
#include <QSplitter>
#include <Q3TextEdit>
#include <QCursor>
#include <QWidget>
#include <QLayout>
#include <QTimer>
#include <QAction>
#include <QMessageBox>
#define WIDTH_OFFSET 2
#define HEIGHT_OFFSET 2
#define INFINITY 9.0e10
#else
#include <qlistview.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qstatusbar.h>
#include <qfiledialog.h>
#include <qheader.h>
#include <qimage.h>
#include <qdockwindow.h>
#include <qspinbox.h>
#include <qradiobutton.h>
#include <qsplitter.h>
#include <qtextedit.h>
#include <qcursor.h>
#include <qwidget.h>
#include <qwidgetstack.h>
#include <qlayout.h>
#include <qtimer.h>
#include <qapplication.h>
#include <qaction.h>
#include <qmessagebox.h>

#define WIDTH_OFFSET 0
#define HEIGHT_OFFSET 0
#endif

#include <GenGraphForm.h>
#include "GUIField.h"

#include <sofa/simulation/tree/Colors.h>
#include "WFloatLineEdit.h"
#include <sofa/core/objectmodel/BaseObject.h>
#include <limits.h>


namespace sofa
{

namespace gui
{

namespace guiviewer
{

#ifdef QT_MODULE_QT3SUPPORT
typedef Q3ListView QListView;
typedef Q3FileDialog QFileDialog;
typedef Q3DockWindow QDockWindow;
typedef QStackedWidget QWidgetStack;
typedef Q3TextEdit QTextEdit;
#else
typedef QListViewItem Q3ListViewItem;
typedef QListView Q3ListView;
typedef QFileDialog Q3FileDialog;
//typedef QWidgetStack QStackedWidget;
typedef QTextEdit Q3TextEdit;
#endif


#include "iconnode.xpm"

using sofa::core::objectmodel::BaseObject;

using namespace sofa::helper::system::thread;
using namespace sofa::simulation::tree;
using namespace sofa::simulation::automatescheduler;


///////////////////////////////////////////////////////////
//////////////////// SofaGUI Interface ////////////////////
///////////////////////////////////////////////////////////

#ifdef SOFA_GUI_QGLVIEWER
SOFA_DECL_CLASS(QGLViewerGUI)
int QGLViewerGUIClass = SofaGUI::RegisterGUI("qglviewer", &RealGUI::CreateGUI, &RealGUI::InitGUI, 2);
#endif
#ifdef SOFA_GUI_QTVIEWER
SOFA_DECL_CLASS(QTGUI)
int QtGUIClass = SofaGUI::RegisterGUI("qt", &RealGUI::CreateGUI, &RealGUI::InitGUI, 1);
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
SOFA_DECL_CLASS(OgreGUI)
int QtOGREGUIClass = SofaGUI::RegisterGUI("ogre", &RealGUI::CreateGUI, &RealGUI::InitGUI, 0);
#endif

int RealGUI::InitGUI(const char* name, const std::vector<std::string>& /* options */)
{
#ifdef SOFA_GUI_QGLVIEWER
    if (!name[0] || !strcmp(name,"qglviewer"))
    {
        return sofa::gui::guiqglviewer::QtGLViewer::EnableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QTVIEWER
        if (!name[0] || !strcmp(name,"qt"))
        {
            return sofa::gui::qt::QtViewer::EnableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!name[0] || !strcmp(name,"ogre"))
            {
                return sofa::gui::qtogreviewer::QtOgreViewer::EnableViewer();
            }
            else
#endif
            {
                std::cerr << "ERROR(QtGUI): unknown or disabled gui name "<<name<<std::endl;
                return 1;
            }
}

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

using sofa::simulation::tree::GNode;

SofaGUI* RealGUI::CreateGUI(const char* name, const std::vector<std::string>& options, sofa::simulation::tree::GNode* groot, const char* filename)
{
    {
        int argc=1;
        char* argv[1];
        argv[0] = strdup(SofaGUI::GetProgramName());
        application = new QApplication(argc,argv);
        free(argv[0]);
    }
    // create interface
    gui = new RealGUI( name, options );
    if (groot)
        gui->setScene(groot, filename);

    //gui->viewer->SwitchToPresetView();

    application->setMainWidget( gui );

    // Threads Management
    if (ThreadSimulation::initialized())
    {
        ThreadSimulation::getInstance()->computeVModelsList(groot);
        groot->setMultiThreadSimulation(true);
        sofa::simulation::automatescheduler::groot = groot;

        Automate::setDrawCB(gui->viewer);

        gui->viewer->getQWidget()->update();
        ThreadSimulation::getInstance()->start();
    }
    // show the gui
    gui->show();
    return gui;
}

int RealGUI::mainLoop()
{
    return application->exec();
}

void RealGUI::redraw()
{
    viewer->getQWidget()->update();
}

int RealGUI::closeGUI()
{
    delete this;
    return 0;
}

sofa::simulation::tree::GNode* RealGUI::currentSimulation()
{
    return viewer->getScene();
}

///////////////////////////////////////////////////////////

static const int iconWidth=8;
static const int iconHeight=10;
static const int iconMargin=6;

/*
static QImage* classIcons = NULL;
static const int iconMargin=7;
static const int iconHeight=20;

// mapping; mmapping; constraint; iff; ffield; topology; mass; mstate; solver; bmodel; vmodel; cmodel; pipeline; context; object; gnode;

static const int iconPos[16]=
{
0, // node
1, // object
2, // context
6, // bmodel
4, // cmodel
8, // mstate
13, // constraint
12, // iff
11, // ff
7, // solver
3, // pipeline
14, // mmap
15, // map
9, // mass
10, // topo
5, // vmodel
};

static QImage icons[16];
*/
static int hexval(char c)
{
    if (c>='0' && c<='9') return c-'0';
    else if (c>='a' && c<='f') return (c-'a')+10;
    else if (c>='A' && c<='F') return (c-'A')+10;
    else return 0;
}

static QPixmap* getPixmap(core::objectmodel::Base* obj)
{
    using namespace sofa::simulation::tree::Colors;
    /*
    if (classIcons == NULL)
    {
    classIcons = new QImage("../examples/classicons.png");
    std::cout << "../examples/classicons.png: "<<classIcons->width()<<"x"<<classIcons->height()<<std::endl;
    if (classIcons->height() < 16) return NULL;
    // Find each icon
    QRgb bg = classIcons->pixel(0,0);
    }
    if (classIcons->height() < 16) return NULL;
    */
    unsigned int flags=0;

    if (dynamic_cast<core::objectmodel::BaseNode*>(obj))
    {
        static QPixmap pixNode((const char**)iconnode_xpm);
        return &pixNode;
        //flags |= 1 << NODE;
    }
    else if (dynamic_cast<core::objectmodel::BaseObject*>(obj))
    {
        if (dynamic_cast<core::objectmodel::ContextObject*>(obj))
            flags |= 1 << CONTEXT;
        if (dynamic_cast<core::BehaviorModel*>(obj))
            flags |= 1 << BMODEL;
        if (dynamic_cast<core::CollisionModel*>(obj))
            flags |= 1 << CMODEL;
        if (dynamic_cast<core::componentmodel::behavior::BaseMechanicalState*>(obj))
            flags |= 1 << MMODEL;
        if (dynamic_cast<core::componentmodel::behavior::BaseConstraint*>(obj))
            flags |= 1 << CONSTRAINT;
        if (dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj) &&
            dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj)->getMechModel1()!=dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj)->getMechModel2())
            flags |= 1 << IFFIELD;
        else if (dynamic_cast<core::componentmodel::behavior::BaseForceField*>(obj))
            flags |= 1 << FFIELD;
        if (dynamic_cast<core::componentmodel::behavior::MasterSolver*>(obj)
            || dynamic_cast<core::componentmodel::behavior::OdeSolver*>(obj))
            flags |= 1 << SOLVER;
        if (dynamic_cast<core::componentmodel::collision::Pipeline*>(obj)
            || dynamic_cast<core::componentmodel::collision::Intersection*>(obj)
            || dynamic_cast<core::componentmodel::collision::Detection*>(obj)
            || dynamic_cast<core::componentmodel::collision::ContactManager*>(obj)
            || dynamic_cast<core::componentmodel::collision::CollisionGroupManager*>(obj))
            flags |= 1 << COLLISION;
        if (dynamic_cast<core::componentmodel::behavior::BaseMechanicalMapping*>(obj))
            flags |= 1 << MMAPPING;
        else if (dynamic_cast<core::BaseMapping*>(obj))
            flags |= 1 << MAPPING;
        if (dynamic_cast<core::componentmodel::behavior::BaseMass*>(obj))
            flags |= 1 << MASS;
        if (dynamic_cast<core::componentmodel::topology::Topology *>(obj))
            flags |= 1 << TOPOLOGY;
        if (dynamic_cast<core::VisualModel*>(obj) && !flags)
            flags |= 1 << VMODEL;
        if (!flags)
            flags |= 1 << OBJECT;
    }
    else return NULL;

    static std::map<unsigned int, QPixmap*> pixmaps;
    if (!pixmaps.count(flags))
    {
        int nc = 0;
        for (int i=0; i<16; i++)
            if (flags & (1<<i))
                ++nc;
        int nx = 2+iconWidth*nc+iconMargin;
        QImage * img = new QImage(nx,iconHeight,32);
        img->setAlphaBuffer(true);
        img->fill(qRgba(0,0,0,0));
        // Workaround for qt 3.x where fill() does not set the alpha channel
        for (int y=0 ; y < iconHeight ; y++)
            for (int x=0 ; x < nx ; x++)
                img->setPixel(x,y,qRgba(0,0,0,0));

        for (int y=0 ; y < iconHeight ; y++)
            img->setPixel(0,y,qRgba(0,0,0,255));
        nc = 0;
        for (int i=0; i<16; i++)
            if (flags & (1<<i))
            {
                int x0 = 1+iconWidth*nc;
                int x1 = x0+iconWidth-1;
                //QColor c(COLOR[i]);
                const char* color = COLOR[i];
                //c.setAlpha(255);
                int r = (hexval(color[1])*16+hexval(color[2]));
                int g = (hexval(color[3])*16+hexval(color[4]));
                int b = (hexval(color[5])*16+hexval(color[6]));
                int a = 255;
                for (int x=x0; x <=x1 ; x++)
                {
                    img->setPixel(x,0,qRgba(0,0,0,255));
                    img->setPixel(x,iconHeight-1,qRgba(0,0,0,255));
                    for (int y=1 ; y < iconHeight-1 ; y++)
                        //img->setPixel(x,y,c.value());
                        img->setPixel(x,y,qRgba(r,g,b,a));
                }
                //bitBlt(img,nimg*(iconWidth+2),0,classIcons,iconMargin,iconPos[i],iconWidth,iconHeight);
                ++nc;
            }
        for (int y=0 ; y < iconHeight ; y++)
            img->setPixel(2+iconWidth*nc-1,y,qRgba(0,0,0,255));
        pixmaps[flags] = new QPixmap(*img);
        delete img;
    }
    return pixmaps[flags];
}


using sofa::simulation::tree::Simulation;
using sofa::simulation::tree::MutationListener;

// TODO: Move this code somewhere else

class GraphListenerQListView : public MutationListener
{
public:
    Q3ListView* widget;
    std::map<core::objectmodel::Base*, Q3ListViewItem* > items;
    GraphListenerQListView(Q3ListView* w)
        : widget(w)
    {
    }

    Q3ListViewItem* createItem(Q3ListViewItem* parent)
    {
        Q3ListViewItem* last = parent->firstChild();
        if (last == NULL)
            return new Q3ListViewItem(parent);
        while (last->nextSibling()!=NULL)
            last = last->nextSibling();
        return new Q3ListViewItem(parent, last);
    }

    void addChild(GNode* parent, GNode* child)
    {
        if (items.count(child)) return;
        Q3ListViewItem* item;
        if (parent == NULL)
            item = new Q3ListViewItem(widget);
        else if (items.count(parent))
            item = createItem(items[parent]);
        else
        {
            std::cerr << "Graph -> QT ERROR: Unknown parent node "<<parent->getName()<<std::endl;
            return;
        }
        if (std::string(child->getName(),0,7) != "default")
            item->setText(0, child->getName().c_str());
        QPixmap* pix = getPixmap(child);
        if (pix)
            item->setPixmap(0, *pix);
        item->setOpen(true);
        items[child] = item;
        // Add all objects and grand-children
        MutationListener::addChild(parent, child);
    }

    void removeChild(GNode* parent, GNode* child)
    {
        MutationListener::removeChild(parent, child);
        if (items.count(child))
        {
            delete items[child];
            items.erase(child);
        }
    }

    void moveChild(GNode* previous, GNode* parent, GNode* child)
    {
        if (!items.count(child) || !items.count(previous))
        {
            addChild(parent, child);
        }
        else if (!items.count(parent))
        {
            removeChild(previous, child);
        }
        else
        {
            Q3ListViewItem* itemChild = items[child];
            Q3ListViewItem* itemPrevious = items[previous];
            Q3ListViewItem* itemParent = items[parent];
            itemPrevious->takeItem(itemChild);
            itemParent->insertItem(itemChild);
        }
    }

    void addObject(GNode* parent, core::objectmodel::BaseObject* object)
    {
        if (items.count(object)) return;
        Q3ListViewItem* item;
        if (items.count(parent))
            item = createItem(items[parent]);
        else
        {
            std::cerr << "Graph -> QT ERROR: Unknown parent node "<<parent->getName()<<std::endl;
            return;
        }
        std::string name = sofa::helper::gettypename(typeid(*object));
        std::string::size_type pos = name.find('<');
        if (pos != std::string::npos)
            name.erase(pos);
        if (std::string(object->getName(),0,7) != "default")
        {
            name += "  ";
            name += object->getName();
        }
        item->setText(0, name.c_str());
        QPixmap* pix = getPixmap(object);
        if (pix)
            item->setPixmap(0, *pix);
        items[object] = item;
    }

    void removeObject(GNode* /*parent*/, core::objectmodel::BaseObject* object)
    {
        if (items.count(object))
        {
            delete items[object];
            items.erase(object);
        }
    }

    void moveObject(GNode* previous, GNode* parent, core::objectmodel::BaseObject* object)
    {
        if (!items.count(object) || !items.count(previous))
        {
            addObject(parent, object);
        }
        else if (!items.count(parent))
        {
            removeObject(previous, object);
        }
        else
        {
            Q3ListViewItem* itemObject = items[object];
            Q3ListViewItem* itemPrevious = items[previous];
            Q3ListViewItem* itemParent = items[parent];
            itemPrevious->takeItem(itemObject);
            itemParent->insertItem(itemObject);
        }
    }
};

RealGUI::RealGUI( const char* viewername, const std::vector<std::string>& /*options*/)
    : viewerName(viewername), graphListener(NULL), id_timer(-1)
{
    left_stack = new QWidgetStack(splitter2);
#ifndef QT_MODULE_QT3SUPPORT
    GUILayout->addWidget(left_stack);
#endif

    connect( startButton, SIGNAL( toggled(bool) ), this , SLOT( playpauseGUI(bool) ) );

    fpsLabel = new QLabel("9999.9 FPS", statusBar());
    fpsLabel->setAlignment(Qt::AlignRight);
    fpsLabel->setMinimumSize(fpsLabel->sizeHint());
    fpsLabel->clear();

    timeLabel = new QLabel("T: 999.9999 s", statusBar());
    timeLabel->setAlignment(Qt::AlignLeft);
    timeLabel->setMinimumSize(timeLabel->sizeHint());
    timeLabel->clear();


    statusBar()->addWidget(fpsLabel);
    statusBar()->addWidget(timeLabel);

    timerStep = new QTimer(this);
    connect( timerStep, SIGNAL(timeout()), this, SLOT(step()) );
    connect( ResetSceneButton, SIGNAL( clicked() ), this, SLOT( resetScene() ) );
    connect( dtEdit, SIGNAL( textChanged(const QString&) ), this, SLOT( setDt(const QString&) ) );
    //connect( ResetViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( resetView() ) );
    //connect( SaveViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( saveView() ) );
    connect( showVisual, SIGNAL( toggled(bool) ), this, SLOT( slot_showVisual(bool) ) );
    connect( showBehavior, SIGNAL( toggled(bool) ), this, SLOT( slot_showBehavior(bool) ) );
    connect( showCollision, SIGNAL( toggled(bool) ), this, SLOT( slot_showCollision(bool) ) );
    connect( showBoundingCollision, SIGNAL( toggled(bool) ), this, SLOT( slot_showBoundingCollision(bool) ) );
    connect( showMapping, SIGNAL( toggled(bool) ), this, SLOT( slot_showMapping(bool) ) );
    connect( showMechanicalMapping, SIGNAL( toggled(bool) ), this, SLOT( slot_showMechanicalMapping(bool) ) );
    connect( showForceField, SIGNAL( toggled(bool) ), this, SLOT( slot_showForceField(bool) ) );
    connect( showInteractionForceField, SIGNAL( toggled(bool) ), this, SLOT( slot_showInteractionForceField(bool) ) );
    connect( showWireFrame, SIGNAL( toggled(bool) ), this, SLOT( slot_showWireFrame(bool) ) );
    connect( showNormals, SIGNAL( toggled(bool) ), this, SLOT( slot_showNormals(bool) ) );
    connect( stepButton, SIGNAL( clicked() ), this, SLOT( step() ) );
    //connect( screenshotButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( screenshot() ) );
    //connect( xmlSave_pushButton, SIGNAL( pressed() ), this, SLOT( saveXML() ) );
    connect( ExportGraphButton, SIGNAL( clicked() ), this, SLOT( exportGraph() ) );
    //connect( exportGraphAction, SIGNAL( activated() ), viewer, SLOT( exportGraph() ) );
    //connect( sizeW, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeW(int) ) );
    //connect( sizeH, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeH(int) ) );
    connect( dumpStateCheckBox, SIGNAL( toggled(bool) ), this, SLOT( dumpState(bool) ) );
    connect( exportGnuplotFilesCheckbox, SIGNAL(toggled(bool)), this, SLOT(setExportGnuplot(bool)) );
    connect( displayComputationTimeCheckBox, SIGNAL( toggled(bool) ), this, SLOT( displayComputationTime(bool) ) );

    addViewer();

#ifdef SOFA_PML
    pmlreader = NULL;
    lmlreader = NULL;
#endif
}

RealGUI::~RealGUI()
{
#ifdef SOFA_PML
    if(pmlreader)
    {
        delete pmlreader;
        pmlreader = NULL;
    }
    if(lmlreader)
    {
        delete lmlreader;
        lmlreader = NULL;
    }
#endif
}

void RealGUI::init()
{
    id_timer = -1;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;
}

void RealGUI::addViewer()
{
    init();
    const char* name = viewerName;

    // set menu state
#ifdef SOFA_GUI_QTVIEWER
    viewerOpenGLAction->setEnabled(true);
#else
    viewerOpenGLAction->setEnabled(false);
    viewerOpenGLAction->setToolTip("enable SOFA_GUI_QTVIEWER in sofa-local.cfg to activate");
#endif
    viewerOpenGLAction->setOn(false);
#ifdef SOFA_GUI_QGLVIEWER
    viewerQGLViewerAction->setEnabled(true);
#else
    viewerQGLViewerAction->setEnabled(false);
    viewerQGLViewerAction->setToolTip("enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate");
#endif
    viewerQGLViewerAction->setOn(false);
#ifdef SOFA_GUI_QTOGREVIEWER
    viewerOGREAction->setEnabled(true);
#else
    viewerOGREAction->setEnabled(false);
    viewerOGREAction->setToolTip("enable SOFA_GUI_QTOGREVIEWER in sofa-local.cfg to activate");
#endif
    viewerOGREAction->setOn(false);

#ifdef SOFA_GUI_QGLVIEWER
    if (!name[0] || !strcmp(name,"qglviewer"))
    {
        viewer = new sofa::gui::guiqglviewer::QtGLViewer( left_stack, "viewer" );
        viewerQGLViewerAction->setOn(true);
    }
    else
#endif
#ifdef SOFA_GUI_QTVIEWER
        if (!name[0] || !strcmp(name,"qt"))
        {
            viewer = new sofa::gui::qt::QtViewer( left_stack, "viewer" );
            viewerOpenGLAction->setOn(true);
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!name[0] || !strcmp(name,"ogre"))
            {
                viewer = new sofa::gui::qtogreviewer::QtOgreViewer( left_stack , "viewer" );
                viewerOGREAction->setOn(true);
            }
            else
#endif
            {
                std::cerr << "ERROR(QtGUI): unknown or disabled viewer name "<<name<<std::endl;
                application->exit();
            }

#ifdef QT_MODULE_QT3SUPPORT
    left_stack->addWidget ( viewer->getQWidget() );
    left_stack->setCurrentWidget ( viewer->getQWidget() );
#else
    int id_viewer = left_stack->addWidget(viewer->getQWidget());
    left_stack->raiseWidget(id_viewer);
#endif
    viewer->getQWidget()->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 100, 1,
            viewer->getQWidget()->sizePolicy().hasHeightForWidth() ) );
    viewer->getQWidget()->setMinimumSize( QSize( 0, 0 ) );
#ifndef QT_MODULE_QT3SUPPORT
    viewer->getQWidget()->setCursor( QCursor( 2 ) );
#endif
    viewer->getQWidget()->setMouseTracking( TRUE );

#ifdef QT_MODULE_QT3SUPPORT
    viewer->getQWidget()->setFocusPolicy( Qt::StrongFocus );
#else
    viewer->getQWidget()->setFocusPolicy( QWidget::StrongFocus );
#endif

    viewer->setup();

    //#ifdef SOFA_GUI_QTOGREVIEWER
    //	id_timer = startTimer(100);
    //#endif

    /*

    //connect( xmlSave_pushButton, SIGNAL( pressed() ), this, SLOT( saveXML() ) );
    if (filename != "")
    {

    switch(TYPE)
    {
    case NORMAL:
    groot = Simulation::load(filename);
    setScene(groot, filename);
    break;
    case PML:
    #ifdef SOFA_PML
    groot = Simulation::load(scene.c_str());
    if (groot){
    if (!pmlreader) pmlreader = new PMLReader;
    pmlreader->BuildStructure(filename, groot);
    setScene(groot, filename);
    }
    #endif
    break;
    default:break;
    }
    }
    */

    connect( ResetViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( resetView() ) );
    connect( SaveViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( saveView() ) );
    connect( screenshotButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( screenshot() ) );
    connect( sizeW, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeW(int) ) );
    connect( sizeH, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeH(int) ) );
    connect(viewer->getQWidget(), SIGNAL(resizeW(int)), sizeW, SLOT(setValue(int)));
    connect(viewer->getQWidget(), SIGNAL(resizeH(int)), sizeH, SLOT(setValue(int)));

    //startTimer(50);

    QSplitter *splitter_ptr = dynamic_cast<QSplitter *> ( splitter2 );
    splitter_ptr->moveToLast(left_stack);

#ifdef QT_MODULE_QT3SUPPORT
    QList<int> list;
#else
    QValueList<int> list;
#endif
    list.push_back(75);
    list.push_back(500);
    splitter_ptr->setSizes(list);
    viewer->getQWidget()->setFocus();
    viewer->getQWidget()->show();

    setGUI();
}

void RealGUI::viewerOpenGL()
{
    viewerOpenGLAction->setOn(setViewer("qt"));
}

void RealGUI::viewerQGLViewer()
{
    viewerOpenGLAction->setOn(setViewer("qglviewer"));
}

void RealGUI::viewerOGRE()
{
    viewerOpenGLAction->setOn(setViewer("ogre"));
}

bool RealGUI::setViewer(const char* name)
{
    if (!strcmp(name,viewerName))
        return true; // nothing to do
    if (!strcmp(name,"qt"))
    {
#ifndef SOFA_GUI_QTVIEWER
        std::cerr << "OpenGL viewer not activated. Enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else if (!strcmp(name,"qglviewer"))
    {
#ifndef SOFA_GUI_QGLVIEWER
        std::cerr << "QGLViewer viewer not activated. Enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else if (!strcmp(name,"ogre"))
    {
#ifndef SOFA_GUI_QTOGREVIEWER
        std::cerr << "OGRE viewer not activated. Enable SOFA_GUI_QTOGREVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else
    {
        std::cerr << "Unknown viewer.\n";
        return false;
    }
    if ( QMessageBox::warning ( this, "Changing Viewer", "Changing viewer requires to reload the current scene.\nAre you sure you want to do that ?", QMessageBox::Yes | QMessageBox::Default, QMessageBox::No ) != QMessageBox::Yes )
        return false;

    std::string filename = viewer->getSceneFileName();
    GNode* groot = new GNode; // empty scene to do the transition
    setScene(groot,filename.c_str());
    left_stack->removeWidget(viewer->getQWidget());
    delete viewer;
    viewer = NULL;
    // Disable Viewer-specific classes
#ifdef SOFA_GUI_QTVIEWER
    if (!strcmp(viewerName,"qt"))
    {
        sofa::gui::qt::QtViewer::DisableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QGLVIEWER
        if (!strcmp(viewerName,"qglviewer"))
        {
            sofa::gui::guiqglviewer::QtGLViewer::DisableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!strcmp(viewerName,"ogre"))
            {
                sofa::gui::qtogreviewer::QtOgreViewer::DisableViewer();
            }
            else
#endif
            {}
    // Enable Viewer-specific classes
#ifdef SOFA_GUI_QTVIEWER
    if (!strcmp(name,"qt"))
    {
        sofa::gui::qt::QtViewer::EnableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QGLVIEWER
        if (!strcmp(name,"qglviewer"))
        {
            sofa::gui::guiqglviewer::QtGLViewer::EnableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!strcmp(name,"ogre"))
            {
                sofa::gui::qtogreviewer::QtOgreViewer::EnableViewer();
            }
#endif
    std::cerr<<"Test Viewer change!\n";
    viewerName = name;
    std::cerr<<"Add Viewer!\n";
    addViewer();
    std::cerr<<"fileOpen!\n";
    fileOpen(filename.c_str());
    return true;
}

void RealGUI::fileOpen(const char* filename)
{
    //left_stack->removeWidget(viewer->getQWidget());
    //graphListener->removeChild(NULL, groot);
    //delete viewer;
    //viewer = NULL;
    //addViewer(filename);
    GNode* groot = Simulation::load(filename);
    if (groot == NULL)
    {
        qFatal("Failed to load %s",filename);
        return;
    }
    setScene(groot, filename);
}

#ifdef SOFA_PML
void RealGUI::pmlOpen(const char* filename, bool resetView)
{
    std::string scene = "PML/default.scn";
    if (!sofa::helper::system::DataRepository.findFile(scene))
    {
        std::cerr << "File " << scene << " not found " << std::endl;
        return;<commit_msg>r1130/sofa-dev : BUGFIX : when changing of viewer, an empty child of the graph was not removed ( could cause a crash if double-clicked in the graph tab)<commit_after>/*******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 1       *
*                (c) 2006-2007 MGH, INRIA, USTL, UJF, CNRS                     *
*                                                                              *
* 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.                    *
*                                                                              *
* Contact information: <EMAIL>                              *
*                                                                              *
* Authors: <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,     *
* <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,        *
* and <NAME>                                                                 *
*******************************************************************************/

#ifdef SOFA_GUI_QTOGREVIEWER
#include "QtOgreViewer/QtOgreViewer.h"
#endif

#ifdef SOFA_GUI_QTVIEWER
#include "QtViewer/QtViewer.h"
#endif

#ifdef SOFA_GUI_QGLVIEWER
#include "QtGLViewer/QtGLViewer.h"
#endif
#include "RealGUI.h"

#include <sofa/simulation/tree/Simulation.h>
#include <sofa/simulation/tree/MutationListener.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/simulation/automatescheduler/ThreadSimulation.h>
#include <sofa/simulation/automatescheduler/ExecBus.h>
#include <sofa/simulation/automatescheduler/Node.h>

namespace sofa
{
namespace simulation
{
namespace automatescheduler
{
extern simulation::tree::GNode* groot;
}
}
}


#ifdef QT_MODULE_QT3SUPPORT
#include <Q3FileDialog>
#include <QStatusBar>
#include <Q3DockWindow>
#include <Q3ListViewItem>
#include <Q3ListView>
#include <QStackedWidget>
#include <QRadioButton>
#include <QSplitter>
#include <Q3TextEdit>
#include <QCursor>
#include <QWidget>
#include <QLayout>
#include <QTimer>
#include <QAction>
#include <QMessageBox>
#define WIDTH_OFFSET 2
#define HEIGHT_OFFSET 2
#define INFINITY 9.0e10
#else
#include <qlistview.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qstatusbar.h>
#include <qfiledialog.h>
#include <qheader.h>
#include <qimage.h>
#include <qdockwindow.h>
#include <qspinbox.h>
#include <qradiobutton.h>
#include <qsplitter.h>
#include <qtextedit.h>
#include <qcursor.h>
#include <qwidget.h>
#include <qwidgetstack.h>
#include <qlayout.h>
#include <qtimer.h>
#include <qapplication.h>
#include <qaction.h>
#include <qmessagebox.h>

#define WIDTH_OFFSET 0
#define HEIGHT_OFFSET 0
#endif

#include <GenGraphForm.h>
#include "GUIField.h"

#include <sofa/simulation/tree/Colors.h>
#include "WFloatLineEdit.h"
#include <sofa/core/objectmodel/BaseObject.h>
#include <limits.h>


namespace sofa
{

namespace gui
{

namespace guiviewer
{

#ifdef QT_MODULE_QT3SUPPORT
typedef Q3ListView QListView;
typedef Q3FileDialog QFileDialog;
typedef Q3DockWindow QDockWindow;
typedef QStackedWidget QWidgetStack;
typedef Q3TextEdit QTextEdit;
#else
typedef QListViewItem Q3ListViewItem;
typedef QListView Q3ListView;
typedef QFileDialog Q3FileDialog;
//typedef QWidgetStack QStackedWidget;
typedef QTextEdit Q3TextEdit;
#endif


#include "iconnode.xpm"

using sofa::core::objectmodel::BaseObject;

using namespace sofa::helper::system::thread;
using namespace sofa::simulation::tree;
using namespace sofa::simulation::automatescheduler;


///////////////////////////////////////////////////////////
//////////////////// SofaGUI Interface ////////////////////
///////////////////////////////////////////////////////////

#ifdef SOFA_GUI_QGLVIEWER
SOFA_DECL_CLASS(QGLViewerGUI)
int QGLViewerGUIClass = SofaGUI::RegisterGUI("qglviewer", &RealGUI::CreateGUI, &RealGUI::InitGUI, 2);
#endif
#ifdef SOFA_GUI_QTVIEWER
SOFA_DECL_CLASS(QTGUI)
int QtGUIClass = SofaGUI::RegisterGUI("qt", &RealGUI::CreateGUI, &RealGUI::InitGUI, 1);
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
SOFA_DECL_CLASS(OgreGUI)
int QtOGREGUIClass = SofaGUI::RegisterGUI("ogre", &RealGUI::CreateGUI, &RealGUI::InitGUI, 0);
#endif

int RealGUI::InitGUI(const char* name, const std::vector<std::string>& /* options */)
{
#ifdef SOFA_GUI_QGLVIEWER
    if (!name[0] || !strcmp(name,"qglviewer"))
    {
        return sofa::gui::guiqglviewer::QtGLViewer::EnableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QTVIEWER
        if (!name[0] || !strcmp(name,"qt"))
        {
            return sofa::gui::qt::QtViewer::EnableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!name[0] || !strcmp(name,"ogre"))
            {
                return sofa::gui::qtogreviewer::QtOgreViewer::EnableViewer();
            }
            else
#endif
            {
                std::cerr << "ERROR(QtGUI): unknown or disabled gui name "<<name<<std::endl;
                return 1;
            }
}

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

using sofa::simulation::tree::GNode;

SofaGUI* RealGUI::CreateGUI(const char* name, const std::vector<std::string>& options, sofa::simulation::tree::GNode* groot, const char* filename)
{
    {
        int argc=1;
        char* argv[1];
        argv[0] = strdup(SofaGUI::GetProgramName());
        application = new QApplication(argc,argv);
        free(argv[0]);
    }
    // create interface
    gui = new RealGUI( name, options );
    if (groot)
        gui->setScene(groot, filename);

    //gui->viewer->SwitchToPresetView();

    application->setMainWidget( gui );

    // Threads Management
    if (ThreadSimulation::initialized())
    {
        ThreadSimulation::getInstance()->computeVModelsList(groot);
        groot->setMultiThreadSimulation(true);
        sofa::simulation::automatescheduler::groot = groot;

        Automate::setDrawCB(gui->viewer);

        gui->viewer->getQWidget()->update();
        ThreadSimulation::getInstance()->start();
    }
    // show the gui
    gui->show();
    return gui;
}

int RealGUI::mainLoop()
{
    return application->exec();
}

void RealGUI::redraw()
{
    viewer->getQWidget()->update();
}

int RealGUI::closeGUI()
{
    delete this;
    return 0;
}

sofa::simulation::tree::GNode* RealGUI::currentSimulation()
{
    return viewer->getScene();
}

///////////////////////////////////////////////////////////

static const int iconWidth=8;
static const int iconHeight=10;
static const int iconMargin=6;

/*
static QImage* classIcons = NULL;
static const int iconMargin=7;
static const int iconHeight=20;

// mapping; mmapping; constraint; iff; ffield; topology; mass; mstate; solver; bmodel; vmodel; cmodel; pipeline; context; object; gnode;

static const int iconPos[16]=
{
0, // node
1, // object
2, // context
6, // bmodel
4, // cmodel
8, // mstate
13, // constraint
12, // iff
11, // ff
7, // solver
3, // pipeline
14, // mmap
15, // map
9, // mass
10, // topo
5, // vmodel
};

static QImage icons[16];
*/
static int hexval(char c)
{
    if (c>='0' && c<='9') return c-'0';
    else if (c>='a' && c<='f') return (c-'a')+10;
    else if (c>='A' && c<='F') return (c-'A')+10;
    else return 0;
}

static QPixmap* getPixmap(core::objectmodel::Base* obj)
{
    using namespace sofa::simulation::tree::Colors;
    /*
    if (classIcons == NULL)
    {
    classIcons = new QImage("../examples/classicons.png");
    std::cout << "../examples/classicons.png: "<<classIcons->width()<<"x"<<classIcons->height()<<std::endl;
    if (classIcons->height() < 16) return NULL;
    // Find each icon
    QRgb bg = classIcons->pixel(0,0);
    }
    if (classIcons->height() < 16) return NULL;
    */
    unsigned int flags=0;

    if (dynamic_cast<core::objectmodel::BaseNode*>(obj))
    {
        static QPixmap pixNode((const char**)iconnode_xpm);
        return &pixNode;
        //flags |= 1 << NODE;
    }
    else if (dynamic_cast<core::objectmodel::BaseObject*>(obj))
    {
        if (dynamic_cast<core::objectmodel::ContextObject*>(obj))
            flags |= 1 << CONTEXT;
        if (dynamic_cast<core::BehaviorModel*>(obj))
            flags |= 1 << BMODEL;
        if (dynamic_cast<core::CollisionModel*>(obj))
            flags |= 1 << CMODEL;
        if (dynamic_cast<core::componentmodel::behavior::BaseMechanicalState*>(obj))
            flags |= 1 << MMODEL;
        if (dynamic_cast<core::componentmodel::behavior::BaseConstraint*>(obj))
            flags |= 1 << CONSTRAINT;
        if (dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj) &&
            dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj)->getMechModel1()!=dynamic_cast<core::componentmodel::behavior::InteractionForceField*>(obj)->getMechModel2())
            flags |= 1 << IFFIELD;
        else if (dynamic_cast<core::componentmodel::behavior::BaseForceField*>(obj))
            flags |= 1 << FFIELD;
        if (dynamic_cast<core::componentmodel::behavior::MasterSolver*>(obj)
            || dynamic_cast<core::componentmodel::behavior::OdeSolver*>(obj))
            flags |= 1 << SOLVER;
        if (dynamic_cast<core::componentmodel::collision::Pipeline*>(obj)
            || dynamic_cast<core::componentmodel::collision::Intersection*>(obj)
            || dynamic_cast<core::componentmodel::collision::Detection*>(obj)
            || dynamic_cast<core::componentmodel::collision::ContactManager*>(obj)
            || dynamic_cast<core::componentmodel::collision::CollisionGroupManager*>(obj))
            flags |= 1 << COLLISION;
        if (dynamic_cast<core::componentmodel::behavior::BaseMechanicalMapping*>(obj))
            flags |= 1 << MMAPPING;
        else if (dynamic_cast<core::BaseMapping*>(obj))
            flags |= 1 << MAPPING;
        if (dynamic_cast<core::componentmodel::behavior::BaseMass*>(obj))
            flags |= 1 << MASS;
        if (dynamic_cast<core::componentmodel::topology::Topology *>(obj))
            flags |= 1 << TOPOLOGY;
        if (dynamic_cast<core::VisualModel*>(obj) && !flags)
            flags |= 1 << VMODEL;
        if (!flags)
            flags |= 1 << OBJECT;
    }
    else return NULL;

    static std::map<unsigned int, QPixmap*> pixmaps;
    if (!pixmaps.count(flags))
    {
        int nc = 0;
        for (int i=0; i<16; i++)
            if (flags & (1<<i))
                ++nc;
        int nx = 2+iconWidth*nc+iconMargin;
        QImage * img = new QImage(nx,iconHeight,32);
        img->setAlphaBuffer(true);
        img->fill(qRgba(0,0,0,0));
        // Workaround for qt 3.x where fill() does not set the alpha channel
        for (int y=0 ; y < iconHeight ; y++)
            for (int x=0 ; x < nx ; x++)
                img->setPixel(x,y,qRgba(0,0,0,0));

        for (int y=0 ; y < iconHeight ; y++)
            img->setPixel(0,y,qRgba(0,0,0,255));
        nc = 0;
        for (int i=0; i<16; i++)
            if (flags & (1<<i))
            {
                int x0 = 1+iconWidth*nc;
                int x1 = x0+iconWidth-1;
                //QColor c(COLOR[i]);
                const char* color = COLOR[i];
                //c.setAlpha(255);
                int r = (hexval(color[1])*16+hexval(color[2]));
                int g = (hexval(color[3])*16+hexval(color[4]));
                int b = (hexval(color[5])*16+hexval(color[6]));
                int a = 255;
                for (int x=x0; x <=x1 ; x++)
                {
                    img->setPixel(x,0,qRgba(0,0,0,255));
                    img->setPixel(x,iconHeight-1,qRgba(0,0,0,255));
                    for (int y=1 ; y < iconHeight-1 ; y++)
                        //img->setPixel(x,y,c.value());
                        img->setPixel(x,y,qRgba(r,g,b,a));
                }
                //bitBlt(img,nimg*(iconWidth+2),0,classIcons,iconMargin,iconPos[i],iconWidth,iconHeight);
                ++nc;
            }
        for (int y=0 ; y < iconHeight ; y++)
            img->setPixel(2+iconWidth*nc-1,y,qRgba(0,0,0,255));
        pixmaps[flags] = new QPixmap(*img);
        delete img;
    }
    return pixmaps[flags];
}


using sofa::simulation::tree::Simulation;
using sofa::simulation::tree::MutationListener;

// TODO: Move this code somewhere else

class GraphListenerQListView : public MutationListener
{
public:
    Q3ListView* widget;
    std::map<core::objectmodel::Base*, Q3ListViewItem* > items;
    GraphListenerQListView(Q3ListView* w)
        : widget(w)
    {
    }

    Q3ListViewItem* createItem(Q3ListViewItem* parent)
    {
        Q3ListViewItem* last = parent->firstChild();
        if (last == NULL)
            return new Q3ListViewItem(parent);
        while (last->nextSibling()!=NULL)
            last = last->nextSibling();
        return new Q3ListViewItem(parent, last);
    }

    void addChild(GNode* parent, GNode* child)
    {
        if (items.count(child)) return;
        Q3ListViewItem* item;
        if (parent == NULL)
            item = new Q3ListViewItem(widget);
        else if (items.count(parent))
            item = createItem(items[parent]);
        else
        {
            std::cerr << "Graph -> QT ERROR: Unknown parent node "<<parent->getName()<<std::endl;
            return;
        }
        if (std::string(child->getName(),0,7) != "default")
            item->setText(0, child->getName().c_str());
        QPixmap* pix = getPixmap(child);
        if (pix)
            item->setPixmap(0, *pix);
        item->setOpen(true);
        items[child] = item;
        // Add all objects and grand-children
        MutationListener::addChild(parent, child);
    }

    void removeChild(GNode* parent, GNode* child)
    {
        MutationListener::removeChild(parent, child);
        if (items.count(child))
        {
            delete items[child];
            items.erase(child);
        }
    }

    void moveChild(GNode* previous, GNode* parent, GNode* child)
    {
        if (!items.count(child) || !items.count(previous))
        {
            addChild(parent, child);
        }
        else if (!items.count(parent))
        {
            removeChild(previous, child);
        }
        else
        {
            Q3ListViewItem* itemChild = items[child];
            Q3ListViewItem* itemPrevious = items[previous];
            Q3ListViewItem* itemParent = items[parent];
            itemPrevious->takeItem(itemChild);
            itemParent->insertItem(itemChild);
        }
    }

    void addObject(GNode* parent, core::objectmodel::BaseObject* object)
    {
        if (items.count(object)) return;
        Q3ListViewItem* item;
        if (items.count(parent))
            item = createItem(items[parent]);
        else
        {
            std::cerr << "Graph -> QT ERROR: Unknown parent node "<<parent->getName()<<std::endl;
            return;
        }
        std::string name = sofa::helper::gettypename(typeid(*object));
        std::string::size_type pos = name.find('<');
        if (pos != std::string::npos)
            name.erase(pos);
        if (std::string(object->getName(),0,7) != "default")
        {
            name += "  ";
            name += object->getName();
        }
        item->setText(0, name.c_str());
        QPixmap* pix = getPixmap(object);
        if (pix)
            item->setPixmap(0, *pix);
        items[object] = item;
    }

    void removeObject(GNode* /*parent*/, core::objectmodel::BaseObject* object)
    {
        if (items.count(object))
        {
            delete items[object];
            items.erase(object);
        }
    }

    void moveObject(GNode* previous, GNode* parent, core::objectmodel::BaseObject* object)
    {
        if (!items.count(object) || !items.count(previous))
        {
            addObject(parent, object);
        }
        else if (!items.count(parent))
        {
            removeObject(previous, object);
        }
        else
        {
            Q3ListViewItem* itemObject = items[object];
            Q3ListViewItem* itemPrevious = items[previous];
            Q3ListViewItem* itemParent = items[parent];
            itemPrevious->takeItem(itemObject);
            itemParent->insertItem(itemObject);
        }
    }
};

RealGUI::RealGUI( const char* viewername, const std::vector<std::string>& /*options*/)
    : viewerName(viewername), graphListener(NULL), id_timer(-1)
{
    left_stack = new QWidgetStack(splitter2);
#ifndef QT_MODULE_QT3SUPPORT
    GUILayout->addWidget(left_stack);
#endif

    connect( startButton, SIGNAL( toggled(bool) ), this , SLOT( playpauseGUI(bool) ) );

    fpsLabel = new QLabel("9999.9 FPS", statusBar());
    fpsLabel->setAlignment(Qt::AlignRight);
    fpsLabel->setMinimumSize(fpsLabel->sizeHint());
    fpsLabel->clear();

    timeLabel = new QLabel("T: 999.9999 s", statusBar());
    timeLabel->setAlignment(Qt::AlignLeft);
    timeLabel->setMinimumSize(timeLabel->sizeHint());
    timeLabel->clear();


    statusBar()->addWidget(fpsLabel);
    statusBar()->addWidget(timeLabel);

    timerStep = new QTimer(this);
    connect( timerStep, SIGNAL(timeout()), this, SLOT(step()) );
    connect( ResetSceneButton, SIGNAL( clicked() ), this, SLOT( resetScene() ) );
    connect( dtEdit, SIGNAL( textChanged(const QString&) ), this, SLOT( setDt(const QString&) ) );
    //connect( ResetViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( resetView() ) );
    //connect( SaveViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( saveView() ) );
    connect( showVisual, SIGNAL( toggled(bool) ), this, SLOT( slot_showVisual(bool) ) );
    connect( showBehavior, SIGNAL( toggled(bool) ), this, SLOT( slot_showBehavior(bool) ) );
    connect( showCollision, SIGNAL( toggled(bool) ), this, SLOT( slot_showCollision(bool) ) );
    connect( showBoundingCollision, SIGNAL( toggled(bool) ), this, SLOT( slot_showBoundingCollision(bool) ) );
    connect( showMapping, SIGNAL( toggled(bool) ), this, SLOT( slot_showMapping(bool) ) );
    connect( showMechanicalMapping, SIGNAL( toggled(bool) ), this, SLOT( slot_showMechanicalMapping(bool) ) );
    connect( showForceField, SIGNAL( toggled(bool) ), this, SLOT( slot_showForceField(bool) ) );
    connect( showInteractionForceField, SIGNAL( toggled(bool) ), this, SLOT( slot_showInteractionForceField(bool) ) );
    connect( showWireFrame, SIGNAL( toggled(bool) ), this, SLOT( slot_showWireFrame(bool) ) );
    connect( showNormals, SIGNAL( toggled(bool) ), this, SLOT( slot_showNormals(bool) ) );
    connect( stepButton, SIGNAL( clicked() ), this, SLOT( step() ) );
    //connect( screenshotButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( screenshot() ) );
    //connect( xmlSave_pushButton, SIGNAL( pressed() ), this, SLOT( saveXML() ) );
    connect( ExportGraphButton, SIGNAL( clicked() ), this, SLOT( exportGraph() ) );
    //connect( exportGraphAction, SIGNAL( activated() ), viewer, SLOT( exportGraph() ) );
    //connect( sizeW, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeW(int) ) );
    //connect( sizeH, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeH(int) ) );
    connect( dumpStateCheckBox, SIGNAL( toggled(bool) ), this, SLOT( dumpState(bool) ) );
    connect( exportGnuplotFilesCheckbox, SIGNAL(toggled(bool)), this, SLOT(setExportGnuplot(bool)) );
    connect( displayComputationTimeCheckBox, SIGNAL( toggled(bool) ), this, SLOT( displayComputationTime(bool) ) );

    addViewer();

#ifdef SOFA_PML
    pmlreader = NULL;
    lmlreader = NULL;
#endif
}

RealGUI::~RealGUI()
{
#ifdef SOFA_PML
    if(pmlreader)
    {
        delete pmlreader;
        pmlreader = NULL;
    }
    if(lmlreader)
    {
        delete lmlreader;
        lmlreader = NULL;
    }
#endif
}

void RealGUI::init()
{
    id_timer = -1;
    _animationOBJ = false;
    _animationOBJcounter = 0;
    m_dumpState = false;
    m_dumpStateStream = 0;
    m_displayComputationTime = false;
    m_exportGnuplot = false;
}

void RealGUI::addViewer()
{
    init();
    const char* name = viewerName;

    // set menu state
#ifdef SOFA_GUI_QTVIEWER
    viewerOpenGLAction->setEnabled(true);
#else
    viewerOpenGLAction->setEnabled(false);
    viewerOpenGLAction->setToolTip("enable SOFA_GUI_QTVIEWER in sofa-local.cfg to activate");
#endif
    viewerOpenGLAction->setOn(false);
#ifdef SOFA_GUI_QGLVIEWER
    viewerQGLViewerAction->setEnabled(true);
#else
    viewerQGLViewerAction->setEnabled(false);
    viewerQGLViewerAction->setToolTip("enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate");
#endif
    viewerQGLViewerAction->setOn(false);
#ifdef SOFA_GUI_QTOGREVIEWER
    viewerOGREAction->setEnabled(true);
#else
    viewerOGREAction->setEnabled(false);
    viewerOGREAction->setToolTip("enable SOFA_GUI_QTOGREVIEWER in sofa-local.cfg to activate");
#endif
    viewerOGREAction->setOn(false);

#ifdef SOFA_GUI_QGLVIEWER
    if (!name[0] || !strcmp(name,"qglviewer"))
    {
        viewer = new sofa::gui::guiqglviewer::QtGLViewer( left_stack, "viewer" );
        viewerQGLViewerAction->setOn(true);
    }
    else
#endif
#ifdef SOFA_GUI_QTVIEWER
        if (!name[0] || !strcmp(name,"qt"))
        {
            viewer = new sofa::gui::qt::QtViewer( left_stack, "viewer" );
            viewerOpenGLAction->setOn(true);
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!name[0] || !strcmp(name,"ogre"))
            {
                viewer = new sofa::gui::qtogreviewer::QtOgreViewer( left_stack , "viewer" );
                viewerOGREAction->setOn(true);
            }
            else
#endif
            {
                std::cerr << "ERROR(QtGUI): unknown or disabled viewer name "<<name<<std::endl;
                application->exit();
            }

#ifdef QT_MODULE_QT3SUPPORT
    left_stack->addWidget ( viewer->getQWidget() );
    left_stack->setCurrentWidget ( viewer->getQWidget() );
#else
    int id_viewer = left_stack->addWidget(viewer->getQWidget());
    left_stack->raiseWidget(id_viewer);
#endif
    viewer->getQWidget()->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 100, 1,
            viewer->getQWidget()->sizePolicy().hasHeightForWidth() ) );
    viewer->getQWidget()->setMinimumSize( QSize( 0, 0 ) );
#ifndef QT_MODULE_QT3SUPPORT
    viewer->getQWidget()->setCursor( QCursor( 2 ) );
#endif
    viewer->getQWidget()->setMouseTracking( TRUE );

#ifdef QT_MODULE_QT3SUPPORT
    viewer->getQWidget()->setFocusPolicy( Qt::StrongFocus );
#else
    viewer->getQWidget()->setFocusPolicy( QWidget::StrongFocus );
#endif

    viewer->setup();

    //#ifdef SOFA_GUI_QTOGREVIEWER
    //	id_timer = startTimer(100);
    //#endif

    /*

    //connect( xmlSave_pushButton, SIGNAL( pressed() ), this, SLOT( saveXML() ) );
    if (filename != "")
    {

    switch(TYPE)
    {
    case NORMAL:
    groot = Simulation::load(filename);
    setScene(groot, filename);
    break;
    case PML:
    #ifdef SOFA_PML
    groot = Simulation::load(scene.c_str());
    if (groot){
    if (!pmlreader) pmlreader = new PMLReader;
    pmlreader->BuildStructure(filename, groot);
    setScene(groot, filename);
    }
    #endif
    break;
    default:break;
    }
    }
    */

    connect( ResetViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( resetView() ) );
    connect( SaveViewButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( saveView() ) );
    connect( screenshotButton, SIGNAL( clicked() ), viewer->getQWidget(), SLOT( screenshot() ) );
    connect( sizeW, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeW(int) ) );
    connect( sizeH, SIGNAL( valueChanged(int) ), viewer->getQWidget(), SLOT( setSizeH(int) ) );
    connect(viewer->getQWidget(), SIGNAL(resizeW(int)), sizeW, SLOT(setValue(int)));
    connect(viewer->getQWidget(), SIGNAL(resizeH(int)), sizeH, SLOT(setValue(int)));

    //startTimer(50);

    QSplitter *splitter_ptr = dynamic_cast<QSplitter *> ( splitter2 );
    splitter_ptr->moveToLast(left_stack);

#ifdef QT_MODULE_QT3SUPPORT
    QList<int> list;
#else
    QValueList<int> list;
#endif
    list.push_back(75);
    list.push_back(500);
    splitter_ptr->setSizes(list);
    viewer->getQWidget()->setFocus();
    viewer->getQWidget()->show();

    setGUI();
}

void RealGUI::viewerOpenGL()
{
    viewerOpenGLAction->setOn(setViewer("qt"));
}

void RealGUI::viewerQGLViewer()
{
    viewerOpenGLAction->setOn(setViewer("qglviewer"));
}

void RealGUI::viewerOGRE()
{
    viewerOpenGLAction->setOn(setViewer("ogre"));
}

bool RealGUI::setViewer(const char* name)
{
    if (!strcmp(name,viewerName))
        return true; // nothing to do
    if (!strcmp(name,"qt"))
    {
#ifndef SOFA_GUI_QTVIEWER
        std::cerr << "OpenGL viewer not activated. Enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else if (!strcmp(name,"qglviewer"))
    {
#ifndef SOFA_GUI_QGLVIEWER
        std::cerr << "QGLViewer viewer not activated. Enable SOFA_GUI_QGLVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else if (!strcmp(name,"ogre"))
    {
#ifndef SOFA_GUI_QTOGREVIEWER
        std::cerr << "OGRE viewer not activated. Enable SOFA_GUI_QTOGREVIEWER in sofa-local.cfg to activate.\n";
        return false;
#endif
    }
    else
    {
        std::cerr << "Unknown viewer.\n";
        return false;
    }
    if ( QMessageBox::warning ( this, "Changing Viewer", "Changing viewer requires to reload the current scene.\nAre you sure you want to do that ?", QMessageBox::Yes | QMessageBox::Default, QMessageBox::No ) != QMessageBox::Yes )
        return false;

    std::string filename = viewer->getSceneFileName();
    GNode* groot = new GNode; // empty scene to do the transition
    setScene(groot,filename.c_str());
    left_stack->removeWidget(viewer->getQWidget());
    delete viewer;
    viewer = NULL;
    // Disable Viewer-specific classes
#ifdef SOFA_GUI_QTVIEWER
    if (!strcmp(viewerName,"qt"))
    {
        sofa::gui::qt::QtViewer::DisableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QGLVIEWER
        if (!strcmp(viewerName,"qglviewer"))
        {
            sofa::gui::guiqglviewer::QtGLViewer::DisableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!strcmp(viewerName,"ogre"))
            {
                sofa::gui::qtogreviewer::QtOgreViewer::DisableViewer();
            }
            else
#endif
            {}
    // Enable Viewer-specific classes
#ifdef SOFA_GUI_QTVIEWER
    if (!strcmp(name,"qt"))
    {
        sofa::gui::qt::QtViewer::EnableViewer();
    }
    else
#endif
#ifdef SOFA_GUI_QGLVIEWER
        if (!strcmp(name,"qglviewer"))
        {
            sofa::gui::guiqglviewer::QtGLViewer::EnableViewer();
        }
        else
#endif
#ifdef SOFA_GUI_QTOGREVIEWER
            if (!strcmp(name,"ogre"))
            {
                sofa::gui::qtogreviewer::QtOgreViewer::EnableViewer();
            }
#endif

    viewerName = name;
    graphListener->removeChild(NULL, groot);
    addViewer();
    fileOpen(filename.c_str());
    return true;
}

void RealGUI::fileOpen(const char* filename)
{
    //left_stack->removeWidget(viewer->getQWidget());
    //graphListener->removeChild(NULL, groot);
    //delete viewer;
    //viewer = NULL;
    //addViewer(filename);
    GNode* groot = Simulation::load(filename);
    if (groot == NULL)
    {
        qFatal("Failed to load %s",filename);
        return;
    }
    setScene(groot, filename);
}

#ifdef SOFA_PML
void RealGUI::pmlOpen(const char* filename, bool resetView)
{
    std::string scene = "PML/default.scn";
    if (!sofa::helper::system::DataRepository.findFile(scene))
    {
        std::cerr << "File " << scene << " not found " << std::endl;
        return;
{'fraction_non_alphanumeric': 0.15424628264182005, 'fraction_numerical': 0.009807870816330106, 'mean_word_length': 2.7883492569002124, 'pattern_counts': {'":': 0, '<': 391, '<?xml version=': 0, '>': 450, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5203586', 'n_tokens_mistral': 18739, 'n_tokens_neox': 18012, 'n_words': 3661}