44 CommandExecutionContext ,
55 CommandReturn ,
66 ISnapper ,
7+ isSelected ,
8+ SChildElementImpl ,
79 SModelElementImpl ,
810 SNodeImpl ,
911 SParentElementImpl ,
@@ -15,93 +17,146 @@ import { LabelAssignment, LabelTypeRegistry } from "./labelTypeRegistry";
1517import { snapPortsOfNode } from "../dfdElements/portSnapper" ;
1618import { EditorModeController } from "../editorMode/editorModeController" ;
1719
18- export interface AddLabelAssignmentAction extends Action {
19- kind : typeof AddLabelAssignmentAction . TYPE ;
20- element : ContainsDfdLabels & SNodeImpl ;
20+ interface LabelAction extends Action {
21+ element ?: ContainsDfdLabels & SNodeImpl ;
2122 labelAssignment : LabelAssignment ;
2223}
23- export namespace AddLabelAssignmentAction {
24- export const TYPE = "add-label-assignment" ;
25- export function create (
26- element : ContainsDfdLabels & SNodeImpl ,
27- labelAssignment : LabelAssignment ,
28- ) : AddLabelAssignmentAction {
29- return {
30- kind : TYPE ,
31- element,
32- labelAssignment,
33- } ;
34- }
35- }
36-
37- @injectable ( )
38- export class AddLabelAssignmentCommand extends Command {
39- public static readonly KIND = AddLabelAssignmentAction . TYPE ;
40- private hasBeenAdded = false ;
41-
24+ abstract class LabelCommand extends Command {
4225 @inject ( EditorModeController )
4326 @optional ( )
44- private readonly editorModeController ?: EditorModeController ;
27+ protected readonly editorModeController ?: EditorModeController ;
28+
29+ protected elements ?: SModelElementImpl [ ] ;
4530
4631 constructor (
47- @inject ( TYPES . Action ) private action : AddLabelAssignmentAction ,
48- @inject ( TYPES . ISnapper ) private snapper : ISnapper ,
32+ @inject ( TYPES . Action ) protected action : LabelAction ,
33+ @inject ( TYPES . ISnapper ) protected snapper : ISnapper ,
4934 ) {
5035 super ( ) ;
5136 }
5237
53- execute ( context : CommandExecutionContext ) : CommandReturn {
38+ protected fetchElements ( context : CommandExecutionContext ) : SModelElementImpl [ ] {
5439 if ( this . editorModeController ?. isReadOnly ( ) ) {
55- return context . root ;
40+ return [ ] ;
5641 }
5742
58- // Check whether the element already has a label with the same type and value assigned
59- this . hasBeenAdded =
60- this . action . element . labels . find ( ( as ) => {
61- return (
62- as . labelTypeId === this . action . labelAssignment . labelTypeId &&
63- as . labelTypeValueId === this . action . labelAssignment . labelTypeValueId
64- ) ;
65- } ) === undefined ;
43+ const allElements = getAllElements ( context . root . children ) ;
44+ const selectedElements = allElements . filter ( ( element ) => isSelected ( element ) ) ;
6645
67- if ( this . hasBeenAdded ) {
68- this . action . element . labels . push ( this . action . labelAssignment ) ;
46+ const selectionHasElement =
47+ selectedElements . find ( ( element ) => element . id === this . action . element ?. id ) !== undefined ;
48+ if ( selectionHasElement ) {
49+ return selectedElements ;
6950 }
51+ return this . action . element ? [ this . action . element ] : selectedElements ;
52+ }
53+
54+ protected addLabel ( context : CommandExecutionContext ) {
55+ if ( this . editorModeController ?. isReadOnly ( ) ) {
56+ return context . root ;
57+ }
58+
59+ if ( this . elements === undefined ) {
60+ this . elements = this . fetchElements ( context ) ;
61+ }
62+
63+ this . elements . forEach ( ( element ) => {
64+ if ( containsDfdLabels ( element ) ) {
65+ const hasBeenAdded =
66+ element . labels . find ( ( as ) => {
67+ return (
68+ as . labelTypeId === this . action . labelAssignment . labelTypeId &&
69+ as . labelTypeValueId === this . action . labelAssignment . labelTypeValueId
70+ ) ;
71+ } ) !== undefined ;
72+ if ( ! hasBeenAdded ) {
73+ element . labels . push ( this . action . labelAssignment ) ;
74+ if ( element instanceof SNodeImpl ) {
75+ snapPortsOfNode ( element , this . snapper ) ;
76+ }
77+ }
78+ }
79+ } ) ;
7080
71- snapPortsOfNode ( this . action . element , this . snapper ) ;
7281 return context . root ;
7382 }
7483
75- undo ( context : CommandExecutionContext ) : CommandReturn {
84+ protected removeLabel ( context : CommandExecutionContext ) {
7685 if ( this . editorModeController ?. isReadOnly ( ) ) {
7786 return context . root ;
7887 }
7988
80- const labels = this . action . element . labels ;
81- const idx = labels . indexOf ( this . action . labelAssignment ) ;
82- if ( idx >= 0 && this . hasBeenAdded ) {
83- labels . splice ( idx , 1 ) ;
89+ if ( this . elements === undefined ) {
90+ this . elements = this . fetchElements ( context ) ;
8491 }
8592
86- snapPortsOfNode ( this . action . element , this . snapper ) ;
93+ this . elements . forEach ( ( element ) => {
94+ if ( containsDfdLabels ( element ) ) {
95+ const labels = element . labels ;
96+ const idx = labels . findIndex (
97+ ( l ) =>
98+ l . labelTypeId == this . action . labelAssignment . labelTypeId &&
99+ l . labelTypeValueId == this . action . labelAssignment . labelTypeValueId ,
100+ ) ;
101+ if ( idx >= 0 ) {
102+ labels . splice ( idx , 1 ) ;
103+ if ( element instanceof SNodeImpl ) {
104+ snapPortsOfNode ( element , this . snapper ) ;
105+ }
106+ }
107+ }
108+ } ) ;
109+
87110 return context . root ;
88111 }
112+ }
113+
114+ export interface AddLabelAssignmentAction extends LabelAction {
115+ kind : typeof AddLabelAssignmentAction . TYPE ;
116+ }
117+ export namespace AddLabelAssignmentAction {
118+ export const TYPE = "add-label-assignment" ;
119+ export function create (
120+ labelAssignment : LabelAssignment ,
121+ element ?: ContainsDfdLabels & SNodeImpl ,
122+ ) : AddLabelAssignmentAction {
123+ return {
124+ kind : TYPE ,
125+ element,
126+ labelAssignment,
127+ } ;
128+ }
129+ }
130+
131+ @injectable ( )
132+ export class AddLabelAssignmentCommand extends LabelCommand {
133+ public static readonly KIND = AddLabelAssignmentAction . TYPE ;
134+
135+ constructor ( @inject ( TYPES . Action ) action : AddLabelAssignmentAction , @inject ( TYPES . ISnapper ) snapper : ISnapper ) {
136+ super ( action , snapper ) ;
137+ }
138+
139+ execute ( context : CommandExecutionContext ) : CommandReturn {
140+ return this . addLabel ( context ) ;
141+ }
142+
143+ undo ( context : CommandExecutionContext ) : CommandReturn {
144+ return this . removeLabel ( context ) ;
145+ }
89146
90147 redo ( context : CommandExecutionContext ) : CommandReturn {
91148 return this . execute ( context ) ;
92149 }
93150}
94151
95- export interface DeleteLabelAssignmentAction extends Action {
152+ export interface DeleteLabelAssignmentAction extends LabelAction {
96153 kind : typeof DeleteLabelAssignmentAction . TYPE ;
97- element : ContainsDfdLabels & SNodeImpl ;
98- labelAssignment : LabelAssignment ;
99154}
100155export namespace DeleteLabelAssignmentAction {
101156 export const TYPE = "delete-label-assignment" ;
102157 export function create (
103- element : ContainsDfdLabels & SNodeImpl ,
104158 labelAssignment : LabelAssignment ,
159+ element ?: ContainsDfdLabels & SNodeImpl ,
105160 ) : DeleteLabelAssignmentAction {
106161 return {
107162 kind : TYPE ,
@@ -112,46 +167,19 @@ export namespace DeleteLabelAssignmentAction {
112167}
113168
114169@injectable ( )
115- export class DeleteLabelAssignmentCommand extends Command {
170+ export class DeleteLabelAssignmentCommand extends LabelCommand {
116171 public static readonly KIND = DeleteLabelAssignmentAction . TYPE ;
117172
118- @inject ( EditorModeController )
119- @optional ( )
120- private readonly editorModeController ?: EditorModeController ;
121-
122- constructor (
123- @inject ( TYPES . Action ) private action : DeleteLabelAssignmentAction ,
124- @inject ( TYPES . ISnapper ) private snapper : ISnapper ,
125- ) {
126- super ( ) ;
173+ constructor ( @inject ( TYPES . Action ) action : DeleteLabelAssignmentAction , @inject ( TYPES . ISnapper ) snapper : ISnapper ) {
174+ super ( action , snapper ) ;
127175 }
128176
129177 execute ( context : CommandExecutionContext ) : CommandReturn {
130- if ( this . editorModeController ?. isReadOnly ( ) ) {
131- return context . root ;
132- }
133-
134- const labels = this . action . element . labels ;
135-
136- const idx = labels . indexOf ( this . action . labelAssignment ) ;
137- if ( idx >= 0 ) {
138- labels . splice ( idx , 1 ) ;
139- }
140-
141- snapPortsOfNode ( this . action . element , this . snapper ) ;
142- return context . root ;
178+ return this . removeLabel ( context ) ;
143179 }
144180
145181 undo ( context : CommandExecutionContext ) : CommandReturn {
146- if ( this . editorModeController ?. isReadOnly ( ) ) {
147- return context . root ;
148- }
149-
150- const labels = this . action . element . labels ;
151- labels . push ( this . action . labelAssignment ) ;
152-
153- snapPortsOfNode ( this . action . element , this . snapper ) ;
154- return context . root ;
182+ return this . addLabel ( context ) ;
155183 }
156184
157185 redo ( context : CommandExecutionContext ) : CommandReturn {
@@ -314,3 +342,14 @@ export class DeleteLabelTypeCommand extends Command {
314342 return this . execute ( context ) ;
315343 }
316344}
345+
346+ function getAllElements ( elements : readonly SChildElementImpl [ ] ) : SModelElementImpl [ ] {
347+ const elementsList : SModelElementImpl [ ] = [ ] ;
348+ for ( const element of elements ) {
349+ elementsList . push ( element ) ;
350+ if ( "children" in element ) {
351+ elementsList . push ( ...getAllElements ( element . children ) ) ;
352+ }
353+ }
354+ return elementsList ;
355+ }
0 commit comments