xsdvi 1.0.0

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +30 -0
  3. data/README.adoc +317 -0
  4. data/exe/xsdvi +6 -0
  5. data/lib/xsdvi/cli.rb +163 -0
  6. data/lib/xsdvi/svg/generator.rb +93 -0
  7. data/lib/xsdvi/svg/symbol.rb +234 -0
  8. data/lib/xsdvi/svg/symbols/all.rb +46 -0
  9. data/lib/xsdvi/svg/symbols/any.rb +59 -0
  10. data/lib/xsdvi/svg/symbols/any_attribute.rb +58 -0
  11. data/lib/xsdvi/svg/symbols/attribute.rb +64 -0
  12. data/lib/xsdvi/svg/symbols/choice.rb +46 -0
  13. data/lib/xsdvi/svg/symbols/element.rb +91 -0
  14. data/lib/xsdvi/svg/symbols/field.rb +42 -0
  15. data/lib/xsdvi/svg/symbols/key.rb +46 -0
  16. data/lib/xsdvi/svg/symbols/keyref.rb +49 -0
  17. data/lib/xsdvi/svg/symbols/loop.rb +35 -0
  18. data/lib/xsdvi/svg/symbols/schema.rb +42 -0
  19. data/lib/xsdvi/svg/symbols/selector.rb +42 -0
  20. data/lib/xsdvi/svg/symbols/sequence.rb +48 -0
  21. data/lib/xsdvi/svg/symbols/unique.rb +46 -0
  22. data/lib/xsdvi/tree/builder.rb +31 -0
  23. data/lib/xsdvi/tree/element.rb +62 -0
  24. data/lib/xsdvi/utils/resource_loader.rb +21 -0
  25. data/lib/xsdvi/utils/width_calculator.rb +23 -0
  26. data/lib/xsdvi/utils/writer.rb +29 -0
  27. data/lib/xsdvi/version.rb +5 -0
  28. data/lib/xsdvi/xsd_handler.rb +323 -0
  29. data/lib/xsdvi.rb +30 -0
  30. data/resources/svg/defined_symbols.svg +9 -0
  31. data/resources/svg/doctype.txt +1 -0
  32. data/resources/svg/menu_buttons.svg +7 -0
  33. data/resources/svg/script.js +265 -0
  34. data/resources/svg/style.css +29 -0
  35. data/resources/svg/style.html +3 -0
  36. data/resources/svg/style.xml +1 -0
  37. data/resources/svg/svg_end.txt +1 -0
  38. data/resources/svg/svg_start.txt +1 -0
  39. data/resources/svg/title.txt +1 -0
  40. data/resources/svg/xml_declaration.xml +1 -0
  41. metadata +113 -0
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../tree/element"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ # Base class for all SVG symbols
8
+ class Symbol < Tree::Element
9
+ # Process contents constants
10
+ PC_STRICT = 1
11
+ PC_SKIP = 2
12
+ PC_LAX = 3
13
+
14
+ # Layout constants
15
+ X_INDENT = 45
16
+ Y_INDENT = 25
17
+ MIN_WIDTH = 60
18
+ MAX_HEIGHT = 46
19
+ MID_HEIGHT = 31
20
+ MIN_HEIGHT = 21
21
+
22
+ attr_accessor :x_position, :y_position, :width, :height,
23
+ :start_y_position, :svg, :description
24
+ attr_reader :description_string_array, :y_shift,
25
+ :additional_height
26
+
27
+ def initialize
28
+ super
29
+ @x_position = 0
30
+ @y_position = 0
31
+ @width = 0
32
+ @height = 0
33
+ @start_y_position = 50
34
+ @description = []
35
+ @description_string_array = []
36
+ @y_shift = 14
37
+ @additional_height = 0
38
+ end
39
+
40
+ def x_end
41
+ x_position + width
42
+ end
43
+
44
+ def y_end
45
+ y_position + MAX_HEIGHT
46
+ end
47
+
48
+ def prepare_box
49
+ if parent?
50
+ @x_position = parent.x_end + X_INDENT
51
+ highest = Symbol.highest_y_position || 0
52
+ @y_position = if first_child?
53
+ highest
54
+ else
55
+ highest + MAX_HEIGHT + Y_INDENT
56
+ end
57
+ else
58
+ @x_position = 20
59
+ @y_position = start_y_position
60
+ end
61
+
62
+ # Ensure values are integers
63
+ @x_position = @x_position.to_i
64
+ @y_position = @y_position.to_i
65
+ @width = calculate_width
66
+ @height = calculate_height
67
+ Symbol.highest_y_position = @y_position
68
+ end
69
+
70
+ def draw
71
+ raise NotImplementedError, "Subclasses must implement draw method"
72
+ end
73
+
74
+ def calculate_width
75
+ MIN_WIDTH
76
+ end
77
+
78
+ def calculate_height
79
+ MAX_HEIGHT
80
+ end
81
+
82
+ class << self
83
+ attr_accessor :highest_y_position, :additional_height_rest,
84
+ :prev_x_position, :prev_y_position
85
+
86
+ def reset_class_variables
87
+ @highest_y_position = 0
88
+ @additional_height_rest = 0
89
+ @prev_x_position = 0
90
+ @prev_y_position = 0
91
+ end
92
+ end
93
+
94
+ reset_class_variables
95
+
96
+ protected
97
+
98
+ def print(string)
99
+ svg.print(string)
100
+ end
101
+
102
+ def draw_g_start
103
+ rest = Symbol.additional_height_rest || 0
104
+ prev_x = Symbol.prev_x_position || 0
105
+ # Always include y_position as integer
106
+ print("<g id='#{code}' class='box' " \
107
+ "transform='translate(#{x_position.to_i},#{y_position.to_i})' " \
108
+ "data-desc-height='#{additional_height.to_i}' " \
109
+ "data-desc-height-rest='#{rest.to_i}' " \
110
+ "data-desc-x='#{prev_x.to_i}'>")
111
+ end
112
+
113
+ def draw_g_end
114
+ print("</g>\n")
115
+ end
116
+
117
+ def draw_connection
118
+ if last_child? && !first_child?
119
+ y_offset = parent.y_position - y_position + (MAX_HEIGHT / 2)
120
+ print("<line class='connection' id='p#{code}' " \
121
+ "x1='#{10 - X_INDENT}' y1='#{y_offset}' " \
122
+ "x2='#{10 - X_INDENT}' y2='#{-15 - Y_INDENT}'/>")
123
+ print("<path class='connection' " \
124
+ "d='M#{10 - X_INDENT},#{-15 - Y_INDENT} " \
125
+ "Q#{10 - X_INDENT},15 0,#{MAX_HEIGHT / 2}'/>")
126
+ elsif parent?
127
+ print("<line class='connection' " \
128
+ "x1='#{10 - X_INDENT}' y1='#{MAX_HEIGHT / 2}' " \
129
+ "x2='0' y2='#{MAX_HEIGHT / 2}'/>")
130
+ end
131
+ end
132
+
133
+ def draw_use
134
+ return unless children?
135
+
136
+ code_str = code
137
+ print("<use x='#{width - 1}' y='#{(MAX_HEIGHT / 2) - 6}' " \
138
+ "xlink:href='#minus' id='s#{code_str}' " \
139
+ "onclick='show(\"#{code_str}\")'/>")
140
+ end
141
+
142
+ def draw_mouseover
143
+ print("onmouseover='makeVisible(\"#{code}\")' " \
144
+ "onmouseout='makeHidden(\"#{code}\")'/>")
145
+ end
146
+
147
+ def process_description
148
+ return if description.empty?
149
+
150
+ wrap_length = (width / 5.5).round
151
+ strings_with_breaks = []
152
+
153
+ description.each do |desc_string|
154
+ # WordUtils.wrap returns string with \n embedded, then split
155
+ wrapped_string = word_utils_wrap(desc_string, wrap_length)
156
+ wrapped_lines = wrapped_string.split("\n")
157
+ strings_with_breaks.concat(wrapped_lines)
158
+ end
159
+
160
+ @description_string_array = strings_with_breaks
161
+ @additional_height = y_shift * strings_with_breaks.size
162
+
163
+ prev_y = Symbol.prev_y_position || 0
164
+ curr_y = y_position || 0
165
+
166
+ if curr_y > prev_y && prev_y != 0
167
+ rest = Symbol.additional_height_rest || 0
168
+ rest -= height
169
+ rest = 0 if rest.negative?
170
+ rest = additional_height if rest < additional_height
171
+ Symbol.additional_height_rest = rest
172
+ elsif additional_height != 0
173
+ Symbol.additional_height_rest = additional_height
174
+ end
175
+
176
+ Symbol.prev_x_position = x_position unless description.empty?
177
+ Symbol.prev_y_position = y_position
178
+ end
179
+
180
+ def draw_description(y_start)
181
+ description_string_array.each do |line|
182
+ y_start += y_shift
183
+ escaped_line = line.gsub("<", "&lt;").gsub(">", "&gt;")
184
+ print("<text x='5' y='#{y_start}' class='desc'>#{escaped_line}</text>")
185
+ end
186
+ end
187
+
188
+ # Apache Commons WordUtils.wrap(str, wrapLength, newLineStr, wrapLongWords)
189
+ # Wraps text at wrapLength, inserting newLineStr, optionally breaking long words
190
+ def word_utils_wrap(input, wrap_length)
191
+ return input if input.nil? || wrap_length < 1
192
+
193
+ input_line_length = input.length
194
+ return input if input_line_length <= wrap_length
195
+
196
+ result = []
197
+ offset = 0
198
+
199
+ while offset < input_line_length
200
+ # Handle existing newline in input
201
+ space_idx = input.index("\n", offset)
202
+ if space_idx && space_idx < wrap_length + offset
203
+ # There's a newline before wrap point
204
+ result << input[offset...space_idx]
205
+ offset = space_idx + 1
206
+ next
207
+ end
208
+
209
+ # Find wrap point
210
+ if input_line_length - offset <= wrap_length
211
+ # Rest of string fits
212
+ result << input[offset..]
213
+ break
214
+ end
215
+
216
+ # Need to wrap - find last space before wrap_length
217
+ space_idx = input.rindex(" ", offset + wrap_length)
218
+
219
+ if space_idx && space_idx >= offset
220
+ # Found space to break at
221
+ result << input[offset...space_idx]
222
+ offset = space_idx + 1
223
+ else
224
+ # No space found - break at wrap_length (wrapLongWords=true)
225
+ result << input[offset...(offset + wrap_length)]
226
+ offset += wrap_length
227
+ end
228
+ end
229
+
230
+ result.join("\n")
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD all compositor
9
+ class All < Symbol
10
+ attr_accessor :cardinality
11
+
12
+ def initialize
13
+ super
14
+ @cardinality = nil
15
+ end
16
+
17
+ def draw
18
+ process_description
19
+ draw_g_start
20
+ print("<rect class='boxcompositor' x='0' y='8' width='#{width}' " \
21
+ "height='#{height}' rx='9'/>")
22
+ print("<circle cx='#{(width / 2) + 12}' cy='14' r='2'/>")
23
+ print("<circle cx='#{(width / 2) + 12}' cy='23' r='2'/>")
24
+ print("<circle cx='#{(width / 2) + 12}' cy='32' r='2'/>")
25
+ print("<text class='small' x='#{width / 2}' y='17'>∀</text>")
26
+ print("<line x1='#{(width / 2) + 12}' y1='14' x2='#{(width / 2) + 12}' y2='32'/>")
27
+ print("<text x='5' y='52'>#{cardinality}</text>") if cardinality
28
+ draw_description(52)
29
+ draw_connection
30
+ draw_use
31
+ draw_g_end
32
+ end
33
+
34
+ def calculate_width
35
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
36
+ calc.new_width(15, cardinality)
37
+ calc.width
38
+ end
39
+
40
+ def calculate_height
41
+ MID_HEIGHT
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD any wildcard
9
+ class Any < Symbol
10
+ attr_accessor :namespace, :process_contents, :cardinality
11
+
12
+ def initialize
13
+ super
14
+ @namespace = nil
15
+ @process_contents = PC_STRICT
16
+ @cardinality = nil
17
+ end
18
+
19
+ def draw
20
+ process_description
21
+ draw_g_start
22
+ print("<rect class='shadow' x='3' y='3' width='#{width}' height='#{height}'/>")
23
+ print("<rect class='boxany' x='0' y='0' width='#{width}' height='#{height}'/>")
24
+
25
+ # Draw process contents boxes
26
+ pc_class = case process_contents
27
+ when PC_STRICT then "strict"
28
+ when PC_SKIP then "skip"
29
+ when PC_LAX then "lax"
30
+ else "strict"
31
+ end
32
+ print("<rect class='#{pc_class}' x='6' y='34' width='6' height='6'/>")
33
+ print("<rect class='#{pc_class}' x='16' y='34' width='6' height='6'/>")
34
+ print("<rect class='#{pc_class}' x='26' y='34' width='6' height='6'/>")
35
+
36
+ print("<text x='5' y='13'>#{namespace}</text>") if namespace
37
+ # Java shows just angle brackets <> not <any>
38
+ print("<text class='strong' x='5' y='27'>&lt;&gt;</text>")
39
+ print("<text x='5' y='59'>#{cardinality}</text>") if cardinality
40
+ draw_description(59)
41
+ draw_connection
42
+ draw_use
43
+ draw_g_end
44
+ end
45
+
46
+ def calculate_width
47
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
48
+ calc.new_width(15, namespace)
49
+ calc.new_width(15, cardinality)
50
+ calc.width
51
+ end
52
+
53
+ def calculate_height
54
+ MAX_HEIGHT
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD anyAttribute wildcard
9
+ class AnyAttribute < Symbol
10
+ attr_accessor :namespace, :process_contents
11
+
12
+ def initialize
13
+ super
14
+ @namespace = nil
15
+ @process_contents = PC_STRICT
16
+ end
17
+
18
+ def draw
19
+ process_description
20
+ draw_g_start
21
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
22
+ "height='#{height}' rx='9'/>")
23
+ print("<rect class='boxanyattribute' x='0' y='0' width='#{width}' " \
24
+ "height='#{height}' rx='9'/>")
25
+
26
+ # Draw process contents boxes
27
+ pc_class = case process_contents
28
+ when PC_STRICT then "strict"
29
+ when PC_SKIP then "skip"
30
+ when PC_LAX then "lax"
31
+ else "strict"
32
+ end
33
+ print("<rect class='#{pc_class}' x='6' y='34' width='6' height='6'/>")
34
+ print("<rect class='#{pc_class}' x='16' y='34' width='6' height='6'/>")
35
+ print("<rect class='#{pc_class}' x='26' y='34' width='6' height='6'/>")
36
+
37
+ print("<text x='5' y='13'>#{namespace}</text>") if namespace
38
+ # Java only shows @ symbol, not the full text
39
+ print("<text class='strong' x='5' y='27'>@</text>")
40
+ draw_description(34)
41
+ draw_connection
42
+ draw_g_end
43
+ end
44
+
45
+ def calculate_width
46
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
47
+ # Java only calculates width based on namespace
48
+ calc.new_width(15, namespace)
49
+ calc.width
50
+ end
51
+
52
+ def calculate_height
53
+ MAX_HEIGHT
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD attributes
9
+ class Attribute < Symbol
10
+ attr_accessor :name, :namespace, :type, :required, :constraint
11
+
12
+ def initialize
13
+ super
14
+ @name = nil
15
+ @namespace = nil
16
+ @type = nil
17
+ @required = false
18
+ @constraint = nil
19
+ end
20
+
21
+ def draw
22
+ process_description
23
+ draw_g_start
24
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
25
+ "height='#{height}' rx='9'/>")
26
+ if required
27
+ print("<rect class='boxattribute1' x='0' y='0' " \
28
+ "width='#{width}' height='#{height}' rx='9'")
29
+ else
30
+ print("<rect class='boxattribute2' x='0' y='0' " \
31
+ "width='#{width}' height='#{height}' rx='9'")
32
+ end
33
+ print("/>")
34
+
35
+ print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
36
+ print("<text class='strong' x='5' y='27'><tspan class='big'>@</tspan> #{name}</text>") if name
37
+ print("<text class='visible' x='5' y='41'>#{type}</text>") if type
38
+
39
+ properties = []
40
+ properties << constraint if constraint
41
+ print("<text x='5' y='59'>#{properties.join(', ')}</text>")
42
+
43
+ draw_description(59)
44
+ draw_connection
45
+ draw_g_end
46
+ end
47
+
48
+ def calculate_width
49
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
50
+ calc.new_width(15, name, 3)
51
+ calc.new_width(15, namespace)
52
+ calc.new_width(15, type)
53
+ calc.new_width(15, 13)
54
+ calc.new_width(15, constraint)
55
+ calc.width
56
+ end
57
+
58
+ def calculate_height
59
+ MAX_HEIGHT
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD choice compositor
9
+ class Choice < Symbol
10
+ attr_accessor :cardinality
11
+
12
+ def initialize
13
+ super
14
+ @cardinality = nil
15
+ end
16
+
17
+ def draw
18
+ process_description
19
+ draw_g_start
20
+ print("<rect class='boxcompositor' x='0' y='8' width='#{width}' " \
21
+ "height='#{height}' rx='9'/>")
22
+ print("<circle cx='#{(width / 2) + 12}' cy='14' r='2'/>")
23
+ print("<circle class='empty' cx='#{(width / 2) + 12}' cy='23' r='2'/>")
24
+ print("<circle class='empty' cx='#{(width / 2) + 12}' cy='32' r='2'/>")
25
+ print("<polyline points='#{(width / 2) - 4},23 #{(width / 2) + 4},23 " \
26
+ "#{(width / 2) + 4},14 #{(width / 2) + 10},14'/>")
27
+ print("<text x='5' y='52'>#{cardinality}</text>") if cardinality
28
+ draw_description(52)
29
+ draw_connection
30
+ draw_use
31
+ draw_g_end
32
+ end
33
+
34
+ def calculate_width
35
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
36
+ calc.new_width(15, cardinality)
37
+ calc.width
38
+ end
39
+
40
+ def calculate_height
41
+ MID_HEIGHT
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD elements
9
+ class Element < Symbol
10
+ attr_accessor :name, :namespace, :type, :cardinality, :nillable,
11
+ :abstract, :substitution, :optional
12
+
13
+ def initialize
14
+ super
15
+ @name = nil
16
+ @namespace = nil
17
+ @type = nil
18
+ @cardinality = nil
19
+ @optional = false
20
+ @nillable = false
21
+ @abstract = false
22
+ @substitution = nil
23
+ end
24
+
25
+ def cardinality=(value)
26
+ @cardinality = value
27
+ @optional = true if value&.start_with?("0")
28
+ end
29
+
30
+ def draw
31
+ print("<a href=\"#\" onclick=\"window.parent.location.href = " \
32
+ "window.parent.location.href.split('#')[0] + " \
33
+ "'#element_#{name}'\">")
34
+
35
+ process_description
36
+
37
+ draw_g_start
38
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
39
+ "height='#{height}'/>")
40
+ if optional
41
+ print("<rect class='boxelementoptional' x='0' y='0' " \
42
+ "width='#{width}' height='#{height}'/>")
43
+ else
44
+ print("<rect class='boxelement' x='0' y='0' width='#{width}' " \
45
+ "height='#{height}'/>")
46
+ end
47
+
48
+ # Show namespace at y=13 (always shown in Java if present)
49
+ if namespace && !namespace.empty?
50
+ print("<text class='visible' x='5' y='13'>#{namespace}</text>")
51
+ end
52
+
53
+ # Show name at y=27 (always shown in Java)
54
+ print("<text class='strong elementlink' x='5' y='27'>#{name}</text>") if name
55
+
56
+ # Show type at y=41 (always shown in Java if present)
57
+ print("<text class='visible' x='5' y='41'>#{type}</text>") if type && !type.empty?
58
+
59
+ # Properties at y=59
60
+ properties = []
61
+ properties << cardinality if cardinality
62
+ properties << "subst.: #{substitution}" if substitution
63
+ properties << "nillable: true" if nillable
64
+ properties << "abstract: true" if abstract
65
+ print("<text x='5' y='59'>#{properties.join(', ')}</text>")
66
+
67
+ draw_description(59)
68
+ draw_connection
69
+ draw_use
70
+ draw_g_end
71
+ print("</a>")
72
+ end
73
+
74
+ def calculate_width
75
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
76
+ calc.new_width(15, name, 3)
77
+ calc.new_width(15, namespace)
78
+ calc.new_width(15, type)
79
+ calc.new_width(15, cardinality)
80
+ calc.new_width(15, substitution ? 22 : 11)
81
+ calc.new_width(15, substitution, 8)
82
+ calc.width
83
+ end
84
+
85
+ def calculate_height
86
+ MAX_HEIGHT
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD field
9
+ class Field < Symbol
10
+ attr_accessor :xpath
11
+
12
+ def initialize
13
+ super
14
+ @xpath = nil
15
+ end
16
+
17
+ def draw
18
+ draw_g_start
19
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
20
+ "height='#{height}' rx='9'/>")
21
+ print("<rect class='boxfield' x='0' y='0' width='#{width}' " \
22
+ "height='#{height}' rx='9'/>")
23
+ print("<text class='strong' x='5' y='13'>field</text>")
24
+ print("<text class='visible' x='5' y='27'>#{xpath}</text>") if xpath
25
+ draw_connection
26
+ draw_g_end
27
+ end
28
+
29
+ def calculate_width
30
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
31
+ calc.new_width(15, 5)
32
+ calc.new_width(15, xpath)
33
+ calc.width
34
+ end
35
+
36
+ def calculate_height
37
+ MID_HEIGHT
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD key identity constraint
9
+ class Key < Symbol
10
+ attr_accessor :name, :namespace
11
+
12
+ def initialize
13
+ super
14
+ @name = nil
15
+ @namespace = nil
16
+ end
17
+
18
+ def draw
19
+ process_description
20
+ draw_g_start
21
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
22
+ "height='#{height}' rx='9'/>")
23
+ print("<rect class='boxkey' x='0' y='0' width='#{width}' " \
24
+ "height='#{height}' rx='9'/>")
25
+ print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
26
+ print("<text class='strong' x='5' y='27'>key: #{name}</text>") if name
27
+ draw_description(27)
28
+ draw_connection
29
+ draw_use
30
+ draw_g_end
31
+ end
32
+
33
+ def calculate_width
34
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
35
+ calc.new_width(15, name, 5)
36
+ calc.new_width(15, namespace)
37
+ calc.width
38
+ end
39
+
40
+ def calculate_height
41
+ MID_HEIGHT
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end