Path: blob/devel/ElmerGUI/Application/src/mainwindow.cpp
3203 views
/*****************************************************************************1* *2* Elmer, A Finite Element Software for Multiphysical Problems *3* *4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *5* *6* This program is free software; you can redistribute it and/or *7* modify it under the terms of the GNU General Public License *8* as published by the Free Software Foundation; either version 2 *9* of the License, or (at your option) any later version. *10* *11* This program is distributed in the hope that it will be useful, *12* but WITHOUT ANY WARRANTY; without even the implied warranty of *13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *14* GNU General Public License for more details. *15* *16* You should have received a copy of the GNU General Public License *17* along with this program (in file fem/GPL-2); if not, write to the *18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *19* Boston, MA 02110-1301, USA. *20* *21*****************************************************************************/2223/*****************************************************************************24* *25* ElmerGUI mainwindow *26* *27*****************************************************************************28* *29* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *30* Email: [email protected] *31* Web: http://www.csc.fi/elmer *32* Address: CSC - IT Center for Science Ltd. *33* Keilaranta 14 *34* 02101 Espoo, Finland *35* *36* Original Date: 15 Mar 2008 *37* *38*****************************************************************************/3940#include <QAction>41#include <QContextMenuEvent>42#include <QDir>43#include <QFile>44#include <QFileInfo>45#include <QFont>46#include <QProgressBar>47#include <QStringList>48#include <QSystemTrayIcon>49#include <QTimeLine>50#include <QtGui>5152#include <fstream>53#include <iostream>5455#include <QDebug>5657#include "mainwindow.h"58#include "newprojectdialog.h"5960#ifdef EG_VTK61#include "vtkpost/vtkpost.h"62VtkPost *vtkp;63#endif6465#ifdef __APPLE__66#include <mach-o/dyld.h>67// #ifndef EG_OCC68// #define EG_OCC69// #endif70#endif7172using namespace std;7374#undef MPICH27576// Construct main window...77//-----------------------------------------------------------------------------78MainWindow::MainWindow() {79#ifdef __APPLE__80// find "Home directory":81char executablePath[MAXPATHLENGTH] = {0};82uint32_t len = MAXPATHLENGTH;83this->homePath = "";84if (!_NSGetExecutablePath((char *)executablePath, &len)) {85// remove executable name from path:86*(strrchr(executablePath, '/')) = '\0';87// remove last path component name from path:88*(strrchr(executablePath, '/')) = '\0';89this->homePath = executablePath;90}91#else92homePath = "";93#endif949596// Set icon theme path97#ifdef __APPLE__DONTGO_HERE_TODO98QString themePath = this->homePath + "/icons";99#else100QString themePath =101QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/icons";102103QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));104105if (!elmerGuiHome.isEmpty())106themePath = elmerGuiHome + "/icons";107108themePath.replace('\\', '/');109#endif110QIcon::setThemeSearchPaths(QStringList(themePath));111QIcon::setThemeName("TangoElmerGUI");112113114// load ini file:115egIni = new EgIni(this);116117// splash screen:118setupSplash();119120// load splash screen:121updateSplash("Loading images...");122123// load tetlib:124updateSplash("Loading tetlib...");125tetlibAPI = new TetlibAPI;126tetlibPresent = tetlibAPI->loadTetlib();127this->in = tetlibAPI->in;128this->out = tetlibAPI->out;129130// load nglib:131updateSplash("Loading nglib...");132nglibAPI = new NglibAPI;133nglibPresent = true;134135// construct elmergrid:136updateSplash("Constructing elmergrid...");137elmergridAPI = new ElmergridAPI;138139// set dynamic limits:140limit = new Limit;141setDynamicLimits();142143// widgets and utilities:144updateSplash("ElmerGUI loading...");145glWidget = new GLWidget(this);146#ifdef WIN32147glWidget->stateDrawSharpEdges = false;148#endif149setCentralWidget(glWidget);150sifWindow = new SifWindow(this);151meshControl = new MeshControl(this);152boundaryDivide = new BoundaryDivide(this);153meshingThread = new MeshingThread(this);154meshutils = new Meshutils;155solverLogWindow = new SolverLogWindow(this);156solver = new QProcess(this);157post = new QProcess(this);158paraview = new QProcess(this);159compiler = new QProcess(this);160meshSplitter = new QProcess(this);161meshUnifier = new QProcess(this);162generalSetup = new GeneralSetup(this);163summaryEditor = new SummaryEditor(this);164sifGenerator = new SifGenerator;165sifGenerator->setLimit(this->limit);166elmerDefs = new QDomDocument;167edfEditor = new EdfEditor;168glControl = new GLcontrol(this);169parallel = new Parallel(this);170checkMpi = new CheckMpi;171materialLibrary = new MaterialLibrary(this);172twodView = new TwodView;173grabTimeLine = new QTimeLine(1000, this);174175#ifdef EG_QWT176convergenceView = new ConvergenceView(limit, this);177#endif178179#ifdef EG_VTK180vtkp = vtkPost = new VtkPost(this);181vtkPostMeshUnifierRunning = false;182#endif183184#ifdef EG_OCC185cadView = new CadView();186if (egIni->isPresent("deflection"))187cadView->setDeflection(egIni->value("deflection").toDouble());188#endif189190createActions();191createMenus();192createToolBars();193createStatusBar();194runPostProcessorAct->setMenu(selectPostMenu);195196// Always, when an action from the menu bar has been selected, synchronize197// menu to state:198connect(menuBar(), SIGNAL(triggered(QAction *)), this,199SLOT(menuBarTriggeredSlot(QAction *)));200connect(contextMenu, SIGNAL(triggered(QAction *)), this,201SLOT(menuBarTriggeredSlot(QAction *)));202203// glWidget emits (list_t*) when a boundary is selected by double clicking:204connect(glWidget, SIGNAL(signalBoundarySelected(list_t *, Qt::KeyboardModifiers)), this,205SLOT(boundarySelectedSlot(list_t *, Qt::KeyboardModifiers)));206207// glWidget emits (void) when esc has been pressed:208connect(glWidget, SIGNAL(escPressed()), this, SLOT(viewNormalModeSlot()));209210// meshingThread emits (void) when the mesh generation has finished or211// terminated:212connect(meshingThread, SIGNAL(started()), this, SLOT(meshingStartedSlot()));213connect(meshingThread, SIGNAL(finished()), this, SLOT(meshingFinishedSlot()));214connect(meshingThread, SIGNAL(terminated()), this,215SLOT(meshingTerminatedSlot()));216217// boundaryDivide emits (double) when "divide button" has been clicked:218connect(boundaryDivide, SIGNAL(signalDoDivideSurface(double)), this,219SLOT(doDivideSurfaceSlot(double)));220221// boundaryDivide emits (double) when "divide button" has been clicked:222connect(boundaryDivide, SIGNAL(signalDoDivideEdge(double)), this,223SLOT(doDivideEdgeSlot(double)));224225// solver emits (int) when finished:226connect(solver, SIGNAL(finished(int)), this, SLOT(solverFinishedSlot(int)));227228// solver emits (void) when there is something to read from stdout:229connect(solver, SIGNAL(readyReadStandardOutput()), this,230SLOT(solverStdoutSlot()));231232// solver emits (void) when there is something to read from stderr:233connect(solver, SIGNAL(readyReadStandardError()), this,234SLOT(solverStderrSlot()));235236// solver emits (QProcess::ProcessError) when error occurs:237connect(solver, SIGNAL(error(QProcess::ProcessError)), this,238SLOT(solverErrorSlot(QProcess::ProcessError)));239240// solver emits (QProcess::ProcessState) when state changed:241connect(solver, SIGNAL(stateChanged(QProcess::ProcessState)), this,242SLOT(solverStateChangedSlot(QProcess::ProcessState)));243244// compiler emits (int) when finished:245connect(compiler, SIGNAL(finished(int)), this,246SLOT(compilerFinishedSlot(int)));247248// compiler emits (void) when there is something to read from stdout:249connect(compiler, SIGNAL(readyReadStandardOutput()), this,250SLOT(compilerStdoutSlot()));251252// compiler emits (void) when there is something to read from stderr:253connect(compiler, SIGNAL(readyReadStandardError()), this,254SLOT(compilerStderrSlot()));255256// post emits (int) when finished:257connect(post, SIGNAL(finished(int)), this,258SLOT(postProcessFinishedSlot(int)));259260// paraview emits (int) when finished:261connect(paraview, SIGNAL(finished(int)), this,262SLOT(paraviewProcessFinishedSlot(int)));263264// meshSplitter emits (int) when finished:265connect(meshSplitter, SIGNAL(finished(int)), this,266SLOT(meshSplitterFinishedSlot(int)));267268// meshSplitter emits(void) when there is something to read from stdout:269connect(meshSplitter, SIGNAL(readyReadStandardOutput()), this,270SLOT(meshSplitterStdoutSlot()));271272// meshSplitter emits(void) when there is something to read from stderr:273connect(meshSplitter, SIGNAL(readyReadStandardError()), this,274SLOT(meshSplitterStderrSlot()));275276// meshUnifier emits (int) when finished:277connect(meshUnifier, SIGNAL(finished(int)), this,278SLOT(meshUnifierFinishedSlot(int)));279280// meshUnifier emits(void) when there is something to read from stdout:281connect(meshUnifier, SIGNAL(readyReadStandardOutput()), this,282SLOT(meshUnifierStdoutSlot()));283284// meshUnifier emits(void) when there is something to read from stderr:285connect(meshUnifier, SIGNAL(readyReadStandardError()), this,286SLOT(meshUnifierStderrSlot()));287288// grabTimeLine emits finished() when done:289connect(grabTimeLine, SIGNAL(finished()), this, SLOT(grabFrameSlot()));290291// set initial state:292operations = 0;293meshControl->nglibPresent = nglibPresent;294meshControl->tetlibPresent = tetlibPresent;295meshControl->defaultControls();296nglibInputOk = false;297tetlibInputOk = false;298activeGenerator = GEN_UNKNOWN;299bcEditActive = false;300bodyEditActive = false;301showConvergence = egIni->isSet("showconvergence");302geometryInputFileName = "";303occInputOk = false;304305// background image:306glWidget->stateUseBgImage = egIni->isSet("bgimage");307glWidget->stateStretchBgImage = egIni->isSet("bgimagestretch");308glWidget->stateAlignRightBgImage = egIni->isSet("bgimagealignright");309glWidget->bgImageFileName = egIni->value("bgimagefile");310311// set font for text editors:312// QFont sansFont("Courier", 10);313// sifWindow->getTextEdit()->setCurrentFont(sansFont);314// solverLogWindow->getTextEdit()->setCurrentFont(sansFont);315316// load definition files:317updateSplash("Loading definitions...");318loadDefinitions();319320// initialization ready:321// synchronizeMenuToState(); Commented out as this will be called from loadSettings() later322setWindowTitle(tr("ElmerGUI"));323setWindowIcon(QIcon(":/icons/Mesh3D.png"));324finalizeSplash();325setupSysTrayIcon();326327// default size:328int defW = egIni->value("width").toInt();329int defH = egIni->value("height").toInt();330if (defW <= 300)331defW = 300;332if (defH <= 300)333defH = 300;334this->resize(defW, defH);335sifWindow->resize(defW - 50, defH - 50);336solverLogWindow->resize(defW - 50, defH - 50);337338loadSettings();339}340341// dtor...342//-----------------------------------------------------------------------------343MainWindow::~MainWindow() {344saveSettings();345qApp->closeAllWindows();346}347348// Set limits for dynamic editors, materials, bcs, etc...349//-----------------------------------------------------------------------------350void MainWindow::setDynamicLimits() {351// Values defined in "edf/egini.xml" that override default limits:352353// Deprecated ** 23/04/09 **354if (egIni->isPresent("max_boundaries")) {355limit->setMaxBoundaries(egIni->value("max_boundaries").toInt());356// cout << "Max boundaries: " << limit->maxBoundaries() << endl;357}358359// Deprecated ** 23/04/09 **360if (egIni->isPresent("max_solvers")) {361limit->setMaxSolvers(egIni->value("max_solvers").toInt());362// cout << "Max solvers: " << limit->maxSolvers() << endl;363}364365// Deprecated ** 23/04/09 **366if (egIni->isPresent("max_bodies")) {367limit->setMaxBodies(egIni->value("max_bodies").toInt());368// cout << "Max bodies: " << limit->maxBodies() << endl;369}370371// Deprecated ** 21/04/09 **372if (egIni->isPresent("max_equations")) {373limit->setMaxEquations(egIni->value("max_equations").toInt());374// cout << "Max equations: " << limit->maxEquations() << endl;375}376377// Deprecated ** 21/04/09 **378if (egIni->isPresent("max_materials")) {379limit->setMaxMaterials(egIni->value("max_materials").toInt());380// cout << "Max materials: " << limit->maxMaterials() << endl;381}382383// Deprecated ** 21/04/09 **384if (egIni->isPresent("max_bodyforces")) {385limit->setMaxBodyforces(egIni->value("max_bodyforces").toInt());386// cout << "Max bodyforces: " << limit->maxBodyforces() << endl;387}388389// Deprecated ** 21/04/09 **390if (egIni->isPresent("max_initialconditions")) {391limit->setMaxInitialconditions(392egIni->value("max_initialconditions").toInt());393// cout << "Max initialconditions: " << limit->maxInitialconditions() <<394// endl;395}396397// Deprecated ** 21/04/09 **398if (egIni->isPresent("max_bcs")) {399limit->setMaxBcs(egIni->value("max_bcs").toInt());400// cout << "Max bcs: " << limit->maxBcs() << endl;401}402}403404// Always synchronize menu to state when the menubar has been triggered...405//-----------------------------------------------------------------------------406void MainWindow::menuBarTriggeredSlot(QAction *act) {407synchronizeMenuToState();408}409410// Create actions...411//-----------------------------------------------------------------------------412void MainWindow::createActions() {413// File -> Open file414openAct =415new QAction(QIcon::fromTheme("document-open"), tr("&Open..."), this);416openAct->setShortcut(tr("Ctrl+O"));417openAct->setStatusTip(tr("Open geometry input file"));418connect(openAct, SIGNAL(triggered()), this, SLOT(openSlot()));419420// File -> Load mesh...421loadAct = new QAction(QIcon::fromTheme("folder"),422tr("&Load mesh..."), this);423loadAct->setStatusTip(tr("Load Elmer mesh files"));424connect(loadAct, SIGNAL(triggered()), this, SLOT(loadSlot()));425426// File -> Load project...427loadProjectAct = new QAction(QIcon::fromTheme("project-load"),428tr("Load &project..."), this);429loadProjectAct->setStatusTip(tr("Load previously saved project"));430connect(loadProjectAct, SIGNAL(triggered()), this, SLOT(loadProjectSlot()));431432// File -> New project...433newProjectAct = new QAction(QIcon::fromTheme("project-new"),434tr("&New project..."), this);435newProjectAct->setStatusTip(tr("Create a new project"));436connect(newProjectAct, SIGNAL(triggered()), this, SLOT(newProjectSlot()));437438// File -> Recent Projects439recentProject0Act = new QAction("", this);440connect(recentProject0Act, SIGNAL(triggered()), this,441SLOT(loadRecentProject0Slot()));442recentProject1Act = new QAction("", this);443connect(recentProject1Act, SIGNAL(triggered()), this,444SLOT(loadRecentProject1Slot()));445recentProject2Act = new QAction("", this);446connect(recentProject2Act, SIGNAL(triggered()), this,447SLOT(loadRecentProject2Slot()));448recentProject3Act = new QAction("", this);449connect(recentProject3Act, SIGNAL(triggered()), this,450SLOT(loadRecentProject3Slot()));451recentProject4Act = new QAction("", this);452connect(recentProject4Act, SIGNAL(triggered()), this,453SLOT(loadRecentProject4Slot()));454recentProject5Act = new QAction("", this);455connect(recentProject5Act, SIGNAL(triggered()), this,456SLOT(loadRecentProject5Slot()));457recentProject6Act = new QAction("", this);458connect(recentProject6Act, SIGNAL(triggered()), this,459SLOT(loadRecentProject6Slot()));460recentProject7Act = new QAction("", this);461connect(recentProject7Act, SIGNAL(triggered()), this,462SLOT(loadRecentProject7Slot()));463recentProject8Act = new QAction("", this);464connect(recentProject8Act, SIGNAL(triggered()), this,465SLOT(loadRecentProject8Slot()));466recentProject9Act = new QAction("", this);467connect(recentProject9Act, SIGNAL(triggered()), this,468SLOT(loadRecentProject9Slot()));469// File -> Definitions...470editDefinitionsAct = new QAction(QIcon::fromTheme("preferences-system"),471tr("&Definitions..."), this);472editDefinitionsAct->setStatusTip(473tr("Load and edit Elmer sif definitions file"));474connect(editDefinitionsAct, SIGNAL(triggered()), this,475SLOT(editDefinitionsSlot()));476477// File -> Save...478saveAct =479new QAction(QIcon::fromTheme("document-save"), tr("&Save..."), this);480saveAct->setShortcut(tr("Ctrl+S"));481saveAct->setStatusTip(tr("Save Elmer mesh and sif-files"));482connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSlot()));483484// File -> Save as...485saveAsAct = new QAction(QIcon::fromTheme("document-save-as"),486tr("&Save as..."), this);487saveAsAct->setStatusTip(tr("Save Elmer mesh and sif-files"));488connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAsSlot()));489490// File -> Save project491saveProjectAct = new QAction(QIcon::fromTheme("project-save"),492tr("&Save project"), this);493saveProjectAct->setStatusTip(tr("Save current project"));494connect(saveProjectAct, SIGNAL(triggered()), this, SLOT(saveProjectSlot()));495496// File -> Save project as...497saveProjectAsAct = new QAction(QIcon::fromTheme("project-save-as"),498tr("&Save project as..."), this);499saveProjectAsAct->setStatusTip(500tr("Save current project by specifying directory"));501connect(saveProjectAsAct, SIGNAL(triggered()), this,502SLOT(saveProjectAsSlot()));503504// File -> Save picture as...505savePictureAct = new QAction(QIcon::fromTheme("image-x-generic"),506tr("&Save picture as..."), this);507savePictureAct->setStatusTip(tr("Save picture in file"));508connect(savePictureAct, SIGNAL(triggered()), this, SLOT(savePictureSlot()));509510// File -> Exit511exitAct =512new QAction(QIcon::fromTheme("emblem-unreadable"), tr("E&xit"), this);513exitAct->setShortcut(tr("Ctrl+Q"));514exitAct->setStatusTip(tr("Exit"));515connect(exitAct, SIGNAL(triggered()), this, SLOT(closeMainWindowSlot()));516517// Model -> Setup...518modelSetupAct = new QAction(QIcon::fromTheme("applications-system"), tr("Setup..."), this);519modelSetupAct->setStatusTip(tr("Setup simulation environment"));520connect(modelSetupAct, SIGNAL(triggered()), this, SLOT(modelSetupSlot()));521522// Model -> Equation...523addEquationAct = new QAction(QIcon(), tr("Add..."), this);524addEquationAct->setStatusTip(tr("Add a PDE-system to the equation list"));525connect(addEquationAct, SIGNAL(triggered()), this, SLOT(addEquationSlot()));526527// Model -> Material...528addMaterialAct = new QAction(QIcon(), tr("Add..."), this);529addMaterialAct->setStatusTip(tr("Add a material set to the material list"));530connect(addMaterialAct, SIGNAL(triggered()), this, SLOT(addMaterialSlot()));531532// Model -> Body force...533addBodyForceAct = new QAction(QIcon(), tr("Add..."), this);534addBodyForceAct->setStatusTip(tr("Add body forces..."));535connect(addBodyForceAct, SIGNAL(triggered()), this, SLOT(addBodyForceSlot()));536537// Model -> Initial condition...538addInitialConditionAct = new QAction(QIcon(), tr("Add..."), this);539addInitialConditionAct->setStatusTip(tr("Add initial conditions..."));540connect(addInitialConditionAct, SIGNAL(triggered()), this,541SLOT(addInitialConditionSlot()));542543// Model -> Boundary condition...544addBoundaryConditionAct = new QAction(QIcon(), tr("Add..."), this);545addBoundaryConditionAct->setStatusTip(tr("Add boundary conditions..."));546connect(addBoundaryConditionAct, SIGNAL(triggered()), this,547SLOT(addBoundaryConditionSlot()));548549// Model -> Set body properties550bodyEditAct = new QAction(QIcon(":/icons/set-body-property.png"),551tr("Set body properties"), this);552bodyEditAct->setStatusTip(553tr("Set body properties (equivalent to holding down the SHIFT key)"));554connect(bodyEditAct, SIGNAL(triggered()), this, SLOT(bodyEditSlot()));555bodyEditAct->setCheckable(true);556557// Model -> Set boundary conditions558bcEditAct = new QAction(QIcon(":/icons/set-boundary-property.png"),559tr("Set boundary properties"), this);560bcEditAct->setStatusTip(561tr("Set boundary properties (equivalent to holding down the ALT key)"));562connect(bcEditAct, SIGNAL(triggered()), this, SLOT(bcEditSlot()));563bcEditAct->setCheckable(true);564565// Model -> Summary...566modelSummaryAct = new QAction(QIcon(), tr("Summary..."), this);567modelSummaryAct->setStatusTip(tr("Model summary"));568connect(modelSummaryAct, SIGNAL(triggered()), this, SLOT(modelSummarySlot()));569570// Model -> Clear571modelClearAct = new QAction(QIcon(), tr("Clear all"), this);572modelClearAct->setStatusTip(tr("Clear all model definitions"));573connect(modelClearAct, SIGNAL(triggered()), this, SLOT(modelClearSlot()));574575// Edit -> Generate sif576generateSifAct = new QAction(QIcon(""), tr("&Generate"), this);577generateSifAct->setShortcut(tr("Ctrl+G"));578generateSifAct->setStatusTip(tr("Generate solver input file"));579connect(generateSifAct, SIGNAL(triggered()), this, SLOT(generateSifSlot()));580581// Edit -> Solver input file...582showsifAct = new QAction(QIcon::fromTheme("text-x-generic-with-pencil"),583tr("&Edit..."), this);584showsifAct->setShortcut(tr("Ctrl+S"));585showsifAct->setStatusTip(tr("Edit solver input file"));586connect(showsifAct, SIGNAL(triggered()), this, SLOT(showsifSlot()));587588// Mesh -> Control589meshcontrolAct =590new QAction(QIcon::fromTheme("configure"), tr("&Configure..."), this);591meshcontrolAct->setShortcut(tr("Ctrl+C"));592meshcontrolAct->setStatusTip(tr("Configure mesh generators"));593connect(meshcontrolAct, SIGNAL(triggered()), this, SLOT(meshcontrolSlot()));594595// Mesh -> Remesh596remeshAct = new QAction(QIcon::fromTheme("edit-redo"), tr("&Remesh"), this);597remeshAct->setShortcut(tr("Ctrl+R"));598remeshAct->setStatusTip(tr("Remesh"));599connect(remeshAct, SIGNAL(triggered()), this, SLOT(remeshSlot()));600601// Mesh -> Kill generator602stopMeshingAct = new QAction(QIcon::fromTheme("dialog-error-round"),603tr("&Terminate meshing"), this);604stopMeshingAct->setStatusTip(tr("Terminate mesh generator"));605connect(stopMeshingAct, SIGNAL(triggered()), this, SLOT(stopMeshingSlot()));606stopMeshingAct->setEnabled(false);607608// Mesh -> Divide surface609surfaceDivideAct =610new QAction(QIcon(":/icons/divide.png"), tr("&Divide surface..."), this);611surfaceDivideAct->setStatusTip(tr("Divide surface by sharp edges"));612connect(surfaceDivideAct, SIGNAL(triggered()), this,613SLOT(surfaceDivideSlot()));614615// Mesh -> Unify surface616surfaceUnifyAct =617new QAction(QIcon(":/icons/unify.png"), tr("&Unify surface"), this);618surfaceUnifyAct->setStatusTip(tr("Unify surface (merge selected)"));619connect(surfaceUnifyAct, SIGNAL(triggered()), this, SLOT(surfaceUnifySlot()));620621// Mesh -> Divide edge622edgeDivideAct = new QAction(QIcon(":/icons/divide-edge.png"),623tr("&Divide edge..."), this);624edgeDivideAct->setStatusTip(tr("Divide edge by sharp points"));625connect(edgeDivideAct, SIGNAL(triggered()), this, SLOT(edgeDivideSlot()));626627// Mesh -> Unify edges628edgeUnifyAct =629new QAction(QIcon(":/icons/unify-edge.png"), tr("&Unify edge"), this);630edgeUnifyAct->setStatusTip(tr("Unify edge (merge selected)"));631connect(edgeUnifyAct, SIGNAL(triggered()), this, SLOT(edgeUnifySlot()));632633// Mesh -> Clean up634cleanHangingSharpEdgesAct = new QAction(QIcon::fromTheme("edit-clear"), tr("Clean up"), this);635cleanHangingSharpEdgesAct->setStatusTip(636tr("Removes hanging/orphan sharp edges (for visualization)"));637connect(cleanHangingSharpEdgesAct, SIGNAL(triggered()), this,638SLOT(cleanHangingSharpEdgesSlot()));639640// View -> Full screen641viewFullScreenAct = new QAction(QIcon::fromTheme("view-fullscreen"), tr("Full screen"), this);642viewFullScreenAct->setShortcut(tr("Ctrl+L"));643viewFullScreenAct->setStatusTip(tr("Full screen mode"));644connect(viewFullScreenAct, SIGNAL(triggered()), this,645SLOT(viewFullScreenSlot()));646viewFullScreenAct->setCheckable(true);647648// View -> Show surface mesh649hidesurfacemeshAct = new QAction(QIcon(), tr("Surface mesh"), this);650hidesurfacemeshAct->setStatusTip(tr("Show/hide surface mesh "651"(do/do not outline surface elements)"));652connect(hidesurfacemeshAct, SIGNAL(triggered()), this,653SLOT(hidesurfacemeshSlot()));654hidesurfacemeshAct->setCheckable(true);655656// View -> Show volume mesh657hidevolumemeshAct = new QAction(QIcon(), tr("Volume mesh"), this);658hidevolumemeshAct->setStatusTip(tr("Show/hide volume mesh "659"(do/do not outline volume mesh edges)"));660connect(hidevolumemeshAct, SIGNAL(triggered()), this,661SLOT(hidevolumemeshSlot()));662hidevolumemeshAct->setCheckable(true);663664// View -> Show sharp edges665hidesharpedgesAct = new QAction(QIcon(), tr("Sharp edges"), this);666hidesharpedgesAct->setStatusTip(tr("Show/hide sharp edges"));667connect(hidesharpedgesAct, SIGNAL(triggered()), this,668SLOT(hidesharpedgesSlot()));669hidesharpedgesAct->setCheckable(true);670671// View -> Compass672viewCoordinatesAct = new QAction(QIcon(), tr("Compass"), this);673viewCoordinatesAct->setStatusTip(tr("View coordinates "674"(RGB=XYZ modulo translation)"));675connect(viewCoordinatesAct, SIGNAL(triggered()), this,676SLOT(viewCoordinatesSlot()));677viewCoordinatesAct->setCheckable(true);678679// View -> Select all surfaces680selectAllSurfacesAct = new QAction(QIcon(), tr("Select all surfaces"), this);681selectAllSurfacesAct->setStatusTip(tr("Select all surfaces"));682connect(selectAllSurfacesAct, SIGNAL(triggered()), this,683SLOT(selectAllSurfacesSlot()));684685// View -> Select all edges686selectAllEdgesAct = new QAction(QIcon(), tr("Select all edges"), this);687selectAllEdgesAct->setStatusTip(tr("Select all edges"));688connect(selectAllEdgesAct, SIGNAL(triggered()), this,689SLOT(selectAllEdgesSlot()));690691// View -> Select defined edges692selectDefinedEdgesAct =693new QAction(QIcon(), tr("Select defined edges"), this);694selectDefinedEdgesAct->setStatusTip(tr("Select defined edges"));695connect(selectDefinedEdgesAct, SIGNAL(triggered()), this,696SLOT(selectDefinedEdgesSlot()));697698// View -> Select defined surfaces699selectDefinedSurfacesAct =700new QAction(QIcon(), tr("Select defined surfaces"), this);701selectDefinedSurfacesAct->setStatusTip(tr("Select defined surfaces"));702connect(selectDefinedSurfacesAct, SIGNAL(triggered()), this,703SLOT(selectDefinedSurfacesSlot()));704705// View -> Hide/show selected706hideselectedAct = new QAction(QIcon(), tr("&Hide/show selected"), this);707hideselectedAct->setShortcut(tr("Ctrl+H"));708hideselectedAct->setStatusTip(tr("Show/hide selected objects"));709connect(hideselectedAct, SIGNAL(triggered()), this, SLOT(hideselectedSlot()));710711// View -> Show surface numbers712showSurfaceNumbersAct =713new QAction(QIcon(), tr("Surface element numbers"), this);714showSurfaceNumbersAct->setStatusTip(715tr("Show surface element numbers "716"(Show the surface element numbering)"));717connect(showSurfaceNumbersAct, SIGNAL(triggered()), this,718SLOT(showSurfaceNumbersSlot()));719showSurfaceNumbersAct->setCheckable(true);720721// View -> Show edge numbers722showEdgeNumbersAct = new QAction(QIcon(), tr("Edge element numbers"), this);723showEdgeNumbersAct->setStatusTip(tr("Show edge element numbers "724"(Show the node element numbering)"));725connect(showEdgeNumbersAct, SIGNAL(triggered()), this,726SLOT(showEdgeNumbersSlot()));727showEdgeNumbersAct->setCheckable(true);728729// View -> Show node numbers730showNodeNumbersAct = new QAction(QIcon(), tr("Node numbers"), this);731showNodeNumbersAct->setStatusTip(tr("Show node numbers "732"(Show the node numbers)"));733connect(showNodeNumbersAct, SIGNAL(triggered()), this,734SLOT(showNodeNumbersSlot()));735showNodeNumbersAct->setCheckable(true);736737// View -> Show boundary index738showBoundaryIndexAct = new QAction(QIcon(), tr("Boundary index"), this);739showBoundaryIndexAct->setStatusTip(tr("Show boundary index"));740connect(showBoundaryIndexAct, SIGNAL(triggered()), this,741SLOT(showBoundaryIndexSlot()));742showBoundaryIndexAct->setCheckable(true);743744// View -> Show body index745showBodyIndexAct = new QAction(QIcon(), tr("Body index"), this);746showBodyIndexAct->setStatusTip(tr("Show body index"));747connect(showBodyIndexAct, SIGNAL(triggered()), this,748SLOT(showBodyIndexSlot()));749showBodyIndexAct->setCheckable(true);750751// View -> Colors -> GL controls752glControlAct = new QAction(QIcon(), tr("GL controls..."), this);753glControlAct->setStatusTip(754tr("Control GL parameters for lights and materials"));755connect(glControlAct, SIGNAL(triggered()), this, SLOT(glControlSlot()));756757// View -> Colors -> Background758chooseBGColorAct = new QAction(QIcon(), tr("Background..."), this);759chooseBGColorAct->setStatusTip(tr("Set background color"));760connect(chooseBGColorAct, SIGNAL(triggered()), this,761SLOT(backgroundColorSlot()));762763// View -> Colors -> Surface elements764chooseSurfaceColorAct = new QAction(QIcon(), tr("Surface elements..."), this);765chooseSurfaceColorAct->setStatusTip(tr("Set surface color"));766connect(chooseSurfaceColorAct, SIGNAL(triggered()), this,767SLOT(surfaceColorSlot()));768769// View -> Colors -> Edge elements770chooseEdgeColorAct = new QAction(QIcon(), tr("Edge elements..."), this);771chooseEdgeColorAct->setStatusTip(tr("Set edge color"));772connect(chooseEdgeColorAct, SIGNAL(triggered()), this, SLOT(edgeColorSlot()));773774// View -> Colors -> Surface mesh775chooseSurfaceMeshColorAct = new QAction(QIcon(), tr("Surface mesh..."), this);776chooseSurfaceMeshColorAct->setStatusTip(tr("Set surface mesh color"));777connect(chooseSurfaceMeshColorAct, SIGNAL(triggered()), this,778SLOT(surfaceMeshColorSlot()));779780// View -> Colors -> Sharp edges781chooseSharpEdgeColorAct = new QAction(QIcon(), tr("Sharp edges..."), this);782chooseSharpEdgeColorAct->setStatusTip(tr("Set sharp edge color"));783connect(chooseSharpEdgeColorAct, SIGNAL(triggered()), this,784SLOT(sharpEdgeColorSlot()));785786// View -> Colors -> Selection787chooseSelectionColorAct = new QAction(QIcon(), tr("Selection..."), this);788chooseSelectionColorAct->setStatusTip(tr("Set selection color"));789connect(chooseSelectionColorAct, SIGNAL(triggered()), this,790SLOT(selectionColorSlot()));791792// View -> Colors -> Boundaries793showBoundaryColorAct = new QAction(QIcon(), tr("Boundaries"), this);794showBoundaryColorAct->setStatusTip(795tr("Visualize different boundary parts with color patches"));796connect(showBoundaryColorAct, SIGNAL(triggered()), this,797SLOT(colorizeBoundarySlot()));798showBoundaryColorAct->setCheckable(true);799800// View -> Colors -> Bodies801showBodyColorAct = new QAction(QIcon(), tr("Bodies"), this);802showBodyColorAct->setStatusTip(803tr("Visualize different body with color patches"));804connect(showBodyColorAct, SIGNAL(triggered()), this,805SLOT(colorizeBodySlot()));806showBodyColorAct->setCheckable(true);807808// View -> Shade model -> Smooth809smoothShadeAct = new QAction(QIcon(), tr("Smooth"), this);810smoothShadeAct->setStatusTip(tr("Set shade model to smooth"));811connect(smoothShadeAct, SIGNAL(triggered()), this, SLOT(smoothShadeSlot()));812smoothShadeAct->setCheckable(true);813814// View -> Shade model -> Flat815flatShadeAct = new QAction(QIcon(), tr("Flat"), this);816flatShadeAct->setStatusTip(tr("Set shade model to flat"));817connect(flatShadeAct, SIGNAL(triggered()), this, SLOT(flatShadeSlot()));818flatShadeAct->setCheckable(true);819820// View -> Projection -> Orthogonal821orthoAct = new QAction(QIcon(), tr("Orthogonal"), this);822orthoAct->setStatusTip(tr("Set projection to orthogonal"));823connect(orthoAct, SIGNAL(triggered()), this, SLOT(orthoSlot()));824orthoAct->setCheckable(true);825826// View -> Projection -> Perspective827perspectiveAct = new QAction(QIcon(), tr("Perspective"), this);828perspectiveAct->setStatusTip(tr("Set projection to perspective"));829connect(perspectiveAct, SIGNAL(triggered()), this, SLOT(perspectiveSlot()));830perspectiveAct->setCheckable(true);831832// View -> Show all833showallAct = new QAction(QIcon(), tr("Show all"), this);834showallAct->setStatusTip(tr("Show all objects"));835connect(showallAct, SIGNAL(triggered()), this, SLOT(showallSlot()));836837// View -> Reset model view838resetAct = new QAction(QIcon(), tr("Reset model view"), this);839resetAct->setStatusTip(tr("Reset model view"));840connect(resetAct, SIGNAL(triggered()), this, SLOT(resetSlot()));841842// View -> Show cad model843showCadModelAct = new QAction(QIcon(), tr("Cad model..."), this);844showCadModelAct->setStatusTip(845tr("Displays the cad model in a separate window"));846connect(showCadModelAct, SIGNAL(triggered()), this, SLOT(showCadModelSlot()));847848// View -> Show 2d view849showTwodViewAct = new QAction(QIcon(), tr("2D modeler..."), this);850showTwodViewAct->setStatusTip(851tr("Displays the 2d geometry in a separate window"));852connect(showTwodViewAct, SIGNAL(triggered()), this, SLOT(showTwodViewSlot()));853854// View -> Show Object Browser855showObjectBrowserAct = new QAction(QIcon(), tr("Show Object Browser"), this);856showObjectBrowserAct->setStatusTip(tr("Show Object Browser"));857connect(showObjectBrowserAct, SIGNAL(triggered()), this,858SLOT(showObjectBrowserSlot()));859showObjectBrowserAct->setCheckable(true);860861// Solver -> Parallel settings862parallelSettingsAct = new QAction(QIcon(), tr("Parallel settings..."), this);863parallelSettingsAct->setStatusTip(864tr("Choose parameters and methods for parallel solution"));865connect(parallelSettingsAct, SIGNAL(triggered()), this,866SLOT(parallelSettingsSlot()));867868// Solver -> Run solver869runsolverAct =870new QAction(QIcon(":/icons/Solver.png"), tr("Start solver"), this);871runsolverAct->setStatusTip(tr("Run ElmerSolver"));872connect(runsolverAct, SIGNAL(triggered()), this, SLOT(runsolverSlot()));873874// Solver -> Kill solver875killsolverAct =876new QAction(QIcon::fromTheme("dialog-error-round"), tr("Kill solver"), this);877killsolverAct->setStatusTip(tr("Kill ElmerSolver"));878connect(killsolverAct, SIGNAL(triggered()), this, SLOT(killsolverSlot()));879killsolverAct->setEnabled(false);880881// Solver -> Show convergence882showConvergenceAct = new QAction(QIcon(), tr("Show convergence"), this);883showConvergenceAct->setStatusTip(tr("Show/hide convergence plot"));884connect(showConvergenceAct, SIGNAL(triggered()), this,885SLOT(showConvergenceSlot()));886showConvergenceAct->setCheckable(true);887888// Solver -> Post process889resultsAct =890new QAction(QIcon(":/icons/Post.png"), tr("Start ElmerPost"), this);891resultsAct->setStatusTip(tr("Run ElmerPost for visualization"));892connect(resultsAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));893894// Solver -> Kill post process895killresultsAct = new QAction(QIcon::fromTheme("dialog-error-round"),896tr("Kill ElmerPost"), this);897killresultsAct->setStatusTip(tr("Kill ElmerPost"));898connect(killresultsAct, SIGNAL(triggered()), this, SLOT(killresultsSlot()));899killresultsAct->setEnabled(false);900901// Solver -> Show Vtk postprocessor902showVtkPostAct = new QAction(QIcon(":/icons/Mesh3D.png"), tr("Start ElmerVTK"), this);903showVtkPostAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));904connect(showVtkPostAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));905906// Solver -> Show ParaView postprocessor907paraviewAct =908new QAction(QIcon(":/icons/Paraview.png"), tr("Start ParaView"), this);909paraviewAct->setStatusTip(tr("Invokes ParaView for visualization"));910connect(paraviewAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));911912// Solver -> Compiler...913compileSolverAct = new QAction(QIcon(""), tr("Compiler..."), this);914compileSolverAct->setStatusTip(tr(915"Compile Elmer specific source code (f90) into a shared library (dll)"));916connect(compileSolverAct, SIGNAL(triggered()), this,917SLOT(compileSolverSlot()));918919// Help -> About920aboutAct = new QAction(QIcon::fromTheme("emblem-notice"), tr("About..."), this);921aboutAct->setStatusTip(tr("Information about the program"));922connect(aboutAct, SIGNAL(triggered()), this, SLOT(showaboutSlot()));923924// Help -> Get started925getStartedAct = new QAction(QIcon(""), tr("Get started..."), this);926getStartedAct->setStatusTip(tr("Information to get started"));927connect(getStartedAct, SIGNAL(triggered()), this, SLOT(getStartedSlot()));928929generateAndSaveAndRunAct =930new QAction(QIcon::fromTheme("doubletriangle-right"),931tr("&Generate, save and run"), this);932generateAndSaveAndRunAct->setStatusTip(933tr("Generate and save sif, save project, then run solver"));934connect(generateAndSaveAndRunAct, SIGNAL(triggered()), this,935SLOT(generateAndSaveAndRunSlot()));936;937938#if WIN32939#else940compileSolverAct->setEnabled(false);941#endif942943if (egIni->isSet("bgimage"))944chooseBGColorAct->setEnabled(false);945946runPostProcessorAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);947runPostProcessorAct->setStatusTip(tr("Select ElmerPost as post-processor"));948connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));949950selectElmerPostAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);951selectElmerPostAct->setStatusTip(tr("Select ElmerPost as post-processor"));952connect(selectElmerPostAct, SIGNAL(triggered()), this, SLOT(selectElmerPostSlot()));953selectElmerPostAct->setCheckable(true);954955selectVtkPostAct = new QAction(QIcon(":/icons/Mesh3D.png"), tr("ElmerVTK"), this);956selectVtkPostAct->setStatusTip(tr("Select ElmerVTK as post-processor"));957connect(selectVtkPostAct, SIGNAL(triggered()), this, SLOT(selectVtkPostSlot()));958selectVtkPostAct->setCheckable(true);959960selectParaViewAct = new QAction(QIcon(":/icons/Paraview.png"), tr("ParaView"), this);961selectParaViewAct->setStatusTip(tr("Select ParaView as post-processor"));962connect(selectParaViewAct, SIGNAL(triggered()), this, SLOT(selectParaViewSlot()));963selectParaViewAct->setCheckable(true);964}965966// Create menus...967//-----------------------------------------------------------------------------968void MainWindow::createMenus() {969// File menu970fileMenu = menuBar()->addMenu(tr("&File"));971fileMenu->addAction(newProjectAct);972fileMenu->addAction(loadProjectAct);973recentProjectsMenu = fileMenu->addMenu(tr("&Recent projects"));974recentProjectsMenu->setEnabled(false);975fileMenu->addAction(saveProjectAct);976fileMenu->addAction(saveProjectAct);977fileMenu->addAction(saveProjectAsAct);978fileMenu->addSeparator();979fileMenu->addAction(openAct);980fileMenu->addAction(loadAct);981fileMenu->addAction(saveAct);982fileMenu->addAction(saveAsAct);983fileMenu->addSeparator();984fileMenu->addAction(editDefinitionsAct);985fileMenu->addSeparator();986fileMenu->addAction(savePictureAct);987fileMenu->addSeparator();988fileMenu->addAction(exitAct);989990// Mesh menu991meshMenu = menuBar()->addMenu(tr("&Mesh"));992meshMenu->addAction(meshcontrolAct);993meshMenu->addAction(remeshAct);994meshMenu->addAction(stopMeshingAct);995meshMenu->addSeparator();996meshMenu->addAction(surfaceDivideAct);997meshMenu->addAction(surfaceUnifyAct);998meshMenu->addSeparator();999meshMenu->addAction(edgeDivideAct);1000meshMenu->addAction(edgeUnifyAct);1001meshMenu->addSeparator();1002meshMenu->addAction(cleanHangingSharpEdgesAct);10031004// Model menu1005modelMenu = menuBar()->addMenu(tr("&Model"));10061007modelMenu->addAction(modelSetupAct);1008modelMenu->addSeparator();10091010equationMenu = modelMenu->addMenu(tr("Equation"));1011equationMenu->addAction(addEquationAct);1012equationMenu->addSeparator();1013connect(equationMenu, SIGNAL(triggered(QAction *)), this,1014SLOT(equationSelectedSlot(QAction *)));10151016modelMenu->addSeparator();1017materialMenu = modelMenu->addMenu(tr("Material"));1018materialMenu->addAction(addMaterialAct);1019materialMenu->addSeparator();1020connect(materialMenu, SIGNAL(triggered(QAction *)), this,1021SLOT(materialSelectedSlot(QAction *)));10221023modelMenu->addSeparator();1024bodyForceMenu = modelMenu->addMenu(tr("Body force"));1025bodyForceMenu->addAction(addBodyForceAct);1026bodyForceMenu->addSeparator();1027connect(bodyForceMenu, SIGNAL(triggered(QAction *)), this,1028SLOT(bodyForceSelectedSlot(QAction *)));10291030modelMenu->addSeparator();1031initialConditionMenu = modelMenu->addMenu(tr("Initial condition"));1032initialConditionMenu->addAction(addInitialConditionAct);1033initialConditionMenu->addSeparator();1034connect(initialConditionMenu, SIGNAL(triggered(QAction *)), this,1035SLOT(initialConditionSelectedSlot(QAction *)));10361037modelMenu->addSeparator();1038boundaryConditionMenu = modelMenu->addMenu(tr("Boundary condition"));1039boundaryConditionMenu->addAction(addBoundaryConditionAct);1040boundaryConditionMenu->addSeparator();1041connect(boundaryConditionMenu, SIGNAL(triggered(QAction *)), this,1042SLOT(boundaryConditionSelectedSlot(QAction *)));10431044modelMenu->addSeparator();1045modelMenu->addAction(bodyEditAct);1046modelMenu->addAction(bcEditAct);1047modelMenu->addSeparator();1048modelMenu->addAction(modelSummaryAct);1049modelMenu->addSeparator();1050modelMenu->addAction(modelClearAct);1051modelMenu->addSeparator();10521053// View menu1054viewMenu = menuBar()->addMenu(tr("&View"));1055viewMenu->addAction(viewFullScreenAct);1056viewMenu->addSeparator();1057viewMenu->addAction(hidesurfacemeshAct);1058viewMenu->addAction(hidevolumemeshAct);1059viewMenu->addAction(hidesharpedgesAct);1060viewMenu->addAction(viewCoordinatesAct);1061viewMenu->addSeparator();1062viewMenu->addAction(selectAllSurfacesAct);1063viewMenu->addAction(selectAllEdgesAct);1064// Momentarily disabled (see comment *** TODO *** below):1065// viewMenu->addSeparator();1066// viewMenu->addAction(selectDefinedEdgesAct);1067// viewMenu->addAction(selectDefinedSurfacesAct);1068viewMenu->addSeparator();1069viewMenu->addAction(hideselectedAct);1070viewMenu->addSeparator();1071shadeMenu = viewMenu->addMenu(tr("Shade model"));1072shadeMenu->addAction(flatShadeAct);1073shadeMenu->addAction(smoothShadeAct);1074viewMenu->addSeparator();1075projectionMenu = viewMenu->addMenu(tr("Projection"));1076projectionMenu->addAction(orthoAct);1077projectionMenu->addAction(perspectiveAct);1078viewMenu->addSeparator();1079numberingMenu = viewMenu->addMenu(tr("Numbering"));1080numberingMenu->addAction(showSurfaceNumbersAct);1081numberingMenu->addAction(showEdgeNumbersAct);1082numberingMenu->addAction(showNodeNumbersAct);1083numberingMenu->addSeparator();1084numberingMenu->addAction(showBoundaryIndexAct);1085numberingMenu->addAction(showBodyIndexAct);1086viewMenu->addSeparator();1087colorizeMenu = viewMenu->addMenu(tr("Lights and colors"));1088colorizeMenu->addAction(glControlAct);1089colorizeMenu->addSeparator();1090colorizeMenu->addAction(chooseBGColorAct);1091colorizeMenu->addSeparator();1092colorizeMenu->addAction(chooseSurfaceColorAct);1093colorizeMenu->addAction(chooseEdgeColorAct);1094colorizeMenu->addSeparator();1095colorizeMenu->addAction(chooseSurfaceMeshColorAct);1096colorizeMenu->addAction(chooseSharpEdgeColorAct);1097colorizeMenu->addSeparator();1098colorizeMenu->addAction(chooseSelectionColorAct);1099colorizeMenu->addSeparator();1100colorizeMenu->addAction(showBoundaryColorAct);1101colorizeMenu->addAction(showBodyColorAct);1102viewMenu->addSeparator();1103viewMenu->addAction(showallAct);1104viewMenu->addAction(resetAct);1105#ifdef EG_OCC1106viewMenu->addSeparator();1107viewMenu->addAction(showCadModelAct);1108#endif1109viewMenu->addAction(showTwodViewAct);1110viewMenu->addSeparator();1111viewMenu->addAction(showObjectBrowserAct);11121113// Edit menu1114editMenu = menuBar()->addMenu(tr("&Sif"));1115editMenu->addAction(generateSifAct);1116editMenu->addSeparator();1117editMenu->addAction(showsifAct);11181119// SolverMenu1120solverMenu = menuBar()->addMenu(tr("&Run"));1121solverMenu->addAction(parallelSettingsAct);1122solverMenu->addSeparator();1123solverMenu->addAction(runsolverAct);1124solverMenu->addAction(killsolverAct);1125#ifdef EG_QWT1126solverMenu->addAction(showConvergenceAct);1127#endif1128solverMenu->addSeparator();1129solverMenu->addAction(resultsAct);1130solverMenu->addAction(killresultsAct);1131#ifdef EG_VTK1132solverMenu->addSeparator();1133solverMenu->addAction(showVtkPostAct);1134#endif1135#ifdef EG_PARAVIEW1136solverMenu->addSeparator();1137solverMenu->addAction(paraviewAct);1138#endif1139solverMenu->addSeparator();1140solverMenu->addAction(compileSolverAct);11411142// Help menu1143helpMenu = menuBar()->addMenu(tr("&Help"));1144helpMenu->addAction(getStartedAct);1145helpMenu->addAction(aboutAct);11461147// Sys tray menu:1148sysTrayMenu = new QMenu;1149sysTrayMenu->addAction(modelSummaryAct);1150sysTrayMenu->addSeparator();1151sysTrayMenu->addAction(stopMeshingAct);1152sysTrayMenu->addSeparator();1153sysTrayMenu->addAction(killsolverAct);1154sysTrayMenu->addAction(killresultsAct);1155sysTrayMenu->addSeparator();1156sysTrayMenu->addAction(aboutAct);1157sysTrayMenu->addSeparator();1158sysTrayMenu->addAction(exitAct);11591160// Context menu:1161contextMenu = new QMenu;1162contextMenu->addMenu(fileMenu);1163contextMenu->addMenu(meshMenu);1164contextMenu->addMenu(modelMenu);1165contextMenu->addMenu(viewMenu);1166contextMenu->addMenu(editMenu);1167contextMenu->addMenu(solverMenu);1168contextMenu->addMenu(helpMenu);11691170selectPostMenu = new QMenu;1171selectPostMenu->addAction(selectElmerPostAct);1172selectPostMenu->addAction(selectVtkPostAct);1173selectPostMenu->addAction(selectParaViewAct);1174#ifndef EG_VTK1175selectVtkPostAct->setEnabled(false);1176#endif1177#ifndef EG_PARAVIEW1178selectParaViewAct->setEnabled(false);1179#endif1180// Disable unavailable external components:1181//------------------------------------------1182if (!egIni->isSet("checkexternalcomponents"))1183return;11841185QProcess testProcess;1186QStringList args;11871188cout << "Checking for ElmerSolver... ";1189updateSplash("Checking for ElmerSolver...");1190args << "-v";1191testProcess.start("ElmerSolver", args);1192if (!testProcess.waitForStarted()) {1193logMessage("no - disabling solver features");1194runsolverAct->setEnabled(false);1195showConvergenceAct->setEnabled(false);1196killsolverAct->setEnabled(false);1197} else {1198cout << "yes" << endl;1199}1200testProcess.waitForFinished(2000);12011202cout << "Checking for ... ";1203updateSplash("Checking for ElmerPost...");1204args << "-v";1205testProcess.start("ElmerPost", args);1206if (!testProcess.waitForStarted()) {1207logMessage("no - disabling ElmerPost postprocessing features");1208resultsAct->setEnabled(false);1209killresultsAct->setEnabled(false);1210} else {1211cout << "yes" << endl;1212}1213testProcess.waitForFinished(2000);12141215cout << "Checking for ElmerGrid... ";1216updateSplash("Checking for ElmerGrid...");1217testProcess.start("ElmerGrid");1218if (!testProcess.waitForStarted()) {1219logMessage("no - disabling parallel features");1220parallelSettingsAct->setEnabled(false);1221} else {1222cout << "yes" << endl;1223}1224testProcess.waitForFinished(2000);12251226cout << "Checking for ElmerSolver_mpi... ";1227updateSplash("Checking for ElmerSolver_mpi...");1228args << "-v";1229testProcess.start("ElmerSolver_mpi", args);1230if (!testProcess.waitForStarted()) {1231logMessage("no - disabling parallel features");1232parallelSettingsAct->setEnabled(false);1233} else {1234cout << "yes" << endl;1235}1236testProcess.waitForFinished(2000);1237}12381239// Create tool bars...1240//-----------------------------------------------------------------------------1241void MainWindow::createToolBars() {1242// File toolbar1243fileToolBar = addToolBar(tr("&File"));1244fileToolBar->addAction(newProjectAct);1245fileToolBar->addAction(loadProjectAct);1246fileToolBar->addAction(saveProjectAct);1247fileToolBar->addAction(saveProjectAsAct);1248fileToolBar->addSeparator();1249fileToolBar->addAction(openAct);1250fileToolBar->addAction(loadAct);1251fileToolBar->addAction(saveAct);1252fileToolBar->addAction(saveAsAct);12531254fileToolBar->addSeparator();1255fileToolBar->addAction(savePictureAct);12561257// Edit toolbar1258editToolBar = addToolBar(tr("&Edit"));1259editToolBar->addAction(showsifAct);12601261// Mesh toolbar1262meshToolBar = addToolBar(tr("&Mesh"));1263meshToolBar->addAction(meshcontrolAct);1264meshToolBar->addAction(remeshAct);1265meshToolBar->addSeparator();1266meshToolBar->addAction(surfaceDivideAct);1267meshToolBar->addAction(surfaceUnifyAct);1268meshToolBar->addSeparator();1269meshToolBar->addAction(edgeDivideAct);1270meshToolBar->addAction(edgeUnifyAct);1271meshToolBar->addSeparator();1272meshToolBar->addAction(bodyEditAct);1273meshToolBar->addAction(bcEditAct);12741275// Solver toolbar1276solverToolBar = addToolBar(tr("&Solver"));1277solverToolBar->addAction(runsolverAct);1278solverToolBar->addAction(runPostProcessorAct);1279solverToolBar->addAction(generateAndSaveAndRunAct);12801281if (egIni->isSet("hidetoolbars")) {1282fileToolBar->hide();1283editToolBar->hide();1284meshToolBar->hide();1285solverToolBar->hide();1286}1287}12881289// Create status bar...1290//-----------------------------------------------------------------------------1291void MainWindow::createStatusBar() {1292progressBar = new QProgressBar;1293progressBar->setMaximumHeight(12);1294progressBar->setMaximumWidth(120);1295progressBar->setTextVisible(false);1296progressBar->hide();12971298progressLabel = new QLabel;1299progressLabel->hide();13001301statusBar()->addPermanentWidget(progressLabel);1302statusBar()->addPermanentWidget(progressBar);13031304statusBar()->showMessage(tr("Ready"));13051306connect(grabTimeLine, SIGNAL(frameChanged(int)), progressBar,1307SLOT(setValue(int)));1308}13091310//*****************************************************************************1311//1312// File MENU1313//1314//*****************************************************************************13151316// File -> Open...1317//-----------------------------------------------------------------------------1318void MainWindow::newProjectSlot() {1319NewProjectDialog dlg;13201321#ifdef __APPLE__DONTGO_HERE_TODO1322QString extraDirpath = this->homePath + "/edf-extra";1323#else1324QString extraDirPath =1325QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";13261327QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));13281329if (!elmerGuiHome.isEmpty())1330extraDirPath = elmerGuiHome + "/edf-extra";13311332extraDirPath.replace('\\', '/');1333#endif13341335QString defaultDir = getDefaultDirName();1336dlg.setDirectories(defaultDir, extraDirPath);13371338if (dlg.exec() == QDialog::Accepted) {13391340// re-initialize1341delete elmerDefs;1342elmerDefs = new QDomDocument;1343delete edfEditor;1344edfEditor = new EdfEditor;1345loadDefinitions();1346geometryInputFileName = "";1347currentProjectDirName = "";1348sifWindow->getTextEdit()->clear();1349sifWindow->hide();1350solverLogWindow->getTextEdit()->clear();1351solverLogWindow->hide();1352delete generalSetup;1353generalSetup = new GeneralSetup(this);1354summaryEditor->ui.summaryEdit->clear();1355delete twodView;1356twodView = new TwodView;1357meshControl->defaultControls();1358delete parallel;1359parallel = new Parallel(this);13601361#ifdef EG_QWT1362convergenceView->removeData();1363#endif13641365#ifdef EG_VTK1366vtkPost->hideAll();1367#endif13681369#ifdef EG_OCC1370settings_setValue("cadView/geometry", cadView->saveGeometry());1371delete cadView;1372cadView = new CadView();1373if (egIni->isPresent("deflection"))1374cadView->setDeflection(egIni->value("deflection").toDouble());1375cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());1376#endif13771378// delete operations1379operation_t *p = operation.next;1380operation_t *q = NULL;1381while (p != NULL) {1382if (p->select_set != NULL)1383delete[] p->select_set;1384q = p->next;1385if (p != NULL)1386delete p;1387p = q;1388}1389operations = 0;1390operation.next = NULL;13911392// reset mesh1393if (glWidget->hasMesh()) {1394glWidget->getMesh()->clear();1395glWidget->deleteMesh();1396}1397glWidget->newMesh();1398meshutils->findSurfaceElementEdges(glWidget->getMesh());1399meshutils->findSurfaceElementNormals(glWidget->getMesh());1400glWidget->rebuildLists();14011402modelClearSlot();14031404// load Elmer mesh/open geometry file1405bool bStartMeshing = false;1406if (dlg.ui.radioButton_elmerMesh->isChecked() &&1407!dlg.ui.label_meshDir->text().isEmpty()) {1408loadElmerMesh(dlg.ui.label_meshDir->text());1409} else if (dlg.ui.radioButton_geometryFile->isChecked() &&1410!dlg.ui.label_geometryFile->text().isEmpty()) {1411QString fileName = dlg.ui.label_geometryFile->text();1412geometryInputFileName = fileName;1413saveDirName = "";1414readInputFile(fileName);1415if (egIni->isSet("automesh"))1416bStartMeshing = true;1417}14181419// save and load project1420saveProject(dlg.ui.label_projectDir->text());1421loadProject(dlg.ui.label_projectDir->text());14221423// load extra solvers1424QString message;1425for (int i = 0; i < dlg.ui.listWidget_selectedSolvers->count(); i++) {1426message = "Load " + extraDirPath + "/" +1427dlg.ui.listWidget_selectedSolvers->item(i)->text() + "... ";1428#if WITH_QT5 || WITH_QT61429cout << string(message.toLatin1());1430cout.flush();1431#else1432cout << string(message.toAscii());1433cout.flush();1434#endif1435edfEditor->appendFrom(extraDirPath + "/" +1436dlg.ui.listWidget_selectedSolvers->item(i)->text());1437cout << " done" << endl;1438}14391440if (bStartMeshing)1441remeshSlot();1442}1443}14441445void MainWindow::parseCmdLine() {1446QStringList args = QCoreApplication::arguments();14471448if (!args.contains("-nogui"))1449this->show();14501451int input = args.indexOf("-i");14521453if (input > 0) {1454QString fileName = args.at(input + 1);14551456QFileInfo fileInfo(fileName);14571458if (!fileInfo.exists()) {1459#if WITH_QT5 || WITH_QT61460cout << "Input file \"" << fileName.toLatin1().data()1461<< "\" does not exist" << endl;1462#else1463cout << "Input file \"" << fileName.toAscii().data()1464<< "\" does not exist" << endl;1465#endif1466QApplication::closeAllWindows();1467exit(0);1468}14691470if (fileName.left(1) != "-") {1471#if WITH_QT5 || WITH_QT61472cout << "Reading input file " << fileName.toLatin1().data() << endl;1473#else1474cout << "Reading input file " << fileName.toAscii().data() << endl;1475#endif1476readInputFile(fileName);1477remeshSlot();1478}1479}1480}14811482// File -> Open...1483//-----------------------------------------------------------------------------1484void MainWindow::openSlot() {1485QString defaultDirName = getDefaultDirName();14861487QString fileName = QFileDialog::getOpenFileName(1488this, tr("Open geometry input file"), defaultDirName);14891490if (!fileName.isEmpty()) {14911492QFileInfo fi(fileName);1493QString absolutePath = fi.absolutePath();1494QDir::setCurrent(absolutePath);14951496} else {14971498logMessage("Unable to open file: file name is empty");1499return;1500}15011502geometryInputFileName = fileName;15031504operation_t *p = operation.next;1505operation_t *q = NULL;15061507while (p != NULL) {1508if (p->select_set != NULL)1509delete[] p->select_set;15101511q = p->next;15121513if (p != NULL)1514delete p;15151516p = q;1517}15181519operations = 0;1520operation.next = NULL;15211522saveDirName = "";1523readInputFile(fileName);15241525if (egIni->isSet("automesh"))1526remeshSlot();1527}15281529// Read input file and populate mesh generator's input structures:1530//-----------------------------------------------------------------------------1531void MainWindow::readInputFile(QString fileName) {1532occInputOk = false;15331534char cs[1024];15351536QFileInfo fi(fileName);1537QString absolutePath = fi.absolutePath();1538QString baseName = fi.baseName();1539QString fileSuffix = fi.suffix();1540QString baseFileName = absolutePath + "/" + baseName;1541#if WITH_QT5 || WITH_QT61542sprintf(cs, "%s", baseFileName.toLatin1().data());1543#else1544sprintf(cs, "%s", baseFileName.toAscii().data());1545#endif15461547fileSuffix = fileSuffix.toLower();1548activeGenerator = GEN_UNKNOWN;1549tetlibInputOk = false;1550nglibInputOk = false;1551ngDim = 3;15521553// Choose generator according to fileSuffix:1554//------------------------------------------1555if ((fileSuffix == "smesh") || (fileSuffix == "poly")) {15561557if (!tetlibPresent) {1558logMessage("unable to mesh - tetlib unavailable");1559return;1560}15611562activeGenerator = GEN_TETLIB;1563cout << "Selected tetlib for smesh/poly-format" << endl;15641565in->deinitialize();1566in->initialize();1567in->load_poly(cs);15681569tetlibInputOk = true;15701571} else if (fileSuffix == "off") {15721573if (!tetlibPresent) {1574logMessage("unable to mesh - tetlib unavailable");1575return;1576}15771578activeGenerator = GEN_TETLIB;1579cout << "Selected tetlib for off-format" << endl;15801581in->deinitialize();1582in->initialize();1583in->load_off(cs);15841585tetlibInputOk = true;15861587} else if (fileSuffix == "ply") {15881589if (!tetlibPresent) {1590logMessage("unable to mesh - tetlib unavailable");1591return;1592}15931594activeGenerator = GEN_TETLIB;1595cout << "Selected tetlib for ply-format" << endl;15961597in->deinitialize();1598in->initialize();1599in->load_ply(cs);16001601tetlibInputOk = true;16021603} else if (fileSuffix == "mesh") {16041605if (!tetlibPresent) {1606logMessage("unable to mesh - tetlib unavailable");1607return;1608}16091610activeGenerator = GEN_TETLIB;1611cout << "Selected tetlib for mesh-format" << endl;16121613in->deinitialize();1614in->initialize();1615in->load_medit(cs, 1);16161617tetlibInputOk = true;16181619} else if (fileSuffix == "stl") {16201621// for stl there are two alternative generators:1622if (meshControl->generatorType == GEN_NGLIB) {16231624if (!nglibPresent) {1625logMessage("unable to mesh - nglib unavailable");1626return;1627}16281629activeGenerator = GEN_NGLIB;1630cout << "Selected nglib for stl-format" << endl;16311632stlFileName = fileName;16331634nglibInputOk = true;16351636} else {16371638if (!tetlibPresent) {1639logMessage("unable to mesh - tetlib unavailable");1640return;1641}16421643activeGenerator = GEN_TETLIB;1644cout << "Selected tetlib for stl-format" << endl;16451646in->deinitialize();1647in->initialize();1648in->load_stl(cs);16491650tetlibInputOk = true;1651}16521653} else if ((fileSuffix == "grd") || (fileSuffix == "fdneut") ||1654(fileSuffix == "msh") || (fileSuffix == "mphtxt") ||1655(fileSuffix == "inp") || (fileSuffix == "unv") ||1656(fileSuffix == "plt")) {16571658activeGenerator = GEN_ELMERGRID;1659cout << "Selected elmergrid" << endl;16601661#if WITH_QT5 || WITH_QT61662int errstat = elmergridAPI->loadElmerMeshStructure(1663(const char *)(fileName.toLatin1()));1664#else1665int errstat = elmergridAPI->loadElmerMeshStructure(1666(const char *)(fileName.toAscii()));1667#endif16681669if (errstat)1670logMessage("loadElmerMeshStructure failed!");16711672return;16731674#ifdef EG_OCC16751676} else if ((fileSuffix.toLower() == "brep") ||1677(fileSuffix.toLower() == "step") ||1678(fileSuffix.toLower() == "stp") ||1679(fileSuffix.toLower() == "iges") ||1680(fileSuffix.toLower() == "igs")) {16811682meshControl->ui.nglibRadioButton->setChecked(true);1683meshControl->generatorType = GEN_NGLIB;1684activeGenerator = meshControl->generatorType;16851686if (egIni->isSet("autoview"))1687cadView->show();16881689occInputOk = cadView->readFile(fileName);16901691ngDim = cadView->getDim();16921693if (!occInputOk) {1694logMessage("Cad import: error: Unable to proceed with input file");1695cadView->close();1696return;1697}16981699nglibInputOk = true;17001701#endif17021703} else if ((fileSuffix.toLower() == "in2d")) {17041705if (!nglibPresent) {1706logMessage("unable to mesh - nglib unavailable");1707return;1708}17091710activeGenerator = GEN_NGLIB;1711cout << "Selected nglib for in2d-format" << endl;17121713in2dFileName = fileName;17141715nglibInputOk = true;17161717ngDim = 2;17181719} else {17201721logMessage("Unable to open file: file type unknown");1722activeGenerator = GEN_UNKNOWN;17231724return;1725}1726}17271728// Populate elmer's mesh structure and make GL-lists (tetlib):1729//-----------------------------------------------------------------------------1730void MainWindow::makeElmerMeshFromTetlib() {1731meshutils->clearMesh(glWidget->getMesh());17321733glWidget->setMesh(tetlibAPI->createElmerMeshStructure());17341735glWidget->rebuildLists();17361737logMessage("Input file processed");1738}17391740// Populate elmer's mesh structure and make GL-lists (nglib):1741//-----------------------------------------------------------------------------1742void MainWindow::makeElmerMeshFromNglib() {1743meshutils->clearMesh(glWidget->getMesh());1744nglibAPI->setDim(this->ngDim);1745nglibAPI->setNgmesh(ngmesh);17461747glWidget->setMesh(nglibAPI->createElmerMeshStructure());1748glWidget->rebuildLists();17491750logMessage("Input file processed");1751}17521753// File -> Load mesh...1754//-----------------------------------------------------------------------------1755void MainWindow::loadSlot() {1756QString defaultDirName = getDefaultDirName();17571758QString dirName = QFileDialog::getExistingDirectory(1759this, tr("Open mesh directory"), defaultDirName);17601761if (!dirName.isEmpty()) {17621763logMessage("Loading from directory " + dirName);17641765} else {17661767logMessage("Unable to load mesh: directory undefined");1768return;1769}17701771loadElmerMesh(dirName);1772}17731774// Import mesh files in elmer-format:1775//-----------------------------------------------------------------------------1776void MainWindow::loadElmerMesh(QString dirName) {1777logMessage("Loading elmer mesh files");17781779if (glWidget->hasMesh()) {1780glWidget->getMesh()->clear();1781glWidget->deleteMesh();1782}17831784glWidget->newMesh();17851786#if WITH_QT5 || WITH_QT61787bool success = glWidget->getMesh()->load(dirName.toLatin1().data());1788#else1789bool success = glWidget->getMesh()->load(dirName.toAscii().data());1790#endif17911792if (!success) {1793glWidget->getMesh()->clear();1794glWidget->deleteMesh();1795logMessage("Failed loading mesh files");1796return;1797}17981799meshutils->findSurfaceElementEdges(glWidget->getMesh());1800meshutils->findSurfaceElementNormals(glWidget->getMesh());18011802glWidget->rebuildLists();18031804QDir::setCurrent(dirName);1805saveDirName = dirName;18061807logMessage("Ready");1808}18091810// File -> Save...1811//-----------------------------------------------------------------------------1812void MainWindow::saveSlot() {1813if (!glWidget->hasMesh()) {1814logMessage("Unable to save mesh: no data");1815return;1816}18171818if (!saveDirName.isEmpty()) {1819logMessage("Output directory " + saveDirName);1820} else {1821saveAsSlot();1822return;1823}18241825saveElmerMesh(saveDirName);1826}18271828// File -> Save as...1829//-----------------------------------------------------------------------------1830void MainWindow::saveAsSlot() {1831if (!glWidget->hasMesh()) {1832logMessage("Unable to save mesh: no data");1833return;1834}18351836QString defaultDirName = getDefaultDirName();18371838QString dirName = QFileDialog::getExistingDirectory(1839this, tr("Open directory to save mesh"), defaultDirName);18401841if (!dirName.isEmpty()) {1842logMessage("Output directory " + dirName);1843saveDirName = dirName;1844} else {1845logMessage("Unable to save: directory undefined");1846return;1847}18481849saveElmerMesh(saveDirName);1850}18511852// File -> Save project1853//-----------------------------------------------------------------------------1854void MainWindow::saveProjectSlot() {1855if (!glWidget->hasMesh()) {1856logMessage("Unable to save project: no mesh");1857return;1858}18591860QString projectDirName = currentProjectDirName;1861if (!projectDirName.isEmpty()) {1862logMessage("Project directory " + projectDirName);1863saveProject(projectDirName);1864} else {1865saveProjectAsSlot();1866}1867}18681869// File -> Save project as...1870//-----------------------------------------------------------------------------1871void MainWindow::saveProjectAsSlot() {1872if (!glWidget->hasMesh()) {1873logMessage("Unable to save project: no mesh");1874return;1875}18761877QString defaultDirName = getDefaultDirName();18781879QString projectDirName = QFileDialog::getExistingDirectory(1880this, tr("Open directory to save project"), defaultDirName);18811882if (!projectDirName.isEmpty()) {1883logMessage("Project directory " + projectDirName);1884} else {1885logMessage("Unable to save project: directory undefined");1886return;1887}18881889saveProject(projectDirName);1890}18911892bool MainWindow::saveProject(QString projectDirName) {1893if (!glWidget->hasMesh()) {1894logMessage("Unable to save project: no mesh");1895return false;1896}18971898progressBar->show();1899progressBar->setRange(0, 13);19001901progressLabel->setText("Saving");1902progressLabel->show();19031904// Create project document:1905//-------------------------1906progressBar->setValue(1);19071908QDomDocument projectDoc("egproject");1909QDomElement contents = projectDoc.createElement("contents");1910projectDoc.appendChild(contents);19111912//===========================================================================1913// SAVE MESH1914//===========================================================================1915progressBar->setValue(2);1916logMessage("Saving mesh files...");1917saveElmerMesh(projectDirName);19181919//===========================================================================1920// SAVE GEOMETRY INPUT FILE(S)1921//===========================================================================1922progressBar->setValue(3);19231924#ifdef Q_OS_LINUX1925QFileInfo fileInfo(geometryInputFileName);1926QString pathName(fileInfo.absolutePath());1927QString baseName(fileInfo.baseName());19281929// System copy command:1930QString cmd("cp -f " + pathName + "/" + baseName + ".* " + projectDirName);19311932if (system(cmd.toLatin1().data()))1933logMessage("Geometry input file(s) not copied");19341935QDomElement geomInput(projectDoc.createElement("geometryinputfile"));1936QDomText geomInputValue(projectDoc.createTextNode(fileInfo.fileName()));1937geomInput.appendChild(geomInputValue);1938contents.appendChild(geomInput);19391940#else1941QFileInfo geometryInputFileInfo(geometryInputFileName);1942QString baseName(geometryInputFileInfo.baseName());19431944QString srcPathName(geometryInputFileInfo.absolutePath());1945QString dstPathName(QDir(projectDirName).absolutePath());19461947// Avoid copying file(s) into it self:19481949if (srcPathName != dstPathName) {1950QDirIterator srcDirIterator(srcPathName);19511952while (srcDirIterator.hasNext()) {1953QString srcFileName(srcDirIterator.next());1954QFileInfo srcFileInfo(srcDirIterator.fileInfo());19551956if (srcFileInfo.baseName() == baseName) {1957logMessage("Copying: " + srcFileName);19581959QFile src(srcFileName);19601961if (!src.open(QFile::ReadOnly)) {1962logMessage("Unable to read: " + src.fileName());1963continue;1964}19651966QFile dst(dstPathName + "/" + srcFileInfo.fileName());19671968if (!dst.open(QFile::WriteOnly)) {1969logMessage("Unable to write: " + dst.fileName());1970src.close();1971continue;1972}19731974QTextStream srcStream(&src);1975QTextStream dstStream(&dst);1976dstStream << srcStream.readAll();19771978dst.close();1979src.close();1980}1981}19821983} else {1984logMessage("Geometry input file(s) not copied");1985}19861987QDomElement geomInput = projectDoc.createElement("geometryinputfile");1988QDomText geomInputValue =1989projectDoc.createTextNode(geometryInputFileInfo.fileName());1990geomInput.appendChild(geomInputValue);1991contents.appendChild(geomInput);1992#endif19931994//===========================================================================1995// SAVE OPERATIONS1996//===========================================================================1997progressBar->setValue(4);1998QDomElement ops = projectDoc.createElement("operations");1999contents.appendChild(ops);2000operation.appendToProject(&projectDoc, &ops);20012002//===========================================================================2003// SAVE GENERAL SETUP2004//===========================================================================2005progressBar->setValue(5);2006logMessage("Saving menu contents... ");2007QDomElement gsBlock = projectDoc.createElement("generalsetup");2008projectDoc.documentElement().appendChild(gsBlock);2009generalSetup->appendToProject(&projectDoc, &gsBlock);20102011//===========================================================================2012// SAVE PARALLEL SETTINGS2013//===========================================================================2014progressBar->setValue(6);2015QDomElement paraBlock = projectDoc.createElement("parallelsettings");2016projectDoc.documentElement().appendChild(paraBlock);2017parallel->appendToProject(&projectDoc, ¶Block);20182019//===========================================================================2020// SAVE MESH PARAMETERS2021//===========================================================================2022progressBar->setValue(7);2023QDomElement meshParams = projectDoc.createElement("meshparameters");2024projectDoc.documentElement().appendChild(meshParams);2025meshControl->appendToProject(&projectDoc, &meshParams);20262027//===========================================================================2028// SAVE SOLVER PARAMETERS2029//===========================================================================2030progressBar->setValue(8);2031QDomElement speBlock = projectDoc.createElement("solverparameters");2032projectDoc.documentElement().appendChild(speBlock);20332034for (int index = 0; index < solverParameterEditor.size(); index++) {2035SolverParameterEditor *spe = solverParameterEditor[index];20362037if (!spe)2038continue;20392040QDomElement item = projectDoc.createElement("item");2041item.setAttribute("index", QString::number(index));2042item.setAttribute("name", spe->solverName);2043speBlock.appendChild(item);2044spe->appendToProject(&projectDoc, &item);2045}20462047//===========================================================================2048// SAVE DYNAMIC MENU CONTENTS2049//===========================================================================2050progressBar->setValue(9);2051saveProjectContents(projectDoc, "equation", equationEditor);2052saveProjectContents(projectDoc, "material", materialEditor);2053saveProjectContents(projectDoc, "bodyforce", bodyForceEditor);2054saveProjectContents(projectDoc, "initialcondition", initialConditionEditor);2055saveProjectContents(projectDoc, "boundarycondition", boundaryConditionEditor);20562057//===========================================================================2058// SAVE SOLVER SPECIFIC OPTIONS2059//===========================================================================2060progressBar->setValue(10);2061QDomElement solverOptionsBlock =2062projectDoc.createElement("solverspecificoptions");2063projectDoc.documentElement().appendChild(solverOptionsBlock);20642065for (int index = 0; index < solverParameterEditor.size(); index++) {2066SolverParameterEditor *spe = solverParameterEditor[index];20672068if (!spe)2069continue;20702071DynamicEditor *dynEdit = spe->generalOptions;20722073if (!dynEdit)2074continue;20752076QDomElement item = projectDoc.createElement("item");2077item.setAttribute("index", QString::number(index));2078item.setAttribute("name", spe->solverName);2079item.setAttribute("id", QString::number(dynEdit->ID));2080solverOptionsBlock.appendChild(item);20812082dynEdit->dumpHash(&projectDoc, &item);2083}20842085//===========================================================================2086// SAVE BODY PROPERTIES2087//===========================================================================2088progressBar->setValue(11);2089QDomElement bodyBlock = projectDoc.createElement("bodyproperties");2090projectDoc.documentElement().appendChild(bodyBlock);20912092for (int index = 0; index < bodyPropertyEditor.size(); index++) {2093BodyPropertyEditor *bpe = bodyPropertyEditor[index];20942095if (!bpe)2096continue;20972098QDomElement item = projectDoc.createElement("item");2099item.setAttribute("index", QString::number(index));2100bodyBlock.appendChild(item);2101bpe->appendToProject(&projectDoc, &item);2102}21032104//===========================================================================2105// SAVE BOUNDARY PROPERTIES2106//===========================================================================2107progressBar->setValue(12);2108QDomElement boundaryBlock = projectDoc.createElement("boundaryproperties");2109projectDoc.documentElement().appendChild(boundaryBlock);21102111for (int index = 0; index < boundaryPropertyEditor.size(); index++) {2112BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];21132114if (!bpe)2115continue;21162117QDomElement item = projectDoc.createElement("item");2118item.setAttribute("index", QString::number(index));2119boundaryBlock.appendChild(item);2120bpe->appendToProject(&projectDoc, &item);2121}21222123//===========================================================================2124// SAVE PROJECT DOCUMENT2125//===========================================================================2126progressBar->setValue(13);2127const int indent = 3;2128QFile projectFile("egproject.xml");2129projectFile.open(QIODevice::WriteOnly);2130QTextStream projectTextStream(&projectFile);2131projectDoc.save(projectTextStream, indent);21322133saveDirName = projectDirName;2134logMessage("Ready");21352136progressBar->hide();2137progressLabel->hide();21382139setWindowTitle(QString("ElmerGUI - ") + projectDirName);2140addRecentProject(projectDirName, true);2141currentProjectDirName = projectDirName;21422143return true;2144}21452146// Helper function for saveProject2147//-----------------------------------------------------------------------------2148void MainWindow::saveProjectContents(QDomDocument projectDoc, QString blockName,2149QVector<DynamicEditor *> &editor) {2150int Nmax = editor.size();21512152QDomElement editorBlock = projectDoc.createElement(blockName);2153projectDoc.documentElement().appendChild(editorBlock);2154int index = 0; // index excluding removed DynamicEditor instances21552156for (int i = 0; i < Nmax; i++) {2157DynamicEditor *de = editor[i];21582159if (de->menuAction == NULL)2160continue;21612162// Menu item number:2163QDomElement item = projectDoc.createElement("item");2164item.setAttribute("index", QString::number(index++));2165editorBlock.appendChild(item);21662167// Is active?2168QDomElement itemActive = projectDoc.createElement("active");2169QDomText itemActiveValue =2170projectDoc.createTextNode(QString::number(de->menuAction != NULL));2171itemActive.appendChild(itemActiveValue);2172item.appendChild(itemActive);21732174// Name:2175if (de->menuAction != NULL) {2176QDomElement itemName = projectDoc.createElement("name");2177QDomText itemNameValue =2178projectDoc.createTextNode(de->nameEdit->text().trimmed());2179itemName.appendChild(itemNameValue);2180item.appendChild(itemName);2181}21822183de->dumpHash(&projectDoc, &item);2184}2185}21862187// File -> Load project...2188//-----------------------------------------------------------------------------2189void MainWindow::loadProjectSlot() {2190QString defaultDirName = getDefaultDirName();21912192QString projectDirName = QFileDialog::getExistingDirectory(2193this, tr("Open project directory"), defaultDirName);21942195loadProject(projectDirName);2196}21972198void MainWindow::loadProject(QString projectDirName) {2199if (!projectDirName.isEmpty()) {2200logMessage("Project directory: " + projectDirName);2201} else {2202logMessage("Unable to load project: directory undefined");2203return;2204}22052206QDir::setCurrent(projectDirName);2207saveDirName = projectDirName;22082209progressBar->show();2210progressBar->setRange(0, 14);22112212progressLabel->setText("Loading");2213progressLabel->show();22142215// Clear previous data:2216//----------------------2217progressBar->setValue(1);22182219logMessage("Clearing model data");2220modelClearSlot();22212222// Re-initialize definitions and edfEditor2223delete elmerDefs;2224delete edfEditor;2225elmerDefs = new QDomDocument;2226edfEditor = new EdfEditor;2227loadDefinitions();22282229// Load project doc:2230//-------------------2231progressBar->setValue(2);22322233logMessage("Loading project document...");2234QDomDocument projectDoc;2235QString errStr;2236int errRow;2237int errCol;2238QFile projectFile("egproject.xml");22392240if (!projectFile.exists()) {2241QMessageBox::information(window(), tr("Project loader"),2242tr("Project file does not exist"));22432244progressBar->hide();2245progressLabel->hide();22462247return;22482249} else {22502251if (!projectDoc.setContent(&projectFile, true, &errStr, &errRow, &errCol)) {2252QMessageBox::information(window(), tr("Project loader"),2253tr("Parse error at line %1, col %2:\n%3")2254.arg(errRow)2255.arg(errCol)2256.arg(errStr));2257projectFile.close();22582259progressBar->hide();2260progressLabel->hide();22612262return;2263}2264}22652266projectFile.close();22672268if (projectDoc.documentElement().tagName() != "contents") {2269QMessageBox::information(window(), tr("Project loader"),2270tr("This is not a project file"));22712272progressBar->hide();2273progressLabel->hide();22742275return;2276}22772278// load extra solvers from /edf-extra2279checkAndLoadExtraSolvers(&projectFile);22802281setWindowTitle(QString("ElmerGUI - ") + projectDirName);2282addRecentProject(projectDirName, true);2283currentProjectDirName = projectDirName;22842285QDomElement contents = projectDoc.documentElement();22862287//===========================================================================2288// LOAD MESH2289//===========================================================================2290progressBar->setValue(3);2291logMessage("Loading mesh files...");2292loadElmerMesh(projectDirName);2293resetSlot();22942295//===========================================================================2296// LOAD GEOMETRY INPUT FILE2297//===========================================================================2298progressBar->setValue(4);2299cout << "Loading geometry input file" << endl;2300QDomElement geomInput = contents.firstChildElement("geometryinputfile");2301geometryInputFileName = projectDirName + "/" + geomInput.text().trimmed();2302logMessage("Geometry input file: " + geometryInputFileName);2303readInputFile(geometryInputFileName);23042305//===========================================================================2306// LOAD OPERATIONS2307//===========================================================================2308logMessage("Loading operations...");2309progressBar->setValue(5);2310QDomElement ops = contents.firstChildElement("operations");2311operations = operation.readFromProject(&projectDoc, &ops);23122313//===========================================================================2314// LOAD GENERAL SETUP2315//===========================================================================2316logMessage("Loading general setup...");2317progressBar->setValue(6);2318QDomElement gsBlock = contents.firstChildElement("generalsetup");2319generalSetup->readFromProject(&projectDoc, &gsBlock);23202321//===========================================================================2322// LOAD PARALLEL SETTINGS2323//===========================================================================2324logMessage("Loading parallel settings...");2325progressBar->setValue(7);2326QDomElement paraBlock = contents.firstChildElement("parallelsettings");2327parallel->readFromProject(&projectDoc, ¶Block);23282329//===========================================================================2330// LOAD MESH PARAMETERS2331//===========================================================================2332logMessage("Loading mesh parameters...");2333progressBar->setValue(8);2334QDomElement meshParams = contents.firstChildElement("meshparameters");2335meshControl->readFromProject(&projectDoc, &meshParams);23362337//===========================================================================2338// LOAD SOLVER PARAMETERS2339//===========================================================================2340logMessage("Loading solver parameters...");2341progressBar->setValue(9);2342QDomElement speBlock = contents.firstChildElement("solverparameters");23432344QDomElement item = speBlock.firstChildElement("item");2345for (; !item.isNull(); item = item.nextSiblingElement()) {2346int index = item.attribute("index").toInt();2347QString name = item.attribute("name");23482349if (name.trimmed().isEmpty())2350continue;23512352// Find the real index for the current edf setup:2353int count = 0, realIndex = -1;2354QDomElement root = elmerDefs->documentElement();2355QDomElement elem = root.firstChildElement("PDE");2356while (!elem.isNull()) {2357QDomElement pdeName = elem.firstChildElement("Name");2358if (pdeName.text().trimmed() == name.trimmed())2359realIndex = count;2360elem = elem.nextSiblingElement();2361count++;2362}23632364if (realIndex < 0) {2365cout << "ERROR: The current edf setup conflicts with the project. "2366"Aborting."2367<< endl;23682369progressBar->hide();2370progressLabel->hide();23712372return;2373}23742375index = realIndex - 1;23762377if (index < 0) {2378logMessage("Load project: solver parameters: index out of bounds");23792380progressBar->hide();2381progressLabel->hide();23822383return;2384}23852386if (index >= solverParameterEditor.size())2387solverParameterEditor.resize(index + 1);23882389if (!solverParameterEditor[index])2390solverParameterEditor[index] = new SolverParameterEditor;23912392SolverParameterEditor *spe = solverParameterEditor[index];2393spe->readFromProject(&projectDoc, &item);2394}23952396#if 02397// Changed the load order in 19 March 2009 for taking the "use as a body"2398// flags into account. The original boundary property loader is below.2399//2400// Changed back to original 23 March 2009. Todo...2401//===========================================================================2402// LOAD BOUNDARY PROPERTIES2403//===========================================================================2404progressBar->setValue(10);2405QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");24062407item = boundaryBlock.firstChildElement("item");2408for( ; !item.isNull(); item = item.nextSiblingElement()) {2409int index = item.attribute("index").toInt();24102411if(index < 0) {2412logMessage("Load project: boundary properties: index out of bounds");24132414progressBar->hide();2415progressLabel->hide();24162417return;2418}24192420if(index >= boundaryPropertyEditor.size())2421boundaryPropertyEditor.resize(index + 1);24222423if(!boundaryPropertyEditor[index])2424boundaryPropertyEditor[index] = new BoundaryPropertyEditor;24252426BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];24272428bpe->readFromProject(&projectDoc, &item);24292430if(bpe->ui.boundaryAsABody->isChecked()) {2431connect(bpe, SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor*, int)),2432this, SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor*, int)));24332434populateBoundaryComboBoxes(bpe);24352436bpe->ui.boundaryAsABody->toggle();2437bpe->ui.boundaryAsABody->toggle();2438bpe->ui.applyButton->click();2439}2440}2441#endif24422443//===========================================================================2444// LOAD DYNAMIC EDITOR CONTENTS2445//===========================================================================2446logMessage("Loading dynamic editor contents...");2447progressBar->setValue(11);2448QDomElement element =2449projectDoc.documentElement().firstChildElement("equation");2450loadProjectContents(element, equationEditor, "Equation");2451element = projectDoc.documentElement().firstChildElement("material");2452loadProjectContents(element, materialEditor, "Material");2453element = projectDoc.documentElement().firstChildElement("bodyforce");2454loadProjectContents(element, bodyForceEditor, "BodyForce");2455element = projectDoc.documentElement().firstChildElement("initialcondition");2456loadProjectContents(element, initialConditionEditor, "InitialCondition");2457element = projectDoc.documentElement().firstChildElement("boundarycondition");2458loadProjectContents(element, boundaryConditionEditor, "BoundaryCondition");24592460//===========================================================================2461// LOAD SOLVER SPECIFIC OPTIONS2462//===========================================================================2463logMessage("Loading solver specific options...");2464progressBar->setValue(12);2465QDomElement solverOptionsBlock =2466contents.firstChildElement("solverspecificoptions");24672468for (item = solverOptionsBlock.firstChildElement("item"); !item.isNull();2469item = item.nextSiblingElement()) {24702471int index = item.attribute("index").toInt();2472QString name = item.attribute("name");2473int id = item.attribute("id").toInt();24742475if (name.trimmed().isEmpty())2476continue;24772478// Find the real index for the current edf setup:2479int count = 0, realIndex = -1;2480QDomElement root = elmerDefs->documentElement();2481QDomElement elem = root.firstChildElement("PDE");2482while (!elem.isNull()) {2483QDomElement pdeName = elem.firstChildElement("Name");2484if (pdeName.text().trimmed() == name.trimmed())2485realIndex = count;2486elem = elem.nextSiblingElement();2487count++;2488}24892490if (realIndex < 0) {2491cout << "ERROR: The current edf setup conflicts with the project. "2492"Aborting."2493<< endl;24942495progressBar->hide();2496progressLabel->hide();24972498return;2499}25002501index = realIndex - 1;25022503if (index < 0) {2504logMessage("Load project: solver specific options: index out of bounds");25052506progressBar->hide();2507progressLabel->hide();25082509return;2510}25112512if (index >= solverParameterEditor.size())2513solverParameterEditor.resize(index + 1);25142515if (!solverParameterEditor[index])2516solverParameterEditor[index] = new SolverParameterEditor;25172518SolverParameterEditor *spe = solverParameterEditor[index];2519spe->solverName = name;25202521if (spe->generalOptions == NULL) {2522spe->generalOptions = new DynamicEditor;25232524// following 3 lines were moved into if() block to avoid doubled "Solver2525// specific options" tabs (Nov 2019 by TS)2526// The argument "index" in the following two functions is changed from "id" to avoid2527// crossed parameters (Mar 2022 by TS) See http://www.elmerfem.org/forum/viewtopic.php?t=76962528spe->generalOptions->setupTabs(elmerDefs, "Solver", index);2529spe->generalOptions->populateHash(&item);2530spe->ui.solverControlTabs->insertTab(25310, spe->generalOptions->tabWidget->widget(index),2532"Solver specific options");2533}2534}25352536//===========================================================================2537// LOAD BODY PROPERTIES2538//===========================================================================2539logMessage("Loading body properties...");2540progressBar->setValue(13);2541QDomElement bodyBlock = contents.firstChildElement("bodyproperties");25422543item = bodyBlock.firstChildElement("item");2544for (; !item.isNull(); item = item.nextSiblingElement()) {2545int index = item.attribute("index").toInt();25462547if (index < 0) {2548logMessage("Load project: body properties: index out of bounds");25492550progressBar->hide();2551progressLabel->hide();25522553return;2554}25552556if (index >= bodyPropertyEditor.size())2557bodyPropertyEditor.resize(index + 1);25582559if (!bodyPropertyEditor[index])2560bodyPropertyEditor[index] = new BodyPropertyEditor;25612562BodyPropertyEditor *bpe = bodyPropertyEditor[index];2563bpe->readFromProject(&projectDoc, &item);2564}25652566//===========================================================================2567// LOAD BOUNDARY PROPERTIES2568//===========================================================================2569logMessage("Loading boundary properties...");2570progressBar->setValue(13);2571QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");25722573item = boundaryBlock.firstChildElement("item");2574for (; !item.isNull(); item = item.nextSiblingElement()) {2575int index = item.attribute("index").toInt();25762577if (index < 0) {2578logMessage("Load project: boundary properties: index out of bounds");25792580progressBar->hide();2581progressLabel->hide();25822583return;2584}25852586if (index >= boundaryPropertyEditor.size())2587boundaryPropertyEditor.resize(index + 1);25882589if (!boundaryPropertyEditor[index])2590boundaryPropertyEditor[index] = new BoundaryPropertyEditor;25912592BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];2593bpe->readFromProject(&projectDoc, &item);2594}25952596//===========================================================================2597// LOAD SIF2598//===========================================================================2599progressBar->setValue(14);2600if (glWidget->hasMesh()) {2601QFile file;2602QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();2603file.setFileName(sifName);2604if (file.open(QIODevice::ReadOnly)) {2605QTextStream inputStream(&file);2606QString line = inputStream.readAll();2607file.close();2608sifWindow->getTextEdit()->clear();2609sifWindow->getTextEdit()->append(line);2610sifWindow->setFirstTime(true);2611sifWindow->setFound(false);2612logMessage(sifName + " loaded.");2613} else {2614logMessage(" failed to open " + sifName);2615}2616}26172618logMessage("Ready");26192620progressBar->hide();2621progressLabel->hide();26222623#ifdef EG_VTK2624vtkPost->hideAll();2625#endif2626}26272628// Helper function for load project2629//--------------------------------------------------------------------------------------------2630void MainWindow::loadProjectContents(QDomElement projectElement,2631QVector<DynamicEditor *> &editor,2632QString Mname) {2633int Nmax = editor.size();26342635QDomElement item = projectElement.firstChildElement("item");26362637for (; !item.isNull(); item = item.nextSiblingElement()) {2638int index = item.attribute("index").toInt();26392640if (index < 0) {2641logMessage("Project loader: index out of bounds (dynamic editor)");2642return;2643}26442645if (index >= editor.size())2646editor.resize(index + 1);26472648if (!editor[index])2649editor[index] = new DynamicEditor;26502651DynamicEditor *de = editor[index];26522653bool active = (item.firstChildElement("active").text().toInt() > 0);26542655if (!active)2656continue;26572658// Set up dynamic editor and connect:2659//------------------------------------2660QString itemName = item.firstChildElement("name").text().trimmed();26612662de->setupTabs(elmerDefs, Mname, index);2663de->nameEdit->setText(itemName);2664de->applyButton->setText("Update");2665de->applyButton->setIcon(QIcon::fromTheme("view-refresh"));2666de->discardButton->setText("Remove");2667de->discardButton->setIcon(QIcon::fromTheme("list-remove"));26682669const QString &tmpName = itemName;2670QAction *act = new QAction(tmpName, this);26712672if (Mname == "Equation") {2673connect(de, SIGNAL(dynamicEditorReady(int, int)), this,2674SLOT(pdeEditorFinishedSlot(int, int)));2675de->spareButton->setText("Edit Solver Settings");2676de->spareButton->show();2677de->spareButton->setIcon(QIcon::fromTheme("preferences-system"));2678de->spareButton->setWhatsThis(tr("Open solver setting window"));2679connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,2680SLOT(editNumericalMethods(int, int)));2681equationMenu->addAction(act);2682}26832684if (Mname == "Material") {2685connect(de, SIGNAL(dynamicEditorReady(int, int)), this,2686SLOT(matEditorFinishedSlot(int, int)));2687de->spareButton->setText("Material library");2688de->spareButton->show();2689de->spareButton->setIcon(QIcon::fromTheme("book-cover-A-Z"));2690de->spareButton->setWhatsThis(tr("Open material library"));2691connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,2692SLOT(showMaterialLibrary(int, int)));2693materialMenu->addAction(act);2694}26952696if (Mname == "BodyForce") {2697connect(de, SIGNAL(dynamicEditorReady(int, int)), this,2698SLOT(bodyForceEditorFinishedSlot(int, int)));2699bodyForceMenu->addAction(act);2700}27012702if (Mname == "InitialCondition") {2703connect(de, SIGNAL(dynamicEditorReady(int, int)), this,2704SLOT(initialConditionEditorFinishedSlot(int, int)));2705initialConditionMenu->addAction(act);2706}27072708if (Mname == "BoundaryCondition") {2709connect(de, SIGNAL(dynamicEditorReady(int, int)), this,2710SLOT(boundaryConditionEditorFinishedSlot(int, int)));2711boundaryConditionMenu->addAction(act);2712}27132714de->menuAction = act;27152716if (Mname == "Equation")2717createBodyCheckBoxes(BODY_EQUATION, de);27182719if (Mname == "Material")2720createBodyCheckBoxes(BODY_MATERIAL, de);27212722if (Mname == "BodyForce")2723createBodyCheckBoxes(BODY_FORCE, de);27242725if (Mname == "InitialCondition")2726createBodyCheckBoxes(BODY_INITIAL, de);27272728if (Mname == "BoundaryCondition")2729createBoundaryCheckBoxes(de);27302731de->populateHash(&item);2732}2733}27342735// Export mesh files in elmer-format:2736//-----------------------------------------------------------------------------2737void MainWindow::saveElmerMesh(QString dirName) {2738logMessage("Saving elmer mesh files");27392740QDir dir(dirName);27412742if (!dir.exists())2743dir.mkdir(dirName);27442745dir.setCurrent(dirName);27462747// Save mesh files:2748//------------------2749#if WITH_QT5 || WITH_QT62750glWidget->getMesh()->save(dirName.toLatin1().data());2751#else2752glWidget->getMesh()->save(dirName.toAscii().data());2753#endif27542755// Save solver input file:2756//-------------------------2757QFile file;2758QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();2759file.setFileName(sifName);2760file.open(QIODevice::WriteOnly);2761QTextStream sif(&file);27622763QApplication::setOverrideCursor(Qt::WaitCursor);2764sif << sifWindow->getTextEdit()->toPlainText();2765QApplication::restoreOverrideCursor();27662767file.close();27682769// Save ELMERSOLVER_STARTINFO:2770//-----------------------------2771file.setFileName("ELMERSOLVER_STARTINFO");2772file.open(QIODevice::WriteOnly);2773QTextStream startinfo(&file);27742775#if WITH_QT62776startinfo << sifName.toLatin1() << Qt::endl << "1" << Qt::endl;2777#elif WITH_QT52778startinfo << sifName.toLatin1() << endl << "1" << endl;2779#else2780startinfo << sifName.toAscii() << endl << "1" << endl;2781#endif27822783file.close();27842785logMessage("Ready");2786}27872788// File -> Exit2789//-----------------------------------------------------------------------------2790void MainWindow::closeMainWindowSlot() {2791saveSlot();2792QApplication::closeAllWindows();2793// close();2794}27952796// File -> Save picture as...2797//-----------------------------------------------------------------------------2798void MainWindow::savePictureSlot() {2799QString defaultDirName(getDefaultDirName());28002801pictureFileName = QFileDialog::getSaveFileName(2802this, tr("Save picture"), defaultDirName,2803tr("Picture files (*.bmp *.jpg *.png *.pbm *.pgm *.ppm)"));28042805if (pictureFileName.isEmpty()) {2806logMessage("File name is empty");2807return;2808}28092810int delay = egIni->value("screenshotdelay").toInt();28112812grabTimeLine->stop();2813grabTimeLine->setDuration(delay);2814#if WITH_QT62815grabTimeLine->setEasingCurve(QEasingCurve(QEasingCurve::Linear));2816#else2817grabTimeLine->setCurveShape(QTimeLine::LinearCurve);2818#endif2819grabTimeLine->setDirection(QTimeLine::Backward);2820grabTimeLine->setFrameRange(0, 10);2821progressLabel->setText("Delay screen shot");2822progressLabel->show();2823progressBar->setRange(0, 10);2824progressBar->show();2825grabTimeLine->start();2826}28272828void MainWindow::grabFrameSlot() {2829progressLabel->hide();2830progressBar->hide();28312832if (pictureFileName.isEmpty()) {2833logMessage("Unable to take screen shot - file name is empty");2834return;2835}28362837QFileInfo fi(pictureFileName);2838QString suffix(fi.suffix());2839suffix = suffix.toUpper();28402841int imageQuality(egIni->value("defaultimagequality").toInt());28422843bool withAlpha(false);28442845glWidget->updateGL();2846glReadBuffer(GL_BACK);28472848#if WITH_QT62849QImage image(glWidget->grabFramebuffer());2850#else2851QImage image(glWidget->grabFrameBuffer(withAlpha));2852#endif28532854#if WITH_QT5 || WITH_QT62855bool success(image.save(pictureFileName, suffix.toLatin1(), imageQuality));2856#else2857bool success(image.save(pictureFileName, suffix.toAscii(), imageQuality));2858#endif28592860if (!success)2861logMessage("Failed writing picture file");2862}28632864//*****************************************************************************2865//2866// Model MENU2867//2868//*****************************************************************************28692870// Model -> Setup...2871//-----------------------------------------------------------------------------2872void MainWindow::modelSetupSlot() { generalSetup->show(); }28732874//-----------------------------------------------------------------------------2875void MainWindow::createBodyCheckBoxes(int which, DynamicEditor *pe) {2876if (!glWidget->hasMesh())2877return;28782879if (pe->spareScroll->widget())2880delete pe->spareScroll->widget();28812882QGridLayout *slayout = new QGridLayout;2883QLabel *l = new QLabel(tr("Apply to bodies:"));28842885int count = 0, even = 0;28862887slayout->addWidget(l, count, 0);2888count++;28892890QMapIterator<int, int> itr(glWidget->bodyMap);2891while (itr.hasNext()) {2892itr.next();2893int n = itr.key();2894if (n >= 0) {2895int m = itr.value();28962897if (m >= bodyPropertyEditor.size())2898bodyPropertyEditor.resize(m + 1);28992900if (!bodyPropertyEditor[m])2901bodyPropertyEditor[m] = new BodyPropertyEditor;29022903BodyPropertyEditor *body = bodyPropertyEditor[m];29042905populateBodyComboBoxes(body);29062907QString title = body->ui.nameEdit->text().trimmed();2908QCheckBox *a;29092910if (title.isEmpty())2911// a = new QCheckBox("Body " + QString::number(n));2912a = new QCheckBox("Body Property " + QString::number(n));2913else2914a = new QCheckBox(title);29152916DynamicEditor *p = NULL;29172918switch (which) {2919case BODY_MATERIAL:2920p = body->material;2921connect(a, SIGNAL(stateChanged(int)), this,2922SLOT(materialBodyChanged(int)));2923break;2924case BODY_INITIAL:2925p = body->initial;2926connect(a, SIGNAL(stateChanged(int)), this,2927SLOT(initialBodyChanged(int)));2928break;2929case BODY_FORCE:2930p = body->force;2931connect(a, SIGNAL(stateChanged(int)), this,2932SLOT(forceBodyChanged(int)));2933break;2934case BODY_EQUATION:2935p = body->equation;2936connect(a, SIGNAL(stateChanged(int)), this,2937SLOT(equationBodyChanged(int)));2938break;2939}29402941a->setProperty("body", (qulonglong)body);2942a->setProperty("editor", (qulonglong)pe);29432944if (p == pe)2945a->setChecked(true);2946else if (p != NULL)2947a->setEnabled(false);2948else2949a->setChecked(false);29502951slayout->addWidget(a, count, even);2952even = 1 - even;2953if (!even)2954count++;2955}2956}29572958for (int i = 0; i < boundaryPropertyEditor.size(); i++) {2959BoundaryPropertyEditor *boundary = boundaryPropertyEditor[i];29602961if (!boundary)2962continue;29632964if (boundary->bodyProperties) {2965BodyPropertyEditor *body = boundary->bodyProperties;2966populateBodyComboBoxes(body);29672968QString title = body->ui.nameEdit->text().trimmed();2969QCheckBox *a;29702971if (title.isEmpty())2972a = new QCheckBox("Body{Boundary " + QString::number(i) + "}");2973else2974a = new QCheckBox(title);29752976DynamicEditor *p = NULL;29772978switch (which) {2979case BODY_MATERIAL:2980p = body->material;2981connect(a, SIGNAL(stateChanged(int)), this,2982SLOT(materialBodyChanged(int)));2983break;2984case BODY_INITIAL:2985p = body->initial;2986connect(a, SIGNAL(stateChanged(int)), this,2987SLOT(initialBodyChanged(int)));2988break;2989case BODY_FORCE:2990p = body->force;2991connect(a, SIGNAL(stateChanged(int)), this,2992SLOT(forceBodyChanged(int)));2993break;2994case BODY_EQUATION:2995p = body->equation;2996connect(a, SIGNAL(stateChanged(int)), this,2997SLOT(equationBodyChanged(int)));2998break;2999}30003001a->setProperty("body", (qulonglong)body);3002a->setProperty("editor", (qulonglong)pe);30033004if (p == pe)3005a->setChecked(true);3006else if (p != NULL)3007a->setEnabled(false);30083009slayout->addWidget(a, count, even);3010even = 1 - even;3011if (!even)3012count++;3013}3014}30153016QGroupBox *box = new QGroupBox;3017box->setLayout(slayout);30183019pe->spareScroll->setWidget(box);3020pe->spareScroll->setMinimumHeight(80);3021pe->spareScroll->show();3022}30233024//-----------------------------------------------------------------------------30253026//*****************************************************************************30273028// Model -> Equation -> Add...3029//-----------------------------------------------------------------------------3030void MainWindow::addEquationSlot() {3031DynamicEditor *pe = new DynamicEditor;3032equationEditor.append(pe);3033int current = equationEditor.size() - 1;30343035pe->setupTabs(elmerDefs, "Equation", current);30363037pe->applyButton->setText("Add");3038pe->applyButton->setIcon(QIcon::fromTheme("list-add"));3039pe->discardButton->setText("Cancel");3040pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));3041pe->show();30423043connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,3044SLOT(pdeEditorFinishedSlot(int, int)));30453046// Use "spareButton" to invoke solver parameter editor:3047pe->spareButton->setText("Edit Solver Settings");3048pe->spareButton->show();3049pe->spareButton->setIcon(QIcon::fromTheme("preferences-system"));3050pe->spareButton->setWhatsThis(tr("Open solver setting window"));3051connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,3052SLOT(editNumericalMethods(int, int)));30533054// Equation is new - add to menu:3055const QString &equationName = pe->nameEdit->text().trimmed();3056QAction *act = new QAction(equationName, this);3057equationMenu->addAction(act);3058pe->menuAction = act;30593060connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,3061SLOT(dynamicEditorNameChange(QString)));30623063createBodyCheckBoxes(BODY_EQUATION, pe);3064}30653066// signal (int, int) emitted by dynamic editor when "spare button" clicked:3067//-----------------------------------------------------------------------------3068void MainWindow::editNumericalMethods(int current, int id) {3069QString title = "";30703071for (int i = 0; i < equationEditor.size(); i++) {3072// ** 23/04/09 **3073if (equationEditor[i]->ID == id) {3074title = equationEditor[i]->tabWidget->tabText(current);3075break;3076}3077}30783079if (title == "General") {3080logMessage("No solver controls for 'General' equation options");3081return;3082}30833084if (current >= solverParameterEditor.size())3085solverParameterEditor.resize(current + 1);30863087if (!solverParameterEditor[current])3088solverParameterEditor[current] = new SolverParameterEditor;30893090SolverParameterEditor *spe = solverParameterEditor[current];30913092spe->setWindowTitle("Solver control for " + title);30933094spe->solverName = title;30953096if (spe->generalOptions == NULL) {3097spe->generalOptions = new DynamicEditor(spe);3098spe->generalOptions->setupTabs(elmerDefs, "Solver", current);3099spe->ui.solverControlTabs->insertTab(31000, spe->generalOptions->tabWidget->widget(current),3101"Solver specific options");31023103#if 03104for( int i=0; i < spe->generalOptions->tabWidget->count(); i++ )3105{3106if ( spe->generalOptions->tabWidget->tabText(i) == title )3107{3108spe->ui.solverControlTabs->insertTab(0, spe->generalOptions->tabWidget->widget(i),3109"Solver specific options");3110break;3111}3112}3113#endif3114}31153116spe->show();3117spe->raise();3118}31193120void MainWindow::dynamicEditorNameChange(QString t) {3121for (int i = 0; i < bodyPropertyEditor.size(); i++) {3122if (!bodyPropertyEditor[i])3123continue;31243125if (bodyPropertyEditor[i]->touched)3126populateBodyComboBoxes(bodyPropertyEditor[i]);3127}31283129for (int i = 0; i < boundaryPropertyEditor.size(); i++) {3130if (!boundaryPropertyEditor[i])3131continue;31323133if (boundaryPropertyEditor[i]->touched)3134populateBoundaryComboBoxes(boundaryPropertyEditor[i]);3135}3136}31373138// signal (int,int) emitted by equation editor when ready:3139//-----------------------------------------------------------------------------3140void MainWindow::pdeEditorFinishedSlot(int signal, int id) {3141DynamicEditor *pe = equationEditor[id];31423143const QString &equationName = pe->nameEdit->text().trimmed();31443145bool signalOK = signal == MAT_OK || signal == MAT_APPLY;31463147if ((equationName.isEmpty()) && signalOK) {3148logMessage("Refusing to add/update equation without name");3149return;3150}31513152if (signalOK) {3153if (pe->menuAction != NULL) {3154pe->menuAction->setText(equationName);3155logMessage("Equation updated");3156if (signal == MAT_OK)3157pe->close();3158}3159} else if (signal == MAT_NEW) {3160addEquationSlot();31613162} else if (signal == MAT_DELETE) {31633164for (int i = 0; i < bodyPropertyEditor.size(); i++) {3165BodyPropertyEditor *body = bodyPropertyEditor[i];31663167if (!body)3168continue;31693170if (body->equation == pe) {3171body->equation = NULL;3172body->ui.equationCombo->setCurrentIndex(0);3173body->touched = true;3174}3175}31763177// Equation is not in menu:3178if (pe->menuAction == NULL) {3179logMessage("Ready");3180pe->close();3181return;3182}31833184// Delete from menu:3185delete pe->menuAction;3186pe->menuAction = NULL;3187pe->close();31883189pe->ID = -100;3190pe->nameEdit->setText("");31913192logMessage("Equation deleted");3193}3194}31953196// signal (QAction*) emitted by equationMenu when an item has been selected:3197//-----------------------------------------------------------------------------3198void MainWindow::equationSelectedSlot(QAction *act) {3199// Edit the selected material:3200for (int i = 0; i < equationEditor.size(); i++) {3201DynamicEditor *pe = equationEditor[i];3202if (pe->menuAction == act) {3203pe->applyButton->setText("Update");3204pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));3205pe->discardButton->setText("Remove");3206pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));3207createBodyCheckBoxes(BODY_EQUATION, pe);3208pe->show();3209pe->raise();3210}3211}3212}32133214//-----------------------------------------------------------------------------3215void MainWindow::equationBodyChanged(int state) {3216QWidget *a = (QWidget *)QObject::sender();3217if (glWidget->getMesh()) {3218BodyPropertyEditor *body =3219(BodyPropertyEditor *)a->property("body").toULongLong();3220populateBodyComboBoxes(body);3221if (state) {3222DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();3223QString mat_name = mat->nameEdit->text().trimmed();3224int ind = body->ui.equationCombo->findText(mat_name);3225body->touched = true;3226body->equation = mat;3227body->ui.equationCombo->setCurrentIndex(ind);3228} else {3229body->equation = NULL;3230body->ui.equationCombo->setCurrentIndex(-1);3231}3232}3233}32343235//*****************************************************************************32363237// Model -> Material -> Add...3238//-----------------------------------------------------------------------------3239void MainWindow::addMaterialSlot() {3240DynamicEditor *pe = new DynamicEditor;3241materialEditor.append(pe);3242int current = materialEditor.size() - 1;32433244pe->setupTabs(elmerDefs, "Material", current);3245pe->applyButton->setText("Add");3246pe->applyButton->setIcon(QIcon::fromTheme("list-add"));3247pe->discardButton->setText("Cancel");3248pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));32493250connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,3251SLOT(matEditorFinishedSlot(int, int)));32523253// Use "spareButton" to invoke material library:3254pe->spareButton->setText("Material library");3255pe->spareButton->show();3256pe->spareButton->setIcon(QIcon::fromTheme("book-cover-A-Z"));3257pe->spareButton->setWhatsThis(tr("Open material library"));3258connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,3259SLOT(showMaterialLibrary(int, int)));32603261connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,3262SLOT(dynamicEditorNameChange(QString)));32633264// Material is new - add to menu:3265const QString &materialName = pe->nameEdit->text().trimmed();3266QAction *act = new QAction(materialName, this);3267materialMenu->addAction(act);3268pe->menuAction = act;32693270createBodyCheckBoxes(BODY_MATERIAL, pe);3271pe->show();3272pe->raise();3273}32743275void MainWindow::showMaterialLibrary(int tab, int ID) {3276materialLibrary->editor = materialEditor[ID];3277materialLibrary->elmerDefs = this->elmerDefs;3278materialLibrary->show();3279}32803281// signal (int,int) emitted by material editor when ready:3282//-----------------------------------------------------------------------------3283void MainWindow::matEditorFinishedSlot(int signal, int id) {3284DynamicEditor *pe = materialEditor[id];32853286const QString &materialName = pe->nameEdit->text().trimmed();32873288bool signalOK = signal == MAT_OK || signal == MAT_APPLY;3289if (materialName.isEmpty() && signalOK) {3290logMessage("Refusing to add/update material with no name");3291return;3292}32933294if (signalOK) {3295if (pe->menuAction != NULL) {3296pe->menuAction->setText(materialName);3297logMessage("Material updated");3298if (signal == MAT_OK)3299pe->close();3300return;3301}3302} else if (signal == MAT_NEW) {33033304addMaterialSlot();33053306} else if (signal == MAT_DELETE) {33073308for (int i = 0; i < bodyPropertyEditor.size(); i++) {3309BodyPropertyEditor *body = bodyPropertyEditor[i];33103311if (!body)3312continue;33133314if (body->material == pe) {3315body->material = NULL;3316body->ui.materialCombo->setCurrentIndex(0);3317body->touched = true;3318}3319}33203321// Material is not in menu:3322if (pe->menuAction == NULL) {3323logMessage("Ready");3324pe->close();3325return;3326}33273328// Delete from menu:3329delete pe->menuAction;3330pe->menuAction = NULL;3331pe->close();33323333pe->ID = -100;3334pe->nameEdit->setText("");33353336logMessage("Material deleted");33373338} else {3339cout << "Matedit: unknown signal" << endl;3340}3341}33423343// signal (QAction*) emitted by materialMenu when an item has been selected:3344//-----------------------------------------------------------------------------3345void MainWindow::materialSelectedSlot(QAction *act) {3346// Edit the selected material:3347for (int i = 0; i < materialEditor.size(); i++) {3348DynamicEditor *pe = materialEditor[i];33493350if (pe->menuAction == act) {3351pe->applyButton->setText("Update");3352pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));3353pe->discardButton->setText("Remove");3354pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));3355createBodyCheckBoxes(BODY_MATERIAL, pe);3356pe->show();3357pe->raise();3358}3359}3360}33613362void MainWindow::materialBodyChanged(int state) {3363QWidget *a = (QWidget *)QObject::sender();3364if (glWidget->hasMesh()) {3365BodyPropertyEditor *body =3366(BodyPropertyEditor *)a->property("body").toULongLong();3367populateBodyComboBoxes(body);33683369if (state > 0) {3370DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();3371QString mat_name = mat->nameEdit->text().trimmed();3372int ind = body->ui.materialCombo->findText(mat_name);33733374body->touched = true;3375body->material = mat;3376body->ui.materialCombo->setCurrentIndex(ind);3377} else {3378body->material = NULL;3379body->ui.materialCombo->setCurrentIndex(-1);3380}3381}3382}33833384//*****************************************************************************33853386// Model -> Body force -> Add...3387//-----------------------------------------------------------------------------3388void MainWindow::addBodyForceSlot() {3389DynamicEditor *pe = new DynamicEditor;3390bodyForceEditor.append(pe);3391int current = bodyForceEditor.size() - 1;33923393pe->setupTabs(elmerDefs, "BodyForce", current);33943395pe->applyButton->setText("Add");3396pe->applyButton->setIcon(QIcon::fromTheme("list-add"));3397pe->discardButton->setText("Cancel");3398pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));33993400connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,3401SLOT(bodyForceEditorFinishedSlot(int, int)));34023403// Body force is new - add to menu:3404const QString &bodyForceName = pe->nameEdit->text().trimmed();3405QAction *act = new QAction(bodyForceName, this);3406bodyForceMenu->addAction(act);3407pe->menuAction = act;34083409connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,3410SLOT(dynamicEditorNameChange(QString)));34113412createBodyCheckBoxes(BODY_FORCE, pe);3413pe->show();3414pe->raise();3415}34163417// signal (int,int) emitted by body force editor when ready:3418//-----------------------------------------------------------------------------3419void MainWindow::bodyForceEditorFinishedSlot(int signal, int id) {3420DynamicEditor *pe = bodyForceEditor[id];34213422const QString &bodyForceName = pe->nameEdit->text().trimmed();34233424bool signalOK = signal == MAT_OK || signal == MAT_APPLY;34253426if ((bodyForceName.isEmpty()) && signalOK) {3427logMessage("Refusing to add/update body force with no name");3428return;3429}34303431if (signalOK) {3432if (pe->menuAction != NULL) {3433pe->menuAction->setText(bodyForceName);3434logMessage("Body force updated");3435if (signal == MAT_OK)3436pe->close();3437}34383439} else if (signal == MAT_NEW) {3440addBodyForceSlot();34413442} else if (signal == MAT_DELETE) {3443for (int i = 0; i < bodyPropertyEditor.size(); i++) {3444BodyPropertyEditor *body = bodyPropertyEditor[i];34453446if (!body)3447continue;34483449if (body->force == pe) {3450body->force = NULL;3451body->ui.bodyForceCombo->setCurrentIndex(0);3452body->touched = true;3453}3454}34553456if (pe->menuAction == NULL) {3457logMessage("Ready");3458pe->close();3459return;3460}34613462// Delete from menu:3463delete pe->menuAction;3464pe->menuAction = NULL;3465pe->close();34663467pe->ID = -100;3468pe->nameEdit->setText("");34693470logMessage("Body force deleted");3471}3472}34733474// signal (QAction*) emitted by bodyForceMenu when an item has been selected:3475//-----------------------------------------------------------------------------3476void MainWindow::bodyForceSelectedSlot(QAction *act) {3477// Edit the selected body force:3478for (int i = 0; i < bodyForceEditor.size(); i++) {3479DynamicEditor *pe = bodyForceEditor[i];3480if (pe->menuAction == act) {3481pe->applyButton->setText("Update");3482pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));3483pe->discardButton->setText("Remove");3484pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));3485createBodyCheckBoxes(BODY_FORCE, pe);3486pe->show();3487pe->raise();3488}3489}3490}34913492//-----------------------------------------------------------------------------3493void MainWindow::forceBodyChanged(int state) {3494QWidget *a = (QWidget *)QObject::sender();3495if (glWidget->hasMesh()) {3496BodyPropertyEditor *body =3497(BodyPropertyEditor *)a->property("body").toULongLong();3498populateBodyComboBoxes(body);34993500if (state) {3501DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();3502QString mat_name = mat->nameEdit->text().trimmed();3503int ind = body->ui.bodyForceCombo->findText(mat_name);35043505body->touched = true;3506body->force = mat;3507body->ui.bodyForceCombo->setCurrentIndex(ind);3508} else {3509body->force = NULL;3510body->ui.bodyForceCombo->setCurrentIndex(-1);3511}3512}3513}35143515//*****************************************************************************35163517// Model -> Initial condition -> Add...3518//-----------------------------------------------------------------------------3519void MainWindow::addInitialConditionSlot() {3520DynamicEditor *pe = new DynamicEditor;3521initialConditionEditor.append(pe);3522int current = initialConditionEditor.size() - 1;35233524pe->setupTabs(elmerDefs, "InitialCondition", current);35253526pe->applyButton->setText("Add");3527pe->applyButton->setIcon(QIcon::fromTheme("list-add"));3528pe->discardButton->setText("Cancel");3529pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));35303531connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,3532SLOT(initialConditionEditorFinishedSlot(int, int)));35333534// Initial condition is new - add to menu:3535const QString &initialConditionName = pe->nameEdit->text().trimmed();3536QAction *act = new QAction(initialConditionName, this);3537initialConditionMenu->addAction(act);3538pe->menuAction = act;35393540connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,3541SLOT(dynamicEditorNameChange(QString)));35423543createBodyCheckBoxes(BODY_INITIAL, pe);3544pe->show();3545pe->raise();3546}35473548// signal (int,int) emitted by initial condition editor when ready:3549//-----------------------------------------------------------------------------3550void MainWindow::initialConditionEditorFinishedSlot(int signal, int id) {3551DynamicEditor *pe = initialConditionEditor[id];35523553const QString &initialConditionName = pe->nameEdit->text().trimmed();35543555bool signalOK = signal == MAT_OK || signal == MAT_APPLY;3556if ((initialConditionName.isEmpty()) && signalOK) {3557logMessage("Refusing to add/update initial condition with no name");3558return;3559}35603561if (signalOK) {3562if (pe->menuAction != NULL) {3563pe->menuAction->setText(initialConditionName);3564logMessage("Initial condition updated");3565if (signal == MAT_OK)3566pe->close();3567}3568} else if (signal == MAT_NEW) {3569addInitialConditionSlot();35703571} else if (signal == MAT_DELETE) {35723573for (int i = 0; i < bodyPropertyEditor.size(); i++) {3574BodyPropertyEditor *body = bodyPropertyEditor[i];35753576if (!body)3577continue;35783579if (body->initial == pe) {3580body->initial = NULL;3581body->ui.initialConditionCombo->setCurrentIndex(0);3582body->touched = true;3583}3584}35853586// Initial condition is not in menu:3587if (pe->menuAction == NULL) {3588logMessage("Ready");3589pe->close();3590return;3591}35923593// Delete from menu:3594delete pe->menuAction;3595pe->menuAction = NULL;3596pe->close();35973598pe->ID = -100;3599pe->nameEdit->setText("");36003601logMessage("Initial condition deleted");3602}3603}36043605// signal (QAction*) emitted by initialConditionMenu when item selected:3606//-----------------------------------------------------------------------------3607void MainWindow::initialConditionSelectedSlot(QAction *act) {3608// Edit the selected initial condition:3609for (int i = 0; i < initialConditionEditor.size(); i++) {3610DynamicEditor *pe = initialConditionEditor[i];3611if (pe->menuAction == act) {3612pe->applyButton->setText("Update");3613pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));3614pe->discardButton->setText("Remove");3615pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));3616createBodyCheckBoxes(BODY_INITIAL, pe);3617pe->show();3618pe->raise();3619}3620}3621}36223623//-----------------------------------------------------------------------------3624void MainWindow::initialBodyChanged(int state) {3625QWidget *a = (QWidget *)QObject::sender();3626if (glWidget->hasMesh()) {3627BodyPropertyEditor *body =3628(BodyPropertyEditor *)a->property("body").toULongLong();3629populateBodyComboBoxes(body);36303631if (state) {3632DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();3633QString mat_name = mat->nameEdit->text().trimmed();3634int ind = body->ui.initialConditionCombo->findText(mat_name);3635body->touched = true;3636body->initial = mat;3637body->ui.initialConditionCombo->setCurrentIndex(ind);3638} else {3639body->initial = NULL;3640body->ui.initialConditionCombo->setCurrentIndex(-1);3641}3642}3643}36443645//*****************************************************************************3646//-----------------------------------------------------------------------------3647void MainWindow::createBoundaryCheckBoxes(DynamicEditor *pe) {3648if (!glWidget->hasMesh())3649return;36503651if (pe->spareScroll->widget()) {3652delete pe->spareScroll->widget();3653}36543655QGridLayout *slayout = new QGridLayout;3656QLabel *l = new QLabel(tr("Apply to boundaries:"));3657int count = 0, even = 0;36583659slayout->addWidget(l, count, 0);3660count++;36613662QMapIterator<int, int> itr(glWidget->boundaryMap);3663while (itr.hasNext()) {3664itr.next();3665int n = itr.key();3666if (n >= 0) {3667int m = itr.value();36683669if (m >= boundaryPropertyEditor.size())3670boundaryPropertyEditor.resize(m + 1);36713672if (!boundaryPropertyEditor[m])3673boundaryPropertyEditor[m] = new BoundaryPropertyEditor;36743675BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];36763677populateBoundaryComboBoxes(boundary);36783679// TODO: check this3680QString title = ""; // boundary->ui.nameEdit->text().trimmed();3681QCheckBox *a;36823683if (title.isEmpty())3684a = new QCheckBox("Boundary " + QString::number(n));3685else3686a = new QCheckBox(title);36873688if (glWidget->stateBcColors) {3689int c[3];3690QPixmap pm(16, 16);36913692GLWidget::indexColors(c, n);3693pm.fill(qRgb(c[0], c[1], c[2]));3694a->setIcon(QIcon(pm));3695}36963697DynamicEditor *p = NULL;36983699p = boundary->condition;3700connect(a, SIGNAL(stateChanged(int)), this, SLOT(bcBoundaryChanged(int)));37013702a->setProperty("boundary", (qulonglong)boundary);3703a->setProperty("condition", (qulonglong)pe);37043705if (p == pe)3706a->setChecked(true);3707else if (p != NULL)3708a->setEnabled(false);37093710slayout->addWidget(a, count, even);3711even = 1 - even;3712if (!even)3713count++;3714}3715}37163717QGroupBox *box = new QGroupBox;3718box->setLayout(slayout);37193720pe->spareScroll->setWidget(box);3721pe->spareScroll->setMinimumHeight(80);3722pe->spareScroll->show();3723}37243725//-----------------------------------------------------------------------------37263727// Model -> Boundary condition -> Add...3728//-----------------------------------------------------------------------------3729void MainWindow::addBoundaryConditionSlot() {3730DynamicEditor *pe = new DynamicEditor;3731boundaryConditionEditor.append(pe);3732int current = boundaryConditionEditor.size() - 1;37333734pe->setupTabs(elmerDefs, "BoundaryCondition", current);37353736pe->applyButton->setText("Add");3737pe->applyButton->setIcon(QIcon::fromTheme("list-add"));3738pe->discardButton->setText("Cancel");3739pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));3740pe->show();37413742connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,3743SLOT(boundaryConditionEditorFinishedSlot(int, int)));37443745// Boundary condition is new - add to menu:3746const QString &boundaryConditionName = pe->nameEdit->text().trimmed();3747QAction *act = new QAction(boundaryConditionName, this);3748boundaryConditionMenu->addAction(act);3749pe->menuAction = act;37503751connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,3752SLOT(dynamicEditorNameChange(QString)));37533754createBoundaryCheckBoxes(pe);3755}37563757// signal (int,int) emitted by boundary condition editor when ready:3758//-----------------------------------------------------------------------------3759void MainWindow::boundaryConditionEditorFinishedSlot(int signal, int id) {3760DynamicEditor *pe = boundaryConditionEditor[id];37613762const QString &boundaryConditionName = pe->nameEdit->text().trimmed();37633764bool signalOK = signal == MAT_OK || signal == MAT_APPLY;37653766if ((boundaryConditionName.isEmpty()) && signalOK) {3767logMessage("Refusing to add/update boundary condition with no name");3768return;3769}37703771if (signalOK) {3772if (pe->menuAction != NULL) {3773pe->menuAction->setText(boundaryConditionName);3774logMessage("Boundary condition updated");3775if (signal == MAT_OK)3776pe->close();3777}3778} else if (signal == MAT_NEW) {3779addBoundaryConditionSlot();37803781} else if (signal == MAT_DELETE) {37823783pe->nameEdit->setText(QString());37843785for (int i = 0; i < boundaryPropertyEditor.size(); i++) {3786BoundaryPropertyEditor *bndry = boundaryPropertyEditor[i];37873788if (!bndry)3789continue;37903791if (bndry->condition == pe) {3792bndry->condition = NULL;3793bndry->ui.boundaryConditionCombo->setCurrentIndex(0);3794bndry->touched = true;3795}3796}37973798// Boundary condition is not in menu:3799if (pe->menuAction == NULL) {3800logMessage("Ready");3801pe->close();3802return;3803}38043805// Delete from menu:3806delete pe->menuAction;3807pe->menuAction = NULL;3808pe->close();38093810pe->ID = -100;3811pe->nameEdit->setText("");38123813logMessage("Boundary condition deleted");3814}3815}38163817// signal (QAction*) emitted by boundaryConditionMenu when item selected:3818//-----------------------------------------------------------------------------3819void MainWindow::boundaryConditionSelectedSlot(QAction *act) {3820// Edit the selected boundary condition:3821for (int i = 0; i < boundaryConditionEditor.size(); i++) {3822DynamicEditor *pe = boundaryConditionEditor[i];3823if (pe->menuAction == act) {3824pe->applyButton->setText("Update");3825pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));3826pe->discardButton->setText("Remove");3827pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));3828createBoundaryCheckBoxes(pe);3829pe->show();3830pe->raise();3831}3832}3833}38343835//-----------------------------------------------------------------------------3836void MainWindow::bcBoundaryChanged(int state) {3837QWidget *a = (QWidget *)QObject::sender();3838if (glWidget->hasMesh()) {3839BoundaryPropertyEditor *boundary =3840(BoundaryPropertyEditor *)a->property("boundary").toULongLong();3841populateBoundaryComboBoxes(boundary);38423843if (state) {3844DynamicEditor *mat =3845(DynamicEditor *)a->property("condition").toULongLong();3846QString mat_name = mat->nameEdit->text().trimmed();3847int ind = boundary->ui.boundaryConditionCombo->findText(mat_name);3848boundary->touched = true;3849boundary->condition = mat;3850boundary->ui.boundaryConditionCombo->setCurrentIndex(ind);3851} else {3852boundary->condition = NULL;3853boundary->ui.boundaryConditionCombo->setCurrentIndex(-1);3854}3855}3856}38573858// Model -> Set body properties3859//-----------------------------------------------------------------------------3860void MainWindow::bodyEditSlot() {3861if (!glWidget->hasMesh()) {3862logMessage("Unable to open body editor - no mesh");3863bodyEditActive = false;3864synchronizeMenuToState();3865return;3866}38673868bodyEditActive = !bodyEditActive;3869glWidget->bodyEditActive = bodyEditActive;38703871if (bodyEditActive)3872bcEditActive = false;38733874synchronizeMenuToState();38753876if (bodyEditActive)3877logMessage("Double click a boundary to edit body properties");3878}38793880// Model -> Set boundary conditions3881//-----------------------------------------------------------------------------3882void MainWindow::bcEditSlot() {3883if (!glWidget->hasMesh()) {3884logMessage("Unable to open BC editor - no mesh");3885bcEditActive = false;3886synchronizeMenuToState();3887return;3888}38893890bcEditActive = !bcEditActive;38913892if (bcEditActive)3893bodyEditActive = false;38943895synchronizeMenuToState();38963897if (bcEditActive)3898logMessage("Double click a boundary to edit BCs");3899}39003901// Model -> Summary...3902//-----------------------------------------------------------------------------3903void MainWindow::modelSummarySlot() {3904mesh_t *mesh = glWidget->getMesh();3905QTextEdit *te = summaryEditor->ui.summaryEdit;3906te->clear();3907summaryEditor->show();39083909if (mesh == NULL) {3910te->append("No mesh");3911return;3912}39133914te->append("FINITE ELEMENT MESH");3915te->append("Mesh dimension: " + QString::number(mesh->getCdim()));3916te->append("Leading element dimension: " + QString::number(mesh->getDim()));3917te->append("Nodes: " + QString::number(mesh->getNodes()));3918te->append("Volume elements: " + QString::number(mesh->getElements()));3919te->append("Surface elements: " + QString::number(mesh->getSurfaces()));3920te->append("Edge elements: " + QString::number(mesh->getEdges()));3921te->append("Point elements: " + QString::number(mesh->getPoints()));3922te->append("");39233924// This is almost duplicate info with the above, they might be fused in some3925// way...3926te->append("ELEMENT TYPES");3927int *elementtypes = new int[828];3928for (int i = 0; i <= 827; i++)3929elementtypes[i] = 0;3930for (int i = 0; i < mesh->getElements(); i++)3931elementtypes[mesh->getElement(i)->getCode()] += 1;3932for (int i = 0; i < mesh->getSurfaces(); i++)3933elementtypes[mesh->getSurface(i)->getCode()] += 1;3934for (int i = 0; i < mesh->getEdges(); i++)3935elementtypes[mesh->getEdge(i)->getCode()] += 1;3936for (int i = 0; i < mesh->getPoints(); i++)3937elementtypes[mesh->getPoint(i)->getCode()] += 1;3938for (int i = 827; i > 0; i--)3939if (elementtypes[i])3940te->append(QString::number(i) + ": " + QString::number(elementtypes[i]));3941te->append("");3942delete[] elementtypes;39433944te->append("BOUNDING BOX");3945QString coordnames[3] = {"X","Y","Z"};3946for (int j = 0; j < 3; j++) {3947double mincoord, maxcoord, coord;3948mincoord = maxcoord = mesh->getNode(0)->getX(j);3949for (int i = 0; i < mesh->getNodes(); i++) {3950coord = mesh->getNode(i)->getX(j);3951if (mincoord > coord)3952mincoord = coord;3953if (maxcoord < coord)3954maxcoord = coord;3955}3956te->append(coordnames[j] + "-coordinate: [ " + QString::number(mincoord) +3957" , " + QString::number(maxcoord) + " ]");3958}3959te->append("");39603961// Check equations:3962int count = 0;3963for (int i = 0; i < equationEditor.size(); i++) {3964if (equationEditor[i]->menuAction != NULL)3965count++;3966}3967te->append("GENERAL");3968te->append("Equations: " + QString::number(count));39693970// Check materials:3971count = 0;3972for (int i = 0; i < materialEditor.size(); i++) {3973if (materialEditor[i]->menuAction != NULL)3974count++;3975}3976te->append("Materials: " + QString::number(count));39773978// Check boundary conditions:3979count = 0;3980for (int i = 0; i < boundaryConditionEditor.size(); i++) {3981if (boundaryConditionEditor[i]->touched)3982count++;3983}3984te->append("Boundary conditions: " + QString::number(count));39853986// Check body properties:3987count = 0;3988for (int i = 0; i < bodyPropertyEditor.size(); i++) {39893990if (!bodyPropertyEditor[i])3991continue;39923993if (bodyPropertyEditor[i]->touched)3994count++;3995}39963997te->append("Body properties: " + QString::number(count));3998te->append("");39994000// Count volume bodies:4001//---------------------4002int undetermined = 0;4003int *tmp = new int[mesh->getElements()];4004for (int i = 0; i < mesh->getElements(); i++)4005tmp[i] = 0;40064007for (int i = 0; i < mesh->getElements(); i++) {4008element_t *e = mesh->getElement(i);4009if (e->getNature() == PDE_BULK) {4010if (e->getIndex() >= 0)4011tmp[e->getIndex()]++;4012else4013undetermined++;4014}4015}40164017te->append("VOLUME BODIES");4018count = 0;4019for (int i = 0; i < mesh->getElements(); i++) {4020if (tmp[i] > 0) {4021count++;4022QString qs = "Body " + QString::number(i) + ": " +4023QString::number(tmp[i]) + " volume elements";40244025element_t *e = mesh->getElement(i);4026int j = e->getIndex();40274028if ((j >= 0) && (j < bodyPropertyEditor.size()))4029if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)4030qs.append(" (Body property set)");40314032te->append(qs);4033}4034}4035te->append("Undetermined: " + QString::number(undetermined));4036te->append("Total: " + QString::number(count) + " volume bodies");4037te->append("");40384039delete[] tmp;40404041// Count surface bodies:4042//---------------------4043undetermined = 0;4044tmp = new int[mesh->getSurfaces()];4045for (int i = 0; i < mesh->getSurfaces(); i++)4046tmp[i] = 0;40474048for (int i = 0; i < mesh->getSurfaces(); i++) {4049surface_t *s = mesh->getSurface(i);4050if (s->getNature() == PDE_BULK) {4051if (s->getIndex() >= 0)4052tmp[s->getIndex()]++;4053else4054undetermined++;4055}4056}40574058te->append("SURFACE BODIES");4059count = 0;4060for (int i = 0; i < mesh->getSurfaces(); i++) {4061if (tmp[i] > 0) {4062count++;4063QString qs = "Body " + QString::number(i) + ": " +4064QString::number(tmp[i]) + " surface elements";40654066surface_t *s = mesh->getSurface(i);4067int j = s->getIndex();40684069if ((j >= 0) && (j < bodyPropertyEditor.size()))4070if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)4071qs.append(" (Body property set)");40724073te->append(qs);4074}4075}4076te->append("Undetermined: " + QString::number(undetermined));4077te->append("Total: " + QString::number(count) + " surface bodies");4078te->append("");40794080delete[] tmp;40814082// Count edge bodies:4083//---------------------4084undetermined = 0;4085tmp = new int[mesh->getEdges()];4086for (int i = 0; i < mesh->getEdges(); i++)4087tmp[i] = 0;40884089for (int i = 0; i < mesh->getEdges(); i++) {4090edge_t *e = mesh->getEdge(i);4091if (e->getNature() == PDE_BULK) {4092if (e->getIndex() >= 0)4093tmp[e->getIndex()]++;4094else4095undetermined++;4096}4097}40984099te->append("EDGE BODIES");4100count = 0;4101for (int i = 0; i < mesh->getEdges(); i++) {4102if (tmp[i] > 0) {4103count++;4104QString qs = "Body " + QString::number(i) + ": " +4105QString::number(tmp[i]) + " edge elements";41064107edge_t *e = mesh->getEdge(i);4108int j = e->getIndex();41094110if ((j >= 0) && (j < bodyPropertyEditor.size()))4111if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)4112qs.append(" (Body property set)");41134114te->append(qs);4115}4116}4117te->append("Undetermined: " + QString::number(undetermined));4118te->append("Total: " + QString::number(count) + " edge bodies");4119te->append("");41204121delete[] tmp;41224123// Count surface boundaries:4124//--------------------------4125undetermined = 0;4126tmp = new int[mesh->getSurfaces()];4127for (int i = 0; i < mesh->getSurfaces(); i++)4128tmp[i] = 0;41294130for (int i = 0; i < mesh->getSurfaces(); i++) {4131surface_t *s = mesh->getSurface(i);4132if (s->getNature() == PDE_BOUNDARY) {4133if (s->getIndex() >= 0)4134tmp[s->getIndex()]++;4135else4136undetermined++;4137}4138}41394140te->append("SURFACE BOUNDARIES");4141count = 0;4142for (int i = 0; i < mesh->getSurfaces(); i++) {4143if (tmp[i] > 0) {4144count++;4145QString qs = "Boundary " + QString::number(i) + ": " +4146QString::number(tmp[i]) + " surface elements";41474148surface_t *s = mesh->getSurface(i);4149int j = s->getIndex();4150if ((j >= 0) && (j < boundaryConditionEditor.size()))4151if (boundaryConditionEditor[j]->touched)4152qs.append(" (BC set)");41534154te->append(qs);4155}4156}4157te->append("Undetermined: " + QString::number(undetermined));4158te->append("Total: " + QString::number(count) + " surface boundaries");4159te->append("");41604161delete[] tmp;41624163// Count edge boundaries:4164//--------------------------4165undetermined = 0;4166tmp = new int[mesh->getEdges()];4167for (int i = 0; i < mesh->getEdges(); i++)4168tmp[i] = 0;41694170for (int i = 0; i < mesh->getEdges(); i++) {4171edge_t *e = mesh->getEdge(i);4172if (e->getNature() == PDE_BOUNDARY) {4173if (e->getIndex() >= 0)4174tmp[e->getIndex()]++;4175else4176undetermined++;4177}4178}41794180te->append("EDGE BOUNDARIES");4181count = 0;4182for (int i = 0; i < mesh->getEdges(); i++) {4183if (tmp[i] > 0) {4184count++;4185QString qs = "Boundary " + QString::number(i) + ": " +4186QString::number(tmp[i]) + " edge elements";41874188edge_t *e = mesh->getEdge(i);4189int j = e->getIndex();4190if ((j >= 0) && (j < boundaryConditionEditor.size()))4191if (boundaryConditionEditor[j]->touched)4192qs.append(" (BC set)");41934194te->append(qs);4195}4196}4197te->append("Undetermined: " + QString::number(undetermined));4198te->append("Total: " + QString::number(count) + " edge boundaries");4199te->append("");42004201delete[] tmp;4202}42034204// Model -> Clear4205//-----------------------------------------------------------------------------4206void MainWindow::modelClearSlot() {4207// clear equations:4208for (int i = 0; i < equationEditor.size(); i++) {4209DynamicEditor *pe = equationEditor[i];4210if (pe->menuAction != NULL)4211delete pe->menuAction;4212}42134214for (int i = 0; i < equationEditor.size(); i++)4215delete equationEditor[i];42164217equationEditor.clear();42184219// clear materials:4220for (int i = 0; i < materialEditor.size(); i++) {4221DynamicEditor *de = materialEditor[i];4222if (de->menuAction != NULL)4223delete de->menuAction;4224}42254226for (int i = 0; i < materialEditor.size(); i++)4227delete materialEditor[i];42284229materialEditor.clear();42304231// clear body forces:4232for (int i = 0; i < bodyForceEditor.size(); i++) {4233DynamicEditor *de = bodyForceEditor[i];4234if (de->menuAction != NULL)4235delete de->menuAction;4236}42374238for (int i = 0; i < bodyForceEditor.size(); i++)4239delete bodyForceEditor[i];42404241bodyForceEditor.clear();42424243// clear initial conditions:4244for (int i = 0; i < initialConditionEditor.size(); i++) {4245DynamicEditor *de = initialConditionEditor[i];4246if (de->menuAction != NULL)4247delete de->menuAction;4248}42494250for (int i = 0; i < initialConditionEditor.size(); i++)4251delete initialConditionEditor[i];42524253initialConditionEditor.clear();42544255// clear boundary conditions:4256for (int i = 0; i < boundaryConditionEditor.size(); i++) {4257DynamicEditor *de = boundaryConditionEditor[i];4258if (de->menuAction != NULL)4259delete de->menuAction;4260}42614262for (int i = 0; i < boundaryConditionEditor.size(); i++)4263if (boundaryConditionEditor[i])4264delete boundaryConditionEditor[i];42654266boundaryConditionEditor.clear();42674268// clear boundary setting:4269for (int i = 0; i < boundaryPropertyEditor.size(); i++)4270if (boundaryPropertyEditor[i])4271delete boundaryPropertyEditor[i];42724273boundaryPropertyEditor.clear();42744275// clear body settings:4276for (int i = 0; i < bodyPropertyEditor.size(); i++)4277if (bodyPropertyEditor[i])4278delete bodyPropertyEditor[i];42794280bodyPropertyEditor.clear();42814282// clear solver specific settings:4283for (int i = 0; i < solverParameterEditor.size(); i++)4284if (solverParameterEditor[i])4285delete solverParameterEditor[i];42864287solverParameterEditor.clear();4288}42894290//*****************************************************************************4291//4292// View MENU4293//4294//*****************************************************************************42954296// View -> Full screen4297//-----------------------------------------------------------------------------4298void MainWindow::viewFullScreenSlot() {4299if (!isFullScreen()) {4300cout << "Switching to full screen mode" << endl;4301cout << "Press 'Esc' to leave full screen mode" << endl;4302menuBar()->hide();4303statusBar()->hide();4304fileToolBar->hide();4305editToolBar->hide();4306meshToolBar->hide();4307solverToolBar->hide();4308this->showFullScreen();4309} else {4310viewNormalModeSlot();4311}4312synchronizeMenuToState();4313}43144315// Return to normal mode (GLWidget emits (void) when esc is pressed)...4316//-----------------------------------------------------------------------------4317void MainWindow::viewNormalModeSlot() {4318if (isFullScreen()) {4319cout << "Switching to normal window mode" << endl;4320this->showNormal();4321menuBar()->show();4322statusBar()->show();4323if (!egIni->isSet("hidetoolbars")) {4324fileToolBar->show();4325editToolBar->show();4326meshToolBar->show();4327solverToolBar->show();4328}4329}4330synchronizeMenuToState();4331statusBar()->showMessage(tr("Ready"));4332}43334334// Context menu event (usually mouse has been right clicked)...4335//-----------------------------------------------------------------------------4336void MainWindow::contextMenuEvent(QContextMenuEvent *event) {4337if(event->reason() != QContextMenuEvent::Mouse){4338contextMenu->popup(event->globalPos());4339}4340}43414342void MainWindow::showContextMenu(QPoint globalPos){4343contextMenu->popup(globalPos);4344}43454346// View -> Surface mesh4347//-----------------------------------------------------------------------------4348void MainWindow::hidesurfacemeshSlot() {4349mesh_t *mesh = glWidget->getMesh();4350int lists = glWidget->getLists();43514352if (mesh == NULL) {4353logMessage("There is no surface mesh to hide/show");4354return;4355}43564357glWidget->stateDrawSurfaceMesh = !glWidget->stateDrawSurfaceMesh;43584359for (int i = 0; i < lists; i++) {4360list_t *l = glWidget->getList(i);4361if (l->getType() == SURFACEMESHLIST) {4362l->setVisible(glWidget->stateDrawSurfaceMesh);43634364// do not set visible if the parent surface list is hidden4365int p = l->getParent();4366if (p >= 0) {4367list_t *lp = glWidget->getList(p);4368if (!lp->isVisible())4369l->setVisible(false);4370}4371}4372}43734374synchronizeMenuToState();43754376if (!glWidget->stateDrawSurfaceMesh)4377logMessage("Surface mesh hidden");4378else4379logMessage("Surface mesh shown");4380}43814382// View -> Volume mesh4383//-----------------------------------------------------------------------------4384void MainWindow::hidevolumemeshSlot() {4385mesh_t *mesh = glWidget->getMesh();4386int lists = glWidget->getLists();43874388if (mesh == NULL) {4389logMessage("There is no volume mesh to hide/show");4390return;4391}43924393glWidget->stateDrawVolumeMesh = !glWidget->stateDrawVolumeMesh;43944395for (int i = 0; i < lists; i++) {4396list_t *l = glWidget->getList(i);4397if (l->getType() == VOLUMEMESHLIST)4398l->setVisible(glWidget->stateDrawVolumeMesh);4399}44004401synchronizeMenuToState();44024403if (!glWidget->stateDrawVolumeMesh)4404logMessage("Volume mesh hidden");4405else4406logMessage("Volume mesh shown");4407}44084409// View -> Sharp edges4410//-----------------------------------------------------------------------------4411void MainWindow::hidesharpedgesSlot() {4412mesh_t *mesh = glWidget->getMesh();4413int lists = glWidget->getLists();44144415if (mesh == NULL) {4416logMessage("There are no sharp edges to hide/show");4417return;4418}44194420glWidget->stateDrawSharpEdges = !glWidget->stateDrawSharpEdges;44214422for (int i = 0; i < lists; i++) {4423list_t *l = glWidget->getList(i);4424if (l->getType() == SHARPEDGELIST)4425l->setVisible(glWidget->stateDrawSharpEdges);4426}44274428synchronizeMenuToState();44294430if (!glWidget->stateDrawSharpEdges)4431logMessage("Sharp edges hidden");4432else4433logMessage("Sharp edges shown");4434}44354436// View -> Coordinates4437//-----------------------------------------------------------------------------4438void MainWindow::viewCoordinatesSlot() {4439if (glWidget->toggleCoordinates())4440logMessage("Coordinates shown");4441else4442logMessage("Coordinates hidden");44434444synchronizeMenuToState();4445}44464447// View -> Select defined edges4448//-----------------------------------------------------------------------------4449void MainWindow::selectDefinedEdgesSlot() {4450mesh_t *mesh = glWidget->getMesh();4451int lists = glWidget->getLists();44524453if (mesh == NULL) {4454logMessage("There are no entities from which to select");4455return;4456}44574458// At the moment only edges are included in search:4459int nmax = 0;4460for (int i = 0; i < glWidget->boundaryMap.count(); i++) {4461int n = glWidget->boundaryMap.key(i);4462if (n > nmax)4463nmax = n;4464}44654466bool *activeboundary = new bool[nmax + 1];4467for (int i = 0; i <= nmax; i++)4468activeboundary[i] = false;44694470for (int i = 0; i < glWidget->boundaryMap.count(); i++) {4471int n = glWidget->boundaryMap.key(i);4472if (n >= 0) {4473int m = glWidget->boundaryMap.value(n);44744475if (m >= boundaryPropertyEditor.size())4476boundaryPropertyEditor.resize(m + 1);44774478if (!boundaryPropertyEditor[m])4479boundaryPropertyEditor[m] = new BoundaryPropertyEditor;44804481BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];4482activeboundary[n] = boundary->condition;4483}4484}44854486for (int i = 0; i < lists; i++) {4487list_t *l = glWidget->getList(i);4488if (l->getType() == EDGELIST) {4489int j = l->getIndex();4490if (j < 0)4491continue;44924493// *** TODO ***4494//4495// This is wrong: Comparing body indices with boundary indices4496if (activeboundary[j])4497l->setSelected(true);4498}4499}45004501for (int i = 0; i < mesh->getEdges(); i++) {4502edge_t *edge = mesh->getEdge(i);4503if (edge->getNature() == PDE_BOUNDARY) {4504int j = edge->getIndex();4505if (j < 0)4506continue;4507if (activeboundary[j])4508edge->setSelected(true);4509}4510}4511delete[] activeboundary;45124513glWidget->rebuildEdgeLists();4514glWidget->updateGL();45154516logMessage("Defined edges selected");4517}45184519// View -> Select defined surfaces4520//-----------------------------------------------------------------------------4521void MainWindow::selectDefinedSurfacesSlot() {4522mesh_t *mesh = glWidget->getMesh();4523int lists = glWidget->getLists();45244525if (mesh == NULL) {4526logMessage("There are no entities from which to select");4527return;4528}45294530// At the moment only surfaces are included in search:4531int nmax = 0;4532for (int i = 0; i < glWidget->bodyMap.count(); i++) {4533int n = glWidget->bodyMap.key(i);4534if (n > nmax)4535nmax = n;4536}45374538bool *activebody = new bool[nmax + 1];4539for (int i = 0; i <= nmax; i++)4540activebody[i] = false;45414542for (int i = 0; i < glWidget->bodyMap.count(); i++) {4543int n = glWidget->bodyMap.key(i);4544if (n >= 0) {4545int m = glWidget->bodyMap.value(n);45464547BodyPropertyEditor *body = bodyPropertyEditor[m];45484549if (!body) {4550cout << "MainWindow: Body index out of bounds" << endl;4551continue;4552}45534554activebody[n] = body->material && body->equation;4555}4556}45574558for (int i = 0; i < lists; i++) {4559list_t *l = glWidget->getList(i);4560if (l->getType() == SURFACELIST) {4561int j = l->getIndex();4562if (j < 0)4563continue;45644565// *** TODO ***4566//4567// This is wrong: Comparing body indices with boundary indexes4568if (activebody[j])4569l->setSelected(true);4570}4571}45724573for (int i = 0; i < mesh->getSurfaces(); i++) {4574surface_t *surface = mesh->getSurface(i);4575if (surface->getNature() == PDE_BULK) {4576int j = surface->getIndex();4577if (j < 0)4578continue;4579if (activebody[j])4580surface->setSelected(true);4581}4582}4583delete[] activebody;45844585glWidget->rebuildSurfaceLists();4586glWidget->updateGL();45874588logMessage("Defined surfaces selected");4589}45904591// View -> Select all surfaces4592//-----------------------------------------------------------------------------4593void MainWindow::selectAllSurfacesSlot() {4594mesh_t *mesh = glWidget->getMesh();4595int lists = glWidget->getLists();45964597if (mesh == NULL) {4598logMessage("There are no surfaces to select");4599return;4600}46014602for (int i = 0; i < lists; i++) {4603list_t *l = glWidget->getList(i);4604if (l->getType() == SURFACELIST) {4605l->setSelected(true);4606for (int j = 0; j < mesh->getSurfaces(); j++) {4607surface_t *surf = mesh->getSurface(j);4608if (l->getIndex() == surf->getIndex())4609surf->setSelected(l->isSelected());4610}4611}4612}46134614glWidget->rebuildSurfaceLists();4615glWidget->updateGL();46164617logMessage("All surfaces selected");4618}46194620// View -> Select all edges4621//-----------------------------------------------------------------------------4622void MainWindow::selectAllEdgesSlot() {4623mesh_t *mesh = glWidget->getMesh();4624int lists = glWidget->getLists();46254626if (mesh == NULL) {4627logMessage("There are no edges to select");4628return;4629}46304631for (int i = 0; i < lists; i++) {4632list_t *l = glWidget->getList(i);46334634if (l->getType() == EDGELIST)4635l->setSelected(true);46364637for (int j = 0; j < mesh->getEdges(); j++) {4638edge_t *edge = mesh->getEdge(j);4639if (l->getIndex() == edge->getIndex())4640edge->setSelected(l->isSelected());4641}4642}46434644glWidget->rebuildEdgeLists();4645glWidget->updateGL();46464647logMessage("All edges selected");4648}46494650// View -> Hide/Show selected4651//-----------------------------------------------------------------------------4652void MainWindow::hideselectedSlot() {4653mesh_t *mesh = glWidget->getMesh();4654int lists = glWidget->getLists();46554656if (mesh == NULL) {4657logMessage("There is nothing to hide/show");4658return;4659}46604661bool something_selected = false;4662for (int i = 0; i < lists; i++) {4663list_t *l = glWidget->getList(i);4664something_selected |= l->isSelected();4665}46664667if (!something_selected) {4668logMessage("Nothing selected");4669return;4670}46714672bool vis = false;4673for (int i = 0; i < lists; i++) {4674list_t *l = glWidget->getList(i);4675if (l->isSelected()) {4676l->setVisible(!l->isVisible());4677if (l->isVisible())4678vis = true;46794680// hide the child surface edge list if parent is hidden4681int c = l->getChild();4682if (c >= 0) {4683list_t *lc = glWidget->getList(c);4684lc->setVisible(l->isVisible());4685if (!glWidget->stateDrawSurfaceMesh)4686lc->setVisible(false);4687}4688}4689}4690glWidget->updateGL();46914692if (!vis)4693logMessage("Selected objects hidden");4694else4695logMessage("Selected objects shown");4696}46974698// View -> Show all4699//-----------------------------------------------------------------------------4700void MainWindow::showallSlot() {4701int lists = glWidget->getLists();47024703glWidget->stateDrawSurfaceMesh = true;4704#ifndef WIN324705glWidget->stateDrawSharpEdges = true;4706#endif4707glWidget->stateDrawSurfaceElements = true;4708glWidget->stateDrawEdgeElements = true;47094710synchronizeMenuToState();47114712for (int i = 0; i < lists; i++) {4713list_t *l = glWidget->getList(i);4714l->setVisible(true);4715}47164717logMessage("All objects visible");4718}47194720// View -> Reset model view4721//-----------------------------------------------------------------------------4722void MainWindow::resetSlot() {4723mesh_t *mesh = glWidget->getMesh();4724int lists = glWidget->getLists();47254726if (mesh == NULL) {4727logMessage("There is nothing to reset");4728return;4729}47304731glWidget->stateFlatShade = true;4732glWidget->stateDrawSurfaceMesh = true;4733#ifndef WIN324734glWidget->stateDrawSharpEdges = true;4735#endif4736glWidget->stateDrawSurfaceElements = true;4737glWidget->stateDrawEdgeElements = true;4738glWidget->stateDrawSurfaceNumbers = false;4739glWidget->stateDrawEdgeNumbers = false;4740glWidget->stateDrawNodeNumbers = false;47414742for (int i = 0; i < lists; i++) {4743list_t *l = glWidget->getList(i);4744l->setVisible(true);4745l->setSelected(false);47464747for (int j = 0; j < mesh->getSurfaces(); j++) {4748surface_t *surf = mesh->getSurface(j);4749if (l->getIndex() == surf->getIndex())4750surf->setSelected(l->isSelected());4751}4752for (int j = 0; j < mesh->getEdges(); j++) {4753edge_t *edge = mesh->getEdge(j);4754if (l->getIndex() == edge->getIndex())4755edge->setSelected(l->isSelected());4756}4757}47584759glWidget->stateBcColors = false;4760glWidget->stateBodyColors = false;47614762glLoadIdentity();4763glWidget->rebuildLists();4764glWidget->updateGL();47654766synchronizeMenuToState();4767logMessage("Reset model view");4768}47694770// View -> Shade model -> Flat4771//-----------------------------------------------------------------------------4772void MainWindow::flatShadeSlot() {4773if (!glWidget->hasMesh()) {4774logMessage("Refusing to change shade model when mesh is empty");4775return;4776}47774778glWidget->stateFlatShade = true;4779glWidget->rebuildSurfaceLists();4780glWidget->updateGL();47814782synchronizeMenuToState();4783logMessage("Shade model: flat");4784}47854786// View -> Shade model -> Smooth4787//-----------------------------------------------------------------------------4788void MainWindow::smoothShadeSlot() {4789if (!glWidget->hasMesh()) {4790logMessage("Refusing to change shade model when mesh is empty");4791return;4792}47934794glWidget->stateFlatShade = false;4795glWidget->rebuildSurfaceLists();4796glWidget->updateGL();47974798synchronizeMenuToState();4799logMessage("Shade model: smooth");4800}48014802// View -> Projection -> Orthogonal4803//-----------------------------------------------------------------------------4804void MainWindow::orthoSlot() {4805if (!glWidget->hasMesh()) {4806logMessage("Refusing to change projection when mesh is empty");4807return;4808}48094810glWidget->stateOrtho = true;4811glWidget->changeProjection();4812glWidget->updateGL();48134814synchronizeMenuToState();4815logMessage("Projection: orthogonal");4816}48174818// View -> Projection -> Perspective4819//-----------------------------------------------------------------------------4820void MainWindow::perspectiveSlot() {4821if (!glWidget->hasMesh()) {4822logMessage("Refusing to change projection when mesh is empty");4823return;4824}48254826glWidget->stateOrtho = false;4827glWidget->changeProjection();4828glWidget->updateGL();48294830synchronizeMenuToState();4831logMessage("Projection: perspective");4832}48334834// View -> Show numbering -> Surface numbering4835//-----------------------------------------------------------------------------4836void MainWindow::showSurfaceNumbersSlot() {4837if (!glWidget->hasMesh()) {4838logMessage("Refusing to show surface element numbering when mesh is empty");4839return;4840}4841glWidget->stateDrawSurfaceNumbers = !glWidget->stateDrawSurfaceNumbers;4842glWidget->updateGL();4843synchronizeMenuToState();48444845if (glWidget->stateDrawSurfaceNumbers)4846logMessage("Surface element numbering turned on");4847else4848logMessage("Surface element numbering turned off");4849}48504851// View -> Show numbering -> Edge numbering4852//-----------------------------------------------------------------------------4853void MainWindow::showEdgeNumbersSlot() {4854if (!glWidget->hasMesh()) {4855logMessage("Refusing to show edge element numbering when mesh is empty");4856return;4857}4858glWidget->stateDrawEdgeNumbers = !glWidget->stateDrawEdgeNumbers;4859glWidget->updateGL();4860synchronizeMenuToState();48614862if (glWidget->stateDrawEdgeNumbers)4863logMessage("Edge element numbering turned on");4864else4865logMessage("Edge element numbering turned off");4866}48674868// View -> Numbering -> Node numbers4869//-----------------------------------------------------------------------------4870void MainWindow::showNodeNumbersSlot() {4871if (!glWidget->hasMesh()) {4872logMessage("Refusing to show node numbering when mesh is empty");4873return;4874}4875glWidget->stateDrawNodeNumbers = !glWidget->stateDrawNodeNumbers;4876glWidget->updateGL();4877synchronizeMenuToState();48784879if (glWidget->stateDrawNodeNumbers)4880logMessage("Node numbering turned on");4881else4882logMessage("Node numbering turned off");4883}48844885// View -> Numbering -> Boundary index4886//-----------------------------------------------------------------------------4887void MainWindow::showBoundaryIndexSlot() {4888if (!glWidget->hasMesh()) {4889logMessage("Refusing to show boundary indices when mesh is empty");4890return;4891}4892glWidget->stateDrawBoundaryIndex = !glWidget->stateDrawBoundaryIndex;4893glWidget->updateGL();4894synchronizeMenuToState();48954896if (glWidget->stateDrawBoundaryIndex)4897logMessage("Boundary indices visible");4898else4899logMessage("Boundary indices hidden");4900}49014902// View -> Numbering -> Body index4903//-----------------------------------------------------------------------------4904void MainWindow::showBodyIndexSlot() {4905if (!glWidget->hasMesh()) {4906logMessage("Refusing to show body indices when mesh is empty");4907return;4908}49094910glWidget->stateDrawBodyIndex = !glWidget->stateDrawBodyIndex;4911glWidget->updateGL();4912synchronizeMenuToState();49134914if (glWidget->stateDrawBodyIndex)4915logMessage("Body indices visible");4916else4917logMessage("Body indices hidden");4918}49194920// View -> Colors -> GL controls4921//-----------------------------------------------------------------------------4922void MainWindow::glControlSlot() {4923if (!glWidget->hasMesh()) {4924logMessage("No mesh - unable to set GL parameters when the mesh is empty");4925return;4926}49274928glControl->glWidget = this->glWidget;4929glControl->show();4930}49314932// View -> Colors -> Boundaries4933//-----------------------------------------------------------------------------4934void MainWindow::colorizeBoundarySlot() {4935if (!glWidget->hasMesh()) {4936logMessage("No mesh - unable to colorize boundaries");4937return;4938}49394940glWidget->stateBcColors = !glWidget->stateBcColors;49414942if (glWidget->stateBcColors)4943glWidget->stateBodyColors = false;49444945glWidget->rebuildLists();4946synchronizeMenuToState();4947}49484949// View -> Colors -> Bodies4950//-----------------------------------------------------------------------------4951void MainWindow::colorizeBodySlot() {4952if (!glWidget->hasMesh()) {4953logMessage("No mesh - unable to colorize bodies");4954return;4955}49564957glWidget->stateBodyColors = !glWidget->stateBodyColors;49584959if (glWidget->stateBodyColors)4960glWidget->stateBcColors = false;49614962glWidget->rebuildLists();4963synchronizeMenuToState();4964}49654966// View -> Colors -> Background4967//-----------------------------------------------------------------------------4968void MainWindow::backgroundColorSlot() {4969QColor newColor = QColorDialog::getColor(glWidget->backgroundColor, this);4970if(!newColor.isValid()) return;49714972#if WITH_QT64973glClearColor(newColor.redF(), newColor.greenF(), newColor.redF(), newColor.alphaF());4974#else4975glWidget->qglClearColor(newColor);4976#endif4977glWidget->backgroundColor = newColor;4978}49794980// View -> Colors -> Surface4981//-----------------------------------------------------------------------------4982void MainWindow::surfaceColorSlot() {4983if (!glWidget->hasMesh()) {4984logMessage("Unable to change surface color when the mesh is empty");4985return;4986}49874988QColor newColor = QColorDialog::getColor(glWidget->surfaceColor, this);4989if(!newColor.isValid()) return;4990glWidget->surfaceColor = newColor;4991glWidget->rebuildLists();4992}49934994// View -> Colors -> Edge4995//-----------------------------------------------------------------------------4996void MainWindow::edgeColorSlot() {4997if (!glWidget->hasMesh()) {4998logMessage("Unable to change edge color when the mesh is empty");4999return;5000}50015002QColor newColor = QColorDialog::getColor(glWidget->edgeColor, this);5003if(!newColor.isValid()) return;5004glWidget->edgeColor = newColor;5005glWidget->rebuildLists();5006}50075008// View -> Colors -> Surface mesh5009//-----------------------------------------------------------------------------5010void MainWindow::surfaceMeshColorSlot() {5011if (!glWidget->hasMesh()) {5012logMessage("Unable to change surface mesh color when the mesh is empty");5013return;5014}50155016QColor newColor = QColorDialog::getColor(glWidget->surfaceMeshColor, this);5017if(!newColor.isValid()) return;5018glWidget->surfaceMeshColor = newColor;5019glWidget->rebuildLists();5020}50215022// View -> Colors -> Sharp edges5023//-----------------------------------------------------------------------------5024void MainWindow::sharpEdgeColorSlot() {5025if (!glWidget->hasMesh()) {5026logMessage("Unable to change sharp edge colors when the mesh is empty");5027return;5028}50295030QColor newColor = QColorDialog::getColor(glWidget->sharpEdgeColor, this);5031if(!newColor.isValid()) return;5032glWidget->sharpEdgeColor = newColor;5033glWidget->rebuildLists();5034}50355036// View -> Colors -> Selection5037//-----------------------------------------------------------------------------5038void MainWindow::selectionColorSlot() {5039if (!glWidget->hasMesh()) {5040logMessage("Unable to change sharp edge colors when the mesh is empty");5041return;5042}50435044QColor newColor = QColorDialog::getColor(glWidget->selectionColor, this);5045if(!newColor.isValid()) return;5046glWidget->selectionColor = newColor;5047glWidget->rebuildLists();5048}50495050// View -> Cad model...5051//-----------------------------------------------------------------------------5052void MainWindow::showCadModelSlot() {5053#ifdef EG_OCC5054cadView->show();5055#endif5056}50575058// View -> Twod model...5059//-----------------------------------------------------------------------------5060void MainWindow::showTwodViewSlot() { twodView->show(); }50615062// View -> VTK post...5063//-----------------------------------------------------------------------------5064void MainWindow::showVtkPostSlot() {5065#ifdef EG_VTK50665067if (glWidget->getMesh() == NULL) {5068vtkPost->show();5069return;5070}50715072QString postFileName =5073saveDirName + "/" + generalSetup->ui.postFileEdit->text().trimmed();5074// Parallel solution:5075//====================5076Ui::parallelDialog ui = parallel->ui;5077bool parallelActive = ui.parallelActiveCheckBox->isChecked();50785079if (parallelActive) {50805081// unify mesh:5082if (meshUnifier->state() == QProcess::Running) {5083logMessage("Mesh unifier is already running - aborted");5084return;5085}50865087if (saveDirName.isEmpty()) {5088logMessage("saveDirName is empty - unable to locate result files");5089return;5090}50915092// Set up log window:5093solverLogWindow->setWindowTitle(tr("ElmerGrid log"));5094solverLogWindow->getTextEdit()->clear();5095solverLogWindow->setFound(false);5096solverLogWindow->show();50975098QString postName = generalSetup->ui.postFileEdit->text().trimmed();5099QStringList postNameSplitted = postName.split(".");5100int nofProcessors = ui.nofProcessorsSpinBox->value();51015102QString unifyingCommand = ui.mergeLineEdit->text().trimmed();5103unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());5104unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));51055106logMessage("Executing: " + unifyingCommand);51075108meshUnifier->start(unifyingCommand);51095110if (!meshUnifier->waitForStarted()) {5111solverLogWindow->getTextEdit()->append(5112"Unable to start ElmerGrid for mesh unification - aborted");5113logMessage("Unable to start ElmerGrid for mesh unification - aborted");5114vtkPostMeshUnifierRunning = false;5115return;5116}51175118// The rest is done in meshUnifierFinishedSlot:5119vtkPostMeshUnifierRunning = true;5120return;5121}51225123// Scalar solution:5124//-----------------5125vtkPost->show();51265127QFileInfo info(postFileName);5128QDir dir = info.dir();5129if(postFileName.endsWith(".vtu", Qt::CaseInsensitive)){5130if(!parallelActive){5131QString vtuFileName = postFileName;5132vtuFileName.insert(vtuFileName.length()-4, "_t0001");5133if(!vtkPost->ReadSingleVtuFile(vtuFileName)){5134vtuFileName = postFileName;5135vtuFileName.insert(vtuFileName.length()-4, "0001");5136vtkPost->ReadSingleVtuFile(vtuFileName);5137}5138}5139}else{5140vtkPost->ReadPostFile(postFileName);5141}5142#endif5143}51445145// View -> Paraview5146//-----------------------------------------------------------------------------5147void MainWindow::showParaViewSlot() {5148#ifdef EG_PARAVIEW51495150if (paraview->state() == QProcess::Running) {5151logMessage("ParaView is already running");5152return;5153}51545155QString postFileName = generalSetup->ui.postFileEdit->text().trimmed();5156QFileInfo pvFile(postFileName);51575158Ui::parallelDialog ui = parallel->ui;5159bool parallelActive = ui.parallelActiveCheckBox->isChecked();51605161QDir currentDir;5162QStringList args;5163QString secondName;51645165currentDir = QDir(saveDirName);51665167// Paraview can deal with case..vtu kind of arguments which however,5168// fail if there is only one file. Use dirty check to see that there5169// are more than one file.51705171if (!parallelActive) {5172secondName = pvFile.baseName() + "_t0002.vtu";5173} else {5174secondName = pvFile.baseName() + "_t0002.pvtu";5175}51765177QFile secondFile(secondName);51785179// Serial solution5180//================5181if (!parallelActive) {5182if (secondFile.exists())5183args << pvFile.baseName() + "_t..vtu";5184else5185args << pvFile.baseName() + "_t0001.vtu";5186}51875188// Parallel solution5189//==================5190if (parallelActive) {5191if (secondFile.exists())5192args << pvFile.baseName() + "_t..pvtu";5193else5194args << pvFile.baseName() + "_t0001.pvtu";5195}51965197// Launch ParaView5198//================5199paraview->start("paraview", args);52005201if (!paraview->waitForStarted()) {5202logMessage("Unable to start ParaView");5203return;5204}52055206logMessage("ParaView started");52075208updateSysTrayIcon("ParaView started",5209"");52105211#endif5212}52135214//*****************************************************************************5215//5216// Mesh MENU5217//5218//*****************************************************************************52195220// Mesh -> Control...5221//-----------------------------------------------------------------------------5222void MainWindow::meshcontrolSlot() {5223meshControl->tetlibPresent = this->tetlibPresent;5224meshControl->nglibPresent = this->nglibPresent;52255226if (!tetlibPresent) {5227meshControl->tetlibPresent = false;5228meshControl->ui.nglibRadioButton->setChecked(true);5229meshControl->ui.tetlibRadioButton->setEnabled(false);5230meshControl->ui.tetlibStringEdit->setEnabled(false);5231}52325233if (!nglibPresent) {5234meshControl->nglibPresent = false;5235meshControl->ui.tetlibRadioButton->setChecked(true);5236meshControl->ui.nglibRadioButton->setEnabled(false);5237meshControl->ui.nglibMaxHEdit->setEnabled(false);5238meshControl->ui.nglibFinenessEdit->setEnabled(false);5239meshControl->ui.nglibBgmeshEdit->setEnabled(false);5240}52415242if (!tetlibPresent && !nglibPresent)5243meshControl->ui.elmerGridRadioButton->setChecked(true);52445245meshControl->show();5246}52475248int checkStlForAscii(const char * filename)5249{5250char ch;5251char bufin[100];5252int stlbinary = 0;5253ifstream stlfile(filename);52545255if (stlfile.is_open()) {5256cout << "Open stl input file: " << filename << endl;52575258for (int j = 0; j < 100; j++) {5259stlfile.get(ch);5260bufin[j] = ch;5261}5262//cout << "bufin: " << bufin << endl;5263if( strstr(bufin,"facet")) {5264cout << "stl input file is in ASCII file format" << endl;5265} else {5266stlbinary = 1;5267cout << "stl input file is in binary file format" << endl;5268}5269cout << endl;5270stlfile.close();5271} else {5272cout << "stl input file not found or is corrupted" << filename << endl;5273}52745275return stlbinary;5276}5277// Mesh -> Remesh5278//-----------------------------------------------------------------------------5279void MainWindow::remeshSlot() {5280if (activeGenerator == GEN_UNKNOWN) {5281logMessage("Unable to (re)mesh: no input data or mesh generator. Allowed: "5282"smesh, poly, off, ply, mesh, stl, grd, FDNEUT, msh, mphtxt, inp, unv, plt, in2d");5283return;5284}52855286// ***** ELMERGRID *****52875288if (activeGenerator == GEN_ELMERGRID) {52895290meshutils->clearMesh(glWidget->getMesh());5291glWidget->newMesh();5292mesh_t *mesh = glWidget->getMesh();52935294#if WITH_QT5 || WITH_QT65295elmergridAPI->createElmerMeshStructure(5296mesh, meshControl->elmerGridControlString.toLatin1());5297#else5298elmergridAPI->createElmerMeshStructure(5299mesh, meshControl->elmerGridControlString.toAscii());5300#endif53015302if (mesh->getSurfaces() == 0)5303meshutils->findSurfaceElements(mesh);53045305for (int i = 0; i < mesh->getSurfaces(); i++) {5306surface_t *surface = mesh->getSurface(i);53075308surface->setEdges((int)(surface->getCode() / 100));5309surface->newEdgeIndexes(surface->getEdges());5310for (int j = 0; j < surface->getEdges(); j++)5311surface->setEdgeIndex(j, -1);5312}53135314meshutils->findSurfaceElementEdges(mesh);5315meshutils->findSurfaceElementNormals(mesh);53165317glWidget->rebuildLists();5318applyOperations();53195320return;5321}53225323// ***** Threaded generators *****53245325if (!remeshAct->isEnabled()) {5326logMessage("Meshing thread is already running - aborting");5327return;5328}53295330if (activeGenerator == GEN_TETLIB) {53315332if (!tetlibPresent) {5333logMessage("tetlib functionality unavailable");5334return;5335}53365337if (!tetlibInputOk) {5338logMessage("Remesh: error: no input data for tetlib");5339return;5340}53415342// Usually "J" should be included in the control string:5343tetlibControlString = meshControl->tetlibControlString;53445345} else if (activeGenerator == GEN_NGLIB) {53465347if (!nglibPresent) {5348logMessage("nglib functionality unavailable");5349return;5350}53515352if (!nglibInputOk) {5353logMessage("Remesh: error: no input data for nglib");5354return;5355}53565357// Init & set mesh params.:5358//--------------------------5359cout << "Initializing nglib" << endl;5360nglib::Ng_Init();53615362char backgroundmesh[1024];5363#if WITH_QT5 || WITH_QT65364sprintf(backgroundmesh, "%s",5365meshControl->nglibBackgroundmesh.toLatin1().data());5366#else5367sprintf(backgroundmesh, "%s",5368meshControl->nglibBackgroundmesh.toAscii().data());5369#endif53705371mp.maxh = meshControl->nglibMaxH.toDouble();5372mp.fineness = meshControl->nglibFineness.toDouble();5373mp.secondorder = 0;5374mp.meshsize_filename = backgroundmesh;53755376if (ngDim == 3) {53775378// STL (3D):5379//-----------5380cout << "Start meshing..." << endl;53815382nggeom = nglib::Ng_STL_NewGeometry();53835384ngmesh = nglib::Ng_NewMesh();53855386if (!occInputOk) {53875388// STL: regenerate structures for nglib:5389//--------------------------------------5390// check if input file is in ascii or binary format5391#if WITH_QT5 || WITH_QT65392int stlbinary = checkStlForAscii(stlFileName.toLatin1().data());5393#else5394int stlbinary = checkStlForAscii(stlFileName.toAscii().data());5395#endif53965397#if WITH_QT5 || WITH_QT65398nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toLatin1().data(), stlbinary);5399#else5400nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toAscii().data(), stlbinary);5401#endif54025403if (!nggeom) {5404logMessage("Ng_STL_LoadGeometry failed");5405return;5406}54075408nglib::Ng_STL_InitSTLGeometry(nggeom);54095410nglib::Ng_STL_MakeEdges(nggeom, ngmesh, &mp);54115412double maxMeshSize = mp.maxh;54135414if (maxMeshSize <= 0)5415maxMeshSize = 10000000;54165417nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);54185419#ifdef EG_OCC5420} else {54215422// OCC: (re)generate STL for nglib:5423//----------------------------------5424cadView->setMesh(ngmesh);5425cadView->setGeom(nggeom);5426cadView->setMp(&mp);5427cadView->generateSTL();5428#endif5429}54305431} else if (ngDim == 2) {54325433// IN2D (2D):5434//------------5435cout << "Start 2D meshing..." << endl;54365437if (!occInputOk) {54385439// Native 2D geometry input for Ng:5440//----------------------------------5441if (in2dFileName.isEmpty()) {5442logMessage("File name is empty - aborting");5443return;5444}54455446ngmesh = nglib::Ng_NewMesh();54475448#if WITH_QT5 || WITH_QT65449nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toLatin1().data());5450#else5451nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toAscii().data());5452#endif54535454if (!nggeom2d) {5455logMessage("Ng_LoadGeometry_2D failed");5456return;5457}54585459nglibAPI->setNggeom2D(nggeom2d);54605461double maxMeshSize = mp.maxh;54625463if (maxMeshSize <= 0)5464maxMeshSize = 10000000;54655466nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);54675468#ifdef EG_OCC5469} else {54705471// Model originates from a 2D cad file:5472//--------------------------------------5473cadView->generateIn2dFile();54745475ngmesh = nglib::Ng_NewMesh();54765477nggeom2d = nglib::Ng_LoadGeometry_2D("iges2ng.in2d");54785479if (!nggeom2d) {5480logMessage("Ng_LoadGeometry_2D failed");5481return;5482}54835484nglibAPI->setNggeom2D(nggeom2d);54855486double maxMeshSize = mp.maxh;54875488if (maxMeshSize <= 0)5489maxMeshSize = 10000000;54905491nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);5492#endif5493}54945495} else {54965497// Unknown spatial dimension:5498//----------------------------5499cout << "Unknown spatial dimension" << endl;5500return;5501}55025503} else {55045505logMessage("Remesh: unknown generator type");5506return;5507}55085509// ***** Start meshing thread *****55105511logMessage("Sending start request to mesh generator...");55125513meshutils->clearMesh(glWidget->getMesh());5514glWidget->newMesh();5515mesh_t *mesh = glWidget->getMesh();55165517// Re-enable when finished() or terminated() signal is received:5518remeshAct->setEnabled(false);5519stopMeshingAct->setEnabled(true);55205521if (activeGenerator == GEN_NGLIB)5522stopMeshingAct->setEnabled(false);55235524meshingThread->generate(activeGenerator, tetlibControlString, tetlibAPI,5525ngmesh, nggeom, nggeom2d, ngDim, &mp);5526}55275528// Mesh -> Kill generator5529//-----------------------------------------------------------------------------5530void MainWindow::stopMeshingSlot() {5531if (remeshAct->isEnabled()) {5532logMessage("Mesh generator is not running");5533return;5534}55355536logMessage("Sending termination request to mesh generator...");5537meshingThread->stopMeshing();5538}55395540// Meshing has started (signaled by meshingThread):5541//-----------------------------------------------------------------------------5542void MainWindow::meshingStartedSlot() {5543logMessage("Mesh generator started");55445545updateSysTrayIcon("Mesh generator started",5546"Use Mesh->Terminate to stop processing");55475548statusBar()->showMessage(tr("Mesh generator started"));55495550progressBar->show();5551progressBar->setRange(0, 0);55525553progressLabel->show();5554progressLabel->setText("Meshing");5555}55565557// Meshing has been terminated (signaled by meshingThread):5558//-----------------------------------------------------------------------------5559void MainWindow::meshingTerminatedSlot() {5560logMessage("Mesh generator terminated");55615562progressBar->hide();5563progressBar->setRange(0, 100);55645565progressLabel->hide();55665567stopMeshingAct->setEnabled(true);55685569updateSysTrayIcon("Mesh generator terminated", "Use Mesh->Remesh to restart");55705571statusBar()->showMessage(tr("Ready"));55725573// clean up:5574if (activeGenerator == GEN_TETLIB) {5575cout << "Cleaning up...";5576out->deinitialize();5577cout << "done" << endl;5578cout.flush();5579}55805581if (activeGenerator == GEN_NGLIB) {5582nglib::Ng_DeleteMesh(ngmesh);5583nglib::Ng_Exit();5584}55855586remeshAct->setEnabled(true);5587stopMeshingAct->setEnabled(false);5588}55895590// Mesh is ready (signaled by meshingThread):5591//-----------------------------------------------------------------------------5592void MainWindow::meshingFinishedSlot() {5593logMessage("Mesh generation ready");55945595progressBar->hide();5596progressBar->setRange(0, 100);55975598progressLabel->hide();55995600if (activeGenerator == GEN_TETLIB) {56015602makeElmerMeshFromTetlib();56035604} else if (activeGenerator == GEN_NGLIB) {56055606this->ngmesh = meshingThread->getNgMesh();56075608makeElmerMeshFromNglib();56095610nglib::Ng_DeleteMesh(ngmesh);5611nglib::Ng_Exit();56125613} else {56145615logMessage("MeshOk: error: unknown mesh generator");5616}56175618applyOperations();56195620statusBar()->showMessage(tr("Ready"));56215622updateSysTrayIcon("Mesh generator has finished",5623"Select Model->Summary for statistics");56245625remeshAct->setEnabled(true);5626stopMeshingAct->setEnabled(false);56275628// Check cmd line arguments:5629//---------------------------5630QStringList args = QCoreApplication::arguments();56315632int output = args.indexOf("-o");56335634if (output > 0) {5635QString dirName = args.at(output + 1);56365637if (dirName.left(1) != "-") {5638cout << "Saving mesh files" << endl;5639saveElmerMesh(dirName);5640}5641}56425643if (args.contains("-e") || args.contains("-nogui")) {5644cout << "Exiting" << endl;5645QApplication::closeAllWindows();5646exit(0);5647}56485649resetSlot();5650}56515652// Mesh -> Divide surface...5653//-----------------------------------------------------------------------------5654void MainWindow::surfaceDivideSlot() {5655if (!glWidget->hasMesh()) {5656logMessage("There is nothing to divide - mesh is empty");5657return;5658}56595660boundaryDivide->target = TARGET_SURFACES;5661boundaryDivide->show();5662}56635664// Make surface division by sharp edges (signalled by boundaryDivide)...5665//-----------------------------------------------------------------------------5666void MainWindow::doDivideSurfaceSlot(double angle) {5667mesh_t *mesh = glWidget->getMesh();5668int lists = glWidget->getLists();56695670if (mesh == NULL) {5671logMessage("No mesh to divide");5672return;5673}56745675operations++;5676operation_t *p = new operation_t;5677operation_t *q = NULL;56785679for (q = &operation; q->next; q = q->next)5680;5681q->next = p;5682p->next = NULL;56835684p->type = OP_DIVIDE_SURFACE;5685p->angle = angle;56865687int selected = 0;56885689for (int i = 0; i < lists; i++) {5690list_t *l = glWidget->getList(i);56915692if (l->isSelected() && (l->getType() == SURFACELIST) &&5693(l->getNature() == PDE_BOUNDARY))5694selected++;5695}5696p->selected = selected;5697p->select_set = new int[selected];5698selected = 0;56995700for (int i = 0; i < lists; i++) {5701list_t *l = glWidget->getList(i);5702if (l->isSelected() && (l->getType() == SURFACELIST) &&5703(l->getNature() == PDE_BOUNDARY))5704p->select_set[selected++] = i;5705}57065707meshutils->findSharpEdges(mesh, angle);5708int parts = meshutils->divideSurfaceBySharpEdges(mesh);57095710QString qs = "Surface divided into " + QString::number(parts) + " parts";5711statusBar()->showMessage(qs);57125713synchronizeMenuToState();5714glWidget->rebuildLists();5715glWidget->updateGL();57165717// Added 05 September 20095718boundaryPropertyEditor.clear();5719boundaryPropertyEditor.resize(parts);5720for (int i = 0; i < parts; i++)5721boundaryPropertyEditor[i] = new BoundaryPropertyEditor;5722}57235724// Mesh -> Unify surface5725//-----------------------------------------------------------------------------5726void MainWindow::surfaceUnifySlot() {5727mesh_t *mesh = glWidget->getMesh();5728int lists = glWidget->getLists();57295730if (mesh == NULL) {5731logMessage("No surfaces to unify");5732return;5733}57345735int targetindex = -1, selected = 0;5736QVector<BoundaryPropertyEditor *> unusedBoundary;5737for (int i = 0; i < lists; i++) {5738list_t *l = glWidget->getList(i);5739if (l->isSelected() && (l->getType() == SURFACELIST) &&5740(l->getNature() == PDE_BOUNDARY)) {5741selected++;5742if (targetindex < 0)5743targetindex = l->getIndex();5744else {5745int v = glWidget->boundaryMap.value(l->getIndex());5746if (v >= 0 && v < boundaryPropertyEditor.size() &&5747boundaryPropertyEditor[v] != NULL) {5748unusedBoundary.append(boundaryPropertyEditor[v]);5749}5750}5751}5752}57535754if (targetindex < 0) {5755logMessage("No surfaces selected");5756return;5757}57585759operations++;5760operation_t *p = new operation_t, *q;5761for (q = &operation; q->next; q = q->next)5762;5763q->next = p;5764p->next = NULL;5765p->type = OP_UNIFY_SURFACE;5766p->selected = selected;5767p->select_set = new int[selected];57685769selected = 0;5770for (int i = 0; i < lists; i++) {5771list_t *l = glWidget->getList(i);5772if (l->isSelected() && (l->getType() == SURFACELIST) &&5773(l->getNature() == PDE_BOUNDARY)) {5774p->select_set[selected++] = i;5775for (int j = 0; j < mesh->getSurfaces(); j++) {5776surface_t *s = mesh->getSurface(j);5777if ((s->getIndex() == l->getIndex()) &&5778(s->getNature() == PDE_BOUNDARY))5779s->setIndex(targetindex);5780}5781}5782}57835784for (int i = 0; i < unusedBoundary.size(); i++) {5785boundaryPropertyEditor.remove(5786boundaryPropertyEditor.indexOf(unusedBoundary[i]));5787delete unusedBoundary[i];5788}57895790cout << "Selected surfaces marked with index " << targetindex << endl;5791cout.flush();57925793glWidget->rebuildLists();57945795logMessage("Selected surfaces unified");5796}57975798void MainWindow::applyOperations() {5799mesh_t *mesh = glWidget->getMesh();58005801cout << "Apply " << operations << " operations" << endl;5802cout.flush();58035804operation_t *p = operation.next;5805for (; p; p = p->next) {5806int lists = glWidget->getLists();58075808for (int i = 0; i < lists; i++)5809glWidget->getList(i)->setSelected(false);58105811for (int j = 0; j < mesh->getSurfaces(); j++)5812mesh->getSurface(j)->setSelected(false);58135814for (int j = 0; j < mesh->getEdges(); j++)5815mesh->getEdge(j)->setSelected(false);58165817for (int i = 0; i < p->selected; i++) {5818list_t *l = glWidget->getList(p->select_set[i]);58195820l->setSelected(true);5821if (p->type < OP_UNIFY_EDGE) {5822for (int j = 0; j < mesh->getSurfaces(); j++) {5823surface_t *surf = mesh->getSurface(j);5824if (l->getIndex() == surf->getIndex())5825surf->setSelected(l->isSelected());5826}5827} else {5828for (int j = 0; j < mesh->getEdges(); j++) {5829edge_t *edge = mesh->getEdge(j);5830if (l->getIndex() == edge->getIndex())5831edge->setSelected(l->isSelected());5832}5833}5834}58355836if (p->type == OP_DIVIDE_SURFACE) {5837meshutils->findSharpEdges(mesh, p->angle);5838int parts = meshutils->divideSurfaceBySharpEdges(mesh);5839QString qs = "Surface divided into " + QString::number(parts) + " parts";5840statusBar()->showMessage(qs);58415842} else if (p->type == OP_DIVIDE_EDGE) {5843meshutils->findEdgeElementPoints(mesh);5844meshutils->findSharpPoints(mesh, p->angle);5845int parts = meshutils->divideEdgeBySharpPoints(mesh);5846QString qs = "Edges divided into " + QString::number(parts) + " parts";5847statusBar()->showMessage(qs);58485849} else if (p->type == OP_UNIFY_SURFACE) {5850int targetindex = -1;58515852for (int i = 0; i < lists; i++) {5853list_t *l = glWidget->getList(i);5854if (l->isSelected() && (l->getType() == SURFACELIST) &&5855(l->getNature() == PDE_BOUNDARY)) {5856if (targetindex < 0) {5857targetindex = l->getIndex();5858break;5859}5860}5861}5862for (int i = 0; i < lists; i++) {5863list_t *l = glWidget->getList(i);5864if (l->isSelected() && (l->getType() == SURFACELIST) &&5865(l->getNature() == PDE_BOUNDARY)) {5866for (int j = 0; j < mesh->getSurfaces(); j++) {5867surface_t *s = mesh->getSurface(j);5868if ((s->getIndex() == l->getIndex()) &&5869(s->getNature() == PDE_BOUNDARY))5870s->setIndex(targetindex);5871}5872}5873}5874cout << "Selected surfaces marked with index " << targetindex << endl;5875cout.flush();58765877} else if (p->type == OP_UNIFY_EDGE) {5878int targetindex = -1;5879for (int i = 0; i < lists; i++) {5880list_t *l = glWidget->getList(i);5881if (l->isSelected() && l->getType() == EDGELIST &&5882l->getNature() == PDE_BOUNDARY) {5883if (targetindex < 0) {5884targetindex = l->getIndex();5885break;5886}5887}5888}5889for (int i = 0; i < lists; i++) {5890list_t *l = glWidget->getList(i);5891if (l->isSelected() && l->getType() == EDGELIST &&5892l->getNature() == PDE_BOUNDARY) {5893for (int j = 0; j < mesh->getEdges(); j++) {5894edge_t *e = mesh->getEdge(j);5895if (e->getIndex() == l->getIndex() &&5896e->getNature() == PDE_BOUNDARY)5897e->setIndex(targetindex);5898}5899}5900}5901cout << "Selected edges marked with index " << targetindex << endl;5902cout.flush();5903}5904glWidget->rebuildLists();5905}59065907synchronizeMenuToState();5908glWidget->updateGL();59095910// Added 05 September 20095911boundaryPropertyEditor.clear();5912int parts = glWidget->getLists();5913boundaryPropertyEditor.resize(parts);5914for (int i = 0; i < parts; i++)5915boundaryPropertyEditor[i] = new BoundaryPropertyEditor;5916}59175918// Mesh -> Divide edge...5919//-----------------------------------------------------------------------------5920void MainWindow::edgeDivideSlot() {5921if (!glWidget->hasMesh()) {5922logMessage("There is nothing to divide - mesh is empty");5923return;5924}59255926boundaryDivide->target = TARGET_EDGES;5927boundaryDivide->show();5928}59295930// Make edge division by sharp points (signalled by boundaryDivide)...5931//-----------------------------------------------------------------------------5932void MainWindow::doDivideEdgeSlot(double angle) {5933mesh_t *mesh = glWidget->getMesh();5934int lists = glWidget->getLists();59355936if (mesh == NULL) {5937logMessage("No mesh to divide");5938return;5939}59405941operations++;5942operation_t *p = new operation_t, *q;5943for (q = &operation; q->next; q = q->next)5944;5945q->next = p;5946p->next = NULL;59475948p->type = OP_DIVIDE_EDGE;5949p->angle = angle;59505951int selected = 0;5952for (int i = 0; i < lists; i++) {5953list_t *l = glWidget->getList(i);5954if (l->isSelected() && l->getType() == EDGELIST &&5955l->getNature() == PDE_BOUNDARY)5956selected++;5957}5958p->selected = selected;5959p->select_set = new int[selected];5960selected = 0;59615962for (int i = 0; i < lists; i++) {5963list_t *l = glWidget->getList(i);5964if (l->isSelected() && l->getType() == EDGELIST &&5965l->getNature() == PDE_BOUNDARY)5966p->select_set[selected++] = i;5967}59685969meshutils->findEdgeElementPoints(mesh);5970meshutils->findSharpPoints(mesh, angle);5971int parts = meshutils->divideEdgeBySharpPoints(mesh);59725973QString qs = "Edge divided into " + QString::number(parts) + " parts";5974statusBar()->showMessage(qs);59755976synchronizeMenuToState();5977glWidget->rebuildLists();5978glWidget->updateGL();59795980// Added 05 September 20095981boundaryPropertyEditor.clear();5982boundaryPropertyEditor.resize(parts);5983for (int i = 0; i < parts; i++)5984boundaryPropertyEditor[i] = new BoundaryPropertyEditor;5985}59865987// Mesh -> Unify edge5988//-----------------------------------------------------------------------------5989void MainWindow::edgeUnifySlot() {5990mesh_t *mesh = glWidget->getMesh();5991int lists = glWidget->getLists();59925993if (mesh == NULL) {5994logMessage("No edges to unify");5995return;5996}59975998int targetindex = -1, selected = 0;5999QVector<BoundaryPropertyEditor *> unusedBoundary;6000for (int i = 0; i < lists; i++) {6001list_t *l = glWidget->getList(i);6002if (l->isSelected() && l->getType() == EDGELIST &&6003l->getNature() == PDE_BOUNDARY) {6004selected++;6005if (targetindex < 0)6006targetindex = l->getIndex();6007else {6008int v = glWidget->boundaryMap.value(l->getIndex());6009if (v >= 0 && v < boundaryPropertyEditor.size() &&6010boundaryPropertyEditor[v] != NULL) {6011unusedBoundary.append(boundaryPropertyEditor[v]);6012}6013}6014}6015}60166017if (targetindex < 0) {6018logMessage("No edges selected");6019return;6020}60216022operations++;6023operation_t *p = new operation_t, *q;6024for (q = &operation; q->next; q = q->next)6025;6026q->next = p;6027p->next = NULL;6028p->type = OP_UNIFY_EDGE;6029p->selected = selected;6030p->select_set = new int[selected];60316032selected = 0;60336034for (int i = 0; i < lists; i++) {6035list_t *l = glWidget->getList(i);6036if (l->isSelected() && l->getType() == EDGELIST &&6037l->getNature() == PDE_BOUNDARY) {6038p->select_set[selected++] = i;6039for (int j = 0; j < mesh->getEdges(); j++) {6040edge_t *e = mesh->getEdge(j);6041if (e->getIndex() == l->getIndex() && e->getNature() == PDE_BOUNDARY)6042e->setIndex(targetindex);6043}6044}6045}60466047for (int i = 0; i < unusedBoundary.size(); i++) {6048boundaryPropertyEditor.remove(6049boundaryPropertyEditor.indexOf(unusedBoundary[i]));6050delete unusedBoundary[i];6051}60526053cout << "Selected edges marked with index " << targetindex << endl;6054cout.flush();60556056glWidget->rebuildLists();60576058logMessage("Selected edges unified");6059}60606061// Mesh -> Clean up6062//-----------------------------------------------------------------------------6063void MainWindow::cleanHangingSharpEdgesSlot() {6064mesh_t *mesh = glWidget->getMesh();60656066if (mesh == NULL)6067return;60686069int count = meshutils->cleanHangingSharpEdges(mesh);60706071cout << "Removed " << count << " hanging sharp edges" << endl;6072cout.flush();60736074glWidget->rebuildLists();6075}60766077//*****************************************************************************6078//6079// Edit MENU6080//6081//*****************************************************************************60826083// Edit -> Sif...6084//-----------------------------------------------------------------------------6085void MainWindow::showsifSlot() {6086// QFont sansFont("Courier", 10);6087// sifWindow->getTextEdit()->setCurrentFont(sansFont);6088if(sifWindow->windowState() & Qt::WindowMinimized){6089sifWindow->showNormal();6090}6091else sifWindow->show();6092}60936094// Edit -> Generate sif6095//-----------------------------------------------------------------------------6096void MainWindow::generateSifSlot() {6097mesh_t *mesh = glWidget->getMesh();60986099if (mesh == NULL) {6100logMessage("Unable to create SIF: no mesh");6101return;6102}61036104if ((mesh->getDim() < 1) || (mesh->getCdim() < 1)) {6105logMessage("Model dimension inconsistent with SIF syntax");6106return;6107}61086109// Clear SIF text editor:6110//------------------------6111sifWindow->getTextEdit()->clear();6112sifWindow->setFirstTime(true);6113sifWindow->setFound(false);6114// QFont sansFont("Courier", 10);6115// sifWindow->getTextEdit()->setCurrentFont(sansFont);61166117// Set up SIF generator:6118//-----------------------6119sifGenerator->setMesh(mesh);6120sifGenerator->setTextEdit(sifWindow->getTextEdit());6121sifGenerator->setDim(mesh->getDim());6122sifGenerator->setCdim(mesh->getCdim());6123sifGenerator->setGeneralSetup(generalSetup);61246125sifGenerator->setEquationEditor(equationEditor);6126sifGenerator->setMaterialEditor(materialEditor);6127sifGenerator->setBodyForceEditor(bodyForceEditor);6128sifGenerator->setInitialConditionEditor(initialConditionEditor);6129sifGenerator->setBoundaryConditionEditor(boundaryConditionEditor);6130sifGenerator->setSolverParameterEditor(solverParameterEditor);6131sifGenerator->setBoundaryPropertyEditor(boundaryPropertyEditor);6132sifGenerator->setBodyPropertyEditor(bodyPropertyEditor);6133sifGenerator->setMeshControl(meshControl);6134sifGenerator->setElmerDefs(elmerDefs);6135sifGenerator->bodyMap = glWidget->bodyMap;6136sifGenerator->boundaryMap = glWidget->boundaryMap;61376138// Make SIF:6139//----------6140sifGenerator->makeHeaderBlock();6141sifGenerator->makeSimulationBlock();6142sifGenerator->makeConstantsBlock();6143sifGenerator->makeBodyBlocks();6144sifGenerator->makeEquationBlocks();6145sifGenerator->makeMaterialBlocks();6146sifGenerator->makeBodyForceBlocks();6147sifGenerator->makeInitialConditionBlocks();6148sifGenerator->makeBoundaryBlocks();6149}61506151// Boundary selected by double clicking (signaled by glWidget::select):6152//-----------------------------------------------------------------------------6153void MainWindow::boundarySelectedSlot(list_t *l, Qt::KeyboardModifiers modifiers) {6154QString qs;61556156if (l->getIndex() < 0) {6157statusBar()->showMessage("Ready");6158return;6159}61606161if (l->isSelected()) {6162if (l->getType() == SURFACELIST) {6163qs = "Selected surface " + QString::number(l->getIndex());6164} else if (l->getType() == EDGELIST) {6165qs = "Selected edge " + QString::number(l->getIndex());6166} else {6167qs = "Selected object " + QString::number(l->getIndex()) +6168" (type unknown)";6169}6170} else {6171if (l->getType() == SURFACELIST) {6172qs = "Unselected surface " + QString::number(l->getIndex());6173} else if (l->getType() == EDGELIST) {6174qs = "Unselected edge " + QString::number(l->getIndex());6175} else {6176qs = "Unselected object " + QString::number(l->getIndex()) +6177" (type unknown)";6178}6179}61806181logMessage(qs);61826183// Open bc property sheet for selected boundary:6184//-----------------------------------------------6185if (l->isSelected() && ((modifiers & Qt::AltModifier) || bcEditActive)) {61866187if (l->getNature() != PDE_BOUNDARY) {6188/*Ignore when double clicking a body of 2D geometry under boundary6189* selection mode*/6190raise();6191return;6192}61936194// renumbering:6195int n = glWidget->boundaryMap.value(l->getIndex());61966197if (n >= boundaryPropertyEditor.size()) {6198logMessage("Error: Boundary index mismatch");6199return;6200}62016202BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];6203populateBoundaryComboBoxes(boundaryEdit);62046205connect(boundaryEdit,6206SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor *, int)), this,6207SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor *, int)));62086209if (boundaryEdit->touched) {6210boundaryEdit->ui.applyButton->setText("Update");6211// boundaryEdit->ui.discardButton->setText("Remove");6212boundaryEdit->ui.discardButton->setText("Cancel");6213boundaryEdit->ui.applyButton->setIcon(6214QIcon::fromTheme("view-refresh"));6215// boundaryEdit->ui.discardButton->setIcon(QIcon::fromTheme("list-remove"));6216boundaryEdit->ui.discardButton->setIcon(6217QIcon::fromTheme("dialog-error-round"));6218} else {6219boundaryEdit->ui.applyButton->setText("Add");6220boundaryEdit->ui.discardButton->setText("Cancel");6221boundaryEdit->ui.applyButton->setIcon(QIcon::fromTheme("list-add"));6222boundaryEdit->ui.discardButton->setIcon(6223QIcon::fromTheme("dialog-error-round"));6224}62256226boundaryEdit->setWindowTitle("Properties for boundary " +6227QString::number(l->getIndex()));6228boundaryEdit->show();6229boundaryEdit->raise();6230}62316232BodyPropertyEditor *bodyEdit = NULL;6233int current = -1, n = -1;62346235// boundary as a body treatment6236// ----------------------------6237if (l->isSelected() && (modifiers & Qt::ControlModifier)) {62386239// renumbering:6240int n = glWidget->boundaryMap.value(l->getIndex());62416242if (n >= boundaryPropertyEditor.size()) {6243logMessage("Error: Boundary index mismatch");6244return;6245}62466247BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];62486249if (!boundaryEdit) {6250cout << "MainWindow: Boundary index out of bounds" << endl;6251return;6252}62536254bodyEdit = boundaryEdit->bodyProperties;62556256if (bodyEdit) {62576258bodyEdit->setWindowTitle("Properties for body " +6259QString::number(current));62606261// if(bodyEdit->ui.nameEdit->text().trimmed().isEmpty())6262// bodyEdit->ui.nameEdit->setText("Body Property{Boundary " +6263// QString::number(n+1) + "}");6264bodyEdit->ui.nameEdit->setText("Body {Boundary " +6265QString::number(n + 1) + "}");6266}6267}62686269// Open body property sheet for selected body:6270//---------------------------------------------6271if ((glWidget->currentlySelectedBody >= 0) &&6272( (modifiers & Qt::ShiftModifier) || bodyEditActive)) {62736274current = glWidget->currentlySelectedBody;62756276cout << "Current selection uniquely determines body: " << current << endl;6277cout.flush();62786279// renumbering:6280n = glWidget->bodyMap.value(current);62816282if (n >= bodyPropertyEditor.size()) {6283logMessage("MainWindow: Body index out of bounds)");6284return;6285}62866287bodyEdit = bodyPropertyEditor[n];62886289if (!bodyEdit)6290cout << "MainWindow: Undetermined body index" << endl;62916292bodyEdit->setWindowTitle("Properties for body " + QString::number(current));62936294if (bodyEdit->ui.nameEdit->text().trimmed().isEmpty())6295bodyEdit->ui.nameEdit->setText("Body Property " + QString::number(n + 1));6296}62976298if (bodyEdit) {6299populateBodyComboBoxes(bodyEdit);63006301if (bodyEdit->touched) {6302bodyEdit->ui.applyButton->setText("Update");6303// bodyEdit->ui.discardButton->setText("Remove");6304bodyEdit->ui.discardButton->setText("Cancel");6305bodyEdit->ui.applyButton->setIcon(QIcon::fromTheme("view-refresh"));6306// bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("list-remove"));6307bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));6308} else {6309bodyEdit->ui.applyButton->setText("Add");6310bodyEdit->ui.discardButton->setText("Cancel");6311bodyEdit->ui.applyButton->setIcon(QIcon::fromTheme("list-add"));6312bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));6313}63146315bodyEdit->show();6316bodyEdit->raise();6317}6318}63196320// Populate boundary editor's comboboxes:6321//---------------------------------------6322void MainWindow::populateBoundaryComboBoxes(BoundaryPropertyEditor *boundary) {6323boundary->disconnect(6324SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)));6325while (boundary && boundary->ui.boundaryConditionCombo &&6326boundary->ui.boundaryConditionCombo->count() > 0)6327boundary->ui.boundaryConditionCombo->removeItem(0);63286329int takethis = 1; //-1;6330int count = 1;6331boundary->ui.boundaryConditionCombo->insertItem(count++, "");63326333for (int i = 0; i < boundaryConditionEditor.size(); i++) {6334DynamicEditor *bcEdit = boundaryConditionEditor[i];6335if (bcEdit->menuAction != NULL) {6336const QString &name = bcEdit->nameEdit->text().trimmed();6337boundary->ui.boundaryConditionCombo->insertItem(count, name);6338if (boundary->condition == bcEdit)6339takethis = count;6340count++;6341}6342}6343connect(boundary,6344SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)), this,6345SLOT(boundaryComboChanged(BoundaryPropertyEditor *, QString)));63466347boundary->ui.boundaryConditionCombo->setCurrentIndex(takethis - 1);6348}63496350//-----------------------------------------------------------------------------6351void MainWindow::boundaryComboChanged(BoundaryPropertyEditor *b, QString text) {6352b->condition = 0;6353b->touched = false;63546355for (int i = 0; i < boundaryConditionEditor.size(); i++) {6356DynamicEditor *bc = boundaryConditionEditor[i];6357if (bc->ID >= 0) {6358if (bc->nameEdit->text().trimmed() == text) {6359b->condition = bc;6360b->touched = true;6361break;6362}6363}6364}6365}63666367//-----------------------------------------------------------------------------6368void MainWindow::boundaryAsABodyChanged(BoundaryPropertyEditor *b, int status) {6369int indx = glWidget->bodyMap.count();63706371if (status) {6372for (int i = 0; i < boundaryPropertyEditor.size(); i++)6373if (boundaryPropertyEditor[i] &&6374boundaryPropertyEditor[i]->bodyProperties)6375indx++;63766377if (indx >= bodyPropertyEditor.size()) {6378cout << "MainWindow: Body index out of bounds" << endl;6379return;6380}63816382if (bodyPropertyEditor[indx])6383b->bodyProperties = bodyPropertyEditor[indx];63846385} else {63866387b->bodyProperties = NULL;6388}6389}63906391// Populate body editor's comboboxes:6392//-----------------------------------6393void MainWindow::populateBodyComboBoxes(BodyPropertyEditor *bodyEdit) {6394// Equation:6395// =========6396bodyEdit->disconnect(6397SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)));6398bodyEdit->ui.equationCombo->clear();63996400int count = 1;6401int takethis = 1; // -16402bodyEdit->ui.equationCombo->insertItem(count++, "");64036404for (int i = 0; i < equationEditor.size(); i++) {6405DynamicEditor *eqEdit = equationEditor[i];6406if (eqEdit->menuAction != NULL) {6407const QString &name = eqEdit->nameEdit->text().trimmed();6408bodyEdit->ui.equationCombo->insertItem(count, name);6409if (bodyEdit->equation == eqEdit)6410takethis = count;6411count++;6412}6413}6414connect(bodyEdit,6415SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)), this,6416SLOT(equationComboChanged(BodyPropertyEditor *, QString)));6417bodyEdit->ui.equationCombo->setCurrentIndex(takethis - 1);64186419// Material6420// =========6421bodyEdit->disconnect(6422SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)));6423bodyEdit->ui.materialCombo->clear();64246425count = 1;6426takethis = 1;6427bodyEdit->ui.materialCombo->insertItem(count, "");6428count++;64296430for (int i = 0; i < materialEditor.size(); i++) {6431DynamicEditor *matEdit = materialEditor[i];64326433if (matEdit->menuAction != NULL) {6434const QString &name = matEdit->nameEdit->text().trimmed();6435bodyEdit->ui.materialCombo->insertItem(count, name);6436if (bodyEdit->material == matEdit)6437takethis = count;6438count++;6439}6440}64416442connect(bodyEdit,6443SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)), this,6444SLOT(materialComboChanged(BodyPropertyEditor *, QString)));64456446bodyEdit->ui.materialCombo->setCurrentIndex(takethis - 1);64476448// Bodyforce:6449//===========6450bodyEdit->disconnect(6451SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)));6452bodyEdit->ui.bodyForceCombo->clear();64536454count = 1;6455takethis = 1; // -16456bodyEdit->ui.bodyForceCombo->insertItem(count++, "");64576458for (int i = 0; i < bodyForceEditor.size(); i++) {6459DynamicEditor *bodyForceEdit = bodyForceEditor[i];6460if (bodyForceEdit->menuAction != NULL) {6461const QString &name = bodyForceEdit->nameEdit->text().trimmed();6462bodyEdit->ui.bodyForceCombo->insertItem(count, name);6463if (bodyEdit->force == bodyForceEdit)6464takethis = count;6465count++;6466}6467}6468connect(bodyEdit,6469SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)), this,6470SLOT(forceComboChanged(BodyPropertyEditor *, QString)));6471bodyEdit->ui.bodyForceCombo->setCurrentIndex(takethis - 1);64726473// Initial Condition:6474//====================6475bodyEdit->disconnect(6476SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)));6477bodyEdit->ui.initialConditionCombo->clear();64786479count = 1;6480takethis = 1; // -16481bodyEdit->ui.initialConditionCombo->insertItem(count++, "");64826483for (int i = 0; i < initialConditionEditor.size(); i++) {6484DynamicEditor *initialConditionEdit = initialConditionEditor[i];6485if (initialConditionEdit->menuAction != NULL) {6486const QString &name = initialConditionEdit->nameEdit->text().trimmed();6487bodyEdit->ui.initialConditionCombo->insertItem(count, name);6488if (bodyEdit->initial == initialConditionEdit)6489takethis = count;6490count++;6491}6492}6493connect(bodyEdit,6494SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)), this,6495SLOT(initialComboChanged(BodyPropertyEditor *, QString)));6496bodyEdit->ui.initialConditionCombo->setCurrentIndex(takethis - 1);6497}64986499//-----------------------------------------------------------------------------6500void MainWindow::materialComboChanged(BodyPropertyEditor *b, QString text) {6501b->material = 0;6502b->touched = false;6503for (int i = 0; i < materialEditor.size(); i++) {6504DynamicEditor *mat = materialEditor[i];65056506if (mat->ID >= 0) {6507if (mat->nameEdit->text().trimmed() == text) {6508b->material = mat;6509b->touched = true;6510break;6511}6512}6513}6514}65156516//-----------------------------------------------------------------------------6517void MainWindow::initialComboChanged(BodyPropertyEditor *b, QString text) {6518b->initial = 0;6519b->touched = false;65206521for (int i = 0; i < initialConditionEditor.size(); i++) {6522DynamicEditor *ic = initialConditionEditor[i];6523if (ic->ID >= 0) {6524if (ic->nameEdit->text().trimmed() == text) {6525b->initial = ic;6526b->touched = true;6527break;6528}6529}6530}6531}65326533//-----------------------------------------------------------------------------6534void MainWindow::forceComboChanged(BodyPropertyEditor *b, QString text) {6535b->force = 0;6536b->touched = false;65376538for (int i = 0; i < bodyForceEditor.size(); i++) {6539DynamicEditor *bf = bodyForceEditor[i];6540if (bf->ID >= 0) {6541if (bf->nameEdit->text().trimmed() == text) {6542b->force = bf;6543b->touched = true;6544break;6545}6546}6547}6548}65496550//-----------------------------------------------------------------------------6551void MainWindow::equationComboChanged(BodyPropertyEditor *b, QString text) {6552b->equation = 0;6553b->touched = false;65546555for (int i = 0; i < equationEditor.size(); i++) {6556DynamicEditor *equ = equationEditor[i];6557if (equ->ID >= 0) {6558if (equ->nameEdit->text().trimmed() == text) {6559b->equation = equ;6560b->touched = true;6561break;6562}6563}6564}6565}65666567// Edit -> Definitions...6568//-----------------------------------------------------------------------------6569void MainWindow::editDefinitionsSlot() {6570if (elmerDefs == NULL)6571return;65726573edfEditor->show();6574}65756576//*****************************************************************************6577//6578// Solver MENU6579//6580//*****************************************************************************65816582// Solver -> Parallel settings6583//-----------------------------------------------------------------------------6584void MainWindow::parallelSettingsSlot() { parallel->show(); }65856586// Solver -> Run solver6587//-----------------------------------------------------------------------------6588void MainWindow::runsolverSlot() {6589if (!glWidget->hasMesh()) {6590logMessage("No mesh - unable to start solver");6591return;6592}65936594if (solver->state() == QProcess::Running) {6595logMessage("Solver is already running - returning");6596return;6597}65986599// Parallel solution:6600//====================6601Ui::parallelDialog ui = parallel->ui;6602bool parallelActive = ui.parallelActiveCheckBox->isChecked();6603bool partitioningActive = !ui.skipPartitioningCheckBox->isChecked();6604int nofProcessors = ui.nofProcessorsSpinBox->value();66056606if (parallelActive) {66076608// Set up log window:6609solverLogWindow->setWindowTitle(tr("Solver log"));6610solverLogWindow->getTextEdit()->clear();6611solverLogWindow->setFound(false);6612solverLogWindow->show();66136614if (!partitioningActive) {66156616// skip splitting:6617meshSplitterFinishedSlot(0);66186619} else {66206621// split mesh:6622if (meshSplitter->state() == QProcess::Running) {6623logMessage("Mesh partitioner is already running - aborted");6624return;6625}66266627if (saveDirName.isEmpty()) {6628logMessage("Please save the mesh before running the parallel solver - "6629"aborted");6630return;6631}66326633QString partitioningCommand = ui.divideLineEdit->text().trimmed();6634partitioningCommand.replace(QString("%msh"), saveDirName);6635partitioningCommand.replace(QString("%n"),6636QString::number(nofProcessors));66376638logMessage("Executing: " + partitioningCommand);66396640meshSplitter->start(partitioningCommand);66416642if (!meshSplitter->waitForStarted()) {6643logMessage("Unable to start ElmerGrid for mesh partitioning - aborted");6644return;6645}6646}66476648// the rest is done in meshSplitterFinishedSlot:6649return;6650}66516652// Scalar solution:6653//==================6654solver->start("ElmerSolver");6655killsolverAct->setEnabled(true);66566657if (!solver->waitForStarted()) {6658logMessage("Unable to start solver");6659return;6660}66616662solverLogWindow->setWindowTitle(tr("Solver log"));6663solverLogWindow->getTextEdit()->clear();6664solverLogWindow->setFound(false);6665solverLogWindow->show();66666667// convergence plot:6668#ifdef EG_QWT6669convergenceView->removeData();6670convergenceView->title = "Convergence history";6671#endif66726673logMessage("Solver started");66746675runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));66766677updateSysTrayIcon("ElmerSolver started",6678"Use Run->Kill solver to stop processing");6679}66806681// meshSplitter emits (int) when ready...6682//-----------------------------------------------------------------------------6683void MainWindow::meshSplitterFinishedSlot(int exitCode) {6684if (exitCode != 0) {6685solverLogWindow->getTextEdit()->append("MeshSplitter failed - aborting");6686logMessage("MeshSplitter failed - aborting");6687return;6688}66896690logMessage("MeshSplitter ready");66916692// Prepare for parallel solution:6693Ui::parallelDialog ui = parallel->ui;66946695int nofProcessors = ui.nofProcessorsSpinBox->value();66966697QString parallelExec = ui.parallelExecLineEdit->text().trimmed();6698#ifdef WIN326699parallelExec = "\"" + parallelExec + "\"";6700#endif67016702QString parallelArgs = ui.parallelArgsLineEdit->text().trimmed();6703parallelArgs.replace(QString("%n"), QString::number(nofProcessors));67046705QString parallelCmd = parallelExec + " " + parallelArgs;67066707logMessage("Executing: " + parallelCmd);67086709solver->start(parallelCmd);6710killsolverAct->setEnabled(true);67116712if (!solver->waitForStarted()) {6713solverLogWindow->getTextEdit()->append("Unable to start parallel solver");6714logMessage("Unable to start parallel solver");6715return;6716}67176718// Set up convergence plot:6719#ifdef EG_QWT6720convergenceView->removeData();6721convergenceView->title = "Convergence history";6722#endif6723logMessage("Parallel solver started");6724runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));67256726updateSysTrayIcon("ElmerSolver started",6727"Use Run->Kill solver to stop processing");6728}67296730// meshSplitter emits (void) when there is something to read from stdout:6731//-----------------------------------------------------------------------------6732void MainWindow::meshSplitterStdoutSlot() {6733QString qs = meshSplitter->readAllStandardOutput();67346735while (qs.at(qs.size() - 1).unicode() == '\n')6736qs.chop(1);67376738solverLogWindow->getTextEdit()->append(qs);6739}67406741// meshSplitter emits (void) when there is something to read from stderr:6742//-----------------------------------------------------------------------------6743void MainWindow::meshSplitterStderrSlot() {6744QString qs = meshSplitter->readAllStandardError();67456746while (qs.at(qs.size() - 1).unicode() == '\n')6747qs.chop(1);67486749solverLogWindow->getTextEdit()->append(qs);6750}67516752// meshUnifier emits (int) when ready...6753//-----------------------------------------------------------------------------6754void MainWindow::meshUnifierFinishedSlot(int exitCode) {6755QStringList args;67566757if (exitCode != 0) {6758solverLogWindow->getTextEdit()->append("MeshUnifier failed - aborting");6759logMessage("MeshUnifier failed - aborting");6760vtkPostMeshUnifierRunning = false;6761return;6762}67636764logMessage("MeshUnifier ready");67656766// Prepare for post processing parallel results:6767//----------------------------------------------6768QString postName = generalSetup->ui.postFileEdit->text().trimmed();67696770// VtkPost:6771//---------6772#ifdef EG_VTK6773if (vtkPostMeshUnifierRunning) {6774vtkPost->show();67756776vtkPost->ReadPostFile(postName);6777// if(!vtkPost->ReadPostFile(postName)) vtkPost->readEpFileSlot();67786779vtkPostMeshUnifierRunning = false;6780return;6781}6782#endif67836784QFile file(postName);6785if (!file.exists()) {6786solverLogWindow->getTextEdit()->append(6787"Elmerpost input file does not exist.");6788logMessage("Elmerpost input file does not exist.");6789vtkPostMeshUnifierRunning = false;6790return;6791}67926793file.open(QIODevice::ReadOnly);6794QTextStream header(&file);67956796int nn, ne, nt, nf;6797QString type, name, tstep;67986799header >> nn >> ne >> nf >> nt >> type >> name;6800if (type == "vector:")6801name = name + "_abs";68026803file.close();68046805QString simtype =6806generalSetup->ui.simulationTypeCombo->currentText().trimmed();6807if (simtype.toLower() == "transient") {6808tstep = QString::number(1);6809} else {6810tstep = QString::number(nt);6811}68126813args << "readfile " + postName + " " + tstep + " " + tstep +6814"1; "6815"set ColorScaleY -0.85; "6816"set ColorScaleEntries 4;"6817"set ColorScaleDecimals 2;"6818"set ColorScaleColor " +6819name +6820";"6821"set DisplayStyle(ColorScale) 1; "6822"set MeshStyle 1; "6823"set MeshColor " +6824name +6825";"6826"set DisplayStyle(ColorMesh) 1; "6827"translate -y 0.2; "6828"UpdateObject; ";68296830post->start("ElmerPost", args);6831killresultsAct->setEnabled(true);68326833if (!post->waitForStarted()) {6834logMessage("Unable to start post processor");6835return;6836}68376838resultsAct->setIcon(QIcon(":/icons/Post-red.png"));68396840logMessage("Post processor started");68416842updateSysTrayIcon("ElmerPost started",6843"Use Run->Kill ElmerPost to stop processing");6844}68456846// meshUnifier emits (void) when there is something to read from stdout:6847//-----------------------------------------------------------------------------6848void MainWindow::meshUnifierStdoutSlot() {6849QString qs = meshUnifier->readAllStandardOutput();68506851while (qs.at(qs.size() - 1).unicode() == '\n')6852qs.chop(1);68536854solverLogWindow->getTextEdit()->append(qs);6855}68566857// meshUnifier emits (void) when there is something to read from stderr:6858//-----------------------------------------------------------------------------6859void MainWindow::meshUnifierStderrSlot() {6860QString qs = meshUnifier->readAllStandardError();68616862while (qs.at(qs.size() - 1).unicode() == '\n')6863qs.chop(1);68646865solverLogWindow->getTextEdit()->append(qs);6866}68676868// solver process emits (void) when there is something to read from stdout:6869//-----------------------------------------------------------------------------6870void MainWindow::solverStdoutSlot() {6871static QString qs_save = "";68726873QString qs = qs_save + solver->readAllStandardOutput();68746875int n = qs.lastIndexOf('\n');68766877if ((n > 0) && (n < qs.size() - 1)) {6878qs_save = qs.mid(n + 1);6879qs = qs.mid(0, n);68806881} else if (n == 0) {6882if (qs.size() == 1) {6883qs_save = "";6884return;6885}6886qs_save = qs.mid(1);6887return;68886889} else if (n < 0) {6890qs_save = qs;6891return;68926893} else6894qs_save = "";68956896while (qs.at(qs.size() - 1).unicode() == '\n')6897qs.chop(1);68986899if (qs.isEmpty())6900return;69016902solverLogWindow->getTextEdit()->append(qs);69036904#ifdef EG_QWT6905if (!showConvergence) {69066907// hide convergence plot6908//----------------------6909convergenceView->hide();69106911} else {69126913// show convergence plot6914//----------------------6915if (!convergenceView->isVisible())6916convergenceView->show();6917}6918#endif69196920QStringList qsl = qs.split("\n");6921for (int i = 0; i < qsl.count(); i++) {6922QString tmp = qsl.at(i).trimmed();69236924if (tmp.contains("Time:")) {6925QStringList tmpSplitted = tmp.split(" ");6926int last = tmpSplitted.count() - 1;6927QString timeString = tmpSplitted.at(last);6928double timeDouble = timeString.toDouble();6929#ifdef EG_QWT6930convergenceView->title =6931"Convergence history (time=" + QString::number(timeDouble) + ")";6932#endif6933}69346935if (tmp.contains("ComputeChange")) { // && tmp.contains("NS")) {6936QString copyOfTmp = tmp;69376938// check solver name:6939QStringList tmpSplitted = tmp.split(":");6940int last = tmpSplitted.count() - 1;6941QString name = tmpSplitted.at(last).trimmed();69426943// parse rest of the line:6944double res1 = 0.0;6945double res2 = 0.0;6946int n = tmp.indexOf("NRM,RELC");6947tmp = tmp.mid(n);6948tmpSplitted = tmp.split("(");69496950if (tmpSplitted.count() >= 2) {6951QString tmp2 = tmpSplitted.at(1).trimmed();6952QStringList tmp2Splitted = tmp2.split(" ");6953QString qs1 = tmp2Splitted.at(0).trimmed();6954res1 = qs1.toDouble();6955int pos = 1;6956// while(tmp2Splitted.at(pos).trimmed() == "") {6957while (tmp2Splitted.at(pos).trimmed().isEmpty()) {6958pos++;6959if (pos > tmp2Splitted.count())6960break;6961}6962QString qs2 = tmp2Splitted.at(pos).trimmed();6963res2 = max(qs2.toDouble(), 1.0e-16);6964}69656966// res1 = norm, res2 = relative change6967#ifdef EG_QWT6968if (copyOfTmp.contains("NS"))6969convergenceView->appendData(res2, "NS/" + name);69706971if (copyOfTmp.contains("SS"))6972convergenceView->appendData(res2, "SS/" + name);6973#endif6974}6975}6976}69776978// solver process emits (void) when there is something to read from stderr:6979//-----------------------------------------------------------------------------6980void MainWindow::solverStderrSlot() {6981QString qs = solver->readAllStandardError();69826983while (qs.at(qs.size() - 1).unicode() == '\n')6984qs.chop(1);69856986solverLogWindow->getTextEdit()->append(qs);6987}69886989// solver process emits (int) when ready...6990//-----------------------------------------------------------------------------6991void MainWindow::solverFinishedSlot(int) {6992logMessage("Solver ready");6993runsolverAct->setIcon(QIcon(":/icons/Solver.png"));6994updateSysTrayIcon(6995"ElmerSolver has finished",6996"Use Run->Start ElmerPost, ElmerVTK or Paraview to view results");6997killsolverAct->setEnabled(false);6998}69997000// solver process emits (QProcess::ProcessError) when error occurs...7001//-----------------------------------------------------------------------------7002void MainWindow::solverErrorSlot(QProcess::ProcessError error) {7003logMessage("Solver emitted error signal: " + QString::number(error));7004solver->kill();7005runsolverAct->setIcon(QIcon(":/icons/Solver.png"));7006}70077008// solver process emits (QProcess::ProcessState) when state changed...7009//-----------------------------------------------------------------------------7010void MainWindow::solverStateChangedSlot(QProcess::ProcessState state) {7011logMessage("Solver emitted signal: QProcess::ProcessState: " +7012QString::number(state));7013// solver->kill();7014// runsolverAct->setIcon(QIcon(":/icons/Solver.png"));7015}70167017// Solver -> Kill solver7018//-----------------------------------------------------------------------------7019void MainWindow::killsolverSlot() {7020solver->kill();70217022logMessage("Solver killed");7023runsolverAct->setIcon(QIcon(":/icons/Solver.png"));7024}70257026// Solver -> Show convergence7027//-----------------------------------------------------------------------------7028void MainWindow::showConvergenceSlot() {7029showConvergence = !showConvergence;7030synchronizeMenuToState();7031}70327033// Solver -> Run post process7034//-----------------------------------------------------------------------------7035void MainWindow::resultsSlot() {7036QStringList args;70377038if (post->state() == QProcess::Running) {7039logMessage("Post processor is already running");7040return;7041}70427043// Parallel solution:7044//====================7045Ui::parallelDialog ui = parallel->ui;7046bool parallelActive = ui.parallelActiveCheckBox->isChecked();70477048if (parallelActive) {70497050// unify mesh:7051if (meshUnifier->state() == QProcess::Running) {7052logMessage("Mesh unifier is already running - aborted");7053return;7054}70557056if (saveDirName.isEmpty()) {7057logMessage("saveDirName is empty - unable to locate result files");7058return;7059}70607061// Set up log window:7062solverLogWindow->setWindowTitle(tr("ElmerGrid log"));7063solverLogWindow->getTextEdit()->clear();7064solverLogWindow->setFound(false);7065solverLogWindow->show();70667067QString postName = generalSetup->ui.postFileEdit->text().trimmed();7068QStringList postNameSplitted = postName.split(".");7069int nofProcessors = ui.nofProcessorsSpinBox->value();70707071QString unifyingCommand = ui.mergeLineEdit->text().trimmed();7072unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());7073unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));70747075logMessage("Executing: " + unifyingCommand);70767077meshUnifier->start(unifyingCommand);70787079if (!meshUnifier->waitForStarted()) {7080solverLogWindow->getTextEdit()->append(7081"Unable to start ElmerGrid for mesh unification - aborted");7082logMessage("Unable to start ElmerGrid for mesh unification - aborted");7083return;7084}70857086// The rest is done in meshUnifierFinishedSlot:7087return;7088}70897090// Scalar solution:7091//==================7092QString postName = generalSetup->ui.postFileEdit->text().trimmed();7093QFile file(postName);7094if (!file.exists()) {7095logMessage("Elmerpost input file does not exist.");7096/*Even though input file does not exist, launch ElmerPost*/7097post->start("ElmerPost");7098killresultsAct->setEnabled(true);7099if (!post->waitForStarted()) {7100logMessage("Unable to start ElmerPost");7101return;7102}7103resultsAct->setIcon(QIcon(":/icons/Post-red.png"));71047105logMessage("ElmerPost started");71067107updateSysTrayIcon("ElmerPost started",7108"Elmerpost input file does not exist.");7109return;7110}71117112file.open(QIODevice::ReadOnly);7113QTextStream header(&file);71147115int nn, ne, nt, nf;7116QString type, name, tstep;71177118header >> nn >> ne >> nf >> nt >> type >> name;7119if (type == "vector:")7120name = name + "_abs";71217122file.close();71237124QString simtype =7125generalSetup->ui.simulationTypeCombo->currentText().trimmed();7126if (simtype.toLower() == "transient") {7127tstep = QString::number(1);7128} else {7129tstep = QString::number(nt);7130}71317132args << "readfile " + postName + " " + tstep + " " + tstep +7133" 1; "7134"set ColorScaleY -0.85; "7135"set ColorScaleEntries 4;"7136"set ColorScaleDecimals 2;"7137"set ColorScaleColor " +7138name +7139";"7140"set DisplayStyle(ColorScale) 1; "7141"set MeshStyle 1; "7142"set MeshColor " +7143name +7144";"7145"set DisplayStyle(ColorMesh) 1; "7146"translate -y 0.2; "7147"UpdateObject; ";71487149post->start("ElmerPost", args);7150killresultsAct->setEnabled(true);71517152if (!post->waitForStarted()) {7153logMessage("Unable to start ElmerPost");7154return;7155}71567157resultsAct->setIcon(QIcon(":/icons/Post-red.png"));71587159logMessage("ElmerPost started");71607161updateSysTrayIcon("ElmerPost started",7162"Use Run->Kill ElmerPost to stop processing");7163}71647165// Signal (int) emitted by postProcess when finished:7166//-----------------------------------------------------------------------------7167void MainWindow::postProcessFinishedSlot(int) {7168logMessage("ElmerPost finished");7169resultsAct->setIcon(QIcon(":/icons/Post.png"));7170updateSysTrayIcon("ElmerPost has finished",7171"Use Run->Start ElmerPost to restart");7172killresultsAct->setEnabled(false);7173}71747175// Signal (int) emitted by paraview when finished:7176//-----------------------------------------------------------------------------7177void MainWindow::paraviewProcessFinishedSlot(int) {7178logMessage("ParaView finished");7179updateSysTrayIcon("ParaView has finished",7180"Use Run->Start ParaView to restart");7181}71827183// Solver -> Kill post process7184//-----------------------------------------------------------------------------7185void MainWindow::killresultsSlot() {7186post->kill();71877188logMessage("Post process killed");7189resultsAct->setIcon(QIcon(":/icons/Post.png"));7190}71917192// Solver -> Compile...7193//-----------------------------------------------------------------------------7194void MainWindow::compileSolverSlot() {7195QString defaultDirName = getDefaultDirName();71967197QString fileName = QFileDialog::getOpenFileName(7198this, tr("Open source file"), defaultDirName, tr("F90 files (*.f90)"));71997200if (!fileName.isEmpty()) {7201QFileInfo fi(fileName);7202QString absolutePath = fi.absolutePath();7203QDir::setCurrent(absolutePath);7204} else {7205logMessage("Unable to open file: file name is empty");7206return;7207}72087209if (compiler->state() == QProcess::Running) {7210logMessage("Compiler is currently running");7211return;7212}72137214QStringList args;7215#ifdef WIN327216args << "/C";7217args << "" + QString(qgetenv("ELMER_HOME")) + "\\bin\\elmerf90.bat";7218QString dllFileName;7219dllFileName = fileName.left(fileName.lastIndexOf(".")) + ".dll";7220args << "-o";7221args << dllFileName;7222#endif7223args << fileName;72247225#ifdef WIN327226compiler->start("cmd.exe", args);7227#else7228logMessage("Run->compiler is currently not implemented on this platform");7229return;7230#endif72317232if (!compiler->waitForStarted()) {7233logMessage("Unable to start compiler");7234return;7235}72367237solverLogWindow->setWindowTitle(tr("Compiler log"));7238solverLogWindow->getTextEdit()->clear();7239solverLogWindow->setFound(false);7240solverLogWindow->show();7241solverLogWindow->statusBar()->showMessage("Compiling...");72427243logMessage("Compiling...");7244}72457246// compiler process emits (void) when there is something to read from stdout:7247//-----------------------------------------------------------------------------7248void MainWindow::compilerStdoutSlot() {7249QString qs = compiler->readAllStandardOutput();72507251while (qs.at(qs.size() - 1).unicode() == '\n')7252qs.chop(1);72537254solverLogWindow->getTextEdit()->append(qs);7255}72567257// compiler process emits (void) when there is something to read from stderr:7258//-----------------------------------------------------------------------------7259void MainWindow::compilerStderrSlot() {7260QString qs = compiler->readAllStandardError();72617262while (qs.at(qs.size() - 1).unicode() == '\n')7263qs.chop(1);72647265solverLogWindow->getTextEdit()->append(qs);7266}72677268// Signal (int) emitted by compiler when finished:7269//-----------------------------------------------------------------------------7270void MainWindow::compilerFinishedSlot(int) {7271logMessage("Ready");7272solverLogWindow->statusBar()->showMessage("Ready");7273solverLogWindow->getTextEdit()->append("Ready");7274}72757276//*****************************************************************************7277//7278// Help MENU7279//7280//*****************************************************************************72817282// About dialog...7283//-----------------------------------------------------------------------------72847285void MainWindow::showaboutSlot() {72867287QMessageBox msgBox(this);7288msgBox.setTextFormat(Qt::RichText);7289QIcon icon(windowIcon());7290msgBox.setIconPixmap( icon.pixmap(32));7291msgBox.setWindowTitle(tr("Information about ElmerGUI"));7292msgBox.setText(7293tr("<P>ElmerGUI is a preprocessor for two and "7294"three dimensional modeling with Elmer "7295"finite element software. The program "7296"uses elmergrid, nglib, and optionally tetlib, "7297"as finite element mesh generators:<BR>"7298"<A HREF='https://www.csc.fi/elmer/'>https://www.csc.fi/elmer/</A><BR>"7299"<A HREF='https://ngsolve.org/'>https://ngsolve.org/</A><BR>"7300"<A HREF='https://www.berlios.de/software/tetgen/'>https://www.berlios.de/software/tetgen/</A></P>"7301"<P>ElmerGUI uses the Qt Cross-Platform "7302"Application Framework by The Qt Company:<BR>"7303"<A HREF='https://www.qt.io/'>https://www.qt.io/</A></P>"7304#ifdef EG_VTK7305"<P>This version of ElmerGUI contains a built-in "7306"postprocessor based on the Visualization Toolkit "7307"(VTK):<BR>"7308"<A HREF='https://vtk.org/'>https://vtk.org/</A></P>"7309#endif73107311#ifdef EG_PARAVIEW7312"<P>This version of ElmerGUI has been linked "7313"against ParaView visualization software.<BR>"7314"<A HREF='https://www.paraview.org/'>https://www.paraview.org</A></P>"7315#endif73167317#ifdef EG_OCC7318"<P>This version of ElmerGUI has been compiled with "7319"the OpenCascade solids modeling library:<BR>"7320"<A HREF='https://www.opencascade.org/'>https://www.opencascade.org/</P>"7321#endif73227323#ifdef EG_QWT7324"<P>This version of ElmerGUI is based in part on the work of the Qwt project.<BR>"7325"<A HREF='http://qwt.sf.net'>http://qwt.sf.net</A></P>"7326#endif73277328#ifdef MPICH27329"<P>The parallel solver of this package has been linked "7330"against the MPICH2 library v. 1.0.7 from Argonne "7331"national laboratory. In order to use the parallel "7332"solver, the MPICH2 runtime environment should be "7333"installed and configured on your system. For more "7334"details, see:<BR>"7335"<A HREF='https://www.mpich.org/'>https://www.mpich.org/</A></P>"7336#endif7337));7338msgBox.setInformativeText(7339tr("<P>The GPL-licensed source code of ElmerGUI is available "7340"from the git repository<BR>"7341"<A HREF='https://github.com/ElmerCSC/elmerfem/'>https://github.com/ElmerCSC/elmerfem/</A></P>"7342"<P>Written by Mikko Lyly, Saeki Takayuki, Juha Ruokolainen, "7343"Peter RÃ¥back and Sampo Sillanpaa 2008-2023</P>"7344"<P>Compiled on " __DATE__ "</P>"));7345msgBox.exec();7346}73477348void MainWindow::getStartedSlot() {7349QMessageBox msgBox(this);7350msgBox.setTextFormat(Qt::RichText);7351QIcon icon(windowIcon());7352msgBox.setIconPixmap( icon.pixmap(32));7353msgBox.setWindowTitle(tr("Get started with Elmer"));7354msgBox.setText(tr(7355"<P>"7356"GetStartedElmer.pdf contains instructions for Windows users, "7357"along with useful information for Linux users."7358"</P>"7359"<A HREF='//www.nic.funet.fi/index/elmer/doc/GetStartedElmer.pdf'>GetStartedElmer.pdf</A>"7360"<P>"7361"Download the full set of Elmer documentation from:"7362"</P>"7363"<A HREF='//www.nic.funet.fi/index/elmer/doc/'>//www.nic.funet.fi/index/elmer/doc/</A>"7364"<P>"7365"Be sure to review ElmerSolverManual.pdf and ElmerModelsManual.pdf<BR><BR>"7366"Youtube has videos about Elmer and Elmer Webinars"7367"</P>"7368"<A HREF='//www.youtube.com/@elmerfem'>Elmer Youtube Webinars and videos</A>"7369"<P>"7370"The Elmer users forum can be found at:"7371"</P>"7372"<A HREF='//http://www.elmerfem.org/forum/'>//http://www.elmerfem.org/forum/</A>"7373"<P>"7374"After having reviewed some of the above documents, and "7375"trying out a few of the tutorials, feel free to post questions on "7376"the forum. To help get answers in a timely fashion, be sure to "7377"post a minimal working example, including a sif file and "7378"geometry file. ElmerGUI project folders can be archived into zip "7379"files or gz files. The forum allows up to 3 attachments per "7380"post and up to 1 Megabyte per post.<BR><BR>"7381"Context Sensitive Help<BR><BR>"7382"Some of the ElmerGUI menu items have context sensitive help text. "7383"Look for the button labeled 'Whatis'. Clicking on the 'Whatis' button "7384"will turn the cursor into either a red 'not' symbol or a small "7385"question mark. Move the cursor around the window and if context "7386"help text is available for a data entry box, then the cursor will "7387"change from a red 'not' symbol into the small question mark. Single "7388"click the left mouse button inside the data entry box to display the help text.<BR>"7389"If the 'Whatis' button is not present in a menu window, then Qt also "7390"offers an alternate method, where after clicking into a data "7391"entry box, press 'shift F1'. If help text is available, then it will be displayed."7392"</P>"7393));7394msgBox.exec();7395}739673977398//*****************************************************************************7399//7400// Auxiliary non-menu items7401//7402//*****************************************************************************74037404// Log message...7405//-----------------------------------------------------------------------------7406void MainWindow::logMessage(QString message) {7407#if WITH_QT5 || WITH_QT67408cout << string(message.toLatin1()) << endl;7409#else7410cout << string(message.toAscii()) << endl;7411#endif7412statusBar()->showMessage(message, 0);7413cout.flush();7414}74157416// Synchronize menu to GL glwidget state variables:7417//-----------------------------------------------------------------------------7418void MainWindow::synchronizeMenuToState() {7419// glwidget state variables:7420if (glWidget->stateDrawSurfaceMesh)7421hidesurfacemeshAct->setChecked(true);7422else7423hidesurfacemeshAct->setChecked(false);74247425if (glWidget->stateDrawVolumeMesh)7426hidevolumemeshAct->setChecked(true);7427else7428hidevolumemeshAct->setChecked(false);74297430if (glWidget->stateDrawSharpEdges)7431hidesharpedgesAct->setChecked(true);7432else7433hidesharpedgesAct->setChecked(false);74347435if (glWidget->stateFlatShade) {7436flatShadeAct->setChecked(true);7437smoothShadeAct->setChecked(false);7438} else {7439flatShadeAct->setChecked(false);7440smoothShadeAct->setChecked(true);7441}74427443if (glWidget->stateOrtho) {7444orthoAct->setChecked(true);7445perspectiveAct->setChecked(false);7446} else {7447orthoAct->setChecked(false);7448perspectiveAct->setChecked(true);7449}74507451if (glWidget->stateDrawSurfaceNumbers)7452showSurfaceNumbersAct->setChecked(true);7453else7454showSurfaceNumbersAct->setChecked(false);74557456if (glWidget->stateDrawEdgeNumbers)7457showEdgeNumbersAct->setChecked(true);7458else7459showEdgeNumbersAct->setChecked(false);74607461if (glWidget->stateDrawNodeNumbers)7462showNodeNumbersAct->setChecked(true);7463else7464showNodeNumbersAct->setChecked(false);74657466if (glWidget->stateDrawBoundaryIndex)7467showBoundaryIndexAct->setChecked(true);7468else7469showBoundaryIndexAct->setChecked(false);74707471if (glWidget->stateDrawBodyIndex)7472showBodyIndexAct->setChecked(true);7473else7474showBodyIndexAct->setChecked(false);74757476if (glWidget->stateDrawCoordinates)7477viewCoordinatesAct->setChecked(true);7478else7479viewCoordinatesAct->setChecked(false);74807481if (bodyEditActive)7482bodyEditAct->setChecked(true);7483else7484bodyEditAct->setChecked(false);74857486if (bcEditActive)7487bcEditAct->setChecked(true);7488else7489bcEditAct->setChecked(false);74907491if (showConvergence)7492showConvergenceAct->setChecked(true);7493else7494showConvergenceAct->setChecked(false);74957496if (glWidget->stateBcColors)7497showBoundaryColorAct->setChecked(true);7498else7499showBoundaryColorAct->setChecked(false);75007501if (glWidget->stateBodyColors)7502showBodyColorAct->setChecked(true);7503else7504showBodyColorAct->setChecked(false);75057506if (isFullScreen())7507viewFullScreenAct->setChecked(true);7508else7509viewFullScreenAct->setChecked(false);7510}75117512// Load definitions...7513//-----------------------------------------------------------------------------7514void MainWindow::loadDefinitions() {7515// Determine edf-file location and name:7516//--------------------------------------7517QString elmerGuiHome;75187519#ifdef __APPLE__DONTGO_HERE_TODO7520QString generalDefs = this->homePath + "/edf/edf.xml";7521#else7522QString generalDefs =7523QCoreApplication::applicationDirPath() +7524"/../share/ElmerGUI/edf/edf.xml"; // @TODO: fix path to share/ElmerGUI/edf75257526elmerGuiHome = QString(getenv("ELMERGUI_HOME"));75277528if (!elmerGuiHome.isEmpty())7529generalDefs = elmerGuiHome + "/edf/edf.xml";75307531// ML 5. August 20107532generalDefs.replace('\\', '/');7533#endif75347535// Load general definitions file:7536//--------------------------------7537#if WITH_QT5 || WITH_QT67538cout << "Load " << string(generalDefs.toLatin1()) << "... ";7539#else7540cout << "Load " << string(generalDefs.toAscii()) << "... ";7541#endif7542cout.flush();7543updateSplash("Loading general definitions...");75447545QFile file(generalDefs);75467547QString errStr;7548int errRow;7549int errCol;75507551if (!file.exists()) {75527553elmerDefs = NULL;7554QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,7555tr("Definitions file does not exist"));7556return;75577558} else {75597560if (!elmerDefs->setContent(&file, true, &errStr, &errRow, &errCol)) {7561QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,7562tr("Parse error at line %1, col %2:\n%3")7563.arg(errRow)7564.arg(errCol)7565.arg(errStr));7566file.close();7567return;75687569} else {75707571if (elmerDefs->documentElement().tagName() != "edf") {7572QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,7573tr("This is not an edf file"));7574delete elmerDefs;7575file.close();7576return;7577}7578}7579}75807581edfEditor->setupEditor(elmerDefs);7582file.close();75837584cout << "done" << endl;7585cout.flush();75867587// load additional definitions:7588//-----------------------------7589#ifdef __APPLE__DONTGO_HERE_TODO7590QDirIterator iterator(homePath + "/edf", QDirIterator::Subdirectories);7591#else7592QString additionalEdfs =7593QCoreApplication::applicationDirPath() +7594"/../share/ElmerGUI/edf"; // @TODO: fix path to share/ElmerGUI/edf75957596if (!elmerGuiHome.isEmpty())7597additionalEdfs = elmerGuiHome + "/edf";75987599QDirIterator iterator(additionalEdfs, QDirIterator::Subdirectories);7600#endif76017602while (iterator.hasNext()) {7603QString fileName = iterator.next();76047605// ML 5. August 20107606fileName.replace('\\', '/');76077608QFileInfo fileInfo(fileName);7609QString fileSuffix = fileInfo.suffix();76107611// The names "egini" and "egmaterials" are reserved, skip them:7612if (fileInfo.completeBaseName() == "egini")7613continue;76147615if (fileInfo.completeBaseName() == "egmaterials")7616continue;76177618if ((fileSuffix == "xml") && (fileName != generalDefs)) {76197620#if WITH_QT5 || WITH_QT67621cout << "Load " << string(fileName.toLatin1()) << "... ";7622#else7623cout << "Load " << string(fileName.toAscii()) << "... ";7624#endif7625cout.flush();76267627updateSplash("Loading " + fileName + "...");76287629file.setFileName(fileName);76307631QDomDocument tmpDoc;7632tmpDoc.clear();76337634if (!tmpDoc.setContent(&file, true, &errStr, &errRow, &errCol)) {7635QMessageBox::information(window(), tr("Edf loader: ") + fileName,7636tr("Parse error at line %1, col %2:\n%3")7637.arg(errRow)7638.arg(errCol)7639.arg(errStr));7640file.close();7641return;76427643} else {76447645if (tmpDoc.documentElement().tagName() != "edf") {7646QMessageBox::information(window(), tr("Edf loader: ") + fileName,7647tr("This is not an edf file"));7648file.close();7649return;7650}7651}76527653// add new elements to the document7654QDomElement root = elmerDefs->documentElement();7655QDomElement tmpRoot = tmpDoc.documentElement();7656QDomElement element = tmpRoot.firstChildElement();76577658while (!element.isNull()) {7659root.appendChild(element);7660element = tmpRoot.firstChildElement();7661}76627663edfEditor->setupEditor(elmerDefs);76647665file.close();76667667cout << "done" << endl;7668cout.flush();7669}7670}76717672// Load qss:7673//-----------7674QString qssFileName = QCoreApplication::applicationDirPath() +7675"/elmergui.qss"; // @TODO: fix path to share/ElmerGUI76767677#ifdef __APPLE__7678qssFileName = homePath + "/elmergui.qss";7679#else7680if (!elmerGuiHome.isEmpty())7681qssFileName = elmerGuiHome + "/elmergui.qss";7682#endif76837684QFile qssFile(qssFileName);76857686if (qssFile.exists()) {7687cout << "Loading QSS style sheet... ";7688qssFile.open(QFile::ReadOnly);7689QString styleSheet = QLatin1String(qssFile.readAll());7690qssFile.close();7691qApp->setStyleSheet(styleSheet);7692cout << "done" << endl;7693}7694}76957696// Setup splash...7697//-----------------------------------------------------------------------------7698void MainWindow::setupSplash() {7699QStringList args = QCoreApplication::arguments();77007701if (args.contains("-nogui"))7702return;77037704if (egIni->isSet("splashscreen")) {7705pixmap.load(":/images/splash.png");7706splash.setPixmap(pixmap);7707splash.show();7708qApp->processEvents();7709}7710}77117712// Update splash...7713//-----------------------------------------------------------------------------7714void MainWindow::updateSplash(QString text) {7715QStringList args = QCoreApplication::arguments();77167717if (args.contains("-nogui"))7718return;77197720if (!egIni->isSet("splashscreen"))7721return;77227723if (splash.isVisible()) {7724splash.showMessage(text, Qt::AlignBottom);7725qApp->processEvents();7726}7727}77287729// Finalize splash...7730//-----------------------------------------------------------------------------7731void MainWindow::finalizeSplash() {7732if (!egIni->isSet("splashscreen"))7733return;77347735if (splash.isVisible())7736splash.finish(this);7737}77387739// Setup system tray icon...7740//-----------------------------------------------------------------------------7741void MainWindow::setupSysTrayIcon() {7742sysTrayIcon = NULL;77437744QStringList args = QCoreApplication::arguments();77457746if (args.contains("-nogui"))7747return;77487749if (!egIni->isSet("systrayicon"))7750return;77517752if (QSystemTrayIcon::isSystemTrayAvailable()) {7753sysTrayIcon = new QSystemTrayIcon(this);7754sysTrayIcon->setIcon(QIcon(":/icons/Mesh3D.png"));7755sysTrayIcon->setVisible(true);7756sysTrayIcon->setContextMenu(sysTrayMenu);7757}7758}77597760// Update system tray icon...7761//-----------------------------------------------------------------------------7762void MainWindow::updateSysTrayIcon(QString label, QString msg) {7763int duration = 3000;77647765QStringList args = QCoreApplication::arguments();77667767if (args.contains("-nogui"))7768return;77697770if (!sysTrayIcon)7771return;77727773if (!egIni->isSet("systraymessages"))7774return;77757776if (isFullScreen())7777return;77787779if (egIni->isPresent("systraymsgduration"))7780duration = egIni->value("systraymsgduration").toInt();77817782if (sysTrayIcon->supportsMessages())7783sysTrayIcon->showMessage(label, msg, QSystemTrayIcon::Information,7784duration);7785}77867787// Finalize system tray icon...7788//-----------------------------------------------------------------------------7789void MainWindow::finalizeSysTrayIcon() {}77907791// Get default open/save directory7792//-----------------------------------------------------------------------------7793QString MainWindow::getDefaultDirName() {7794QString defaultDirName = "";77957796#ifdef WIN327797defaultDirName = egIni->value("win32defaultdir");7798#else7799#ifdef __APPLE__7800defaultDirName = egIni->value("macxdefaultdir");7801#else7802defaultDirName = egIni->value("unixdefaultdir");7803#endif7804#endif78057806if (!saveDirName.isEmpty())7807defaultDirName = saveDirName;78087809return defaultDirName;7810}78117812// Load settings7813//-----------------------------------------------------------------------------7814void MainWindow::loadSettings() {7815restoreGeometry(settings_value("mainWindow/geometry").toByteArray());7816sifWindow->restoreGeometry(7817settings_value("sifWindow/geometry").toByteArray());7818solverLogWindow->restoreGeometry(7819settings_value("solverLogWindow/geometry").toByteArray());78207821#ifdef EG_QWT7822convergenceView->restoreGeometry(7823settings_value("convergenceView/geometry").toByteArray());7824#endif78257826#ifdef EG_OCC7827cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());7828#endif78297830#ifdef EG_VTK7831vtkPost->restoreGeometry(settings_value("vtkPost/geometry").toByteArray());7832#endif78337834int n = settings_value("recentProject/n", 0).toInt();7835QString key = "recentProject/";7836char num[] = "0123456789";7837QString path;7838for (int i = n - 1; i >= 0; i--) {7839path = settings_value(key + num[i], "$").toString();7840if (path != "$")7841addRecentProject(path, false);7842}78437844if (settings_value("objectBrowser/show", true).toBool()) {7845objectBrowser = new ObjectBrowser(this);7846showObjectBrowserAct->setChecked(true);7847} else {7848objectBrowser = NULL;7849}78507851switch (settings_value("postProcessor/i", 0).toInt()){7852case 0: selectElmerPostSlot(); break;7853case 1: selectVtkPostSlot(); break;7854case 2: selectParaViewSlot(); break;7855}78567857saveDirName = settings_value("defaultDir/project", "").toString();7858// Color settings7859glWidget->backgroundColor = settings_value("color/background", glWidget->backgroundColor).value<QColor>();7860glWidget->surfaceColor = settings_value("color/surface", glWidget->surfaceColor).value<QColor>();7861glWidget->edgeColor = settings_value("color/edge", glWidget->edgeColor).value<QColor>();7862glWidget->surfaceMeshColor = settings_value("color/surfaceMesh", glWidget->surfaceMeshColor).value<QColor>();7863glWidget->sharpEdgeColor = settings_value("color/sharpEdge", glWidget->sharpEdgeColor).value<QColor>();7864glWidget->selectionColor = settings_value("color/selection", glWidget->selectionColor).value<QColor>();78657866synchronizeMenuToState();7867}78687869// Save settings7870//-----------------------------------------------------------------------------7871void MainWindow::saveSettings() {7872settings_setValue("mainWindow/geometry", saveGeometry());7873settings_setValue("sifWindow/geometry", sifWindow->saveGeometry());7874settings_setValue("solverLogWindow/geometry",7875solverLogWindow->saveGeometry());78767877#ifdef EG_QWT7878settings_setValue("convergenceView/geometry",7879convergenceView->saveGeometry());7880#endif78817882#ifdef EG_OCC7883settings_setValue("cadView/geometry", cadView->saveGeometry());7884#endif78857886#ifdef EG_VTK7887settings_setValue("vtkPost/geometry", vtkPost->saveGeometry());7888#endif78897890if (showObjectBrowserAct->isChecked() && objectBrowser != NULL) {7891settings_setValue("objectBrowser/show", true);7892} else {7893settings_setValue("objectBrowser/show", false);7894}78957896if(selectElmerPostAct->isChecked()){7897settings_setValue("postProcessor/i", 0);7898}else if(selectVtkPostAct->isChecked()){7899settings_setValue("postProcessor/i", 1);7900}else if(selectParaViewAct->isChecked()){7901settings_setValue("postProcessor/i", 2);7902}79037904settings_setValue("defaultDir/project", saveDirName);79057906// Commented out as restoring defaultEdfDir is not so useful7907// settings_setValue("defaultDir/edfEditor", edfEditor->defaultEdfDir());79087909// Color settings7910settings_setValue("color/background", glWidget->backgroundColor);7911settings_setValue("color/surface", glWidget->surfaceColor);7912settings_setValue("color/edge", glWidget->edgeColor);7913settings_setValue("color/surfaceMesh", glWidget->surfaceMeshColor);7914settings_setValue("color/sharpEdge", glWidget->sharpEdgeColor);7915settings_setValue("color/selection", glWidget->selectionColor);7916}79177918void MainWindow::addRecentProject(QString dir, bool bSaveToIni) {7919if (recentProject.indexOf(dir) != -1) {7920recentProject.removeAt(recentProject.indexOf(dir));7921}7922recentProject.prepend(dir);79237924int i = 0;79257926recentProjectsMenu->removeAction(recentProject0Act);7927recentProjectsMenu->removeAction(recentProject1Act);7928recentProjectsMenu->removeAction(recentProject2Act);7929recentProjectsMenu->removeAction(recentProject3Act);7930recentProjectsMenu->removeAction(recentProject4Act);7931recentProjectsMenu->removeAction(recentProject5Act);7932recentProjectsMenu->removeAction(recentProject6Act);7933recentProjectsMenu->removeAction(recentProject7Act);7934recentProjectsMenu->removeAction(recentProject8Act);7935recentProjectsMenu->removeAction(recentProject9Act);7936recentProjectsMenu->clear(); // just in case79377938if (i < 10 && i < recentProject.size()) {7939recentProject0Act->setText(recentProject.at(i));7940recentProjectsMenu->addAction(recentProject0Act);7941}7942i++;7943if (i < 10 && i < recentProject.size()) {7944recentProject1Act->setText(recentProject.at(i));7945recentProjectsMenu->addAction(recentProject1Act);7946}7947i++;7948if (i < 10 && i < recentProject.size()) {7949recentProject2Act->setText(recentProject.at(i));7950recentProjectsMenu->addAction(recentProject2Act);7951}7952i++;7953if (i < 10 && i < recentProject.size()) {7954recentProject3Act->setText(recentProject.at(i));7955recentProjectsMenu->addAction(recentProject3Act);7956}7957i++;7958if (i < 10 && i < recentProject.size()) {7959recentProject4Act->setText(recentProject.at(i));7960recentProjectsMenu->addAction(recentProject4Act);7961}7962i++;7963if (i < 10 && i < recentProject.size()) {7964recentProject5Act->setText(recentProject.at(i));7965recentProjectsMenu->addAction(recentProject5Act);7966}7967i++;7968if (i < 10 && i < recentProject.size()) {7969recentProject6Act->setText(recentProject.at(i));7970recentProjectsMenu->addAction(recentProject6Act);7971}7972i++;7973if (i < 10 && i < recentProject.size()) {7974recentProject7Act->setText(recentProject.at(i));7975recentProjectsMenu->addAction(recentProject7Act);7976}7977i++;7978if (i < 10 && i < recentProject.size()) {7979recentProject8Act->setText(recentProject.at(i));7980recentProjectsMenu->addAction(recentProject8Act);7981}7982i++;7983if (i < 10 && i < recentProject.size()) {7984recentProject9Act->setText(recentProject.at(i));7985recentProjectsMenu->addAction(recentProject9Act);7986}7987recentProjectsMenu->setEnabled(recentProject.size() > 0);79887989if (bSaveToIni) {7990int n = recentProject.size();7991if (n > 10)7992n = 10;7993settings_setValue("recentProject/n", n);7994QString key = "recentProject/";7995char num[] = "0123456789";7996for (int i = 0; i < n; i++) {7997settings_setValue(key + num[i], recentProject.at(i));7998}7999}8000}80018002void MainWindow::loadRecentProject0Slot() { loadProject(recentProject.at(0)); }80038004void MainWindow::loadRecentProject1Slot() { loadProject(recentProject.at(1)); }80058006void MainWindow::loadRecentProject2Slot() { loadProject(recentProject.at(2)); }80078008void MainWindow::loadRecentProject3Slot() { loadProject(recentProject.at(3)); }80098010void MainWindow::loadRecentProject4Slot() { loadProject(recentProject.at(4)); }80118012void MainWindow::loadRecentProject5Slot() { loadProject(recentProject.at(5)); }80138014void MainWindow::loadRecentProject6Slot() { loadProject(recentProject.at(6)); }80158016void MainWindow::loadRecentProject7Slot() { loadProject(recentProject.at(7)); }80178018void MainWindow::loadRecentProject8Slot() { loadProject(recentProject.at(8)); }80198020void MainWindow::loadRecentProject9Slot() { loadProject(recentProject.at(9)); }80218022bool MainWindow::loadExtraSolver(QString solverName) {80238024#ifdef __APPLE__DONTGO_HERE_TODO8025QString extraDirpath = this->homePath + "/edf-extra";8026#else8027QString extraDirPath =8028QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";80298030QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));80318032if (!elmerGuiHome.isEmpty())8033extraDirPath = elmerGuiHome + "/edf-extra";80348035extraDirPath.replace('\\', '/');8036#endif80378038QString name;8039QDir extraDir(extraDirPath);8040QStringList nameFilters;8041nameFilters << "*.xml";8042QString message;8043QStringList fileNameList =8044extraDir.entryList(nameFilters, QDir::Files | QDir::Readable);8045for (int i = 0; i < fileNameList.size(); i++) {8046QFile file(extraDirPath + "/" + fileNameList.at(i));8047if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {8048QTextStream in(&file);8049while (!in.atEnd()) {8050QString line = in.readLine();8051if (line.indexOf("<PDE Name=") > 0) {8052line = in.readLine();8053while (line.indexOf("<Name>") == -1 && !in.atEnd())8054line = in.readLine();8055int i0 = line.indexOf("<Name>");8056if (i0 >= 0) {8057int i1 = line.indexOf("</Name>", i0 + 6);8058if (i1 > 0) {8059name = line.mid(i0 + 6, i1 - i0 - 6).trimmed();8060if (solverName.trimmed() == name) {8061file.close();80628063message =8064"Load " + extraDirPath + "/" + fileNameList.at(i) + "... ";8065#if WITH_QT5 || WITH_QT68066cout << string(message.toLatin1());8067cout.flush();8068#else8069cout << string(message.toAscii());8070cout.flush();8071#endif80728073edfEditor->appendFrom(extraDirPath + "/" + fileNameList.at(i));80748075cout << "done" << endl;80768077return true;8078}8079}8080}8081}8082}80838084file.close();8085} else {8086logMessage(" failed to open " + fileNameList.at(i));8087return false;8088}8089}8090logMessage(" Extra solver " + solverName + " not found");8091return false;8092}80938094void MainWindow::checkAndLoadExtraSolvers(QFile *file) {8095QStringList loadedSolverName;8096QStringList unloadedSolverName;8097QDomElement root = elmerDefs->documentElement();8098QDomElement elem = root.firstChildElement("PDE");8099while (!elem.isNull()) {8100QDomElement pdeName = elem.firstChildElement("Name");8101loadedSolverName.append(pdeName.text().trimmed());8102elem = elem.nextSiblingElement();8103}81048105QString name;8106if (file->open(QIODevice::ReadOnly | QIODevice::Text)) {8107QTextStream in(file);8108while (!in.atEnd()) {8109QString line = in.readLine();8110int i0, i1;8111i0 = line.indexOf("<key>/");8112if (i0 >= 0) {8113i1 = line.indexOf("/", i0 + 7);8114if (i1 > 0) {8115name = line.mid(i0 + 6, i1 - i0 - 6);8116if (!loadedSolverName.contains(name)) {8117loadExtraSolver(name);81188119// update list (to avoid doubled loading - one solver file can8120// generate multiple tabs)8121loadedSolverName.clear();8122QDomElement root = elmerDefs->documentElement();8123QDomElement elem = root.firstChildElement("PDE");8124while (!elem.isNull()) {8125QDomElement pdeName = elem.firstChildElement("Name");8126loadedSolverName.append(pdeName.text().trimmed());8127elem = elem.nextSiblingElement();8128}8129}8130}8131}8132}8133} else {8134logMessage(" failed to open project file" + name);8135}81368137/*8138QString name;8139if (file->open(QIODevice::ReadOnly | QIODevice::Text)){8140QTextStream in(file);8141while (!in.atEnd()) {8142QString line = in.readLine();8143int i0, i1;8144i0=line.indexOf("<key>/");8145if( i0 >= 0){8146i1 = line.indexOf("/", i0+7);8147if(i1 > 0){8148name = line.mid(i0+6, i1-i0-6);8149if(!loadedSolverName.contains(name) &&8150!unloadedSolverName.contains(name) ){ unloadedSolverName.append(name);8151loadExtraSolver(name);8152}8153}8154}8155}8156}else{8157logMessage(" failed to open project file" + name);8158}8159*/8160}81618162QVariant MainWindow::settings_value(const QString &key,8163const QVariant &defaultValue) {8164QString oldElmerGuiIniFilePath =8165QCoreApplication::applicationDirPath() + "/ElmerGUI.ini";8166QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";8167if (!QFile::exists(elmerGuiIniFilePath) &&8168QFile::exists(oldElmerGuiIniFilePath)) {8169elmerGuiIniFilePath = oldElmerGuiIniFilePath;8170}8171QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);8172return settings.value(key, defaultValue);8173}81748175void MainWindow::settings_setValue(const QString &key, const QVariant &value) {8176QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";8177QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);8178settings.setValue(key, value);8179}81808181void MainWindow::saveAndRun(bool generateSif) {81828183//------- Save project -------//8184if (!glWidget->hasMesh()) {8185logMessage("Unable to save project: no mesh");8186return;8187}81888189QString projectDirName = currentProjectDirName;8190if (projectDirName.isEmpty()) {8191QString defaultDirName = getDefaultDirName();8192projectDirName = QFileDialog::getExistingDirectory(8193this, tr("Open directory to save project"), defaultDirName);81948195if (!projectDirName.isEmpty()) {8196logMessage("Project directory " + projectDirName);8197} else {8198logMessage("Unable to save project: directory undefined");8199return;8200}8201}82028203if(generateSif){ generateSifSlot();}82048205bool ret = saveProject(projectDirName);82068207//------- Run solver -------//8208if (ret) {8209runsolverSlot();8210}8211}82128213void MainWindow::generateAndSaveAndRunSlot() { saveAndRun(true); }82148215void MainWindow::closeEvent(QCloseEvent *event) {8216saveSettings();8217delete objectBrowser;8218}82198220void MainWindow::showObjectBrowserSlot() {8221if (showObjectBrowserAct->isChecked()) {8222delete objectBrowser; // just in case8223objectBrowser = new ObjectBrowser(this);8224} else {8225delete objectBrowser;8226objectBrowser = NULL;8227}8228}82298230void MainWindow::selectElmerPostSlot(){8231runPostProcessorAct->setText(tr("Start ElmerPost"));8232runPostProcessorAct->setIcon(QIcon(":/icons/Post.png"));8233runPostProcessorAct->setStatusTip(tr("Run ElmerPost for visualization"));8234runPostProcessorAct->disconnect();8235connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));8236selectElmerPostAct->setChecked(true);8237selectVtkPostAct->setChecked(false);8238selectParaViewAct->setChecked(false);8239}8240void MainWindow::selectVtkPostSlot(){8241runPostProcessorAct->setText(tr("Start ElmerVTK"));8242runPostProcessorAct->setIcon(QIcon(":/icons/Mesh3D.png"));8243runPostProcessorAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));8244runPostProcessorAct->disconnect();8245connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));8246selectElmerPostAct->setChecked(false);8247selectVtkPostAct->setChecked(true);8248selectParaViewAct->setChecked(false);8249}8250void MainWindow::selectParaViewSlot(){8251runPostProcessorAct->setText(tr("Start ParaView"));8252runPostProcessorAct->setIcon(QIcon(":/icons/Paraview.png"));8253runPostProcessorAct->setStatusTip(tr("Invokes ParaView for visualization"));8254runPostProcessorAct->disconnect();8255connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));8256selectElmerPostAct->setChecked(false);8257selectVtkPostAct->setChecked(false);8258selectParaViewAct->setChecked(true);8259}82608261void MainWindow::rebuildGLLists(){8262/*8263This function is assumed to be called from ObjectBrowser to avoid a problem of 3D surface8264mesh not shown correctly when project loading (typically, TemperatureGeneric sample)8265*/8266glWidget->rebuildLists();8267}826882698270