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