AbstractCommand *NodeElement::changeParentCommand(const Id &newParent, const QPointF &position) const { EditorViewScene *evScene = dynamic_cast<EditorViewScene *>(scene()); Element *oldParentElem = dynamic_cast<Element *>(parentItem()); const Id oldParent = oldParentElem ? oldParentElem->id() : evScene->rootItemId(); if (oldParent == newParent) { return nullptr; } const QPointF oldPos = mResizeCommand ? mResizeCommand->geometryBeforeDrag().topLeft() : mPos; const QPointF oldScenePos = oldParentElem ? oldParentElem->mapToScene(oldPos) : oldPos; // Without pre-translating into new position parent gets wrong child coords // when redo happens and resizes when he doesn`t need it. // So we mush pre-translate child into new scene position first, but when // it lays in some container it also resizes. So we need to change parent to // root, then translate into a new position and change parent to a new one. // Also that element itself doesn`t change position in change parent command // so using translation command ChangeParentCommand *changeParentToSceneCommand = new ChangeParentCommand(mLogicalAssistApi, mGraphicalAssistApi, false , id(), oldParent, evScene->rootItemId(), oldPos, oldScenePos); AbstractCommand *translateCommand = ResizeCommand::create(this, mContents , position, mContents, oldScenePos); ChangeParentCommand *result = new ChangeParentCommand( mLogicalAssistApi, mGraphicalAssistApi, false , id(), evScene->rootItemId(), newParent, position, position); result->addPreAction(changeParentToSceneCommand); result->addPreAction(translateCommand); return result; }
void NodeElement::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (dynamic_cast<NodeElement *>(scene()->mouseGrabberItem()) == this) { ungrabMouse(); } if (event->button() == Qt::RightButton) { event->accept(); return; } deleteGuides(); storeGeometry(); if (scene() && (scene()->selectedItems().size() == 1) && isSelected()) { setVisibleEmbeddedLinkers(true); } if (mDragState == None) { Element::mouseReleaseEvent(event); } EditorViewScene *evScene = dynamic_cast<EditorViewScene *>(scene()); commands::InsertIntoEdgeCommand *insertCommand = new commands::InsertIntoEdgeCommand( *evScene, mModels, id(), id(), Id::rootId(), event->scenePos(), boundingRect().bottomRight(), false); bool shouldProcessResize = true; // we should use mHighlightedNode to determine if there is a highlighted node // insert current element into them and set mHighlightedNode to nullptr // but because of mouseRelease twice triggering we can't do it // This may cause more bugs if (flags() & ItemIsMovable) { if (mHighlightedNode) { NodeElement *newParent = mHighlightedNode; Element *insertBefore = mHighlightedNode->getPlaceholderNextElement(); mHighlightedNode->erasePlaceholder(false); // commented because of bug with double event sending (see #204) // mHighlightedNode = nullptr; QPointF newPos = mapToItem(newParent, mapFromScene(scenePos())); AbstractCommand *parentCommand = changeParentCommand(newParent->id(), newPos); mController->execute(parentCommand); // Position change already processed in change parent command shouldProcessResize = parentCommand == nullptr; setPos(newPos); if (insertBefore) { mGraphicalAssistApi.stackBefore(id(), insertBefore->id()); } newParent->resize(); while (newParent) { newParent->mContents = newParent->mContents.normalized(); newParent->storeGeometry(); newParent = dynamic_cast<NodeElement*>(newParent->parentItem()); } } else { AbstractCommand *parentCommand = changeParentCommand(evScene->rootItemId(), scenePos()); mController->execute(parentCommand); // Position change already processed in change parent command shouldProcessResize = parentCommand == nullptr; } } for (EdgeElement* edge : mEdgeList) { edge->layOut(); if (SettingsManager::value("ActivateGrid").toBool()) { edge->alignToGrid(); } } if (shouldProcessResize && mResizeCommand) { mResizeCommand->addPostAction(insertCommand); endResize(); } updateBySelection(); mDragState = None; }