MainWindow.cpp
Go to the documentation of this file.
00001 /*
00002         Aseba - an event-based framework for distributed robot control
00003         Copyright (C) 2007--2012:
00004                 Stephane Magnenat <stephane at magnenat dot net>
00005                 (http://stephane.magnenat.net)
00006                 and other contributors, see authors.txt for details
00007         
00008         This program is free software: you can redistribute it and/or modify
00009         it under the terms of the GNU Lesser General Public License as published
00010         by the Free Software Foundation, version 3 of the License.
00011         
00012         This program is distributed in the hope that it will be useful,
00013         but WITHOUT ANY WARRANTY; without even the implied warranty of
00014         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015         GNU Lesser General Public License for more details.
00016         
00017         You should have received a copy of the GNU Lesser General Public License
00018         along with this program. If not, see <http://www.gnu.org/licenses/>.
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 //      /** \addtogroup studio */
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;   // not yet initialized
00084                 vmMemorySize[1] = -1;   // not yet initialized
00085                 readSettings();         // read user's preferences
00086                 connect(this, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
00087         }
00088 
00089         EditorsPlotsTabWidget::~EditorsPlotsTabWidget()
00090         {
00091                 // store user's preferences
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                 // manage the sections size for the vmMemoryView child widget
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                 // keep track of the current value, to apply it on the other tabs
00170                 vmMemorySize[col] = newSize;
00171         }
00172 
00173         void EditorsPlotsTabWidget::tabChanged(int index)
00174         {
00175                 // resize the vmMemoryView, to match the user choice
00176                 NodeTab* tab = dynamic_cast<NodeTab*>(currentWidget());
00177                 if (!tab)
00178                         return;
00179 
00180                 vmMemoryViewResize(tab);
00181                 // reset the tab highlight
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                 // resize the vmMemoryView QTreeView, according to the global value
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                 // editor widget
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                 // setup some variables
00261                 rehighlighting = false;
00262                 errorPos = -1;
00263                 allocatedVariablesCount = 0;
00264                 
00265                 // create models
00266                 vmFunctionsModel = new TargetFunctionsModel(target->getDescription(id));
00267                 vmMemoryModel = new TargetVariablesModel();
00268                 variablesModel = vmMemoryModel;
00269                 subscribeToVariableOfInterest(ASEBA_PID_VAR_NAME);
00270 
00271                 // create gui
00272                 setupWidgets();
00273                 setupConnections();
00274 
00275                 // create aggregated models
00276                 // local and global events
00277                 ModelAggregator* aggregator = new ModelAggregator(this);
00278                 aggregator->addModel(vmLocalEvents->model());
00279                 aggregator->addModel(mainWindow->eventsDescriptionsModel);
00280                 eventAggregator = aggregator;
00281                 // variables and constants
00282                 aggregator = new ModelAggregator(this);
00283                 aggregator->addModel(vmMemoryModel);
00284                 aggregator->addModel(mainWindow->constantsDefinitionsModel);
00285                 variableAggregator = aggregator;
00286 
00287                 // create the sorting proxy
00288                 sortingProxy = new QSortFilterProxyModel(this);
00289                 sortingProxy->setDynamicSortFilter(true);
00290                 sortingProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
00291                 sortingProxy->setSortRole(Qt::DisplayRole);
00292 
00293                 // create the chainsaw filter for native functions
00294                 functionsFlatModel = new TreeChainsawFilter(this);
00295                 functionsFlatModel->setSourceModel(vmFunctionsModel);
00296 
00297                 editor->setFocus();
00298                 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
00299                 
00300                 // get the value of the variables
00301                 // compile in this thread the first time
00302                 NodeTab::CompilationResult* result = compilationThread(*target->getDescription(id), *commonDefinitions, editor->toPlainText(), false);
00303                 processCompilationResult(result);
00304         }
00305 
00306         NodeTab::~NodeTab()
00307         {
00308                 // Note: this might memory leak, depending on when the signal/slots get disconnected
00309                 // but this is a rare case and can be safely ignored
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                 // only fetch what is visible
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                                         // new request
00344                                         currentReqPos = var.pos;
00345                                         currentReqCount = var.value.size();
00346                                 }
00347                                 else if (currentReqPos + currentReqCount == var.pos)
00348                                 {
00349                                         // continuous, append
00350                                         currentReqCount += var.value.size();
00351                                 }
00352                                 else
00353                                 {
00354                                         // flush and reset
00355                                         target->getVariables(id, currentReqPos, currentReqCount);
00356                                         // new request
00357                                         currentReqPos = var.pos;
00358                                         currentReqCount = var.value.size();
00359                                 }
00360                         }
00361                 }
00362                 if (currentReqCount != 0)
00363                 {
00364                         // flush request
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                         // only regenerate if pid has changed
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                 // editor related notification widgets
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                 // memory usage notification area
00401                 memoryUsageText = new QLabel();
00402                 memoryUsageText->setAlignment(Qt::AlignLeft);
00403                 
00404                 // editor area
00405                 QHBoxLayout *editorAreaLayout = new QHBoxLayout;
00406                 editorAreaLayout->setSpacing(0);
00407                 editorAreaLayout->addWidget(breakpoints);
00408                 editorAreaLayout->addWidget(linenumbers);
00409                 editorAreaLayout->addWidget(editor);
00410                 
00411                 // keywords
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                 // panel
00441                 
00442                 // buttons
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                 // memory
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                 //vmMemoryView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00475                 //vmMemoryView->setHeaderHidden(true);
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                 // functions
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                 // local events
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                 // toolbox
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                 // panel
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                 // compiler
00563                 connect(&compilationWatcher, SIGNAL(finished()), SLOT(compilationCompleted()));
00564                 
00565                 // execution
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                 // memory
00574                 connect(vmMemoryModel, SIGNAL(variableValuesChanged(unsigned, const VariablesDataVector &)), SLOT(setVariableValues(unsigned, const VariablesDataVector &)));
00575                 connect(vmMemoryFilter, SIGNAL(textChanged(const QString &)), SLOT(updateHidden()));
00576                 
00577                 // editor
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                 // tools plugins
00589                 connect(mainWindow, SIGNAL(MainWindowClosed()), SLOT(closePlugins()));
00590                 
00591                 // keywords
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                 // following default settings
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                 // first recreate plugins
00635                 for (SavedPlugins::const_iterator it(savedPlugins.begin()); it != savedPlugins.end(); ++it)
00636                 {
00637                         nodeToolRegistrer.update(it->first, this, tools);
00638                 }
00639                 // then reload data
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                 // delete menu entries
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                 // generate menu entries
00659                 for (NodeToolInterfaces::const_iterator it(tools.begin()); it != tools.end(); ++it)
00660                         toolListLayout->addWidget((*it)->createMenuEntry());
00661                 
00662                 // if elements were added, ensure that this tab is visible
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                         //target->getVariables(id, 0, allocatedVariablesCount);
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                 // as we explicitely clicked, refresh all variables
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); // 5 Hz
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                 // See AS001 at https://aseba.wikidot.com/asebaspecifications
00769                 
00770                 // header
00771                 const char* magic = "ABO";
00772                 file.write(magic, 4);
00773                 write16(file, 0); // binary format version
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                 // bytecode
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                 // only top level names have to be inserted
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                                 // language completion
00818                                 const QString& line(cursor.block().text());
00819                                 QString keyword(line);
00820                                 
00821                                 // make sure the string does not have any trailing space
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                 // Quick hack to hide hidden variable in the treeview and not in vmMemoryModel
00955                 // FIXME use a model proxy to perform this task
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                 // compile
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                         // show progress icon
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                 // as long as result is dirty, continue compilation
01015                 if (compilationDirty)
01016                 {
01017                         delete result;
01018                         recompile();
01019                         return;
01020                 }
01021                 
01022                 // process results
01023                 processCompilationResult(result);
01024         }
01025         
01026         void NodeTab::processCompilationResult(CompilationResult* result)
01027         {
01028                 // clear old user data
01029                 // doRehighlight is required to prevent infinite recursion because there are no slot
01030                 // to differentiate user changes from highlight changes in documents
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                 // show memory usage
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                 // update state following result
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                         // we have an error, set the correct user data
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                 // we have finished with the results
01103                 delete result;
01104                 
01105                 // clear bearkpoints of target if currently in debugging mode
01106                 if (editor->debugging)
01107                 {
01108                         //target->stop(id);
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                 // fix tab
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                 // remove execution error
01151                 if (clearEditorProperty("executionError"))
01152                         rehighlight();
01153         }
01154         
01155         void NodeTab::refreshCompleterModel(LocalContext context)
01156         {
01157 //              qDebug() << "New context: " << context;
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);        // both variables and constants
01165                 }
01166                 else if (context == LeftValueContext)
01167                 {
01168                         sortingProxy->setSourceModel(vmMemoryModel);
01169                         sortingProxy->sort(0);
01170                         editor->setCompleterModel(sortingProxy);        // only variables
01171                 }
01172                 else if (context == VarDefContext)
01173                         editor->setCompleterModel(0);           // disable auto-completion in this case
01174                 else if (context == FunctionContext)
01175                 {
01176                         sortingProxy->setSourceModel(functionsFlatModel);
01177                         sortingProxy->sort(0);
01178                         editor->setCompleterModel(sortingProxy);        // native functions
01179                 }
01180                 else if (context == EventContext)
01181                 {
01182                         sortingProxy->setSourceModel(eventAggregator);
01183                         sortingProxy->sort(0);
01184                         //connect(mainWindow->eventsDescriptionsModel, SIGNAL(publicRowsInserted()), SLOT(sortCompleterModel()));
01185                         //connect(mainWindow->eventsDescriptionsModel, SIGNAL(publicRowsRemoved()), SLOT(sortCompleterModel()));
01186                         editor->setCompleterModel(sortingProxy);        // both local and global events
01187                 }
01188         }
01189 /*
01190         void NodeTab::sortCompleterModel()
01191         {
01192                 sortingProxy->sort(0);
01193                 editor->setCompleterModel(0);
01194                 editor->setCompleterModel(sortingProxy);
01195         }
01196 */
01197         void NodeTab::variablesMemoryChanged(unsigned start, const VariablesDataVector &variables)
01198         {
01199                 // update memory view
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                 // change active state
01224                 currentPC = line;
01225                 if (setEditorProperty("active", QVariant(), line, true))
01226                         rehighlight();
01227         }
01228         
01229         void NodeTab::executionModeChanged(Target::ExecutionMode mode)
01230         {
01231                 // ignore those messages if we are not in debugging mode
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                 // Filter spurious messages, to detect a stop at a breakpoint
01240                 if (previousMode != mode)
01241                 {
01242                         previousMode = mode;
01243                         if ((mode == Target::EXECUTION_STEP_BY_STEP) && editor->isBreakpoint(currentPC))
01244                         {
01245                                 // we are at a breakpoint
01246                                 if (mainWindow->currentScriptTab != this)
01247                                 {
01248                                         // not the current tab -> hidden tab -> highlight me in red
01249                                         mainWindow->nodes->highlightTab(mainWindow->getIndexFromId(id), Qt::red);
01250                                 }
01251                                 // go to this line
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                         // go to this line and next line is visible
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                 // set the tab icon to show the current execution mode
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                                 // set propety
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                                 // remove if exists
01364                                 if (uData && removeOld && uData->properties.contains(property))
01365                                 {
01366                                         uData->properties.remove(property);
01367                                         if (uData->properties.isEmpty())
01368                                         {
01369                                                 // garbage collect UserData
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                 // find line, remove property
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                                                 // garbage collect UserData
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                 // go through all blocks, remove property if found
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                                         // garbage collect UserData
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                 // create the widgets
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                 // create the layout
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                 // set modal
01478                 setModal(true);
01479 
01480                 // connections
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);          // make it wide enough
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                 // create target
01522                 target = new DashelTarget(translators, commandLineTarget);
01523 
01524                 // create models
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                 // create config dialog + read settings on-disk
01532                 ConfigDialog::init(this);
01533 
01534                 // create gui
01535                 setupWidgets();
01536                 setupMenu();
01537                 setupConnections();
01538                 
01539                 // cosmetic fix-up
01540                 updateWindowTitle();
01541                 if (readSettings() == false)
01542                         resize(1000,700);
01543                 
01544                 // when everything is ready, get description
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                         // we must only have NodeTab* left.
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                 // make sure we do not loose changes
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                                                 // load plugins xml data
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                                                 // get text
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                                                 // reconstruct nodes
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                         // check if there was some matching problem
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                         // update recent files
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                 // initiate DOM tree
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                 // events
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                 // constants
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                 // keywords
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                 // source code
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                 // remove old connections, if any
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                 // reconnect to new
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                                         // because this is a new tab, get content of variables
02335                                         target->getVariables(nodeTab->id, 0, nodeTab->allocatedVariablesCount);
02336                                         
02337                                         showCompilationMsg->setEnabled(true);
02338                                         findDialog->replaceGroupBox->setEnabled(true);
02339                                         // paste and replace are only available when the editor is in read/write mode
02340                                         pasteAct->setEnabled(true);
02341                                         replaceAct->setEnabled(true);
02342                                 }
02343                                 else
02344                                 {
02345                                         showCompilationMsg->setEnabled(false);
02346                                         findDialog->replaceGroupBox->setEnabled(false);
02347                                 }
02348                                 
02349                                 // TODO: it would be nice to find a way to setup this correctly
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                 // this slot shouldn't be callable when an unactive tab is show
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                 // prompt the user for the named value
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                 // prompt the user for the named value
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                 // create a new tab for the node
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                 // check if there is an absent node tab with this id and name, and copy data
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                 // connect and show new tab
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                 // collect all node ids to disconnect
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                 // disconnect all node ids
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                 // iterate over all viewer for this event
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                 //setColumnStretch
02939                 
02940                 /*QHBoxLayout* constantsAddRemoveLayout = new QHBoxLayout;;
02941                 constantsAddRemoveLayout->addStretch();
02942                 addConstantButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
02943                 constantsAddRemoveLayout->addWidget(addConstantButton);
02944                 removeConstantButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
02945                 removeConstantButton->setEnabled(false);
02946                 constantsAddRemoveLayout->addWidget(removeConstantButton);
02947                 
02948                 eventsDockLayout->addLayout(constantsAddRemoveLayout);
02949                 eventsDockLayout->addWidget(constantsView, 1);*/
02950                 
02951                 
02952                 /*eventsDockLayout->addWidget(new QLabel(tr("<b>Events</b>")));
02953                 
02954                 QHBoxLayout* eventsAddRemoveLayout = new QHBoxLayout;;
02955                 eventsAddRemoveLayout->addStretch();
02956                 addEventNameButton = new QPushButton(QPixmap(QString(":/images/add.png")), "");
02957                 eventsAddRemoveLayout->addWidget(addEventNameButton);
02958                 removeEventNameButton = new QPushButton(QPixmap(QString(":/images/remove.png")), "");
02959                 removeEventNameButton->setEnabled(false);
02960                 eventsAddRemoveLayout->addWidget(removeEventNameButton);
02961                 sendEventButton = new QPushButton(QPixmap(QString(":/images/newmsg.png")), "");
02962                 sendEventButton->setEnabled(false);
02963                 eventsAddRemoveLayout->addWidget(sendEventButton);
02964                 
02965                 eventsDockLayout->addLayout(eventsAddRemoveLayout);
02966                                 
02967                 eventsDockLayout->addWidget(eventsDescriptionsView, 1);*/
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                 //eventsLayout->setColumnStretch(2, 0);
03007                 eventsLayout->addWidget(removeEventNameButton,1,1);
03008                 //eventsLayout->setColumnStretch(3, 0);
03009                 //eventsLayout->setColumnStretch(0, 1);
03010                 eventsLayout->addWidget(sendEventButton,1,2);
03011                 //eventsLayout->setColumnStretch(1, 0);
03012                 #ifdef HAVE_QWT
03013                 eventsLayout->addWidget(plotEventButton,1,3);
03014                 #endif // HAVE_QWT
03015                 eventsLayout->addWidget(eventsDescriptionsView, 2, 0, 1, 4);
03016                 
03017                 /*logger = new QListWidget;
03018                 logger->setMinimumSize(80,100);
03019                 logger->setSelectionMode(QAbstractItemView::NoSelection);
03020                 eventsDockLayout->addWidget(logger, 3);
03021                 clearLogger = new QPushButton(tr("Clear"));
03022                 eventsDockLayout->addWidget(clearLogger);*/
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                 // panel
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                 // main window
03052                 splitter->addWidget(rightPanelSplitter);
03053                 splitter->setSizes(QList<int>() << 800 << 200);
03054                 
03055                 // dialog box
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                 // help viewer
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                 // general connections
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                 // global actions
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                 // events
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                 // logger
03100                 connect(clearLogger, SIGNAL(clicked()), logger, SLOT(clear()));
03101                 connect(clearLogger, SIGNAL(clicked()), SLOT(clearAllExecutionError()));
03102                 
03103                 // constants
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                 // target events
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                 // Add all other actions excepted the one we are processing
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                 // remove old target-specific actions
03213                 while (!targetSpecificHelp.isEmpty())
03214                 {
03215                         QAction *action(targetSpecificHelp.takeFirst());
03216                         helpMenu->removeAction(action);
03217                         delete action;
03218                 }
03219                 
03220                 // add back target-specific actions
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                 // File menu
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                 /*fileMenu->addAction(QIcon(":/images/network.png"), tr("Connect to &target"),
03299                                                         target, SLOT(connect()),
03300                                                         QKeySequence(tr("Ctrl+T", "File|Connect to target")));
03301                 fileMenu->addSeparator();*/
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                 // Edit menu
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                 // View menu
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                 // Debug actions
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                 // Debug toolbar
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                 // Debug menu
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                 //clearAllBreakpointsAct->setShortcut();
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                 // Tool menu
03449                 QMenu *toolMenu = new QMenu(tr("&Tools"), this);
03450                 menuBar()->addMenu(toolMenu);
03451                 /*toolMenu->addAction(QIcon(":/images/view_text.png"), tr("&Show last compilation messages"),
03452                                                         this, SLOT(showCompilationMessages()),
03453                                                         QKeySequence(tr("Ctrl+M", "Tools|Show last compilation messages")));*/
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                 // Help menu
03468                 helpMenu = new QMenu(tr("&Help"), this);
03469                 menuBar()->addMenu(helpMenu);
03470                 generateHelpMenu();
03471                 regenerateHelpMenu();
03472                 
03473                 // add dynamic stuff
03474                 regenerateToolsMenus();
03475 
03476                 // Load the state from the settings (thus from hard drive)
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                                 // Save was clicked
03505                                 if (save())
03506                                         return true;
03507                                 else
03508                                         return false;
03509                         case QMessageBox::Discard:
03510                                 // Don't Save was clicked
03511                                 return true;
03512                         case QMessageBox::Cancel:
03513                                 // Cancel was clicked
03514                                 return false;
03515                         default:
03516                                 // should never be reached
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 }; // Aseba
03580 


aseba
Author(s): Stéphane Magnenat
autogenerated on Thu Jan 2 2014 11:17:16