ea 0.6.14 → 0.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ea/model/classifier.rb +4 -0
- data/lib/ea/sources/qea/classifier_builder.rb +2 -0
- data/lib/ea/sources/qea/diagram_builder.rb +35 -6
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +23 -4
- data/lib/ea/svg/ea_emitter/elements.rb +31 -5
- data/lib/ea/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a8c5868e2f18d7a28583d8e862f15f7f3f46703012ba58914d273a12f390b357
|
|
4
|
+
data.tar.gz: 61024b7e2ddb30066b9daafcad0ba9b324451e70d2344db82ab2106fc16e53e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 76574a19dbc1a01c1add8adca00fad58dc18b436ba28869564e5bab050609fc701b5cc0874d6693d9553e670120bd19582d91477a41981e7a2ed8812dd2b45a5
|
|
7
|
+
data.tar.gz: cfe049c8be3f068b1dedc0f65dff2fb2b856b0eee9eafa63efd2fdd088ab0a71bd7894ce86693cb06d574baae6c686a7aa5afca2f507f1c60ff0e8e8d36e6b5c
|
data/lib/ea/model/classifier.rb
CHANGED
|
@@ -15,6 +15,8 @@ module Ea
|
|
|
15
15
|
attribute :package_id, :string # containing package
|
|
16
16
|
attribute :package_name, :string # containing package name
|
|
17
17
|
attribute :is_abstract, :boolean, default: false
|
|
18
|
+
attribute :is_root, :boolean, default: false
|
|
19
|
+
attribute :is_leaf, :boolean, default: false
|
|
18
20
|
attribute :visibility, :string
|
|
19
21
|
attribute :model_kind, :string, default: -> { "classifier" }
|
|
20
22
|
attribute :properties, Property, collection: true, initialize_empty: true
|
|
@@ -31,6 +33,8 @@ module Ea
|
|
|
31
33
|
map "packageId", to: :package_id
|
|
32
34
|
map "packageName", to: :package_name
|
|
33
35
|
map "isAbstract", to: :is_abstract, render_default: true
|
|
36
|
+
map "isRoot", to: :is_root, render_default: true
|
|
37
|
+
map "isLeaf", to: :is_leaf, render_default: true
|
|
34
38
|
map "visibility", to: :visibility
|
|
35
39
|
map "modelKind", to: :model_kind, render_default: true
|
|
36
40
|
map "properties", to: :properties, render_empty: true
|
|
@@ -94,6 +94,8 @@ module Ea
|
|
|
94
94
|
package_name: package_name_for(object),
|
|
95
95
|
qualified_name: qualified_name_for(object),
|
|
96
96
|
is_abstract: abstract?(object),
|
|
97
|
+
is_root: object.isroot.to_i == 1,
|
|
98
|
+
is_leaf: object.isleaf.to_i == 1,
|
|
97
99
|
visibility: visibility_from_scope(object.scope),
|
|
98
100
|
properties: properties_for(object),
|
|
99
101
|
operations: OperationBuilder.new(database).build_all_for(object),
|
|
@@ -377,15 +377,31 @@ module Ea
|
|
|
377
377
|
element_edge_point(target_placement, :target, edge_out)
|
|
378
378
|
|
|
379
379
|
intermediate = intermediate_waypoints(link_row)
|
|
380
|
-
if edge_out == 2 && source_port && target_port
|
|
381
|
-
|
|
382
|
-
#
|
|
383
|
-
#
|
|
384
|
-
#
|
|
385
|
-
#
|
|
380
|
+
if edge_out == 2 && source_port && target_port &&
|
|
381
|
+
!valid_tree_path?(intermediate, source_placement)
|
|
382
|
+
# EA recomputes tree routes at DRAW TIME from current
|
|
383
|
+
# element positions when the stored Path no longer lands
|
|
384
|
+
# on the source's facing edge (hand-verified: SY 8542's
|
|
385
|
+
# stale Path vs EA-drawn route; CityObjectGroup's current
|
|
386
|
+
# Path renders byte-exact and is kept). Computed route:
|
|
387
|
+
# source port -> corner at (target dock x, source exit
|
|
388
|
+
# y) -> target port.
|
|
386
389
|
points = [[source_point[0], source_point[1]],
|
|
387
390
|
[target_point[0], source_point[1]],
|
|
388
391
|
[target_point[0], target_point[1]]]
|
|
392
|
+
elsif edge_out == 2 && intermediate.size == 1
|
|
393
|
+
# Current tree Path (bend on the source's facing edge):
|
|
394
|
+
# EA's draw-time route shape — source right edge at the
|
|
395
|
+
# bend's y, corner at the bend, target facing edge at the
|
|
396
|
+
# bend's x (byte-exact on CityObjectGroup).
|
|
397
|
+
src = bounds_from_rect(source_placement)
|
|
398
|
+
tgt = bounds_from_rect(target_placement)
|
|
399
|
+
bend = intermediate.first
|
|
400
|
+
going_up = tgt.y + tgt.height <= src.y
|
|
401
|
+
target_y = going_up ? tgt.y + tgt.height : tgt.y
|
|
402
|
+
points = [[src.x + src.width, bend[1]],
|
|
403
|
+
[bend[0], bend[1]],
|
|
404
|
+
[bend[0], target_y]]
|
|
389
405
|
elsif intermediate.any?
|
|
390
406
|
points = [source_point, *intermediate, target_point]
|
|
391
407
|
elsif source_port || target_port
|
|
@@ -401,6 +417,19 @@ module Ea
|
|
|
401
417
|
end
|
|
402
418
|
end
|
|
403
419
|
|
|
420
|
+
# A tree Path is current when its bend height still falls
|
|
421
|
+
# within the source element's y-range (the exit height EA
|
|
422
|
+
# records); a bend outside the element is stale and EA
|
|
423
|
+
# re-derives the route at draw time. The bend's x may sit
|
|
424
|
+
# arbitrarily far right (trunk position).
|
|
425
|
+
def valid_tree_path?(intermediate, source_placement)
|
|
426
|
+
return false if intermediate.empty?
|
|
427
|
+
|
|
428
|
+
bend = intermediate.first
|
|
429
|
+
b = bounds_from_rect(source_placement)
|
|
430
|
+
bend[1].between?(b.y - 5, b.y + b.height + 5)
|
|
431
|
+
end
|
|
432
|
+
|
|
404
433
|
# Absolute connection point EA docks the connector's visible
|
|
405
434
|
# endpoint at, derived from the Geometry SX/SY (source) and
|
|
406
435
|
# EX/EY (target) offsets. The offsets are measured inward from
|
|
@@ -20,6 +20,8 @@ module Ea
|
|
|
20
20
|
attr_reader :bounds, :size, :header_lines_count,
|
|
21
21
|
:attr_lines_count, :op_lines_count,
|
|
22
22
|
:tagged_values_count,
|
|
23
|
+
:constraints_count,
|
|
24
|
+
:enum_literals_count,
|
|
23
25
|
:header_top_padding, :header_line_offset,
|
|
24
26
|
:divider_offset, :attr_line_offset,
|
|
25
27
|
:attr_first_offset
|
|
@@ -27,6 +29,8 @@ module Ea
|
|
|
27
29
|
def initialize(bounds:, size:, header_lines_count:,
|
|
28
30
|
attr_lines_count:, op_lines_count:,
|
|
29
31
|
tagged_values_count:,
|
|
32
|
+
constraints_count: 0,
|
|
33
|
+
enum_literals_count: 0,
|
|
30
34
|
header_top_padding: 12,
|
|
31
35
|
header_line_offset: 6,
|
|
32
36
|
divider_offset: 8,
|
|
@@ -38,6 +42,8 @@ module Ea
|
|
|
38
42
|
@attr_lines_count = attr_lines_count
|
|
39
43
|
@op_lines_count = op_lines_count
|
|
40
44
|
@tagged_values_count = tagged_values_count
|
|
45
|
+
@constraints_count = constraints_count
|
|
46
|
+
@enum_literals_count = enum_literals_count
|
|
41
47
|
@header_top_padding = header_top_padding
|
|
42
48
|
@header_line_offset = header_line_offset
|
|
43
49
|
@divider_offset = divider_offset
|
|
@@ -102,11 +108,24 @@ module Ea
|
|
|
102
108
|
# present). EA does not emit a separate divider — the
|
|
103
109
|
# italic "tags" header marks the compartment.
|
|
104
110
|
def tagged_value_first_y
|
|
105
|
-
return nil unless tagged_values_count
|
|
111
|
+
return nil unless tagged_values_count.to_i.positive? || constraints_count.to_i.positive?
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
content_bottom_y + size + 5
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The lowest content edge among attributes, enum literals,
|
|
117
|
+
# and operations — the anchor for trailing compartments.
|
|
118
|
+
def content_bottom_y
|
|
119
|
+
bottoms = [attr_bottom_y]
|
|
120
|
+
bottoms << enum_literals_bottom_y if enum_literals_count.to_i.positive?
|
|
121
|
+
bottoms << op_bottom_y if op_lines_count.to_i.positive?
|
|
122
|
+
bottoms.compact.max
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def enum_literals_bottom_y
|
|
126
|
+
return nil unless enum_literal_first_y
|
|
127
|
+
|
|
128
|
+
enum_literal_first_y + ([enum_literals_count, 1].max - 1) * (size + 6)
|
|
110
129
|
end
|
|
111
130
|
end
|
|
112
131
|
end
|
|
@@ -82,7 +82,9 @@ module Ea
|
|
|
82
82
|
op_lines = (is_classifier && show_operations?) ? Element::OperationRenderer.lines_for(classifier) : []
|
|
83
83
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
84
84
|
tagged_values_for(classifier).size,
|
|
85
|
-
header_lines
|
|
85
|
+
header_lines,
|
|
86
|
+
constraints_count: constraints_for(classifier).size,
|
|
87
|
+
enum_literals_count: enum_literals_for(classifier).size)
|
|
86
88
|
# EA suppresses the whole attribute compartment when it does
|
|
87
89
|
# not fit the stored box height (never truncates rows) - the
|
|
88
90
|
# AOS box on CityFurniture hides its association property
|
|
@@ -92,7 +94,9 @@ module Ea
|
|
|
92
94
|
attr_lines = []
|
|
93
95
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
94
96
|
tagged_values_for(classifier).size,
|
|
95
|
-
header_lines
|
|
97
|
+
header_lines,
|
|
98
|
+
constraints_count: constraints_for(classifier).size,
|
|
99
|
+
enum_literals_count: enum_literals_for(classifier).size)
|
|
96
100
|
end
|
|
97
101
|
# EA suppresses the operations compartment when its rows
|
|
98
102
|
# overflow the stored box height (same rule as attributes).
|
|
@@ -101,7 +105,9 @@ module Ea
|
|
|
101
105
|
op_lines = []
|
|
102
106
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
103
107
|
tagged_values_for(classifier).size,
|
|
104
|
-
header_lines
|
|
108
|
+
header_lines,
|
|
109
|
+
constraints_count: constraints_for(classifier).size,
|
|
110
|
+
enum_literals_count: enum_literals_for(classifier).size)
|
|
105
111
|
end
|
|
106
112
|
RenderContext.new(
|
|
107
113
|
element: element,
|
|
@@ -130,12 +136,15 @@ module Ea
|
|
|
130
136
|
end
|
|
131
137
|
|
|
132
138
|
def compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
133
|
-
tagged_count, header_lines
|
|
139
|
+
tagged_count, header_lines,
|
|
140
|
+
constraints_count: 0, enum_literals_count: 0)
|
|
134
141
|
CompartmentGeometry.new(bounds: bounds, size: size,
|
|
135
142
|
header_lines_count: header_lines.size,
|
|
136
143
|
attr_lines_count: attr_lines.size,
|
|
137
144
|
op_lines_count: op_lines.size,
|
|
138
145
|
tagged_values_count: tagged_count,
|
|
146
|
+
constraints_count: constraints_count,
|
|
147
|
+
enum_literals_count: enum_literals_count,
|
|
139
148
|
header_top_padding: header_padding_for(header_lines),
|
|
140
149
|
header_line_offset: theme.compartments.header_line_offset,
|
|
141
150
|
divider_offset: theme.compartments.divider_offset,
|
|
@@ -185,7 +194,24 @@ module Ea
|
|
|
185
194
|
def constraints_for(classifier)
|
|
186
195
|
return [] unless classifier.is_a?(Ea::Model::Classifier)
|
|
187
196
|
|
|
188
|
-
|
|
197
|
+
marker_line = root_leaf_marker_for(classifier)
|
|
198
|
+
marker = marker_line ? [marker_constraint(marker_line)] : []
|
|
199
|
+
marker + (classifier.constraints || [])
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# EA renders the element's Root/Leaf checkboxes as {root},
|
|
203
|
+
# {leaf}, or {root,leaf} first in the constraints compartment
|
|
204
|
+
# (t_object.IsRoot/IsLeaf — verified on LanguageCode boxes).
|
|
205
|
+
def root_leaf_marker_for(classifier)
|
|
206
|
+
parts = []
|
|
207
|
+
parts << "root" if classifier.is_root
|
|
208
|
+
parts << "leaf" if classifier.is_leaf
|
|
209
|
+
parts.empty? ? nil : "{#{parts.join(',')}}"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def marker_constraint(text)
|
|
213
|
+
name = text[1..-2]
|
|
214
|
+
Ea::Model::Constraint.new(name: name, kind: "Marker")
|
|
189
215
|
end
|
|
190
216
|
|
|
191
217
|
# EA renders the off-canvas parent classifier's name as an
|
data/lib/ea/version.rb
CHANGED