Bug Summary

File:OMEdit/OMEditLIB/Editors/CompositeModelEditor.cpp
Warning:line 572, column 11
Value stored to 'annotationFound' is never read

Annotated Source Code

[?] Use j/k keys for keyboard navigation

1/*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
13 * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
14 *
15 * The OpenModelica software and the Open Source Modelica
16 * Consortium (OSMC) Public License (OSMC-PL) are obtained
17 * from OSMC, either from the above address,
18 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
19 * http://www.openmodelica.org, and in the OpenModelica distribution.
20 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
21 *
22 * This program is distributed WITHOUT ANY WARRANTY; without
23 * even the implied warranty of MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
25 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
26 *
27 * See the full OSMC Public License conditions for more details.
28 *
29 */
30
31#include "CompositeModelEditor.h"
32#include "MainWindow.h"
33#include "Options/OptionsDialog.h"
34#include "Modeling/MessagesWidget.h"
35#include "Modeling/Commands.h"
36#include "Options/NotificationsDialog.h"
37
38#include <QMessageBox>
39#include <QMenu>
40
41XMLDocument::XMLDocument()
42 : QDomDocument()
43{
44
45}
46
47XMLDocument::XMLDocument(CompositeModelEditor *pCompositeModelEditor)
48 : QDomDocument()
49{
50 mpCompositeModelEditor = pCompositeModelEditor;
51}
52
53QString XMLDocument::toString() const
54{
55 TabSettings tabSettings = OptionsDialog::instance()->getTabSettings();
56 return QDomDocument::toString(tabSettings.getIndentSize());
57}
58
59
60CompositeModelEditor::CompositeModelEditor(QWidget *pParent)
61 : BaseEditor(pParent), mLastValidText(""), mTextChanged(false)
62{
63 mXmlDocument = XMLDocument(this);
64}
65
66/*!
67 * \brief CompositeModelEditor::popUpCompleter()
68 * \we do not have completer for this
69 */
70void CompositeModelEditor::popUpCompleter()
71{
72
73}
74
75/*!
76 * \brief CompositeModelEditor::validateText
77 * When user make some changes in the CompositeModelEditor text then this method validates the text.
78 * \return
79 */
80bool CompositeModelEditor::validateText()
81{
82 if (mTextChanged) {
83 // if the user makes few mistakes in the text then dont let him change the perspective
84 if (!mpModelWidget->compositeModelEditorTextChanged()) {
85 QSettings *pSettings = Utilities::getApplicationSettings();
86 int answer = -1;
87 if (pSettings->contains("textEditor/revertPreviousOrFixErrorsManually")) {
88 answer = pSettings->value("textEditor/revertPreviousOrFixErrorsManually").toInt();
89 }
90 if (answer < 0 || OptionsDialog::instance()->getNotificationsPage()->getAlwaysAskForTextEditorErrorCheckBox()->isChecked()) {
91 NotificationsDialog *pNotificationsDialog = new NotificationsDialog(NotificationsDialog::RevertPreviousOrFixErrorsManually,
92 NotificationsDialog::CriticalIcon,
93 MainWindow::instance());
94 pNotificationsDialog->setNotificationLabelString(GUIMessages::getMessage(GUIMessages::ERROR_IN_TEXT).arg("Composite Model")
95 .append(GUIMessages::getMessage(GUIMessages::CHECK_MESSAGES_BROWSER))
96 .append(GUIMessages::getMessage(GUIMessages::REVERT_PREVIOUS_OR_FIX_ERRORS_MANUALLY)));
97 pNotificationsDialog->getOkButton()->setText(Helper::revertToLastCorrectVersion);
98 pNotificationsDialog->getOkButton()->setAutoDefault(false);
99 pNotificationsDialog->getCancelButton()->setText(Helper::fixErrorsManually);
100 pNotificationsDialog->getCancelButton()->setAutoDefault(true);
101 pNotificationsDialog->getButtonBox()->removeButton(pNotificationsDialog->getOkButton());
102 pNotificationsDialog->getButtonBox()->removeButton(pNotificationsDialog->getCancelButton());
103 pNotificationsDialog->getButtonBox()->addButton(pNotificationsDialog->getCancelButton(), QDialogButtonBox::ActionRole);
104 pNotificationsDialog->getButtonBox()->addButton(pNotificationsDialog->getOkButton(), QDialogButtonBox::ActionRole);
105 // we set focus to this widget here so when the error dialog is closed Qt gives back the focus to this widget.
106 mpPlainTextEdit->setFocus(Qt::ActiveWindowFocusReason);
107 answer = pNotificationsDialog->exec();
108 }
109 switch (answer) {
110 case QMessageBox::RejectRole:
111 mTextChanged = false;
112 // revert back to last correct version
113 setPlainText(mLastValidText);
114 return true;
115 case QMessageBox::AcceptRole:
116 default:
117 mTextChanged = true;
118 return false;
119 }
120 } else {
121 mTextChanged = false;
122 mLastValidText = mpPlainTextEdit->toPlainText();
123 }
124 }
125 updateAllOrientations();
126 return true;
127}
128
129
130/*!
131 * @\brief CompositeModelEditor::getSubModelElement
132 * Returns SubModel element tag by model name
133 * @param name Name of the sub model to search for
134 * @return
135 */
136QDomElement CompositeModelEditor::getSubModelElement(QString name)
137{
138 QDomElement subModelsElement = getSubModelsElement();
139 if(!subModelsElement.isNull()) {
140 QDomElement subModelElement = subModelsElement.firstChildElement("SubModel");
141 while(!subModelElement.isNull()) {
142 if(subModelElement.attribute("Name").compare(name) == 0) {
143 return subModelElement;
144 }
145 subModelElement = subModelElement.nextSiblingElement("SubModel");
146 }
147 }
148 return QDomElement();
149}
150
151QStringList CompositeModelEditor::getParameterNames(QString subModelName)
152{
153 QStringList ret;
154 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
155 for (int i = 0 ; i < subModelList.size() ; i++) {
156 QDomElement subModelElement = subModelList.at(i).toElement();
157 if(subModelElement.attribute("Name").compare(subModelName) == 0) {
158 QDomElement parameterElement = subModelElement.firstChildElement("Parameter");
159 while(!parameterElement.isNull()) {
160 ret << parameterElement.attribute("Name");
161 parameterElement = parameterElement.nextSiblingElement("Parameter");
162 }
163 }
164 }
165 return ret;
166}
167
168QString CompositeModelEditor::getParameterValue(QString subModelName, QString parameterName)
169{
170 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
171 for (int i = 0 ; i < subModelList.size() ; i++) {
172 QDomElement subModelElement = subModelList.at(i).toElement();
173 if(subModelElement.attribute("Name").compare(subModelName) == 0) {
174 QDomElement parameterElement = subModelElement.firstChildElement("Parameter");
175 while(!parameterElement.isNull()) {
176 if(parameterElement.attribute("Name").compare(parameterName) == 0) {
177 return parameterElement.attribute("Value");
178 }
179 parameterElement = parameterElement.nextSiblingElement("Parameter");
180 }
181 }
182 }
183 return ""; //Should never happen
184}
185
186void CompositeModelEditor::setParameterValue(QString subModelName, QString parameterName, QString value)
187{
188 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
189 for (int i = 0 ; i < subModelList.size() ; i++) {
190 QDomElement subModelElement = subModelList.at(i).toElement();
191 if (subModelElement.attribute("Name").compare(subModelName) == 0) {
192 QDomElement parameterElement = subModelElement.firstChildElement("Parameter");
193 while(!parameterElement.isNull()) {
194 if(parameterElement.attribute("Name").compare(parameterName) == 0) {
195 parameterElement.setAttribute("Value",value);
196 setPlainText(mXmlDocument.toString());
197 return;
198 }
199 parameterElement = parameterElement.nextSiblingElement("Parameter");
200 }
201 //Parameter not found, insert it
202 QDomElement parameterPoint = mXmlDocument.createElement("Parameter");
203 parameterPoint.setAttribute("Name", parameterName);
204 parameterPoint.setAttribute("Value", value);
205 subModelElement.appendChild(parameterPoint);
206 setPlainText(mXmlDocument.toString());
207 return;
208 }
209 }
210}
211
212/*!
213 * \brief CompositeModelEditor::getCompositeModelName
214 * Gets the CompositeModel name.
215 * \return
216 */
217QString CompositeModelEditor::getCompositeModelName()
218{
219 QDomNodeList nodes = mXmlDocument.elementsByTagName("Model");
220 for (int i = 0; i < nodes.size(); i++) {
221 QDomElement node = nodes.at(i).toElement();
222 return node.attribute("Name");
223 }
224 return "";
225}
226
227/*!
228 * \brief CompositeModelEditor::getSubModelsElement
229 * Returns the SubModels element tag.
230 * \return
231 */
232QDomElement CompositeModelEditor::getSubModelsElement()
233{
234 QDomNodeList subModels = mXmlDocument.elementsByTagName("SubModels");
235 if (subModels.size() > 0) {
236 return subModels.at(0).toElement();
237 }
238 return QDomElement();
239}
240
241/*!
242 * \brief CompositeModelEditor::getSubModels
243 * Returns the list of SubModel tags.
244 * \return
245 */
246QDomNodeList CompositeModelEditor::getSubModels()
247{
248 return mXmlDocument.elementsByTagName("SubModel");
249}
250
251/*!
252 * \brief CompositeModelEditor::getInterfacePoint
253 * \param subModelName
254 * \param interfaceName
255 * \return
256 */
257QDomElement CompositeModelEditor::getInterfacePoint(QString subModelName, QString interfaceName)
258{
259 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
260 for (int i = 0 ; i < subModelList.size() ; i++) {
261 QDomElement subModel = subModelList.at(i).toElement();
262 if (subModel.attribute("Name").compare(subModelName) == 0) {
263 QDomNodeList subModelChildren = subModel.childNodes();
264 for (int j = 0 ; j < subModelChildren.size() ; j++) {
265 QDomElement interfaceElement = subModelChildren.at(j).toElement();
266 if (interfaceElement.tagName().compare("InterfacePoint") == 0 && interfaceElement.attribute("Name").compare(interfaceName) == 0) {
267 return interfaceElement;
268 }
269 }
270 }
271 }
272 return QDomElement();
273}
274
275/*!
276 * \brief CompositeModelEditor::getConnectionsElement
277 * Returns the Connections element tag.
278 * \return
279 */
280QDomElement CompositeModelEditor::getConnectionsElement()
281{
282 QDomNodeList connections = mXmlDocument.elementsByTagName("Connections");
283 if (connections.size() > 0) {
284 return connections.at(0).toElement();
285 }
286 return QDomElement();
287}
288
289/*!
290 * \brief CompositeModelEditor::getConnections
291 * Returns the list of Connection tags.
292 * \return
293 */
294QDomNodeList CompositeModelEditor::getConnections()
295{
296 return mXmlDocument.elementsByTagName("Connection");
297}
298
299/*!
300 * \brief CompositeModelEditor::setCompositeModelName
301 * Sets the CompositeModel name.
302 * \param name
303 */
304void CompositeModelEditor::setCompositeModelName(QString name)
305{
306 QDomNodeList nodes = mXmlDocument.elementsByTagName("Model");
307 for (int i = 0; i < nodes.size(); i++) {
308 QDomElement node = nodes.at(i).toElement();
309 node.setAttribute("Name", name);
310 setPlainText(mXmlDocument.toString());
311 break;
312 }
313}
314
315/*!
316 * \brief CompositeModelEditor::addSubModel
317 * Adds a SubModel tag with Annotation tag as child of it.
318 * \param pComponent
319 * \return
320 */
321bool CompositeModelEditor::addSubModel(Component *pComponent)
322{
323 pComponent->getComponentInfo()->setName(pComponent->getName().remove("."));
324 QDomElement subModels = getSubModelsElement();
325 if (!subModels.isNull()) {
326 QDomElement subModel = mXmlDocument.createElement("SubModel");
327 subModel.setAttribute("Name", pComponent->getName());
328 subModel.setAttribute("ModelFile", pComponent->getComponentInfo()->getModelFile());
329 subModel.setAttribute("StartCommand", pComponent->getComponentInfo()->getStartCommand());
330 subModel.setAttribute("Position", pComponent->getComponentInfo()->getPosition());
331 subModel.setAttribute("Angle321", pComponent->getComponentInfo()->getAngle321());
332 if (pComponent->getComponentInfo()->getGeometryFile().isEmpty()) {
333 subModel.removeAttribute("GeometryFile");
334 } else {
335 QFileInfo geometryFileInfo(pComponent->getComponentInfo()->getGeometryFile());
336 subModel.setAttribute("GeometryFile", geometryFileInfo.fileName());
337 }
338 // create Annotation Element
339 QDomElement annotation = mXmlDocument.createElement("Annotation");
340 annotation.setAttribute("Visible", pComponent->mTransformation.getVisible() ? "true" : "false");
341 annotation.setAttribute("Origin", pComponent->getTransformationOrigin());
342 annotation.setAttribute("Extent", pComponent->getTransformationExtent());
343 annotation.setAttribute("Rotation", QString::number(pComponent->mTransformation.getRotateAngle()));
344 subModel.appendChild(annotation);
345 subModels.appendChild(subModel);
346 setPlainText(mXmlDocument.toString());
347 return true;
348 }
349 return false;
350}
351
352/*!
353 * \brief CompositeModelEditor::createAnnotationElement
354 * Creates an Annotation tag for SubModel.
355 * \param subModel
356 * \param visible
357 * \param origin
358 * \param extent
359 * \param rotation
360 */
361void CompositeModelEditor::createAnnotationElement(QDomElement subModel, QString visible, QString origin, QString extent, QString rotation)
362{
363 QDomElement annotation = mXmlDocument.createElement("Annotation");
364 annotation.setAttribute("Visible", visible);
365 annotation.setAttribute("Origin", origin);
366 annotation.setAttribute("Extent", extent);
367 annotation.setAttribute("Rotation", rotation);
368 subModel.insertBefore(annotation, QDomNode());
369 setPlainText(mXmlDocument.toString());
370}
371
372/*!
373 * \brief CompositeModelEditor::updateSubModelPlacementAnnotation
374 * Updates the SubModel annotation.
375 * \param name
376 * \param visible
377 * \param origin
378 * \param extent
379 * \param rotation
380 */
381void CompositeModelEditor::updateSubModelPlacementAnnotation(QString name, QString visible, QString origin, QString extent, QString rotation)
382{
383 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
384 for (int i = 0 ; i < subModelList.size() ; i++) {
385 QDomElement subModel = subModelList.at(i).toElement();
386 if (subModel.attribute("Name").compare(name) == 0) {
387 QDomNodeList subModelChildren = subModel.childNodes();
388 for (int j = 0 ; j < subModelChildren.size() ; j++) {
389 QDomElement annotationElement = subModelChildren.at(j).toElement();
390 if (annotationElement.tagName().compare("Annotation") == 0) {
391 annotationElement.setAttribute("Visible", visible);
392 annotationElement.setAttribute("Origin", origin);
393 annotationElement.setAttribute("Extent", extent);
394 annotationElement.setAttribute("Rotation", rotation);
395 setPlainText(mXmlDocument.toString());
396 return;
397 }
398 }
399 // create annotation element
400 createAnnotationElement(subModel, visible, origin, extent, rotation);
401 break;
402 }
403 }
404}
405
406/*!
407 * \brief CompositeModelEditor::updateSubModelParameters
408 * Updates the SubModel parameters.
409 * \param name
410 * \param startCommand
411 * \param exactStep
412 * \param geometryFile
413 */
414void CompositeModelEditor::updateSubModelParameters(QString name, QString startCommand, QString exactStep, QString geometryFile)
415{
416 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
417 for (int i = 0 ; i < subModelList.size() ; i++) {
418 QDomElement subModel = subModelList.at(i).toElement();
419 if (subModel.attribute("Name").compare(name) == 0) {
420 subModel.setAttribute("StartCommand", startCommand);
421 if (exactStep.compare("true") == 0) {
422 subModel.setAttribute("ExactStep", exactStep);
423 } else if (subModel.hasAttribute("ExactStep")) {
424 subModel.removeAttribute("ExactStep");
425 }
426 if (geometryFile.isEmpty()) {
427 subModel.removeAttribute("GeometryFile");
428 } else {
429 QFileInfo geometryFileInfo(geometryFile);
430 subModel.setAttribute("GeometryFile", geometryFileInfo.fileName());
431 }
432 setPlainText(mXmlDocument.toString());
433 return;
434 }
435 }
436}
437
438void CompositeModelEditor::updateSubModelOrientation(QString name, QGenericMatrix<3,1,double> pos, QGenericMatrix<3,1,double> rot)
439{
440 QString pos_str = QString("%1,%2,%3").arg(pos(0,0)).arg(pos(0,1)).arg(pos(0,2));
441 getSubModelElement(name).setAttribute("Position", pos_str);
442 QString rot_str = QString("%1,%2,%3").arg(rot(0,0)).arg(rot(0,1)).arg(rot(0,2));
443 getSubModelElement(name).setAttribute("Angle321", rot_str);
444 setPlainText(mXmlDocument.toString());
445
446 Component *pComp = mpModelWidget->getDiagramGraphicsView()->getComponentObject(name);
447 if(pComp) {
448 pComp->getComponentInfo()->setPosition(pos_str);
449 pComp->getComponentInfo()->setAngle321(rot_str);
450 }
451}
452
453/*!
454 * \brief CompositeModelEditor::createConnection
455 * Adds a connection tag with Annotation tag as child of it.
456 * \param pConnectionLineAnnotation
457 * \return
458 */
459bool CompositeModelEditor::createConnection(LineAnnotation *pConnectionLineAnnotation)
460{
461 QDomElement connections = getConnectionsElement();
462 if (!connections.isNull()) {
463 QDomElement connection = mXmlDocument.createElement("Connection");
464 connection.setAttribute("From", pConnectionLineAnnotation->getStartComponentName());
465 connection.setAttribute("To", pConnectionLineAnnotation->getEndComponentName());
466 connection.setAttribute("Delay", pConnectionLineAnnotation->getDelay());
467 if(!pConnectionLineAnnotation->getAlpha().isEmpty()) {
468 connection.setAttribute("alpha", pConnectionLineAnnotation->getAlpha());
469 }
470 if(!pConnectionLineAnnotation->getZf().isEmpty()) {
471 connection.setAttribute("Zf", pConnectionLineAnnotation->getZf());
472 }
473 if(!pConnectionLineAnnotation->getZfr().isEmpty()) {
474 connection.setAttribute("Zfr", pConnectionLineAnnotation->getZfr());
475 }
476 // create Annotation Element
477 QDomElement annotation = mXmlDocument.createElement("Annotation");
478 annotation.setAttribute("Points", pConnectionLineAnnotation->getCompositeModelShapeAnnotation());
479 connection.appendChild(annotation);
480 connections.appendChild(connection);
481 setPlainText(mXmlDocument.toString());
482 // check if interfaces are aligned
483 bool aligned = interfacesAligned(pConnectionLineAnnotation->getStartComponentName(), pConnectionLineAnnotation->getEndComponentName());
484 pConnectionLineAnnotation->setAligned(aligned);
485
486 if (this->getInterfaceCausality(pConnectionLineAnnotation->getEndComponentName()) ==
487 StringHandler::getTLMCausality(StringHandler::TLMInput)) {
488 pConnectionLineAnnotation->setLinePattern(StringHandler::LineDash);
489 pConnectionLineAnnotation->setEndArrow(StringHandler::ArrowFilled);
490 } else if(this->getInterfaceCausality(pConnectionLineAnnotation->getEndComponentName()) ==
491 StringHandler::getTLMCausality(StringHandler::TLMOutput)) {
492 pConnectionLineAnnotation->setLinePattern(StringHandler::LineDash);
493 pConnectionLineAnnotation->setStartArrow(StringHandler::ArrowFilled);
494 }
495 return true;
496 }
497 return false;
498}
499
500/*!
501 * \brief CompositeModelEditor::okToConnect
502 * Checks if a connection between two interfaces is legal
503 * \param pConnectionLineAnnotation
504 * \return
505 */
506bool CompositeModelEditor::okToConnect(LineAnnotation *pConnectionLineAnnotation)
507{
508 QString startComp = pConnectionLineAnnotation->getStartComponentName();
509 QString endComp = pConnectionLineAnnotation->getEndComponentName();
510
511 int dimensions1 = getInterfaceDimensions(startComp);
512 int dimensions2 = getInterfaceDimensions(endComp);
513 QString causality1 = getInterfaceCausality(startComp);
514 QString causality2 = getInterfaceCausality(endComp);
515 QString domain1 = getInterfaceDomain(startComp);
516 QString domain2 = getInterfaceDomain(endComp);
517
518 if (dimensions1 != dimensions2) {
519 MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::CompositeModel,
520 tr("Cannot connect interface points of different dimensions (%1 to %2)")
521 .arg(QString::number(dimensions1), QString::number(dimensions2)),
522 Helper::scriptingKind, Helper::errorLevel));
523 return false;
524 }
525 if (!(causality1 == StringHandler::getTLMCausality(StringHandler::TLMBidirectional) &&
526 causality2 == StringHandler::getTLMCausality(StringHandler::TLMBidirectional)) &&
527 !(causality1 == StringHandler::getTLMCausality(StringHandler::TLMInput) &&
528 causality2 == StringHandler::getTLMCausality(StringHandler::TLMOutput)) &&
529 !(causality1 == StringHandler::getTLMCausality(StringHandler::TLMOutput) &&
530 causality2 == StringHandler::getTLMCausality(StringHandler::TLMInput))) {
531 MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::CompositeModel,
532 tr("Cannot connect interface points of different causality (%1 to %2)")
533 .arg(causality1, causality2), Helper::scriptingKind, Helper::errorLevel));
534 return false;
535 }
536 if (domain1 != domain2) {
537 MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::CompositeModel,
538 tr("Cannot connect interface points of different domains (%1 to %2)")
539 .arg(domain1, domain2), Helper::scriptingKind, Helper::errorLevel));
540 return false;
541 }
542 return true;
543}
544
545/*!
546 * \brief CompositeModelEditor::updateConnection
547 * Updates the CompositeModel connection annotation.
548 * \param pConnectionLineAnnotation
549 */
550void CompositeModelEditor::updateConnection(LineAnnotation *pConnectionLineAnnotation)
551{
552 QDomNodeList connectionList = mXmlDocument.elementsByTagName("Connection");
553 for (int i = 0 ; i < connectionList.size() ; i++) {
554 QDomElement connection = connectionList.at(i).toElement();
555 if (connection.attribute("From").compare(pConnectionLineAnnotation->getStartComponentName()) == 0 &&
556 connection.attribute("To").compare(pConnectionLineAnnotation->getEndComponentName()) == 0) {
557 connection.setAttribute("Delay", pConnectionLineAnnotation->getDelay());
558 if(connection.hasAttribute("alpha")) {
559 connection.setAttribute("alpha", pConnectionLineAnnotation->getAlpha());
560 }
561 if(connection.hasAttribute("Zf")) {
562 connection.setAttribute("Zf", pConnectionLineAnnotation->getZf());
563 }
564 if(connection.hasAttribute("Zfr")) {
565 connection.setAttribute("Zfr", pConnectionLineAnnotation->getZfr());
566 }
567 QDomNodeList connectionChildren = connection.childNodes();
568 bool annotationFound = false;
569 for (int j = 0 ; j < connectionChildren.size() ; j++) {
570 QDomElement annotationElement = connectionChildren.at(j).toElement();
571 if (annotationElement.tagName().compare("Annotation") == 0) {
572 annotationFound = true;
Value stored to 'annotationFound' is never read
573 annotationElement.setAttribute("Points", pConnectionLineAnnotation->getCompositeModelShapeAnnotation());
574 setPlainText(mXmlDocument.toString());
575 return;
576 }
577 }
578 // if we found the connection and there is no annotation with it then add the annotation element.
579 if (!annotationFound) {
580 QDomElement annotationElement = mXmlDocument.createElement("Annotation");
581 annotationElement.setAttribute("Points", pConnectionLineAnnotation->getCompositeModelShapeAnnotation());
582 connection.appendChild(annotationElement);
583 setPlainText(mXmlDocument.toString());
584 }
585 break;
586 }
587 }
588}
589
590/*!
591 * \brief CompositeModelEditor::updateSimulationParams
592 * Updates the simulation parameters.
593 * \param startTime
594 * \param stopTime
595 */
596void CompositeModelEditor::updateSimulationParams(QString startTime, QString stopTime)
597{
598 QDomElement simulationParamsElement = mXmlDocument.documentElement().firstChildElement("SimulationParams");
599 if (!simulationParamsElement.isNull()) {
600 simulationParamsElement.setAttribute("StartTime", startTime);
601 simulationParamsElement.setAttribute("StopTime", stopTime);
602 }
603 setPlainText(mXmlDocument.toString());
604}
605
606/*!
607 * \brief CompositeModelEditor::isSimulationParams
608 * Updates the simulation parameters.
609 */
610bool CompositeModelEditor::isSimulationParams()
611{
612 QDomElement simulationParamsElement = mXmlDocument.documentElement().firstChildElement("SimulationParams");
613 if (!simulationParamsElement.isNull()) {
614 return true;
615 }
616 return false;
617}
618
619/*!
620 * \brief CompositeModelEditor::getSimulationStartTime
621 * Gets the simulation start time.
622 */
623QString CompositeModelEditor::getSimulationStartTime()
624{
625 QDomElement simulationParamsElement = mXmlDocument.documentElement().firstChildElement("SimulationParams");
626 return simulationParamsElement.attribute("StartTime");
627}
628
629/*!
630 * \brief CompositeModelEditor::getSimulationStopTime
631 * Gets the simulation stop time.
632 */
633QString CompositeModelEditor::getSimulationStopTime()
634{
635 QDomElement simulationParamsElement = mXmlDocument.documentElement().firstChildElement("SimulationParams");
636 return simulationParamsElement.attribute("StopTime");
637}
638/*!
639 * \brief CompositeModelEditor::addInterfacesData
640 * Adds the InterfacePoint tag to SubModel.
641 * \param interfaces
642 */
643void CompositeModelEditor::addInterfacesData(QDomElement interfaces, QDomElement parameters, QString singleModel)
644{
645 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
646 for (int i = 0 ; i < subModelList.size() ; i++) {
647 QDomElement subModel = subModelList.at(i).toElement();
648 QDomElement interfaceDataElement = interfaces.firstChildElement();
649 while (!interfaceDataElement.isNull()) {
650 subModel = subModelList.at(i).toElement();
651 if (subModel.attribute("Name").compare(interfaceDataElement.attribute("model")) == 0 &&
652 (subModel.attribute("Name") == singleModel || singleModel.isEmpty())) {
653 QDomElement interfacePoint;
654 // update interface point
655 if (existInterfacePoint(subModel.attribute("Name"), interfaceDataElement.attribute("Name"))) {
656 interfacePoint = getInterfacePoint(subModel.attribute("Name"), interfaceDataElement.attribute("Name"));
657 interfacePoint.setAttribute("Name", interfaceDataElement.attribute("Name"));
658 interfacePoint.setAttribute("Position", interfaceDataElement.attribute("Position"));
659 interfacePoint.setAttribute("Angle321", interfaceDataElement.attribute("Angle321"));
660 interfacePoint.setAttribute("Dimensions", interfaceDataElement.attribute("Dimensions"));
661 interfacePoint.setAttribute("Domain", interfaceDataElement.attribute("Domain"));
662 interfacePoint.setAttribute("Causality", interfaceDataElement.attribute("Causality"));
663 setPlainText(mXmlDocument.toString());
664 // check if interface is aligned
665 foreach (LineAnnotation* pConnectionLineAnnotation, mpModelWidget->getDiagramGraphicsView()->getConnectionsList())for (auto _container_ = QtPrivate::qMakeForeachContainer(mpModelWidget
->getDiagramGraphicsView()->getConnectionsList()); _container_
.control && _container_.i != _container_.e; ++_container_
.i, _container_.control ^= 1) for (LineAnnotation* pConnectionLineAnnotation
= *_container_.i; _container_.control; _container_.control =
0)
{
666 QString interfaceName = QString("%1.%2").arg(subModel.attribute("Name")).arg(interfaceDataElement.attribute("Name"));
667 if (pConnectionLineAnnotation->getStartComponentName().compare(interfaceName) == 0 ||
668 pConnectionLineAnnotation->getEndComponentName().compare(interfaceName) == 0) {
669 bool aligned = interfacesAligned(pConnectionLineAnnotation->getStartComponentName(), pConnectionLineAnnotation->getEndComponentName());
670 pConnectionLineAnnotation->setAligned(aligned);
671 }
672 }
673 } else { // insert interface point
674 QDomElement interfacePoint = mXmlDocument.createElement("InterfacePoint");
675 interfacePoint.setAttribute("Name", interfaceDataElement.attribute("Name"));
676 interfacePoint.setAttribute("Position", interfaceDataElement.attribute("Position"));
677 interfacePoint.setAttribute("Angle321", interfaceDataElement.attribute("Angle321"));
678 interfacePoint.setAttribute("Dimensions", interfaceDataElement.attribute("Dimensions"));
679 interfacePoint.setAttribute("Causality", interfaceDataElement.attribute("Causality"));
680 interfacePoint.setAttribute("Domain", interfaceDataElement.attribute("Domain"));
681 subModel.appendChild(interfacePoint);
682 setPlainText(mXmlDocument.toString());
683 Component *pComponent = mpModelWidget->getDiagramGraphicsView()->getComponentObject(subModel.attribute("Name"));
684 if (pComponent) {
685 pComponent->insertInterfacePoint(interfaceDataElement.attribute("Name"),
686 interfaceDataElement.attribute("Position", "0,0,0"),
687 interfaceDataElement.attribute("Angle321", "0,0,0"),
688 interfaceDataElement.attribute("Dimensions", "3").toInt(),
689 interfaceDataElement.attribute("Causality", StringHandler::getTLMCausality(StringHandler::TLMBidirectional)),
690 interfaceDataElement.attribute("Domain", StringHandler::getTLMDomain(StringHandler::Mechanical)));
691 }
692 }
693 }
694 interfaceDataElement = interfaceDataElement.nextSiblingElement();
695 }
696
697 //Now remove all elements in sub model that does not exist in fetched interfaces (i.e. has been externally removed)
698 subModel = subModelList.at(i).toElement();
699 if(subModel.attribute("Name") != singleModel && !singleModel.isEmpty()){
700 continue; //Ignore other models if single model is specified
701 }
702 Component *pComponent = mpModelWidget->getDiagramGraphicsView()->getComponentObject(subModel.attribute("Name"));
703 QDomElement subModelInterfaceDataElement = subModel.firstChildElement("InterfacePoint");
704 while (!subModelInterfaceDataElement.isNull()) {
705 bool interfaceExists = false;
706 interfaceDataElement = interfaces.firstChildElement();
707 while (!interfaceDataElement.isNull()) {
708 if (subModelInterfaceDataElement.attribute("Name") == interfaceDataElement.attribute("Name") &&
709 subModel.attribute("Name") == interfaceDataElement.attribute("model")) {
710 interfaceExists = true;
711 }
712 interfaceDataElement = interfaceDataElement.nextSiblingElement();
713 }
714 if (!interfaceExists) {
715 QDomElement elementToRemove = subModelInterfaceDataElement;
716 subModelInterfaceDataElement = subModelInterfaceDataElement.nextSiblingElement("InterfacePoint");
717 if (pComponent) {
718 pComponent->removeInterfacePoint(elementToRemove.attribute("Name"));
719 }
720 subModel.removeChild(elementToRemove);
721 }
722 else {
723 subModelInterfaceDataElement = subModelInterfaceDataElement.nextSiblingElement("InterfacePoint");
724 }
725 }
726
727 //Add or update parameters
728 QDomElement parameterDataElement = parameters.firstChildElement();
729 while (!parameterDataElement.isNull()) {
730 subModel = subModelList.at(i).toElement();
731 if (subModel.attribute("Name").compare(parameterDataElement.attribute("model")) == 0 &&
732 (subModel.attribute("Name") == singleModel || singleModel.isEmpty())) {
733 QDomElement parameterPoint;
734 // update parameter
735 //Do nothing if parameter already exists (i.e. never overwrite values)
736 if (!existParameter(subModel.attribute("Name"), parameterDataElement)) { // insert parameter
737 QDomElement parameterPoint = mXmlDocument.createElement("Parameter");
738 parameterPoint.setAttribute("Name", parameterDataElement.attribute("Name"));
739 parameterPoint.setAttribute("Value", parameterDataElement.attribute("DefaultValue"));
740 subModel.appendChild(parameterPoint);
741 }
742 }
743 parameterDataElement = parameterDataElement.nextSiblingElement();
744 }
745
746 //Remove all parameters in sub model that does not exist in fetched data (i.e. has been externally removed)
747 subModel = subModelList.at(i).toElement();
748 if(subModel.attribute("Name") != singleModel && !singleModel.isEmpty()){
749 continue; //Ignore other models if single model is specified
750 }
751 pComponent = mpModelWidget->getDiagramGraphicsView()->getComponentObject(subModel.attribute("Name"));
752 QDomElement subModelParameterDataElement = subModel.firstChildElement("Parameter");
753 while (!subModelParameterDataElement.isNull()) {
754 bool parameterExists = false;
755 parameterDataElement = parameters.firstChildElement();
756 while (!parameterDataElement.isNull()) {
757 if (subModelParameterDataElement.attribute("Name") == parameterDataElement.attribute("Name") &&
758 subModel.attribute("Name") == parameterDataElement.attribute("model")) {
759 parameterExists = true;
760 }
761 parameterDataElement = parameterDataElement.nextSiblingElement();
762 }
763 if (!parameterExists) {
764 QDomElement elementToRemove = subModelParameterDataElement;
765 subModelParameterDataElement = subModelParameterDataElement.nextSiblingElement("Parameter");
766 subModel.removeChild(elementToRemove);
767 }
768 else {
769 subModelParameterDataElement = subModelParameterDataElement.nextSiblingElement("Parameter");
770 }
771 }
772 }
773
774 //Remove connections between no longer existing elements
775 QDomNodeList connectionsList = mXmlDocument.elementsByTagName("Connection");
776 for (int i = 0 ; i < connectionsList.size() ; i++) {
777 QDomElement connection = connectionsList.at(i).toElement();
778 QString from = connection.attribute("From");
779 QString to = connection.attribute("To");
780
781 bool fromExists = false;
782 bool toExists = false;
783 for(int i = 0 ; i < subModelList.size() ; ++i) {
784 QDomElement subModel = subModelList.at(i).toElement();
785 QDomElement subModelInterfaceDataElement = subModel.firstChildElement("InterfacePoint");
786 while (!subModelInterfaceDataElement.isNull()) {
787 if (subModel.attribute("Name") == from.section(".",0,0) && subModelInterfaceDataElement.attribute("Name") == from.section(".",1,1)) {
788 fromExists = true;
789 }
790 else if (subModel.attribute("Name") == to.section(".",0,0) && subModelInterfaceDataElement.attribute("Name") == to.section(".",1,1)) {
791 toExists = true;
792 }
793 subModelInterfaceDataElement = subModelInterfaceDataElement.nextSiblingElement("InterfacePoint");
794 }
795 }
796 if (!fromExists || !toExists) {
797 foreach (LineAnnotation *pConnectionLineAnnotation, mpModelWidget->getDiagramGraphicsView()->getConnectionsList())for (auto _container_ = QtPrivate::qMakeForeachContainer(mpModelWidget
->getDiagramGraphicsView()->getConnectionsList()); _container_
.control && _container_.i != _container_.e; ++_container_
.i, _container_.control ^= 1) for (LineAnnotation *pConnectionLineAnnotation
= *_container_.i; _container_.control; _container_.control =
0)
{
798 if (pConnectionLineAnnotation->getStartComponentName().compare(from) == 0 ||
799 pConnectionLineAnnotation->getEndComponentName().compare(to) == 0) {
800 mpModelWidget->getDiagramGraphicsView()->deleteConnectionFromList(pConnectionLineAnnotation);
801 mpModelWidget->getDiagramGraphicsView()->removeItem(pConnectionLineAnnotation);
802 pConnectionLineAnnotation->deleteLater();
803 }
804 }
805 connection.parentNode().removeChild(connection);
806 --i;
807 }
808 }
809
810 setPlainText(mXmlDocument.toString());
811}
812
813/*!
814 * \brief CompositeModelEditor::addInterface
815 * Adds the interface to submodel.
816 * \param pInterfaceComponent
817 * \param subModel
818 */
819void CompositeModelEditor::addInterface(Component *pInterfaceComponent, QString subModel)
820{
821 QDomElement subModelElement = getSubModelElement(subModel);
822 QDomElement interfacePoint = mXmlDocument.createElement("InterfacePoint");
823 interfacePoint.setAttribute("Name", pInterfaceComponent->getName());
824 interfacePoint.setAttribute("Position", pInterfaceComponent->getComponentInfo()->getPosition());
825 interfacePoint.setAttribute("Angle321", pInterfaceComponent->getComponentInfo()->getAngle321());
826 interfacePoint.setAttribute("Dimensions", pInterfaceComponent->getComponentInfo()->getDimensions());
827 interfacePoint.setAttribute("Causality", pInterfaceComponent->getComponentInfo()->getTLMCausality());
828 interfacePoint.setAttribute("Domain", pInterfaceComponent->getComponentInfo()->getDomain());
829 subModelElement.appendChild(interfacePoint);
830 setPlainText(mXmlDocument.toString());
831}
832
833/*!
834 * \brief CompositeModelEditor::interfacesAligned
835 * Checkes whether specified TLM interfaces are aligned
836 * \param interface1 First interface (submodel1.interface1)
837 * \param interface2 Second interface (submodel2.interface2)
838 * \return
839 */
840bool CompositeModelEditor::interfacesAligned(QString interface1, QString interface2)
841{
842 if(getInterfaceCausality(interface1) != StringHandler::getTLMCausality(StringHandler::TLMBidirectional)) {
843 //Assume interface2 has same causality and dimensions, otherwise they could not be connected)
844 return true; //Alignment is not relevant for non-bidirectional connections
845 }
846
847 //Extract rotation and position vectors to Qt matrices
848 QGenericMatrix<3,1,double> CG_X1_PHI_CG; //Rotation of X1 relative to CG expressed in CG
849 QGenericMatrix<3,1,double> X1_C1_PHI_X1; //Rotation of C1 relative to X1 expressed in X1
850 QGenericMatrix<3,1,double> CG_X1_R_CG; //Position of X1 relative to CG expressed in CG
851 QGenericMatrix<3,1,double> X1_C1_R_X1; //Position of C1 relative to X1 expressed in X1
852 if (!getPositionAndRotationVectors(interface1,CG_X1_PHI_CG, X1_C1_PHI_X1,CG_X1_R_CG,X1_C1_R_X1)) {
853 return false;
854 }
855
856 QGenericMatrix<3,1,double> CG_X2_PHI_CG; //Rotation of X2 relative to CG expressed in CG
857 QGenericMatrix<3,1,double> X2_C2_PHI_X2; //Rotation of C2 relative to X2 expressed in X2
858 QGenericMatrix<3,1,double> CG_X2_R_CG; //Position of X2 relative to CG expressed in CG
859 QGenericMatrix<3,1,double> X2_C2_R_X2; //Position of C2 relative to X2 expressed in X2
860
861 if (!getPositionAndRotationVectors(interface2,CG_X2_PHI_CG, X2_C2_PHI_X2,CG_X2_R_CG,X2_C2_R_X2)) {
862 return false;
863 } else if(getInterfaceCausality(interface1) == StringHandler::getTLMCausality(StringHandler::TLMBidirectional) &&
864 getInterfaceDimensions(interface1) == 1) {
865 //Handle 1D- interfaces
866 //Assume interface2 has same causality and dimensions, otherwise they could not be connected)
867 //Only compare first element of interface position relative to external model,
868 //the model orientation should not matter for 1D connections
869 return fuzzyCompare(X1_C1_R_X1(0,0),X2_C2_R_X2(0,0));
870 }
871
872 QGenericMatrix<3,1,double> CG_C1_R_CG, CG_C1_PHI_CG, CG_C2_R_CG, CG_C2_PHI_CG;
873 QGenericMatrix<3,3,double> R_X1_C1, R_CG_X1, R_CG_C1, R_X2_C2, R_CG_X2, R_CG_C2;
874
875 //Compute rotation matrices for both interfaces relative to CG and make sure they are the same
876 R_X1_C1 = Utilities::getRotationMatrix(X1_C1_PHI_X1); //Rotation matrix between X1 and C1
877 R_CG_X1 = Utilities::getRotationMatrix(CG_X1_PHI_CG); //Rotation matrix between CG and X1
878 R_CG_C1 = R_X1_C1*R_CG_X1; //Rotation matrix between CG and C1
879 R_X2_C2 = Utilities::getRotationMatrix(X2_C2_PHI_X2); //Rotation matrix between X2 and C2
880 R_CG_X2 = Utilities::getRotationMatrix(CG_X2_PHI_CG); //Rotation matrix between CG and X2
881 R_CG_C2 = R_X2_C2*R_CG_X2; //Rotation matrix between CG and C2
882
883 bool success=true;
884 for (int i=0; i<3; ++i) {
885 for (int j=0; j<3; ++j) {
886 if (!fuzzyCompare(R_CG_C1(i,j),R_CG_C2(i,j))) {
887 success=false;
888 }
889 }
890 }
891
892 //Compute positions for both interfaces relative to CG and make sure they are the same
893 CG_C1_R_CG = CG_X1_R_CG + X1_C1_R_X1*R_CG_X1; //Position of C1 relative to CG exressed in CG
894 CG_C2_R_CG = CG_X2_R_CG + X2_C2_R_X2*R_CG_X2; //Position of C2 relative to CG exressed in CG
895
896 for (int i=0; i<3; ++i) {
897 if (!fuzzyCompare(CG_C1_R_CG(0,i),CG_C2_R_CG(0,i))) {
898 success=false;
899 }
900 }
901
902 return success;
903}
904
905/*!
906 * \brief CompositeModelEditor::deleteSubModel
907 * Delets a SubModel.
908 * \param name
909 * \return
910 */
911bool CompositeModelEditor::deleteSubModel(QString name)
912{
913 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
914 for (int i = 0 ; i < subModelList.size() ; i++) {
915 QDomElement subModel = subModelList.at(i).toElement();
916 if (subModel.attribute("Name").compare(name) == 0) {
917 QDomElement subModels = getSubModelsElement();
918 if (!subModels.isNull()) {
919 subModels.removeChild(subModel);
920 setPlainText(mXmlDocument.toString());
921 return true;
922 }
923 break;
924 }
925 }
926 return false;
927}
928
929/*!
930 * \brief CompositeModelEditor::deleteConnection
931 * Delets a connection.
932 * \param name
933 * \return
934 */
935bool CompositeModelEditor::deleteConnection(QString startSubModelName, QString endSubModelName)
936{
937 QDomNodeList connectionList = mXmlDocument.elementsByTagName("Connection");
938 for (int i = 0 ; i < connectionList.size() ; i++) {
939 QDomElement connection = connectionList.at(i).toElement();
940 QString startName = connection.attribute("From");
941 QString endName = connection.attribute("To");
942 if (startName.compare(startSubModelName) == 0 && endName.compare(endSubModelName) == 0 ) {
943 QDomElement connections = getConnectionsElement();
944 if (!connections.isNull()) {
945 connections.removeChild(connection);
946 setPlainText(mXmlDocument.toString());
947 return true;
948 }
949 break;
950 }
951 }
952 return false;
953}
954
955/*!
956 * \brief CompositeModelEditor::existInterfacePoint
957 * Checks whether the interface already exists in CompositeModel or not.
958 * \param subModelName
959 * \param interfaceName
960 * \return
961 */
962bool CompositeModelEditor::existInterfacePoint(QString subModelName, QString interfaceName)
963{
964 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
965 for (int i = 0 ; i < subModelList.size() ; i++) {
966 QDomElement subModel = subModelList.at(i).toElement();
967 if (subModel.attribute("Name").compare(subModelName) == 0) {
968 QDomNodeList subModelChildren = subModel.childNodes();
969 for (int j = 0 ; j < subModelChildren.size() ; j++) {
970 QDomElement interfaceElement = subModelChildren.at(j).toElement();
971 if (interfaceElement.tagName().compare("InterfacePoint") == 0 &&
972 interfaceElement.attribute("Name").compare(interfaceName) == 0) {
973 return true;
974 }
975 }
976 break;
977 }
978 }
979 return false;
980}
981
982bool CompositeModelEditor::existParameter(QString subModelName, QDomElement parameterDataElement)
983{
984 QDomNodeList subModelList = mXmlDocument.elementsByTagName("SubModel");
985 for (int i = 0 ; i < subModelList.size() ; i++) {
986 QDomElement subModel = subModelList.at(i).toElement();
987 if (subModel.attribute("Name").compare(subModelName) == 0) {
988 QDomNodeList subModelChildren = subModel.childNodes();
989 for (int j = 0 ; j < subModelChildren.size() ; j++) {
990 QDomElement parameterElement = subModelChildren.at(j).toElement();
991 if (parameterElement.tagName().compare("Parameter") == 0 &&
992 parameterElement.attribute("Name").compare(parameterDataElement.attribute("Name")) == 0) {
993 return true;
994 }
995 }
996 break;
997 }
998 }
999 return false;
1000}
1001
1002/*!
1003 * \brief CompositeModelEditor::getRotationVector
1004 * Computes a rotation vector (321) from a rotation matrix
1005 * \param R
1006 * \return
1007 */
1008QGenericMatrix<3,1,double> CompositeModelEditor::getRotationVector(QGenericMatrix<3,3,double> R)
1009{
1010 double a11 = R(0,0);
1011 double a12 = R(0,1);
1012 double a13 = R(0,2);
1013 double a23 = R(1,2);
1014 double a33 = R(2,2);
1015
1016 double phi[3];
1017 phi[1] = (fabs(a13) < DBL_MIN2.2250738585072014e-308)? 0.0 : asin((a13<-1.0) ? 1.0 : ((a13>1.0) ? -1.0 : -a13));
1018 double tmp = cos(phi[1]);
1019 double cosphi1 = tmp+sign(tmp)*1.0e-50;
1020
1021 phi[0] = atan2(a23/cosphi1, a33/cosphi1);
1022 phi[2] = atan2(a12/cosphi1, a11/cosphi1);
1023
1024 return QGenericMatrix<3,1,double>(phi);
1025}
1026
1027void CompositeModelEditor::updateAllOrientations()
1028{
1029 QDomNodeList subModelList = getSubModels();
1030 for (int i=0; i<subModelList.size(); ++i) {
1031 QDomElement subModelElement = subModelList.at(i).toElement();
1032 GraphicsView *pView = mpModelWidget->getDiagramGraphicsView();
1033 QString modelName = subModelElement.attribute("Name");
1034
1035 if(subModelElement.hasAttribute("Position") && subModelElement.hasAttribute("Angle321")) {
1036 Component *pComp = pView->getComponentObject(modelName);
1037 if(pComp) {
1038 pComp->getComponentInfo()->setPosition(subModelElement.attribute("Position"));
1039 pComp->getComponentInfo()->setAngle321(subModelElement.attribute("Angle321"));
1040 }
1041 }
1042 }
1043#if !defined(WITHOUT_OSG)
1044 mpModelWidget->getModelWidgetContainer()->updateThreeDViewer(mpModelWidget);
1045#endif
1046}
1047
1048/*!
1049 * \brief CompositeModelEditor::getPositionAndRotationVectors
1050 * Extracts position and rotation vectors for specified TLM interface, both between CG and model X and between X and interface C
1051 * \param interfacePoint Interface on the form "submodel.interface"
1052 * \param CG_X_PHI_CG Rotation vector between CG abd X
1053 * \param X_C_PHI_X Rotation vector between X and C
1054 * \param CG_X_R_CG Position vector between CG and X
1055 * \param X_C_R_X Position vector between X and C
1056 * \return
1057 */
1058bool CompositeModelEditor::getPositionAndRotationVectors(QString interfacePoint, QGenericMatrix<3,1,double> &CG_X_PHI_CG,
1059 QGenericMatrix<3,1,double> &X_C_PHI_X, QGenericMatrix<3,1,double> &CG_X_R_CG,
1060 QGenericMatrix<3,1,double> &X_C_R_X)
1061{
1062 //Extract submodel and interface names
1063 QString modelName = interfacePoint.split(".").at(0);
1064 QString interfaceName = interfacePoint.split(".").at(1);
1065 //Read positions and rotations from XML
1066 QString x_c_r_x_str, x_c_phi_x_str;
1067 QString cg_x_phi_cg_str, cg_x_r_cg_str;
1068 QDomElement subModelElement = getSubModelElement(modelName);
1069 cg_x_r_cg_str = subModelElement.attribute("Position", "0,0,0");
1070 cg_x_phi_cg_str = subModelElement.attribute("Angle321", "0,0,0");
1071 QDomElement interfaceElement = subModelElement.firstChildElement("InterfacePoint");
1072 while (!interfaceElement.isNull()) {
1073 if (interfaceElement.attribute("Name").compare(interfaceName) == 0) {
1074 x_c_r_x_str = interfaceElement.attribute("Position");
1075 x_c_phi_x_str = interfaceElement.attribute("Angle321");
1076 break;
1077 }
1078 interfaceElement = interfaceElement.nextSiblingElement("InterfacePoint");
1079 }
1080
1081 //Make sure that all vector strings are found in XML
1082 if (cg_x_phi_cg_str.isEmpty() || cg_x_r_cg_str.isEmpty() || x_c_r_x_str.isEmpty() || x_c_phi_x_str.isEmpty()) {
1083 QString msg = tr("Interface coordinates does not exist in xml");
1084 MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::CompositeModel, msg, Helper::scriptingKind,
1085 Helper::errorLevel));
1086 return false;
1087 }
1088
1089 //Convert from strings to arrays
1090 double cg_x_phi_cg[3],x_c_phi_x[3];
1091 double cg_x_r_cg[3],x_c_r_x[3];
1092
1093 cg_x_phi_cg[0] = cg_x_phi_cg_str.split(",")[0].toDouble();
1094 cg_x_phi_cg[1] = cg_x_phi_cg_str.split(",")[1].toDouble();
1095 cg_x_phi_cg[2] = cg_x_phi_cg_str.split(",")[2].toDouble();
1096
1097 x_c_phi_x[0] = x_c_phi_x_str.split(",")[0].toDouble();
1098 x_c_phi_x[1] = x_c_phi_x_str.split(",")[1].toDouble();
1099 x_c_phi_x[2] = x_c_phi_x_str.split(",")[2].toDouble();
1100
1101 cg_x_r_cg[0] = cg_x_r_cg_str.split(",")[0].toDouble();
1102 cg_x_r_cg[1] = cg_x_r_cg_str.split(",")[1].toDouble();
1103 cg_x_r_cg[2] = cg_x_r_cg_str.split(",")[2].toDouble();
1104
1105 x_c_r_x[0] = x_c_r_x_str.split(",")[0].toDouble();
1106 x_c_r_x[1] = x_c_r_x_str.split(",")[1].toDouble();
1107 x_c_r_x[2] = x_c_r_x_str.split(",")[2].toDouble();
1108
1109 //Convert from arrays to Qt matrices
1110 CG_X_PHI_CG = QGenericMatrix<3,1,double>(cg_x_phi_cg); //Rotation of X relative to CG expressed in CG
1111 X_C_PHI_X = QGenericMatrix<3,1,double>(x_c_phi_x); //Rotation of C relative to X expressed in X
1112 CG_X_R_CG = QGenericMatrix<3,1,double>(cg_x_r_cg); //Position of X1 relative to CG expressed in CG
1113 X_C_R_X = QGenericMatrix<3,1,double>(x_c_r_x); //Position of C relative to X expressed in X
1114
1115 return true;
1116}
1117
1118/*!
1119 * \brief CompositeModelEditor::alignInterfaces
1120 * Aligns interface C1 in model X1 to interface C2 in model X2
1121 * \param fromSubModel Full name of first interfae (X1.C1)
1122 * \param toSubModel Full name of second interface (X2.C2)
1123 * \param showError
1124 */
1125void CompositeModelEditor::alignInterfaces(QString fromInterface, QString toInterface, bool showError)
1126{
1127 //Extract rotation and position vectors to Qt matrices
1128 QGenericMatrix<3,1,double> CG_X1_PHI_CG; //Rotation of X1 relative to CG expressed in CG
1129 QGenericMatrix<3,1,double> X1_C1_PHI_X1; //Rotation of C1 relative to X1 expressed in X1
1130 QGenericMatrix<3,1,double> CG_X1_R_CG; //Position of X1 relative to CG expressed in CG
1131 QGenericMatrix<3,1,double> X1_C1_R_X1; //Position of C1 relative to X1 expressed in X1
1132 if(!getPositionAndRotationVectors(fromInterface,CG_X1_PHI_CG, X1_C1_PHI_X1,CG_X1_R_CG,X1_C1_R_X1)) return;
1133
1134 QGenericMatrix<3,1,double> CG_X2_PHI_CG; //Rotation of X2 relative to CG expressed in CG
1135 QGenericMatrix<3,1,double> X2_C2_PHI_X2; //Rotation of C2 relative to X2 expressed in X2
1136 QGenericMatrix<3,1,double> CG_X2_R_CG; //Position of X2 relative to CG expressed in CG
1137 QGenericMatrix<3,1,double> X2_C2_R_X2; //Position of C2 relative to X2 expressed in X2
1138 if(!getPositionAndRotationVectors(toInterface,CG_X2_PHI_CG, X2_C2_PHI_X2,CG_X2_R_CG,X2_C2_R_X2)) return;
1139
1140 QGenericMatrix<3,3,double> R_X2_C2, R_CG_X1, R_CG_X2, R_CG_C2, R_X1_C1;
1141
1142 //Equations from BEAST
1143 R_X2_C2 = Utilities::getRotationMatrix(X2_C2_PHI_X2); //Rotation matrix between X2 and C2
1144 R_CG_X2 = Utilities::getRotationMatrix(CG_X2_PHI_CG); //Rotation matrix between CG and X2
1145 R_CG_C2 = R_X2_C2*R_CG_X2; //Rotation matrix between CG and C2
1146
1147 R_X1_C1 = Utilities::getRotationMatrix(X1_C1_PHI_X1); //Rotation matrix between X1 and C1
1148 R_CG_X1 = R_X1_C1.transposed()*R_CG_C2; //New rotation matrix between CG and X1
1149
1150 //Extract angles from rotation matrix
1151 QGenericMatrix<3,1,double> CG_X1_PHI_CG_new = getRotationVector(R_CG_X1);
1152 // CG_X1_PHI_CG(0,0) = atan2(R_CG_X1(2,1),R_CG_X1(2,2));
1153 // CG_X1_PHI_CG(0,1) = atan2(-R_CG_X1(2,0),sqrt(R_CG_X1(2,1)*R_CG_X1(2,1) + R_CG_X1(2,2)*R_CG_X1(2,2)));
1154 // CG_X1_PHI_CG(0,2) = atan2(R_CG_X1(1,0),R_CG_X1(0,0));
1155
1156 //New position of X1 relative to CG
1157 QGenericMatrix<3,1,double> CG_X1_R_CG_new = CG_X2_R_CG + X2_C2_R_X2*R_CG_X2 - X1_C1_R_X1*R_CG_X1;
1158
1159 // get the relevant connection
1160 LineAnnotation* pFoundConnectionLineAnnotation = 0;
1161 foreach (LineAnnotation* pConnectionLineAnnotation, mpModelWidget->getDiagramGraphicsView()->getConnectionsList())for (auto _container_ = QtPrivate::qMakeForeachContainer(mpModelWidget
->getDiagramGraphicsView()->getConnectionsList()); _container_
.control && _container_.i != _container_.e; ++_container_
.i, _container_.control ^= 1) for (LineAnnotation* pConnectionLineAnnotation
= *_container_.i; _container_.control; _container_.control =
0)
{
1162 if (pConnectionLineAnnotation->getStartComponentName().compare(fromInterface) == 0 &&
1163 pConnectionLineAnnotation->getEndComponentName().compare(toInterface) == 0) {
1164 pFoundConnectionLineAnnotation = pConnectionLineAnnotation;
1165 break;
1166 }
1167 }
1168 // push the align interface to undo stack
1169 mpModelWidget->getUndoStack()->push(new AlignInterfacesCommand(this, fromInterface, toInterface, CG_X1_R_CG, CG_X1_PHI_CG, CG_X1_R_CG_new,
1170 CG_X1_PHI_CG_new, pFoundConnectionLineAnnotation));
1171 mpModelWidget->updateModelText();
1172 // Give error message if alignment failed
1173 if (!interfacesAligned(fromInterface, toInterface)) {
1174 if (showError) {
1175 MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::CompositeModel, tr("Alignment operation failed."),
1176 Helper::scriptingKind, Helper::errorLevel));
1177 }
1178 }
1179}
1180
1181/*!
1182 * \brief CompositeModelEditor::getInterfaceType
1183 * Returns the type of specified interface (e.g. "3D", "Input"...)
1184 * \param pConnectionLineAnnotation
1185 * \return
1186 */
1187int CompositeModelEditor::getInterfaceDimensions(QString interfacePoint)
1188{
1189 //Extract submodel and interface names
1190 QString modelName = interfacePoint.split(".").at(0);
1191 QString interfaceName = interfacePoint.split(".").at(1);
1192
1193 QDomElement subModelElement = getSubModelElement(modelName);
1194 QDomElement interfaceElement = subModelElement.firstChildElement("InterfacePoint");
1195 while (!interfaceElement.isNull()) {
1196 if (interfaceElement.attribute("Name").compare(interfaceName) == 0) {
1197 return interfaceElement.attribute("Dimensions", "3").toInt();
1198 }
1199 interfaceElement = interfaceElement.nextSiblingElement("InterfacePoint");
1200 }
1201 return 3; //Backwards compatibility
1202}
1203
1204QString CompositeModelEditor::getInterfaceCausality(QString interfacePoint)
1205{
1206 //Extract submodel and interface names
1207 QString modelName = interfacePoint.split(".").at(0);
1208 QString interfaceName = interfacePoint.split(".").at(1);
1209
1210 QDomElement subModelElement = getSubModelElement(modelName);
1211 QDomElement interfaceElement = subModelElement.firstChildElement("InterfacePoint");
1212 while (!interfaceElement.isNull()) {
1213 if (interfaceElement.attribute("Name").compare(interfaceName) == 0) {
1214 return interfaceElement.attribute("Causality", StringHandler::getTLMCausality(StringHandler::TLMBidirectional));
1215 }
1216 interfaceElement = interfaceElement.nextSiblingElement("InterfacePoint");
1217 }
1218 return StringHandler::getTLMCausality(StringHandler::TLMBidirectional); //Backwards compatibility
1219}
1220
1221/*!
1222 * \brief CompositeModelEditor::getInterfaceDomain
1223 * Returns the physical domain of specified interface (e.g. "Mechanical", "Hydraulic"...)
1224 * \param pConnectionLineAnnotation
1225 * \return
1226 */
1227QString CompositeModelEditor::getInterfaceDomain(QString interfacePoint)
1228{
1229 //Extract submodel and interface names
1230 QString modelName = interfacePoint.split(".").at(0);
1231 QString interfaceName = interfacePoint.split(".").at(1);
1232
1233 QDomElement subModelElement = getSubModelElement(modelName);
1234 QDomElement interfaceElement = subModelElement.firstChildElement("InterfacePoint");
1235 while (!interfaceElement.isNull()) {
1236 if (interfaceElement.attribute("Name").compare(interfaceName) == 0) {
1237 //Default to mechanical for backwards compatibility
1238 return interfaceElement.attribute("Domain", StringHandler::getTLMDomain(StringHandler::Mechanical));
1239 }
1240 interfaceElement = interfaceElement.nextSiblingElement("InterfacePoint");
1241 }
1242 return StringHandler::getTLMDomain(StringHandler::Mechanical); //Backwards compatibility
1243}
1244
1245/*!
1246 * \brief CompositeModelEditor::fuzzyCompare
1247 * Special implementation of fuzzyCompare. Uses much larger tolerance than built-in qFuzzyCompare()
1248 * \param p1
1249 * \param p2
1250 * \return
1251 */
1252inline__inline__ bool CompositeModelEditor::fuzzyCompare(double p1, double p2)
1253{
1254 //! @todo What tolerance should be used? This is just a random number that seemed to work for some reason.
1255 return (qAbs(p1 - p2) <= qMax(1e-4 * qMin(qAbs(p1), qAbs(p2)),1e-5));
1256}
1257
1258/*!
1259 * \brief CompositeModelEditor::showContextMenu
1260 * Create a context menu.
1261 * \param point
1262 */
1263void CompositeModelEditor::showContextMenu(QPoint point)
1264{
1265 QMenu *pMenu = createStandardContextMenu();
1266 pMenu->exec(mapToGlobal(point));
1267 delete pMenu;
1268}
1269
1270/*!
1271 * \brief CompositeModelEditor::setPlainText
1272 * Reimplementation of QPlainTextEdit::setPlainText method.
1273 * Makes sure we dont update if the passed text is same.
1274 * \param text the string to set.
1275 * \param useInserText
1276 */
1277void CompositeModelEditor::setPlainText(const QString &text, bool useInserText)
1278{
1279 if (text != mpPlainTextEdit->toPlainText()) {
1280 mForceSetPlainText = true;
1281 mXmlDocument.setContent(text);
1282 updateAllOrientations();
1283 // use the text from mXmlDocument so that we can map error to line numbers. We don't care about users formatting in the file.
1284 if (!useInserText) {
1285 mpPlainTextEdit->setPlainText(mXmlDocument.toString());
1286 } else {
1287 QTextCursor textCursor (mpPlainTextEdit->document());
1288 textCursor.beginEditBlock();
1289 textCursor.select(QTextCursor::Document);
1290 textCursor.insertText(mXmlDocument.toString());
1291 textCursor.endEditBlock();
1292 mpPlainTextEdit->setTextCursor(textCursor);
1293 }
1294 mForceSetPlainText = false;
1295 mLastValidText = text;
1296 }
1297}
1298
1299/*!
1300 * \brief CompositeModelEditor::contentsHasChanged
1301 * Slot activated when CompositeModelEditor's QTextDocument contentsChanged SIGNAL is raised.\n
1302 * Sets the model as modified so that user knows that his current CompositeModel is not saved.
1303 * \param position
1304 * \param charsRemoved
1305 * \param charsAdded
1306 */
1307void CompositeModelEditor::contentsHasChanged(int position, int charsRemoved, int charsAdded)
1308{
1309 Q_UNUSED(position)(void)position;;
1310 if (mpModelWidget->isVisible()) {
1311 if (charsRemoved == 0 && charsAdded == 0) {
1312 return;
1313 }
1314 /* if user is changing the read only file. */
1315 if (mpModelWidget->getLibraryTreeItem()->isReadOnly() && !mForceSetPlainText) {
1316 /* if user is changing the read-only class. */
1317 mpInfoBar->showMessage(tr("<b>Warning: </b>You are changing a read-only class."));
1318 } else {
1319 /* if user is changing, the normal file. */
1320 if (!mForceSetPlainText) {
1321 mpModelWidget->setWindowTitle(QString(mpModelWidget->getLibraryTreeItem()->getName()).append("*"));
1322 mpModelWidget->getLibraryTreeItem()->setIsSaved(false);
1323 MainWindow::instance()->getLibraryWidget()->getLibraryTreeModel()->updateLibraryTreeItem(mpModelWidget->getLibraryTreeItem());
1324 mTextChanged = true;
1325 }
1326 }
1327 }
1328}
1329
1330//! @class CompositeModelHighlighter
1331//! @brief A syntax highlighter for CompositeModelEditor.
1332
1333//! Constructor
1334CompositeModelHighlighter::CompositeModelHighlighter(CompositeModelEditorPage *pCompositeModelEditorPage, QPlainTextEdit *pPlainTextEdit)
1335 : QSyntaxHighlighter(pPlainTextEdit->document())
1336{
1337 mpCompositeModelEditorPage = pCompositeModelEditorPage;
1338 mpPlainTextEdit = pPlainTextEdit;
1339 initializeSettings();
1340}
1341
1342//! Initialized the syntax highlighter with default values.
1343void CompositeModelHighlighter::initializeSettings()
1344{
1345 QFont font;
1346 font.setFamily(mpCompositeModelEditorPage->getOptionsDialog()->getTextEditorPage()->getFontFamilyComboBox()->currentFont().family());
1347 font.setPointSizeF(mpCompositeModelEditorPage->getOptionsDialog()->getTextEditorPage()->getFontSizeSpinBox()->value());
1348 mpPlainTextEdit->document()->setDefaultFont(font);
1349 mpPlainTextEdit->setTabStopWidth(mpCompositeModelEditorPage->getOptionsDialog()->getTextEditorPage()->getTabSizeSpinBox()->value() * QFontMetrics(font).width(QLatin1Char(' ')));
1350 // set color highlighting
1351 mHighlightingRules.clear();
1352 HighlightingRule rule;
1353 mTextFormat.setForeground(mpCompositeModelEditorPage->getColor("Text"));
1354 mTagFormat.setForeground(mpCompositeModelEditorPage->getColor("Tag"));
1355 mElementFormat.setForeground(mpCompositeModelEditorPage->getColor("Element"));
1356 mCommentFormat.setForeground(mpCompositeModelEditorPage->getColor("Comment"));
1357 mQuotationFormat.setForeground(QColor(mpCompositeModelEditorPage->getColor("Quotes")));
1358
1359 rule.mPattern = QRegExp("\\b[A-Za-z_][A-Za-z0-9_]*");
1360 rule.mFormat = mTextFormat;
1361 mHighlightingRules.append(rule);
1362
1363 // CompositeModel Tags
1364 QStringList compositeModelTags;
1365 compositeModelTags << "<\\?"
1366 << "<"
1367 << "</"
1368 << "\\?>"
1369 << ">"
1370 << "/>";
1371 foreach (const QString &compositeModelTag, compositeModelTags)for (auto _container_ = QtPrivate::qMakeForeachContainer(compositeModelTags
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (const QString
&compositeModelTag = *_container_.i; _container_.control
; _container_.control = 0)
{
1372 rule.mPattern = QRegExp(compositeModelTag);
1373 rule.mFormat = mTagFormat;
1374 mHighlightingRules.append(rule);
1375 }
1376
1377 // CompositeModel Elements
1378 QStringList elementPatterns;
1379 elementPatterns << "\\bxml\\b"
1380 << "\\bModel\\b"
1381 << "\\bAnnotations\\b"
1382 << "\\bAnnotation\\b"
1383 << "\\bSubModels\\b"
1384 << "\\bSubModel\\b"
1385 << "\\bInterfacePoint\\b"
1386 << "\\bParameter\\b"
1387 << "\\bConnections\\b"
1388 << "\\bConnection\\b"
1389 << "\\bLines\\b"
1390 << "\\bLine\\b"
1391 << "\\bSimulationParams\\b";
1392 foreach (const QString &elementPattern, elementPatterns)for (auto _container_ = QtPrivate::qMakeForeachContainer(elementPatterns
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (const QString
&elementPattern = *_container_.i; _container_.control; _container_
.control = 0)
1393 {
1394 rule.mPattern = QRegExp(elementPattern);
1395 rule.mFormat = mElementFormat;
1396 mHighlightingRules.append(rule);
1397 }
1398
1399 // CompositeModel Comments
1400 mCommentStartExpression = QRegExp("<!--");
1401 mCommentEndExpression = QRegExp("-->");
1402}
1403
1404/*!
1405 Highlights the multilines text.\n
1406 Quoted text.
1407 */
1408void CompositeModelHighlighter::highlightMultiLine(const QString &text)
1409{
1410 int index = 0, startIndex = 0;
1411 int blockState = previousBlockState();
1412 // fprintf(stderr, "%s with blockState %d\n", text.toStdString().c_str(), blockState);
1413
1414 while (index < text.length())
1415 {
1416 switch (blockState) {
1417 case 2:
1418 if (text[index] == '-' &&
1419 index+1<text.length() && text[index+1] == '-' &&
1420 index+2<text.length() && text[index+2] == '>') {
1421 index = index+2;
1422 setFormat(startIndex, index-startIndex+1, mCommentFormat);
1423 blockState = 0;
1424 }
1425 break;
1426 case 3:
1427 if (text[index] == '\\') {
1428 index++;
1429 } else if (text[index] == '"') {
1430 setFormat(startIndex, index-startIndex+1, mQuotationFormat);
1431 blockState = 0;
1432 }
1433 break;
1434 default:
1435 if (text[index] == '<' &&
1436 index+1<text.length() && text[index+1] == '!' &&
1437 index+2<text.length() && text[index+2] == '-' &&
1438 index+3<text.length() && text[index+3] == '-') {
1439 startIndex = index;
1440 blockState = 2;
1441 } else if (text[index] == '"') {
1442 startIndex = index;
1443 blockState = 3;
1444 }
1445 }
1446 index++;
1447 }
1448 switch (blockState) {
1449 case 2:
1450 setFormat(startIndex, text.length()-startIndex, mCommentFormat);
1451 setCurrentBlockState(2);
1452 break;
1453 case 3:
1454 setFormat(startIndex, text.length()-startIndex, mQuotationFormat);
1455 setCurrentBlockState(3);
1456 break;
1457 }
1458}
1459
1460//! Reimplementation of QSyntaxHighlighter::highlightBlock
1461void CompositeModelHighlighter::highlightBlock(const QString &text)
1462{
1463 /* Only highlight the text if user has enabled the syntax highlighting */
1464 if (!mpCompositeModelEditorPage->getOptionsDialog()->getTextEditorPage()->getSyntaxHighlightingGroupBox()->isChecked()) {
1465 return;
1466 }
1467 // set text block state
1468 setCurrentBlockState(0);
1469 setFormat(0, text.length(), mpCompositeModelEditorPage->getColor("Text"));
1470 foreach (const HighlightingRule &rule, mHighlightingRules)for (auto _container_ = QtPrivate::qMakeForeachContainer(mHighlightingRules
); _container_.control && _container_.i != _container_
.e; ++_container_.i, _container_.control ^= 1) for (const HighlightingRule
&rule = *_container_.i; _container_.control; _container_
.control = 0)
{
1471 QRegExp expression(rule.mPattern);
1472 int index = expression.indexIn(text);
1473 while (index >= 0) {
1474 int length = expression.matchedLength();
1475 setFormat(index, length, rule.mFormat);
1476 index = expression.indexIn(text, index + length);
1477 }
1478 }
1479 highlightMultiLine(text);
1480}
1481
1482//! Slot activated whenever ModelicaEditor text settings changes.
1483void CompositeModelHighlighter::settingsChanged()
1484{
1485 initializeSettings();
1486 rehighlight();
1487}