00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "MainWindow.h"
00022 #include "ClickableLabel.h"
00023 #include "DashelTarget.h"
00024 #include "TargetModels.h"
00025 #include "NamedValuesVectorModel.h"
00026 #include "AeslEditor.h"
00027 #include "EventViewer.h"
00028 #include "FindDialog.h"
00029 #include "ModelAggregator.h"
00030 #include "translations/CompilerTranslator.h"
00031 #include "../common/consts.h"
00032 #include "../common/productids.h"
00033 #include "../utils/utils.h"
00034 #include <QtGui>
00035 #include <QtXml>
00036 #include <sstream>
00037 #include <iostream>
00038 #include <cassert>
00039 #include <QTabWidget>
00040 #include <QtConcurrentRun>
00041
00042 #include <MainWindow.moc>
00043 #include <version.h>
00044
00045 #include <iostream>
00046
00047 using std::copy;
00048
00049
00050 namespace Aseba
00051 {
00052
00055 CompilationLogDialog::CompilationLogDialog(QWidget *parent) :
00056 QTextEdit(parent)
00057 {
00058 QFont font;
00059 font.setFamily("");
00060 font.setStyleHint(QFont::TypeWriter);
00061 font.setFixedPitch(true);
00062 font.setPointSize(10);
00063
00064 setFont(font);
00065 setTabStopWidth( QFontMetrics(font).width(' ') * 4);
00066 setReadOnly(true);
00067
00068 setWindowTitle(tr("Aseba Studio: Output of last compilation"));
00069
00070 resize(600, 560);
00071 }
00072
00073 void CompilationLogDialog::hideEvent( QHideEvent * event )
00074 {
00075 if (!isVisible())
00076 emit hidden();
00077 }
00078
00080
00081 EditorsPlotsTabWidget::EditorsPlotsTabWidget()
00082 {
00083 vmMemorySize[0] = -1;
00084 vmMemorySize[1] = -1;
00085 readSettings();
00086 connect(this, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
00087 }
00088
00089 EditorsPlotsTabWidget::~EditorsPlotsTabWidget()
00090 {
00091
00092 writeSettings();
00093 }
00094
00095 void EditorsPlotsTabWidget::addTab(QWidget* widget, const QString& label, bool closable)
00096 {
00097 const int index = QTabWidget::addTab(widget, label);
00098 #if QT_VERSION >= 0x040500
00099 if (closable)
00100 {
00101 QPushButton* button = new QPushButton(QIcon(":/images/remove.png"), "");
00102 button->setFlat(true);
00103 connect(button, SIGNAL(clicked(bool)), this, SLOT(removeAndDeleteTab()));
00104 tabBar()->setTabButton(index, QTabBar::RightSide, button);
00105 }
00106 #endif // QT_VERSION >= 0x040500
00107
00108
00109 NodeTab* tab = dynamic_cast<NodeTab*>(widget);
00110 if (tab)
00111 {
00112 vmMemoryViewResize(tab);
00113 connect(tab->vmMemoryView->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(vmMemoryResized(int,int,int)));
00114 }
00115 }
00116
00117 void EditorsPlotsTabWidget::highlightTab(int index, QColor color)
00118 {
00119 tabBar()->setTabTextColor(index, color);
00120 }
00121
00122 void EditorsPlotsTabWidget::setExecutionMode(int index, Target::ExecutionMode state)
00123 {
00124 if (state == Target::EXECUTION_UNKNOWN)
00125 {
00126 setTabIcon(index, QIcon());
00127 }
00128 else if (state == Target::EXECUTION_RUN)
00129 {
00130 setTabIcon(index, QIcon(":/images/play.png"));
00131 }
00132 else if (state == Target::EXECUTION_STEP_BY_STEP)
00133 {
00134 setTabIcon(index, QIcon(":/images/pause.png"));
00135 }
00136 else if (state == Target::EXECUTION_STOP)
00137 {
00138 setTabIcon(index, QIcon(":/images/stop.png"));
00139 }
00140 }
00141
00142 void EditorsPlotsTabWidget::removeAndDeleteTab(int index)
00143 {
00144 #if QT_VERSION >= 0x040500
00145 if (index < 0)
00146 {
00147 QWidget* button(polymorphic_downcast<QWidget*>(sender()));
00148 for (int i = 0; i < count(); ++i)
00149 {
00150 if (tabBar()->tabButton(i, QTabBar::RightSide) == button)
00151 {
00152 index = i;
00153 break;
00154 }
00155 }
00156 }
00157 #endif // QT_VERSION >= 0x040500
00158
00159 if (index >= 0)
00160 {
00161 QWidget* w(widget(index));
00162 QTabWidget::removeTab(index);
00163 w->deleteLater();
00164 }
00165 }
00166
00167 void EditorsPlotsTabWidget::vmMemoryResized(int col, int oldSize, int newSize)
00168 {
00169
00170 vmMemorySize[col] = newSize;
00171 }
00172
00173 void EditorsPlotsTabWidget::tabChanged(int index)
00174 {
00175
00176 NodeTab* tab = dynamic_cast<NodeTab*>(currentWidget());
00177 if (!tab)
00178 return;
00179
00180 vmMemoryViewResize(tab);
00181
00182 resetHighlight(index);
00183 }
00184
00185 void EditorsPlotsTabWidget::resetHighlight(int index)
00186 {
00187 tabBar()->setTabTextColor(index, Qt::black);
00188 }
00189
00190 void EditorsPlotsTabWidget::vmMemoryViewResize(NodeTab *tab)
00191 {
00192 if (!tab)
00193 return;
00194
00195
00196 for (int i = 0; i < 2; i++)
00197 if (vmMemorySize[i] != -1)
00198 tab->vmMemoryView->header()->resizeSection(i, vmMemorySize[i]);
00199 }
00200
00201 void EditorsPlotsTabWidget::readSettings()
00202 {
00203 QSettings settings;
00204 vmMemorySize[0] = settings.value("vmMemoryView/col0", -1).toInt();
00205 vmMemorySize[1] = settings.value("vmMemoryView/col1", -1).toInt();
00206 }
00207
00208 void EditorsPlotsTabWidget::writeSettings()
00209 {
00210 QSettings settings;
00211 settings.setValue("vmMemoryView/col0", vmMemorySize[0]);
00212 settings.setValue("vmMemoryView/col1", vmMemorySize[1]);
00213 }
00214
00216
00217 void ScriptTab::createEditor()
00218 {
00219
00220 editor = new AeslEditor(this);
00221 breakpoints = new AeslBreakpointSidebar(editor);
00222 linenumbers = new AeslLineNumberSidebar(editor);
00223 highlighter = new AeslHighlighter(editor, editor->document());
00224 }
00225
00227
00228 AbsentNodeTab::AbsentNodeTab(const unsigned id, const QString& name, const QString& sourceCode, const SavedPlugins& savedPlugins) :
00229 ScriptTab(id),
00230 name(name),
00231 savedPlugins(savedPlugins)
00232 {
00233 createEditor();
00234 editor->setReadOnly(true);
00235 editor->setPlainText(sourceCode);
00236 QVBoxLayout *layout = new QVBoxLayout;
00237 layout->addWidget(editor);
00238 setLayout(layout);
00239 }
00240
00242
00243 NodeTab::CompilationResult* compilationThread(const TargetDescription targetDescription, const CommonDefinitions commonDefinitions, QString source, bool dump);
00244
00245 NodeTab::NodeTab(MainWindow* mainWindow, Target *target, const CommonDefinitions *commonDefinitions, int id, QWidget *parent) :
00246 QSplitter(parent),
00247 ScriptTab(id),
00248 VariableListener(0),
00249 pid(ASEBA_PID_UNDEFINED),
00250 target(target),
00251 commonDefinitions(commonDefinitions),
00252 mainWindow(mainWindow),
00253 currentPC(0),
00254 previousMode(Target::EXECUTION_UNKNOWN),
00255 firstCompilation(true),
00256 showHidden(mainWindow->showHiddenAct->isChecked()),
00257 compilationDirty(false),
00258 isSynchronized(true)
00259 {
00260
00261 rehighlighting = false;
00262 errorPos = -1;
00263 allocatedVariablesCount = 0;
00264
00265
00266 vmFunctionsModel = new TargetFunctionsModel(target->getDescription(id));
00267 vmMemoryModel = new TargetVariablesModel();
00268 variablesModel = vmMemoryModel;
00269 subscribeToVariableOfInterest(ASEBA_PID_VAR_NAME);
00270
00271
00272 setupWidgets();
00273 setupConnections();
00274
00275
00276
00277 ModelAggregator* aggregator = new ModelAggregator(this);
00278 aggregator->addModel(vmLocalEvents->model());
00279 aggregator->addModel(mainWindow->eventsDescriptionsModel);
00280 eventAggregator = aggregator;
00281
00282 aggregator = new ModelAggregator(this);
00283 aggregator->addModel(vmMemoryModel);
00284 aggregator->addModel(mainWindow->constantsDefinitionsModel);
00285 variableAggregator = aggregator;
00286
00287
00288 sortingProxy = new QSortFilterProxyModel(this);
00289 sortingProxy->setDynamicSortFilter(true);
00290 sortingProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
00291 sortingProxy->setSortRole(Qt::DisplayRole);
00292
00293
00294 functionsFlatModel = new TreeChainsawFilter(this);
00295 functionsFlatModel->setSourceModel(vmFunctionsModel);
00296
00297 editor->setFocus();
00298 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
00299
00300
00301
00302 NodeTab::CompilationResult* result = compilationThread(*target->getDescription(id), *commonDefinitions, editor->toPlainText(), false);
00303 processCompilationResult(result);
00304 }
00305
00306 NodeTab::~NodeTab()
00307 {
00308
00309
00310 compilationFuture.waitForFinished();
00311 for (NodeToolInterfaces::const_iterator it(tools.begin()); it != tools.end(); ++it)
00312 {
00313 NodeToolInterface* tool(*it);
00314 if (!tool->surviveTabDestruction())
00315 delete (*it);
00316 }
00317 delete vmFunctionsModel;
00318 delete vmMemoryModel;
00319 }
00320
00321 void NodeTab::timerEvent ( QTimerEvent * event )
00322 {
00323 if (mainWindow->nodes->currentWidget() != this)
00324 return;
00325
00326
00327 const QList<TargetVariablesModel::Variable> variables(variablesModel->getVariables());
00328 assert(variables.size() == variablesModel->rowCount());
00329
00330 unsigned currentReqCount(0);
00331 unsigned currentReqPos(0);
00332 for (int i = 0; i < variables.size(); ++i)
00333 {
00334 const TargetVariablesModel::Variable& var(variables[i]);
00335 if (((var.value.size() == 1) ||
00336 (vmMemoryView->isExpanded(variablesModel->index(i, 0)))
00337 ) &&
00338 (!vmMemoryView->isRowHidden(i, QModelIndex()))
00339 )
00340 {
00341 if (currentReqCount == 0)
00342 {
00343
00344 currentReqPos = var.pos;
00345 currentReqCount = var.value.size();
00346 }
00347 else if (currentReqPos + currentReqCount == var.pos)
00348 {
00349
00350 currentReqCount += var.value.size();
00351 }
00352 else
00353 {
00354
00355 target->getVariables(id, currentReqPos, currentReqCount);
00356
00357 currentReqPos = var.pos;
00358 currentReqCount = var.value.size();
00359 }
00360 }
00361 }
00362 if (currentReqCount != 0)
00363 {
00364
00365 target->getVariables(id, currentReqPos, currentReqCount);
00366 }
00367 }
00368
00369 void NodeTab::variableValueUpdated(const QString& name, const VariablesDataVector& values)
00370 {
00371 if ((name == ASEBA_PID_VAR_NAME) && (values.size() >= 1))
00372 {
00373
00374 if (values[0] != int(pid))
00375 {
00376 pid = values[0];
00377 nodeToolRegistrer.update(pid, this, tools);
00378 updateToolList();
00379
00380 mainWindow->regenerateHelpMenu();
00381 }
00382 }
00383 }
00384
00385 void NodeTab::setupWidgets()
00386 {
00387 createEditor();
00388
00389
00390 cursorPosText = new QLabel;
00391 compilationResultImage = new ClickableLabel;
00392 compilationResultText = new ClickableLabel;
00393 compilationResultText->setWordWrap(true);
00394 compilationResultText->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
00395 QHBoxLayout *compilationResultLayout = new QHBoxLayout;
00396 compilationResultLayout->addWidget(cursorPosText);
00397 compilationResultLayout->addWidget(compilationResultText, 1000);
00398 compilationResultLayout->addWidget(compilationResultImage);
00399
00400
00401 memoryUsageText = new QLabel();
00402 memoryUsageText->setAlignment(Qt::AlignLeft);
00403
00404
00405 QHBoxLayout *editorAreaLayout = new QHBoxLayout;
00406 editorAreaLayout->setSpacing(0);
00407 editorAreaLayout->addWidget(breakpoints);
00408 editorAreaLayout->addWidget(linenumbers);
00409 editorAreaLayout->addWidget(editor);
00410
00411
00412 keywordsToolbar = new QToolBar();
00413 varButton = new QToolButton(); varButton->setText("var");
00414 ifButton = new QToolButton(); ifButton->setText("if");
00415 elseifButton = new QToolButton(); elseifButton->setText("elseif");
00416 elseButton = new QToolButton(); elseButton->setText("else");
00417 oneventButton = new QToolButton(); oneventButton->setText("onevent");
00418 whileButton = new QToolButton(); whileButton->setText("while");
00419 forButton = new QToolButton(); forButton->setText("for");
00420 subroutineButton = new QToolButton(); subroutineButton->setText("sub");
00421 callsubButton = new QToolButton(); callsubButton->setText("callsub");
00422 keywordsToolbar->addWidget(new QLabel(tr("<b>Keywords</b>")));
00423 keywordsToolbar->addSeparator();
00424 keywordsToolbar->addWidget(varButton);
00425 keywordsToolbar->addWidget(ifButton);
00426 keywordsToolbar->addWidget(elseifButton);
00427 keywordsToolbar->addWidget(elseButton);
00428 keywordsToolbar->addWidget(oneventButton);
00429 keywordsToolbar->addWidget(whileButton);
00430 keywordsToolbar->addWidget(forButton);
00431 keywordsToolbar->addWidget(subroutineButton);
00432 keywordsToolbar->addWidget(callsubButton);
00433
00434 QVBoxLayout *editorLayout = new QVBoxLayout;
00435 editorLayout->addWidget(keywordsToolbar);
00436 editorLayout->addLayout(editorAreaLayout);
00437 editorLayout->addLayout(compilationResultLayout);
00438 editorLayout->addWidget(memoryUsageText);
00439
00440
00441
00442
00443 executionModeLabel = new QLabel(tr("unknown"));
00444
00445 loadButton = new QPushButton(QIcon(":/images/upload.png"), tr("Load"));
00446 resetButton = new QPushButton(QIcon(":/images/reset.png"), tr("Reset"));
00447 resetButton->setEnabled(false);
00448 runInterruptButton = new QPushButton(QIcon(":/images/play.png"), tr("Run"));
00449 runInterruptButton->setEnabled(false);
00450 nextButton = new QPushButton(QIcon(":/images/step.png"), tr("Next"));
00451 nextButton->setEnabled(false);
00452 refreshMemoryButton = new QPushButton(QIcon(":/images/rescan.png"), tr("refresh"));
00453 autoRefreshMemoryCheck = new QCheckBox(tr("auto"));
00454
00455 QGridLayout* buttonsLayout = new QGridLayout;
00456 buttonsLayout->addWidget(new QLabel(tr("<b>Execution</b>")), 0, 0);
00457 buttonsLayout->addWidget(executionModeLabel, 0, 1);
00458 buttonsLayout->addWidget(loadButton, 1, 0);
00459 buttonsLayout->addWidget(runInterruptButton, 1, 1);
00460 buttonsLayout->addWidget(resetButton, 2, 0);
00461 buttonsLayout->addWidget(nextButton, 2, 1);
00462
00463
00464 vmMemoryView = new QTreeView;
00465 vmMemoryView->setModel(vmMemoryModel);
00466 vmMemoryView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00467 vmMemoryView->setItemDelegate(new SpinBoxDelegate(-32768, 32767, this));
00468 vmMemoryView->setColumnWidth(0, 200-QFontMetrics(QFont()).width("-8888888##"));
00469 vmMemoryView->setColumnWidth(1, QFontMetrics(QFont()).width("-8888888##"));
00470 vmMemoryView->setSelectionMode(QAbstractItemView::SingleSelection);
00471 vmMemoryView->setSelectionBehavior(QAbstractItemView::SelectItems);
00472 vmMemoryView->setDragDropMode(QAbstractItemView::DragOnly);
00473 vmMemoryView->setDragEnabled(true);
00474
00475
00476
00477 QVBoxLayout *memoryLayout = new QVBoxLayout;
00478 QHBoxLayout *memorySubLayout = new QHBoxLayout;
00479 memorySubLayout->addWidget(new QLabel(tr("<b>Variables</b>")));
00480 memorySubLayout->addStretch();
00481 memorySubLayout->addWidget(autoRefreshMemoryCheck);
00482 memorySubLayout->addWidget(refreshMemoryButton);
00483 memoryLayout->addLayout(memorySubLayout);
00484 memoryLayout->addWidget(vmMemoryView);
00485 memorySubLayout = new QHBoxLayout;
00486 QLabel* filterLabel(new QLabel(tr("F&ilter:")));
00487 memorySubLayout->addWidget(filterLabel);
00488 vmMemoryFilter= new QLineEdit;
00489 filterLabel->setBuddy(vmMemoryFilter);
00490 memorySubLayout->addWidget(vmMemoryFilter);
00491 memoryLayout->addLayout(memorySubLayout);
00492
00493
00494 vmFunctionsView = new QTreeView;
00495 vmFunctionsView->setMinimumHeight(40);
00496 vmFunctionsView->setMinimumSize(QSize(50,40));
00497 vmFunctionsView->setModel(vmFunctionsModel);
00498 vmFunctionsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00499 vmFunctionsView->setSelectionMode(QAbstractItemView::SingleSelection);
00500 vmFunctionsView->setSelectionBehavior(QAbstractItemView::SelectItems);
00501 vmFunctionsView->setDragDropMode(QAbstractItemView::DragOnly);
00502 vmFunctionsView->setDragEnabled(true);
00503 vmFunctionsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
00504 vmFunctionsView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
00505 #if QT_VERSION >= 0x040400
00506 vmFunctionsView->setHeaderHidden(true);
00507 #elif (!defined(_MSC_VER))
00508 #warning "Some feature have been disabled because you are using Qt < 4.4.0"
00509 #endif
00510
00511
00512 vmLocalEvents = new DraggableListWidget;
00513 vmLocalEvents->setMinimumHeight(40);
00514 vmLocalEvents->setSelectionMode(QAbstractItemView::SingleSelection);
00515 vmLocalEvents->setDragDropMode(QAbstractItemView::DragOnly);
00516 vmLocalEvents->setDragEnabled(true);
00517 for (size_t i = 0; i < target->getDescription(id)->localEvents.size(); i++)
00518 {
00519 QListWidgetItem* item = new QListWidgetItem(QString::fromStdWString(target->getDescription(id)->localEvents[i].name));
00520 item->setToolTip(QString::fromStdWString(target->getDescription(id)->localEvents[i].description));
00521 vmLocalEvents->addItem(item);
00522 }
00523
00524
00525 toolBox = new QToolBox;
00526 toolBox->addItem(vmFunctionsView, tr("Native Functions"));
00527 toolBox->addItem(vmLocalEvents, tr("Local Events"));
00528 QWidget* toolListWidget(new QWidget);
00529 toolListLayout = new QVBoxLayout;
00530 toolListWidget->setLayout(toolListLayout);
00531 toolListIndex = toolBox->addItem(toolListWidget, tr("Local Tools"));
00532 QVBoxLayout* toolBoxLayout = new QVBoxLayout;
00533 toolBoxLayout->addWidget(toolBox);
00534 QWidget* toolBoxWidget = new QWidget;
00535 toolBoxWidget->setLayout(toolBoxLayout);
00536
00537
00538 QSplitter *panelSplitter = new QSplitter(Qt::Vertical);
00539
00540 QWidget* buttonsWidget = new QWidget;
00541 buttonsWidget->setLayout(buttonsLayout);
00542 panelSplitter->addWidget(buttonsWidget);
00543 panelSplitter->setCollapsible(0, false);
00544
00545 QWidget* memoryWidget = new QWidget;
00546 memoryWidget->setLayout(memoryLayout);
00547 panelSplitter->addWidget(memoryWidget);
00548 panelSplitter->setStretchFactor(1, 3);
00549
00550 panelSplitter->addWidget(toolBoxWidget);
00551 panelSplitter->setStretchFactor(2, 1);
00552
00553 addWidget(panelSplitter);
00554 QWidget *editorWidget = new QWidget;
00555 editorWidget->setLayout(editorLayout);
00556 addWidget(editorWidget);
00557 setSizes(QList<int>() << 250 << 550);
00558 }
00559
00560 void NodeTab::setupConnections()
00561 {
00562
00563 connect(&compilationWatcher, SIGNAL(finished()), SLOT(compilationCompleted()));
00564
00565
00566 connect(loadButton, SIGNAL(clicked()), SLOT(loadClicked()));
00567 connect(resetButton, SIGNAL(clicked()), SLOT(resetClicked()));
00568 connect(runInterruptButton, SIGNAL(clicked()), SLOT(runInterruptClicked()));
00569 connect(nextButton, SIGNAL(clicked()), SLOT(nextClicked()));
00570 connect(refreshMemoryButton, SIGNAL(clicked()), SLOT(refreshMemoryClicked()));
00571 connect(autoRefreshMemoryCheck, SIGNAL(stateChanged(int)), SLOT(autoRefreshMemoryClicked(int)));
00572
00573
00574 connect(vmMemoryModel, SIGNAL(variableValuesChanged(unsigned, const VariablesDataVector &)), SLOT(setVariableValues(unsigned, const VariablesDataVector &)));
00575 connect(vmMemoryFilter, SIGNAL(textChanged(const QString &)), SLOT(updateHidden()));
00576
00577
00578 connect(editor, SIGNAL(textChanged()), SLOT(editorContentChanged()));
00579 connect(editor, SIGNAL(cursorPositionChanged() ), SLOT(cursorMoved()));
00580 connect(editor, SIGNAL(breakpointSet(unsigned)), SLOT(setBreakpoint(unsigned)));
00581 connect(editor, SIGNAL(breakpointCleared(unsigned)), SLOT(clearBreakpoint(unsigned)));
00582 connect(editor, SIGNAL(breakpointClearedAll()), SLOT(breakpointClearedAll()));
00583 connect(editor, SIGNAL(refreshModelRequest(LocalContext)), SLOT(refreshCompleterModel(LocalContext)));
00584
00585 connect(compilationResultImage, SIGNAL(clicked()), SLOT(goToError()));
00586 connect(compilationResultText, SIGNAL(clicked()), SLOT(goToError()));
00587
00588
00589 connect(mainWindow, SIGNAL(MainWindowClosed()), SLOT(closePlugins()));
00590
00591
00592 signalMapper = new QSignalMapper(this);
00593 signalMapper->setMapping(varButton, QString("var "));
00594 signalMapper->setMapping(ifButton, QString("if"));
00595 signalMapper->setMapping(elseifButton, QString("elseif"));
00596 signalMapper->setMapping(elseButton, QString("else\n\t"));
00597 signalMapper->setMapping(oneventButton, QString("onevent "));
00598 signalMapper->setMapping(whileButton, QString("while"));
00599 signalMapper->setMapping(forButton, QString("for"));
00600 signalMapper->setMapping(subroutineButton, QString("sub "));
00601 signalMapper->setMapping(callsubButton, QString("callsub "));
00602
00603 connect(varButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00604 connect(ifButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00605 connect(elseifButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00606 connect(elseButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00607 connect(oneventButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00608 connect(whileButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00609 connect(forButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00610 connect(subroutineButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00611 connect(callsubButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
00612
00613 connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(keywordClicked(QString)));
00614
00615
00616 if (mainWindow->autoMemoryRefresh)
00617 autoRefreshMemoryCheck->setChecked(true);
00618 }
00619
00620 ScriptTab::SavedPlugins NodeTab::savePlugins() const
00621 {
00622 SavedPlugins savedPlugins;
00623 for (NodeToolInterfaces::const_iterator it(tools.begin()); it != tools.end(); ++it)
00624 {
00625 const SavedContent savedContent((*it)->getSaved());
00626 if (!savedContent.first.isEmpty() && !savedContent.second.isNull())
00627 savedPlugins.push_back(savedContent);
00628 }
00629 return savedPlugins;
00630 }
00631
00632 void NodeTab::restorePlugins(const SavedPlugins& savedPlugins, bool fromFile)
00633 {
00634
00635 for (SavedPlugins::const_iterator it(savedPlugins.begin()); it != savedPlugins.end(); ++it)
00636 {
00637 nodeToolRegistrer.update(it->first, this, tools);
00638 }
00639
00640 for (SavedPlugins::const_iterator it(savedPlugins.begin()); it != savedPlugins.end(); ++it)
00641 {
00642 NodeToolInterface* interface(tools.getNamed(it->first));
00643 interface->loadFromDom(it->second, fromFile);
00644 }
00645 }
00646
00647 void NodeTab::updateToolList()
00648 {
00649
00650 int oldCount = toolListLayout->count();
00651 QLayoutItem *child;
00652 while ((child = toolListLayout->takeAt(0)) != 0)
00653 {
00654 child->widget()->deleteLater();
00655 delete child;
00656 }
00657
00658
00659 for (NodeToolInterfaces::const_iterator it(tools.begin()); it != tools.end(); ++it)
00660 toolListLayout->addWidget((*it)->createMenuEntry());
00661
00662
00663 if (toolListLayout->count() != oldCount)
00664 toolBox->setCurrentIndex(toolListIndex);
00665 }
00666
00667 void NodeTab::resetClicked()
00668 {
00669 clearExecutionErrors();
00670 target->reset(id);
00671 }
00672
00673 void NodeTab::loadClicked()
00674 {
00675 if (errorPos == -1)
00676 {
00677 clearEditorProperty("executionError");
00678 target->uploadBytecode(id, bytecode);
00679
00680 editor->debugging = true;
00681 reSetBreakpoints();
00682 rehighlight();
00683 }
00684
00685 isSynchronized = true;
00686 mainWindow->resetStatusText();
00687 }
00688
00689 void NodeTab::runInterruptClicked()
00690 {
00691 if (runInterruptButton->text() == tr("Run"))
00692 target->run(id);
00693 else
00694 target->pause(id);
00695 }
00696
00697 void NodeTab::nextClicked()
00698 {
00699 target->next(id);
00700 }
00701
00702 void NodeTab::refreshMemoryClicked()
00703 {
00704
00705 target->getVariables(id, 0, allocatedVariablesCount);
00706 }
00707
00708 void NodeTab::autoRefreshMemoryClicked(int state)
00709 {
00710 if (state == Qt::Checked)
00711 {
00712 refreshMemoryButton->setEnabled(false);
00713 refreshTimer = startTimer(200);
00714 }
00715 else
00716 {
00717 refreshMemoryButton->setEnabled(true);
00718 killTimer(refreshTimer);
00719 refreshMemoryClicked();
00720 }
00721 }
00722
00723 void NodeTab::writeBytecode()
00724 {
00725 if (errorPos == -1)
00726 {
00727 loadClicked();
00728 target->writeBytecode(id);
00729 }
00730 }
00731
00732 void NodeTab::reboot()
00733 {
00734 markTargetUnsynced();
00735 target->reboot(id);
00736 }
00737
00738 static void write16(QIODevice& dev, const uint16 v)
00739 {
00740 dev.write((const char*)&v, 2);
00741 }
00742
00743 static void write16(QIODevice& dev, const VariablesDataVector& data, const char *varName)
00744 {
00745 if (data.empty())
00746 {
00747 std::cerr << "Warning, cannot find " << varName << " required to save bytecode, using 0" << std::endl;
00748 write16(dev, 0);
00749 }
00750 else
00751 dev.write((const char *)&data[0], 2);
00752 }
00753
00754 static uint16 crcXModem(const uint16 oldCrc, const QString& s)
00755 {
00756 return crcXModem(oldCrc, s.toStdWString());
00757 }
00758
00759 void NodeTab::saveBytecode()
00760 {
00761 const QString& nodeName(target->getName(id));
00762 QString bytecodeFileName = QFileDialog::getSaveFileName(mainWindow, tr("Save the binary code of %0").arg(nodeName), "", "Aseba Binary Object (*.abo);;All Files (*)");
00763
00764 QFile file(bytecodeFileName);
00765 if (!file.open(QFile::WriteOnly | QFile::Truncate))
00766 return;
00767
00768
00769
00770
00771 const char* magic = "ABO";
00772 file.write(magic, 4);
00773 write16(file, 0);
00774 write16(file, ASEBA_PROTOCOL_VERSION);
00775 write16(file, vmMemoryModel->getVariableValue("_productId"), "product identifier (_productId)");
00776 write16(file, vmMemoryModel->getVariableValue("_fwversion"), "firmware version (_fwversion)");
00777 write16(file, id);
00778 write16(file, crcXModem(0, nodeName));
00779 write16(file, target->getDescription(id)->crc());
00780
00781
00782 write16(file, bytecode.size());
00783 uint16 crc(0);
00784 for (size_t i = 0; i < bytecode.size(); ++i)
00785 {
00786 const uint16 bc(bytecode[i]);
00787 write16(file, bc);
00788 crc = crcXModem(crc, bc);
00789 }
00790 write16(file, crc);
00791 }
00792
00793 void NodeTab::setVariableValues(unsigned index, const VariablesDataVector &values)
00794 {
00795 target->setVariables(id, index, values);
00796 }
00797
00798 void NodeTab::insertVariableName(const QModelIndex &index)
00799 {
00800
00801 if (!index.parent().isValid() && (index.column() == 0))
00802 editor->insertPlainText(index.data().toString());
00803 }
00804
00805 void NodeTab::editorContentChanged()
00806 {
00807 if (rehighlighting)
00808 {
00809 rehighlighting = false;
00810 }
00811 else
00812 {
00813
00814 QTextCursor cursor(editor->textCursor());
00815 if (ConfigDialog::getAutoCompletion() && cursor.atBlockEnd())
00816 {
00817
00818 const QString& line(cursor.block().text());
00819 QString keyword(line);
00820
00821
00822 int nonWhitespace(0);
00823 while ((nonWhitespace < keyword.size()) && ((keyword.at(nonWhitespace) == ' ') || (keyword.at(nonWhitespace) == '\t')))
00824 ++nonWhitespace;
00825 keyword.remove(0,nonWhitespace);
00826
00827 if (!keyword.trimmed().isEmpty())
00828 {
00829 QString prefix;
00830 QString postfix;
00831 if (keyword == "if")
00832 {
00833 const QString headSpace = line.left(line.indexOf("if"));
00834 prefix = " ";
00835 postfix = " then\n" + headSpace + "\t\n" + headSpace + "end";
00836 }
00837 else if (keyword == "when")
00838 {
00839 const QString headSpace = line.left(line.indexOf("when"));
00840 prefix = " ";
00841 postfix = " do\n" + headSpace + "\t\n" + headSpace + "end";
00842 }
00843 else if (keyword == "for")
00844 {
00845 const QString headSpace = line.left(line.indexOf("for"));
00846 prefix = " ";
00847 postfix = "i in 0:0 do\n" + headSpace + "\t\n" + headSpace + "end";
00848 }
00849 else if (keyword == "while")
00850 {
00851 const QString headSpace = line.left(line.indexOf("while"));
00852 prefix = " ";
00853 postfix = " do\n" + headSpace + "\t\n" + headSpace + "end";
00854 }
00855 else if ((keyword == "else") && cursor.block().next().isValid())
00856 {
00857 const QString tab = QString("\t");
00858 QString headSpace = line.left(line.indexOf("else"));
00859
00860 if( headSpace.size() >= tab.size())
00861 {
00862 headSpace = headSpace.left(headSpace.size() - tab.size());
00863 if (cursor.block().next().text() == headSpace + "end")
00864 {
00865 prefix = "\n" + headSpace + "else";
00866 postfix = "\n" + headSpace + "\t";
00867
00868 cursor.select(QTextCursor::BlockUnderCursor);
00869 cursor.removeSelectedText();
00870 }
00871 }
00872 }
00873 else if (keyword == "elseif")
00874 {
00875 const QString headSpace = line.left(line.indexOf("elseif"));
00876 prefix = " ";
00877 postfix = " then";
00878 }
00879
00880 if (!prefix.isNull() || !postfix.isNull())
00881 {
00882 cursor.beginEditBlock();
00883 cursor.insertText(prefix);
00884 const int pos = cursor.position();
00885 cursor.insertText(postfix);
00886 cursor.setPosition(pos);
00887 cursor.endEditBlock();
00888 editor->setTextCursor(cursor);
00889 }
00890 }
00891 }
00892 recompile();
00893 if (!firstCompilation)
00894 mainWindow->sourceChanged();
00895 else
00896 firstCompilation = false;
00897 }
00898 }
00899
00900 void NodeTab::keywordClicked(QString keyword)
00901 {
00902 QTextCursor cursor(editor->textCursor());
00903
00904 cursor.beginEditBlock();
00905 cursor.insertText(keyword);
00906 cursor.endEditBlock();
00907 editorContentChanged();
00908 }
00909
00910 void NodeTab::displayCode(QList<QString> code, int line)
00911 {
00912 editor->clear();
00913 QTextCharFormat format;
00914 QTextCursor cursor(editor->textCursor());
00915 int pos=0;
00916
00917 for(int i=0; i<code.size(); i++)
00918 {
00919 if( i == line )
00920 {
00921 format.setBackground(QBrush(QColor(255,255,200)));
00922 cursor.insertText(code[i], format);
00923 pos = cursor.position();
00924 }
00925 else
00926 {
00927 format.setBackground(QBrush(Qt::white));
00928 cursor.insertText(code[i], format);
00929 }
00930 }
00931
00932 cursor.setPosition(pos);
00933 editor->setTextCursor(cursor);
00934 editor->ensureCursorVisible();
00935 }
00936
00937 void NodeTab::showKeywords(bool show)
00938 {
00939 if(show)
00940 keywordsToolbar->show();
00941 else
00942 keywordsToolbar->hide();
00943 }
00944
00945 void NodeTab::showMemoryUsage(bool show)
00946 {
00947 memoryUsageText->setVisible(show);
00948 }
00949
00950 void NodeTab::updateHidden()
00951 {
00952 const QString& filterString(vmMemoryFilter->text());
00953 const QRegExp filterRegexp(filterString);
00954
00955
00956 for(int i = 0; i < vmMemoryModel->rowCount(QModelIndex()); i++)
00957 {
00958 QString name(vmMemoryModel->data(vmMemoryModel->index(i,0), Qt::DisplayRole).toString());
00959 bool hidden(false);
00960 if (
00961 (!showHidden && (name.at(0) == '_' || name.contains(QString("._")))) ||
00962 (!filterString.isEmpty() && name.indexOf(filterRegexp)==-1)
00963 )
00964 hidden = true;
00965 vmMemoryView->setRowHidden(i,QModelIndex(), hidden);
00966 }
00967
00968 }
00969
00970 NodeTab::CompilationResult* compilationThread(const TargetDescription targetDescription, const CommonDefinitions commonDefinitions, QString source, bool dump)
00971 {
00972 NodeTab::CompilationResult* result(new NodeTab::CompilationResult(dump));
00973
00974 Compiler compiler;
00975 compiler.setTargetDescription(&targetDescription);
00976 compiler.setCommonDefinitions(&commonDefinitions);
00977 compiler.setTranslateCallback(CompilerTranslator::translate);
00978
00979 std::wistringstream is(source.toStdWString());
00980
00981 if (dump)
00982 result->success = compiler.compile(is, result->bytecode, result->allocatedVariablesCount, result->error, &result->compilationMessages);
00983 else
00984 result->success = compiler.compile(is, result->bytecode, result->allocatedVariablesCount, result->error);
00985
00986 if (result->success)
00987 result->variablesMap = *compiler.getVariablesMap();
00988
00989 return result;
00990 }
00991
00992 void NodeTab::recompile()
00993 {
00994
00995 if (compilationFuture.isRunning())
00996 compilationDirty = true;
00997 else
00998 {
00999 bool dump(mainWindow->nodes->currentWidget() == this);
01000 compilationFuture = QtConcurrent::run(compilationThread, *target->getDescription(id), *commonDefinitions, editor->toPlainText(), dump);
01001 compilationWatcher.setFuture(compilationFuture);
01002 compilationDirty = false;
01003
01004
01005 compilationResultImage->setPixmap(QPixmap(QString(":/images/busy.png")));
01006 }
01007 }
01008
01009 void NodeTab::compilationCompleted()
01010 {
01011 CompilationResult* result(compilationFuture.result());
01012 assert(result);
01013
01014
01015 if (compilationDirty)
01016 {
01017 delete result;
01018 recompile();
01019 return;
01020 }
01021
01022
01023 processCompilationResult(result);
01024 }
01025
01026 void NodeTab::processCompilationResult(CompilationResult* result)
01027 {
01028
01029
01030
01031 bool doRehighlight = clearEditorProperty("errorPos");
01032
01033 if (result->dump)
01034 {
01035 mainWindow->compilationMessageBox->setWindowTitle(
01036 tr("Aseba Studio: Output of last compilation for %0").arg(target->getName(id))
01037 );
01038
01039 if (result->success)
01040 mainWindow->compilationMessageBox->setText(
01041 tr("Compilation success.") + QString("\n\n") +
01042 QString::fromStdWString(result->compilationMessages.str())
01043 );
01044 else
01045 mainWindow->compilationMessageBox->setText(
01046 QString::fromStdWString(result->error.toWString()) + ".\n\n" +
01047 QString::fromStdWString(result->compilationMessages.str())
01048 );
01049
01050 }
01051
01052
01053 if (result->success)
01054 {
01055 const unsigned variableCount = result->allocatedVariablesCount;
01056 const unsigned variableTotal = (*target->getDescription(id)).variablesSize;
01057 const unsigned bytecodeCount = result->bytecode.size();
01058 const unsigned bytecodeTotal = (*target->getDescription(id)).bytecodeSize;
01059 assert(variableCount);
01060 assert(bytecodeCount);
01061 const QString variableText = tr("variables: %1 on %2 (%3\%)").arg(variableCount).arg(variableTotal).arg((double)variableCount*100./variableTotal, 0, 'f', 1);
01062 const QString bytecodeText = tr("bytecode: %1 on %2 (%3\%)").arg(bytecodeCount).arg(bytecodeTotal).arg((double)bytecodeCount*100./bytecodeTotal, 0, 'f', 1);
01063 memoryUsageText->setText(trUtf8("<b>Memory usage</b> : %1, %2").arg(variableText).arg(bytecodeText));
01064 }
01065
01066
01067 if (result->success)
01068 {
01069 bytecode = result->bytecode;
01070 allocatedVariablesCount = result->allocatedVariablesCount;
01071 vmMemoryModel->updateVariablesStructure(&result->variablesMap);
01072
01073 updateHidden();
01074 compilationResultText->setText(tr("Compilation success."));
01075 compilationResultImage->setPixmap(QPixmap(QString(":/images/ok.png")));
01076 loadButton->setEnabled(true);
01077 emit uploadReadynessChanged(true);
01078
01079 errorPos = -1;
01080 }
01081 else
01082 {
01083 compilationResultText->setText(QString::fromStdWString(result->error.toWString()));
01084 compilationResultImage->setPixmap(QPixmap(QString(":/images/warning.png")));
01085 loadButton->setEnabled(false);
01086 emit uploadReadynessChanged(false);
01087
01088
01089 if (result->error.pos.valid)
01090 {
01091 errorPos = result->error.pos.character;
01092 QTextBlock textBlock = editor->document()->findBlock(errorPos);
01093 int posInBlock = errorPos - textBlock.position();
01094 if (textBlock.userData())
01095 polymorphic_downcast<AeslEditorUserData *>(textBlock.userData())->properties["errorPos"] = posInBlock;
01096 else
01097 textBlock.setUserData(new AeslEditorUserData("errorPos", posInBlock));
01098 doRehighlight = true;
01099 }
01100 }
01101
01102
01103 delete result;
01104
01105
01106 if (editor->debugging)
01107 {
01108
01109 markTargetUnsynced();
01110 doRehighlight = true;
01111
01112 }
01113
01114 if (doRehighlight)
01115 rehighlight();
01116 }
01117
01119 void NodeTab::markTargetUnsynced()
01120 {
01121 editor->debugging = false;
01122 resetButton->setEnabled(false);
01123 runInterruptButton->setEnabled(false);
01124 nextButton->setEnabled(false);
01125 target->clearBreakpoints(id);
01126 switchEditorProperty("breakpoint", "breakpointPending");
01127 executionModeLabel->setText(tr("unknown"));
01128 mainWindow->nodes->setExecutionMode(mainWindow->getIndexFromId(id), Target::EXECUTION_UNKNOWN);
01129 }
01130
01131 void NodeTab::cursorMoved()
01132 {
01133
01134 cursorPosText->setText(QString("Line: %0 Col: %1").arg(editor->textCursor().blockNumber() + 1).arg(editor->textCursor().columnNumber() + 1));
01135 }
01136
01137 void NodeTab::goToError()
01138 {
01139 if (errorPos >= 0)
01140 {
01141 QTextCursor cursor = editor->textCursor();
01142 cursor.setPosition(errorPos);
01143 editor->setTextCursor(cursor);
01144 editor->ensureCursorVisible();
01145 }
01146 }
01147
01148 void NodeTab::clearExecutionErrors()
01149 {
01150
01151 if (clearEditorProperty("executionError"))
01152 rehighlight();
01153 }
01154
01155 void NodeTab::refreshCompleterModel(LocalContext context)
01156 {
01157
01158 disconnect(mainWindow->eventsDescriptionsModel, 0, sortingProxy, 0);
01159
01160 if ((context == GeneralContext) || (context == UnknownContext))
01161 {
01162 sortingProxy->setSourceModel(variableAggregator);
01163 sortingProxy->sort(0);
01164 editor->setCompleterModel(sortingProxy);
01165 }
01166 else if (context == LeftValueContext)
01167 {
01168 sortingProxy->setSourceModel(vmMemoryModel);
01169 sortingProxy->sort(0);
01170 editor->setCompleterModel(sortingProxy);
01171 }
01172 else if (context == VarDefContext)
01173 editor->setCompleterModel(0);
01174 else if (context == FunctionContext)
01175 {
01176 sortingProxy->setSourceModel(functionsFlatModel);
01177 sortingProxy->sort(0);
01178 editor->setCompleterModel(sortingProxy);
01179 }
01180 else if (context == EventContext)
01181 {
01182 sortingProxy->setSourceModel(eventAggregator);
01183 sortingProxy->sort(0);
01184
01185
01186 editor->setCompleterModel(sortingProxy);
01187 }
01188 }
01189
01190
01191
01192
01193
01194
01195
01196
01197 void NodeTab::variablesMemoryChanged(unsigned start, const VariablesDataVector &variables)
01198 {
01199
01200 vmMemoryModel->setVariablesData(start, variables);
01201 }
01202
01203 void NodeTab::setBreakpoint(unsigned line)
01204 {
01205 rehighlight();
01206 target->setBreakpoint(id, line);
01207 }
01208
01209 void NodeTab::clearBreakpoint(unsigned line)
01210 {
01211 rehighlight();
01212 target->clearBreakpoint(id, line);
01213 }
01214
01215 void NodeTab::breakpointClearedAll()
01216 {
01217 rehighlight();
01218 target->clearBreakpoints(id);
01219 }
01220
01221 void NodeTab::executionPosChanged(unsigned line)
01222 {
01223
01224 currentPC = line;
01225 if (setEditorProperty("active", QVariant(), line, true))
01226 rehighlight();
01227 }
01228
01229 void NodeTab::executionModeChanged(Target::ExecutionMode mode)
01230 {
01231
01232 if (!editor->debugging)
01233 return;
01234
01235 resetButton->setEnabled(true);
01236 runInterruptButton->setEnabled(true);
01237 compilationResultImage->setPixmap(QPixmap(QString(":/images/ok.png")));
01238
01239
01240 if (previousMode != mode)
01241 {
01242 previousMode = mode;
01243 if ((mode == Target::EXECUTION_STEP_BY_STEP) && editor->isBreakpoint(currentPC))
01244 {
01245
01246 if (mainWindow->currentScriptTab != this)
01247 {
01248
01249 mainWindow->nodes->highlightTab(mainWindow->getIndexFromId(id), Qt::red);
01250 }
01251
01252 editor->setTextCursor(QTextCursor(editor->document()->findBlockByLineNumber(currentPC)));
01253 editor->ensureCursorVisible();
01254 }
01255 }
01256
01257 if (mode == Target::EXECUTION_RUN)
01258 {
01259 executionModeLabel->setText(tr("running"));
01260
01261 runInterruptButton->setText(tr("Pause"));
01262 runInterruptButton->setIcon(QIcon(":/images/pause.png"));
01263
01264 nextButton->setEnabled(false);
01265
01266 if (clearEditorProperty("active"))
01267 rehighlight();
01268 }
01269 else if (mode == Target::EXECUTION_STEP_BY_STEP)
01270 {
01271 executionModeLabel->setText(tr("step by step"));
01272
01273 runInterruptButton->setText(tr("Run"));
01274 runInterruptButton->setIcon(QIcon(":/images/play.png"));
01275
01276 nextButton->setEnabled(true);
01277
01278
01279 editor->setTextCursor(QTextCursor(editor->document()->findBlockByLineNumber(currentPC+1)));
01280 editor->ensureCursorVisible();
01281 editor->setTextCursor(QTextCursor(editor->document()->findBlockByLineNumber(currentPC)));
01282 }
01283 else if (mode == Target::EXECUTION_STOP)
01284 {
01285 executionModeLabel->setText(tr("stopped"));
01286
01287 runInterruptButton->setText(tr("Run"));
01288 runInterruptButton->setIcon(QIcon(":/images/play.png"));
01289
01290 nextButton->setEnabled(false);
01291
01292 if (clearEditorProperty("active"))
01293 rehighlight();
01294 }
01295
01296
01297 mainWindow->nodes->setExecutionMode(mainWindow->getIndexFromId(id), mode);
01298 }
01299
01300 void NodeTab::breakpointSetResult(unsigned line, bool success)
01301 {
01302 clearEditorProperty("breakpointPending", line);
01303 if (success)
01304 setEditorProperty("breakpoint", QVariant(), line);
01305 rehighlight();
01306 }
01307
01308 void NodeTab::closePlugins()
01309 {
01310 for (NodeToolInterfaces::const_iterator it(tools.begin()); it != tools.end(); ++it)
01311 (*it)->closeAsSoonAsPossible();
01312 }
01313
01314 void NodeTab::rehighlight()
01315 {
01316 rehighlighting = true;
01317 highlighter->rehighlight();
01318 }
01319
01320 void NodeTab::reSetBreakpoints()
01321 {
01322 target->clearBreakpoints(id);
01323 QTextBlock block = editor->document()->begin();
01324 unsigned lineCounter = 0;
01325 while (block != editor->document()->end())
01326 {
01327 AeslEditorUserData *uData = polymorphic_downcast_or_null<AeslEditorUserData *>(block.userData());
01328 if (uData && (uData->properties.contains("breakpoint") || uData->properties.contains("breakpointPending")))
01329 target->setBreakpoint(id, lineCounter);
01330 block = block.next();
01331 lineCounter++;
01332 }
01333 }
01334
01335 bool NodeTab::setEditorProperty(const QString &property, const QVariant &value, unsigned line, bool removeOld)
01336 {
01337 bool changed = false;
01338
01339 QTextBlock block = editor->document()->begin();
01340 unsigned lineCounter = 0;
01341 while (block != editor->document()->end())
01342 {
01343 AeslEditorUserData *uData = polymorphic_downcast_or_null<AeslEditorUserData *>(block.userData());
01344 if (lineCounter == line)
01345 {
01346
01347 if (uData)
01348 {
01349 if (!uData->properties.contains(property) || (uData->properties[property] != value))
01350 {
01351 uData->properties[property] = value;
01352 changed = true;
01353 }
01354 }
01355 else
01356 {
01357 block.setUserData(new AeslEditorUserData(property, value));
01358 changed = true;
01359 }
01360 }
01361 else
01362 {
01363
01364 if (uData && removeOld && uData->properties.contains(property))
01365 {
01366 uData->properties.remove(property);
01367 if (uData->properties.isEmpty())
01368 {
01369
01370 block.setUserData(0);
01371 }
01372 changed = true;
01373 }
01374 }
01375
01376 block = block.next();
01377 lineCounter++;
01378 }
01379
01380 return changed;
01381 }
01382
01383 bool NodeTab::clearEditorProperty(const QString &property, unsigned line)
01384 {
01385 bool changed = false;
01386
01387
01388 QTextBlock block = editor->document()->begin();
01389 unsigned lineCounter = 0;
01390 while (block != editor->document()->end())
01391 {
01392 if (lineCounter == line)
01393 {
01394 AeslEditorUserData *uData = polymorphic_downcast_or_null<AeslEditorUserData *>(block.userData());
01395 if (uData && uData->properties.contains(property))
01396 {
01397 uData->properties.remove(property);
01398 if (uData->properties.isEmpty())
01399 {
01400
01401 block.setUserData(0);
01402 }
01403 changed = true;
01404 }
01405 }
01406 block = block.next();
01407 lineCounter++;
01408 }
01409
01410 return changed;
01411 }
01412
01413 bool NodeTab::clearEditorProperty(const QString &property)
01414 {
01415 bool changed = false;
01416
01417
01418 QTextBlock block = editor->document()->begin();
01419 while (block != editor->document()->end())
01420 {
01421 AeslEditorUserData *uData = polymorphic_downcast_or_null<AeslEditorUserData *>(block.userData());
01422 if (uData && uData->properties.contains(property))
01423 {
01424 uData->properties.remove(property);
01425 if (uData->properties.isEmpty())
01426 {
01427
01428 block.setUserData(0);
01429 }
01430 changed = true;
01431 }
01432 block = block.next();
01433 }
01434
01435 return changed;
01436 }
01437
01438 void NodeTab::switchEditorProperty(const QString &oldProperty, const QString &newProperty)
01439 {
01440 QTextBlock block = editor->document()->begin();
01441 while (block != editor->document()->end())
01442 {
01443 AeslEditorUserData *uData = polymorphic_downcast_or_null<AeslEditorUserData *>(block.userData());
01444 if (uData && uData->properties.contains(oldProperty))
01445 {
01446 uData->properties.remove(oldProperty);
01447 uData->properties[newProperty] = QVariant();
01448 }
01449 block = block.next();
01450 }
01451 }
01452
01453 NewNamedValueDialog::NewNamedValueDialog(QString *name, int *value, int min, int max) :
01454 name(name),
01455 value(value)
01456 {
01457
01458 label1 = new QLabel(tr("Name", "Name of the named value (can be a constant, event,...)"));
01459 line1 = new QLineEdit(*name);
01460 label2 = new QLabel(tr("Default description", "When no description is given for the named value"));
01461 line2 = new QSpinBox();
01462 line2->setRange(min, max);
01463 line2->setValue(*value);
01464 QLabel* lineHelp = new QLabel(QString("(%1 ... %2)").arg(min).arg(max));
01465 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
01466
01467
01468 QVBoxLayout* mainLayout = new QVBoxLayout();
01469 mainLayout->addWidget(label1);
01470 mainLayout->addWidget(line1);
01471 mainLayout->addWidget(label2);
01472 mainLayout->addWidget(line2);
01473 mainLayout->addWidget(lineHelp);
01474 mainLayout->addWidget(buttonBox);
01475 setLayout(mainLayout);
01476
01477
01478 setModal(true);
01479
01480
01481 connect(buttonBox, SIGNAL(accepted()), this, SLOT(okSlot()));
01482 connect(buttonBox, SIGNAL(rejected()), this, SLOT(cancelSlot()));
01483 }
01484
01485 bool NewNamedValueDialog::getNamedValue(QString *name, int *value, int min, int max, QString title, QString valueName, QString valueDescription)
01486 {
01487 NewNamedValueDialog dialog(name, value, min, max);
01488 dialog.setWindowTitle(title);
01489 dialog.label1->setText(valueName);
01490 dialog.label2->setText(valueDescription);
01491 dialog.resize(500, 0);
01492
01493 int ret = dialog.exec();
01494
01495 if (ret)
01496 return true;
01497 else
01498 return false;
01499 }
01500
01501 void NewNamedValueDialog::okSlot()
01502 {
01503 *name = line1->text();
01504 *value = line2->value();
01505 accept();
01506 }
01507
01508 void NewNamedValueDialog::cancelSlot()
01509 {
01510 *name = "";
01511 *value = -1;
01512 reject();
01513 }
01514
01515 MainWindow::MainWindow(QVector<QTranslator*> translators, const QString& commandLineTarget, bool autoRefresh, QWidget *parent) :
01516 QMainWindow(parent),
01517 getDescriptionTimer(0),
01518 sourceModified(false),
01519 autoMemoryRefresh(autoRefresh)
01520 {
01521
01522 target = new DashelTarget(translators, commandLineTarget);
01523
01524
01525 eventsDescriptionsModel = new MaskableNamedValuesVectorModel(&commonDefinitions.events, tr("Event number %0"), this);
01526 eventsDescriptionsModel->setExtraMimeType("application/aseba-events");
01527 constantsDefinitionsModel = new NamedValuesVectorModel(&commonDefinitions.constants, this);
01528 constantsDefinitionsModel->setExtraMimeType("application/aseba-constants");
01529 constantsDefinitionsModel->setEditable(true);
01530
01531
01532 ConfigDialog::init(this);
01533
01534
01535 setupWidgets();
01536 setupMenu();
01537 setupConnections();
01538
01539
01540 updateWindowTitle();
01541 if (readSettings() == false)
01542 resize(1000,700);
01543
01544
01545 target->broadcastGetDescription();
01546 }
01547
01548 MainWindow::~MainWindow()
01549 {
01550 #ifdef HAVE_QWT
01551 for (EventViewers::iterator it = eventsViewers.begin(); it != eventsViewers.end(); ++it)
01552 {
01553 it.value()->detachFromMain();
01554 }
01555 #endif // HAVE_QWT
01556
01557 delete target;
01558 }
01559
01560 void MainWindow::about()
01561 {
01562 QString text = tr("<p>Aseba version informations:</p>" \
01563 "<ul><li>Aseba ver. %0"\
01564 "<br/>(build ver. %1/protocol ver. %2)" \
01565 "</li><li>Dashel ver. %3"\
01566 "<br/>(supported stream types: %4)"\
01567 "</li></ul>" \
01568 "<p>(c) 2006-2012 <a href=\"http://stephane.magnenat.net\">Stéphane Magnenat</a> and other contributors.</p>" \
01569 "<p><a href=\"%5\">%5</a></p>" \
01570 "<p>Aseba is open-source licensed under the LGPL version 3.</p>");
01571
01572 text = text.
01573 arg(ASEBA_VERSION).
01574 arg(ASEBA_BUILD_VERSION).
01575 arg(ASEBA_PROTOCOL_VERSION).
01576 arg(DASHEL_VERSION).
01577 arg(QString::fromStdString(Dashel::streamTypeRegistry.list())).
01578 arg(tr("http://aseba.wikidot.com/en:start"));
01579
01580 QMessageBox::about(this, tr("About Aseba Studio"), text);
01581 }
01582
01583 bool MainWindow::newFile()
01584 {
01585 if (askUserBeforeDiscarding())
01586 {
01587 clearDocumentSpecificTabs();
01588
01589 for (int i = 0; i < nodes->count(); i++)
01590 {
01591 NodeTab* tab = polymorphic_downcast<NodeTab*>(nodes->widget(i));
01592 Q_ASSERT(tab);
01593 tab->editor->clear();
01594 }
01595 actualFileName.clear();
01596 sourceModified = false;
01597 constantsDefinitionsModel->clear();
01598 constantsDefinitionsModel->clearWasModified();
01599 eventsDescriptionsModel->clear();
01600 eventsDescriptionsModel->clearWasModified();
01601 updateWindowTitle();
01602 return true;
01603 }
01604 return false;
01605 }
01606
01607 void MainWindow::openFile(const QString &path)
01608 {
01609
01610 if (askUserBeforeDiscarding() == false)
01611 return;
01612
01613 QString fileName = path;
01614
01615 if (fileName.isEmpty())
01616 fileName = QFileDialog::getOpenFileName(this,
01617 tr("Open Script"), "", "Aseba scripts (*.aesl)");
01618
01619 QFile file(fileName);
01620 if (!file.open(QFile::ReadOnly))
01621 return;
01622
01623 QDomDocument document("aesl-source");
01624 QString errorMsg;
01625 int errorLine;
01626 int errorColumn;
01627 if (document.setContent(&file, false, &errorMsg, &errorLine, &errorColumn))
01628 {
01629 eventsDescriptionsModel->clear();
01630 constantsDefinitionsModel->clear();
01631
01632 int noNodeCount = 0;
01633 clearDocumentSpecificTabs();
01634 actualFileName = fileName;
01635 QDomNode domNode = document.documentElement().firstChild();
01636 while (!domNode.isNull())
01637 {
01638 if (domNode.isElement())
01639 {
01640 QDomElement element = domNode.toElement();
01641 if (element.tagName() == "node")
01642 {
01643
01644 ScriptTab::SavedPlugins savedPlugins;
01645 QDomElement toolsPlugins(element.firstChildElement("toolsPlugins"));
01646 QDomElement toolPlugin(toolsPlugins.firstChildElement());
01647 while (!toolPlugin.isNull())
01648 {
01649 QDomDocument pluginDataDocument("tool-plugin-data");
01650 pluginDataDocument.appendChild(pluginDataDocument.importNode(toolPlugin.firstChildElement(), true));
01651 NodeToolInterface::SavedContent savedContent(toolPlugin.nodeName(), pluginDataDocument);
01652 savedPlugins.push_back(savedContent);
01653 toolPlugin = toolPlugin.nextSiblingElement();
01654 }
01655
01656
01657 QString text;
01658 for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
01659 {
01660 QDomText t = n.toText();
01661 if (!t.isNull())
01662 text += t.data();
01663 }
01664
01665
01666 NodeTab* tab = getTabFromName(element.attribute("name"), element.attribute("nodeId", 0).toUInt());
01667 if (tab)
01668 {
01669 tab->restorePlugins(savedPlugins, true);
01670 tab->editor->setPlainText(text);
01671 }
01672 else
01673 {
01674 nodes->addTab(
01675 new AbsentNodeTab(
01676 0,
01677 element.attribute("name"), text,
01678 savedPlugins
01679 ),
01680 element.attribute("name") + tr(" (not available)")
01681 );
01682 noNodeCount++;
01683 }
01684 }
01685 else if (element.tagName() == "event")
01686 {
01687 const QString eventName(element.attribute("name"));
01688 const unsigned eventSize(element.attribute("size").toUInt());
01689 eventsDescriptionsModel->addNamedValue(NamedValue(eventName.toStdWString(), std::min(unsigned(ASEBA_MAX_EVENT_ARG_SIZE), eventSize)));
01690 }
01691 else if (element.tagName() == "constant")
01692 {
01693 constantsDefinitionsModel->addNamedValue(NamedValue(element.attribute("name").toStdWString(), element.attribute("value").toInt()));
01694 }
01695 else if (element.tagName() == "keywords")
01696 {
01697 if( element.attribute("flag") == "true" )
01698 showKeywordsAct->setChecked(true);
01699 else
01700 showKeywordsAct->setChecked(false);
01701 }
01702
01703 }
01704 domNode = domNode.nextSibling();
01705 }
01706
01707
01708 if (noNodeCount)
01709 QMessageBox::warning(this,
01710 tr("Loading"),
01711 tr("%0 scripts have no corresponding nodes in the current network and have not been loaded.").arg(noNodeCount)
01712 );
01713
01714
01715 updateRecentFiles(fileName);
01716 regenerateOpenRecentMenu();
01717
01718 recompileAll();
01719
01720 sourceModified = false;
01721 constantsDefinitionsModel->clearWasModified();
01722 eventsDescriptionsModel->clearWasModified();
01723 updateWindowTitle();
01724 }
01725 else
01726 {
01727 QMessageBox::warning(this,
01728 tr("Loading"),
01729 tr("Error in XML source file: %0 at line %1, column %2").arg(errorMsg).arg(errorLine).arg(errorColumn)
01730 );
01731 }
01732
01733 file.close();
01734 }
01735
01736 void MainWindow::openRecentFile()
01737 {
01738 QAction* entry = polymorphic_downcast<QAction*>(sender());
01739 openFile(entry->text());
01740 }
01741
01742 bool MainWindow::save()
01743 {
01744 return saveFile(actualFileName);
01745 }
01746
01747 bool MainWindow::saveFile(const QString &previousFileName)
01748 {
01749 QString fileName = previousFileName;
01750
01751 if (fileName.isEmpty())
01752 fileName = QFileDialog::getSaveFileName(this,
01753 tr("Save Script"), actualFileName, "Aseba scripts (*.aesl)");
01754
01755 if (fileName.isEmpty())
01756 return false;
01757
01758 if (fileName.lastIndexOf(".") < 0)
01759 fileName += ".aesl";
01760
01761 QFile file(fileName);
01762 if (!file.open(QFile::WriteOnly | QFile::Truncate))
01763 return false;
01764
01765 actualFileName = fileName;
01766 updateRecentFiles(fileName);
01767
01768
01769 QDomDocument document("aesl-source");
01770 QDomElement root = document.createElement("network");
01771 document.appendChild(root);
01772
01773 root.appendChild(document.createTextNode("\n\n\n"));
01774 root.appendChild(document.createComment("list of global events"));
01775
01776
01777 for (size_t i = 0; i < commonDefinitions.events.size(); i++)
01778 {
01779 QDomElement element = document.createElement("event");
01780 element.setAttribute("name", QString::fromStdWString(commonDefinitions.events[i].name));
01781 element.setAttribute("size", QString::number(commonDefinitions.events[i].value));
01782 root.appendChild(element);
01783 }
01784
01785 root.appendChild(document.createTextNode("\n\n\n"));
01786 root.appendChild(document.createComment("list of constants"));
01787
01788
01789 for (size_t i = 0; i < commonDefinitions.constants.size(); i++)
01790 {
01791 QDomElement element = document.createElement("constant");
01792 element.setAttribute("name", QString::fromStdWString(commonDefinitions.constants[i].name));
01793 element.setAttribute("value", QString::number(commonDefinitions.constants[i].value));
01794 root.appendChild(element);
01795 }
01796
01797
01798 root.appendChild(document.createTextNode("\n\n\n"));
01799 root.appendChild(document.createComment("show keywords state"));
01800
01801 QDomElement keywords = document.createElement("keywords");
01802 if( showKeywordsAct->isChecked() )
01803 keywords.setAttribute("flag", "true");
01804 else
01805 keywords.setAttribute("flag", "false");
01806 root.appendChild(keywords);
01807
01808
01809 for (int i = 0; i < nodes->count(); i++)
01810 {
01811 const ScriptTab* tab = dynamic_cast<const ScriptTab*>(nodes->widget(i));
01812 if (tab)
01813 {
01814 QString nodeName;
01815
01816 const NodeTab* nodeTab = dynamic_cast<const NodeTab*>(tab);
01817 if (nodeTab)
01818 nodeName = target->getName(nodeTab->nodeId());
01819
01820 const AbsentNodeTab* absentNodeTab = dynamic_cast<const AbsentNodeTab*>(tab);
01821 if (absentNodeTab)
01822 nodeName = absentNodeTab->name;
01823
01824 const QString& nodeContent = tab->editor->toPlainText();
01825
01826 root.appendChild(document.createTextNode("\n\n\n"));
01827 root.appendChild(document.createComment(QString("node %0").arg(nodeName)));
01828
01829 QDomElement element = document.createElement("node");
01830 element.setAttribute("name", nodeName);
01831 element.setAttribute("nodeId", tab->nodeId());
01832 QDomText text = document.createTextNode(nodeContent);
01833 element.appendChild(text);
01834 ScriptTab::SavedPlugins savedPlugins(tab->savePlugins());
01835 if (!savedPlugins.isEmpty())
01836 {
01837 QDomElement plugins = document.createElement("toolsPlugins");
01838 for (ScriptTab::SavedPlugins::const_iterator it(savedPlugins.begin()); it != savedPlugins.end(); ++it)
01839 {
01840 const NodeToolInterface::SavedContent content(*it);
01841 QDomElement plugin(document.createElement(content.first));
01842 plugin.appendChild(document.importNode(content.second.documentElement(), true));
01843 plugins.appendChild(plugin);
01844 }
01845 element.appendChild(plugins);
01846 }
01847 root.appendChild(element);
01848 }
01849 }
01850 root.appendChild(document.createTextNode("\n\n\n"));
01851
01852 QTextStream out(&file);
01853 document.save(out, 0);
01854
01855 sourceModified = false;
01856 constantsDefinitionsModel->clearWasModified();
01857 eventsDescriptionsModel->clearWasModified();
01858 updateWindowTitle();
01859
01860 return true;
01861 }
01862
01863 void MainWindow::exportMemoriesContent()
01864 {
01865 QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export memory content"), "", "All Files (*);;CSV files (*.csv);;Text files (*.txt)");
01866
01867 QFile file(exportFileName);
01868 if (!file.open(QFile::WriteOnly | QFile::Truncate))
01869 return;
01870
01871 QTextStream out(&file);
01872
01873 for (int i = 0; i < nodes->count(); i++)
01874 {
01875 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01876 if (tab)
01877 {
01878 const QString nodeName(target->getName(tab->nodeId()));
01879 const QList<TargetVariablesModel::Variable>& variables(tab->vmMemoryModel->getVariables());
01880
01881 for (int j = 0; j < variables.size(); ++j)
01882 {
01883 const TargetVariablesModel::Variable& variable(variables[j]);
01884 out << nodeName << "." << variable.name << " ";
01885 for (size_t k = 0; k < variable.value.size(); ++k)
01886 {
01887 out << variable.value[k] << " ";
01888 }
01889 out << "\n";
01890 }
01891 }
01892 }
01893 }
01894
01895 void MainWindow::importMemoriesContent()
01896 {
01897 QString importFileName = QFileDialog::getOpenFileName(this, tr("Import memory content"), "", "All Files (*);;CSV files (*.csv);;Text files (*.txt)");
01898
01899 QFile file(importFileName);
01900 if (!file.open(QFile::ReadOnly))
01901 return;
01902
01903 QTextStream in(&file);
01904
01905 QSet<QString> nodesNotFound;
01906 QStringList variablesNotFound;
01907
01908 while (!in.atEnd())
01909 {
01910 QString line(in.readLine());
01911 int pointPos(line.indexOf('.'));
01912 QString nodeName(line.left(pointPos));
01913 NodeTab* tab(getTabFromName(nodeName));
01914 if (tab)
01915 {
01916 int endVarNamePos(line.indexOf(' ', pointPos+1));
01917 if (endVarNamePos != -1)
01918 {
01919 QString variableName(line.mid(pointPos+1, endVarNamePos-pointPos-1));
01920 VariablesDataVector values;
01921 int index(endVarNamePos);
01922 while (index != -1)
01923 {
01924 int nextIndex(line.indexOf(' ', index+1));
01925 QString value(line.mid(index+1, nextIndex - index - 1));
01926 if (value.isEmpty())
01927 break;
01928 values.push_back(value.toShort());
01929 index = nextIndex;
01930 }
01931 if (!tab->vmMemoryModel->setVariableValues(variableName, values))
01932 {
01933 variablesNotFound << tr("%0 on node %1").arg(variableName).arg(nodeName);
01934 }
01935 }
01936 }
01937 else
01938 nodesNotFound.insert(nodeName);
01939 }
01940
01941 if (!nodesNotFound.isEmpty() || !variablesNotFound.isEmpty())
01942 {
01943 QString msg;
01944 if (!nodesNotFound.isEmpty())
01945 {
01946 msg += tr("The following nodes are not present in the current network and their associated content was not imported:\n");
01947 foreach (QString value, nodesNotFound)
01948 msg += "• " + value + "\n";
01949 }
01950 if (!variablesNotFound.isEmpty())
01951 {
01952 msg += tr("The following variables are not present in the current network and their associated content was not imported:\n");
01953 foreach (QString value, variablesNotFound)
01954 msg += "• " + value + "\n";
01955 }
01956 QMessageBox::warning(this,
01957 tr("Some content was not imported"),
01958 msg
01959 );
01960 }
01961 }
01962
01963 void MainWindow::copyAll()
01964 {
01965 QString toCopy;
01966 for (int i = 0; i < nodes->count(); i++)
01967 {
01968 const NodeTab* nodeTab = dynamic_cast<NodeTab*>(nodes->widget(i));
01969 if (nodeTab)
01970 {
01971 toCopy += QString("# node %0\n").arg(target->getName(nodeTab->nodeId()));
01972 toCopy += nodeTab->editor->toPlainText();
01973 toCopy += "\n\n";
01974 }
01975 const AbsentNodeTab* absentNodeTab = dynamic_cast<AbsentNodeTab*>(nodes->widget(i));
01976 if (absentNodeTab)
01977 {
01978 toCopy += QString("# absent node named %0\n").arg(absentNodeTab->name);
01979 toCopy += absentNodeTab->editor->toPlainText();
01980 toCopy += "\n\n";
01981 }
01982 }
01983 QApplication::clipboard()->setText(toCopy);
01984 }
01985
01986 void MainWindow::findTriggered()
01987 {
01988 ScriptTab* tab = dynamic_cast<ScriptTab*>(nodes->currentWidget());
01989 if (tab && tab->editor->textCursor().hasSelection())
01990 findDialog->setFindText(tab->editor->textCursor().selectedText());
01991 findDialog->replaceGroupBox->setChecked(false);
01992 findDialog->show();
01993 }
01994
01995 void MainWindow::replaceTriggered()
01996 {
01997 findDialog->replaceGroupBox->setChecked(true);
01998 findDialog->show();
01999 }
02000
02001 void MainWindow::commentTriggered()
02002 {
02003 assert(currentScriptTab);
02004 currentScriptTab->editor->commentAndUncommentSelection(AeslEditor::CommentSelection);
02005 }
02006
02007 void MainWindow::uncommentTriggered()
02008 {
02009 assert(currentScriptTab);
02010 currentScriptTab->editor->commentAndUncommentSelection(AeslEditor::UncommentSelection);
02011 }
02012
02013 void MainWindow::showLineNumbersChanged(bool state)
02014 {
02015 for (int i = 0; i < nodes->count(); i++)
02016 {
02017 NodeTab* tab = polymorphic_downcast<NodeTab*>(nodes->widget(i));
02018 Q_ASSERT(tab);
02019 tab->linenumbers->showLineNumbers(state);
02020 }
02021 ConfigDialog::setShowLineNumbers(state);
02022 }
02023
02024 void MainWindow::goToLine()
02025 {
02026 assert(currentScriptTab);
02027 QTextEdit* editor(currentScriptTab->editor);
02028 const QTextDocument* document(editor->document());
02029 QTextCursor cursor(editor->textCursor());
02030 bool ok;
02031 const int curLine = cursor.blockNumber() + 1;
02032 const int minLine = 1;
02033 const int maxLine = document->lineCount();
02034 const int line = QInputDialog::getInt(
02035 this, tr("Go To Line"), tr("Line:"), curLine, minLine, maxLine, 1, &ok);
02036 if (ok)
02037 editor->setTextCursor(QTextCursor(document->findBlockByLineNumber(line-1)));
02038 }
02039
02040 void MainWindow::showSettings()
02041 {
02042 ConfigDialog::showConfig();
02043 }
02044
02045 void MainWindow::toggleBreakpoint()
02046 {
02047 assert(currentScriptTab);
02048 currentScriptTab->editor->toggleBreakpoint();
02049 }
02050
02051 void MainWindow::clearAllBreakpoints()
02052 {
02053 assert(currentScriptTab);
02054 currentScriptTab->editor->clearAllBreakpoints();
02055 }
02056
02057 void MainWindow::resetAll()
02058 {
02059 for (int i = 0; i < nodes->count(); i++)
02060 {
02061 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02062 if (tab)
02063 tab->resetClicked();
02064 }
02065 }
02066
02067 void MainWindow::loadAll()
02068 {
02069 for (int i = 0; i < nodes->count(); i++)
02070 {
02071 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02072 if (tab)
02073 tab->loadClicked();
02074 }
02075 }
02076
02077 void MainWindow::runAll()
02078 {
02079 for (int i = 0; i < nodes->count(); i++)
02080 {
02081 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02082 if (tab)
02083 target->run(tab->nodeId());
02084 }
02085 }
02086
02087 void MainWindow::pauseAll()
02088 {
02089 for (int i = 0; i < nodes->count(); i++)
02090 {
02091 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02092 if (tab)
02093 target->pause(tab->nodeId());
02094 }
02095 }
02096
02097 void MainWindow::stopAll()
02098 {
02099 for (int i = 0; i < nodes->count(); i++)
02100 {
02101 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02102 if (tab)
02103 target->stop(tab->nodeId());
02104 }
02105 }
02106
02107 void MainWindow::showHidden(bool show)
02108 {
02109 for (int i = 0; i < nodes->count(); i++)
02110 {
02111 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02112 if (tab)
02113 {
02114 tab->vmFunctionsModel->recreateTreeFromDescription(show);
02115 tab->showHidden = show;
02116 tab->updateHidden();
02117 }
02118 }
02119 ConfigDialog::setShowHidden(show);
02120 }
02121
02122 void MainWindow::showKeywords(bool show)
02123 {
02124 for (int i = 0; i < nodes->count(); i++)
02125 {
02126 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02127 if (tab)
02128 tab->showKeywords(show);
02129 }
02130 ConfigDialog::setShowKeywordToolbar(show);
02131 }
02132
02133 void MainWindow::clearAllExecutionError()
02134 {
02135 for (int i = 0; i < nodes->count(); i++)
02136 {
02137 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02138 if (tab)
02139 tab->clearExecutionErrors();
02140 }
02141 logger->setStyleSheet("");
02142 }
02143
02144 void MainWindow::uploadReadynessChanged()
02145 {
02146 bool ready = true;
02147 for (int i = 0; i < nodes->count(); i++)
02148 {
02149 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02150 if (tab)
02151 {
02152 if (!tab->loadButton->isEnabled())
02153 {
02154 ready = false;
02155 break;
02156 }
02157 }
02158 }
02159
02160 loadAllAct->setEnabled(ready);
02161 writeAllBytecodesAct->setEnabled(ready);
02162 }
02163
02164 void MainWindow::sendEvent()
02165 {
02166 QModelIndex currentRow = eventsDescriptionsView->selectionModel()->currentIndex();
02167 Q_ASSERT(currentRow.isValid());
02168
02169 const unsigned eventId = currentRow.row();
02170 const QString eventName = QString::fromStdWString(commonDefinitions.events[eventId].name);
02171 const int argsCount = commonDefinitions.events[eventId].value;
02172 VariablesDataVector data(argsCount);
02173
02174 if (argsCount > 0)
02175 {
02176 QString argList;
02177 while (true)
02178 {
02179 bool ok;
02180 argList = QInputDialog::getText(this, tr("Specify event arguments"), tr("Please specify the %0 arguments of event %1").arg(argsCount).arg(eventName), QLineEdit::Normal, argList, &ok);
02181 if (ok)
02182 {
02183 QStringList args = argList.split(QRegExp("[\\s,]+"), QString::SkipEmptyParts);
02184 if (args.size() != argsCount)
02185 {
02186 QMessageBox::warning(this,
02187 tr("Wrong number of arguments"),
02188 tr("You gave %0 arguments where event %1 requires %2").arg(args.size()).arg(eventName).arg(argsCount)
02189 );
02190 continue;
02191 }
02192 for (int i = 0; i < args.size(); i++)
02193 {
02194 data[i] = args.at(i).toShort(&ok);
02195 if (!ok)
02196 {
02197 QMessageBox::warning(this,
02198 tr("Invalid value"),
02199 tr("Invalid value for argument %0 of event %1").arg(i).arg(eventName)
02200 );
02201 break;
02202 }
02203 }
02204 if (ok)
02205 break;
02206 }
02207 else
02208 return;
02209 }
02210 }
02211
02212 target->sendEvent(eventId, data);
02213 userEvent(eventId, data);
02214 }
02215
02216 void MainWindow::sendEventIf(const QModelIndex &index)
02217 {
02218 if (index.column() == 0)
02219 sendEvent();
02220 }
02221
02222 void MainWindow::toggleEventVisibleButton(const QModelIndex &index)
02223 {
02224 if (index.column() == 2)
02225 eventsDescriptionsModel->toggle(index);
02226 }
02227
02228 void MainWindow::plotEvent()
02229 {
02230 #ifdef HAVE_QWT
02231 QModelIndex currentRow = eventsDescriptionsView->selectionModel()->currentIndex();
02232 Q_ASSERT(currentRow.isValid());
02233 const unsigned eventId = currentRow.row();
02234 plotEvent(eventId);
02235 #endif // HAVE_QWT
02236 }
02237
02238 void MainWindow::eventContextMenuRequested(const QPoint & pos)
02239 {
02240 #ifdef HAVE_QWT
02241 const QModelIndex index(eventsDescriptionsView->indexAt(pos));
02242 if (index.isValid() && (index.column() == 0))
02243 {
02244 const QString eventName(eventsDescriptionsModel->data(index).toString());
02245 QMenu menu;
02246 menu.addAction(tr("Plot event %1").arg(eventName));
02247 const QAction* ret = menu.exec(eventsDescriptionsView->mapToGlobal(pos));
02248 if (ret)
02249 {
02250 const unsigned eventId = index.row();
02251 plotEvent(eventId);
02252 }
02253 }
02254 #endif // HAVE_QWT
02255 }
02256
02257 void MainWindow::plotEvent(const unsigned eventId)
02258 {
02259 #ifdef HAVE_QWT
02260 const unsigned eventVariablesCount(eventsDescriptionsModel->data(eventsDescriptionsModel->index(eventId, 1)).toUInt());
02261 const QString eventName(eventsDescriptionsModel->data(eventsDescriptionsModel->index(eventId, 0)).toString());
02262 const QString tabTitle(tr("plot of %1").arg(eventName));
02263 nodes->addTab(new EventViewer(eventId, eventName, eventVariablesCount, &eventsViewers), tabTitle, true);
02264 #endif // HAVE_QWT
02265 }
02266
02267 void MainWindow::logEntryDoubleClicked(QListWidgetItem * item)
02268 {
02269 if (item->data(Qt::UserRole).type() == QVariant::Point)
02270 {
02271 int node = item->data(Qt::UserRole).toPoint().x();
02272 int line = item->data(Qt::UserRole).toPoint().y();
02273
02274 NodeTab* tab = getTabFromId(node);
02275 Q_ASSERT(tab);
02276 nodes->setCurrentWidget(tab);
02277 tab->editor->setTextCursor(QTextCursor(tab->editor->document()->findBlockByLineNumber(line)));
02278 tab->editor->setFocus();
02279 }
02280 }
02281
02282 void MainWindow::tabChanged(int index)
02283 {
02284
02285 if (currentScriptTab)
02286 {
02287 disconnect(cutAct, SIGNAL(triggered()), currentScriptTab->editor, SLOT(cut()));
02288 disconnect(copyAct, SIGNAL(triggered()), currentScriptTab->editor, SLOT(copy()));
02289 disconnect(pasteAct, SIGNAL(triggered()), currentScriptTab->editor, SLOT(paste()));
02290 disconnect(undoAct, SIGNAL(triggered()), currentScriptTab->editor, SLOT(undo()));
02291 disconnect(redoAct, SIGNAL(triggered()), currentScriptTab->editor, SLOT(redo()));
02292
02293 disconnect(currentScriptTab->editor, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
02294 disconnect(currentScriptTab->editor, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
02295 disconnect(currentScriptTab->editor, SIGNAL(undoAvailable(bool)), undoAct, SLOT(setEnabled(bool)));
02296 disconnect(currentScriptTab->editor, SIGNAL(redoAvailable(bool)), redoAct, SLOT(setEnabled(bool)));
02297
02298 pasteAct->setEnabled(false);
02299 findDialog->hide();
02300 findDialog->editor = 0;
02301 findAct->setEnabled(false);
02302 replaceAct->setEnabled(false);
02303 goToLineAct->setEnabled(false);
02304 }
02305
02306
02307 if (index >= 0)
02308 {
02309 ScriptTab *tab = dynamic_cast<ScriptTab*>(nodes->widget(index));
02310 if (tab)
02311 {
02312 connect(copyAct, SIGNAL(triggered()), tab->editor, SLOT(copy()));
02313 connect(tab->editor, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
02314
02315 findDialog->editor = tab->editor;
02316 findAct->setEnabled(true);
02317 goToLineAct->setEnabled(true);
02318
02319 NodeTab *nodeTab = dynamic_cast<NodeTab*>(tab);
02320 if (nodeTab)
02321 {
02322 connect(cutAct, SIGNAL(triggered()), tab->editor, SLOT(cut()));
02323 connect(pasteAct, SIGNAL(triggered()), tab->editor, SLOT(paste()));
02324 connect(undoAct, SIGNAL(triggered()), tab->editor, SLOT(undo()));
02325 connect(redoAct, SIGNAL(triggered()), tab->editor, SLOT(redo()));
02326
02327 connect(tab->editor, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
02328 connect(tab->editor, SIGNAL(undoAvailable(bool)), undoAct, SLOT(setEnabled(bool)));
02329 connect(tab->editor, SIGNAL(redoAvailable(bool)), redoAct, SLOT(setEnabled(bool)));
02330
02331 if (compilationMessageBox->isVisible())
02332 nodeTab->recompile();
02333
02334
02335 target->getVariables(nodeTab->id, 0, nodeTab->allocatedVariablesCount);
02336
02337 showCompilationMsg->setEnabled(true);
02338 findDialog->replaceGroupBox->setEnabled(true);
02339
02340 pasteAct->setEnabled(true);
02341 replaceAct->setEnabled(true);
02342 }
02343 else
02344 {
02345 showCompilationMsg->setEnabled(false);
02346 findDialog->replaceGroupBox->setEnabled(false);
02347 }
02348
02349
02350 cutAct->setEnabled(false);
02351 copyAct->setEnabled(false);
02352 undoAct->setEnabled(false);
02353 redoAct->setEnabled(false);
02354
02355 currentScriptTab = tab;
02356 }
02357 else
02358 currentScriptTab = 0;
02359 }
02360 else
02361 currentScriptTab = 0;
02362 }
02363
02364 void MainWindow::showCompilationMessages(bool doShow)
02365 {
02366
02367 compilationMessageBox->setVisible(doShow);
02368 if (nodes->currentWidget())
02369 polymorphic_downcast<NodeTab *>(nodes->currentWidget())->recompile();
02370 }
02371
02372 void MainWindow::compilationMessagesWasHidden()
02373 {
02374 showCompilationMsg->setChecked(false);
02375 }
02376
02377 void MainWindow::showMemoryUsage(bool show)
02378 {
02379 for (int i = 0; i < nodes->count(); i++)
02380 {
02381 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02382 if (tab)
02383 tab->showMemoryUsage(show);
02384 }
02385 ConfigDialog::setShowMemoryUsage(show);
02386 }
02387
02388 void MainWindow::addEventNameClicked()
02389 {
02390 QString eventName;
02391 int eventNbArgs = 0;
02392
02393
02394 const bool ok = NewNamedValueDialog::getNamedValue(&eventName, &eventNbArgs, 0, 32767, tr("Add a new event"), tr("Name:"), tr("Number of arguments", "For the newly created event"));
02395
02396 eventName = eventName.trimmed();
02397 if (ok && !eventName.isEmpty())
02398 {
02399 if (commonDefinitions.events.contains(eventName.toStdWString()))
02400 {
02401 QMessageBox::warning(this, tr("Event already exists"), tr("Event %0 already exists.").arg(eventName));
02402 }
02403 else if (!QRegExp("\\w(\\w|\\.)*").exactMatch(eventName) || eventName[0].isDigit())
02404 {
02405 QMessageBox::warning(this, tr("Invalid event name"), tr("Event %0 has an invalid name. Valid names start with an alphabetical character or an \"_\", and continue with any number of alphanumeric characters, \"_\" and \".\"").arg(eventName));
02406 }
02407 else
02408 {
02409 eventsDescriptionsModel->addNamedValue(NamedValue(eventName.toStdWString(), eventNbArgs));
02410 }
02411 }
02412 }
02413
02414 void MainWindow::removeEventNameClicked()
02415 {
02416 QModelIndex currentRow = eventsDescriptionsView->selectionModel()->currentIndex();
02417 Q_ASSERT(currentRow.isValid());
02418 eventsDescriptionsModel->delNamedValue(currentRow.row());
02419
02420 for (int i = 0; i < nodes->count(); i++)
02421 {
02422 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02423 if (tab)
02424 tab->isSynchronized = false;
02425 }
02426 }
02427
02428 void MainWindow::eventsUpdated(bool indexChanged)
02429 {
02430 if (indexChanged)
02431 {
02432 statusText->setText(tr("Desynchronised! Please reload."));
02433 statusText->show();
02434 }
02435 recompileAll();
02436 updateWindowTitle();
02437 }
02438
02439 void MainWindow::eventsUpdatedDirty()
02440 {
02441 eventsUpdated(true);
02442 }
02443
02444 void MainWindow::eventsDescriptionsSelectionChanged()
02445 {
02446 bool isSelected = eventsDescriptionsView->selectionModel()->currentIndex().isValid();
02447 removeEventNameButton->setEnabled(isSelected);
02448 sendEventButton->setEnabled(isSelected);
02449 #ifdef HAVE_QWT
02450 plotEventButton->setEnabled(isSelected);
02451 #endif // HAVE_QWT
02452 }
02453
02454 void MainWindow::resetStatusText()
02455 {
02456 bool flag = true;
02457
02458 for (int i = 0; i < nodes->count(); i++)
02459 {
02460 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02461 if (tab)
02462 {
02463 if( !tab->isSynchronized )
02464 {
02465 flag = false;
02466 break;
02467 }
02468 }
02469 }
02470
02471 if (flag)
02472 {
02473 statusText->clear();
02474 statusText->hide();
02475 }
02476 }
02477
02478 void MainWindow::addConstantClicked()
02479 {
02480 bool ok;
02481 QString constantName;
02482 int constantValue = 0;
02483
02484
02485 ok = NewNamedValueDialog::getNamedValue(&constantName, &constantValue, -32768, 32767, tr("Add a new constant"), tr("Name:"), tr("Value", "Value assigned to the constant"));
02486
02487 if (ok && !constantName.isEmpty())
02488 {
02489 if (commonDefinitions.constants.contains(constantName.toStdWString()))
02490 {
02491 QMessageBox::warning(this, tr("Constant already defined"), tr("Constant %0 is already defined.").arg(constantName));
02492 }
02493 else
02494 {
02495 constantsDefinitionsModel->addNamedValue(NamedValue(constantName.toStdWString(), constantValue));
02496 recompileAll();
02497 updateWindowTitle();
02498 }
02499 }
02500 }
02501
02502 void MainWindow::removeConstantClicked()
02503 {
02504 QModelIndex currentRow = constantsView->selectionModel()->currentIndex();
02505 Q_ASSERT(currentRow.isValid());
02506 constantsDefinitionsModel->delNamedValue(currentRow.row());
02507
02508 recompileAll();
02509 updateWindowTitle();
02510 }
02511
02512 void MainWindow::constantsSelectionChanged()
02513 {
02514 bool isSelected = constantsView->selectionModel()->currentIndex().isValid();
02515 removeConstantButton->setEnabled(isSelected);
02516 }
02517
02518 void MainWindow::recompileAll()
02519 {
02520 for (int i = 0; i < nodes->count(); i++)
02521 {
02522 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02523 if (tab)
02524 tab->recompile();
02525 }
02526 }
02527
02528 void MainWindow::writeAllBytecodes()
02529 {
02530 for (int i = 0; i < nodes->count(); i++)
02531 {
02532 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02533 if (tab)
02534 tab->writeBytecode();
02535 }
02536 }
02537
02538 void MainWindow::rebootAllNodes()
02539 {
02540 for (int i = 0; i < nodes->count(); i++)
02541 {
02542 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02543 if (tab)
02544 tab->reboot();
02545 }
02546 }
02547
02548 void MainWindow::sourceChanged()
02549 {
02550 sourceModified = true;
02551 updateWindowTitle();
02552 }
02553
02554 void MainWindow::showUserManual()
02555 {
02556 helpViewer.showHelp(HelpViewer::USERMANUAL);
02557 }
02558
02560 void MainWindow::nodeConnected(unsigned node)
02561 {
02562
02563 NodeTab* tab = new NodeTab(this, target, &commonDefinitions, node);
02564 tab->showKeywords(showKeywordsAct->isChecked());
02565 tab->linenumbers->showLineNumbers(showLineNumbers->isChecked());
02566 tab->showMemoryUsage(showMemoryUsageAct->isChecked());
02567
02568
02569 const int absentIndex(getAbsentIndexFromId(node));
02570 const AbsentNodeTab* absentTab(getAbsentTabFromId(node));
02571 if (absentTab && nodes->tabText(absentIndex) == target->getName(node))
02572 {
02573 tab->editor->document()->setPlainText(absentTab->editor->document()->toPlainText());
02574 tab->restorePlugins(absentTab->savePlugins(), false);
02575 tab->updateToolList();
02576 nodes->removeAndDeleteTab(absentIndex);
02577 }
02578
02579
02580 connect(tab, SIGNAL(uploadReadynessChanged(bool)), SLOT(uploadReadynessChanged()));
02581 nodes->addTab(tab, target->getName(node));
02582
02583 regenerateToolsMenus();
02584 }
02585
02587 void MainWindow::nodeDisconnected(unsigned node)
02588 {
02589 const int index = getIndexFromId(node);
02590 Q_ASSERT(index >= 0);
02591 const NodeTab* tab = getTabFromId(node);
02592 const QString& tabName = nodes->tabText(index);
02593
02594 nodes->addTab(
02595 new AbsentNodeTab(
02596 node,
02597 tabName,
02598 tab->editor->document()->toPlainText(),
02599 tab->savePlugins()
02600 ),
02601 tabName
02602 );
02603
02604 nodes->removeAndDeleteTab(index);
02605
02606 regenerateToolsMenus();
02607 regenerateHelpMenu();
02608
02609 if (!getDescriptionTimer)
02610 getDescriptionTimer = startTimer(2000);
02611 }
02612
02614 void MainWindow::networkDisconnected()
02615 {
02616
02617 std::vector<unsigned> toDisconnect;
02618 for (int i = 0; i < nodes->count(); i++)
02619 {
02620 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02621 if (tab)
02622 toDisconnect.push_back(tab->nodeId());
02623 }
02624
02625
02626 for (size_t i = 0; i < toDisconnect.size(); i++)
02627 nodeDisconnected(toDisconnect[i]);
02628 }
02629
02631 void MainWindow::userEvent(unsigned id, const VariablesDataVector &data)
02632 {
02633 if (eventsDescriptionsModel->isVisible(id))
02634 {
02635 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
02636
02637 if (id < commonDefinitions.events.size())
02638 text += QString("\n%0 : ").arg(QString::fromStdWString(commonDefinitions.events[id].name));
02639 else
02640 text += tr("\nevent %0 : ").arg(id);
02641
02642 for (size_t i = 0; i < data.size(); i++)
02643 text += QString("%0 ").arg(data[i]);
02644
02645 if (logger->count() > 50)
02646 delete logger->takeItem(0);
02647 QListWidgetItem * item = new QListWidgetItem(QIcon(":/images/info.png"), text, logger);
02648 logger->scrollToBottom();
02649 Q_UNUSED(item);
02650 }
02651
02652 #ifdef HAVE_QWT
02653
02654
02655 QList<EventViewer*> viewers = eventsViewers.values(id);
02656 for (int i = 0; i < viewers.size(); ++i)
02657 viewers.at(i)->addData(data);
02658
02659 #endif // HAVE_QWT
02660 }
02661
02663 void MainWindow::userEventsDropped(unsigned amount)
02664 {
02665 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
02666 text += QString("\n%0 user events not shown").arg(amount);
02667
02668 if (logger->count() > 50)
02669 delete logger->takeItem(0);
02670 QListWidgetItem * item = new QListWidgetItem(QIcon(":/images/info.png"), text, logger);
02671 logger->scrollToBottom();
02672 Q_UNUSED(item);
02673 logger->setStyleSheet(" QListView::item { background: rgb(255,128,128); }");
02674 }
02675
02677 void MainWindow::arrayAccessOutOfBounds(unsigned node, unsigned line, unsigned size, unsigned index)
02678 {
02679 addErrorEvent(node, line, tr("array access at %0 out of bounds [0..%1]").arg(index).arg(size-1));
02680 }
02681
02683 void MainWindow::divisionByZero(unsigned node, unsigned line)
02684 {
02685 addErrorEvent(node, line, tr("division by zero"));
02686 }
02687
02689 void MainWindow::eventExecutionKilled(unsigned node, unsigned line)
02690 {
02691 addErrorEvent(node, line, tr("event execution killed"));
02692 }
02693
02695 void MainWindow::nodeSpecificError(unsigned node, unsigned line, const QString& message)
02696 {
02697 addErrorEvent(node, line, message);
02698 }
02699
02701 void MainWindow::addErrorEvent(unsigned node, unsigned line, const QString& message)
02702 {
02703 NodeTab* tab = getTabFromId(node);
02704 Q_ASSERT(tab);
02705
02706 if (tab->setEditorProperty("executionError", QVariant(), line, true))
02707 {
02708 tab->rehighlighting = true;
02709 tab->highlighter->rehighlight();
02710 }
02711
02712 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
02713 text += "\n" + tr("%0:%1: %2").arg(target->getName(node)).arg(line + 1).arg(message);
02714
02715 if (logger->count() > 50)
02716 delete logger->takeItem(0);
02717 QListWidgetItem *item = new QListWidgetItem(QIcon(":/images/warning.png"), text, logger);
02718 item->setData(Qt::UserRole, QPoint(node, line));
02719 logger->scrollToBottom();
02720 }
02721
02722
02724 void MainWindow::executionPosChanged(unsigned node, unsigned line)
02725 {
02726 NodeTab* tab = getTabFromId(node);
02727 Q_ASSERT(tab);
02728
02729 tab->executionPosChanged(line);
02730 }
02731
02733 void MainWindow::executionModeChanged(unsigned node, Target::ExecutionMode mode)
02734 {
02735 NodeTab* tab = getTabFromId(node);
02736 Q_ASSERT(tab);
02737
02738 tab->executionModeChanged(mode);
02739 }
02740
02742 void MainWindow::variablesMemoryEstimatedDirty(unsigned node)
02743 {
02744 NodeTab* tab = getTabFromId(node);
02745 Q_ASSERT(tab);
02746
02747 tab->refreshMemoryClicked();
02748 }
02749
02751 void MainWindow::variablesMemoryChanged(unsigned node, unsigned start, const VariablesDataVector &variables)
02752 {
02753 NodeTab* tab = getTabFromId(node);
02754 Q_ASSERT(tab);
02755
02756 tab->vmMemoryModel->setVariablesData(start, variables);
02757 }
02758
02760 void MainWindow::breakpointSetResult(unsigned node, unsigned line, bool success)
02761 {
02762 NodeTab* tab = getTabFromId(node);
02763 Q_ASSERT(tab);
02764
02765 tab->breakpointSetResult(line, success);
02766 }
02767
02769 void MainWindow::timerEvent ( QTimerEvent * event )
02770 {
02771 bool doSend(false);
02772
02773 for (int i = 0; i < nodes->count(); i++)
02774 {
02775 AbsentNodeTab* tab = dynamic_cast<AbsentNodeTab*>(nodes->widget(i));
02776 if (tab)
02777 doSend = doSend || (tab->id != 0);
02778 }
02779
02780 if (doSend)
02781 {
02782 target->broadcastGetDescription();
02783 }
02784 else
02785 {
02786 killTimer(getDescriptionTimer);
02787 getDescriptionTimer = 0;
02788 }
02789 }
02790
02792 int MainWindow::getIndexFromId(unsigned node) const
02793 {
02794 for (int i = 0; i < nodes->count(); i++)
02795 {
02796 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02797 if (tab)
02798 {
02799 if (tab->nodeId() == node)
02800 return i;
02801 }
02802 }
02803 return -1;
02804 }
02805
02807 NodeTab* MainWindow::getTabFromId(unsigned node) const
02808 {
02809 for (int i = 0; i < nodes->count(); i++)
02810 {
02811 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02812 if (tab)
02813 {
02814 if (tab->nodeId() == node)
02815 return tab;
02816 }
02817 }
02818 return 0;
02819 }
02820
02822 NodeTab* MainWindow::getTabFromName(const QString& name, unsigned preferedId) const
02823 {
02824 NodeTab* bestFound(0);
02825 for (int i = 0; i < nodes->count(); i++)
02826 {
02827 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02828 if (tab)
02829 {
02830 const unsigned id(tab->nodeId());
02831 if (target->getName(id) == name)
02832 {
02833 if (id == preferedId)
02834 return tab;
02835 else if (!bestFound)
02836 bestFound = tab;
02837 }
02838 }
02839 }
02840 return bestFound;
02841 }
02842
02844 int MainWindow::getAbsentIndexFromId(unsigned node) const
02845 {
02846 for (int i = 0; i < nodes->count(); i++)
02847 {
02848 AbsentNodeTab* tab = dynamic_cast<AbsentNodeTab*>(nodes->widget(i));
02849 if (tab)
02850 {
02851 if (tab->nodeId() == node)
02852 return i;
02853 }
02854 }
02855 return -1;
02856 }
02857
02859 AbsentNodeTab* MainWindow::getAbsentTabFromId(unsigned node) const
02860 {
02861 for (int i = 0; i < nodes->count(); i++)
02862 {
02863 AbsentNodeTab* tab = dynamic_cast<AbsentNodeTab*>(nodes->widget(i));
02864 if (tab)
02865 {
02866 if (tab->nodeId() == node)
02867 return tab;
02868 }
02869 }
02870 return 0;
02871 }
02872
02873 void MainWindow::clearDocumentSpecificTabs()
02874 {
02875 bool changed = false;
02876 do
02877 {
02878 changed = false;
02879 for (int i = 0; i < nodes->count(); i++)
02880 {
02881 QWidget* tab = nodes->widget(i);
02882
02883 #ifdef HAVE_QWT
02884 if (dynamic_cast<AbsentNodeTab*>(tab) || dynamic_cast<EventViewer*>(tab))
02885 #else // HAVE_QWT
02886 if (dynamic_cast<AbsentNodeTab*>(tab))
02887 #endif // HAVE_QWT
02888 {
02889 nodes->removeAndDeleteTab(i);
02890 changed = true;
02891 break;
02892 }
02893 }
02894 }
02895 while (changed);
02896 }
02897
02898 void MainWindow::setupWidgets()
02899 {
02900 currentScriptTab = 0;
02901 nodes = new EditorsPlotsTabWidget;
02902 nodes->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
02903
02904 QSplitter *splitter = new QSplitter();
02905 splitter->addWidget(nodes);
02906 setCentralWidget(splitter);
02907
02908 addConstantButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
02909 removeConstantButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
02910 addConstantButton->setToolTip(tr("Add a new constant"));
02911 removeConstantButton->setToolTip(tr("Remove this constant"));
02912 removeConstantButton->setEnabled(false);
02913
02914 constantsView = new FixedWidthTableView;
02915 constantsView->setShowGrid(false);
02916 constantsView->verticalHeader()->hide();
02917 constantsView->horizontalHeader()->hide();
02918 constantsView->setModel(constantsDefinitionsModel);
02919 constantsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
02920 constantsView->setSelectionMode(QAbstractItemView::SingleSelection);
02921 constantsView->setSelectionBehavior(QAbstractItemView::SelectRows);
02922 constantsView->setDragDropMode(QAbstractItemView::InternalMove);
02923 constantsView->setDragEnabled(true);
02924 constantsView->setDropIndicatorShown(true);
02925 constantsView->setItemDelegateForColumn(1, new SpinBoxDelegate(-32768, 32767, this));
02926 constantsView->setMinimumHeight(100);
02927 constantsView->setSecondColumnLongestContent("-888888##");
02928 constantsView->resizeRowsToContents();
02929
02930 QGridLayout* constantsLayout = new QGridLayout;
02931 constantsLayout->addWidget(new QLabel(tr("<b>Constants</b>")),0,0);
02932 constantsLayout->setColumnStretch(0, 1);
02933 constantsLayout->addWidget(addConstantButton,0,1);
02934 constantsLayout->setColumnStretch(1, 0);
02935 constantsLayout->addWidget(removeConstantButton,0,2);
02936 constantsLayout->setColumnStretch(2, 0);
02937 constantsLayout->addWidget(constantsView, 1, 0, 1, 3);
02938
02939
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970 addEventNameButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
02971 removeEventNameButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
02972 removeEventNameButton->setEnabled(false);
02973 sendEventButton = new QPushButton(QPixmap(QString(":/images/newmsg.png")), "");
02974 sendEventButton->setEnabled(false);
02975
02976 addEventNameButton->setToolTip(tr("Add a new event"));
02977 removeEventNameButton->setToolTip(tr("Remove this event"));
02978 sendEventButton->setToolTip(tr("Send this event"));
02979
02980 #ifdef HAVE_QWT
02981 plotEventButton = new QPushButton(QPixmap(QString(":/images/plot.png")), "");
02982 plotEventButton->setEnabled(false);
02983 plotEventButton->setToolTip(tr("Plot this event"));
02984 #endif // HAVE_QWT
02985
02986 eventsDescriptionsView = new FixedWidthTableView;
02987 eventsDescriptionsView->setShowGrid(false);
02988 eventsDescriptionsView->verticalHeader()->hide();
02989 eventsDescriptionsView->horizontalHeader()->hide();
02990 eventsDescriptionsView->setModel(eventsDescriptionsModel);
02991 eventsDescriptionsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
02992 eventsDescriptionsView->setSelectionMode(QAbstractItemView::SingleSelection);
02993 eventsDescriptionsView->setSelectionBehavior(QAbstractItemView::SelectRows);
02994 eventsDescriptionsView->setDragDropMode(QAbstractItemView::InternalMove);
02995 eventsDescriptionsView->setDragEnabled(true);
02996 eventsDescriptionsView->setDropIndicatorShown(true);
02997 eventsDescriptionsView->setItemDelegateForColumn(1, new SpinBoxDelegate(0, ASEBA_MAX_EVENT_ARG_COUNT, this));
02998 eventsDescriptionsView->setMinimumHeight(100);
02999 eventsDescriptionsView->setSecondColumnLongestContent("255###");
03000 eventsDescriptionsView->resizeRowsToContents();
03001 eventsDescriptionsView->setContextMenuPolicy(Qt::CustomContextMenu);
03002
03003 QGridLayout* eventsLayout = new QGridLayout;
03004 eventsLayout->addWidget(new QLabel(tr("<b>Global Events</b>")),0,0,1,4);
03005 eventsLayout->addWidget(addEventNameButton,1,0);
03006
03007 eventsLayout->addWidget(removeEventNameButton,1,1);
03008
03009
03010 eventsLayout->addWidget(sendEventButton,1,2);
03011
03012 #ifdef HAVE_QWT
03013 eventsLayout->addWidget(plotEventButton,1,3);
03014 #endif // HAVE_QWT
03015 eventsLayout->addWidget(eventsDescriptionsView, 2, 0, 1, 4);
03016
03017
03018
03019
03020
03021
03022
03023
03024 logger = new QListWidget;
03025 logger->setMinimumSize(80,100);
03026 logger->setSelectionMode(QAbstractItemView::NoSelection);
03027 clearLogger = new QPushButton(tr("Clear"));
03028 statusText = new QLabel("");
03029 statusText->hide();
03030
03031 QVBoxLayout* loggerLayout = new QVBoxLayout;
03032 loggerLayout->addWidget(statusText);
03033 loggerLayout->addWidget(logger);
03034 loggerLayout->addWidget(clearLogger);
03035
03036
03037 QSplitter* rightPanelSplitter = new QSplitter(Qt::Vertical);
03038
03039 QWidget* constantsWidget = new QWidget;
03040 constantsWidget->setLayout(constantsLayout);
03041 rightPanelSplitter->addWidget(constantsWidget);
03042
03043 QWidget* eventsWidget = new QWidget;
03044 eventsWidget->setLayout(eventsLayout);
03045 rightPanelSplitter->addWidget(eventsWidget);
03046
03047 QWidget* loggerWidget = new QWidget;
03048 loggerWidget->setLayout(loggerLayout);
03049 rightPanelSplitter->addWidget(loggerWidget);
03050
03051
03052 splitter->addWidget(rightPanelSplitter);
03053 splitter->setSizes(QList<int>() << 800 << 200);
03054
03055
03056 compilationMessageBox = new CompilationLogDialog();
03057 connect(this, SIGNAL(MainWindowClosed()), compilationMessageBox, SLOT(close()));
03058 connect(this, SIGNAL(MainWindowClosed()), compilationMessageBox, SLOT(deleteLater()));
03059 findDialog = new FindDialog(this);
03060 connect(this, SIGNAL(MainWindowClosed()), findDialog, SLOT(close()));
03061
03062
03063 QString lang = target->getLanguage().left(2);
03064 if (lang != "")
03065 helpViewer.setLanguage(lang);
03066 else
03067 helpViewer.setLanguage(QLocale::system().name());
03068 connect(this, SIGNAL(MainWindowClosed()), &helpViewer, SLOT(close()));
03069 }
03070
03071 void MainWindow::setupConnections()
03072 {
03073
03074 connect(nodes, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
03075 connect(logger, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(logEntryDoubleClicked(QListWidgetItem *)));
03076 connect(ConfigDialog::getInstance(), SIGNAL(settingsChanged()), SLOT(applySettings()));
03077
03078
03079 connect(loadAllAct, SIGNAL(triggered()), SLOT(loadAll()));
03080 connect(resetAllAct, SIGNAL(triggered()), SLOT(resetAll()));
03081 connect(runAllAct, SIGNAL(triggered()), SLOT(runAll()));
03082 connect(pauseAllAct, SIGNAL(triggered()), SLOT(pauseAll()));
03083
03084
03085 connect(addEventNameButton, SIGNAL(clicked()), SLOT(addEventNameClicked()));
03086 connect(removeEventNameButton, SIGNAL(clicked()), SLOT(removeEventNameClicked()));
03087 connect(sendEventButton, SIGNAL(clicked()), SLOT(sendEvent()));
03088 #ifdef HAVE_QWT
03089 connect(plotEventButton, SIGNAL(clicked()), SLOT(plotEvent()));
03090 #endif // HAVE_QWT
03091 connect(eventsDescriptionsView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(eventsDescriptionsSelectionChanged()));
03092 connect(eventsDescriptionsView, SIGNAL(doubleClicked(const QModelIndex &)), SLOT(sendEventIf(const QModelIndex &)));
03093 connect(eventsDescriptionsView, SIGNAL(clicked(const QModelIndex &)), SLOT(toggleEventVisibleButton(const QModelIndex &)) );
03094 connect(eventsDescriptionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(eventsUpdated()));
03095 connect(eventsDescriptionsModel, SIGNAL(publicRowsInserted()), SLOT(eventsUpdated()));
03096 connect(eventsDescriptionsModel, SIGNAL(publicRowsRemoved()), SLOT(eventsUpdatedDirty()));
03097 connect(eventsDescriptionsView, SIGNAL(customContextMenuRequested ( const QPoint & )), SLOT(eventContextMenuRequested(const QPoint & )));
03098
03099
03100 connect(clearLogger, SIGNAL(clicked()), logger, SLOT(clear()));
03101 connect(clearLogger, SIGNAL(clicked()), SLOT(clearAllExecutionError()));
03102
03103
03104 connect(addConstantButton, SIGNAL(clicked()), SLOT(addConstantClicked()));
03105 connect(removeConstantButton, SIGNAL(clicked()), SLOT(removeConstantClicked()));
03106 connect(constantsView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(constantsSelectionChanged()));
03107 connect(constantsDefinitionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(recompileAll()));
03108 connect(constantsDefinitionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(updateWindowTitle()));
03109
03110
03111 connect(target, SIGNAL(nodeConnected(unsigned)), SLOT(nodeConnected(unsigned)));
03112 connect(target, SIGNAL(nodeDisconnected(unsigned)), SLOT(nodeDisconnected(unsigned)));
03113 connect(target, SIGNAL(networkDisconnected()), SLOT(networkDisconnected()));
03114
03115 connect(target, SIGNAL(userEvent(unsigned, const VariablesDataVector &)), SLOT(userEvent(unsigned, const VariablesDataVector &)));
03116 connect(target, SIGNAL(userEventsDropped(unsigned)), SLOT(userEventsDropped(unsigned)));
03117 connect(target, SIGNAL(arrayAccessOutOfBounds(unsigned, unsigned, unsigned, unsigned)), SLOT(arrayAccessOutOfBounds(unsigned, unsigned, unsigned, unsigned)));
03118 connect(target, SIGNAL(divisionByZero(unsigned, unsigned)), SLOT(divisionByZero(unsigned, unsigned)));
03119 connect(target, SIGNAL(eventExecutionKilled(unsigned, unsigned)), SLOT(eventExecutionKilled(unsigned, unsigned)));
03120 connect(target, SIGNAL(nodeSpecificError(unsigned, unsigned, QString)), SLOT(nodeSpecificError(unsigned, unsigned, QString)));
03121
03122 connect(target, SIGNAL(executionPosChanged(unsigned, unsigned)), SLOT(executionPosChanged(unsigned, unsigned)));
03123 connect(target, SIGNAL(executionModeChanged(unsigned, Target::ExecutionMode)), SLOT(executionModeChanged(unsigned, Target::ExecutionMode)));
03124 connect(target, SIGNAL(variablesMemoryEstimatedDirty(unsigned)), SLOT(variablesMemoryEstimatedDirty(unsigned)));
03125
03126 connect(target, SIGNAL(variablesMemoryChanged(unsigned, unsigned, const VariablesDataVector &)), SLOT(variablesMemoryChanged(unsigned, unsigned, const VariablesDataVector &)));
03127
03128 connect(target, SIGNAL(breakpointSetResult(unsigned, unsigned, bool)), SLOT(breakpointSetResult(unsigned, unsigned, bool)));
03129 }
03130
03131 void MainWindow::regenerateOpenRecentMenu()
03132 {
03133 openRecentMenu->clear();
03134
03135
03136 QSettings settings;
03137 QStringList recentFiles = settings.value("recent files").toStringList();
03138 for (int i = 0; i < recentFiles.size(); i++)
03139 {
03140 const QString& fileName(recentFiles.at(i));
03141 openRecentMenu->addAction(fileName, this, SLOT(openRecentFile()));
03142 }
03143 }
03144
03145 void MainWindow::updateRecentFiles(const QString& fileName)
03146 {
03147 QSettings settings;
03148 QStringList recentFiles = settings.value("recent files").toStringList();
03149 if (recentFiles.contains(fileName))
03150 recentFiles.removeAt(recentFiles.indexOf(fileName));
03151 recentFiles.push_front(fileName);
03152 const int maxRecentFiles = 8;
03153 if (recentFiles.size() > maxRecentFiles)
03154 recentFiles.pop_back();
03155 settings.setValue("recent files", recentFiles);
03156 }
03157
03158 void MainWindow::regenerateToolsMenus()
03159 {
03160 writeBytecodeMenu->clear();
03161 rebootMenu->clear();
03162 saveBytecodeMenu->clear();
03163
03164 unsigned activeVMCount(0);
03165 for (int i = 0; i < nodes->count(); i++)
03166 {
03167 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
03168 if (tab)
03169 {
03170 QAction *act = writeBytecodeMenu->addAction(tr("...inside %0").arg(target->getName(tab->nodeId())),tab, SLOT(writeBytecode()));
03171 connect(tab, SIGNAL(uploadReadynessChanged(bool)), act, SLOT(setEnabled(bool)));
03172
03173 rebootMenu->addAction(tr("...%0").arg(target->getName(tab->nodeId())),tab, SLOT(reboot()));
03174
03175 act = saveBytecodeMenu->addAction(tr("...of %0").arg(target->getName(tab->nodeId())),tab, SLOT(saveBytecode()));
03176 connect(tab, SIGNAL(uploadReadynessChanged(bool)), act, SLOT(setEnabled(bool)));
03177
03178 ++activeVMCount;
03179 }
03180 }
03181
03182 writeBytecodeMenu->addSeparator();
03183 writeAllBytecodesAct = writeBytecodeMenu->addAction(tr("...inside all nodes"), this, SLOT(writeAllBytecodes()));
03184
03185 rebootMenu->addSeparator();
03186 rebootMenu->addAction(tr("...all nodes"), this, SLOT(rebootAllNodes()));
03187
03188 globalToolBar->setVisible(activeVMCount > 1);
03189 }
03190
03191 void MainWindow::generateHelpMenu()
03192 {
03193 helpMenu->addAction(tr("&User Manual..."), this, SLOT(showUserManual()), QKeySequence(tr("F1", "Help|User Manual")));
03194 helpMenu->addSeparator();
03195
03196 helpMenuTargetSpecificSeparator = helpMenu->addSeparator();
03197 helpMenu->addAction(tr("Web site Aseba..."), this, SLOT(openToUrlFromAction()))->setData(QUrl(tr("http://aseba.wikidot.com/en:start")));
03198 helpMenu->addAction(tr("Report bug..."), this, SLOT(openToUrlFromAction()))->setData(QUrl(tr("http://github.com/aseba-community/aseba/issues/new")));
03199
03200 #ifdef Q_WS_MAC
03201 helpMenu->addAction("about", this, SLOT(about()));
03202 helpMenu->addAction("About &Qt...", qApp, SLOT(aboutQt()));
03203 #else // Q_WS_MAC
03204 helpMenu->addSeparator();
03205 helpMenu->addAction(tr("&About..."), this, SLOT(about()));
03206 helpMenu->addAction(tr("About &Qt..."), qApp, SLOT(aboutQt()));
03207 #endif // Q_WS_MAC
03208 }
03209
03210 void MainWindow::regenerateHelpMenu()
03211 {
03212
03213 while (!targetSpecificHelp.isEmpty())
03214 {
03215 QAction *action(targetSpecificHelp.takeFirst());
03216 helpMenu->removeAction(action);
03217 delete action;
03218 }
03219
03220
03221 typedef std::set<int> ProductIds;
03222 ProductIds productIds;
03223 for (int i = 0; i < nodes->count(); i++)
03224 {
03225 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
03226 if (tab)
03227 productIds.insert(tab->productId());
03228 }
03229 for (ProductIds::const_iterator it(productIds.begin()); it != productIds.end(); ++it)
03230 {
03231 QAction *action;
03232 switch (*it)
03233 {
03234 case ASEBA_PID_THYMIO2:
03235 action = new QAction(tr("Thymio programming tutorial..."), helpMenu);
03236 connect(action, SIGNAL(triggered()), SLOT(openToUrlFromAction()));
03237 action->setData(QUrl(tr("http://aseba.wikidot.com/en:thymiotutoriel")));
03238 targetSpecificHelp.append(action);
03239 helpMenu->insertAction(helpMenuTargetSpecificSeparator, action);
03240 action = new QAction(tr("Thymio programming interface..."), helpMenu);
03241 connect(action, SIGNAL(triggered()), SLOT(openToUrlFromAction()));
03242 action->setData(QUrl(tr("http://aseba.wikidot.com/en:thymioapi")));
03243 targetSpecificHelp.append(action);
03244 helpMenu->insertAction(helpMenuTargetSpecificSeparator, action);
03245 break;
03246
03247 case ASEBA_PID_CHALLENGE:
03248 action = new QAction(tr("Challenge tutorial..."), helpMenu);
03249 connect(action, SIGNAL(triggered()), SLOT(openToUrlFromAction()));
03250 action->setData(QUrl(tr("http://aseba.wikidot.com/en:gettingstarted")));
03251 targetSpecificHelp.append(action);
03252 helpMenu->insertAction(helpMenuTargetSpecificSeparator, action);
03253 break;
03254
03255 case ASEBA_PID_MARXBOT:
03256 action = new QAction(tr("MarXbot user manual..."), helpMenu);
03257 connect(action, SIGNAL(triggered()), SLOT(openToUrlFromAction()));
03258 action->setData(QUrl(tr("http://mobots.epfl.ch/data/robots/marxbot-user-manual.pdf")));
03259 targetSpecificHelp.append(action);
03260 helpMenu->insertAction(helpMenuTargetSpecificSeparator, action);
03261 break;
03262
03263 default:
03264 break;
03265 }
03266 }
03267 }
03268
03269 void MainWindow::openToUrlFromAction() const
03270 {
03271 const QAction *action(reinterpret_cast<QAction *>(sender()));
03272 QDesktopServices::openUrl(action->data().toUrl());
03273 }
03274
03275 void MainWindow::setupMenu()
03276 {
03277
03278 QMenu *fileMenu = new QMenu(tr("&File"), this);
03279 menuBar()->addMenu(fileMenu);
03280
03281 fileMenu->addAction(QIcon(":/images/filenew.png"), tr("&New"),
03282 this, SLOT(newFile()),
03283 QKeySequence(tr("Ctrl+N", "File|New")));
03284 fileMenu->addAction(QIcon(":/images/fileopen.png"), tr("&Open..."),
03285 this, SLOT(openFile()),
03286 QKeySequence(tr("Ctrl+O", "File|Open")));
03287 openRecentMenu = new QMenu(tr("Open &Recent"), fileMenu);
03288 regenerateOpenRecentMenu();
03289 fileMenu->addMenu(openRecentMenu)->setIcon(QIcon(":/images/fileopen.png"));
03290
03291 fileMenu->addAction(QIcon(":/images/filesave.png"), tr("&Save..."),
03292 this, SLOT(save()),
03293 QKeySequence(tr("Ctrl+S", "File|Save")));
03294 fileMenu->addAction(QIcon(":/images/filesaveas.png"), tr("Save &As..."),
03295 this, SLOT(saveFile()));
03296
03297 fileMenu->addSeparator();
03298
03299
03300
03301
03302 fileMenu->addAction(QIcon(":/images/filesaveas.png"), tr("Export &memories content..."),
03303 this, SLOT(exportMemoriesContent()));
03304 fileMenu->addAction(QIcon(":/images/fileopen.png"), tr("&Import memories content..."),
03305 this, SLOT(importMemoriesContent()));
03306 fileMenu->addSeparator();
03307 #ifdef Q_WS_MAC
03308 fileMenu->addAction(QIcon(":/images/exit.png"), "quit",
03309 this, SLOT(close()),
03310 QKeySequence(tr("Ctrl+Q", "File|Quit")));
03311 #else // Q_WS_MAC
03312 fileMenu->addAction(QIcon(":/images/exit.png"), tr("&Quit"),
03313 this, SLOT(close()),
03314 QKeySequence(tr("Ctrl+Q", "File|Quit")));
03315 #endif // Q_WS_MAC
03316
03317
03318 cutAct = new QAction(QIcon(":/images/editcut.png"), tr("Cu&t"), this);
03319 cutAct->setShortcut(tr("Ctrl+X", "Edit|Cut"));
03320 cutAct->setEnabled(false);
03321
03322 copyAct = new QAction(QIcon(":/images/editcopy.png"), tr("&Copy"), this);
03323 copyAct->setShortcut(tr("Ctrl+C", "Edit|Copy"));
03324 copyAct->setEnabled(false);
03325
03326 pasteAct = new QAction(QIcon(":/images/editpaste.png"), tr("&Paste"), this);
03327 pasteAct->setShortcut(tr("Ctrl+V", "Edit|Paste"));
03328 pasteAct->setEnabled(false);
03329
03330 undoAct = new QAction(QIcon(":/images/undo.png"), tr("&Undo"), this);
03331 undoAct->setShortcut(tr("Ctrl+Z", "Edit|Undo"));
03332 undoAct->setEnabled(false);
03333
03334 redoAct = new QAction(QIcon(":/images/redo.png"), tr("Re&do"), this);
03335 redoAct->setShortcut(tr("Ctrl+Shift+Z", "Edit|Redo"));
03336 redoAct->setEnabled(false);
03337
03338 findAct = new QAction(QIcon(":/images/find.png"), tr("&Find..."), this);
03339 findAct->setShortcut(tr("Ctrl+F", "Edit|Find"));
03340 connect(findAct, SIGNAL(triggered()), SLOT(findTriggered()));
03341 findAct->setEnabled(false);
03342
03343 replaceAct = new QAction(QIcon(":/images/edit.png"), tr("&Replace..."), this);
03344 replaceAct->setShortcut(tr("Ctrl+R", "Edit|Replace"));
03345 connect(replaceAct, SIGNAL(triggered()), SLOT(replaceTriggered()));
03346 replaceAct->setEnabled(false);
03347
03348 commentAct = new QAction(tr("Comment the selection"), this);
03349 commentAct->setShortcut(tr("Ctrl+D", "Edit|Comment the selection"));
03350 connect(commentAct, SIGNAL(triggered()), SLOT(commentTriggered()));
03351
03352 uncommentAct = new QAction(tr("Uncomment the selection"), this);
03353 uncommentAct->setShortcut(tr("Shift+Ctrl+D", "Edit|Uncomment the selection"));
03354 connect(uncommentAct, SIGNAL(triggered()), SLOT(uncommentTriggered()));
03355
03356 QMenu *editMenu = new QMenu(tr("&Edit"), this);
03357 menuBar()->addMenu(editMenu);
03358 editMenu->addAction(cutAct);
03359 editMenu->addAction(copyAct);
03360 editMenu->addAction(pasteAct);
03361 editMenu->addSeparator();
03362 editMenu->addAction(QIcon(":/images/editcopy.png"), tr("Copy &all"), this, SLOT(copyAll()));
03363 editMenu->addSeparator();
03364 editMenu->addAction(undoAct);
03365 editMenu->addAction(redoAct);
03366 editMenu->addSeparator();
03367 editMenu->addAction(findAct);
03368 editMenu->addAction(replaceAct);
03369 editMenu->addSeparator();
03370 editMenu->addAction(commentAct);
03371 editMenu->addAction(uncommentAct);
03372
03373
03374 showKeywordsAct = new QAction(tr("Show &keywords"), this);
03375 showKeywordsAct->setCheckable(true);
03376 connect(showKeywordsAct, SIGNAL(toggled(bool)), SLOT(showKeywords(bool)));
03377
03378 showMemoryUsageAct = new QAction(tr("Show memory usage"), this);
03379 showMemoryUsageAct->setCheckable(true);
03380 connect(showMemoryUsageAct, SIGNAL(toggled(bool)), SLOT(showMemoryUsage(bool)));
03381
03382 showHiddenAct = new QAction(tr("S&how hidden variables and functions"), this);
03383 showHiddenAct->setCheckable(true);
03384 connect(showHiddenAct, SIGNAL(toggled(bool)), SLOT(showHidden(bool)));
03385
03386 showLineNumbers = new QAction(tr("Show Line Numbers"), this);
03387 showLineNumbers->setShortcut(tr("F11", "Edit|Show Line Numbers"));
03388 showLineNumbers->setCheckable(true);
03389 connect(showLineNumbers, SIGNAL(toggled(bool)), SLOT(showLineNumbersChanged(bool)));
03390
03391 goToLineAct = new QAction(QIcon(":/images/goto.png"), tr("&Go To Line..."), this);
03392 goToLineAct->setShortcut(tr("Ctrl+G", "Edit|Go To Line"));
03393 goToLineAct->setEnabled(false);
03394 connect(goToLineAct, SIGNAL(triggered()), SLOT(goToLine()));
03395
03396 QMenu *viewMenu = new QMenu(tr("&View"), this);
03397 viewMenu->addAction(showKeywordsAct);
03398 viewMenu->addAction(showMemoryUsageAct);
03399 viewMenu->addAction(showHiddenAct);
03400 viewMenu->addSeparator();
03401 viewMenu->addAction(showLineNumbers);
03402 viewMenu->addAction(goToLineAct);
03403 viewMenu->addSeparator();
03404 viewMenu->addAction(tr("&Settings"), this, SLOT(showSettings()));
03405 menuBar()->addMenu(viewMenu);
03406
03407
03408 loadAllAct = new QAction(QIcon(":/images/upload.png"), tr("&Load all"), this);
03409 loadAllAct->setShortcut(tr("F7", "Load|Load all"));
03410
03411 resetAllAct = new QAction(QIcon(":/images/reset.png"), tr("&Reset all"), this);
03412 resetAllAct->setShortcut(tr("F8", "Debug|Reset all"));
03413
03414 runAllAct = new QAction(QIcon(":/images/play.png"), tr("Ru&n all"), this);
03415 runAllAct->setShortcut(tr("F9", "Debug|Run all"));
03416
03417 pauseAllAct = new QAction(QIcon(":/images/pause.png"), tr("&Pause all"), this);
03418 pauseAllAct->setShortcut(tr("F10", "Debug|Pause all"));
03419
03420
03421 globalToolBar = addToolBar(tr("Debug"));
03422 globalToolBar->setObjectName("debug toolbar");
03423 globalToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
03424 globalToolBar->addAction(loadAllAct);
03425 globalToolBar->addAction(resetAllAct);
03426 globalToolBar->addAction(runAllAct);
03427 globalToolBar->addAction(pauseAllAct);
03428
03429
03430 toggleBreakpointAct = new QAction(tr("Toggle breakpoint"), this);
03431 toggleBreakpointAct->setShortcut(tr("Ctrl+B", "Debug|Toggle breakpoint"));
03432 connect(toggleBreakpointAct, SIGNAL(triggered()), SLOT(toggleBreakpoint()));
03433
03434 clearAllBreakpointsAct = new QAction(tr("Clear all breakpoints"), this);
03435
03436 connect(clearAllBreakpointsAct, SIGNAL(triggered()), SLOT(clearAllBreakpoints()));
03437
03438 QMenu *debugMenu = new QMenu(tr("&Debug"), this);
03439 menuBar()->addMenu(debugMenu);
03440 debugMenu->addAction(toggleBreakpointAct);
03441 debugMenu->addAction(clearAllBreakpointsAct);
03442 debugMenu->addSeparator();
03443 debugMenu->addAction(loadAllAct);
03444 debugMenu->addAction(resetAllAct);
03445 debugMenu->addAction(runAllAct);
03446 debugMenu->addAction(pauseAllAct);
03447
03448
03449 QMenu *toolMenu = new QMenu(tr("&Tools"), this);
03450 menuBar()->addMenu(toolMenu);
03451
03452
03453
03454 showCompilationMsg = new QAction(QIcon(":/images/view_text.png"), tr("&Show last compilation messages"), this);
03455 showCompilationMsg->setCheckable(true);
03456 toolMenu->addAction(showCompilationMsg);
03457 connect(showCompilationMsg, SIGNAL(toggled(bool)), SLOT(showCompilationMessages(bool)));
03458 connect(compilationMessageBox, SIGNAL(hidden()), SLOT(compilationMessagesWasHidden()));
03459 toolMenu->addSeparator();
03460 writeBytecodeMenu = new QMenu(tr("Write the program(s)..."), toolMenu);
03461 toolMenu->addMenu(writeBytecodeMenu);
03462 rebootMenu = new QMenu(tr("Reboot..."), toolMenu);
03463 toolMenu->addMenu(rebootMenu);
03464 saveBytecodeMenu = new QMenu(tr("Save the binary code..."), toolMenu);
03465 toolMenu->addMenu(saveBytecodeMenu);
03466
03467
03468 helpMenu = new QMenu(tr("&Help"), this);
03469 menuBar()->addMenu(helpMenu);
03470 generateHelpMenu();
03471 regenerateHelpMenu();
03472
03473
03474 regenerateToolsMenus();
03475
03476
03477 applySettings();
03478 }
03480
03483 bool MainWindow::askUserBeforeDiscarding()
03484 {
03485 const bool anythingModified = sourceModified || constantsDefinitionsModel->checkIfModified() || eventsDescriptionsModel->checkIfModified();
03486 if (anythingModified == false)
03487 return true;
03488
03489 QString docName(tr("Untitled"));
03490 if (!actualFileName.isEmpty())
03491 docName = actualFileName.mid(actualFileName.lastIndexOf("/") + 1);
03492
03493 QMessageBox msgBox;
03494 msgBox.setWindowTitle(tr("Aseba Studio - Confirmation Dialog"));
03495 msgBox.setText(tr("The document \"%0\" has been modified.").arg(docName));
03496 msgBox.setInformativeText(tr("Do you want to save your changes or discard them?"));
03497 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
03498 msgBox.setDefaultButton(QMessageBox::Save);
03499
03500 int ret = msgBox.exec();
03501 switch (ret)
03502 {
03503 case QMessageBox::Save:
03504
03505 if (save())
03506 return true;
03507 else
03508 return false;
03509 case QMessageBox::Discard:
03510
03511 return true;
03512 case QMessageBox::Cancel:
03513
03514 return false;
03515 default:
03516
03517 assert(false);
03518 break;
03519 }
03520
03521 return false;
03522 }
03523
03524 void MainWindow::closeEvent ( QCloseEvent * event )
03525 {
03526 if (askUserBeforeDiscarding())
03527 {
03528 writeSettings();
03529 event->accept();
03530 emit MainWindowClosed();
03531 }
03532 else
03533 {
03534 event->ignore();
03535 }
03536 }
03537
03538 bool MainWindow::readSettings()
03539 {
03540 bool result;
03541
03542 QSettings settings;
03543 result = restoreGeometry(settings.value("MainWindow/geometry").toByteArray());
03544 restoreState(settings.value("MainWindow/windowState").toByteArray());
03545 return result;
03546 }
03547
03548 void MainWindow::writeSettings()
03549 {
03550 QSettings settings;
03551 settings.setValue("MainWindow/geometry", saveGeometry());
03552 settings.setValue("MainWindow/windowState", saveState());
03553 }
03554
03555 void MainWindow::updateWindowTitle()
03556 {
03557 const bool anythingModified = sourceModified || constantsDefinitionsModel->checkIfModified() || eventsDescriptionsModel->checkIfModified();
03558
03559 QString modifiedText;
03560 if (anythingModified)
03561 modifiedText = tr("[modified] ");
03562
03563 QString docName(tr("Untitled"));
03564 if (!actualFileName.isEmpty())
03565 docName = actualFileName.mid(actualFileName.lastIndexOf("/") + 1);
03566
03567 setWindowTitle(tr("%0 %1- Aseba Studio").arg(docName).arg(modifiedText));
03568 }
03569
03570 void MainWindow::applySettings()
03571 {
03572 showKeywordsAct->setChecked(ConfigDialog::getShowKeywordToolbar());
03573 showMemoryUsageAct->setChecked(ConfigDialog::getShowMemoryUsage());
03574 showHiddenAct->setChecked(ConfigDialog::getShowHidden());
03575 showLineNumbers->setChecked(ConfigDialog::getShowLineNumbers());
03576 }
03577
03579 };
03580