Commit 222f8947 authored by Jochen Becher's avatar Jochen Becher

ModelEditor: Avoid chrashes if model is broken

Add some debugging code checking integrity of diagrams. Based on the
analysis avoid chrashes if ends of relations on diagrams are gone.

Change-Id: I86da4a6d422de5d51e551b44e7842e992590958c
Reviewed-by: Tobias Hunger's avatarTobias Hunger <tobias.hunger@qt.io>
parent 36e7f454
......@@ -46,6 +46,8 @@
#include "qmt/model/mdiagram.h"
#include "qmt/model/mrelation.h"
#include <QDebug>
namespace qmt {
class DiagramController::Clone
......@@ -166,6 +168,7 @@ private:
emit diagramController->endUpdateElement(row, diagram);
}
diagramController->diagramModified(diagram);
diagramController->verifyDiagramsIntegrity();
}
DiagramController::UpdateAction m_updateAction = DiagramController::UpdateMajor;
......@@ -208,6 +211,7 @@ protected:
}
if (removed)
diagramController->diagramModified(diagram);
diagramController->verifyDiagramsIntegrity();
}
void insert()
......@@ -227,6 +231,7 @@ protected:
}
if (inserted)
diagramController->diagramModified(diagram);
diagramController->verifyDiagramsIntegrity();
}
QList<DiagramController::Clone> m_clonedElements;
......@@ -398,6 +403,7 @@ void DiagramController::addElement(DElement *element, MDiagram *diagram)
diagram->addDiagramElement(element);
emit endInsertElement(row, diagram);
diagramModified(diagram);
verifyDiagramsIntegrity();
}
void DiagramController::removeElement(DElement *element, MDiagram *diagram)
......@@ -413,6 +419,7 @@ void DiagramController::removeElement(DElement *element, MDiagram *diagram)
diagram->removeDiagramElement(element);
emit endRemoveElement(row, diagram);
diagramModified(diagram);
verifyDiagramsIntegrity();
}
DElement *DiagramController::findElement(const Uid &key, const MDiagram *diagram) const
......@@ -452,6 +459,7 @@ void DiagramController::finishUpdateElement(DElement *element, MDiagram *diagram
emit endUpdateElement(diagram->diagramElements().indexOf(element), diagram);
if (!cancelled)
diagramModified(diagram);
verifyDiagramsIntegrity();
}
void DiagramController::breakUndoChain()
......@@ -540,6 +548,7 @@ void DiagramController::pasteElements(const DContainer &diagramContainer, MDiagr
diagramModified(diagram);
if (m_undoController)
m_undoController->endMergeSequence();
verifyDiagramsIntegrity();
}
void DiagramController::deleteElements(const DSelection &diagramSelection, MDiagram *diagram)
......@@ -570,6 +579,7 @@ void DiagramController::onEndResetModel()
updateElementFromModel(element, diagram, false);
}
emit endResetAllDiagrams();
verifyDiagramsIntegrity();
}
void DiagramController::onBeginUpdateObject(int row, const MObject *parent)
......@@ -601,6 +611,7 @@ void DiagramController::onEndUpdateObject(int row, const MObject *parent)
}
}
}
verifyDiagramsIntegrity();
}
void DiagramController::onBeginInsertObject(int row, const MObject *owner)
......@@ -618,6 +629,7 @@ void DiagramController::onEndInsertObject(int row, const MObject *owner)
QMT_CHECK(!m_allDiagrams.contains(modelDiagram));
m_allDiagrams.append(modelDiagram);
}
verifyDiagramsIntegrity();
}
void DiagramController::onBeginRemoveObject(int row, const MObject *parent)
......@@ -654,6 +666,7 @@ void DiagramController::onEndMoveObject(int row, const MObject *owner)
updateElementFromModel(diagramElement, modelDiagram, false);
emit endResetDiagram(modelDiagram);
}
verifyDiagramsIntegrity();
}
void DiagramController::onBeginUpdateRelation(int row, const MObject *owner)
......@@ -673,6 +686,7 @@ void DiagramController::onEndUpdateRelation(int row, const MObject *owner)
updateElementFromModel(relation, diagram, true);
}
}
verifyDiagramsIntegrity();
}
void DiagramController::onBeginRemoveRelation(int row, const MObject *owner)
......@@ -733,6 +747,7 @@ void DiagramController::deleteElements(const DSelection &diagramSelection, MDiag
diagramModified(diagram);
if (m_undoController)
m_undoController->endMergeSequence();
verifyDiagramsIntegrity();
}
DElement *DiagramController::findElementOnAnyDiagram(const Uid &uid)
......@@ -772,6 +787,7 @@ void DiagramController::removeObjects(MObject *modelObject)
removeElement(element, diagram);
}
}
verifyDiagramsIntegrity();
}
void DiagramController::removeRelations(MRelation *modelRelation)
......@@ -781,6 +797,7 @@ void DiagramController::removeRelations(MRelation *modelRelation)
if (diagramElement)
removeElement(diagramElement, diagram);
}
verifyDiagramsIntegrity();
}
void DiagramController::removeRelations(DElement *element, MDiagram *diagram)
......@@ -795,6 +812,7 @@ void DiagramController::removeRelations(DElement *element, MDiagram *diagram)
}
}
}
verifyDiagramsIntegrity();
}
}
......@@ -847,6 +865,7 @@ void DiagramController::updateElementFromModel(DElement *element, const MDiagram
} else {
melement->accept(&visitor);
}
verifyDiagramsIntegrity();
}
void DiagramController::diagramModified(MDiagram *diagram)
......@@ -897,4 +916,51 @@ void DiagramController::updateAllDiagramsList()
}
}
void DiagramController::verifyDiagramsIntegrity()
{
static const bool debugDiagramsIntegrity = false;
if (debugDiagramsIntegrity) {
QList<MDiagram *> allDiagrams;
if (m_modelController && m_modelController->rootPackage()) {
FindDiagramsVisitor visitor(&allDiagrams);
m_modelController->rootPackage()->accept(&visitor);
}
QMT_CHECK(allDiagrams == m_allDiagrams);
foreach (const MDiagram *diagram, allDiagrams)
verifyDiagramIntegrity(diagram);
}
}
void DiagramController::verifyDiagramIntegrity(const MDiagram *diagram)
{
QHash<Uid, const DElement *> delementsMap;
foreach (const DElement *delement, diagram->diagramElements()) {
delementsMap.insert(delement->uid(), delement);
if (dynamic_cast<const DObject *>(delement) != 0 || dynamic_cast<const DRelation *>(delement) != 0) {
QMT_CHECK(delement->modelUid().isValid());
QMT_CHECK(m_modelController->findElement(delement->modelUid()) != 0);
if (!delement->modelUid().isValid() || m_modelController->findElement(delement->modelUid()) == 0) {
if (const DObject *dobject = dynamic_cast<const DObject *>(delement))
qWarning() << "Diagram" << diagram->name() << diagram->uid().toString() << ": object" << dobject->name() << dobject->uid().toString() << "has invalid reference to model element.";
else if (const DRelation *drelation = dynamic_cast<const DRelation *>(delement))
qWarning() << "Diagram" << diagram->name() << diagram->uid().toString() << ": relation" << drelation->uid().toString() << "has invalid refeference to model element.";
}
} else {
QMT_CHECK(!delement->modelUid().isValid());
}
}
foreach (const DElement *delement, diagram->diagramElements()) {
if (const DRelation *drelation = dynamic_cast<const DRelation *>(delement)) {
QMT_CHECK(drelation->endAUid().isValid());
QMT_CHECK(delementsMap.contains(drelation->endAUid()));
if (!drelation->endAUid().isValid() || !delementsMap.contains(drelation->endAUid()))
qWarning() << "Diagram" << diagram->name() << diagram->uid().toString() << ": relation" << drelation->uid().toString() << "has invalid end A.";
QMT_CHECK(drelation->endBUid().isValid());
QMT_CHECK(delementsMap.contains(drelation->endBUid()));
if (!drelation->endBUid().isValid() || !delementsMap.contains(drelation->endBUid()))
qWarning() << "Diagram" << diagram->name() << diagram->uid().toString() << ": relation" << drelation->uid().toString() << "has invalid end B.";
}
}
}
} // namespace qmt
......@@ -163,6 +163,9 @@ private:
void updateAllDiagramsList();
void verifyDiagramsIntegrity();
void verifyDiagramIntegrity(const MDiagram *diagram);
ModelController *m_modelController;
UndoController *m_undoController;
QList<MDiagram *> m_allDiagrams;
......
......@@ -814,7 +814,7 @@ void DiagramSceneModel::onSelectionChanged()
QMT_CHECK(endBObject);
QGraphicsItem *endBItem = m_elementToItemMap.value(endBObject);
QMT_CHECK(endBItem);
if (!relationItem->isSelected()
if (relationItem && !relationItem->isSelected()
&& (m_selectedItems.contains(endAItem) || newSecondarySelectedItems.contains(endAItem))
&& (m_selectedItems.contains(endBItem) || newSecondarySelectedItems.contains(endBItem))) {
QMT_CHECK(!m_selectedItems.contains(relationItem));
......
......@@ -68,14 +68,17 @@ public:
{
DObject *baseObject = m_diagramSceneModel->diagramController()->findElement<DObject>(inheritance->base(), m_diagramSceneModel->diagram());
QMT_CHECK(baseObject);
bool baseIsInterface = baseObject->stereotypes().contains(QStringLiteral("interface"));
bool baseIsInterface = false;
bool lollipopDisplay = false;
if (baseIsInterface) {
StereotypeDisplayVisitor stereotypeDisplayVisitor;
stereotypeDisplayVisitor.setModelController(m_diagramSceneModel->diagramSceneController()->modelController());
stereotypeDisplayVisitor.setStereotypeController(m_diagramSceneModel->stereotypeController());
baseObject->accept(&stereotypeDisplayVisitor);
lollipopDisplay = stereotypeDisplayVisitor.stereotypeDisplay() == DObject::StereotypeIcon;
if (baseObject) {
baseIsInterface = baseObject->stereotypes().contains(QStringLiteral("interface"));
if (baseIsInterface) {
StereotypeDisplayVisitor stereotypeDisplayVisitor;
stereotypeDisplayVisitor.setModelController(m_diagramSceneModel->diagramSceneController()->modelController());
stereotypeDisplayVisitor.setStereotypeController(m_diagramSceneModel->stereotypeController());
baseObject->accept(&stereotypeDisplayVisitor);
lollipopDisplay = stereotypeDisplayVisitor.stereotypeDisplay() == DObject::StereotypeIcon;
}
}
if (lollipopDisplay) {
m_arrow->setShaft(ArrowItem::ShaftSolid);
......@@ -484,7 +487,8 @@ QPointF RelationItem::calcEndPoint(const Uid &end, const Uid &otherEnd, int near
} else {
DObject *endOtherObject = m_diagramSceneModel->diagramController()->findElement<DObject>(otherEnd, m_diagramSceneModel->diagram());
QMT_CHECK(endOtherObject);
otherEndPos = endOtherObject->pos();
if (endOtherObject)
otherEndPos = endOtherObject->pos();
}
return calcEndPoint(end, otherEndPos, nearestIntermediatePointIndex);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment