forked from qt-creator/qt-creator
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 <tobias.hunger@qt.io>
This commit is contained in:
@@ -46,6 +46,8 @@
|
|||||||
#include "qmt/model/mdiagram.h"
|
#include "qmt/model/mdiagram.h"
|
||||||
#include "qmt/model/mrelation.h"
|
#include "qmt/model/mrelation.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
namespace qmt {
|
namespace qmt {
|
||||||
|
|
||||||
class DiagramController::Clone
|
class DiagramController::Clone
|
||||||
@@ -166,6 +168,7 @@ private:
|
|||||||
emit diagramController->endUpdateElement(row, diagram);
|
emit diagramController->endUpdateElement(row, diagram);
|
||||||
}
|
}
|
||||||
diagramController->diagramModified(diagram);
|
diagramController->diagramModified(diagram);
|
||||||
|
diagramController->verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagramController::UpdateAction m_updateAction = DiagramController::UpdateMajor;
|
DiagramController::UpdateAction m_updateAction = DiagramController::UpdateMajor;
|
||||||
@@ -208,6 +211,7 @@ protected:
|
|||||||
}
|
}
|
||||||
if (removed)
|
if (removed)
|
||||||
diagramController->diagramModified(diagram);
|
diagramController->diagramModified(diagram);
|
||||||
|
diagramController->verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert()
|
void insert()
|
||||||
@@ -227,6 +231,7 @@ protected:
|
|||||||
}
|
}
|
||||||
if (inserted)
|
if (inserted)
|
||||||
diagramController->diagramModified(diagram);
|
diagramController->diagramModified(diagram);
|
||||||
|
diagramController->verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<DiagramController::Clone> m_clonedElements;
|
QList<DiagramController::Clone> m_clonedElements;
|
||||||
@@ -398,6 +403,7 @@ void DiagramController::addElement(DElement *element, MDiagram *diagram)
|
|||||||
diagram->addDiagramElement(element);
|
diagram->addDiagramElement(element);
|
||||||
emit endInsertElement(row, diagram);
|
emit endInsertElement(row, diagram);
|
||||||
diagramModified(diagram);
|
diagramModified(diagram);
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::removeElement(DElement *element, MDiagram *diagram)
|
void DiagramController::removeElement(DElement *element, MDiagram *diagram)
|
||||||
@@ -413,6 +419,7 @@ void DiagramController::removeElement(DElement *element, MDiagram *diagram)
|
|||||||
diagram->removeDiagramElement(element);
|
diagram->removeDiagramElement(element);
|
||||||
emit endRemoveElement(row, diagram);
|
emit endRemoveElement(row, diagram);
|
||||||
diagramModified(diagram);
|
diagramModified(diagram);
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
DElement *DiagramController::findElement(const Uid &key, const MDiagram *diagram) const
|
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);
|
emit endUpdateElement(diagram->diagramElements().indexOf(element), diagram);
|
||||||
if (!cancelled)
|
if (!cancelled)
|
||||||
diagramModified(diagram);
|
diagramModified(diagram);
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::breakUndoChain()
|
void DiagramController::breakUndoChain()
|
||||||
@@ -540,6 +548,7 @@ void DiagramController::pasteElements(const DContainer &diagramContainer, MDiagr
|
|||||||
diagramModified(diagram);
|
diagramModified(diagram);
|
||||||
if (m_undoController)
|
if (m_undoController)
|
||||||
m_undoController->endMergeSequence();
|
m_undoController->endMergeSequence();
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::deleteElements(const DSelection &diagramSelection, MDiagram *diagram)
|
void DiagramController::deleteElements(const DSelection &diagramSelection, MDiagram *diagram)
|
||||||
@@ -570,6 +579,7 @@ void DiagramController::onEndResetModel()
|
|||||||
updateElementFromModel(element, diagram, false);
|
updateElementFromModel(element, diagram, false);
|
||||||
}
|
}
|
||||||
emit endResetAllDiagrams();
|
emit endResetAllDiagrams();
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::onBeginUpdateObject(int row, const MObject *parent)
|
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)
|
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));
|
QMT_CHECK(!m_allDiagrams.contains(modelDiagram));
|
||||||
m_allDiagrams.append(modelDiagram);
|
m_allDiagrams.append(modelDiagram);
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::onBeginRemoveObject(int row, const MObject *parent)
|
void DiagramController::onBeginRemoveObject(int row, const MObject *parent)
|
||||||
@@ -654,6 +666,7 @@ void DiagramController::onEndMoveObject(int row, const MObject *owner)
|
|||||||
updateElementFromModel(diagramElement, modelDiagram, false);
|
updateElementFromModel(diagramElement, modelDiagram, false);
|
||||||
emit endResetDiagram(modelDiagram);
|
emit endResetDiagram(modelDiagram);
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::onBeginUpdateRelation(int row, const MObject *owner)
|
void DiagramController::onBeginUpdateRelation(int row, const MObject *owner)
|
||||||
@@ -673,6 +686,7 @@ void DiagramController::onEndUpdateRelation(int row, const MObject *owner)
|
|||||||
updateElementFromModel(relation, diagram, true);
|
updateElementFromModel(relation, diagram, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::onBeginRemoveRelation(int row, const MObject *owner)
|
void DiagramController::onBeginRemoveRelation(int row, const MObject *owner)
|
||||||
@@ -733,6 +747,7 @@ void DiagramController::deleteElements(const DSelection &diagramSelection, MDiag
|
|||||||
diagramModified(diagram);
|
diagramModified(diagram);
|
||||||
if (m_undoController)
|
if (m_undoController)
|
||||||
m_undoController->endMergeSequence();
|
m_undoController->endMergeSequence();
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
DElement *DiagramController::findElementOnAnyDiagram(const Uid &uid)
|
DElement *DiagramController::findElementOnAnyDiagram(const Uid &uid)
|
||||||
@@ -772,6 +787,7 @@ void DiagramController::removeObjects(MObject *modelObject)
|
|||||||
removeElement(element, diagram);
|
removeElement(element, diagram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::removeRelations(MRelation *modelRelation)
|
void DiagramController::removeRelations(MRelation *modelRelation)
|
||||||
@@ -781,6 +797,7 @@ void DiagramController::removeRelations(MRelation *modelRelation)
|
|||||||
if (diagramElement)
|
if (diagramElement)
|
||||||
removeElement(diagramElement, diagram);
|
removeElement(diagramElement, diagram);
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::removeRelations(DElement *element, MDiagram *diagram)
|
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 {
|
} else {
|
||||||
melement->accept(&visitor);
|
melement->accept(&visitor);
|
||||||
}
|
}
|
||||||
|
verifyDiagramsIntegrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagramController::diagramModified(MDiagram *diagram)
|
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
|
} // namespace qmt
|
||||||
|
@@ -163,6 +163,9 @@ private:
|
|||||||
|
|
||||||
void updateAllDiagramsList();
|
void updateAllDiagramsList();
|
||||||
|
|
||||||
|
void verifyDiagramsIntegrity();
|
||||||
|
void verifyDiagramIntegrity(const MDiagram *diagram);
|
||||||
|
|
||||||
ModelController *m_modelController;
|
ModelController *m_modelController;
|
||||||
UndoController *m_undoController;
|
UndoController *m_undoController;
|
||||||
QList<MDiagram *> m_allDiagrams;
|
QList<MDiagram *> m_allDiagrams;
|
||||||
|
@@ -814,7 +814,7 @@ void DiagramSceneModel::onSelectionChanged()
|
|||||||
QMT_CHECK(endBObject);
|
QMT_CHECK(endBObject);
|
||||||
QGraphicsItem *endBItem = m_elementToItemMap.value(endBObject);
|
QGraphicsItem *endBItem = m_elementToItemMap.value(endBObject);
|
||||||
QMT_CHECK(endBItem);
|
QMT_CHECK(endBItem);
|
||||||
if (!relationItem->isSelected()
|
if (relationItem && !relationItem->isSelected()
|
||||||
&& (m_selectedItems.contains(endAItem) || newSecondarySelectedItems.contains(endAItem))
|
&& (m_selectedItems.contains(endAItem) || newSecondarySelectedItems.contains(endAItem))
|
||||||
&& (m_selectedItems.contains(endBItem) || newSecondarySelectedItems.contains(endBItem))) {
|
&& (m_selectedItems.contains(endBItem) || newSecondarySelectedItems.contains(endBItem))) {
|
||||||
QMT_CHECK(!m_selectedItems.contains(relationItem));
|
QMT_CHECK(!m_selectedItems.contains(relationItem));
|
||||||
|
@@ -68,14 +68,17 @@ public:
|
|||||||
{
|
{
|
||||||
DObject *baseObject = m_diagramSceneModel->diagramController()->findElement<DObject>(inheritance->base(), m_diagramSceneModel->diagram());
|
DObject *baseObject = m_diagramSceneModel->diagramController()->findElement<DObject>(inheritance->base(), m_diagramSceneModel->diagram());
|
||||||
QMT_CHECK(baseObject);
|
QMT_CHECK(baseObject);
|
||||||
bool baseIsInterface = baseObject->stereotypes().contains(QStringLiteral("interface"));
|
bool baseIsInterface = false;
|
||||||
bool lollipopDisplay = false;
|
bool lollipopDisplay = false;
|
||||||
if (baseIsInterface) {
|
if (baseObject) {
|
||||||
StereotypeDisplayVisitor stereotypeDisplayVisitor;
|
baseIsInterface = baseObject->stereotypes().contains(QStringLiteral("interface"));
|
||||||
stereotypeDisplayVisitor.setModelController(m_diagramSceneModel->diagramSceneController()->modelController());
|
if (baseIsInterface) {
|
||||||
stereotypeDisplayVisitor.setStereotypeController(m_diagramSceneModel->stereotypeController());
|
StereotypeDisplayVisitor stereotypeDisplayVisitor;
|
||||||
baseObject->accept(&stereotypeDisplayVisitor);
|
stereotypeDisplayVisitor.setModelController(m_diagramSceneModel->diagramSceneController()->modelController());
|
||||||
lollipopDisplay = stereotypeDisplayVisitor.stereotypeDisplay() == DObject::StereotypeIcon;
|
stereotypeDisplayVisitor.setStereotypeController(m_diagramSceneModel->stereotypeController());
|
||||||
|
baseObject->accept(&stereotypeDisplayVisitor);
|
||||||
|
lollipopDisplay = stereotypeDisplayVisitor.stereotypeDisplay() == DObject::StereotypeIcon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (lollipopDisplay) {
|
if (lollipopDisplay) {
|
||||||
m_arrow->setShaft(ArrowItem::ShaftSolid);
|
m_arrow->setShaft(ArrowItem::ShaftSolid);
|
||||||
@@ -484,7 +487,8 @@ QPointF RelationItem::calcEndPoint(const Uid &end, const Uid &otherEnd, int near
|
|||||||
} else {
|
} else {
|
||||||
DObject *endOtherObject = m_diagramSceneModel->diagramController()->findElement<DObject>(otherEnd, m_diagramSceneModel->diagram());
|
DObject *endOtherObject = m_diagramSceneModel->diagramController()->findElement<DObject>(otherEnd, m_diagramSceneModel->diagram());
|
||||||
QMT_CHECK(endOtherObject);
|
QMT_CHECK(endOtherObject);
|
||||||
otherEndPos = endOtherObject->pos();
|
if (endOtherObject)
|
||||||
|
otherEndPos = endOtherObject->pos();
|
||||||
}
|
}
|
||||||
return calcEndPoint(end, otherEndPos, nearestIntermediatePointIndex);
|
return calcEndPoint(end, otherEndPos, nearestIntermediatePointIndex);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user