20 #include <sys/types.h>
23 #include <QMdiSubWindow>
24 #include <QFileDialog>
25 #include <QMessageBox>
36 #include <qtermwidget5/qtermwidget.h>
43 "pip install libconf\n"
47 "MMOC_SRC = os.environ['MMOC_SRC']\n"
48 "sys.path.append(MMOC_SRC+'/python')\n"
49 "sys.path.append(MMOC_SRC+'/python/qss_solver')\n"
51 "import qss_solver.results as solver_results\n"
52 "import qss_solver.model as solver_model\n"
53 "import qss_solver.simulate as solver_sim\n"
54 "c = os.system(\'clear\')\n";
64 QByteArray new_geometry = saveGeometry();
65 QByteArray new_state = saveState(0);
67 settings.setValue(
"main_window_geometry", new_geometry);
68 settings.setValue(
"main_window_state", new_state);
78 _sim_progress->setVisible(
false);
80 headers << tr(
"File") << tr(
"Variable") << tr(
"Settings");
85 _compiler_msg->setTextColor(Qt::black);
86 _compiler_msg->setReadOnly(
true);
87 setWindowState(Qt::WindowMaximized);
106 _console->setScrollBarPosition(QTermWidget::ScrollBarRight);
108 _console_widget->setWidget(
_console);
111 const auto geometry = settings.value(
"main_window_geometry").toByteArray();
112 const auto state = settings.value(
"main_window_state").toByteArray();
114 restoreGeometry(geometry);
121 action_New->setEnabled(f);
122 action_Load->setEnabled(f);
123 actionImport->setEnabled(f);
124 action_Save->setEnabled(f);
125 action_Save_As->setEnabled(f);
126 actionSa_ve_All->setEnabled(f);
127 actionRun->setEnabled(f);
128 actionRun_2->setEnabled(f);
129 actionSettings->setEnabled(f);
130 actionCompile->setEnabled(!f);
131 actionDebug->setEnabled(f);
132 actionLog->setEnabled(f);
133 actionGraphics->setEnabled(f);
134 actionClear_Log->setEnabled(f);
135 actionMicroModelica_Language_Scpefication->setEnabled(f);
140 _model_toolbar->addAction(action_New);
141 _model_toolbar->addAction(action_Load);
142 _model_toolbar->addAction(actionImport);
143 _model_toolbar->addSeparator();
144 _model_toolbar->addAction(action_Save);
145 _model_toolbar->addAction(action_Save_As);
146 _model_toolbar->addAction(actionSa_ve_All);
147 _model_toolbar->addAction(actionSettings);
148 _model_toolbar->addSeparator();
149 _model_toolbar->addAction(actionRun);
150 _model_toolbar->addAction(actionRun_2);
151 _model_toolbar->addAction(actionCompile);
152 _model_toolbar->addAction(actionDebug);
153 _model_toolbar->addSeparator();
154 _model_toolbar->addAction(actionLog);
155 _model_toolbar->addAction(actionGraphics);
156 _model_toolbar->addAction(actionClear_Log);
161 menu_View->addAction(_model_plot->toggleViewAction());
162 menu_View->addAction(_model_messages->toggleViewAction());
167 QMdiSubWindow *sw = mdiArea->currentSubWindow();
173 _model_variables->setModel(NULL);
181 QMdiSubWindow *sw = mdiArea->currentSubWindow();
191 QMdiSubWindow
const *sw = mdiArea->currentSubWindow();
207 QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Load SBML Model"),
_utils->
appDir(
MMOC_MODELS),
"XML *.xml (*.xml)");
208 if (fileName.isNull()) {
211 QFileInfo sbmlfi(fileName);
213 modelsDir.mkdir(sbmlfi.baseName());
214 modelsDir.cd(sbmlfi.baseName());
215 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nImport SBML model: ") + fileName);
216 _proc =
new QProcess(
this);
218 _sbmlFile = modelsDir.absolutePath() +
SLASH + sbmlfi.baseName() +
".mo";
223 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
225 _proc->setProcessEnvironment(env);
235 QMdiSubWindow *sw = mdiArea->currentSubWindow();
239 QMdiSubWindow *sw =
new QMdiSubWindow(
this, Qt::CustomizeWindowHint);
241 mdiArea->addSubWindow(sw);
253 QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Load Model"),
_utils->
appDir(
MMOC_MODELS),
"MicroModelica *.mo (*.mo)");
254 if (fileName.isNull()) {
263 _compiler_msg->clear();
270 QString link =
"http://www.fceia.unr.edu.ar/control/modelica/micromodelicaspec.pdf";
271 QDesktopServices::openUrl(QUrl(link));
276 QString link =
"http://www.cifasis-conicet.gov.ar/jfernandez/engine/";
277 QDesktopServices::openUrl(QUrl(link));
282 QString link =
"http://www.cifasis-conicet.gov.ar/jfernandez/mmoc/";
283 QDesktopServices::openUrl(QUrl(link));
288 QString link =
"http://www.cifasis-conicet.gov.ar/jfernandez/sbml/";
289 QDesktopServices::openUrl(QUrl(link));
294 if (exitStatus == QProcess::NormalExit && exitCode == 0) {
295 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_proc->readAllStandardError());
296 QByteArray logs =
_proc->readAllStandardOutput();
297 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") + logs);
298 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"Simulation ended."));
306 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_proc->readAllStandardError());
307 QByteArray logs =
_proc->readAllStandardOutput();
308 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") + logs);
309 _compiler_msg->setPlainText(_compiler_msg->toPlainText() +
"Simulation failed. Exit code: " + QString::number(exitCode));
313 _compiler_msg->moveCursor(QTextCursor::End);
314 _compiler_msg->ensureCursorVisible();
316 _sim_progress->setVisible(
false);
327 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCreating/cleaning directory: ") + outputDir.absolutePath());
329 _proc =
new QProcess(
this);
334 args << QString(
"true");
336 args << _mo_file.absolutePath();
338 args << QString(
"false");
341 args << QString(
"true");
343 args << QString(
"false");
347 _sim_progress->setMaximum(100);
348 _sim_progress->reset();
349 _sim_progress->setVisible(
true);
350 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nStarting simulation.\n"));
351 _compiler_msg->moveCursor(QTextCursor::End);
352 _compiler_msg->ensureCursorVisible();
354 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
366 _proc->setProcessEnvironment(env);
372 QString out(
_proc->readAllStandardError().constData());
373 int _init = out.lastIndexOf(
'*');
375 int pc = (out.mid(_init + 1).toDouble() /
_timeInterval) * 100.0;
376 _sim_progress->setValue(pc);
425 if (!exefi.exists()) {
445 QMessageBox::information(
this,
"Simulation",
"No model definition found.");
448 _compiler_msg->clear();
488 if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
489 QMessageBox::critical(
this, QString(tr(
"Error")), QString(tr(
"Can't open file ")) + name + QString(
".plt"));
494 _data.append(
"set title \"").append(name).append(
"\"\n");
495 _data.append(
"set ylabel \"State Variables\"\n");
496 _data.append(
"set xlabel \"Time\"\n");
498 buff.append(
"set xrange [0:").append(
Editor::instance()->stopTime()).append(
"]\n");
500 _data.append(
"set grid\n");
501 _data.append(
"plot ");
502 for (
int k = 0; k <
_model->rowCount(); k++) {
503 QStandardItem *it =
_model->item(k);
504 for (
int g = 0; g < it->rowCount(); g++) {
505 QStandardItem *c = it->child(g, 1);
506 QString name = c->text();
507 if (c->checkState() == Qt::Checked) {
511 .append(
_model->item(k)->text())
516 if (c->text() !=
"None") {
517 _data.append(
" with ").append(c->text());
519 _data.append(
" title \"").append(name).append(
"\"");
525 int l = _data.length();
526 _data = _data.remove(l - 2, 1);
528 if (file.write(_data.toStdString().c_str()) == -1) {
529 QMessageBox::critical(
this, QString(tr(
"Error")), QString(tr(
"Can't write data ")) + name + QString(
".plt"));
534 QMessageBox::critical(
this, QString(tr(
"Error")), QString(tr(
"Can't save file ")) + name + QString(
".plt"));
550 if (makefi.exists()) {
551 buildDir.remove(makefi.absoluteFilePath());
554 buildDir.remove(cfi.absoluteFilePath());
556 if (exefi.exists()) {
557 buildDir.remove(exefi.absoluteFilePath());
564 _compiler_msg->clear();
570 if (QFile::exists(fileName)) {
571 QFile::remove(fileName);
574 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + buildDir.absolutePath());
581 _proc =
new QProcess(
this);
588 if (!flags.isEmpty()) {
593 if (flags.isEmpty()) {
594 QMessageBox::warning(
this,
"Debug Flags",
"Debug mode enabled but no debug flags found. They can be set from \"File->Settings\"");
603 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCompiling model: "));
604 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_utils->
appDir(
MMOC_BIN) +
SLASH + comp +
" " + set +
" " +
606 _compiler_msg->moveCursor(QTextCursor::End);
607 _compiler_msg->ensureCursorVisible();
608 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
619 _proc->setProcessEnvironment(env);
626 if (exitStatus == QProcess::NormalExit) {
627 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_proc->readAllStandardError());
631 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCan not import SBML file.") + QString::number(exitCode));
640 if (exitStatus == QProcess::NormalExit) {
646 QFileInfo exefi(execName);
647 if (!exefi.exists()) {
648 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_proc->readAllStandardError());
649 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCan't generate binary file.") + QString::number(exitCode));
654 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nBinary file generated, ready to start simulation."));
657 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nError generating binary file.).") + QString::number(exitCode));
664 _compiler_msg->moveCursor(QTextCursor::End);
665 _compiler_msg->ensureCursorVisible();
671 if (exitStatus == QProcess::NormalExit) {
676 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") +
_proc->readAllStandardError());
677 QByteArray logs =
_proc->readAllStandardOutput();
678 if (!logs.isEmpty()) _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") + logs);
680 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCan't generate C file."));
686 QDir modeldir = modelfi.absoluteDir();
687 QFileInfoList filst = modeldir.entryInfoList(QStringList() <<
"*.c"
689 foreach (QFileInfo qfi, filst) {
690 QFile file(qfi.filePath());
691 file.copy(buildDir.absolutePath() +
SLASH + qfi.fileName());
694 modeldir = QCoreApplication::applicationDirPath();
695 filst = modeldir.entryInfoList(QStringList() <<
"*.im");
696 foreach (QFileInfo qfi, filst) {
697 QFile file(qfi.filePath());
698 file.copy(buildDir.absolutePath() +
SLASH + qfi.fileName());
702 if (!makefi.exists()) {
703 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nCan't generate makefile."));
708 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nRunning makefile."));
711 args << makefi.baseName();
712 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n") + QString(
"make -f ") + buildDir.absolutePath() +
SLASH +
716 _proc =
new QProcess(
this);
718 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
721 _proc->setProcessEnvironment(env);
726 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\nError during compilation.") + QString::number(exitCode));
730 _compiler_msg->moveCursor(QTextCursor::End);
731 _compiler_msg->ensureCursorVisible();
741 Q_PID pid =
_proc->pid();
745 params << QString::number(pid);
748 params <<
"--noheaders";
749 killer.start(
"/bin/ps", params, QIODevice::ReadOnly);
750 if (killer.waitForStarted(-1)) {
751 if (killer.waitForFinished(-1)) {
752 QByteArray temp = killer.readAllStandardOutput();
753 QString str = QString::fromLocal8Bit(temp);
754 QStringList list = str.split(
"\n");
756 for (
int i = 0; i < list.size(); i++) {
757 if (!list.at(i).isEmpty()) ::kill(list.at(i).toInt(), SIGKILL);
769 if (name.isEmpty()) {
773 _log =
new QProcess(
this);
777 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
780 _log->setProcessEnvironment(env);
789 QStringList dirs = outputDir.entryList(QStringList() <<
"*.log"
792 foreach (QString f, dirs) {
802 for (
int k = 0; k <
_model->rowCount(); k++) {
803 QStandardItem *it =
_model->item(k);
804 if (name == it->text()) {
810 _model->removeRows(idx, 1);
811 _model_variables->setModel(
_model);
812 _model_variables->setItemDelegateForColumn(2,
_cboxd);
813 for (
int column = 0; column <
_model->columnCount(); ++column) {
814 _model_variables->resizeColumnToContents(column);
825 exitAct =
new QAction(tr(
"E&xit"),
this);
826 exitAct->setShortcuts(QKeySequence::Quit);
827 exitAct->setStatusTip(tr(
"Exit the application"));
828 connect(
exitAct, &QAction::triggered, qApp, &QApplication::quit);
832 menu_File->addSeparator();
839 QAction *action = qobject_cast<QAction *>(sender());
841 loadFile(action->data().toString());
847 QSettings settings(QCoreApplication::applicationDirPath() +
"/qss-solver.ini", QSettings::IniFormat);
849 QStringList files = settings.value(
"Editor/recentFileList").toStringList();
853 for (
int i = 0; i < numRecentFiles; ++i) {
854 QString text = tr(
"&%1 %2").arg(i + 1).arg(
strippedName(files[i]));
875 QSettings settings(QCoreApplication::applicationDirPath() +
"/qss-solver.ini", QSettings::IniFormat);
876 QStringList files = settings.value(
"Editor/recentFileList").toStringList();
877 files.removeAll(fileName);
878 files.prepend(fileName);
881 settings.setValue(
"Editor/recentFileList", files);
889 for (
int k = 0; k <
_model->rowCount(); k++) {
890 QStandardItem *it =
_model->item(k);
891 Qt::CheckState cs = Qt::Unchecked;
892 if (name == it->text()) {
894 QModelIndex idx =
_model->index(k, 0, QModelIndex());
895 _model_variables->setExpanded(idx,
true);
898 QModelIndex idx =
_model->index(k, 0, QModelIndex());
899 _model_variables->setExpanded(idx,
false);
901 for (
int g = 0; g < it->rowCount(); g++) {
902 QStandardItem *c = it->child(g, 1);
903 QString name = c->text();
904 c->setCheckState(cs);
909 int k =
_model->rowCount() - 1;
911 QStandardItem *it =
_model->item(k);
912 Qt::CheckState cs = Qt::Checked;
913 QModelIndex idx =
_model->index(k, 0, QModelIndex());
914 _model_variables->setExpanded(idx,
true);
915 for (
int g = 0; g < it->rowCount(); g++) {
916 QStandardItem *c = it->child(g, 1);
917 QString name = c->text();
918 c->setCheckState(cs);
926 for (
int k = 0; k <
_model->rowCount(); k++) {
927 QStandardItem *it =
_model->item(k);
928 if (name == it->text()) {
932 if (!name.isEmpty()) {
936 _model_variables->setModel(
_model);
937 _model_variables->setModel(
_model);
938 _model_variables->setItemDelegateForColumn(2,
_cboxd);
939 for (
int column = 0; column <
_model->columnCount(); ++column) {
940 _model_variables->resizeColumnToContents(column);
948 if (name.isEmpty())
return;
952 _compiler_msg->clear();
956 QFileInfo of(gpxdir +
SLASH + name + QString(
".plt"));
958 _compiler_msg->setPlainText(_compiler_msg->toPlainText() + QString(
"\n Can't find plot script: ") + name + QString(
".plt"));
961 _plot =
new QProcess(
this);
964 if (plotOptions.isEmpty()) {
965 plotOptions =
"-persist";
968 args << of.absoluteFilePath();
969 _plot->start(plotCmd, args);
974 QString msgs =
_plot->readAllStandardError();
975 if (exitStatus == QProcess::NormalExit && !msgs.isEmpty()) {
976 _compiler_msg->setPlainText(_compiler_msg->toPlainText() +
"\nPlot script error: " + QString::number(exitCode) +
"\n" + msgs);
987 sh.append(
"Modeling and simulation environment for continuous and hybrid systems.\n");
988 sh.append(
"Version: ");
991 sh.append(
"Branch: ");
994 sh.append(
"HomePage: ");
995 sh.append(
"https://github.com/CIFASIS/qss-solver\n");
996 sh.append(
"Developed by:\n");
997 sh.append(
"Joaquin Fernandez (fernandez@cifasis-conicet.gov.ar)\n");
999 sh.append(
"Directed by:\n");
1000 sh.append(
"Ernesto Kofman (kofman@cifasis-conicet.gov.ar)\n");
1001 QString title(
"QSS Solver");
1002 QMessageBox::about(
this, title, sh);
1014 }
else if (exitStatus == QProcess::NormalExit) {
1015 QString msgs =
_log->readAllStandardError();
1016 _compiler_msg->setPlainText(_compiler_msg->toPlainText() +
"\nLog file error: " + QString::number(exitCode) +
"\n" + msgs);