Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fbp 325 improved cascade handling #362

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class KeyboardEventHandler(private val project: Project, private val canvas: Can
KeyEvent.VK_DOWN -> canvas.dragCanvas(start, Point2D.Float(0.0f, -step))
KeyEvent.VK_LEFT -> canvas.dragCanvas(start, Point2D.Float(step, 0.0f))
KeyEvent.VK_RIGHT -> canvas.dragCanvas(start, Point2D.Float(-step, 0.0f))
KeyEvent.VK_DELETE -> currentRemoveActionHandler(project).deleteElem()
KeyEvent.VK_DELETE -> currentRemoveActionHandler(project).deleteSelectedElements()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.valb3r.bpmn.intellij.plugin.core.actions

import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.Event
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.PropertyUpdateWithId
import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState

fun removeElements(state: RenderState, diagramElementIds: List<Any>): List<Event> {
val toDelete = mutableListOf<Event>()
toDelete += diagramElementIds.mapNotNull { state.elemMap[it] }.flatMap {
val elemRemoval = it.getEventsToElementWithItsDiagram()
return@flatMap elemRemoval.diagram + elemRemoval.bpmn + elemRemoval.other
}
val inOrder = toDelete.sortedBy {
when (it) {
is PropertyUpdateWithId -> return@sortedBy 0
else -> return@sortedBy 100
}
}
return inOrder
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.valb3r.bpmn.intellij.plugin.core.actions

import com.intellij.openapi.project.Project
import com.valb3r.bpmn.intellij.plugin.core.events.BpmnElementRemovedEvent
import com.valb3r.bpmn.intellij.plugin.core.events.DiagramElementRemovedEvent
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.Event
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.PropertyUpdateWithId
import com.valb3r.bpmn.intellij.plugin.core.events.updateEventsRegistry
import com.valb3r.bpmn.intellij.plugin.core.render.AreaType
import com.valb3r.bpmn.intellij.plugin.core.render.currentCanvas
import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState
import com.valb3r.bpmn.intellij.plugin.core.render.lastRenderedState
import java.util.*

Expand All @@ -19,17 +19,12 @@ fun currentRemoveActionHandler(project: Project): ElementRemoveActionHandler {

class ElementRemoveActionHandler(private val project: Project) {

fun deleteElem() {
fun deleteSelectedElements() {
val state = lastRenderedState(project)?.state ?: return
val targetIds = state.ctx.selectedIds.filter {
val area = state.elemMap[it]?.areaType
area == AreaType.SHAPE_THAT_NESTS || area == AreaType.SHAPE || area == AreaType.EDGE
}

updateEventsRegistry(project).addElementRemovedEvent(
targetIds.map { DiagramElementRemovedEvent(it) },
targetIds.mapNotNull { state.currentState.elementByDiagramId[it] }.map { BpmnElementRemovedEvent(it) }
)

val inOrder = removeElements(state, state.ctx.selectedIds.toList())

updateEventsRegistry(project).addEvents(inOrder)

currentCanvas(project).repaint()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.ShapeElement
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.EdgeWithIdentifiableWaypoints
import com.valb3r.bpmn.intellij.plugin.bpmn.api.info.Property
import com.valb3r.bpmn.intellij.plugin.bpmn.api.info.PropertyType
import com.valb3r.bpmn.intellij.plugin.core.actions.removeElements
import com.valb3r.bpmn.intellij.plugin.core.events.*
import com.valb3r.bpmn.intellij.plugin.core.render.EdgeElementState
import com.valb3r.bpmn.intellij.plugin.core.render.elements.BaseDiagramRenderElement
Expand Down Expand Up @@ -93,13 +94,9 @@ class CopyPasteActionHandler(private val clipboard: SystemClipboard) {
.filter { if (alreadyRemovedBpmn.contains(it)) false else { alreadyRemovedBpmn += it; true } }
.mapNotNull { elementsById[it] }

val bpmnToRemove = mutableListOf<BpmnElementRemovedEvent>()
val diagramToRemove = mutableListOf<DiagramElementRemovedEvent>()
val events = removeElements(ctx, elemsToDelete.map { it.elementId })
updateEvents.addEvents(events)

elemsToDelete.forEach { bpmnToRemove += it.getEventsToDeleteElement() }
elemsToDelete.forEach { diagramToRemove += it.getEventsToDeleteDiagram() }

updateEvents.addElementRemovedEvent(diagramToRemove, bpmnToRemove)
clipboard.setContents(ClipboardFlavor(mapper.writeValueAsString(toCopy)), null)
}

Expand All @@ -123,8 +120,12 @@ class CopyPasteActionHandler(private val clipboard: SystemClipboard) {
?: 0.0f
val delta = Point2D.Float(sceneLocation.x - minX, sceneLocation.y - minY)

val updatedShapes = updateShapes(delta, context.shapes, updatedIds, updatedDiagramIds)
val updatedEdges = updateEdges(delta, context.edges, updatedIds, updatedDiagramIds)
// TODO incoming/outgoing not handled properly
var updatedShapes = updateShapes(delta, context.shapes, updatedIds, updatedDiagramIds)
var updatedEdges = updateEdges(delta, context.edges, updatedIds, updatedDiagramIds)
// Update properties since they might depend on both shapes and edges
updatedShapes = updatedShapes.mapIndexed { index, shape -> shape.copy(props = copied(context.shapes[index].props, updatedIds)) }.toMutableList()
updatedEdges = updatedEdges.mapIndexed { index, edge -> edge.copy(props = copied(context.edges[index].props, updatedIds)) }.toMutableList()
val updatedSelectedElems = computeElementsToSelect(context, updatedEdges, updatedDiagramIds)

context.copy(shapes = updatedShapes, edges = updatedEdges, selectElements = updatedSelectedElems)
Expand Down Expand Up @@ -218,7 +219,7 @@ class CopyPasteActionHandler(private val clipboard: SystemClipboard) {
when {
v.value == null -> result.add(k, v)
PropertyType.ID == k -> result[k] = Property(copied(BpmnElementId(v.value as String), updatedIds).id)
PropertyType.ID == k.updatedBy -> result[k] = Property(copiedExistsOrEmpty(BpmnElementId(v.value as String), updatedIds))
PropertyType.ID == k.updatedBy -> result.add(k, Property(copiedExistsOrEmpty(BpmnElementId(v.value as String), updatedIds)))
else -> result.add(k, v)
}
}
Expand All @@ -240,7 +241,7 @@ class CopyPasteActionHandler(private val clipboard: SystemClipboard) {
)
}

return result.map { it.copy(props = copied(it.props, updatedIds), shape = copied(it.shape, delta, updatedIds, updatedDiagramIds)) }.toMutableList()
return result.map { it.copy(props = PropertyTable(mutableMapOf()), shape = copied(it.shape, delta, updatedIds, updatedDiagramIds)) }.toMutableList()
}

private fun updateEdges(
Expand All @@ -257,7 +258,7 @@ class CopyPasteActionHandler(private val clipboard: SystemClipboard) {
)
)
}
return result.map { it.copy(props = copied(it.props, updatedIds), edge = copied(it.edge, delta, updatedIds, updatedDiagramIds)) }.toMutableList()
return result.map { it.copy(props = PropertyTable(mutableMapOf()), edge = copied(it.edge, delta, updatedIds, updatedDiagramIds)) }.toMutableList()
}

private fun ensureRootElementsComeFirst(idsToCopy: MutableList<DiagramElementId>, ctx: RenderState, elementsById: Map<BpmnElementId, BaseDiagramRenderElement>): MutableList<DiagramElementId> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class ProcessModelUpdateEvents(private val committer: FileCommitter, private val
is BpmnEdgeObjectAddedEvent -> addObjectEdgeEvent(toStore as Order<BpmnEdgeObjectAddedEvent>)
is BpmnElementRemovedEvent -> removeBpmnElement(event.bpmnElementId , toStore as Order<BpmnElementRemovedEvent> )
is BpmnElementTypeChangeEvent -> changeBpmnElement(event.elementId , toStore as Order<BpmnElementRemovedEvent>, toStore as Order<BpmnEdgeObjectAddedEvent>)
is DiagramElementRemovedEvent -> removeDiagramElement(event, toStore as Order<DiagramElementRemovedEvent>)
else -> throw IllegalArgumentException("Can't bulk add: " + event::class.qualifiedName)
}
}
Expand All @@ -196,7 +197,7 @@ class ProcessModelUpdateEvents(private val committer: FileCommitter, private val
diagram.forEachIndexed {index, event ->
val toStore = Order(current + index, event, EventBlock(blockSize))
updates.add(toStore)
deletionsByStaticId.computeIfAbsent(event.elementId) { CopyOnWriteArrayList() } += toStore
removeDiagramElement(event, toStore)
}

bpmn.forEachIndexed {index, event ->
Expand All @@ -214,6 +215,13 @@ class ProcessModelUpdateEvents(private val committer: FileCommitter, private val
commitToFile()
}

private fun removeDiagramElement(
event: DiagramElementRemovedEvent,
toStore: Order<DiagramElementRemovedEvent>
) {
deletionsByStaticId.computeIfAbsent(event.elementId) { CopyOnWriteArrayList() } += toStore
}

private fun removeBpmnElement(
bpmnElement: BpmnElementId,
toStore: Order<BpmnElementRemovedEvent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ class DefaultBpmnProcessRenderer(private val project: Project, val icons: IconPr
BoundsElement(maxX, minY, actionsIcoSize, actionsIcoSize),
icons.recycleBin
)
state.ctx.interactionContext.clickCallbacks[delId] = { currentRemoveActionHandler(project).deleteElem() }
state.ctx.interactionContext.clickCallbacks[delId] = { currentRemoveActionHandler(project).deleteSelectedElements() }
renderedArea[delId] =
AreaWithZindex(deleteIconArea, AreaType.POINT, mutableSetOf(), mutableSetOf(), ANCHOR_Z_INDEX, null)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.valb3r.bpmn.intellij.plugin.core.render.elements
import com.valb3r.bpmn.intellij.plugin.bpmn.api.bpmn.BpmnElementId
import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.DiagramElementId
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.Event
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.PropertyUpdateWithId
import com.valb3r.bpmn.intellij.plugin.core.Colors
import com.valb3r.bpmn.intellij.plugin.core.events.BpmnElementRemovedEvent
import com.valb3r.bpmn.intellij.plugin.core.events.DiagramElementRemovedEvent
Expand Down Expand Up @@ -115,6 +116,10 @@ abstract class BaseDiagramRenderElement(
return listOf()
}

open fun getEventsToElementWithItsDiagram(): ElementRemovalEvents {
return ElementRemovalEvents(getEventsToDeleteDiagram(), getEventsToDeleteElement(), emptyList())
}

open fun zIndex(): Int {
return if (isActiveOrDragged()) ANCHOR_Z_INDEX else (parents.firstOrNull()?.zIndex() ?: -1) + 1
}
Expand Down Expand Up @@ -287,4 +292,10 @@ abstract class BaseDiagramRenderElement(
currentOnScreenRect(state().ctx.canvas.camera)
children.forEach {it.currentOnScreenRect(state().ctx.canvas.camera)}
}
}
}

data class ElementRemovalEvents(
val diagram: List<DiagramElementRemovedEvent>,
val bpmn: List<BpmnElementRemovedEvent>,
val other: List<PropertyUpdateWithId>
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.valb3r.bpmn.intellij.plugin.bpmn.api.bpmn.BpmnElementId
import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.DiagramElementId
import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.BoundsElement
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.EdgeWithIdentifiableWaypoints
import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.Event
import com.valb3r.bpmn.intellij.plugin.bpmn.api.info.PropertyType
import com.valb3r.bpmn.intellij.plugin.core.Colors
import com.valb3r.bpmn.intellij.plugin.core.events.BpmnElementRemovedEvent
Expand All @@ -27,14 +28,19 @@ class EdgeRenderElement(
val delId = elementId.elemIdToRemove()
val deleteIconArea = state().ctx.canvas.drawIcon(BoundsElement(x, y - ACTIONS_ICO_SIZE, ACTIONS_ICO_SIZE, ACTIONS_ICO_SIZE), state().icons.recycleBin)
state().ctx.interactionContext.clickCallbacks[delId] = { dest ->
val currentProps = state().currentState.propertyWithElementByPropertyType
val cascadeEvents = computeCascadeChangeOfBpmnIncomingOutgoingIndex(bpmnElementId, currentProps, PropertyType.BPMN_INCOMING).toMutableList() +
computeCascadeChangeOfBpmnIncomingOutgoingIndex(bpmnElementId, currentProps, PropertyType.BPMN_OUTGOING)
dest.addElementRemovedEvent(getEventsToDeleteDiagram(), getEventsToDeleteElement(), cascadeEvents)
val removalEvents = getEventsToElementWithItsDiagram()
dest.addElementRemovedEvent(removalEvents.diagram, removalEvents.bpmn, removalEvents.other)
}

return mutableMapOf(
delId to AreaWithZindex(deleteIconArea, AreaType.POINT, mutableSetOf(), mutableSetOf(), ICON_Z_INDEX, elementId)
)
}

override fun getEventsToElementWithItsDiagram(): ElementRemovalEvents {
val currentProps = state().currentState.propertyWithElementByPropertyType
val cascadeEvents = computeCascadeChangeOfBpmnIncomingOutgoingIndex(bpmnElementId, currentProps, PropertyType.BPMN_INCOMING).toMutableList() +
computeCascadeChangeOfBpmnIncomingOutgoingIndex(bpmnElementId, currentProps, PropertyType.BPMN_OUTGOING)
return ElementRemovalEvents(getEventsToDeleteDiagram(), getEventsToDeleteElement(), cascadeEvents)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ abstract class ShapeRenderElement(
val delId = elementId.elemIdToRemove()
val deleteIconArea = state().ctx.canvas.drawIcon(BoundsElement(x, currY, ACTIONS_ICO_SIZE, ACTIONS_ICO_SIZE), state().icons.recycleBin)
state().ctx.interactionContext.clickCallbacks[delId] = { dest ->
dest.addElementRemovedEvent(getEventsToDeleteDiagram(), getEventsToDeleteElement())
val removalEvents = getEventsToElementWithItsDiagram()
dest.addElementRemovedEvent(removalEvents.diagram, removalEvents.bpmn, removalEvents.other)
}

if (ACTIONS_ICO_SIZE * actionCount >= (right.y - left.y)) {
Expand Down Expand Up @@ -119,7 +120,6 @@ abstract class ShapeRenderElement(
)
}


abstract fun doRender(ctx: RenderContext, shapeCtx: ShapeCtx): Map<DiagramElementId, AreaWithZindex>

override fun doDragToWithoutChildren(dx: Float, dy: Float) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,10 @@ abstract class BaseBpmnParser: BpmnParser {

var (attrName, attrValue) = attributeSelector?.split("=") ?: listOf(null, null)
if (true == attrValue?.contains('@')) {
if (null == value && null == valueIndexInArray) { // Skip null unindexable props
if (null == value || null == valueIndexInArray) { // Skip null unindexable props
return
}
attrValue = attrValue.replace("@", valueIndexInArray!!.removeAt(0))
attrValue = attrValue.replace("@", valueIndexInArray.removeAt(0))
}

val child = childOf(currentNode, name, attrName, attrValue)
Expand Down