diff --git a/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.cpp b/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.cpp new file mode 100644 index 00000000000..bd9fb388ce1 --- /dev/null +++ b/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.cpp @@ -0,0 +1,566 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE + * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Volker Waurich + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include <../../osgQt/OMEdit_GraphicsWindowQt.h> + +#include "AbstractAnimationWindow.h" +#include "Modeling/MessagesWidget.h" +#include "Options/OptionsDialog.h" +#include "Modeling/MessagesWidget.h" +#include "Plotting/PlotWindowContainer.h" +#include "Visualizer.h" +#include "VisualizerMAT.h" +#include "VisualizerCSV.h" + +/*! + * \class AbstractAnimationWindow + * \brief Abstract animation class defines a QMainWindow for animation. + */ +/*! + * \brief AbstractAnimationWindow::AbstractAnimationWindow + * \param pParent + */ +AbstractAnimationWindow::AbstractAnimationWindow(QWidget *pParent) + : QMainWindow(pParent), + osgViewer::CompositeViewer(), + mPathName(""), + mFileName(""), + mpSceneView(new osgViewer::View()), + mpVisualizer(nullptr), + mpViewerWidget(nullptr), + mpAnimationToolBar(new QToolBar(QString("Animation Toolbar"),this)), + mpAnimationChooseFileAction(nullptr), + mpAnimationInitializeAction(nullptr), + mpAnimationPlayAction(nullptr), + mpAnimationPauseAction(nullptr), + mpAnimationSlider(nullptr), + mpAnimationTimeLabel(nullptr), + mpTimeTextBox(nullptr), + mpAnimationSpeedLabel(nullptr), + mpSpeedComboBox(nullptr), + mpPerspectiveDropDownBox(nullptr), + mpRotateCameraLeftAction(nullptr), + mpRotateCameraRightAction(nullptr) +{ + // to distinguish this widget as a subwindow among the plotwindows + this->setObjectName(QString("animationWidget")); + // the osg threading model + setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); + //the viewer widget + mpViewerWidget = setupViewWidget(); + // we need to set the minimum height so that visualization window is still shown when we cascade windows. + mpViewerWidget->setMinimumHeight(100); + // let render timer do a render frame at every tick + mRenderFrameTimer.setInterval(100); + QObject::connect(&mRenderFrameTimer, SIGNAL(timeout()), this, SLOT(renderFrame())); + mRenderFrameTimer.start(); + // toolbar icon size + int toolbarIconSize = OptionsDialog::instance()->getGeneralSettingsPage()->getToolbarIconSizeSpinBox()->value(); + mpAnimationToolBar->setIconSize(QSize(toolbarIconSize, toolbarIconSize)); + addToolBar(Qt::TopToolBarArea, mpAnimationToolBar); + // Viewer layout + QGridLayout *pGridLayout = new QGridLayout; + pGridLayout->setContentsMargins(0, 0, 0, 0); + pGridLayout->addWidget(mpViewerWidget); + // add the viewer to the frame for boxed rectangle around it. + QFrame *pCentralWidgetFrame = new QFrame; + pCentralWidgetFrame->setFrameStyle(QFrame::StyledPanel); + pCentralWidgetFrame->setLayout(pGridLayout); + setCentralWidget(pCentralWidgetFrame); +} + +/*! + * \brief AbstractAnimationWindow::openAnimationFile + * \param fileName + */ +void AbstractAnimationWindow::openAnimationFile(QString fileName) +{ + std::string file = fileName.toStdString(); + if (file.compare("")) { + std::size_t pos = file.find_last_of("/\\"); + mPathName = file.substr(0, pos + 1); + mFileName = file.substr(pos + 1, file.length()); + //std::cout<<"file "<setEnabled(true); + mpAnimationPlayAction->setEnabled(true); + mpAnimationPauseAction->setEnabled(true); + mpAnimationSlider->setEnabled(true); + bool state = mpAnimationSlider->blockSignals(true); + mpAnimationSlider->setValue(0); + mpAnimationSlider->blockSignals(state); + mpSpeedComboBox->setEnabled(true); + mpTimeTextBox->setEnabled(true); + mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getStartTime())); + /* Only use isometric view as default for csv file type. + * Otherwise use side view as default which suits better for Modelica models. + */ + if (isCSV(mFileName)) { + mpPerspectiveDropDownBox->setCurrentIndex(0); + cameraPositionIsometric(); + } else { + mpPerspectiveDropDownBox->setCurrentIndex(1); + cameraPositionSide(); + } + } + } +} + +void AbstractAnimationWindow::createActions() +{ + // perspective drop down + mpPerspectiveDropDownBox = new QComboBox(this); + mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective0.svg"), QString("Isometric")); + mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective1.svg"),QString("Side")); + mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective2.svg"),QString("Front")); + mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective3.svg"),QString("Top")); + connect(mpPerspectiveDropDownBox, SIGNAL(activated(int)), this, SLOT(setPerspective(int))); + // rotate camera left action + mpRotateCameraLeftAction = new QAction(QIcon(":/Resources/icons/rotateCameraLeft.svg"), tr("Rotate Left"), this); + mpRotateCameraLeftAction->setStatusTip(tr("Rotates the camera left")); + connect(mpRotateCameraLeftAction, SIGNAL(triggered()), this, SLOT(rotateCameraLeft())); + // rotate camera right action + mpRotateCameraRightAction = new QAction(QIcon(":/Resources/icons/rotateCameraRight.svg"), tr("Rotate Right"), this); + mpRotateCameraRightAction->setStatusTip(tr("Rotates the camera right")); + connect(mpRotateCameraRightAction, SIGNAL(triggered()), this, SLOT(rotateCameraRight())); +} + +/*! + * \brief AbstractAnimationWindow::setupViewWidget + * creates the widget for the osg viewer + * \return the widget + */ +QWidget* AbstractAnimationWindow::setupViewWidget() +{ + //desktop resolution + QRect rec = QApplication::desktop()->screenGeometry(); + int height = rec.height(); + int width = rec.width(); + //int height = 1000; + //int width = 2000; + //get context + osg::ref_ptr ds = osg::DisplaySettings::instance().get(); + osg::ref_ptr traits = new osg::GraphicsContext::Traits(); + traits->windowName = ""; + traits->windowDecoration = false; + traits->x = 0; + traits->y = 0; + traits->width = width; + traits->height = height; + traits->doubleBuffer = true; + traits->alpha = ds->getMinimumNumAlphaBits(); + traits->stencil = ds->getMinimumNumStencilBits(); + traits->sampleBuffers = ds->getMultiSamples(); + traits->samples = ds->getNumMultiSamples(); + osg::ref_ptr gw = new osgQt::GraphicsWindowQt(traits.get()); + //add a scene to viewer + addView(mpSceneView); + //get the viewer widget + osg::ref_ptr camera = mpSceneView->getCamera(); + camera->setGraphicsContext(gw); + camera->setClearColor(osg::Vec4(0.95, 0.95, 0.95, 1.0)); + //camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); + camera->setViewport(new osg::Viewport(0, 0, width, height)); + camera->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width/2) / static_cast(traits->height/2), 1.0f, 10000.0f); + mpSceneView->addEventHandler(new osgViewer::StatsHandler()); + // reverse the mouse wheel zooming + osgGA::MultiTouchTrackballManipulator *pMultiTouchTrackballManipulator = new osgGA::MultiTouchTrackballManipulator(); + pMultiTouchTrackballManipulator->setWheelZoomFactor(-pMultiTouchTrackballManipulator->getWheelZoomFactor()); + mpSceneView->setCameraManipulator(pMultiTouchTrackballManipulator); +#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) + gw->setTouchEventsEnabled(true); +#endif + return gw->getGLWidget(); +} + +/*! + * \brief AbstractAnimationWindow::loadVisualization + * loads the data and the xml scene description + * \return + */ +bool AbstractAnimationWindow::loadVisualization() +{ + VisType visType = VisType::NONE; + // Get visualization type. + if (isFMU(mFileName)) { + visType = VisType::FMU; + } else if (isMAT(mFileName)) { + visType = VisType::MAT; + } else if (isCSV(mFileName)) { + visType = VisType::CSV; + } else { + MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, tr("Unknown visualization type."), + Helper::scriptingKind, Helper::errorLevel)); + return false; + } + //load the XML File, build osgTree, get initial values for the shapes + bool xmlExists = checkForXMLFile(mFileName, mPathName); + if (!xmlExists) { + QString msg = tr("Could not find the visual XML file %1.").arg(QString(assembleXMLFileName(mFileName, mPathName).c_str())); + MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, msg, Helper::scriptingKind, + Helper::errorLevel)); + return false; + } else { + //init visualizer + if (visType == VisType::MAT) { + mpVisualizer = new VisualizerMAT(mFileName, mPathName); + } else if (visType == VisType::CSV) { + mpVisualizer = new VisualizerCSV(mFileName, mPathName); + } else if (visType == VisType::FMU) { + mpVisualizer = new VisualizerFMU(mFileName, mPathName); + } else { + QString msg = tr("Could not init %1 %2.").arg(QString(mPathName.c_str())).arg(QString(mFileName.c_str())); + MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, msg, Helper::scriptingKind, + Helper::errorLevel)); + return false; + } + connect(mpVisualizer->getTimeManager()->getUpdateSceneTimer(), SIGNAL(timeout()), SLOT(updateScene())); + mpVisualizer->initData(); + mpVisualizer->setUpScene(); + mpVisualizer->initVisualization(); + //add scene for the chosen visualization + mpSceneView->setSceneData(mpVisualizer->getOMVisScene()->getScene().getRootNode()); + } + //add window title + this->setWindowTitle(QString::fromStdString(mFileName)); + //open settings dialog for FMU simulation + if (visType == VisType::FMU) { + openFMUSettingsDialog(dynamic_cast(mpVisualizer)); + } + return true; +} + +/*! + * \brief AbstractAnimationWindow::resetCamera + * resets the camera position + */ +void AbstractAnimationWindow::resetCamera() +{ + mpSceneView->home(); +} + +/*! + * \brief AbstractAnimationWindow::cameraPositionIsometric + * sets the camera position to isometric view + */ +void AbstractAnimationWindow::cameraPositionIsometric() +{ + double d = computeDistanceToOrigin(); + osg::Matrixd mat = osg::Matrixd(0.7071, 0, -0.7071, 0, + -0.409, 0.816, -0.409, 0, + 0.57735, 0.57735, 0.57735, 0, + 0.57735*d, 0.57735*d, 0.57735*d, 1); + mpSceneView->getCameraManipulator()->setByMatrix(mat); +} + +/*! + * \brief AbstractAnimationWindow::cameraPositionSide + * sets the camera position to Side + */ +void AbstractAnimationWindow::cameraPositionSide() +{ + double d = computeDistanceToOrigin(); + osg::Matrixd mat = osg::Matrixd(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, d, 1); + mpSceneView->getCameraManipulator()->setByMatrix(mat); +} + +/*! + * \brief AbstractAnimationWindow::cameraPositionFront + * sets the camera position to Front + */ +void AbstractAnimationWindow::cameraPositionFront() +{ + double d = computeDistanceToOrigin(); + osg::Matrixd mat = osg::Matrixd(0, 0, 1, 0, + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, d, 0, 1); + mpSceneView->getCameraManipulator()->setByMatrix(mat); +} + +/*! + * \brief AbstractAnimationWindow::cameraPositionTop + * sets the camera position to Top + */ +void AbstractAnimationWindow::cameraPositionTop() +{ + double d = computeDistanceToOrigin(); + osg::Matrixd mat = osg::Matrixd( 0, 0,-1, 0, + 0, 1, 0, 0, + 1, 0, 0, 0, + d, 0, 0, 1); + mpSceneView->getCameraManipulator()->setByMatrix(mat); +} + +/*! + * \brief AbstractAnimationWindow::computeDistanceToOrigin + * computes distance to origin using pythagoras theorem + */ +double AbstractAnimationWindow::computeDistanceToOrigin() +{ + osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); + osg::Matrixd mat = manipulator->getMatrix(); + //assemble + + //Compute distance to center using pythagoras theorem + double d = sqrt(abs(mat(3,0))*abs(mat(3,0))+ + abs(mat(3,1))*abs(mat(3,1))+ + abs(mat(3,2))*abs(mat(3,2))); + + //If d is very small (~0), set it to 1 as default + if(d < 1e-10) { + d=1; + } + + return d; +} + +/*! + * \brief AbstractAnimationWindow::openFMUSettingsDialog + * Opens a dialog to set the settings for the FMU visualization + * \param pVisualizerFMU + */ +void AbstractAnimationWindow::openFMUSettingsDialog(VisualizerFMU* pVisualizerFMU) +{ + FMUSettingsDialog *pFMUSettingsDialog = new FMUSettingsDialog(this, pVisualizerFMU); + pFMUSettingsDialog->exec(); +} + +/*! + * \brief AbstractAnimationWindow::renderFrame + * renders the osg viewer + */ +void AbstractAnimationWindow::renderFrame() +{ + frame(); +} + +/*! + * \brief AbstractAnimationWindow::updateSceneFunction + * updates the visualization objects + */ +void AbstractAnimationWindow::updateScene() +{ + if (!(mpVisualizer == NULL)) { + //set time label + if (!mpVisualizer->getTimeManager()->isPaused()) { + mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); + // set time slider + if (mpVisualizer->getVisType() != VisType::FMU) { + int time = mpVisualizer->getTimeManager()->getTimeFraction(); + bool state = mpAnimationSlider->blockSignals(true); + mpAnimationSlider->setValue(time); + mpAnimationSlider->blockSignals(state); + } + } + //update the scene + mpVisualizer->sceneUpdate(); + } +} + +/*! + * \brief AbstractAnimationWindow::animationFileSlotFunction + * opens a file dialog to chooes an animation + */ +void AbstractAnimationWindow::chooseAnimationFileSlotFunction() +{ + QString fileName = StringHandler::getOpenFileName(this, QString("%1 - %2").arg(Helper::applicationName).arg(Helper::chooseFile), + NULL, Helper::visualizationFileTypes, NULL); + if (fileName.isEmpty()) { + return; + } + openAnimationFile(fileName); +} + +/*! + * \brief AbstractAnimationWindow::initSlotFunction + * slot function for the init button + */ +void AbstractAnimationWindow::initSlotFunction() +{ + mpVisualizer->initVisualization(); + bool state = mpAnimationSlider->blockSignals(true); + mpAnimationSlider->setValue(0); + mpAnimationSlider->blockSignals(state); + mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); +} + +/*! + * \brief AbstractAnimationWindow::playSlotFunction + * slot function for the play button + */ +void AbstractAnimationWindow::playSlotFunction() +{ + mpVisualizer->getTimeManager()->setPause(false); +} + +/*! + * \brief AbstractAnimationWindow::pauseSlotFunction + * slot function for the pause button + */ +void AbstractAnimationWindow::pauseSlotFunction() +{ + mpVisualizer->getTimeManager()->setPause(true); +} + +/*! + * \brief AbstractAnimationWindow::sliderSetTimeSlotFunction + * slot function for the time slider to jump to the adjusted point of time + */ +void AbstractAnimationWindow::sliderSetTimeSlotFunction(int value) +{ + float time = (mpVisualizer->getTimeManager()->getEndTime() + - mpVisualizer->getTimeManager()->getStartTime()) + * (float) (value / 100.0); + mpVisualizer->getTimeManager()->setVisTime(time); + mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); + mpVisualizer->updateScene(time); +} + +/*! + * \brief AbstractAnimationWindow::jumpToTimeSlotFunction + * slot function to jump to the user input point of time + */ +void AbstractAnimationWindow::jumpToTimeSlotFunction() +{ + QString str = mpTimeTextBox->text(); + bool isFloat = true; + double start = mpVisualizer->getTimeManager()->getStartTime(); + double end = mpVisualizer->getTimeManager()->getEndTime(); + double value = str.toFloat(&isFloat); + if (isFloat && value >= 0.0) { + if (value < start) { + value = start; + } else if (value > end) { + value = end; + } + mpVisualizer->getTimeManager()->setVisTime(value); + bool state = mpAnimationSlider->blockSignals(true); + mpAnimationSlider->setValue(mpVisualizer->getTimeManager()->getTimeFraction()); + mpAnimationSlider->blockSignals(state); + mpVisualizer->updateScene(value); + } +} + +/*! + * \brief AbstractAnimationWindow::setSpeedUpSlotFunction + * slot function to set the user input speed up + */ +void AbstractAnimationWindow::setSpeedSlotFunction() +{ + QString str = mpSpeedComboBox->lineEdit()->text(); + bool isFloat = true; + double value = str.toFloat(&isFloat); + if (isFloat && value > 0.0) { + mpVisualizer->getTimeManager()->setSpeedUp(value); + } +} + +/*! + * \brief AbstractAnimationWindow::setPerspective + * gets the identifier for the chosen perspective and calls the functions + */ +void AbstractAnimationWindow::setPerspective(int value) +{ + switch(value) { + case 0: + cameraPositionIsometric(); + break; + case 1: + cameraPositionSide(); + break; + case 2: + cameraPositionTop(); + break; + case 3: + cameraPositionFront(); + break; + } +} + +/*! + * \brief AbstractAnimationWindow::rotateCameraLeft + * rotates the camera 90 degress left about the line of sight + */ +void AbstractAnimationWindow::rotateCameraLeft() +{ + osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); + osg::Matrixd mat = manipulator->getMatrix(); + osg::Camera *pCamera = mpSceneView->getCamera(); + + osg::Vec3d eye, center, up; + pCamera->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d rotationAxis = center-eye; + + osg::Matrixd rotMatrix; + rotMatrix.makeRotate(3.1415/2.0, rotationAxis); + + mpSceneView->getCameraManipulator()->setByMatrix(mat*rotMatrix); +} + +/*! + * \brief AbstractAnimationWindow::rotateCameraRight + * rotates the camera 90 degress right about the line of sight + */ +void AbstractAnimationWindow::rotateCameraRight() +{ + osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); + osg::Matrixd mat = manipulator->getMatrix(); + osg::Camera *pCamera = mpSceneView->getCamera(); + + osg::Vec3d eye, center, up; + pCamera->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d rotationAxis = center-eye; + + osg::Matrixd rotMatrix; + rotMatrix.makeRotate(-3.1415/2.0, rotationAxis); + + mpSceneView->getCameraManipulator()->setByMatrix(mat*rotMatrix); +} + + diff --git a/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.h b/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.h new file mode 100644 index 00000000000..af4072e08ae --- /dev/null +++ b/OMEdit/OMEditGUI/Animation/AbstractAnimationWindow.h @@ -0,0 +1,110 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE + * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Volker Waurich + */ + +#ifndef ABSTRACTANIMATIONWINDOW_H +#define ABSTRACTANIMATIONWINDOW_H + +#include + +#include +#include +#include +#include +#include +#include + +#include "FMUSettingsDialog.h" + +class VisualizerAbstract; +class Label; + +class AbstractAnimationWindow : public QMainWindow, public osgViewer::CompositeViewer +{ + Q_OBJECT +public: + AbstractAnimationWindow(QWidget *pParent); + void stopRenderFrameTimer() {mRenderFrameTimer.stop();} + void startRenderFrameTimer() {mRenderFrameTimer.start();} + void openAnimationFile(QString fileName); + virtual void createActions(); +private: + QWidget* setupViewWidget(); + bool loadVisualization(); +protected: + //to be animated + std::string mPathName; + std::string mFileName; + //osg viewer scene + osgViewer::View* mpSceneView; + //stores the data for the shapes, time management, functionality for updating the values(mat/fmu) etc. + VisualizerAbstract* mpVisualizer; + //widgets + QWidget* mpViewerWidget; + QTimer mRenderFrameTimer; + QToolBar* mpAnimationToolBar; + QAction *mpAnimationChooseFileAction; + QAction *mpAnimationInitializeAction; + QAction *mpAnimationPlayAction; + QAction *mpAnimationPauseAction; + QSlider* mpAnimationSlider; + Label *mpAnimationTimeLabel; + QLineEdit *mpTimeTextBox; + Label *mpAnimationSpeedLabel; + QComboBox *mpSpeedComboBox; + QComboBox *mpPerspectiveDropDownBox; + QAction *mpRotateCameraLeftAction; + QAction *mpRotateCameraRightAction; + + void resetCamera(); + void cameraPositionIsometric(); + void cameraPositionSide(); + void cameraPositionFront(); + void cameraPositionTop(); + double computeDistanceToOrigin(); + void openFMUSettingsDialog(VisualizerFMU *pVisualizerFMU); +public slots: + void renderFrame(); + void updateScene(); + void chooseAnimationFileSlotFunction(); + void initSlotFunction(); + void playSlotFunction(); + void pauseSlotFunction(); + void sliderSetTimeSlotFunction(int value); + void jumpToTimeSlotFunction(); + void setSpeedSlotFunction(); + void setPerspective(int value); + void rotateCameraLeft(); + void rotateCameraRight(); +}; + +#endif // ABSTRACTANIMATIONWINDOW_H diff --git a/OMEdit/OMEditGUI/Animation/AnimationWindow.cpp b/OMEdit/OMEditGUI/Animation/AnimationWindow.cpp index 9a72f8a62f4..eb5e1ee94d7 100644 --- a/OMEdit/OMEditGUI/Animation/AnimationWindow.cpp +++ b/OMEdit/OMEditGUI/Animation/AnimationWindow.cpp @@ -33,14 +33,9 @@ */ #include "AnimationWindow.h" -#include "Modeling/MessagesWidget.h" #include "Options/OptionsDialog.h" -#include "Modeling/MessagesWidget.h" -#include "Plotting/PlotWindowContainer.h" #include "Visualizer.h" -#include "VisualizerMAT.h" -#include "VisualizerCSV.h" -#include "VisualizerFMU.h" +#include /*! * \class AnimationWindow @@ -48,56 +43,59 @@ */ /*! * \brief AnimationWindow::AnimationWindow - * \param pPlotWindowContainer + * \param pParent */ -AnimationWindow::AnimationWindow(PlotWindowContainer *pPlotWindowContainer) - : QMainWindow(pPlotWindowContainer), - osgViewer::CompositeViewer(), - mpPlotWindowContainer(pPlotWindowContainer), - mPathName(""), - mFileName(""), - mpSceneView(new osgViewer::View()), - mpVisualizer(nullptr), - mpViewerWidget(nullptr), - mpAnimationToolBar(new QToolBar(QString("Animation Toolbar"),this)), - mpFMUSettingsDialog(nullptr), - mpAnimationChooseFileAction(nullptr), - mpAnimationInitializeAction(nullptr), - mpAnimationPlayAction(nullptr), - mpAnimationPauseAction(nullptr) +AnimationWindow::AnimationWindow(QWidget *pParent) + : AbstractAnimationWindow(pParent) { - // to distinguish this widget as a subwindow among the plotwindows - this->setObjectName(QString("animationWidget")); - // the osg threading model - setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); - // disable the default setting of viewer.done() by pressing Escape. - setKeyEventSetsDone(0); - //the viewer widget - mpViewerWidget = setupViewWidget(); - // we need to set the minimum height so that visualization window is still shown when we cascade windows. - mpViewerWidget->setMinimumHeight(100); - // let render timer do a render frame at every tick - mRenderFrameTimer.setInterval(100); - QObject::connect(&mRenderFrameTimer, SIGNAL(timeout()), this, SLOT(renderFrame())); - mRenderFrameTimer.start(); + createActions(); +} + +/*! + * \brief AnimationWindow::~AnimationWindow + */ +AnimationWindow::~AnimationWindow() +{ + if (mpVisualizer) { + delete mpVisualizer; + } +} + +/*! + * \brief AnimationWindow::createActions + */ +void AnimationWindow::createActions() +{ + AbstractAnimationWindow::createActions(); // actions and widgets for the toolbar int toolbarIconSize = OptionsDialog::instance()->getGeneralSettingsPage()->getToolbarIconSizeSpinBox()->value(); + // choose file action mpAnimationChooseFileAction = new QAction(QIcon(":/Resources/icons/open.svg"), Helper::animationChooseFile, this); mpAnimationChooseFileAction->setStatusTip(Helper::animationChooseFileTip); + connect(mpAnimationChooseFileAction, SIGNAL(triggered()),this, SLOT(chooseAnimationFileSlotFunction())); + // initialize action mpAnimationInitializeAction = new QAction(QIcon(":/Resources/icons/initialize.svg"), Helper::animationInitialize, this); mpAnimationInitializeAction->setStatusTip(Helper::animationInitializeTip); mpAnimationInitializeAction->setEnabled(false); + connect(mpAnimationInitializeAction, SIGNAL(triggered()),this, SLOT(initSlotFunction())); + // animation play action mpAnimationPlayAction = new QAction(QIcon(":/Resources/icons/play_animation.svg"), Helper::animationPlay, this); mpAnimationPlayAction->setStatusTip(Helper::animationPlayTip); mpAnimationPlayAction->setEnabled(false); + connect(mpAnimationPlayAction, SIGNAL(triggered()),this, SLOT(playSlotFunction())); + // animation pause action mpAnimationPauseAction = new QAction(QIcon(":/Resources/icons/pause.svg"), Helper::animationPause, this); mpAnimationPauseAction->setStatusTip(Helper::animationPauseTip); mpAnimationPauseAction->setEnabled(false); + connect(mpAnimationPauseAction, SIGNAL(triggered()),this, SLOT(pauseSlotFunction())); + // animation slide mpAnimationSlider = new QSlider(Qt::Horizontal); mpAnimationSlider->setMinimum(0); mpAnimationSlider->setMaximum(100); mpAnimationSlider->setSliderPosition(0); mpAnimationSlider->setEnabled(false); + connect(mpAnimationSlider, SIGNAL(valueChanged(int)),this, SLOT(sliderSetTimeSlotFunction(int))); + // animation time QDoubleValidator *pDoubleValidator = new QDoubleValidator(this); pDoubleValidator->setBottom(0); mpAnimationTimeLabel = new Label; @@ -106,6 +104,8 @@ AnimationWindow::AnimationWindow(PlotWindowContainer *pPlotWindowContainer) mpTimeTextBox->setMaximumSize(QSize(toolbarIconSize*2, toolbarIconSize)); mpTimeTextBox->setEnabled(false); mpTimeTextBox->setValidator(pDoubleValidator); + connect(mpTimeTextBox, SIGNAL(returnPressed()),this, SLOT(jumpToTimeSlotFunction())); + // animation speed mpAnimationSpeedLabel = new Label; mpAnimationSpeedLabel->setText(tr("Speed:")); mpSpeedComboBox = new QComboBox(this); @@ -116,28 +116,8 @@ AnimationWindow::AnimationWindow(PlotWindowContainer *pPlotWindowContainer) mpSpeedComboBox->setEnabled(false); mpSpeedComboBox->setValidator(pDoubleValidator); mpSpeedComboBox->setCompleter(0); - mpPerspectiveDropDownBox = new QComboBox(this); - mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective0.svg"), QString("Isometric")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective1.svg"),QString("Left 1")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective2.svg"),QString("Left 2")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective3.svg"),QString("Right 1")); - mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective1.svg"),QString("Side")); - mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective2.svg"),QString("Front")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective6.svg"),QString("Front 2")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective7.svg"),QString("Front 3")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective8.svg"),QString("Back 1")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective9.svg"),QString("Back 2")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective10.svg"),QString("Back 3")); - mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective3.svg"),QString("Top")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective12.svg"),QString("Top 2")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective13.svg"),QString("Top 3")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective14.svg"),QString("Bottom 1")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective15.svg"),QString("Bottom 2")); -// mpPerspectiveDropDownBox->addItem(QIcon(":/Resources/icons/perspective16.svg"),QString("Bottom 3")); - mpRotateCameraLeftButton = new QToolButton(this); - mpRotateCameraLeftButton->setIcon(QIcon(":/Resources/icons/rotateCameraLeft.svg")); - mpRotateCameraRightButton = new QToolButton(this); - mpRotateCameraRightButton->setIcon(QIcon(":/Resources/icons/rotateCameraRight.svg")); + connect(mpSpeedComboBox, SIGNAL(currentIndexChanged(int)),this, SLOT(setSpeedSlotFunction())); + connect(mpSpeedComboBox->lineEdit(), SIGNAL(textChanged(QString)),this, SLOT(setSpeedSlotFunction())); //assemble the animation toolbar mpAnimationToolBar->addAction(mpAnimationChooseFileAction); mpAnimationToolBar->addSeparator(); @@ -156,535 +136,6 @@ AnimationWindow::AnimationWindow(PlotWindowContainer *pPlotWindowContainer) mpAnimationToolBar->addWidget(mpSpeedComboBox); mpAnimationToolBar->addSeparator(); mpAnimationToolBar->addWidget(mpPerspectiveDropDownBox); - mpAnimationToolBar->addWidget(mpRotateCameraLeftButton); - mpAnimationToolBar->addWidget(mpRotateCameraRightButton); - mpAnimationToolBar->setIconSize(QSize(toolbarIconSize, toolbarIconSize)); - addToolBar(Qt::TopToolBarArea,mpAnimationToolBar); - // Viewer layout - QGridLayout *pGridLayout = new QGridLayout; - pGridLayout->setContentsMargins(0, 0, 0, 0); - pGridLayout->addWidget(mpViewerWidget); - // add the viewer to the frame for boxed rectangle around it. - QFrame *pCentralWidgetFrame = new QFrame; - pCentralWidgetFrame->setFrameStyle(QFrame::StyledPanel); - pCentralWidgetFrame->setLayout(pGridLayout); - setCentralWidget(pCentralWidgetFrame); - //connections - connect(mpAnimationChooseFileAction, SIGNAL(triggered()),this, SLOT(chooseAnimationFileSlotFunction())); - connect(mpAnimationInitializeAction, SIGNAL(triggered()),this, SLOT(initSlotFunction())); - connect(mpAnimationPlayAction, SIGNAL(triggered()),this, SLOT(playSlotFunction())); - connect(mpAnimationPauseAction, SIGNAL(triggered()),this, SLOT(pauseSlotFunction())); - connect(mpPerspectiveDropDownBox, SIGNAL(activated(int)), this, SLOT(setPerspective(int))); - connect(mpRotateCameraLeftButton, SIGNAL(clicked()), this, SLOT(rotateCameraLeft())); - connect(mpRotateCameraRightButton, SIGNAL(clicked()), this, SLOT(rotateCameraRight())); - connect(mpAnimationSlider, SIGNAL(valueChanged(int)),this, SLOT(sliderSetTimeSlotFunction(int))); - connect(mpSpeedComboBox, SIGNAL(currentIndexChanged(int)),this, SLOT(setSpeedSlotFunction())); - connect(mpSpeedComboBox->lineEdit(), SIGNAL(textChanged(QString)),this, SLOT(setSpeedSlotFunction())); - connect(mpTimeTextBox, SIGNAL(returnPressed()),this, SLOT(jumpToTimeSlotFunction())); -} - -/*! - * \brief AnimationWindow::jumpToTimeSlotFunction - * slot function to jump to the user input point of time - */ -void AnimationWindow::jumpToTimeSlotFunction() -{ - QString str = mpTimeTextBox->text(); - bool isFloat = true; - double start = mpVisualizer->getTimeManager()->getStartTime(); - double end = mpVisualizer->getTimeManager()->getEndTime(); - double value = str.toFloat(&isFloat); - if (isFloat && value >= 0.0) { - if (value < start) { - value = start; - } else if (value > end) { - value = end; - } - mpVisualizer->getTimeManager()->setVisTime(value); - bool state = mpAnimationSlider->blockSignals(true); - mpAnimationSlider->setValue(mpVisualizer->getTimeManager()->getTimeFraction()); - mpAnimationSlider->blockSignals(state); - mpVisualizer->updateScene(value); - } -} - -/*! - * \brief AnimationWindow::setSpeedUpSlotFunction - * slot function to set the user input speed up - */ -void AnimationWindow::setSpeedSlotFunction() -{ - QString str = mpSpeedComboBox->lineEdit()->text(); - bool isFloat = true; - double value = str.toFloat(&isFloat); - if (isFloat && value > 0.0) { - mpVisualizer->getTimeManager()->setSpeedUp(value); - } -} - -AnimationWindow::~AnimationWindow() -{ - if (mpVisualizer) { - delete mpVisualizer; - } -} - -/*! - * \brief AnimationWindow::setupViewWidget - * creates the widget for the osg viewer - * \return the widget - */ -QWidget* AnimationWindow::setupViewWidget() -{ - //desktop resolution - QRect rec = QApplication::desktop()->screenGeometry(); - int height = rec.height(); - int width = rec.width(); - //int height = 1000; - //int width = 2000; - //get context - osg::ref_ptr ds = osg::DisplaySettings::instance().get(); - osg::ref_ptr traits = new osg::GraphicsContext::Traits(); - traits->windowName = ""; - traits->windowDecoration = false; - traits->x = 0; - traits->y = 0; - traits->width = width; - traits->height = height; - traits->doubleBuffer = true; - traits->alpha = ds->getMinimumNumAlphaBits(); - traits->stencil = ds->getMinimumNumStencilBits(); - traits->sampleBuffers = ds->getMultiSamples(); - traits->samples = ds->getNumMultiSamples(); - osg::ref_ptr gw = new osgQt::GraphicsWindowQt(traits.get()); - //add a scene to viewer - addView(mpSceneView); - //get the viewer widget - osg::ref_ptr camera = mpSceneView->getCamera(); - camera->setGraphicsContext(gw); - camera->setClearColor(osg::Vec4(0.95, 0.95, 0.95, 1.0)); - //camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); - camera->setViewport(new osg::Viewport(0, 0, width, height)); - camera->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width/2) / static_cast(traits->height/2), 1.0f, 10000.0f); - mpSceneView->addEventHandler(new osgViewer::StatsHandler()); - // reverse the mouse wheel zooming - osgGA::MultiTouchTrackballManipulator *pMultiTouchTrackballManipulator = new osgGA::MultiTouchTrackballManipulator(); - pMultiTouchTrackballManipulator->setWheelZoomFactor(-pMultiTouchTrackballManipulator->getWheelZoomFactor()); - mpSceneView->setCameraManipulator(pMultiTouchTrackballManipulator); -#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) - gw->setTouchEventsEnabled(true); -#endif - return gw->getGLWidget(); -} - -/*! - * \brief AnimationWindow::loadVisualization - * loads the data and the xml scene description - */ -void AnimationWindow::loadVisualization() -{ - VisType visType = VisType::NONE; - // Get visualization type. - if (isFMU(mFileName)) { - visType = VisType::FMU; - } else if (isMAT(mFileName)) { - visType = VisType::MAT; - } else if (isCSV(mFileName)) { - visType = VisType::CSV; - } else { - MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, tr("Unknown visualization type."), - Helper::scriptingKind, Helper::errorLevel)); - } - //init visualizer - if (visType == VisType::MAT) { - mpVisualizer = new VisualizerMAT(mFileName, mPathName); - } else if (visType == VisType::CSV) { - mpVisualizer = new VisualizerCSV(mFileName, mPathName); - } else if (visType == VisType::FMU) { - mpVisualizer = new VisualizerFMU(mFileName, mPathName); - } else { - QString msg = tr("Could not init %1 %2.").arg(QString(mPathName.c_str())).arg(QString(mFileName.c_str())); - MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, msg, Helper::scriptingKind, - Helper::errorLevel)); - } - //load the XML File, build osgTree, get initial values for the shapes - bool xmlExists = checkForXMLFile(mFileName, mPathName); - if (!xmlExists) { - QString msg = tr("Could not find the visual XML file %1.").arg(QString(assembleXMLFileName(mFileName, mPathName).c_str())); - MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, msg, Helper::scriptingKind, - Helper::errorLevel)); - } else { - connect(mpVisualizer->getTimeManager()->getUpdateSceneTimer(), SIGNAL(timeout()), SLOT(updateScene())); - mpVisualizer->initData(); - mpVisualizer->setUpScene(); - mpVisualizer->initVisualization(); - //add scene for the chosen visualization - mpSceneView->setSceneData(mpVisualizer->getOMVisScene()->getScene().getRootNode()); - } - //FMU settings dialog - if (visType == VisType::FMU) { - //openFMUSettingsDialog(); - } - //add window title - this->setWindowTitle(QString::fromStdString(mFileName)); - //jump to xy-view - cameraPositionIsometric(); -} - -/*! - * \brief AnimationWindow::animationFileSlotFunction - * opens a file dialog to chooes an animation - */ -void AnimationWindow::chooseAnimationFileSlotFunction() -{ - QString fileName = StringHandler::getOpenFileName(this, QString("%1 - %2").arg(Helper::applicationName).arg(Helper::chooseFile), - NULL, Helper::visualizationFileTypes, NULL); - if (fileName.isEmpty()) { - return; - } - openAnimationFile(fileName); -} - -/*! - * \brief AnimationWindow::getTimeFraction - * gets the fraction of the complete simulation time to move the slider - */ -double AnimationWindow::getTimeFraction() -{ - if (mpVisualizer==NULL) { - return 0.0; - } else { - return mpVisualizer->getTimeManager()->getTimeFraction(); - } -} - -/*! - * \brief AnimationWindow::sliderSetTimeSlotFunction - * slot function for the time slider to jump to the adjusted point of time - */ -void AnimationWindow::sliderSetTimeSlotFunction(int value) -{ - float time = (mpVisualizer->getTimeManager()->getEndTime() - - mpVisualizer->getTimeManager()->getStartTime()) - * (float) (value / 100.0); - mpVisualizer->getTimeManager()->setVisTime(time); - mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); - mpVisualizer->updateScene(time); -} - -/*! - * \brief AnimationWindow::playSlotFunction - * slot function for the play button - */ -void AnimationWindow::playSlotFunction() -{ - mpVisualizer->getTimeManager()->setPause(false); -} - -/*! - * \brief AnimationWindow::pauseSlotFunction - * slot function for the pause button - */ -void AnimationWindow::pauseSlotFunction() -{ - mpVisualizer->getTimeManager()->setPause(true); -} - -/*! - * \brief AnimationWindow::initSlotFunction - * slot function for the init button - */ -void AnimationWindow::initSlotFunction() -{ - mpVisualizer->initVisualization(); - bool state = mpAnimationSlider->blockSignals(true); - mpAnimationSlider->setValue(0); - mpAnimationSlider->blockSignals(state); - mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); -} - -/*! - * \brief AnimationWindow::updateSceneFunction - * updates the visualization objects - */ -void AnimationWindow::updateScene() -{ - if (!(mpVisualizer == NULL)) { - //set time label - if (!mpVisualizer->getTimeManager()->isPaused()) { - mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getVisTime())); - // set time slider - if (mpVisualizer->getVisType() != VisType::FMU) { - int time = mpVisualizer->getTimeManager()->getTimeFraction(); - bool state = mpAnimationSlider->blockSignals(true); - mpAnimationSlider->setValue(time); - mpAnimationSlider->blockSignals(state); - } - } - //update the scene - mpVisualizer->sceneUpdate(); - } -} - -/*! - * \brief AnimationWindow::renderFrame - * renders the osg viewer - */ -void AnimationWindow::renderFrame() -{ - frame(); -} - -/*! - * \brief AnimationWindow::getVisTime - * returns the current visualization time - */ -double AnimationWindow::getVisTime() -{ - if (mpVisualizer==NULL) { - return -1.0; - } else { - return mpVisualizer->getTimeManager()->getVisTime(); - } -} - -/*! - * \brief AnimationWindow::setPathName - * sets mpPathName - */ -void AnimationWindow::setPathName(std::string pathName) -{ - mPathName = pathName; -} - -/*! - * \brief AnimationWindow::setFileName - * sets mpFileName - */ -void AnimationWindow::setFileName(std::string fileName) -{ - mFileName = fileName; -} - -/*! - * \brief AnimationWindow::openAnimationFile - * \param fileName - */ -void AnimationWindow::openAnimationFile(QString fileName) -{ - std::string file = fileName.toStdString(); - if (file.compare("")) { - std::size_t pos = file.find_last_of("/\\"); - mPathName = file.substr(0, pos + 1); - mFileName = file.substr(pos + 1, file.length()); - //std::cout<<"file "<setEnabled(true); - mpAnimationPlayAction->setEnabled(true); - mpAnimationPauseAction->setEnabled(true); - mpAnimationSlider->setEnabled(true); - bool state = mpAnimationSlider->blockSignals(true); - mpAnimationSlider->setValue(0); - mpAnimationSlider->blockSignals(state); - mpSpeedComboBox->setEnabled(true); - mpTimeTextBox->setEnabled(true); - mpTimeTextBox->setText(QString::number(mpVisualizer->getTimeManager()->getStartTime())); - state = mpPerspectiveDropDownBox->blockSignals(true); - mpPerspectiveDropDownBox->setCurrentIndex(0); - mpPerspectiveDropDownBox->blockSignals(state); - } -} - -/*! - * \brief AnimationWindow::cameraPositionIsometric - * sets the camera position to isometric view - */ -void AnimationWindow::cameraPositionIsometric() -{ - double d = computeDistanceToOrigin(); - osg::Matrixd mat = osg::Matrixd(0.7071, 0, -0.7071, 0, - -0.409, 0.816, -0.409, 0, - 0.57735, 0.57735, 0.57735, 0, - 0.57735*d, 0.57735*d, 0.57735*d, 1); - mpSceneView->getCameraManipulator()->setByMatrix(mat); -} - -/*! - * \brief AnimationWindow::cameraPositionSide - * sets the camera position to Side - */ -void AnimationWindow::cameraPositionSide() -{ - double d = computeDistanceToOrigin(); - osg::Matrixd mat = osg::Matrixd(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, d, 1); - mpSceneView->getCameraManipulator()->setByMatrix(mat); -} - -/*! - * \brief AnimationWindow::cameraPositionFront - * sets the camera position to Front - */ -void AnimationWindow::cameraPositionFront() -{ - double d = computeDistanceToOrigin(); - osg::Matrixd mat = osg::Matrixd(0, 0, 1, 0, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, d, 0, 1); - mpSceneView->getCameraManipulator()->setByMatrix(mat); -} - -/*! - * \brief AnimationWindow::cameraPositionTop - * sets the camera position to Top - */ -void AnimationWindow::cameraPositionTop() -{ - double d = computeDistanceToOrigin(); - osg::Matrixd mat = osg::Matrixd( 0, 0,-1, 0, - 0, 1, 0, 0, - 1, 0, 0, 0, - d, 0, 0, 1); - mpSceneView->getCameraManipulator()->setByMatrix(mat); -} - -/*! - * \brief AnimationWindow::rotateCameraLeft - * rotates the camera 90 degress left about the line of sight - */ -void AnimationWindow::rotateCameraLeft() -{ - osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); - osg::Matrixd mat = manipulator->getMatrix(); - osg::Camera *pCamera = mpSceneView->getCamera(); - - osg::Vec3d eye, center, up; - pCamera->getViewMatrixAsLookAt(eye, center, up); - osg::Vec3d rotationAxis = center-eye; - - osg::Matrixd rotMatrix; - rotMatrix.makeRotate(3.1415/2.0, rotationAxis); - - mpSceneView->getCameraManipulator()->setByMatrix(mat*rotMatrix); -} - -/*! - * \brief AnimationWindow::rotateCameraLeft - * rotates the camera 90 degress right about the line of sight - */ -void AnimationWindow::rotateCameraRight() -{ - osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); - osg::Matrixd mat = manipulator->getMatrix(); - osg::Camera *pCamera = mpSceneView->getCamera(); - - osg::Vec3d eye, center, up; - pCamera->getViewMatrixAsLookAt(eye, center, up); - osg::Vec3d rotationAxis = center-eye; - - osg::Matrixd rotMatrix; - rotMatrix.makeRotate(-3.1415/2.0, rotationAxis); - - mpSceneView->getCameraManipulator()->setByMatrix(mat*rotMatrix); -} - -/*! - * \brief AnimationWindow::computeDistanceToOrigin - * computes distance to origin using pythagoras theorem - */ -// -double AnimationWindow::computeDistanceToOrigin() -{ - osg::ref_ptr manipulator = mpSceneView->getCameraManipulator(); - osg::Matrixd mat = manipulator->getMatrix(); - //assemble - - //Compute distance to center using pythagoras theorem - double d = sqrt(abs(mat(3,0))*abs(mat(3,0))+ - abs(mat(3,1))*abs(mat(3,1))+ - abs(mat(3,2))*abs(mat(3,2))); - - //If d is very small (~0), set it to 1 as default - if(d < 1e-10) { - d=1; - } - - return d; -} - -/*! - * \brief AnimationWindow::resetCamera - * resets the camera position - */ -void AnimationWindow::resetCamera() -{ - mpSceneView->home(); -} - -/*! - * \brief AnimationWindow::setPerspective - * gets the identifier for the chosen perspective and calls the functions - */ -void AnimationWindow::setPerspective(int value) -{ - switch(value) { - case 0: - cameraPositionIsometric(); - break; - case 1: - cameraPositionSide(); - break; - case 2: - cameraPositionTop(); - break; - case 3: - cameraPositionFront(); - break; - } -} - -/*! - * \brief AnimationWindow::openmpFMUSettingsDialog - * opens a dialog to set the settings for the FMU visualization - */ -void AnimationWindow::openFMUSettingsDialog() -{ - //create dialog - mpFMUSettingsDialog = new QDialog(this); - mpFMUSettingsDialog->setWindowTitle("FMU settings"); - mpFMUSettingsDialog->setWindowIcon(QIcon(":/Resources/icons/animation.svg")); - //the layouts - QVBoxLayout *mainLayout = new QVBoxLayout; - QHBoxLayout *simulationLayout = new QHBoxLayout; - QVBoxLayout *leftSimLayout = new QVBoxLayout; - QVBoxLayout *rightSimLayout = new QVBoxLayout; - //the widgets - QLabel *simulationLabel = new QLabel(tr("Simulation settings")); - QPushButton *okButton = new QPushButton(tr("OK")); - //solver settings - QLabel *solverLabel = new QLabel(tr("solver")); - QComboBox *solverComboBox = new QComboBox(mpFMUSettingsDialog); - solverComboBox->addItem(QString("euler forward")); - //assemble - mainLayout->addWidget(simulationLabel); - mainLayout->addLayout(simulationLayout); - simulationLayout->addLayout(leftSimLayout); - simulationLayout->addLayout(rightSimLayout); - leftSimLayout->addWidget(solverLabel); - rightSimLayout->addWidget(solverComboBox); - mainLayout->addWidget(okButton); - mpFMUSettingsDialog->setLayout(mainLayout); - //connections - connect(okButton, SIGNAL(clicked()),this, SLOT(saveSimSettings())); - mpFMUSettingsDialog->show(); -} - -void AnimationWindow::saveSimSettings() -{ - std::cout<<"save simulation settings"<close(); + mpAnimationToolBar->addAction(mpRotateCameraLeftAction); + mpAnimationToolBar->addAction(mpRotateCameraRightAction); } diff --git a/OMEdit/OMEditGUI/Animation/AnimationWindow.h b/OMEdit/OMEditGUI/Animation/AnimationWindow.h index a98de6dbf62..441b5469313 100644 --- a/OMEdit/OMEditGUI/Animation/AnimationWindow.h +++ b/OMEdit/OMEditGUI/Animation/AnimationWindow.h @@ -35,94 +35,16 @@ #ifndef ANIMATIONWINDOW_H #define ANIMATIONWINDOW_H -#include -#include +#include "AbstractAnimationWindow.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include <../../osgQt/OMEdit_GraphicsWindowQt.h> - -#include -#include -#include -#include -#include -#include - -class PlotWindowContainer; -class VisualizerAbstract; -class Label; - -class AnimationWindow : public QMainWindow, public osgViewer::CompositeViewer +class AnimationWindow : public AbstractAnimationWindow { Q_OBJECT public: - AnimationWindow(PlotWindowContainer *pPlotWindowContainer); + AnimationWindow(QWidget *pParent); ~AnimationWindow(); - QWidget* setupViewWidget(); - void loadVisualization(); - double getTimeFraction(); - double getVisTime(); - void setPathName(std::string name); - void setFileName(std::string name); - void openAnimationFile(QString fileName); - void openFMUSettingsDialog(); -public slots: - void sliderSetTimeSlotFunction(int value); - void playSlotFunction(); - void pauseSlotFunction(); - void initSlotFunction(); - void updateScene(); - void renderFrame(); - void chooseAnimationFileSlotFunction(); - void setSpeedSlotFunction(); - void jumpToTimeSlotFunction(); - void resetCamera(); - void cameraPositionIsometric(); - void cameraPositionSide(); - void cameraPositionFront(); - void cameraPositionTop(); - void rotateCameraLeft(); - void rotateCameraRight(); - double computeDistanceToOrigin(); - void setPerspective(int value); - void saveSimSettings(); -private: - PlotWindowContainer *mpPlotWindowContainer; - //to be animated - std::string mPathName; - std::string mFileName; - //osg viewer scene - osgViewer::View* mpSceneView; - //stores the data for the shapes, time management, functionality for updating the values(mat/fmu) etc. - VisualizerAbstract* mpVisualizer; - //widgets - QWidget* mpViewerWidget; - QTimer mRenderFrameTimer; - QToolBar* mpAnimationToolBar; - QSlider* mpAnimationSlider; - Label *mpAnimationTimeLabel; - QLineEdit *mpTimeTextBox; - Label *mpAnimationSpeedLabel; - QComboBox *mpSpeedComboBox; - QComboBox *mpPerspectiveDropDownBox; - QToolButton *mpRotateCameraLeftButton; - QToolButton *mpRotateCameraRightButton; - QDialog *mpFMUSettingsDialog; - //actions - QAction *mpAnimationChooseFileAction; - QAction *mpAnimationInitializeAction; - QAction *mpAnimationPlayAction; - QAction *mpAnimationPauseAction; + void createActions() override; }; #endif // ANIMATIONWINDOW_H diff --git a/OMEdit/OMEditGUI/Animation/AnimationWindow.h.Rt6712 b/OMEdit/OMEditGUI/Animation/AnimationWindow.h.Rt6712 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/OMEdit/OMEditGUI/Animation/ExtraShapes.cpp b/OMEdit/OMEditGUI/Animation/ExtraShapes.cpp index 60b149b64ed..d753de1ec97 100644 --- a/OMEdit/OMEditGUI/Animation/ExtraShapes.cpp +++ b/OMEdit/OMEditGUI/Animation/ExtraShapes.cpp @@ -682,9 +682,6 @@ DXFile::DXFile(std::string filename) (*facette)[1] = (i * 4) + 1; (*facette)[2] = (i * 4) + 2; this->addPrimitiveSet(facette); - - //normal calculation - osg::Vec3f normal = faces[i].calcNormals(); } else { diff --git a/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.cpp b/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.cpp new file mode 100644 index 00000000000..c284a3ff63e --- /dev/null +++ b/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.cpp @@ -0,0 +1,113 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Volker Waurich + */ + +#include "FMUSettingsDialog.h" +#include "Util/Helper.h" +#include "Util/Utilities.h" + +/*! + * \class FMUSettingsDialog + * \brief widget for FMU-simulation settings. + */ +/*! + * \brief FMUSettingsDialog::FMUSettingsDialog + * \param pParent + * \param pVisualizerFMU + */ +FMUSettingsDialog::FMUSettingsDialog(QWidget *pParent, VisualizerFMU* pVisualizerFMU) + : QDialog(pParent), + mpVisualizerFMU(pVisualizerFMU), + mStepSize(0.001), + mRenderFreq(0.1) +{ + setAttribute(Qt::WA_DeleteOnClose); + //create dialog + setWindowTitle(QString("%1 - %2").arg(Helper::applicationName, tr("FMU-Simulation Settings"))); + //the widgets + QLabel *solverLabel = new QLabel(tr("Solver")); + mpSolverComboBox = new QComboBox(); + mpSolverComboBox->addItem(QString("Explicit Euler"), QVariant((int)Solver::EULER_FORWARD)); + Label *stepsizeLabel = new Label(tr("Step Size [s]")); + mpStepSizeLineEdit = new QLineEdit(QString::number(mStepSize)); + Label *handleEventsLabel = new Label(tr("Process Events in FMU")); + mpHandleEventsCheck = new QCheckBox(); + mpHandleEventsCheck->setCheckState(Qt::Checked); + // Create the buttons + mpOkButton = new QPushButton(Helper::ok); + mpOkButton->setAutoDefault(true); + connect(mpOkButton, SIGNAL(clicked()), SLOT(saveSimSettings())); + mpCancelButton = new QPushButton(Helper::cancel); + mpCancelButton->setAutoDefault(false); + connect(mpCancelButton, SIGNAL(clicked()), SLOT(reject())); + // create buttons box + mpButtonBox = new QDialogButtonBox(Qt::Horizontal); + mpButtonBox->addButton(mpOkButton, QDialogButtonBox::ActionRole); + mpButtonBox->addButton(mpCancelButton, QDialogButtonBox::ActionRole); + //connections + QObject::connect(mpButtonBox, SIGNAL(accepted()), this, SLOT(saveSimSettings())); + QObject::connect(mpButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + //assemble + QGridLayout *pMainLayout = new QGridLayout; + pMainLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + pMainLayout->addWidget(solverLabel, 0, 0); + pMainLayout->addWidget(mpSolverComboBox, 0, 1); + pMainLayout->addWidget(stepsizeLabel, 1, 0); + pMainLayout->addWidget(mpStepSizeLineEdit, 1, 1); + pMainLayout->addWidget(handleEventsLabel, 2, 0); + pMainLayout->addWidget(mpHandleEventsCheck, 2, 1); + pMainLayout->addWidget(mpButtonBox, 3, 0, 1, 2, Qt::AlignRight); + setLayout(pMainLayout); +} + +/*! + * \brief FMUSettingsDialog::saveSimSettings + */ +void FMUSettingsDialog::saveSimSettings() +{ + //step size + bool isFloat = true; + double stepSize = mpStepSizeLineEdit->text().toFloat(&isFloat); + if (!isFloat) { + stepSize = 0.0001; + } + //handle events + bool handleEvents = true; + if (!mpHandleEventsCheck->isChecked()){ + handleEvents = false; + }; + //store in FMU simulator + mpVisualizerFMU->setSimulationSettings(stepSize, static_cast(mpSolverComboBox->itemData(mpSolverComboBox->currentIndex()).toInt()), + handleEvents); + accept(); +} diff --git a/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.h b/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.h new file mode 100644 index 00000000000..9a8f0969c9c --- /dev/null +++ b/OMEdit/OMEditGUI/Animation/FMUSettingsDialog.h @@ -0,0 +1,70 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Volker Waurich + */ + + +#ifndef FMU_SETTINGS_WINDOW_H +#define FMU_SETTINGS_WINDOW_H + +#include "VisualizerFMU.h" + +#include +#include +#include +#include +#include +#include +#include + +class FMUSettingsDialog : public QDialog +{ + Q_OBJECT +public: + FMUSettingsDialog(QWidget *pParent, VisualizerFMU *pVisualizerFMU); +private: + VisualizerFMU *mpVisualizerFMU; + double mStepSize; + double mRenderFreq; + bool mHandleEvents; + QLineEdit* mpStepSizeLineEdit; + QCheckBox* mpHandleEventsCheck; + QComboBox* mpSolverComboBox; + QPushButton *mpOkButton; + QPushButton *mpCancelButton; + QDialogButtonBox *mpButtonBox; +public slots: + void saveSimSettings(); +}; + + +#endif // end FMU_SETTINGS_WINDOW_H diff --git a/OMEdit/OMEditGUI/Animation/FMUWrapper.cpp b/OMEdit/OMEditGUI/Animation/FMUWrapper.cpp index e0eace4064d..c787f4aa707 100644 --- a/OMEdit/OMEditGUI/Animation/FMUWrapper.cpp +++ b/OMEdit/OMEditGUI/Animation/FMUWrapper.cpp @@ -43,7 +43,8 @@ SimSettingsFMU::SimSettingsFMU() _hdef(0.1), _tend(0.1), _relativeTolerance(0.001), - _solver(Solver::EULER_FORWARD) + _solver(Solver::EULER_FORWARD), + mIterateEvents(true) { } @@ -107,6 +108,15 @@ int SimSettingsFMU::getIntermediateResults() return _intermediateResults; } +void SimSettingsFMU::setIterateEvents(bool iE) +{ + mIterateEvents = iE; +} + +bool SimSettingsFMU::getIterateEvents() +{ + return mIterateEvents; +} //------------------------------- // Abstract FMU class //------------------------------- @@ -145,7 +155,7 @@ FMUWrapper_ME_1::~FMUWrapper_ME_1() void FMUWrapper_ME_1::fmi_get_real(unsigned int* valueRef, double* res) { - fmi1_import_get_real(mpFMU, valueRef, 1, res); + fmi1_import_get_real(mpFMU, valueRef, 1, res); } unsigned int FMUWrapper_ME_1::fmi_get_variable_by_name(const char* name) @@ -321,7 +331,7 @@ FMUWrapper_ME_2::FMUWrapper_ME_2() mCallBackFunctions(), mFMUdata() { - mFMUdata.terminateSimulation = fmi2_false; + mFMUdata.terminateSimulation = fmi2_false; } FMUWrapper_ME_2::~FMUWrapper_ME_2() @@ -342,7 +352,7 @@ FMUWrapper_ME_2::~FMUWrapper_ME_2() void FMUWrapper_ME_2::fmi_get_real(unsigned int* valueRef, double* res) { - fmi2_import_get_real(mpFMU, valueRef, 1, res); + fmi2_import_get_real(mpFMU, valueRef, 1, res); } void FMUWrapper_ME_2::load(const std::string& modelFile, const std::string& path, fmi_import_context_t* context) @@ -403,7 +413,7 @@ void FMUWrapper_ME_2::initialize(const std::shared_ptr simSettin try { mFMUdata.fmiStatus2 = fmi2_import_enter_initialization_mode(mpFMU); - mFMUdata.fmiStatus2 = fmi2_import_exit_initialization_mode(mpFMU); + mFMUdata.fmiStatus2 = fmi2_import_exit_initialization_mode(mpFMU); } catch (std::exception &ex) { @@ -480,7 +490,7 @@ void FMUWrapper_ME_2::updateNextTimeStep(const double hdef) double tlast = mFMUdata._tcur; mFMUdata._tcur += hdef; if (mFMUdata.eventInfo2.nextEventTimeDefined && (mFMUdata._tcur >= mFMUdata.eventInfo2.nextEventTime)) { - mFMUdata._tcur = mFMUdata.eventInfo2.nextEventTime; + mFMUdata._tcur = mFMUdata.eventInfo2.nextEventTime; } mFMUdata._hcur = mFMUdata._tcur - tlast; } @@ -488,11 +498,11 @@ void FMUWrapper_ME_2::updateNextTimeStep(const double hdef) void FMUWrapper_ME_2::handleEvents(const int intermediateResults) { //std::cout<<"Handle event at "< + */ + +#include "ThreeDViewer.h" +#include "Visualizer.h" + +/*! + * \class ThreeDViewer + * \brief A QMainWindow for 3d view. + */ +/*! + * \brief ThreeDViewer::ThreeDViewer + * \param pParent + */ +ThreeDViewer::ThreeDViewer(QWidget *pParent) + : AbstractAnimationWindow(pParent) +{ + createActions(); +} + +/*! + * \brief ThreeDViewer::~ThreeDViewer + */ +ThreeDViewer::~ThreeDViewer() +{ + if (mpVisualizer) { + delete mpVisualizer; + } +} + +/*! + * \brief ThreeDViewer::createActions + */ +void ThreeDViewer::createActions() +{ + AbstractAnimationWindow::createActions(); + mpAnimationToolBar->addWidget(mpPerspectiveDropDownBox); + mpAnimationToolBar->addAction(mpRotateCameraLeftAction); + mpAnimationToolBar->addAction(mpRotateCameraRightAction); +} diff --git a/OMEdit/OMEditGUI/Animation/ThreeDViewer.h b/OMEdit/OMEditGUI/Animation/ThreeDViewer.h new file mode 100644 index 00000000000..dd7887272a6 --- /dev/null +++ b/OMEdit/OMEditGUI/Animation/ThreeDViewer.h @@ -0,0 +1,48 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE + * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Adeel Asghar + */ + +#ifndef THREEDVIEWER_H +#define THREEDVIEWER_H + +#include "AbstractAnimationWindow.h" + +class ThreeDViewer : public AbstractAnimationWindow +{ + Q_OBJECT +public: + ThreeDViewer(QWidget *pParent); + ~ThreeDViewer(); + void createActions() override; +}; + +#endif // THREEDVIEWER_H diff --git a/OMEdit/OMEditGUI/Animation/VisualizerFMU.cpp b/OMEdit/OMEditGUI/Animation/VisualizerFMU.cpp index 0e731000727..8d7dda84629 100644 --- a/OMEdit/OMEditGUI/Animation/VisualizerFMU.cpp +++ b/OMEdit/OMEditGUI/Animation/VisualizerFMU.cpp @@ -44,9 +44,9 @@ VisualizerFMU::VisualizerFMU(const std::string& modelFile, const std::string& pa } VisualizerFMU::~VisualizerFMU() { - if (mpFMU){ - free(mpFMU); - } + if (mpFMU){ + free(mpFMU); + } } @@ -92,7 +92,7 @@ void VisualizerFMU::allocateContext(const std::string& modelFile, const std::str mCallbacks.realloc = realloc; mCallbacks.free = free; mCallbacks.logger = jm_default_logger; - mCallbacks.log_level = jm_log_level_debug; // jm_log_level_error; + mCallbacks.log_level = jm_log_level_error; // jm_log_level_error; mCallbacks.context = 0; #ifdef FMILIB_GENERATE_BUILD_STAMP std::cout << "Library build stamp: \n" << fmilib_get_build_stamp() << std::endl; @@ -183,7 +183,7 @@ double VisualizerFMU::simulateStep(const double time) bool zeroCrossingEvent = mpFMU->checkForTriggeredEvent(); // Handle any events - if (mpSimSettings->getCallEventUpdate() || zeroCrossingEvent || mpFMU->itsEventTime()) + if (mpSimSettings->getIterateEvents() && (mpSimSettings->getCallEventUpdate() || zeroCrossingEvent || mpFMU->itsEventTime())) { mpFMU->handleEvents(mpSimSettings->getIntermediateResults()); } @@ -327,3 +327,9 @@ void VisualizerFMU::updateObjectAttributeFMU(ShapeObjectAttribute* attr, FMUWrap } } +void VisualizerFMU::setSimulationSettings(double stepsize, Solver solver, bool iterateEvents) +{ + mpSimSettings->setHdef(stepsize); + mpSimSettings->setSolver(solver); + mpSimSettings->setIterateEvents(iterateEvents); +} diff --git a/OMEdit/OMEditGUI/Animation/VisualizerFMU.h b/OMEdit/OMEditGUI/Animation/VisualizerFMU.h index 9649beb1d7e..89da34de1b0 100644 --- a/OMEdit/OMEditGUI/Animation/VisualizerFMU.h +++ b/OMEdit/OMEditGUI/Animation/VisualizerFMU.h @@ -61,6 +61,7 @@ class VisualizerFMU : public VisualizerAbstract void updateVisAttributes(const double time) override; void updateScene(const double time = 0.0) override; void updateObjectAttributeFMU(ShapeObjectAttribute* attr, FMUWrapperAbstract* fmuWrapper); + void setSimulationSettings(double stepsize, Solver solver, bool iterateEvents); private: std::shared_ptr mpContext; jm_callbacks mCallbacks; diff --git a/OMEdit/OMEditGUI/Animation/VisualizerMAT.cpp b/OMEdit/OMEditGUI/Animation/VisualizerMAT.cpp index 537b9d4a97b..340b2daddb1 100644 --- a/OMEdit/OMEditGUI/Animation/VisualizerMAT.cpp +++ b/OMEdit/OMEditGUI/Animation/VisualizerMAT.cpp @@ -209,10 +209,4 @@ double VisualizerMAT::omcGetVarValue(ModelicaMatReader* reader, const char* varN return val; } -/* -void VisualizerMAT::setSimulationSettings(const UserSimSettingsMAT& simSetMAT) -{ - auto newVal = simSetMAT.speedup * _timeManager->getHVisual(); - _timeManager->setHVisual(newVal); -} -*/ + diff --git a/OMEdit/OMEditGUI/Annotations/LineAnnotation.cpp b/OMEdit/OMEditGUI/Annotations/LineAnnotation.cpp index 09ed1374f44..1a7c5c0e6bb 100644 --- a/OMEdit/OMEditGUI/Annotations/LineAnnotation.cpp +++ b/OMEdit/OMEditGUI/Annotations/LineAnnotation.cpp @@ -640,6 +640,7 @@ void LineAnnotation::updateEndPoint(QPointF point) mPoints.back() = point; updateCornerItem(lastIndex); /* update the 2nd point */ + assert(secondLastIndex < mGeometries.size()); if (mGeometries[secondLastIndex] == ShapeAnnotation::HorizontalLine) { mPoints[secondLastIndex] = QPointF(mPoints[secondLastIndex].x(), mPoints[secondLastIndex].y() + dy); } else if (mGeometries[secondLastIndex] == ShapeAnnotation::VerticalLine) { diff --git a/OMEdit/OMEditGUI/Annotations/ShapePropertiesDialog.cpp b/OMEdit/OMEditGUI/Annotations/ShapePropertiesDialog.cpp index a7e87994c85..c489867d754 100644 --- a/OMEdit/OMEditGUI/Annotations/ShapePropertiesDialog.cpp +++ b/OMEdit/OMEditGUI/Annotations/ShapePropertiesDialog.cpp @@ -828,6 +828,9 @@ bool ShapePropertiesDialog::applyShapeProperties() LineAnnotation::LineType lineType = LineAnnotation::ShapeType; if (mpLineAnnotation) { lineType = mpLineAnnotation->getLineType(); + if (lineType == LineAnnotation::ConnectionType) { + mpLineAnnotation->adjustGeometries(); + } } // if nothing has changed then just simply return true. if (mOldAnnotation.compare(mpShapeAnnotation->getOMCShapeAnnotation()) == 0) { diff --git a/OMEdit/OMEditGUI/Annotations/TextAnnotation.cpp b/OMEdit/OMEditGUI/Annotations/TextAnnotation.cpp index 1afc665afd7..b8977cdeb49 100644 --- a/OMEdit/OMEditGUI/Annotations/TextAnnotation.cpp +++ b/OMEdit/OMEditGUI/Annotations/TextAnnotation.cpp @@ -398,7 +398,10 @@ QString TextAnnotation::getShapeAnnotation() annotationString.append(QString("fontSize=").append(QString::number(mFontSize))); } // get the font name - if (!mFontName.isEmpty()) { + /* Ticket:4204 + * Don't insert the default font name as it might be operating system specific. + */ + if (!mFontName.isEmpty() && mFontName.compare(Helper::systemFontInfo.family()) != 0) { annotationString.append(QString("fontName=\"").append(mFontName).append("\"")); } // get the font styles @@ -453,7 +456,15 @@ void TextAnnotation::updateTextStringHelper(QRegExp regExp) if ((!variable.isEmpty()) && (variable.compare("%%") != 0) && (variable.compare("%name") != 0) && (variable.compare("%class") != 0)) { variable.remove("%"); if (!variable.isEmpty()) { - QString textValue = mpComponent->getParameterDisplayString(variable); + QString textValue; + /* Ticket:4204 + * If we have extend component then call Component::getParameterDisplayString from root component. + */ + if (mpComponent->getComponentType() == Component::Extend) { + textValue = mpComponent->getRootParentComponent()->getParameterDisplayString(variable); + } else { + textValue = mpComponent->getRootParentComponent()->getParameterDisplayString(variable); + } if (!textValue.isEmpty()) { mTextString.replace(pos, regExp.matchedLength(), textValue); } else { /* if the value of %\\W* is empty then remove the % sign. */ diff --git a/OMEdit/OMEditGUI/Component/Component.cpp b/OMEdit/OMEditGUI/Component/Component.cpp index f21b5ca3a8b..d652927eb59 100644 --- a/OMEdit/OMEditGUI/Component/Component.cpp +++ b/OMEdit/OMEditGUI/Component/Component.cpp @@ -482,6 +482,11 @@ Component::Component(QString name, LibraryTreeItem *pLibraryTreeItem, QString tr } connect(this, SIGNAL(transformHasChanged()), SLOT(updatePlacementAnnotation())); connect(this, SIGNAL(transformHasChanged()), SLOT(updateOriginItem())); + /* Ticket:4204 + * If the child class use text annotation from base class then we need to call this + * since when the base class is created the child class doesn't exist. + */ + displayTextChangedRecursive(); } Component::Component(LibraryTreeItem *pLibraryTreeItem, Component *pParentComponent) @@ -598,6 +603,11 @@ Component::Component(Component *pComponent, GraphicsView *pGraphicsView) connect(mpReferenceComponent, SIGNAL(displayTextChanged()), SIGNAL(displayTextChanged())); connect(mpReferenceComponent, SIGNAL(changed()), SLOT(referenceComponentChanged())); connect(mpReferenceComponent, SIGNAL(deleted()), SLOT(referenceComponentDeleted())); + /* Ticket:4204 + * If the child class use text annotation from base class then we need to call this + * since when the base class is created the child class doesn't exist. + */ + displayTextChangedRecursive(); } Component::Component(ComponentInfo *pComponentInfo, Component *pParentComponent) @@ -1106,8 +1116,9 @@ QString Component::getParameterDisplayString(QString parameterName) mpLibraryTreeItem->getModelWidget()->loadDiagramView(); foreach (Component *pComponent, mpLibraryTreeItem->getModelWidget()->getDiagramGraphicsView()->getComponentsList()) { if (pComponent->getComponentInfo()->getName().compare(parameterName) == 0) { - if (displayString.isEmpty()) + if (displayString.isEmpty()) { displayString = pComponent->getComponentInfo()->getParameterValue(pOMCProxy, mpLibraryTreeItem->getNameStructure()); + } typeName = pComponent->getComponentInfo()->getClassName(); checkEnumerationDisplayString(displayString, typeName); break; @@ -1592,18 +1603,23 @@ void Component::updateConnections() QString Component::getParameterDisplayStringFromExtendsModifiers(QString parameterName) { QString displayString = ""; - foreach (Component *pComponent, mInheritedComponentsList) { - if (pComponent->getLibraryTreeItem()) { - QMap extendsModifiersMap = pComponent->getLibraryTreeItem()->getModelWidget()->getExtendsModifiersMap(pComponent->getLibraryTreeItem()->getNameStructure()); - displayString = extendsModifiersMap.value(parameterName, ""); + /* Ticket:4204 + * Get the extends modifiers of the class not the inherited class. + */ + if (mpLibraryTreeItem) { + foreach (Component *pComponent, mInheritedComponentsList) { + if (pComponent->getLibraryTreeItem()) { + QMap extendsModifiersMap = mpLibraryTreeItem->getModelWidget()->getExtendsModifiersMap(pComponent->getLibraryTreeItem()->getNameStructure()); + displayString = extendsModifiersMap.value(parameterName, ""); + if (!displayString.isEmpty()) { + return displayString; + } + } + displayString = pComponent->getParameterDisplayStringFromExtendsModifiers(parameterName); if (!displayString.isEmpty()) { return displayString; } } - displayString = pComponent->getParameterDisplayStringFromExtendsModifiers(parameterName); - if (!displayString.isEmpty()) { - return displayString; - } } return displayString; } @@ -1625,9 +1641,13 @@ QString Component::getParameterDisplayStringFromExtendsParameters(QString parame foreach (Component *pComponent, pInheritedComponent->getLibraryTreeItem()->getModelWidget()->getDiagramGraphicsView()->getComponentsList()) { if (pComponent->getComponentInfo()->getName().compare(parameterName) == 0) { OMCProxy *pOMCProxy = MainWindow::instance()->getOMCProxy(); - if (pComponent->getLibraryTreeItem()) { - if (displayString.isEmpty()) - displayString = pComponent->getComponentInfo()->getParameterValue(pOMCProxy, pComponent->getLibraryTreeItem()->getNameStructure()); + /* Ticket:4204 + * Look for the parameter value in the parameter containing class not in the parameter class. + */ + if (pInheritedComponent->getLibraryTreeItem()) { + if (displayString.isEmpty()) { + displayString = pComponent->getComponentInfo()->getParameterValue(pOMCProxy, pInheritedComponent->getLibraryTreeItem()->getNameStructure()); + } typeName = pComponent->getComponentInfo()->getClassName(); checkEnumerationDisplayString(displayString, typeName); if (!(displayString.isEmpty() || typeName.isEmpty())) { diff --git a/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.cpp b/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.cpp new file mode 100644 index 00000000000..3aa704109d5 --- /dev/null +++ b/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.cpp @@ -0,0 +1,176 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE + * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Adeel Asghar + */ + +#include "GDBBacktrace.h" +#ifdef WIN32 +#include +#else +#include +#endif +#include "Util/Utilities.h" +#include "Util/Helper.h" +#include "CrashReportDialog.h" + +#include +#include + +/*! + * \class GDBBacktrace + * \brief Prints the backtrace of the program using the GDB backtrace feature. + */ +/*! + * \brief GDBBacktrace::GDBBacktrace + * \param parent + */ +GDBBacktrace::GDBBacktrace(QObject *parent) + : QObject(parent) +{ + // GDB process + mpGDBProcess = new QProcess; + connect(mpGDBProcess, SIGNAL(readyRead()), SLOT(readGDBOutput())); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect(mpGDBProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(handleGDBProcessError(QProcess::ProcessError))); +#else + connect(mpGDBProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(handleGDBProcessError(QProcess::ProcessError))); +#endif + connect(mpGDBProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(handleGDBProcessFinished(int,QProcess::ExitStatus))); + connect(mpGDBProcess, SIGNAL(finished(int,QProcess::ExitStatus)), mpGDBProcess, SLOT(deleteLater())); + mpGDBProcess->setProcessChannelMode(QProcess::MergedChannels); + QString program = QLatin1String("gdb"); +#ifdef WIN32 + program = Utilities::getGDBPath(); + const qint64 processId = GetCurrentProcessId(); +#else + const qint64 processId = getpid(); +#endif + mGDBArguments.clear(); + mGDBArguments << "-q" << "--nw" << "--nx" << "--batch" << "--command" << createTemporaryCommandsFile() << "--pid" << QString::number(processId); + mOutput.clear(); + mErrorOccurred = false; + mpGDBProcess->start(program, mGDBArguments); + mpGDBProcess->waitForFinished(-1); +} + +/*! + * \brief GDBBacktrace::createTemporaryCommandsFile + * Creates a temporary file for GDB commands. + * \return + */ +QString GDBBacktrace::createTemporaryCommandsFile() +{ + QTemporaryFile *pCommandsFile = new QTemporaryFile; + if (!pCommandsFile->open()) { + mOutput.append("Error: Could not create temporary commands file."); + return QString(); + } + connect(this, SIGNAL(finished()), pCommandsFile, SLOT(deleteLater())); + const char GdbBatchCommands[] = + "set height 0\n" + "set width 0\n" + "thread\n" + "thread apply all bt full\n"; + if (pCommandsFile->write(GdbBatchCommands) == -1) { + pCommandsFile->close(); + mOutput.append("Error: Could not write temporary commands file."); + return QString(); + } + pCommandsFile->close(); + return pCommandsFile->fileName(); +} + +/*! + * \brief GDBBacktrace::showCrashReportDialog + * Writes the stack trace file and shows the CrashReportDialog + */ +void GDBBacktrace::showCrashReportDialog() +{ + // Dump a stack trace to a file. + QFile stackTraceFile; + stackTraceFile.setFileName(QString("%1/openmodelica.stacktrace.%2").arg(Utilities::tempDirectory()).arg(Helper::OMCServerName)); + if (stackTraceFile.open(QIODevice::WriteOnly)) { + QTextStream out(&stackTraceFile); + out.setCodec(Helper::utf8.toStdString().data()); + out.setGenerateByteOrderMark(false); + out << mOutput; + out.flush(); + stackTraceFile.close(); + } + CrashReportDialog *pCrashReportDialog = new CrashReportDialog; + pCrashReportDialog->exec(); + emit finished(); +} + +/*! + * \brief GDBBacktrace::readGDBOutput + * Reads the GDB output. + */ +void GDBBacktrace::readGDBOutput() +{ + QString msg = QString(mpGDBProcess->readAll()); + // if we are unable to attach then set error occurred to true. + if (msg.startsWith("Could not attach to process", Qt::CaseInsensitive)) { + mErrorOccurred = true; + } + mOutput.append(msg); +} + +/*! + * \brief GDBBacktrace::handleGDBProcessError + * Handles the GDB process error. + * \param error + */ +void GDBBacktrace::handleGDBProcessError(QProcess::ProcessError error) +{ + Q_UNUSED(error); + mErrorOccurred = true; + mOutput.append(GUIMessages::getMessage(GUIMessages::GDB_ERROR).arg(mpGDBProcess->errorString()).arg(mGDBArguments.join(" "))); +} + +/*! + * \brief GDBBacktrace::handleGDBProcessFinished + * Handles the GDB process finished. + * \param exitCode + * \param exitStatus + */ +void GDBBacktrace::handleGDBProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + QString exitCodeStr = tr("GDB process failed. Exited with code %1.").arg(exitCode); + if (exitStatus == QProcess::NormalExit && exitCode == 0) { + if (!mErrorOccurred) { + showCrashReportDialog(); + } + } else { + mErrorOccurred = true; + mOutput.append(mpGDBProcess->errorString() + "\n" + exitCodeStr); + } +} diff --git a/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.h b/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.h new file mode 100644 index 00000000000..a23fb15ae50 --- /dev/null +++ b/OMEdit/OMEditGUI/CrashReport/GDBBacktrace.h @@ -0,0 +1,63 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE + * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ +/* + * @author Adeel Asghar + */ + +#ifndef GDBBACKTRACE_H +#define GDBBACKTRACE_H + +#include +#include + +class GDBBacktrace : public QObject +{ + Q_OBJECT +public: + GDBBacktrace(QObject *parent = 0); + QString output() {return mOutput;} + bool errorOccurred() {return mErrorOccurred;} +private: + QProcess *mpGDBProcess; + QStringList mGDBArguments; + QString mOutput; + bool mErrorOccurred; + + QString createTemporaryCommandsFile(); + void showCrashReportDialog(); +signals: + void finished(); +public slots: + void readGDBOutput(); + void handleGDBProcessError(QProcess::ProcessError error); + void handleGDBProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); +}; + +#endif // GDBBACKTRACE_H diff --git a/OMEdit/OMEditGUI/Debugger/GDB/GDBAdapter.cpp b/OMEdit/OMEditGUI/Debugger/GDB/GDBAdapter.cpp index 8ed6e0d86b9..ee9bd7c245a 100644 --- a/OMEdit/OMEditGUI/Debugger/GDB/GDBAdapter.cpp +++ b/OMEdit/OMEditGUI/Debugger/GDB/GDBAdapter.cpp @@ -1490,22 +1490,12 @@ void GDBAdapter::readGDBErrorOutput() */ void GDBAdapter::handleGDBProcessError(QProcess::ProcessError error) { + Q_UNUSED(error); /* this signal is raised when we kill the timed out GDB forcefully. */ if (isGDBKilled()) { return; } - QString errorString; - switch (error) { - case QProcess::FailedToStart: - errorString = tr("%1 GDB arguments are \"%2\"").arg(mpGDBProcess->errorString()).arg(mGDBArguments.join(" ")); - break; - case QProcess::Crashed: - errorString = tr("GDB crashed with the error %1. GDB arguments are \"%2\"").arg(mpGDBProcess->errorString()).arg(mGDBArguments.join(" ")); - break; - default: - errorString = tr("Following error has occurred %1. GDB arguments are \"%2\"").arg(mpGDBProcess->errorString()).arg(mGDBArguments.join(" ")); - break; - } + QString errorString = GUIMessages::getMessage(GUIMessages::GDB_ERROR).arg(mpGDBProcess->errorString()).arg(mGDBArguments.join(" ")); MainWindow::instance()->getTargetOutputWidget()->logDebuggerErrorOutput(errorString); setGDBRunning(false); } diff --git a/OMEdit/OMEditGUI/MainWindow.cpp b/OMEdit/OMEditGUI/MainWindow.cpp index 87967e77089..9f52f6274a3 100644 --- a/OMEdit/OMEditGUI/MainWindow.cpp +++ b/OMEdit/OMEditGUI/MainWindow.cpp @@ -44,6 +44,9 @@ #include "Debugger/Locals/LocalsWidget.h" #include "Modeling/DocumentationWidget.h" #include "Plotting/VariablesWidget.h" +#if !defined(WITHOUT_OSG) +#include "Animation/ThreeDViewer.h" +#endif #include "Util/Helper.h" #include "Simulation/SimulationOutputWidget.h" #include "TLM/FetchInterfaceDataDialog.h" @@ -135,7 +138,7 @@ void MainWindow::setUpMainWindow() setbuf(stdout, NULL); // used non-buffered stdout mpOutputFileDataNotifier = 0; mpOutputFileDataNotifier = new FileDataNotifier(outputFileName); - connect(mpOutputFileDataNotifier, SIGNAL(bytesAvailable(qint64)), SLOT(readOutputFile(qint64))); + connect(mpOutputFileDataNotifier, SIGNAL(sendData(QString)), SLOT(writeOutputFileData(QString))); mpOutputFileDataNotifier->start(); // Reopen the standard error stream. QString errorFileName = Utilities::tempDirectory() + "/omediterror.txt"; @@ -143,7 +146,7 @@ void MainWindow::setUpMainWindow() setbuf(stderr, NULL); // used non-buffered stderr mpErrorFileDataNotifier = 0; mpErrorFileDataNotifier = new FileDataNotifier(errorFileName); - connect(mpErrorFileDataNotifier, SIGNAL(bytesAvailable(qint64)), SLOT(readErrorFile(qint64))); + connect(mpErrorFileDataNotifier, SIGNAL(sendData(QString)), SLOT(writeErrorFileData(QString))); mpErrorFileDataNotifier->start(); // Create an object of QProgressBar mpProgressBar = new QProgressBar; @@ -263,6 +266,19 @@ void MainWindow::setUpMainWindow() mpVariablesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, mpVariablesDockWidget); mpVariablesDockWidget->setWidget(mpVariablesWidget); +#if !defined(WITHOUT_OSG) + // create an object of ThreeDViewer + mpThreeDViewer = new ThreeDViewer(this); + mpThreeDViewer->stopRenderFrameTimer(); + // Create ThreeDViewer dock + mpThreeDViewerDockWidget = new QDockWidget(tr("3D Viewer Browser"), this); + mpThreeDViewerDockWidget->setObjectName("3DViewer"); + mpThreeDViewerDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + mpThreeDViewerDockWidget->setWidget(mpThreeDViewer); + addDockWidget(Qt::RightDockWidgetArea, mpThreeDViewerDockWidget); + mpThreeDViewerDockWidget->hide(); + connect(mpThreeDViewerDockWidget, SIGNAL(visibilityChanged(bool)), SLOT(threeDViewerDockWidgetVisibilityChanged(bool))); +#endif // set the corners for the dock widgets setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); @@ -1364,25 +1380,25 @@ void MainWindow::loadSystemLibrary() } /*! - * \brief MainWindow::readOutputFile - * Reads the available output data from file and adds it to MessagesWidget. - * \param bytes + * \brief MainWindow::writeOutputFileData + * Writes the output data from stdout file and adds it to MessagesWidget. + * \param data */ -void MainWindow::readOutputFile(qint64 bytes) +void MainWindow::writeOutputFileData(QString data) { - QString data = mpOutputFileDataNotifier->read(bytes); - MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, data, Helper::scriptingKind, Helper::notificationLevel)); + MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, data, + Helper::scriptingKind, Helper::notificationLevel)); } /*! - * \brief MainWindow::readErrorFile - * Reads the available error data from file and adds it to MessagesWidget. - * \param bytes + * \brief MainWindow::writeErrorFileData + * Writes the error data from stderr file and adds it to MessagesWidget. + * \param data */ -void MainWindow::readErrorFile(qint64 bytes) +void MainWindow::writeErrorFileData(QString data) { - QString data = mpErrorFileDataNotifier->read(bytes); - MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, data, Helper::scriptingKind, Helper::notificationLevel)); + MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, "", false, 0, 0, 0, 0, data, + Helper::scriptingKind, Helper::errorLevel)); } //! Opens the recent file. @@ -2293,6 +2309,22 @@ void MainWindow::documentationDockWidgetVisibilityChanged(bool visible) } } +/*! + * \brief MainWindow::threeDViewerDockWidgetVisibilityChanged + * Handles the VisibilityChanged signal of ThreeDViewer Dock Widget. + * \param visible + */ +void MainWindow::threeDViewerDockWidgetVisibilityChanged(bool visible) +{ +#if !defined(WITHOUT_OSG) + if (visible) { + mpThreeDViewer->startRenderFrameTimer(); + } else { + mpThreeDViewer->stopRenderFrameTimer(); + } +#endif +} + /*! * \brief MainWindow::autoSave * Slot activated when mpAutoSaveTimer timeout SIGNAL is raised.\n @@ -2876,6 +2908,9 @@ void MainWindow::createMenus() pViewWindowsMenu->addAction(mpLibraryDockWidget->toggleViewAction()); pViewWindowsMenu->addAction(mpDocumentationDockWidget->toggleViewAction()); pViewWindowsMenu->addAction(mpVariablesDockWidget->toggleViewAction()); +#if !defined(WITHOUT_OSG) + pViewWindowsMenu->addAction(mpThreeDViewerDockWidget->toggleViewAction()); +#endif pViewWindowsMenu->addAction(mpMessagesDockWidget->toggleViewAction()); pViewWindowsMenu->addAction(mpStackFramesDockWidget->toggleViewAction()); pViewWindowsMenu->addAction(mpBreakpointsDockWidget->toggleViewAction()); @@ -2988,9 +3023,8 @@ void MainWindow::createMenus() */ void MainWindow::autoSaveHelper(LibraryTreeItem *pLibraryTreeItem) { - for (int i = 0; i < pLibraryTreeItem->childrenSize(); i++) { - LibraryTreeItem *pChildLibraryTreeItem = pLibraryTreeItem->child(i); - if (!pChildLibraryTreeItem->isSystemLibrary()) { + foreach (LibraryTreeItem *pChildLibraryTreeItem, pLibraryTreeItem->childrenItems()) { + if (pChildLibraryTreeItem && !pChildLibraryTreeItem->isSystemLibrary()) { if (pChildLibraryTreeItem->isFilePathValid() && !pChildLibraryTreeItem->isSaved()) { mpLibraryWidget->saveLibraryTreeItem(pChildLibraryTreeItem); } else { diff --git a/OMEdit/OMEditGUI/MainWindow.h b/OMEdit/OMEditGUI/MainWindow.h index 1f9f749b9e8..2c755bb1704 100644 --- a/OMEdit/OMEditGUI/MainWindow.h +++ b/OMEdit/OMEditGUI/MainWindow.h @@ -63,6 +63,9 @@ class GDBLoggerWidget; class DocumentationWidget; class PlotWindowContainer; class VariablesWidget; +#if !defined(WITHOUT_OSG) +class ThreeDViewer; +#endif class BreakpointsWidget; class SimulationDialog; class TLMCoSimulationDialog; @@ -213,6 +216,10 @@ class MainWindow : public QMainWindow PlotWindowContainer *mpPlotWindowContainer; VariablesWidget *mpVariablesWidget; QDockWidget *mpVariablesDockWidget; +#if !defined(WITHOUT_OSG) + ThreeDViewer *mpThreeDViewer; + QDockWidget *mpThreeDViewerDockWidget; +#endif SimulationDialog *mpSimulationDialog; TLMCoSimulationDialog *mpTLMCoSimulationDialog; ModelWidgetContainer *mpModelWidgetContainer; @@ -361,8 +368,8 @@ public slots: void loadExternalModels(); void openDirectory(); void loadSystemLibrary(); - void readOutputFile(qint64 bytes); - void readErrorFile(qint64 bytes); + void writeOutputFileData(QString data); + void writeErrorFileData(QString data); void openRecentFile(); void clearRecentFilesList(); void undo(); @@ -420,6 +427,7 @@ public slots: private slots: void perspectiveTabChanged(int tabIndex); void documentationDockWidgetVisibilityChanged(bool visible); + void threeDViewerDockWidgetVisibilityChanged(bool visible); void autoSave(); void switchToWelcomePerspectiveSlot(); void switchToModelingPerspectiveSlot(); diff --git a/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.cpp b/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.cpp index 127584b749f..d3f579dbfc6 100644 --- a/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.cpp +++ b/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.cpp @@ -2580,7 +2580,6 @@ void LibraryTreeView::createActions() // simulate Action mpSimulateAction = new QAction(QIcon(":/Resources/icons/simulate.svg"), Helper::simulate, this); mpSimulateAction->setStatusTip(Helper::simulateTip); - mpSimulateAction->setShortcut(QKeySequence("Ctrl+b")); connect(mpSimulateAction, SIGNAL(triggered()), SLOT(simulate())); // simulate with transformational debugger Action mpSimulateWithTransformationalDebuggerAction = new QAction(QIcon(":/Resources/icons/simulate-equation.svg"), Helper::simulateWithTransformationalDebugger, this); diff --git a/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.h b/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.h index 505bb5bc204..4dbc8682649 100644 --- a/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.h +++ b/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.h @@ -92,6 +92,7 @@ class LibraryTreeItem : public QObject bool isRootItem() {return mIsRootItem;} int childrenSize() const {return mChildren.size();} LibraryTreeItem* childAt(int index) const {return mChildren.at(index);} + QList childrenItems() {return mChildren;} LibraryType getLibraryType() {return mLibraryType;} void setLibraryType(LibraryType libraryType) {mLibraryType = libraryType;} void setSystemLibrary(bool systemLibrary) {mSystemLibrary = systemLibrary;} diff --git a/OMEdit/OMEditGUI/Modeling/ModelWidgetContainer.cpp b/OMEdit/OMEditGUI/Modeling/ModelWidgetContainer.cpp index f28836b327e..45a38631d0f 100644 --- a/OMEdit/OMEditGUI/Modeling/ModelWidgetContainer.cpp +++ b/OMEdit/OMEditGUI/Modeling/ModelWidgetContainer.cpp @@ -1880,7 +1880,7 @@ void GraphicsView::mouseDoubleClickEvent(QMouseEvent *event) /* Double click on Component also end up here. * But we don't have GraphicsView for the shapes inside the Component so we can go out of this block. */ - if (pShapeAnnotation && pShapeAnnotation->getGraphicsView()) { + if (!isCreatingConnection() && pShapeAnnotation && pShapeAnnotation->getGraphicsView()) { if (mpModelWidget->getLibraryTreeItem()->getLibraryType() == LibraryTreeItem::Modelica) { pShapeAnnotation->showShapeProperties(); return; diff --git a/OMEdit/OMEditGUI/OMC/OMCProxy.cpp b/OMEdit/OMEditGUI/OMC/OMCProxy.cpp index b40a31314df..6a65a933cab 100644 --- a/OMEdit/OMEditGUI/OMC/OMCProxy.cpp +++ b/OMEdit/OMEditGUI/OMC/OMCProxy.cpp @@ -952,6 +952,10 @@ QString OMCProxy::getComponentModifierValue(QString className, QString name) */ bool OMCProxy::setComponentModifierValue(QString className, QString modifierName, QString modifierValue) { + modifierValue = StringHandler::removeFirstLastQuotes(modifierValue); + if (StringHandler::containsSpace(modifierValue)) { + modifierValue = QString("\"%1\"").arg(modifierValue); + } QString expression; if (modifierValue.isEmpty()) { expression = QString("setComponentModifierValue(%1, %2, $Code(()))").arg(className).arg(modifierName); @@ -961,7 +965,7 @@ bool OMCProxy::setComponentModifierValue(QString className, QString modifierName expression = QString("setComponentModifierValue(%1, %2, $Code(=%3))").arg(className).arg(modifierName).arg(modifierValue); } sendCommand(expression); - if (getResult().toLower().contains("ok")) { + if (getResult().toLower().compare("ok") == 0) { return true; } else { QString msg = tr("Unable to set the component modifier value using command %1").arg(expression); @@ -1016,6 +1020,10 @@ QString OMCProxy::getExtendsModifierValue(QString className, QString extendsClas bool OMCProxy::setExtendsModifierValue(QString className, QString extendsClassName, QString modifierName, QString modifierValue) { + modifierValue = StringHandler::removeFirstLastQuotes(modifierValue); + if (StringHandler::containsSpace(modifierValue)) { + modifierValue = QString("\"%1\"").arg(modifierValue); + } QString expression; if (modifierValue.isEmpty()) { expression = QString("setExtendsModifierValue(%1, %2, %3, $Code(()))").arg(className).arg(extendsClassName).arg(modifierName); @@ -1027,7 +1035,7 @@ bool OMCProxy::setExtendsModifierValue(QString className, QString extendsClassNa .arg(modifierValue); } sendCommand(expression); - if (getResult().toLower().contains("ok")) { + if (getResult().toLower().compare("ok") == 0) { return true; } else { QString msg = tr("Unable to set the extends modifier value using command %1").arg(expression); @@ -1798,10 +1806,11 @@ bool OMCProxy::renameComponentInClass(QString className, QString oldName, QStrin bool OMCProxy::updateConnection(QString from, QString to, QString className, QString annotation) { sendCommand("updateConnection(" + from + "," + to + "," + className + "," + annotation + ")"); - if (getResult().contains("Ok")) + if (getResult().toLower().compare("ok") == 0) { return true; - else + } else { return false; + } } /*! @@ -1857,7 +1866,7 @@ bool OMCProxy::setComponentComment(QString className, QString componentName, QSt bool OMCProxy::setComponentDimensions(QString className, QString componentName, QString dimensions) { sendCommand("setComponentDimensions(" + className + "," + componentName + "," + dimensions + ")"); - if (getResult().contains("Ok")) { + if (getResult().toLower().compare("ok") == 0) { return true; } else { return false; @@ -1879,7 +1888,7 @@ bool OMCProxy::addConnection(QString from, QString to, QString className, QStrin } else { sendCommand("addConnection(" + from + "," + to + "," + className + "," + annotation + ")"); } - if (getResult().contains("Ok")) { + if (getResult().toLower().compare("ok") == 0) { return true; } else { return false; @@ -1896,10 +1905,9 @@ bool OMCProxy::addConnection(QString from, QString to, QString className, QStrin bool OMCProxy::deleteConnection(QString from, QString to, QString className) { sendCommand("deleteConnection(" + from + "," + to + "," + className + ")"); - if (getResult().contains("Ok")) + if (getResult().toLower().compare("ok") == 0) { return true; - else - { + } else { printMessagesStringInternal(); return false; } diff --git a/OMEdit/OMEditGUI/OMEditGUI.pro b/OMEdit/OMEditGUI/OMEditGUI.pro index ae18f385065..6269ade605e 100644 --- a/OMEdit/OMEditGUI/OMEditGUI.pro +++ b/OMEdit/OMEditGUI/OMEditGUI.pro @@ -98,13 +98,18 @@ win32 { CONFIG += osg } else { # Unix libraries and includes include(OMEdit.config) + # required for backtrace + # In order to get the stack trace in Windows we must add -g flag. Qt automatically adds the -O2 flag for optimization. + # We should also unset the QMAKE_LFLAGS_RELEASE define because it is defined as QMAKE_LFLAGS_RELEASE = -Wl,-s in qmake.conf file for MinGW + # -s will remove all symbol table and relocation information from the executable. # On unix we use backtrace of execinfo.h which requires -rdynamic # The symbol names may be unavailable without the use of special linker # options. For systems using the GNU linker, it is necessary to use # the -rdynamic linker option. Note that names of "static" functions # are not exposed, and won't be available in the backtrace. CONFIG(release, debug|release) { - QMAKE_LFLAGS_RELEASE += -rdynamic + QMAKE_CXXFLAGS += -g + QMAKE_LFLAGS_RELEASE = -rdynamic } } @@ -172,6 +177,7 @@ SOURCES += main.cpp \ Debugger/Attach/AttachToProcessDialog.cpp \ Debugger/Attach/ProcessListModel.cpp \ CrashReport/backtrace.c \ + CrashReport/GDBBacktrace.cpp \ CrashReport/CrashReportDialog.cpp HEADERS += Util/Helper.h \ @@ -239,29 +245,36 @@ HEADERS += Util/Helper.h \ Debugger/Attach/AttachToProcessDialog.h \ Debugger/Attach/ProcessListModel.h \ CrashReport/backtrace.h \ + CrashReport/GDBBacktrace.h \ CrashReport/CrashReportDialog.h CONFIG(osg) { -SOURCES += Animation/AnimationWindow.cpp \ +SOURCES += Animation/AbstractAnimationWindow.cpp \ + Animation/AnimationWindow.cpp \ + Animation/ThreeDViewer.cpp \ Animation/ExtraShapes.cpp \ Animation/Visualizer.cpp \ Animation/VisualizerMAT.cpp \ Animation/VisualizerCSV.cpp \ Animation/VisualizerFMU.cpp \ + Animation/FMUSettingsDialog.cpp \ Animation/FMUWrapper.cpp \ Animation/Shapes.cpp \ Animation/TimeManager.cpp \ ../../osgQt/GraphicsWindowQt.cpp \ -HEADERS += Animation/AnimationWindow.h \ +HEADERS += Animation/AbstractAnimationWindow.h \ + Animation/AnimationWindow.h \ + Animation/ThreeDViewer.h \ Animation/AnimationUtil.h \ Animation/ExtraShapes.h \ Animation/Visualizer.h \ Animation/VisualizerMAT.h \ Animation/VisualizerCSV.h \ Animation/VisualizerFMU.h \ + Animation/FMUSettingsDialog.h \ Animation/FMUWrapper.h \ Animation/Shapes.h \ Animation/TimeManager.h \ diff --git a/OMEdit/OMEditGUI/Options/OptionsDialog.cpp b/OMEdit/OMEditGUI/Options/OptionsDialog.cpp index f985636f7a6..c453874175b 100644 --- a/OMEdit/OMEditGUI/Options/OptionsDialog.cpp +++ b/OMEdit/OMEditGUI/Options/OptionsDialog.cpp @@ -801,6 +801,7 @@ void OptionsDialog::saveGeneralSettings() // save auto save mpSettings->setValue("autoSave/enable", mpGeneralSettingsPage->getEnableAutoSaveGroupBox()->isChecked()); mpSettings->setValue("autoSave/interval", mpGeneralSettingsPage->getAutoSaveIntervalSpinBox()->value()); + MainWindow::instance()->getAutoSaveTimer()->setInterval(mpGeneralSettingsPage->getAutoSaveIntervalSpinBox()->value() * 1000); MainWindow::instance()->toggleAutoSave(); // save welcome page switch (mpGeneralSettingsPage->getWelcomePageView()) { @@ -3974,19 +3975,7 @@ DebuggerPage::DebuggerPage(OptionsDialog *pOptionsDialog) mpGDBPathLabel = new Label(tr("GDB Path:")); mpGDBPathTextBox = new QLineEdit; #ifdef WIN32 -#if defined(__MINGW32__) && !defined(__MINGW64__) - const char *sgdb = "/tools/msys/mingw32/bin/gdb.exe"; -#endif -#if defined(__MINGW64__) - const char *sgdb = "/tools/msys/mingw64/bin/gdb.exe"; -#endif - const char *OMDEV = getenv("OMDEV"); - if (QString(OMDEV).isEmpty()) { - mpGDBPathTextBox->setPlaceholderText(QString(Helper::OpenModelicaHome).append(sgdb)); - } else { - QString qOMDEV = QString(OMDEV).replace("\\", "/"); - mpGDBPathTextBox->setPlaceholderText(QString(qOMDEV).append(sgdb)); - } + mpGDBPathTextBox->setPlaceholderText(Utilities::getGDBPath()); #else mpGDBPathTextBox->setPlaceholderText("gdb"); #endif diff --git a/OMEdit/OMEditGUI/Resources/icons/play.svg b/OMEdit/OMEditGUI/Resources/icons/play.svg deleted file mode 100644 index b51ba6dd02f..00000000000 --- a/OMEdit/OMEditGUI/Resources/icons/play.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/OMEdit/OMEditGUI/Simulation/SimulationDialog.cpp b/OMEdit/OMEditGUI/Simulation/SimulationDialog.cpp index 9729218e4c2..ca041f658ad 100644 --- a/OMEdit/OMEditGUI/Simulation/SimulationDialog.cpp +++ b/OMEdit/OMEditGUI/Simulation/SimulationDialog.cpp @@ -1215,6 +1215,8 @@ void SimulationDialog::performSimulation() } MainWindow::instance()->getOMCProxy()->setCommandLineOptions("+profiling=" + mpProfilingComboBox->currentText()); simulationOptions = createSimulationOptions(); + // change the cursor to Qt::WaitCursor + QApplication::setOverrideCursor(Qt::WaitCursor); // show the progress bar MainWindow::instance()->getStatusBar()->showMessage(tr("Translating %1.").arg(mClassName)); MainWindow::instance()->getProgressBar()->setRange(0, 0); @@ -1223,6 +1225,8 @@ void SimulationDialog::performSimulation() // hide the progress bar MainWindow::instance()->hideProgressBar(); MainWindow::instance()->getStatusBar()->clearMessage(); + // restore the cursor + QApplication::restoreOverrideCursor(); mIsReSimulate = false; if (isTranslationSuccessful) { // check if we can compile using the target compiler diff --git a/OMEdit/OMEditGUI/Simulation/SimulationOutputWidget.cpp b/OMEdit/OMEditGUI/Simulation/SimulationOutputWidget.cpp index 88f009b2bc9..965742ac37a 100644 --- a/OMEdit/OMEditGUI/Simulation/SimulationOutputWidget.cpp +++ b/OMEdit/OMEditGUI/Simulation/SimulationOutputWidget.cpp @@ -596,6 +596,7 @@ void SimulationOutputWidget::simulationProcessFinished(int exitCode, QProcess::E void SimulationOutputWidget::cancelCompilationOrSimulation() { if (mpSimulationProcessThread->isCompilationProcessRunning()) { + mpSimulationProcessThread->setCompilationProcessKilled(true); mpSimulationProcessThread->getCompilationProcess()->kill(); mpProgressLabel->setText(tr("Compilation of %1 is cancelled.").arg(mSimulationOptions.getClassName())); mpProgressBar->setRange(0, 1); @@ -603,6 +604,7 @@ void SimulationOutputWidget::cancelCompilationOrSimulation() mpCancelButton->setEnabled(false); mpArchivedSimulationItem->setStatus(Helper::finished); } else if (mpSimulationProcessThread->isSimulationProcessRunning()) { + mpSimulationProcessThread->setSimulationProcessKilled(true); mpSimulationProcessThread->getSimulationProcess()->kill(); mpProgressLabel->setText(tr("Simulation of %1 is cancelled.").arg(mSimulationOptions.getClassName())); mpProgressBar->setValue(mpProgressBar->maximum()); diff --git a/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.cpp b/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.cpp index 987af702844..10d0088ad67 100644 --- a/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.cpp +++ b/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.cpp @@ -40,8 +40,10 @@ SimulationProcessThread::SimulationProcessThread(SimulationOutputWidget *pSimula : QThread(pSimulationOutputWidget), mpSimulationOutputWidget(pSimulationOutputWidget) { mpCompilationProcess = 0; + setCompilationProcessKilled(false); mIsCompilationProcessRunning = false; mpSimulationProcess = 0; + setSimulationProcessKilled(false); mIsSimulationProcessRunning = false; } @@ -68,10 +70,16 @@ void SimulationProcessThread::compileModel() mpCompilationProcess = new QProcess; SimulationOptions simulationOptions = mpSimulationOutputWidget->getSimulationOptions(); mpCompilationProcess->setWorkingDirectory(simulationOptions.getWorkingDirectory()); + qRegisterMetaType("QProcess::ProcessError"); qRegisterMetaType("QProcess::ExitStatus"); connect(mpCompilationProcess, SIGNAL(started()), SLOT(compilationProcessStarted()), Qt::DirectConnection); connect(mpCompilationProcess, SIGNAL(readyReadStandardOutput()), SLOT(readCompilationStandardOutput()), Qt::DirectConnection); connect(mpCompilationProcess, SIGNAL(readyReadStandardError()), SLOT(readCompilationStandardError()), Qt::DirectConnection); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect(mpCompilationProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(compilationProcessError(QProcess::ProcessError)), Qt::DirectConnection); +#else + connect(mpCompilationProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(compilationProcessError(QProcess::ProcessError)), Qt::DirectConnection); +#endif connect(mpCompilationProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(compilationProcessFinished(int,QProcess::ExitStatus)), Qt::DirectConnection); QString numProcs; if (simulationOptions.getNumberOfProcessors() == 0) { @@ -89,16 +97,16 @@ void SimulationProcessThread::compileModel() #endif args << simulationOptions.getOutputFileName() << pSimulationPage->getTargetCompilerComboBox()->currentText() << omPlatform << "parallel" << numProcs << "0"; QString compilationProcessPath = QString(Helper::OpenModelicaHome) + "/share/omc/scripts/Compile.bat"; - mpCompilationProcess->start(compilationProcessPath, args); emit sendCompilationOutput(QString("%1 %2\n").arg(compilationProcessPath).arg(args.join(" ")), Qt::blue); + mpCompilationProcess->start(compilationProcessPath, args); #else int numProcsInt = numProcs.toInt(); if (numProcsInt > 1) { args << "-j" + numProcs; } args << "-f" << simulationOptions.getOutputFileName() + ".makefile"; - mpCompilationProcess->start("make", args); emit sendCompilationOutput(QString("%1 %2\n").arg("make").arg(args.join(" ")), Qt::blue); + mpCompilationProcess->start("make", args); #endif } @@ -115,6 +123,11 @@ void SimulationProcessThread::runSimulationExecutable() connect(mpSimulationProcess, SIGNAL(started()), SLOT(simulationProcessStarted()), Qt::DirectConnection); connect(mpSimulationProcess, SIGNAL(readyReadStandardOutput()), SLOT(readSimulationStandardOutput()), Qt::DirectConnection); connect(mpSimulationProcess, SIGNAL(readyReadStandardError()), SLOT(readSimulationStandardError()), Qt::DirectConnection); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect(mpSimulationProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(simulationProcessError(QProcess::ProcessError)), Qt::DirectConnection); +#else + connect(mpSimulationProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(simulationProcessError(QProcess::ProcessError)), Qt::DirectConnection); +#endif connect(mpSimulationProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(simulationProcessFinished(int,QProcess::ExitStatus)), Qt::DirectConnection); QStringList args(QString("-port=").append(QString::number(mpSimulationOutputWidget->getTcpServer()->serverPort()))); args << "-logFormat=xmltcp" << simulationOptions.getSimulationFlags(); @@ -129,8 +142,8 @@ void SimulationProcessThread::runSimulationExecutable() processEnvironment.insert("PATH", fileInfo.absoluteDir().absolutePath() + ";" + processEnvironment.value("PATH")); mpSimulationProcess->setProcessEnvironment(processEnvironment); #endif - mpSimulationProcess->start(fileName, args); emit sendSimulationOutput(QString("%1 %2").arg(fileName).arg(args.join(" ")), StringHandler::OMEditInfo, true); + mpSimulationProcess->start(fileName, args); } /*! @@ -164,6 +177,23 @@ void SimulationProcessThread::readCompilationStandardError() emit sendCompilationOutput(QString(mpCompilationProcess->readAllStandardError()), Qt::red); } +/*! + * \brief SimulationProcessThread::compilationProcessError + * Slot activated when mpCompilationProcess errorOccurred signal is raised.\n + * Notifies the SimulationOutputWidget about the erro by emitting the sendCompilationOutput signal. + * \param error + */ +void SimulationProcessThread::compilationProcessError(QProcess::ProcessError error) +{ + Q_UNUSED(error); + /* this signal is raised when we kill the compilation process forcefully. */ + if (isCompilationProcessKilled()) { + return; + } + mIsCompilationProcessRunning = false; + emit sendCompilationOutput(mpCompilationProcess->errorString(), Qt::red); +} + /*! * \brief SimulationProcessThread::compilationProcessFinished * Slot activated when mpCompilationProcess finished signal is raised.\n @@ -224,6 +254,23 @@ void SimulationProcessThread::readSimulationStandardError() emit sendSimulationOutput(QString(mpSimulationProcess->readAllStandardError()), StringHandler::Error, true); } +/*! + * \brief SimulationProcessThread::simulationProcessError + * Slot activated when mpSimulationProcess errorOccurred signal is raised.\n + * Notifies the SimulationOutputWidget about the erro by emitting the sendSimulationOutput signal. + * \param error + */ +void SimulationProcessThread::simulationProcessError(QProcess::ProcessError error) +{ + Q_UNUSED(error); + /* this signal is raised when we kill the simulation process forcefully. */ + if (isSimulationProcessKilled()) { + return; + } + mIsSimulationProcessRunning = false; + emit sendSimulationOutput(mpSimulationProcess->errorString(), StringHandler::Error, true); +} + /*! * \brief SimulationProcessThread::simulationProcessFinished * Slot activated when mpSimulationProcess finished signal is raised.\n diff --git a/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.h b/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.h index 5e7b086f118..750b1b789b5 100644 --- a/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.h +++ b/OMEdit/OMEditGUI/Simulation/SimulationProcessThread.h @@ -46,16 +46,22 @@ class SimulationProcessThread : public QThread public: SimulationProcessThread(SimulationOutputWidget *pSimulationOutputWidget); QProcess* getCompilationProcess() {return mpCompilationProcess;} + void setCompilationProcessKilled(bool killed) {mIsCompilationProcessKilled = killed;} + bool isCompilationProcessKilled() {return mIsCompilationProcessKilled;} bool isCompilationProcessRunning() {return mIsCompilationProcessRunning;} QProcess* getSimulationProcess() {return mpSimulationProcess;} + void setSimulationProcessKilled(bool killed) {mIsSimulationProcessKilled = killed;} + bool isSimulationProcessKilled() {return mIsSimulationProcessKilled;} bool isSimulationProcessRunning() {return mIsSimulationProcessRunning;} protected: virtual void run(); private: SimulationOutputWidget *mpSimulationOutputWidget; QProcess *mpCompilationProcess; + bool mIsCompilationProcessKilled; bool mIsCompilationProcessRunning; QProcess *mpSimulationProcess; + bool mIsSimulationProcessKilled; bool mIsSimulationProcessRunning; void compileModel(); @@ -64,10 +70,12 @@ private slots: void compilationProcessStarted(); void readCompilationStandardOutput(); void readCompilationStandardError(); + void compilationProcessError(QProcess::ProcessError error); void compilationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void simulationProcessStarted(); void readSimulationStandardOutput(); void readSimulationStandardError(); + void simulationProcessError(QProcess::ProcessError error); void simulationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); signals: void sendCompilationStarted(); diff --git a/OMEdit/OMEditGUI/Util/Helper.cpp b/OMEdit/OMEditGUI/Util/Helper.cpp index d533b092d93..b3ed8acc40c 100644 --- a/OMEdit/OMEditGUI/Util/Helper.cpp +++ b/OMEdit/OMEditGUI/Util/Helper.cpp @@ -49,7 +49,7 @@ QString Helper::omFileTypes = "Modelica Files (*.mo)"; QString Helper::omnotebookFileTypes = "OMNotebook Files (*.onb *.onbz *.nb)"; QString Helper::ngspiceNetlistFileTypes = "ngspice Netlist Files (*.cir *.sp *.spice)"; QString Helper::imageFileTypes = "SVG (*.svg);;PNG image (*.png);;Windows BMP image (*.bmp);;TIFF (*.tiff)"; -QString Helper::bitmapFileTypes = "PNG image (*.png);Windows BMP image (*.bmp);JPEG (*.jpg *.jpeg)"; +QString Helper::bitmapFileTypes = "Image Files (*.png *.bmp *.jpg *.jpeg);;PNG image (*.png);;Windows BMP image (*.bmp);;JPEG (*.jpg *.jpeg)"; QString Helper::fmuFileTypes = "FMU Files (*.fmu)"; QString Helper::xmlFileTypes = "XML Files (*.xml)"; QString Helper::infoXmlFileTypes = "OM Info Files (*_info.json)"; @@ -680,6 +680,8 @@ QString GUIMessages::getMessage(int type) .arg(Helper::simulate); case MULTIPLE_DECLARATIONS_COMPONENT: return tr("Multiple declarations of component %1 are found."); + case GDB_ERROR: + return tr("Following error has occurred %1 GDB arguments are \"%2\""); default: return ""; } diff --git a/OMEdit/OMEditGUI/Util/Helper.h b/OMEdit/OMEditGUI/Util/Helper.h index a389fa093e9..7d159e12c2d 100644 --- a/OMEdit/OMEditGUI/Util/Helper.h +++ b/OMEdit/OMEditGUI/Util/Helper.h @@ -397,7 +397,8 @@ class GUIMessages : public QObject TERMINAL_COMMAND_NOT_SET, UNABLE_FIND_COMPONENT, SELECT_SIMULATION_OPTION, - MULTIPLE_DECLARATIONS_COMPONENT + MULTIPLE_DECLARATIONS_COMPONENT, + GDB_ERROR }; static QString getMessage(int type); diff --git a/OMEdit/OMEditGUI/Util/StringHandler.cpp b/OMEdit/OMEditGUI/Util/StringHandler.cpp index 3c231d6ed67..9d58ec821a5 100644 --- a/OMEdit/OMEditGUI/Util/StringHandler.cpp +++ b/OMEdit/OMEditGUI/Util/StringHandler.cpp @@ -1607,3 +1607,19 @@ bool StringHandler::isFileWritAble(QString filePath) return true; } } + +/*! + * \brief StringHandler::containsSpace + * Returns true if string contains a space. + * \param str + * \return + */ +bool StringHandler::containsSpace(QString str) +{ + for (int i = 0 ; i < str.size() ; i++) { + if (str.at(i).isSpace()) { + return true; + } + } + return false; +} diff --git a/OMEdit/OMEditGUI/Util/StringHandler.h b/OMEdit/OMEditGUI/Util/StringHandler.h index 19b98df8673..5d25812b24a 100644 --- a/OMEdit/OMEditGUI/Util/StringHandler.h +++ b/OMEdit/OMEditGUI/Util/StringHandler.h @@ -152,6 +152,7 @@ class StringHandler : public QObject static QMap getLeadingSpaces(QString contents); static int getLeadingSpacesSize(QString str); static bool isFileWritAble(QString filePath); + static bool containsSpace(QString str); protected: static QString mLastOpenDir; }; diff --git a/OMEdit/OMEditGUI/Util/Utilities.cpp b/OMEdit/OMEditGUI/Util/Utilities.cpp index d47936742f1..f5fbd1a923c 100644 --- a/OMEdit/OMEditGUI/Util/Utilities.cpp +++ b/OMEdit/OMEditGUI/Util/Utilities.cpp @@ -149,7 +149,6 @@ FileDataNotifier::FileDataNotifier(const QString fileName) { mFile.setFileName(fileName); mStop = false; - mBytesAvailable = 0; } /*! @@ -164,17 +163,6 @@ void FileDataNotifier::exit(int retcode) QThread::exit(retcode); } -/*! - * \brief FileDataNotifier::read - * Reads the bytes from the file. - * \param maxlen - * \return - */ -QByteArray FileDataNotifier::read(qint64 maxlen) -{ - return mFile.read(maxlen); -} - /*! * \brief FileDataNotifier::run * Reimplentation of QThread::run(). @@ -190,9 +178,8 @@ void FileDataNotifier::run() break; } // if file has bytes available to read. - if (mFile.bytesAvailable() > mBytesAvailable) { - mBytesAvailable = mFile.bytesAvailable(); - emit bytesAvailable(mFile.bytesAvailable()); + if (mFile.bytesAvailable() > 0) { + emit sendData(QString(mFile.readAll())); } Sleep::sleep(1); } @@ -813,6 +800,25 @@ QGenericMatrix<3,3, double> Utilities::getRotationMatrix(QGenericMatrix<3,1,doub return R; } +#ifdef WIN32 +QString Utilities::getGDBPath() +{ +#if defined(__MINGW32__) && !defined(__MINGW64__) + const char *sgdb = "/tools/msys/mingw32/bin/gdb.exe"; +#endif +#if defined(__MINGW64__) + const char *sgdb = "/tools/msys/mingw64/bin/gdb.exe"; +#endif + const char *OMDEV = getenv("OMDEV"); + if (QString(OMDEV).isEmpty()) { + return QString(Helper::OpenModelicaHome).append(sgdb); + } else { + QString qOMDEV = QString(OMDEV).replace("\\", "/"); + return QString(qOMDEV).append(sgdb); + } +} +#endif + Utilities::FileIconProvider::FileIconProviderImplementation *instance() { static Utilities::FileIconProvider::FileIconProviderImplementation theInstance; diff --git a/OMEdit/OMEditGUI/Util/Utilities.h b/OMEdit/OMEditGUI/Util/Utilities.h index 3bfc5397db6..7d600cfcc9e 100644 --- a/OMEdit/OMEditGUI/Util/Utilities.h +++ b/OMEdit/OMEditGUI/Util/Utilities.h @@ -120,17 +120,15 @@ class FileDataNotifier : public QThread public: FileDataNotifier(const QString fileName); void exit(int retcode = 0); - QByteArray read(qint64 maxlen); private: QFile mFile; bool mStop; - qint64 mBytesAvailable; protected: void run(); public slots: void start(Priority = InheritPriority); signals: - void bytesAvailable(qint64 bytes); + void sendData(QString data); }; /*! @@ -444,6 +442,9 @@ namespace Utilities { bool isModelicaFile(QString extension); void insertText(QPlainTextEdit *pPlainTextEdit, QString text, QTextCharFormat format = QTextCharFormat()); QGenericMatrix<3,3, double> getRotationMatrix(QGenericMatrix<3,1,double> rotation); +#ifdef WIN32 + QString getGDBPath(); +#endif namespace FileIconProvider { class FileIconProviderImplementation : public QFileIconProvider diff --git a/OMEdit/OMEditGUI/main.cpp b/OMEdit/OMEditGUI/main.cpp index 9b791c2be18..0d9d4d97263 100644 --- a/OMEdit/OMEditGUI/main.cpp +++ b/OMEdit/OMEditGUI/main.cpp @@ -59,6 +59,7 @@ #include "MainWindow.h" #include "Util/Helper.h" +#include "CrashReport/GDBBacktrace.h" #include "CrashReport/CrashReportDialog.h" #include "Modeling/LibraryTreeWidget.h" #include "meta/meta_modelica.h" @@ -71,116 +72,135 @@ #include #ifdef QT_NO_DEBUG -#ifndef WIN32 +/*! + * \brief writeGDBErrorFile + * Writes the gdberror.log file if gdb based stack trace has failed. + * \param output + */ +static inline void writeGDBErrorFile(QString output) +{ + QFile gdbErrorFile; + gdbErrorFile.setFileName(QString("%1gdberror.log").arg(Utilities::tempDirectory())); + if (gdbErrorFile.open(QIODevice::WriteOnly)) { + QTextStream out(&gdbErrorFile); + out.setCodec(Helper::utf8.toStdString().data()); + out.setGenerateByteOrderMark(false); + out << output; + out.flush(); + gdbErrorFile.close(); + } +} + +#ifdef WIN32 +#include "CrashReport/backtrace.h" + +static char *g_output = NULL; +LONG WINAPI exceptionFilter(LPEXCEPTION_POINTERS info) +{ + GDBBacktrace *pGDBBacktrace = new GDBBacktrace; + if (pGDBBacktrace->errorOccurred()) { + /* gdb backtrace has failed fallback to normal one. + * write a file gdberror.log to see why gdb backtrace has failed. + */ + writeGDBErrorFile(pGDBBacktrace->output()); + if (g_output == NULL) { + g_output = (char*) malloc(BUFFER_MAX); + } + struct output_buffer ob; + output_init(&ob, g_output, BUFFER_MAX); + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) { + output_print(&ob,"Failed to init symbol context\n"); + } else { + bfd_init(); + struct bfd_set *set = (bfd_set*)calloc(1,sizeof(*set)); + _backtrace(&ob , set , 128 , info->ContextRecord); + release_set(set); + SymCleanup(GetCurrentProcess()); + } + // Dump a stack trace to a file. + QFile stackTraceFile; + stackTraceFile.setFileName(QString("%1/openmodelica.stacktrace.%2").arg(Utilities::tempDirectory()).arg(Helper::OMCServerName)); + if (stackTraceFile.open(QIODevice::WriteOnly)) { + QTextStream out(&stackTraceFile); + out.setCodec(Helper::utf8.toStdString().data()); + out.setGenerateByteOrderMark(false); + out << g_output; + out.flush(); + stackTraceFile.close(); + } + CrashReportDialog *pCrashReportDialog = new CrashReportDialog; + pCrashReportDialog->exec(); + } + exit(1); +} +#else // Unix #include #include + static inline void printStackTrace(QFile *pFile, int signalNumber, const char* signalName, unsigned int max_frames = 50) { QTextStream out(pFile); out.setCodec(Helper::utf8.toStdString().data()); out.setGenerateByteOrderMark(false); - if (signalName) + if (signalName) { out << QString("Caught signal %1 (%2)\n").arg(QString::number(signalNumber)).arg(signalName); - else + } else { out << QString("Caught signal %1\n").arg(QString::number(signalNumber)); + } out.flush(); // storage array for stack trace address data void* addrlist[max_frames+1]; // retrieve current stack addresses int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); - if (addrlen == 0) - { + if (addrlen == 0) { out << "Stack address length is empty.\n"; return; } // create readable strings to each frame. backtrace_symbols_fd(addrlist, addrlen, pFile->handle()); - /* - backtrace_symbols uses malloc. Its better to use backtrace_symbols_fd. - */ + /* backtrace_symbols uses malloc. Its better to use backtrace_symbols_fd. */ /*char** symbollist = backtrace_symbols(addrlist, addrlen); - // print the stack trace. - for (int i = 4; i < addrlen; i++) - { - out << QString("%1\n").arg(symbollist[i]); - } - free(symbollist);*/ -} - -void signalHandler(int signum) -{ - // associate each signal with a signal name string. - const char* name = NULL; - switch(signum) - { - case SIGABRT: name = "SIGABRT"; break; - case SIGSEGV: name = "SIGSEGV"; break; - case SIGILL: name = "SIGILL"; break; - case SIGFPE: name = "SIGFPE"; break; - default: break; - } - // Dump a stack trace to a file. - QFile stackTraceFile; - QString& tmpPath = Utilities::tempDirectory(); - stackTraceFile.setFileName(QString("%1openmodelica.stacktrace.%2").arg(tmpPath).arg(Helper::OMCServerName)); - if (stackTraceFile.open(QIODevice::WriteOnly | QIODevice::Text)) + // print the stack trace. + for (int i = 4; i < addrlen; i++) { - printStackTrace(&stackTraceFile, signum, name); - stackTraceFile.close(); + out << QString("%1\n").arg(symbollist[i]); } - if (name) - fprintf(stderr, "Caught signal %d", signum); - else - fprintf(stderr, "Caught signal %d (%s)", signum, name); - CrashReportDialog *pCrashReportDialog = new CrashReportDialog; - pCrashReportDialog->exec(); - - // If you caught one of the above signals, it is likely you just - // want to quit your program right now. - exit(signum); + free(symbollist);*/ } -#endif // #ifndef WIN32 -#endif // #ifdef QT_NO_DEBUG -#ifdef QT_NO_DEBUG -#ifdef WIN32 -#include "CrashReport/backtrace.h" -static char *g_output = NULL; -LONG WINAPI exceptionFilter(LPEXCEPTION_POINTERS info) +void signalHandler(int signum) { - if (g_output == NULL) - { - g_output = (char*) malloc(BUFFER_MAX); - } - struct output_buffer ob; - output_init(&ob, g_output, BUFFER_MAX); - if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) - { - output_print(&ob,"Failed to init symbol context\n"); - } - else - { - bfd_init(); - struct bfd_set *set = (bfd_set*)calloc(1,sizeof(*set)); - _backtrace(&ob , set , 128 , info->ContextRecord); - release_set(set); - SymCleanup(GetCurrentProcess()); - } - // Dump a stack trace to a file. - QFile stackTraceFile; - stackTraceFile.setFileName(QString("%1/openmodelica.stacktrace.%2").arg(Utilities::tempDirectory()).arg(Helper::OMCServerName)); - if (stackTraceFile.open(QIODevice::WriteOnly | QIODevice::Text)) - { - QTextStream out(&stackTraceFile); - out.setCodec(Helper::utf8.toStdString().data()); - out.setGenerateByteOrderMark(false); - out << g_output; - out.flush(); - stackTraceFile.close(); + GDBBacktrace *pGDBBacktrace = new GDBBacktrace; + if (pGDBBacktrace->errorOccurred()) { + /* gdb backtrace has failed fallback to normal one. + * write a file gdberror.log to see why gdb backtrace has failed. + */ + writeGDBErrorFile(pGDBBacktrace->output()); + // associate each signal with a signal name string. + const char* name = NULL; + switch(signum) { + case SIGABRT: name = "SIGABRT"; break; + case SIGSEGV: name = "SIGSEGV"; break; + case SIGILL: name = "SIGILL"; break; + case SIGFPE: name = "SIGFPE"; break; + default: break; + } + // Dump a stack trace to a file. + QFile stackTraceFile; + stackTraceFile.setFileName(QString("%1openmodelica.stacktrace.%2").arg(Utilities::tempDirectory()).arg(Helper::OMCServerName)); + if (stackTraceFile.open(QIODevice::WriteOnly)) { + printStackTrace(&stackTraceFile, signum, name); + stackTraceFile.close(); + } + if (name) { + fprintf(stderr, "Caught signal %d", signum); + } else { + fprintf(stderr, "Caught signal %d (%s)", signum, name); + } + CrashReportDialog *pCrashReportDialog = new CrashReportDialog; + pCrashReportDialog->exec(); } - CrashReportDialog *pCrashReportDialog = new CrashReportDialog; - pCrashReportDialog->exec(); - exit(1); + exit(signum); } #endif // #ifdef WIN32 #endif // #ifdef QT_NO_DEBUG