Bug Summary

File:OMEdit/OMEditLIB/Simulation/SimulationOutputWidget.cpp
Warning:line 447, column 5
Potential leak of memory pointed to by 'pCHighlighter'

Annotated Source Code

[?] Use j/k keys for keyboard navigation

1/*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
13 * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
14 *
15 * The OpenModelica software and the Open Source Modelica
16 * Consortium (OSMC) Public License (OSMC-PL) are obtained
17 * from OSMC, either from the above address,
18 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
19 * http://www.openmodelica.org, and in the OpenModelica distribution.
20 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
21 *
22 * This program is distributed WITHOUT ANY WARRANTY; without
23 * even the implied warranty of MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
25 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
26 *
27 * See the full OSMC Public License conditions for more details.
28 *
29 */
30/*
31 * @author Adeel Asghar <adeel.asghar@liu.se>
32 */
33
34#include "Simulation/SimulationOutputWidget.h"
35#include "MainWindow.h"
36#include "Modeling/LibraryTreeWidget.h"
37#include "Modeling/ItemDelegate.h"
38#include "Options/OptionsDialog.h"
39#include "SimulationOutputHandler.h"
40#include "Editors/CEditor.h"
41#include "Editors/TextEditor.h"
42#include "SimulationProcessThread.h"
43#include "SimulationDialog.h"
44#include "TransformationalDebugger/TransformationsWidget.h"
45
46#include <QApplication>
47#include <QObject>
48#include <QHeaderView>
49#include <QAction>
50#include <QMenu>
51#include <QDesktopWidget>
52#include <QTcpSocket>
53#include <QMessageBox>
54
55/*!
56 * \class SimulationOutputTree
57 * \brief A tree based structure for simulation output messages.
58 */
59/*!
60 * \brief SimulationOutputTree::SimulationOutputTree
61 * \param pSimulationOutputWidget
62 */
63SimulationOutputTree::SimulationOutputTree(SimulationOutputWidget *pSimulationOutputWidget)
64 : QTreeView(pSimulationOutputWidget), mpSimulationOutputWidget(pSimulationOutputWidget)
65{
66 setItemDelegate(new ItemDelegate(this, true));
67 setTextElideMode(Qt::ElideNone);
68 setIndentation(Helper::treeIndentation);
69 setExpandsOnDoubleClick(false);
70 setHeaderHidden(true);
71 setMouseTracking(true); /* important for Debug more links. */
72 setSelectionMode(QAbstractItemView::ExtendedSelection);
73 setContextMenuPolicy(Qt::CustomContextMenu);
74 connect(this, SIGNAL(customContextMenuRequested(QPoint))"2""customContextMenuRequested(QPoint)", SLOT(showContextMenu(QPoint))"1""showContextMenu(QPoint)");
75 connect(header(), SIGNAL(sectionResized(int,int,int))"2""sectionResized(int,int,int)", SLOT(callLayoutChanged(int,int,int))"1""callLayoutChanged(int,int,int)");
76 // create actions
77 mpSelectAllAction = new QAction(tr("Select All"), this);
78 mpSelectAllAction->setShortcut(QKeySequence("Ctrl+a"));
79 mpSelectAllAction->setStatusTip(tr("Selects all the Messages"));
80 connect(mpSelectAllAction, SIGNAL(triggered())"2""triggered()", SLOT(selectAllMessages())"1""selectAllMessages()");
81 mpCopyAction = new QAction(QIcon(":/Resources/icons/copy.svg"), Helper::copy, this);
82 mpCopyAction->setShortcut(QKeySequence("Ctrl+c"));
83 mpCopyAction->setStatusTip(tr("Copy the Message"));
84 connect(mpCopyAction, SIGNAL(triggered())"2""triggered()", SLOT(copyMessages())"1""copyMessages()");
85 mpExpandAllAction = new QAction(Helper::expandAll, this);
86 mpExpandAllAction->setStatusTip(tr("Copy the Message"));
87 connect(mpExpandAllAction, SIGNAL(triggered())"2""triggered()", SLOT(expandAll())"1""expandAll()");
88 mpCollapseAllAction = new QAction(Helper::collapseAll, this);
89 mpCollapseAllAction->setStatusTip(tr("Copy the Message"));
90 connect(mpCollapseAllAction, SIGNAL(triggered())"2""triggered()", SLOT(collapseAll())"1""collapseAll()");
91}
92
93/*!
94 * \brief SimulationOutputTree::getDepth
95 * Asks the model about the depth/level of QModelIndex.
96 * \param index
97 * \return
98 */
99int SimulationOutputTree::getDepth(const QModelIndex &index) const
100{
101 SimulationMessageModel *pSimulationMessageModel = qobject_cast<SimulationMessageModel*>(model());
102 if (pSimulationMessageModel) {
103 return pSimulationMessageModel->getDepth(index);
104 } else {
105 return 1;
106 }
107}
108
109/*!
110 * \brief SimulationOutputTree::showContextMenu
111 * Shows a context menu when user right click on the Messages tree.
112 * Slot activated when SimulationOutputTree::customContextMenuRequested() signal is raised.
113 * \param point
114 */
115void SimulationOutputTree::showContextMenu(QPoint point)
116{
117 QMenu menu(this);
118 menu.addAction(mpSelectAllAction);
119 menu.addAction(mpCopyAction);
120 menu.addSeparator();
121 menu.addAction(mpExpandAllAction);
122 menu.addAction(mpCollapseAllAction);
123 menu.exec(viewport()->mapToGlobal(point));
124}
125
126/*!
127 * \brief SimulationOutputTree::callLayoutChanged
128 * Slot activated when QHeaderView sectionResized signal is raised.\n
129 * Tells the model to emit layoutChanged signal.\n
130 * \sa SimulationMessageModel::callLayoutChanged()
131 * \param logicalIndex
132 * \param oldSize
133 * \param newSize
134 */
135void SimulationOutputTree::callLayoutChanged(int logicalIndex, int oldSize, int newSize)
136{
137 Q_UNUSED(logicalIndex)(void)logicalIndex;;
138 Q_UNUSED(oldSize)(void)oldSize;;
139 Q_UNUSED(newSize)(void)newSize;;
140 SimulationMessageModel *pSimulationMessageModel = qobject_cast<SimulationMessageModel*>(model());
141 if (pSimulationMessageModel) {
142 pSimulationMessageModel->callLayoutChanged();
143 }
144}
145
146/*!
147 * \brief SimulationOutputTree::selectAllMessages
148 * Selects all the Messages.
149 * Slot activated when mpSelectAllAction triggered signal is raised.
150 */
151void SimulationOutputTree::selectAllMessages()
152{
153 selectAll();
154}
155
156/*!
157 * \brief compareSimulationMessageDeweyId
158 * Compares the QModelIndexes based on their deweyid
159 * \param index1
160 * \param index2
161 * \return
162 */
163bool compareSimulationMessageDeweyId(const QModelIndex &index1, const QModelIndex &index2)
164{
165 SimulationMessage *pSimulationMessage1 = static_cast<SimulationMessage*>(index1.internalPointer());
166 SimulationMessage *pSimulationMessage2 = static_cast<SimulationMessage*>(index2.internalPointer());
167
168 return pSimulationMessage1 && pSimulationMessage2 && pSimulationMessage1->mDeweyId < pSimulationMessage2->mDeweyId;
169}
170
171/*!
172 * \brief SimulationOutputTree::copyMessages
173 * Copy the selected Messages to the clipboard.
174 * Slot activated when mpCopyAction triggered signal is raised.
175 */
176void SimulationOutputTree::copyMessages()
177{
178 SimulationMessageModel *pSimulationMessageModel = qobject_cast<SimulationMessageModel*>(model());
179 if (pSimulationMessageModel) {
180 QStringList textToCopy;
181 QModelIndexList modelIndexes = selectionModel()->selectedRows();
182 // sort the selected indexes based on deweyid so that we get the correct order since selectionModel()->selectedRows() changes the order.
183 std::sort(modelIndexes.begin(), modelIndexes.end(), compareSimulationMessageDeweyId);
184 foreach (QModelIndex modelIndex, modelIndexes)for (auto _container_ = QtPrivate::qMakeForeachContainer(modelIndexes
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (QModelIndex
modelIndex = *_container_.i; _container_.control; _container_
.control = 0)
{
185 SimulationMessage *pSimulationMessage = static_cast<SimulationMessage*>(modelIndex.internalPointer());
186 if (pSimulationMessage) {
187 /* Ticket:4778 Remove HTML formatting. */
188// textToCopy.append(QString("%1 | %2 | %3")
189// .arg(pSimulationMessage->mStream)
190// .arg(StringHandler::getSimulationMessageTypeString(pSimulationMessage->mType))
191// .arg(pSimulationMessage->mText));
192 textToCopy.append(QTextDocumentFragment::fromHtml(QString(pSimulationMessage->mText).remove("<p>").remove("</p>")).toPlainText());
193 }
194 }
195 QApplication::clipboard()->setText(textToCopy.join("\n"));
196 }
197}
198
199/*!
200 * \brief SimulationOutputTree::keyPressEvent
201 * Reimplementation of keypressevent.
202 * Defines what to do for Ctrl+A, Ctrl+C and Del buttons.
203 * \param event
204 */
205void SimulationOutputTree::keyPressEvent(QKeyEvent *event)
206{
207 bool controlModifier = event->modifiers().testFlag(Qt::ControlModifier);
208 if (controlModifier && event->key() == Qt::Key_A) {
209 selectAllMessages();
210 } else if (controlModifier && event->key() == Qt::Key_C) {
211 copyMessages();
212 } else {
213 QTreeView::keyPressEvent(event);
214 }
215}
216
217/*!
218 * \class SimulationOutputDialog
219 * \brief Creates a dialog that shows the current simulation output.
220 */
221/*!
222 * \brief SimulationOutputWidget::SimulationOutputWidget
223 * \param simulationOptions
224 * \param pParent
225 */
226SimulationOutputWidget::SimulationOutputWidget(SimulationOptions simulationOptions, QWidget *pParent)
227 : mSimulationOptions(simulationOptions)
228{
229 Q_UNUSED(pParent)(void)pParent;;
230 setWindowTitle(QString("%1 - %2 %3").arg(Helper::applicationName).arg(mSimulationOptions.getClassName()).arg(Helper::simulationOutput));
231 // progress label
232 mpProgressLabel = new Label;
233 mpProgressLabel->setElideMode(Qt::ElideMiddle);
234 mpCancelButton = new QPushButton(tr("Cancel Compilation"));
235 mpCancelButton->setEnabled(false);
236 connect(mpCancelButton, SIGNAL(clicked())"2""clicked()", SLOT(cancelCompilationOrSimulation())"1""cancelCompilationOrSimulation()");
237 mpOpenTransformationalDebuggerButton = new QToolButton;
238 mpOpenTransformationalDebuggerButton->setIcon(QIcon(":/Resources/icons/equational-debugger.svg"));
239 mpOpenTransformationalDebuggerButton->setToolTip(tr("Open Transformational Debugger"));
240 connect(mpOpenTransformationalDebuggerButton, SIGNAL(clicked())"2""clicked()", SLOT(openTransformationalDebugger())"1""openTransformationalDebugger()");
241 mpOpenOutputFileButton = new QPushButton(tr("Open Output File"));
242 mpOpenOutputFileButton->setEnabled(false);
243 connect(mpOpenOutputFileButton, SIGNAL(clicked())"2""clicked()", SLOT(openSimulationLogFile())"1""openSimulationLogFile()");
244 mpProgressBar = new QProgressBar;
245 mpProgressBar->setAlignment(Qt::AlignHCenter);
246 // Generated Files tab widget
247 mpGeneratedFilesTabWidget = new QTabWidget;
248 mpGeneratedFilesTabWidget->setMovable(true);
249 mpSimulationOutputHandler = 0;
250 // Simulation Output TextBox
251 if (OptionsDialog::instance()->getSimulationPage()->getOutputMode().compare(Helper::structuredOutput) == 0) {
1
Assuming the condition is true
2
Taking true branch
252 mIsOutputStructured = true;
253 // simulation output browser
254 mpSimulationOutputTextBrowser = 0;
255 // simulation output tree
256 mpSimulationOutputTree = new SimulationOutputTree(this);
257 mpGeneratedFilesTabWidget->addTab(mpSimulationOutputTree, Helper::output);
258 } else {
259 mIsOutputStructured = false;
260 // simulation output browser
261 mpSimulationOutputTextBrowser = new QTextBrowser;
262 mpSimulationOutputTextBrowser->setFont(QFont(Helper::monospacedFontInfo.family()));
263 mpSimulationOutputTextBrowser->setOpenLinks(false);
264 mpSimulationOutputTextBrowser->setOpenExternalLinks(false);
265 connect(mpSimulationOutputTextBrowser, SIGNAL(anchorClicked(QUrl))"2""anchorClicked(QUrl)", SLOT(openTransformationBrowser(QUrl))"1""openTransformationBrowser(QUrl)");
266 // simulation output tree
267 mpSimulationOutputTree = 0;
268 mpGeneratedFilesTabWidget->addTab(mpSimulationOutputTextBrowser, Helper::output);
269 }
270 mpGeneratedFilesTabWidget->setTabEnabled(0, false);
271 // Compilation Output TextBox
272 mpCompilationOutputTextBox = new QPlainTextEdit;
273 mpCompilationOutputTextBox->setFont(QFont(Helper::monospacedFontInfo.family()));
274 mpGeneratedFilesTabWidget->addTab(mpCompilationOutputTextBox, tr("Compilation"));
275 mpGeneratedFilesTabWidget->setTabEnabled(1, false);
276 mGeneratedFilesList << "%1.makefile";
277 // cpp-runtime generated files
278 if (simulationOptions.getTargetLanguage().compare("Cpp") == 0) {
3
Assuming the condition is true
4
Taking true branch
279 mGeneratedFilesList << "%1.bat"
280 << "OMCpp%1.cpp"
281 << "OMCpp%1.h"
282 << "OMCpp%1.exp"
283 << "OMCpp%1.lib"
284 << "OMCpp%1AlgLoopMain.cpp"
285 << "OMCpp%1CalcHelperMain.cpp"
286 << "OMCpp%1CalcHelperMain.obj"
287 << "OMCpp%1CalcHelperMain.o"
288 << "OMCpp%1FactoryExport.cpp"
289 << "OMCpp%1Functions.cpp"
290 << "OMCpp%1Functions.h"
291 << "OMCpp%1Initialize.cpp"
292 << "OMCpp%1Initialize.h"
293 << "OMCpp%1Jacobian.cpp"
294 << "OMCpp%1Jacobian.h"
295 << "OMCpp%1Main.cpp"
296 << "OMCpp%1Main.obj"
297 << "OMCpp%1Mixed.cpp"
298 << "OMCpp%1Mixed.h"
299 << "OMCpp%1StateSelection.cpp"
300 << "OMCpp%1StateSelection.h"
301 << "OMCpp%1Types.h"
302 << "OMCpp%1WriteOutput.cpp"
303 << "OMCpp%1WriteOutput.h";
304
305 mGeneratedAlgLoopFilesList << QString("OMCpp%1Algloop*.h").arg(simulationOptions.getOutputFileName())
306 << QString("OMCpp%1Algloop*.cpp").arg(simulationOptions.getOutputFileName());
307 } else {
308 // c-runtime generated files
309 mGeneratedFilesList << "%1.c"
310 << "%1.o"
311 << "%1_01exo.c"
312 << "%1_01exo.o"
313 << "%1_02nls.c"
314 << "%1_02nls.o"
315 << "%1_03lsy.c"
316 << "%1_03lsy.o"
317 << "%1_04set.c"
318 << "%1_04set.o"
319 << "%1_05evt.c"
320 << "%1_05evt.o"
321 << "%1_06inz.c"
322 << "%1_06inz.o"
323 << "%1_07dly.c"
324 << "%1_07dly.o"
325 << "%1_08bnd.c"
326 << "%1_08bnd.o"
327 << "%1_09alg.c"
328 << "%1_09alg.o"
329 << "%1_10asr.c"
330 << "%1_10asr.o"
331 << "%1_11mix.c"
332 << "%1_11mix.o"
333 << "%1_11mix.h"
334 << "%1_12jac.c"
335 << "%1_12jac.o"
336 << "%1_12jac.h"
337 << "%1_13opt.c"
338 << "%1_13opt.o"
339 << "%1_13opt.h"
340 << "%1_14lnz.c"
341 << "%1_14lnz.o"
342 << "%1_15syn.c"
343 << "%1_15syn.o"
344 << "%1_16dae.c"
345 << "%1_16dae.o"
346 << "%1_16dae.h"
347 << "%1_17inl.c"
348 << "%1_17inl.o"
349 << "%1_functions.c"
350 << "%1_functions.o"
351 << "%1_functions.h"
352 << "%1_records.c"
353 << "%1_records.o"
354 << "%1_includes.h"
355 << "%1_literals.h"
356 << "%1_model.h";
357
358 mGeneratedAlgLoopFilesList.clear();
359 }
360 if (mSimulationOptions.getShowGeneratedFiles()) {
5
Assuming the condition is true
6
Taking true branch
361 QString workingDirectory = mSimulationOptions.getWorkingDirectory();
362 QString outputFile = mSimulationOptions.getOutputFileName();
363 foreach (QString fileName, mGeneratedFilesList)for (auto _container_ = QtPrivate::qMakeForeachContainer(mGeneratedFilesList
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (QString fileName
= *_container_.i; _container_.control; _container_.control =
0)
{
364 // filter *.o files and .makefile
365 if (!fileName.endsWith(".o") && fileName.compare(".makefile") != 0) {
366 addGeneratedFileTab(QString("%1/%2").arg(workingDirectory, QString(fileName).arg(outputFile)));
367 }
368 }
369 // Delete the Algloop*.cpp/h files generated by cpp runtime
370 if (mSimulationOptions.getTargetLanguage().compare("Cpp") == 0) {
7
Assuming the condition is false
8
Taking false branch
371 QStringList filesList = QDir(workingDirectory).entryList(mGeneratedAlgLoopFilesList, QDir::Files | QDir::NoSymLinks |
372 QDir::NoDotAndDotDot | QDir::Writable | QDir::CaseSensitive);
373 foreach (QString fileName, filesList)for (auto _container_ = QtPrivate::qMakeForeachContainer(filesList
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (QString fileName
= *_container_.i; _container_.control; _container_.control =
0)
{
374 addGeneratedFileTab(QString("%1/%2").arg(workingDirectory, fileName));
375 }
376 }
377 if (simulationOptions.getTargetLanguage().compare("C") == 0) {
9
Assuming the condition is false
10
Taking false branch
378 /* className_info.json tab */
379 addGeneratedFileTab(QString("%1/%2%3").arg(workingDirectory, outputFile).arg("_info.json"));
380 }
381 /* className_init.xml tab */
382 addGeneratedFileTab(QString("%1/%2%3").arg(workingDirectory, outputFile).arg("_init.xml"));
11
Calling 'SimulationOutputWidget::addGeneratedFileTab'
383 }
384 // layout
385 QGridLayout *pMainLayout = new QGridLayout;
386 pMainLayout->setContentsMargins(5, 5, 5, 5);
387 pMainLayout->addWidget(mpProgressLabel, 0, 0, 1, 4);
388 pMainLayout->addWidget(mpProgressBar, 1, 0);
389 pMainLayout->addWidget(mpCancelButton, 1, 1);
390 pMainLayout->addWidget(mpOpenTransformationalDebuggerButton, 1, 2);
391 pMainLayout->addWidget(mpOpenOutputFileButton, 1, 3);
392 pMainLayout->addWidget(mpGeneratedFilesTabWidget, 2, 0, 1, 4);
393 setLayout(pMainLayout);
394 // create the ArchivedSimulationItem
395 mpArchivedSimulationItem = new ArchivedSimulationItem(mSimulationOptions, this);
396 MainWindow::instance()->getSimulationDialog()->getArchivedSimulationsTreeWidget()->addTopLevelItem(mpArchivedSimulationItem);
397 // start the tcp server
398 mpTcpServer = new QTcpServer;
399 mSocketDisconnected = true;
400 mpTcpServer->listen(QHostAddress(QHostAddress::LocalHost));
401 connect(mpTcpServer, SIGNAL(newConnection())"2""newConnection()", SLOT(createSimulationProgressSocket())"1""createSimulationProgressSocket()");
402 // create the thread
403 mpSimulationProcessThread = new SimulationProcessThread(this);
404 connect(mpSimulationProcessThread, SIGNAL(sendCompilationStarted())"2""sendCompilationStarted()", SLOT(compilationProcessStarted())"1""compilationProcessStarted()");
405 connect(mpSimulationProcessThread, SIGNAL(sendCompilationOutput(QString,QColor))"2""sendCompilationOutput(QString,QColor)", SLOT(writeCompilationOutput(QString,QColor))"1""writeCompilationOutput(QString,QColor)");
406 connect(mpSimulationProcessThread, SIGNAL(sendCompilationFinished(int,QProcess::ExitStatus))"2""sendCompilationFinished(int,QProcess::ExitStatus)",
407 SLOT(compilationProcessFinished(int,QProcess::ExitStatus))"1""compilationProcessFinished(int,QProcess::ExitStatus)");
408 connect(mpSimulationProcessThread, SIGNAL(sendSimulationStarted())"2""sendSimulationStarted()", SLOT(simulationProcessStarted())"1""simulationProcessStarted()");
409 connect(mpSimulationProcessThread, SIGNAL(sendSimulationOutput(QString,StringHandler::SimulationMessageType,bool))"2""sendSimulationOutput(QString,StringHandler::SimulationMessageType,bool)",
410 SLOT(writeSimulationOutput(QString,StringHandler::SimulationMessageType,bool))"1""writeSimulationOutput(QString,StringHandler::SimulationMessageType,bool)");
411 connect(mpSimulationProcessThread, SIGNAL(sendSimulationFinished(int,QProcess::ExitStatus))"2""sendSimulationFinished(int,QProcess::ExitStatus)",
412 SLOT(simulationProcessFinished(int,QProcess::ExitStatus))"1""simulationProcessFinished(int,QProcess::ExitStatus)");
413 mpSimulationProcessThread->start();
414}
415
416SimulationOutputWidget::~SimulationOutputWidget()
417{
418 if (OptionsDialog::instance()->getGeneralSettingsPage()->getPreserveUserCustomizations()) {
419 Utilities::getApplicationSettings()->setValue("SimulationOutputWidget/geometry", saveGeometry());
420 }
421 /* Ticket:3788 comment:12 Delete the entire simulation folder. */
422 if (OptionsDialog::instance()->getSimulationPage()->getDeleteEntireSimulationDirectoryCheckBox()->isChecked()) {
423 Utilities::removeDirectoryRecursivly(mSimulationOptions.getWorkingDirectory());
424 }
425 if (mpSimulationOutputHandler) {
426 delete mpSimulationOutputHandler;
427 }
428 if (mpTcpServer) {
429 delete mpTcpServer;
430 }
431}
432
433void SimulationOutputWidget::addGeneratedFileTab(QString fileName)
434{
435 QFile file(fileName);
436 QFileInfo fileInfo(fileName);
437 if (file.exists()) {
12
Assuming the condition is true
13
Taking true branch
438 file.open(QIODevice::ReadOnly);
439 BaseEditor *pEditor;
440 if (Utilities::isCFile(fileInfo.suffix())) {
14
Assuming the condition is true
15
Taking true branch
441 pEditor = new CEditor(MainWindow::instance());
442 CHighlighter *pCHighlighter = new CHighlighter(OptionsDialog::instance()->getCEditorPage(), pEditor->getPlainTextEdit());
16
Memory is allocated
443 Q_UNUSED(pCHighlighter)(void)pCHighlighter;;
444 } else {
445 pEditor = new TextEditor(MainWindow::instance());
446 }
447 pEditor->getPlainTextEdit()->setPlainText(QString(file.readAll()));
17
Potential leak of memory pointed to by 'pCHighlighter'
448 mpGeneratedFilesTabWidget->addTab(pEditor, fileInfo.fileName());
449 file.close();
450 }
451}
452
453/*!
454 * \brief SimulationOutputWidget::writeSimulationMessage
455 * Writes the simulation output in a formatted text form.\n
456 * \param pSimulationMessage - the simulation output message.
457 */
458void SimulationOutputWidget::writeSimulationMessage(SimulationMessage *pSimulationMessage)
459{
460 static QString lastSream;
461 static QString lastType;
462 /* format the error message */
463 QString type = StringHandler::getSimulationMessageTypeString(pSimulationMessage->mType);
464 QString text;
465 if (pSimulationMessage->mType != StringHandler::OMEditInfo) {
466 text = ((lastSream == pSimulationMessage->mStream && pSimulationMessage->mLevel > 0) ? "|" : pSimulationMessage->mStream) + "\t\t| ";
467 text += ((lastSream == pSimulationMessage->mStream && lastType == type && pSimulationMessage->mLevel > 0) ? "|" : type) + "\t | ";
468 for (int i = 0 ; i < pSimulationMessage->mLevel ; ++i)
469 text += "| ";
470 }
471 text += pSimulationMessage->mText;
472 /* move the cursor down before adding to the logger. */
473 QTextCursor textCursor = mpSimulationOutputTextBrowser->textCursor();
474 textCursor.movePosition(QTextCursor::End);
475 mpSimulationOutputTextBrowser->setTextCursor(textCursor);
476 /* set the text color */
477 QTextCharFormat charFormat = mpSimulationOutputTextBrowser->currentCharFormat();
478 charFormat.setForeground(StringHandler::getSimulationMessageTypeColor(pSimulationMessage->mType));
479 mpSimulationOutputTextBrowser->setCurrentCharFormat(charFormat);
480 /* append the output */
481 /* write the error message */
482 if (pSimulationMessage->mText.compare("Reached display limit") == 0) {
483 QString simulationLogFilePath = QString("%1/%2.log").arg(mSimulationOptions.getWorkingDirectory()).arg(mSimulationOptions.getClassName());
484 mpSimulationOutputTextBrowser->insertHtml(QString("Reached display limit. To read the full log open the file <a href=\"file:///%1\">%1</a>")
485 .arg(simulationLogFilePath));
486 } else {
487 mpSimulationOutputTextBrowser->insertPlainText(text);
488 }
489 /* write the error link */
490 if (!pSimulationMessage->mIndex.isEmpty()) {
491 mpSimulationOutputTextBrowser->insertHtml("&nbsp;<a href=\"omedittransformationsbrowser://" + QUrl::fromLocalFile(mSimulationOptions.getWorkingDirectory() + "/" + mSimulationOptions.getOutputFileName() + "_info.json").path() + "?index=" + pSimulationMessage->mIndex + "\">Debug more</a><br />");
492 } else {
493 mpSimulationOutputTextBrowser->insertPlainText("\n");
494 }
495 /* save the current stream & type as last */
496 lastSream = pSimulationMessage->mStream;
497 lastType = type;
498 /* write the child messages */
499 foreach (SimulationMessage* pSimulationMessage, pSimulationMessage->mChildren)for (auto _container_ = QtPrivate::qMakeForeachContainer(pSimulationMessage
->mChildren); _container_.control && _container_.i
!= _container_.e; ++_container_.i, _container_.control ^= 1)
for (SimulationMessage* pSimulationMessage = *_container_.i;
_container_.control; _container_.control = 0)
{
500 writeSimulationMessage(pSimulationMessage);
501 }
502}
503
504/*!
505 * \brief SimulationOutputWidget::embeddedServerInitialized
506 * Calls a function for creating an OpcUaClient object.
507 */
508void SimulationOutputWidget::embeddedServerInitialized()
509{
510 MainWindow::instance()->getSimulationDialog()->createOpcUaClient(mSimulationOptions);
511}
512
513/*!
514 * \brief SimulationOutputWidget::deleteIntermediateCompilationFiles
515 * Deletes the intermediate compilation files
516 */
517void SimulationOutputWidget::deleteIntermediateCompilationFiles()
518{
519 if (OptionsDialog::instance()->getSimulationPage()->getDeleteIntermediateCompilationFilesCheckBox()->isChecked()) {
520 QString workingDirectory = mSimulationOptions.getWorkingDirectory();
521 QString outputFile = mSimulationOptions.getOutputFileName();
522 foreach (QString fileName, mGeneratedFilesList)for (auto _container_ = QtPrivate::qMakeForeachContainer(mGeneratedFilesList
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (QString fileName
= *_container_.i; _container_.control; _container_.control =
0)
{
523 if (QFile::exists(QString("%1/%2").arg(workingDirectory, QString(fileName).arg(outputFile)))) {
524 QFile::remove(QString("%1/%2").arg(workingDirectory, QString(fileName).arg(outputFile)));
525 }
526 }
527 // Delete the Algloop*.cpp/h files generated by cpp runtime
528 if (mSimulationOptions.getTargetLanguage().compare("Cpp") == 0) {
529 QStringList filesList = QDir(workingDirectory).entryList(mGeneratedAlgLoopFilesList, QDir::Files | QDir::NoSymLinks |
530 QDir::NoDotAndDotDot | QDir::Writable | QDir::CaseSensitive);
531 foreach (QString fileName, filesList)for (auto _container_ = QtPrivate::qMakeForeachContainer(filesList
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (QString fileName
= *_container_.i; _container_.control; _container_.control =
0)
{
532 if (QFile::exists(QString("%1/%2").arg(workingDirectory, fileName))) {
533 QFile::remove(QString("%1/%2").arg(workingDirectory, fileName));
534 }
535 }
536 }
537 }
538}
539
540/*!
541 * \brief SimulationOutputWidget::createSimulationProgressSocket
542 * Slot activated when QTcpServer newConnection SIGNAL is raised.\n
543 * Accepts the incoming connection and connects to readyRead SIGNAL of QTcpSocket.
544 */
545void SimulationOutputWidget::createSimulationProgressSocket()
546{
547 if (sender()) {
548 QTcpServer *pTcpServer = qobject_cast<QTcpServer*>(const_cast<QObject*>(sender()));
549 if (pTcpServer && pTcpServer->hasPendingConnections()) {
550 QTcpSocket *pTcpSocket = pTcpServer->nextPendingConnection();
551 mSocketDisconnected = false;
552 connect(pTcpSocket, SIGNAL(readyRead())"2""readyRead()", SLOT(readSimulationProgress())"1""readSimulationProgress()");
553 connect(pTcpSocket, SIGNAL(disconnected())"2""disconnected()", SLOT(socketDisconnected())"1""socketDisconnected()");
554 disconnect(pTcpServer, SIGNAL(newConnection())"2""newConnection()", this, SLOT(createSimulationProgressSocket())"1""createSimulationProgressSocket()");
555 }
556 }
557}
558
559/*!
560 * \brief SimulationProcessThread::readSimulationProgress
561 * Slot activated when QTcpSocket readyRead or disconnected SIGNAL is raised.\n
562 * Sends the recieved data to xml parser.
563 */
564void SimulationOutputWidget::readSimulationProgress()
565{
566 if (sender()) {
567 QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(const_cast<QObject*>(sender()));
568 if (pTcpSocket) {
569 QString output = QString(pTcpSocket->readAll());
570 if (!output.isEmpty()) {
571 writeSimulationOutput(output, StringHandler::Unknown, false);
572 }
573 }
574 }
575}
576
577/*!
578 * \brief SimulationOutputWidget::socketDisconnected
579 * Slot activated when QTcpSocket disconnected SIGNAL is raised.\n
580 * Writes the exit status and exit code of the simulation process.
581 */
582void SimulationOutputWidget::socketDisconnected()
583{
584 mSocketDisconnected = true;
585}
586
587/*!
588 * \brief SimulationOutputWidget::compilationProcessStarted
589 * Slot activated when SimulationProcessThread sendCompilationStarted signal is raised.\n
590 * Updates the progress label, bar and button controls.
591 */
592void SimulationOutputWidget::compilationProcessStarted()
593{
594 mpProgressLabel->setText(tr("Compiling %1. Please wait for a while.").arg(mSimulationOptions.getClassName()));
595 mpProgressBar->setRange(0, 0);
596 mpProgressBar->setTextVisible(false);
597 mpCancelButton->setText(tr("Cancel Compilation"));
598 mpCancelButton->setEnabled(true);
599}
600
601/*!
602 * \brief SimulationOutputWidget::writeCompilationOutput
603 * Slot activated when SimulationProcessThread sendCompilationStandardOutput signal is raised.\n
604 * Writes the compilation standard output to the compilation output text box.
605 * \param output
606 * \param color
607 */
608void SimulationOutputWidget::writeCompilationOutput(QString output, QColor color)
609{
610 mpGeneratedFilesTabWidget->setTabEnabled(1, true);
611 QTextCharFormat format;
612 format.setForeground(color);
613 Utilities::insertText(mpCompilationOutputTextBox, output, format);
614 /* make the compilation tab the current one */
615 mpGeneratedFilesTabWidget->setCurrentIndex(1);
616}
617
618/*!
619 * \brief SimulationOutputWidget::compilationProcessFinished
620 * Slot activated when SimulationProcessThread sendCompilationFinished signal is raised.\n
621 * Calls the Transformational Debugger or Algorithmic Debugger depending on the user selections.
622 * \param exitCode
623 * \param exitStatus
624 */
625void SimulationOutputWidget::compilationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
626{
627 mpProgressLabel->setText(tr("Compilation of %1 is finished.").arg(mSimulationOptions.getClassName()));
628 mpProgressBar->setRange(0, 1);
629 mpProgressBar->setValue(1);
630 mpCancelButton->setEnabled(false);
631 if (exitStatus == QProcess::NormalExit && exitCode == 0) {
632 if (mSimulationOptions.getBuildOnly() &&
633 (OptionsDialog::instance()->getDebuggerPage()->getAlwaysShowTransformationsCheckBox()->isChecked() ||
634 mSimulationOptions.getLaunchTransformationalDebugger() || mSimulationOptions.getProfiling() != "none")) {
635 MainWindow::instance()->showTransformationsWidget(mSimulationOptions.getWorkingDirectory() + "/" + mSimulationOptions.getOutputFileName() + "_info.json");
636 }
637 MainWindow::instance()->getSimulationDialog()->showAlgorithmicDebugger(mSimulationOptions);
638 }
639 mpArchivedSimulationItem->setStatus(Helper::finished);
640 // remove the generated files
641 if (mSimulationOptions.getBuildOnly()) {
642 deleteIntermediateCompilationFiles();
643 }
644}
645
646/*!
647 * \brief SimulationOutputWidget::simulationProcessStarted
648 * Slot activated when SimulationProcessThread sendSimulationStarted signal is raised.\n
649 * Updates the progress label, bar and button controls.
650 */
651void SimulationOutputWidget::simulationProcessStarted()
652{
653 if (mSimulationOptions.isInteractiveSimulation()) {
654 mpProgressLabel->setText(tr("Running interactive simulation of %1.").arg(mSimulationOptions.getClassName()));
655 } else {
656 mpProgressLabel->setText(tr("Running simulation of %1. Please wait for a while.").arg(mSimulationOptions.getClassName()));
657 }
658 mpProgressBar->setRange(0, 100);
659 mpProgressBar->setTextVisible(true);
660 mpCancelButton->setText(Helper::cancelSimulation);
661 mpCancelButton->setEnabled(true);
662 mpOpenOutputFileButton->setEnabled(true);
663 // save the current datetime as last modified datetime for result file.
664 mResultFileLastModifiedDateTime = QDateTime::currentDateTime();
665 mpArchivedSimulationItem->setStatus(Helper::running);
666}
667
668/*!
669 * \brief SimulationOutputWidget::writeSimulationOutput
670 * Slot activated when SimulationProcessThread sendSimulationOutput signal is raised.\n
671 * Writes the simulation standard output to the simulation output text box.
672 * \param output
673 * \param type
674 * \param textFormat
675 */
676void SimulationOutputWidget::writeSimulationOutput(QString output, StringHandler::SimulationMessageType type, bool textFormat)
677{
678 mpGeneratedFilesTabWidget->setTabEnabled(0, true);
679
680 if (textFormat) {
681#if (QT_VERSION((5<<16)|(9<<8)|(5)) >= QT_VERSION_CHECK(5, 0, 0)((5<<16)|(0<<8)|(0)))
682 QString escaped = QString(output).toHtmlEscaped();
683#else /* Qt4 */
684 QString escaped = Qt::escape(output);
685#endif
686 output = QString("<message stream=\"stdout\" type=\"%1\" text=\"%2\" />")
687 .arg(StringHandler::getSimulationMessageTypeString(type))
688 .arg(escaped);
689 }
690
691 if (!mpSimulationOutputHandler) {
692 mpSimulationOutputHandler = new SimulationOutputHandler(this, output);
693 if (isOutputStructured()) {
694 mpSimulationOutputTree->setModel(mpSimulationOutputHandler->getSimulationMessageModel());
695 }
696 } else {
697 mpSimulationOutputHandler->parseSimulationOutput(output);
698 }
699 /* make the compilation tab the current one */
700 mpGeneratedFilesTabWidget->setCurrentIndex(0);
701}
702
703/*!
704 * \brief SimulationOutputWidget::simulationProcessFinished
705 * Slot activated when SimulationProcessThread sendSimulationFinished signal is raised.\n
706 * Reads the result variables, populates the variables browser and shows the plotting view.
707 * \param exitCode
708 * \param exitStatus
709 */
710void SimulationOutputWidget::simulationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
711{
712 Q_UNUSED(exitCode)(void)exitCode;;
713 Q_UNUSED(exitStatus)(void)exitStatus;;
714 mpProgressLabel->setText(tr("Simulation of %1 is finished.").arg(mSimulationOptions.getClassName()));
715 mpProgressBar->setValue(mpProgressBar->maximum());
716 mpCancelButton->setEnabled(false);
717 MainWindow::instance()->getSimulationDialog()->simulationProcessFinished(mSimulationOptions, mResultFileLastModifiedDateTime);
718 mpArchivedSimulationItem->setStatus(Helper::finished);
719 if (mpSimulationOutputHandler) {
720 mpSimulationOutputHandler->simulationProcessFinished();
721 }
722 // remove the generated files
723 if (!mSimulationOptions.getBuildOnly()) {
724 deleteIntermediateCompilationFiles();
725 }
726}
727
728/*!
729 * \brief SimulationOutputWidget::cancelCompilationOrSimulation
730 * Slot activated when mpCancelButton clicked signal is raised.\n
731 * Cancels a running compilaiton/simulation by killing the compilation/simulation process.
732 */
733void SimulationOutputWidget::cancelCompilationOrSimulation()
734{
735 if (mpSimulationProcessThread->isCompilationProcessRunning()) {
736 mpSimulationProcessThread->setCompilationProcessKilled(true);
737 mpSimulationProcessThread->getCompilationProcess()->kill();
738 mpProgressLabel->setText(tr("Compilation of %1 is cancelled.").arg(mSimulationOptions.getClassName()));
739 mpProgressBar->setRange(0, 1);
740 mpProgressBar->setValue(1);
741 mpCancelButton->setEnabled(false);
742 mpArchivedSimulationItem->setStatus(Helper::finished);
743 } else if (mpSimulationProcessThread->isSimulationProcessRunning()) {
744 mpSimulationProcessThread->setSimulationProcessKilled(true);
745 mpSimulationProcessThread->getSimulationProcess()->kill();
746 mpProgressLabel->setText(tr("Simulation of %1 is cancelled.").arg(mSimulationOptions.getClassName()));
747 mpProgressBar->setValue(mpProgressBar->maximum());
748 mpCancelButton->setEnabled(false);
749 mpArchivedSimulationItem->setStatus(Helper::finished);
750 }
751}
752
753/*!
754 * \brief SimulationOutputWidget::openTransformationalDebugger
755 * Slot activated when mpOpenTransformationalDebuggerButton clicked SIGNAL is raised.\n
756 * Opens the transformational debugger.
757 */
758void SimulationOutputWidget::openTransformationalDebugger()
759{
760 QString fileName = QString("%1/%2_info.json").arg(mSimulationOptions.getWorkingDirectory(), mSimulationOptions.getOutputFileName());
761 /* open the model_info.json file */
762 if (QFileInfo(fileName).exists()) {
763 MainWindow::instance()->showTransformationsWidget(fileName);
764 } else {
765 QMessageBox::critical(this, QString("%1 - %2").arg(Helper::applicationName, Helper::error),
766 GUIMessages::getMessage(GUIMessages::FILE_NOT_FOUND).arg(fileName), Helper::ok);
767 }
768}
769
770/*!
771 * \brief SimulationOutputWidget::openSimulationLogFile
772 * Slot activated when mpOpenOutputFileButton clicked SIGNAL is raised.\n
773 * Opens the simulation log file.
774 */
775void SimulationOutputWidget::openSimulationLogFile()
776{
777 QUrl logFile (QString("file:///%1/%2.log").arg(mSimulationOptions.getWorkingDirectory(), mSimulationOptions.getClassName()));
778 if (!QDesktopServices::openUrl(logFile)) {
779 QMessageBox::critical(this, QString("%1 - %2").arg(Helper::applicationName, Helper::error),
780 GUIMessages::getMessage(GUIMessages::UNABLE_TO_OPEN_FILE).arg(logFile.toString()), Helper::ok);
781 }
782}
783
784/*!
785 * \brief SimulationOutputWidget::openTransformationBrowser
786 * Slot activated when a link is clicked from simulation output.\n
787 * Parses the url and loads the TransformationsWidget with the used equation.
788 * \param url - the url that is clicked
789 */
790/*
791 * <a href="omedittransformationsbrowser://model_info.json?index=4></a>"
792 */
793void SimulationOutputWidget::openTransformationBrowser(QUrl url)
794{
795 if (url.scheme().compare("omedittransformationsbrowser") == 0) {
796 /* read the file name */
797 QString fileName = url.path();
798#ifdef WIN32
799 if (fileName.startsWith("/")) fileName.remove(0, 1);
800#endif
801 /* open the model_info.json file */
802 if (QFileInfo(fileName).exists()) {
803 TransformationsWidget *pTransformationsWidget = MainWindow::instance()->showTransformationsWidget(fileName);
804#if (QT_VERSION((5<<16)|(9<<8)|(5)) >= QT_VERSION_CHECK(5, 0, 0)((5<<16)|(0<<8)|(0)))
805 QUrlQuery query(url);
806 int equationIndex = query.queryItemValue("index").toInt();
807#else /* Qt4 */
808 int equationIndex = url.queryItemValue("index").toInt();
809#endif
810 QTreeWidgetItem *pTreeWidgetItem = pTransformationsWidget->findEquationTreeItem(equationIndex);
811 if (pTreeWidgetItem) {
812 pTransformationsWidget->getEquationsTreeWidget()->clearSelection();
813 pTransformationsWidget->getEquationsTreeWidget()->setCurrentItem(pTreeWidgetItem);
814 }
815 pTransformationsWidget->fetchEquationData(equationIndex);
816 } else {
817 QMessageBox::critical(this, QString("%1 - %2").arg(Helper::applicationName, Helper::error), QString("%1<br />%2")
818 .arg(GUIMessages::getMessage(GUIMessages::FILE_NOT_FOUND).arg(fileName))
819 .arg(tr("Url is <b>%1</b>").arg(url.toString())), Helper::ok);
820 }
821 } else if (url.scheme().compare("file") == 0) {
822 // we know that file link is always simulation log file.
823 openSimulationLogFile();
824 } else {
825 /* TODO: Write error-message?! */
826 }
827}
828
829/*!
830 * \brief SimulationOutputWidget::keyPressEvent
831 * Closes the widget when Esc key is pressed.
832 * \param event
833 */
834void SimulationOutputWidget::keyPressEvent(QKeyEvent *event)
835{
836 if (event->key() == Qt::Key_Escape) {
837 close();
838 return;
839 }
840 QWidget::keyPressEvent(event);
841}