ARGoS  3
A parallel, multi-engine simulator for swarm robotics
plugins/simulator/visualizations/qt-opengl/qtopengl_lua_main_window.cpp
Go to the documentation of this file.
00001 
00006 #include "qtopengl_lua_main_window.h"
00007 #include "qtopengl_lua_editor.h"
00008 #include "qtopengl_lua_find_dialog.h"
00009 #include "qtopengl_lua_statetree_model.h"
00010 #include "qtopengl_main_window.h"
00011 #include "qtopengl_widget.h"
00012 
00013 #include <argos3/core/config.h>
00014 #include <argos3/core/wrappers/lua/lua_controller.h>
00015 #include <argos3/core/simulator/simulator.h>
00016 #include <argos3/core/simulator/space/space.h>
00017 #include <argos3/core/simulator/entity/composable_entity.h>
00018 #include <argos3/core/simulator/entity/controllable_entity.h>
00019 #include <argos3/core/wrappers/lua/lua_utility.h>
00020 
00021 #include <QApplication>
00022 #include <QDockWidget>
00023 #include <QFileDialog>
00024 #include <QHeaderView>
00025 #include <QMenu>
00026 #include <QMenuBar>
00027 #include <QMessageBox>
00028 #include <QProcess>
00029 #include <QSettings>
00030 #include <QStatusBar>
00031 #include <QTemporaryFile>
00032 #include <QTextStream>
00033 #include <QToolBar>
00034 #include <QTableWidget>
00035 #include <QTreeView>
00036 
00037 namespace argos {
00038 
00039    /****************************************/
00040    /****************************************/
00041 
00042    static QString SCRIPT_TEMPLATE =
00043       "-- Put your global variables here\n\n\n\n"
00044       "--[[ This function is executed every time you press the 'execute'\n"
00045       "     button ]]\n"
00046       "function init()\n"
00047       "   -- put your code here\n"
00048       "end\n\n\n\n"
00049       "--[[ This function is executed at each time step\n"
00050       "     It must contain the logic of your controller ]]\n"
00051       "function step()\n"
00052       "   -- put your code here\n"
00053       "end\n\n\n\n"
00054       "--[[ This function is executed every time you press the 'reset'\n"
00055       "     button in the GUI. It is supposed to restore the state\n"
00056       "     of the controller to whatever it was right after init() was\n"
00057       "     called. The state of sensors and actuators is reset\n"
00058       "     automatically by ARGoS. ]]\n"
00059       "function reset()\n"
00060       "   -- put your code here\n"
00061       "end\n\n\n\n"
00062       "--[[ This function is executed only once, when the robot is removed\n"
00063       "     from the simulation ]]\n"
00064       "function destroy()\n"
00065       "   -- put your code here\n"
00066       "end\n";
00067 
00068    /****************************************/
00069    /****************************************/
00070 
00071    CQTOpenGLLuaMainWindow::CQTOpenGLLuaMainWindow(CQTOpenGLMainWindow* pc_parent) :
00072       QMainWindow(pc_parent),
00073       m_pcMainWindow(pc_parent),
00074       m_pcStatusbar(NULL),
00075       m_pcCodeEditor(NULL),
00076       m_pcFindDialog(NULL),
00077       m_pcLuaMessageTable(NULL) {
00078       /* Add a status bar */
00079       m_pcStatusbar = new QStatusBar(this);
00080       setStatusBar(m_pcStatusbar);
00081       /* Create the Lua message table */
00082       CreateLuaMessageTable();
00083       /* Populate list of Lua controllers */
00084       PopulateLuaControllers();
00085       /* Create the Lua state docks */
00086       CreateLuaStateDocks();
00087       /* Create editor */
00088       CreateCodeEditor();
00089       /* Create actions */
00090       CreateFileActions();
00091       CreateEditActions();
00092       CreateCodeActions();
00093       /* Set empty file */
00094       SetCurrentFile("");
00095       /* Read settings */
00096       ReadSettings();
00097    }
00098 
00099    /****************************************/
00100    /****************************************/
00101 
00102    CQTOpenGLLuaMainWindow::~CQTOpenGLLuaMainWindow() {
00103       WriteSettings();
00104    }
00105 
00106    /****************************************/
00107    /****************************************/
00108 
00109    void CQTOpenGLLuaMainWindow::New() {
00110       if(MaybeSave()) {
00111          m_pcCodeEditor->setPlainText(SCRIPT_TEMPLATE);
00112          SetCurrentFile("");
00113       }
00114    }
00115 
00116    /****************************************/
00117    /****************************************/
00118 
00119    void CQTOpenGLLuaMainWindow::Open() {
00120       if(MaybeSave()) {
00121          QString strNewFileName =
00122             QFileDialog::getOpenFileName(this,
00123                                          tr("Open File"),
00124                                          "",
00125                                          "Lua Files (*.lua)");
00126          if (!strNewFileName.isEmpty()) {
00127             OpenFile(strNewFileName);
00128          }
00129       }
00130    }
00131 
00132    /****************************************/
00133    /****************************************/
00134 
00135    void CQTOpenGLLuaMainWindow::OpenRecentFile() {
00136       QAction* pcAction = qobject_cast<QAction*>(sender());
00137       if (pcAction) {
00138          OpenFile(pcAction->data().toString());
00139       }
00140    }
00141 
00142    /****************************************/
00143    /****************************************/
00144 
00145    bool CQTOpenGLLuaMainWindow::Save() {
00146       if (m_strFileName.isEmpty()) {
00147          return SaveAs();
00148       } else {
00149          return SaveFile(m_strFileName);
00150       }
00151    }
00152 
00153    /****************************************/
00154    /****************************************/
00155 
00156    bool CQTOpenGLLuaMainWindow::SaveAs() {
00157       QString strNewFileName =
00158          QFileDialog::getSaveFileName(this,
00159                                       tr("Save File"),
00160                                       "",
00161                                       "Lua Files (*.lua)");
00162       if (strNewFileName.isEmpty())
00163          return false;
00164       return SaveFile(strNewFileName);
00165    }
00166 
00167    /****************************************/
00168    /****************************************/
00169 
00170    static QString DetectLuaC() {
00171       QProcess cLuaCompiler;
00172       cLuaCompiler.start("luac", QStringList() << "-v");
00173       /* First, try to execute luac */
00174       if(!cLuaCompiler.waitForStarted()) {
00175          /* luac is not installed */
00176          return "";
00177       }
00178       /* luac is installed, but is it the right version? */
00179       cLuaCompiler.waitForFinished();
00180       if(QString(cLuaCompiler.readAllStandardOutput()).mid(4,3) == "5.1") {
00181          return "luac";
00182       }
00183       cLuaCompiler.start("luac5.1", QStringList() << "-v");
00184       if(!cLuaCompiler.waitForStarted()) {
00185          /* luac51 is not installed */
00186          return "";
00187       }
00188       else {
00189          /* luac51 is installed */
00190          cLuaCompiler.waitForFinished();
00191          return "luac5.1";
00192       }
00193    }
00194 
00195    void CQTOpenGLLuaMainWindow::Execute() {
00196       /* Save script */
00197       Save();
00198       /* Change cursor */
00199       QApplication::setOverrideCursor(Qt::WaitCursor);
00200       /* Stop simulation */
00201       m_pcMainWindow->StopSimulation();
00202       m_pcMainWindow->SimulationCanProceed(true);
00203       /* Clear the message table */
00204       m_pcLuaMessageTable->clearContents();
00205       m_pcLuaMessageTable->setRowCount(1);
00206       /* Create temporary file to contain the bytecode */
00207       QTemporaryFile cByteCode;
00208       if(! cByteCode.open()) {
00209          SetMessage(0, "ALL", "Can't create bytecode file.");
00210          m_pcMainWindow->SimulationCanProceed(false);
00211          QApplication::restoreOverrideCursor();
00212          return;
00213       }
00214       /*
00215        * Compile script
00216        */
00217       /* Check for luac 5.1 */
00218       QString cLuaC = DetectLuaC();
00219       if(cLuaC == "") {
00220          /* luac 5.1 not found, fall back to sending the script directly to robots */
00221          for(size_t i = 0; i < m_vecControllers.size(); ++i) {
00222             m_vecControllers[i]->SetLuaScript(m_strFileName.toStdString());
00223          }
00224       }
00225       else {
00226          QProcess cLuaCompiler;
00227          cLuaCompiler.start(cLuaC, QStringList() << "-o" << cByteCode.fileName() << m_strFileName);
00228          if(! cLuaCompiler.waitForFinished()) {
00229             SetMessage(0, "ALL", QString(cLuaCompiler.readAllStandardError()));
00230             m_pcMainWindow->SimulationCanProceed(false);
00231             QApplication::restoreOverrideCursor();
00232             return;
00233          }
00234          if(cLuaCompiler.exitCode() != 0) {
00235             SetMessage(0, "ALL", QString(cLuaCompiler.readAllStandardError()));
00236             m_pcMainWindow->SimulationCanProceed(false);
00237             QApplication::restoreOverrideCursor();
00238             return;
00239          }
00240          SetMessage(0, "ALL", "Compilation successful.");
00241          /* Set the script for all the robots */
00242          for(size_t i = 0; i < m_vecControllers.size(); ++i) {
00243             m_vecControllers[i]->SetLuaScript(cByteCode.fileName().toStdString());
00244          }
00245       }
00246       /* Update Lua state if visible */
00247       if(m_pcLuaVariableDock->isVisible()) {
00248          static_cast<CQTOpenGLLuaStateTreeModel*>(m_pcLuaVariableTree->model())->SetLuaState(
00249             m_vecControllers[m_unSelectedRobot]->GetLuaState());
00250       }
00251       if(m_pcLuaFunctionDock->isVisible()) {
00252          static_cast<CQTOpenGLLuaStateTreeModel*>(m_pcLuaFunctionTree->model())->SetLuaState(
00253             m_vecControllers[m_unSelectedRobot]->GetLuaState());
00254       }
00255       QApplication::restoreOverrideCursor();
00256       statusBar()->showMessage(tr("Execution started"), 2000);
00257    }
00258 
00259    /****************************************/
00260    /****************************************/
00261 
00262    void CQTOpenGLLuaMainWindow::Find() {
00263       if(! m_pcFindDialog) {
00264          m_pcFindDialog = new CQTOpenGLLuaFindDialog(this);
00265       }
00266       m_pcFindDialog->show();
00267    }
00268 
00269    /****************************************/
00270    /****************************************/
00271 
00272    void CQTOpenGLLuaMainWindow::CodeModified() {
00273       setWindowModified(m_pcCodeEditor->document()->isModified());
00274    }
00275 
00276    /****************************************/
00277    /****************************************/
00278 
00279    bool CQTOpenGLLuaMainWindow::MaybeSave() {
00280       if(m_pcCodeEditor->document()->isModified()) {
00281          QMessageBox::StandardButton tReply;
00282          tReply = QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
00283                                        tr("The document has been modified.\n"
00284                                           "Do you want to save your changes?"),
00285                                        QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
00286          if (tReply == QMessageBox::Save)
00287             return Save();
00288          else if (tReply == QMessageBox::Cancel)
00289             return false;
00290       }
00291       return true;
00292    }
00293 
00294    /****************************************/
00295    /****************************************/
00296 
00297    void CQTOpenGLLuaMainWindow::PopulateLuaControllers() {
00298       /* Get list of controllable entities */
00299       CSpace& cSpace = CSimulator::GetInstance().GetSpace();
00300       CSpace::TMapPerType& tControllables = cSpace.GetEntitiesByType("controller");
00301       /* Go through them and keep a pointer to each Lua controller */
00302       for(CSpace::TMapPerType::iterator it = tControllables.begin();
00303           it != tControllables.end();
00304           ++it) {
00305          /* Try to convert the controller into a Lua controller */
00306          CControllableEntity* pcControllable = any_cast<CControllableEntity*>(it->second);
00307          CLuaController* pcLuaController = dynamic_cast<CLuaController*>(&(pcControllable->GetController()));
00308          if(pcLuaController) {
00309             /* Conversion succeeded, add to indices */
00310             m_vecControllers.push_back(pcLuaController);
00311             m_vecRobots.push_back(&pcControllable->GetParent());
00312          }
00313          else {
00314             LOGERR << "[WARNING] Entity \""
00315                    << pcControllable->GetParent().GetId()
00316                    << "\" does not have a Lua controller associated"
00317                    << std::endl;
00318          }
00319       }
00320    }
00321 
00322    /****************************************/
00323    /****************************************/
00324 
00325    void CQTOpenGLLuaMainWindow::ReadSettings() {
00326       QSettings cSettings;
00327       cSettings.beginGroup("LuaEditor");
00328       resize(cSettings.value("size", QSize(640,480)).toSize());
00329       move(cSettings.value("position", QPoint(0,0)).toPoint());
00330       cSettings.endGroup();
00331    }
00332 
00333    /****************************************/
00334    /****************************************/
00335 
00336    void CQTOpenGLLuaMainWindow::WriteSettings() {
00337       QSettings cSettings;
00338       cSettings.beginGroup("LuaEditor");
00339       cSettings.setValue("size", size());
00340       cSettings.setValue("position", pos());
00341       cSettings.endGroup();
00342    }
00343 
00344    /****************************************/
00345    /****************************************/
00346 
00347    void CQTOpenGLLuaMainWindow::CreateCodeEditor() {
00348       /* Create code editor */
00349       m_pcCodeEditor = new CQTOpenGLLuaEditor(this);
00350       setCentralWidget(m_pcCodeEditor);
00351       m_pcCodeEditor->setPlainText(SCRIPT_TEMPLATE);
00352       /* Connect stuff */
00353       connect(m_pcCodeEditor->document(), SIGNAL(contentsChanged()),
00354               this, SLOT(CodeModified()));
00355       connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
00356               this, SLOT(CheckLuaStatus(int)));
00357    }
00358 
00359    /****************************************/
00360    /****************************************/
00361 
00362    void CQTOpenGLLuaMainWindow::CreateLuaMessageTable() {
00363       m_pcLuaMsgDock = new QDockWidget(tr("Messages"), this);
00364       m_pcLuaMsgDock->setObjectName("LuaMessageDock");
00365       m_pcLuaMsgDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
00366       m_pcLuaMsgDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
00367       m_pcLuaMessageTable = new QTableWidget();
00368       m_pcLuaMessageTable->setColumnCount(3);
00369       QStringList listHeaders;
00370       listHeaders << tr("Robot")
00371                   << tr("Line")
00372                   << tr("Message");
00373       m_pcLuaMessageTable->setHorizontalHeaderLabels(listHeaders);
00374       m_pcLuaMessageTable->horizontalHeader()->setStretchLastSection(true);
00375       m_pcLuaMessageTable->setSelectionBehavior(QAbstractItemView::SelectRows);
00376       m_pcLuaMessageTable->setSelectionMode(QAbstractItemView::SingleSelection);
00377       m_pcLuaMsgDock->setWidget(m_pcLuaMessageTable);
00378       addDockWidget(Qt::BottomDockWidgetArea, m_pcLuaMsgDock);
00379       connect(m_pcLuaMessageTable, SIGNAL(itemSelectionChanged()),
00380               this, SLOT(HandleMsgTableSelection()));
00381       m_pcLuaMsgDock->hide();
00382    }
00383 
00384    /****************************************/
00385    /****************************************/
00386 
00387    void CQTOpenGLLuaMainWindow::CreateLuaStateDocks() {
00388       /* Variable tree dock */
00389       m_pcLuaVariableDock = new QDockWidget(tr("Variables"), this);
00390       m_pcLuaVariableDock->setObjectName("LuaVariableDock");
00391       m_pcLuaVariableDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
00392       m_pcLuaVariableDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
00393       m_pcLuaVariableTree = new QTreeView();
00394       m_pcLuaVariableDock->setWidget(m_pcLuaVariableTree);
00395       addDockWidget(Qt::LeftDockWidgetArea, m_pcLuaVariableDock);
00396       m_pcLuaVariableDock->hide();
00397       /* Function tree dock */
00398       m_pcLuaFunctionDock = new QDockWidget(tr("Functions"), this);
00399       m_pcLuaFunctionDock->setObjectName("LuaFunctionDock");
00400       m_pcLuaFunctionDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
00401       m_pcLuaFunctionDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
00402       m_pcLuaFunctionTree = new QTreeView();
00403       m_pcLuaFunctionDock->setWidget(m_pcLuaFunctionTree);
00404       addDockWidget(Qt::LeftDockWidgetArea, m_pcLuaFunctionDock);
00405       m_pcLuaFunctionDock->hide();
00406       /* Connect stuff */
00407       connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(EntitySelected(size_t)),
00408               this, SLOT(HandleEntitySelection(size_t)));
00409       connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(EntityDeselected(size_t)),
00410               this, SLOT(HandleEntityDeselection(size_t)));
00411    }
00412 
00413    /****************************************/
00414    /****************************************/
00415 
00416    void CQTOpenGLLuaMainWindow::CreateFileActions() {
00417       QIcon cFileNewIcon;
00418       cFileNewIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/new.png"));
00419       m_pcFileNewAction = new QAction(cFileNewIcon, tr("&New"), this);
00420       m_pcFileNewAction->setToolTip(tr("Create a new file"));
00421       m_pcFileNewAction->setStatusTip(tr("Create a new file"));
00422       m_pcFileNewAction->setShortcut(QKeySequence::New);
00423       connect(m_pcFileNewAction, SIGNAL(triggered()),
00424               this, SLOT(New()));
00425       QIcon cFileOpenIcon;
00426       cFileOpenIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/open.png"));
00427       m_pcFileOpenAction = new QAction(cFileOpenIcon, tr("&Open..."), this);
00428       m_pcFileOpenAction->setToolTip(tr("Open a file"));
00429       m_pcFileOpenAction->setStatusTip(tr("Open a file"));
00430       m_pcFileOpenAction->setShortcut(QKeySequence::Open);
00431       connect(m_pcFileOpenAction, SIGNAL(triggered()),
00432               this, SLOT(Open()));
00433       for (int i = 0; i < MAX_RECENT_FILES; ++i) {
00434          m_pcFileOpenRecentAction[i] = new QAction(this);
00435          m_pcFileOpenRecentAction[i]->setVisible(false);
00436          connect(m_pcFileOpenRecentAction[i], SIGNAL(triggered()),
00437                  this, SLOT(OpenRecentFile()));
00438       }
00439       QIcon cFileSaveIcon;
00440       cFileSaveIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/save.png"));
00441       m_pcFileSaveAction = new QAction(cFileSaveIcon, tr("&Save"), this);
00442       m_pcFileSaveAction->setToolTip(tr("Save the current file"));
00443       m_pcFileSaveAction->setStatusTip(tr("Save the current file"));
00444       m_pcFileSaveAction->setShortcut(QKeySequence::Save);
00445       connect(m_pcFileSaveAction, SIGNAL(triggered()),
00446               this, SLOT(Save()));
00447       QIcon cFileSaveAsIcon;
00448       cFileSaveAsIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/saveas.png"));
00449       m_pcFileSaveAsAction = new QAction(cFileSaveAsIcon, tr("S&ave as..."), this);
00450       m_pcFileSaveAsAction->setToolTip(tr("Save the current file under a new name"));
00451       m_pcFileSaveAsAction->setStatusTip(tr("Save the current file under a new name"));
00452       m_pcFileSaveAsAction->setShortcut(QKeySequence::SaveAs);
00453       connect(m_pcFileSaveAsAction, SIGNAL(triggered()),
00454               this, SLOT(SaveAs()));
00455       QMenu* pcMenu = menuBar()->addMenu(tr("&File"));
00456       pcMenu->addAction(m_pcFileNewAction);
00457       pcMenu->addSeparator();
00458       pcMenu->addAction(m_pcFileOpenAction);
00459       pcMenu->addSeparator();
00460       pcMenu->addAction(m_pcFileSaveAction);
00461       pcMenu->addAction(m_pcFileSaveAsAction);
00462       m_pcFileSeparateRecentAction = pcMenu->addSeparator();
00463       for (int i = 0; i < MAX_RECENT_FILES; ++i) {
00464          pcMenu->addAction(m_pcFileOpenRecentAction[i]);
00465       }
00466       QToolBar* pcToolBar = addToolBar(tr("File"));
00467       pcToolBar->setObjectName("FileToolBar");
00468       pcToolBar->addAction(m_pcFileNewAction);
00469       pcToolBar->addAction(m_pcFileOpenAction);
00470       pcToolBar->addAction(m_pcFileSaveAction);
00471       UpdateRecentFiles();
00472    }
00473 
00474    /****************************************/
00475    /****************************************/
00476 
00477    void CQTOpenGLLuaMainWindow::CreateEditActions() {
00478       QIcon cEditUndoIcon;
00479       cEditUndoIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/undo.png"));
00480       m_pcEditUndoAction = new QAction(cEditUndoIcon, tr("&Undo"), this);
00481       m_pcEditUndoAction->setToolTip(tr("Undo last operation"));
00482       m_pcEditUndoAction->setStatusTip(tr("Undo last operation"));
00483       m_pcEditUndoAction->setShortcut(QKeySequence::Undo);
00484       connect(m_pcEditUndoAction, SIGNAL(triggered()),
00485               m_pcCodeEditor, SLOT(undo()));
00486       QIcon cEditRedoIcon;
00487       cEditRedoIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/redo.png"));
00488       m_pcEditRedoAction = new QAction(cEditRedoIcon, tr("&Redo"), this);
00489       m_pcEditRedoAction->setToolTip(tr("Redo last operation"));
00490       m_pcEditRedoAction->setStatusTip(tr("Redo last operation"));
00491       m_pcEditRedoAction->setShortcut(QKeySequence::Redo);
00492       connect(m_pcEditRedoAction, SIGNAL(triggered()),
00493               m_pcCodeEditor, SLOT(redo()));
00494       QIcon cEditCopyIcon;
00495       cEditCopyIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/copy.png"));
00496       m_pcEditCopyAction = new QAction(cEditCopyIcon, tr("&Copy"), this);
00497       m_pcEditCopyAction->setToolTip(tr("Copy selected text into clipboard"));
00498       m_pcEditCopyAction->setStatusTip(tr("Copy selected text into clipboard"));
00499       m_pcEditCopyAction->setShortcut(QKeySequence::Copy);
00500       connect(m_pcEditCopyAction, SIGNAL(triggered()),
00501               m_pcCodeEditor, SLOT(copy()));
00502       QIcon cEditCutIcon;
00503       cEditCutIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/cut.png"));
00504       m_pcEditCutAction = new QAction(cEditCutIcon, tr("&Cut"), this);
00505       m_pcEditCutAction->setToolTip(tr("Move selected text into clipboard"));
00506       m_pcEditCutAction->setStatusTip(tr("Move selected text into clipboard"));
00507       m_pcEditCutAction->setShortcut(QKeySequence::Cut);
00508       connect(m_pcEditCutAction, SIGNAL(triggered()),
00509               m_pcCodeEditor, SLOT(cut()));
00510       QIcon cEditPasteIcon;
00511       cEditPasteIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/paste.png"));
00512       m_pcEditPasteAction = new QAction(cEditPasteIcon, tr("&Paste"), this);
00513       m_pcEditPasteAction->setToolTip(tr("Paste text from clipboard"));
00514       m_pcEditPasteAction->setStatusTip(tr("Paste text from clipboard"));
00515       m_pcEditPasteAction->setShortcut(QKeySequence::Paste);
00516       connect(m_pcEditPasteAction, SIGNAL(triggered()),
00517               m_pcCodeEditor, SLOT(paste()));
00518       // QIcon cEditFindIcon;
00519       // cEditFindIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/find.png"));
00520       // m_pcEditFindAction = new QAction(cEditFindIcon, tr("&Find/Replace"), this);
00521       // m_pcEditFindAction->setToolTip(tr("Find/replace text"));
00522       // m_pcEditFindAction->setStatusTip(tr("Find/replace text"));
00523       // m_pcEditFindAction->setShortcut(QKeySequence::Find);
00524       // connect(m_pcEditFindAction, SIGNAL(triggered()),
00525       //         this, SLOT(Find()));
00526       QMenu* pcMenu = menuBar()->addMenu(tr("&Edit"));
00527       pcMenu->addAction(m_pcEditUndoAction);
00528       pcMenu->addAction(m_pcEditRedoAction);
00529       pcMenu->addSeparator();
00530       pcMenu->addAction(m_pcEditCopyAction);
00531       pcMenu->addAction(m_pcEditCutAction);
00532       pcMenu->addAction(m_pcEditPasteAction);
00533       // pcMenu->addSeparator();
00534       // pcMenu->addAction(m_pcEditFindAction);
00535       QToolBar* pcToolBar = addToolBar(tr("Edit"));
00536       pcToolBar->setObjectName("EditToolBar");
00537       pcToolBar->addAction(m_pcEditUndoAction);
00538       pcToolBar->addAction(m_pcEditRedoAction);
00539       pcToolBar->addSeparator();
00540       pcToolBar->addAction(m_pcEditCopyAction);
00541       pcToolBar->addAction(m_pcEditCutAction);
00542       pcToolBar->addAction(m_pcEditPasteAction);
00543       // pcToolBar->addAction(m_pcEditFindAction);
00544    }
00545 
00546    /****************************************/
00547    /****************************************/
00548 
00549    void CQTOpenGLLuaMainWindow::CreateCodeActions() {
00550       QIcon cCodeExecuteIcon;
00551       cCodeExecuteIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/execute.png"));
00552       m_pcCodeExecuteAction = new QAction(cCodeExecuteIcon, tr("&Execute"), this);
00553       m_pcCodeExecuteAction->setToolTip(tr("Execute code"));
00554       m_pcCodeExecuteAction->setStatusTip(tr("Execute code"));
00555       m_pcCodeExecuteAction->setShortcut(tr("Ctrl+E"));
00556       connect(m_pcCodeExecuteAction, SIGNAL(triggered()),
00557               this, SLOT(Execute()));
00558       QMenu* pcMenu = menuBar()->addMenu(tr("&Code"));
00559       pcMenu->addAction(m_pcCodeExecuteAction);
00560       QToolBar* pcToolBar = addToolBar(tr("Code"));
00561       pcToolBar->setObjectName("CodeToolBar");
00562       pcToolBar->addAction(m_pcCodeExecuteAction);
00563    }
00564 
00565    /****************************************/
00566    /****************************************/
00567 
00568    void CQTOpenGLLuaMainWindow::OpenFile(const QString& str_path) {
00569       QFile cFile(str_path);
00570       if(! cFile.open(QFile::ReadOnly | QFile::Text)) {
00571          QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
00572                               tr("Cannot read file %1:\n%2.")
00573                               .arg(str_path)
00574                               .arg(cFile.errorString()));
00575          return;
00576       }
00577       QApplication::setOverrideCursor(Qt::WaitCursor);
00578       m_pcCodeEditor->setPlainText(cFile.readAll());
00579       QApplication::restoreOverrideCursor();
00580       SetCurrentFile(str_path);
00581       statusBar()->showMessage(tr("File loaded"), 2000);
00582    }
00583 
00584    /****************************************/
00585    /****************************************/
00586 
00587    bool CQTOpenGLLuaMainWindow::SaveFile(const QString& str_path) {
00588       QFile cFile(str_path);
00589       if(! cFile.open(QFile::WriteOnly | QFile::Text)) {
00590          QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
00591                               tr("Cannot write file %1:\n%2.")
00592                               .arg(str_path)
00593                               .arg(cFile.errorString()));
00594          return false;
00595       }
00596       QTextStream cOut(&cFile);
00597       QApplication::setOverrideCursor(Qt::WaitCursor);
00598       cOut << m_pcCodeEditor->toPlainText();
00599       QApplication::restoreOverrideCursor();
00600       SetCurrentFile(str_path);
00601       statusBar()->showMessage(tr("File saved"), 2000);
00602       return true;
00603    }
00604 
00605    /****************************************/
00606    /****************************************/
00607 
00608    void CQTOpenGLLuaMainWindow::SetCurrentFile(const QString& str_path) {
00609       m_strFileName = str_path;
00610       QString strShownName;
00611       if(m_strFileName.isEmpty()) {
00612          strShownName = "untitled";
00613       }
00614       else {
00615          strShownName = StrippedFileName(m_strFileName);
00616       }
00617       setWindowTitle(tr("%1[*] - ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor").arg(strShownName));
00618       if(!m_strFileName.isEmpty()) {
00619          m_pcCodeEditor->document()->setModified(false);
00620          setWindowModified(false);
00621          QSettings cSettings;
00622          cSettings.beginGroup("LuaEditor");
00623          QStringList listFiles = cSettings.value("recent_files").toStringList();
00624          listFiles.removeAll(m_strFileName);
00625          listFiles.prepend(m_strFileName);
00626          while(listFiles.size() > MAX_RECENT_FILES) {
00627             listFiles.removeLast();
00628          }
00629          cSettings.setValue("recent_files", listFiles);
00630          cSettings.endGroup();
00631          UpdateRecentFiles();
00632       }
00633       else {
00634          m_pcCodeEditor->document()->setModified(true);
00635          setWindowModified(true);
00636       }
00637    }
00638 
00639    /****************************************/
00640    /****************************************/
00641 
00642    void CQTOpenGLLuaMainWindow::CheckLuaStatus(int n_step) {
00643       int nRow = 0;
00644       m_pcLuaMessageTable->clearContents();
00645       m_pcLuaMessageTable->setRowCount(m_vecControllers.size());
00646       for(size_t i = 0; i < m_vecControllers.size(); ++i) {
00647          if(! m_vecControllers[i]->IsOK()) {
00648             SetMessage(nRow,
00649                        QString::fromStdString(m_vecControllers[i]->GetId()),
00650                        QString::fromStdString(m_vecControllers[i]->GetErrorMessage()));
00651             ++nRow;
00652          }
00653       }
00654       m_pcLuaMessageTable->setRowCount(nRow);
00655       if(nRow > 0) {
00656          m_pcMainWindow->StopSimulation();
00657          m_pcMainWindow->SimulationCanProceed(false);
00658       }
00659       else {
00660          m_pcLuaMsgDock->hide();
00661       }
00662    }
00663 
00664    /****************************************/
00665    /****************************************/
00666 
00667    void CQTOpenGLLuaMainWindow::HandleMsgTableSelection() {
00668       QList<QTableWidgetItem*> listSel = m_pcLuaMessageTable->selectedItems();
00669       if(! listSel.empty()) {
00670          int nLine = listSel[1]->data(Qt::DisplayRole).toInt();
00671          QTextCursor cCursor = m_pcCodeEditor->textCursor();
00672          int nCurLine = cCursor.blockNumber();
00673          if(nCurLine < nLine) {
00674             cCursor.movePosition(QTextCursor::NextBlock,
00675                                  QTextCursor::MoveAnchor,
00676                                  nLine - nCurLine - 1);
00677          }
00678          else if(nCurLine > nLine) {
00679             cCursor.movePosition(QTextCursor::PreviousBlock,
00680                                  QTextCursor::MoveAnchor,
00681                                  nCurLine - nLine + 1);
00682          }
00683          cCursor.movePosition(QTextCursor::StartOfBlock);
00684          m_pcCodeEditor->setTextCursor(cCursor);
00685          m_pcCodeEditor->setFocus();
00686       }
00687    }
00688 
00689    /****************************************/
00690    /****************************************/
00691 
00692    void CQTOpenGLLuaMainWindow::HandleEntitySelection(size_t un_index) {
00693       CComposableEntity* pcSelectedEntity = dynamic_cast<CComposableEntity*>(CSimulator::GetInstance().GetSpace().GetRootEntityVector()[un_index]);
00694       if(pcSelectedEntity != NULL) {
00695          bool bFound = false;
00696          m_unSelectedRobot = 0;
00697          while(!bFound && m_unSelectedRobot < m_vecRobots.size()) {
00698             if(m_vecRobots[m_unSelectedRobot] == pcSelectedEntity) {
00699                bFound = true;
00700             }
00701             else {
00702                ++m_unSelectedRobot;
00703             }
00704          }
00705          if(bFound &&
00706             m_vecControllers[m_unSelectedRobot]->GetLuaState() != NULL) {
00707             CQTOpenGLLuaStateTreeVariableModel* pcVarModel =
00708                new CQTOpenGLLuaStateTreeVariableModel(m_vecControllers[m_unSelectedRobot]->GetLuaState(),
00709                                                       false,
00710                                                       m_pcLuaVariableTree);
00711             pcVarModel->Refresh();
00712             connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
00713                     pcVarModel, SLOT(Refresh(int)));
00714             connect(m_pcMainWindow, SIGNAL(SimulationReset()),
00715                     pcVarModel, SLOT(Refresh()));
00716             connect(pcVarModel, SIGNAL(modelReset()),
00717                     this, SLOT(VariableTreeChanged()),
00718                     Qt::QueuedConnection);
00719             m_pcLuaVariableTree->setModel(pcVarModel);
00720             m_pcLuaVariableTree->setRootIndex(pcVarModel->index(0, 0));
00721             m_pcLuaVariableTree->expandAll();
00722             m_pcLuaVariableDock->show();
00723             CQTOpenGLLuaStateTreeFunctionModel* pcFunModel =
00724                new CQTOpenGLLuaStateTreeFunctionModel(m_vecControllers[m_unSelectedRobot]->GetLuaState(),
00725                                                       true,
00726                                                       m_pcLuaFunctionTree);
00727             pcFunModel->Refresh();
00728             connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
00729                     pcFunModel, SLOT(Refresh(int)));
00730             connect(m_pcMainWindow, SIGNAL(SimulationReset()),
00731                     pcFunModel, SLOT(Refresh()));
00732             connect(pcFunModel, SIGNAL(modelReset()),
00733                     this, SLOT(FunctionTreeChanged()),
00734                     Qt::QueuedConnection);
00735             m_pcLuaFunctionTree->setModel(pcFunModel);
00736             m_pcLuaFunctionTree->setRootIndex(pcFunModel->index(0, 0));
00737             m_pcLuaFunctionTree->expandAll();
00738             m_pcLuaFunctionDock->show();
00739          }
00740       }
00741    }
00742 
00743    /****************************************/
00744    /****************************************/
00745 
00746    void CQTOpenGLLuaMainWindow::HandleEntityDeselection(size_t) {
00747       disconnect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
00748                  m_pcLuaVariableTree->model(), SLOT(Refresh(int)));
00749       disconnect(m_pcMainWindow, SIGNAL(SimulationReset()),
00750                  m_pcLuaVariableTree->model(), SLOT(Refresh()));
00751       disconnect(m_pcLuaVariableTree->model(), SIGNAL(modelReset()),
00752                  this, SLOT(VariableTreeChanged()));
00753       m_pcLuaVariableDock->hide();
00754       delete m_pcLuaVariableTree->model();
00755       m_pcLuaVariableTree->setModel(NULL);
00756       disconnect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
00757                  m_pcLuaFunctionTree->model(), SLOT(Refresh(int)));
00758       disconnect(m_pcMainWindow, SIGNAL(SimulationReset()),
00759                  m_pcLuaFunctionTree->model(), SLOT(Refresh()));
00760       disconnect(m_pcLuaFunctionTree->model(), SIGNAL(modelReset()),
00761                  this, SLOT(FunctionTreeChanged()));
00762       m_pcLuaFunctionDock->hide();
00763       delete m_pcLuaFunctionTree->model();
00764       m_pcLuaFunctionTree->setModel(NULL);
00765    }
00766 
00767    /****************************************/
00768    /****************************************/
00769 
00770    void CQTOpenGLLuaMainWindow::VariableTreeChanged() {
00771       m_pcLuaVariableTree->setRootIndex(m_pcLuaVariableTree->model()->index(0, 0));
00772       m_pcLuaVariableTree->expandAll();
00773    }
00774 
00775    /****************************************/
00776    /****************************************/
00777 
00778    void CQTOpenGLLuaMainWindow::FunctionTreeChanged() {
00779       m_pcLuaFunctionTree->setRootIndex(m_pcLuaFunctionTree->model()->index(0, 0));
00780       m_pcLuaFunctionTree->expandAll();
00781    }
00782 
00783    /****************************************/
00784    /****************************************/
00785 
00786    void CQTOpenGLLuaMainWindow::UpdateRecentFiles() {
00787       QSettings cSettings;
00788       cSettings.beginGroup("LuaEditor");
00789       QStringList listFiles = cSettings.value("recent_files").toStringList();
00790       int nRecentFiles = qMin(listFiles.size(), (int)MAX_RECENT_FILES);
00791       for(int i = 0; i < nRecentFiles; ++i) {
00792          m_pcFileOpenRecentAction[i]->setText(tr("&%1 %2").arg(i+1).arg(StrippedFileName(listFiles[i])));
00793          m_pcFileOpenRecentAction[i]->setData(listFiles[i]);
00794          m_pcFileOpenRecentAction[i]->setVisible(true);
00795       }
00796       for(int i = nRecentFiles; i < MAX_RECENT_FILES; ++i) {
00797          m_pcFileOpenRecentAction[i]->setVisible(false);
00798       }
00799       m_pcFileSeparateRecentAction->setVisible(nRecentFiles > 0);
00800       cSettings.endGroup();
00801    }
00802 
00803    /****************************************/
00804    /****************************************/
00805 
00806    void CQTOpenGLLuaMainWindow::SetMessage(int n_row,
00807                                            const QString& str_robot_id,
00808                                            const QString& str_message) {
00809       QStringList listFields = str_message.split(":",
00810                                                  QString::KeepEmptyParts,
00811                                                  Qt::CaseInsensitive);
00812       m_pcLuaMessageTable->setItem(
00813          n_row, 0,
00814          new QTableWidgetItem(str_robot_id));
00815       if(listFields.size() == 3) {
00816          m_pcLuaMessageTable->setItem(
00817             n_row, 1,
00818             new QTableWidgetItem(listFields[1]));
00819          m_pcLuaMessageTable->setItem(
00820             n_row, 2,
00821             new QTableWidgetItem(listFields[2]));
00822       }
00823       else if(listFields.size() == 4) {
00824          m_pcLuaMessageTable->setItem(
00825             n_row, 1,
00826             new QTableWidgetItem(listFields[2]));
00827          m_pcLuaMessageTable->setItem(
00828             n_row, 2,
00829             new QTableWidgetItem(listFields[3]));
00830       }
00831       else {
00832          m_pcLuaMessageTable->setItem(
00833             n_row, 2,
00834             new QTableWidgetItem(str_message));
00835       }
00836       m_pcLuaMsgDock->show();
00837    }
00838 
00839    /****************************************/
00840    /****************************************/
00841 
00842    QString CQTOpenGLLuaMainWindow::StrippedFileName(const QString& str_path) {
00843       return QFileInfo(str_path).fileName();
00844    }
00845 
00846    /****************************************/
00847    /****************************************/
00848 
00849    void CQTOpenGLLuaMainWindow::closeEvent(QCloseEvent* pc_event) {
00850       pc_event->ignore();
00851    }
00852 
00853    /****************************************/
00854    /****************************************/
00855 
00856 }