qtopengl_lua_main_window.cpp
Go to the documentation of this file.
1 
7 #include "qtopengl_lua_editor.h"
10 #include "qtopengl_main_window.h"
11 #include "qtopengl_widget.h"
12 
13 #include <argos3/core/config.h>
14 #include <argos3/core/wrappers/lua/lua_controller.h>
15 #include <argos3/core/simulator/simulator.h>
16 #include <argos3/core/simulator/space/space.h>
17 #include <argos3/core/simulator/entity/composable_entity.h>
18 #include <argos3/core/simulator/entity/controllable_entity.h>
19 #include <argos3/core/wrappers/lua/lua_utility.h>
20 
21 #include <QApplication>
22 #include <QDockWidget>
23 #include <QFileDialog>
24 #include <QHeaderView>
25 #include <QMenu>
26 #include <QMenuBar>
27 #include <QMessageBox>
28 #include <QProcess>
29 #include <QSettings>
30 #include <QStatusBar>
31 #include <QTemporaryFile>
32 #include <QTextStream>
33 #include <QToolBar>
34 #include <QTableWidget>
35 #include <QTreeView>
36 
37 namespace argos {
38 
39  /****************************************/
40  /****************************************/
41 
42  static QString SCRIPT_TEMPLATE =
43  "-- Use Shift + Click to select a robot\n"
44  "-- When a robot is selected, its variables appear in this editor\n\n"
45  "-- Use Ctrl + Click (Cmd + Click on Mac) to move a selected robot to a different location\n\n\n\n"
46  "-- Put your global variables here\n\n\n\n"
47  "--[[ This function is executed every time you press the 'execute' button ]]\n"
48  "function init()\n"
49  " -- put your code here\n"
50  "end\n\n\n\n"
51  "--[[ This function is executed at each time step\n"
52  " It must contain the logic of your controller ]]\n"
53  "function step()\n"
54  " -- put your code here\n"
55  "end\n\n\n\n"
56  "--[[ This function is executed every time you press the 'reset'\n"
57  " button in the GUI. It is supposed to restore the state\n"
58  " of the controller to whatever it was right after init() was\n"
59  " called. The state of sensors and actuators is reset\n"
60  " automatically by ARGoS. ]]\n"
61  "function reset()\n"
62  " -- put your code here\n"
63  "end\n\n\n\n"
64  "--[[ This function is executed only once, when the robot is removed\n"
65  " from the simulation ]]\n"
66  "function destroy()\n"
67  " -- put your code here\n"
68  "end\n";
69 
70  /****************************************/
71  /****************************************/
72 
74  QMainWindow(pc_parent),
75  m_pcMainWindow(pc_parent),
76  m_pcStatusbar(NULL),
77  m_pcCodeEditor(NULL),
78  m_pcFindDialog(NULL),
79  m_pcLuaMessageTable(NULL) {
80  /* Add a status bar */
81  m_pcStatusbar = new QStatusBar(this);
82  setStatusBar(m_pcStatusbar);
83  /* Create the Lua message table */
84  CreateLuaMessageTable();
85  /* Populate list of Lua controllers */
86  PopulateLuaControllers();
87  /* Create the Lua state docks */
88  CreateLuaStateDocks();
89  /* Create editor */
90  CreateCodeEditor();
91  /* Create actions */
92  CreateFileActions();
93  CreateEditActions();
94  CreateCodeActions();
95  /* Set empty file */
96  SetCurrentFile("");
97  /* Read settings */
98  ReadSettings();
99  }
100 
101  /****************************************/
102  /****************************************/
103 
105  WriteSettings();
106  }
107 
108  /****************************************/
109  /****************************************/
110 
112  if(MaybeSave()) {
113  m_pcCodeEditor->setPlainText(SCRIPT_TEMPLATE);
114  SetCurrentFile("");
115  }
116  }
117 
118  /****************************************/
119  /****************************************/
120 
122  if(MaybeSave()) {
123  QString strNewFileName =
124  QFileDialog::getOpenFileName(this,
125  tr("Open File"),
126  "",
127  "Lua Files (*.lua)");
128  if (!strNewFileName.isEmpty()) {
129  OpenFile(strNewFileName);
130  }
131  }
132  }
133 
134  /****************************************/
135  /****************************************/
136 
138  QAction* pcAction = qobject_cast<QAction*>(sender());
139  if (pcAction) {
140  OpenFile(pcAction->data().toString());
141  }
142  }
143 
144  /****************************************/
145  /****************************************/
146 
148  if (m_strFileName.isEmpty()) {
149  return SaveAs();
150  } else {
151  return SaveFile(m_strFileName);
152  }
153  }
154 
155  /****************************************/
156  /****************************************/
157 
159  QString strNewFileName =
160  QFileDialog::getSaveFileName(this,
161  tr("Save File"),
162  "",
163  "Lua Files (*.lua)");
164  if (strNewFileName.isEmpty())
165  return false;
166  return SaveFile(strNewFileName);
167  }
168 
169  /****************************************/
170  /****************************************/
171 
172  static QString DetectLuaC() {
173  QProcess cLuaCompiler;
174  cLuaCompiler.start("luac", QStringList() << "-v");
175  /* First, try to execute luac */
176  if(!cLuaCompiler.waitForStarted()) {
177  /* luac is not installed */
178  return "";
179  }
180  /* luac is installed, but is it the right version? */
181  cLuaCompiler.waitForFinished();
182  if(QString(cLuaCompiler.readAllStandardOutput()).mid(4,3) == "5.2") {
183  return "luac";
184  }
185  cLuaCompiler.start("luac5.2", QStringList() << "-v");
186  if(!cLuaCompiler.waitForStarted()) {
187  /* luac52 is not installed */
188  return "";
189  }
190  else {
191  /* luac52 is installed */
192  cLuaCompiler.waitForFinished();
193  return "luac5.2";
194  }
195  }
196 
198  /* Save script */
199  Save();
200  /* Change cursor */
201  QApplication::setOverrideCursor(Qt::WaitCursor);
202  /* Stop simulation */
203  m_pcMainWindow->SuspendExperiment();
204  /* Clear the message table */
205  m_pcLuaMessageTable->clearContents();
206  m_pcLuaMessageTable->setRowCount(1);
207  /* Create temporary file to contain the bytecode */
208  QTemporaryFile cByteCode;
209  if(! cByteCode.open()) {
210  SetMessage(0, "ALL", "Can't create bytecode file.");
211  QApplication::restoreOverrideCursor();
212  return;
213  }
214  /*
215  * Compile script
216  */
217  /* Check for luac 5.2 */
218  QString cLuaC = DetectLuaC();
219  if(cLuaC == "") {
220  /* luac 5.2 not found, fall back to sending the script directly to robots */
221  for(size_t i = 0; i < m_vecControllers.size(); ++i) {
222  m_vecControllers[i]->SetLuaScript(m_strFileName.toStdString());
223  }
224  }
225  else {
226  QProcess cLuaCompiler;
227  cLuaCompiler.start(cLuaC, QStringList() << "-o" << cByteCode.fileName() << m_strFileName);
228  if(! cLuaCompiler.waitForFinished()) {
229  SetMessage(0, "ALL", QString(cLuaCompiler.readAllStandardError()));
230  QApplication::restoreOverrideCursor();
231  return;
232  }
233  if(cLuaCompiler.exitCode() != 0) {
234  SetMessage(0, "ALL", QString(cLuaCompiler.readAllStandardError()));
235  QApplication::restoreOverrideCursor();
236  return;
237  }
238  SetMessage(0, "ALL", "Compilation successful.");
239  /* Set the script for all the robots */
240  for(size_t i = 0; i < m_vecControllers.size(); ++i) {
241  m_vecControllers[i]->SetLuaScript(cByteCode.fileName().toStdString());
242  }
243  }
244  /* Update Lua state if visible */
245  if(m_pcLuaVariableDock->isVisible()) {
246  static_cast<CQTOpenGLLuaStateTreeModel*>(m_pcLuaVariableTree->model())->SetLuaState(
247  m_vecControllers[m_unSelectedRobot]->GetLuaState());
248  }
249  if(m_pcLuaFunctionDock->isVisible()) {
250  static_cast<CQTOpenGLLuaStateTreeModel*>(m_pcLuaFunctionTree->model())->SetLuaState(
251  m_vecControllers[m_unSelectedRobot]->GetLuaState());
252  }
253  /* Resume simulation */
254  m_pcMainWindow->ResumeExperiment();
255  QApplication::restoreOverrideCursor();
256  statusBar()->showMessage(tr("Execution started"), 2000);
257  }
258 
259  /****************************************/
260  /****************************************/
261 
263  if(! m_pcFindDialog) {
264  m_pcFindDialog = new CQTOpenGLLuaFindDialog(this);
265  }
266  m_pcFindDialog->show();
267  }
268 
269  /****************************************/
270  /****************************************/
271 
273  setWindowModified(m_pcCodeEditor->document()->isModified());
274  }
275 
276  /****************************************/
277  /****************************************/
278 
279  bool CQTOpenGLLuaMainWindow::MaybeSave() {
280  if(m_pcCodeEditor->document()->isModified()) {
281  QMessageBox::StandardButton tReply;
282  tReply = QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
283  tr("The document has been modified.\n"
284  "Do you want to save your changes?"),
285  QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
286  if (tReply == QMessageBox::Save)
287  return Save();
288  else if (tReply == QMessageBox::Cancel)
289  return false;
290  }
291  return true;
292  }
293 
294  /****************************************/
295  /****************************************/
296 
297  void CQTOpenGLLuaMainWindow::PopulateLuaControllers() {
298  /* Get list of controllable entities */
299  CSpace& cSpace = CSimulator::GetInstance().GetSpace();
300  CSpace::TMapPerType& tControllables = cSpace.GetEntitiesByType("controller");
301  /* Go through them and keep a pointer to each Lua controller */
302  for(CSpace::TMapPerType::iterator it = tControllables.begin();
303  it != tControllables.end();
304  ++it) {
305  /* Try to convert the controller into a Lua controller */
306  CControllableEntity* pcControllable = any_cast<CControllableEntity*>(it->second);
307  CLuaController* pcLuaController = dynamic_cast<CLuaController*>(&(pcControllable->GetController()));
308  if(pcLuaController) {
309  /* Conversion succeeded, add to indices */
310  m_vecControllers.push_back(pcLuaController);
311  m_vecRobots.push_back(&pcControllable->GetParent());
312  }
313  else {
314  LOGERR << "[WARNING] Entity \""
315  << pcControllable->GetParent().GetId()
316  << "\" does not have a Lua controller associated"
317  << std::endl;
318  }
319  }
320  }
321 
322  /****************************************/
323  /****************************************/
324 
325  void CQTOpenGLLuaMainWindow::ReadSettings() {
326  QSettings cSettings;
327  cSettings.beginGroup("LuaEditor");
328  resize(cSettings.value("size", QSize(640,480)).toSize());
329  move(cSettings.value("position", QPoint(0,0)).toPoint());
330  cSettings.endGroup();
331  }
332 
333  /****************************************/
334  /****************************************/
335 
336  void CQTOpenGLLuaMainWindow::WriteSettings() {
337  QSettings cSettings;
338  cSettings.beginGroup("LuaEditor");
339  cSettings.setValue("size", size());
340  cSettings.setValue("position", pos());
341  cSettings.endGroup();
342  }
343 
344  /****************************************/
345  /****************************************/
346 
347  void CQTOpenGLLuaMainWindow::CreateCodeEditor() {
348  /* Create code editor */
349  m_pcCodeEditor = new CQTOpenGLLuaEditor(this);
350  setCentralWidget(m_pcCodeEditor);
351  m_pcCodeEditor->setPlainText(SCRIPT_TEMPLATE);
352  /* Connect stuff */
353  connect(m_pcCodeEditor->document(), SIGNAL(contentsChanged()),
354  this, SLOT(CodeModified()));
355  connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
356  this, SLOT(CheckLuaStatus(int)));
357  }
358 
359  /****************************************/
360  /****************************************/
361 
362  void CQTOpenGLLuaMainWindow::CreateLuaMessageTable() {
363  m_pcLuaMsgDock = new QDockWidget(tr("Messages"), this);
364  m_pcLuaMsgDock->setObjectName("LuaMessageDock");
365  m_pcLuaMsgDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
366  m_pcLuaMsgDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
367  m_pcLuaMessageTable = new QTableWidget();
368  m_pcLuaMessageTable->setColumnCount(3);
369  QStringList listHeaders;
370  listHeaders << tr("Robot")
371  << tr("Line")
372  << tr("Message");
373  m_pcLuaMessageTable->setHorizontalHeaderLabels(listHeaders);
374  m_pcLuaMessageTable->horizontalHeader()->setStretchLastSection(true);
375  m_pcLuaMessageTable->setSelectionBehavior(QAbstractItemView::SelectRows);
376  m_pcLuaMessageTable->setSelectionMode(QAbstractItemView::SingleSelection);
377  m_pcLuaMsgDock->setWidget(m_pcLuaMessageTable);
378  addDockWidget(Qt::BottomDockWidgetArea, m_pcLuaMsgDock);
379  connect(m_pcLuaMessageTable, SIGNAL(itemSelectionChanged()),
380  this, SLOT(HandleMsgTableSelection()));
381  m_pcLuaMsgDock->hide();
382  }
383 
384  /****************************************/
385  /****************************************/
386 
387  void CQTOpenGLLuaMainWindow::CreateLuaStateDocks() {
388  /* Variable tree dock */
389  m_pcLuaVariableDock = new QDockWidget(tr("Variables"), this);
390  m_pcLuaVariableDock->setObjectName("LuaVariableDock");
391  m_pcLuaVariableDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
392  m_pcLuaVariableDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
393  m_pcLuaVariableTree = new QTreeView();
394  m_pcLuaVariableDock->setWidget(m_pcLuaVariableTree);
395  addDockWidget(Qt::LeftDockWidgetArea, m_pcLuaVariableDock);
396  m_pcLuaVariableDock->hide();
397  /* Function tree dock */
398  m_pcLuaFunctionDock = new QDockWidget(tr("Functions"), this);
399  m_pcLuaFunctionDock->setObjectName("LuaFunctionDock");
400  m_pcLuaFunctionDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
401  m_pcLuaFunctionDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
402  m_pcLuaFunctionTree = new QTreeView();
403  m_pcLuaFunctionDock->setWidget(m_pcLuaFunctionTree);
404  addDockWidget(Qt::LeftDockWidgetArea, m_pcLuaFunctionDock);
405  m_pcLuaFunctionDock->hide();
406  /* Connect stuff */
407  connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(EntitySelected(CEntity*)),
408  this, SLOT(HandleEntitySelection(CEntity*)));
409  connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(EntityDeselected(CEntity*)),
410  this, SLOT(HandleEntityDeselection(CEntity*)));
411  }
412 
413  /****************************************/
414  /****************************************/
415 
416  void CQTOpenGLLuaMainWindow::CreateFileActions() {
417  QIcon cFileNewIcon;
418  cFileNewIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/new.png"));
419  m_pcFileNewAction = new QAction(cFileNewIcon, tr("&New"), this);
420  m_pcFileNewAction->setToolTip(tr("Create a new file"));
421  m_pcFileNewAction->setStatusTip(tr("Create a new file"));
422  m_pcFileNewAction->setShortcut(QKeySequence::New);
423  connect(m_pcFileNewAction, SIGNAL(triggered()),
424  this, SLOT(New()));
425  QIcon cFileOpenIcon;
426  cFileOpenIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/open.png"));
427  m_pcFileOpenAction = new QAction(cFileOpenIcon, tr("&Open..."), this);
428  m_pcFileOpenAction->setToolTip(tr("Open a file"));
429  m_pcFileOpenAction->setStatusTip(tr("Open a file"));
430  m_pcFileOpenAction->setShortcut(QKeySequence::Open);
431  connect(m_pcFileOpenAction, SIGNAL(triggered()),
432  this, SLOT(Open()));
433  for (int i = 0; i < MAX_RECENT_FILES; ++i) {
434  m_pcFileOpenRecentAction[i] = new QAction(this);
435  m_pcFileOpenRecentAction[i]->setVisible(false);
436  connect(m_pcFileOpenRecentAction[i], SIGNAL(triggered()),
437  this, SLOT(OpenRecentFile()));
438  }
439  QIcon cFileSaveIcon;
440  cFileSaveIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/save.png"));
441  m_pcFileSaveAction = new QAction(cFileSaveIcon, tr("&Save"), this);
442  m_pcFileSaveAction->setToolTip(tr("Save the current file"));
443  m_pcFileSaveAction->setStatusTip(tr("Save the current file"));
444  m_pcFileSaveAction->setShortcut(QKeySequence::Save);
445  connect(m_pcFileSaveAction, SIGNAL(triggered()),
446  this, SLOT(Save()));
447  QIcon cFileSaveAsIcon;
448  cFileSaveAsIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/saveas.png"));
449  m_pcFileSaveAsAction = new QAction(cFileSaveAsIcon, tr("S&ave as..."), this);
450  m_pcFileSaveAsAction->setToolTip(tr("Save the current file under a new name"));
451  m_pcFileSaveAsAction->setStatusTip(tr("Save the current file under a new name"));
452  m_pcFileSaveAsAction->setShortcut(QKeySequence::SaveAs);
453  connect(m_pcFileSaveAsAction, SIGNAL(triggered()),
454  this, SLOT(SaveAs()));
455  QMenu* pcMenu = menuBar()->addMenu(tr("&File"));
456  pcMenu->addAction(m_pcFileNewAction);
457  pcMenu->addSeparator();
458  pcMenu->addAction(m_pcFileOpenAction);
459  pcMenu->addSeparator();
460  pcMenu->addAction(m_pcFileSaveAction);
461  pcMenu->addAction(m_pcFileSaveAsAction);
462  m_pcFileSeparateRecentAction = pcMenu->addSeparator();
463  for (int i = 0; i < MAX_RECENT_FILES; ++i) {
464  pcMenu->addAction(m_pcFileOpenRecentAction[i]);
465  }
466  QToolBar* pcToolBar = addToolBar(tr("File"));
467  pcToolBar->setObjectName("FileToolBar");
468  pcToolBar->setIconSize(QSize(32,32));
469  pcToolBar->addAction(m_pcFileNewAction);
470  pcToolBar->addAction(m_pcFileOpenAction);
471  pcToolBar->addAction(m_pcFileSaveAction);
472  UpdateRecentFiles();
473  }
474 
475  /****************************************/
476  /****************************************/
477 
478  void CQTOpenGLLuaMainWindow::CreateEditActions() {
479  QIcon cEditUndoIcon;
480  cEditUndoIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/undo.png"));
481  m_pcEditUndoAction = new QAction(cEditUndoIcon, tr("&Undo"), this);
482  m_pcEditUndoAction->setToolTip(tr("Undo last operation"));
483  m_pcEditUndoAction->setStatusTip(tr("Undo last operation"));
484  m_pcEditUndoAction->setShortcut(QKeySequence::Undo);
485  connect(m_pcEditUndoAction, SIGNAL(triggered()),
486  m_pcCodeEditor, SLOT(undo()));
487  QIcon cEditRedoIcon;
488  cEditRedoIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/redo.png"));
489  m_pcEditRedoAction = new QAction(cEditRedoIcon, tr("&Redo"), this);
490  m_pcEditRedoAction->setToolTip(tr("Redo last operation"));
491  m_pcEditRedoAction->setStatusTip(tr("Redo last operation"));
492  m_pcEditRedoAction->setShortcut(QKeySequence::Redo);
493  connect(m_pcEditRedoAction, SIGNAL(triggered()),
494  m_pcCodeEditor, SLOT(redo()));
495  QIcon cEditCopyIcon;
496  cEditCopyIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/copy.png"));
497  m_pcEditCopyAction = new QAction(cEditCopyIcon, tr("&Copy"), this);
498  m_pcEditCopyAction->setToolTip(tr("Copy selected text into clipboard"));
499  m_pcEditCopyAction->setStatusTip(tr("Copy selected text into clipboard"));
500  m_pcEditCopyAction->setShortcut(QKeySequence::Copy);
501  connect(m_pcEditCopyAction, SIGNAL(triggered()),
502  m_pcCodeEditor, SLOT(copy()));
503  QIcon cEditCutIcon;
504  cEditCutIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/cut.png"));
505  m_pcEditCutAction = new QAction(cEditCutIcon, tr("&Cut"), this);
506  m_pcEditCutAction->setToolTip(tr("Move selected text into clipboard"));
507  m_pcEditCutAction->setStatusTip(tr("Move selected text into clipboard"));
508  m_pcEditCutAction->setShortcut(QKeySequence::Cut);
509  connect(m_pcEditCutAction, SIGNAL(triggered()),
510  m_pcCodeEditor, SLOT(cut()));
511  QIcon cEditPasteIcon;
512  cEditPasteIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/paste.png"));
513  m_pcEditPasteAction = new QAction(cEditPasteIcon, tr("&Paste"), this);
514  m_pcEditPasteAction->setToolTip(tr("Paste text from clipboard"));
515  m_pcEditPasteAction->setStatusTip(tr("Paste text from clipboard"));
516  m_pcEditPasteAction->setShortcut(QKeySequence::Paste);
517  connect(m_pcEditPasteAction, SIGNAL(triggered()),
518  m_pcCodeEditor, SLOT(paste()));
519  // QIcon cEditFindIcon;
520  // cEditFindIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/find.png"));
521  // m_pcEditFindAction = new QAction(cEditFindIcon, tr("&Find/Replace"), this);
522  // m_pcEditFindAction->setToolTip(tr("Find/replace text"));
523  // m_pcEditFindAction->setStatusTip(tr("Find/replace text"));
524  // m_pcEditFindAction->setShortcut(QKeySequence::Find);
525  // connect(m_pcEditFindAction, SIGNAL(triggered()),
526  // this, SLOT(Find()));
527  QMenu* pcMenu = menuBar()->addMenu(tr("&Edit"));
528  pcMenu->addAction(m_pcEditUndoAction);
529  pcMenu->addAction(m_pcEditRedoAction);
530  pcMenu->addSeparator();
531  pcMenu->addAction(m_pcEditCopyAction);
532  pcMenu->addAction(m_pcEditCutAction);
533  pcMenu->addAction(m_pcEditPasteAction);
534  // pcMenu->addSeparator();
535  // pcMenu->addAction(m_pcEditFindAction);
536  QToolBar* pcToolBar = addToolBar(tr("Edit"));
537  pcToolBar->setObjectName("EditToolBar");
538  pcToolBar->setIconSize(QSize(32,32));
539  pcToolBar->addAction(m_pcEditUndoAction);
540  pcToolBar->addAction(m_pcEditRedoAction);
541  pcToolBar->addSeparator();
542  pcToolBar->addAction(m_pcEditCopyAction);
543  pcToolBar->addAction(m_pcEditCutAction);
544  pcToolBar->addAction(m_pcEditPasteAction);
545  // pcToolBar->addAction(m_pcEditFindAction);
546  }
547 
548  /****************************************/
549  /****************************************/
550 
551  void CQTOpenGLLuaMainWindow::CreateCodeActions() {
552  QIcon cCodeExecuteIcon;
553  cCodeExecuteIcon.addPixmap(QPixmap(m_pcMainWindow->GetIconDir() + "/execute.png"));
554  m_pcCodeExecuteAction = new QAction(cCodeExecuteIcon, tr("&Execute"), this);
555  m_pcCodeExecuteAction->setToolTip(tr("Execute code"));
556  m_pcCodeExecuteAction->setStatusTip(tr("Execute code"));
557  m_pcCodeExecuteAction->setShortcut(tr("Ctrl+E"));
558  connect(m_pcCodeExecuteAction, SIGNAL(triggered()),
559  this, SLOT(Execute()));
560  QMenu* pcMenu = menuBar()->addMenu(tr("&Code"));
561  pcMenu->addAction(m_pcCodeExecuteAction);
562  QToolBar* pcToolBar = addToolBar(tr("Code"));
563  pcToolBar->setObjectName("CodeToolBar");
564  pcToolBar->setIconSize(QSize(32,32));
565  pcToolBar->addAction(m_pcCodeExecuteAction);
566  }
567 
568  /****************************************/
569  /****************************************/
570 
571  void CQTOpenGLLuaMainWindow::OpenFile(const QString& str_path) {
572  QFile cFile(str_path);
573  if(! cFile.open(QFile::ReadOnly | QFile::Text)) {
574  QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
575  tr("Cannot read file %1:\n%2.")
576  .arg(str_path)
577  .arg(cFile.errorString()));
578  return;
579  }
580  QApplication::setOverrideCursor(Qt::WaitCursor);
581  m_pcCodeEditor->setPlainText(cFile.readAll());
582  QApplication::restoreOverrideCursor();
583  SetCurrentFile(str_path);
584  statusBar()->showMessage(tr("File loaded"), 2000);
585  }
586 
587  /****************************************/
588  /****************************************/
589 
590  bool CQTOpenGLLuaMainWindow::SaveFile(const QString& str_path) {
591  QFile cFile(str_path);
592  if(! cFile.open(QFile::WriteOnly | QFile::Text)) {
593  QMessageBox::warning(this, tr("ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor"),
594  tr("Cannot write file %1:\n%2.")
595  .arg(str_path)
596  .arg(cFile.errorString()));
597  return false;
598  }
599  QTextStream cOut(&cFile);
600  QApplication::setOverrideCursor(Qt::WaitCursor);
601  cOut << m_pcCodeEditor->toPlainText();
602  QApplication::restoreOverrideCursor();
603  SetCurrentFile(str_path);
604  statusBar()->showMessage(tr("File saved"), 2000);
605  return true;
606  }
607 
608  /****************************************/
609  /****************************************/
610 
611  void CQTOpenGLLuaMainWindow::SetCurrentFile(const QString& str_path) {
612  m_strFileName = str_path;
613  QString strShownName;
614  if(m_strFileName.isEmpty()) {
615  strShownName = "untitled";
616  }
617  else {
618  strShownName = StrippedFileName(m_strFileName);
619  }
620  setWindowTitle(tr("%1[*] - ARGoS v" ARGOS_VERSION "-" ARGOS_RELEASE " - Lua Editor").arg(strShownName));
621  if(!m_strFileName.isEmpty()) {
622  m_pcCodeEditor->document()->setModified(false);
623  setWindowModified(false);
624  QSettings cSettings;
625  cSettings.beginGroup("LuaEditor");
626  QStringList listFiles = cSettings.value("recent_files").toStringList();
627  listFiles.removeAll(m_strFileName);
628  listFiles.prepend(m_strFileName);
629  while(listFiles.size() > MAX_RECENT_FILES) {
630  listFiles.removeLast();
631  }
632  cSettings.setValue("recent_files", listFiles);
633  cSettings.endGroup();
634  UpdateRecentFiles();
635  }
636  else {
637  m_pcCodeEditor->document()->setModified(true);
638  setWindowModified(true);
639  }
640  }
641 
642  /****************************************/
643  /****************************************/
644 
646  int nRow = 0;
647  m_pcLuaMessageTable->clearContents();
648  m_pcLuaMessageTable->setRowCount(m_vecControllers.size());
649  for(size_t i = 0; i < m_vecControllers.size(); ++i) {
650  if(! m_vecControllers[i]->IsOK()) {
651  SetMessage(nRow,
652  QString::fromStdString(m_vecControllers[i]->GetId()),
653  QString::fromStdString(m_vecControllers[i]->GetErrorMessage()));
654  ++nRow;
655  }
656  }
657  m_pcLuaMessageTable->setRowCount(nRow);
658  if(nRow > 0) {
659  m_pcMainWindow->SuspendExperiment();
660  }
661  else {
662  m_pcLuaMsgDock->hide();
663  }
664  }
665 
666  /****************************************/
667  /****************************************/
668 
670  QList<QTableWidgetItem*> listSel = m_pcLuaMessageTable->selectedItems();
671  if(! listSel.empty()) {
672  int nLine = listSel[1]->data(Qt::DisplayRole).toInt();
673  QTextCursor cCursor = m_pcCodeEditor->textCursor();
674  int nCurLine = cCursor.blockNumber();
675  if(nCurLine < nLine) {
676  cCursor.movePosition(QTextCursor::NextBlock,
677  QTextCursor::MoveAnchor,
678  nLine - nCurLine - 1);
679  }
680  else if(nCurLine > nLine) {
681  cCursor.movePosition(QTextCursor::PreviousBlock,
682  QTextCursor::MoveAnchor,
683  nCurLine - nLine + 1);
684  }
685  cCursor.movePosition(QTextCursor::StartOfBlock);
686  m_pcCodeEditor->setTextCursor(cCursor);
687  m_pcCodeEditor->setFocus();
688  }
689  }
690 
691  /****************************************/
692  /****************************************/
693 
695  CComposableEntity* pcSelectedEntity = dynamic_cast<CComposableEntity*>(pc_entity);
696  if(pcSelectedEntity != NULL) {
697  bool bFound = false;
698  m_unSelectedRobot = 0;
699  while(!bFound && m_unSelectedRobot < m_vecRobots.size()) {
700  if(m_vecRobots[m_unSelectedRobot] == pcSelectedEntity) {
701  bFound = true;
702  }
703  else {
704  ++m_unSelectedRobot;
705  }
706  }
707  if(bFound &&
708  m_vecControllers[m_unSelectedRobot]->GetLuaState() != NULL) {
710  new CQTOpenGLLuaStateTreeVariableModel(m_vecControllers[m_unSelectedRobot]->GetLuaState(),
711  false,
712  m_pcLuaVariableTree);
713  pcVarModel->Refresh();
714  connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
715  pcVarModel, SLOT(Refresh(int)));
716  connect(m_pcMainWindow, SIGNAL(ExperimentReset()),
717  pcVarModel, SLOT(Refresh()));
718  connect(pcVarModel, SIGNAL(modelReset()),
719  this, SLOT(VariableTreeChanged()),
720  Qt::QueuedConnection);
721  m_pcLuaVariableTree->setModel(pcVarModel);
722  m_pcLuaVariableTree->setRootIndex(pcVarModel->index(0, 0));
723  m_pcLuaVariableTree->expandAll();
724  m_pcLuaVariableDock->show();
726  new CQTOpenGLLuaStateTreeFunctionModel(m_vecControllers[m_unSelectedRobot]->GetLuaState(),
727  true,
728  m_pcLuaFunctionTree);
729  pcFunModel->Refresh();
730  connect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
731  pcFunModel, SLOT(Refresh(int)));
732  connect(m_pcMainWindow, SIGNAL(ExperimentReset()),
733  pcFunModel, SLOT(Refresh()));
734  connect(pcFunModel, SIGNAL(modelReset()),
735  this, SLOT(FunctionTreeChanged()),
736  Qt::QueuedConnection);
737  m_pcLuaFunctionTree->setModel(pcFunModel);
738  m_pcLuaFunctionTree->setRootIndex(pcFunModel->index(0, 0));
739  m_pcLuaFunctionTree->expandAll();
740  m_pcLuaFunctionDock->show();
741  }
742  }
743  }
744 
745  /****************************************/
746  /****************************************/
747 
749  disconnect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
750  m_pcLuaVariableTree->model(), SLOT(Refresh(int)));
751  disconnect(m_pcMainWindow, SIGNAL(ExperimentReset()),
752  m_pcLuaVariableTree->model(), SLOT(Refresh()));
753  disconnect(m_pcLuaVariableTree->model(), SIGNAL(modelReset()),
754  this, SLOT(VariableTreeChanged()));
755  m_pcLuaVariableDock->hide();
756  delete m_pcLuaVariableTree->model();
757  m_pcLuaVariableTree->setModel(NULL);
758  disconnect(&(m_pcMainWindow->GetOpenGLWidget()), SIGNAL(StepDone(int)),
759  m_pcLuaFunctionTree->model(), SLOT(Refresh(int)));
760  disconnect(m_pcMainWindow, SIGNAL(ExperimentReset()),
761  m_pcLuaFunctionTree->model(), SLOT(Refresh()));
762  disconnect(m_pcLuaFunctionTree->model(), SIGNAL(modelReset()),
763  this, SLOT(FunctionTreeChanged()));
764  m_pcLuaFunctionDock->hide();
765  delete m_pcLuaFunctionTree->model();
766  m_pcLuaFunctionTree->setModel(NULL);
767  }
768 
769  /****************************************/
770  /****************************************/
771 
773  m_pcLuaVariableTree->setRootIndex(m_pcLuaVariableTree->model()->index(0, 0));
774  m_pcLuaVariableTree->expandAll();
775  }
776 
777  /****************************************/
778  /****************************************/
779 
781  m_pcLuaFunctionTree->setRootIndex(m_pcLuaFunctionTree->model()->index(0, 0));
782  m_pcLuaFunctionTree->expandAll();
783  }
784 
785  /****************************************/
786  /****************************************/
787 
788  void CQTOpenGLLuaMainWindow::UpdateRecentFiles() {
789  QSettings cSettings;
790  cSettings.beginGroup("LuaEditor");
791  QStringList listFiles = cSettings.value("recent_files").toStringList();
792  int nRecentFiles = qMin(listFiles.size(), (int)MAX_RECENT_FILES);
793  for(int i = 0; i < nRecentFiles; ++i) {
794  m_pcFileOpenRecentAction[i]->setText(tr("&%1 %2").arg(i+1).arg(StrippedFileName(listFiles[i])));
795  m_pcFileOpenRecentAction[i]->setData(listFiles[i]);
796  m_pcFileOpenRecentAction[i]->setVisible(true);
797  }
798  for(int i = nRecentFiles; i < MAX_RECENT_FILES; ++i) {
799  m_pcFileOpenRecentAction[i]->setVisible(false);
800  }
801  m_pcFileSeparateRecentAction->setVisible(nRecentFiles > 0);
802  cSettings.endGroup();
803  }
804 
805  /****************************************/
806  /****************************************/
807 
808  void CQTOpenGLLuaMainWindow::SetMessage(int n_row,
809  const QString& str_robot_id,
810  const QString& str_message) {
811  QStringList listFields = str_message.split(":",
812 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
813  Qt::KeepEmptyParts,
814 #else
815  QString::KeepEmptyParts,
816 #endif
817  Qt::CaseInsensitive);
818  m_pcLuaMessageTable->setItem(
819  n_row, 0,
820  new QTableWidgetItem(str_robot_id));
821  if(listFields.size() == 3) {
822  m_pcLuaMessageTable->setItem(
823  n_row, 1,
824  new QTableWidgetItem(listFields[1]));
825  m_pcLuaMessageTable->setItem(
826  n_row, 2,
827  new QTableWidgetItem(listFields[2]));
828  }
829  else if(listFields.size() == 4) {
830  m_pcLuaMessageTable->setItem(
831  n_row, 1,
832  new QTableWidgetItem(listFields[2]));
833  m_pcLuaMessageTable->setItem(
834  n_row, 2,
835  new QTableWidgetItem(listFields[3]));
836  }
837  else {
838  m_pcLuaMessageTable->setItem(
839  n_row, 2,
840  new QTableWidgetItem(str_message));
841  }
842  m_pcLuaMsgDock->show();
843  }
844 
845  /****************************************/
846  /****************************************/
847 
848  QString CQTOpenGLLuaMainWindow::StrippedFileName(const QString& str_path) {
849  return QFileInfo(str_path).fileName();
850  }
851 
852  /****************************************/
853  /****************************************/
854 
855  void CQTOpenGLLuaMainWindow::closeEvent(QCloseEvent* pc_event) {
856  pc_event->ignore();
857  }
858 
859  /****************************************/
860  /****************************************/
861 
862 }
The namespace containing all the ARGoS related code.
Definition: ci_actuator.h:12
CARGoSLog LOGERR(std::cerr, SLogColor(ARGOS_LOG_ATTRIBUTE_BRIGHT, ARGOS_LOG_COLOR_RED))
Definition: argos_log.h:180
Basic class for an entity that contains other entities.
The basic entity type.
Definition: entity.h:90
CSpace & GetSpace() const
Returns a reference to the simulated space.
Definition: simulator.h:104
static CSimulator & GetInstance()
Returns the instance to the CSimulator class.
Definition: simulator.cpp:78
std::map< std::string, CAny, std::less< std::string > > TMapPerType
A map of entities indexed by type description.
Definition: space.h:56
void HandleEntityDeselection(CEntity *pc_entity)
CQTOpenGLLuaMainWindow(CQTOpenGLMainWindow *pc_parent)
void HandleEntitySelection(CEntity *pc_entity)
virtual QModelIndex index(int n_row, int n_column, const QModelIndex &c_parent=QModelIndex()) const
void SuspendExperiment()
Suspends an experiment due to an error.
const QString & GetIconDir() const
CQTOpenGLWidget & GetOpenGLWidget()
void ResumeExperiment()
Resumes a suspended experiment.