00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "MainWindow.h"
00025 #include "ClickableLabel.h"
00026 #include "DashelTarget.h"
00027 #include "TargetModels.h"
00028 #include "NamedValuesVectorModel.h"
00029 #include "CustomDelegate.h"
00030 #include "AeslEditor.h"
00031 #include "VariablesViewPlugin.h"
00032 #include "EventViewer.h"
00033 #include "../common/consts.h"
00034 #include <QtGui>
00035 #include <QtXml>
00036 #include <sstream>
00037 #include <iostream>
00038 #include <cassert>
00039 #include <QTabWidget>
00040
00041 #include <MainWindow.moc>
00042
00043 using std::copy;
00044
00045
00046 template<typename Derived, typename Base>
00047 static inline Derived polymorphic_downcast(Base base)
00048 {
00049 Derived derived = dynamic_cast<Derived>(base);
00050 if (!derived)
00051 abort();
00052 return derived;
00053 }
00054
00055 namespace Aseba
00056 {
00057 #define ASEBA_SVN_REV "$Revision: 411 $"
00058
00061
00062 CompilationLogDialog::CompilationLogDialog(QWidget *parent) :
00063 QTextEdit(parent)
00064 {
00065 QFont font;
00066 font.setFamily("");
00067 font.setStyleHint(QFont::TypeWriter);
00068 font.setFixedPitch(true);
00069 font.setPointSize(10);
00070
00071 setFont(font);
00072 setTabStopWidth( QFontMetrics(font).width(' ') * 4);
00073 setReadOnly(true);
00074
00075 setWindowTitle(tr("Aseba Studio: Output of last compilation"));
00076 }
00077
00079
00080 class DraggableListWidget: public QListWidget
00081 {
00082 QStringList mimeTypes () const
00083 {
00084 QStringList types;
00085 types << "text/plain";
00086 return types;
00087 }
00088
00089 QMimeData * mimeData ( const QList<QListWidgetItem *> items ) const
00090 {
00091 QString texts;
00092 foreach (QListWidgetItem *item, items)
00093 {
00094 texts += item->text();
00095 }
00096
00097 QMimeData *mimeData = new QMimeData();
00098 mimeData->setText(texts);
00099 return mimeData;
00100 }
00101 };
00102
00104
00105 FixedWidthTableView::FixedWidthTableView()
00106 {
00107 col1Width = 50;
00108 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00109 }
00110
00111 void FixedWidthTableView::setSecondColumnLongestContent(const QString& content)
00112 {
00113 Q_ASSERT(model ()->columnCount() == 2);
00114 QFontMetrics fm(font());
00115 col1Width = fm.width(content);
00116 }
00117
00118 void FixedWidthTableView::resizeEvent ( QResizeEvent * event )
00119 {
00120 Q_ASSERT(model ()->columnCount() == 2);
00121 int col0Width = event->size().width() - col1Width;
00122 setColumnWidth(0, col0Width);
00123 setColumnWidth(1, col1Width);
00124 }
00125
00127
00128 void EditorsPlotsTabWidget::addTab(QWidget* widget, const QString& label, bool closable)
00129 {
00130 const int index = QTabWidget::addTab(widget, label);
00131 #if QT_VERSION >= 0x040500
00132 if (closable)
00133 {
00134 QPushButton* button = new QPushButton(QIcon(":/images/remove.png"), "");
00135 button->setFlat(true);
00136 connect(button, SIGNAL(clicked(bool)), this, SLOT(removeAndDeleteTab()));
00137 tabBar()->setTabButton(index, QTabBar::RightSide, button);
00138 }
00139 #endif // QT_VERSION >= 0x040500
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
00168
00169 void ScriptTab::createEditor()
00170 {
00171
00172 editor = new AeslEditor;
00173 highlighter = new AeslHighlighter(editor, editor->document());
00174 }
00175
00177
00178 AbsentNodeTab::AbsentNodeTab(const QString& name, const QString& sourceCode) :
00179 name(name)
00180 {
00181 createEditor();
00182 editor->setReadOnly(true);
00183 editor->setPlainText(sourceCode);
00184 QVBoxLayout *layout = new QVBoxLayout;
00185 layout->addWidget(editor);
00186 setLayout(layout);
00187 }
00188
00190
00191 NodeTab::NodeTab(MainWindow* mainWindow, Target *target, const CommonDefinitions *commonDefinitions, int id, QWidget *parent) :
00192 QSplitter(parent),
00193 id(id),
00194 target(target),
00195 mainWindow(mainWindow),
00196 firstCompilation(true),
00197 showHidden(mainWindow->showHiddenAct->isChecked())
00198 {
00199
00200 rehighlighting = false;
00201 errorPos = -1;
00202 allocatedVariablesCount = 0;
00203
00204
00205 compiler.setTargetDescription(target->getDescription(id));
00206 compiler.setCommonDefinitions(commonDefinitions);
00207 vmFunctionsModel = new TargetFunctionsModel(target->getDescription(id));
00208 vmMemoryModel = new TargetVariablesModel();
00209
00210
00211 setupWidgets();
00212 setupConnections();
00213
00214 editor->setFocus();
00215 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
00216
00217
00218
00219 refreshMemoryClicked();
00220 }
00221
00222 NodeTab::~NodeTab()
00223 {
00224 delete vmFunctionsModel;
00225 delete vmMemoryModel;
00226 }
00227
00228 void NodeTab::setupWidgets()
00229 {
00230 createEditor();
00231
00232
00233 cursorPosText = new QLabel;
00234 compilationResultImage = new ClickableLabel;
00235 compilationResultText = new ClickableLabel;
00236 compilationResultText->setWordWrap(true);
00237 compilationResultText->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
00238 QHBoxLayout *compilationResultLayout = new QHBoxLayout;
00239 compilationResultLayout->addWidget(cursorPosText);
00240 compilationResultLayout->addWidget(compilationResultText, 1000);
00241 compilationResultLayout->addWidget(compilationResultImage);
00242
00243
00244 QVBoxLayout *editorLayout = new QVBoxLayout;
00245 editorLayout->addWidget(editor);
00246 editorLayout->addLayout(compilationResultLayout);
00247
00248
00249
00250
00251 executionModeLabel = new QLabel(tr("unknown"));
00252
00253 loadButton = new QPushButton(QIcon(":/images/upload.png"), tr("Load"));
00254 resetButton = new QPushButton(QIcon(":/images/reset.png"), tr("Reset"));
00255 resetButton->setEnabled(false);
00256 runInterruptButton = new QPushButton(QIcon(":/images/play.png"), tr("Run"));
00257 runInterruptButton->setEnabled(false);
00258 nextButton = new QPushButton(QIcon(":/images/step.png"), tr("Next"));
00259 nextButton->setEnabled(false);
00260 refreshMemoryButton = new QPushButton(QIcon(":/images/rescan.png"), tr("refresh"));
00261
00262 QGridLayout* buttonsLayout = new QGridLayout;
00263 buttonsLayout->addWidget(new QLabel(tr("<b>Execution</b>")), 0, 0);
00264 buttonsLayout->addWidget(executionModeLabel, 0, 1);
00265 buttonsLayout->addWidget(loadButton, 1, 0);
00266 buttonsLayout->addWidget(runInterruptButton, 1, 1);
00267 buttonsLayout->addWidget(resetButton, 2, 0);
00268 buttonsLayout->addWidget(nextButton, 2, 1);
00269
00270
00271 vmMemoryView = new QTreeView;
00272 vmMemoryView->setModel(vmMemoryModel);
00273 vmMemoryView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00274 vmMemoryView->setItemDelegate(new SpinBoxDelegate(-32768, 32767, this));
00275 vmMemoryView->setColumnWidth(0, 200-QFontMetrics(QFont()).width("-8888888##"));
00276 vmMemoryView->setColumnWidth(1, QFontMetrics(QFont()).width("-8888888##"));
00277 vmMemoryView->setSelectionMode(QAbstractItemView::SingleSelection);
00278 vmMemoryView->setSelectionBehavior(QAbstractItemView::SelectItems);
00279 vmMemoryView->setDragDropMode(QAbstractItemView::DragOnly);
00280 vmMemoryView->setDragEnabled(true);
00281
00282
00283
00284 QGridLayout *memoryLayout = new QGridLayout;
00285 memoryLayout->addWidget(new QLabel(tr("<b>Memory</b>")), 0, 0);
00286 memoryLayout->addWidget(refreshMemoryButton, 0, 1);
00287 memoryLayout->addWidget(vmMemoryView, 1, 0, 1, 2);
00288
00289
00290 vmFunctionsView = new QTreeView;
00291 vmFunctionsView->setMinimumHeight(40);
00292 vmFunctionsView->setMinimumSize(QSize(50,40));
00293 vmFunctionsView->setModel(vmFunctionsModel);
00294 vmFunctionsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00295 vmFunctionsView->setSelectionMode(QAbstractItemView::SingleSelection);
00296 vmFunctionsView->setSelectionBehavior(QAbstractItemView::SelectItems);
00297 vmFunctionsView->setDragDropMode(QAbstractItemView::DragOnly);
00298 vmFunctionsView->setDragEnabled(true);
00299 vmFunctionsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
00300 vmFunctionsView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
00301 #if QT_VERSION >= 0x040400
00302 vmFunctionsView->setHeaderHidden(true);
00303 #elif (!defined(_MSC_VER))
00304 #warning "Some feature have been disabled because you are using Qt < 4.4.0"
00305 #endif
00306
00307
00308 vmLocalEvents = new DraggableListWidget;
00309 vmLocalEvents->setMinimumHeight(40);
00310 vmLocalEvents->setSelectionMode(QAbstractItemView::SingleSelection);
00311 vmLocalEvents->setDragDropMode(QAbstractItemView::DragOnly);
00312 vmLocalEvents->setDragEnabled(true);
00313 for (size_t i = 0; i < compiler.getTargetDescription()->localEvents.size(); i++)
00314 {
00315 QListWidgetItem* item = new QListWidgetItem(QString::fromUtf8(compiler.getTargetDescription()->localEvents[i].name.c_str()));
00316 item->setToolTip(QString::fromUtf8(compiler.getTargetDescription()->localEvents[i].description.c_str()));
00317 vmLocalEvents->addItem(item);
00318 }
00319
00320
00321 QToolBox* toolBox = new QToolBox;
00322 toolBox->addItem(vmFunctionsView, tr("Native Functions"));
00323 toolBox->addItem(vmLocalEvents, tr("Local Events"));
00324 QVBoxLayout* toolBoxLayout = new QVBoxLayout;
00325 toolBoxLayout->addWidget(toolBox);
00326 QWidget* toolBoxWidget = new QWidget;
00327 toolBoxWidget->setLayout(toolBoxLayout);
00328
00329
00330 QSplitter *panelSplitter = new QSplitter(Qt::Vertical);
00331
00332 QWidget* buttonsWidget = new QWidget;
00333 buttonsWidget->setLayout(buttonsLayout);
00334 panelSplitter->addWidget(buttonsWidget);
00335 panelSplitter->setCollapsible(0, false);
00336
00337 QWidget* memoryWidget = new QWidget;
00338 memoryWidget->setLayout(memoryLayout);
00339 panelSplitter->addWidget(memoryWidget);
00340 panelSplitter->setStretchFactor(1, 3);
00341
00342 panelSplitter->addWidget(toolBoxWidget);
00343 panelSplitter->setStretchFactor(2, 1);
00344
00345 addWidget(panelSplitter);
00346 QWidget *editorWidget = new QWidget;
00347 editorWidget->setLayout(editorLayout);
00348 addWidget(editorWidget);
00349 setSizes(QList<int>() << 250 << 550);
00350 }
00351
00352 void NodeTab::setupConnections()
00353 {
00354
00355 connect(loadButton, SIGNAL(clicked()), SLOT(loadClicked()));
00356 connect(resetButton, SIGNAL(clicked()), SLOT(resetClicked()));
00357 connect(runInterruptButton, SIGNAL(clicked()), SLOT(runInterruptClicked()));
00358 connect(nextButton, SIGNAL(clicked()), SLOT(nextClicked()));
00359 connect(refreshMemoryButton, SIGNAL(clicked()), SLOT(refreshMemoryClicked()));
00360
00361
00362 connect(vmMemoryModel, SIGNAL(variableValuesChanged(unsigned, const VariablesDataVector &)), SLOT(setVariableValues(unsigned, const VariablesDataVector &)));
00363
00364
00365 connect(editor, SIGNAL(textChanged()), SLOT(editorContentChanged()));
00366 connect(editor, SIGNAL(cursorPositionChanged() ), SLOT(cursorMoved()));
00367 connect(editor, SIGNAL(breakpointSet(unsigned)), SLOT(setBreakpoint(unsigned)));
00368 connect(editor, SIGNAL(breakpointCleared(unsigned)), SLOT(clearBreakpoint(unsigned)));
00369 connect(editor, SIGNAL(breakpointClearedAll()), SLOT(breakpointClearedAll()));
00370
00371 connect(compilationResultImage, SIGNAL(clicked()), SLOT(goToError()));
00372 connect(compilationResultText, SIGNAL(clicked()), SLOT(goToError()));
00373 }
00374
00375 void NodeTab::resetClicked()
00376 {
00377 clearExecutionErrors();
00378 target->reset(id);
00379 }
00380
00381 void NodeTab::loadClicked()
00382 {
00383 if (errorPos == -1)
00384 {
00385 clearEditorProperty("executionError");
00386 target->uploadBytecode(id, bytecode);
00387
00388 editor->debugging = true;
00389 reSetBreakpoints();
00390 rehighlight();
00391 }
00392 }
00393
00394 void NodeTab::runInterruptClicked()
00395 {
00396 if (runInterruptButton->text() == tr("Run"))
00397 target->run(id);
00398 else
00399 target->pause(id);
00400 }
00401
00402 void NodeTab::nextClicked()
00403 {
00404 target->next(id);
00405 }
00406
00407 void NodeTab::refreshMemoryClicked()
00408 {
00409 target->getVariables(id, 0, allocatedVariablesCount);
00410 }
00411
00412 void NodeTab::writeBytecode()
00413 {
00414 if (errorPos == -1)
00415 {
00416 loadClicked();
00417 target->writeBytecode(id);
00418 }
00419 }
00420
00421 void NodeTab::reboot()
00422 {
00423 markTargetUnsynced();
00424 target->reboot(id);
00425 }
00426
00427 void NodeTab::setVariableValues(unsigned index, const VariablesDataVector &values)
00428 {
00429 target->setVariables(id, index, values);
00430 }
00431
00432 void NodeTab::insertVariableName(const QModelIndex &index)
00433 {
00434
00435 if (!index.parent().isValid() && (index.column() == 0))
00436 editor->insertPlainText(index.data().toString());
00437 }
00438
00439 void NodeTab::editorContentChanged()
00440 {
00441 if (rehighlighting)
00442 {
00443 rehighlighting = false;
00444 }
00445 else
00446 {
00447 recompile();
00448 if (!firstCompilation)
00449 mainWindow->sourceChanged();
00450 else
00451 firstCompilation = false;
00452 }
00453 }
00454
00455 void NodeTab::updateHidden()
00456 {
00457
00458 for(int i = 0; i < vmMemoryModel->rowCount(QModelIndex()); i++)
00459 {
00460 QString name;
00461 name = vmMemoryModel->data(vmMemoryModel->index(i,0), Qt::DisplayRole).toString();
00462 if(name.at(0) == '_' || name.contains(QString("._")))
00463 vmMemoryView->setRowHidden(i,QModelIndex(), !showHidden);
00464 }
00465
00466 }
00467
00468 void NodeTab::recompile()
00469 {
00470
00471 Error error;
00472
00473
00474
00475
00476 bool doRehighlight = clearEditorProperty("errorPos");
00477
00478
00479 std::istringstream is(editor->toPlainText().toStdString());
00480 bool result;
00481 if (mainWindow->nodes->currentWidget() == this)
00482 {
00483 std::ostringstream compilationMessages;
00484 result = compiler.compile(is, bytecode, allocatedVariablesCount, error, &compilationMessages);
00485
00486 mainWindow->compilationMessageBox->setWindowTitle(
00487 tr("Aseba Studio: Output of last compilation for %0").arg(target->getName(id))
00488 );
00489
00490 if (result)
00491 mainWindow->compilationMessageBox->setText(
00492 tr("Compilation success.") + QString("\n\n") +
00493 QString::fromStdString(compilationMessages.str())
00494 );
00495 else
00496 mainWindow->compilationMessageBox->setText(
00497 QString::fromStdString(error.toString()) + ".\n\n" +
00498 QString::fromStdString(compilationMessages.str())
00499 );
00500 }
00501 else
00502 result = compiler.compile(is, bytecode, allocatedVariablesCount, error);
00503
00504
00505 if (result)
00506 {
00507 vmMemoryModel->updateVariablesStructure(compiler.getVariablesMap());
00508 updateHidden();
00509 compilationResultText->setText(tr("Compilation success."));
00510 compilationResultImage->setPixmap(QPixmap(QString(":/images/ok.png")));
00511 loadButton->setEnabled(true);
00512 emit uploadReadynessChanged(true);
00513
00514 errorPos = -1;
00515 }
00516 else
00517 {
00518 compilationResultText->setText(QString::fromStdString(error.toString()));
00519 compilationResultImage->setPixmap(QPixmap(QString(":/images/no.png")));
00520 loadButton->setEnabled(false);
00521 emit uploadReadynessChanged(false);
00522
00523
00524 if (error.pos.valid)
00525 {
00526 errorPos = error.pos.character;
00527 QTextBlock textBlock = editor->document()->findBlock(errorPos);
00528 int posInBlock = errorPos - textBlock.position();
00529 if (textBlock.userData())
00530 static_cast<AeslEditorUserData *>(textBlock.userData())->properties["errorPos"] = posInBlock;
00531 else
00532 textBlock.setUserData(new AeslEditorUserData("errorPos", posInBlock));
00533 doRehighlight = true;
00534 }
00535 }
00536
00537
00538 if (editor->debugging)
00539 {
00540
00541 markTargetUnsynced();
00542 doRehighlight = true;
00543
00544 }
00545
00546 if (doRehighlight)
00547 rehighlight();
00548 }
00549
00551 void NodeTab::markTargetUnsynced()
00552 {
00553 editor->debugging = false;
00554 resetButton->setEnabled(false);
00555 runInterruptButton->setEnabled(false);
00556 nextButton->setEnabled(false);
00557 target->clearBreakpoints(id);
00558 switchEditorProperty("breakpoint", "breakpointPending");
00559 executionModeLabel->setText(tr("unknown"));
00560 }
00561
00562 void NodeTab::cursorMoved()
00563 {
00564
00565 cursorPosText->setText(QString("Line: %0 Col: %1").arg(editor->textCursor().blockNumber() + 1).arg(editor->textCursor().columnNumber() + 1));
00566 }
00567
00568 void NodeTab::goToError()
00569 {
00570 if (errorPos >= 0)
00571 {
00572 QTextCursor cursor = editor->textCursor();
00573 cursor.setPosition(errorPos);
00574 editor->setTextCursor(cursor);
00575 editor->ensureCursorVisible();
00576 }
00577 }
00578
00579 void NodeTab::clearExecutionErrors()
00580 {
00581
00582 if (clearEditorProperty("executionError"))
00583 rehighlight();
00584 }
00585
00586 void NodeTab::variablesMemoryChanged(unsigned start, const VariablesDataVector &variables)
00587 {
00588
00589 vmMemoryModel->setVariablesData(start, variables);
00590 }
00591
00592 void NodeTab::setBreakpoint(unsigned line)
00593 {
00594 rehighlight();
00595 target->setBreakpoint(id, line);
00596 }
00597
00598 void NodeTab::clearBreakpoint(unsigned line)
00599 {
00600 rehighlight();
00601 target->clearBreakpoint(id, line);
00602 }
00603
00604 void NodeTab::breakpointClearedAll()
00605 {
00606 rehighlight();
00607 target->clearBreakpoints(id);
00608 }
00609
00610 void NodeTab::executionPosChanged(unsigned line)
00611 {
00612
00613 if (setEditorProperty("active", QVariant(), line, true))
00614 rehighlight();
00615 }
00616
00617 void NodeTab::executionModeChanged(Target::ExecutionMode mode)
00618 {
00619
00620 if (!editor->debugging)
00621 return;
00622
00623 resetButton->setEnabled(true);
00624 runInterruptButton->setEnabled(true);
00625 compilationResultImage->setPixmap(QPixmap(QString(":/images/ok.png")));
00626
00627 if (mode == Target::EXECUTION_RUN)
00628 {
00629 executionModeLabel->setText(tr("running"));
00630
00631 runInterruptButton->setText(tr("Pause"));
00632 runInterruptButton->setIcon(QIcon(":/images/pause.png"));
00633
00634 nextButton->setEnabled(false);
00635
00636 if (clearEditorProperty("active"))
00637 rehighlight();
00638 }
00639 else if (mode == Target::EXECUTION_STEP_BY_STEP)
00640 {
00641 executionModeLabel->setText(tr("step by step"));
00642
00643 runInterruptButton->setText(tr("Run"));
00644 runInterruptButton->setIcon(QIcon(":/images/play.png"));
00645
00646 nextButton->setEnabled(true);
00647 }
00648 else if (mode == Target::EXECUTION_STOP)
00649 {
00650 executionModeLabel->setText(tr("stopped"));
00651
00652 runInterruptButton->setText(tr("Run"));
00653 runInterruptButton->setIcon(QIcon(":/images/play.png"));
00654
00655 nextButton->setEnabled(false);
00656
00657 if (clearEditorProperty("active"))
00658 rehighlight();
00659 }
00660 }
00661
00662 void NodeTab::breakpointSetResult(unsigned line, bool success)
00663 {
00664 clearEditorProperty("breakpointPending", line);
00665 if (success)
00666 setEditorProperty("breakpoint", QVariant(), line);
00667 rehighlight();
00668 }
00669
00670 void NodeTab::rehighlight()
00671 {
00672 rehighlighting = true;
00673 highlighter->rehighlight();
00674 }
00675
00676 void NodeTab::reSetBreakpoints()
00677 {
00678 target->clearBreakpoints(id);
00679 QTextBlock block = editor->document()->begin();
00680 unsigned lineCounter = 0;
00681 while (block != editor->document()->end())
00682 {
00683 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00684 if (uData && (uData->properties.contains("breakpoint") || uData->properties.contains("breakpointPending")))
00685 target->setBreakpoint(id, lineCounter);
00686 block = block.next();
00687 lineCounter++;
00688 }
00689 }
00690
00691 bool NodeTab::setEditorProperty(const QString &property, const QVariant &value, unsigned line, bool removeOld)
00692 {
00693 bool changed = false;
00694
00695 QTextBlock block = editor->document()->begin();
00696 unsigned lineCounter = 0;
00697 while (block != editor->document()->end())
00698 {
00699 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00700 if (lineCounter == line)
00701 {
00702
00703 if (uData)
00704 {
00705 if (!uData->properties.contains(property) || (uData->properties[property] != value))
00706 {
00707 uData->properties[property] = value;
00708 changed = true;
00709 }
00710 }
00711 else
00712 {
00713 block.setUserData(new AeslEditorUserData(property, value));
00714 changed = true;
00715 }
00716 }
00717 else
00718 {
00719
00720 if (uData && removeOld && uData->properties.contains(property))
00721 {
00722 uData->properties.remove(property);
00723 if (uData->properties.isEmpty())
00724 {
00725
00726 block.setUserData(0);
00727 }
00728 changed = true;
00729 }
00730 }
00731
00732 block = block.next();
00733 lineCounter++;
00734 }
00735
00736 return changed;
00737 }
00738
00739 bool NodeTab::clearEditorProperty(const QString &property, unsigned line)
00740 {
00741 bool changed = false;
00742
00743
00744 QTextBlock block = editor->document()->begin();
00745 unsigned lineCounter = 0;
00746 while (block != editor->document()->end())
00747 {
00748 if (lineCounter == line)
00749 {
00750 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00751 if (uData && uData->properties.contains(property))
00752 {
00753 uData->properties.remove(property);
00754 if (uData->properties.isEmpty())
00755 {
00756
00757 block.setUserData(0);
00758 }
00759 changed = true;
00760 }
00761 }
00762 block = block.next();
00763 lineCounter++;
00764 }
00765
00766 return changed;
00767 }
00768
00769 bool NodeTab::clearEditorProperty(const QString &property)
00770 {
00771 bool changed = false;
00772
00773
00774 QTextBlock block = editor->document()->begin();
00775 while (block != editor->document()->end())
00776 {
00777 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00778 if (uData && uData->properties.contains(property))
00779 {
00780 uData->properties.remove(property);
00781 if (uData->properties.isEmpty())
00782 {
00783
00784 block.setUserData(0);
00785 }
00786 changed = true;
00787 }
00788 block = block.next();
00789 }
00790
00791 return changed;
00792 }
00793
00794 void NodeTab::switchEditorProperty(const QString &oldProperty, const QString &newProperty)
00795 {
00796 QTextBlock block = editor->document()->begin();
00797 while (block != editor->document()->end())
00798 {
00799 AeslEditorUserData *uData = static_cast<AeslEditorUserData *>(block.userData());
00800 if (uData && uData->properties.contains(oldProperty))
00801 {
00802 uData->properties.remove(oldProperty);
00803 uData->properties[newProperty] = QVariant();
00804 }
00805 block = block.next();
00806 }
00807 }
00808
00809
00810 MainWindow::MainWindow(QVector<QTranslator*> translators, const QString& commandLineTarget, QWidget *parent) :
00811 QMainWindow(parent),
00812 sourceModified(false)
00813 {
00814
00815 target = new DashelTarget(translators, commandLineTarget);
00816
00817
00818 eventsDescriptionsModel = new NamedValuesVectorModel(&commonDefinitions.events, tr("Event number %0"), this);
00819 constantsDefinitionsModel = new NamedValuesVectorModel(&commonDefinitions.constants, this);
00820
00821
00822 setupWidgets();
00823 setupMenu();
00824 setupConnections();
00825
00826
00827 updateWindowTitle();
00828 resize(1000,700);
00829 }
00830
00831 MainWindow::~MainWindow()
00832 {
00833 for (EventViewers::iterator it = eventsViewers.begin(); it != eventsViewers.end(); ++it)
00834 {
00835 it.value()->detachFromMain();
00836 }
00837
00838 delete target;
00839 }
00840
00841 #ifndef SVN_REV
00842 #define SVN_REV "unknown, please configure your build system to set SVN_REV correctly"
00843 #endif
00844
00845 void MainWindow::about()
00846 {
00847 QString revString(ASEBA_SVN_REV);
00848 QStringList revStringList = revString.split(" ");
00849 revStringList.pop_front();
00850
00851 QString text = tr( "<p>Aseba pre-release:</p>" \
00852 "<ul><li>Aseba " \
00853 "SVN rev. %0 / protocol ver. %1" \
00854 "</li><li>Dashel ver. "\
00855 DASHEL_VERSION \
00856 "</li></ul>" \
00857 "<p>(c) 2006-2009 <a href=\"http://stephane.magnenat.net\">Stéphane Magnenat</a> and other contributors.</p>" \
00858 "<p><a href=\"http://mobots.epfl.ch\">http://mobots.epfl.ch/aseba.html</a></p>" \
00859 "<p>Aseba is open-source licensed under the GPL version 3.</p>");
00860
00861 text = text.arg(revStringList.front()).arg(ASEBA_PROTOCOL_VERSION);
00862
00863 QMessageBox::about(this, tr("About Aseba Studio"), text);
00864 }
00865
00866 void MainWindow::newFile()
00867 {
00868 if (askUserBeforeDiscarding())
00869 {
00870 clearDocumentSpecificTabs();
00871
00872 for (int i = 0; i < nodes->count(); i++)
00873 {
00874 NodeTab* tab = polymorphic_downcast<NodeTab*>(nodes->widget(i));
00875 Q_ASSERT(tab);
00876 tab->editor->clear();
00877 }
00878 constantsDefinitionsModel->clear();
00879 eventsDescriptionsModel->clear();
00880 actualFileName.clear();
00881 }
00882 }
00883
00884 void MainWindow::openFile(const QString &path)
00885 {
00886
00887 if (askUserBeforeDiscarding() == false)
00888 return;
00889
00890 QString fileName = path;
00891
00892 if (fileName.isEmpty())
00893 fileName = QFileDialog::getOpenFileName(this,
00894 tr("Open Script"), "", "Aseba scripts (*.aesl)");
00895
00896 QFile file(fileName);
00897 if (!file.open(QFile::ReadOnly))
00898 return;
00899
00900 QDomDocument document("aesl-source");
00901 QString errorMsg;
00902 int errorLine;
00903 int errorColumn;
00904 if (document.setContent(&file, false, &errorMsg, &errorLine, &errorColumn))
00905 {
00906 eventsDescriptionsModel->clear();
00907 constantsDefinitionsModel->clear();
00908
00909 int noNodeCount = 0;
00910 clearDocumentSpecificTabs();
00911 actualFileName = fileName;
00912 QDomNode domNode = document.documentElement().firstChild();
00913 while (!domNode.isNull())
00914 {
00915 if (domNode.isElement())
00916 {
00917 QDomElement element = domNode.toElement();
00918 if (element.tagName() == "node")
00919 {
00920 NodeTab* tab = getTabFromName(element.attribute("name"));
00921 if (tab)
00922 tab->editor->setPlainText(element.firstChild().toText().data());
00923 else
00924 {
00925 nodes->addTab(new AbsentNodeTab(element.attribute("name"), element.firstChild().toText().data()), element.attribute("name") + tr(" (not available)"));
00926 noNodeCount++;
00927 }
00928 }
00929 else if (element.tagName() == "event")
00930 {
00931 const QString eventName(element.attribute("name"));
00932 const unsigned eventSize(element.attribute("size").toUInt());
00933 eventsDescriptionsModel->addNamedValue(NamedValue(eventName.toStdString(), std::min(unsigned(ASEBA_MAX_EVENT_ARG_SIZE), eventSize)));
00934 }
00935 else if (element.tagName() == "constant")
00936 {
00937 constantsDefinitionsModel->addNamedValue(NamedValue(element.attribute("name").toStdString(), element.attribute("value").toInt()));
00938 }
00939 }
00940 domNode = domNode.nextSibling();
00941 }
00942
00943
00944 if (noNodeCount)
00945 QMessageBox::warning(this,
00946 tr("Loading"),
00947 tr("%0 scripts have no corresponding nodes in the current network and have not been loaded.").arg(noNodeCount)
00948 );
00949
00950
00951 updateRecentFiles(fileName);
00952 regenerateOpenRecentMenu();
00953
00954 recompileAll();
00955
00956 sourceModified = false;
00957 constantsDefinitionsModel->clearWasModified();
00958 eventsDescriptionsModel->clearWasModified();
00959 updateWindowTitle();
00960 }
00961 else
00962 {
00963 QMessageBox::warning(this,
00964 tr("Loading"),
00965 tr("Error in XML source file: %0 at line %1, column %2").arg(errorMsg).arg(errorLine).arg(errorColumn)
00966 );
00967 }
00968
00969 file.close();
00970 }
00971
00972 void MainWindow::openRecentFile()
00973 {
00974 QAction* entry = polymorphic_downcast<QAction*>(sender());
00975 openFile(entry->text());
00976 }
00977
00978 bool MainWindow::save()
00979 {
00980 return saveFile(actualFileName);
00981 }
00982
00983 bool MainWindow::saveFile(const QString &previousFileName)
00984 {
00985 QString fileName = previousFileName;
00986
00987 if (fileName.isEmpty())
00988 fileName = QFileDialog::getSaveFileName(this,
00989 tr("Save Script"), actualFileName, "Aseba scripts (*.aesl)");
00990
00991 if (fileName.isEmpty())
00992 return false;
00993
00994 if (fileName.lastIndexOf(".") < 0)
00995 fileName += ".aesl";
00996
00997 QFile file(fileName);
00998 if (!file.open(QFile::WriteOnly | QFile::Truncate))
00999 return false;
01000
01001 actualFileName = fileName;
01002 updateRecentFiles(fileName);
01003
01004
01005 QDomDocument document("aesl-source");
01006 QDomElement root = document.createElement("network");
01007 document.appendChild(root);
01008
01009 root.appendChild(document.createTextNode("\n\n\n"));
01010 root.appendChild(document.createComment("list of global events"));
01011
01012
01013 for (size_t i = 0; i < commonDefinitions.events.size(); i++)
01014 {
01015 QDomElement element = document.createElement("event");
01016 element.setAttribute("name", QString::fromStdString(commonDefinitions.events[i].name));
01017 element.setAttribute("size", QString::number(commonDefinitions.events[i].value));
01018 root.appendChild(element);
01019 }
01020
01021 root.appendChild(document.createTextNode("\n\n\n"));
01022 root.appendChild(document.createComment("list of constants"));
01023
01024
01025 for (size_t i = 0; i < commonDefinitions.constants.size(); i++)
01026 {
01027 QDomElement element = document.createElement("constant");
01028 element.setAttribute("name", QString::fromStdString(commonDefinitions.constants[i].name));
01029 element.setAttribute("value", QString::number(commonDefinitions.constants[i].value));
01030 root.appendChild(element);
01031 }
01032
01033
01034 for (int i = 0; i < nodes->count(); i++)
01035 {
01036 const ScriptTab* tab = dynamic_cast<const ScriptTab*>(nodes->widget(i));
01037 if (tab)
01038 {
01039 QString nodeName;
01040
01041 const NodeTab* nodeTab = dynamic_cast<const NodeTab*>(tab);
01042 if (nodeTab)
01043 nodeName = target->getName(nodeTab->nodeId());
01044
01045 const AbsentNodeTab* absentNodeTab = dynamic_cast<const AbsentNodeTab*>(tab);
01046 if (absentNodeTab)
01047 nodeName = absentNodeTab->name;
01048
01049 const QString& nodeContent = tab->editor->toPlainText();
01050
01051 root.appendChild(document.createTextNode("\n\n\n"));
01052 root.appendChild(document.createComment(QString("source code of node %0").arg(nodeName)));
01053
01054 QDomElement element = document.createElement("node");
01055 element.setAttribute("name", nodeName);
01056 QDomText text = document.createTextNode(nodeContent);
01057 element.appendChild(text);
01058 root.appendChild(element);
01059 }
01060 }
01061 root.appendChild(document.createTextNode("\n\n\n"));
01062
01063 QTextStream out(&file);
01064 document.save(out, 0);
01065
01066 sourceModified = false;
01067 constantsDefinitionsModel->clearWasModified();
01068 eventsDescriptionsModel->clearWasModified();
01069 updateWindowTitle();
01070
01071 return true;
01072 }
01073
01074 void MainWindow::exportMemoriesContent()
01075 {
01076 QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export memories content"), "", "All Files (*);;CSV files (*.csv);;Text files (*.txt)");
01077
01078 QFile file(exportFileName);
01079 if (!file.open(QFile::WriteOnly | QFile::Truncate))
01080 return;
01081
01082 QTextStream out(&file);
01083
01084 for (int i = 0; i < nodes->count(); i++)
01085 {
01086 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01087 if (tab)
01088 {
01089 const QString nodeName(target->getName(tab->nodeId()));
01090 const QList<TargetVariablesModel::Variable>& variables(tab->vmMemoryModel->getVariables());
01091
01092 for (int j = 0; j < variables.size(); ++j)
01093 {
01094 const TargetVariablesModel::Variable& variable(variables[j]);
01095 out << nodeName << "." << variable.name << " ";
01096 for (size_t k = 0; k < variable.value.size(); ++k)
01097 {
01098 out << variable.value[k] << " ";
01099 }
01100 out << "\n";
01101 }
01102 }
01103 }
01104 }
01105
01106 void MainWindow::importMemoriesContent()
01107 {
01108 QString importFileName = QFileDialog::getOpenFileName(this, tr("Import memories content"), "", "All Files (*);;CSV files (*.csv);;Text files (*.txt)");
01109
01110 QFile file(importFileName);
01111 if (!file.open(QFile::ReadOnly))
01112 return;
01113
01114 QTextStream in(&file);
01115
01116 QSet<QString> nodesNotFound;
01117 QStringList variablesNotFound;
01118
01119 while (!in.atEnd())
01120 {
01121 QString line(in.readLine());
01122 int pointPos(line.indexOf('.'));
01123 QString nodeName(line.left(pointPos));
01124 NodeTab* tab(getTabFromName(nodeName));
01125 if (tab)
01126 {
01127 int endVarNamePos(line.indexOf(' ', pointPos+1));
01128 if (endVarNamePos != -1)
01129 {
01130 QString variableName(line.mid(pointPos+1, endVarNamePos-pointPos-1));
01131 VariablesDataVector values;
01132 int index(endVarNamePos);
01133 while (index != -1)
01134 {
01135 int nextIndex(line.indexOf(' ', index+1));
01136 QString value(line.mid(index+1, nextIndex - index - 1));
01137 if (value.isEmpty())
01138 break;
01139 values.push_back(value.toShort());
01140 index = nextIndex;
01141 }
01142 if (!tab->vmMemoryModel->setVariableValues(variableName, values))
01143 {
01144 variablesNotFound << tr("%0 on node %1").arg(variableName).arg(nodeName);
01145 }
01146 }
01147 }
01148 else
01149 nodesNotFound.insert(nodeName);
01150 }
01151
01152 if (!nodesNotFound.isEmpty() || !variablesNotFound.isEmpty())
01153 {
01154 QString msg;
01155 if (!nodesNotFound.isEmpty())
01156 {
01157 msg += tr("The following nodes are not present in the current network and their associated content was not imported:\n");
01158 foreach (QString value, nodesNotFound)
01159 msg += "• " + value + "\n";
01160 }
01161 if (!variablesNotFound.isEmpty())
01162 {
01163 msg += tr("The following variables are not present in the current network and their associated content was not imported:\n");
01164 foreach (QString value, variablesNotFound)
01165 msg += "• " + value + "\n";
01166 }
01167 QMessageBox::warning(this,
01168 tr("Some content was not imported"),
01169 msg
01170 );
01171 }
01172 }
01173
01174 void MainWindow::copyAll()
01175 {
01176 QString toCopy;
01177 for (int i = 0; i < nodes->count(); i++)
01178 {
01179 const NodeTab* nodeTab = dynamic_cast<NodeTab*>(nodes->widget(i));
01180 if (nodeTab)
01181 {
01182 toCopy += QString("# node %0\n").arg(target->getName(nodeTab->nodeId()));
01183 toCopy += nodeTab->editor->toPlainText();
01184 toCopy += "\n\n";
01185 }
01186 const AbsentNodeTab* absentNodeTab = dynamic_cast<AbsentNodeTab*>(nodes->widget(i));
01187 if (absentNodeTab)
01188 {
01189 toCopy += QString("# abscent node named %0\n").arg(absentNodeTab->name);
01190 toCopy += absentNodeTab->editor->toPlainText();
01191 toCopy += "\n\n";
01192 }
01193 }
01194 QApplication::clipboard()->setText(toCopy);
01195 }
01196
01197 void MainWindow::resetAll()
01198 {
01199 for (int i = 0; i < nodes->count(); i++)
01200 {
01201 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01202 if (tab)
01203 tab->resetClicked();
01204 }
01205 }
01206
01207 void MainWindow::loadAll()
01208 {
01209 for (int i = 0; i < nodes->count(); i++)
01210 {
01211 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01212 if (tab)
01213 tab->loadClicked();
01214 }
01215 }
01216
01217 void MainWindow::runAll()
01218 {
01219 for (int i = 0; i < nodes->count(); i++)
01220 {
01221 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01222 if (tab)
01223 target->run(tab->nodeId());
01224 }
01225 }
01226
01227 void MainWindow::pauseAll()
01228 {
01229 for (int i = 0; i < nodes->count(); i++)
01230 {
01231 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01232 if (tab)
01233 target->pause(tab->nodeId());
01234 }
01235 }
01236
01237 void MainWindow::stopAll()
01238 {
01239 for (int i = 0; i < nodes->count(); i++)
01240 {
01241 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01242 if (tab)
01243 target->stop(tab->nodeId());
01244 }
01245 }
01246
01247 void MainWindow::showHidden(bool show)
01248 {
01249 for (int i = 0; i < nodes->count(); i++)
01250 {
01251 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01252 if (tab)
01253 {
01254 tab->vmFunctionsModel->recreateTreeFromDescription(show);
01255 tab->showHidden = show;
01256 tab->updateHidden();
01257 }
01258 }
01259 }
01260
01261 void MainWindow::clearAllExecutionError()
01262 {
01263 for (int i = 0; i < nodes->count(); i++)
01264 {
01265 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01266 if (tab)
01267 tab->clearExecutionErrors();
01268 }
01269 logger->setStyleSheet("");
01270 }
01271
01272 void MainWindow::uploadReadynessChanged()
01273 {
01274 bool ready = true;
01275 for (int i = 0; i < nodes->count(); i++)
01276 {
01277 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01278 if (tab)
01279 {
01280 if (!tab->loadButton->isEnabled())
01281 {
01282 ready = false;
01283 break;
01284 }
01285 }
01286 }
01287
01288 loadAllAct->setEnabled(ready);
01289 writeAllBytecodesAct->setEnabled(ready);
01290 }
01291
01292 void MainWindow::sendEvent()
01293 {
01294 QModelIndex currentRow = eventsDescriptionsView->selectionModel()->currentIndex();
01295 Q_ASSERT(currentRow.isValid());
01296
01297 unsigned eventId = currentRow.row();
01298 QString eventName = QString::fromStdString(commonDefinitions.events[eventId].name);
01299 int argsCount = commonDefinitions.events[eventId].value;
01300 VariablesDataVector data(argsCount);
01301
01302 if (argsCount > 0)
01303 {
01304 QString argList;
01305 while (true)
01306 {
01307 bool ok;
01308 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);
01309 if (ok)
01310 {
01311 QStringList args = argList.split(QRegExp("[\\s,]+"), QString::SkipEmptyParts);
01312 if (args.size() != argsCount)
01313 {
01314 QMessageBox::warning(this,
01315 tr("Wrong number of arguments"),
01316 tr("You gave %0 arguments where event %1 requires %2").arg(args.size()).arg(eventName).arg(argsCount)
01317 );
01318 continue;
01319 }
01320 for (int i = 0; i < args.size(); i++)
01321 {
01322 data[i] = args.at(i).toShort(&ok);
01323 if (!ok)
01324 {
01325 QMessageBox::warning(this,
01326 tr("Invalid value"),
01327 tr("Invalid value for argument %0 of event %1").arg(i).arg(eventName)
01328 );
01329 break;
01330 }
01331 }
01332 if (ok)
01333 break;
01334 }
01335 else
01336 return;
01337 }
01338 }
01339
01340 target->sendEvent(eventId, data);
01341 userEvent(eventId, data);
01342 }
01343
01344 void MainWindow::sendEventIf(const QModelIndex &index)
01345 {
01346 if (index.column() == 0)
01347 sendEvent();
01348 }
01349
01350 void MainWindow::eventContextMenuRequested(const QPoint & pos)
01351 {
01352 #ifdef HAVE_QWT
01353 QModelIndex index(eventsDescriptionsView->indexAt(pos));
01354 if (index.isValid() && (index.column() == 0))
01355 {
01356 QString eventName(eventsDescriptionsModel->data(index).toString());
01357 QMenu menu;
01358 menu.addAction(tr("Plot event %1").arg(eventName));
01359 QAction* ret = menu.exec(eventsDescriptionsView->mapToGlobal(pos));
01360 if (ret)
01361 {
01362 const unsigned eventId = index.row();
01363 const unsigned eventVariablesCount = eventsDescriptionsModel->data(eventsDescriptionsModel->index(eventId, 1)).toUInt();
01364 const QString tabTitle(tr("plot of %1").arg(eventName));
01365 nodes->addTab(new EventViewer(eventId, eventName, eventVariablesCount, &eventsViewers), tabTitle, true);
01366 }
01367 }
01368 #endif // HAVE_QWT
01369 }
01370
01371 void MainWindow::logEntryDoubleClicked(QListWidgetItem * item)
01372 {
01373 if (item->data(Qt::UserRole).type() == QVariant::Point)
01374 {
01375 int node = item->data(Qt::UserRole).toPoint().x();
01376 int line = item->data(Qt::UserRole).toPoint().y();
01377
01378 NodeTab* tab = getTabFromId(node);
01379 Q_ASSERT(tab);
01380 nodes->setCurrentWidget(tab);
01381 QTextBlock block = tab->editor->document()->begin();
01382 for (int i = 0; i < line; i++)
01383 {
01384 if (block == tab->editor->document()->end())
01385 return;
01386 block = block.next();
01387 }
01388
01389 tab->editor->textCursor().setPosition(block.position(), QTextCursor::MoveAnchor);
01390 }
01391 }
01392
01393 void MainWindow::tabChanged(int index)
01394 {
01395
01396 if (previousActiveTab)
01397 {
01398 disconnect(cutAct, SIGNAL(triggered()), previousActiveTab->editor, SLOT(cut()));
01399 disconnect(copyAct, SIGNAL(triggered()), previousActiveTab->editor, SLOT(copy()));
01400 disconnect(pasteAct, SIGNAL(triggered()), previousActiveTab->editor, SLOT(paste()));
01401 disconnect(undoAct, SIGNAL(triggered()), previousActiveTab->editor, SLOT(undo()));
01402 disconnect(redoAct, SIGNAL(triggered()), previousActiveTab->editor, SLOT(redo()));
01403
01404 disconnect(previousActiveTab->editor, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
01405 disconnect(previousActiveTab->editor, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
01406 disconnect(previousActiveTab->editor, SIGNAL(undoAvailable(bool)), undoAct, SLOT(setEnabled(bool)));
01407 disconnect(previousActiveTab->editor, SIGNAL(redoAvailable(bool)), redoAct, SLOT(setEnabled(bool)));
01408 }
01409
01410
01411 if (index >= 0)
01412 {
01413 ScriptTab *tab = dynamic_cast<ScriptTab*>(nodes->widget(index));
01414 if (tab)
01415 {
01416 connect(copyAct, SIGNAL(triggered()), tab->editor, SLOT(copy()));
01417 connect(tab->editor, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
01418
01419 NodeTab *nodeTab = dynamic_cast<NodeTab*>(tab);
01420 if (nodeTab)
01421 {
01422 connect(cutAct, SIGNAL(triggered()), tab->editor, SLOT(cut()));
01423 connect(pasteAct, SIGNAL(triggered()), tab->editor, SLOT(paste()));
01424 connect(undoAct, SIGNAL(triggered()), tab->editor, SLOT(undo()));
01425 connect(redoAct, SIGNAL(triggered()), tab->editor, SLOT(redo()));
01426
01427 connect(tab->editor, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
01428 connect(tab->editor, SIGNAL(undoAvailable(bool)), undoAct, SLOT(setEnabled(bool)));
01429 connect(tab->editor, SIGNAL(redoAvailable(bool)), redoAct, SLOT(setEnabled(bool)));
01430
01431 if (compilationMessageBox->isVisible())
01432 nodeTab->recompile();
01433
01434 target->getVariables(nodeTab->id, 0, nodeTab->allocatedVariablesCount);
01435
01436 showCompilationMsg->setEnabled(true);
01437 }
01438 else
01439 showCompilationMsg->setEnabled(false);
01440
01441
01442 cutAct->setEnabled(false);
01443 copyAct->setEnabled(false);
01444 undoAct->setEnabled(false);
01445 redoAct->setEnabled(false);
01446
01447 previousActiveTab = tab;
01448 }
01449 else
01450 previousActiveTab = 0;
01451 }
01452 else
01453 previousActiveTab = 0;
01454 }
01455
01456 void MainWindow::showCompilationMessages(bool doShow)
01457 {
01458
01459 compilationMessageBox->setVisible(doShow);
01460 if (nodes->currentWidget())
01461 polymorphic_downcast<NodeTab *>(nodes->currentWidget())->recompile();
01462 }
01463
01464 void MainWindow::addEventNameClicked()
01465 {
01466 bool ok;
01467 QString eventName = QInputDialog::getText(this, tr("Add a new event"), tr("Name:"), QLineEdit::Normal, "", &ok);
01468 eventName = eventName.trimmed();
01469 if (ok && !eventName.isEmpty())
01470 {
01471 if (commonDefinitions.events.contains(eventName.toStdString()))
01472 {
01473 QMessageBox::warning(this, tr("Event already exists"), tr("Event %0 already exists.").arg(eventName));
01474 }
01475 else
01476 {
01477 eventsDescriptionsModel->addNamedValue(NamedValue(eventName.toStdString(), 0));
01478 recompileAll();
01479 updateWindowTitle();
01480 }
01481 }
01482 }
01483
01484 void MainWindow::removeEventNameClicked()
01485 {
01486 QModelIndex currentRow = eventsDescriptionsView->selectionModel()->currentIndex();
01487 Q_ASSERT(currentRow.isValid());
01488 eventsDescriptionsModel->delNamedValue(currentRow.row());
01489
01490 recompileAll();
01491 updateWindowTitle();
01492 }
01493
01494 void MainWindow::eventsDescriptionsSelectionChanged()
01495 {
01496 bool isSelected = eventsDescriptionsView->selectionModel()->currentIndex().isValid();
01497 removeEventNameButton->setEnabled(isSelected);
01498 sendEventButton->setEnabled(isSelected);
01499 }
01500
01501 void MainWindow::addConstantClicked()
01502 {
01503 bool ok;
01504 QString constantName = QInputDialog::getText(this, tr("Add a new constant"), tr("Name:"), QLineEdit::Normal, "", &ok);
01505 if (ok && !constantName.isEmpty())
01506 {
01507 if (commonDefinitions.constants.contains(constantName.toStdString()))
01508 {
01509 QMessageBox::warning(this, tr("Constant already defined"), tr("Constant %0 is already defined.").arg(constantName));
01510 }
01511 else
01512 {
01513 constantsDefinitionsModel->addNamedValue(NamedValue(constantName.toStdString(), 0));
01514 recompileAll();
01515 updateWindowTitle();
01516 }
01517 }
01518 }
01519
01520 void MainWindow::removeConstantClicked()
01521 {
01522 QModelIndex currentRow = constantsView->selectionModel()->currentIndex();
01523 Q_ASSERT(currentRow.isValid());
01524 constantsDefinitionsModel->delNamedValue(currentRow.row());
01525
01526 recompileAll();
01527 updateWindowTitle();
01528 }
01529
01530 void MainWindow::constantsSelectionChanged()
01531 {
01532 bool isSelected = constantsView->selectionModel()->currentIndex().isValid();
01533 removeConstantButton->setEnabled(isSelected);
01534 }
01535
01536 void MainWindow::recompileAll()
01537 {
01538 for (int i = 0; i < nodes->count(); i++)
01539 {
01540 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01541 if (tab)
01542 tab->recompile();
01543 }
01544 }
01545
01546 void MainWindow::writeAllBytecodes()
01547 {
01548 for (int i = 0; i < nodes->count(); i++)
01549 {
01550 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01551 if (tab)
01552 tab->writeBytecode();
01553 }
01554 }
01555
01556 void MainWindow::rebootAllNodes()
01557 {
01558 for (int i = 0; i < nodes->count(); i++)
01559 {
01560 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01561 if (tab)
01562 tab->reboot();
01563 }
01564 }
01565
01566 void MainWindow::sourceChanged()
01567 {
01568 sourceModified = true;
01569 updateWindowTitle();
01570 }
01571
01572 void MainWindow::addPluginLinearCameraView()
01573 {
01574 if (nodes->currentWidget())
01575 {
01576 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->currentWidget());
01577 if (tab)
01578 {
01579
01580 QWidget* plugin = new LinearCameraViewPlugin(tab->vmMemoryModel);
01581 connect(this, SIGNAL(MainWindowClosed()), plugin, SLOT(close()));
01582 }
01583 }
01584 }
01585
01586 void MainWindow::showHelpLanguage()
01587 {
01588
01589 if (target->getLanguage().left(2) == "fr")
01590 helpViewer->setSource(QString("qrc:/doc/aseba-language.fr.html"));
01591 else
01592 helpViewer->setSource(QString("qrc:/doc/aseba-language.en.html"));
01593 helpViewer->moveCursor(QTextCursor::Start);
01594 helpViewer->setWindowTitle(tr("Aseba Studio Help: Language"));
01595 helpViewer->show();
01596 }
01597
01598 void MainWindow::showHelpStudio()
01599 {
01600
01601 if (target->getLanguage().left(2) == "fr")
01602 helpViewer->setSource(QString("qrc:/doc/studio.fr.html"));
01603 else
01604 helpViewer->setSource(QString("qrc:/doc/studio.en.html"));
01605 helpViewer->moveCursor(QTextCursor::Start);
01606 helpViewer->setWindowTitle(tr("Aseba Studio Help: Studio"));
01607 helpViewer->show();
01608 }
01609
01611 void MainWindow::nodeConnected(unsigned node)
01612 {
01613 NodeTab* tab = new NodeTab(this, target, &commonDefinitions, node);
01614 connect(tab, SIGNAL(uploadReadynessChanged(bool)), SLOT(uploadReadynessChanged()));
01615 nodes->addTab(tab, target->getName(node));
01616
01617 regenerateToolsMenus();
01618 }
01619
01621 void MainWindow::nodeDisconnected(unsigned node)
01622 {
01623 int index = getIndexFromId(node);
01624 Q_ASSERT(index >= 0);
01625
01626 nodes->removeAndDeleteTab(index);
01627
01628 regenerateToolsMenus();
01629 }
01630
01632 void MainWindow::networkDisconnected()
01633 {
01634 disconnect(nodes, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
01635 std::vector<QWidget *> widgets(nodes->count());
01636 for (int i = 0; i < nodes->count(); i++)
01637 widgets[i] = nodes->widget(i);
01638 nodes->clear();
01639 for (size_t i = 0; i < widgets.size(); i++)
01640 widgets[i]->deleteLater();
01641 connect(nodes, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
01642 }
01643
01645 void MainWindow::userEvent(unsigned id, const VariablesDataVector &data)
01646 {
01647 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
01648 if (id < commonDefinitions.events.size())
01649 text += QString("\n%0 : ").arg(QString::fromStdString(commonDefinitions.events[id].name));
01650 else
01651 text += tr("\nevent %0 : ").arg(id);
01652 for (size_t i = 0; i < data.size(); i++)
01653 text += QString("%0 ").arg(data[i]);
01654
01655 if (logger->count() > 50)
01656 delete logger->takeItem(0);
01657 QListWidgetItem * item = new QListWidgetItem(QIcon(":/images/info.png"), text, logger);
01658 logger->scrollToBottom();
01659 Q_UNUSED(item);
01660
01661 #ifdef HAVE_QWT
01662
01663
01664 QList<EventViewer*> viewers = eventsViewers.values(id);
01665 for (int i = 0; i < viewers.size(); ++i)
01666 viewers.at(i)->addData(data);
01667
01668 #endif // HAVE_QWT
01669 }
01670
01672 void MainWindow::userEventsDropped(unsigned amount)
01673 {
01674 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
01675 text += QString("\n%0 user events not shown").arg(amount);
01676
01677 if (logger->count() > 50)
01678 delete logger->takeItem(0);
01679 QListWidgetItem * item = new QListWidgetItem(QIcon(":/images/info.png"), text, logger);
01680 logger->scrollToBottom();
01681 Q_UNUSED(item);
01682 logger->setStyleSheet(" QListView::item { background: rgb(255,128,128); }");
01683 }
01684
01686 void MainWindow::arrayAccessOutOfBounds(unsigned node, unsigned line, unsigned size, unsigned index)
01687 {
01688 addErrorEvent(node, line, tr("array access at %0 out of bounds [0..%1]").arg(index).arg(size-1));
01689 }
01690
01692 void MainWindow::divisionByZero(unsigned node, unsigned line)
01693 {
01694 addErrorEvent(node, line, tr("division by zero"));
01695 }
01696
01698 void MainWindow::eventExecutionKilled(unsigned node, unsigned line)
01699 {
01700 addErrorEvent(node, line, tr("event execution killed"));
01701 }
01702
01704 void MainWindow::nodeSpecificError(unsigned node, unsigned line, const QString& message)
01705 {
01706 addErrorEvent(node, line, message);
01707 }
01708
01710 void MainWindow::addErrorEvent(unsigned node, unsigned line, const QString& message)
01711 {
01712 NodeTab* tab = getTabFromId(node);
01713 Q_ASSERT(tab);
01714
01715 if (tab->setEditorProperty("executionError", QVariant(), line, true))
01716 {
01717 tab->rehighlighting = true;
01718 tab->highlighter->rehighlight();
01719 }
01720
01721 QString text = QTime::currentTime().toString("hh:mm:ss.zzz");
01722 text += "\n" + tr("%0:%1: %2").arg(target->getName(node)).arg(line + 1).arg(message);
01723
01724 if (logger->count() > 50)
01725 delete logger->takeItem(0);
01726 QListWidgetItem *item = new QListWidgetItem(QIcon(":/images/warning.png"), text, logger);
01727 item->setData(Qt::UserRole, QPoint(node, line));
01728 logger->scrollToBottom();
01729 }
01730
01731
01733 void MainWindow::executionPosChanged(unsigned node, unsigned line)
01734 {
01735 NodeTab* tab = getTabFromId(node);
01736 Q_ASSERT(tab);
01737
01738 tab->executionPosChanged(line);
01739 }
01740
01742 void MainWindow::executionModeChanged(unsigned node, Target::ExecutionMode mode)
01743 {
01744 NodeTab* tab = getTabFromId(node);
01745 Q_ASSERT(tab);
01746
01747 tab->executionModeChanged(mode);
01748 }
01749
01751 void MainWindow::variablesMemoryEstimatedDirty(unsigned node)
01752 {
01753 NodeTab* tab = getTabFromId(node);
01754 Q_ASSERT(tab);
01755
01756 tab->refreshMemoryClicked();
01757 }
01758
01760 void MainWindow::variablesMemoryChanged(unsigned node, unsigned start, const VariablesDataVector &variables)
01761 {
01762 NodeTab* tab = getTabFromId(node);
01763 Q_ASSERT(tab);
01764
01765 tab->vmMemoryModel->setVariablesData(start, variables);
01766 }
01767
01769 void MainWindow::breakpointSetResult(unsigned node, unsigned line, bool success)
01770 {
01771 NodeTab* tab = getTabFromId(node);
01772 Q_ASSERT(tab);
01773
01774 tab->breakpointSetResult(line, success);
01775 }
01776
01777 int MainWindow::getIndexFromId(unsigned node)
01778 {
01779 for (int i = 0; i < nodes->count(); i++)
01780 {
01781 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01782 if (tab)
01783 {
01784 if (tab->nodeId() == node)
01785 return i;
01786 }
01787 }
01788 return -1;
01789 }
01790
01791 NodeTab* MainWindow::getTabFromId(unsigned node)
01792 {
01793 for (int i = 0; i < nodes->count(); i++)
01794 {
01795 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01796 if (tab)
01797 {
01798 if (tab->nodeId() == node)
01799 return tab;
01800 }
01801 }
01802 return 0;
01803 }
01804
01805 NodeTab* MainWindow::getTabFromName(const QString& name)
01806 {
01807 for (int i = 0; i < nodes->count(); i++)
01808 {
01809 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
01810 if (tab)
01811 {
01812 if (target->getName(tab->nodeId()) == name)
01813 return tab;
01814 }
01815 }
01816 return 0;
01817 }
01818
01819 void MainWindow::clearDocumentSpecificTabs()
01820 {
01821 bool changed = false;
01822 do
01823 {
01824 changed = false;
01825 for (int i = 0; i < nodes->count(); i++)
01826 {
01827 QWidget* tab = nodes->widget(i);
01828
01829 #ifdef HAVE_QWT
01830 if (dynamic_cast<AbsentNodeTab*>(tab) || dynamic_cast<EventViewer*>(tab))
01831 #else // HAVE_QWT
01832 if (dynamic_cast<AbsentNodeTab*>(tab))
01833 #endif // HAVE_QWT
01834 {
01835 nodes->removeAndDeleteTab(i);
01836 changed = true;
01837 break;
01838 }
01839 }
01840 }
01841 while (changed);
01842 }
01843
01844 void MainWindow::setupWidgets()
01845 {
01846 previousActiveTab = 0;
01847 nodes = new EditorsPlotsTabWidget;
01848 nodes->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
01849
01850 QSplitter *splitter = new QSplitter();
01851 splitter->addWidget(nodes);
01852 setCentralWidget(splitter);
01853
01854
01855
01856 addConstantButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
01857 removeConstantButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
01858 removeConstantButton->setEnabled(false);
01859
01860 constantsView = new FixedWidthTableView;
01861 constantsView->setShowGrid(false);
01862 constantsView->verticalHeader()->hide();
01863 constantsView->horizontalHeader()->hide();
01864 constantsView->setModel(constantsDefinitionsModel);
01865 constantsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
01866 constantsView->setSelectionMode(QAbstractItemView::SingleSelection);
01867 constantsView->setSelectionBehavior(QAbstractItemView::SelectRows);
01868 constantsView->setDragDropMode(QAbstractItemView::DragOnly);
01869 constantsView->setDragEnabled(true);
01870 constantsView->setItemDelegateForColumn(1, new SpinBoxDelegate(-32768, 32767, this));
01871 constantsView->setMinimumHeight(100);
01872 constantsView->setSecondColumnLongestContent("-888888##");
01873 constantsView->resizeRowsToContents();
01874
01875 QGridLayout* constantsLayout = new QGridLayout;
01876 constantsLayout->addWidget(new QLabel(tr("<b>Constants</b>")),0,0);
01877 constantsLayout->setColumnStretch(0, 1);
01878 constantsLayout->addWidget(addConstantButton,0,1);
01879 constantsLayout->setColumnStretch(1, 0);
01880 constantsLayout->addWidget(removeConstantButton,0,2);
01881 constantsLayout->setColumnStretch(2, 0);
01882 constantsLayout->addWidget(constantsView, 1, 0, 1, 3);
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915 addEventNameButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
01916 removeEventNameButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
01917 removeEventNameButton->setEnabled(false);
01918 sendEventButton = new QPushButton(QPixmap(QString(":/images/newmsg.png")), "");
01919 sendEventButton->setEnabled(false);
01920
01921 eventsDescriptionsView = new FixedWidthTableView;
01922 eventsDescriptionsView->setShowGrid(false);
01923 eventsDescriptionsView->verticalHeader()->hide();
01924 eventsDescriptionsView->horizontalHeader()->hide();
01925 eventsDescriptionsView->setModel(eventsDescriptionsModel);
01926 eventsDescriptionsView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
01927 eventsDescriptionsView->setSelectionMode(QAbstractItemView::SingleSelection);
01928 eventsDescriptionsView->setSelectionBehavior(QAbstractItemView::SelectRows);
01929 eventsDescriptionsView->setDragDropMode(QAbstractItemView::DragOnly);
01930 eventsDescriptionsView->setDragEnabled(true);
01931 eventsDescriptionsView->setItemDelegateForColumn(1, new SpinBoxDelegate(0, (ASEBA_MAX_PACKET_SIZE-6)/2, this));
01932 eventsDescriptionsView->setMinimumHeight(100);
01933 eventsDescriptionsView->setSecondColumnLongestContent("255###");
01934 eventsDescriptionsView->resizeRowsToContents();
01935 eventsDescriptionsView->setContextMenuPolicy(Qt::CustomContextMenu);
01936
01937 QGridLayout* eventsLayout = new QGridLayout;
01938 eventsLayout->addWidget(new QLabel(tr("<b>Events</b>")),0,0);
01939 eventsLayout->setColumnStretch(0, 1);
01940 eventsLayout->addWidget(sendEventButton,0,1);
01941 eventsLayout->setColumnStretch(1, 0);
01942 eventsLayout->addWidget(addEventNameButton,0,2);
01943 eventsLayout->setColumnStretch(2, 0);
01944 eventsLayout->addWidget(removeEventNameButton,0,3);
01945 eventsLayout->setColumnStretch(3, 0);
01946 eventsLayout->addWidget(eventsDescriptionsView, 1, 0, 1, 4);
01947
01948
01949
01950
01951
01952
01953
01954
01955 logger = new QListWidget;
01956 logger->setMinimumSize(80,100);
01957 logger->setSelectionMode(QAbstractItemView::NoSelection);
01958 clearLogger = new QPushButton(tr("Clear"));
01959
01960 QVBoxLayout* loggerLayout = new QVBoxLayout;
01961 loggerLayout->addWidget(logger);
01962 loggerLayout->addWidget(clearLogger);
01963
01964
01965 QSplitter* rightPanelSplitter = new QSplitter(Qt::Vertical);
01966
01967 QWidget* constantsWidget = new QWidget;
01968 constantsWidget->setLayout(constantsLayout);
01969 rightPanelSplitter->addWidget(constantsWidget);
01970
01971 QWidget* eventsWidget = new QWidget;
01972 eventsWidget->setLayout(eventsLayout);
01973 rightPanelSplitter->addWidget(eventsWidget);
01974
01975 QWidget* loggerWidget = new QWidget;
01976 loggerWidget->setLayout(loggerLayout);
01977 rightPanelSplitter->addWidget(loggerWidget);
01978
01979
01980 splitter->addWidget(rightPanelSplitter);
01981 splitter->setSizes(QList<int>() << 800 << 200);
01982
01983
01984 compilationMessageBox = new CompilationLogDialog();
01985
01986
01987 helpViewer = new QTextBrowser();
01988 helpViewer->setReadOnly(true);
01989 helpViewer->resize(600, 500);
01990 connect(this, SIGNAL(MainWindowClosed()), helpViewer, SLOT(close()));
01991 }
01992
01993 void MainWindow::setupConnections()
01994 {
01995
01996 connect(nodes, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
01997 connect(logger, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(logEntryDoubleClicked(QListWidgetItem *)));
01998
01999
02000 connect(loadAllAct, SIGNAL(triggered()), SLOT(loadAll()));
02001 connect(resetAllAct, SIGNAL(triggered()), SLOT(resetAll()));
02002 connect(runAllAct, SIGNAL(triggered()), SLOT(runAll()));
02003 connect(pauseAllAct, SIGNAL(triggered()), SLOT(pauseAll()));
02004 connect(showHiddenAct, SIGNAL(toggled(bool)), SLOT(showHidden(bool)));
02005
02006
02007 connect(addEventNameButton, SIGNAL(clicked()), SLOT(addEventNameClicked()));
02008 connect(removeEventNameButton, SIGNAL(clicked()), SLOT(removeEventNameClicked()));
02009 connect(sendEventButton, SIGNAL(clicked()), SLOT(sendEvent()));
02010 connect(eventsDescriptionsView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(eventsDescriptionsSelectionChanged()));
02011 connect(eventsDescriptionsView, SIGNAL(doubleClicked(const QModelIndex &)), SLOT(sendEventIf(const QModelIndex &)));
02012 connect(eventsDescriptionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(recompileAll()));
02013 connect(eventsDescriptionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(updateWindowTitle()));
02014 connect(eventsDescriptionsView, SIGNAL(customContextMenuRequested ( const QPoint & )), SLOT(eventContextMenuRequested(const QPoint & )));
02015
02016
02017 connect(clearLogger, SIGNAL(clicked()), logger, SLOT(clear()));
02018 connect(clearLogger, SIGNAL(clicked()), SLOT(clearAllExecutionError()));
02019
02020
02021 connect(addConstantButton, SIGNAL(clicked()), SLOT(addConstantClicked()));
02022 connect(removeConstantButton, SIGNAL(clicked()), SLOT(removeConstantClicked()));
02023 connect(constantsView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(constantsSelectionChanged()));
02024 connect(constantsDefinitionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(recompileAll()));
02025 connect(constantsDefinitionsModel, SIGNAL(dataChanged ( const QModelIndex &, const QModelIndex & ) ), SLOT(updateWindowTitle()));
02026
02027
02028 connect(target, SIGNAL(nodeConnected(unsigned)), SLOT(nodeConnected(unsigned)));
02029 connect(target, SIGNAL(nodeDisconnected(unsigned)), SLOT(nodeDisconnected(unsigned)));
02030 connect(target, SIGNAL(networkDisconnected()), SLOT(networkDisconnected()));
02031
02032 connect(target, SIGNAL(userEvent(unsigned, const VariablesDataVector &)), SLOT(userEvent(unsigned, const VariablesDataVector &)));
02033 connect(target, SIGNAL(userEventsDropped(unsigned)), SLOT(userEventsDropped(unsigned)));
02034 connect(target, SIGNAL(arrayAccessOutOfBounds(unsigned, unsigned, unsigned, unsigned)), SLOT(arrayAccessOutOfBounds(unsigned, unsigned, unsigned, unsigned)));
02035 connect(target, SIGNAL(divisionByZero(unsigned, unsigned)), SLOT(divisionByZero(unsigned, unsigned)));
02036 connect(target, SIGNAL(eventExecutionKilled(unsigned, unsigned)), SLOT(eventExecutionKilled(unsigned, unsigned)));
02037 connect(target, SIGNAL(nodeSpecificError(unsigned, unsigned, QString)), SLOT(nodeSpecificError(unsigned, unsigned, QString)));
02038
02039 connect(target, SIGNAL(executionPosChanged(unsigned, unsigned)), SLOT(executionPosChanged(unsigned, unsigned)));
02040 connect(target, SIGNAL(executionModeChanged(unsigned, Target::ExecutionMode)), SLOT(executionModeChanged(unsigned, Target::ExecutionMode)));
02041 connect(target, SIGNAL(variablesMemoryEstimatedDirty(unsigned)), SLOT(variablesMemoryEstimatedDirty(unsigned)));
02042
02043 connect(target, SIGNAL(variablesMemoryChanged(unsigned, unsigned, const VariablesDataVector &)), SLOT(variablesMemoryChanged(unsigned, unsigned, const VariablesDataVector &)));
02044
02045 connect(target, SIGNAL(breakpointSetResult(unsigned, unsigned, bool)), SLOT(breakpointSetResult(unsigned, unsigned, bool)));
02046 }
02047
02048 void MainWindow::regenerateOpenRecentMenu()
02049 {
02050 openRecentMenu->clear();
02051
02052 QSettings settings("EPFL-LSRO-Mobots", "Aseba Studio");
02053 QStringList recentFiles = settings.value("recent files").toStringList();
02054
02055 for (int i = 0; i < recentFiles.size(); i++)
02056 openRecentMenu->addAction(recentFiles.at(i), this, SLOT(openRecentFile()));
02057 }
02058
02059 void MainWindow::updateRecentFiles(const QString& fileName)
02060 {
02061 QSettings settings("EPFL-LSRO-Mobots", "Aseba Studio");
02062 QStringList recentFiles = settings.value("recent files").toStringList();
02063 if (recentFiles.contains(fileName))
02064 recentFiles.removeAt(recentFiles.indexOf(fileName));
02065 recentFiles.push_front(fileName);
02066 const int maxRecentFiles = 8;
02067 if (recentFiles.size() > maxRecentFiles)
02068 recentFiles.pop_back();
02069 settings.setValue("recent files", recentFiles);
02070 }
02071
02072 void MainWindow::regenerateToolsMenus()
02073 {
02074 writeBytecodeMenu->clear();
02075 rebootMenu->clear();
02076
02077 for (int i = 0; i < nodes->count(); i++)
02078 {
02079 NodeTab* tab = dynamic_cast<NodeTab*>(nodes->widget(i));
02080 if (tab)
02081 {
02082 QAction *act = writeBytecodeMenu->addAction(tr("...inside %0").arg(target->getName(tab->nodeId())),tab, SLOT(writeBytecode()));
02083
02084 connect(tab, SIGNAL(uploadReadynessChanged(bool)), act, SLOT(setEnabled(bool)));
02085
02086 rebootMenu->addAction(tr("...%0").arg(target->getName(tab->nodeId())),tab, SLOT(reboot()));
02087 }
02088 }
02089
02090 writeBytecodeMenu->addSeparator();
02091 writeAllBytecodesAct = writeBytecodeMenu->addAction(tr("...inside all nodes"), this, SLOT(writeAllBytecodes()));
02092
02093 rebootMenu->addSeparator();
02094 rebootMenu->addAction(tr("...all nodes"), this, SLOT(rebootAllNodes()));
02095 }
02096
02097 void MainWindow::setupMenu()
02098 {
02099
02100 QMenu *fileMenu = new QMenu(tr("&File"), this);
02101 menuBar()->addMenu(fileMenu);
02102
02103 fileMenu->addAction(QIcon(":/images/filenew.png"), tr("&New"),
02104 this, SLOT(newFile()),
02105 QKeySequence(tr("Ctrl+N", "File|New")));
02106 fileMenu->addAction(QIcon(":/images/fileopen.png"), tr("&Open..."),
02107 this, SLOT(openFile()),
02108 QKeySequence(tr("Ctrl+O", "File|Open")));
02109 openRecentMenu = new QMenu(tr("Open &Recent"));
02110 regenerateOpenRecentMenu();
02111 fileMenu->addMenu(openRecentMenu)->setIcon(QIcon(":/images/fileopen.png"));
02112
02113 fileMenu->addAction(QIcon(":/images/filesave.png"), tr("&Save..."),
02114 this, SLOT(save()),
02115 QKeySequence(tr("Ctrl+S", "File|Save")));
02116 fileMenu->addAction(QIcon(":/images/filesaveas.png"), tr("Save &As..."),
02117 this, SLOT(saveFile()));
02118
02119 fileMenu->addSeparator();
02120
02121
02122
02123
02124 fileMenu->addAction(QIcon(":/images/filesaveas.png"), tr("Export &memories content..."),
02125 this, SLOT(exportMemoriesContent()));
02126 fileMenu->addAction(QIcon(":/images/fileopen.png"), tr("&Import memories content..."),
02127 this, SLOT(importMemoriesContent()));
02128 fileMenu->addSeparator();
02129 fileMenu->addAction(QIcon(":/images/exit.png"), tr("&Quit"),
02130 this, SLOT(close()),
02131 QKeySequence(tr("Ctrl+Q", "File|Quit")));
02132
02133
02134 cutAct = new QAction(QIcon(":/images/editcut.png"), tr("Cu&t"), this);
02135 cutAct->setShortcut(tr("Ctrl+X", "Edit|Cut"));
02136
02137 copyAct = new QAction(QIcon(":/images/editcopy.png"), tr("&Copy"), this);
02138 copyAct->setShortcut(tr("Ctrl+C", "Edit|Copy"));
02139
02140 pasteAct = new QAction(QIcon(":/images/editpaste.png"), tr("&Paste"), this);
02141 pasteAct->setShortcut(tr("Ctrl+V", "Edit|Paste"));
02142
02143 undoAct = new QAction(QIcon(":/images/undo.png"), tr("&Undo"), this);
02144 undoAct->setShortcut(tr("Ctrl+Z", "Edit|Undo"));
02145
02146 redoAct = new QAction(QIcon(":/images/redo.png"), tr("Re&do"), this);
02147 redoAct->setShortcut(tr("Ctrl+Shift+Z", "Edit|Redo"));
02148
02149 cutAct->setEnabled(false);
02150 copyAct->setEnabled(false);
02151 undoAct->setEnabled(false);
02152 redoAct->setEnabled(false);
02153
02154 QMenu *editMenu = new QMenu(tr("&Edit"), this);
02155 menuBar()->addMenu(editMenu);
02156 editMenu->addAction(cutAct);
02157 editMenu->addAction(copyAct);
02158 editMenu->addAction(pasteAct);
02159 editMenu->addSeparator();
02160 editMenu->addAction(QIcon(":/images/editcopy.png"), tr("Copy &all"), this, SLOT(copyAll()));
02161 editMenu->addSeparator();
02162 editMenu->addAction(undoAct);
02163 editMenu->addAction(redoAct);
02164 editMenu->addSeparator();
02165
02166
02167 loadAllAct = new QAction(QIcon(":/images/upload.png"), tr("&Load all"), this);
02168 loadAllAct->setShortcut(tr("F7", "Load|Load all"));
02169
02170 resetAllAct = new QAction(QIcon(":/images/reset.png"), tr("&Reset all"), this);
02171 resetAllAct->setShortcut(tr("F8", "Debug|Reset all"));
02172
02173 runAllAct = new QAction(QIcon(":/images/play.png"), tr("Ru&n all"), this);
02174 runAllAct->setShortcut(tr("F9", "Debug|Run all"));
02175
02176 pauseAllAct = new QAction(QIcon(":/images/pause.png"), tr("&Pause all"), this);
02177 pauseAllAct->setShortcut(tr("F10", "Debug|Pause all"));
02178
02179
02180 QToolBar* globalToolBar = addToolBar(tr("Debug"));
02181 globalToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
02182 globalToolBar->addAction(loadAllAct);
02183 globalToolBar->addAction(resetAllAct);
02184 globalToolBar->addAction(runAllAct);
02185 globalToolBar->addAction(pauseAllAct);
02186
02187
02188 QMenu *debugMenu = new QMenu(tr("&Debug"), this);
02189 menuBar()->addMenu(debugMenu);
02190 debugMenu->addAction(loadAllAct);
02191 debugMenu->addAction(resetAllAct);
02192 debugMenu->addAction(runAllAct);
02193 debugMenu->addAction(pauseAllAct);
02194
02195
02196 QMenu *toolMenu = new QMenu(tr("&Tools"), this);
02197 menuBar()->addMenu(toolMenu);
02198
02199
02200
02201 showCompilationMsg = new QAction(QIcon(":/images/view_text.png"), tr("&Show last compilation messages"), this);
02202 showCompilationMsg->setCheckable(true);
02203 toolMenu->addAction(showCompilationMsg);
02204 connect(showCompilationMsg, SIGNAL(toggled(bool)), SLOT(showCompilationMessages(bool)));
02205 toolMenu->addSeparator();
02206 writeBytecodeMenu = new QMenu(tr("Write the program(s)..."));
02207 toolMenu->addMenu(writeBytecodeMenu);
02208 rebootMenu = new QMenu(tr("Reboot..."));
02209 toolMenu->addMenu(rebootMenu);
02210 regenerateToolsMenus();
02211
02212
02213 QMenu *settingsMenu = new QMenu(tr("&Settings"), this);
02214 menuBar()->addMenu(settingsMenu);
02215 showHiddenAct = new QAction(tr("S&how hidden variables and functions"), this);
02216 showHiddenAct->setCheckable(true);
02217 settingsMenu->addAction(showHiddenAct);
02218
02219
02220 QMenu *pluginMenu = new QMenu(tr("&Plug-ins"), this);
02221 menuBar()->addMenu(pluginMenu);
02222 pluginMenu->addAction(tr("&Linear Camera View"), this, SLOT(addPluginLinearCameraView()));
02223
02224
02225 QMenu *helpMenu = new QMenu(tr("&Help"), this);
02226 menuBar()->addMenu(helpMenu);
02227 helpMenu->addAction(tr("&Language"), this, SLOT(showHelpLanguage()));
02228 helpMenu->addAction(tr("&Studio"), this, SLOT(showHelpStudio()));
02229 helpMenu->addSeparator();
02230 helpMenu->addAction(tr("&About"), this, SLOT(about()));
02231 helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
02232 }
02233
02234 void MainWindow::hideEvent(QHideEvent * event)
02235 {
02236 compilationMessageBox->hide();
02237 }
02238
02240
02243 bool MainWindow::askUserBeforeDiscarding()
02244 {
02245 const bool anythingModified = sourceModified || constantsDefinitionsModel->checkIfModified() || eventsDescriptionsModel->checkIfModified();
02246 if (anythingModified == false)
02247 return true;
02248
02249 QString docName(tr("Untitled"));
02250 if (!actualFileName.isEmpty())
02251 docName = actualFileName.mid(actualFileName.lastIndexOf("/") + 1);
02252
02253 QMessageBox msgBox;
02254 msgBox.setText(tr("The document \"%0\" has been modified.").arg(docName));
02255 msgBox.setInformativeText(tr("Do you want to save your changes or discard them?"));
02256 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
02257 msgBox.setDefaultButton(QMessageBox::Save);
02258
02259 int ret = msgBox.exec();
02260 switch (ret)
02261 {
02262 case QMessageBox::Save:
02263
02264 if (save())
02265 return true;
02266 else
02267 return false;
02268 case QMessageBox::Discard:
02269
02270 return true;
02271 case QMessageBox::Cancel:
02272
02273 return false;
02274 default:
02275
02276 assert(false);
02277 break;
02278 }
02279
02280 return false;
02281 }
02282
02283 void MainWindow::closeEvent ( QCloseEvent * event )
02284 {
02285 if (askUserBeforeDiscarding())
02286 {
02287 event->accept();
02288 emit MainWindowClosed();
02289 }
02290 else
02291 {
02292 event->ignore();
02293 }
02294 }
02295
02296 void MainWindow::updateWindowTitle()
02297 {
02298 const bool anythingModified = sourceModified || constantsDefinitionsModel->checkIfModified() || eventsDescriptionsModel->checkIfModified();
02299
02300 QString modifiedText;
02301 if (anythingModified)
02302 modifiedText = tr("[modified] ");
02303
02304 QString docName(tr("Untitled"));
02305 if (!actualFileName.isEmpty())
02306 docName = actualFileName.mid(actualFileName.lastIndexOf("/") + 1);
02307
02308 setWindowTitle(tr("%0 %1- Aseba Studio").arg(docName).arg(modifiedText));
02309 }
02310
02312 };
02313