1 /*****************************************************************************
2 * *
3 * Elmer, A Finite Element Software for Multiphysical Problems *
4 * *
5 * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License *
9 * as published by the Free Software Foundation; either version 2 *
10 * of the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program (in file fem/GPL-2); if not, write to the *
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
20 * Boston, MA 02110-1301, USA. *
21 * *
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * *
26 * ElmerGUI mainwindow *
27 * *
28 *****************************************************************************
29 * *
30 * Authors: Mikko Lyly, Juha Ruokolainen and Peter R�back *
31 * Email: Juha.Ruokolainen@csc.fi *
32 * Web: http://www.csc.fi/elmer *
33 * Address: CSC - IT Center for Science Ltd. *
34 * Keilaranta 14 *
35 * 02101 Espoo, Finland *
36 * *
37 * Original Date: 15 Mar 2008 *
38 * *
39 *****************************************************************************/
40
41 #include <QAction>
42 #include <QContextMenuEvent>
43 #include <QDir>
44 #include <QFile>
45 #include <QFileInfo>
46 #include <QFont>
47 #include <QProgressBar>
48 #include <QStringList>
49 #include <QSystemTrayIcon>
50 #include <QTimeLine>
51 #include <QtGui>
52
53 #include <fstream>
54 #include <iostream>
55
56 #include <QDebug>
57
58 #include "mainwindow.h"
59 #include "newprojectdialog.h"
60
61 #ifdef EG_VTK
62 #include "vtkpost/vtkpost.h"
63 VtkPost *vtkp;
64 #endif
65
66 #ifdef __APPLE__
67 #include <mach-o/dyld.h>
68 // #ifndef EG_OCC
69 // #define EG_OCC
70 // #endif
71 #endif
72
73 using namespace std;
74
75 #undef MPICH2
76
77 // Construct main window...
78 //-----------------------------------------------------------------------------
MainWindow()79 MainWindow::MainWindow() {
80 #ifdef __APPLE__
81 // find "Home directory":
82 char executablePath[MAXPATHLENGTH] = {0};
83 uint32_t len = MAXPATHLENGTH;
84 this->homePath = "";
85 if (!_NSGetExecutablePath((char *)executablePath, &len)) {
86 // remove executable name from path:
87 *(strrchr(executablePath, '/')) = '\0';
88 // remove last path component name from path:
89 *(strrchr(executablePath, '/')) = '\0';
90 this->homePath = executablePath;
91 }
92 #else
93 homePath = "";
94 #endif
95
96 // load ini file:
97 egIni = new EgIni(this);
98
99 // splash screen:
100 setupSplash();
101
102 // load splash screen:
103 updateSplash("Loading images...");
104
105 // load tetlib:
106 updateSplash("Loading tetlib...");
107 tetlibAPI = new TetlibAPI;
108 tetlibPresent = tetlibAPI->loadTetlib();
109 this->in = tetlibAPI->in;
110 this->out = tetlibAPI->out;
111
112 // load nglib:
113 updateSplash("Loading nglib...");
114 nglibAPI = new NglibAPI;
115 nglibPresent = true;
116
117 // construct elmergrid:
118 updateSplash("Constructing elmergrid...");
119 elmergridAPI = new ElmergridAPI;
120
121 // set dynamic limits:
122 limit = new Limit;
123 setDynamicLimits();
124
125 // widgets and utilities:
126 updateSplash("ElmerGUI loading...");
127 glWidget = new GLWidget(this);
128 #ifdef WIN32
129 glWidget->stateDrawSharpEdges = false;
130 #endif
131 setCentralWidget(glWidget);
132 sifWindow = new SifWindow(this);
133 meshControl = new MeshControl(this);
134 boundaryDivide = new BoundaryDivide(this);
135 meshingThread = new MeshingThread(this);
136 meshutils = new Meshutils;
137 solverLogWindow = new SolverLogWindow(this);
138 solver = new QProcess(this);
139 post = new QProcess(this);
140 paraview = new QProcess(this);
141 compiler = new QProcess(this);
142 meshSplitter = new QProcess(this);
143 meshUnifier = new QProcess(this);
144 generalSetup = new GeneralSetup(this);
145 summaryEditor = new SummaryEditor(this);
146 sifGenerator = new SifGenerator;
147 sifGenerator->setLimit(this->limit);
148 elmerDefs = new QDomDocument;
149 edfEditor = new EdfEditor;
150 glControl = new GLcontrol(this);
151 parallel = new Parallel(this);
152 checkMpi = new CheckMpi;
153 materialLibrary = new MaterialLibrary(this);
154 twodView = new TwodView;
155 grabTimeLine = new QTimeLine(1000, this);
156
157 #ifdef EG_QWT
158 convergenceView = new ConvergenceView(limit, this);
159 #endif
160
161 #ifdef EG_VTK
162 vtkp = vtkPost = new VtkPost(this);
163 vtkPostMeshUnifierRunning = false;
164 #endif
165
166 #ifdef EG_OCC
167 cadView = new CadView();
168 if (egIni->isPresent("deflection"))
169 cadView->setDeflection(egIni->value("deflection").toDouble());
170 #endif
171
172 createActions();
173 createMenus();
174 createToolBars();
175 createStatusBar();
176 runPostProcessorAct->setMenu(selectPostMenu);
177
178 // Always, when an action from the menu bar has been selected, synchronize
179 // menu to state:
180 connect(menuBar(), SIGNAL(triggered(QAction *)), this,
181 SLOT(menuBarTriggeredSlot(QAction *)));
182 connect(contextMenu, SIGNAL(triggered(QAction *)), this,
183 SLOT(menuBarTriggeredSlot(QAction *)));
184
185 // glWidget emits (list_t*) when a boundary is selected by double clicking:
186 connect(glWidget, SIGNAL(signalBoundarySelected(list_t *)), this,
187 SLOT(boundarySelectedSlot(list_t *)));
188
189 // glWidget emits (void) when esc has been pressed:
190 connect(glWidget, SIGNAL(escPressed()), this, SLOT(viewNormalModeSlot()));
191
192 // meshingThread emits (void) when the mesh generation has finished or
193 // terminated:
194 connect(meshingThread, SIGNAL(started()), this, SLOT(meshingStartedSlot()));
195 connect(meshingThread, SIGNAL(finished()), this, SLOT(meshingFinishedSlot()));
196 connect(meshingThread, SIGNAL(terminated()), this,
197 SLOT(meshingTerminatedSlot()));
198
199 // boundaryDivide emits (double) when "divide button" has been clicked:
200 connect(boundaryDivide, SIGNAL(signalDoDivideSurface(double)), this,
201 SLOT(doDivideSurfaceSlot(double)));
202
203 // boundaryDivide emits (double) when "divide button" has been clicked:
204 connect(boundaryDivide, SIGNAL(signalDoDivideEdge(double)), this,
205 SLOT(doDivideEdgeSlot(double)));
206
207 // solver emits (int) when finished:
208 connect(solver, SIGNAL(finished(int)), this, SLOT(solverFinishedSlot(int)));
209
210 // solver emits (void) when there is something to read from stdout:
211 connect(solver, SIGNAL(readyReadStandardOutput()), this,
212 SLOT(solverStdoutSlot()));
213
214 // solver emits (void) when there is something to read from stderr:
215 connect(solver, SIGNAL(readyReadStandardError()), this,
216 SLOT(solverStderrSlot()));
217
218 // solver emits (QProcess::ProcessError) when error occurs:
219 connect(solver, SIGNAL(error(QProcess::ProcessError)), this,
220 SLOT(solverErrorSlot(QProcess::ProcessError)));
221
222 // solver emits (QProcess::ProcessState) when state changed:
223 connect(solver, SIGNAL(stateChanged(QProcess::ProcessState)), this,
224 SLOT(solverStateChangedSlot(QProcess::ProcessState)));
225
226 // compiler emits (int) when finished:
227 connect(compiler, SIGNAL(finished(int)), this,
228 SLOT(compilerFinishedSlot(int)));
229
230 // compiler emits (void) when there is something to read from stdout:
231 connect(compiler, SIGNAL(readyReadStandardOutput()), this,
232 SLOT(compilerStdoutSlot()));
233
234 // compiler emits (void) when there is something to read from stderr:
235 connect(compiler, SIGNAL(readyReadStandardError()), this,
236 SLOT(compilerStderrSlot()));
237
238 // post emits (int) when finished:
239 connect(post, SIGNAL(finished(int)), this,
240 SLOT(postProcessFinishedSlot(int)));
241
242 // paraview emits (int) when finished:
243 connect(paraview, SIGNAL(finished(int)), this,
244 SLOT(paraviewProcessFinishedSlot(int)));
245
246 // meshSplitter emits (int) when finished:
247 connect(meshSplitter, SIGNAL(finished(int)), this,
248 SLOT(meshSplitterFinishedSlot(int)));
249
250 // meshSplitter emits(void) when there is something to read from stdout:
251 connect(meshSplitter, SIGNAL(readyReadStandardOutput()), this,
252 SLOT(meshSplitterStdoutSlot()));
253
254 // meshSplitter emits(void) when there is something to read from stderr:
255 connect(meshSplitter, SIGNAL(readyReadStandardError()), this,
256 SLOT(meshSplitterStderrSlot()));
257
258 // meshUnifier emits (int) when finished:
259 connect(meshUnifier, SIGNAL(finished(int)), this,
260 SLOT(meshUnifierFinishedSlot(int)));
261
262 // meshUnifier emits(void) when there is something to read from stdout:
263 connect(meshUnifier, SIGNAL(readyReadStandardOutput()), this,
264 SLOT(meshUnifierStdoutSlot()));
265
266 // meshUnifier emits(void) when there is something to read from stderr:
267 connect(meshUnifier, SIGNAL(readyReadStandardError()), this,
268 SLOT(meshUnifierStderrSlot()));
269
270 // grabTimeLine emits finished() when done:
271 connect(grabTimeLine, SIGNAL(finished()), this, SLOT(grabFrameSlot()));
272
273 // set initial state:
274 operations = 0;
275 meshControl->nglibPresent = nglibPresent;
276 meshControl->tetlibPresent = tetlibPresent;
277 meshControl->defaultControls();
278 nglibInputOk = false;
279 tetlibInputOk = false;
280 activeGenerator = GEN_UNKNOWN;
281 bcEditActive = false;
282 bodyEditActive = false;
283 showConvergence = egIni->isSet("showconvergence");
284 geometryInputFileName = "";
285 occInputOk = false;
286
287 // background image:
288 glWidget->stateUseBgImage = egIni->isSet("bgimage");
289 glWidget->stateStretchBgImage = egIni->isSet("bgimagestretch");
290 glWidget->stateAlignRightBgImage = egIni->isSet("bgimagealignright");
291 glWidget->bgImageFileName = egIni->value("bgimagefile");
292
293 // set font for text editors:
294 // QFont sansFont("Courier", 10);
295 // sifWindow->getTextEdit()->setCurrentFont(sansFont);
296 // solverLogWindow->getTextEdit()->setCurrentFont(sansFont);
297
298 // load definition files:
299 updateSplash("Loading definitions...");
300 loadDefinitions();
301
302 // initialization ready:
303 synchronizeMenuToState();
304 setWindowTitle(tr("ElmerGUI"));
305 setWindowIcon(QIcon(":/icons/Mesh3D.png"));
306 finalizeSplash();
307 setupSysTrayIcon();
308
309 // default size:
310 int defW = egIni->value("width").toInt();
311 int defH = egIni->value("height").toInt();
312 if (defW <= 200)
313 defW = 200;
314 if (defH <= 200)
315 defH = 200;
316 this->resize(defW, defH);
317
318 loadSettings();
319 }
320
321 // dtor...
322 //-----------------------------------------------------------------------------
~MainWindow()323 MainWindow::~MainWindow() {
324 saveSettings();
325 qApp->closeAllWindows();
326 }
327
328 // Set limits for dynamic editors, materials, bcs, etc...
329 //-----------------------------------------------------------------------------
setDynamicLimits()330 void MainWindow::setDynamicLimits() {
331 // Values defined in "edf/egini.xml" that override default limits:
332
333 // Deprecated ** 23/04/09 **
334 if (egIni->isPresent("max_boundaries")) {
335 limit->setMaxBoundaries(egIni->value("max_boundaries").toInt());
336 // cout << "Max boundaries: " << limit->maxBoundaries() << endl;
337 }
338
339 // Deprecated ** 23/04/09 **
340 if (egIni->isPresent("max_solvers")) {
341 limit->setMaxSolvers(egIni->value("max_solvers").toInt());
342 // cout << "Max solvers: " << limit->maxSolvers() << endl;
343 }
344
345 // Deprecated ** 23/04/09 **
346 if (egIni->isPresent("max_bodies")) {
347 limit->setMaxBodies(egIni->value("max_bodies").toInt());
348 // cout << "Max bodies: " << limit->maxBodies() << endl;
349 }
350
351 // Deprecated ** 21/04/09 **
352 if (egIni->isPresent("max_equations")) {
353 limit->setMaxEquations(egIni->value("max_equations").toInt());
354 // cout << "Max equations: " << limit->maxEquations() << endl;
355 }
356
357 // Deprecated ** 21/04/09 **
358 if (egIni->isPresent("max_materials")) {
359 limit->setMaxMaterials(egIni->value("max_materials").toInt());
360 // cout << "Max materials: " << limit->maxMaterials() << endl;
361 }
362
363 // Deprecated ** 21/04/09 **
364 if (egIni->isPresent("max_bodyforces")) {
365 limit->setMaxBodyforces(egIni->value("max_bodyforces").toInt());
366 // cout << "Max bodyforces: " << limit->maxBodyforces() << endl;
367 }
368
369 // Deprecated ** 21/04/09 **
370 if (egIni->isPresent("max_initialconditions")) {
371 limit->setMaxInitialconditions(
372 egIni->value("max_initialconditions").toInt());
373 // cout << "Max initialconditions: " << limit->maxInitialconditions() <<
374 // endl;
375 }
376
377 // Deprecated ** 21/04/09 **
378 if (egIni->isPresent("max_bcs")) {
379 limit->setMaxBcs(egIni->value("max_bcs").toInt());
380 // cout << "Max bcs: " << limit->maxBcs() << endl;
381 }
382 }
383
384 // Always synchronize menu to state when the menubar has been triggered...
385 //-----------------------------------------------------------------------------
menuBarTriggeredSlot(QAction * act)386 void MainWindow::menuBarTriggeredSlot(QAction *act) {
387 synchronizeMenuToState();
388 }
389
390 // Create actions...
391 //-----------------------------------------------------------------------------
createActions()392 void MainWindow::createActions() {
393 // File -> Open file
394 openAct =
395 new QAction(QIcon(":/icons/document-open.png"), tr("&Open..."), this);
396 openAct->setShortcut(tr("Ctrl+O"));
397 openAct->setStatusTip(tr("Open geometry input file"));
398 connect(openAct, SIGNAL(triggered()), this, SLOT(openSlot()));
399
400 // File -> Load mesh...
401 loadAct = new QAction(QIcon(":/icons/document-open-folder.png"),
402 tr("&Load mesh..."), this);
403 loadAct->setStatusTip(tr("Load Elmer mesh files"));
404 connect(loadAct, SIGNAL(triggered()), this, SLOT(loadSlot()));
405
406 // File -> Load project...
407 loadProjectAct = new QAction(QIcon(":/icons/document-import.png"),
408 tr("Load &project..."), this);
409 loadProjectAct->setStatusTip(tr("Load previously saved project"));
410 connect(loadProjectAct, SIGNAL(triggered()), this, SLOT(loadProjectSlot()));
411
412 // File -> New project...
413 newProjectAct = new QAction(QIcon(":/icons/document-new.png"),
414 tr("&New project..."), this);
415 newProjectAct->setStatusTip(tr("Create a new project"));
416 connect(newProjectAct, SIGNAL(triggered()), this, SLOT(newProjectSlot()));
417
418 // File -> Recent Projects
419 recentProject0Act = new QAction("", this);
420 connect(recentProject0Act, SIGNAL(triggered()), this,
421 SLOT(loadRecentProject0Slot()));
422 recentProject1Act = new QAction("", this);
423 connect(recentProject1Act, SIGNAL(triggered()), this,
424 SLOT(loadRecentProject1Slot()));
425 recentProject2Act = new QAction("", this);
426 connect(recentProject2Act, SIGNAL(triggered()), this,
427 SLOT(loadRecentProject2Slot()));
428 recentProject3Act = new QAction("", this);
429 connect(recentProject3Act, SIGNAL(triggered()), this,
430 SLOT(loadRecentProject3Slot()));
431 recentProject4Act = new QAction("", this);
432 connect(recentProject4Act, SIGNAL(triggered()), this,
433 SLOT(loadRecentProject4Slot()));
434
435 // File -> Definitions...
436 editDefinitionsAct = new QAction(QIcon(":/icons/games-config-custom.png"),
437 tr("&Definitions..."), this);
438 editDefinitionsAct->setStatusTip(
439 tr("Load and edit Elmer sif definitions file"));
440 connect(editDefinitionsAct, SIGNAL(triggered()), this,
441 SLOT(editDefinitionsSlot()));
442
443 // File -> Save...
444 saveAct =
445 new QAction(QIcon(":/icons/document-save.png"), tr("&Save..."), this);
446 saveAct->setShortcut(tr("Ctrl+S"));
447 saveAct->setStatusTip(tr("Save Elmer mesh and sif-files"));
448 connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSlot()));
449
450 // File -> Save as...
451 saveAsAct = new QAction(QIcon(":/icons/document-save-as.png"),
452 tr("&Save as..."), this);
453 saveAsAct->setStatusTip(tr("Save Elmer mesh and sif-files"));
454 connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAsSlot()));
455
456 // File -> Save project
457 saveProjectAct = new QAction(QIcon(":/icons/document-export.png"),
458 tr("&Save project"), this);
459 saveProjectAct->setStatusTip(tr("Save current project"));
460 connect(saveProjectAct, SIGNAL(triggered()), this, SLOT(saveProjectSlot()));
461
462 // File -> Save project as...
463 saveProjectAsAct = new QAction(QIcon(":/icons/edit-copy.png"),
464 tr("&Save project as..."), this);
465 saveProjectAsAct->setStatusTip(
466 tr("Save current project by specifing directory"));
467 connect(saveProjectAsAct, SIGNAL(triggered()), this,
468 SLOT(saveProjectAsSlot()));
469
470 // File -> Save picture as...
471 savePictureAct = new QAction(QIcon(":/icons/view-preview.png"),
472 tr("&Save picture as..."), this);
473 savePictureAct->setStatusTip(tr("Save picture in file"));
474 connect(savePictureAct, SIGNAL(triggered()), this, SLOT(savePictureSlot()));
475
476 // File -> Exit
477 exitAct =
478 new QAction(QIcon(":/icons/application-exit.png"), tr("E&xit"), this);
479 exitAct->setShortcut(tr("Ctrl+Q"));
480 exitAct->setStatusTip(tr("Exit"));
481 connect(exitAct, SIGNAL(triggered()), this, SLOT(closeMainWindowSlot()));
482
483 // Model -> Setup...
484 modelSetupAct = new QAction(QIcon(), tr("Setup..."), this);
485 modelSetupAct->setStatusTip(tr("Setup simulation environment"));
486 connect(modelSetupAct, SIGNAL(triggered()), this, SLOT(modelSetupSlot()));
487
488 // Model -> Equation...
489 addEquationAct = new QAction(QIcon(), tr("Add..."), this);
490 addEquationAct->setStatusTip(tr("Add a PDE-system to the equation list"));
491 connect(addEquationAct, SIGNAL(triggered()), this, SLOT(addEquationSlot()));
492
493 // Model -> Material...
494 addMaterialAct = new QAction(QIcon(), tr("Add..."), this);
495 addMaterialAct->setStatusTip(tr("Add a material set to the material list"));
496 connect(addMaterialAct, SIGNAL(triggered()), this, SLOT(addMaterialSlot()));
497
498 // Model -> Body force...
499 addBodyForceAct = new QAction(QIcon(), tr("Add..."), this);
500 addBodyForceAct->setStatusTip(tr("Add body forces..."));
501 connect(addBodyForceAct, SIGNAL(triggered()), this, SLOT(addBodyForceSlot()));
502
503 // Model -> Initial condition...
504 addInitialConditionAct = new QAction(QIcon(), tr("Add..."), this);
505 addInitialConditionAct->setStatusTip(tr("Add initial conditions..."));
506 connect(addInitialConditionAct, SIGNAL(triggered()), this,
507 SLOT(addInitialConditionSlot()));
508
509 // Model -> Boundary condition...
510 addBoundaryConditionAct = new QAction(QIcon(), tr("Add..."), this);
511 addBoundaryConditionAct->setStatusTip(tr("Add boundary conditions..."));
512 connect(addBoundaryConditionAct, SIGNAL(triggered()), this,
513 SLOT(addBoundaryConditionSlot()));
514
515 // Model -> Set body properties
516 bodyEditAct = new QAction(QIcon(":/icons/set-body-property.png"),
517 tr("Set body properties"), this);
518 bodyEditAct->setStatusTip(
519 tr("Set body properties (equivalent to holding down the SHIFT key)"));
520 connect(bodyEditAct, SIGNAL(triggered()), this, SLOT(bodyEditSlot()));
521 bodyEditAct->setCheckable(true);
522
523 // Model -> Set boundary conditions
524 bcEditAct = new QAction(QIcon(":/icons/set-boundary-property.png"),
525 tr("Set boundary properties"), this);
526 bcEditAct->setStatusTip(
527 tr("Set boundary properties (equivalent to holding down the ALT key)"));
528 connect(bcEditAct, SIGNAL(triggered()), this, SLOT(bcEditSlot()));
529 bcEditAct->setCheckable(true);
530
531 // Model -> Summary...
532 modelSummaryAct = new QAction(QIcon(), tr("Summary..."), this);
533 modelSummaryAct->setStatusTip(tr("Model summary"));
534 connect(modelSummaryAct, SIGNAL(triggered()), this, SLOT(modelSummarySlot()));
535
536 // Model -> Clear
537 modelClearAct = new QAction(QIcon(), tr("Clear all"), this);
538 modelClearAct->setStatusTip(tr("Clear all model definitions"));
539 connect(modelClearAct, SIGNAL(triggered()), this, SLOT(modelClearSlot()));
540
541 // Edit -> Generate sif
542 generateSifAct = new QAction(QIcon(""), tr("&Generate"), this);
543 generateSifAct->setShortcut(tr("Ctrl+G"));
544 generateSifAct->setStatusTip(tr("Genarete solver input file"));
545 connect(generateSifAct, SIGNAL(triggered()), this, SLOT(generateSifSlot()));
546
547 // Edit -> Solver input file...
548 showsifAct = new QAction(QIcon(":/icons/document-properties.png"),
549 tr("&Edit..."), this);
550 showsifAct->setShortcut(tr("Ctrl+S"));
551 showsifAct->setStatusTip(tr("Edit solver input file"));
552 connect(showsifAct, SIGNAL(triggered()), this, SLOT(showsifSlot()));
553
554 // Mesh -> Control
555 meshcontrolAct =
556 new QAction(QIcon(":/icons/configure.png"), tr("&Configure..."), this);
557 meshcontrolAct->setShortcut(tr("Ctrl+C"));
558 meshcontrolAct->setStatusTip(tr("Configure mesh generators"));
559 connect(meshcontrolAct, SIGNAL(triggered()), this, SLOT(meshcontrolSlot()));
560
561 // Mesh -> Remesh
562 remeshAct = new QAction(QIcon(":/icons/edit-redo.png"), tr("&Remesh"), this);
563 remeshAct->setShortcut(tr("Ctrl+R"));
564 remeshAct->setStatusTip(tr("Remesh"));
565 connect(remeshAct, SIGNAL(triggered()), this, SLOT(remeshSlot()));
566
567 // Mesh -> Kill generator
568 stopMeshingAct = new QAction(QIcon(":/icons/window-close.png"),
569 tr("&Terminate meshing"), this);
570 stopMeshingAct->setStatusTip(tr("Terminate mesh generator"));
571 connect(stopMeshingAct, SIGNAL(triggered()), this, SLOT(stopMeshingSlot()));
572 stopMeshingAct->setEnabled(false);
573
574 // Mesh -> Divide surface
575 surfaceDivideAct =
576 new QAction(QIcon(":/icons/divide.png"), tr("&Divide surface..."), this);
577 surfaceDivideAct->setStatusTip(tr("Divide surface by sharp edges"));
578 connect(surfaceDivideAct, SIGNAL(triggered()), this,
579 SLOT(surfaceDivideSlot()));
580
581 // Mesh -> Unify surface
582 surfaceUnifyAct =
583 new QAction(QIcon(":/icons/unify.png"), tr("&Unify surface"), this);
584 surfaceUnifyAct->setStatusTip(tr("Unify surface (merge selected)"));
585 connect(surfaceUnifyAct, SIGNAL(triggered()), this, SLOT(surfaceUnifySlot()));
586
587 // Mesh -> Divide edge
588 edgeDivideAct = new QAction(QIcon(":/icons/divide-edge.png"),
589 tr("&Divide edge..."), this);
590 edgeDivideAct->setStatusTip(tr("Divide edge by sharp points"));
591 connect(edgeDivideAct, SIGNAL(triggered()), this, SLOT(edgeDivideSlot()));
592
593 // Mesh -> Unify edges
594 edgeUnifyAct =
595 new QAction(QIcon(":/icons/unify-edge.png"), tr("&Unify edge"), this);
596 edgeUnifyAct->setStatusTip(tr("Unify edge (merge selected)"));
597 connect(edgeUnifyAct, SIGNAL(triggered()), this, SLOT(edgeUnifySlot()));
598
599 // Mesh -> Clean up
600 cleanHangingSharpEdgesAct = new QAction(QIcon(""), tr("Clean up"), this);
601 cleanHangingSharpEdgesAct->setStatusTip(
602 tr("Removes hanging/orphan sharp edges (for visualization)"));
603 connect(cleanHangingSharpEdgesAct, SIGNAL(triggered()), this,
604 SLOT(cleanHangingSharpEdgesSlot()));
605
606 // View -> Full screen
607 viewFullScreenAct = new QAction(QIcon(), tr("Full screen"), this);
608 viewFullScreenAct->setShortcut(tr("Ctrl+L"));
609 viewFullScreenAct->setStatusTip(tr("Full screen mode"));
610 connect(viewFullScreenAct, SIGNAL(triggered()), this,
611 SLOT(viewFullScreenSlot()));
612 viewFullScreenAct->setCheckable(true);
613
614 // View -> Show surface mesh
615 hidesurfacemeshAct = new QAction(QIcon(), tr("Surface mesh"), this);
616 hidesurfacemeshAct->setStatusTip(tr("Show/hide surface mesh "
617 "(do/do not outline surface elements)"));
618 connect(hidesurfacemeshAct, SIGNAL(triggered()), this,
619 SLOT(hidesurfacemeshSlot()));
620 hidesurfacemeshAct->setCheckable(true);
621
622 // View -> Show volume mesh
623 hidevolumemeshAct = new QAction(QIcon(), tr("Volume mesh"), this);
624 hidevolumemeshAct->setStatusTip(tr("Show/hide volume mesh "
625 "(do/do not outline volume mesh edges)"));
626 connect(hidevolumemeshAct, SIGNAL(triggered()), this,
627 SLOT(hidevolumemeshSlot()));
628 hidevolumemeshAct->setCheckable(true);
629
630 // View -> Show sharp edges
631 hidesharpedgesAct = new QAction(QIcon(), tr("Sharp edges"), this);
632 hidesharpedgesAct->setStatusTip(tr("Show/hide sharp edges"));
633 connect(hidesharpedgesAct, SIGNAL(triggered()), this,
634 SLOT(hidesharpedgesSlot()));
635 hidesharpedgesAct->setCheckable(true);
636
637 // View -> Compass
638 viewCoordinatesAct = new QAction(QIcon(), tr("Compass"), this);
639 viewCoordinatesAct->setStatusTip(tr("View coordinates "
640 "(RGB=XYZ modulo translation)"));
641 connect(viewCoordinatesAct, SIGNAL(triggered()), this,
642 SLOT(viewCoordinatesSlot()));
643 viewCoordinatesAct->setCheckable(true);
644
645 // View -> Select all surfaces
646 selectAllSurfacesAct = new QAction(QIcon(), tr("Select all surfaces"), this);
647 selectAllSurfacesAct->setStatusTip(tr("Select all surfaces"));
648 connect(selectAllSurfacesAct, SIGNAL(triggered()), this,
649 SLOT(selectAllSurfacesSlot()));
650
651 // View -> Select all edges
652 selectAllEdgesAct = new QAction(QIcon(), tr("Select all edges"), this);
653 selectAllEdgesAct->setStatusTip(tr("Select all edges"));
654 connect(selectAllEdgesAct, SIGNAL(triggered()), this,
655 SLOT(selectAllEdgesSlot()));
656
657 // View -> Select defined edges
658 selectDefinedEdgesAct =
659 new QAction(QIcon(), tr("Select defined edges"), this);
660 selectDefinedEdgesAct->setStatusTip(tr("Select defined edges"));
661 connect(selectDefinedEdgesAct, SIGNAL(triggered()), this,
662 SLOT(selectDefinedEdgesSlot()));
663
664 // View -> Select defined surfaces
665 selectDefinedSurfacesAct =
666 new QAction(QIcon(), tr("Select defined surfaces"), this);
667 selectDefinedSurfacesAct->setStatusTip(tr("Select defined surfaces"));
668 connect(selectDefinedSurfacesAct, SIGNAL(triggered()), this,
669 SLOT(selectDefinedSurfacesSlot()));
670
671 // View -> Hide/show selected
672 hideselectedAct = new QAction(QIcon(), tr("&Hide/show selected"), this);
673 hideselectedAct->setShortcut(tr("Ctrl+H"));
674 hideselectedAct->setStatusTip(tr("Show/hide selected objects"));
675 connect(hideselectedAct, SIGNAL(triggered()), this, SLOT(hideselectedSlot()));
676
677 // View -> Show surface numbers
678 showSurfaceNumbersAct =
679 new QAction(QIcon(), tr("Surface element numbers"), this);
680 showSurfaceNumbersAct->setStatusTip(
681 tr("Show surface element numbers "
682 "(Show the surface element numbering)"));
683 connect(showSurfaceNumbersAct, SIGNAL(triggered()), this,
684 SLOT(showSurfaceNumbersSlot()));
685 showSurfaceNumbersAct->setCheckable(true);
686
687 // View -> Show edge numbers
688 showEdgeNumbersAct = new QAction(QIcon(), tr("Edge element numbers"), this);
689 showEdgeNumbersAct->setStatusTip(tr("Show edge element numbers "
690 "(Show the node element numbering)"));
691 connect(showEdgeNumbersAct, SIGNAL(triggered()), this,
692 SLOT(showEdgeNumbersSlot()));
693 showEdgeNumbersAct->setCheckable(true);
694
695 // View -> Show node numbers
696 showNodeNumbersAct = new QAction(QIcon(), tr("Node numbers"), this);
697 showNodeNumbersAct->setStatusTip(tr("Show node numbers "
698 "(Show the node numbers)"));
699 connect(showNodeNumbersAct, SIGNAL(triggered()), this,
700 SLOT(showNodeNumbersSlot()));
701 showNodeNumbersAct->setCheckable(true);
702
703 // View -> Show boundray index
704 showBoundaryIndexAct = new QAction(QIcon(), tr("Boundary index"), this);
705 showBoundaryIndexAct->setStatusTip(tr("Show boundary index"));
706 connect(showBoundaryIndexAct, SIGNAL(triggered()), this,
707 SLOT(showBoundaryIndexSlot()));
708 showBoundaryIndexAct->setCheckable(true);
709
710 // View -> Show body index
711 showBodyIndexAct = new QAction(QIcon(), tr("Body index"), this);
712 showBodyIndexAct->setStatusTip(tr("Show body index"));
713 connect(showBodyIndexAct, SIGNAL(triggered()), this,
714 SLOT(showBodyIndexSlot()));
715 showBodyIndexAct->setCheckable(true);
716
717 // View -> Colors -> GL controls
718 glControlAct = new QAction(QIcon(), tr("GL controls..."), this);
719 glControlAct->setStatusTip(
720 tr("Control GL parameters for lights and materials"));
721 connect(glControlAct, SIGNAL(triggered()), this, SLOT(glControlSlot()));
722
723 // View -> Colors -> Background
724 chooseBGColorAct = new QAction(QIcon(), tr("Background..."), this);
725 chooseBGColorAct->setStatusTip(tr("Set background color"));
726 connect(chooseBGColorAct, SIGNAL(triggered()), this,
727 SLOT(backgroundColorSlot()));
728
729 // View -> Colors -> Surface elements
730 chooseSurfaceColorAct = new QAction(QIcon(), tr("Surface elements..."), this);
731 chooseSurfaceColorAct->setStatusTip(tr("Set surface color"));
732 connect(chooseSurfaceColorAct, SIGNAL(triggered()), this,
733 SLOT(surfaceColorSlot()));
734
735 // View -> Colors -> Edge elements
736 chooseEdgeColorAct = new QAction(QIcon(), tr("Edge elements..."), this);
737 chooseEdgeColorAct->setStatusTip(tr("Set edge color"));
738 connect(chooseEdgeColorAct, SIGNAL(triggered()), this, SLOT(edgeColorSlot()));
739
740 // View -> Colors -> Surface mesh
741 chooseSurfaceMeshColorAct = new QAction(QIcon(), tr("Surface mesh..."), this);
742 chooseSurfaceMeshColorAct->setStatusTip(tr("Set surface mesh color"));
743 connect(chooseSurfaceMeshColorAct, SIGNAL(triggered()), this,
744 SLOT(surfaceMeshColorSlot()));
745
746 // View -> Colors -> Sharp edges
747 chooseSharpEdgeColorAct = new QAction(QIcon(), tr("Sharp edges..."), this);
748 chooseSharpEdgeColorAct->setStatusTip(tr("Set sharp edge color"));
749 connect(chooseSharpEdgeColorAct, SIGNAL(triggered()), this,
750 SLOT(sharpEdgeColorSlot()));
751
752 // View -> Colors -> Boundaries
753 showBoundaryColorAct = new QAction(QIcon(), tr("Boundaries"), this);
754 showBoundaryColorAct->setStatusTip(
755 tr("Visualize different boundary parts with color patches"));
756 connect(showBoundaryColorAct, SIGNAL(triggered()), this,
757 SLOT(colorizeBoundarySlot()));
758 showBoundaryColorAct->setCheckable(true);
759
760 // View -> Colors -> Bodies
761 showBodyColorAct = new QAction(QIcon(), tr("Bodies"), this);
762 showBodyColorAct->setStatusTip(
763 tr("Visualize different body with color patches"));
764 connect(showBodyColorAct, SIGNAL(triggered()), this,
765 SLOT(colorizeBodySlot()));
766 showBodyColorAct->setCheckable(true);
767
768 // View -> Shade model -> Smooth
769 smoothShadeAct = new QAction(QIcon(), tr("Smooth"), this);
770 smoothShadeAct->setStatusTip(tr("Set shade model to smooth"));
771 connect(smoothShadeAct, SIGNAL(triggered()), this, SLOT(smoothShadeSlot()));
772 smoothShadeAct->setCheckable(true);
773
774 // View -> Shade model -> Flat
775 flatShadeAct = new QAction(QIcon(), tr("Flat"), this);
776 flatShadeAct->setStatusTip(tr("Set shade model to flat"));
777 connect(flatShadeAct, SIGNAL(triggered()), this, SLOT(flatShadeSlot()));
778 flatShadeAct->setCheckable(true);
779
780 // View -> Projection -> Orthogonal
781 orthoAct = new QAction(QIcon(), tr("Orthogonal"), this);
782 orthoAct->setStatusTip(tr("Set projection to orthogonal"));
783 connect(orthoAct, SIGNAL(triggered()), this, SLOT(orthoSlot()));
784 orthoAct->setCheckable(true);
785
786 // View -> Projection -> Perspective
787 perspectiveAct = new QAction(QIcon(), tr("Perspective"), this);
788 perspectiveAct->setStatusTip(tr("Set projection to perspective"));
789 connect(perspectiveAct, SIGNAL(triggered()), this, SLOT(perspectiveSlot()));
790 perspectiveAct->setCheckable(true);
791
792 // View -> Show all
793 showallAct = new QAction(QIcon(), tr("Show all"), this);
794 showallAct->setStatusTip(tr("Show all objects"));
795 connect(showallAct, SIGNAL(triggered()), this, SLOT(showallSlot()));
796
797 // View -> Reset model view
798 resetAct = new QAction(QIcon(), tr("Reset model view"), this);
799 resetAct->setStatusTip(tr("Reset model view"));
800 connect(resetAct, SIGNAL(triggered()), this, SLOT(resetSlot()));
801
802 // View -> Show cad model
803 showCadModelAct = new QAction(QIcon(), tr("Cad model..."), this);
804 showCadModelAct->setStatusTip(
805 tr("Displays the cad model in a separate window"));
806 connect(showCadModelAct, SIGNAL(triggered()), this, SLOT(showCadModelSlot()));
807
808 // View -> Show 2d view
809 showTwodViewAct = new QAction(QIcon(), tr("2D modeler..."), this);
810 showTwodViewAct->setStatusTip(
811 tr("Displays the 2d geometry in a separate window"));
812 connect(showTwodViewAct, SIGNAL(triggered()), this, SLOT(showTwodViewSlot()));
813
814 // View -> Show Object Browser
815 showObjectBrowserAct = new QAction(QIcon(), tr("Show Object Browser"), this);
816 showObjectBrowserAct->setStatusTip(tr("Show Object Browser"));
817 connect(showObjectBrowserAct, SIGNAL(triggered()), this,
818 SLOT(showObjectBrowserSlot()));
819 showObjectBrowserAct->setCheckable(true);
820
821 // Solver -> Parallel settings
822 parallelSettingsAct = new QAction(QIcon(), tr("Parallel settings..."), this);
823 parallelSettingsAct->setStatusTip(
824 tr("Choose parameters and methods for parallel solution"));
825 connect(parallelSettingsAct, SIGNAL(triggered()), this,
826 SLOT(parallelSettingsSlot()));
827
828 // Solver -> Run solver
829 runsolverAct =
830 new QAction(QIcon(":/icons/Solver.png"), tr("Start solver"), this);
831 runsolverAct->setStatusTip(tr("Run ElmerSolver"));
832 connect(runsolverAct, SIGNAL(triggered()), this, SLOT(runsolverSlot()));
833
834 // Solver -> Kill solver
835 killsolverAct =
836 new QAction(QIcon(":/icons/window-close.png"), tr("Kill solver"), this);
837 killsolverAct->setStatusTip(tr("Kill ElmerSolver"));
838 connect(killsolverAct, SIGNAL(triggered()), this, SLOT(killsolverSlot()));
839 killsolverAct->setEnabled(false);
840
841 // Solver -> Show convergence
842 showConvergenceAct = new QAction(QIcon(), tr("Show convergence"), this);
843 showConvergenceAct->setStatusTip(tr("Show/hide convergence plot"));
844 connect(showConvergenceAct, SIGNAL(triggered()), this,
845 SLOT(showConvergenceSlot()));
846 showConvergenceAct->setCheckable(true);
847
848 // Solver -> Post process
849 resultsAct =
850 new QAction(QIcon(":/icons/Post.png"), tr("Start ElmerPost"), this);
851 resultsAct->setStatusTip(tr("Run ElmerPost for visualization"));
852 connect(resultsAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
853
854 // Solver -> Kill post process
855 killresultsAct = new QAction(QIcon(":/icons/window-close.png"),
856 tr("Kill ElmerPost"), this);
857 killresultsAct->setStatusTip(tr("Kill ElmerPost"));
858 connect(killresultsAct, SIGNAL(triggered()), this, SLOT(killresultsSlot()));
859 killresultsAct->setEnabled(false);
860
861 // Solver -> Show Vtk postprocessor
862 showVtkPostAct = new QAction(QIcon(), tr("Start ElmerVTK"), this);
863 showVtkPostAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));
864 connect(showVtkPostAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));
865
866 // Solver -> Show ParaView postprocessor
867 paraviewAct =
868 new QAction(QIcon(":/icons/Paraview.png"), tr("Start ParaView"), this);
869 paraviewAct->setStatusTip(tr("Invokes ParaView for visualization"));
870 connect(paraviewAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));
871
872 // Solver -> Compiler...
873 compileSolverAct = new QAction(QIcon(""), tr("Compiler..."), this);
874 compileSolverAct->setStatusTip(tr(
875 "Compile Elmer specific source code (f90) into a shared library (dll)"));
876 connect(compileSolverAct, SIGNAL(triggered()), this,
877 SLOT(compileSolverSlot()));
878
879 // Help -> About
880 aboutAct = new QAction(QIcon(":/icons/help-about.png"), tr("About..."), this);
881 aboutAct->setStatusTip(tr("Information about the program"));
882 connect(aboutAct, SIGNAL(triggered()), this, SLOT(showaboutSlot()));
883
884 generateAndSaveAndRunAct =
885 new QAction(QIcon(":/icons/arrow-right-double.png"),
886 tr("&Generate, save and run"), this);
887 generateAndSaveAndRunAct->setStatusTip(
888 tr("Generate and save sif, save project, then run solver"));
889 connect(generateAndSaveAndRunAct, SIGNAL(triggered()), this,
890 SLOT(generateAndSaveAndRunSlot()));
891 ;
892
893 #if WIN32
894 #else
895 compileSolverAct->setEnabled(false);
896 #endif
897
898 if (egIni->isSet("bgimage"))
899 chooseBGColorAct->setEnabled(false);
900
901 runPostProcessorAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);
902 runPostProcessorAct->setStatusTip(tr("Select ElmerPost as post-processor"));
903 connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
904
905 selectElmerPostAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);
906 selectElmerPostAct->setStatusTip(tr("Select ElmerPost as post-processor"));
907 connect(selectElmerPostAct, SIGNAL(triggered()), this, SLOT(selectElmerPostSlot()));
908 selectElmerPostAct->setCheckable(true);
909
910 selectVtkPostAct = new QAction(QIcon(":/icons/Mesh3D.png"), tr("ElmerVTK"), this);
911 selectVtkPostAct->setStatusTip(tr("Select ElmerVTK as post-processor"));
912 connect(selectVtkPostAct, SIGNAL(triggered()), this, SLOT(selectVtkPostSlot()));
913 selectVtkPostAct->setCheckable(true);
914
915 selectParaViewAct = new QAction(QIcon(":/icons/Paraview.png"), tr("ParaView"), this);
916 selectParaViewAct->setStatusTip(tr("Select ParaView as post-processor"));
917 connect(selectParaViewAct, SIGNAL(triggered()), this, SLOT(selectParaViewSlot()));
918 selectParaViewAct->setCheckable(true);
919 }
920
921 // Create menus...
922 //-----------------------------------------------------------------------------
createMenus()923 void MainWindow::createMenus() {
924 // File menu
925 fileMenu = menuBar()->addMenu(tr("&File"));
926 fileMenu->addAction(newProjectAct);
927 fileMenu->addAction(loadProjectAct);
928 recentProjectsMenu = fileMenu->addMenu(tr("&Recent projects"));
929 recentProjectsMenu->setEnabled(false);
930 fileMenu->addAction(saveProjectAct);
931 fileMenu->addAction(saveProjectAct);
932 fileMenu->addAction(saveProjectAsAct);
933 fileMenu->addSeparator();
934 fileMenu->addAction(openAct);
935 fileMenu->addAction(loadAct);
936 fileMenu->addAction(saveAct);
937 fileMenu->addAction(saveAsAct);
938 fileMenu->addSeparator();
939 fileMenu->addAction(editDefinitionsAct);
940 fileMenu->addSeparator();
941 fileMenu->addAction(savePictureAct);
942 fileMenu->addSeparator();
943 fileMenu->addAction(exitAct);
944
945 // Mesh menu
946 meshMenu = menuBar()->addMenu(tr("&Mesh"));
947 meshMenu->addAction(meshcontrolAct);
948 meshMenu->addAction(remeshAct);
949 meshMenu->addAction(stopMeshingAct);
950 meshMenu->addSeparator();
951 meshMenu->addAction(surfaceDivideAct);
952 meshMenu->addAction(surfaceUnifyAct);
953 meshMenu->addSeparator();
954 meshMenu->addAction(edgeDivideAct);
955 meshMenu->addAction(edgeUnifyAct);
956 meshMenu->addSeparator();
957 meshMenu->addAction(cleanHangingSharpEdgesAct);
958
959 // Model menu
960 modelMenu = menuBar()->addMenu(tr("&Model"));
961
962 modelMenu->addAction(modelSetupAct);
963 modelMenu->addSeparator();
964
965 equationMenu = modelMenu->addMenu(tr("Equation"));
966 equationMenu->addAction(addEquationAct);
967 equationMenu->addSeparator();
968 connect(equationMenu, SIGNAL(triggered(QAction *)), this,
969 SLOT(equationSelectedSlot(QAction *)));
970
971 modelMenu->addSeparator();
972 materialMenu = modelMenu->addMenu(tr("Material"));
973 materialMenu->addAction(addMaterialAct);
974 materialMenu->addSeparator();
975 connect(materialMenu, SIGNAL(triggered(QAction *)), this,
976 SLOT(materialSelectedSlot(QAction *)));
977
978 modelMenu->addSeparator();
979 bodyForceMenu = modelMenu->addMenu(tr("Body force"));
980 bodyForceMenu->addAction(addBodyForceAct);
981 bodyForceMenu->addSeparator();
982 connect(bodyForceMenu, SIGNAL(triggered(QAction *)), this,
983 SLOT(bodyForceSelectedSlot(QAction *)));
984
985 modelMenu->addSeparator();
986 initialConditionMenu = modelMenu->addMenu(tr("Initial condition"));
987 initialConditionMenu->addAction(addInitialConditionAct);
988 initialConditionMenu->addSeparator();
989 connect(initialConditionMenu, SIGNAL(triggered(QAction *)), this,
990 SLOT(initialConditionSelectedSlot(QAction *)));
991
992 modelMenu->addSeparator();
993 boundaryConditionMenu = modelMenu->addMenu(tr("Boundary condition"));
994 boundaryConditionMenu->addAction(addBoundaryConditionAct);
995 boundaryConditionMenu->addSeparator();
996 connect(boundaryConditionMenu, SIGNAL(triggered(QAction *)), this,
997 SLOT(boundaryConditionSelectedSlot(QAction *)));
998
999 modelMenu->addSeparator();
1000 modelMenu->addAction(bodyEditAct);
1001 modelMenu->addAction(bcEditAct);
1002 modelMenu->addSeparator();
1003 modelMenu->addAction(modelSummaryAct);
1004 modelMenu->addSeparator();
1005 modelMenu->addAction(modelClearAct);
1006 modelMenu->addSeparator();
1007
1008 // View menu
1009 viewMenu = menuBar()->addMenu(tr("&View"));
1010 viewMenu->addAction(viewFullScreenAct);
1011 viewMenu->addSeparator();
1012 viewMenu->addAction(hidesurfacemeshAct);
1013 viewMenu->addAction(hidevolumemeshAct);
1014 viewMenu->addAction(hidesharpedgesAct);
1015 viewMenu->addAction(viewCoordinatesAct);
1016 viewMenu->addSeparator();
1017 viewMenu->addAction(selectAllSurfacesAct);
1018 viewMenu->addAction(selectAllEdgesAct);
1019 // Momentarily disabled (see comment *** TODO *** below):
1020 // viewMenu->addSeparator();
1021 // viewMenu->addAction(selectDefinedEdgesAct);
1022 // viewMenu->addAction(selectDefinedSurfacesAct);
1023 viewMenu->addSeparator();
1024 viewMenu->addAction(hideselectedAct);
1025 viewMenu->addSeparator();
1026 shadeMenu = viewMenu->addMenu(tr("Shade model"));
1027 shadeMenu->addAction(flatShadeAct);
1028 shadeMenu->addAction(smoothShadeAct);
1029 viewMenu->addSeparator();
1030 projectionMenu = viewMenu->addMenu(tr("Projection"));
1031 projectionMenu->addAction(orthoAct);
1032 projectionMenu->addAction(perspectiveAct);
1033 viewMenu->addSeparator();
1034 numberingMenu = viewMenu->addMenu(tr("Numbering"));
1035 numberingMenu->addAction(showSurfaceNumbersAct);
1036 numberingMenu->addAction(showEdgeNumbersAct);
1037 numberingMenu->addAction(showNodeNumbersAct);
1038 numberingMenu->addSeparator();
1039 numberingMenu->addAction(showBoundaryIndexAct);
1040 numberingMenu->addAction(showBodyIndexAct);
1041 viewMenu->addSeparator();
1042 colorizeMenu = viewMenu->addMenu(tr("Lights and colors"));
1043 colorizeMenu->addAction(glControlAct);
1044 colorizeMenu->addSeparator();
1045 colorizeMenu->addAction(chooseBGColorAct);
1046 colorizeMenu->addSeparator();
1047 colorizeMenu->addAction(chooseSurfaceColorAct);
1048 colorizeMenu->addAction(chooseEdgeColorAct);
1049 colorizeMenu->addSeparator();
1050 colorizeMenu->addAction(chooseSurfaceMeshColorAct);
1051 colorizeMenu->addAction(chooseSharpEdgeColorAct);
1052 colorizeMenu->addSeparator();
1053 colorizeMenu->addAction(showBoundaryColorAct);
1054 colorizeMenu->addAction(showBodyColorAct);
1055 viewMenu->addSeparator();
1056 viewMenu->addAction(showallAct);
1057 viewMenu->addAction(resetAct);
1058 #ifdef EG_OCC
1059 viewMenu->addSeparator();
1060 viewMenu->addAction(showCadModelAct);
1061 #endif
1062 viewMenu->addAction(showTwodViewAct);
1063 viewMenu->addSeparator();
1064 viewMenu->addAction(showObjectBrowserAct);
1065
1066 // Edit menu
1067 editMenu = menuBar()->addMenu(tr("&Sif"));
1068 editMenu->addAction(generateSifAct);
1069 editMenu->addSeparator();
1070 editMenu->addAction(showsifAct);
1071
1072 // SolverMenu
1073 solverMenu = menuBar()->addMenu(tr("&Run"));
1074 solverMenu->addAction(parallelSettingsAct);
1075 solverMenu->addSeparator();
1076 solverMenu->addAction(runsolverAct);
1077 solverMenu->addAction(killsolverAct);
1078 #ifdef EG_QWT
1079 solverMenu->addAction(showConvergenceAct);
1080 #endif
1081 solverMenu->addSeparator();
1082 solverMenu->addAction(resultsAct);
1083 solverMenu->addAction(killresultsAct);
1084 #ifdef EG_VTK
1085 solverMenu->addSeparator();
1086 solverMenu->addAction(showVtkPostAct);
1087 #endif
1088 #ifdef EG_PARAVIEW
1089 solverMenu->addSeparator();
1090 solverMenu->addAction(paraviewAct);
1091 #endif
1092 solverMenu->addSeparator();
1093 solverMenu->addAction(compileSolverAct);
1094
1095 // Help menu
1096 helpMenu = menuBar()->addMenu(tr("&Help"));
1097 helpMenu->addAction(aboutAct);
1098
1099 // Sys tray menu:
1100 sysTrayMenu = new QMenu;
1101 sysTrayMenu->addAction(modelSummaryAct);
1102 sysTrayMenu->addSeparator();
1103 sysTrayMenu->addAction(stopMeshingAct);
1104 sysTrayMenu->addSeparator();
1105 sysTrayMenu->addAction(killsolverAct);
1106 sysTrayMenu->addAction(killresultsAct);
1107 sysTrayMenu->addSeparator();
1108 sysTrayMenu->addAction(aboutAct);
1109 sysTrayMenu->addSeparator();
1110 sysTrayMenu->addAction(exitAct);
1111
1112 // Context menu:
1113 contextMenu = new QMenu;
1114 contextMenu->addMenu(fileMenu);
1115 contextMenu->addMenu(meshMenu);
1116 contextMenu->addMenu(modelMenu);
1117 contextMenu->addMenu(viewMenu);
1118 contextMenu->addMenu(editMenu);
1119 contextMenu->addMenu(solverMenu);
1120 contextMenu->addMenu(helpMenu);
1121
1122 selectPostMenu = new QMenu;
1123 selectPostMenu->addAction(selectElmerPostAct);
1124 selectPostMenu->addAction(selectVtkPostAct);
1125 selectPostMenu->addAction(selectParaViewAct);
1126 #ifndef EG_VTK
1127 selectVtkPostAct->setEnabled(false);
1128 #endif
1129 #ifndef EG_PARAVIEW
1130 selectParaViewAct->setEnabled(false);
1131 #endif
1132 // Disable unavailable external components:
1133 //------------------------------------------
1134 if (!egIni->isSet("checkexternalcomponents"))
1135 return;
1136
1137 QProcess testProcess;
1138 QStringList args;
1139
1140 cout << "Checking for ElmerSolver... ";
1141 updateSplash("Checking for ElmerSolver...");
1142 args << "-v";
1143 testProcess.start("ElmerSolver", args);
1144 if (!testProcess.waitForStarted()) {
1145 logMessage("no - disabling solver features");
1146 runsolverAct->setEnabled(false);
1147 showConvergenceAct->setEnabled(false);
1148 killsolverAct->setEnabled(false);
1149 } else {
1150 cout << "yes" << endl;
1151 }
1152 testProcess.waitForFinished(2000);
1153
1154 cout << "Checking for ... ";
1155 updateSplash("Checking for ElmerPost...");
1156 args << "-v";
1157 testProcess.start("ElmerPost", args);
1158 if (!testProcess.waitForStarted()) {
1159 logMessage("no - disabling ElmerPost postprocessing features");
1160 resultsAct->setEnabled(false);
1161 killresultsAct->setEnabled(false);
1162 } else {
1163 cout << "yes" << endl;
1164 }
1165 testProcess.waitForFinished(2000);
1166
1167 cout << "Checking for ElmerGrid... ";
1168 updateSplash("Checking for ElmerGrid...");
1169 testProcess.start("ElmerGrid");
1170 if (!testProcess.waitForStarted()) {
1171 logMessage("no - disabling parallel features");
1172 parallelSettingsAct->setEnabled(false);
1173 } else {
1174 cout << "yes" << endl;
1175 }
1176 testProcess.waitForFinished(2000);
1177
1178 cout << "Checking for ElmerSolver_mpi... ";
1179 updateSplash("Checking for ElmerSolver_mpi...");
1180 args << "-v";
1181 testProcess.start("ElmerSolver_mpi", args);
1182 if (!testProcess.waitForStarted()) {
1183 logMessage("no - disabling parallel features");
1184 parallelSettingsAct->setEnabled(false);
1185 } else {
1186 cout << "yes" << endl;
1187 }
1188 testProcess.waitForFinished(2000);
1189 }
1190
1191 // Create tool bars...
1192 //-----------------------------------------------------------------------------
createToolBars()1193 void MainWindow::createToolBars() {
1194 // File toolbar
1195 fileToolBar = addToolBar(tr("&File"));
1196 fileToolBar->addAction(newProjectAct);
1197 fileToolBar->addAction(loadProjectAct);
1198 fileToolBar->addAction(saveProjectAct);
1199 fileToolBar->addAction(saveProjectAsAct);
1200 fileToolBar->addSeparator();
1201 fileToolBar->addAction(openAct);
1202 fileToolBar->addAction(loadAct);
1203 fileToolBar->addAction(saveAct);
1204 fileToolBar->addAction(saveAsAct);
1205
1206 fileToolBar->addSeparator();
1207 fileToolBar->addAction(savePictureAct);
1208
1209 // Edit toolbar
1210 editToolBar = addToolBar(tr("&Edit"));
1211 editToolBar->addAction(showsifAct);
1212
1213 // Mesh toolbar
1214 meshToolBar = addToolBar(tr("&Mesh"));
1215 meshToolBar->addAction(meshcontrolAct);
1216 meshToolBar->addAction(remeshAct);
1217 meshToolBar->addSeparator();
1218 meshToolBar->addAction(surfaceDivideAct);
1219 meshToolBar->addAction(surfaceUnifyAct);
1220 meshToolBar->addSeparator();
1221 meshToolBar->addAction(edgeDivideAct);
1222 meshToolBar->addAction(edgeUnifyAct);
1223 meshToolBar->addSeparator();
1224 meshToolBar->addAction(bodyEditAct);
1225 meshToolBar->addAction(bcEditAct);
1226
1227 // Solver toolbar
1228 solverToolBar = addToolBar(tr("&Solver"));
1229 solverToolBar->addAction(runsolverAct);
1230 solverToolBar->addAction(runPostProcessorAct);
1231 solverToolBar->addAction(generateAndSaveAndRunAct);
1232
1233 if (egIni->isSet("hidetoolbars")) {
1234 fileToolBar->hide();
1235 editToolBar->hide();
1236 meshToolBar->hide();
1237 solverToolBar->hide();
1238 }
1239 }
1240
1241 // Create status bar...
1242 //-----------------------------------------------------------------------------
createStatusBar()1243 void MainWindow::createStatusBar() {
1244 progressBar = new QProgressBar;
1245 progressBar->setMaximumHeight(12);
1246 progressBar->setMaximumWidth(120);
1247 progressBar->setTextVisible(false);
1248 progressBar->hide();
1249
1250 progressLabel = new QLabel;
1251 progressLabel->hide();
1252
1253 statusBar()->addPermanentWidget(progressLabel);
1254 statusBar()->addPermanentWidget(progressBar);
1255
1256 statusBar()->showMessage(tr("Ready"));
1257
1258 connect(grabTimeLine, SIGNAL(frameChanged(int)), progressBar,
1259 SLOT(setValue(int)));
1260 }
1261
1262 //*****************************************************************************
1263 //
1264 // File MENU
1265 //
1266 //*****************************************************************************
1267
1268 // File -> Open...
1269 //-----------------------------------------------------------------------------
newProjectSlot()1270 void MainWindow::newProjectSlot() {
1271 NewProjectDialog dlg;
1272
1273 #ifdef __APPLE__DONTGO_HERE_TODO
1274 QString extraDirpath = this->homePath + "/edf-extra";
1275 #else
1276 QString extraDirPath =
1277 QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";
1278
1279 QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
1280
1281 if (!elmerGuiHome.isEmpty())
1282 extraDirPath = elmerGuiHome + "/edf-extra";
1283
1284 extraDirPath.replace('\\', '/');
1285 #endif
1286
1287 QString defaultDir = getDefaultDirName();
1288 dlg.setDirectories(defaultDir, extraDirPath);
1289
1290 if (dlg.exec() == QDialog::Accepted) {
1291
1292 // re-initialize
1293 delete elmerDefs;
1294 elmerDefs = new QDomDocument;
1295 delete edfEditor;
1296 edfEditor = new EdfEditor;
1297 loadDefinitions();
1298 geometryInputFileName = "";
1299 currentProjectDirName = "";
1300 sifWindow->getTextEdit()->clear();
1301 sifWindow->hide();
1302 solverLogWindow->getTextEdit()->clear();
1303 solverLogWindow->hide();
1304 delete generalSetup;
1305 generalSetup = new GeneralSetup(this);
1306 summaryEditor->ui.summaryEdit->clear();
1307 delete twodView;
1308 twodView = new TwodView;
1309 meshControl->defaultControls();
1310 delete parallel;
1311 parallel = new Parallel(this);
1312
1313 #ifdef EG_QWT
1314 convergenceView->removeData();
1315 #endif
1316
1317 #ifdef EG_VTK
1318 settings_setValue("vtkPost/geometry", vtkPost->saveGeometry());
1319 delete vtkPost;
1320 vtkPost = new VtkPost(this);
1321 vtkPostMeshUnifierRunning = false;
1322 vtkPost->restoreGeometry(settings_value("vtkPost/geometry").toByteArray());
1323 #endif
1324
1325 #ifdef EG_OCC
1326 settings_setValue("cadView/geometry", cadView->saveGeometry());
1327 delete cadView;
1328 cadView = new CadView();
1329 if (egIni->isPresent("deflection"))
1330 cadView->setDeflection(egIni->value("deflection").toDouble());
1331 cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());
1332 #endif
1333
1334 // delete operations
1335 operation_t *p = operation.next;
1336 operation_t *q = NULL;
1337 while (p != NULL) {
1338 if (p->select_set != NULL)
1339 delete[] p->select_set;
1340 q = p->next;
1341 if (p != NULL)
1342 delete p;
1343 p = q;
1344 }
1345 operations = 0;
1346 operation.next = NULL;
1347
1348 // reset mesh
1349 if (glWidget->hasMesh()) {
1350 glWidget->getMesh()->clear();
1351 glWidget->deleteMesh();
1352 }
1353 glWidget->newMesh();
1354 meshutils->findSurfaceElementEdges(glWidget->getMesh());
1355 meshutils->findSurfaceElementNormals(glWidget->getMesh());
1356 glWidget->rebuildLists();
1357
1358 modelClearSlot();
1359
1360 // load Elmer mesh/open geometry file
1361 bool bStartMeshing = false;
1362 if (dlg.ui.radioButton_elmerMesh->isChecked() &&
1363 !dlg.ui.label_meshDir->text().isEmpty()) {
1364 loadElmerMesh(dlg.ui.label_meshDir->text());
1365 } else if (dlg.ui.radioButton_geometryFile->isChecked() &&
1366 !dlg.ui.label_geometryFile->text().isEmpty()) {
1367 QString fileName = dlg.ui.label_geometryFile->text();
1368 geometryInputFileName = fileName;
1369 saveDirName = "";
1370 readInputFile(fileName);
1371 if (egIni->isSet("automesh"))
1372 bStartMeshing = true;
1373 }
1374
1375 // save and load project
1376 saveProject(dlg.ui.label_projectDir->text());
1377 loadProject(dlg.ui.label_projectDir->text());
1378
1379 // load extra solvers
1380 QString message;
1381 for (int i = 0; i < dlg.ui.listWidget_selectedSolvers->count(); i++) {
1382 message = "Load " + extraDirPath + "/" +
1383 dlg.ui.listWidget_selectedSolvers->item(i)->text() + "... ";
1384 #if WITH_QT5
1385 cout << string(message.toLatin1());
1386 cout.flush();
1387 #else
1388 cout << string(message.toAscii());
1389 cout.flush();
1390 #endif
1391 edfEditor->appendFrom(extraDirPath + "/" +
1392 dlg.ui.listWidget_selectedSolvers->item(i)->text());
1393 cout << " done" << endl;
1394 }
1395
1396 if (bStartMeshing)
1397 remeshSlot();
1398 }
1399 }
1400
parseCmdLine()1401 void MainWindow::parseCmdLine() {
1402 QStringList args = QCoreApplication::arguments();
1403
1404 if (!args.contains("-nogui"))
1405 this->show();
1406
1407 int input = args.indexOf("-i");
1408
1409 if (input > 0) {
1410 QString fileName = args.at(input + 1);
1411
1412 QFileInfo fileInfo(fileName);
1413
1414 if (!fileInfo.exists()) {
1415 #if WITH_QT5
1416 cout << "Input file \"" << fileName.toLatin1().data()
1417 << "\" does not exist" << endl;
1418 #else
1419 cout << "Input file \"" << fileName.toAscii().data()
1420 << "\" does not exist" << endl;
1421 #endif
1422 QApplication::closeAllWindows();
1423 exit(0);
1424 }
1425
1426 if (fileName.left(1) != "-") {
1427 #if WITH_QT5
1428 cout << "Reading input file " << fileName.toLatin1().data() << endl;
1429 #else
1430 cout << "Reading input file " << fileName.toAscii().data() << endl;
1431 #endif
1432 readInputFile(fileName);
1433 remeshSlot();
1434 }
1435 }
1436 }
1437
1438 // File -> Open...
1439 //-----------------------------------------------------------------------------
openSlot()1440 void MainWindow::openSlot() {
1441 QString defaultDirName = getDefaultDirName();
1442
1443 QString fileName = QFileDialog::getOpenFileName(
1444 this, tr("Open geometry input file"), defaultDirName);
1445
1446 if (!fileName.isEmpty()) {
1447
1448 QFileInfo fi(fileName);
1449 QString absolutePath = fi.absolutePath();
1450 QDir::setCurrent(absolutePath);
1451
1452 } else {
1453
1454 logMessage("Unable to open file: file name is empty");
1455 return;
1456 }
1457
1458 geometryInputFileName = fileName;
1459
1460 operation_t *p = operation.next;
1461 operation_t *q = NULL;
1462
1463 while (p != NULL) {
1464 if (p->select_set != NULL)
1465 delete[] p->select_set;
1466
1467 q = p->next;
1468
1469 if (p != NULL)
1470 delete p;
1471
1472 p = q;
1473 }
1474
1475 operations = 0;
1476 operation.next = NULL;
1477
1478 saveDirName = "";
1479 readInputFile(fileName);
1480
1481 if (egIni->isSet("automesh"))
1482 remeshSlot();
1483 }
1484
1485 // Read input file and populate mesh generator's input structures:
1486 //-----------------------------------------------------------------------------
readInputFile(QString fileName)1487 void MainWindow::readInputFile(QString fileName) {
1488 occInputOk = false;
1489
1490 char cs[1024];
1491
1492 QFileInfo fi(fileName);
1493 QString absolutePath = fi.absolutePath();
1494 QString baseName = fi.baseName();
1495 QString fileSuffix = fi.suffix();
1496 QString baseFileName = absolutePath + "/" + baseName;
1497 #if WITH_QT5
1498 sprintf(cs, "%s", baseFileName.toLatin1().data());
1499 #else
1500 sprintf(cs, "%s", baseFileName.toAscii().data());
1501 #endif
1502
1503 activeGenerator = GEN_UNKNOWN;
1504 tetlibInputOk = false;
1505 nglibInputOk = false;
1506 ngDim = 3;
1507
1508 // Choose generator according to fileSuffix:
1509 //------------------------------------------
1510 if ((fileSuffix == "smesh") || (fileSuffix == "poly")) {
1511
1512 if (!tetlibPresent) {
1513 logMessage("unable to mesh - tetlib unavailable");
1514 return;
1515 }
1516
1517 activeGenerator = GEN_TETLIB;
1518 cout << "Selected tetlib for smesh/poly-format" << endl;
1519
1520 in->deinitialize();
1521 in->initialize();
1522 in->load_poly(cs);
1523
1524 tetlibInputOk = true;
1525
1526 } else if (fileSuffix == "off") {
1527
1528 if (!tetlibPresent) {
1529 logMessage("unable to mesh - tetlib unavailable");
1530 return;
1531 }
1532
1533 activeGenerator = GEN_TETLIB;
1534 cout << "Selected tetlib for off-format" << endl;
1535
1536 in->deinitialize();
1537 in->initialize();
1538 in->load_off(cs);
1539
1540 tetlibInputOk = true;
1541
1542 } else if (fileSuffix == "ply") {
1543
1544 if (!tetlibPresent) {
1545 logMessage("unable to mesh - tetlib unavailable");
1546 return;
1547 }
1548
1549 activeGenerator = GEN_TETLIB;
1550 cout << "Selected tetlib for ply-format" << endl;
1551
1552 in->deinitialize();
1553 in->initialize();
1554 in->load_ply(cs);
1555
1556 tetlibInputOk = true;
1557
1558 } else if (fileSuffix == "mesh") {
1559
1560 if (!tetlibPresent) {
1561 logMessage("unable to mesh - tetlib unavailable");
1562 return;
1563 }
1564
1565 activeGenerator = GEN_TETLIB;
1566 cout << "Selected tetlib for mesh-format" << endl;
1567
1568 in->deinitialize();
1569 in->initialize();
1570 in->load_medit(cs, 1);
1571
1572 tetlibInputOk = true;
1573
1574 } else if (fileSuffix == "stl") {
1575
1576 // for stl there are two alternative generators:
1577 if (meshControl->generatorType == GEN_NGLIB) {
1578
1579 if (!nglibPresent) {
1580 logMessage("unable to mesh - nglib unavailable");
1581 return;
1582 }
1583
1584 activeGenerator = GEN_NGLIB;
1585 cout << "Selected nglib for stl-format" << endl;
1586
1587 stlFileName = fileName;
1588
1589 nglibInputOk = true;
1590
1591 } else {
1592
1593 if (!tetlibPresent) {
1594 logMessage("unable to mesh - tetlib unavailable");
1595 return;
1596 }
1597
1598 activeGenerator = GEN_TETLIB;
1599 cout << "Selected tetlib for stl-format" << endl;
1600
1601 in->deinitialize();
1602 in->initialize();
1603 in->load_stl(cs);
1604
1605 tetlibInputOk = true;
1606 }
1607
1608 } else if ((fileSuffix == "grd") || (fileSuffix == "FDNEUT") ||
1609 (fileSuffix == "msh") || (fileSuffix == "mphtxt") ||
1610 (fileSuffix == "inp") || (fileSuffix == "unv") ||
1611 (fileSuffix == "plt")) {
1612
1613 activeGenerator = GEN_ELMERGRID;
1614 cout << "Selected elmergrid" << endl;
1615
1616 #if WITH_QT5
1617 int errstat = elmergridAPI->loadElmerMeshStructure(
1618 (const char *)(fileName.toLatin1()));
1619 #else
1620 int errstat = elmergridAPI->loadElmerMeshStructure(
1621 (const char *)(fileName.toAscii()));
1622 #endif
1623
1624 if (errstat)
1625 logMessage("loadElmerMeshStructure failed!");
1626
1627 return;
1628
1629 #ifdef EG_OCC
1630
1631 } else if ((fileSuffix.toLower() == "brep") ||
1632 (fileSuffix.toLower() == "step") ||
1633 (fileSuffix.toLower() == "stp") ||
1634 (fileSuffix.toLower() == "iges") ||
1635 (fileSuffix.toLower() == "igs")) {
1636
1637 meshControl->ui.nglibRadioButton->setChecked(true);
1638 meshControl->generatorType = GEN_NGLIB;
1639 activeGenerator = meshControl->generatorType;
1640
1641 if (egIni->isSet("autoview"))
1642 cadView->show();
1643
1644 occInputOk = cadView->readFile(fileName);
1645
1646 ngDim = cadView->getDim();
1647
1648 if (!occInputOk) {
1649 logMessage("Cad import: error: Unable to proceed with input file");
1650 cadView->close();
1651 return;
1652 }
1653
1654 nglibInputOk = true;
1655
1656 #endif
1657
1658 } else if ((fileSuffix.toLower() == "in2d")) {
1659
1660 if (!nglibPresent) {
1661 logMessage("unable to mesh - nglib unavailable");
1662 return;
1663 }
1664
1665 activeGenerator = GEN_NGLIB;
1666 cout << "Selected nglib for in2d-format" << endl;
1667
1668 in2dFileName = fileName;
1669
1670 nglibInputOk = true;
1671
1672 ngDim = 2;
1673
1674 } else {
1675
1676 logMessage("Unable to open file: file type unknown");
1677 activeGenerator = GEN_UNKNOWN;
1678
1679 return;
1680 }
1681 }
1682
1683 // Populate elmer's mesh structure and make GL-lists (tetlib):
1684 //-----------------------------------------------------------------------------
makeElmerMeshFromTetlib()1685 void MainWindow::makeElmerMeshFromTetlib() {
1686 meshutils->clearMesh(glWidget->getMesh());
1687
1688 glWidget->setMesh(tetlibAPI->createElmerMeshStructure());
1689
1690 glWidget->rebuildLists();
1691
1692 logMessage("Input file processed");
1693 }
1694
1695 // Populate elmer's mesh structure and make GL-lists (nglib):
1696 //-----------------------------------------------------------------------------
makeElmerMeshFromNglib()1697 void MainWindow::makeElmerMeshFromNglib() {
1698 meshutils->clearMesh(glWidget->getMesh());
1699 nglibAPI->setDim(this->ngDim);
1700 nglibAPI->setNgmesh(ngmesh);
1701
1702 glWidget->setMesh(nglibAPI->createElmerMeshStructure());
1703 glWidget->rebuildLists();
1704
1705 logMessage("Input file processed");
1706 }
1707
1708 // File -> Load mesh...
1709 //-----------------------------------------------------------------------------
loadSlot()1710 void MainWindow::loadSlot() {
1711 QString defaultDirName = getDefaultDirName();
1712
1713 QString dirName = QFileDialog::getExistingDirectory(
1714 this, tr("Open mesh directory"), defaultDirName);
1715
1716 if (!dirName.isEmpty()) {
1717
1718 logMessage("Loading from directory " + dirName);
1719
1720 } else {
1721
1722 logMessage("Unable to load mesh: directory undefined");
1723 return;
1724 }
1725
1726 loadElmerMesh(dirName);
1727 }
1728
1729 // Import mesh files in elmer-format:
1730 //-----------------------------------------------------------------------------
loadElmerMesh(QString dirName)1731 void MainWindow::loadElmerMesh(QString dirName) {
1732 logMessage("Loading elmer mesh files");
1733
1734 if (glWidget->hasMesh()) {
1735 glWidget->getMesh()->clear();
1736 glWidget->deleteMesh();
1737 }
1738
1739 glWidget->newMesh();
1740
1741 #if WITH_QT5
1742 bool success = glWidget->getMesh()->load(dirName.toLatin1().data());
1743 #else
1744 bool success = glWidget->getMesh()->load(dirName.toAscii().data());
1745 #endif
1746
1747 if (!success) {
1748 glWidget->getMesh()->clear();
1749 glWidget->deleteMesh();
1750 logMessage("Failed loading mesh files");
1751 return;
1752 }
1753
1754 meshutils->findSurfaceElementEdges(glWidget->getMesh());
1755 meshutils->findSurfaceElementNormals(glWidget->getMesh());
1756
1757 glWidget->rebuildLists();
1758
1759 QDir::setCurrent(dirName);
1760 saveDirName = dirName;
1761
1762 logMessage("Ready");
1763 }
1764
1765 // File -> Save...
1766 //-----------------------------------------------------------------------------
saveSlot()1767 void MainWindow::saveSlot() {
1768 if (!glWidget->hasMesh()) {
1769 logMessage("Unable to save mesh: no data");
1770 return;
1771 }
1772
1773 if (!saveDirName.isEmpty()) {
1774 logMessage("Output directory " + saveDirName);
1775 } else {
1776 saveAsSlot();
1777 return;
1778 }
1779
1780 saveElmerMesh(saveDirName);
1781 }
1782
1783 // File -> Save as...
1784 //-----------------------------------------------------------------------------
saveAsSlot()1785 void MainWindow::saveAsSlot() {
1786 if (!glWidget->hasMesh()) {
1787 logMessage("Unable to save mesh: no data");
1788 return;
1789 }
1790
1791 QString defaultDirName = getDefaultDirName();
1792
1793 saveDirName = QFileDialog::getExistingDirectory(
1794 this, tr("Open directory to save mesh"), defaultDirName);
1795
1796 if (!saveDirName.isEmpty()) {
1797 logMessage("Output directory " + saveDirName);
1798 } else {
1799 logMessage("Unable to save: directory undefined");
1800 return;
1801 }
1802
1803 saveElmerMesh(saveDirName);
1804 }
1805
1806 // File -> Save project
1807 //-----------------------------------------------------------------------------
saveProjectSlot()1808 void MainWindow::saveProjectSlot() {
1809 if (!glWidget->hasMesh()) {
1810 logMessage("Unable to save project: no mesh");
1811 return;
1812 }
1813
1814 QString projectDirName = currentProjectDirName;
1815 if (!projectDirName.isEmpty()) {
1816 logMessage("Project directory " + projectDirName);
1817 saveProject(projectDirName);
1818 } else {
1819 saveProjectAsSlot();
1820 }
1821 }
1822
1823 // File -> Save project as...
1824 //-----------------------------------------------------------------------------
saveProjectAsSlot()1825 void MainWindow::saveProjectAsSlot() {
1826 if (!glWidget->hasMesh()) {
1827 logMessage("Unable to save project: no mesh");
1828 return;
1829 }
1830
1831 QString defaultDirName = getDefaultDirName();
1832
1833 QString projectDirName = QFileDialog::getExistingDirectory(
1834 this, tr("Open directory to save project"), defaultDirName);
1835
1836 if (!projectDirName.isEmpty()) {
1837 logMessage("Project directory " + projectDirName);
1838 } else {
1839 logMessage("Unable to save project: directory undefined");
1840 return;
1841 }
1842
1843 saveProject(projectDirName);
1844 }
1845
saveProject(QString projectDirName)1846 bool MainWindow::saveProject(QString projectDirName) {
1847 if (!glWidget->hasMesh()) {
1848 logMessage("Unable to save project: no mesh");
1849 return false;
1850 }
1851
1852 progressBar->show();
1853 progressBar->setRange(0, 13);
1854
1855 progressLabel->setText("Saving");
1856 progressLabel->show();
1857
1858 // Create project document:
1859 //-------------------------
1860 progressBar->setValue(1);
1861
1862 QDomDocument projectDoc("egproject");
1863 QDomElement contents = projectDoc.createElement("contents");
1864 projectDoc.appendChild(contents);
1865
1866 //===========================================================================
1867 // SAVE MESH
1868 //===========================================================================
1869 progressBar->setValue(2);
1870 logMessage("Saving mesh files...");
1871 saveElmerMesh(projectDirName);
1872
1873 //===========================================================================
1874 // SAVE GEOMETRY INPUT FILE(S)
1875 //===========================================================================
1876 progressBar->setValue(3);
1877
1878 #ifdef Q_OS_LINUX
1879 QFileInfo fileInfo(geometryInputFileName);
1880 QString pathName(fileInfo.absolutePath());
1881 QString baseName(fileInfo.baseName());
1882
1883 // System copy command:
1884 QString cmd("cp -f " + pathName + "/" + baseName + ".* " + projectDirName);
1885
1886 if (system(cmd.toLatin1().data()))
1887 logMessage("Geometry input file(s) not copied");
1888
1889 QDomElement geomInput(projectDoc.createElement("geometryinputfile"));
1890 QDomText geomInputValue(projectDoc.createTextNode(fileInfo.fileName()));
1891 geomInput.appendChild(geomInputValue);
1892 contents.appendChild(geomInput);
1893
1894 #else
1895 QFileInfo geometryInputFileInfo(geometryInputFileName);
1896 QString baseName(geometryInputFileInfo.baseName());
1897
1898 QString srcPathName(geometryInputFileInfo.absolutePath());
1899 QString dstPathName(QDir(projectDirName).absolutePath());
1900
1901 // Avoid copying file(s) into it self:
1902
1903 if (srcPathName != dstPathName) {
1904 QDirIterator srcDirIterator(srcPathName);
1905
1906 while (srcDirIterator.hasNext()) {
1907 QString srcFileName(srcDirIterator.next());
1908 QFileInfo srcFileInfo(srcDirIterator.fileInfo());
1909
1910 if (srcFileInfo.baseName() == baseName) {
1911 logMessage("Copying: " + srcFileName);
1912
1913 QFile src(srcFileName);
1914
1915 if (!src.open(QFile::ReadOnly)) {
1916 logMessage("Unable to read: " + src.fileName());
1917 continue;
1918 }
1919
1920 QFile dst(dstPathName + "/" + srcFileInfo.fileName());
1921
1922 if (!dst.open(QFile::WriteOnly)) {
1923 logMessage("Unable to write: " + dst.fileName());
1924 src.close();
1925 continue;
1926 }
1927
1928 QTextStream srcStream(&src);
1929 QTextStream dstStream(&dst);
1930 dstStream << srcStream.readAll();
1931
1932 dst.close();
1933 src.close();
1934 }
1935 }
1936
1937 } else {
1938 logMessage("Geometry input file(s) not copied");
1939 }
1940
1941 QDomElement geomInput = projectDoc.createElement("geometryinputfile");
1942 QDomText geomInputValue =
1943 projectDoc.createTextNode(geometryInputFileInfo.fileName());
1944 geomInput.appendChild(geomInputValue);
1945 contents.appendChild(geomInput);
1946 #endif
1947
1948 //===========================================================================
1949 // SAVE OPERATIONS
1950 //===========================================================================
1951 progressBar->setValue(4);
1952 QDomElement ops = projectDoc.createElement("operations");
1953 contents.appendChild(ops);
1954 operation.appendToProject(&projectDoc, &ops);
1955
1956 //===========================================================================
1957 // SAVE GENERAL SETUP
1958 //===========================================================================
1959 progressBar->setValue(5);
1960 logMessage("Saving menu contents... ");
1961 QDomElement gsBlock = projectDoc.createElement("generalsetup");
1962 projectDoc.documentElement().appendChild(gsBlock);
1963 generalSetup->appendToProject(&projectDoc, &gsBlock);
1964
1965 //===========================================================================
1966 // SAVE PARALLEL SETTINGS
1967 //===========================================================================
1968 progressBar->setValue(6);
1969 QDomElement paraBlock = projectDoc.createElement("parallelsettings");
1970 projectDoc.documentElement().appendChild(paraBlock);
1971 parallel->appendToProject(&projectDoc, ¶Block);
1972
1973 //===========================================================================
1974 // SAVE MESH PARAMETERS
1975 //===========================================================================
1976 progressBar->setValue(7);
1977 QDomElement meshParams = projectDoc.createElement("meshparameters");
1978 projectDoc.documentElement().appendChild(meshParams);
1979 meshControl->appendToProject(&projectDoc, &meshParams);
1980
1981 //===========================================================================
1982 // SAVE SOLVER PARAMETERS
1983 //===========================================================================
1984 progressBar->setValue(8);
1985 QDomElement speBlock = projectDoc.createElement("solverparameters");
1986 projectDoc.documentElement().appendChild(speBlock);
1987
1988 for (int index = 0; index < solverParameterEditor.size(); index++) {
1989 SolverParameterEditor *spe = solverParameterEditor[index];
1990
1991 if (!spe)
1992 continue;
1993
1994 QDomElement item = projectDoc.createElement("item");
1995 item.setAttribute("index", QString::number(index));
1996 item.setAttribute("name", spe->solverName);
1997 speBlock.appendChild(item);
1998 spe->appendToProject(&projectDoc, &item);
1999 }
2000
2001 //===========================================================================
2002 // SAVE DYNAMIC MENU CONTENTS
2003 //===========================================================================
2004 progressBar->setValue(9);
2005 saveProjectContents(projectDoc, "equation", equationEditor);
2006 saveProjectContents(projectDoc, "material", materialEditor);
2007 saveProjectContents(projectDoc, "bodyforce", bodyForceEditor);
2008 saveProjectContents(projectDoc, "initialcondition", initialConditionEditor);
2009 saveProjectContents(projectDoc, "boundarycondition", boundaryConditionEditor);
2010
2011 //===========================================================================
2012 // SAVE SOLVER SPECIFIC OPTIONS
2013 //===========================================================================
2014 progressBar->setValue(10);
2015 QDomElement solverOptionsBlock =
2016 projectDoc.createElement("solverspecificoptions");
2017 projectDoc.documentElement().appendChild(solverOptionsBlock);
2018
2019 for (int index = 0; index < solverParameterEditor.size(); index++) {
2020 SolverParameterEditor *spe = solverParameterEditor[index];
2021
2022 if (!spe)
2023 continue;
2024
2025 DynamicEditor *dynEdit = spe->generalOptions;
2026
2027 if (!dynEdit)
2028 continue;
2029
2030 QDomElement item = projectDoc.createElement("item");
2031 item.setAttribute("index", QString::number(index));
2032 item.setAttribute("name", spe->solverName);
2033 item.setAttribute("id", QString::number(dynEdit->ID));
2034 solverOptionsBlock.appendChild(item);
2035
2036 dynEdit->dumpHash(&projectDoc, &item);
2037 }
2038
2039 //===========================================================================
2040 // SAVE BODY PROPERTIES
2041 //===========================================================================
2042 progressBar->setValue(11);
2043 QDomElement bodyBlock = projectDoc.createElement("bodyproperties");
2044 projectDoc.documentElement().appendChild(bodyBlock);
2045
2046 for (int index = 0; index < bodyPropertyEditor.size(); index++) {
2047 BodyPropertyEditor *bpe = bodyPropertyEditor[index];
2048
2049 if (!bpe)
2050 continue;
2051
2052 QDomElement item = projectDoc.createElement("item");
2053 item.setAttribute("index", QString::number(index));
2054 bodyBlock.appendChild(item);
2055 bpe->appendToProject(&projectDoc, &item);
2056 }
2057
2058 //===========================================================================
2059 // SAVE BOUNDARY PROPERTIES
2060 //===========================================================================
2061 progressBar->setValue(12);
2062 QDomElement boundaryBlock = projectDoc.createElement("boundaryproperties");
2063 projectDoc.documentElement().appendChild(boundaryBlock);
2064
2065 for (int index = 0; index < boundaryPropertyEditor.size(); index++) {
2066 BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2067
2068 if (!bpe)
2069 continue;
2070
2071 QDomElement item = projectDoc.createElement("item");
2072 item.setAttribute("index", QString::number(index));
2073 boundaryBlock.appendChild(item);
2074 bpe->appendToProject(&projectDoc, &item);
2075 }
2076
2077 //===========================================================================
2078 // SAVE PROJECT DOCUMENT
2079 //===========================================================================
2080 progressBar->setValue(13);
2081 const int indent = 3;
2082 QFile projectFile("egproject.xml");
2083 projectFile.open(QIODevice::WriteOnly);
2084 QTextStream projectTextStream(&projectFile);
2085 projectDoc.save(projectTextStream, indent);
2086
2087 saveDirName = projectDirName;
2088 logMessage("Ready");
2089
2090 progressBar->hide();
2091 progressLabel->hide();
2092
2093 setWindowTitle(QString("ElmerGUI - ") + projectDirName);
2094 addRecentProject(projectDirName, true);
2095 currentProjectDirName = projectDirName;
2096
2097 return true;
2098 }
2099
2100 // Helper function for saveProject
2101 //-----------------------------------------------------------------------------
saveProjectContents(QDomDocument projectDoc,QString blockName,QVector<DynamicEditor * > & editor)2102 void MainWindow::saveProjectContents(QDomDocument projectDoc, QString blockName,
2103 QVector<DynamicEditor *> &editor) {
2104 int Nmax = editor.size();
2105
2106 QDomElement editorBlock = projectDoc.createElement(blockName);
2107 projectDoc.documentElement().appendChild(editorBlock);
2108 int index = 0; // index excluding removed DynamicEditor instances
2109
2110 for (int i = 0; i < Nmax; i++) {
2111 DynamicEditor *de = editor[i];
2112
2113 if (de->menuAction == NULL)
2114 continue;
2115
2116 // Menu item number:
2117 QDomElement item = projectDoc.createElement("item");
2118 item.setAttribute("index", QString::number(index++));
2119 editorBlock.appendChild(item);
2120
2121 // Is active?
2122 QDomElement itemActive = projectDoc.createElement("active");
2123 QDomText itemActiveValue =
2124 projectDoc.createTextNode(QString::number(de->menuAction != NULL));
2125 itemActive.appendChild(itemActiveValue);
2126 item.appendChild(itemActive);
2127
2128 // Name:
2129 if (de->menuAction != NULL) {
2130 QDomElement itemName = projectDoc.createElement("name");
2131 QDomText itemNameValue =
2132 projectDoc.createTextNode(de->nameEdit->text().trimmed());
2133 itemName.appendChild(itemNameValue);
2134 item.appendChild(itemName);
2135 }
2136
2137 de->dumpHash(&projectDoc, &item);
2138 }
2139 }
2140
2141 // File -> Load project...
2142 //-----------------------------------------------------------------------------
loadProjectSlot()2143 void MainWindow::loadProjectSlot() {
2144 QString defaultDirName = getDefaultDirName();
2145
2146 QString projectDirName = QFileDialog::getExistingDirectory(
2147 this, tr("Open project directory"), defaultDirName);
2148
2149 loadProject(projectDirName);
2150 }
2151
loadProject(QString projectDirName)2152 void MainWindow::loadProject(QString projectDirName) {
2153 if (!projectDirName.isEmpty()) {
2154 logMessage("Project directory: " + projectDirName);
2155 } else {
2156 logMessage("Unable to load project: directory undefined");
2157 return;
2158 }
2159
2160 QDir::setCurrent(projectDirName);
2161 saveDirName = projectDirName;
2162
2163 progressBar->show();
2164 progressBar->setRange(0, 14);
2165
2166 progressLabel->setText("Loading");
2167 progressLabel->show();
2168
2169 // Clear previous data:
2170 //----------------------
2171 progressBar->setValue(1);
2172
2173 logMessage("Clearing model data");
2174 modelClearSlot();
2175
2176 // Re-initialize definitions and edfEditor
2177 delete elmerDefs;
2178 delete edfEditor;
2179 elmerDefs = new QDomDocument;
2180 edfEditor = new EdfEditor;
2181 loadDefinitions();
2182
2183 // Load project doc:
2184 //-------------------
2185 progressBar->setValue(2);
2186
2187 logMessage("Loading project document...");
2188 QDomDocument projectDoc;
2189 QString errStr;
2190 int errRow;
2191 int errCol;
2192 QFile projectFile("egproject.xml");
2193
2194 if (!projectFile.exists()) {
2195 QMessageBox::information(window(), tr("Project loader"),
2196 tr("Project file does not exist"));
2197
2198 progressBar->hide();
2199 progressLabel->hide();
2200
2201 return;
2202
2203 } else {
2204
2205 if (!projectDoc.setContent(&projectFile, true, &errStr, &errRow, &errCol)) {
2206 QMessageBox::information(window(), tr("Project loader"),
2207 tr("Parse error at line %1, col %2:\n%3")
2208 .arg(errRow)
2209 .arg(errCol)
2210 .arg(errStr));
2211 projectFile.close();
2212
2213 progressBar->hide();
2214 progressLabel->hide();
2215
2216 return;
2217 }
2218 }
2219
2220 projectFile.close();
2221
2222 if (projectDoc.documentElement().tagName() != "contents") {
2223 QMessageBox::information(window(), tr("Project loader"),
2224 tr("This is not a project file"));
2225
2226 progressBar->hide();
2227 progressLabel->hide();
2228
2229 return;
2230 }
2231
2232 // load extra solvers from /edf-extra
2233 checkAndLoadExtraSolvers(&projectFile);
2234
2235 setWindowTitle(QString("ElmerGUI - ") + projectDirName);
2236 addRecentProject(projectDirName, true);
2237 currentProjectDirName = projectDirName;
2238
2239 QDomElement contents = projectDoc.documentElement();
2240
2241 //===========================================================================
2242 // LOAD MESH
2243 //===========================================================================
2244 progressBar->setValue(3);
2245 logMessage("Loading mesh files...");
2246 loadElmerMesh(projectDirName);
2247 resetSlot();
2248
2249 //===========================================================================
2250 // LOAD GEOMETRY INPUT FILE
2251 //===========================================================================
2252 progressBar->setValue(4);
2253 cout << "Loading geometry input file" << endl;
2254 QDomElement geomInput = contents.firstChildElement("geometryinputfile");
2255 geometryInputFileName = projectDirName + "/" + geomInput.text().trimmed();
2256 logMessage("Geometry input file: " + geometryInputFileName);
2257 readInputFile(geometryInputFileName);
2258
2259 //===========================================================================
2260 // LOAD OPERATIONS
2261 //===========================================================================
2262 logMessage("Loading operations...");
2263 progressBar->setValue(5);
2264 QDomElement ops = contents.firstChildElement("operations");
2265 operations = operation.readFromProject(&projectDoc, &ops);
2266
2267 //===========================================================================
2268 // LOAD GENERAL SETUP
2269 //===========================================================================
2270 logMessage("Loading general setup...");
2271 progressBar->setValue(6);
2272 QDomElement gsBlock = contents.firstChildElement("generalsetup");
2273 generalSetup->readFromProject(&projectDoc, &gsBlock);
2274
2275 //===========================================================================
2276 // LOAD PARALLEL SETTINGS
2277 //===========================================================================
2278 logMessage("Loading parallel settings...");
2279 progressBar->setValue(7);
2280 QDomElement paraBlock = contents.firstChildElement("parallelsettings");
2281 parallel->readFromProject(&projectDoc, ¶Block);
2282
2283 //===========================================================================
2284 // LOAD MESH PARAMETERS
2285 //===========================================================================
2286 logMessage("Loading mesh parameters...");
2287 progressBar->setValue(8);
2288 QDomElement meshParams = contents.firstChildElement("meshparameters");
2289 meshControl->readFromProject(&projectDoc, &meshParams);
2290
2291 //===========================================================================
2292 // LOAD SOLVER PARAMETERS
2293 //===========================================================================
2294 logMessage("Loading solver parameters...");
2295 progressBar->setValue(9);
2296 QDomElement speBlock = contents.firstChildElement("solverparameters");
2297
2298 QDomElement item = speBlock.firstChildElement("item");
2299 for (; !item.isNull(); item = item.nextSiblingElement()) {
2300 int index = item.attribute("index").toInt();
2301 QString name = item.attribute("name");
2302
2303 if (name.trimmed().isEmpty())
2304 continue;
2305
2306 // Find the real index for the current edf setup:
2307 int count = 0, realIndex = -1;
2308 QDomElement root = elmerDefs->documentElement();
2309 QDomElement elem = root.firstChildElement("PDE");
2310 while (!elem.isNull()) {
2311 QDomElement pdeName = elem.firstChildElement("Name");
2312 if (pdeName.text().trimmed() == name.trimmed())
2313 realIndex = count;
2314 elem = elem.nextSiblingElement();
2315 count++;
2316 }
2317
2318 if (realIndex < 0) {
2319 cout << "ERROR: The current edf setup conflicts with the project. "
2320 "Aborting."
2321 << endl;
2322
2323 progressBar->hide();
2324 progressLabel->hide();
2325
2326 return;
2327 }
2328
2329 index = realIndex - 1;
2330
2331 if (index < 0) {
2332 logMessage("Load project: solver parameters: index out of bounds");
2333
2334 progressBar->hide();
2335 progressLabel->hide();
2336
2337 return;
2338 }
2339
2340 if (index >= solverParameterEditor.size())
2341 solverParameterEditor.resize(index + 1);
2342
2343 if (!solverParameterEditor[index])
2344 solverParameterEditor[index] = new SolverParameterEditor;
2345
2346 SolverParameterEditor *spe = solverParameterEditor[index];
2347 spe->readFromProject(&projectDoc, &item);
2348 }
2349
2350 #if 0
2351 // Changed the load order in 19 March 2009 for taking the "use as a body"
2352 // flags into account. The original boundary property loader is below.
2353 //
2354 // Changed back to original 23 March 2009. Todo...
2355 //===========================================================================
2356 // LOAD BOUNDARY PROPERTIES
2357 //===========================================================================
2358 progressBar->setValue(10);
2359 QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");
2360
2361 item = boundaryBlock.firstChildElement("item");
2362 for( ; !item.isNull(); item = item.nextSiblingElement()) {
2363 int index = item.attribute("index").toInt();
2364
2365 if(index < 0) {
2366 logMessage("Load project: boundary properties: index out of bounds");
2367
2368 progressBar->hide();
2369 progressLabel->hide();
2370
2371 return;
2372 }
2373
2374 if(index >= boundaryPropertyEditor.size())
2375 boundaryPropertyEditor.resize(index + 1);
2376
2377 if(!boundaryPropertyEditor[index])
2378 boundaryPropertyEditor[index] = new BoundaryPropertyEditor;
2379
2380 BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2381
2382 bpe->readFromProject(&projectDoc, &item);
2383
2384 if(bpe->ui.boundaryAsABody->isChecked()) {
2385 connect(bpe, SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor*, int)),
2386 this, SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor*, int)));
2387
2388 populateBoundaryComboBoxes(bpe);
2389
2390 bpe->ui.boundaryAsABody->toggle();
2391 bpe->ui.boundaryAsABody->toggle();
2392 bpe->ui.applyButton->click();
2393 }
2394 }
2395 #endif
2396
2397 //===========================================================================
2398 // LOAD DYNAMIC EDITOR CONTENTS
2399 //===========================================================================
2400 logMessage("Loading dynamic editor contents...");
2401 progressBar->setValue(11);
2402 QDomElement element =
2403 projectDoc.documentElement().firstChildElement("equation");
2404 loadProjectContents(element, equationEditor, "Equation");
2405 element = projectDoc.documentElement().firstChildElement("material");
2406 loadProjectContents(element, materialEditor, "Material");
2407 element = projectDoc.documentElement().firstChildElement("bodyforce");
2408 loadProjectContents(element, bodyForceEditor, "BodyForce");
2409 element = projectDoc.documentElement().firstChildElement("initialcondition");
2410 loadProjectContents(element, initialConditionEditor, "InitialCondition");
2411 element = projectDoc.documentElement().firstChildElement("boundarycondition");
2412 loadProjectContents(element, boundaryConditionEditor, "BoundaryCondition");
2413
2414 //===========================================================================
2415 // LOAD SOLVER SPECIFIC OPTIONS
2416 //===========================================================================
2417 logMessage("Loading solver specific options...");
2418 progressBar->setValue(12);
2419 QDomElement solverOptionsBlock =
2420 contents.firstChildElement("solverspecificoptions");
2421
2422 for (item = solverOptionsBlock.firstChildElement("item"); !item.isNull();
2423 item = item.nextSiblingElement()) {
2424
2425 int index = item.attribute("index").toInt();
2426 QString name = item.attribute("name");
2427 int id = item.attribute("id").toInt();
2428
2429 if (name.trimmed().isEmpty())
2430 continue;
2431
2432 // Find the real index for the current edf setup:
2433 int count = 0, realIndex = -1;
2434 QDomElement root = elmerDefs->documentElement();
2435 QDomElement elem = root.firstChildElement("PDE");
2436 while (!elem.isNull()) {
2437 QDomElement pdeName = elem.firstChildElement("Name");
2438 if (pdeName.text().trimmed() == name.trimmed())
2439 realIndex = count;
2440 elem = elem.nextSiblingElement();
2441 count++;
2442 }
2443
2444 if (realIndex < 0) {
2445 cout << "ERROR: The current edf setup conflicts with the project. "
2446 "Aborting."
2447 << endl;
2448
2449 progressBar->hide();
2450 progressLabel->hide();
2451
2452 return;
2453 }
2454
2455 index = realIndex - 1;
2456
2457 if (index < 0) {
2458 logMessage("Load project: solver specific options: index out of bounds");
2459
2460 progressBar->hide();
2461 progressLabel->hide();
2462
2463 return;
2464 }
2465
2466 if (index >= solverParameterEditor.size())
2467 solverParameterEditor.resize(index + 1);
2468
2469 if (!solverParameterEditor[index])
2470 solverParameterEditor[index] = new SolverParameterEditor;
2471
2472 SolverParameterEditor *spe = solverParameterEditor[index];
2473 spe->solverName = name;
2474
2475 if (spe->generalOptions == NULL) {
2476 spe->generalOptions = new DynamicEditor;
2477
2478 // following 3 lines were moved into if() block to avoid doubled "Solver
2479 // specific options" tabs (Nov 2019 by TS)
2480 spe->generalOptions->setupTabs(elmerDefs, "Solver", id);
2481 spe->generalOptions->populateHash(&item);
2482 spe->ui.solverControlTabs->insertTab(
2483 0, spe->generalOptions->tabWidget->widget(id),
2484 "Solver specific options");
2485 }
2486 }
2487
2488 //===========================================================================
2489 // LOAD BODY PROPERTIES
2490 //===========================================================================
2491 logMessage("Loading body properties...");
2492 progressBar->setValue(13);
2493 QDomElement bodyBlock = contents.firstChildElement("bodyproperties");
2494
2495 item = bodyBlock.firstChildElement("item");
2496 for (; !item.isNull(); item = item.nextSiblingElement()) {
2497 int index = item.attribute("index").toInt();
2498
2499 if (index < 0) {
2500 logMessage("Load project: body properties: index out of bounds");
2501
2502 progressBar->hide();
2503 progressLabel->hide();
2504
2505 return;
2506 }
2507
2508 if (index >= bodyPropertyEditor.size())
2509 bodyPropertyEditor.resize(index + 1);
2510
2511 if (!bodyPropertyEditor[index])
2512 bodyPropertyEditor[index] = new BodyPropertyEditor;
2513
2514 BodyPropertyEditor *bpe = bodyPropertyEditor[index];
2515 bpe->readFromProject(&projectDoc, &item);
2516 }
2517
2518 //===========================================================================
2519 // LOAD BOUNDARY PROPERTIES
2520 //===========================================================================
2521 logMessage("Loading boundary properties...");
2522 progressBar->setValue(13);
2523 QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");
2524
2525 item = boundaryBlock.firstChildElement("item");
2526 for (; !item.isNull(); item = item.nextSiblingElement()) {
2527 int index = item.attribute("index").toInt();
2528
2529 if (index < 0) {
2530 logMessage("Load project: boundary properties: index out of bounds");
2531
2532 progressBar->hide();
2533 progressLabel->hide();
2534
2535 return;
2536 }
2537
2538 if (index >= boundaryPropertyEditor.size())
2539 boundaryPropertyEditor.resize(index + 1);
2540
2541 if (!boundaryPropertyEditor[index])
2542 boundaryPropertyEditor[index] = new BoundaryPropertyEditor;
2543
2544 BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2545 bpe->readFromProject(&projectDoc, &item);
2546 }
2547
2548 //===========================================================================
2549 // LOAD SIF
2550 //===========================================================================
2551 progressBar->setValue(14);
2552 if (glWidget->hasMesh()) {
2553 QFile file;
2554 QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();
2555 file.setFileName(sifName);
2556 if (file.open(QIODevice::ReadOnly)) {
2557 QTextStream inputStream(&file);
2558 QString line = inputStream.readAll();
2559 file.close();
2560 sifWindow->getTextEdit()->clear();
2561 sifWindow->getTextEdit()->append(line);
2562 sifWindow->setFirstTime(true);
2563 sifWindow->setFound(false);
2564 logMessage(sifName + " loaded.");
2565 } else {
2566 logMessage(" failed to open " + sifName);
2567 }
2568 }
2569
2570 logMessage("Ready");
2571
2572 progressBar->hide();
2573 progressLabel->hide();
2574 }
2575
2576 // Helper function for load project
2577 //--------------------------------------------------------------------------------------------
loadProjectContents(QDomElement projectElement,QVector<DynamicEditor * > & editor,QString Mname)2578 void MainWindow::loadProjectContents(QDomElement projectElement,
2579 QVector<DynamicEditor *> &editor,
2580 QString Mname) {
2581 int Nmax = editor.size();
2582
2583 QDomElement item = projectElement.firstChildElement("item");
2584
2585 for (; !item.isNull(); item = item.nextSiblingElement()) {
2586 int index = item.attribute("index").toInt();
2587
2588 if (index < 0) {
2589 logMessage("Project loader: index out of bounds (dynamic editor)");
2590 return;
2591 }
2592
2593 if (index >= editor.size())
2594 editor.resize(index + 1);
2595
2596 if (!editor[index])
2597 editor[index] = new DynamicEditor;
2598
2599 DynamicEditor *de = editor[index];
2600
2601 bool active = (item.firstChildElement("active").text().toInt() > 0);
2602
2603 if (!active)
2604 continue;
2605
2606 // Set up dynamic editor and connect:
2607 //------------------------------------
2608 QString itemName = item.firstChildElement("name").text().trimmed();
2609
2610 de->setupTabs(elmerDefs, Mname, index);
2611 de->nameEdit->setText(itemName);
2612 de->applyButton->setText("Update");
2613 de->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
2614 de->discardButton->setText("Remove");
2615 de->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
2616
2617 const QString &tmpName = itemName;
2618 QAction *act = new QAction(tmpName, this);
2619
2620 if (Mname == "Equation") {
2621 connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2622 SLOT(pdeEditorFinishedSlot(int, int)));
2623 de->spareButton->setText("Edit Solver Settings");
2624 de->spareButton->show();
2625 de->spareButton->setIcon(QIcon(":/icons/tools-wizard.png"));
2626 connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
2627 SLOT(editNumericalMethods(int, int)));
2628 equationMenu->addAction(act);
2629 }
2630
2631 if (Mname == "Material") {
2632 connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2633 SLOT(matEditorFinishedSlot(int, int)));
2634 de->spareButton->setText("Material library");
2635 de->spareButton->show();
2636 de->spareButton->setIcon(QIcon(":/icons/tools-wizard.png"));
2637 connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
2638 SLOT(showMaterialLibrary(int, int)));
2639 materialMenu->addAction(act);
2640 }
2641
2642 if (Mname == "BodyForce") {
2643 connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2644 SLOT(bodyForceEditorFinishedSlot(int, int)));
2645 bodyForceMenu->addAction(act);
2646 }
2647
2648 if (Mname == "InitialCondition") {
2649 connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2650 SLOT(initialConditionEditorFinishedSlot(int, int)));
2651 initialConditionMenu->addAction(act);
2652 }
2653
2654 if (Mname == "BoundaryCondition") {
2655 connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2656 SLOT(boundaryConditionEditorFinishedSlot(int, int)));
2657 boundaryConditionMenu->addAction(act);
2658 }
2659
2660 de->menuAction = act;
2661
2662 if (Mname == "Equation")
2663 createBodyCheckBoxes(BODY_EQUATION, de);
2664
2665 if (Mname == "Material")
2666 createBodyCheckBoxes(BODY_MATERIAL, de);
2667
2668 if (Mname == "BodyForce")
2669 createBodyCheckBoxes(BODY_FORCE, de);
2670
2671 if (Mname == "InitialCondition")
2672 createBodyCheckBoxes(BODY_INITIAL, de);
2673
2674 if (Mname == "BoundaryCondition")
2675 createBoundaryCheckBoxes(de);
2676
2677 de->populateHash(&item);
2678 }
2679 }
2680
2681 // Export mesh files in elmer-format:
2682 //-----------------------------------------------------------------------------
saveElmerMesh(QString dirName)2683 void MainWindow::saveElmerMesh(QString dirName) {
2684 logMessage("Saving elmer mesh files");
2685
2686 QDir dir(dirName);
2687
2688 if (!dir.exists())
2689 dir.mkdir(dirName);
2690
2691 dir.setCurrent(dirName);
2692
2693 // Save mesh files:
2694 //------------------
2695 #if WITH_QT5
2696 glWidget->getMesh()->save(dirName.toLatin1().data());
2697 #else
2698 glWidget->getMesh()->save(dirName.toAscii().data());
2699 #endif
2700
2701 // Save solver input file:
2702 //-------------------------
2703 QFile file;
2704 QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();
2705 file.setFileName(sifName);
2706 file.open(QIODevice::WriteOnly);
2707 QTextStream sif(&file);
2708
2709 QApplication::setOverrideCursor(Qt::WaitCursor);
2710 sif << sifWindow->getTextEdit()->toPlainText();
2711 QApplication::restoreOverrideCursor();
2712
2713 file.close();
2714
2715 // Save ELMERSOLVER_STARTINFO:
2716 //-----------------------------
2717 file.setFileName("ELMERSOLVER_STARTINFO");
2718 file.open(QIODevice::WriteOnly);
2719 QTextStream startinfo(&file);
2720
2721 #if WITH_QT5
2722 startinfo << sifName.toLatin1() << endl << "1" << endl;
2723 #else
2724 startinfo << sifName.toAscii() << endl << "1" << endl;
2725 #endif
2726
2727 file.close();
2728
2729 logMessage("Ready");
2730 }
2731
2732 // File -> Exit
2733 //-----------------------------------------------------------------------------
closeMainWindowSlot()2734 void MainWindow::closeMainWindowSlot() {
2735 saveSlot();
2736 QApplication::closeAllWindows();
2737 // close();
2738 }
2739
2740 // File -> Save picture as...
2741 //-----------------------------------------------------------------------------
savePictureSlot()2742 void MainWindow::savePictureSlot() {
2743 QString defaultDirName(getDefaultDirName());
2744
2745 pictureFileName = QFileDialog::getSaveFileName(
2746 this, tr("Save picture"), defaultDirName,
2747 tr("Picture files (*.bmp *.jpg *.png *.pbm *.pgm *.ppm)"));
2748
2749 if (pictureFileName.isEmpty()) {
2750 logMessage("File name is empty");
2751 return;
2752 }
2753
2754 int delay = egIni->value("screenshotdelay").toInt();
2755
2756 grabTimeLine->stop();
2757 grabTimeLine->setDuration(delay);
2758 grabTimeLine->setCurveShape(QTimeLine::LinearCurve);
2759 grabTimeLine->setDirection(QTimeLine::Backward);
2760 grabTimeLine->setFrameRange(0, 10);
2761 progressLabel->setText("Delay screen shot");
2762 progressLabel->show();
2763 progressBar->setRange(0, 10);
2764 progressBar->show();
2765 grabTimeLine->start();
2766 }
2767
grabFrameSlot()2768 void MainWindow::grabFrameSlot() {
2769 progressLabel->hide();
2770 progressBar->hide();
2771
2772 if (pictureFileName.isEmpty()) {
2773 logMessage("Unable to take screen shot - file name is empty");
2774 return;
2775 }
2776
2777 QFileInfo fi(pictureFileName);
2778 QString suffix(fi.suffix());
2779 suffix.toUpper();
2780
2781 int imageQuality(egIni->value("defaultimagequality").toInt());
2782
2783 bool withAlpha(false);
2784
2785 glWidget->updateGL();
2786 glReadBuffer(GL_BACK);
2787
2788 QImage image(glWidget->grabFrameBuffer(withAlpha));
2789
2790 #if WITH_QT5
2791 bool success(image.save(pictureFileName, suffix.toLatin1(), imageQuality));
2792 #else
2793 bool success(image.save(pictureFileName, suffix.toAscii(), imageQuality));
2794 #endif
2795
2796 if (!success)
2797 logMessage("Failed writing picture file");
2798 }
2799
2800 //*****************************************************************************
2801 //
2802 // Model MENU
2803 //
2804 //*****************************************************************************
2805
2806 // Model -> Setup...
2807 //-----------------------------------------------------------------------------
modelSetupSlot()2808 void MainWindow::modelSetupSlot() { generalSetup->show(); }
2809
2810 //-----------------------------------------------------------------------------
createBodyCheckBoxes(int which,DynamicEditor * pe)2811 void MainWindow::createBodyCheckBoxes(int which, DynamicEditor *pe) {
2812 if (!glWidget->hasMesh())
2813 return;
2814
2815 if (pe->spareScroll->widget())
2816 delete pe->spareScroll->widget();
2817
2818 QGridLayout *slayout = new QGridLayout;
2819 QLabel *l = new QLabel(tr("Apply to bodies:"));
2820
2821 int count = 0, even = 0;
2822
2823 slayout->addWidget(l, count, 0);
2824 count++;
2825
2826 QMapIterator<int, int> itr(glWidget->bodyMap);
2827 while (itr.hasNext()) {
2828 itr.next();
2829 int n = itr.key();
2830 if (n >= 0) {
2831 int m = itr.value();
2832
2833 if (m >= bodyPropertyEditor.size())
2834 bodyPropertyEditor.resize(m + 1);
2835
2836 if (!bodyPropertyEditor[m])
2837 bodyPropertyEditor[m] = new BodyPropertyEditor;
2838
2839 BodyPropertyEditor *body = bodyPropertyEditor[m];
2840
2841 populateBodyComboBoxes(body);
2842
2843 QString title = body->ui.nameEdit->text().trimmed();
2844 QCheckBox *a;
2845
2846 if (title.isEmpty())
2847 // a = new QCheckBox("Body " + QString::number(n));
2848 a = new QCheckBox("Body Property " + QString::number(n));
2849 else
2850 a = new QCheckBox(title);
2851
2852 DynamicEditor *p = NULL;
2853
2854 switch (which) {
2855 case BODY_MATERIAL:
2856 p = body->material;
2857 connect(a, SIGNAL(stateChanged(int)), this,
2858 SLOT(materialBodyChanged(int)));
2859 break;
2860 case BODY_INITIAL:
2861 p = body->initial;
2862 connect(a, SIGNAL(stateChanged(int)), this,
2863 SLOT(initialBodyChanged(int)));
2864 break;
2865 case BODY_FORCE:
2866 p = body->force;
2867 connect(a, SIGNAL(stateChanged(int)), this,
2868 SLOT(forceBodyChanged(int)));
2869 break;
2870 case BODY_EQUATION:
2871 p = body->equation;
2872 connect(a, SIGNAL(stateChanged(int)), this,
2873 SLOT(equationBodyChanged(int)));
2874 break;
2875 }
2876
2877 a->setProperty("body", (qulonglong)body);
2878 a->setProperty("editor", (qulonglong)pe);
2879
2880 if (p == pe)
2881 a->setChecked(true);
2882 else if (p != NULL)
2883 a->setEnabled(false);
2884 else
2885 a->setChecked(false);
2886
2887 slayout->addWidget(a, count, even);
2888 even = 1 - even;
2889 if (!even)
2890 count++;
2891 }
2892 }
2893
2894 for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
2895 BoundaryPropertyEditor *boundary = boundaryPropertyEditor[i];
2896
2897 if (!boundary)
2898 continue;
2899
2900 if (boundary->bodyProperties) {
2901 BodyPropertyEditor *body = boundary->bodyProperties;
2902 populateBodyComboBoxes(body);
2903
2904 QString title = body->ui.nameEdit->text().trimmed();
2905 QCheckBox *a;
2906
2907 if (title.isEmpty())
2908 a = new QCheckBox("Body{Boundary " + QString::number(i) + "}");
2909 else
2910 a = new QCheckBox(title);
2911
2912 DynamicEditor *p = NULL;
2913
2914 switch (which) {
2915 case BODY_MATERIAL:
2916 p = body->material;
2917 connect(a, SIGNAL(stateChanged(int)), this,
2918 SLOT(materialBodyChanged(int)));
2919 break;
2920 case BODY_INITIAL:
2921 p = body->initial;
2922 connect(a, SIGNAL(stateChanged(int)), this,
2923 SLOT(initialBodyChanged(int)));
2924 break;
2925 case BODY_FORCE:
2926 p = body->force;
2927 connect(a, SIGNAL(stateChanged(int)), this,
2928 SLOT(forceBodyChanged(int)));
2929 break;
2930 case BODY_EQUATION:
2931 p = body->equation;
2932 connect(a, SIGNAL(stateChanged(int)), this,
2933 SLOT(equationBodyChanged(int)));
2934 break;
2935 }
2936
2937 a->setProperty("body", (qulonglong)body);
2938 a->setProperty("editor", (qulonglong)pe);
2939
2940 if (p == pe)
2941 a->setChecked(true);
2942 else if (p != NULL)
2943 a->setEnabled(false);
2944
2945 slayout->addWidget(a, count, even);
2946 even = 1 - even;
2947 if (!even)
2948 count++;
2949 }
2950 }
2951
2952 QGroupBox *box = new QGroupBox;
2953 box->setLayout(slayout);
2954
2955 pe->spareScroll->setWidget(box);
2956 pe->spareScroll->setMinimumHeight(80);
2957 pe->spareScroll->show();
2958 }
2959
2960 //-----------------------------------------------------------------------------
2961
2962 //*****************************************************************************
2963
2964 // Model -> Equation -> Add...
2965 //-----------------------------------------------------------------------------
addEquationSlot()2966 void MainWindow::addEquationSlot() {
2967 DynamicEditor *pe = new DynamicEditor;
2968 equationEditor.append(pe);
2969 int current = equationEditor.size() - 1;
2970
2971 pe->setupTabs(elmerDefs, "Equation", current);
2972
2973 pe->applyButton->setText("Add");
2974 pe->applyButton->setIcon(QIcon(":/icons/list-add.png"));
2975 pe->discardButton->setText("Cancel");
2976 pe->discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
2977 pe->show();
2978
2979 connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
2980 SLOT(pdeEditorFinishedSlot(int, int)));
2981
2982 // Use "spareButton" to invoke solver parameter editor:
2983 pe->spareButton->setText("Edit Solver Settings");
2984 pe->spareButton->show();
2985 pe->spareButton->setIcon(QIcon(":/icons/tools-wizard.png"));
2986 connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
2987 SLOT(editNumericalMethods(int, int)));
2988
2989 // Equation is new - add to menu:
2990 const QString &equationName = pe->nameEdit->text().trimmed();
2991 QAction *act = new QAction(equationName, this);
2992 equationMenu->addAction(act);
2993 pe->menuAction = act;
2994
2995 connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
2996 SLOT(dynamicEditorNameChange(QString)));
2997
2998 createBodyCheckBoxes(BODY_EQUATION, pe);
2999 }
3000
3001 // signal (int, int) emitted by dynamic editor when "spare button" clicked:
3002 //-----------------------------------------------------------------------------
editNumericalMethods(int current,int id)3003 void MainWindow::editNumericalMethods(int current, int id) {
3004 QString title = "";
3005
3006 for (int i = 0; i < equationEditor.size(); i++) {
3007 // ** 23/04/09 **
3008 if (equationEditor[i]->ID == id) {
3009 title = equationEditor[i]->tabWidget->tabText(current);
3010 break;
3011 }
3012 }
3013
3014 if (title == "General") {
3015 logMessage("No solver controls for 'General' equation options");
3016 return;
3017 }
3018
3019 if (current >= solverParameterEditor.size())
3020 solverParameterEditor.resize(current + 1);
3021
3022 if (!solverParameterEditor[current])
3023 solverParameterEditor[current] = new SolverParameterEditor;
3024
3025 SolverParameterEditor *spe = solverParameterEditor[current];
3026
3027 spe->setWindowTitle("Solver control for " + title);
3028
3029 spe->solverName = title;
3030
3031 if (spe->generalOptions == NULL) {
3032 spe->generalOptions = new DynamicEditor(spe);
3033 spe->generalOptions->setupTabs(elmerDefs, "Solver", current);
3034 spe->ui.solverControlTabs->insertTab(
3035 0, spe->generalOptions->tabWidget->widget(current),
3036 "Solver specific options");
3037
3038 #if 0
3039 for( int i=0; i < spe->generalOptions->tabWidget->count(); i++ )
3040 {
3041 if ( spe->generalOptions->tabWidget->tabText(i) == title )
3042 {
3043 spe->ui.solverControlTabs->insertTab(0, spe->generalOptions->tabWidget->widget(i),
3044 "Solver specific options");
3045 break;
3046 }
3047 }
3048 #endif
3049 }
3050
3051 spe->show();
3052 spe->raise();
3053 }
3054
dynamicEditorNameChange(QString t)3055 void MainWindow::dynamicEditorNameChange(QString t) {
3056 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3057 if (!bodyPropertyEditor[i])
3058 continue;
3059
3060 if (bodyPropertyEditor[i]->touched)
3061 populateBodyComboBoxes(bodyPropertyEditor[i]);
3062 }
3063
3064 for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
3065 if (!boundaryPropertyEditor[i])
3066 continue;
3067
3068 if (boundaryPropertyEditor[i]->touched)
3069 populateBoundaryComboBoxes(boundaryPropertyEditor[i]);
3070 }
3071 }
3072
3073 // signal (int,int) emitted by equation editor when ready:
3074 //-----------------------------------------------------------------------------
pdeEditorFinishedSlot(int signal,int id)3075 void MainWindow::pdeEditorFinishedSlot(int signal, int id) {
3076 DynamicEditor *pe = equationEditor[id];
3077
3078 const QString &equationName = pe->nameEdit->text().trimmed();
3079
3080 bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3081
3082 if ((equationName.isEmpty()) && signalOK) {
3083 logMessage("Refusing to add/update equation without name");
3084 return;
3085 }
3086
3087 if (signalOK) {
3088 if (pe->menuAction != NULL) {
3089 pe->menuAction->setText(equationName);
3090 logMessage("Equation updated");
3091 if (signal == MAT_OK)
3092 pe->close();
3093 }
3094 } else if (signal == MAT_NEW) {
3095 addEquationSlot();
3096
3097 } else if (signal == MAT_DELETE) {
3098
3099 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3100 BodyPropertyEditor *body = bodyPropertyEditor[i];
3101
3102 if (!body)
3103 continue;
3104
3105 if (body->equation == pe) {
3106 body->equation = NULL;
3107 body->ui.equationCombo->setCurrentIndex(0);
3108 body->touched = true;
3109 }
3110 }
3111
3112 // Equation is not in menu:
3113 if (pe->menuAction == NULL) {
3114 logMessage("Ready");
3115 pe->close();
3116 return;
3117 }
3118
3119 // Delete from menu:
3120 delete pe->menuAction;
3121 pe->menuAction = NULL;
3122 pe->close();
3123
3124 pe->ID = -100;
3125 pe->nameEdit->setText("");
3126
3127 logMessage("Equation deleted");
3128 }
3129 }
3130
3131 // signal (QAction*) emitted by equationMenu when an item has been selected:
3132 //-----------------------------------------------------------------------------
equationSelectedSlot(QAction * act)3133 void MainWindow::equationSelectedSlot(QAction *act) {
3134 // Edit the selected material:
3135 for (int i = 0; i < equationEditor.size(); i++) {
3136 DynamicEditor *pe = equationEditor[i];
3137 if (pe->menuAction == act) {
3138 pe->applyButton->setText("Update");
3139 pe->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
3140 pe->discardButton->setText("Remove");
3141 pe->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
3142 createBodyCheckBoxes(BODY_EQUATION, pe);
3143 pe->show();
3144 pe->raise();
3145 }
3146 }
3147 }
3148
3149 //-----------------------------------------------------------------------------
equationBodyChanged(int state)3150 void MainWindow::equationBodyChanged(int state) {
3151 QWidget *a = (QWidget *)QObject::sender();
3152 if (glWidget->getMesh()) {
3153 BodyPropertyEditor *body =
3154 (BodyPropertyEditor *)a->property("body").toULongLong();
3155 populateBodyComboBoxes(body);
3156 if (state) {
3157 DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3158 QString mat_name = mat->nameEdit->text().trimmed();
3159 int ind = body->ui.equationCombo->findText(mat_name);
3160 body->touched = true;
3161 body->equation = mat;
3162 body->ui.equationCombo->setCurrentIndex(ind);
3163 } else {
3164 body->equation = NULL;
3165 body->ui.equationCombo->setCurrentIndex(-1);
3166 }
3167 }
3168 }
3169
3170 //*****************************************************************************
3171
3172 // Model -> Material -> Add...
3173 //-----------------------------------------------------------------------------
addMaterialSlot()3174 void MainWindow::addMaterialSlot() {
3175 DynamicEditor *pe = new DynamicEditor;
3176 materialEditor.append(pe);
3177 int current = materialEditor.size() - 1;
3178
3179 pe->setupTabs(elmerDefs, "Material", current);
3180 pe->applyButton->setText("Add");
3181 pe->applyButton->setIcon(QIcon(":/icons/list-add.png"));
3182 pe->discardButton->setText("Cancel");
3183 pe->discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
3184
3185 connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3186 SLOT(matEditorFinishedSlot(int, int)));
3187
3188 // Use "spareButton" to invoke material library:
3189 pe->spareButton->setText("Material library");
3190 pe->spareButton->show();
3191 pe->spareButton->setIcon(QIcon(":/icons/tools-wizard.png"));
3192 connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
3193 SLOT(showMaterialLibrary(int, int)));
3194
3195 connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3196 SLOT(dynamicEditorNameChange(QString)));
3197
3198 // Material is new - add to menu:
3199 const QString &materialName = pe->nameEdit->text().trimmed();
3200 QAction *act = new QAction(materialName, this);
3201 materialMenu->addAction(act);
3202 pe->menuAction = act;
3203
3204 createBodyCheckBoxes(BODY_MATERIAL, pe);
3205 pe->show();
3206 pe->raise();
3207 }
3208
showMaterialLibrary(int tab,int ID)3209 void MainWindow::showMaterialLibrary(int tab, int ID) {
3210 materialLibrary->editor = materialEditor[ID];
3211 materialLibrary->elmerDefs = this->elmerDefs;
3212 materialLibrary->show();
3213 }
3214
3215 // signal (int,int) emitted by material editor when ready:
3216 //-----------------------------------------------------------------------------
matEditorFinishedSlot(int signal,int id)3217 void MainWindow::matEditorFinishedSlot(int signal, int id) {
3218 DynamicEditor *pe = materialEditor[id];
3219
3220 const QString &materialName = pe->nameEdit->text().trimmed();
3221
3222 bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3223 if (materialName.isEmpty() && signalOK) {
3224 logMessage("Refusing to add/update material with no name");
3225 return;
3226 }
3227
3228 if (signalOK) {
3229 if (pe->menuAction != NULL) {
3230 pe->menuAction->setText(materialName);
3231 logMessage("Material updated");
3232 if (signal == MAT_OK)
3233 pe->close();
3234 return;
3235 }
3236 } else if (signal == MAT_NEW) {
3237
3238 addMaterialSlot();
3239
3240 } else if (signal == MAT_DELETE) {
3241
3242 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3243 BodyPropertyEditor *body = bodyPropertyEditor[i];
3244
3245 if (!body)
3246 continue;
3247
3248 if (body->material == pe) {
3249 body->material = NULL;
3250 body->ui.materialCombo->setCurrentIndex(0);
3251 body->touched = true;
3252 }
3253 }
3254
3255 // Material is not in menu:
3256 if (pe->menuAction == NULL) {
3257 logMessage("Ready");
3258 pe->close();
3259 return;
3260 }
3261
3262 // Delete from menu:
3263 delete pe->menuAction;
3264 pe->menuAction = NULL;
3265 pe->close();
3266
3267 pe->ID = -100;
3268 pe->nameEdit->setText("");
3269
3270 logMessage("Material deleted");
3271
3272 } else {
3273 cout << "Matedit: unknown signal" << endl;
3274 }
3275 }
3276
3277 // signal (QAction*) emitted by materialMenu when an item has been selected:
3278 //-----------------------------------------------------------------------------
materialSelectedSlot(QAction * act)3279 void MainWindow::materialSelectedSlot(QAction *act) {
3280 // Edit the selected material:
3281 for (int i = 0; i < materialEditor.size(); i++) {
3282 DynamicEditor *pe = materialEditor[i];
3283
3284 if (pe->menuAction == act) {
3285 pe->applyButton->setText("Update");
3286 pe->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
3287 pe->discardButton->setText("Remove");
3288 pe->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
3289 createBodyCheckBoxes(BODY_MATERIAL, pe);
3290 pe->show();
3291 pe->raise();
3292 }
3293 }
3294 }
3295
materialBodyChanged(int state)3296 void MainWindow::materialBodyChanged(int state) {
3297 QWidget *a = (QWidget *)QObject::sender();
3298 if (glWidget->hasMesh()) {
3299 BodyPropertyEditor *body =
3300 (BodyPropertyEditor *)a->property("body").toULongLong();
3301 populateBodyComboBoxes(body);
3302
3303 if (state > 0) {
3304 DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3305 QString mat_name = mat->nameEdit->text().trimmed();
3306 int ind = body->ui.materialCombo->findText(mat_name);
3307
3308 body->touched = true;
3309 body->material = mat;
3310 body->ui.materialCombo->setCurrentIndex(ind);
3311 } else {
3312 body->material = NULL;
3313 body->ui.materialCombo->setCurrentIndex(-1);
3314 }
3315 }
3316 }
3317
3318 //*****************************************************************************
3319
3320 // Model -> Body force -> Add...
3321 //-----------------------------------------------------------------------------
addBodyForceSlot()3322 void MainWindow::addBodyForceSlot() {
3323 DynamicEditor *pe = new DynamicEditor;
3324 bodyForceEditor.append(pe);
3325 int current = bodyForceEditor.size() - 1;
3326
3327 pe->setupTabs(elmerDefs, "BodyForce", current);
3328
3329 pe->applyButton->setText("Add");
3330 pe->applyButton->setIcon(QIcon(":/icons/list-add.png"));
3331 pe->discardButton->setText("Cancel");
3332 pe->discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
3333
3334 connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3335 SLOT(bodyForceEditorFinishedSlot(int, int)));
3336
3337 // Body force is new - add to menu:
3338 const QString &bodyForceName = pe->nameEdit->text().trimmed();
3339 QAction *act = new QAction(bodyForceName, this);
3340 bodyForceMenu->addAction(act);
3341 pe->menuAction = act;
3342
3343 connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3344 SLOT(dynamicEditorNameChange(QString)));
3345
3346 createBodyCheckBoxes(BODY_FORCE, pe);
3347 pe->show();
3348 pe->raise();
3349 }
3350
3351 // signal (int,int) emitted by body force editor when ready:
3352 //-----------------------------------------------------------------------------
bodyForceEditorFinishedSlot(int signal,int id)3353 void MainWindow::bodyForceEditorFinishedSlot(int signal, int id) {
3354 DynamicEditor *pe = bodyForceEditor[id];
3355
3356 const QString &bodyForceName = pe->nameEdit->text().trimmed();
3357
3358 bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3359
3360 if ((bodyForceName.isEmpty()) && signalOK) {
3361 logMessage("Refusing to add/update body force with no name");
3362 return;
3363 }
3364
3365 if (signalOK) {
3366 if (pe->menuAction != NULL) {
3367 pe->menuAction->setText(bodyForceName);
3368 logMessage("Body force updated");
3369 if (signal == MAT_OK)
3370 pe->close();
3371 }
3372
3373 } else if (signal == MAT_NEW) {
3374 addBodyForceSlot();
3375
3376 } else if (signal == MAT_DELETE) {
3377 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3378 BodyPropertyEditor *body = bodyPropertyEditor[i];
3379
3380 if (!body)
3381 continue;
3382
3383 if (body->force == pe) {
3384 body->force = NULL;
3385 body->ui.bodyForceCombo->setCurrentIndex(0);
3386 body->touched = true;
3387 }
3388 }
3389
3390 if (pe->menuAction == NULL) {
3391 logMessage("Ready");
3392 pe->close();
3393 return;
3394 }
3395
3396 // Delete from menu:
3397 delete pe->menuAction;
3398 pe->menuAction = NULL;
3399 pe->close();
3400
3401 pe->ID = -100;
3402 pe->nameEdit->setText("");
3403
3404 logMessage("Body force deleted");
3405 }
3406 }
3407
3408 // signal (QAction*) emitted by bodyForceMenu when an item has been selected:
3409 //-----------------------------------------------------------------------------
bodyForceSelectedSlot(QAction * act)3410 void MainWindow::bodyForceSelectedSlot(QAction *act) {
3411 // Edit the selected body force:
3412 for (int i = 0; i < bodyForceEditor.size(); i++) {
3413 DynamicEditor *pe = bodyForceEditor[i];
3414 if (pe->menuAction == act) {
3415 pe->applyButton->setText("Update");
3416 pe->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
3417 pe->discardButton->setText("Remove");
3418 pe->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
3419 createBodyCheckBoxes(BODY_FORCE, pe);
3420 pe->show();
3421 pe->raise();
3422 }
3423 }
3424 }
3425
3426 //-----------------------------------------------------------------------------
forceBodyChanged(int state)3427 void MainWindow::forceBodyChanged(int state) {
3428 QWidget *a = (QWidget *)QObject::sender();
3429 if (glWidget->hasMesh()) {
3430 BodyPropertyEditor *body =
3431 (BodyPropertyEditor *)a->property("body").toULongLong();
3432 populateBodyComboBoxes(body);
3433
3434 if (state) {
3435 DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3436 QString mat_name = mat->nameEdit->text().trimmed();
3437 int ind = body->ui.bodyForceCombo->findText(mat_name);
3438
3439 body->touched = true;
3440 body->force = mat;
3441 body->ui.bodyForceCombo->setCurrentIndex(ind);
3442 } else {
3443 body->force = NULL;
3444 body->ui.bodyForceCombo->setCurrentIndex(-1);
3445 }
3446 }
3447 }
3448
3449 //*****************************************************************************
3450
3451 // Model -> Initial condition -> Add...
3452 //-----------------------------------------------------------------------------
addInitialConditionSlot()3453 void MainWindow::addInitialConditionSlot() {
3454 DynamicEditor *pe = new DynamicEditor;
3455 initialConditionEditor.append(pe);
3456 int current = initialConditionEditor.size() - 1;
3457
3458 pe->setupTabs(elmerDefs, "InitialCondition", current);
3459
3460 pe->applyButton->setText("Add");
3461 pe->applyButton->setIcon(QIcon(":/icons/list-add.png"));
3462 pe->discardButton->setText("Cancel");
3463 pe->discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
3464
3465 connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3466 SLOT(initialConditionEditorFinishedSlot(int, int)));
3467
3468 // Initial condition is new - add to menu:
3469 const QString &initialConditionName = pe->nameEdit->text().trimmed();
3470 QAction *act = new QAction(initialConditionName, this);
3471 initialConditionMenu->addAction(act);
3472 pe->menuAction = act;
3473
3474 connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3475 SLOT(dynamicEditorNameChange(QString)));
3476
3477 createBodyCheckBoxes(BODY_INITIAL, pe);
3478 pe->show();
3479 pe->raise();
3480 }
3481
3482 // signal (int,int) emitted by initial condition editor when ready:
3483 //-----------------------------------------------------------------------------
initialConditionEditorFinishedSlot(int signal,int id)3484 void MainWindow::initialConditionEditorFinishedSlot(int signal, int id) {
3485 DynamicEditor *pe = initialConditionEditor[id];
3486
3487 const QString &initialConditionName = pe->nameEdit->text().trimmed();
3488
3489 bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3490 if ((initialConditionName.isEmpty()) && signalOK) {
3491 logMessage("Refusing to add/update initial condition with no name");
3492 return;
3493 }
3494
3495 if (signalOK) {
3496 if (pe->menuAction != NULL) {
3497 pe->menuAction->setText(initialConditionName);
3498 logMessage("Initial condition updated");
3499 if (signal == MAT_OK)
3500 pe->close();
3501 }
3502 } else if (signal == MAT_NEW) {
3503 addInitialConditionSlot();
3504
3505 } else if (signal == MAT_DELETE) {
3506
3507 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3508 BodyPropertyEditor *body = bodyPropertyEditor[i];
3509
3510 if (!body)
3511 continue;
3512
3513 if (body->initial == pe) {
3514 body->initial = NULL;
3515 body->ui.initialConditionCombo->setCurrentIndex(0);
3516 body->touched = true;
3517 }
3518 }
3519
3520 // Initial condition is not in menu:
3521 if (pe->menuAction == NULL) {
3522 logMessage("Ready");
3523 pe->close();
3524 return;
3525 }
3526
3527 // Delete from menu:
3528 delete pe->menuAction;
3529 pe->menuAction = NULL;
3530 pe->close();
3531
3532 pe->ID = -100;
3533 pe->nameEdit->setText("");
3534
3535 logMessage("Initial condition deleted");
3536 }
3537 }
3538
3539 // signal (QAction*) emitted by initialConditionMenu when item selected:
3540 //-----------------------------------------------------------------------------
initialConditionSelectedSlot(QAction * act)3541 void MainWindow::initialConditionSelectedSlot(QAction *act) {
3542 // Edit the selected initial condition:
3543 for (int i = 0; i < initialConditionEditor.size(); i++) {
3544 DynamicEditor *pe = initialConditionEditor[i];
3545 if (pe->menuAction == act) {
3546 pe->applyButton->setText("Update");
3547 pe->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
3548 pe->discardButton->setText("Remove");
3549 pe->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
3550 createBodyCheckBoxes(BODY_INITIAL, pe);
3551 pe->show();
3552 pe->raise();
3553 }
3554 }
3555 }
3556
3557 //-----------------------------------------------------------------------------
initialBodyChanged(int state)3558 void MainWindow::initialBodyChanged(int state) {
3559 QWidget *a = (QWidget *)QObject::sender();
3560 if (glWidget->hasMesh()) {
3561 BodyPropertyEditor *body =
3562 (BodyPropertyEditor *)a->property("body").toULongLong();
3563 populateBodyComboBoxes(body);
3564
3565 if (state) {
3566 DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3567 QString mat_name = mat->nameEdit->text().trimmed();
3568 int ind = body->ui.initialConditionCombo->findText(mat_name);
3569 body->touched = true;
3570 body->initial = mat;
3571 body->ui.initialConditionCombo->setCurrentIndex(ind);
3572 } else {
3573 body->initial = NULL;
3574 body->ui.initialConditionCombo->setCurrentIndex(-1);
3575 }
3576 }
3577 }
3578
3579 //*****************************************************************************
3580 //-----------------------------------------------------------------------------
createBoundaryCheckBoxes(DynamicEditor * pe)3581 void MainWindow::createBoundaryCheckBoxes(DynamicEditor *pe) {
3582 if (!glWidget->hasMesh())
3583 return;
3584
3585 if (pe->spareScroll->widget()) {
3586 delete pe->spareScroll->widget();
3587 }
3588
3589 QGridLayout *slayout = new QGridLayout;
3590 QLabel *l = new QLabel(tr("Apply to boundaries:"));
3591 int count = 0, even = 0;
3592
3593 slayout->addWidget(l, count, 0);
3594 count++;
3595
3596 QMapIterator<int, int> itr(glWidget->boundaryMap);
3597 while (itr.hasNext()) {
3598 itr.next();
3599 int n = itr.key();
3600 if (n >= 0) {
3601 int m = itr.value();
3602
3603 if (m >= boundaryPropertyEditor.size())
3604 boundaryPropertyEditor.resize(m + 1);
3605
3606 if (!boundaryPropertyEditor[m])
3607 boundaryPropertyEditor[m] = new BoundaryPropertyEditor;
3608
3609 BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];
3610
3611 populateBoundaryComboBoxes(boundary);
3612
3613 // TODO: check this
3614 QString title = ""; // boundary->ui.nameEdit->text().trimmed();
3615 QCheckBox *a;
3616
3617 if (title.isEmpty())
3618 a = new QCheckBox("Boundary " + QString::number(n));
3619 else
3620 a = new QCheckBox(title);
3621
3622 if (glWidget->stateBcColors) {
3623 int c[3];
3624 QPixmap pm(16, 16);
3625
3626 GLWidget::indexColors(c, n);
3627 pm.fill(qRgb(c[0], c[1], c[2]));
3628 a->setIcon(QIcon(pm));
3629 }
3630
3631 DynamicEditor *p = NULL;
3632
3633 p = boundary->condition;
3634 connect(a, SIGNAL(stateChanged(int)), this, SLOT(bcBoundaryChanged(int)));
3635
3636 a->setProperty("boundary", (qulonglong)boundary);
3637 a->setProperty("condition", (qulonglong)pe);
3638
3639 if (p == pe)
3640 a->setChecked(true);
3641 else if (p != NULL)
3642 a->setEnabled(false);
3643
3644 slayout->addWidget(a, count, even);
3645 even = 1 - even;
3646 if (!even)
3647 count++;
3648 }
3649 }
3650
3651 QGroupBox *box = new QGroupBox;
3652 box->setLayout(slayout);
3653
3654 pe->spareScroll->setWidget(box);
3655 pe->spareScroll->setMinimumHeight(80);
3656 pe->spareScroll->show();
3657 }
3658
3659 //-----------------------------------------------------------------------------
3660
3661 // Model -> Boundary condition -> Add...
3662 //-----------------------------------------------------------------------------
addBoundaryConditionSlot()3663 void MainWindow::addBoundaryConditionSlot() {
3664 DynamicEditor *pe = new DynamicEditor;
3665 boundaryConditionEditor.append(pe);
3666 int current = boundaryConditionEditor.size() - 1;
3667
3668 pe->setupTabs(elmerDefs, "BoundaryCondition", current);
3669
3670 pe->applyButton->setText("Add");
3671 pe->applyButton->setIcon(QIcon(":/icons/list-add.png"));
3672 pe->discardButton->setText("Cancel");
3673 pe->discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
3674 pe->show();
3675
3676 connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3677 SLOT(boundaryConditionEditorFinishedSlot(int, int)));
3678
3679 // Boundary condition is new - add to menu:
3680 const QString &boundaryConditionName = pe->nameEdit->text().trimmed();
3681 QAction *act = new QAction(boundaryConditionName, this);
3682 boundaryConditionMenu->addAction(act);
3683 pe->menuAction = act;
3684
3685 connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3686 SLOT(dynamicEditorNameChange(QString)));
3687
3688 createBoundaryCheckBoxes(pe);
3689 }
3690
3691 // signal (int,int) emitted by boundary condition editor when ready:
3692 //-----------------------------------------------------------------------------
boundaryConditionEditorFinishedSlot(int signal,int id)3693 void MainWindow::boundaryConditionEditorFinishedSlot(int signal, int id) {
3694 DynamicEditor *pe = boundaryConditionEditor[id];
3695
3696 const QString &boundaryConditionName = pe->nameEdit->text().trimmed();
3697
3698 bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3699
3700 if ((boundaryConditionName.isEmpty()) && signalOK) {
3701 logMessage("Refusing to add/update boundary condition with no name");
3702 return;
3703 }
3704
3705 if (signalOK) {
3706 if (pe->menuAction != NULL) {
3707 pe->menuAction->setText(boundaryConditionName);
3708 logMessage("Boundary condition updated");
3709 if (signal == MAT_OK)
3710 pe->close();
3711 }
3712 } else if (signal == MAT_NEW) {
3713 addBoundaryConditionSlot();
3714
3715 } else if (signal == MAT_DELETE) {
3716
3717 pe->nameEdit->setText(QString());
3718
3719 for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
3720 BoundaryPropertyEditor *bndry = boundaryPropertyEditor[i];
3721
3722 if (!bndry)
3723 continue;
3724
3725 if (bndry->condition == pe) {
3726 bndry->condition = NULL;
3727 bndry->ui.boundaryConditionCombo->setCurrentIndex(0);
3728 bndry->touched = true;
3729 }
3730 }
3731
3732 // Boundary condition is not in menu:
3733 if (pe->menuAction == NULL) {
3734 logMessage("Ready");
3735 pe->close();
3736 return;
3737 }
3738
3739 // Delete from menu:
3740 delete pe->menuAction;
3741 pe->menuAction = NULL;
3742 pe->close();
3743
3744 pe->ID = -100;
3745 pe->nameEdit->setText("");
3746
3747 logMessage("Boundary condition deleted");
3748 }
3749 }
3750
3751 // signal (QAction*) emitted by boundaryConditionMenu when item selected:
3752 //-----------------------------------------------------------------------------
boundaryConditionSelectedSlot(QAction * act)3753 void MainWindow::boundaryConditionSelectedSlot(QAction *act) {
3754 // Edit the selected boundary condition:
3755 for (int i = 0; i < boundaryConditionEditor.size(); i++) {
3756 DynamicEditor *pe = boundaryConditionEditor[i];
3757 if (pe->menuAction == act) {
3758 pe->applyButton->setText("Update");
3759 pe->applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
3760 pe->discardButton->setText("Remove");
3761 pe->discardButton->setIcon(QIcon(":/icons/list-remove.png"));
3762 createBoundaryCheckBoxes(pe);
3763 pe->show();
3764 pe->raise();
3765 }
3766 }
3767 }
3768
3769 //-----------------------------------------------------------------------------
bcBoundaryChanged(int state)3770 void MainWindow::bcBoundaryChanged(int state) {
3771 QWidget *a = (QWidget *)QObject::sender();
3772 if (glWidget->hasMesh()) {
3773 BoundaryPropertyEditor *boundary =
3774 (BoundaryPropertyEditor *)a->property("boundary").toULongLong();
3775 populateBoundaryComboBoxes(boundary);
3776
3777 if (state) {
3778 DynamicEditor *mat =
3779 (DynamicEditor *)a->property("condition").toULongLong();
3780 QString mat_name = mat->nameEdit->text().trimmed();
3781 int ind = boundary->ui.boundaryConditionCombo->findText(mat_name);
3782 boundary->touched = true;
3783 boundary->condition = mat;
3784 boundary->ui.boundaryConditionCombo->setCurrentIndex(ind);
3785 } else {
3786 boundary->condition = NULL;
3787 boundary->ui.boundaryConditionCombo->setCurrentIndex(-1);
3788 }
3789 }
3790 }
3791
3792 // Model -> Set body properties
3793 //-----------------------------------------------------------------------------
bodyEditSlot()3794 void MainWindow::bodyEditSlot() {
3795 if (!glWidget->hasMesh()) {
3796 logMessage("Unable to open body editor - no mesh");
3797 bodyEditActive = false;
3798 synchronizeMenuToState();
3799 return;
3800 }
3801
3802 bodyEditActive = !bodyEditActive;
3803 glWidget->bodyEditActive = bodyEditActive;
3804
3805 if (bodyEditActive)
3806 bcEditActive = false;
3807
3808 synchronizeMenuToState();
3809
3810 if (bodyEditActive)
3811 logMessage("Double click a boundary to edit body properties");
3812 }
3813
3814 // Model -> Set boundary conditions
3815 //-----------------------------------------------------------------------------
bcEditSlot()3816 void MainWindow::bcEditSlot() {
3817 if (!glWidget->hasMesh()) {
3818 logMessage("Unable to open BC editor - no mesh");
3819 bcEditActive = false;
3820 synchronizeMenuToState();
3821 return;
3822 }
3823
3824 bcEditActive = !bcEditActive;
3825
3826 if (bcEditActive)
3827 bodyEditActive = false;
3828
3829 synchronizeMenuToState();
3830
3831 if (bcEditActive)
3832 logMessage("Double click a boundary to edit BCs");
3833 }
3834
3835 // Model -> Summary...
3836 //-----------------------------------------------------------------------------
modelSummarySlot()3837 void MainWindow::modelSummarySlot() {
3838 mesh_t *mesh = glWidget->getMesh();
3839 QTextEdit *te = summaryEditor->ui.summaryEdit;
3840 te->clear();
3841 summaryEditor->show();
3842
3843 if (mesh == NULL) {
3844 te->append("No mesh");
3845 return;
3846 }
3847
3848 te->append("FINITE ELEMENT MESH");
3849 te->append("Mesh dimension: " + QString::number(mesh->getCdim()));
3850 te->append("Leading element dimension: " + QString::number(mesh->getDim()));
3851 te->append("Nodes: " + QString::number(mesh->getNodes()));
3852 te->append("Volume elements: " + QString::number(mesh->getElements()));
3853 te->append("Surface elements: " + QString::number(mesh->getSurfaces()));
3854 te->append("Edge elements: " + QString::number(mesh->getEdges()));
3855 te->append("Point elements: " + QString::number(mesh->getPoints()));
3856 te->append("");
3857
3858 // This is almost duplicate info with the above, they might be fused in some
3859 // way...
3860 te->append("ELEMENT TYPES");
3861 int *elementtypes = new int[828];
3862 for (int i = 0; i <= 827; i++)
3863 elementtypes[i] = 0;
3864 for (int i = 0; i < mesh->getElements(); i++)
3865 elementtypes[mesh->getElement(i)->getCode()] += 1;
3866 for (int i = 0; i < mesh->getSurfaces(); i++)
3867 elementtypes[mesh->getSurface(i)->getCode()] += 1;
3868 for (int i = 0; i < mesh->getEdges(); i++)
3869 elementtypes[mesh->getEdge(i)->getCode()] += 1;
3870 for (int i = 0; i < mesh->getPoints(); i++)
3871 elementtypes[mesh->getPoint(i)->getCode()] += 1;
3872 for (int i = 827; i > 0; i--)
3873 if (elementtypes[i])
3874 te->append(QString::number(i) + ": " + QString::number(elementtypes[i]));
3875 te->append("");
3876 delete[] elementtypes;
3877
3878 te->append("BOUNDING BOX");
3879 QString coordnames = "XYZ";
3880 for (int j = 0; j < 3; j++) {
3881 double mincoord, maxcoord, coord;
3882 mincoord = maxcoord = mesh->getNode(0)->getX(j);
3883 for (int i = 0; i < mesh->getNodes(); i++) {
3884 coord = mesh->getNode(i)->getX(j);
3885 if (mincoord > coord)
3886 mincoord = coord;
3887 if (maxcoord < coord)
3888 maxcoord = coord;
3889 }
3890 te->append(coordnames[j] + "-coordinate: [ " + QString::number(mincoord) +
3891 " , " + QString::number(maxcoord) + " ]");
3892 }
3893 te->append("");
3894
3895 // Check equations:
3896 int count = 0;
3897 for (int i = 0; i < equationEditor.size(); i++) {
3898 if (equationEditor[i]->menuAction != NULL)
3899 count++;
3900 }
3901 te->append("GENERAL");
3902 te->append("Equations: " + QString::number(count));
3903
3904 // Check materials:
3905 count = 0;
3906 for (int i = 0; i < materialEditor.size(); i++) {
3907 if (materialEditor[i]->menuAction != NULL)
3908 count++;
3909 }
3910 te->append("Materials: " + QString::number(count));
3911
3912 // Check boundary conditions:
3913 count = 0;
3914 for (int i = 0; i < boundaryConditionEditor.size(); i++) {
3915 if (boundaryConditionEditor[i]->touched)
3916 count++;
3917 }
3918 te->append("Boundary conditions: " + QString::number(count));
3919
3920 // Check body properties:
3921 count = 0;
3922 for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3923
3924 if (!bodyPropertyEditor[i])
3925 continue;
3926
3927 if (bodyPropertyEditor[i]->touched)
3928 count++;
3929 }
3930
3931 te->append("Body properties: " + QString::number(count));
3932 te->append("");
3933
3934 // Count volume bodies:
3935 //---------------------
3936 int undetermined = 0;
3937 int *tmp = new int[mesh->getElements()];
3938 for (int i = 0; i < mesh->getElements(); i++)
3939 tmp[i] = 0;
3940
3941 for (int i = 0; i < mesh->getElements(); i++) {
3942 element_t *e = mesh->getElement(i);
3943 if (e->getNature() == PDE_BULK) {
3944 if (e->getIndex() >= 0)
3945 tmp[e->getIndex()]++;
3946 else
3947 undetermined++;
3948 }
3949 }
3950
3951 te->append("VOLUME BODIES");
3952 count = 0;
3953 for (int i = 0; i < mesh->getElements(); i++) {
3954 if (tmp[i] > 0) {
3955 count++;
3956 QString qs = "Body " + QString::number(i) + ": " +
3957 QString::number(tmp[i]) + " volume elements";
3958
3959 element_t *e = mesh->getElement(i);
3960 int j = e->getIndex();
3961
3962 if ((j >= 0) && (j < bodyPropertyEditor.size()))
3963 if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
3964 qs.append(" (Body property set)");
3965
3966 te->append(qs);
3967 }
3968 }
3969 te->append("Undetermined: " + QString::number(undetermined));
3970 te->append("Total: " + QString::number(count) + " volume bodies");
3971 te->append("");
3972
3973 delete[] tmp;
3974
3975 // Count surface bodies:
3976 //---------------------
3977 undetermined = 0;
3978 tmp = new int[mesh->getSurfaces()];
3979 for (int i = 0; i < mesh->getSurfaces(); i++)
3980 tmp[i] = 0;
3981
3982 for (int i = 0; i < mesh->getSurfaces(); i++) {
3983 surface_t *s = mesh->getSurface(i);
3984 if (s->getNature() == PDE_BULK) {
3985 if (s->getIndex() >= 0)
3986 tmp[s->getIndex()]++;
3987 else
3988 undetermined++;
3989 }
3990 }
3991
3992 te->append("SURFACE BODIES");
3993 count = 0;
3994 for (int i = 0; i < mesh->getSurfaces(); i++) {
3995 if (tmp[i] > 0) {
3996 count++;
3997 QString qs = "Body " + QString::number(i) + ": " +
3998 QString::number(tmp[i]) + " surface elements";
3999
4000 surface_t *s = mesh->getSurface(i);
4001 int j = s->getIndex();
4002
4003 if ((j >= 0) && (j < bodyPropertyEditor.size()))
4004 if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
4005 qs.append(" (Body property set)");
4006
4007 te->append(qs);
4008 }
4009 }
4010 te->append("Undetermined: " + QString::number(undetermined));
4011 te->append("Total: " + QString::number(count) + " surface bodies");
4012 te->append("");
4013
4014 delete[] tmp;
4015
4016 // Count edge bodies:
4017 //---------------------
4018 undetermined = 0;
4019 tmp = new int[mesh->getEdges()];
4020 for (int i = 0; i < mesh->getEdges(); i++)
4021 tmp[i] = 0;
4022
4023 for (int i = 0; i < mesh->getEdges(); i++) {
4024 edge_t *e = mesh->getEdge(i);
4025 if (e->getNature() == PDE_BULK) {
4026 if (e->getIndex() >= 0)
4027 tmp[e->getIndex()]++;
4028 else
4029 undetermined++;
4030 }
4031 }
4032
4033 te->append("EDGE BODIES");
4034 count = 0;
4035 for (int i = 0; i < mesh->getEdges(); i++) {
4036 if (tmp[i] > 0) {
4037 count++;
4038 QString qs = "Body " + QString::number(i) + ": " +
4039 QString::number(tmp[i]) + " edge elements";
4040
4041 edge_t *e = mesh->getEdge(i);
4042 int j = e->getIndex();
4043
4044 if ((j >= 0) && (j < bodyPropertyEditor.size()))
4045 if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
4046 qs.append(" (Body property set)");
4047
4048 te->append(qs);
4049 }
4050 }
4051 te->append("Undetermined: " + QString::number(undetermined));
4052 te->append("Total: " + QString::number(count) + " edge bodies");
4053 te->append("");
4054
4055 delete[] tmp;
4056
4057 // Count surface boundaries:
4058 //--------------------------
4059 undetermined = 0;
4060 tmp = new int[mesh->getSurfaces()];
4061 for (int i = 0; i < mesh->getSurfaces(); i++)
4062 tmp[i] = 0;
4063
4064 for (int i = 0; i < mesh->getSurfaces(); i++) {
4065 surface_t *s = mesh->getSurface(i);
4066 if (s->getNature() == PDE_BOUNDARY) {
4067 if (s->getIndex() >= 0)
4068 tmp[s->getIndex()]++;
4069 else
4070 undetermined++;
4071 }
4072 }
4073
4074 te->append("SURFACE BOUNDARIES");
4075 count = 0;
4076 for (int i = 0; i < mesh->getSurfaces(); i++) {
4077 if (tmp[i] > 0) {
4078 count++;
4079 QString qs = "Boundary " + QString::number(i) + ": " +
4080 QString::number(tmp[i]) + " surface elements";
4081
4082 surface_t *s = mesh->getSurface(i);
4083 int j = s->getIndex();
4084 if ((j >= 0) && (j < boundaryConditionEditor.size()))
4085 if (boundaryConditionEditor[j]->touched)
4086 qs.append(" (BC set)");
4087
4088 te->append(qs);
4089 }
4090 }
4091 te->append("Undetermined: " + QString::number(undetermined));
4092 te->append("Total: " + QString::number(count) + " surface boundaries");
4093 te->append("");
4094
4095 delete[] tmp;
4096
4097 // Count edge boundaries:
4098 //--------------------------
4099 undetermined = 0;
4100 tmp = new int[mesh->getEdges()];
4101 for (int i = 0; i < mesh->getEdges(); i++)
4102 tmp[i] = 0;
4103
4104 for (int i = 0; i < mesh->getEdges(); i++) {
4105 edge_t *e = mesh->getEdge(i);
4106 if (e->getNature() == PDE_BOUNDARY) {
4107 if (e->getIndex() >= 0)
4108 tmp[e->getIndex()]++;
4109 else
4110 undetermined++;
4111 }
4112 }
4113
4114 te->append("EDGE BOUNDARIES");
4115 count = 0;
4116 for (int i = 0; i < mesh->getEdges(); i++) {
4117 if (tmp[i] > 0) {
4118 count++;
4119 QString qs = "Boundary " + QString::number(i) + ": " +
4120 QString::number(tmp[i]) + " edge elements";
4121
4122 edge_t *e = mesh->getEdge(i);
4123 int j = e->getIndex();
4124 if ((j >= 0) && (j < boundaryConditionEditor.size()))
4125 if (boundaryConditionEditor[j]->touched)
4126 qs.append(" (BC set)");
4127
4128 te->append(qs);
4129 }
4130 }
4131 te->append("Undetermined: " + QString::number(undetermined));
4132 te->append("Total: " + QString::number(count) + " edge boundaries");
4133 te->append("");
4134
4135 delete[] tmp;
4136 }
4137
4138 // Model -> Clear
4139 //-----------------------------------------------------------------------------
modelClearSlot()4140 void MainWindow::modelClearSlot() {
4141 // clear equations:
4142 for (int i = 0; i < equationEditor.size(); i++) {
4143 DynamicEditor *pe = equationEditor[i];
4144 if (pe->menuAction != NULL)
4145 delete pe->menuAction;
4146 }
4147
4148 for (int i = 0; i < equationEditor.size(); i++)
4149 delete equationEditor[i];
4150
4151 equationEditor.clear();
4152
4153 // clear materials:
4154 for (int i = 0; i < materialEditor.size(); i++) {
4155 DynamicEditor *de = materialEditor[i];
4156 if (de->menuAction != NULL)
4157 delete de->menuAction;
4158 }
4159
4160 for (int i = 0; i < materialEditor.size(); i++)
4161 delete materialEditor[i];
4162
4163 materialEditor.clear();
4164
4165 // clear body forces:
4166 for (int i = 0; i < bodyForceEditor.size(); i++) {
4167 DynamicEditor *de = bodyForceEditor[i];
4168 if (de->menuAction != NULL)
4169 delete de->menuAction;
4170 }
4171
4172 for (int i = 0; i < bodyForceEditor.size(); i++)
4173 delete bodyForceEditor[i];
4174
4175 bodyForceEditor.clear();
4176
4177 // clear initial conditions:
4178 for (int i = 0; i < initialConditionEditor.size(); i++) {
4179 DynamicEditor *de = initialConditionEditor[i];
4180 if (de->menuAction != NULL)
4181 delete de->menuAction;
4182 }
4183
4184 for (int i = 0; i < initialConditionEditor.size(); i++)
4185 delete initialConditionEditor[i];
4186
4187 initialConditionEditor.clear();
4188
4189 // clear boundary conditions:
4190 for (int i = 0; i < boundaryConditionEditor.size(); i++) {
4191 DynamicEditor *de = boundaryConditionEditor[i];
4192 if (de->menuAction != NULL)
4193 delete de->menuAction;
4194 }
4195
4196 for (int i = 0; i < boundaryConditionEditor.size(); i++)
4197 if (boundaryConditionEditor[i])
4198 delete boundaryConditionEditor[i];
4199
4200 boundaryConditionEditor.clear();
4201
4202 // clear boundary setting:
4203 for (int i = 0; i < boundaryPropertyEditor.size(); i++)
4204 if (boundaryPropertyEditor[i])
4205 delete boundaryPropertyEditor[i];
4206
4207 boundaryPropertyEditor.clear();
4208
4209 // clear body settings:
4210 for (int i = 0; i < bodyPropertyEditor.size(); i++)
4211 if (bodyPropertyEditor[i])
4212 delete bodyPropertyEditor[i];
4213
4214 bodyPropertyEditor.clear();
4215
4216 // clear solver specific settings:
4217 for (int i = 0; i < solverParameterEditor.size(); i++)
4218 if (solverParameterEditor[i])
4219 delete solverParameterEditor[i];
4220
4221 solverParameterEditor.clear();
4222 }
4223
4224 //*****************************************************************************
4225 //
4226 // View MENU
4227 //
4228 //*****************************************************************************
4229
4230 // View -> Full screen
4231 //-----------------------------------------------------------------------------
viewFullScreenSlot()4232 void MainWindow::viewFullScreenSlot() {
4233 if (!isFullScreen()) {
4234 cout << "Switching to full screen mode" << endl;
4235 menuBar()->hide();
4236 statusBar()->hide();
4237 fileToolBar->hide();
4238 editToolBar->hide();
4239 meshToolBar->hide();
4240 solverToolBar->hide();
4241 this->showFullScreen();
4242 } else {
4243 viewNormalModeSlot();
4244 }
4245 synchronizeMenuToState();
4246 }
4247
4248 // Return to normal mode (GLWidget emits (void) when esc is pressed)...
4249 //-----------------------------------------------------------------------------
viewNormalModeSlot()4250 void MainWindow::viewNormalModeSlot() {
4251 if (isFullScreen()) {
4252 cout << "Switching to normal window mode" << endl;
4253 this->showNormal();
4254 menuBar()->show();
4255 statusBar()->show();
4256 if (!egIni->isSet("hidetoolbars")) {
4257 fileToolBar->show();
4258 editToolBar->show();
4259 meshToolBar->show();
4260 solverToolBar->show();
4261 }
4262 }
4263 synchronizeMenuToState();
4264 statusBar()->showMessage(tr("Ready"));
4265 }
4266
4267 // Context menu event (usually mouse has been right clicked)...
4268 //-----------------------------------------------------------------------------
contextMenuEvent(QContextMenuEvent * event)4269 void MainWindow::contextMenuEvent(QContextMenuEvent *event) {
4270 // if(isFullScreen())
4271 contextMenu->popup(event->globalPos());
4272 }
4273
4274 // View -> Surface mesh
4275 //-----------------------------------------------------------------------------
hidesurfacemeshSlot()4276 void MainWindow::hidesurfacemeshSlot() {
4277 mesh_t *mesh = glWidget->getMesh();
4278 int lists = glWidget->getLists();
4279
4280 if (mesh == NULL) {
4281 logMessage("There is no surface mesh to hide/show");
4282 return;
4283 }
4284
4285 glWidget->stateDrawSurfaceMesh = !glWidget->stateDrawSurfaceMesh;
4286
4287 for (int i = 0; i < lists; i++) {
4288 list_t *l = glWidget->getList(i);
4289 if (l->getType() == SURFACEMESHLIST) {
4290 l->setVisible(glWidget->stateDrawSurfaceMesh);
4291
4292 // do not set visible if the parent surface list is hidden
4293 int p = l->getParent();
4294 if (p >= 0) {
4295 list_t *lp = glWidget->getList(p);
4296 if (!lp->isVisible())
4297 l->setVisible(false);
4298 }
4299 }
4300 }
4301
4302 synchronizeMenuToState();
4303
4304 if (!glWidget->stateDrawSurfaceMesh)
4305 logMessage("Surface mesh hidden");
4306 else
4307 logMessage("Surface mesh shown");
4308 }
4309
4310 // View -> Volume mesh
4311 //-----------------------------------------------------------------------------
hidevolumemeshSlot()4312 void MainWindow::hidevolumemeshSlot() {
4313 mesh_t *mesh = glWidget->getMesh();
4314 int lists = glWidget->getLists();
4315
4316 if (mesh == NULL) {
4317 logMessage("There is no volume mesh to hide/show");
4318 return;
4319 }
4320
4321 glWidget->stateDrawVolumeMesh = !glWidget->stateDrawVolumeMesh;
4322
4323 for (int i = 0; i < lists; i++) {
4324 list_t *l = glWidget->getList(i);
4325 if (l->getType() == VOLUMEMESHLIST)
4326 l->setVisible(glWidget->stateDrawVolumeMesh);
4327 }
4328
4329 synchronizeMenuToState();
4330
4331 if (!glWidget->stateDrawVolumeMesh)
4332 logMessage("Volume mesh hidden");
4333 else
4334 logMessage("Volume mesh shown");
4335 }
4336
4337 // View -> Sharp edges
4338 //-----------------------------------------------------------------------------
hidesharpedgesSlot()4339 void MainWindow::hidesharpedgesSlot() {
4340 mesh_t *mesh = glWidget->getMesh();
4341 int lists = glWidget->getLists();
4342
4343 if (mesh == NULL) {
4344 logMessage("There are no sharp edges to hide/show");
4345 return;
4346 }
4347
4348 glWidget->stateDrawSharpEdges = !glWidget->stateDrawSharpEdges;
4349
4350 for (int i = 0; i < lists; i++) {
4351 list_t *l = glWidget->getList(i);
4352 if (l->getType() == SHARPEDGELIST)
4353 l->setVisible(glWidget->stateDrawSharpEdges);
4354 }
4355
4356 synchronizeMenuToState();
4357
4358 if (!glWidget->stateDrawSharpEdges)
4359 logMessage("Sharp edges hidden");
4360 else
4361 logMessage("Sharp edges shown");
4362 }
4363
4364 // View -> Coordinates
4365 //-----------------------------------------------------------------------------
viewCoordinatesSlot()4366 void MainWindow::viewCoordinatesSlot() {
4367 if (glWidget->toggleCoordinates())
4368 logMessage("Coordinates shown");
4369 else
4370 logMessage("Coordinates hidden");
4371
4372 synchronizeMenuToState();
4373 }
4374
4375 // View -> Select defined edges
4376 //-----------------------------------------------------------------------------
selectDefinedEdgesSlot()4377 void MainWindow::selectDefinedEdgesSlot() {
4378 mesh_t *mesh = glWidget->getMesh();
4379 int lists = glWidget->getLists();
4380
4381 if (mesh == NULL) {
4382 logMessage("There are no entities from which to select");
4383 return;
4384 }
4385
4386 // At the moment only edges are included in search:
4387 int nmax = 0;
4388 for (int i = 0; i < glWidget->boundaryMap.count(); i++) {
4389 int n = glWidget->boundaryMap.key(i);
4390 if (n > nmax)
4391 nmax = n;
4392 }
4393
4394 bool *activeboundary = new bool[nmax + 1];
4395 for (int i = 0; i <= nmax; i++)
4396 activeboundary[i] = false;
4397
4398 for (int i = 0; i < glWidget->boundaryMap.count(); i++) {
4399 int n = glWidget->boundaryMap.key(i);
4400 if (n >= 0) {
4401 int m = glWidget->boundaryMap.value(n);
4402
4403 if (m >= boundaryPropertyEditor.size())
4404 boundaryPropertyEditor.resize(m + 1);
4405
4406 if (!boundaryPropertyEditor[m])
4407 boundaryPropertyEditor[m] = new BoundaryPropertyEditor;
4408
4409 BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];
4410 activeboundary[n] = boundary->condition;
4411 }
4412 }
4413
4414 for (int i = 0; i < lists; i++) {
4415 list_t *l = glWidget->getList(i);
4416 if (l->getType() == EDGELIST) {
4417 int j = l->getIndex();
4418 if (j < 0)
4419 continue;
4420
4421 // *** TODO ***
4422 //
4423 // This is wrong: Comparing body indices with boundary indices
4424 if (activeboundary[j])
4425 l->setSelected(true);
4426 }
4427 }
4428
4429 for (int i = 0; i < mesh->getEdges(); i++) {
4430 edge_t *edge = mesh->getEdge(i);
4431 if (edge->getNature() == PDE_BOUNDARY) {
4432 int j = edge->getIndex();
4433 if (j < 0)
4434 continue;
4435 if (activeboundary[j])
4436 edge->setSelected(true);
4437 }
4438 }
4439 delete[] activeboundary;
4440
4441 glWidget->rebuildEdgeLists();
4442 glWidget->updateGL();
4443
4444 logMessage("Defined edges selected");
4445 }
4446
4447 // View -> Select defined surfaces
4448 //-----------------------------------------------------------------------------
selectDefinedSurfacesSlot()4449 void MainWindow::selectDefinedSurfacesSlot() {
4450 mesh_t *mesh = glWidget->getMesh();
4451 int lists = glWidget->getLists();
4452
4453 if (mesh == NULL) {
4454 logMessage("There are no entities from which to select");
4455 return;
4456 }
4457
4458 // At the moment only surfaces are included in search:
4459 int nmax = 0;
4460 for (int i = 0; i < glWidget->bodyMap.count(); i++) {
4461 int n = glWidget->bodyMap.key(i);
4462 if (n > nmax)
4463 nmax = n;
4464 }
4465
4466 bool *activebody = new bool[nmax + 1];
4467 for (int i = 0; i <= nmax; i++)
4468 activebody[i] = false;
4469
4470 for (int i = 0; i < glWidget->bodyMap.count(); i++) {
4471 int n = glWidget->bodyMap.key(i);
4472 if (n >= 0) {
4473 int m = glWidget->bodyMap.value(n);
4474
4475 BodyPropertyEditor *body = bodyPropertyEditor[m];
4476
4477 if (!body) {
4478 cout << "MainWindow: Body index out of bounds" << endl;
4479 continue;
4480 }
4481
4482 activebody[n] = body->material && body->equation;
4483 }
4484 }
4485
4486 for (int i = 0; i < lists; i++) {
4487 list_t *l = glWidget->getList(i);
4488 if (l->getType() == SURFACELIST) {
4489 int j = l->getIndex();
4490 if (j < 0)
4491 continue;
4492
4493 // *** TODO ***
4494 //
4495 // This is wrong: Comparing body indices with boundary indexes
4496 if (activebody[j])
4497 l->setSelected(true);
4498 }
4499 }
4500
4501 for (int i = 0; i < mesh->getSurfaces(); i++) {
4502 surface_t *surface = mesh->getSurface(i);
4503 if (surface->getNature() == PDE_BULK) {
4504 int j = surface->getIndex();
4505 if (j < 0)
4506 continue;
4507 if (activebody[j])
4508 surface->setSelected(true);
4509 }
4510 }
4511 delete[] activebody;
4512
4513 glWidget->rebuildSurfaceLists();
4514 glWidget->updateGL();
4515
4516 logMessage("Defined surfaces selected");
4517 }
4518
4519 // View -> Select all surfaces
4520 //-----------------------------------------------------------------------------
selectAllSurfacesSlot()4521 void MainWindow::selectAllSurfacesSlot() {
4522 mesh_t *mesh = glWidget->getMesh();
4523 int lists = glWidget->getLists();
4524
4525 if (mesh == NULL) {
4526 logMessage("There are no surfaces to select");
4527 return;
4528 }
4529
4530 for (int i = 0; i < lists; i++) {
4531 list_t *l = glWidget->getList(i);
4532 if (l->getType() == SURFACELIST) {
4533 l->setSelected(true);
4534 for (int j = 0; j < mesh->getSurfaces(); j++) {
4535 surface_t *surf = mesh->getSurface(j);
4536 if (l->getIndex() == surf->getIndex())
4537 surf->setSelected(l->isSelected());
4538 }
4539 }
4540 }
4541
4542 glWidget->rebuildSurfaceLists();
4543 glWidget->updateGL();
4544
4545 logMessage("All surfaces selected");
4546 }
4547
4548 // View -> Select all edges
4549 //-----------------------------------------------------------------------------
selectAllEdgesSlot()4550 void MainWindow::selectAllEdgesSlot() {
4551 mesh_t *mesh = glWidget->getMesh();
4552 int lists = glWidget->getLists();
4553
4554 if (mesh == NULL) {
4555 logMessage("There are no edges to select");
4556 return;
4557 }
4558
4559 for (int i = 0; i < lists; i++) {
4560 list_t *l = glWidget->getList(i);
4561
4562 if (l->getType() == EDGELIST)
4563 l->setSelected(true);
4564
4565 for (int j = 0; j < mesh->getEdges(); j++) {
4566 edge_t *edge = mesh->getEdge(j);
4567 if (l->getIndex() == edge->getIndex())
4568 edge->setSelected(l->isSelected());
4569 }
4570 }
4571
4572 glWidget->rebuildEdgeLists();
4573 glWidget->updateGL();
4574
4575 logMessage("All edges selected");
4576 }
4577
4578 // View -> Hide/Show selected
4579 //-----------------------------------------------------------------------------
hideselectedSlot()4580 void MainWindow::hideselectedSlot() {
4581 mesh_t *mesh = glWidget->getMesh();
4582 int lists = glWidget->getLists();
4583
4584 if (mesh == NULL) {
4585 logMessage("There is nothing to hide/show");
4586 return;
4587 }
4588
4589 bool something_selected = false;
4590 for (int i = 0; i < lists; i++) {
4591 list_t *l = glWidget->getList(i);
4592 something_selected |= l->isSelected();
4593 }
4594
4595 if (!something_selected) {
4596 logMessage("Nothing selected");
4597 return;
4598 }
4599
4600 bool vis = false;
4601 for (int i = 0; i < lists; i++) {
4602 list_t *l = glWidget->getList(i);
4603 if (l->isSelected()) {
4604 l->setVisible(!l->isVisible());
4605 if (l->isVisible())
4606 vis = true;
4607
4608 // hide the child surface edge list if parent is hidden
4609 int c = l->getChild();
4610 if (c >= 0) {
4611 list_t *lc = glWidget->getList(c);
4612 lc->setVisible(l->isVisible());
4613 if (!glWidget->stateDrawSurfaceMesh)
4614 lc->setVisible(false);
4615 }
4616 }
4617 }
4618 glWidget->updateGL();
4619
4620 if (!vis)
4621 logMessage("Selected objects hidden");
4622 else
4623 logMessage("Selected objects shown");
4624 }
4625
4626 // View -> Show all
4627 //-----------------------------------------------------------------------------
showallSlot()4628 void MainWindow::showallSlot() {
4629 int lists = glWidget->getLists();
4630
4631 glWidget->stateDrawSurfaceMesh = true;
4632 #ifndef WIN32
4633 glWidget->stateDrawSharpEdges = true;
4634 #endif
4635 glWidget->stateDrawSurfaceElements = true;
4636 glWidget->stateDrawEdgeElements = true;
4637
4638 synchronizeMenuToState();
4639
4640 for (int i = 0; i < lists; i++) {
4641 list_t *l = glWidget->getList(i);
4642 l->setVisible(true);
4643 }
4644
4645 logMessage("All objects visible");
4646 }
4647
4648 // View -> Reset model view
4649 //-----------------------------------------------------------------------------
resetSlot()4650 void MainWindow::resetSlot() {
4651 mesh_t *mesh = glWidget->getMesh();
4652 int lists = glWidget->getLists();
4653
4654 if (mesh == NULL) {
4655 logMessage("There is nothing to reset");
4656 return;
4657 }
4658
4659 glWidget->stateFlatShade = true;
4660 glWidget->stateDrawSurfaceMesh = true;
4661 #ifndef WIN32
4662 glWidget->stateDrawSharpEdges = true;
4663 #endif
4664 glWidget->stateDrawSurfaceElements = true;
4665 glWidget->stateDrawEdgeElements = true;
4666 glWidget->stateDrawSurfaceNumbers = false;
4667 glWidget->stateDrawEdgeNumbers = false;
4668 glWidget->stateDrawNodeNumbers = false;
4669
4670 for (int i = 0; i < lists; i++) {
4671 list_t *l = glWidget->getList(i);
4672 l->setVisible(true);
4673 l->setSelected(false);
4674
4675 for (int j = 0; j < mesh->getSurfaces(); j++) {
4676 surface_t *surf = mesh->getSurface(j);
4677 if (l->getIndex() == surf->getIndex())
4678 surf->setSelected(l->isSelected());
4679 }
4680 for (int j = 0; j < mesh->getEdges(); j++) {
4681 edge_t *edge = mesh->getEdge(j);
4682 if (l->getIndex() == edge->getIndex())
4683 edge->setSelected(l->isSelected());
4684 }
4685 }
4686
4687 glWidget->stateBcColors = false;
4688 glWidget->stateBodyColors = false;
4689
4690 glLoadIdentity();
4691 glWidget->rebuildLists();
4692 glWidget->updateGL();
4693
4694 synchronizeMenuToState();
4695 logMessage("Reset model view");
4696 }
4697
4698 // View -> Shade model -> Flat
4699 //-----------------------------------------------------------------------------
flatShadeSlot()4700 void MainWindow::flatShadeSlot() {
4701 if (!glWidget->hasMesh()) {
4702 logMessage("Refusing to change shade model when mesh is empty");
4703 return;
4704 }
4705
4706 glWidget->stateFlatShade = true;
4707 glWidget->rebuildSurfaceLists();
4708 glWidget->updateGL();
4709
4710 synchronizeMenuToState();
4711 logMessage("Shade model: flat");
4712 }
4713
4714 // View -> Shade model -> Smooth
4715 //-----------------------------------------------------------------------------
smoothShadeSlot()4716 void MainWindow::smoothShadeSlot() {
4717 if (!glWidget->hasMesh()) {
4718 logMessage("Refusing to change shade model when mesh is empty");
4719 return;
4720 }
4721
4722 glWidget->stateFlatShade = false;
4723 glWidget->rebuildSurfaceLists();
4724 glWidget->updateGL();
4725
4726 synchronizeMenuToState();
4727 logMessage("Shade model: smooth");
4728 }
4729
4730 // View -> Projection -> Orthogonal
4731 //-----------------------------------------------------------------------------
orthoSlot()4732 void MainWindow::orthoSlot() {
4733 if (!glWidget->hasMesh()) {
4734 logMessage("Refusing to change projection when mesh is empty");
4735 return;
4736 }
4737
4738 glWidget->stateOrtho = true;
4739 glWidget->changeProjection();
4740 glWidget->updateGL();
4741
4742 synchronizeMenuToState();
4743 logMessage("Projection: orthogonal");
4744 }
4745
4746 // View -> Projection -> Perspective
4747 //-----------------------------------------------------------------------------
perspectiveSlot()4748 void MainWindow::perspectiveSlot() {
4749 if (!glWidget->hasMesh()) {
4750 logMessage("Refusing to change projection when mesh is empty");
4751 return;
4752 }
4753
4754 glWidget->stateOrtho = false;
4755 glWidget->changeProjection();
4756 glWidget->updateGL();
4757
4758 synchronizeMenuToState();
4759 logMessage("Projection: perspective");
4760 }
4761
4762 // View -> Show numbering -> Surface numbering
4763 //-----------------------------------------------------------------------------
showSurfaceNumbersSlot()4764 void MainWindow::showSurfaceNumbersSlot() {
4765 if (!glWidget->hasMesh()) {
4766 logMessage("Refusing to show surface element numbering when mesh is empty");
4767 return;
4768 }
4769 glWidget->stateDrawSurfaceNumbers = !glWidget->stateDrawSurfaceNumbers;
4770 glWidget->updateGL();
4771 synchronizeMenuToState();
4772
4773 if (glWidget->stateDrawSurfaceNumbers)
4774 logMessage("Surface element numbering turned on");
4775 else
4776 logMessage("Surface element numbering turned off");
4777 }
4778
4779 // View -> Show numbering -> Edge numbering
4780 //-----------------------------------------------------------------------------
showEdgeNumbersSlot()4781 void MainWindow::showEdgeNumbersSlot() {
4782 if (!glWidget->hasMesh()) {
4783 logMessage("Refusing to show edge element numbering when mesh is empty");
4784 return;
4785 }
4786 glWidget->stateDrawEdgeNumbers = !glWidget->stateDrawEdgeNumbers;
4787 glWidget->updateGL();
4788 synchronizeMenuToState();
4789
4790 if (glWidget->stateDrawEdgeNumbers)
4791 logMessage("Edge element numbering turned on");
4792 else
4793 logMessage("Edge element numbering turned off");
4794 }
4795
4796 // View -> Numbering -> Node numbers
4797 //-----------------------------------------------------------------------------
showNodeNumbersSlot()4798 void MainWindow::showNodeNumbersSlot() {
4799 if (!glWidget->hasMesh()) {
4800 logMessage("Refusing to show node numbering when mesh is empty");
4801 return;
4802 }
4803 glWidget->stateDrawNodeNumbers = !glWidget->stateDrawNodeNumbers;
4804 glWidget->updateGL();
4805 synchronizeMenuToState();
4806
4807 if (glWidget->stateDrawNodeNumbers)
4808 logMessage("Node numbering turned on");
4809 else
4810 logMessage("Node numbering turned off");
4811 }
4812
4813 // View -> Numbering -> Boundary index
4814 //-----------------------------------------------------------------------------
showBoundaryIndexSlot()4815 void MainWindow::showBoundaryIndexSlot() {
4816 if (!glWidget->hasMesh()) {
4817 logMessage("Refusing to show boundary indices when mesh is empty");
4818 return;
4819 }
4820 glWidget->stateDrawBoundaryIndex = !glWidget->stateDrawBoundaryIndex;
4821 glWidget->updateGL();
4822 synchronizeMenuToState();
4823
4824 if (glWidget->stateDrawBoundaryIndex)
4825 logMessage("Boundary indices visible");
4826 else
4827 logMessage("Boundary indices hidden");
4828 }
4829
4830 // View -> Numbering -> Body index
4831 //-----------------------------------------------------------------------------
showBodyIndexSlot()4832 void MainWindow::showBodyIndexSlot() {
4833 if (!glWidget->hasMesh()) {
4834 logMessage("Refusing to show body indices when mesh is empty");
4835 return;
4836 }
4837
4838 glWidget->stateDrawBodyIndex = !glWidget->stateDrawBodyIndex;
4839 glWidget->updateGL();
4840 synchronizeMenuToState();
4841
4842 if (glWidget->stateDrawBodyIndex)
4843 logMessage("Body indices visible");
4844 else
4845 logMessage("Body indices hidden");
4846 }
4847
4848 // View -> Colors -> GL controls
4849 //-----------------------------------------------------------------------------
glControlSlot()4850 void MainWindow::glControlSlot() {
4851 if (!glWidget->hasMesh()) {
4852 logMessage("No mesh - unable to set GL parameters when the mesh is empty");
4853 return;
4854 }
4855
4856 glControl->glWidget = this->glWidget;
4857 glControl->show();
4858 }
4859
4860 // View -> Colors -> Boundaries
4861 //-----------------------------------------------------------------------------
colorizeBoundarySlot()4862 void MainWindow::colorizeBoundarySlot() {
4863 if (!glWidget->hasMesh()) {
4864 logMessage("No mesh - unable to colorize boundaries");
4865 return;
4866 }
4867
4868 glWidget->stateBcColors = !glWidget->stateBcColors;
4869
4870 if (glWidget->stateBcColors)
4871 glWidget->stateBodyColors = false;
4872
4873 glWidget->rebuildLists();
4874 synchronizeMenuToState();
4875 }
4876
4877 // View -> Colors -> Bodies
4878 //-----------------------------------------------------------------------------
colorizeBodySlot()4879 void MainWindow::colorizeBodySlot() {
4880 if (!glWidget->hasMesh()) {
4881 logMessage("No mesh - unable to colorize bodies");
4882 return;
4883 }
4884
4885 glWidget->stateBodyColors = !glWidget->stateBodyColors;
4886
4887 if (glWidget->stateBodyColors)
4888 glWidget->stateBcColors = false;
4889
4890 glWidget->rebuildLists();
4891 synchronizeMenuToState();
4892 }
4893
4894 // View -> Colors -> Background
4895 //-----------------------------------------------------------------------------
backgroundColorSlot()4896 void MainWindow::backgroundColorSlot() {
4897 QColor newColor = QColorDialog::getColor(glWidget->backgroundColor, this);
4898 glWidget->qglClearColor(newColor);
4899 glWidget->backgroundColor = newColor;
4900 }
4901
4902 // View -> Colors -> Surface
4903 //-----------------------------------------------------------------------------
surfaceColorSlot()4904 void MainWindow::surfaceColorSlot() {
4905 if (!glWidget->hasMesh()) {
4906 logMessage("Unable to change surface color when the mesh is empty");
4907 return;
4908 }
4909
4910 QColor newColor = QColorDialog::getColor(glWidget->surfaceColor, this);
4911 glWidget->surfaceColor = newColor;
4912 glWidget->rebuildLists();
4913 }
4914
4915 // View -> Colors -> Edge
4916 //-----------------------------------------------------------------------------
edgeColorSlot()4917 void MainWindow::edgeColorSlot() {
4918 if (!glWidget->hasMesh()) {
4919 logMessage("Unable to change edge color when the mesh is empty");
4920 return;
4921 }
4922
4923 QColor newColor = QColorDialog::getColor(glWidget->edgeColor, this);
4924 glWidget->edgeColor = newColor;
4925 glWidget->rebuildLists();
4926 }
4927
4928 // View -> Colors -> Surface mesh
4929 //-----------------------------------------------------------------------------
surfaceMeshColorSlot()4930 void MainWindow::surfaceMeshColorSlot() {
4931 if (!glWidget->hasMesh()) {
4932 logMessage("Unable to change surface mesh color when the mesh is empty");
4933 return;
4934 }
4935
4936 QColor newColor = QColorDialog::getColor(glWidget->surfaceMeshColor, this);
4937 glWidget->surfaceMeshColor = newColor;
4938 glWidget->rebuildLists();
4939 }
4940
4941 // View -> Colors -> Sharp edges
4942 //-----------------------------------------------------------------------------
sharpEdgeColorSlot()4943 void MainWindow::sharpEdgeColorSlot() {
4944 if (!glWidget->hasMesh()) {
4945 logMessage("Unable to change sharp edge colors when the mesh is empty");
4946 return;
4947 }
4948
4949 QColor newColor = QColorDialog::getColor(glWidget->sharpEdgeColor, this);
4950 glWidget->sharpEdgeColor = newColor;
4951 glWidget->rebuildLists();
4952 }
4953
4954 // View -> Cad model...
4955 //-----------------------------------------------------------------------------
showCadModelSlot()4956 void MainWindow::showCadModelSlot() {
4957 #ifdef EG_OCC
4958 cadView->show();
4959 #endif
4960 }
4961
4962 // View -> Twod model...
4963 //-----------------------------------------------------------------------------
showTwodViewSlot()4964 void MainWindow::showTwodViewSlot() { twodView->show(); }
4965
4966 // View -> VTK post...
4967 //-----------------------------------------------------------------------------
showVtkPostSlot()4968 void MainWindow::showVtkPostSlot() {
4969 #ifdef EG_VTK
4970 QString postFileName =
4971 saveDirName + "/" + generalSetup->ui.postFileEdit->text().trimmed();
4972 // Parallel solution:
4973 //====================
4974 Ui::parallelDialog ui = parallel->ui;
4975 bool parallelActive = ui.parallelActiveCheckBox->isChecked();
4976
4977 if (parallelActive) {
4978
4979 // unify mesh:
4980 if (meshUnifier->state() == QProcess::Running) {
4981 logMessage("Mesh unifier is already running - aborted");
4982 return;
4983 }
4984
4985 if (saveDirName.isEmpty()) {
4986 logMessage("saveDirName is empty - unable to locate result files");
4987 return;
4988 }
4989
4990 // Set up log window:
4991 solverLogWindow->setWindowTitle(tr("ElmerGrid log"));
4992 solverLogWindow->getTextEdit()->clear();
4993 solverLogWindow->setFound(false);
4994 solverLogWindow->show();
4995
4996 QString postName = generalSetup->ui.postFileEdit->text().trimmed();
4997 QStringList postNameSplitted = postName.split(".");
4998 int nofProcessors = ui.nofProcessorsSpinBox->value();
4999
5000 QString unifyingCommand = ui.mergeLineEdit->text().trimmed();
5001 unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());
5002 unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));
5003
5004 logMessage("Executing: " + unifyingCommand);
5005
5006 meshUnifier->start(unifyingCommand);
5007
5008 if (!meshUnifier->waitForStarted()) {
5009 solverLogWindow->getTextEdit()->append(
5010 "Unable to start ElmerGrid for mesh unification - aborted");
5011 logMessage("Unable to start ElmerGrid for mesh unification - aborted");
5012 vtkPostMeshUnifierRunning = false;
5013 return;
5014 }
5015
5016 // The rest is done in meshUnifierFinishedSlot:
5017 vtkPostMeshUnifierRunning = true;
5018 return;
5019 }
5020
5021 // Scalar solution:
5022 //-----------------
5023 vtkPost->show();
5024
5025 QFileInfo info(postFileName);
5026 QDir dir = info.dir();
5027 if(postFileName.endsWith(".vtu", Qt::CaseInsensitive)){
5028 if(!parallelActive){
5029 QString vtuFileName = postFileName;
5030 vtuFileName.insert(vtuFileName.length()-4, "_t0001");
5031 if(!vtkPost->ReadSingleVtuFile(vtuFileName)){
5032 vtuFileName = postFileName;
5033 vtuFileName.insert(vtuFileName.length()-4, "0001");
5034 vtkPost->ReadSingleVtuFile(vtuFileName);
5035 }
5036 }
5037 }else{
5038 vtkPost->ReadPostFile(postFileName);
5039 }
5040 #endif
5041 }
5042
5043 // View -> Paraview
5044 //-----------------------------------------------------------------------------
showParaViewSlot()5045 void MainWindow::showParaViewSlot() {
5046 #ifdef EG_PARAVIEW
5047
5048 if (paraview->state() == QProcess::Running) {
5049 logMessage("ParaView is already running");
5050 return;
5051 }
5052
5053 QString postFileName = generalSetup->ui.postFileEdit->text().trimmed();
5054 QFileInfo pvFile(postFileName);
5055
5056 Ui::parallelDialog ui = parallel->ui;
5057 bool parallelActive = ui.parallelActiveCheckBox->isChecked();
5058
5059 QDir currentDir;
5060 QStringList args;
5061 QString secondName;
5062
5063 currentDir = QDir(saveDirName);
5064
5065 // Paraview can deal with case..vtu kind of arguments which however,
5066 // fail if there is only one file. Use dirty check to see that there
5067 // are more than one file.
5068
5069 if (!parallelActive) {
5070 secondName = pvFile.baseName() + "_t0002.vtu";
5071 } else {
5072 secondName = pvFile.baseName() + "_t0002.pvtu";
5073 }
5074
5075 QFile secondFile(secondName);
5076
5077 // Serial solution
5078 //================
5079 if (!parallelActive) {
5080 if (secondFile.exists())
5081 args << pvFile.baseName() + "_t..vtu";
5082 else
5083 args << pvFile.baseName() + "_t0001.vtu";
5084 }
5085
5086 // Parallel solution
5087 //==================
5088 if (parallelActive) {
5089 if (secondFile.exists())
5090 args << pvFile.baseName() + "_t..pvtu";
5091 else
5092 args << pvFile.baseName() + "_t0001.pvtu";
5093 }
5094
5095 // Launch ParaView
5096 //================
5097 paraview->start("paraview", args);
5098
5099 if (!paraview->waitForStarted()) {
5100 logMessage("Unable to start ParaView");
5101 return;
5102 }
5103
5104 logMessage("ParaView started");
5105
5106 updateSysTrayIcon("ParaView started",
5107 "");
5108
5109 #endif
5110 }
5111
5112 //*****************************************************************************
5113 //
5114 // Mesh MENU
5115 //
5116 //*****************************************************************************
5117
5118 // Mesh -> Control...
5119 //-----------------------------------------------------------------------------
meshcontrolSlot()5120 void MainWindow::meshcontrolSlot() {
5121 meshControl->tetlibPresent = this->tetlibPresent;
5122 meshControl->nglibPresent = this->nglibPresent;
5123
5124 if (!tetlibPresent) {
5125 meshControl->tetlibPresent = false;
5126 meshControl->ui.nglibRadioButton->setChecked(true);
5127 meshControl->ui.tetlibRadioButton->setEnabled(false);
5128 meshControl->ui.tetlibStringEdit->setEnabled(false);
5129 }
5130
5131 if (!nglibPresent) {
5132 meshControl->nglibPresent = false;
5133 meshControl->ui.tetlibRadioButton->setChecked(true);
5134 meshControl->ui.nglibRadioButton->setEnabled(false);
5135 meshControl->ui.nglibMaxHEdit->setEnabled(false);
5136 meshControl->ui.nglibFinenessEdit->setEnabled(false);
5137 meshControl->ui.nglibBgmeshEdit->setEnabled(false);
5138 }
5139
5140 if (!tetlibPresent && !nglibPresent)
5141 meshControl->ui.elmerGridRadioButton->setChecked(true);
5142
5143 meshControl->show();
5144 }
5145
5146 // Mesh -> Remesh
5147 //-----------------------------------------------------------------------------
remeshSlot()5148 void MainWindow::remeshSlot() {
5149 if (activeGenerator == GEN_UNKNOWN) {
5150 logMessage("Unable to (re)mesh: no input data or mesh generator (please "
5151 "make sure that your input file suffix is in lower case)");
5152 return;
5153 }
5154
5155 // ***** ELMERGRID *****
5156
5157 if (activeGenerator == GEN_ELMERGRID) {
5158
5159 meshutils->clearMesh(glWidget->getMesh());
5160 glWidget->newMesh();
5161 mesh_t *mesh = glWidget->getMesh();
5162
5163 #if WITH_QT5
5164 elmergridAPI->createElmerMeshStructure(
5165 mesh, meshControl->elmerGridControlString.toLatin1());
5166 #else
5167 elmergridAPI->createElmerMeshStructure(
5168 mesh, meshControl->elmerGridControlString.toAscii());
5169 #endif
5170
5171 if (mesh->getSurfaces() == 0)
5172 meshutils->findSurfaceElements(mesh);
5173
5174 for (int i = 0; i < mesh->getSurfaces(); i++) {
5175 surface_t *surface = mesh->getSurface(i);
5176
5177 surface->setEdges((int)(surface->getCode() / 100));
5178 surface->newEdgeIndexes(surface->getEdges());
5179 for (int j = 0; j < surface->getEdges(); j++)
5180 surface->setEdgeIndex(j, -1);
5181 }
5182
5183 meshutils->findSurfaceElementEdges(mesh);
5184 meshutils->findSurfaceElementNormals(mesh);
5185
5186 glWidget->rebuildLists();
5187 applyOperations();
5188
5189 return;
5190 }
5191
5192 // ***** Threaded generators *****
5193
5194 if (!remeshAct->isEnabled()) {
5195 logMessage("Meshing thread is already running - aborting");
5196 return;
5197 }
5198
5199 if (activeGenerator == GEN_TETLIB) {
5200
5201 if (!tetlibPresent) {
5202 logMessage("tetlib functionality unavailable");
5203 return;
5204 }
5205
5206 if (!tetlibInputOk) {
5207 logMessage("Remesh: error: no input data for tetlib");
5208 return;
5209 }
5210
5211 // Usually "J" should be included in the control string:
5212 tetlibControlString = meshControl->tetlibControlString;
5213
5214 } else if (activeGenerator == GEN_NGLIB) {
5215
5216 if (!nglibPresent) {
5217 logMessage("nglib functionality unavailable");
5218 return;
5219 }
5220
5221 if (!nglibInputOk) {
5222 logMessage("Remesh: error: no input data for nglib");
5223 return;
5224 }
5225
5226 // Init & set mesh params.:
5227 //--------------------------
5228 cout << "Initializing nglib" << endl;
5229 nglib::Ng_Init();
5230
5231 char backgroundmesh[1024];
5232 #if WITH_QT5
5233 sprintf(backgroundmesh, "%s",
5234 meshControl->nglibBackgroundmesh.toLatin1().data());
5235 #else
5236 sprintf(backgroundmesh, "%s",
5237 meshControl->nglibBackgroundmesh.toAscii().data());
5238 #endif
5239
5240 mp.maxh = meshControl->nglibMaxH.toDouble();
5241 mp.fineness = meshControl->nglibFineness.toDouble();
5242 mp.secondorder = 0;
5243 mp.meshsize_filename = backgroundmesh;
5244
5245 if (ngDim == 3) {
5246
5247 // STL (3D):
5248 //-----------
5249 cout << "Start meshing..." << endl;
5250
5251 nggeom = nglib::Ng_STL_NewGeometry();
5252
5253 ngmesh = nglib::Ng_NewMesh();
5254
5255 if (!occInputOk) {
5256
5257 // STL: regenerate structures for nglib:
5258 //--------------------------------------
5259 #if WITH_QT5
5260 nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toLatin1().data(), 0);
5261 #else
5262 nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toAscii().data(), 0);
5263 #endif
5264
5265 if (!nggeom) {
5266 logMessage("Ng_STL_LoadGeometry failed");
5267 return;
5268 }
5269
5270 nglib::Ng_STL_InitSTLGeometry(nggeom);
5271
5272 nglib::Ng_STL_MakeEdges(nggeom, ngmesh, &mp);
5273
5274 double maxMeshSize = mp.maxh;
5275
5276 if (maxMeshSize <= 0)
5277 maxMeshSize = 10000000;
5278
5279 nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5280
5281 #ifdef EG_OCC
5282 } else {
5283
5284 // OCC: (re)generate STL for nglib:
5285 //----------------------------------
5286 cadView->setMesh(ngmesh);
5287 cadView->setGeom(nggeom);
5288 cadView->setMp(&mp);
5289 cadView->generateSTL();
5290 #endif
5291 }
5292
5293 } else if (ngDim == 2) {
5294
5295 // IN2D (2D):
5296 //------------
5297 cout << "Start 2D meshing..." << endl;
5298
5299 if (!occInputOk) {
5300
5301 // Native 2D geometry input for Ng:
5302 //----------------------------------
5303 if (in2dFileName.isEmpty()) {
5304 logMessage("File name is empty - aborting");
5305 return;
5306 }
5307
5308 ngmesh = nglib::Ng_NewMesh();
5309
5310 #if WITH_QT5
5311 nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toLatin1().data());
5312 #else
5313 nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toAscii().data());
5314 #endif
5315
5316 if (!nggeom2d) {
5317 logMessage("Ng_LoadGeometry_2D failed");
5318 return;
5319 }
5320
5321 nglibAPI->setNggeom2D(nggeom2d);
5322
5323 double maxMeshSize = mp.maxh;
5324
5325 if (maxMeshSize <= 0)
5326 maxMeshSize = 10000000;
5327
5328 nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5329
5330 #ifdef EG_OCC
5331 } else {
5332
5333 // Model originates from a 2D cad file:
5334 //--------------------------------------
5335 cadView->generateIn2dFile();
5336
5337 ngmesh = nglib::Ng_NewMesh();
5338
5339 nggeom2d = nglib::Ng_LoadGeometry_2D("iges2ng.in2d");
5340
5341 if (!nggeom2d) {
5342 logMessage("Ng_LoadGeometry_2D failed");
5343 return;
5344 }
5345
5346 nglibAPI->setNggeom2D(nggeom2d);
5347
5348 double maxMeshSize = mp.maxh;
5349
5350 if (maxMeshSize <= 0)
5351 maxMeshSize = 10000000;
5352
5353 nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5354 #endif
5355 }
5356
5357 } else {
5358
5359 // Unknown spatial dimension:
5360 //----------------------------
5361 cout << "Unknown spatial dimension" << endl;
5362 return;
5363 }
5364
5365 } else {
5366
5367 logMessage("Remesh: unknown generator type");
5368 return;
5369 }
5370
5371 // ***** Start meshing thread *****
5372
5373 logMessage("Sending start request to mesh generator...");
5374
5375 meshutils->clearMesh(glWidget->getMesh());
5376 glWidget->newMesh();
5377 mesh_t *mesh = glWidget->getMesh();
5378
5379 // Re-enable when finished() or terminated() signal is received:
5380 remeshAct->setEnabled(false);
5381 stopMeshingAct->setEnabled(true);
5382
5383 if (activeGenerator == GEN_NGLIB)
5384 stopMeshingAct->setEnabled(false);
5385
5386 meshingThread->generate(activeGenerator, tetlibControlString, tetlibAPI,
5387 ngmesh, nggeom, nggeom2d, ngDim, &mp);
5388 }
5389
5390 // Mesh -> Kill generator
5391 //-----------------------------------------------------------------------------
stopMeshingSlot()5392 void MainWindow::stopMeshingSlot() {
5393 if (remeshAct->isEnabled()) {
5394 logMessage("Mesh generator is not running");
5395 return;
5396 }
5397
5398 logMessage("Sending termination request to mesh generator...");
5399 meshingThread->stopMeshing();
5400 }
5401
5402 // Meshing has started (signaled by meshingThread):
5403 //-----------------------------------------------------------------------------
meshingStartedSlot()5404 void MainWindow::meshingStartedSlot() {
5405 logMessage("Mesh generator started");
5406
5407 updateSysTrayIcon("Mesh generator started",
5408 "Use Mesh->Terminate to stop processing");
5409
5410 statusBar()->showMessage(tr("Mesh generator started"));
5411
5412 progressBar->show();
5413 progressBar->setRange(0, 0);
5414
5415 progressLabel->show();
5416 progressLabel->setText("Meshing");
5417 }
5418
5419 // Meshing has been terminated (signaled by meshingThread):
5420 //-----------------------------------------------------------------------------
meshingTerminatedSlot()5421 void MainWindow::meshingTerminatedSlot() {
5422 logMessage("Mesh generator terminated");
5423
5424 progressBar->hide();
5425 progressBar->setRange(0, 100);
5426
5427 progressLabel->hide();
5428
5429 stopMeshingAct->setEnabled(true);
5430
5431 updateSysTrayIcon("Mesh generator terminated", "Use Mesh->Remesh to restart");
5432
5433 statusBar()->showMessage(tr("Ready"));
5434
5435 // clean up:
5436 if (activeGenerator == GEN_TETLIB) {
5437 cout << "Cleaning up...";
5438 out->deinitialize();
5439 cout << "done" << endl;
5440 cout.flush();
5441 }
5442
5443 if (activeGenerator == GEN_NGLIB) {
5444 nglib::Ng_DeleteMesh(ngmesh);
5445 nglib::Ng_Exit();
5446 }
5447
5448 remeshAct->setEnabled(true);
5449 stopMeshingAct->setEnabled(false);
5450 }
5451
5452 // Mesh is ready (signaled by meshingThread):
5453 //-----------------------------------------------------------------------------
meshingFinishedSlot()5454 void MainWindow::meshingFinishedSlot() {
5455 logMessage("Mesh generation ready");
5456
5457 progressBar->hide();
5458 progressBar->setRange(0, 100);
5459
5460 progressLabel->hide();
5461
5462 if (activeGenerator == GEN_TETLIB) {
5463
5464 makeElmerMeshFromTetlib();
5465
5466 } else if (activeGenerator == GEN_NGLIB) {
5467
5468 this->ngmesh = meshingThread->getNgMesh();
5469
5470 makeElmerMeshFromNglib();
5471
5472 nglib::Ng_DeleteMesh(ngmesh);
5473 nglib::Ng_Exit();
5474
5475 } else {
5476
5477 logMessage("MeshOk: error: unknown mesh generator");
5478 }
5479
5480 applyOperations();
5481
5482 statusBar()->showMessage(tr("Ready"));
5483
5484 updateSysTrayIcon("Mesh generator has finished",
5485 "Select Model->Summary for statistics");
5486
5487 remeshAct->setEnabled(true);
5488 stopMeshingAct->setEnabled(false);
5489
5490 // Check cmd line arguments:
5491 //---------------------------
5492 QStringList args = QCoreApplication::arguments();
5493
5494 int output = args.indexOf("-o");
5495
5496 if (output > 0) {
5497 QString dirName = args.at(output + 1);
5498
5499 if (dirName.left(1) != "-") {
5500 cout << "Saving mesh files" << endl;
5501 saveElmerMesh(dirName);
5502 }
5503 }
5504
5505 if (args.contains("-e") || args.contains("-nogui")) {
5506 cout << "Exiting" << endl;
5507 QApplication::closeAllWindows();
5508 exit(0);
5509 }
5510
5511 resetSlot();
5512 }
5513
5514 // Mesh -> Divide surface...
5515 //-----------------------------------------------------------------------------
surfaceDivideSlot()5516 void MainWindow::surfaceDivideSlot() {
5517 if (!glWidget->hasMesh()) {
5518 logMessage("There is nothing to divide - mesh is empty");
5519 return;
5520 }
5521
5522 boundaryDivide->target = TARGET_SURFACES;
5523 boundaryDivide->show();
5524 }
5525
5526 // Make surface division by sharp edges (signalled by boundaryDivide)...
5527 //-----------------------------------------------------------------------------
doDivideSurfaceSlot(double angle)5528 void MainWindow::doDivideSurfaceSlot(double angle) {
5529 mesh_t *mesh = glWidget->getMesh();
5530 int lists = glWidget->getLists();
5531
5532 if (mesh == NULL) {
5533 logMessage("No mesh to divide");
5534 return;
5535 }
5536
5537 operations++;
5538 operation_t *p = new operation_t;
5539 operation_t *q = NULL;
5540
5541 for (q = &operation; q->next; q = q->next)
5542 ;
5543 q->next = p;
5544 p->next = NULL;
5545
5546 p->type = OP_DIVIDE_SURFACE;
5547 p->angle = angle;
5548
5549 int selected = 0;
5550
5551 for (int i = 0; i < lists; i++) {
5552 list_t *l = glWidget->getList(i);
5553
5554 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5555 (l->getNature() == PDE_BOUNDARY))
5556 selected++;
5557 }
5558 p->selected = selected;
5559 p->select_set = new int[selected];
5560 selected = 0;
5561
5562 for (int i = 0; i < lists; i++) {
5563 list_t *l = glWidget->getList(i);
5564 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5565 (l->getNature() == PDE_BOUNDARY))
5566 p->select_set[selected++] = i;
5567 }
5568
5569 meshutils->findSharpEdges(mesh, angle);
5570 int parts = meshutils->divideSurfaceBySharpEdges(mesh);
5571
5572 QString qs = "Surface divided into " + QString::number(parts) + " parts";
5573 statusBar()->showMessage(qs);
5574
5575 synchronizeMenuToState();
5576 glWidget->rebuildLists();
5577 glWidget->updateGL();
5578
5579 // Added 05 September 2009
5580 boundaryPropertyEditor.clear();
5581 boundaryPropertyEditor.resize(parts);
5582 for (int i = 0; i < parts; i++)
5583 boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5584 }
5585
5586 // Mesh -> Unify surface
5587 //-----------------------------------------------------------------------------
surfaceUnifySlot()5588 void MainWindow::surfaceUnifySlot() {
5589 mesh_t *mesh = glWidget->getMesh();
5590 int lists = glWidget->getLists();
5591
5592 if (mesh == NULL) {
5593 logMessage("No surfaces to unify");
5594 return;
5595 }
5596
5597 int targetindex = -1, selected = 0;
5598 QVector<BoundaryPropertyEditor *> unusedBoundary;
5599 for (int i = 0; i < lists; i++) {
5600 list_t *l = glWidget->getList(i);
5601 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5602 (l->getNature() == PDE_BOUNDARY)) {
5603 selected++;
5604 if (targetindex < 0)
5605 targetindex = l->getIndex();
5606 else {
5607 int v = glWidget->boundaryMap.value(l->getIndex());
5608 if (v >= 0 && v < boundaryPropertyEditor.size() &&
5609 boundaryPropertyEditor[v] != NULL) {
5610 unusedBoundary.append(boundaryPropertyEditor[v]);
5611 }
5612 }
5613 }
5614 }
5615
5616 if (targetindex < 0) {
5617 logMessage("No surfaces selected");
5618 return;
5619 }
5620
5621 operations++;
5622 operation_t *p = new operation_t, *q;
5623 for (q = &operation; q->next; q = q->next)
5624 ;
5625 q->next = p;
5626 p->next = NULL;
5627 p->type = OP_UNIFY_SURFACE;
5628 p->selected = selected;
5629 p->select_set = new int[selected];
5630
5631 selected = 0;
5632 for (int i = 0; i < lists; i++) {
5633 list_t *l = glWidget->getList(i);
5634 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5635 (l->getNature() == PDE_BOUNDARY)) {
5636 p->select_set[selected++] = i;
5637 for (int j = 0; j < mesh->getSurfaces(); j++) {
5638 surface_t *s = mesh->getSurface(j);
5639 if ((s->getIndex() == l->getIndex()) &&
5640 (s->getNature() == PDE_BOUNDARY))
5641 s->setIndex(targetindex);
5642 }
5643 }
5644 }
5645
5646 for (int i = 0; i < unusedBoundary.size(); i++) {
5647 boundaryPropertyEditor.remove(
5648 boundaryPropertyEditor.indexOf(unusedBoundary[i]));
5649 delete unusedBoundary[i];
5650 }
5651
5652 cout << "Selected surfaces marked with index " << targetindex << endl;
5653 cout.flush();
5654
5655 glWidget->rebuildLists();
5656
5657 logMessage("Selected surfaces unified");
5658 }
5659
applyOperations()5660 void MainWindow::applyOperations() {
5661 mesh_t *mesh = glWidget->getMesh();
5662
5663 cout << "Apply " << operations << " operations" << endl;
5664 cout.flush();
5665
5666 operation_t *p = operation.next;
5667 for (; p; p = p->next) {
5668 int lists = glWidget->getLists();
5669
5670 for (int i = 0; i < lists; i++)
5671 glWidget->getList(i)->setSelected(false);
5672
5673 for (int j = 0; j < mesh->getSurfaces(); j++)
5674 mesh->getSurface(j)->setSelected(false);
5675
5676 for (int j = 0; j < mesh->getEdges(); j++)
5677 mesh->getEdge(j)->setSelected(false);
5678
5679 for (int i = 0; i < p->selected; i++) {
5680 list_t *l = glWidget->getList(p->select_set[i]);
5681
5682 l->setSelected(true);
5683 if (p->type < OP_UNIFY_EDGE) {
5684 for (int j = 0; j < mesh->getSurfaces(); j++) {
5685 surface_t *surf = mesh->getSurface(j);
5686 if (l->getIndex() == surf->getIndex())
5687 surf->setSelected(l->isSelected());
5688 }
5689 } else {
5690 for (int j = 0; j < mesh->getEdges(); j++) {
5691 edge_t *edge = mesh->getEdge(j);
5692 if (l->getIndex() == edge->getIndex())
5693 edge->setSelected(l->isSelected());
5694 }
5695 }
5696 }
5697
5698 if (p->type == OP_DIVIDE_SURFACE) {
5699 meshutils->findSharpEdges(mesh, p->angle);
5700 int parts = meshutils->divideSurfaceBySharpEdges(mesh);
5701 QString qs = "Surface divided into " + QString::number(parts) + " parts";
5702 statusBar()->showMessage(qs);
5703
5704 } else if (p->type == OP_DIVIDE_EDGE) {
5705 meshutils->findEdgeElementPoints(mesh);
5706 meshutils->findSharpPoints(mesh, p->angle);
5707 int parts = meshutils->divideEdgeBySharpPoints(mesh);
5708 QString qs = "Edges divided into " + QString::number(parts) + " parts";
5709 statusBar()->showMessage(qs);
5710
5711 } else if (p->type == OP_UNIFY_SURFACE) {
5712 int targetindex = -1;
5713
5714 for (int i = 0; i < lists; i++) {
5715 list_t *l = glWidget->getList(i);
5716 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5717 (l->getNature() == PDE_BOUNDARY)) {
5718 if (targetindex < 0) {
5719 targetindex = l->getIndex();
5720 break;
5721 }
5722 }
5723 }
5724 for (int i = 0; i < lists; i++) {
5725 list_t *l = glWidget->getList(i);
5726 if (l->isSelected() && (l->getType() == SURFACELIST) &&
5727 (l->getNature() == PDE_BOUNDARY)) {
5728 for (int j = 0; j < mesh->getSurfaces(); j++) {
5729 surface_t *s = mesh->getSurface(j);
5730 if ((s->getIndex() == l->getIndex()) &&
5731 (s->getNature() == PDE_BOUNDARY))
5732 s->setIndex(targetindex);
5733 }
5734 }
5735 }
5736 cout << "Selected surfaces marked with index " << targetindex << endl;
5737 cout.flush();
5738
5739 } else if (p->type == OP_UNIFY_EDGE) {
5740 int targetindex = -1;
5741 for (int i = 0; i < lists; i++) {
5742 list_t *l = glWidget->getList(i);
5743 if (l->isSelected() && l->getType() == EDGELIST &&
5744 l->getNature() == PDE_BOUNDARY) {
5745 if (targetindex < 0) {
5746 targetindex = l->getIndex();
5747 break;
5748 }
5749 }
5750 }
5751 for (int i = 0; i < lists; i++) {
5752 list_t *l = glWidget->getList(i);
5753 if (l->isSelected() && l->getType() == EDGELIST &&
5754 l->getNature() == PDE_BOUNDARY) {
5755 for (int j = 0; j < mesh->getEdges(); j++) {
5756 edge_t *e = mesh->getEdge(j);
5757 if (e->getIndex() == l->getIndex() &&
5758 e->getNature() == PDE_BOUNDARY)
5759 e->setIndex(targetindex);
5760 }
5761 }
5762 }
5763 cout << "Selected edges marked with index " << targetindex << endl;
5764 cout.flush();
5765 }
5766 glWidget->rebuildLists();
5767 }
5768
5769 synchronizeMenuToState();
5770 glWidget->updateGL();
5771
5772 // Added 05 September 2009
5773 boundaryPropertyEditor.clear();
5774 int parts = glWidget->getLists();
5775 boundaryPropertyEditor.resize(parts);
5776 for (int i = 0; i < parts; i++)
5777 boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5778 }
5779
5780 // Mesh -> Divide edge...
5781 //-----------------------------------------------------------------------------
edgeDivideSlot()5782 void MainWindow::edgeDivideSlot() {
5783 if (!glWidget->hasMesh()) {
5784 logMessage("There is nothing to divide - mesh is empty");
5785 return;
5786 }
5787
5788 boundaryDivide->target = TARGET_EDGES;
5789 boundaryDivide->show();
5790 }
5791
5792 // Make edge division by sharp points (signalled by boundaryDivide)...
5793 //-----------------------------------------------------------------------------
doDivideEdgeSlot(double angle)5794 void MainWindow::doDivideEdgeSlot(double angle) {
5795 mesh_t *mesh = glWidget->getMesh();
5796 int lists = glWidget->getLists();
5797
5798 if (mesh == NULL) {
5799 logMessage("No mesh to divide");
5800 return;
5801 }
5802
5803 operations++;
5804 operation_t *p = new operation_t, *q;
5805 for (q = &operation; q->next; q = q->next)
5806 ;
5807 q->next = p;
5808 p->next = NULL;
5809
5810 p->type = OP_DIVIDE_EDGE;
5811 p->angle = angle;
5812
5813 int selected = 0;
5814 for (int i = 0; i < lists; i++) {
5815 list_t *l = glWidget->getList(i);
5816 if (l->isSelected() && l->getType() == EDGELIST &&
5817 l->getNature() == PDE_BOUNDARY)
5818 selected++;
5819 }
5820 p->selected = selected;
5821 p->select_set = new int[selected];
5822 selected = 0;
5823
5824 for (int i = 0; i < lists; i++) {
5825 list_t *l = glWidget->getList(i);
5826 if (l->isSelected() && l->getType() == EDGELIST &&
5827 l->getNature() == PDE_BOUNDARY)
5828 p->select_set[selected++] = i;
5829 }
5830
5831 meshutils->findEdgeElementPoints(mesh);
5832 meshutils->findSharpPoints(mesh, angle);
5833 int parts = meshutils->divideEdgeBySharpPoints(mesh);
5834
5835 QString qs = "Edge divided into " + QString::number(parts) + " parts";
5836 statusBar()->showMessage(qs);
5837
5838 synchronizeMenuToState();
5839 glWidget->rebuildLists();
5840 glWidget->updateGL();
5841
5842 // Added 05 September 2009
5843 boundaryPropertyEditor.clear();
5844 boundaryPropertyEditor.resize(parts);
5845 for (int i = 0; i < parts; i++)
5846 boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5847 }
5848
5849 // Mesh -> Unify edge
5850 //-----------------------------------------------------------------------------
edgeUnifySlot()5851 void MainWindow::edgeUnifySlot() {
5852 mesh_t *mesh = glWidget->getMesh();
5853 int lists = glWidget->getLists();
5854
5855 if (mesh == NULL) {
5856 logMessage("No edges to unify");
5857 return;
5858 }
5859
5860 int targetindex = -1, selected = 0;
5861 QVector<BoundaryPropertyEditor *> unusedBoundary;
5862 for (int i = 0; i < lists; i++) {
5863 list_t *l = glWidget->getList(i);
5864 if (l->isSelected() && l->getType() == EDGELIST &&
5865 l->getNature() == PDE_BOUNDARY) {
5866 selected++;
5867 if (targetindex < 0)
5868 targetindex = l->getIndex();
5869 else {
5870 int v = glWidget->boundaryMap.value(l->getIndex());
5871 if (v >= 0 && v < boundaryPropertyEditor.size() &&
5872 boundaryPropertyEditor[v] != NULL) {
5873 unusedBoundary.append(boundaryPropertyEditor[v]);
5874 }
5875 }
5876 }
5877 }
5878
5879 if (targetindex < 0) {
5880 logMessage("No edges selected");
5881 return;
5882 }
5883
5884 operations++;
5885 operation_t *p = new operation_t, *q;
5886 for (q = &operation; q->next; q = q->next)
5887 ;
5888 q->next = p;
5889 p->next = NULL;
5890 p->type = OP_UNIFY_EDGE;
5891 p->selected = selected;
5892 p->select_set = new int[selected];
5893
5894 selected = 0;
5895
5896 for (int i = 0; i < lists; i++) {
5897 list_t *l = glWidget->getList(i);
5898 if (l->isSelected() && l->getType() == EDGELIST &&
5899 l->getNature() == PDE_BOUNDARY) {
5900 p->select_set[selected++] = i;
5901 for (int j = 0; j < mesh->getEdges(); j++) {
5902 edge_t *e = mesh->getEdge(j);
5903 if (e->getIndex() == l->getIndex() && e->getNature() == PDE_BOUNDARY)
5904 e->setIndex(targetindex);
5905 }
5906 }
5907 }
5908
5909 for (int i = 0; i < unusedBoundary.size(); i++) {
5910 boundaryPropertyEditor.remove(
5911 boundaryPropertyEditor.indexOf(unusedBoundary[i]));
5912 delete unusedBoundary[i];
5913 }
5914
5915 cout << "Selected edges marked with index " << targetindex << endl;
5916 cout.flush();
5917
5918 glWidget->rebuildLists();
5919
5920 logMessage("Selected edges unified");
5921 }
5922
5923 // Mesh -> Clean up
5924 //-----------------------------------------------------------------------------
cleanHangingSharpEdgesSlot()5925 void MainWindow::cleanHangingSharpEdgesSlot() {
5926 mesh_t *mesh = glWidget->getMesh();
5927
5928 if (mesh == NULL)
5929 return;
5930
5931 int count = meshutils->cleanHangingSharpEdges(mesh);
5932
5933 cout << "Removed " << count << " hanging sharp edges" << endl;
5934 cout.flush();
5935
5936 glWidget->rebuildLists();
5937 }
5938
5939 //*****************************************************************************
5940 //
5941 // Edit MENU
5942 //
5943 //*****************************************************************************
5944
5945 // Edit -> Sif...
5946 //-----------------------------------------------------------------------------
showsifSlot()5947 void MainWindow::showsifSlot() {
5948 // QFont sansFont("Courier", 10);
5949 // sifWindow->getTextEdit()->setCurrentFont(sansFont);
5950 if(sifWindow->windowState() & Qt::WindowMinimized){
5951 sifWindow->showNormal();
5952 }
5953 else sifWindow->show();
5954 }
5955
5956 // Edit -> Generate sif
5957 //-----------------------------------------------------------------------------
generateSifSlot()5958 void MainWindow::generateSifSlot() {
5959 mesh_t *mesh = glWidget->getMesh();
5960
5961 if (mesh == NULL) {
5962 logMessage("Unable to create SIF: no mesh");
5963 return;
5964 }
5965
5966 if ((mesh->getDim() < 1) || (mesh->getCdim() < 1)) {
5967 logMessage("Model dimension inconsistent with SIF syntax");
5968 return;
5969 }
5970
5971 // Clear SIF text editor:
5972 //------------------------
5973 sifWindow->getTextEdit()->clear();
5974 sifWindow->setFirstTime(true);
5975 sifWindow->setFound(false);
5976 // QFont sansFont("Courier", 10);
5977 // sifWindow->getTextEdit()->setCurrentFont(sansFont);
5978
5979 // Set up SIF generator:
5980 //-----------------------
5981 sifGenerator->setMesh(mesh);
5982 sifGenerator->setTextEdit(sifWindow->getTextEdit());
5983 sifGenerator->setDim(mesh->getDim());
5984 sifGenerator->setCdim(mesh->getCdim());
5985 sifGenerator->setGeneralSetup(generalSetup);
5986
5987 sifGenerator->setEquationEditor(equationEditor);
5988 sifGenerator->setMaterialEditor(materialEditor);
5989 sifGenerator->setBodyForceEditor(bodyForceEditor);
5990 sifGenerator->setInitialConditionEditor(initialConditionEditor);
5991 sifGenerator->setBoundaryConditionEditor(boundaryConditionEditor);
5992 sifGenerator->setSolverParameterEditor(solverParameterEditor);
5993 sifGenerator->setBoundaryPropertyEditor(boundaryPropertyEditor);
5994 sifGenerator->setBodyPropertyEditor(bodyPropertyEditor);
5995 sifGenerator->setMeshControl(meshControl);
5996 sifGenerator->setElmerDefs(elmerDefs);
5997 sifGenerator->bodyMap = glWidget->bodyMap;
5998 sifGenerator->boundaryMap = glWidget->boundaryMap;
5999
6000 // Make SIF:
6001 //----------
6002 sifGenerator->makeHeaderBlock();
6003 sifGenerator->makeSimulationBlock();
6004 sifGenerator->makeConstantsBlock();
6005 sifGenerator->makeBodyBlocks();
6006 sifGenerator->makeEquationBlocks();
6007 sifGenerator->makeMaterialBlocks();
6008 sifGenerator->makeBodyForceBlocks();
6009 sifGenerator->makeInitialConditionBlocks();
6010 sifGenerator->makeBoundaryBlocks();
6011 }
6012
6013 // Boundary selected by double clicking (signaled by glWidget::select):
6014 //-----------------------------------------------------------------------------
boundarySelectedSlot(list_t * l)6015 void MainWindow::boundarySelectedSlot(list_t *l) {
6016 QString qs;
6017
6018 if (l->getIndex() < 0) {
6019 statusBar()->showMessage("Ready");
6020 return;
6021 }
6022
6023 if (l->isSelected()) {
6024 if (l->getType() == SURFACELIST) {
6025 qs = "Selected surface " + QString::number(l->getIndex());
6026 } else if (l->getType() == EDGELIST) {
6027 qs = "Selected edge " + QString::number(l->getIndex());
6028 } else {
6029 qs = "Selected object " + QString::number(l->getIndex()) +
6030 " (type unknown)";
6031 }
6032 } else {
6033 if (l->getType() == SURFACELIST) {
6034 qs = "Unselected surface " + QString::number(l->getIndex());
6035 } else if (l->getType() == EDGELIST) {
6036 qs = "Unselected edge " + QString::number(l->getIndex());
6037 } else {
6038 qs = "Unselected object " + QString::number(l->getIndex()) +
6039 " (type unknown)";
6040 }
6041 }
6042
6043 logMessage(qs);
6044
6045 // Open bc property sheet for selected boundary:
6046 //-----------------------------------------------
6047 if (l->isSelected() && (glWidget->altPressed || bcEditActive)) {
6048 glWidget->ctrlPressed = false;
6049 glWidget->shiftPressed = false;
6050 glWidget->altPressed = false;
6051
6052 if (l->getNature() != PDE_BOUNDARY) {
6053 /*Ignore when double clicking a body of 2D geometry under boundary
6054 * selection mode*/
6055 raise();
6056 return;
6057 }
6058
6059 // renumbering:
6060 int n = glWidget->boundaryMap.value(l->getIndex());
6061
6062 if (n >= boundaryPropertyEditor.size()) {
6063 logMessage("Error: Boundary index mismatch");
6064 return;
6065 }
6066
6067 BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];
6068 populateBoundaryComboBoxes(boundaryEdit);
6069
6070 connect(boundaryEdit,
6071 SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor *, int)), this,
6072 SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor *, int)));
6073
6074 if (boundaryEdit->touched) {
6075 boundaryEdit->ui.applyButton->setText("Update");
6076 // boundaryEdit->ui.discardButton->setText("Remove");
6077 boundaryEdit->ui.discardButton->setText("Cancel");
6078 boundaryEdit->ui.applyButton->setIcon(
6079 QIcon(":/icons/dialog-ok-apply.png"));
6080 // boundaryEdit->ui.discardButton->setIcon(QIcon(":/icons/list-remove.png"));
6081 boundaryEdit->ui.discardButton->setIcon(
6082 QIcon(":/icons/dialog-close.png"));
6083 } else {
6084 boundaryEdit->ui.applyButton->setText("Add");
6085 boundaryEdit->ui.discardButton->setText("Cancel");
6086 boundaryEdit->ui.applyButton->setIcon(QIcon(":/icons/list-add.png"));
6087 boundaryEdit->ui.discardButton->setIcon(
6088 QIcon(":/icons/dialog-close.png"));
6089 }
6090
6091 boundaryEdit->setWindowTitle("Properties for boundary " +
6092 QString::number(l->getIndex()));
6093 boundaryEdit->show();
6094 boundaryEdit->raise();
6095 }
6096
6097 BodyPropertyEditor *bodyEdit = NULL;
6098 int current = -1, n = -1;
6099
6100 // boundary as a body treatment
6101 // ----------------------------
6102 if (l->isSelected() && glWidget->ctrlPressed) {
6103
6104 // renumbering:
6105 int n = glWidget->boundaryMap.value(l->getIndex());
6106
6107 if (n >= boundaryPropertyEditor.size()) {
6108 logMessage("Error: Boundary index mismatch");
6109 return;
6110 }
6111
6112 BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];
6113
6114 if (!boundaryEdit) {
6115 cout << "MainWindow: Boundary index out of bounds" << endl;
6116 return;
6117 }
6118
6119 bodyEdit = boundaryEdit->bodyProperties;
6120
6121 if (bodyEdit) {
6122 glWidget->ctrlPressed = false;
6123 glWidget->shiftPressed = false;
6124 glWidget->altPressed = false;
6125
6126 bodyEdit->setWindowTitle("Properties for body " +
6127 QString::number(current));
6128
6129 // if(bodyEdit->ui.nameEdit->text().trimmed().isEmpty())
6130 // bodyEdit->ui.nameEdit->setText("Body Property{Boundary " +
6131 // QString::number(n+1) + "}");
6132 bodyEdit->ui.nameEdit->setText("Body {Boundary " +
6133 QString::number(n + 1) + "}");
6134 }
6135 }
6136
6137 // Open body property sheet for selected body:
6138 //---------------------------------------------
6139 if ((glWidget->currentlySelectedBody >= 0) &&
6140 (glWidget->shiftPressed || bodyEditActive)) {
6141
6142 glWidget->ctrlPressed = false;
6143 glWidget->shiftPressed = false;
6144 glWidget->altPressed = false;
6145
6146 current = glWidget->currentlySelectedBody;
6147
6148 cout << "Current selection uniquely determines body: " << current << endl;
6149 cout.flush();
6150
6151 // renumbering:
6152 n = glWidget->bodyMap.value(current);
6153
6154 if (n >= bodyPropertyEditor.size()) {
6155 logMessage("MainWindow: Body index out of bounds)");
6156 return;
6157 }
6158
6159 bodyEdit = bodyPropertyEditor[n];
6160
6161 if (!bodyEdit)
6162 cout << "MainWindow: Undetermined body index" << endl;
6163
6164 bodyEdit->setWindowTitle("Properties for body " + QString::number(current));
6165
6166 if (bodyEdit->ui.nameEdit->text().trimmed().isEmpty())
6167 bodyEdit->ui.nameEdit->setText("Body Property " + QString::number(n + 1));
6168 }
6169
6170 if (bodyEdit) {
6171 populateBodyComboBoxes(bodyEdit);
6172
6173 if (bodyEdit->touched) {
6174 bodyEdit->ui.applyButton->setText("Update");
6175 // bodyEdit->ui.discardButton->setText("Remove");
6176 bodyEdit->ui.discardButton->setText("Cancel");
6177 bodyEdit->ui.applyButton->setIcon(QIcon(":/icons/dialog-ok-apply.png"));
6178 // bodyEdit->ui.discardButton->setIcon(QIcon(":/icons/list-remove.png"));
6179 bodyEdit->ui.discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
6180 } else {
6181 bodyEdit->ui.applyButton->setText("Add");
6182 bodyEdit->ui.discardButton->setText("Cancel");
6183 bodyEdit->ui.applyButton->setIcon(QIcon(":/icons/list-add.png"));
6184 bodyEdit->ui.discardButton->setIcon(QIcon(":/icons/dialog-close.png"));
6185 }
6186
6187 bodyEdit->show();
6188 bodyEdit->raise();
6189 }
6190 }
6191
6192 // Populate boundary editor's comboboxes:
6193 //---------------------------------------
populateBoundaryComboBoxes(BoundaryPropertyEditor * boundary)6194 void MainWindow::populateBoundaryComboBoxes(BoundaryPropertyEditor *boundary) {
6195 boundary->disconnect(
6196 SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)));
6197 while (boundary && boundary->ui.boundaryConditionCombo &&
6198 boundary->ui.boundaryConditionCombo->count() > 0)
6199 boundary->ui.boundaryConditionCombo->removeItem(0);
6200
6201 int takethis = 1; //-1;
6202 int count = 1;
6203 boundary->ui.boundaryConditionCombo->insertItem(count++, "");
6204
6205 for (int i = 0; i < boundaryConditionEditor.size(); i++) {
6206 DynamicEditor *bcEdit = boundaryConditionEditor[i];
6207 if (bcEdit->menuAction != NULL) {
6208 const QString &name = bcEdit->nameEdit->text().trimmed();
6209 boundary->ui.boundaryConditionCombo->insertItem(count, name);
6210 if (boundary->condition == bcEdit)
6211 takethis = count;
6212 count++;
6213 }
6214 }
6215 connect(boundary,
6216 SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)), this,
6217 SLOT(boundaryComboChanged(BoundaryPropertyEditor *, QString)));
6218
6219 boundary->ui.boundaryConditionCombo->setCurrentIndex(takethis - 1);
6220 }
6221
6222 //-----------------------------------------------------------------------------
boundaryComboChanged(BoundaryPropertyEditor * b,QString text)6223 void MainWindow::boundaryComboChanged(BoundaryPropertyEditor *b, QString text) {
6224 b->condition = 0;
6225 b->touched = false;
6226
6227 for (int i = 0; i < boundaryConditionEditor.size(); i++) {
6228 DynamicEditor *bc = boundaryConditionEditor[i];
6229 if (bc->ID >= 0) {
6230 if (bc->nameEdit->text().trimmed() == text) {
6231 b->condition = bc;
6232 b->touched = true;
6233 break;
6234 }
6235 }
6236 }
6237 }
6238
6239 //-----------------------------------------------------------------------------
boundaryAsABodyChanged(BoundaryPropertyEditor * b,int status)6240 void MainWindow::boundaryAsABodyChanged(BoundaryPropertyEditor *b, int status) {
6241 int indx = glWidget->bodyMap.count();
6242
6243 if (status) {
6244 for (int i = 0; i < boundaryPropertyEditor.size(); i++)
6245 if (boundaryPropertyEditor[i] &&
6246 boundaryPropertyEditor[i]->bodyProperties)
6247 indx++;
6248
6249 if (indx >= bodyPropertyEditor.size()) {
6250 cout << "MainWindow: Body index out of bounds" << endl;
6251 return;
6252 }
6253
6254 if (bodyPropertyEditor[indx])
6255 b->bodyProperties = bodyPropertyEditor[indx];
6256
6257 } else {
6258
6259 b->bodyProperties = NULL;
6260 }
6261 }
6262
6263 // Populate body editor's comboboxes:
6264 //-----------------------------------
populateBodyComboBoxes(BodyPropertyEditor * bodyEdit)6265 void MainWindow::populateBodyComboBoxes(BodyPropertyEditor *bodyEdit) {
6266 // Equation:
6267 // =========
6268 bodyEdit->disconnect(
6269 SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)));
6270 bodyEdit->ui.equationCombo->clear();
6271
6272 int count = 1;
6273 int takethis = 1; // -1
6274 bodyEdit->ui.equationCombo->insertItem(count++, "");
6275
6276 for (int i = 0; i < equationEditor.size(); i++) {
6277 DynamicEditor *eqEdit = equationEditor[i];
6278 if (eqEdit->menuAction != NULL) {
6279 const QString &name = eqEdit->nameEdit->text().trimmed();
6280 bodyEdit->ui.equationCombo->insertItem(count, name);
6281 if (bodyEdit->equation == eqEdit)
6282 takethis = count;
6283 count++;
6284 }
6285 }
6286 connect(bodyEdit,
6287 SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)), this,
6288 SLOT(equationComboChanged(BodyPropertyEditor *, QString)));
6289 bodyEdit->ui.equationCombo->setCurrentIndex(takethis - 1);
6290
6291 // Material
6292 // =========
6293 bodyEdit->disconnect(
6294 SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)));
6295 bodyEdit->ui.materialCombo->clear();
6296
6297 count = 1;
6298 takethis = 1;
6299 bodyEdit->ui.materialCombo->insertItem(count, "");
6300 count++;
6301
6302 for (int i = 0; i < materialEditor.size(); i++) {
6303 DynamicEditor *matEdit = materialEditor[i];
6304
6305 if (matEdit->menuAction != NULL) {
6306 const QString &name = matEdit->nameEdit->text().trimmed();
6307 bodyEdit->ui.materialCombo->insertItem(count, name);
6308 if (bodyEdit->material == matEdit)
6309 takethis = count;
6310 count++;
6311 }
6312 }
6313
6314 connect(bodyEdit,
6315 SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)), this,
6316 SLOT(materialComboChanged(BodyPropertyEditor *, QString)));
6317
6318 bodyEdit->ui.materialCombo->setCurrentIndex(takethis - 1);
6319
6320 // Bodyforce:
6321 //===========
6322 bodyEdit->disconnect(
6323 SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)));
6324 bodyEdit->ui.bodyForceCombo->clear();
6325
6326 count = 1;
6327 takethis = 1; // -1
6328 bodyEdit->ui.bodyForceCombo->insertItem(count++, "");
6329
6330 for (int i = 0; i < bodyForceEditor.size(); i++) {
6331 DynamicEditor *bodyForceEdit = bodyForceEditor[i];
6332 if (bodyForceEdit->menuAction != NULL) {
6333 const QString &name = bodyForceEdit->nameEdit->text().trimmed();
6334 bodyEdit->ui.bodyForceCombo->insertItem(count, name);
6335 if (bodyEdit->force == bodyForceEdit)
6336 takethis = count;
6337 count++;
6338 }
6339 }
6340 connect(bodyEdit,
6341 SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)), this,
6342 SLOT(forceComboChanged(BodyPropertyEditor *, QString)));
6343 bodyEdit->ui.bodyForceCombo->setCurrentIndex(takethis - 1);
6344
6345 // Initial Condition:
6346 //====================
6347 bodyEdit->disconnect(
6348 SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)));
6349 bodyEdit->ui.initialConditionCombo->clear();
6350
6351 count = 1;
6352 takethis = 1; // -1
6353 bodyEdit->ui.initialConditionCombo->insertItem(count++, "");
6354
6355 for (int i = 0; i < initialConditionEditor.size(); i++) {
6356 DynamicEditor *initialConditionEdit = initialConditionEditor[i];
6357 if (initialConditionEdit->menuAction != NULL) {
6358 const QString &name = initialConditionEdit->nameEdit->text().trimmed();
6359 bodyEdit->ui.initialConditionCombo->insertItem(count, name);
6360 if (bodyEdit->initial == initialConditionEdit)
6361 takethis = count;
6362 count++;
6363 }
6364 }
6365 connect(bodyEdit,
6366 SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)), this,
6367 SLOT(initialComboChanged(BodyPropertyEditor *, QString)));
6368 bodyEdit->ui.initialConditionCombo->setCurrentIndex(takethis - 1);
6369 }
6370
6371 //-----------------------------------------------------------------------------
materialComboChanged(BodyPropertyEditor * b,QString text)6372 void MainWindow::materialComboChanged(BodyPropertyEditor *b, QString text) {
6373 b->material = 0;
6374 b->touched = false;
6375 for (int i = 0; i < materialEditor.size(); i++) {
6376 DynamicEditor *mat = materialEditor[i];
6377
6378 if (mat->ID >= 0) {
6379 if (mat->nameEdit->text().trimmed() == text) {
6380 b->material = mat;
6381 b->touched = true;
6382 break;
6383 }
6384 }
6385 }
6386 }
6387
6388 //-----------------------------------------------------------------------------
initialComboChanged(BodyPropertyEditor * b,QString text)6389 void MainWindow::initialComboChanged(BodyPropertyEditor *b, QString text) {
6390 b->initial = 0;
6391 b->touched = false;
6392
6393 for (int i = 0; i < initialConditionEditor.size(); i++) {
6394 DynamicEditor *ic = initialConditionEditor[i];
6395 if (ic->ID >= 0) {
6396 if (ic->nameEdit->text().trimmed() == text) {
6397 b->initial = ic;
6398 b->touched = true;
6399 break;
6400 }
6401 }
6402 }
6403 }
6404
6405 //-----------------------------------------------------------------------------
forceComboChanged(BodyPropertyEditor * b,QString text)6406 void MainWindow::forceComboChanged(BodyPropertyEditor *b, QString text) {
6407 b->force = 0;
6408 b->touched = false;
6409
6410 for (int i = 0; i < bodyForceEditor.size(); i++) {
6411 DynamicEditor *bf = bodyForceEditor[i];
6412 if (bf->ID >= 0) {
6413 if (bf->nameEdit->text().trimmed() == text) {
6414 b->force = bf;
6415 b->touched = true;
6416 break;
6417 }
6418 }
6419 }
6420 }
6421
6422 //-----------------------------------------------------------------------------
equationComboChanged(BodyPropertyEditor * b,QString text)6423 void MainWindow::equationComboChanged(BodyPropertyEditor *b, QString text) {
6424 b->equation = 0;
6425 b->touched = false;
6426
6427 for (int i = 0; i < equationEditor.size(); i++) {
6428 DynamicEditor *equ = equationEditor[i];
6429 if (equ->ID >= 0) {
6430 if (equ->nameEdit->text().trimmed() == text) {
6431 b->equation = equ;
6432 b->touched = true;
6433 break;
6434 }
6435 }
6436 }
6437 }
6438
6439 // Edit -> Definitions...
6440 //-----------------------------------------------------------------------------
editDefinitionsSlot()6441 void MainWindow::editDefinitionsSlot() {
6442 if (elmerDefs == NULL)
6443 return;
6444
6445 edfEditor->show();
6446 }
6447
6448 //*****************************************************************************
6449 //
6450 // Solver MENU
6451 //
6452 //*****************************************************************************
6453
6454 // Solver -> Parallel settings
6455 //-----------------------------------------------------------------------------
parallelSettingsSlot()6456 void MainWindow::parallelSettingsSlot() { parallel->show(); }
6457
6458 // Solver -> Run solver
6459 //-----------------------------------------------------------------------------
runsolverSlot()6460 void MainWindow::runsolverSlot() {
6461 if (!glWidget->hasMesh()) {
6462 logMessage("No mesh - unable to start solver");
6463 return;
6464 }
6465
6466 if (solver->state() == QProcess::Running) {
6467 logMessage("Solver is already running - returning");
6468 return;
6469 }
6470
6471 // Parallel solution:
6472 //====================
6473 Ui::parallelDialog ui = parallel->ui;
6474 bool parallelActive = ui.parallelActiveCheckBox->isChecked();
6475 bool partitioningActive = !ui.skipPartitioningCheckBox->isChecked();
6476 int nofProcessors = ui.nofProcessorsSpinBox->value();
6477
6478 if (parallelActive) {
6479
6480 // Set up log window:
6481 solverLogWindow->setWindowTitle(tr("Solver log"));
6482 solverLogWindow->getTextEdit()->clear();
6483 solverLogWindow->setFound(false);
6484 solverLogWindow->show();
6485
6486 if (!partitioningActive) {
6487
6488 // skip splitting:
6489 meshSplitterFinishedSlot(0);
6490
6491 } else {
6492
6493 // split mesh:
6494 if (meshSplitter->state() == QProcess::Running) {
6495 logMessage("Mesh partitioner is already running - aborted");
6496 return;
6497 }
6498
6499 if (saveDirName.isEmpty()) {
6500 logMessage("Please save the mesh before running the parallel solver - "
6501 "aborted");
6502 return;
6503 }
6504
6505 QString partitioningCommand = ui.divideLineEdit->text().trimmed();
6506 partitioningCommand.replace(QString("%msh"), saveDirName);
6507 partitioningCommand.replace(QString("%n"),
6508 QString::number(nofProcessors));
6509
6510 logMessage("Executing: " + partitioningCommand);
6511
6512 meshSplitter->start(partitioningCommand);
6513
6514 if (!meshSplitter->waitForStarted()) {
6515 logMessage("Unable to start ElmerGrid for mesh partitioning - aborted");
6516 return;
6517 }
6518 }
6519
6520 // the rest is done in meshSplitterFinishedSlot:
6521 return;
6522 }
6523
6524 // Scalar solution:
6525 //==================
6526 solver->start("ElmerSolver");
6527 killsolverAct->setEnabled(true);
6528
6529 if (!solver->waitForStarted()) {
6530 logMessage("Unable to start solver");
6531 return;
6532 }
6533
6534 solverLogWindow->setWindowTitle(tr("Solver log"));
6535 solverLogWindow->getTextEdit()->clear();
6536 solverLogWindow->setFound(false);
6537 solverLogWindow->show();
6538
6539 // convergence plot:
6540 #ifdef EG_QWT
6541 convergenceView->removeData();
6542 convergenceView->title = "Convergence history";
6543 #endif
6544
6545 logMessage("Solver started");
6546
6547 runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));
6548
6549 updateSysTrayIcon("ElmerSolver started",
6550 "Use Run->Kill solver to stop processing");
6551 }
6552
6553 // meshSplitter emits (int) when ready...
6554 //-----------------------------------------------------------------------------
meshSplitterFinishedSlot(int exitCode)6555 void MainWindow::meshSplitterFinishedSlot(int exitCode) {
6556 if (exitCode != 0) {
6557 solverLogWindow->getTextEdit()->append("MeshSplitter failed - aborting");
6558 logMessage("MeshSplitter failed - aborting");
6559 return;
6560 }
6561
6562 logMessage("MeshSplitter ready");
6563
6564 // Prepare for parallel solution:
6565 Ui::parallelDialog ui = parallel->ui;
6566
6567 int nofProcessors = ui.nofProcessorsSpinBox->value();
6568
6569 QString parallelExec = ui.parallelExecLineEdit->text().trimmed();
6570 #ifdef WIN32
6571 parallelExec = "\"" + parallelExec + "\"";
6572 #endif
6573
6574 QString parallelArgs = ui.parallelArgsLineEdit->text().trimmed();
6575 parallelArgs.replace(QString("%n"), QString::number(nofProcessors));
6576
6577 QString parallelCmd = parallelExec + " " + parallelArgs;
6578
6579 logMessage("Executing: " + parallelCmd);
6580
6581 solver->start(parallelCmd);
6582 killsolverAct->setEnabled(true);
6583
6584 if (!solver->waitForStarted()) {
6585 solverLogWindow->getTextEdit()->append("Unable to start parallel solver");
6586 logMessage("Unable to start parallel solver");
6587 return;
6588 }
6589
6590 // Set up convergence plot:
6591 #ifdef EG_QWT
6592 convergenceView->removeData();
6593 convergenceView->title = "Convergence history";
6594 #endif
6595 logMessage("Parallel solver started");
6596 runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));
6597
6598 updateSysTrayIcon("ElmerSolver started",
6599 "Use Run->Kill solver to stop processing");
6600 }
6601
6602 // meshSplitter emits (void) when there is something to read from stdout:
6603 //-----------------------------------------------------------------------------
meshSplitterStdoutSlot()6604 void MainWindow::meshSplitterStdoutSlot() {
6605 QString qs = meshSplitter->readAllStandardOutput();
6606
6607 while (qs.at(qs.size() - 1).unicode() == '\n')
6608 qs.chop(1);
6609
6610 solverLogWindow->getTextEdit()->append(qs);
6611 }
6612
6613 // meshSplitter emits (void) when there is something to read from stderr:
6614 //-----------------------------------------------------------------------------
meshSplitterStderrSlot()6615 void MainWindow::meshSplitterStderrSlot() {
6616 QString qs = meshSplitter->readAllStandardError();
6617
6618 while (qs.at(qs.size() - 1).unicode() == '\n')
6619 qs.chop(1);
6620
6621 solverLogWindow->getTextEdit()->append(qs);
6622 }
6623
6624 // meshUnifier emits (int) when ready...
6625 //-----------------------------------------------------------------------------
meshUnifierFinishedSlot(int exitCode)6626 void MainWindow::meshUnifierFinishedSlot(int exitCode) {
6627 QStringList args;
6628
6629 if (exitCode != 0) {
6630 solverLogWindow->getTextEdit()->append("MeshUnifier failed - aborting");
6631 logMessage("MeshUnifier failed - aborting");
6632 vtkPostMeshUnifierRunning = false;
6633 return;
6634 }
6635
6636 logMessage("MeshUnifier ready");
6637
6638 // Prepare for post processing parallel reults:
6639 //----------------------------------------------
6640 QString postName = generalSetup->ui.postFileEdit->text().trimmed();
6641
6642 // VtkPost:
6643 //---------
6644 #ifdef EG_VTK
6645 if (vtkPostMeshUnifierRunning) {
6646 vtkPost->show();
6647
6648 vtkPost->ReadPostFile(postName);
6649 // if(!vtkPost->ReadPostFile(postName)) vtkPost->readEpFileSlot();
6650
6651 vtkPostMeshUnifierRunning = false;
6652 return;
6653 }
6654 #endif
6655
6656 QFile file(postName);
6657 if (!file.exists()) {
6658 solverLogWindow->getTextEdit()->append(
6659 "Elmerpost input file does not exist.");
6660 logMessage("Elmerpost input file does not exist.");
6661 vtkPostMeshUnifierRunning = false;
6662 return;
6663 }
6664
6665 file.open(QIODevice::ReadOnly);
6666 QTextStream header(&file);
6667
6668 int nn, ne, nt, nf;
6669 QString type, name, tstep;
6670
6671 header >> nn >> ne >> nf >> nt >> type >> name;
6672 if (type == "vector:")
6673 name = name + "_abs";
6674
6675 file.close();
6676
6677 QString simtype =
6678 generalSetup->ui.simulationTypeCombo->currentText().trimmed();
6679 if (simtype.toLower() == "transient") {
6680 tstep = QString::number(1);
6681 } else {
6682 tstep = QString::number(nt);
6683 }
6684
6685 args << "readfile " + postName + " " + tstep + " " + tstep +
6686 "1; "
6687 "set ColorScaleY -0.85; "
6688 "set ColorScaleEntries 4;"
6689 "set ColorScaleDecimals 2;"
6690 "set ColorScaleColor " +
6691 name +
6692 ";"
6693 "set DisplayStyle(ColorScale) 1; "
6694 "set MeshStyle 1; "
6695 "set MeshColor " +
6696 name +
6697 ";"
6698 "set DisplayStyle(ColorMesh) 1; "
6699 "translate -y 0.2; "
6700 "UpdateObject; ";
6701
6702 post->start("ElmerPost", args);
6703 killresultsAct->setEnabled(true);
6704
6705 if (!post->waitForStarted()) {
6706 logMessage("Unable to start post processor");
6707 return;
6708 }
6709
6710 resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
6711
6712 logMessage("Post processor started");
6713
6714 updateSysTrayIcon("ElmerPost started",
6715 "Use Run->Kill ElmerPost to stop processing");
6716 }
6717
6718 // meshUnifier emits (void) when there is something to read from stdout:
6719 //-----------------------------------------------------------------------------
meshUnifierStdoutSlot()6720 void MainWindow::meshUnifierStdoutSlot() {
6721 QString qs = meshUnifier->readAllStandardOutput();
6722
6723 while (qs.at(qs.size() - 1).unicode() == '\n')
6724 qs.chop(1);
6725
6726 solverLogWindow->getTextEdit()->append(qs);
6727 }
6728
6729 // meshUnifier emits (void) when there is something to read from stderr:
6730 //-----------------------------------------------------------------------------
meshUnifierStderrSlot()6731 void MainWindow::meshUnifierStderrSlot() {
6732 QString qs = meshUnifier->readAllStandardError();
6733
6734 while (qs.at(qs.size() - 1).unicode() == '\n')
6735 qs.chop(1);
6736
6737 solverLogWindow->getTextEdit()->append(qs);
6738 }
6739
6740 // solver process emits (void) when there is something to read from stdout:
6741 //-----------------------------------------------------------------------------
solverStdoutSlot()6742 void MainWindow::solverStdoutSlot() {
6743 static QString qs_save = "";
6744
6745 QString qs = qs_save + solver->readAllStandardOutput();
6746
6747 int n = qs.lastIndexOf('\n');
6748
6749 if ((n > 0) && (n < qs.size() - 1)) {
6750 qs_save = qs.mid(n + 1);
6751 qs = qs.mid(0, n);
6752
6753 } else if (n == 0) {
6754 if (qs.size() == 1) {
6755 qs_save = "";
6756 return;
6757 }
6758 qs_save = qs.mid(1);
6759 return;
6760
6761 } else if (n < 0) {
6762 qs_save = qs;
6763 return;
6764
6765 } else
6766 qs_save = "";
6767
6768 while (qs.at(qs.size() - 1).unicode() == '\n')
6769 qs.chop(1);
6770
6771 if (qs.isEmpty())
6772 return;
6773
6774 solverLogWindow->getTextEdit()->append(qs);
6775
6776 #ifdef EG_QWT
6777 if (!showConvergence) {
6778
6779 // hide convergence plot
6780 //----------------------
6781 convergenceView->hide();
6782
6783 } else {
6784
6785 // show convergence plot
6786 //----------------------
6787 if (!convergenceView->isVisible())
6788 convergenceView->show();
6789 }
6790 #endif
6791
6792 QStringList qsl = qs.split("\n");
6793 for (int i = 0; i < qsl.count(); i++) {
6794 QString tmp = qsl.at(i).trimmed();
6795
6796 if (tmp.contains("Time:")) {
6797 QStringList tmpSplitted = tmp.split(" ");
6798 int last = tmpSplitted.count() - 1;
6799 QString timeString = tmpSplitted.at(last);
6800 double timeDouble = timeString.toDouble();
6801 #ifdef EG_QWT
6802 convergenceView->title =
6803 "Convergence history (time=" + QString::number(timeDouble) + ")";
6804 #endif
6805 }
6806
6807 if (tmp.contains("ComputeChange")) { // && tmp.contains("NS")) {
6808 QString copyOfTmp = tmp;
6809
6810 // check solver name:
6811 QStringList tmpSplitted = tmp.split(":");
6812 int last = tmpSplitted.count() - 1;
6813 QString name = tmpSplitted.at(last).trimmed();
6814
6815 // parse rest of the line:
6816 double res1 = 0.0;
6817 double res2 = 0.0;
6818 int n = tmp.indexOf("NRM,RELC");
6819 tmp = tmp.mid(n);
6820 tmpSplitted = tmp.split("(");
6821
6822 if (tmpSplitted.count() >= 2) {
6823 QString tmp2 = tmpSplitted.at(1).trimmed();
6824 QStringList tmp2Splitted = tmp2.split(" ");
6825 QString qs1 = tmp2Splitted.at(0).trimmed();
6826 res1 = qs1.toDouble();
6827 int pos = 1;
6828 // while(tmp2Splitted.at(pos).trimmed() == "") {
6829 while (tmp2Splitted.at(pos).trimmed().isEmpty()) {
6830 pos++;
6831 if (pos > tmp2Splitted.count())
6832 break;
6833 }
6834 QString qs2 = tmp2Splitted.at(pos).trimmed();
6835 res2 = max(qs2.toDouble(), 1.0e-16);
6836 }
6837
6838 // res1 = norm, res2 = relative change
6839 #ifdef EG_QWT
6840 if (copyOfTmp.contains("NS"))
6841 convergenceView->appendData(res2, "NS/" + name);
6842
6843 if (copyOfTmp.contains("SS"))
6844 convergenceView->appendData(res2, "SS/" + name);
6845 #endif
6846 }
6847 }
6848 }
6849
6850 // solver process emits (void) when there is something to read from stderr:
6851 //-----------------------------------------------------------------------------
solverStderrSlot()6852 void MainWindow::solverStderrSlot() {
6853 QString qs = solver->readAllStandardError();
6854
6855 while (qs.at(qs.size() - 1).unicode() == '\n')
6856 qs.chop(1);
6857
6858 solverLogWindow->getTextEdit()->append(qs);
6859 }
6860
6861 // solver process emits (int) when ready...
6862 //-----------------------------------------------------------------------------
solverFinishedSlot(int)6863 void MainWindow::solverFinishedSlot(int) {
6864 logMessage("Solver ready");
6865 runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
6866 updateSysTrayIcon(
6867 "ElmerSolver has finished",
6868 "Use Run->Start ElmerPost, ElmerVTK or Paraview to view results");
6869 killsolverAct->setEnabled(false);
6870 }
6871
6872 // solver process emits (QProcess::ProcessError) when error occurs...
6873 //-----------------------------------------------------------------------------
solverErrorSlot(QProcess::ProcessError error)6874 void MainWindow::solverErrorSlot(QProcess::ProcessError error) {
6875 logMessage("Solver emitted error signal: " + QString::number(error));
6876 solver->kill();
6877 runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
6878 }
6879
6880 // solver process emits (QProcess::ProcessState) when state changed...
6881 //-----------------------------------------------------------------------------
solverStateChangedSlot(QProcess::ProcessState state)6882 void MainWindow::solverStateChangedSlot(QProcess::ProcessState state) {
6883 logMessage("Solver emitted signal: QProcess::ProcessState: " +
6884 QString::number(state));
6885 // solver->kill();
6886 // runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
6887 }
6888
6889 // Solver -> Kill solver
6890 //-----------------------------------------------------------------------------
killsolverSlot()6891 void MainWindow::killsolverSlot() {
6892 solver->kill();
6893
6894 logMessage("Solver killed");
6895 runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
6896 }
6897
6898 // Solver -> Show convergence
6899 //-----------------------------------------------------------------------------
showConvergenceSlot()6900 void MainWindow::showConvergenceSlot() {
6901 showConvergence = !showConvergence;
6902 synchronizeMenuToState();
6903 }
6904
6905 // Solver -> Run post process
6906 //-----------------------------------------------------------------------------
resultsSlot()6907 void MainWindow::resultsSlot() {
6908 QStringList args;
6909
6910 if (post->state() == QProcess::Running) {
6911 logMessage("Post processor is already running");
6912 return;
6913 }
6914
6915 // Parallel solution:
6916 //====================
6917 Ui::parallelDialog ui = parallel->ui;
6918 bool parallelActive = ui.parallelActiveCheckBox->isChecked();
6919
6920 if (parallelActive) {
6921
6922 // unify mesh:
6923 if (meshUnifier->state() == QProcess::Running) {
6924 logMessage("Mesh unifier is already running - aborted");
6925 return;
6926 }
6927
6928 if (saveDirName.isEmpty()) {
6929 logMessage("saveDirName is empty - unable to locate result files");
6930 return;
6931 }
6932
6933 // Set up log window:
6934 solverLogWindow->setWindowTitle(tr("ElmerGrid log"));
6935 solverLogWindow->getTextEdit()->clear();
6936 solverLogWindow->setFound(false);
6937 solverLogWindow->show();
6938
6939 QString postName = generalSetup->ui.postFileEdit->text().trimmed();
6940 QStringList postNameSplitted = postName.split(".");
6941 int nofProcessors = ui.nofProcessorsSpinBox->value();
6942
6943 QString unifyingCommand = ui.mergeLineEdit->text().trimmed();
6944 unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());
6945 unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));
6946
6947 logMessage("Executing: " + unifyingCommand);
6948
6949 meshUnifier->start(unifyingCommand);
6950
6951 if (!meshUnifier->waitForStarted()) {
6952 solverLogWindow->getTextEdit()->append(
6953 "Unable to start ElmerGrid for mesh unification - aborted");
6954 logMessage("Unable to start ElmerGrid for mesh unification - aborted");
6955 return;
6956 }
6957
6958 // The rest is done in meshUnifierFinishedSlot:
6959 return;
6960 }
6961
6962 // Scalar solution:
6963 //==================
6964 QString postName = generalSetup->ui.postFileEdit->text().trimmed();
6965 QFile file(postName);
6966 if (!file.exists()) {
6967 logMessage("Elmerpost input file does not exist.");
6968 /*Even though input file does not exist, lauch ElmerPost*/
6969 post->start("ElmerPost");
6970 killresultsAct->setEnabled(true);
6971 if (!post->waitForStarted()) {
6972 logMessage("Unable to start ElmerPost");
6973 return;
6974 }
6975 resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
6976
6977 logMessage("ElmerPost started");
6978
6979 updateSysTrayIcon("ElmerPost started",
6980 "Elmerpost input file does not exist.");
6981 return;
6982 }
6983
6984 file.open(QIODevice::ReadOnly);
6985 QTextStream header(&file);
6986
6987 int nn, ne, nt, nf;
6988 QString type, name, tstep;
6989
6990 header >> nn >> ne >> nf >> nt >> type >> name;
6991 if (type == "vector:")
6992 name = name + "_abs";
6993
6994 file.close();
6995
6996 QString simtype =
6997 generalSetup->ui.simulationTypeCombo->currentText().trimmed();
6998 if (simtype.toLower() == "transient") {
6999 tstep = QString::number(1);
7000 } else {
7001 tstep = QString::number(nt);
7002 }
7003
7004 args << "readfile " + postName + " " + tstep + " " + tstep +
7005 " 1; "
7006 "set ColorScaleY -0.85; "
7007 "set ColorScaleEntries 4;"
7008 "set ColorScaleDecimals 2;"
7009 "set ColorScaleColor " +
7010 name +
7011 ";"
7012 "set DisplayStyle(ColorScale) 1; "
7013 "set MeshStyle 1; "
7014 "set MeshColor " +
7015 name +
7016 ";"
7017 "set DisplayStyle(ColorMesh) 1; "
7018 "translate -y 0.2; "
7019 "UpdateObject; ";
7020
7021 post->start("ElmerPost", args);
7022 killresultsAct->setEnabled(true);
7023
7024 if (!post->waitForStarted()) {
7025 logMessage("Unable to start ElmerPost");
7026 return;
7027 }
7028
7029 resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
7030
7031 logMessage("ElmerPost started");
7032
7033 updateSysTrayIcon("ElmerPost started",
7034 "Use Run->Kill ElmerPost to stop processing");
7035 }
7036
7037 // Signal (int) emitted by postProcess when finished:
7038 //-----------------------------------------------------------------------------
postProcessFinishedSlot(int)7039 void MainWindow::postProcessFinishedSlot(int) {
7040 logMessage("ElmerPost finished");
7041 resultsAct->setIcon(QIcon(":/icons/Post.png"));
7042 updateSysTrayIcon("ElmerPost has finished",
7043 "Use Run->Start ElmerPost to restart");
7044 killresultsAct->setEnabled(false);
7045 }
7046
7047 // Signal (int) emitted by paraview when finished:
7048 //-----------------------------------------------------------------------------
paraviewProcessFinishedSlot(int)7049 void MainWindow::paraviewProcessFinishedSlot(int) {
7050 logMessage("ParaView finished");
7051 updateSysTrayIcon("ParaView has finished",
7052 "Use Run->Start ParaView to restart");
7053 }
7054
7055 // Solver -> Kill post process
7056 //-----------------------------------------------------------------------------
killresultsSlot()7057 void MainWindow::killresultsSlot() {
7058 post->kill();
7059
7060 logMessage("Post process killed");
7061 resultsAct->setIcon(QIcon(":/icons/Post.png"));
7062 }
7063
7064 // Solver -> Compile...
7065 //-----------------------------------------------------------------------------
compileSolverSlot()7066 void MainWindow::compileSolverSlot() {
7067 QString defaultDirName = getDefaultDirName();
7068
7069 QString fileName = QFileDialog::getOpenFileName(
7070 this, tr("Open source file"), defaultDirName, tr("F90 files (*.f90)"));
7071
7072 if (!fileName.isEmpty()) {
7073 QFileInfo fi(fileName);
7074 QString absolutePath = fi.absolutePath();
7075 QDir::setCurrent(absolutePath);
7076 } else {
7077 logMessage("Unable to open file: file name is empty");
7078 return;
7079 }
7080
7081 if (compiler->state() == QProcess::Running) {
7082 logMessage("Compiler is currently running");
7083 return;
7084 }
7085
7086 QStringList args;
7087 #ifdef WIN32
7088 args << "/C";
7089 args << "" + QString(qgetenv("ELMER_HOME")) + "\\bin\\elmerf90.bat";
7090 QString dllFileName;
7091 dllFileName = fileName.left(fileName.lastIndexOf(".")) + ".dll";
7092 args << "-o";
7093 args << dllFileName;
7094 #endif
7095 args << fileName;
7096
7097 #ifdef WIN32
7098 compiler->start("cmd.exe", args);
7099 #else
7100 logMessage("Run->compiler is currently not implemented on this platform");
7101 return;
7102 #endif
7103
7104 if (!compiler->waitForStarted()) {
7105 logMessage("Unable to start compiler");
7106 return;
7107 }
7108
7109 solverLogWindow->setWindowTitle(tr("Compiler log"));
7110 solverLogWindow->getTextEdit()->clear();
7111 solverLogWindow->setFound(false);
7112 solverLogWindow->show();
7113 solverLogWindow->statusBar()->showMessage("Compiling...");
7114
7115 logMessage("Compiling...");
7116 }
7117
7118 // compiler process emits (void) when there is something to read from stdout:
7119 //-----------------------------------------------------------------------------
compilerStdoutSlot()7120 void MainWindow::compilerStdoutSlot() {
7121 QString qs = compiler->readAllStandardOutput();
7122
7123 while (qs.at(qs.size() - 1).unicode() == '\n')
7124 qs.chop(1);
7125
7126 solverLogWindow->getTextEdit()->append(qs);
7127 }
7128
7129 // compiler process emits (void) when there is something to read from stderr:
7130 //-----------------------------------------------------------------------------
compilerStderrSlot()7131 void MainWindow::compilerStderrSlot() {
7132 QString qs = compiler->readAllStandardError();
7133
7134 while (qs.at(qs.size() - 1).unicode() == '\n')
7135 qs.chop(1);
7136
7137 solverLogWindow->getTextEdit()->append(qs);
7138 }
7139
7140 // Signal (int) emitted by compiler when finished:
7141 //-----------------------------------------------------------------------------
compilerFinishedSlot(int)7142 void MainWindow::compilerFinishedSlot(int) {
7143 logMessage("Ready");
7144 solverLogWindow->statusBar()->showMessage("Ready");
7145 solverLogWindow->getTextEdit()->append("Ready");
7146 }
7147
7148 //*****************************************************************************
7149 //
7150 // Help MENU
7151 //
7152 //*****************************************************************************
7153
7154 // About dialog...
7155 //-----------------------------------------------------------------------------
showaboutSlot()7156 void MainWindow::showaboutSlot() {
7157 QMessageBox::about(
7158 this, tr("Information about ElmerGUI"),
7159 tr("ElmerGUI is a preprocessor for two and "
7160 "three dimensional modeling with Elmer "
7161 "finite element software. The program "
7162 "uses elmergrid, nglib, and optionally tetlib, "
7163 "as finite element mesh generators:\n\n"
7164 "http://www.csc.fi/elmer/\n"
7165 "https://ngsolve.org/\n"
7166 "http://tetgen.berlios.de/\n\n"
7167 "ElmerGUI uses the Qt Cross-Platform "
7168 "Application Framework by The Qt Company:\n\n"
7169 "http://www.qt.io/\n\n"
7170 #ifdef EG_VTK
7171 "This version of ElmerGUI contains a built-in "
7172 "postprocessor based on the Visualization Toolkit "
7173 "(VTK):\n\n"
7174 "http://www.vtk.org/\n\n"
7175 #endif
7176
7177 #ifdef EG_PARAVIEW
7178 "This version of ElmerGUI has been linked "
7179 "against ParaView visualization software."
7180 "\n\n"
7181 "http://www.paraview.org\n\n"
7182 #endif
7183
7184 #ifdef EG_OCC
7185 "This version of ElmerGUI has been compiled with "
7186 "the OpenCascade solids modeling library:\n\n"
7187 "http://www.opencascade.org/\n\n"
7188 #endif
7189
7190 #ifdef MPICH2
7191 "The parallel solver of this package has been linked "
7192 "against the MPICH2 library v. 1.0.7 from Argonne "
7193 "national laboratory. In order to use the parallel "
7194 "solver, the MPICH2 runtime environment should be "
7195 "installed and configured on your system. For more "
7196 "details, see:\n\n"
7197 "http://www.mcs.anl.gov/research/projects/mpich2/\n\n"
7198 #endif
7199 "The GPL-licensed source code of ElmerGUI is available "
7200 "from the git repository\n\n"
7201 "https://github.com/ElmerCSC/elmerfem/\n\n"
7202 "Written by Mikko Lyly, Juha Ruokolainen, Saeki Takayuki,\n"
7203 "Peter Raback and Sampo Sillanpaa 2008-2020"));
7204 }
7205
7206 //*****************************************************************************
7207 //
7208 // Auxiliary non-menu items
7209 //
7210 //*****************************************************************************
7211
7212 // Log message...
7213 //-----------------------------------------------------------------------------
logMessage(QString message)7214 void MainWindow::logMessage(QString message) {
7215 #if WITH_QT5
7216 cout << string(message.toLatin1()) << endl;
7217 #else
7218 cout << string(message.toAscii()) << endl;
7219 #endif
7220 statusBar()->showMessage(message, 0);
7221 cout.flush();
7222 }
7223
7224 // Synchronize menu to GL glwidget state variables:
7225 //-----------------------------------------------------------------------------
synchronizeMenuToState()7226 void MainWindow::synchronizeMenuToState() {
7227 // glwidget state variables:
7228 if (glWidget->stateDrawSurfaceMesh)
7229 hidesurfacemeshAct->setChecked(true);
7230 else
7231 hidesurfacemeshAct->setChecked(false);
7232
7233 if (glWidget->stateDrawVolumeMesh)
7234 hidevolumemeshAct->setChecked(true);
7235 else
7236 hidevolumemeshAct->setChecked(false);
7237
7238 if (glWidget->stateDrawSharpEdges)
7239 hidesharpedgesAct->setChecked(true);
7240 else
7241 hidesharpedgesAct->setChecked(false);
7242
7243 if (glWidget->stateFlatShade) {
7244 flatShadeAct->setChecked(true);
7245 smoothShadeAct->setChecked(false);
7246 } else {
7247 flatShadeAct->setChecked(false);
7248 smoothShadeAct->setChecked(true);
7249 }
7250
7251 if (glWidget->stateOrtho) {
7252 orthoAct->setChecked(true);
7253 perspectiveAct->setChecked(false);
7254 } else {
7255 orthoAct->setChecked(false);
7256 perspectiveAct->setChecked(true);
7257 }
7258
7259 if (glWidget->stateDrawSurfaceNumbers)
7260 showSurfaceNumbersAct->setChecked(true);
7261 else
7262 showSurfaceNumbersAct->setChecked(false);
7263
7264 if (glWidget->stateDrawEdgeNumbers)
7265 showEdgeNumbersAct->setChecked(true);
7266 else
7267 showEdgeNumbersAct->setChecked(false);
7268
7269 if (glWidget->stateDrawNodeNumbers)
7270 showNodeNumbersAct->setChecked(true);
7271 else
7272 showNodeNumbersAct->setChecked(false);
7273
7274 if (glWidget->stateDrawBoundaryIndex)
7275 showBoundaryIndexAct->setChecked(true);
7276 else
7277 showBoundaryIndexAct->setChecked(false);
7278
7279 if (glWidget->stateDrawBodyIndex)
7280 showBodyIndexAct->setChecked(true);
7281 else
7282 showBodyIndexAct->setChecked(false);
7283
7284 if (glWidget->stateDrawCoordinates)
7285 viewCoordinatesAct->setChecked(true);
7286 else
7287 viewCoordinatesAct->setChecked(false);
7288
7289 if (bodyEditActive)
7290 bodyEditAct->setChecked(true);
7291 else
7292 bodyEditAct->setChecked(false);
7293
7294 if (bcEditActive)
7295 bcEditAct->setChecked(true);
7296 else
7297 bcEditAct->setChecked(false);
7298
7299 if (showConvergence)
7300 showConvergenceAct->setChecked(true);
7301 else
7302 showConvergenceAct->setChecked(false);
7303
7304 if (glWidget->stateBcColors)
7305 showBoundaryColorAct->setChecked(true);
7306 else
7307 showBoundaryColorAct->setChecked(false);
7308
7309 if (glWidget->stateBodyColors)
7310 showBodyColorAct->setChecked(true);
7311 else
7312 showBodyColorAct->setChecked(false);
7313
7314 if (isFullScreen())
7315 viewFullScreenAct->setChecked(true);
7316 else
7317 viewFullScreenAct->setChecked(false);
7318 }
7319
7320 // Load definitions...
7321 //-----------------------------------------------------------------------------
loadDefinitions()7322 void MainWindow::loadDefinitions() {
7323 // Determine edf-file location and name:
7324 //--------------------------------------
7325 QString elmerGuiHome;
7326
7327 #ifdef __APPLE__DONTGO_HERE_TODO
7328 QString generalDefs = this->homePath + "/edf/edf.xml";
7329 #else
7330 QString generalDefs =
7331 QCoreApplication::applicationDirPath() +
7332 "/../share/ElmerGUI/edf/edf.xml"; // @TODO: fix path to share/ElmerGUI/edf
7333
7334 elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
7335
7336 if (!elmerGuiHome.isEmpty())
7337 generalDefs = elmerGuiHome + "/edf/edf.xml";
7338
7339 // ML 5. August 2010
7340 generalDefs.replace('\\', '/');
7341 #endif
7342
7343 // Load general definitions file:
7344 //--------------------------------
7345 #if WITH_QT5
7346 cout << "Load " << string(generalDefs.toLatin1()) << "... ";
7347 #else
7348 cout << "Load " << string(generalDefs.toAscii()) << "... ";
7349 #endif
7350 cout.flush();
7351 updateSplash("Loading general definitions...");
7352
7353 QFile file(generalDefs);
7354
7355 QString errStr;
7356 int errRow;
7357 int errCol;
7358
7359 if (!file.exists()) {
7360
7361 elmerDefs = NULL;
7362 QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7363 tr("Definitions file does not exist"));
7364 return;
7365
7366 } else {
7367
7368 if (!elmerDefs->setContent(&file, true, &errStr, &errRow, &errCol)) {
7369 QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7370 tr("Parse error at line %1, col %2:\n%3")
7371 .arg(errRow)
7372 .arg(errCol)
7373 .arg(errStr));
7374 file.close();
7375 return;
7376
7377 } else {
7378
7379 if (elmerDefs->documentElement().tagName() != "edf") {
7380 QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7381 tr("This is not an edf file"));
7382 delete elmerDefs;
7383 file.close();
7384 return;
7385 }
7386 }
7387 }
7388
7389 edfEditor->setupEditor(elmerDefs);
7390 file.close();
7391
7392 cout << "done" << endl;
7393 cout.flush();
7394
7395 // load additional definitions:
7396 //-----------------------------
7397 #ifdef __APPLE__DONTGO_HERE_TODO
7398 QDirIterator iterator(homePath + "/edf", QDirIterator::Subdirectories);
7399 #else
7400 QString additionalEdfs =
7401 QCoreApplication::applicationDirPath() +
7402 "/../share/ElmerGUI/edf"; // @TODO: fix path to share/ElmerGUI/edf
7403
7404 if (!elmerGuiHome.isEmpty())
7405 additionalEdfs = elmerGuiHome + "/edf";
7406
7407 QDirIterator iterator(additionalEdfs, QDirIterator::Subdirectories);
7408 #endif
7409
7410 while (iterator.hasNext()) {
7411 QString fileName = iterator.next();
7412
7413 // ML 5. August 2010
7414 fileName.replace('\\', '/');
7415
7416 QFileInfo fileInfo(fileName);
7417 QString fileSuffix = fileInfo.suffix();
7418
7419 // The names "egini" and "egmaterials" are reserved, skip them:
7420 if (fileInfo.completeBaseName() == "egini")
7421 continue;
7422
7423 if (fileInfo.completeBaseName() == "egmaterials")
7424 continue;
7425
7426 if ((fileSuffix == "xml") && (fileName != generalDefs)) {
7427
7428 #if WITH_QT5
7429 cout << "Load " << string(fileName.toLatin1()) << "... ";
7430 #else
7431 cout << "Load " << string(fileName.toAscii()) << "... ";
7432 #endif
7433 cout.flush();
7434
7435 updateSplash("Loading " + fileName + "...");
7436
7437 file.setFileName(fileName);
7438
7439 QDomDocument tmpDoc;
7440 tmpDoc.clear();
7441
7442 if (!tmpDoc.setContent(&file, true, &errStr, &errRow, &errCol)) {
7443 QMessageBox::information(window(), tr("Edf loader: ") + fileName,
7444 tr("Parse error at line %1, col %2:\n%3")
7445 .arg(errRow)
7446 .arg(errCol)
7447 .arg(errStr));
7448 file.close();
7449 return;
7450
7451 } else {
7452
7453 if (tmpDoc.documentElement().tagName() != "edf") {
7454 QMessageBox::information(window(), tr("Edf loader: ") + fileName,
7455 tr("This is not an edf file"));
7456 file.close();
7457 return;
7458 }
7459 }
7460
7461 // add new elements to the document
7462 QDomElement root = elmerDefs->documentElement();
7463 QDomElement tmpRoot = tmpDoc.documentElement();
7464 QDomElement element = tmpRoot.firstChildElement();
7465
7466 while (!element.isNull()) {
7467 root.appendChild(element);
7468 element = tmpRoot.firstChildElement();
7469 }
7470
7471 edfEditor->setupEditor(elmerDefs);
7472
7473 file.close();
7474
7475 cout << "done" << endl;
7476 cout.flush();
7477 }
7478 }
7479
7480 // Load qss:
7481 //-----------
7482 QString qssFileName = QCoreApplication::applicationDirPath() +
7483 "/elmergui.qss"; // @TODO: fix path to share/ElmerGUI
7484
7485 #ifdef __APPLE__
7486 qssFileName = homePath + "/elmergui.qss";
7487 #else
7488 if (!elmerGuiHome.isEmpty())
7489 qssFileName = elmerGuiHome + "/elmergui.qss";
7490 #endif
7491
7492 QFile qssFile(qssFileName);
7493
7494 if (qssFile.exists()) {
7495 cout << "Loading QSS style sheet... ";
7496 qssFile.open(QFile::ReadOnly);
7497 QString styleSheet = QLatin1String(qssFile.readAll());
7498 qssFile.close();
7499 qApp->setStyleSheet(styleSheet);
7500 cout << "done" << endl;
7501 }
7502 }
7503
7504 // Setup splash...
7505 //-----------------------------------------------------------------------------
setupSplash()7506 void MainWindow::setupSplash() {
7507 QStringList args = QCoreApplication::arguments();
7508
7509 if (args.contains("-nogui"))
7510 return;
7511
7512 if (egIni->isSet("splashscreen")) {
7513 pixmap.load(":/images/splash.png");
7514 splash.setPixmap(pixmap);
7515 splash.show();
7516 qApp->processEvents();
7517 }
7518 }
7519
7520 // Update splash...
7521 //-----------------------------------------------------------------------------
updateSplash(QString text)7522 void MainWindow::updateSplash(QString text) {
7523 QStringList args = QCoreApplication::arguments();
7524
7525 if (args.contains("-nogui"))
7526 return;
7527
7528 if (!egIni->isSet("splashscreen"))
7529 return;
7530
7531 if (splash.isVisible()) {
7532 splash.showMessage(text, Qt::AlignBottom);
7533 qApp->processEvents();
7534 }
7535 }
7536
7537 // Finalize splash...
7538 //-----------------------------------------------------------------------------
finalizeSplash()7539 void MainWindow::finalizeSplash() {
7540 if (!egIni->isSet("splashscreen"))
7541 return;
7542
7543 if (splash.isVisible())
7544 splash.finish(this);
7545 }
7546
7547 // Setup system tray icon...
7548 //-----------------------------------------------------------------------------
setupSysTrayIcon()7549 void MainWindow::setupSysTrayIcon() {
7550 sysTrayIcon = NULL;
7551
7552 QStringList args = QCoreApplication::arguments();
7553
7554 if (args.contains("-nogui"))
7555 return;
7556
7557 if (!egIni->isSet("systrayicon"))
7558 return;
7559
7560 if (QSystemTrayIcon::isSystemTrayAvailable()) {
7561 sysTrayIcon = new QSystemTrayIcon(this);
7562 sysTrayIcon->setIcon(QIcon(":/icons/Mesh3D.png"));
7563 sysTrayIcon->setVisible(true);
7564 sysTrayIcon->setContextMenu(sysTrayMenu);
7565 }
7566 }
7567
7568 // Update system tray icon...
7569 //-----------------------------------------------------------------------------
updateSysTrayIcon(QString label,QString msg)7570 void MainWindow::updateSysTrayIcon(QString label, QString msg) {
7571 int duration = 3000;
7572
7573 QStringList args = QCoreApplication::arguments();
7574
7575 if (args.contains("-nogui"))
7576 return;
7577
7578 if (!sysTrayIcon)
7579 return;
7580
7581 if (!egIni->isSet("systraymessages"))
7582 return;
7583
7584 if (isFullScreen())
7585 return;
7586
7587 if (egIni->isPresent("systraymsgduration"))
7588 duration = egIni->value("systraymsgduration").toInt();
7589
7590 if (sysTrayIcon->supportsMessages())
7591 sysTrayIcon->showMessage(label, msg, QSystemTrayIcon::Information,
7592 duration);
7593 }
7594
7595 // Finalize system tray icon...
7596 //-----------------------------------------------------------------------------
finalizeSysTrayIcon()7597 void MainWindow::finalizeSysTrayIcon() {}
7598
7599 // Get default open/save directory
7600 //-----------------------------------------------------------------------------
getDefaultDirName()7601 QString MainWindow::getDefaultDirName() {
7602 QString defaultDirName = "";
7603
7604 #ifdef WIN32
7605 defaultDirName = egIni->value("win32defaultdir");
7606 #else
7607 #ifdef __APPLE__
7608 defaultDirName = egIni->value("macxdefaultdir");
7609 #else
7610 defaultDirName = egIni->value("unixdefaultdir");
7611 #endif
7612 #endif
7613
7614 if (!saveDirName.isEmpty())
7615 defaultDirName = saveDirName;
7616
7617 return defaultDirName;
7618 }
7619
7620 // Load settings
7621 //-----------------------------------------------------------------------------
loadSettings()7622 void MainWindow::loadSettings() {
7623 restoreGeometry(settings_value("mainWindow/geometry").toByteArray());
7624 sifWindow->restoreGeometry(
7625 settings_value("sifWindow/geometry").toByteArray());
7626 solverLogWindow->restoreGeometry(
7627 settings_value("solverLogWindow/geometry").toByteArray());
7628
7629 #ifdef EG_QWT
7630 convergenceView->restoreGeometry(
7631 settings_value("convergenceView/geometry").toByteArray());
7632 #endif
7633
7634 #ifdef EG_OCC
7635 cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());
7636 #endif
7637
7638 #ifdef EG_VTK
7639 vtkPost->restoreGeometry(settings_value("vtkPost/geometry").toByteArray());
7640 #endif
7641
7642 int n = settings_value("recentProject/n", 0).toInt();
7643 QString key = "recentProject/";
7644 char num[] = "01234";
7645 QString path;
7646 for (int i = n - 1; i >= 0; i--) {
7647 path = settings_value(key + num[i], "$").toString();
7648 if (path != "$")
7649 addRecentProject(path, false);
7650 }
7651
7652 if (settings_value("objectBrowser/show", true).toBool()) {
7653 objectBrowser = new ObjectBrowser(this);
7654 showObjectBrowserAct->setChecked(true);
7655 } else {
7656 objectBrowser = NULL;
7657 }
7658
7659 switch (settings_value("postProcessor/i", 0).toInt()){
7660 case 0: selectElmerPostSlot(); break;
7661 case 1: selectVtkPostSlot(); break;
7662 case 2: selectParaViewSlot(); break;
7663 }
7664 }
7665
7666 // Save settings
7667 //-----------------------------------------------------------------------------
saveSettings()7668 void MainWindow::saveSettings() {
7669 settings_setValue("mainWindow/geometry", saveGeometry());
7670 settings_setValue("sifWindow/geometry", sifWindow->saveGeometry());
7671 settings_setValue("solverLogWindow/geometry",
7672 solverLogWindow->saveGeometry());
7673
7674 #ifdef EG_QWT
7675 settings_setValue("convergenceView/geometry",
7676 convergenceView->saveGeometry());
7677 #endif
7678
7679 #ifdef EG_OCC
7680 settings_setValue("cadView/geometry", cadView->saveGeometry());
7681 #endif
7682
7683 #ifdef EG_VTK
7684 settings_setValue("vtkPost/geometry", vtkPost->saveGeometry());
7685 #endif
7686
7687 if (showObjectBrowserAct->isChecked() && objectBrowser != NULL) {
7688 settings_setValue("objectBrowser/show", true);
7689 } else {
7690 settings_setValue("objectBrowser/show", false);
7691 }
7692
7693 if(selectElmerPostAct->isChecked()){
7694 settings_setValue("postProcessor/i", 0);
7695 }else if(selectVtkPostAct->isChecked()){
7696 settings_setValue("postProcessor/i", 1);
7697 }else if(selectParaViewAct->isChecked()){
7698 settings_setValue("postProcessor/i", 2);
7699 }
7700 }
7701
addRecentProject(QString dir,bool bSaveToIni)7702 void MainWindow::addRecentProject(QString dir, bool bSaveToIni) {
7703 if (recentProject.indexOf(dir) != -1) {
7704 recentProject.removeAt(recentProject.indexOf(dir));
7705 }
7706 recentProject.prepend(dir);
7707
7708 int i = 0;
7709
7710 recentProjectsMenu->removeAction(recentProject0Act);
7711 recentProjectsMenu->removeAction(recentProject1Act);
7712 recentProjectsMenu->removeAction(recentProject2Act);
7713 recentProjectsMenu->removeAction(recentProject3Act);
7714 recentProjectsMenu->removeAction(recentProject4Act);
7715 recentProjectsMenu->clear(); // just in case
7716
7717 if (i < 5 && i < recentProject.size()) {
7718 recentProject0Act->setText(recentProject.at(i));
7719 recentProjectsMenu->addAction(recentProject0Act);
7720 }
7721 i++;
7722 if (i < 5 && i < recentProject.size()) {
7723 recentProject1Act->setText(recentProject.at(i));
7724 recentProjectsMenu->addAction(recentProject1Act);
7725 }
7726 i++;
7727 if (i < 5 && i < recentProject.size()) {
7728 recentProject2Act->setText(recentProject.at(i));
7729 recentProjectsMenu->addAction(recentProject2Act);
7730 }
7731 i++;
7732 if (i < 5 && i < recentProject.size()) {
7733 recentProject3Act->setText(recentProject.at(i));
7734 recentProjectsMenu->addAction(recentProject3Act);
7735 }
7736 i++;
7737 if (i < 5 && i < recentProject.size()) {
7738 recentProject4Act->setText(recentProject.at(i));
7739 recentProjectsMenu->addAction(recentProject4Act);
7740 }
7741 recentProjectsMenu->setEnabled(recentProject.size() > 0);
7742
7743 if (bSaveToIni) {
7744 int n = recentProject.size();
7745 if (n > 5)
7746 n = 5;
7747 settings_setValue("recentProject/n", n);
7748 QString key = "recentProject/";
7749 char num[] = "01234";
7750 for (int i = 0; i < n; i++) {
7751 settings_setValue(key + num[i], recentProject.at(i));
7752 }
7753 }
7754 }
7755
loadRecentProject0Slot()7756 void MainWindow::loadRecentProject0Slot() { loadProject(recentProject.at(0)); }
7757
loadRecentProject1Slot()7758 void MainWindow::loadRecentProject1Slot() { loadProject(recentProject.at(1)); }
7759
loadRecentProject2Slot()7760 void MainWindow::loadRecentProject2Slot() { loadProject(recentProject.at(2)); }
7761
loadRecentProject3Slot()7762 void MainWindow::loadRecentProject3Slot() { loadProject(recentProject.at(3)); }
7763
loadRecentProject4Slot()7764 void MainWindow::loadRecentProject4Slot() { loadProject(recentProject.at(4)); }
7765
loadExtraSolver(QString solverName)7766 bool MainWindow::loadExtraSolver(QString solverName) {
7767
7768 #ifdef __APPLE__DONTGO_HERE_TODO
7769 QString extraDirpath = this->homePath + "/edf-extra";
7770 #else
7771 QString extraDirPath =
7772 QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";
7773
7774 QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
7775
7776 if (!elmerGuiHome.isEmpty())
7777 extraDirPath = elmerGuiHome + "/edf-extra";
7778
7779 extraDirPath.replace('\\', '/');
7780 #endif
7781
7782 QString name;
7783 QDir extraDir(extraDirPath);
7784 QStringList nameFilters;
7785 nameFilters << "*.xml";
7786 QString message;
7787 QStringList fileNameList =
7788 extraDir.entryList(nameFilters, QDir::Files | QDir::Readable);
7789 for (int i = 0; i < fileNameList.size(); i++) {
7790 QFile file(extraDirPath + "/" + fileNameList.at(i));
7791 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
7792 QTextStream in(&file);
7793 while (!in.atEnd()) {
7794 QString line = in.readLine();
7795 if (line.indexOf("<PDE Name=") > 0) {
7796 line = in.readLine();
7797 while (line.indexOf("<Name>") == -1 && !in.atEnd())
7798 line = in.readLine();
7799 int i0 = line.indexOf("<Name>");
7800 if (i0 >= 0) {
7801 int i1 = line.indexOf("</Name>", i0 + 6);
7802 if (i1 > 0) {
7803 name = line.mid(i0 + 6, i1 - i0 - 6).trimmed();
7804 if (solverName.trimmed() == name) {
7805 file.close();
7806
7807 message =
7808 "Load " + extraDirPath + "/" + fileNameList.at(i) + "... ";
7809 #if WITH_QT5
7810 cout << string(message.toLatin1());
7811 cout.flush();
7812 #else
7813 cout << string(message.toAscii());
7814 cout.flush();
7815 #endif
7816
7817 edfEditor->appendFrom(extraDirPath + "/" + fileNameList.at(i));
7818
7819 cout << "done" << endl;
7820
7821 return true;
7822 }
7823 }
7824 }
7825 }
7826 }
7827
7828 file.close();
7829 } else {
7830 logMessage(" failed to open " + fileNameList.at(i));
7831 return false;
7832 }
7833 }
7834 logMessage(" Extra solver " + solverName + " not found");
7835 return false;
7836 }
7837
checkAndLoadExtraSolvers(QFile * file)7838 void MainWindow::checkAndLoadExtraSolvers(QFile *file) {
7839 QStringList loadedSolverName;
7840 QStringList unloadedSolverName;
7841 QDomElement root = elmerDefs->documentElement();
7842 QDomElement elem = root.firstChildElement("PDE");
7843 while (!elem.isNull()) {
7844 QDomElement pdeName = elem.firstChildElement("Name");
7845 loadedSolverName.append(pdeName.text().trimmed());
7846 elem = elem.nextSiblingElement();
7847 }
7848
7849 QString name;
7850 if (file->open(QIODevice::ReadOnly | QIODevice::Text)) {
7851 QTextStream in(file);
7852 while (!in.atEnd()) {
7853 QString line = in.readLine();
7854 int i0, i1;
7855 i0 = line.indexOf("<key>/");
7856 if (i0 >= 0) {
7857 i1 = line.indexOf("/", i0 + 7);
7858 if (i1 > 0) {
7859 name = line.mid(i0 + 6, i1 - i0 - 6);
7860 if (!loadedSolverName.contains(name)) {
7861 loadExtraSolver(name);
7862
7863 // update list (to avoid doubled loading - one solver file can
7864 // generate multiple tabs)
7865 loadedSolverName.clear();
7866 QDomElement root = elmerDefs->documentElement();
7867 QDomElement elem = root.firstChildElement("PDE");
7868 while (!elem.isNull()) {
7869 QDomElement pdeName = elem.firstChildElement("Name");
7870 loadedSolverName.append(pdeName.text().trimmed());
7871 elem = elem.nextSiblingElement();
7872 }
7873 }
7874 }
7875 }
7876 }
7877 } else {
7878 logMessage(" failed to open project file" + name);
7879 }
7880
7881 /*
7882 QString name;
7883 if (file->open(QIODevice::ReadOnly | QIODevice::Text)){
7884 QTextStream in(file);
7885 while (!in.atEnd()) {
7886 QString line = in.readLine();
7887 int i0, i1;
7888 i0=line.indexOf("<key>/");
7889 if( i0 >= 0){
7890 i1 = line.indexOf("/", i0+7);
7891 if(i1 > 0){
7892 name = line.mid(i0+6, i1-i0-6);
7893 if(!loadedSolverName.contains(name) &&
7894 !unloadedSolverName.contains(name) ){ unloadedSolverName.append(name);
7895 loadExtraSolver(name);
7896 }
7897 }
7898 }
7899 }
7900 }else{
7901 logMessage(" failed to open project file" + name);
7902 }
7903 */
7904 }
7905
settings_value(const QString & key,const QVariant & defaultValue) const7906 QVariant MainWindow::settings_value(const QString &key,
7907 const QVariant &defaultValue) const {
7908 QString oldElmerGuiIniFilePath =
7909 QCoreApplication::applicationDirPath() + "/ElmerGUI.ini";
7910 QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";
7911 if (!QFile::exists(elmerGuiIniFilePath) &&
7912 QFile::exists(oldElmerGuiIniFilePath)) {
7913 elmerGuiIniFilePath = oldElmerGuiIniFilePath;
7914 }
7915 QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);
7916 return settings.value(key, defaultValue);
7917 }
7918
settings_setValue(const QString & key,const QVariant & value)7919 void MainWindow::settings_setValue(const QString &key, const QVariant &value) {
7920 QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";
7921 QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);
7922 settings.setValue(key, value);
7923 }
7924
saveAndRun(bool generateSif)7925 void MainWindow::saveAndRun(bool generateSif) {
7926
7927 //------- Save project -------//
7928 if (!glWidget->hasMesh()) {
7929 logMessage("Unable to save project: no mesh");
7930 return;
7931 }
7932
7933 QString projectDirName = currentProjectDirName;
7934 if (projectDirName.isEmpty()) {
7935 QString defaultDirName = getDefaultDirName();
7936 projectDirName = QFileDialog::getExistingDirectory(
7937 this, tr("Open directory to save project"), defaultDirName);
7938
7939 if (!projectDirName.isEmpty()) {
7940 logMessage("Project directory " + projectDirName);
7941 } else {
7942 logMessage("Unable to save project: directory undefined");
7943 return;
7944 }
7945 }
7946
7947 if(generateSif){ generateSifSlot();}
7948
7949 bool ret = saveProject(projectDirName);
7950
7951 //------- Run solver -------//
7952 if (ret) {
7953 runsolverSlot();
7954 }
7955 }
7956
generateAndSaveAndRunSlot()7957 void MainWindow::generateAndSaveAndRunSlot() { saveAndRun(true); }
7958
closeEvent(QCloseEvent * event)7959 void MainWindow::closeEvent(QCloseEvent *event) {
7960 saveSettings();
7961 delete objectBrowser;
7962 }
7963
showObjectBrowserSlot()7964 void MainWindow::showObjectBrowserSlot() {
7965 if (showObjectBrowserAct->isChecked()) {
7966 delete objectBrowser; // just in case
7967 objectBrowser = new ObjectBrowser(this);
7968 } else {
7969 delete objectBrowser;
7970 objectBrowser = NULL;
7971 }
7972 }
7973
selectElmerPostSlot()7974 void MainWindow::selectElmerPostSlot(){
7975 runPostProcessorAct->setText(tr("Start ElmerPost"));
7976 runPostProcessorAct->setIcon(QIcon(":/icons/Post.png"));
7977 runPostProcessorAct->setStatusTip(tr("Run ElmerPost for visualization"));
7978 runPostProcessorAct->disconnect();
7979 connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
7980 selectElmerPostAct->setChecked(true);
7981 selectVtkPostAct->setChecked(false);
7982 selectParaViewAct->setChecked(false);
7983 }
selectVtkPostSlot()7984 void MainWindow::selectVtkPostSlot(){
7985 runPostProcessorAct->setText(tr("Start ElmerVTK"));
7986 runPostProcessorAct->setIcon(QIcon(":/icons/Mesh3D.png"));
7987 runPostProcessorAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));
7988 runPostProcessorAct->disconnect();
7989 connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));
7990 selectElmerPostAct->setChecked(false);
7991 selectVtkPostAct->setChecked(true);
7992 selectParaViewAct->setChecked(false);
7993 }
selectParaViewSlot()7994 void MainWindow::selectParaViewSlot(){
7995 runPostProcessorAct->setText(tr("Start ParaView"));
7996 runPostProcessorAct->setIcon(QIcon(":/icons/Paraview.png"));
7997 runPostProcessorAct->setStatusTip(tr("Invokes ParaView for visualization"));
7998 runPostProcessorAct->disconnect();
7999 connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));
8000 selectElmerPostAct->setChecked(false);
8001 selectVtkPostAct->setChecked(false);
8002 selectParaViewAct->setChecked(true);
8003 }
8004