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 edfeditor                                                       *
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 <QtGui>
42 #include <iostream>
43 #include "edfeditor.h"
44 
45 using namespace std;
46 
47 // ctor...
48 //----------------------------------------------------------------------------
EdfEditor(QWidget * parent)49 EdfEditor::EdfEditor(QWidget *parent)
50   : QWidget(parent)
51 {
52   addIcon = QIcon(":/icons/list-add.png");
53   removeIcon = QIcon(":/icons/list-remove.png");
54   collapseIcon = QIcon(":/icons/arrow-up.png");
55   expandIcon = QIcon(":/icons/arrow-down.png");
56   openIcon = QIcon(":/icons/document-open.png");
57   appendIcon = QIcon(":/icons/tab-new-background.png"); // todo
58   saveAsIcon = QIcon(":/icons/document-save.png");
59   applyIcon = QIcon(":/icons/dialog-close.png");
60   previewIcon = QIcon(":/icons/document-preview.png");
61 
62   lastActiveItem = NULL;
63   ctrlPressed = false;
64 
65   // Set up tree widget:
66   //--------------------
67   edfTree = new QTreeWidget;
68 
69   connect(edfTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
70 	  this, SLOT(treeItemClicked(QTreeWidgetItem*,int)));
71 
72   edfTree->setColumnCount(3);
73   edfTree->setColumnWidth(0,200);
74   edfTree->setColumnWidth(1,200);
75   edfTree->setColumnWidth(2,200);
76 
77   edfTree->setAnimated(true);
78 
79   // Set internal drag'n drop mode on:
80   //----------------------------------
81   edfTree->setDragEnabled(true);
82   edfTree->setDragDropMode(QAbstractItemView::InternalMove);
83   edfTree->setDropIndicatorShown(true);
84   edfTree->setDragDropOverwriteMode(false);
85 
86   QStringList qsl;
87   qsl << "Tag" << "Attributes" << "Value";
88   edfTree->setHeaderLabels(qsl);
89   edfTree->setAlternatingRowColors(true);
90 
91   // Buttons:
92   //---------
93   addButton = new QPushButton(tr("&Add child"));
94   addButton->setIcon(addIcon);
95   connect(addButton, SIGNAL(clicked()), this, SLOT(addButtonClicked()));
96 
97   removeButton = new QPushButton(tr("&Remove item"));
98   removeButton->setIcon(removeIcon);
99   connect(removeButton, SIGNAL(clicked()), this, SLOT(removeButtonClicked()));
100 
101   expandCollapseAllButton = new QPushButton(tr("Collapse all"));
102   expandCollapseAllButton->setIcon(collapseIcon);
103   connect(expandCollapseAllButton, SIGNAL(clicked()),
104 	  this, SLOT(expandCollapseAllButtonClicked()));
105 
106   openButton = new QPushButton(tr("&Open"));
107   openButton->setIcon(openIcon);
108   connect(openButton, SIGNAL(clicked()), this, SLOT(openButtonClicked()));
109 
110   appendButton = new QPushButton(tr("&Append"));
111   appendButton->setIcon(appendIcon);
112   connect(appendButton, SIGNAL(clicked()), this, SLOT(appendButtonClicked()));
113 
114   previewButton = new QPushButton(tr("&Preview"));
115   previewButton->setIcon(previewIcon);
116   connect(previewButton, SIGNAL(clicked()), this, SLOT(previewButtonClicked()));
117 
118   saveAsButton = new QPushButton(tr("&Save as"));
119   saveAsButton->setIcon(saveAsIcon);
120   connect(saveAsButton, SIGNAL(clicked()), this, SLOT(saveAsButtonClicked()));
121 
122   applyButton = new QPushButton(tr("&Close"));
123   applyButton->setIcon(applyIcon);
124   connect(applyButton, SIGNAL(clicked()), this, SLOT(applyButtonClicked()));
125 
126   QHBoxLayout *buttonLayout = new QHBoxLayout;
127   buttonLayout->addWidget(addButton);
128   buttonLayout->addWidget(removeButton);
129   buttonLayout->addWidget(expandCollapseAllButton);
130   buttonLayout->addWidget(openButton);
131   buttonLayout->addWidget(appendButton);
132   buttonLayout->addWidget(previewButton);
133   buttonLayout->addWidget(saveAsButton);
134   buttonLayout->addWidget(applyButton);
135 
136   // Main layout:
137   //-------------
138   QVBoxLayout *mainLayout = new QVBoxLayout;
139   mainLayout->addWidget(edfTree);
140   mainLayout->addLayout(buttonLayout);
141   setLayout(mainLayout);
142 
143   setWindowTitle("Elmer Definitions File editor");
144 
145   setFocusPolicy(Qt::ClickFocus);
146 
147   expandCollapseAll = false;
148 
149   dynamicEditorSimulation = new DynamicEditor;
150   dynamicEditorConstants = new DynamicEditor;
151   dynamicEditorEquation = new DynamicEditor;
152   dynamicEditorSolver = new DynamicEditor;
153   dynamicEditorMaterial = new DynamicEditor;
154   dynamicEditorBodyForce = new DynamicEditor;
155   dynamicEditorBC = new DynamicEditor;
156   dynamicEditorIC = new DynamicEditor;
157 
158   setWindowIcon(QIcon(":/icons/Mesh3D.png"));
159 }
160 
161 // dtor...
162 //----------------------------------------------------------------------------
~EdfEditor()163 EdfEditor::~EdfEditor()
164 {
165 }
166 
167 // Min window size...
168 //----------------------------------------------------------------------------
minimumSizeHint() const169 QSize EdfEditor::minimumSizeHint() const
170 {
171   return QSize(64, 64);
172 }
173 
174 // Default window size...
175 //----------------------------------------------------------------------------
sizeHint() const176 QSize EdfEditor::sizeHint() const
177 {
178   return QSize(720, 480);
179 }
180 
181 // preview panels
182 //-----------------------------------------------------------------------------
previewButtonClicked()183 void EdfEditor::previewButtonClicked()
184 {
185   if(elmerDefs == NULL)
186     return;
187 
188   // always create a new instance:
189   QMainWindow *sandBox = new QMainWindow;
190   QMdiArea *mdiArea = new QMdiArea;
191 
192   sandBox->setCentralWidget(mdiArea);
193   sandBox->setWindowTitle(tr("Preview definitions"));
194   sandBox->show();
195 
196   if(dynamicEditorSimulation) delete dynamicEditorSimulation;
197   dynamicEditorSimulation = new DynamicEditor;
198   dynamicEditorSimulation->setupTabs(elmerDefs, "Simulation",1);
199   QMdiSubWindow *simulationSubWindow = new QMdiSubWindow;
200   simulationSubWindow->setWidget(dynamicEditorSimulation);
201   mdiArea->addSubWindow(simulationSubWindow);
202   simulationSubWindow->show();
203 
204   if(dynamicEditorConstants) delete dynamicEditorConstants;
205   dynamicEditorConstants = new DynamicEditor;
206   dynamicEditorConstants->setupTabs(elmerDefs, "Constants",1);
207   QMdiSubWindow *constantsSubWindow = new QMdiSubWindow;
208   constantsSubWindow->setWidget(dynamicEditorConstants);
209   mdiArea->addSubWindow(constantsSubWindow);
210   constantsSubWindow->show();
211 
212   if(dynamicEditorEquation) delete dynamicEditorEquation;
213   dynamicEditorEquation = new DynamicEditor;
214   dynamicEditorEquation->setupTabs(elmerDefs, "Equation",1);
215   QMdiSubWindow *equationSubWindow = new QMdiSubWindow;
216   equationSubWindow->setWidget(dynamicEditorEquation);
217   mdiArea->addSubWindow(equationSubWindow);
218   equationSubWindow->show();
219 
220   if(dynamicEditorSolver) delete dynamicEditorSolver;
221   dynamicEditorSolver = new DynamicEditor;
222   dynamicEditorSolver->setupTabs(elmerDefs, "Solver",1 );
223   QMdiSubWindow *solverSubWindow = new QMdiSubWindow;
224   solverSubWindow->setWidget(dynamicEditorSolver);
225   mdiArea->addSubWindow(solverSubWindow);
226   solverSubWindow->show();
227 
228   if(dynamicEditorMaterial) delete dynamicEditorMaterial;
229   dynamicEditorMaterial = new DynamicEditor;
230   dynamicEditorMaterial->setupTabs(elmerDefs, "Material",1 );
231   QMdiSubWindow *materialSubWindow = new QMdiSubWindow;
232   materialSubWindow->setWidget(dynamicEditorMaterial);
233   mdiArea->addSubWindow(materialSubWindow);
234   materialSubWindow->show();
235 
236   if(dynamicEditorBodyForce) delete dynamicEditorBodyForce;
237   dynamicEditorBodyForce = new DynamicEditor;
238   dynamicEditorBodyForce->setupTabs(elmerDefs, "BodyForce",1 );
239   QMdiSubWindow *bodyForceSubWindow = new QMdiSubWindow;
240   bodyForceSubWindow->setWidget(dynamicEditorBodyForce);
241   mdiArea->addSubWindow(bodyForceSubWindow);
242   bodyForceSubWindow->show();
243 
244   if(dynamicEditorIC) delete dynamicEditorIC;
245   dynamicEditorIC = new DynamicEditor;
246   dynamicEditorIC->setupTabs(elmerDefs, "InitialCondition",1 );
247   QMdiSubWindow *initialConditionSubWindow = new QMdiSubWindow;
248   initialConditionSubWindow->setWidget(dynamicEditorIC);
249   mdiArea->addSubWindow(initialConditionSubWindow);
250   initialConditionSubWindow->show();
251 
252   if(dynamicEditorBC) delete dynamicEditorBC;
253   dynamicEditorBC = new DynamicEditor;
254   dynamicEditorBC->setupTabs(elmerDefs, "BoundaryCondition",1 );
255   QMdiSubWindow *bcSubWindow = new QMdiSubWindow;
256   bcSubWindow->setWidget(dynamicEditorBC);
257   mdiArea->addSubWindow(bcSubWindow);
258   bcSubWindow->show();
259 
260   mdiArea->tileSubWindows();
261   //mdiArea->cascadeSubWindows();
262 
263 }
264 
265 
266 
267 // Add items from document to tree view...
268 //----------------------------------------------------------------------------
insertItemForElement(QDomElement element,QTreeWidgetItem * parentItem)269 void EdfEditor::insertItemForElement(QDomElement element,
270 				     QTreeWidgetItem *parentItem)
271 {
272   if(element.isNull())
273     return;
274 
275   // set expanded
276 //  if(parentItem != NULL)
277 //    parentItem->setExpanded(true);
278 
279   // create new tree item
280   QTreeWidgetItem *newItem = new QTreeWidgetItem(parentItem);
281 
282   newItem->setText(0, element.tagName().trimmed());
283   newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
284 
285   // display attributes
286   QStringList list;
287   QDomNamedNodeMap attributeMap = element.attributes();
288   for(int index = 0; index < (int)attributeMap.length(); index++) {
289     QDomNode attribute = attributeMap.item(index);
290     list << attribute.nodeName() + "=\"" + attribute.nodeValue() + "\"";
291   }
292   newItem->setText(1, list.join(" "));
293 
294   // display value
295   if(element.firstChildElement().isNull())
296     newItem->setText(2, element.text().split("\n").join(" ").trimmed());
297 
298   // update hash
299   elementForItem.insert(newItem, element);
300 
301   // add item
302   edfTree->addTopLevelItem(newItem);
303 
304   if(!element.firstChildElement().isNull())
305     insertItemForElement(element.firstChildElement(), newItem);
306 
307   insertItemForElement(element.nextSiblingElement(), parentItem);
308 }
309 
310 // Construct tree view...
311 //----------------------------------------------------------------------------
setupEditor(QDomDocument * elmerDefs)312 void EdfEditor::setupEditor(QDomDocument *elmerDefs)
313 {
314   this->elmerDefs = elmerDefs;
315 
316   disconnect(edfTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
317 	     this, SLOT(updateElement(QTreeWidgetItem*, int)));
318 
319   // clear tree view & hash
320   edfTree->clear();
321   elementForItem.clear();
322 
323   // get root entry & recursively add items to the tree:
324   QDomElement root = elmerDefs->documentElement();
325   insertItemForElement(root, NULL);
326   edfTree->setCurrentItem(NULL);
327 
328   connect(edfTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
329 	  this, SLOT(updateElement(QTreeWidgetItem*, int)));
330 
331   edfTree->expandAll();
332   expandCollapseAllButton->setText("Collapse all");
333   expandCollapseAllButton->setIcon(collapseIcon);
334   expandCollapseAll = false;
335 
336   edfTree->setCurrentItem(NULL);
337 }
338 
339 // Tree view item has been edited: update document accordingly...
340 //----------------------------------------------------------------------------
updateElement(QTreeWidgetItem * item,int column)341 void EdfEditor::updateElement(QTreeWidgetItem *item, int column)
342 {
343   // get element from hash
344   QDomElement element = elementForItem.value(item);
345 
346   if(element.isNull())
347     return;
348 
349   // set new tag
350   element.setTagName(item->text(0).trimmed());
351 
352   // delete old attributes
353   QDomNamedNodeMap oldAttributes = element.attributes();
354   for(int i = 0; i<(int)oldAttributes.length(); i++) {
355     QDomNode node = oldAttributes.item(i);
356     QString name = node.nodeName();
357     element.removeAttribute(name);
358   }
359 
360   // parse and set new attributes
361   QString pattern = "([a-zA-Z0-9]+)[ \t]*=[ \t]*[\"]([^\"]+)[\"]";
362   QRegExp expression(pattern);
363   QString qs = item->text(1).trimmed();
364 
365   int index = qs.indexOf(expression);
366 
367   QString parsedString = "";
368   if(index < 0)
369     parsedString = qs;
370 
371   while(index >= 0) {
372     int length = expression.matchedLength();
373     QString currentMatch = qs.mid(index, length);
374     QStringList currentList = currentMatch.split("=");
375     QString name = currentList.at(0);
376     QString value = currentList.at(1);
377 
378     int firstPar = value.indexOf("\"", 0);
379     int secondPar = value.indexOf("\"", firstPar+1);
380     value = value.mid(firstPar+1, secondPar-firstPar-1);
381 
382     parsedString.append(name + "=\"" + value + "\" ");
383 
384     element.setAttribute(name.trimmed(), value.trimmed());
385     index = qs.indexOf(expression, index + length);
386   }
387 
388   // update display with parsed attributes
389   item->setText(1, parsedString);
390 
391   // set new text (iff old element has no children)
392   if(element.firstChildElement().isNull()) {
393 
394     // remove old text node
395     QDomNodeList children = element.childNodes();
396     for(int i=0;  i<(int)children.length(); i++) {
397       QDomNode node = children.at(i);
398       if(node.isText())
399 	element.removeChild(node);
400     }
401 
402     // new text node
403     QDomText text = elmerDefs->createTextNode(item->text(2));
404     element.appendChild(text);
405 
406   } else {
407 
408     // clear value from tree view to avoid confusions:
409     item->setText(2, "");
410   }
411 
412   // no need to update hash
413 }
414 
415 // Add tree view item & document element...
416 //----------------------------------------------------------------------------
addButtonClicked()417 void EdfEditor::addButtonClicked()
418 {
419   QTreeWidgetItem *current = edfTree->currentItem();
420 
421   if(current == NULL)
422     return;
423 
424   QString newTag = "empty";
425   QString newAttribute = "attribute";
426   QString newAttributeValue = "empty";
427   QString newValue = "empty";
428 
429   // add item to tree view:
430   QTreeWidgetItem *newItem = new QTreeWidgetItem(current);
431 
432   newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
433 
434   newItem->setText(0, newTag);
435   newItem->setText(1, newAttribute + "=\"" + newAttributeValue + "\"");
436   newItem->setText(2, newValue);
437   current->addChild(newItem);
438   newItem->parent()->setExpanded(true);
439 
440   // clear the value field for current item (as it just became parent)
441   current->setText(2, "");
442 
443   // add to document
444   QDomElement newElement = elmerDefs->createElement(newTag);
445   newElement.setAttribute(newAttribute, newAttributeValue);
446 
447   QDomText newText = elmerDefs->createTextNode(newValue);
448   newElement.appendChild(newText);
449 
450   QDomElement parent = elementForItem.value(newItem->parent());
451   parent.appendChild(newElement);
452 
453   // update hash
454   elementForItem.insert(newItem, newElement);
455 
456   edfTree->setCurrentItem(newItem);
457 }
458 
459 // Remove item from tree view item & element from document...
460 //----------------------------------------------------------------------------
removeButtonClicked()461 void EdfEditor::removeButtonClicked()
462 {
463   QTreeWidgetItem *currentItem = edfTree->currentItem();
464 
465   if(currentItem == NULL)
466     return;
467 
468   QTreeWidgetItem *parentItem = currentItem->parent();
469   QDomElement element = elementForItem.value(currentItem);
470   QDomElement parentElement = elementForItem.value(parentItem);
471 
472   parentItem->removeChild(currentItem);
473   parentElement.removeChild(element);
474 
475   // update hash
476   elementForItem.remove(currentItem);
477 
478   edfTree->setCurrentItem(NULL);
479 }
480 
481 // Save as...
482 //----------------------------------------------------------------------------
saveAsButtonClicked()483 void EdfEditor::saveAsButtonClicked()
484 {
485   QString fileName;
486 
487   fileName = QFileDialog::getSaveFileName(this,
488                  tr("Save definitions"), "", tr("EDF (*.xml)") );
489 
490   if(fileName.isEmpty())
491     return;
492 
493   const int indent = 3;
494 
495   QFile file;
496   file.setFileName(fileName);
497   file.open(QIODevice::WriteOnly);
498   QTextStream out(&file);
499   elmerDefs->save(out, indent);
500 }
501 
502 
503 // Expand/collapse tree view...
504 //----------------------------------------------------------------------------
expandCollapseAllButtonClicked()505 void EdfEditor::expandCollapseAllButtonClicked()
506 {
507   if(expandCollapseAll) {
508     edfTree->expandAll();
509     expandCollapseAllButton->setText("Collapse all");
510     expandCollapseAllButton->setIcon(collapseIcon);
511     expandCollapseAll = false;
512   } else {
513     edfTree->collapseAll();
514     expandCollapseAllButton->setText("Expand all");
515     expandCollapseAllButton->setIcon(expandIcon);
516     expandCollapseAll = true;
517   }
518 }
519 
520 // Open...
521 //----------------------------------------------------------------------------
openButtonClicked()522 void EdfEditor::openButtonClicked()
523 {
524   QString fileName;
525 
526   fileName = QFileDialog::getOpenFileName(this,
527 	      tr("Open definitions"), "", tr("EDF (*.xml)") );
528 
529   if(fileName.isEmpty())
530     return;
531 
532   QFile file;
533   file.setFileName(fileName);
534   file.open(QIODevice::ReadOnly);
535 
536   QString errStr;
537   int errRow;
538   int errCol;
539 
540   if(!elmerDefs->setContent(&file, true, &errStr, &errRow, &errCol)) {
541     QMessageBox::information(window(), tr("Elmer definitions file"),
542 			     tr("Parse error at line %1, col %2:\n%3")
543 			     .arg(errRow).arg(errCol).arg(errStr));
544     file.close();
545     return;
546 
547   } else {
548 
549     if(elmerDefs->documentElement().tagName() != "edf") {
550       QMessageBox::information(window(), tr("Elmer definitions file"),
551 			       tr("This is not an edf file"));
552       delete elmerDefs;
553       file.close();
554       return;
555 
556     }
557   }
558 
559   setupEditor(elmerDefs);
560 
561   edfTree->setCurrentItem(NULL);
562 }
563 
564 
565 // Append...
566 //----------------------------------------------------------------------------
appendButtonClicked()567 void EdfEditor::appendButtonClicked()
568 {
569   QString fileName;
570 
571   fileName = QFileDialog::getOpenFileName(this,
572 	      tr("Open definitions"), "", tr("EDF (*.xml)") );
573 
574   if(fileName.isEmpty())
575     return;
576 
577   QFile file;
578   file.setFileName(fileName);
579   file.open(QIODevice::ReadOnly);
580 
581   QDomDocument tmpDoc;
582 
583   QString errStr;
584   int errRow;
585   int errCol;
586 
587   if(!tmpDoc.setContent(&file, true, &errStr, &errRow, &errCol)) {
588     QMessageBox::information(window(), tr("Elmer definitions file"),
589 			     tr("Parse error at line %1, col %2:\n%3")
590 			     .arg(errRow).arg(errCol).arg(errStr));
591     file.close();
592     return;
593 
594   } else {
595 
596     if(tmpDoc.documentElement().tagName() != "edf") {
597       QMessageBox::information(window(), tr("Elmer definitions file"),
598 			       tr("This is not an edf file"));
599       file.close();
600       return;
601     }
602   }
603 
604   // add new elements to the document
605   QDomElement root = elmerDefs->documentElement();
606   QDomElement tmpRoot = tmpDoc.documentElement();
607 
608   QDomElement element = tmpRoot.firstChildElement();
609   while(!element.isNull()) {
610     root.appendChild(element);
611     element = tmpRoot.firstChildElement();
612   }
613 
614   setupEditor(elmerDefs);
615 
616   edfTree->setCurrentItem(NULL);
617 }
618 
619 
620 // Close...
621 //----------------------------------------------------------------------------
applyButtonClicked()622 void EdfEditor::applyButtonClicked()
623 {
624   // rebuild document from tree view:
625   //---------------------------------
626   this->close();
627 }
628 
629 // Change the place of two items and elements...
630 //----------------------------------------------------------------------------
treeItemClicked(QTreeWidgetItem * item,int column)631 void EdfEditor::treeItemClicked(QTreeWidgetItem *item, int column)
632 {
633   if(item == lastActiveItem)
634     return;
635 
636   if(lastActiveItem == NULL) {
637     lastActiveItem = item;
638     return;
639   }
640 
641   if(!ctrlPressed)
642     return;
643 
644   // items must have the same parent:
645   if(item->parent() != lastActiveItem->parent()) {
646     // cout << "Items have different parent - unable to swap" << endl;
647     // cout.flush();
648     lastActiveItem = item;
649     return;
650   }
651 
652   // get elements:
653   QDomElement element = elementForItem.value(item);
654   QDomElement lastActiveItemElement = elementForItem.value(lastActiveItem);
655 
656   // elements must have the same parent (should always be true):
657   if(element.parentNode() != lastActiveItemElement.parentNode()) {
658     // cout << "Parent element mismatch - unable to swap items" << endl;
659     // cout.flush();
660     lastActiveItem = item;
661     return;
662   }
663 
664   // clone elements:
665   QDomNode clone = element.cloneNode(true);
666   QDomNode lastActiveItemClone = lastActiveItemElement.cloneNode(true);
667 
668   // replace elements with their clones:
669   element.parentNode().replaceChild(lastActiveItemClone, element);
670   lastActiveItemElement.parentNode().replaceChild(clone, lastActiveItemElement);
671 
672   // remove old elements from the document:
673   element.parentNode().removeChild(element);
674   lastActiveItemElement.parentNode().removeChild(lastActiveItemElement);
675 
676   // make sure that old elements are cleared (they should be already):
677   element.clear();
678   lastActiveItemElement.clear();
679 
680   // rebuild tree & hash:
681   setupEditor(elmerDefs);
682 
683   // set focus back to the last selected item:
684   lastActiveItem = NULL;
685   for(int i = 0; i < elementForItem.count(); i++) {
686     if(elementForItem.values().at(i) == lastActiveItemClone) {
687       edfTree->setCurrentItem(elementForItem.keys().at(i));
688       edfTree->scrollToItem(elementForItem.keys().at(i),
689 			    QAbstractItemView::PositionAtCenter);
690     }
691   }
692 
693   return;
694 }
695 
696 // Key pressed...
697 //-----------------------------------------------------------------------------
keyPressEvent(QKeyEvent * event)698 void EdfEditor::keyPressEvent(QKeyEvent *event)
699 {
700   if(event->key() == Qt::Key_Control)
701     ctrlPressed = true;
702 
703   if(event->key() == Qt::Key_Alt)
704     altPressed = true;
705 }
706 
707 
708 // Key released...
709 //-----------------------------------------------------------------------------
keyReleaseEvent(QKeyEvent * event)710 void EdfEditor::keyReleaseEvent(QKeyEvent *event)
711 {
712   if(event->key() == Qt::Key_Control)
713     ctrlPressed = false;
714 
715   if(event->key() == Qt::Key_Alt)
716     altPressed = false;
717 }
718 
719 // Append from specified file path Nov 2019 by TS
720 //----------------------------------------------------------------------------
appendFrom(QString path)721 bool EdfEditor::appendFrom(QString path)
722 {
723   QString fileName = path;
724 
725   if(fileName.isEmpty())
726     return false;
727 
728   QFile file;
729   file.setFileName(fileName);
730   file.open(QIODevice::ReadOnly);
731 
732   QDomDocument tmpDoc;
733 
734   QString errStr;
735   int errRow;
736   int errCol;
737 
738   if(!tmpDoc.setContent(&file, true, &errStr, &errRow, &errCol)) {
739     QMessageBox::information(window(), tr("Elmer definitions file"),
740 			     tr("Parse error at line %1, col %2:\n%3")
741 			     .arg(errRow).arg(errCol).arg(errStr));
742     file.close();
743     return false;
744 
745   } else {
746 
747     if(tmpDoc.documentElement().tagName() != "edf") {
748       QMessageBox::information(window(), tr("Elmer definitions file"),
749 			       tr("This is not an edf file"));
750       file.close();
751       return false;
752     }
753   }
754 
755   // add new elements to the document
756   QDomElement root = elmerDefs->documentElement();
757   QDomElement tmpRoot = tmpDoc.documentElement();
758 
759   QDomElement element = tmpRoot.firstChildElement();
760   while(!element.isNull()) {
761     root.appendChild(element);
762     element = tmpRoot.firstChildElement();
763   }
764 
765   setupEditor(elmerDefs);
766 
767   edfTree->setCurrentItem(NULL);
768 
769   return true;
770 }