diff --git a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps index d79377fa0..7e0a22dda 100644 --- a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps +++ b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps @@ -2409,7 +2409,7 @@ - + @@ -3452,7 +3452,7 @@ - + @@ -3515,7 +3515,7 @@ - + diff --git a/code/debugger/buildsolution/models/org.fbme.debugger.build.mps b/code/debugger/buildsolution/models/org.fbme.debugger.build.mps index e62b1e639..7699996d1 100644 --- a/code/debugger/buildsolution/models/org.fbme.debugger.build.mps +++ b/code/debugger/buildsolution/models/org.fbme.debugger.build.mps @@ -138,7 +138,7 @@ - + diff --git a/code/debugger/solutions/org.fbme.debugger/models/org.fbme.debugger.plugin.mps b/code/debugger/solutions/org.fbme.debugger/models/org.fbme.debugger.plugin.mps index f61dac21e..d2fce4640 100644 --- a/code/debugger/solutions/org.fbme.debugger/models/org.fbme.debugger.plugin.mps +++ b/code/debugger/solutions/org.fbme.debugger/models/org.fbme.debugger.plugin.mps @@ -38,7 +38,7 @@ - + @@ -60,6 +60,7 @@ + @@ -458,7 +459,7 @@ - + @@ -497,7 +498,7 @@ - + @@ -552,8 +553,8 @@ - - + + @@ -970,7 +971,7 @@ - + @@ -997,7 +998,7 @@ - + @@ -1032,11 +1033,11 @@ - + - + @@ -1075,7 +1076,7 @@ - + @@ -1126,7 +1127,7 @@ - + @@ -1140,7 +1141,7 @@ - + @@ -1180,11 +1181,11 @@ - + - + @@ -1221,7 +1222,7 @@ - + @@ -1232,7 +1233,7 @@ - + @@ -1293,7 +1294,7 @@ - + @@ -1315,7 +1316,7 @@ - + @@ -1348,7 +1349,7 @@ - + @@ -1367,7 +1368,7 @@ - + @@ -1385,7 +1386,7 @@ - + @@ -1407,7 +1408,7 @@ - + @@ -1469,11 +1470,11 @@ - + - + @@ -1502,7 +1503,7 @@ - + @@ -1526,7 +1527,7 @@ - + @@ -1610,7 +1611,7 @@ - + @@ -1632,7 +1633,7 @@ - + @@ -1694,11 +1695,11 @@ - + - + @@ -1727,7 +1728,7 @@ - + @@ -1750,7 +1751,7 @@ - + @@ -1830,7 +1831,7 @@ - + @@ -1852,7 +1853,7 @@ - + @@ -1933,11 +1934,11 @@ - + - + @@ -1963,7 +1964,7 @@ - + @@ -2022,7 +2023,7 @@ - + @@ -2044,7 +2045,7 @@ - + @@ -2077,7 +2078,7 @@ - + @@ -2096,7 +2097,7 @@ - + @@ -2114,7 +2115,7 @@ - + @@ -2136,7 +2137,7 @@ - + @@ -2198,11 +2199,11 @@ - + - + @@ -2231,7 +2232,7 @@ - + @@ -2255,7 +2256,7 @@ - + @@ -2339,7 +2340,7 @@ - + @@ -2361,7 +2362,7 @@ - + @@ -2423,11 +2424,11 @@ - + - + @@ -2456,7 +2457,7 @@ - + @@ -2479,7 +2480,7 @@ - + @@ -2559,7 +2560,7 @@ - + @@ -2581,7 +2582,7 @@ - + @@ -2662,11 +2663,11 @@ - + - + @@ -2692,7 +2693,7 @@ - + @@ -2811,8 +2812,8 @@ - - + + @@ -6202,7 +6203,7 @@ - + @@ -7608,7 +7609,7 @@ - + @@ -7774,8 +7775,8 @@ - - + + @@ -8194,8 +8195,8 @@ - - + + @@ -8298,7 +8299,7 @@ - + @@ -8997,8 +8998,8 @@ - - + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl index 9304586c9..7352eddd1 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl +++ b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl @@ -52,6 +52,7 @@ + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.ecc.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.ecc.mps index 69bc1d52f..c2786151f 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.ecc.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.ecc.mps @@ -1127,8 +1127,8 @@ - + @@ -1816,8 +1816,8 @@ - + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps index a96f9933b..3f83322d9 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps @@ -68,6 +68,7 @@ + @@ -111,7 +112,6 @@ - @@ -137,6 +137,9 @@ + + + @@ -198,6 +201,9 @@ + + + @@ -210,6 +216,12 @@ + + + + + + @@ -217,6 +229,7 @@ + @@ -399,25 +412,53 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - + - + @@ -425,28 +466,55 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + - @@ -479,8 +547,8 @@ - + @@ -611,25 +679,53 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - + - + @@ -637,23 +733,51 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + @@ -689,8 +813,8 @@ - + @@ -804,25 +928,53 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + - + - + - + @@ -830,23 +982,51 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + @@ -1916,25 +2096,53 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + - + - + - + @@ -1942,28 +2150,55 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + - @@ -1996,8 +2231,8 @@ - + @@ -2128,25 +2363,53 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + - + - + - + @@ -2154,23 +2417,51 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + @@ -2321,25 +2612,53 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + - + - + - + @@ -2347,23 +2666,51 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + diff --git a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt index eca6aeb1d..d94630316 100644 --- a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt +++ b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt @@ -49,16 +49,22 @@ internal class PlatformDeclarationsScope( return myRepository.getAdapter(findNode(identifier), FunctionBlockDeclaration::class.java) } - override fun findAllFBTypeDeclarations(): List { + override fun findAllFBTypeDeclarations(): List = + findAllTypeDeclarations(FBTypeDeclaration::class.java) + + override fun findAllAdapterTypeDeclarations(): List = + findAllTypeDeclarations(AdapterTypeDeclaration::class.java) + + private fun findAllTypeDeclarations(clazz: Class): List { return myRepository.mpsRepository.modules - .flatMap { it.models } - .filter { - myModel == null || - myModel.reference == it.reference || - ModelImports(myModel).importedModels.contains(it.reference) - } - .flatMap { it.rootNodes } - .mapNotNull { myRepository.getAdapter(it, FBTypeDeclaration::class.java) } + .flatMap { it.models } + .filter { + myModel == null || + myModel.reference == it.reference || + ModelImports(myModel).importedModels.contains(it.reference) + } + .flatMap { it.rootNodes } + .mapNotNull { myRepository.getAdapter(it, clazz) } } private fun findNode(identifier: Identifier): SNode? { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt index 3e35d940a..6103e9d54 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt @@ -15,4 +15,5 @@ interface DeclarationsScope { fun findResourceDeclaration(identifier: Identifier): ResourceDeclaration? fun findFunctionBlockDeclaration(identifier: Identifier): FunctionBlockDeclaration? fun findAllFBTypeDeclarations(): List + fun findAllAdapterTypeDeclarations(): List } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterDeclaration.kt new file mode 100644 index 000000000..a087a44ee --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterDeclaration.kt @@ -0,0 +1,9 @@ +package org.fbme.lib.iec61499.declarations + +import org.fbme.lib.common.Reference +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase + +interface AdapterDeclaration : FunctionBlockDeclarationBase { + override val container: FBInterfaceDeclarationWithAdapters? + val typeReference: Reference +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/PlugDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/PlugDeclaration.kt index 9d7f8ee96..7ca44abe4 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/PlugDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/PlugDeclaration.kt @@ -1,9 +1,3 @@ package org.fbme.lib.iec61499.declarations -import org.fbme.lib.common.Reference -import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase - -interface PlugDeclaration : FunctionBlockDeclarationBase { - override val container: FBInterfaceDeclarationWithAdapters? - val typeReference: Reference -} +interface PlugDeclaration : AdapterDeclaration diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SocketDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SocketDeclaration.kt index 0887a1eb8..027227883 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SocketDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SocketDeclaration.kt @@ -1,9 +1,3 @@ package org.fbme.lib.iec61499.declarations -import org.fbme.lib.common.Reference -import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase - -interface SocketDeclaration : FunctionBlockDeclarationBase { - override val container: FBInterfaceDeclarationWithAdapters? - val typeReference: Reference -} +interface SocketDeclaration : AdapterDeclaration diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt index e5c999aee..26242174a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt @@ -3,6 +3,7 @@ package org.fbme.lib.iec61499.fbnetwork import org.fbme.lib.common.Declaration import org.fbme.lib.common.Element import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import java.util.* interface FBNetwork : Element { @@ -44,6 +45,39 @@ interface FBNetwork : Element { return components } + val allConnections: List + get() = eventConnections.union(dataConnections).union(adapterConnections).toList() + + fun getAllPorts(): List { + val result: MutableList = mutableListOf() + + this.contextDataSources.forEachIndexed { index, it -> + result.add(FBPortDescriptor(it.name, EntryKind.DATA, index, true, true, it)) + } + + this.contextEventSources.forEachIndexed { index, it -> + result.add(FBPortDescriptor(it.name, EntryKind.EVENT, index, true, true, it)) + } + + this.contextDataDestinations.forEachIndexed { index, it -> + result.add(FBPortDescriptor(it.name, EntryKind.DATA, index, false, true, it)) + } + + this.contextEventDestinations.forEachIndexed { index, it -> + result.add(FBPortDescriptor(it.name, EntryKind.EVENT, index, false, true, it)) + } + + return result + } + + fun getConnections(kind: EntryKind): MutableList { + return when (kind) { + EntryKind.EVENT -> this.eventConnections + EntryKind.DATA -> this.dataConnections + EntryKind.ADAPTER -> this.adapterConnections + } + } + companion object { @JvmStatic fun extractNetwork(declaration: Declaration?): FBNetwork? { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FunctionBlockDeclarationBase.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FunctionBlockDeclarationBase.kt index bfc3c0f79..78c69dd18 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FunctionBlockDeclarationBase.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FunctionBlockDeclarationBase.kt @@ -26,6 +26,16 @@ interface FunctionBlockDeclarationBase : Declaration, ContainedElement { generatePorts(result, this, type.plugPorts) return result } + + fun getAllPorts(): List = + type.eventInputPorts + .union(type.eventOutputPorts) + .union(type.dataInputPorts) + .union(type.dataOutputPorts) + .union(type.socketPorts) + .union(type.plugPorts) + .toList() + var x: Int var y: Int diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/PortPath.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/PortPath.kt index ef8749c91..ad6a5804a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/PortPath.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/PortPath.kt @@ -37,7 +37,7 @@ class PortPath private constructor( @JvmStatic fun createEventPortPath( functionBlock: FunctionBlockDeclarationBase?, - portTarget: EventDeclaration + portTarget: EventDeclaration, ): PortPath { return PortPath(functionBlock, portTarget) } @@ -45,7 +45,7 @@ class PortPath private constructor( @JvmStatic fun createDataPortPath( functionBlock: FunctionBlockDeclarationBase?, - portTarget: ParameterDeclaration + portTarget: ParameterDeclaration, ): PortPath { return PortPath(functionBlock, portTarget) } @@ -53,7 +53,7 @@ class PortPath private constructor( @JvmStatic fun createPlugPortPath( functionBlock: FunctionBlockDeclarationBase?, - portTarget: PlugDeclaration + portTarget: PlugDeclaration, ): PortPath { return PortPath(functionBlock, portTarget) } @@ -61,7 +61,7 @@ class PortPath private constructor( @JvmStatic fun createSocketPortPath( functionBlock: FunctionBlockDeclarationBase?, - portTarget: SocketDeclaration + portTarget: SocketDeclaration, ): PortPath { return PortPath(functionBlock, portTarget) } @@ -83,5 +83,12 @@ class PortPath private constructor( } } } + + @JvmStatic + fun createBrokenPortPath( + functionBlock: FunctionBlockDeclarationBase?, + kind: EntryKind, + portName: String + ): PortPath = PortPath(functionBlock, BrokenPortDeclaration(portName, kind, functionBlock)) } } diff --git a/code/library/src/main/kotlin/org/fbme/lib/st/types/DataType.kt b/code/library/src/main/kotlin/org/fbme/lib/st/types/DataType.kt index fe3182f3e..894b44c00 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/st/types/DataType.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/st/types/DataType.kt @@ -2,4 +2,11 @@ package org.fbme.lib.st.types interface DataType { fun stringify(): String + + companion object { + @JvmStatic + fun getAllValues(): List { + return listOf(*GenericType.values(), *ElementaryType.values()) + } + } } diff --git a/code/nxt-integration/solutions/org.fbme.integration.nxt/models/org.fbme.integration.nxt.plugin.mps b/code/nxt-integration/solutions/org.fbme.integration.nxt/models/org.fbme.integration.nxt.plugin.mps index f8856b44e..bbf7d07a1 100644 --- a/code/nxt-integration/solutions/org.fbme.integration.nxt/models/org.fbme.integration.nxt.plugin.mps +++ b/code/nxt-integration/solutions/org.fbme.integration.nxt/models/org.fbme.integration.nxt.plugin.mps @@ -14,7 +14,7 @@ - + @@ -46,6 +46,7 @@ + @@ -433,7 +434,7 @@ - + @@ -498,7 +499,7 @@ - + @@ -682,7 +683,7 @@ - + @@ -701,7 +702,6 @@ - diff --git a/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps b/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps index 2527e4cc0..b0a6e541b 100644 --- a/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps +++ b/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps @@ -56,8 +56,9 @@ + + - @@ -2056,7 +2057,7 @@ - + @@ -2096,7 +2097,7 @@ - + @@ -2235,7 +2236,7 @@ - + @@ -2302,7 +2303,7 @@ - + diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/CollapseAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/CollapseAction.kt deleted file mode 100644 index 3d40e4d28..000000000 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/CollapseAction.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.fbme.ide.richediting.actions - -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.DumbAware -import jetbrains.mps.ide.editor.MPSEditorDataKeys -import org.fbme.ide.richediting.adapters.fbnetwork.actions.CollapseAction - -class CollapseAction : AnAction(), DumbAware { - - override fun update(event: AnActionEvent) { - event.presentation.isEnabledAndVisible = event.getData(MPSEditorDataKeys.EDITOR_CELL) != null - } - - override fun actionPerformed(event: AnActionEvent) { - event.executeReadActionInEditor { - CollapseAction(event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL)).apply() - } - } -} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ExpandAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ExpandAction.kt deleted file mode 100644 index f8b074dee..000000000 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ExpandAction.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.fbme.ide.richediting.actions - -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.DumbAware -import jetbrains.mps.ide.editor.MPSEditorDataKeys -import org.fbme.ide.richediting.adapters.fbnetwork.actions.ExpandAction - -class ExpandAction : AnAction(), DumbAware { - - override fun update(event: AnActionEvent) { - event.presentation.isEnabledAndVisible = event.getData(MPSEditorDataKeys.EDITOR_CELL) != null - } - - override fun actionPerformed(event: AnActionEvent) { - event.executeReadActionInEditor { - ExpandAction(event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL)).apply() - } - } -} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddStateActionAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AddStateActionAction.kt similarity index 90% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddStateActionAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AddStateActionAction.kt index ca929c094..01ae02b3f 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddStateActionAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AddStateActionAction.kt @@ -1,10 +1,11 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.actions.executeWriteActionInEditor import org.fbme.ide.richediting.editor.RichEditorStyleAttributes class AddStateActionAction : AnAction(), DumbAware { diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AlgorithmBodyVisibilityAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AlgorithmBodyVisibilityAction.kt similarity index 94% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AlgorithmBodyVisibilityAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AlgorithmBodyVisibilityAction.kt index 08b6be3f1..a00f26dc9 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AlgorithmBodyVisibilityAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AlgorithmBodyVisibilityAction.kt @@ -1,9 +1,10 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.executeReadActionInEditor import org.fbme.ide.richediting.adapters.ecc.ECCEditors import org.fbme.ide.richediting.adapters.ecc.cell.AlgorithmCell import org.fbme.ide.richediting.editor.RichEditorStyleAttributes diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllAlgorithmBodyVisibilityAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllAlgorithmBodyVisibilityAction.kt similarity index 91% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllAlgorithmBodyVisibilityAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllAlgorithmBodyVisibilityAction.kt index 88a47abe2..0bf0aa4b4 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllAlgorithmBodyVisibilityAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllAlgorithmBodyVisibilityAction.kt @@ -1,9 +1,11 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.element +import org.fbme.ide.richediting.actions.executeReadActionInEditor import org.fbme.ide.richediting.adapters.ecc.ECCEditors import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration import org.fbme.scenes.cells.EditorCell_Scene diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllStateActionVisibilityAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllStateActionVisibilityAction.kt similarity index 90% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllStateActionVisibilityAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllStateActionVisibilityAction.kt index c1105e8a8..1c3b142ff 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AllStateActionVisibilityAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/AllStateActionVisibilityAction.kt @@ -1,9 +1,11 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.element +import org.fbme.ide.richediting.actions.executeReadActionInEditor import org.fbme.ide.richediting.adapters.ecc.ECCEditors import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration import org.fbme.scenes.cells.EditorCell_Scene diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmAction.kt similarity index 89% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmAction.kt index 604e09e3e..b6e5766e6 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmAction.kt @@ -1,10 +1,10 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys -import org.fbme.ide.richediting.adapters.ecc.cell.AlgorithmCell +import org.fbme.ide.richediting.actions.executeWriteActionInEditor import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.iec61499.declarations.AlgorithmDeclaration diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmActionGroup.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmActionGroup.kt similarity index 89% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmActionGroup.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmActionGroup.kt index 413785574..89962d1de 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeAlgorithmActionGroup.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeAlgorithmActionGroup.kt @@ -1,10 +1,12 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.element +import org.fbme.ide.richediting.actions.executeReadAction import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputAction.kt similarity index 90% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputAction.kt index d74c99be2..bc5c616f2 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputAction.kt @@ -1,10 +1,10 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys -import org.fbme.ide.richediting.adapters.ecc.cell.AlgorithmCell +import org.fbme.ide.richediting.actions.executeWriteActionInEditor import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.fbnetwork.PortPath.Companion.createEventPortPath diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputActionGroup.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputActionGroup.kt similarity index 88% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputActionGroup.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputActionGroup.kt index ee529190d..d7a7bea69 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ChangeOutputActionGroup.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/ChangeOutputActionGroup.kt @@ -1,10 +1,12 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.element +import org.fbme.ide.richediting.actions.executeReadAction import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/DeleteStateActionAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/DeleteStateActionAction.kt similarity index 89% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/DeleteStateActionAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/DeleteStateActionAction.kt index 48cc64d00..1ec743667 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/DeleteStateActionAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/DeleteStateActionAction.kt @@ -1,9 +1,10 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys +import org.fbme.ide.richediting.actions.executeWriteActionInEditor import org.fbme.ide.richediting.editor.RichEditorStyleAttributes class DeleteStateActionAction : AnAction(), DumbAware { diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/NewAlgorithmAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/NewAlgorithmAction.kt similarity index 94% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/NewAlgorithmAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/NewAlgorithmAction.kt index 87b5610ab..a54195725 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/NewAlgorithmAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/ecc/NewAlgorithmAction.kt @@ -1,10 +1,11 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.ecc import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.actions.executeWriteActionInEditor import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.common.StringIdentifier import org.fbme.lib.iec61499.declarations.AlgorithmLanguage diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AbstractFBEditAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AbstractFBEditAction.kt new file mode 100644 index 000000000..8b61af16a --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AbstractFBEditAction.kt @@ -0,0 +1,43 @@ +package org.fbme.ide.richediting.actions.network + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAware +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.viewmodel.FunctionBlockView + +abstract class AbstractFBEditAction: AnAction(), DumbAware { + override fun update(event: AnActionEvent) { + val project = event.getData(MPSEditorDataKeys.MPS_PROJECT) + val cell = event.getData(MPSEditorDataKeys.EDITOR_CELL) + + if (project == null || cell == null) { + notApplicable(event) + return + } + + val editedFBS = cell.style.get(RichEditorStyleAttributes.EDITED_FBS)?.editedComponents + val fbCell = editedFBS?.find { it.associatedNode == cell.sNode } + + if (fbCell == null) { + notApplicable(event) + return + } + + internalConditionCheck(event, fbCell, cell, project) + } + + protected abstract fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) + + protected fun notApplicable(event: AnActionEvent) { + event.presentation.isEnabledAndVisible = false + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddConstantToPortAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AddConstantToPortAction.kt similarity index 90% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddConstantToPortAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AddConstantToPortAction.kt index a7fbd6ae7..bc8f2ae5b 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/AddConstantToPortAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/AddConstantToPortAction.kt @@ -1,10 +1,12 @@ -package org.fbme.ide.richediting.actions +package org.fbme.ide.richediting.actions.network import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.DumbAware import jetbrains.mps.ide.editor.MPSEditorDataKeys import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.richediting.actions.executeWriteActionInEditor +import org.fbme.ide.richediting.actions.repository import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.lib.iec61499.declarations.ParameterDeclaration import org.fbme.lib.iec61499.fbnetwork.EntryKind diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/ChangeTypeAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/ChangeTypeAction.kt new file mode 100644 index 000000000..a73254685 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/ChangeTypeAction.kt @@ -0,0 +1,66 @@ +package org.fbme.ide.richediting.actions.network + +import com.intellij.openapi.actionSystem.AnActionEvent +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.actions.modelAccess +import org.fbme.ide.richediting.adapters.fbnetwork.actions.ChangeTypeAction +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration + +class ChangeTypeAction : AbstractFBEditAction() { + override fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) { + when (val declaration = fbCell.type.declaration) { + is CompositeFBTypeDeclaration -> { + event.presentation.text = TO_BASIC_FB_TYPE + event.presentation.isEnabled = checkCompositeBlock(declaration) + } + + is BasicFBTypeDeclaration -> { + event.presentation.text = TO_COMPOSITE_FB_TYPE + event.presentation.isEnabled = checkBasicBlock(declaration) + } + + else -> { + notApplicable(event) + } + } + } + + private fun checkBasicBlock(declaration: BasicFBTypeDeclaration): Boolean { + if (declaration.ecc.states.size > 1) { + return false + } + + if (declaration.ecc.transitions.isNotEmpty()) { + return false + } + + return declaration.algorithms.isEmpty() + } + + private fun checkCompositeBlock(declaration: CompositeFBTypeDeclaration): Boolean { + return declaration.network.allComponents.isEmpty() + } + + override fun actionPerformed(event: AnActionEvent) { + event.modelAccess.executeCommandInEDT { + ChangeTypeAction( + event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL), + event.getRequiredData(MPSEditorDataKeys.MPS_PROJECT) + ).apply() + } + } + + companion object { + const val TO_BASIC_FB_TYPE = "Change type to basic" + const val TO_COMPOSITE_FB_TYPE = "Change type to composite" + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/CreateViewAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/CreateViewAction.kt new file mode 100644 index 000000000..4c34e9d35 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/CreateViewAction.kt @@ -0,0 +1,30 @@ +package org.fbme.ide.richediting.actions.network + +import com.intellij.openapi.actionSystem.AnActionEvent +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.actions.modelAccess +import org.fbme.ide.richediting.adapters.fbnetwork.actions.CreateViewAction +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration + +class CreateViewAction : AbstractFBEditAction() { + override fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) { + event.presentation.isEnabled = fbCell.type.declaration !is CompositeFBTypeDeclaration + } + + override fun actionPerformed(event: AnActionEvent) { + event.modelAccess.executeCommandInEDT { + CreateViewAction( + event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL), + event.getRequiredData(MPSEditorDataKeys.MPS_PROJECT) + ).apply() + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/NetworkExtractorAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/NetworkExtractorAction.kt new file mode 100644 index 000000000..54af0fb47 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/NetworkExtractorAction.kt @@ -0,0 +1,39 @@ +package org.fbme.ide.richediting.actions.network + +import com.intellij.openapi.actionSystem.AnActionEvent +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.actions.modelAccess +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.ide.richediting.adapters.fbnetwork.actions.NetworkExtractorAction +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration + +class NetworkExtractorAction : AbstractFBEditAction() { + override fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) { + val declaration = fbCell.type.declaration + if (declaration !is CompositeFBTypeDeclaration) { + notApplicable(event) + return + } + event.modelAccess.runReadAction { + event.presentation.isEnabled = declaration.network.functionBlocks.isNotEmpty() + && declaration.sockets.isEmpty() + && declaration.plugs.isEmpty() + } + } + + override fun actionPerformed(event: AnActionEvent) { + event.modelAccess.executeCommandInEDT { + NetworkExtractorAction( + event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL), + event.getRequiredData(MPSEditorDataKeys.MPS_PROJECT) + ).apply() + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/CollapseAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/CollapseAction.kt new file mode 100644 index 000000000..f19467891 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/CollapseAction.kt @@ -0,0 +1,33 @@ +package org.fbme.ide.richediting.actions.network.expand + +import com.intellij.openapi.actionSystem.AnActionEvent +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.actions.executeReadActionInEditor +import org.fbme.ide.richediting.actions.network.AbstractFBEditAction +import org.fbme.ide.richediting.adapters.fbnetwork.actions.expand.CollapseAction +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.viewmodel.FunctionBlockView + +class CollapseAction : AbstractFBEditAction() { + override fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) { + event.presentation.isEnabled = + cell.style.get(RichEditorStyleAttributes.EXPANDED_COMPONENTS_CONTROLLER)?.isExpanded(fbCell) ?: false + } + + + override fun actionPerformed(event: AnActionEvent) { + event.executeReadActionInEditor { + CollapseAction( + event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL), + event.getRequiredData(MPSEditorDataKeys.MPS_PROJECT) + ).apply() + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/ExpandAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/ExpandAction.kt new file mode 100644 index 000000000..a6433b7fb --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/network/expand/ExpandAction.kt @@ -0,0 +1,33 @@ +package org.fbme.ide.richediting.actions.network.expand + +import com.intellij.openapi.actionSystem.AnActionEvent +import jetbrains.mps.ide.editor.MPSEditorDataKeys +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.richediting.actions.executeReadActionInEditor +import org.fbme.ide.richediting.actions.network.AbstractFBEditAction +import org.fbme.ide.richediting.adapters.fbnetwork.actions.expand.ExpandAction +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.viewmodel.FunctionBlockView + +class ExpandAction : AbstractFBEditAction() { + + override fun internalConditionCheck( + event: AnActionEvent, + fbCell: FunctionBlockView, + cell: EditorCell, + project: MPSProject + ) { + event.presentation.isEnabled = + cell.style.get(RichEditorStyleAttributes.EXPANDED_COMPONENTS_CONTROLLER)?.isExpanded(fbCell) == false + } + + override fun actionPerformed(event: AnActionEvent) { + event.executeReadActionInEditor { + ExpandAction( + event.getRequiredData(MPSEditorDataKeys.EDITOR_CELL), + event.getRequiredData(MPSEditorDataKeys.MPS_PROJECT) + ).apply() + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCViewAdapter.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCViewAdapter.kt index b5c91a073..9f8f4a648 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCViewAdapter.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCViewAdapter.kt @@ -20,6 +20,10 @@ class ECCViewAdapter( return HashSet(ecc.transitions) } + override fun portsTemplates(component: StateDeclaration): Set { + return emptySet() + } + override fun addEdge(sourcePort: StateDeclaration, targetPort: StateDeclaration): StateTransition { val transition = factory.createStateTransition() transition.sourceReference.setTarget(sourcePort) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECPortSettingProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECPortSettingProvider.kt index 7f1e19511..b34e5334b 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECPortSettingProvider.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECPortSettingProvider.kt @@ -8,7 +8,7 @@ import java.awt.Rectangle import java.util.function.Function class ECPortSettingProvider(private val mapper: Function) : - PortSettingProvider { + PortSettingProvider { override fun getBounds(componentForm: Point, port: StateDeclaration): Rectangle { val controller = mapper.apply(port) val bounds = Rectangle(controller.getBounds(componentForm)) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EditedComponentsController.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EditedComponentsController.kt new file mode 100644 index 000000000..2a227739b --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EditedComponentsController.kt @@ -0,0 +1,32 @@ +package org.fbme.ide.richediting.adapters.fbnetwork + +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.scenes.cells.EditorCell_Scene +import org.fbme.scenes.controllers.edited.EditedModel +import org.fbme.scenes.controllers.scene.SceneStateKey + +class EditedComponentsController(val scene: EditorCell_Scene) : EditedModel { + override val editedComponents: MutableList = scene.loadState(EDITED_FBS_KEY) + ?: mutableListOf() + + override fun setEdited(component: FunctionBlockView, edited: Boolean) { + if (edited) { + editedComponents.add(component) + return + } + + editedComponents.remove(component) + } + + override fun isEdited(component: FunctionBlockView): Boolean { + return editedComponents.contains(component) + } + + init { + scene.storeState(EDITED_FBS_KEY, editedComponents) + } + + companion object { + private val EDITED_FBS_KEY = SceneStateKey>("edited-fbs") + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EndpointPortCell.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EndpointPortCell.kt index 7404d0272..5dffde6cf 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EndpointPortCell.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/EndpointPortCell.kt @@ -9,6 +9,7 @@ import jetbrains.mps.nodeEditor.cells.ParentSettings import jetbrains.mps.openapi.editor.EditorContext import org.fbme.ide.richediting.adapters.fbnetwork.fb.AbstractFBCell import org.fbme.ide.richediting.adapters.fbnetwork.fb.DiagramColors +import org.fbme.ide.richediting.adapters.fbnetwork.port.PortCell import org.fbme.ide.richediting.viewmodel.InterfaceEndpointView import org.fbme.lib.iec61499.fbnetwork.EntryKind import org.fbme.scenes.cells.EditorCell_SceneLabel diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt index 27fe94e7c..daa5c6dc5 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt @@ -146,26 +146,19 @@ class FBConnectionController(context: EditorContext, view: NetworkConnectionView } private fun magnetizeHorizontal(index: Int, bendPoints: MutableList) { - if (index >= bendPoints.size) { - return - } - val u = bendPoints[index - 1] - val v = bendPoints[index] - val uPrev = bendPoints[index - 2] - val vNext = bendPoints[index + 1] - if (abs(vNext.y - v.y) < scale(SELECTION_PADDING)) { - u.y = vNext.y - bendPoints.removeAt(index + 1) - bendPoints.removeAt(index) - } - if (abs(u.y - uPrev.y) < scale(SELECTION_PADDING)) { - v.y = uPrev.y - bendPoints.removeAt(index - 1) - bendPoints.removeAt(index - 2) - } + magnetize(index, bendPoints, { p -> p.y }, { p, v -> p.y = v }) } private fun magnetizeVertical(index: Int, bendPoints: MutableList) { + magnetize(index, bendPoints, { p -> p.x }, { p, v -> p.x = v }) + } + + private fun magnetize( + index: Int, + bendPoints: MutableList, + extractor: (p: Point) -> Int, + setter: (p: Point, x: Int) -> Unit + ) { if (index >= bendPoints.size) { return } @@ -173,13 +166,13 @@ class FBConnectionController(context: EditorContext, view: NetworkConnectionView val v = bendPoints[index] val uPrev = if (index - 2 >= 0) bendPoints[index - 2] else null val vNext = if (index + 1 < bendPoints.size) bendPoints[index + 1] else null - if (vNext != null && abs(vNext.x - v.x) < scale(SELECTION_PADDING)) { - u.x = vNext.x + if (vNext != null && abs(extractor(vNext) - extractor(v)) < scale(SELECTION_PADDING)) { + setter(u, extractor(vNext)) bendPoints.removeAt(index + 1) bendPoints.removeAt(index) } - if (uPrev != null && abs(u.x - uPrev.x) < scale(SELECTION_PADDING)) { - v.x = uPrev.x + if (uPrev != null && abs(extractor(u) - extractor(uPrev)) < scale(SELECTION_PADDING)) { + setter(v, extractor(uPrev)) bendPoints.removeAt(index - 1) bendPoints.removeAt(index - 2) } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkComponentController.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkComponentController.kt index b3220c778..b7146d31a 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkComponentController.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkComponentController.kt @@ -6,18 +6,15 @@ import java.awt.Rectangle interface FBNetworkComponentController { fun getBounds(position: Point): Rectangle - fun getFBCellBounds(position: Point): Rectangle { - return getBounds(position) - } - + fun getFBCellBounds(position: Point): Rectangle = getBounds(position) + fun getFBPortTemplates(): Set = emptySet() fun getPortCoordinates(port: NetworkPortView, position: Point): Point fun getPortBounds(port: NetworkPortView, position: Point): Rectangle fun isSource(port: NetworkPortView): Boolean - fun canBeSourcedAt(port: NetworkPortView, position: Point): Boolean { - return isSource(port) - } - - fun canBeTargetedAt(port: NetworkPortView, position: Point): Boolean { - return !isSource(port) - } + fun canBeSourcedAt(port: NetworkPortView, position: Point): Boolean = isSource(port) + fun canBeTargetedAt(port: NetworkPortView, position: Point): Boolean = !isSource(port) + fun getTemplateBounds(template: NetworkPortView, modelForm: Point): Rectangle = Rectangle(0, 0) + fun getTemplatePosition(template: NetworkPortView, modelForm: Point): Point = Point(0, 0) + fun createPort(source: NetworkPortView, template: NetworkPortView): NetworkPortView? = null + fun connectTo(port: NetworkPortView, source: NetworkPortView) {} } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt index f9915f4cf..9d32d9f7d 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt @@ -1,5 +1,6 @@ package org.fbme.ide.richediting.adapters.fbnetwork +import com.intellij.util.alsoIfNull import jetbrains.mps.nodeEditor.EditorComponent import jetbrains.mps.nodeEditor.MPSColors import jetbrains.mps.nodeEditor.cells.EditorCell @@ -13,14 +14,14 @@ import org.fbme.ide.richediting.RicheditingMpsBridge import org.fbme.ide.richediting.editor.RichEditorDataKeys import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.ide.richediting.inspections.NetworkInspectionsFacility +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.utils.ProjectProvider +import org.fbme.ide.richediting.utils.fb.FBCompletionProvider import org.fbme.ide.richediting.viewmodel.* import org.fbme.lib.common.Declaration -import org.fbme.lib.common.StringIdentifier import org.fbme.lib.iec61499.DeclarationsScope import org.fbme.lib.iec61499.IEC61499Factory -import org.fbme.lib.iec61499.declarations.FBTypeDeclaration import org.fbme.lib.iec61499.declarations.ParameterAssignment -import org.fbme.lib.iec61499.fbnetwork.FBNetwork import org.fbme.lib.iec61499.instances.Instance import org.fbme.lib.iec61499.instances.NetworkInstance import org.fbme.scenes.cells.EditorCell_Scene @@ -28,14 +29,15 @@ import org.fbme.scenes.cells.SceneStyleAttributes.SCENE_BACKGROUND import org.fbme.scenes.controllers.* import org.fbme.scenes.controllers.components.* import org.fbme.scenes.controllers.diagram.* +import org.fbme.scenes.controllers.edited.EditedModel import org.fbme.scenes.controllers.scene.* -import org.fbme.scenes.viewmodel.PositionalCompletionItem import org.jetbrains.mps.openapi.model.SNode import java.awt.Point object FBNetworkEditors { @JvmField - val CONNECTION_CONTROLLER_FACTORY: ConnectionControllerFactory = + val CONNECTION_CONTROLLER_FACTORY: + ConnectionControllerFactory = object : ConnectionControllerFactory { override fun create( context: EditorContext, @@ -57,8 +59,10 @@ object FBNetworkEditors { compController: ComponentController ): ComponentExtController { require(!(extView !is InlineValueView || compController !is FunctionBlockController)) - val repository: PlatformElementsOwner = - PlatformRepositoryProvider.getInstance(context.operationContext.project) + val project = ProjectProvider.getInstance(context).alsoIfNull { + Notifier.showError("Can't get project from context!") + } ?: error("Project missing") + val repository: PlatformElementsOwner = PlatformRepositoryProvider.getInstance(project) val node = extView.associatedNode.parent val parameter = repository.getAdapter(node, ParameterAssignment::class.java) ?: error("Parameter assignment is null") @@ -111,7 +115,8 @@ object FBNetworkEditors { editorShift: Point = Point() ): EditorCell { val scene = EditorCell_Scene(context, node!!, layout) - val repository: PlatformElementsOwner = PlatformRepositoryProvider.getInstance(context.operationContext.project) + val project = ProjectProvider.getInstance(context) ?: error("Can't get project instance from context!") + val repository: PlatformElementsOwner = PlatformRepositoryProvider.getInstance(project) val declaration = repository.getAdapter(node, Declaration::class.java) ?: error("Error when creating NetworkCell: Declaration is null") val networkInstance = NetworkInstance.createForDeclaration(declaration, parent) @@ -133,10 +138,10 @@ object FBNetworkEditors { style.set(RichEditorStyleAttributes.NETWORK_INSTANCE, networkInstance) style.set(SCENE_BACKGROUND, MPSColors.WHITE) val component = context.editorComponent as EditorComponent - val project = context.operationContext.project + val project = ProjectProvider.getInstance(context) ?: error("Can't get project") val repository = PlatformRepositoryProvider.getInstance(project) try { - val isEditable = networkInstance.parent == null + val isEditable = true val networkView = NetworkView(repository.iec61499Factory, networkDeclaration, isEditable) val backgroundLayer = scene.createLayer(0f) val tracesLayer = scene.createLayer(1f) @@ -161,10 +166,19 @@ object FBNetworkEditors { style.set(RichEditorStyleAttributes.SELECTED_FBS, componentsSelection) val componentsLayout = DefaultLayoutModel(context.repository) val expandedComponentsController = ExpandedComponentsController(scene, context) + style.set(RichEditorStyleAttributes.EXPANDED_COMPONENTS_CONTROLLER, expandedComponentsController) + val editedComponentsController: EditedModel = EditedComponentsController(scene) + style.set(RichEditorStyleAttributes.EDITED_FBS, editedComponentsController) val componentsFacility = ComponentsFacility( scene, networkView.componentsView, - getComponentControllerFactory(networkInstance, expandedComponentsController), + getComponentControllerFactory( + networkInstance, + expandedComponentsController, + editedComponentsController, + repository.iec61499Factory, + repository.getDeclarationScopeFor(model) + ), FBNetworkComponentSynchronizer(viewpoint, scale, expandedComponentsController), componentsLayout, componentsSelection, @@ -173,10 +187,8 @@ object FBNetworkEditors { tracesLayer ) style.set(RichEditorStyleAttributes.COMPONENTS_FACILITY, componentsFacility) - val completionScope = repository.getDeclarationScopeFor(model) - val factory = repository.iec61499Factory val provider: SceneCompletionProvider = CompletionProviderByViewpoint(viewpoint) { - getCompletion(completionScope, factory, networkDeclaration, scale) + FBCompletionProvider.getCompletionItems(networkInstance, context) } scene.addCompletionProvider(provider) val inlineValuesView = networkView.extensionsView @@ -259,13 +271,24 @@ object FBNetworkEditors { @JvmStatic fun getComponentControllerFactory( - instance: NetworkInstance, - expandedComponentsController: ExpandedComponentsController + instance: NetworkInstance, + expandedComponentsController: ExpandedComponentsController, + editedComponentsController: EditedModel, + iec61499Factory: IEC61499Factory, + scope: DeclarationsScope ): ComponentControllerFactory { return object : ComponentControllerFactory { override fun create(context: EditorContext, view: NetworkComponentView): ComponentController? { if (view is FunctionBlockView) { - return FunctionBlockController(context, view, instance, expandedComponentsController) + return FunctionBlockController( + context, + view, + instance, + expandedComponentsController, + editedComponentsController, + iec61499Factory, + scope + ) } if (view is InterfaceEndpointView) { return EndpointPortController(context, view) @@ -274,32 +297,4 @@ object FBNetworkEditors { } } } - - private fun getCompletion( - scope: DeclarationsScope, - factory: IEC61499Factory, - fbNetwork: FBNetwork, - scale: Float - ): List { - return scope.findAllFBTypeDeclarations().map { type: FBTypeDeclaration -> - object : PositionalCompletionItem { - override fun getMatchingText(pattern: String?): String { - return type.name - } - - override val descriptionText: String - get() { - return "create function block" - } - - override fun invoke(pattern: String?, x: Int, y: Int) { - val declaration = factory.createFunctionBlockDeclaration(StringIdentifier(type.name)) - declaration.x = (x / scale).toInt() - declaration.y = (y / scale).toInt() - declaration.typeReference.setTarget(type) - fbNetwork.functionBlocks.add(declaration) - } - } - } - } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBPortSettingProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBPortSettingProvider.kt index bdf99501e..4f51aee37 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBPortSettingProvider.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBPortSettingProvider.kt @@ -8,8 +8,9 @@ import java.awt.Point import java.awt.Rectangle import java.util.function.Function -class FBPortSettingProvider(private val myMapper: Function) : - PortSettingProvider { +class FBPortSettingProvider( + private val myMapper: Function +) : PortSettingProvider { override fun getBounds(componentForm: Point, port: NetworkPortView): Rectangle { val component = port.component val controller = myMapper.apply(component) @@ -22,6 +23,10 @@ class FBPortSettingProvider(private val myMapper: Function { + return myMapper.apply(componentForm).getFBPortTemplates() + } + override fun canBeSourcedAt(componentForm: Point, port: NetworkPortView, x: Int, y: Int): Boolean { val component = port.component val controller = myMapper.apply(component) @@ -39,4 +44,29 @@ class FBPortSettingProvider(private val myMapper: Function, + val iec61499Factory: IEC61499Factory, + scope: DeclarationsScope, ) : ComponentController, FBNetworkComponentController { private val myNameProperty: EditorCell_Property - private val cellCollection: jetbrains.mps.nodeEditor.cells.EditorCell_Collection + private val editButton: EditorCell_Button + private val cellCollection: EditorCell_Collection private val isEditable: Boolean = view.isEditable - private val fbCell: FBCell + private var fbCell: FBCell private val networkInstance: NetworkInstance override fun getFBCellBounds(position: Point): Rectangle { @@ -39,61 +62,42 @@ class FunctionBlockController( } private fun getNameProperty(context: EditorContext, view: FunctionBlockView, node: SNode): EditorCell_Property { - return EditorCell_Property( - context, - object : ModelAccessor { - override fun getText(): String? { - val name = view.component.name - return if (name == "") null else name - } + return EditorCell_Property(context, object : ModelAccessor { + override fun getText(): String? { + val name = view.component.name + return if (name == "") null else name + } - override fun setText(text: String) { - view.component.name = text - } + override fun setText(text: String) { + view.component.name = text + } - override fun isValidText(text: String): Boolean { - return true - } - }, - node - ) + override fun isValidText(text: String): Boolean { + return true + } + }, node) } - private fun createRootCell( - context: EditorContext, - node: SNode - ): jetbrains.mps.nodeEditor.cells.EditorCell_Collection { - return EditorCell_Collection( - context, - node, - object : CellLayout_Vertical() { - override fun doLayout(editorCells: EditorCell_Collection) { - super.doLayout(editorCells) - fbCell.rootCell.moveTo(cellCollection.x, cellCollection.y + lineSize) - myNameProperty.moveTo( - cellCollection.x + fbCell.width / 2 - myNameProperty.width / 2, - cellCollection.y - lineSize / 4 - ) - } - } - ) + private fun createRootCell(context: EditorContext, node: SNode): EditorCell_Collection { + return EditorCell_Collection(context, node, CellLayout_Vertical()) } private fun initializeFBSceneCell(editorShift: Point = Point()): FBCell { - return FBSceneCell( - cellCollection.context, - view.type, - view.associatedNode, - false, - networkInstance.getChild(view.component)!!, - editorShift - ) + return FBSceneCell(cellCollection.context, view.type, view.associatedNode, false, networkInstance.getChild(view.component)!!, editorShift) } private fun initializeFBCell(): FBCell { return FBTypeCellComponent(cellCollection.context, view.type, view.associatedNode, isEditable) } + private fun initializeFBEditCell(iec61499Factory: IEC61499Factory, scope: DeclarationsScope): FBCell { + return EditableFBTypeCell(cellCollection.context, view.type, view.associatedNode, iec61499Factory, scope, isEditable) + } + + private fun getEditButton(context: EditorContext, node: SNode): EditorCell_Button { + return EditorCell_Button(context, node, if (!editedController.isEdited(view)) EditButton() else TickButton()) + } + val fbInstance: FunctionBlockInstance? get() = networkInstance.getChild(view.component) @@ -114,18 +118,13 @@ class FunctionBlockController( val kind = functionBlockPort.kind val isSource = functionBlockPort.isSource val coordinates: Point = when (kind) { - EntryKind.EVENT -> if (isSource) fbCell.getOutputEventPortPosition(index) else fbCell.getInputEventPortPosition( - index - ) + EntryKind.EVENT -> if (isSource) fbCell.getOutputEventPortPosition(index) else fbCell.getInputEventPortPosition(index) - EntryKind.DATA -> if (isSource) fbCell.getOutputDataPortPosition(index) else fbCell.getInputDataPortPosition( - index - ) + EntryKind.DATA -> if (isSource) fbCell.getOutputDataPortPosition(index) else fbCell.getInputDataPortPosition(index) EntryKind.ADAPTER -> if (isSource) fbCell.getPlugPortPosition(index) else fbCell.getSocketPortPosition(index) - else -> error("") } - coordinates.translate(position.x, position.y + lineSize) + coordinates.translate(position.x, position.y + getVerticalOffset()) return coordinates } @@ -135,18 +134,13 @@ class FunctionBlockController( val kind = functionBlockPort.kind val isSource = functionBlockPort.isSource val bounds: Rectangle = when (kind) { - EntryKind.EVENT -> if (isSource) fbCell.getOutputEventPortBounds(index) else fbCell.getInputEventPortBounds( - index - ) + EntryKind.EVENT -> if (isSource) fbCell.getOutputEventPortBounds(index) else fbCell.getInputEventPortBounds(index) - EntryKind.DATA -> if (isSource) fbCell.getOutputDataPortBounds(index) else fbCell.getInputDataPortBounds( - index - ) + EntryKind.DATA -> if (isSource) fbCell.getOutputDataPortBounds(index) else fbCell.getInputDataPortBounds(index) EntryKind.ADAPTER -> if (isSource) fbCell.getPlugPortBounds(index) else fbCell.getSocketPortBounds(index) - else -> error("Unknown port kind") } - bounds.translate(position.x, position.y + lineSize) + bounds.translate(position.x, position.y + getVerticalOffset()) return bounds } @@ -155,11 +149,123 @@ class FunctionBlockController( return functionBlockPort.isSource } + override fun getTemplateBounds(template: NetworkPortView, modelForm: Point): Rectangle { + if (!editedController.isEdited(view)) { + return super.getTemplateBounds(template, modelForm) + } + + val buttons = (fbCell as EditableFBTypeCell).buttons[template.kind] + template as FunctionBlockPortView + val button = (if (template.isSource) buttons?.cells?.last() else buttons?.cells?.first()) + val bounds = Rectangle(button?.x ?: 0, button?.y ?: 0, button?.width ?: 0, (button?.height ?: 0)) + return bounds + } + + override fun getTemplatePosition(template: NetworkPortView, modelForm: Point): Point { + if (!editedController.isEdited(view)) { + return super.getTemplatePosition(template, modelForm) + } + + val buttons = (fbCell as EditableFBTypeCell).buttons[template.kind] + template as FunctionBlockPortView + val button = (if (template.isSource) buttons?.cells?.last() else buttons?.cells?.first()) + val bounds = Rectangle(button?.width ?: 0, (button?.height ?: 0) + getVerticalOffset()) + val x = bounds.x + if (template.isSource) bounds.width else 0 + val y = bounds.y + bounds.height / 2 + val point = Point(x, y) + point.translate(modelForm.x, modelForm.y + getVerticalOffset()) + return point + } + + override fun createPort(source: NetworkPortView, template: NetworkPortView): NetworkPortView? { + require(template is FunctionBlockPortView && (source is NetworkPortViewAdd)) { "invalid port" } + + if (template.isSource == source.isSource) return null + + val declaration = view.type.declaration + + if (declaration !is FBInterfaceDeclaration) return null + val name = source.target.name + + when(template.kind) { + EntryKind.EVENT -> { + val list = if (template.isSource) declaration.outputEvents else declaration.inputEvents + val identifier = PortActionFactory.identifierSupplier(name, list.map { it.name }).get() + val nEvent = iec61499Factory.createEventDeclaration(identifier) + list.add(nEvent) + (fbCell as EditableFBTypeCell).addPort(if (template.isSource) view.type.eventOutputPorts.last() else view.type.eventInputPorts.last()) + return FunctionBlockPortView(template.component, list.size - 1, EntryKind.EVENT, template.isSource, nEvent) + } + EntryKind.DATA -> { + val list = if (template.isSource) declaration.outputParameters else declaration.inputParameters + val identifier = PortActionFactory.identifierSupplier(name, list.map { it.name }).get() + val nParameter = iec61499Factory.createParameterDeclaration(identifier) + nParameter.type = (source.target as ParameterDeclaration).type + list.add(nParameter) + (fbCell as EditableFBTypeCell).addPort(if (template.isSource) view.type.dataOutputPorts.last() else view.type.dataInputPorts.last()) + return FunctionBlockPortView(template.component, list.size - 1, EntryKind.DATA, template.isSource, nParameter) + } + EntryKind.ADAPTER -> { + if (declaration !is FBInterfaceDeclarationWithAdapters) { + return null + } + if (template.isSource) { + val list = declaration.plugs + val identifier = PortActionFactory.identifierSupplier(name, list.map { it.name }).get() + val nParameter = iec61499Factory.createPlugDeclaration(identifier) + val dec = source.target as PlugDeclaration + nParameter.typeReference.setTarget(dec.typeReference.getTarget()!!) + list.add(nParameter) + (fbCell as EditableFBTypeCell).addPort(view.type.plugPorts.last()) + return FunctionBlockPortView(template.component, list.size - 1, EntryKind.ADAPTER, template.isSource, nParameter) + } + val list = declaration.sockets + val identifier = PortActionFactory.identifierSupplier(name, list.map { it.name }).get() + val nParameter = iec61499Factory.createSocketDeclaration(identifier) + val dec = source.target as SocketDeclaration + nParameter.typeReference.setTarget(dec.typeReference.getTarget()!!) + list.add(nParameter) + (fbCell as EditableFBTypeCell).addPort(view.type.socketPorts.last()) + return FunctionBlockPortView(template.component, list.size - 1, EntryKind.DATA, template.isSource, nParameter) + } + } + } + + override fun connectTo(port: NetworkPortView, source: NetworkPortView) { + if (!editedController.isEdited(view)) return + if (port.kind != source.kind || port.kind == EntryKind.EVENT) return + if (source !is FunctionBlockPortView) return + + val myPort = assertMine(port) + + if (myPort.target is ParameterDeclaration && source.target is ParameterDeclaration) { + myPort.target.type = source.target.type + } else if (myPort.target is AdapterDeclaration && source.target is AdapterDeclaration) { + val target = source.target.typeReference.getTarget() ?: return + myPort.target.typeReference.setTarget(target) + } + } + private fun assertMine(port: NetworkPortView): FunctionBlockPortView { + if (port is BrokenPortView && port.component == view) { + val descriptor = view.findPort(port.declaration!!.name, port.declaration.kind, port.isInput) + ?: throw NoEntityException("Port doesn't belong fb!") + return FunctionBlockPortView.create(view, port.declaration, descriptor) + } require(!(port.component != view || port !is FunctionBlockPortView)) { "invalid port" } return port } + private fun FunctionBlockView.findPort(name: String, kind: EntryKind, isInput: Boolean): FBPortDescriptor? { + val ports = when (kind) { + EntryKind.EVENT -> this.type.eventInputPorts to this.type.eventOutputPorts + EntryKind.DATA -> this.type.dataInputPorts to this.type.dataOutputPorts + EntryKind.ADAPTER -> this.type.socketPorts to this.type.plugPorts + } + + return (if (isInput) ports.first else ports.second).find { it.name == name } + } + override fun translateForm(originalForm: Point, dx: Int, dy: Int): Point { val position = Point(originalForm) position.translate(dx, dy) @@ -177,32 +283,88 @@ class FunctionBlockController( override fun updateCellSelection(selected: Boolean) { myNameProperty.style.set(StyleAttributes.FONT_STYLE, if (selected) Font.BOLD else Font.PLAIN) + if (selected) { + cellCollection.addEditorCellBefore(editButton, myNameProperty) + } else if (cellCollection.containsCell(editButton)) { + cellCollection.removeCell(editButton) + } + //editButton.style.set(StyleAttributes.TRANSPARENT, selected) } override fun paintTrace(g: Graphics?, form: Point) { - fbCell.paintTrace( - g!!.create() as Graphics2D, - form.x, - form.y + if (fbCell is FBTypeCellComponent) lineSize else 0 - ) + fbCell.paintTrace(g!!.create() as Graphics2D, form.x, form.y + if (fbCell is FBTypeCellComponent) getVerticalOffset() else 0) } private val lineSize: Int get() = getLineSize(cellCollection.style) + override fun getFBPortTemplates(): Set { + if (!editedController.isEdited(view)) { + return super.getFBPortTemplates() + } + + return (fbCell as EditableFBTypeCell).getPortTemplates(view) + } + init { val node = view.associatedNode cellCollection = createRootCell(context, node) cellCollection.style.set(RichEditorStyleAttributes.FB, view.component) cellCollection.isBig = true this.networkInstance = networkInstance + editButton = getEditButton(context, node) + editButton.style.set(StyleAttributes.HORIZONTAL_ALIGN, CellAlign.RIGHT) + editButton.setAction(CellActionType.CLICK, toEditModeAction()) + editButton.style.set(StyleAttributes.PADDING_BOTTOM, Padding(EditorCell_Button.OY_OFFSET.toDouble(), Measure.PIXELS)) + editButton.style.set(StyleAttributes.TRANSPARENT, true) + cellCollection.addEditorCell(editButton) myNameProperty = getNameProperty(context, view, node) myNameProperty.style.set(StyleAttributes.TEXT_COLOR, if (isEditable) MPSColors.BLACK else MPSColors.DARK_GRAY) + myNameProperty.style.set(StyleAttributes.HORIZONTAL_ALIGN, CellAlign.CENTER) cellCollection.addEditorCell(myNameProperty) + val isExpanded = expandedComponentsController.isExpanded(view) val editorShift = expandedComponentsController.getEditorShift(view) - fbCell = if (isExpanded) initializeFBSceneCell(editorShift) else initializeFBCell() + + + fbCell = if (isExpanded) initializeFBSceneCell(editorShift) else if (editedController.isEdited(view)) initializeFBEditCell(iec61499Factory, scope) else initializeFBCell() cellCollection.addEditorCell(fbCell.rootCell) fbCell.relayout() } + + private fun getVerticalOffset(): Int { + return fbCell.rootCell.y - cellCollection.y + } + + private fun toEditModeAction(): CellAction { + return object : CellAction { + override fun getDescriptionText(): String = "on click" + + override fun executeInCommand(): Boolean = true + + override fun canExecute(context: EditorContext): Boolean { + val project = ProjectProvider.getInstance(context)!! + val res = FBUsageFinder + .findUsages(project, view.component.type.declaration!!) + .filter { + it.key.identifier != networkInstance.declaration.identifier + }.map { + it.key + } + if (res.isNotEmpty()) { + Notifier.showWarning( + "This function block uses also in " + + res.joinToString { it.name } + "!", + project.project + ) + } + return true + } + + override fun execute(context: EditorContext) { + editedController.setEdited(view, !editedController.isEdited(view)) + context.editorComponent.updater.update() + } + } + } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortBase.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortBase.kt deleted file mode 100644 index 3c89edcb0..000000000 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortBase.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.fbme.ide.richediting.adapters.fbnetwork - -import org.fbme.lib.iec61499.descriptors.FBPortDescriptor -import org.fbme.lib.iec61499.fbnetwork.EntryKind - -open class PortBase(port: FBPortDescriptor) : Port { - override val connectionKind: EntryKind = port.connectionKind -} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ChangeTypeAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ChangeTypeAction.kt new file mode 100644 index 000000000..8bcbbb6ac --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ChangeTypeAction.kt @@ -0,0 +1,93 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions + +import com.intellij.util.alsoIfNull +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.utils.exceptions.CreationException +import org.fbme.ide.richediting.utils.fb.FBFactory +import org.fbme.ide.richediting.utils.fb.FBUtils +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration + +class ChangeTypeAction(cell: EditorCell, project: MPSProject) : FBNetworkAction(cell, project) { + fun apply() { + val funBlock = editedFBs.find { it.associatedNode == cell.sNode }.alsoIfNull{ + showNotification(CANT_GET_FB_CELL) + } ?: return + + when (val declaration = funBlock.type.declaration) { + is CompositeFBTypeDeclaration -> convertToBasicFB(funBlock, declaration) + is BasicFBTypeDeclaration -> convertToComposite(funBlock, declaration) + } + + Notifier.showInformation("Successfully change type!", project.project) + + cell.editorComponent.updater.update() + } + + private fun convertFB( + oldFB: FunctionBlockView, + oldDeclaration: FBTypeDeclaration, + supplier: (name: String, context: EditorContext) -> FBTypeDeclaration + ) { + val identifier = StringIdentifier(oldDeclaration.name + TMP_SUFFIX) + + val network = networkInstance.networkDeclaration + val repository = PlatformRepositoryProvider.getInstance(project) + val factory = repository.iec61499Factory + + val networkModel = (network as PlatformElement).node.model.alsoIfNull { + showNotification("""Can't convert ${oldDeclaration.name} to basic functional block!""") + } ?: return + + val type = supplier(identifier.value, cell.context) + + val createdDeclaration = factory.createFunctionBlockDeclaration(identifier) + + createdDeclaration.x = oldFB.component.x + createdDeclaration.y = oldFB.component.y + + createdDeclaration.typeReference.setTarget(type) + network.functionBlocks.replaceAll { + if (oldFB.component.type.typeName == it.type.typeName) createdDeclaration else it + } + + FBUtils.copyInterface(oldDeclaration, type, factory) + + FBUtils.replaceFBInConnections(network, oldFB.component, createdDeclaration) + + networkModel.removeRootNode((oldDeclaration as PlatformElement).node) + + createdDeclaration.name = oldFB.component.name + type.name = type.name.substringBeforeLast(TMP_SUFFIX) + editedFBsController.setEdited(FunctionBlockView(createdDeclaration, true), true) + } + + private fun convertToBasicFB(funBlock: FunctionBlockView, declaration: CompositeFBTypeDeclaration) { + try { + convertFB(funBlock, declaration, FBFactory::createBasicFunBlock) + } catch (e: CreationException) { + showNotification("Can't change type of block to basic! Exception: ${e.message}") + } + } + + private fun convertToComposite(funBlock: FunctionBlockView, declaration: BasicFBTypeDeclaration) { + try { + convertFB(funBlock, declaration, FBFactory::createCompositeFunBlock) + } catch (e: CreationException) { + showNotification("Can't change type of block to composite! Exception: ${e.message}") + } + } + + companion object { + const val CANT_GET_FB_CELL = "Couldn't find functional block!" + const val TMP_SUFFIX = "_tmp" + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CreateViewAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CreateViewAction.kt new file mode 100644 index 000000000..985e1cd2f --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CreateViewAction.kt @@ -0,0 +1,107 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions + +import com.intellij.util.alsoIfNull +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.utils.fb.FBFactory +import org.fbme.ide.richediting.utils.fb.FBUtils +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.declarations.FBInterfaceDeclaration +import org.fbme.lib.iec61499.fbnetwork.ConnectionPath +import org.fbme.lib.iec61499.fbnetwork.EntryKind +import org.fbme.lib.iec61499.fbnetwork.PortPath + +class CreateViewAction(cell: EditorCell, project: MPSProject) : FBNetworkAction(cell, project) { + fun apply() { + val funBlock = editedFBs.find { it.associatedNode == cell.sNode }.alsoIfNull{ + showNotification(CANT_GET_FB_CELL) + } ?: return + + createView(funBlock) + + cell.editorComponent.updater.update() + } + + private fun createView(functionBlockView: FunctionBlockView) { + val repository = PlatformRepositoryProvider.getInstance(project) + val factory = repository.iec61499Factory + val network = networkInstance.networkDeclaration + val oldNetworkComponent = functionBlockView.component + + val oldDeclaration = functionBlockView.type.declaration.alsoIfNull { + showNotification("Declaration of function block is null!") + } ?: return + + if (oldDeclaration !is FBInterfaceDeclaration) { + showNotification("Declaration of this is block isn't acceptable. Block should have interface!") + return + } + + val identifier = StringIdentifier(oldDeclaration.name + VIEW_SUFFIX) + + val viewType = FBFactory.createCompositeFunBlock(identifier.value, cell.context) + + val createdView = factory.createFunctionBlockDeclaration(identifier) + + createdView.typeReference.setTarget(viewType) + createdView.x = oldNetworkComponent.x + createdView.y = oldNetworkComponent.y + + network.functionBlocks.add(createdView) + + FBUtils.copyInterface(oldDeclaration, viewType, factory) + FBUtils.replaceFBInConnections(network, oldNetworkComponent, createdView) + + val oldFBDeclaration = network.functionBlocks.find { it == oldNetworkComponent } ?: return + network.functionBlocks.remove(oldFBDeclaration) + + createdView.name = oldNetworkComponent.name + VIEW_SUFFIX + + val oldFBDeclarationInNewNetwork = factory + .createFunctionBlockDeclaration(StringIdentifier(oldNetworkComponent.name)) + oldFBDeclarationInNewNetwork.x = 500 + oldFBDeclarationInNewNetwork.y = 250 + val originType = oldFBDeclaration.typeReference.getTarget() ?: return + oldFBDeclarationInNewNetwork.typeReference.setTarget(originType) + viewType.network.functionBlocks.add(oldFBDeclarationInNewNetwork) + + val oldPorts = oldFBDeclarationInNewNetwork.getAllPorts() + viewType.network.getAllPorts().forEach { + val newConnection = factory.createFBNetworkConnection(it.connectionKind) + val otherPort = oldPorts.find { + port -> FBUtils.PORT_COMPARATOR(it, port) + }?.declaration!! + + val fb = PortPath.createPortPath(oldFBDeclarationInNewNetwork, it.connectionKind, otherPort) + val view = PortPath.createPortPath(null, it.connectionKind, it.declaration!!) + + if (it.isInput) { + newConnection.sourceReference.setTarget(view) + newConnection.targetReference.setTarget(fb) + } else { + newConnection.sourceReference.setTarget(fb) + newConnection.targetReference.setTarget(view) + } + + newConnection.path = ConnectionPath(200) + + when (it.connectionKind) { + EntryKind.EVENT -> viewType.network.eventConnections.add(newConnection) + EntryKind.DATA -> viewType.network.dataConnections.add(newConnection) + EntryKind.ADAPTER -> viewType.network.adapterConnections.add(newConnection) + } + } + + editedFBsController.setEdited(FunctionBlockView(createdView, true), true) + + Notifier.showInformation("View has been created!", project.project) + } + + companion object { + const val CANT_GET_FB_CELL = "Couldn't find functional block!" + const val VIEW_SUFFIX = "View" + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandOrCollapseAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/FBNetworkAction.kt similarity index 75% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandOrCollapseAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/FBNetworkAction.kt index e29431ae1..4e548480d 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandOrCollapseAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/FBNetworkAction.kt @@ -1,25 +1,39 @@ package org.fbme.ide.richediting.adapters.fbnetwork.actions import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject import org.fbme.ide.richediting.adapters.fbnetwork.FBConnectionCursor import org.fbme.ide.richediting.adapters.fbnetwork.FBConnectionPath import org.fbme.ide.richediting.adapters.fbnetwork.FBConnectionPathSynchronizer import org.fbme.ide.richediting.adapters.fbnetwork.FBNetworkComponentSynchronizer import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.viewmodel.FunctionBlockView import org.fbme.ide.richediting.viewmodel.NetworkComponentView import org.fbme.ide.richediting.viewmodel.NetworkConnectionView import org.fbme.ide.richediting.viewmodel.NetworkPortView +import org.fbme.lib.iec61499.instances.NetworkInstance import org.fbme.scenes.controllers.SceneViewpoint import org.fbme.scenes.controllers.components.ComponentsFacility import org.fbme.scenes.controllers.diagram.ConnectionsFacility import org.fbme.scenes.controllers.diagram.DiagramController import org.fbme.scenes.controllers.diagram.DiagramFacility +import org.fbme.scenes.controllers.edited.EditedModel import java.awt.Point -abstract class ExpandOrCollapseAction protected constructor(cell: EditorCell) { +abstract class FBNetworkAction protected constructor(protected val cell: EditorCell, protected val project: MPSProject) { @JvmField protected val selectedFBs: Set + @JvmField + protected val editedFBs: List + + @JvmField + protected val editedFBsController: EditedModel + + @JvmField + protected val networkInstance: NetworkInstance + @JvmField protected val componentsFacility: ComponentsFacility @@ -41,9 +55,16 @@ abstract class ExpandOrCollapseAction protected constructor(cell: EditorCell) { @JvmField protected val connectionSynchronizer: FBConnectionPathSynchronizer + protected fun showNotification(message: String) { + Notifier.showWarning(message, project.project) + } + init { val style = cell.style selectedFBs = style.get(RichEditorStyleAttributes.SELECTED_FBS).selectedComponents + editedFBs = style.get(RichEditorStyleAttributes.EDITED_FBS).editedComponents + editedFBsController = style.get(RichEditorStyleAttributes.EDITED_FBS) + networkInstance = style.get(RichEditorStyleAttributes.NETWORK_INSTANCE) componentsFacility = style.get(RichEditorStyleAttributes.COMPONENTS_FACILITY) as ComponentsFacility connectionsFacility = style.get(RichEditorStyleAttributes.CONNECTIONS_FACILITY) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/NetworkExtractorAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/NetworkExtractorAction.kt new file mode 100644 index 000000000..59d449ed0 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/NetworkExtractorAction.kt @@ -0,0 +1,206 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions + +import com.intellij.util.alsoIfNull +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.fbnetwork.* + +class NetworkExtractorAction(cell: EditorCell, project: MPSProject) : FBNetworkAction(cell, project) { + fun apply() { + val funBlock = editedFBs.find { it.associatedNode == cell.sNode }.alsoIfNull{ + showNotification(CANT_GET_FB_CELL) + } ?: return + + extractNetwork(funBlock) + + cell.editorComponent.updater.update() + } + + private fun extractNetwork(funBlock: FunctionBlockView) { + val network = networkInstance.networkDeclaration + val repository = PlatformRepositoryProvider.getInstance(project) + val factory = repository.iec61499Factory + + val declaration = + repository + .declarationsScope + .findCompositeFBTypeDeclaration(funBlock.component.type.declaration!!.identifier).alsoIfNull { + Notifier.showWarning("Couldn't find composite block to deconstruct!") + } ?: return + + val compositeNetwork = declaration.network + + //Add blocks from composite blocks to network + val blocksViews = addBlocksFromComposite(funBlock, compositeNetwork, network, factory) + + //Add connections to added blocks + val creatingConnections: MutableList = mutableListOf() + val connectionsToComposite: MutableList = mutableListOf() + + addConnectionsToInternalNetwork( + network, + funBlock, + connectionsToComposite, + compositeNetwork, + factory, + blocksViews, + creatingConnections + ) + + network.eventConnections.addAll(creatingConnections.filter { it.kind == EntryKind.EVENT }) + network.dataConnections.addAll(creatingConnections.filter { it.kind == EntryKind.DATA }) + network.adapterConnections.addAll(creatingConnections.filter { it.kind == EntryKind.ADAPTER }) + + //Delete old connections to composite block + network.eventConnections.removeAll(connectionsToComposite) + network.dataConnections.removeAll(connectionsToComposite) + network.adapterConnections.removeAll(connectionsToComposite) + + //Delete composite block from network + network.functionBlocks.remove(funBlock.component) + } + + private fun addConnectionsToInternalNetwork( + network: FBNetwork, + funBlock: FunctionBlockView, + connectionsToComposite: MutableList, + compositeNetwork: FBNetwork, + factory: IEC61499Factory, + blocksViews: Map, + creatingConnections: MutableList + ) { + val map: MutableMap>> = HashMap() + + network.allConnections.forEach { + if (it.targetReference.getTarget()?.functionBlock == funBlock.component + || it.sourceReference.getTarget()?.functionBlock == funBlock.component) { + connectionsToComposite.add(it) + } + } + + compositeNetwork.allConnections.forEach { + val target = it.targetReference.getTarget() ?: return@forEach + val source = it.sourceReference.getTarget() ?: return@forEach + + if (source.functionBlock == null && target.functionBlock == null) return@forEach + + if (source.functionBlock != null && target.functionBlock != null) { + val newConnection = factory.createFBNetworkConnection(it.kind) + newConnection.targetReference.setTarget( + PortPath.createPortPath(blocksViews[target.functionBlock]!!, it.kind, target.portTarget)) + newConnection.sourceReference.setTarget( + PortPath.createPortPath(blocksViews[source.functionBlock]!!, it.kind, source.portTarget)) + newConnection.path = it.path + creatingConnections.add(newConnection) + } + + if (source.functionBlock == null) { + if (map[source.portTarget] == null) { + map[source.portTarget] = mutableListOf() + } + + map[source.portTarget]!!.add(target.portTarget to (target.functionBlock as FunctionBlockDeclaration)) + + connectionsToComposite.filterNot { + it.sourceReference.getTarget()?.functionBlock == it.targetReference.getTarget()?.functionBlock + }.forEach { connToComposite -> + val cTarget = connToComposite.targetReference.getTarget() + val cSource = connToComposite.sourceReference.getTarget() + + if (cTarget?.portTarget == source.portTarget && cSource != null) { + val newConnection = factory.createFBNetworkConnection(it.kind) + newConnection.targetReference.setTarget( + PortPath.createPortPath(blocksViews[target.functionBlock]!!, it.kind, target.portTarget) + ) + newConnection.path = it.path + newConnection.sourceReference.setTarget( + PortPath.createPortPath(cSource.functionBlock, it.kind, cSource.portTarget) + ) + creatingConnections.add(newConnection) + } + } + } + + if (target.functionBlock == null) { + if (map[target.portTarget] == null) { + map[target.portTarget] = mutableListOf() + } + + map[target.portTarget]!!.add(source.portTarget to (source.functionBlock as FunctionBlockDeclaration)) + + connectionsToComposite.filterNot { + it.sourceReference.getTarget()?.functionBlock == it.targetReference.getTarget()?.functionBlock + }.forEach { connToComposite -> + val cSource = connToComposite.sourceReference.getTarget() + val cTarget = connToComposite.targetReference.getTarget() + + if (cSource?.portTarget == target.portTarget && cTarget != null) { + val newConnection = factory.createFBNetworkConnection(it.kind) + newConnection.sourceReference.setTarget( + PortPath.createPortPath(blocksViews[target.functionBlock]!!, it.kind, target.portTarget) + ) + newConnection.path = it.path + newConnection.targetReference.setTarget( + PortPath.createPortPath(cTarget.functionBlock, it.kind, cTarget.portTarget)) + creatingConnections.add(newConnection) + } + } + } + } + + connectionsToComposite.filter { + it.sourceReference.getTarget()?.functionBlock == it.targetReference.getTarget()?.functionBlock + }.forEach { + val source = it.sourceReference.getTarget() ?: return@forEach + val target = it.targetReference.getTarget() ?: return@forEach + val targetList = map[target.portTarget] + val sourceList = map[source.portTarget] + + targetList?.forEach{(tPort, tFb) -> + sourceList?.forEach {(sPort, sFb) -> + val newConnection = factory.createFBNetworkConnection(it.kind) + newConnection.sourceReference.setTarget( + PortPath.createPortPath(blocksViews[sFb]!!, it.kind, sPort) + ) + newConnection.targetReference.setTarget( + PortPath.createPortPath(blocksViews[tFb]!!, it.kind, tPort) + ) + newConnection.path = ConnectionPath(30, 300, 30) + creatingConnections.add(newConnection) + } + } + } + } + + private fun addBlocksFromComposite( + funBlock: FunctionBlockView, + compositeNetwork: FBNetwork, + network: FBNetwork, + factory: IEC61499Factory + ): Map { + val blocksViews = compositeNetwork.functionBlocks.associateWith { + val identifier = StringIdentifier("${funBlock.component.name}_${it.name}") + val newView = factory.createFunctionBlockDeclaration(identifier) + newView.typeReference.setTarget(it.typeReference.getTarget()!!) + newView.x = it.x + funBlock.component.x + newView.y = it.y + funBlock.component.y + newView + } + + blocksViews.values.forEach { + network.functionBlocks.add(it) + } + + return blocksViews + } + + companion object { + const val CANT_GET_FB_CELL = "Couldn't find functional block!" + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DeclarationNameAccessor.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DeclarationNameAccessor.kt new file mode 100644 index 000000000..3f8b76d2d --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DeclarationNameAccessor.kt @@ -0,0 +1,18 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions.cell + +import jetbrains.mps.nodeEditor.cells.ModelAccessor +import org.fbme.lib.common.Declaration +import java.util.function.Predicate + +class DeclarationNameAccessor( + val declaration: Declaration?, + private val validator: Predicate = Predicate { true } +) : ModelAccessor { + override fun getText(): String = declaration?.name ?: "" + + override fun setText(text: String?) { + declaration?.name = text ?: "" + } + + override fun isValidText(text: String?): Boolean = validator.test(text) +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DefaultAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DefaultAction.kt new file mode 100644 index 000000000..a959f6a6e --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/DefaultAction.kt @@ -0,0 +1,10 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions.cell + +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.CellAction + +abstract class DefaultAction(val executeInCommand: Boolean, var canExecute: Boolean) : CellAction { + override fun executeInCommand(): Boolean = executeInCommand + + override fun canExecute(context: EditorContext?): Boolean = canExecute +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/ShowSubstituteChooserAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/ShowSubstituteChooserAction.kt new file mode 100644 index 000000000..7b0ab6675 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/ShowSubstituteChooserAction.kt @@ -0,0 +1,18 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions.cell + +import jetbrains.mps.nodeEditor.EditorComponent +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.EditorCell + +open class ShowSubstituteChooserAction( + val cell: EditorCell, + canExecute: Boolean = true, + executeInCommand: Boolean = true, +) : DefaultAction(executeInCommand = executeInCommand, canExecute = canExecute) { + override fun getDescriptionText(): String = "Show suggestion tab" + + override fun execute(context: EditorContext?) { + val ec = context?.editorComponent as? EditorComponent + ec?.activateNodeSubstituteChooser(cell, true, true) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/AddPortAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/AddPortAction.kt new file mode 100644 index 000000000..510b9b16e --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/AddPortAction.kt @@ -0,0 +1,24 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.port + +import jetbrains.mps.openapi.editor.EditorContext +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.DefaultAction +import java.util.function.Supplier + +open class AddPortAction( + private val descriptionText: String, + private val portsDescription: MutableList, + private val portFactory: Supplier, + canExecute: Boolean = true, + executeInCommand: Boolean = true, +) : DefaultAction(canExecute = canExecute, executeInCommand = executeInCommand) { + override fun getDescriptionText(): String = descriptionText + + override fun execute(context: EditorContext?) { + context ?: return + + context.repository.modelAccess.runWriteInEDT { + portsDescription.add(portFactory.get()) + context.editorComponent.updater.update() + } + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/DeletePortAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/DeletePortAction.kt new file mode 100644 index 000000000..053f2c014 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/cell/port/DeletePortAction.kt @@ -0,0 +1,35 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.port + +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.style.Style +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.DefaultAction +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor + +class DeletePortAction( + private val port: FBPortDescriptor, + private val ports: MutableList, + private val style: Style +): DefaultAction(canExecute = false, executeInCommand = true) { + override fun getDescriptionText(): String = "Delete port" + + override fun canExecute(context: EditorContext?): Boolean { + return port.declaration?.name.isNullOrEmpty() + } + + override fun execute(context: EditorContext?) { + context ?: return + val networkInstance = style.get(RichEditorStyleAttributes.NETWORK_INSTANCE) ?: return + + context.repository.modelAccess.executeCommandInEDT { + networkInstance.networkDeclaration.getConnections(port.connectionKind).removeAll { + val reference = if (port.isInput) it.targetReference else it.sourceReference + reference.getTarget()?.portTarget == port.declaration + } + + ports.remove(port.declaration) + context.editorComponent.updater.update() + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CollapseAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/CollapseAction.kt similarity index 76% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CollapseAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/CollapseAction.kt index 0160a912a..070189ac2 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/CollapseAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/CollapseAction.kt @@ -1,10 +1,12 @@ -package org.fbme.ide.richediting.adapters.fbnetwork.actions +package org.fbme.ide.richediting.adapters.fbnetwork.actions.expand import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.project.MPSProject import org.fbme.ide.richediting.adapters.fbnetwork.FunctionBlockController +import org.fbme.ide.richediting.adapters.fbnetwork.actions.FBNetworkAction import org.fbme.ide.richediting.viewmodel.FunctionBlockView -class CollapseAction(cell: EditorCell) : ExpandOrCollapseAction(cell.parent) { +class CollapseAction(cell: EditorCell, project: MPSProject) : FBNetworkAction(cell.parent, project) { fun apply() { collapse(selectedFBs.filterIsInstance()) } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/ExpandAction.kt similarity index 94% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandAction.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/ExpandAction.kt index cf15c357a..c3934782f 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/ExpandAction.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/actions/expand/ExpandAction.kt @@ -1,10 +1,12 @@ -package org.fbme.ide.richediting.adapters.fbnetwork.actions +package org.fbme.ide.richediting.adapters.fbnetwork.actions.expand import jetbrains.mps.editor.runtime.HeadlessEditorComponent import jetbrains.mps.openapi.editor.cells.EditorCell import jetbrains.mps.openapi.editor.style.Style +import jetbrains.mps.project.MPSProject import org.fbme.ide.iec61499.repository.PlatformElement import org.fbme.ide.richediting.adapters.fbnetwork.FunctionBlockController +import org.fbme.ide.richediting.adapters.fbnetwork.actions.FBNetworkAction import org.fbme.ide.richediting.viewmodel.FunctionBlockView import org.fbme.ide.richediting.viewmodel.InterfaceEndpointView import org.fbme.ide.richediting.viewmodel.NetworkComponentView @@ -16,7 +18,7 @@ import org.jetbrains.mps.openapi.module.SRepository import java.awt.Point import java.awt.Rectangle -class ExpandAction(cell: EditorCell) : ExpandOrCollapseAction(cell) { +class ExpandAction(cell: EditorCell, project: MPSProject) : FBNetworkAction(cell, project) { fun apply() { val functionBlock = selectedFBs.filterIsInstance().last() functionBlock.expand() diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/AbstractFBCell.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/AbstractFBCell.kt index 2fd9a137f..0060813d2 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/AbstractFBCell.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/AbstractFBCell.kt @@ -2,8 +2,8 @@ package org.fbme.ide.richediting.adapters.fbnetwork.fb import jetbrains.mps.nodeEditor.EditorSettings import jetbrains.mps.openapi.editor.EditorContext -import org.fbme.ide.richediting.adapters.fbnetwork.Port -import org.fbme.ide.richediting.adapters.fbnetwork.PortBase +import org.fbme.ide.richediting.adapters.fbnetwork.port.Port +import org.fbme.ide.richediting.adapters.fbnetwork.port.PortBase import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor import org.fbme.scenes.cells.EditorCell_SceneLabel @@ -75,53 +75,29 @@ abstract class AbstractFBCell protected constructor( relayoutChildren() } - override fun getInputEventPortPosition(eventNumber: Int): Point { + protected open fun getPortPosition(bounds: Rectangle, isOutput: Boolean = false): Point { val lineSize = lineSize - val bounds = getInputEventPortBounds(eventNumber) - val x = bounds.x - scale(PORT_SIZE) / 2 + val xOffset = if (isOutput) bounds.width + scale(PORT_SIZE) / 2 else - scale(PORT_SIZE) / 2 + val x = bounds.x + xOffset val y = bounds.y + lineSize / 2 return Point(x, y) } - override fun getOutputEventPortPosition(eventNumber: Int): Point { - val lineSize = lineSize - val bounds = getOutputEventPortBounds(eventNumber) - val x = bounds.x + bounds.width + scale(PORT_SIZE) / 2 - val y = bounds.y + lineSize / 2 - return Point(x, y) - } + override fun getInputEventPortPosition(eventNumber: Int): Point = + getPortPosition(getInputEventPortBounds(eventNumber)) - override fun getInputDataPortPosition(dataNumber: Int): Point { - val lineSize = lineSize - val bounds = getInputDataPortBounds(dataNumber) - val x = bounds.x - scale(PORT_SIZE) / 2 - val y = bounds.y + lineSize / 2 - return Point(x, y) - } + override fun getOutputEventPortPosition(eventNumber: Int): Point = + getPortPosition(getOutputEventPortBounds(eventNumber), isOutput = true) - override fun getOutputDataPortPosition(dataNumber: Int): Point { - val lineSize = lineSize - val bounds = getOutputDataPortBounds(dataNumber) - val x = bounds.x + bounds.width + scale(PORT_SIZE) / 2 - val y = bounds.y + lineSize / 2 - return Point(x, y) - } + override fun getInputDataPortPosition(dataNumber: Int): Point = getPortPosition(getInputDataPortBounds(dataNumber)) - override fun getSocketPortPosition(dataNumber: Int): Point { - val lineSize = lineSize - val bounds = getSocketPortBounds(dataNumber) - val x = bounds.x - scale(PORT_SIZE) / 2 - val y = bounds.y + lineSize / 2 - return Point(x, y) - } + override fun getOutputDataPortPosition(dataNumber: Int): Point = + getPortPosition(getOutputDataPortBounds(dataNumber), isOutput = true) - override fun getPlugPortPosition(dataNumber: Int): Point { - val lineSize = lineSize - val bounds = getPlugPortBounds(dataNumber) - val x = bounds.x + bounds.width + scale(PORT_SIZE) / 2 - val y = bounds.y + lineSize / 2 - return Point(x, y) - } + override fun getSocketPortPosition(dataNumber: Int): Point = getPortPosition(getSocketPortBounds(dataNumber)) + + override fun getPlugPortPosition(dataNumber: Int): Point = + getPortPosition(getPlugPortBounds(dataNumber), isOutput = true) protected fun initPorts() { initPorts(inputEventPorts, fbType.eventInputPorts) @@ -181,7 +157,7 @@ abstract class AbstractFBCell protected constructor( return EditorCell_SceneLabel(context, node, fbType.typeName, typeDeclaration == null) } - protected fun getComponentShape(x: Int, y: Int): GeneralPath { + protected open fun getComponentShape(x: Int, y: Int): GeneralPath { val shape = GeneralPath() val eventPortsCount = eventPortsCount val lineSize = lineSize diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/EditableFBTypeCell.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/EditableFBTypeCell.kt new file mode 100644 index 000000000..9ddcc083f --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/EditableFBTypeCell.kt @@ -0,0 +1,529 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.fb + +import jetbrains.mps.editor.runtime.style.CellAlign +import jetbrains.mps.editor.runtime.style.Measure +import jetbrains.mps.editor.runtime.style.Padding +import jetbrains.mps.editor.runtime.style.StyleAttributes +import jetbrains.mps.nodeEditor.MPSColors +import jetbrains.mps.nodeEditor.cellLayout.CellLayout_Horizontal +import jetbrains.mps.nodeEditor.cellLayout.CellLayout_Vertical +import jetbrains.mps.nodeEditor.cells.EditorCell_Collection +import jetbrains.mps.nodeEditor.cells.EditorCell_Property +import jetbrains.mps.nodeEditor.cells.ParentSettings +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.CellAction +import jetbrains.mps.openapi.editor.cells.CellActionType +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.openapi.editor.style.StyleAttribute +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.richediting.adapters.fbnetwork.FBConnectionPathPainter +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.DeclarationNameAccessor +import org.fbme.ide.richediting.adapters.fbnetwork.port.EditablePortLabel +import org.fbme.ide.richediting.adapters.fbnetwork.port.EditablePortWithTypeAndLabel +import org.fbme.ide.richediting.adapters.fbnetwork.port.Port +import org.fbme.ide.richediting.adapters.fbnetwork.port.PortActionFactory +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.viewmodel.FunctionBlockPortView +import org.fbme.ide.richediting.viewmodel.FunctionBlockView +import org.fbme.ide.richediting.viewmodel.NetworkPortView +import org.fbme.lib.iec61499.DeclarationsScope +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor +import org.fbme.lib.iec61499.fbnetwork.EntryKind +import org.fbme.lib.iec61499.instances.NetworkInstance +import org.fbme.lib.st.types.DataType +import org.fbme.scenes.cells.EditorCell_Button +import org.fbme.scenes.cells.button.PlusButton +import org.fbme.scenes.viewmodel.CompletionItem +import org.jetbrains.mps.openapi.model.SNode +import java.awt.* +import java.awt.geom.AffineTransform +import java.awt.geom.GeneralPath +import java.util.* +import kotlin.math.max + +class EditableFBTypeCell( + context: EditorContext, + fbType: FBTypeDescriptor, + node: SNode, + val iec61499Factory: IEC61499Factory, + val scope: DeclarationsScope, + isEditable: Boolean, +) : AbstractFBCell(context, fbType, node, isEditable) { + + private val typeNameLabel: EditorCell_Property + + override val rootCell: EditorCell_Collection + val buttons: EnumMap + private val eventPortsContainer: EditorCell_Collection + private val dataPortsContainer: EditorCell_Collection + private val otherPortsContainer: EditorCell_Collection + + private val inputPorts: Set + get() = inputEventPorts.union(inputDataPorts).union(socketPorts) + private val outputPorts: Set + get() = outputEventPorts.union(outputDataPorts).union(plugPorts) + private val backgroundColor: Color + get() { + val background = rootCell.style.get(StyleAttributes.BACKGROUND_COLOR) + return background ?: MPSColors.LIGHT_GRAY + } + private val typeBackgroundColor: Color + get() = MPSColors.LIGHT_BLUE + private val foregroundColor: Color + get() = rootCell.style.get(StyleAttributes.TEXT_COLOR) + + init { + val declaration = fbType.declaration + + rootCell = createRootCell() + rootCell.style.set(RichEditorStyleAttributes.TYPE, fbType) + + buttons = EnumMap(EntryKind::class.java) + + eventPortsContainer = createPortContainer(fbType.eventInputPorts, fbType.eventOutputPorts, inputEventPorts, outputEventPorts, ::createPortBlock) + typeNameLabel = createNameLabel() + dataPortsContainer = createPortContainer(fbType.dataInputPorts, fbType.dataOutputPorts, inputDataPorts, outputDataPorts, ::createDataPortBlock) + otherPortsContainer = createPortContainer(fbType.socketPorts, fbType.plugPorts, socketPorts, plugPorts, ::createPlugSocketPortBlock) + + rootCell.addEditorCell(eventPortsContainer) + if (declaration is FBInterfaceDeclaration) { + buttons[EntryKind.EVENT] = createButtonContainer(PortActionFactory.createInputEventAction(declaration, iec61499Factory), PortActionFactory.createOutputEventAction(declaration, iec61499Factory)) + + rootCell.addEditorCell(buttons[EntryKind.EVENT]) + } + rootCell.addEditorCell(typeNameLabel) + rootCell.addEditorCell(dataPortsContainer) + if (declaration is FBInterfaceDeclaration) { + buttons[EntryKind.DATA] = createButtonContainer(PortActionFactory.createInputParameterAction(declaration, iec61499Factory), PortActionFactory.createOutputParameterAction(declaration, iec61499Factory)) + + rootCell.addEditorCell(buttons[EntryKind.DATA]) + } + rootCell.addEditorCell(otherPortsContainer) + if (declaration is FBInterfaceDeclarationWithAdapters) { + buttons[EntryKind.ADAPTER] = createButtonContainer(PortActionFactory.createSocketAction(declaration, iec61499Factory), PortActionFactory.createPluginAction(declaration, iec61499Factory)) + + rootCell.addEditorCell(buttons[EntryKind.ADAPTER]) + } + rootCell.style.set(StyleAttributes.TEXT_COLOR, if (isEditable) MPSColors.BLACK else MPSColors.DARK_GRAY) + } + + private fun createButtonContainer(inputAction: CellAction, outputAction: CellAction): EditorCell_Collection { + val container = object : EditorCell_Collection(context, node, CellLayout_Horizontal()) {} + + val leftButton = createButton(inputAction) + val rightButton = createButton(outputAction) + + container.style.set(StyleAttributes.HORIZONTAL_ALIGN, CellAlign.CENTER) + + container.addEditorCell(leftButton) + container.addEditorCell(rightButton) + + return container + } + + private fun createButton(cellAction: CellAction): EditorCell { + val button = EditorCell_Button(context, node, PlusButton()) + + button.setAction(CellActionType.CLICK, cellAction) + + return button + } + + private fun createPortContainer( + input: List, + output: List, + inputList: MutableList, + outputList: MutableList, + creator: ( + portsDescriptors: List, + ports: MutableList, + horizontalAlign: CellAlign, + padding: StyleAttribute, + ) -> EditorCell_Collection, + ): EditorCell_Collection { + val container = object : EditorCell_Collection(context, node, CellLayout_Horizontal()) {} + + val inputContainer = creator(input, inputList, CellAlign.LEFT, StyleAttributes.PADDING_LEFT) + val outputContainer = creator(output, outputList, CellAlign.RIGHT, StyleAttributes.PADDING_RIGHT) + + container.addEditorCell(inputContainer) + container.addEditorCell(outputContainer) + + container.style.set(StyleAttributes.HORIZONTAL_ALIGN, CellAlign.CENTER) + + return container + } + + private fun createPortBlock( + portsDescriptors: List, + ports: MutableList, + horizontalAlign: CellAlign, + padding: StyleAttribute, + ): EditorCell_Collection { + val block = object : EditorCell_Collection(context, node, CellLayout_Vertical()) {} + + for (port in portsDescriptors) { + val portWithLabel = EditablePortLabel(context, node, port, fbType.declaration) + portWithLabel.label.style.set(StyleAttributes.HORIZONTAL_ALIGN, horizontalAlign) + portWithLabel.label.style.set(padding, Padding(INNER_BORDER_PADDING.toDouble(), Measure.PIXELS)) + ports.add(portWithLabel) + block.addEditorCell(portWithLabel.label) + } + + return block + } + + fun addPort(port: FBPortDescriptor) { + when (port.connectionKind) { + EntryKind.EVENT -> { + val value = EditablePortLabel(context, node, port, fbType.declaration) + if (port.isInput) { + (eventPortsContainer.cells.first() as EditorCell_Collection).addEditorCell(value.label) + inputEventPorts.add(value) + } else { + (eventPortsContainer.cells.last() as EditorCell_Collection).addEditorCell(value.label) + outputEventPorts.add(value) + } + } + + EntryKind.DATA -> { + val typeDeclaration = port.declaration as ParameterDeclaration + val value = EditablePortWithTypeAndLabel(context, node, port, fbType.declaration, typeDeclaration.type?.stringify(), getDataTypeSuggestions(typeDeclaration)) + if (port.isInput) { + (dataPortsContainer.cells.first() as EditorCell_Collection).addEditorCell(value.cell) + inputDataPorts.add(value) + } else { + (dataPortsContainer.cells.last() as EditorCell_Collection).addEditorCell(value.cell) + outputDataPorts.add(value) + } + } + + EntryKind.ADAPTER -> { + val types = scope.findAllAdapterTypeDeclarations() + if (port.isInput) { + addPlugSocketPort(port, socketPorts, otherPortsContainer.cells.first() as EditorCell_Collection, types, CellAlign.LEFT, StyleAttributes.PADDING_LEFT) + } else { + addPlugSocketPort(port, plugPorts, otherPortsContainer.cells.last() as EditorCell_Collection, types, CellAlign.RIGHT, StyleAttributes.PADDING_RIGHT) + } + } + } + } + + private fun createDataPortBlock( + portsDescriptors: List, + ports: MutableList, + horizontalAlign: CellAlign, + padding: StyleAttribute, + ): EditorCell_Collection { + val block = object : EditorCell_Collection(context, node, CellLayout_Vertical()) {} + + for (port in portsDescriptors) { + val typeDeclaration = port.declaration as ParameterDeclaration + val portWithLabel = EditablePortWithTypeAndLabel(context, node, port, fbType.declaration, typeDeclaration.type?.stringify(), getDataTypeSuggestions(typeDeclaration)) + portWithLabel.label.style.set(StyleAttributes.HORIZONTAL_ALIGN, horizontalAlign) + portWithLabel.label.style.set(padding, Padding(INNER_BORDER_PADDING.toDouble(), Measure.PIXELS)) + ports.add(portWithLabel) + block.addEditorCell(portWithLabel.cell) + } + + return block + } + + private fun getDataTypeSuggestions(typeDeclaration: ParameterDeclaration): List { + return DataType.getAllValues().map { + object : CompletionItem { + override fun getMatchingText(pattern: String?): String = it.stringify() + + override val descriptionText: String = "" + + override fun doSubstitute(editorContext: EditorContext?, pattern: String?): SNode? { + typeDeclaration.type = it + return null + } + } + } + } + + private fun createPlugSocketPortBlock( + portsDescriptors: List, + ports: MutableList, + horizontalAlign: CellAlign, + padding: StyleAttribute, + ): EditorCell_Collection { + val block = object : EditorCell_Collection(context, node, CellLayout_Vertical()) {} + val types = scope.findAllAdapterTypeDeclarations() + + for (port in portsDescriptors) { + addPlugSocketPort(port, ports, block, types, horizontalAlign, padding) + } + + return block + } + + fun addPlugSocketPort(port: FBPortDescriptor, ports: MutableList, block: EditorCell_Collection, types: List, horizontalAlign: CellAlign, + padding: StyleAttribute) { + val typeDeclaration = port.declaration as AdapterDeclaration + val items = types.map { + object : CompletionItem { + override fun getMatchingText(pattern: String?): String = it.name + + override val descriptionText: String = "" + + override fun doSubstitute(editorContext: EditorContext?, pattern: String?): SNode? { + typeDeclaration.typeReference.setTarget(it) + return null + } + } + } + val portWithLabel = EditablePortWithTypeAndLabel(context, node, port, fbType.declaration, typeDeclaration.typeReference.presentation, items) + portWithLabel.label.style.set(StyleAttributes.HORIZONTAL_ALIGN, horizontalAlign) + portWithLabel.label.style.set(padding, Padding(INNER_BORDER_PADDING.toDouble(), Measure.PIXELS)) + ports.add(portWithLabel) + block.addEditorCell(portWithLabel.cell) + } + + private fun createRootCell(): EditorCell_Collection { + return object : EditorCell_Collection(context, node, object : CellLayout_Vertical() { + override fun doLayout(editorCells: jetbrains.mps.openapi.editor.cells.EditorCell_Collection?) { + super.doLayout(editorCells) + relayout() + } + }) { + + + override fun paintContent(g: Graphics, parentSettings: ParentSettings) { + this@EditableFBTypeCell.paint(g.create() as Graphics2D) + } + + override fun paintSelection(g: Graphics, c: Color, drawBorder: Boolean, parentSettings: ParentSettings) { // do noting + } + + override fun findLeaf(x: Int, y: Int): EditorCell? { + val leaf = super.findLeaf(x, y) + if (leaf != null) { + return leaf + } + return if (Rectangle(myX, myY, myWidth, myHeight).contains(x, y)) { + this + } else null + } + + override fun onAdd() { + super.onAdd() + installNavigatable() + setAction(CellActionType.BACKSPACE, parent.parent.getAction(CellActionType.BACKSPACE)) + } + } + } + + private fun paint(graphics: Graphics2D) { + val background = backgroundColor + val foreground = foregroundColor + drawComponentShape(graphics, background, foreground) + drawPortIcons(graphics, foreground) + } + + private fun drawPortIcons(graphics: Graphics2D, color: Color?) { + drawPortIcons(graphics, rootCell.x - scale(PORT_SIZE), inputPorts, color) + drawPortIcons(graphics, rootCell.x + rootCell.width, outputPorts, color) + } + + private fun drawPortIcons(graphics: Graphics2D, x: Int, ports: Set, color: Color?) { + for (port in ports) { + val portWithLabel = port as EditablePortLabel + val y = portWithLabel.label.y + portWithLabel.label.height / 2 - scale(PORT_SIZE) / 2 + val form = Rectangle(x, y, scale(PORT_SIZE), scale(PORT_SIZE)) + + graphics.color = DiagramColors.getColorFor(port.connectionKind, isEditable) + graphics.fill(form) + graphics.color = color + graphics.draw(form) + } + } + + private fun drawComponentShape(graphics: Graphics2D, background: Color, foreground: Color) { + val x = rootCell.x + val y = rootCell.y + val shape = getComponentShape(x, y) + val shadowShape = shape.createTransformedShape(AffineTransform.getTranslateInstance(2.0, 2.0)) + graphics.paint = Color(0xEEEEEE) + graphics.fill(shadowShape) + graphics.paint = DiagramColors.createGradientPaint(background, Rectangle(x, y, rootCell.width, rootCell.height)) + graphics.fill(shape) + graphics.paint = DiagramColors.createGradientPaint(typeBackgroundColor, Rectangle(x, y, rootCell.width, rootCell.height)) + graphics.fill(Rectangle(x, typeNameLabel.y + lineSize / 2, rootCell.width, typeNameLabel.height - lineSize)) + graphics.stroke = BasicStroke(scale(1).toFloat()) + graphics.color = foreground + graphics.draw(shape) + } + + override fun getComponentShape(x: Int, y: Int): GeneralPath { + val shape = GeneralPath() + val lineSize = lineSize.toDouble() + val width = rootCell.width.toDouble() + val height = rootCell.height.toDouble() + val xRight = x + width + val yTop = y + height + val yCenterB = typeNameLabel.y - lineSize / 2 + val yCenterT = typeNameLabel.y + lineSize / 2 + val xLeftS = x + PLUS_BUTTON_SIZE.toDouble() + val xRightS = xRight - PLUS_BUTTON_SIZE.toDouble() + shape.moveTo(x.toDouble(), y.toDouble()) + shape.lineTo(x.toDouble(), yCenterB) + shape.lineTo(xLeftS, yCenterB) + shape.lineTo(xLeftS, yCenterT) + shape.lineTo(x.toDouble(), yCenterT) + shape.lineTo(x.toDouble(), yTop) + shape.lineTo(xRight, yTop) + shape.lineTo(xRight, yCenterT) + shape.lineTo(xRightS, yCenterT) + shape.lineTo(xRightS, yCenterB) + shape.lineTo(xRight, yCenterB) + shape.lineTo(xRight, y.toDouble()) + shape.closePath() + return shape + } + + private fun installNavigatable() { + val style = typeNameLabel.style + val instance = style.get(RichEditorStyleAttributes.NETWORK_INSTANCE) + if (instance != null) { + val functionBlock = style.get(RichEditorStyleAttributes.FB) + val child = instance.getChild(functionBlock!!) + if (child != null) { + val childNetworkInstance = child.containedNetwork + if (childNetworkInstance is NetworkInstance) { + //val navigationStub = NetworkInstanceNavigationSupport.getNavigationStub(rootCell.context.operationContext.project, childNetworkInstance) + val typeDeclaration = style.get(RichEditorStyleAttributes.TYPE).declaration + //style.set(StyleAttributes.NAVIGATABLE_NODE, navigationStub) + style.set(StyleAttributes.NAVIGATABLE_NODE, (typeDeclaration as PlatformElement).node) + return + } + } + } + val typeDeclaration = style.get(RichEditorStyleAttributes.TYPE).declaration + if (typeDeclaration is PlatformElement) { + style.set(StyleAttributes.NAVIGATABLE_NODE, (typeDeclaration as PlatformElement).node) + } + } + + override fun paintTrace(g: Graphics2D, x: Int, y: Int) { + val shape = getComponentShape(x, rootCell.y) + g.paint = MPSColors.GRAY + FBConnectionPathPainter.setupShadowPathPaint(g, scale(1).toFloat()) + g.draw(shape) + } + + private fun getPortBounds(port: Port, isOutput: Boolean = false): Rectangle { + val editablePort = port as EditablePortLabel + + val width = editablePort.label.width + scale(INNER_BORDER_PADDING) + val y = editablePort.label.y - rootCell.y + + val x = if (isOutput) rootCell.width - width else 0 + + return Rectangle(x, y, width, editablePort.label.height) + } + + override fun getInputEventPortBounds(eventNumber: Int): Rectangle = getPortBounds(inputEventPorts[eventNumber]) + + override fun getOutputEventPortBounds(eventNumber: Int): Rectangle = getPortBounds(outputEventPorts[eventNumber], true) + + override fun getInputDataPortBounds(dataNumber: Int): Rectangle = getPortBounds(inputDataPorts[dataNumber]) + + override fun getOutputDataPortBounds(dataNumber: Int): Rectangle = getPortBounds(outputDataPorts[dataNumber], true) + + override fun getSocketPortBounds(socketNumber: Int): Rectangle = getPortBounds(socketPorts[socketNumber]) + + override fun getPlugPortBounds(plugNumber: Int): Rectangle = getPortBounds(plugPorts[plugNumber], true) + + private fun calculateWidth(): Int { + val typeNameRowWidth = typeNameLabel.width + val inputsWidth = portsColumnWidth(inputPorts) + val outputsWidth = portsColumnWidth(outputPorts) + + val regularRowsWidth = max(inputsWidth, outputsWidth) * 2 + scale(CENTER_PADDING + 2 * INNER_BORDER_PADDING) + return (listOf(regularRowsWidth, typeNameRowWidth).maxOrNull() ?: 0) + scale(2 * INNER_BORDER_PADDING) + } + + private fun createNameLabel(): EditorCell_Property { + val result = EditorCell_Property(context, DeclarationNameAccessor(fbType.declaration) { !it.isNullOrEmpty() }, node) + + result.style.set(StyleAttributes.HORIZONTAL_ALIGN, CellAlign.CENTER) + result.style.set(StyleAttributes.FONT_SIZE, fontSize) + result.style.set(StyleAttributes.PADDING_TOP, Padding((lineSize).toDouble() / 2, Measure.PIXELS)) + result.style.set(StyleAttributes.PADDING_BOTTOM, Padding((lineSize).toDouble() / 2, Measure.PIXELS)) + return result + } + + override fun relayout() { + super.relayout() + val width = calculateWidth() + rootCell.width = width + eventPortsContainer.width = width + dataPortsContainer.width = width + otherPortsContainer.width = width + addCentralGap(width) + + buttons.values.forEach { + addGapForButtons(width, it) + it.height = it.cells.first().height + lineSize / 2 + it.width = width + } + } + + private fun addCentralGap(width: Int) { + addCentralGap(width, outputEventPorts, eventPortsContainer) + addCentralGap(width, outputDataPorts, dataPortsContainer) + addCentralGap(width, plugPorts, otherPortsContainer) + } + + private fun addCentralGap(width: Int, ports: List, container: EditorCell_Collection) { + val right = container.cells.last() + val gap = (width - portsColumnWidth(ports) - INNER_BORDER_PADDING) + right.moveTo(gap, right.y) + } + + private fun addGapForButtons(width: Int, cell: EditorCell_Collection) { + val left = cell.cells.first() + val right = cell.cells.last() + right.moveTo(width - PLUS_BUTTON_SIZE, right.y + cell.height - right.height) + left.moveTo(0, left.y + cell.height - left.height) + } + + fun getPortTemplates(view: FunctionBlockView): Set { + val result = mutableSetOf() + + if (fbType.declaration is FBInterfaceDeclaration) { + result.add(FunctionBlockPortView(view, -1, EntryKind.EVENT, true, fbType.declaration!!)) + result.add(FunctionBlockPortView(view, -1, EntryKind.EVENT, false, fbType.declaration!!)) + result.add(FunctionBlockPortView(view, -1, EntryKind.DATA, true, fbType.declaration!!)) + result.add(FunctionBlockPortView(view, -1, EntryKind.DATA, false, fbType.declaration!!)) + } + + if (fbType.declaration is FBInterfaceDeclarationWithAdapters) { + result.add(FunctionBlockPortView(view, -1, EntryKind.ADAPTER, true, fbType.declaration!!)) + result.add(FunctionBlockPortView(view, -1, EntryKind.ADAPTER, false, fbType.declaration!!)) + } + + return result + } + + companion object { + private const val CENTER_PADDING = 20 + private const val INNER_BORDER_PADDING = 2 + private const val PLUS_BUTTON_SIZE = 16 + + private fun portsColumnWidth(ports: Collection): Int { + return ports.maxOfOrNull { + if (it is EditablePortWithTypeAndLabel) + it.cell.width + else + (it as EditablePortLabel).label.width + } ?: 0 + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/FBTypeCellComponent.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/FBTypeCellComponent.kt index 03ac0ad2a..f5e7d4148 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/FBTypeCellComponent.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/FBTypeCellComponent.kt @@ -12,10 +12,11 @@ import jetbrains.mps.openapi.editor.cells.CellActionType import jetbrains.mps.openapi.editor.cells.EditorCell import org.fbme.ide.iec61499.repository.PlatformElement import org.fbme.ide.richediting.adapters.fbnetwork.FBConnectionPathPainter -import org.fbme.ide.richediting.adapters.fbnetwork.Port -import org.fbme.ide.richediting.adapters.fbnetwork.PortWithLabel +import org.fbme.ide.richediting.adapters.fbnetwork.port.Port +import org.fbme.ide.richediting.adapters.fbnetwork.port.PortWithLabel import org.fbme.ide.richediting.editor.NetworkInstanceNavigationSupport import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.ide.richediting.utils.ProjectProvider import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor import org.fbme.lib.iec61499.instances.NetworkInstance @@ -27,8 +28,7 @@ import java.util.* import kotlin.math.max class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node: SNode, isEditable: Boolean) : - AbstractFBCell(context, fbType, node, isEditable) { - + AbstractFBCell(context, fbType, node, isEditable) { private val typeNameLabel: EditorCell_SceneLabel override val rootCell: EditorCell_Collection private val backgroundColor: Color @@ -48,6 +48,7 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node rootCell.addEditorCell(typeNameLabel) rootCell.style.set(StyleAttributes.TEXT_COLOR, if (isEditable) MPSColors.BLACK else MPSColors.DARK_GRAY) initPorts() + relayout() } override fun initPorts(ports: MutableList, portDescriptors: List) { @@ -73,53 +74,41 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node relayoutLabel(lineSize) } - override fun getInputEventPortBounds(eventNumber: Int): Rectangle { + private fun getPortBounds( + position: Int, + ports: List, + isOutput: Boolean = false, + verticalOffset: Int = 0): Rectangle { val lineSize = lineSize - val port = inputEventPorts[eventNumber] - val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = eventNumber * lineSize - return Rectangle(0, y, width, lineSize) - } + val port = ports[position] - override fun getOutputEventPortBounds(eventNumber: Int): Rectangle { - val lineSize = lineSize - val port = outputEventPorts[eventNumber] val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = eventNumber * lineSize - return Rectangle(rootCell.width - width, y, width, lineSize) - } - override fun getInputDataPortBounds(dataNumber: Int): Rectangle { - val lineSize = lineSize - val port = inputDataPorts[dataNumber] - val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = (eventPortsCount + 2 + dataNumber) * lineSize - return Rectangle(0, y, width, lineSize) - } + val y = (verticalOffset + position) * lineSize + val x = if (isOutput) rootCell.width - width else 0 - override fun getOutputDataPortBounds(dataNumber: Int): Rectangle { - val lineSize = lineSize - val port = outputDataPorts[dataNumber] - val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = (eventPortsCount + 2 + dataNumber) * lineSize - return Rectangle(rootCell.width - width, y, width, lineSize) + return Rectangle(x, y, width, lineSize) } - override fun getSocketPortBounds(socketNumber: Int): Rectangle { - val lineSize = lineSize - val port = socketPorts[socketNumber] - val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = (eventPortsCount + inputDataPortsCount + 2 + socketNumber) * lineSize - return Rectangle(0, y, width, lineSize) - } + override fun getInputEventPortBounds(eventNumber: Int): Rectangle = + getPortBounds(eventNumber, inputEventPorts) - override fun getPlugPortBounds(plugNumber: Int): Rectangle { - val lineSize = lineSize - val port = plugPorts[plugNumber] - val width = (port as PortWithLabel).label.width + scale(INNER_BORDER_PADDING) - val y = (eventPortsCount + 2 + outputDataPortsCount + plugNumber) * lineSize - return Rectangle(rootCell.width - width, y, width, lineSize) - } + override fun getOutputEventPortBounds(eventNumber: Int): Rectangle = + getPortBounds(eventNumber, outputEventPorts, isOutput = true) + + override fun getInputDataPortBounds(dataNumber: Int): Rectangle = + getPortBounds(dataNumber, inputDataPorts, verticalOffset = 2 + eventPortsCount) + + override fun getOutputDataPortBounds(dataNumber: Int): Rectangle = + getPortBounds(dataNumber, outputDataPorts, isOutput = true, verticalOffset = 2 + eventPortsCount) + + + override fun getSocketPortBounds(socketNumber: Int): Rectangle = + getPortBounds(socketNumber, socketPorts, verticalOffset = 2 + eventPortsCount + inputDataPortsCount) + + override fun getPlugPortBounds(plugNumber: Int): Rectangle = + getPortBounds(plugNumber, plugPorts, isOutput = true, + verticalOffset = 2 + eventPortsCount + outputDataPortsCount) private fun relayoutPortLabels(lineSize: Int) { val leftX = rootCell.x + scale(INNER_BORDER_PADDING) @@ -134,51 +123,36 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node relayoutPlugPortLabels(rightX, dataY + lineSize * outputDataPorts.size, lineSize) } - private fun relayoutDataOutputPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutOutputPortLabels(x, y, lineSize, outputDataPorts) - } + private fun relayoutDataOutputPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, outputDataPorts, isOutput = true) - private fun relayoutEventOutputPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutOutputPortLabels(x, y, lineSize, outputEventPorts) - } + private fun relayoutEventOutputPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, outputEventPorts, isOutput = true) - private fun relayoutPlugPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutOutputPortLabels(x, y, lineSize, plugPorts) - } - - private fun relayoutOutputPortLabels(x: Int, y: Int, lineSize: Int, outputPorts: List) { - var curY = y - for (port in outputPorts) { - val label = (port as PortWithLabel).label - label.moveTo(x - label.width, curY) - curY += lineSize - } - } + private fun relayoutPlugPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, plugPorts, isOutput = true) - private fun relayoutDataInputPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutInputPortLabels(x, y, lineSize, inputDataPorts) - } + private fun relayoutDataInputPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, inputDataPorts) - private fun relayoutEventInputPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutInputPortLabels(x, y, lineSize, inputEventPorts) - } + private fun relayoutEventInputPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, inputEventPorts) - private fun relayoutSocketPortLabels(x: Int, y: Int, lineSize: Int) { - relayoutInputPortLabels(x, y, lineSize, socketPorts) - } + private fun relayoutSocketPortLabels(x: Int, y: Int, lineSize: Int) = + relayoutPortLabels(x, y, lineSize, socketPorts) + private fun relayoutPortLabels(x: Int, y: Int, lineSize: Int, ports: List, isOutput: Boolean = false) = + ports.forEachIndexed { index, port -> + val label = (port as PortWithLabel).label + val curY = y + index * lineSize + val curX = x - if (isOutput) label.width else 0 + label.moveTo(curX, curY) + } - private fun relayoutInputPortLabels(x: Int, y: Int, lineSize: Int, inputPorts: List) { - var curY = y - for (port in inputPorts) { - (port as PortWithLabel).label.moveTo(x, curY) - curY += lineSize - } - } private fun relayoutLabel(lineSize: Int) { typeNameLabel.moveTo( - rootCell.x + rootCell.width / 2 - typeNameLabel.width / 2, - rootCell.y + (eventPortsCount + 1) * lineSize - lineSize / 4 + rootCell.x + rootCell.width / 2 - typeNameLabel.width / 2, + rootCell.y + (eventPortsCount + 1) * lineSize - lineSize / 4 ) } @@ -206,8 +180,8 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node graphics.paint = DiagramColors.createGradientPaint(background, Rectangle(x, y, rootCell.width, rootCell.height)) graphics.fill(shape) graphics.paint = DiagramColors.createGradientPaint( - typeBackgroundColor, - Rectangle(x, y, rootCell.width, rootCell.height) + typeBackgroundColor, + Rectangle(x, y, rootCell.width, rootCell.height) ) graphics.fill(Rectangle(x, typeNameY, rootCell.width, lineSize)) graphics.stroke = BasicStroke(scale(1).toFloat()) @@ -224,12 +198,12 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node private fun calculateWidth(): Int { val typeNameRowWidth = typeNameLabel.width val inputsWidth = max( - portsColumnWidth(inputEventPorts), - max(portsColumnWidth(inputDataPorts), portsColumnWidth(socketPorts)) + portsColumnWidth(inputEventPorts), + max(portsColumnWidth(inputDataPorts), portsColumnWidth(socketPorts)) ) val outputsWidth = max( - portsColumnWidth(outputEventPorts), - max(portsColumnWidth(outputDataPorts), portsColumnWidth(plugPorts)) + portsColumnWidth(outputEventPorts), + max(portsColumnWidth(outputDataPorts), portsColumnWidth(plugPorts)) ) val regularRowsWidth = inputsWidth + outputsWidth + scale(CENTER_PADDING + 2 * INNER_BORDER_PADDING) return max(regularRowsWidth, typeNameRowWidth) + scale(2 * INNER_BORDER_PADDING) @@ -237,18 +211,18 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node private fun createRootCell(): EditorCell_Collection { return object : EditorCell_Collection( - context, - node, - object : AbstractCellLayout() { - override fun doLayout(collection: jetbrains.mps.openapi.editor.cells.EditorCell_Collection) { - assert(collection === rootCell) - relayout() - } - - override fun doLayoutText(iterable: Iterable): TextBuilder { - return TextBuilderImpl() + context, + node, + object : AbstractCellLayout() { + override fun doLayout(collection: jetbrains.mps.openapi.editor.cells.EditorCell_Collection) { + assert(collection === rootCell) + relayout() + } + + override fun doLayoutText(iterable: Iterable): TextBuilder { + return TextBuilderImpl() + } } - } ) { override fun paintContent(g: Graphics, parentSettings: ParentSettings) { this@FBTypeCellComponent.paint(g.create() as Graphics2D) @@ -286,8 +260,7 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node val childNetworkInstance = child.containedNetwork if (childNetworkInstance is NetworkInstance) { val navigationStub = NetworkInstanceNavigationSupport.getNavigationStub( - rootCell.context.operationContext.project, - childNetworkInstance + ProjectProvider.getInstance(rootCell.context)!!, childNetworkInstance ) style.set(StyleAttributes.NAVIGATABLE_NODE, navigationStub) return @@ -304,17 +277,17 @@ class FBTypeCellComponent(context: EditorContext, fbType: FBTypeDescriptor, node private const val CENTER_PADDING = 20 private const val INNER_BORDER_PADDING = 2 private val PORT_LABEL_WIDTH_COMPARATOR = - Comparator.comparing { port: Port -> (port as PortWithLabel).label.width } + Comparator.comparing { port: Port -> (port as PortWithLabel).label.width } private fun portsColumnWidth(ports: List): Int { return if (ports.isEmpty()) { 0 } else ( - Collections.max( - ports, - PORT_LABEL_WIDTH_COMPARATOR - ) as PortWithLabel - ).label.width + Collections.max( + ports, + PORT_LABEL_WIDTH_COMPARATOR + ) as PortWithLabel + ).label.width } } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortLabel.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortLabel.kt new file mode 100644 index 000000000..8591df85f --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortLabel.kt @@ -0,0 +1,25 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.port + +import jetbrains.mps.nodeEditor.cells.EditorCell_Property +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.CellActionType +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.DeclarationNameAccessor +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.jetbrains.mps.openapi.model.SNode + +open class EditablePortLabel( + context: EditorContext, + node: SNode, + port: FBPortDescriptor, + declaration: Declaration?, +) : PortBase(port) { + val label: EditorCell_Property + + init { + label = EditorCell_Property(context, DeclarationNameAccessor(port.declaration) { true }, node) + label.setAction(CellActionType.BACKSPACE, PortActionFactory.deletePortAction(port, declaration, label.style)) + label.style.set(RichEditorStyleAttributes.PORT, port) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortWithTypeAndLabel.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortWithTypeAndLabel.kt new file mode 100644 index 000000000..56c90d784 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/EditablePortWithTypeAndLabel.kt @@ -0,0 +1,70 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.port + +import com.intellij.ui.JBColor +import jetbrains.mps.editor.runtime.style.Measure +import jetbrains.mps.editor.runtime.style.Padding +import jetbrains.mps.editor.runtime.style.StyleAttributes +import jetbrains.mps.nodeEditor.cellLayout.CellLayout_Vertical +import jetbrains.mps.nodeEditor.cells.EditorCell_Collection +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.CellActionType +import org.fbme.ide.richediting.adapters.fbnetwork.suggestion.CustomSubstituteInfo +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.scenes.cells.EditorCell_SceneLabel +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.ShowSubstituteChooserAction +import org.fbme.ide.richediting.editor.RichEditorStyleAttributes +import org.fbme.scenes.viewmodel.CompletionItem +import org.jetbrains.mps.openapi.model.SNode + +class EditablePortWithTypeAndLabel( + context: EditorContext, + node: SNode, + port: FBPortDescriptor, + val declaration: Declaration?, + typeName: String?, + items: List, +) : EditablePortLabel(context, node, port, declaration) { + val cell: EditorCell_Collection + val typeLabel: EditorCell_SceneLabel + + private fun createTypeLabel( + context: EditorContext, + node: SNode, + typeName: String?, + items: List, + ): EditorCell_SceneLabel { + val typeLabel = object : EditorCell_SceneLabel(context, node, typeName + ?: TYPE_DEFAULT_NAME, typeName.isNullOrEmpty()) { + } + + //set style + typeLabel.style.set(StyleAttributes.PADDING_LEFT, Padding(HORIZONTAL_PADDING, Measure.PIXELS)) + typeLabel.style.set(StyleAttributes.PADDING_RIGHT, Padding(HORIZONTAL_PADDING, Measure.PIXELS)) + typeLabel.style.set(StyleAttributes.UNDERLINED, true) + typeLabel.style.set(StyleAttributes.FONT_SIZE, TYPE_FONT_SIZE) //TODO: add color with error + typeLabel.style.set(StyleAttributes.TEXT_COLOR, TYPE_ERROR_COLOR) + + //Add showing suggestion + typeLabel.setAction(CellActionType.CLICK, ShowSubstituteChooserAction(typeLabel)) + typeLabel.substituteInfo = CustomSubstituteInfo(context, typeLabel, items) + typeLabel.style.set(RichEditorStyleAttributes.PORT, port) + + return typeLabel + } + + init { + cell = EditorCell_Collection(context, node, CellLayout_Vertical()) + typeLabel = createTypeLabel(context, node, typeName, items) + + cell.addEditorCell(label) + cell.addEditorCell(typeLabel) + } + + companion object { + const val HORIZONTAL_PADDING = 10.0 + const val TYPE_FONT_SIZE = 10 + val TYPE_ERROR_COLOR = JBColor.RED!! + const val TYPE_DEFAULT_NAME = "none" + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/Port.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/Port.kt similarity index 64% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/Port.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/Port.kt index d791a3a10..4b3cf54ae 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/Port.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/Port.kt @@ -1,4 +1,4 @@ -package org.fbme.ide.richediting.adapters.fbnetwork +package org.fbme.ide.richediting.adapters.fbnetwork.port import org.fbme.lib.iec61499.fbnetwork.EntryKind diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortActionFactory.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortActionFactory.kt new file mode 100644 index 000000000..7babf4877 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortActionFactory.kt @@ -0,0 +1,149 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.port + +import jetbrains.mps.openapi.editor.cells.CellAction +import jetbrains.mps.openapi.editor.style.Style +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.port.AddPortAction +import org.fbme.ide.richediting.adapters.fbnetwork.actions.cell.port.DeletePortAction +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.fbnetwork.EntryKind +import java.util.function.Supplier + +object PortActionFactory { + fun createInputEventAction( + declaration: FBInterfaceDeclaration, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Ievent", + declaration.inputEvents.map { it.name } + ), + ): AddPortAction { + return AddPortAction( + "Add input event port", + declaration.inputEvents, + { iec61499Factory.createEventDeclaration(identifierFactory.get()) } + ) + } + + fun createOutputEventAction( + declaration: FBInterfaceDeclaration, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Oevent", + declaration.outputEvents.map { it.name } + ), + ): AddPortAction { + return AddPortAction( + "Add output event port", + declaration.outputEvents, + { iec61499Factory.createEventDeclaration(identifierFactory.get()) } + ) + } + + fun createInputParameterAction( + declaration: FBInterfaceDeclaration, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Idata", + declaration.inputParameters.map { it.name } + ), + ) : AddPortAction { + return AddPortAction( + "Add input data port", + declaration.inputParameters, + { iec61499Factory.createParameterDeclaration(identifierFactory.get()) } + ) + } + + fun createOutputParameterAction( + declaration: FBInterfaceDeclaration, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Odata", + declaration.outputParameters.map { it.name } + ), + ) : AddPortAction { + return AddPortAction( + "Add output data port", + declaration.outputParameters, + { iec61499Factory.createParameterDeclaration(identifierFactory.get()) } + ) + } + + fun createSocketAction( + declaration: FBInterfaceDeclarationWithAdapters, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Socket", + declaration.sockets.map { it.name } + ), + ) : AddPortAction { + return AddPortAction( + "Add socket port", + declaration.sockets, + { iec61499Factory.createSocketDeclaration(identifierFactory.get()) } + ) + } + + fun createPluginAction( + declaration: FBInterfaceDeclarationWithAdapters, + iec61499Factory: IEC61499Factory, + identifierFactory: Supplier = identifierSupplier( + "Plugin", + declaration.plugs.map { it.name } + ), + ) : AddPortAction { + return AddPortAction( + "Add plugin port", + declaration.plugs, + { iec61499Factory.createPlugDeclaration(identifierFactory.get()) } + ) + } + + fun deletePortAction(port: FBPortDescriptor, fbTypeDeclaration: Declaration?, style: Style) : CellAction? { + fbTypeDeclaration ?: return null + + if (fbTypeDeclaration !is FBInterfaceDeclaration) { + return null + } + + val ports: MutableList = when (port.connectionKind) { + EntryKind.EVENT -> if (port.isInput) fbTypeDeclaration.inputEvents else fbTypeDeclaration.outputEvents + EntryKind.DATA -> if (port.isInput) fbTypeDeclaration.inputParameters + else fbTypeDeclaration.outputParameters + EntryKind.ADAPTER -> { + if (fbTypeDeclaration !is FBInterfaceDeclarationWithAdapters) { + return null + } + + if (port.isInput) { + fbTypeDeclaration.sockets + } else { + fbTypeDeclaration.plugs + } + } + } + + return DeletePortAction(port, ports, style) + } + + fun identifierSupplier(prefix: String, values: List): Supplier { + var index: Int? = null + + val getName: () -> String = { + "${prefix}${index ?: ""}" + } + + return Supplier { + while (values.contains(getName())) { + index = (index ?: 0) + 1 + } + + StringIdentifier(getName()) + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortBase.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortBase.kt new file mode 100644 index 000000000..bf74b601f --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortBase.kt @@ -0,0 +1,9 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.port + +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.fbnetwork.EntryKind + +open class PortBase(val port: FBPortDescriptor) : Port { + override val connectionKind: EntryKind + get() = port.connectionKind +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortCell.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortCell.kt similarity index 88% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortCell.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortCell.kt index 8d63c7ff9..28d1fe1e0 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortCell.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortCell.kt @@ -1,4 +1,4 @@ -package org.fbme.ide.richediting.adapters.fbnetwork +package org.fbme.ide.richediting.adapters.fbnetwork.port import jetbrains.mps.nodeEditor.cells.EditorCell_Collection import java.awt.Graphics2D diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortWithLabel.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortWithLabel.kt similarity index 90% rename from code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortWithLabel.kt rename to code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortWithLabel.kt index 3266cc452..39ddc6448 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/PortWithLabel.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/port/PortWithLabel.kt @@ -1,4 +1,4 @@ -package org.fbme.ide.richediting.adapters.fbnetwork +package org.fbme.ide.richediting.adapters.fbnetwork.port import jetbrains.mps.openapi.editor.EditorContext import org.fbme.ide.richediting.editor.RichEditorStyleAttributes diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/suggestion/CustomSubstituteInfo.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/suggestion/CustomSubstituteInfo.kt new file mode 100644 index 000000000..09e1698b0 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/suggestion/CustomSubstituteInfo.kt @@ -0,0 +1,27 @@ +package org.fbme.ide.richediting.adapters.fbnetwork.suggestion + +import jetbrains.mps.nodeEditor.cellMenu.AbstractNodeSubstituteInfo +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.openapi.editor.cells.EditorCell +import jetbrains.mps.openapi.editor.cells.SubstituteAction +import jetbrains.mps.smodel.action.AbstractSubstituteAction +import org.fbme.scenes.viewmodel.CompletionItem +import org.jetbrains.mps.openapi.model.SNode + +class CustomSubstituteInfo( + context: EditorContext, + val cell: EditorCell, + val items: List, +) : AbstractNodeSubstituteInfo(context) { + override fun createActions(): MutableList = items.map { + object : AbstractSubstituteAction(cell.sNode) { + override fun getMatchingText(pattern: String?): String = it.getMatchingText(pattern) ?: "" + + override fun getDescriptionText(description: String?): String = it.descriptionText ?: "" + + override fun doSubstitute(editorContext: EditorContext?, pattern: String?): SNode? { + return it.doSubstitute(editorContext, pattern) + } + } + }.toMutableList() +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichEditorStyleAttributes.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichEditorStyleAttributes.kt index 23a4eff54..15f47c32b 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichEditorStyleAttributes.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichEditorStyleAttributes.kt @@ -2,13 +2,12 @@ package org.fbme.ide.richediting.editor import jetbrains.mps.editor.runtime.style.InheritableStyleAttribute import jetbrains.mps.editor.runtime.style.SimpleStyleAttribute -import jetbrains.mps.nodeEditor.cells.EditorCell_Collection import jetbrains.mps.openapi.editor.style.StyleAttribute import org.fbme.ide.richediting.adapters.ecc.cell.ActionBlock +import org.fbme.ide.richediting.adapters.fbnetwork.ExpandedComponentsController import org.fbme.ide.richediting.inspections.NetworkInspectionsFacility +import org.fbme.ide.richediting.viewmodel.FunctionBlockView import org.fbme.ide.richediting.viewmodel.NetworkComponentView -import org.fbme.lib.iec61499.declarations.AlgorithmDeclaration -import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor import org.fbme.lib.iec61499.ecc.ECC @@ -18,10 +17,11 @@ import org.fbme.lib.iec61499.fbnetwork.FBNetwork import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase import org.fbme.lib.iec61499.instances.NetworkInstance import org.fbme.scenes.controllers.SceneViewpoint -import org.fbme.scenes.controllers.SelectionModel import org.fbme.scenes.controllers.components.ComponentsFacility import org.fbme.scenes.controllers.diagram.ConnectionsFacility import org.fbme.scenes.controllers.diagram.DiagramFacility +import org.fbme.scenes.controllers.edited.EditedModel +import org.fbme.scenes.controllers.selection.SelectionModel object RichEditorStyleAttributes { @JvmField @@ -42,6 +42,13 @@ object RichEditorStyleAttributes { @JvmField val SELECTED_FBS: StyleAttribute> = InheritableStyleAttribute("selected-fbs") + @JvmField + val EDITED_FBS: StyleAttribute> = InheritableStyleAttribute("edited-fbs") + + @JvmField + val EXPANDED_COMPONENTS_CONTROLLER: StyleAttribute = + InheritableStyleAttribute("expanded-controller") + @JvmField val STATE_ACTION: StyleAttribute = InheritableStyleAttribute("state-action") @@ -80,6 +87,7 @@ object RichEditorStyleAttributes { TYPE.register() FB.register() SELECTED_FBS.register() + EDITED_FBS.register() STATE_ACTION.register() ACTIONS.register() STATE_DECLARATION.register() @@ -89,5 +97,6 @@ object RichEditorStyleAttributes { INSPECTIONS_FACILITY.register() VIEWPOINT.register() ECC.register() + EXPANDED_COMPONENTS_CONTROLLER.register() } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/inspections/NetworkInspectionsFacility.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/inspections/NetworkInspectionsFacility.kt index 5f9aa1847..08391be94 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/inspections/NetworkInspectionsFacility.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/inspections/NetworkInspectionsFacility.kt @@ -1,6 +1,5 @@ package org.fbme.ide.richediting.inspections -import jetbrains.mps.editor.runtime.style.Padding import jetbrains.mps.editor.runtime.style.StyleAttributes import jetbrains.mps.nodeEditor.EditorSettings import jetbrains.mps.nodeEditor.MPSColors diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/Notifier.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/Notifier.kt new file mode 100644 index 000000000..e4241c078 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/Notifier.kt @@ -0,0 +1,33 @@ +package org.fbme.ide.richediting.utils + +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project + +object Notifier { + private const val NOTIFICATION_GROUP = "Custom-richediting" + + fun showWarning(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.WARNING) + .notify(project) + } + + fun showInformation(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.INFORMATION) + .notify(project) + } + + fun showError(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.ERROR) + .notify(project) + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/ProjectProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/ProjectProvider.kt new file mode 100644 index 000000000..9d572aa55 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/ProjectProvider.kt @@ -0,0 +1,29 @@ +package org.fbme.ide.richediting.utils + +import com.intellij.ide.DataManager +import jetbrains.mps.ide.project.ProjectHelper +import jetbrains.mps.openapi.editor.EditorContext +import jetbrains.mps.project.MPSProject +import jetbrains.mps.workbench.MPSDataKeys +import java.awt.Component + +object ProjectProvider { + /** + * This solution doesn't work if component is headless and doesn't belong to UI hierarchy. + */ + fun getInstance(context: EditorContext): MPSProject? { + val component: Component = context.editorComponent as Component + return MPSDataKeys.MPS_PROJECT.getData(DataManager.getInstance().getDataContext(component)) + } + + /** + * This solution depends on project with which repository have been initialized. + */ + fun getInstanceFromRepository(context: EditorContext): MPSProject? { + return ProjectHelper.getProject(context.repository)?.let { project -> + ProjectHelper.toIdeaProject(project)?.let {ideaProject -> + ProjectHelper.fromIdeaProject(ideaProject) + } + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/exceptions/CreationException.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/exceptions/CreationException.kt new file mode 100644 index 000000000..8088b79e5 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/exceptions/CreationException.kt @@ -0,0 +1,9 @@ +package org.fbme.ide.richediting.utils.exceptions + +class CreationException : Exception { + constructor() : super() + + constructor(message: String?) : super(message) + + constructor(message: String?, cause: Throwable?) : super(message, cause) +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBCompletionProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBCompletionProvider.kt new file mode 100644 index 000000000..372663755 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBCompletionProvider.kt @@ -0,0 +1,117 @@ +package org.fbme.ide.richediting.utils.fb + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.InputValidator +import com.intellij.openapi.ui.Messages +import com.intellij.util.alsoIfNull +import jetbrains.mps.openapi.editor.EditorContext +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.RicheditingMpsBridge +import org.fbme.ide.richediting.utils.Notifier +import org.fbme.ide.richediting.utils.ProjectProvider +import org.fbme.ide.richediting.utils.exceptions.CreationException +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.fbme.lib.iec61499.instances.NetworkInstance +import org.fbme.scenes.viewmodel.PositionalCompletionItem +import java.util.* + +object FBCompletionProvider { + fun getCompletionItems( + networkInstance: NetworkInstance, + context: EditorContext + ): List { + val result: MutableList = LinkedList() + + val project = ProjectProvider.getInstance(context).alsoIfNull { + Notifier.showWarning("Can't get project from context!") + } ?: return result + + val scale = RicheditingMpsBridge.getEditorScale(project) + val repository = PlatformRepositoryProvider.getInstance(project) + val factory = repository.iec61499Factory + val network = networkInstance.networkDeclaration + val scope = repository.getDeclarationScopeFor( + (network as PlatformElement).node.model + ) + + val allFBTypes = scope.findAllFBTypeDeclarations() + val existedFBNames = allFBTypes.map { it.name }.toSet() + + fun invokeFun(type: FBTypeDeclaration): (String?, Int, Int) -> Unit = { _: String?, x: Int, y: Int -> + val declaration = factory.createFunctionBlockDeclaration(StringIdentifier(type.name)) + declaration.x = (x / scale).toInt() + declaration.y = (y / scale).toInt() + declaration.typeReference.setTarget(type) + network.functionBlocks.add(declaration) + } + + fun createNewType( + typeName: String, + factory: (name: String, context: EditorContext) -> FBTypeDeclaration + ): PositionalCompletionItem = + createPositionalCompletionItem( + "New $typeName FB", + "Creates empty $typeName FB" + ) { parameter: String?, x: Int, y: Int -> + val type = createNewCompositeBlock( + project.project, + context, + existedFBNames, + factory + ) ?: return@createPositionalCompletionItem + invokeFun(type)(parameter, x, y) + } + + allFBTypes.sortedBy { it.name }.forEach { type -> + result.add(createPositionalCompletionItem(type.name, invokeFun = invokeFun(type))) + } + + result.add(createNewType("basic", FBFactory::createBasicFunBlock)) + result.add(createNewType("composite", FBFactory::createCompositeFunBlock)) + + return result + } + + private fun createNewCompositeBlock( + project: Project, + context: EditorContext, + existedFBNames: Set, + factory: (name: String, context: EditorContext) -> FBTypeDeclaration + ): FBTypeDeclaration? { + val inputValidator = object : InputValidator { + override fun checkInput(text: String?): Boolean = !existedFBNames.contains(text) + + override fun canClose(text: String?): Boolean = true + } + val name = Messages.showInputDialog( + project, + "Enter name for new functional block", + null, Messages.getQuestionIcon(), + null, + inputValidator + ) ?: return null + + return try { + factory(name, context) + } catch (e: CreationException) { + Notifier.showWarning("Can't create new functional block!", project) + null + } + } + + private fun createPositionalCompletionItem( + name: String, + description: String? = null, + invokeFun: (pattern: String?, x: Int, y: Int) -> Unit + ): PositionalCompletionItem { + return object : PositionalCompletionItem { + override fun getMatchingText(pattern: String?): String = name + + override val descriptionText: String = description ?: "" + + override fun invoke(pattern: String?, x: Int, y: Int) = invokeFun(pattern, x, y) + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBFactory.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBFactory.kt new file mode 100644 index 000000000..2a34ae96a --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBFactory.kt @@ -0,0 +1,48 @@ +package org.fbme.ide.richediting.utils.fb + +import jetbrains.mps.openapi.editor.EditorContext +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.richediting.utils.ProjectProvider +import org.fbme.ide.richediting.utils.exceptions.CreationException +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import kotlin.jvm.Throws + +object FBFactory { + @Throws(CreationException::class) + fun createCompositeFunBlock(name: String, context: EditorContext): CompositeFBTypeDeclaration { + return createBlock(name, context) { + iec61499Factory, identifier -> iec61499Factory.createCompositeFBTypeDeclaration(identifier) + } + } + + @Throws(CreationException::class) + fun createBasicFunBlock(name: String, context: EditorContext): BasicFBTypeDeclaration { + return createBlock(name, context) { + iec61499Factory, identifier -> iec61499Factory.createBasicFBTypeDeclaration(identifier) + } + } + + @Throws(CreationException::class) + private fun createBlock( + name: String, + context: EditorContext, + creator: (iec61499Factory: IEC61499Factory, identifier: Identifier) -> T + ) : T { + val identifier = StringIdentifier(name) + + val project = ProjectProvider.getInstance(context) ?: throw CreationException("Can't get project from context") + + val repository = PlatformRepositoryProvider.getInstance(project) + val model = context.model + + val createdType = creator(repository.iec61499Factory, identifier) + model.addRootNode((createdType as PlatformElement).node) + + return createdType + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUsageFinder.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUsageFinder.kt new file mode 100644 index 000000000..9c531caf1 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUsageFinder.kt @@ -0,0 +1,31 @@ +package org.fbme.ide.richediting.utils.fb + +import jetbrains.mps.findUsages.FindUsagesManager +import jetbrains.mps.project.MPSProject +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.lib.common.Declaration +import org.jetbrains.mps.openapi.model.SNode + +object FBUsageFinder { + fun findUsages(project: MPSProject, fbBlock: Declaration) + : Map { + val manager = project.getComponent(FindUsagesManager::class.java) + val platformElement = (fbBlock as PlatformElement) + val nodes = manager.findUsages(project.scope, mutableSetOf(platformElement.node), null) + val repository = PlatformRepositoryProvider.getInstance(project) + + val result: MutableMap = HashMap() + nodes.mapNotNull { + it.sourceNode.parent + }.forEach { + val declaration = repository.getAdapter(it, Declaration::class.java) + + if (declaration != null) { + result[declaration] = it + } + } + + return result + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUtils.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUtils.kt new file mode 100644 index 000000000..94ac24181 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/utils/fb/FBUtils.kt @@ -0,0 +1,108 @@ +package org.fbme.ide.richediting.utils.fb + +import org.fbme.lib.common.CompositeReference +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.fbnetwork.* + +object FBUtils { + fun copyInterface(oldFB: T, newFB: T, factory: IEC61499Factory) { + oldFB.inputEvents.copyTo(newFB.inputEvents) { + factory.createEventDeclaration(StringIdentifier(it.name)) + } + oldFB.outputEvents.copyTo(newFB.outputEvents) { + factory.createEventDeclaration(StringIdentifier(it.name)) + } + oldFB.inputParameters.copyTo(newFB.inputParameters) { + val port = factory.createParameterDeclaration(StringIdentifier(it.name)) + port.type = it.type + port + } + oldFB.outputParameters.copyTo(newFB.outputParameters) { + val port = factory.createParameterDeclaration(StringIdentifier(it.name)) + port.type = it.type + port + } + + if (oldFB is FBInterfaceDeclarationWithAdapters && newFB is FBInterfaceDeclarationWithAdapters) { + oldFB.plugs.copyTo(newFB.plugs) { + val port = factory.createPlugDeclaration(StringIdentifier(it.name)) + val target = it.typeReference.getTarget() + if (target != null) { + port.typeReference.setTarget(target) + } + port + } + oldFB.sockets.copyTo(newFB.sockets) { + val port = factory.createSocketDeclaration(StringIdentifier(it.name)) + val target = it.typeReference.getTarget() + if (target != null) { + port.typeReference.setTarget(target) + } + port + } + } + } + + private fun MutableList.copyTo(newList: MutableList, transformer: (i: T) -> T) { + this.toList().forEach { + newList.add(transformer(it)) + } + } + + fun replaceFBInConnections( + network: FBNetwork, + oldFB: FunctionBlockDeclarationBase, + newFB: FunctionBlockDeclarationBase + ) { + val newPortsDescriptors = newFB.getAllPorts() + val oldPortsDescriptors = oldFB.getAllPorts() + + listOf( + network.eventConnections to EntryKind.EVENT, + network.dataConnections to EntryKind.DATA, + network.adapterConnections to EntryKind.ADAPTER + ).forEach { (connections, kind) -> + connections.forEach { + it.sourceReference.updateTarget(oldFB, newFB, kind, newPortsDescriptors, oldPortsDescriptors) + it.targetReference.updateTarget(oldFB, newFB, kind, newPortsDescriptors, oldPortsDescriptors) + } + } + } + + private fun CompositeReference>.updateTarget( + old: FunctionBlockDeclarationBase, + created: FunctionBlockDeclarationBase, + kind: EntryKind, + newPortsDescriptors: List, + oldPortsDescriptors: List + ) { + val target = this.getTarget() ?: return + + if (target.functionBlock?.equals(old) == true) { + val oldDescriptor = oldPortsDescriptors.find { + it.declaration?.equals(target.portTarget) == true + } ?: return + + val newDeclaration = newPortsDescriptors.find { + PORT_COMPARATOR(it, oldDescriptor) + }?.declaration ?: return + + this.setTarget(PortPath.createPortPath(created, kind, newDeclaration)) + } + } + + val PORT_COMPARATOR: (a: FBPortDescriptor, b: FBPortDescriptor) -> Boolean = { + a: FBPortDescriptor, b: FBPortDescriptor -> + val aDeclaration = a.declaration + val bDeclaration = b.declaration + (a.isInput == b.isInput) + && (a.connectionKind == b.connectionKind) + && (a.name == b.name) + && (((aDeclaration is EventDeclaration) && (bDeclaration is EventDeclaration)) + || (aDeclaration is ParameterDeclaration && bDeclaration is ParameterDeclaration && aDeclaration.type == bDeclaration.type) + || (aDeclaration is AdapterDeclaration && bDeclaration is AdapterDeclaration && aDeclaration.typeReference.getTarget() == bDeclaration.typeReference.getTarget())) + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/BrokenPortView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/BrokenPortView.kt index d94ac1572..a4035bbe1 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/BrokenPortView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/BrokenPortView.kt @@ -1,8 +1,13 @@ package org.fbme.ide.richediting.viewmodel +import org.fbme.lib.iec61499.fbnetwork.BrokenPortDeclaration import org.fbme.lib.iec61499.fbnetwork.EntryKind -class BrokenPortView : NetworkComponentView, NetworkPortView { +class BrokenPortView( + val isInput: Boolean, + val declaration: BrokenPortDeclaration? = null, + private val myComponent: NetworkComponentView? = null +) : NetworkComponentView, NetworkPortView { private var myOpposite: NetworkPortView? = null override val kind: EntryKind @@ -10,7 +15,7 @@ class BrokenPortView : NetworkComponentView, NetworkPortView { override val isEditable: Boolean get() = false override val component: NetworkComponentView - get() = this + get() = myComponent ?: this override fun equals(other: Any?): Boolean { if (this === other) { diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortTemplateView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortTemplateView.kt new file mode 100644 index 000000000..021cd54e2 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortTemplateView.kt @@ -0,0 +1,12 @@ +package org.fbme.ide.richediting.viewmodel + +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.fbnetwork.EntryKind + +data class FunctionBlockPortTemplateView( + override val component: FunctionBlockView, + val position: Int, + override val kind: EntryKind, + val isSource: Boolean, + val target: Declaration, +) : NetworkPortView diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortView.kt index a3e40f63a..b78056e18 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockPortView.kt @@ -1,12 +1,26 @@ package org.fbme.ide.richediting.viewmodel import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import org.fbme.lib.iec61499.fbnetwork.EntryKind data class FunctionBlockPortView( - override val component: FunctionBlockView, - val position: Int, - override val kind: EntryKind, - val isSource: Boolean, - val target: Declaration -) : NetworkPortView + override val component: FunctionBlockView, + val position: Int, + override val kind: EntryKind, + override val isSource: Boolean, + override val target: Declaration +) : NetworkPortViewAdd { + companion object { + @JvmStatic + fun create(component: FunctionBlockView, declaration: Declaration, descriptor: FBPortDescriptor): FunctionBlockPortView { + return FunctionBlockPortView( + component, + descriptor.position, + descriptor.connectionKind, + !descriptor.isInput, + declaration + ) + } + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt index 1c6b08c02..9691167f4 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt @@ -7,7 +7,7 @@ import org.jetbrains.mps.openapi.model.SNode class FunctionBlockView(val component: FunctionBlockDeclarationBase, isEditable: Boolean) : NetworkComponentView { val associatedNode: SNode = (component as PlatformElement).node - private val myTypeDescriptor: TypeDescriptorAdapter + private val myTypeDescriptor: TypeDescriptorAdapter = TypeDescriptorAdapter(component.type) override val isEditable: Boolean val type: FBTypeDescriptor @@ -30,7 +30,6 @@ class FunctionBlockView(val component: FunctionBlockDeclarationBase, isEditable: } init { - myTypeDescriptor = TypeDescriptorAdapter(component.type) this.isEditable = isEditable } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/InterfaceEndpointView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/InterfaceEndpointView.kt index 4ce344fd4..9ff2dec6b 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/InterfaceEndpointView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/InterfaceEndpointView.kt @@ -11,9 +11,9 @@ data class InterfaceEndpointView( private val endpointCoordinate: EndpointCoordinate, val position: Int, override val kind: EntryKind, - val isSource: Boolean, - val target: Declaration -) : NetworkComponentView, NetworkPortView { + override val isSource: Boolean, + override val target: Declaration +) : NetworkComponentView, NetworkPortViewAdd { val associatedNode = (target as PlatformElement).node val name = target.name diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkPortView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkPortView.kt index 8023eb8c7..d88c693a0 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkPortView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkPortView.kt @@ -1,8 +1,14 @@ package org.fbme.ide.richediting.viewmodel +import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.fbnetwork.EntryKind interface NetworkPortView { val kind: EntryKind val component: NetworkComponentView } + +interface NetworkPortViewAdd: NetworkPortView { + val isSource: Boolean + val target: Declaration +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt index ce3af9c34..a3c03df83 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt @@ -4,6 +4,7 @@ import org.fbme.lib.common.Declaration import org.fbme.lib.common.Element import org.fbme.lib.iec61499.IEC61499Factory import org.fbme.lib.iec61499.declarations.FBInterfaceDeclaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor import org.fbme.lib.iec61499.fbnetwork.* import org.fbme.lib.iec61499.fbnetwork.subapp.SubappNetwork import org.fbme.scenes.controllers.diagram.DiagramView @@ -15,6 +16,7 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: private val myMainComponents: MutableSet = HashSet() private val myAuxComponents: MutableMap> = HashMap() private val myComponentToPorts: MutableMap> = HashMap() + private val myComponentToPortTemplates: MutableMap> = HashMap() private val myPorts: MutableMap = HashMap() private val myConnectionSources: MutableMap = HashMap() private val myConnectionDestinations: MutableMap = HashMap() @@ -113,14 +115,8 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: } private fun initConnections(network: FBNetwork, editable: Boolean) { - for (connection in network.eventConnections) { - addConnection(connection, editable) - } - for (connection in network.dataConnections) { - addConnection(connection, editable) - } - for (connection in network.adapterConnections) { - addConnection(connection, editable) + network.allConnections.forEach { + addConnection(it, editable) } } @@ -149,8 +145,7 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: myAuxComponents[view] = exts for (parameter in functionBlock.parameters) { val parameterDeclaration = parameter.parameterReference.getTarget() - ?: // TODO handle broken parameters - continue + ?: /*TODO handle broken parameters */continue val declaration = parameterDeclaration.container as FBInterfaceDeclaration? val index = declaration!!.inputParameters.indexOf(parameterDeclaration) val oppositePortView = FunctionBlockPortView(view, index, EntryKind.DATA, false, parameterDeclaration) @@ -163,48 +158,31 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: myConnectionSources[parameterConnectionView] = inlineValueView myConnectionDestinations[parameterConnectionView] = oppositePortView } + val ports = HashSet() - var i = 0 myComponentToPorts[view] = ports - for (dataInput in type.dataInputPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.DATA, false, dataInput.declaration!!) - ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.DATA, dataInput.declaration!!)] = port - myPorts[port] = view - } - i = 0 - for (dataOutput in type.dataOutputPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.DATA, true, dataOutput.declaration!!) - ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.DATA, dataOutput.declaration!!)] = port - myPorts[port] = view - } - i = 0 - for (dataInput in type.eventInputPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.EVENT, false, dataInput.declaration!!) - ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.EVENT, dataInput.declaration!!)] = port - myPorts[port] = view - } - i = 0 - for (dataOutput in type.eventOutputPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.EVENT, true, dataOutput.declaration!!) - ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.EVENT, dataOutput.declaration!!)] = port - myPorts[port] = view - } - i = 0 - for (socket in type.socketPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.ADAPTER, false, socket.declaration!!) - ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.ADAPTER, socket.declaration!!)] = port - myPorts[port] = view - } - i = 0 - for (plug in type.plugPorts) { - val port = FunctionBlockPortView(view, i++, EntryKind.ADAPTER, true, plug.declaration!!) + + addPortView(type.dataInputPorts, view, ports) + addPortView(type.dataOutputPorts, view, ports) + addPortView(type.eventInputPorts, view, ports) + addPortView(type.eventOutputPorts, view, ports) + addPortView(type.socketPorts, view, ports) + addPortView(type.plugPorts, view, ports) + //TODO: add ports templates + } + + private fun addPortView( + typePorts: List, + view: FunctionBlockView, + ports: HashSet + ) { + typePorts.forEachIndexed { index, fbPortDescriptor -> + val declaration = fbPortDescriptor.declaration!! + val port = FunctionBlockPortView( + view, index, fbPortDescriptor.connectionKind, !fbPortDescriptor.isInput, declaration + ) ports.add(port) - myPortModelMap[PortPath.createPortPath(functionBlock, EntryKind.ADAPTER, plug.declaration!!)] = port + myPortModelMap[PortPath.createPortPath(view.component, fbPortDescriptor.connectionKind, declaration)] = port myPorts[port] = view } } @@ -214,14 +192,21 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: myConnectionModelMap[connection] = view val source = connection.sourceReference.getTarget() val target = connection.targetReference.getTarget() + val targetPort = target?.portTarget + val sourcePort = source?.portTarget val targetView: NetworkPortView? - val sourceView: NetworkPortView? = if (source != null) { + val sourceView: NetworkPortView? = if (source != null && sourcePort !is BrokenPortDeclaration) { myPortModelMap[source] } else { view.shrink() - BrokenPortView() + + if (sourcePort is BrokenPortDeclaration) { + BrokenPortView(false, sourcePort, myElementModelMap[sourcePort.functionBlock]) + } else { + BrokenPortView(false) + } } - if (target != null) { + if (target != null && targetPort !is BrokenPortDeclaration) { targetView = myPortModelMap[target] if (sourceView is BrokenPortView) { sourceView.setOpposite(targetView) @@ -231,15 +216,57 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: return null } view.shrink() - val portView = BrokenPortView() + val portView = if (targetPort is BrokenPortDeclaration) { + BrokenPortView(true, targetPort, myElementModelMap[targetPort.functionBlock]) + } else { + BrokenPortView(true) + } + (targetPort as BrokenPortDeclaration).functionBlock portView.setOpposite(sourceView) targetView = portView } + + if (sourcePort is BrokenPortDeclaration) { + val fb = myElementModelMap[sourcePort.functionBlock] + if (fb is FunctionBlockView) { + fb.brokenPorts.addPort(sourcePort.name, sourcePort.kind, false) + val port = fb.findPort(sourcePort.name, sourcePort.kind, false) + if (port != null) { + myPortModelMap[source] = sourceView!! + myPorts[sourceView] = fb + (myComponentToPorts[fb] as HashSet).add(sourceView) + } + } + } + + if (targetPort is BrokenPortDeclaration) { + val fb = myElementModelMap[targetPort.functionBlock] + if (fb is FunctionBlockView) { + fb.brokenPorts.addPort(targetPort.name, targetPort.kind, true) + val port = fb.findPort(targetPort.name, targetPort.kind, true) + if (port != null) { + myPortModelMap[source] = targetView!! + myPorts[targetView] = fb + (myComponentToPorts[fb] as HashSet).add(targetView) + } + } + } + myConnectionSources[view] = sourceView myConnectionDestinations[view] = targetView return view } + private fun FunctionBlockView.findPort(name: String, kind: EntryKind, isInput: Boolean): FBPortDescriptor? { + val ports = when (kind) { + EntryKind.EVENT -> this.type.eventInputPorts to this.type.eventOutputPorts + EntryKind.DATA -> this.type.dataInputPorts to this.type.dataOutputPorts + EntryKind.ADAPTER -> this.type.socketPorts to this.type.plugPorts + } + + return (if (isInput) ports.first else ports.second).find { it.name == name } + } + val diagramView: DiagramView = object : DiagramView { override fun components(): Set { @@ -250,6 +277,10 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: return myConnectionSources.keys } + override fun portsTemplates(component: NetworkComponentView): Set { + return myComponentToPortTemplates[component] ?: emptySet() + } + override fun ports(component: NetworkComponentView): Set { return myComponentToPorts[component]!! } @@ -292,6 +323,10 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: return null } + override fun addPort(port: NetworkPortView, component: NetworkComponentView) { + myPorts[port] = component + } + override fun removeEdge(edge: NetworkConnectionView) { val connection = edge.connection if (connection != null && edge.isEditable) { @@ -315,6 +350,8 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: return null } + + override val isEditable: Boolean get() = this@NetworkView.isEditable } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/TypeDescriptorAdapter.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/TypeDescriptorAdapter.kt index 51761eb9e..714ef30ef 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/TypeDescriptorAdapter.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/TypeDescriptorAdapter.kt @@ -17,65 +17,35 @@ class TypeDescriptorAdapter(private val myOriginal: FBTypeDescriptor) : FBTypeDe return myOriginal.declaration } override val eventInputPorts: List - get() { - val ports = myOriginal.eventInputPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.inputEvents) { - list.add(FBPortDescriptor(eventName, EntryKind.EVENT, i++, true, false, null)) - } - return list - } + get() = getPorts(myOriginal.eventInputPorts, brokenPorts.inputEvents) override val eventOutputPorts: List - get() { - val ports = myOriginal.eventOutputPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.outputEvents) { - list.add(FBPortDescriptor(eventName, EntryKind.EVENT, i++, false, false, null)) - } - return list - } + get() = getPorts(myOriginal.eventOutputPorts, brokenPorts.outputEvents) override val dataInputPorts: List - get() { - val ports = myOriginal.dataInputPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.inputDatas) { - list.add(FBPortDescriptor(eventName, EntryKind.DATA, i++, true, false, null)) - } - return list - } + get() = getPorts(myOriginal.dataInputPorts, brokenPorts.inputDatas) override val dataOutputPorts: List - get() { - val ports = myOriginal.dataOutputPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.outputDatas) { - list.add(FBPortDescriptor(eventName, EntryKind.DATA, i++, false, false, null)) - } - return list - } + get() = getPorts(myOriginal.dataOutputPorts, brokenPorts.outputDatas) override val socketPorts: List - get() { - val ports = myOriginal.socketPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.sockets) { - list.add(FBPortDescriptor(eventName, EntryKind.ADAPTER, i++, true, false, null)) - } - return list - } + get() = getPorts(myOriginal.socketPorts, brokenPorts.sockets) override val plugPorts: List - get() { - val ports = myOriginal.plugPorts - val list = ArrayList(ports) - var i = ports.size - for (eventName in brokenPorts.plugs) { - list.add(FBPortDescriptor(eventName, EntryKind.ADAPTER, i++, true, false, null)) - } - return list + get() = getPorts(myOriginal.plugPorts, brokenPorts.plugs) + + private fun getPorts( + validPorts: List, + brokenPorts: List + ): List { + val result = ArrayList(validPorts) + brokenPorts.forEach { + result.add(FBPortDescriptor( + it.name, + it.connectionKind, + validPorts.size + (- it.position), + it.isInput, + it.isValid, + it.declaration) + ) } + return result + } override fun getAssociatedVariablesForInputEvent(eventNumber: Int): List { return myOriginal.getAssociatedVariablesForInputEvent(eventNumber) @@ -87,22 +57,33 @@ class TypeDescriptorAdapter(private val myOriginal: FBTypeDescriptor) : FBTypeDe class BrokenPorts { @JvmField - val inputEvents: List = ArrayList() + val inputEvents: MutableList = ArrayList() @JvmField - val outputEvents: List = ArrayList() + val outputEvents: MutableList = ArrayList() @JvmField - val inputDatas: List = ArrayList() + val inputDatas: MutableList = ArrayList() @JvmField - val outputDatas: List = ArrayList() + val outputDatas: MutableList = ArrayList() @JvmField - val plugs: List = ArrayList() + val plugs: MutableList = ArrayList() @JvmField - val sockets: List = ArrayList() + val sockets: MutableList = ArrayList() + + fun addPort(name: String, kind: EntryKind, isInput: Boolean) : FBPortDescriptor { + val list = when (kind) { + EntryKind.EVENT -> if (isInput) inputDatas else outputEvents + EntryKind.DATA -> if (isInput) inputDatas else outputDatas + EntryKind.ADAPTER -> if (isInput) sockets else plugs + } + val entry = FBPortDescriptor(name, kind, -list.size, isInput, false, null) + list.add(entry) + return entry + } } init { diff --git a/code/richediting/src/main/resources/META-INF/plugin.xml b/code/richediting/src/main/resources/META-INF/plugin.xml index ae49df50a..2ffc9da06 100644 --- a/code/richediting/src/main/resources/META-INF/plugin.xml +++ b/code/richediting/src/main/resources/META-INF/plugin.xml @@ -11,52 +11,62 @@ + + class="org.fbme.ide.richediting.actions.ecc.AlgorithmBodyVisibilityAction"/> + + + diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_Button.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_Button.kt new file mode 100644 index 000000000..e688b7837 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_Button.kt @@ -0,0 +1,34 @@ +package org.fbme.scenes.cells + +import jetbrains.mps.nodeEditor.cells.EditorCell_Basic +import jetbrains.mps.nodeEditor.cells.ParentSettings +import jetbrains.mps.openapi.editor.EditorContext +import org.fbme.scenes.cells.button.Button +import org.jetbrains.mps.openapi.model.SNode +import java.awt.Color +import java.awt.Graphics +import java.awt.Graphics2D + +class EditorCell_Button( + context: EditorContext, + node: SNode?, + private val button: Button +) : EditorCell_Basic(context, node) { + override fun paintContent(g: Graphics, p1: ParentSettings) { + button.paint(this.editor, g.create() as Graphics2D, myX, myY) + } + + override fun paintSelection(g: Graphics, c: Color?, drawBorder: Boolean, parentSettings: ParentSettings?) { + button.paintSelection(this.editor, g.create() as Graphics2D, myX, myY) + } + + init { + myWidth = button.width + myHeight = button.height + } + + companion object { + const val OY_OFFSET = -5 + const val DEFAULT_SIZE = 14 + } +} diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_SceneLabel.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_SceneLabel.kt index ef6a59e96..b8d1e9be8 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_SceneLabel.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/EditorCell_SceneLabel.kt @@ -9,7 +9,7 @@ import org.jetbrains.mps.openapi.model.SNode import java.awt.Color import java.awt.Graphics -class EditorCell_SceneLabel( +open class EditorCell_SceneLabel( context: EditorContext, node: SNode?, text: String?, diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/Button.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/Button.kt new file mode 100644 index 000000000..aff78aff6 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/Button.kt @@ -0,0 +1,11 @@ +package org.fbme.scenes.cells.button + +import java.awt.Component +import java.awt.Graphics2D + +interface Button { + val width: Int + val height: Int + fun paint(c: Component, g: Graphics2D, x: Int, y: Int) + fun paintSelection(c: Component, g: Graphics2D, x: Int, y: Int) +} diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/EditButton.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/EditButton.kt new file mode 100644 index 000000000..4fc933db3 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/EditButton.kt @@ -0,0 +1,3 @@ +package org.fbme.scenes.cells.button + +class EditButton : IconButton({ MyIcons.EditIcon }) diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/IconButton.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/IconButton.kt new file mode 100644 index 000000000..8408dddd3 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/IconButton.kt @@ -0,0 +1,20 @@ +package org.fbme.scenes.cells.button + +import java.awt.Component +import java.awt.Graphics2D +import javax.swing.Icon + +abstract class IconButton(private val icon: () -> Icon) : Button { + override val width: Int + get() = icon().iconWidth + override val height: Int + get() = icon().iconHeight + + override fun paint(c: Component, g: Graphics2D, x: Int, y: Int) { + icon().paintIcon(c, g, x, y) + } + + override fun paintSelection(c: Component, g: Graphics2D, x: Int, y: Int) { + icon().paintIcon(c, g, x, y) + } +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/MyIcons.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/MyIcons.kt new file mode 100644 index 000000000..6c8e8407e --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/MyIcons.kt @@ -0,0 +1,14 @@ +package org.fbme.scenes.cells.button + +import com.intellij.openapi.util.IconLoader + +object MyIcons { + @JvmField + val EditIcon = IconLoader.getIcon("/icons/pen.svg", javaClass) + @JvmField + val AddIcon = IconLoader.getIcon("/icons/add.svg", javaClass) + @JvmField + val AddIcon_Dark = IconLoader.getIcon("/icons/add_dark.svg", javaClass) + @JvmField + val TickIcon = IconLoader.getIcon("/icons/tick.svg", javaClass) +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/PlusButton.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/PlusButton.kt new file mode 100644 index 000000000..9d4a9b102 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/PlusButton.kt @@ -0,0 +1,5 @@ +package org.fbme.scenes.cells.button + +import com.intellij.util.ui.UIUtil + +class PlusButton : IconButton({ if (UIUtil.isUnderDarcula()) MyIcons.AddIcon_Dark else MyIcons.AddIcon }) diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/TickButton.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/TickButton.kt new file mode 100644 index 000000000..654c186d0 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/cells/button/TickButton.kt @@ -0,0 +1,3 @@ +package org.fbme.scenes.cells.button + +class TickButton : IconButton({ MyIcons.TickIcon }) diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/DefaultSelectionModel.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/DefaultSelectionModel.kt index 8288ccf17..8309178ef 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/DefaultSelectionModel.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/DefaultSelectionModel.kt @@ -1,5 +1,7 @@ package org.fbme.scenes.controllers +import org.fbme.scenes.controllers.selection.SelectionModelBase + class DefaultSelectionModel : SelectionModelBase() { override val selectedComponents: MutableSet = HashSet() diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/components/ComponentsFacility.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/components/ComponentsFacility.kt index 36e002663..08212d02f 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/components/ComponentsFacility.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/components/ComponentsFacility.kt @@ -6,21 +6,22 @@ import jetbrains.mps.openapi.editor.cells.CellAction import jetbrains.mps.openapi.editor.cells.CellActionType import org.fbme.scenes.controllers.* import org.fbme.scenes.controllers.scene.* +import org.fbme.scenes.controllers.selection.SelectionModel import org.fbme.scenes.viewmodel.ComponentsView import java.awt.Graphics2D import java.awt.Point import java.awt.Rectangle class ComponentsFacility( - val editor: SceneEditor, - val view: ComponentsView, - val controllerFactory: ComponentControllerFactory, - val componentSynchronizer: ComponentSynchronizer, - val layout: LayoutModel, - val selection: SelectionModel, - val sceneFocus: SceneFocusModel, - componentsLayer: Layer, - tracesLayer: Layer + val editor: SceneEditor, + val view: ComponentsView, + val controllerFactory: ComponentControllerFactory, + val componentSynchronizer: ComponentSynchronizer, + val layout: LayoutModel, + val selection: SelectionModel, + val sceneFocus: SceneFocusModel, + componentsLayer: Layer, + tracesLayer: Layer ) { var components: MutableMap> = HashMap() @@ -202,6 +203,8 @@ class ComponentsFacility( override fun dragTo(x: Int, y: Int) { val dx = x - myOrigin.x val dy = y - myOrigin.y + + if (!(dx * dx > 25 || dy * dy > 25)) return myHandle.moveTo(dx, dy) editor.fireRelayout() for (component in myMovedComponents) { @@ -210,6 +213,11 @@ class ComponentsFacility( } override fun completeAt(x: Int, y: Int) { + val dx = x - myOrigin.x + val dy = y - myOrigin.y + + if (!(dx * dx > 25 || dy * dy > 25)) return + myHandle.moveTo(x - myOrigin.x, y - myOrigin.y) myHandle.complete() editor.fireRelayout() diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt index 02bf1050c..5b115a953 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt @@ -6,7 +6,11 @@ import jetbrains.mps.openapi.editor.EditorContext import jetbrains.mps.openapi.editor.cells.CellAction import jetbrains.mps.openapi.editor.cells.CellActionType import org.fbme.scenes.controllers.* +import org.fbme.scenes.controllers.diagram.entry.ConnectionEntry import org.fbme.scenes.controllers.scene.* +import org.fbme.scenes.controllers.selection.SelectionModel +import org.fbme.scenes.exceptions.InitializationException +import org.fbme.scenes.utils.Notifier import java.awt.Graphics import java.awt.Graphics2D import java.awt.Point @@ -16,17 +20,17 @@ import java.util.function.BiFunction import java.util.function.Function class ConnectionsFacility( - val scene: SceneEditor, - val controllerFactory: ConnectionControllerFactory, - private val newPathFactory: BiFunction, - private val newPathPainter: BiConsumer, - val connectionSynchronizer: ConnectionPathSynchronizer, - componentsLayout: ROLayoutModel, - val componentsSelection: SelectionModel, - val diagramController: DiagramController, - connectionsLayer: Layer, - tracesLayer: Layer, - val sceneFocus: SceneFocusModel + val scene: SceneEditor, + val controllerFactory: ConnectionControllerFactory, + private val newPathFactory: BiFunction, + private val newPathPainter: BiConsumer, + val connectionSynchronizer: ConnectionPathSynchronizer, + componentsLayout: ROLayoutModel, + val componentsSelection: SelectionModel, + val diagramController: DiagramController, + connectionsLayer: Layer, + tracesLayer: Layer, + val sceneFocus: SceneFocusModel ) { private val connections: MutableMap> = HashMap() val connectionsSelection: MutableSet = HashSet() @@ -61,7 +65,11 @@ class ConnectionsFacility( private fun init() { val viewConnections = diagramController.connections for (connection in viewConnections) { - connections[connection] = ConnectionEntry(this@ConnectionsFacility, connection) + try { + connections[connection] = ConnectionEntry(this@ConnectionsFacility, connection) + } catch (e: InitializationException) { + Notifier.showError(e.message ?: "Can't initialize connection entry!") + } } } @@ -113,10 +121,10 @@ class ConnectionsFacility( } private fun changePath( - entry: ConnectionEntry, - connectionView: ConnT, - translatedPath: PathT, - completed: Boolean + entry: ConnectionEntry, + connectionView: ConnT, + translatedPath: PathT, + completed: Boolean ) { if (completed) { connectionSynchronizer.setPath(connectionView, translatedPath) @@ -334,12 +342,31 @@ class ConnectionsFacility( val targetSettings = diagramController.getPortController(target) if (targetSettings.canBeTargetedAt(x, y)) { scene.editorContext.repository.modelAccess.executeCommandInEDT { + targetSettings.connectTo(source) val edge = diagramController.addEdge(source, target) ?: return@executeCommandInEDT val newPath = newPathFactory.apply(sourceLocation, targetSettings.modelEndpointPosition) connectionSynchronizer.setPath(edge, newPath) } } + } else { + val template = diagramController.findPortTemplate(x, y) + if (template != null) { + val templateController = diagramController.getTemplateController(template) + if (templateController.canBeTargetedAt(x, y)) { + scene.editorContext.repository.modelAccess.executeCommandInEDT { + val nTarget = templateController.createPort(source) ?: return@executeCommandInEDT + val targetSettings = diagramController.getPortController(nTarget) + diagramController.addPort(nTarget) + val edge = diagramController.addEdge(source, nTarget) ?: return@executeCommandInEDT + val newPath = newPathFactory.apply(sourceLocation, targetSettings.modelEndpointPosition) + connectionSynchronizer.setPath(edge, newPath) + scene.editorContext.editorComponent.updater.update() + } + } + + } } + newConnectionPath = null scene.fireRepaint() } @@ -364,11 +391,29 @@ class ConnectionsFacility( val sourceSettings = diagramController.getPortController(source) if (sourceSettings.canBeSourcedAt(x, y)) { scene.editorContext.repository.modelAccess.executeCommandInEDT { + sourceSettings.connectTo(target) val edge = diagramController.addEdge(source, target) ?: return@executeCommandInEDT val newPath = newPathFactory.apply(sourceSettings.modelEndpointPosition, targetLocation) connectionSynchronizer.setPath(edge, newPath) } } + } else { + val template = diagramController.findPortTemplate(x, y) + if (template != null) { + val templateController = diagramController.getTemplateController(template) + if (templateController.canBeTargetedAt(x, y)) { + scene.editorContext.repository.modelAccess.executeCommandInEDT { + val nTarget = templateController.createPort(target) ?: return@executeCommandInEDT + val targetSettings = diagramController.getPortController(nTarget) + diagramController.addPort(nTarget) + val edge = diagramController.addEdge(nTarget, target) ?: return@executeCommandInEDT + val newPath = newPathFactory.apply(targetLocation, targetSettings.modelEndpointPosition) + connectionSynchronizer.setPath(edge, newPath) + scene.editorContext.editorComponent.updater.update() + } + } + + } } newConnectionPath = null scene.fireRepaint() diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramController.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramController.kt index 89131e92e..98cf08c24 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramController.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramController.kt @@ -2,8 +2,10 @@ package org.fbme.scenes.controllers.diagram interface DiagramController { val isDiagramEditable: Boolean - fun getPortController(port: PortT): PortController + fun getPortController(port: PortT): PortController + fun getTemplateController(template: PortT): TemplateController fun findPort(x: Int, y: Int): PortT? + fun findPortTemplate(x: Int, y: Int): PortT? val components: Set val connections: Set fun getPorts(component: CompT): Set @@ -14,4 +16,5 @@ interface DiagramController { fun setTarget(edge: ConnT, port: PortT) fun removeEdge(edge: ConnT) fun addEdge(sourcePort: PortT, targetPort: PortT): ConnT? + fun addPort(port: PortT) } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt index 0b25ab078..6b01c5469 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt @@ -1,11 +1,12 @@ package org.fbme.scenes.controllers.diagram -import java.awt.Point -import java.awt.Rectangle +import org.fbme.scenes.controllers.diagram.entry.PortEntry +import org.fbme.scenes.controllers.diagram.entry.PortTemplateEntry +import org.fbme.scenes.exceptions.NoEntityException class DiagramFacility( private val diagramModel: DiagramView, - private val portSettingProvider: PortSettingProvider, + private val portSettingProvider: PortSettingProvider, private val componentSettings: DiagramComponentSettingProvider ) { private val components: MutableSet = HashSet() @@ -14,7 +15,9 @@ class DiagramFacility( private val portToComponent: MutableMap = HashMap() private val connectionToSource: MutableMap = HashMap() private val connectionToTarget: MutableMap = HashMap() - private val ports: MutableMap = HashMap() + private val portTemplates: MutableList = mutableListOf() + private val portTemplatesToComponent: MutableMap, CompT> = HashMap() + private val ports: MutableMap> = HashMap() val diagramController: DiagramController = MyDiagramController() private fun init() { @@ -23,9 +26,25 @@ class DiagramFacility( val ports = HashSet(diagramModel.ports(component)) componentToPorts[component] = ports for (port in ports) { - this.ports.computeIfAbsent(port) { PortEntry(it) } + this.ports.computeIfAbsent(port) { + PortEntry(it, component, componentSettings, portSettingProvider) + } portToComponent[port] = component } + + val templates = portSettingProvider.getPortTemplates(component) + portTemplates.addAll(templates) + templates.forEach { + val template = PortTemplateEntry( + it, + component, + this.portToComponent, + this.ports, + componentSettings, + portSettingProvider + ) + portTemplatesToComponent[template] = component + } } for (edge in diagramModel.edges()) { edges.add(edge) @@ -37,17 +56,26 @@ class DiagramFacility( private inner class MyDiagramController : DiagramController { override val isDiagramEditable: Boolean get() = diagramModel.isEditable + + override fun getTemplateController(template: PortT): TemplateController { + return portTemplatesToComponent.keys.find { it.template == template }!! + } + override val components: Set get() = this@DiagramFacility.components override val connections: Set get() = edges + override fun addPort(port: PortT) { + diagramModel.addPort(port, portToComponent[port]!!) + } + override fun getComponent(port: PortT): CompT { - return portToComponent[port] ?: error("Component not found") + return portToComponent[port] ?: throw NoEntityException("Can't find component") } - override fun getPortController(port: PortT): PortController { - return ports[port] ?: error("Port controller not found") + override fun getPortController(port: PortT): PortController { + return ports[port] ?: throw NoEntityException("Can't find port controller") } override fun findPort(x: Int, y: Int): PortT? { @@ -59,8 +87,17 @@ class DiagramFacility( return null } + override fun findPortTemplate(x: Int, y: Int): PortT? { + for (entry in portTemplatesToComponent.keys) { + if (entry.bounds.contains(x, y)) { + return entry.template + } + } + return null + } + override fun getPorts(component: CompT): Set { - return componentToPorts[component] ?: error("Ports not found") + return componentToPorts[component] ?: throw NoEntityException("Can't find port!") } override fun getSource(edge: ConnT): PortT? { @@ -88,35 +125,6 @@ class DiagramFacility( } } - private inner class PortEntry(val port: PortT) : PortController { - override val bounds: Rectangle - get() { - val component = portToComponent[port] ?: error("Component not found") - return portSettingProvider.getBounds(componentSettings.getModelForm(component), port) - } - override val modelEndpointPosition: Point - get() { - val component = portToComponent[port] ?: error("Component not found") - return portSettingProvider.getEndpointPosition(componentSettings.getModelForm(component), port) - } - override val transformedEndpointPosition: Point? - get() { - val component = portToComponent[port] ?: error("Component not found") - val transformedForm = componentSettings.getTransformedForm(component) ?: return null - return portSettingProvider.getEndpointPosition(transformedForm, port) - } - - override fun canBeSourcedAt(x: Int, y: Int): Boolean { - val component = portToComponent[port] ?: error("Component not found") - return portSettingProvider.canBeSourcedAt(componentSettings.getModelForm(component), port, x, y) - } - - override fun canBeTargetedAt(x: Int, y: Int): Boolean { - val component = portToComponent[port] ?: error("Component not found") - return portSettingProvider.canBeTargetedAt(componentSettings.getModelForm(component), port, x, y) - } - } - init { init() } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramView.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramView.kt index 8256e7848..2a91ec63f 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramView.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramView.kt @@ -5,6 +5,7 @@ interface DiagramView { fun components(): Set fun edges(): Set fun ports(component: C): Set

+ fun portsTemplates(component: C): Set

fun component(port: P): C fun sourcePort(edge: E): P fun setSourcePort(edge: E, port: P) @@ -12,4 +13,5 @@ interface DiagramView { fun setTargetPort(edge: E, port: P) fun removeEdge(edge: E) fun addEdge(sourcePort: P, targetPort: P): E? + fun addPort(port: P, component: C) {} } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortController.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortController.kt index c622e938a..1e9567833 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortController.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortController.kt @@ -3,10 +3,11 @@ package org.fbme.scenes.controllers.diagram import java.awt.Point import java.awt.Rectangle -interface PortController { +interface PortController { val bounds: Rectangle val modelEndpointPosition: Point val transformedEndpointPosition: Point? fun canBeSourcedAt(x: Int, y: Int): Boolean fun canBeTargetedAt(x: Int, y: Int): Boolean + fun connectTo(port: PortT) } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortSettingProvider.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortSettingProvider.kt index 7f34393fc..fe4f874c6 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortSettingProvider.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/PortSettingProvider.kt @@ -3,9 +3,14 @@ package org.fbme.scenes.controllers.diagram import java.awt.Point import java.awt.Rectangle -interface PortSettingProvider { +interface PortSettingProvider { fun getBounds(componentForm: CFormT, port: PortT): Rectangle fun getEndpointPosition(componentForm: CFormT, port: PortT): Point + + fun getPortTemplates(componentForm: CompT): Set { + return emptySet() + } + fun canBeSourcedAt(componentForm: CFormT, port: PortT, x: Int, y: Int): Boolean { return true } @@ -13,4 +18,19 @@ interface PortSettingProvider { fun canBeTargetedAt(componentForm: CFormT, port: PortT, x: Int, y: Int): Boolean { return true } + + fun getTemplateBounds(modelForm: CFormT, template: PortT): Rectangle { + return Rectangle(0, 0) + } + + fun getTemplateEndpointPosition(modelForm: CFormT, template: PortT): Point { + return Point(0, 0) + } + + fun createPort(source: PortT, template: PortT): PortT? { + return null + } + + fun connectPortTo(source: PortT, port: PortT) { + } } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/TemplateController.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/TemplateController.kt new file mode 100644 index 000000000..e1e33ac31 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/TemplateController.kt @@ -0,0 +1,7 @@ +package org.fbme.scenes.controllers.diagram + +interface TemplateController { + fun canBeSourcedAt(x: Int, y: Int): Boolean + fun canBeTargetedAt(x: Int, y: Int): Boolean + fun createPort(source: PortT): PortT? +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/ConnectionEntry.kt similarity index 78% rename from code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt rename to code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/ConnectionEntry.kt index 057c0c25e..69e6e0a1f 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/ConnectionEntry.kt @@ -1,11 +1,15 @@ -package org.fbme.scenes.controllers.diagram +package org.fbme.scenes.controllers.diagram.entry +import org.fbme.scenes.controllers.diagram.ConnectionController +import org.fbme.scenes.controllers.diagram.ConnectionsFacility +import org.fbme.scenes.exceptions.InitializationException +import org.fbme.scenes.exceptions.NoEntityException import java.awt.Point import java.awt.Rectangle internal class ConnectionEntry( - private val connectionsFacility: ConnectionsFacility, - val connection: ConnT + private val connectionsFacility: ConnectionsFacility, + val connection: ConnT ) { val controller: ConnectionController = connectionsFacility.controllerFactory.create(connectionsFacility.scene.editorContext, connection) @@ -57,10 +61,13 @@ internal class ConnectionEntry( init { val diagramController = connectionsFacility.diagramController - val sourcePort = diagramController.getSource(connection) ?: error("Source not found") - val targetPort = diagramController.getTarget(connection) ?: error("Target not found") - val sourcePortController = diagramController.getPortController(sourcePort) - val targetPortController = diagramController.getPortController(targetPort) + val sourcePort = diagramController.getSource(connection) ?: throw InitializationException("Source not found") + val targetPort = diagramController.getTarget(connection) ?: throw InitializationException("Target not found") + val (sourcePortController, targetPortController) = try { + diagramController.getPortController(sourcePort) to diagramController.getPortController(targetPort) + } catch (e: NoEntityException) { + throw InitializationException(e.message, e) + } modelPath = pathProvider(sourcePortController.modelEndpointPosition, targetPortController.modelEndpointPosition) } } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortEntry.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortEntry.kt new file mode 100644 index 000000000..e34a4df52 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortEntry.kt @@ -0,0 +1,40 @@ +package org.fbme.scenes.controllers.diagram.entry + +import org.fbme.scenes.controllers.diagram.DiagramComponentSettingProvider +import org.fbme.scenes.controllers.diagram.PortController +import org.fbme.scenes.controllers.diagram.PortSettingProvider +import java.awt.Point +import java.awt.Rectangle + +class PortEntry( + val port: PortT, + val component: CompT, + private val componentSettings: DiagramComponentSettingProvider, + private val portSettingProvider: PortSettingProvider, +) : PortController { + override val bounds: Rectangle + get() { + return portSettingProvider.getBounds(componentSettings.getModelForm(component), port) + } + override val modelEndpointPosition: Point + get() { + return portSettingProvider.getEndpointPosition(componentSettings.getModelForm(component), port) + } + override val transformedEndpointPosition: Point? + get() { + val transformedForm = componentSettings.getTransformedForm(component) ?: return null + return portSettingProvider.getEndpointPosition(transformedForm, port) + } + + override fun canBeSourcedAt(x: Int, y: Int): Boolean { + return portSettingProvider.canBeSourcedAt(componentSettings.getModelForm(component), port, x, y) + } + + override fun canBeTargetedAt(x: Int, y: Int): Boolean { + return portSettingProvider.canBeTargetedAt(componentSettings.getModelForm(component), port, x, y) + } + + override fun connectTo(source: PortT) { + portSettingProvider.connectPortTo(source, port) + } +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortTemplateEntry.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortTemplateEntry.kt new file mode 100644 index 000000000..08111245e --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/entry/PortTemplateEntry.kt @@ -0,0 +1,43 @@ +package org.fbme.scenes.controllers.diagram.entry + +import org.fbme.scenes.controllers.diagram.DiagramComponentSettingProvider +import org.fbme.scenes.controllers.diagram.PortController +import org.fbme.scenes.controllers.diagram.PortSettingProvider +import org.fbme.scenes.controllers.diagram.TemplateController +import java.awt.Point +import java.awt.Rectangle + +class PortTemplateEntry( + val template: PortT, + val component: CompT, + val portToComponent: MutableMap, + val ports: MutableMap>, + private val componentSettings: DiagramComponentSettingProvider, + private val portSettingProvider: PortSettingProvider, +) : PortController, TemplateController { + override val bounds: Rectangle + get() = portSettingProvider.getTemplateBounds(componentSettings.getModelForm(component), template) + override val modelEndpointPosition: Point + get() = portSettingProvider.getTemplateEndpointPosition(componentSettings.getModelForm(component), template) + override val transformedEndpointPosition: Point? + get() = TODO("Not yet implemented") + + override fun canBeSourcedAt(x: Int, y: Int): Boolean { + return true + } + + override fun canBeTargetedAt(x: Int, y: Int): Boolean { + return true + } + + override fun connectTo(port: PortT) { + //TODO + } + + override fun createPort(source: PortT): PortT? { + val nPort = portSettingProvider.createPort(source, template) ?: return null + ports.computeIfAbsent(nPort) { PortEntry(nPort, component, componentSettings, portSettingProvider) } + portToComponent[nPort] = component + return nPort + } +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/edited/EditedModel.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/edited/EditedModel.kt new file mode 100644 index 000000000..5ca73b604 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/edited/EditedModel.kt @@ -0,0 +1,9 @@ +package org.fbme.scenes.controllers.edited + +interface EditedModel { + val editedComponents: List + + fun setEdited(component: T, edited: Boolean) + + fun isEdited(component: T): Boolean +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModel.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModel.kt similarity index 90% rename from code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModel.kt rename to code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModel.kt index e17db034b..a6c19b6e6 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModel.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModel.kt @@ -1,4 +1,4 @@ -package org.fbme.scenes.controllers +package org.fbme.scenes.controllers.selection interface SelectionModel { val selectedComponents: Set diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModelBase.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModelBase.kt similarity index 92% rename from code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModelBase.kt rename to code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModelBase.kt index e66578afa..150f9707d 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/SelectionModelBase.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/selection/SelectionModelBase.kt @@ -1,4 +1,4 @@ -package org.fbme.scenes.controllers +package org.fbme.scenes.controllers.selection abstract class SelectionModelBase : SelectionModel { private val listeners: MutableSet> = HashSet() diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/InitializationException.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/InitializationException.kt new file mode 100644 index 000000000..b10736d02 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/InitializationException.kt @@ -0,0 +1,6 @@ +package org.fbme.scenes.exceptions + +class InitializationException : Exception { + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/NoEntityException.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/NoEntityException.kt new file mode 100644 index 000000000..92f04d2d8 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/exceptions/NoEntityException.kt @@ -0,0 +1,6 @@ +package org.fbme.scenes.exceptions + +class NoEntityException : Exception { + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) +} \ No newline at end of file diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/utils/Notifier.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/utils/Notifier.kt new file mode 100644 index 000000000..c0784d89f --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/utils/Notifier.kt @@ -0,0 +1,33 @@ +package org.fbme.scenes.utils + +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project + +object Notifier { + private const val NOTIFICATION_GROUP = "Custom-scenes" + + fun showWarning(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.WARNING) + .notify(project) + } + + fun showInformation(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.INFORMATION) + .notify(project) + } + + fun showError(message: String, project: Project? = null) { + NotificationGroupManager + .getInstance() + .getNotificationGroup(NOTIFICATION_GROUP) + .createNotification(message, NotificationType.ERROR) + .notify(project) + } +} diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/viewmodel/CompletionItem.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/viewmodel/CompletionItem.kt new file mode 100644 index 000000000..d541507d8 --- /dev/null +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/viewmodel/CompletionItem.kt @@ -0,0 +1,10 @@ +package org.fbme.scenes.viewmodel + +import jetbrains.mps.openapi.editor.EditorContext +import org.jetbrains.mps.openapi.model.SNode + +interface CompletionItem { + fun getMatchingText(pattern: String?): String? + val descriptionText: String? + fun doSubstitute(editorContext: EditorContext?, pattern: String?): SNode? +} \ No newline at end of file diff --git a/code/scenes/src/main/resources/META-INF/plugin.xml b/code/scenes/src/main/resources/META-INF/plugin.xml index b0a61eb9d..89be27770 100644 --- a/code/scenes/src/main/resources/META-INF/plugin.xml +++ b/code/scenes/src/main/resources/META-INF/plugin.xml @@ -11,6 +11,7 @@ + diff --git a/code/scenes/src/main/resources/icons/add.svg b/code/scenes/src/main/resources/icons/add.svg new file mode 100644 index 000000000..19eb5a038 --- /dev/null +++ b/code/scenes/src/main/resources/icons/add.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/code/scenes/src/main/resources/icons/add_dark.svg b/code/scenes/src/main/resources/icons/add_dark.svg new file mode 100644 index 000000000..3c65e2b33 --- /dev/null +++ b/code/scenes/src/main/resources/icons/add_dark.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/code/scenes/src/main/resources/icons/pen.svg b/code/scenes/src/main/resources/icons/pen.svg new file mode 100644 index 000000000..132b31694 --- /dev/null +++ b/code/scenes/src/main/resources/icons/pen.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/code/scenes/src/main/resources/icons/tick.svg b/code/scenes/src/main/resources/icons/tick.svg new file mode 100644 index 000000000..32743d9d1 --- /dev/null +++ b/code/scenes/src/main/resources/icons/tick.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps b/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps index 67b9e3804..9105febc4 100644 --- a/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps +++ b/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps @@ -956,8 +956,8 @@ - - + + @@ -976,8 +976,8 @@ - - + + @@ -989,8 +989,8 @@ - - + + @@ -1014,8 +1014,8 @@ - - + + @@ -1027,7 +1027,7 @@ - + @@ -1053,8 +1053,8 @@ - - + + @@ -1117,7 +1117,9 @@ - + + + @@ -1128,14 +1130,18 @@ - + + + + + - - + + @@ -1236,33 +1242,20 @@ - - + + - - + + - - - - - - - - - - - - -