glimmer 0.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 (61) hide show
  1. data/COPYING.LGPL +504 -0
  2. data/README +27 -0
  3. data/samples/contactmanager/contact.rb +12 -0
  4. data/samples/contactmanager/contact_manager.rb +65 -0
  5. data/samples/contactmanager/contact_manager_presenter.rb +23 -0
  6. data/samples/contactmanager/contact_repository.rb +27 -0
  7. data/samples/hello_world.rb +26 -0
  8. data/samples/login.rb +97 -0
  9. data/samples/tictactoe/tic_tac_toe.rb +67 -0
  10. data/samples/tictactoe/tic_tac_toe_board.rb +149 -0
  11. data/src/command_handler.rb +11 -0
  12. data/src/command_handler_chain_factory.rb +23 -0
  13. data/src/command_handler_chain_link.rb +22 -0
  14. data/src/command_handlers.rb +26 -0
  15. data/src/command_handlers/bind_command_handler.rb +29 -0
  16. data/src/command_handlers/data_binding_command_handler.rb +64 -0
  17. data/src/command_handlers/models/model_observer.rb +25 -0
  18. data/src/command_handlers/models/observable_array.rb +46 -0
  19. data/src/command_handlers/models/observable_model.rb +35 -0
  20. data/src/command_handlers/models/r_runnable.rb +14 -0
  21. data/src/command_handlers/models/r_shell.rb +27 -0
  22. data/src/command_handlers/models/r_widget.rb +146 -0
  23. data/src/command_handlers/models/r_widget_listener.rb +12 -0
  24. data/src/command_handlers/models/r_widget_packages.rb +9 -0
  25. data/src/command_handlers/models/table_items_updater.rb +39 -0
  26. data/src/command_handlers/models/widget_observer.rb +23 -0
  27. data/src/command_handlers/shell_command_handler.rb +18 -0
  28. data/src/command_handlers/swt_constant_command_handler.rb +22 -0
  29. data/src/command_handlers/table_column_properties_data_binding_command_handler.rb +24 -0
  30. data/src/command_handlers/table_items_data_binding_command_handler.rb +30 -0
  31. data/src/command_handlers/widget_command_handler.rb +26 -0
  32. data/src/command_handlers/widget_listener_command_handler.rb +35 -0
  33. data/src/command_handlers/widget_method_command_handler.rb +22 -0
  34. data/src/glimmer.rb +45 -0
  35. data/src/parent.rb +8 -0
  36. data/src/shine.rb +24 -0
  37. data/src/swt.rb +10 -0
  38. data/src/xml.rb +10 -0
  39. data/src/xml_command_handlers.rb +18 -0
  40. data/src/xml_command_handlers/html_command_handler.rb +49 -0
  41. data/src/xml_command_handlers/models/depth_first_search_iterator.rb +20 -0
  42. data/src/xml_command_handlers/models/name_space_visitor.rb +21 -0
  43. data/src/xml_command_handlers/models/node.rb +83 -0
  44. data/src/xml_command_handlers/models/node_visitor.rb +12 -0
  45. data/src/xml_command_handlers/models/xml_visitor.rb +62 -0
  46. data/src/xml_command_handlers/xml_command_handler.rb +22 -0
  47. data/src/xml_command_handlers/xml_name_space_command_handler.rb +34 -0
  48. data/src/xml_command_handlers/xml_tag_command_handler.rb +26 -0
  49. data/src/xml_command_handlers/xml_text_command_handler.rb +22 -0
  50. data/test/glimmer_constant_test.rb +36 -0
  51. data/test/glimmer_data_binding_test.rb +236 -0
  52. data/test/glimmer_listeners_test.rb +61 -0
  53. data/test/glimmer_shine_data_binding_test.rb +88 -0
  54. data/test/glimmer_table_data_binding_test.rb +135 -0
  55. data/test/glimmer_test.rb +233 -0
  56. data/test/observable_model_test.rb +27 -0
  57. data/test/r_widget_test.rb +52 -0
  58. data/test/samples/contactmanager/contact_manager_presenter_test.rb +60 -0
  59. data/test/samples/tictactoe/tic_tac_toe_test.rb +265 -0
  60. data/test/xml/glimmer_xml_test.rb +163 -0
  61. metadata +126 -0
@@ -0,0 +1,20 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class DepthFirstSearchIterator
5
+ def initialize(node, node_visitor)
6
+ @node = node
7
+ @node_visitor = node_visitor
8
+ end
9
+
10
+ def iterate
11
+ process(@node)
12
+ end
13
+
14
+ def process(node)
15
+ @node_visitor.process_before_children(node)
16
+ node.children.each { |child| process(child) } unless node.is_a?(String)
17
+ @node_visitor.process_after_children(node)
18
+ end
19
+
20
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/node_visitor"
5
+
6
+ class NameSpaceVisitor < NodeVisitor
7
+
8
+ def initialize(name_space_name)
9
+ @name_space_name = name_space_name
10
+ end
11
+
12
+ def process_before_children(node)
13
+ return if node.is_a?(String)
14
+ node.name_space = Node.new(nil, @name_space_name, nil) if node and !node.name_space
15
+ end
16
+
17
+ def process_after_children(node)
18
+ #NOOP
19
+ end
20
+
21
+ end
@@ -0,0 +1,83 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/depth_first_search_iterator"
5
+ require File.dirname(__FILE__) + "/xml_visitor"
6
+
7
+ class Node
8
+ include Parent, Glimmer
9
+
10
+ attr_accessor :children, :name, :contents, :attributes, :is_name_space, :is_attribute, :name_space, :parent
11
+
12
+ def initialize(parent, name, attributes, &contents)
13
+ @is_name_space = false
14
+ @children = []
15
+ @parent = parent
16
+ if (parent and parent.is_name_space)
17
+ @name_space = parent
18
+ @parent = @name_space.parent
19
+ end
20
+ @parent.children << self if @parent
21
+ @name = name
22
+ @contents = contents
23
+ @attributes = attributes
24
+ if @attributes
25
+ @attributes.each_key do |attribute|
26
+ if attribute.is_a?(Node)
27
+ attribute.is_attribute = true
28
+ attribute.parent.children.delete(attribute) if attribute.parent
29
+ attribute.parent = nil #attributes do not usually have parents
30
+ end
31
+ end
32
+ p attributes
33
+ end
34
+ end
35
+
36
+ def method_missing(symbol, *args, &block)
37
+ @is_name_space = true
38
+ parent.children.delete(self) if parent
39
+ Glimmer.add_contents(self) {@tag = super}
40
+ @tag
41
+ end
42
+
43
+ def to_xml
44
+ xml_visitor = XmlVisitor.new
45
+ DepthFirstSearchIterator.new(self, xml_visitor).iterate
46
+ xml_visitor.document
47
+ end
48
+
49
+ def process_block(block)
50
+ return_value = block.call(@widget)
51
+ if return_value.is_a?(String) and !@children.include?(return_value)
52
+ text = return_value
53
+ first_match = text.match(/[#][^{]+[{][^}]+[}]/)
54
+ match = first_match
55
+ while (match)
56
+ Glimmer.module_eval(text_command(match.pre_match))
57
+ tag_text = match.to_s
58
+ Glimmer.module_eval(rubyize(tag_text))
59
+ text = tag_text
60
+ post_match = match.post_match
61
+ match = text.match(/[#]\w+[{]\w+[}]/)
62
+ end
63
+ Glimmer.module_eval(text_command(post_match)) if post_match
64
+ @children << return_value unless first_match
65
+ end
66
+ end
67
+
68
+ def text_command(text)
69
+ "text \"#{text}\""
70
+ end
71
+
72
+ def rubyize(text)
73
+ text = text.gsub(/[}]/, '"}')
74
+ text = text.gsub(/[{]/, '{"')
75
+ text = text.gsub(/[#]/, '')
76
+ end
77
+
78
+ #override Object default id method and route it to Glimmer engine
79
+ def id
80
+ method_missing(:id)
81
+ end
82
+
83
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class NodeVisitor
5
+ def process_before_children
6
+ raise "must be implemented by a class"
7
+ end
8
+
9
+ def process_after_children
10
+ raise "must be implemented by a class"
11
+ end
12
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/node_visitor"
5
+
6
+ class XmlVisitor < NodeVisitor
7
+
8
+ attr_reader :document
9
+
10
+ def initialize
11
+ @document = ""
12
+ end
13
+
14
+ def process_before_children(node)
15
+ if (node.is_a?(String))
16
+ @document << node
17
+ return
18
+ end
19
+ begin_open_tag(node)
20
+ append_attributes(node) if node.attributes
21
+ end_open_tag(node)
22
+ end
23
+
24
+ def process_after_children(node)
25
+ return if (node.is_a?(String))
26
+ append_close_tag(node)
27
+ end
28
+
29
+ def begin_open_tag(node)
30
+ @document << "<"
31
+ @document << "#{node.name_space.name}:" if node.name_space
32
+ @document << node.name
33
+ end
34
+
35
+ def end_open_tag(node)
36
+ if (node.contents)
37
+ @document << ">"
38
+ else
39
+ @document << " " if node.attributes.keys.size > 0
40
+ @document << "/>"
41
+ end
42
+ end
43
+
44
+ def append_close_tag(node)
45
+ if (node.contents)
46
+ @document << "</"
47
+ @document << "#{node.name_space.name}:" if node.name_space
48
+ @document << "#{node.name}>"
49
+ end
50
+ end
51
+
52
+ def append_attributes(node)
53
+ puts "Take 3"
54
+ p node.attributes
55
+ node.attributes.each_key do |attribute|
56
+ attribute_name = attribute
57
+ attribute_name = "#{attribute.name_space.name}:#{attribute.name}" if attribute.is_a?(Node)
58
+ @document << " #{attribute_name}=\"#{node.attributes[attribute]}\""
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "facets/dictionary"
5
+ require File.dirname(__FILE__) + "/../command_handler"
6
+ require File.dirname(__FILE__) + "/models/node"
7
+
8
+ class XmlCommandHandler
9
+ include CommandHandler
10
+
11
+ def can_handle?(parent, command_symbol, *args, &block)
12
+ (parent == nil or parent.is_a?(Node)) and
13
+ (args.size == 0 or ((args.size == 1) and ((args[0].is_a?(Hash)) or (args[0].is_a?(Hash)))))
14
+ end
15
+
16
+ def do_handle(parent, command_symbol, *args, &block)
17
+ attributes = Dictionary.new
18
+ attributes = args[0] if (args.size == 1)
19
+ Node.new(parent, command_symbol.to_s, attributes, &block)
20
+ end
21
+
22
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/../command_handler"
5
+ require File.dirname(__FILE__) + "/models/node"
6
+ require File.dirname(__FILE__) + "/models/depth_first_search_iterator"
7
+ require File.dirname(__FILE__) + "/models/name_space_visitor"
8
+
9
+ class XmlNameSpaceCommandHandler
10
+ include CommandHandler, Glimmer
11
+
12
+ def can_handle?(parent, command_symbol, *args, &block)
13
+ (parent == nil or parent.is_a?(Node)) and
14
+ (command_symbol.to_s == "name_space")
15
+ (args.size == 1) and
16
+ (args[0].is_a?(Symbol)) and
17
+ block
18
+ end
19
+
20
+ def do_handle(parent, command_symbol, *args, &block)
21
+ node = block.call
22
+ unless node.is_a?(String)
23
+ name_space_visitor = NameSpaceVisitor.new(args[0].to_s)
24
+ DepthFirstSearchIterator.new(node, name_space_visitor).iterate
25
+ def node.process_block(block)
26
+ puts 'block'
27
+ #NOOP
28
+ end
29
+ end
30
+ parent.children << node if parent and !parent.children.include?(node)
31
+ node
32
+ end
33
+
34
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "facets/dictionary"
5
+ require File.dirname(__FILE__) + "/../command_handler"
6
+ require File.dirname(__FILE__) + "/models/node"
7
+
8
+ class XmlTagCommandHandler
9
+ include CommandHandler
10
+
11
+ def can_handle?(parent, command_symbol, *args, &block)
12
+ (parent == nil or parent.is_a?(Node)) and
13
+ (command_symbol.to_s == "tag") and
14
+ ((args.size == 1) and ((args[0].is_a?(Hash)) or (args[0].is_a?(Hash)))) and
15
+ args[0].include?(:_name)
16
+ end
17
+
18
+ def do_handle(parent, command_symbol, *args, &block)
19
+ attributes = nil
20
+ attributes = args[0] if (args.size == 1)
21
+ tag_name = attributes[:_name]
22
+ attributes.delete(:_name)
23
+ Node.new(parent, tag_name, attributes, &block)
24
+ end
25
+
26
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/../command_handler"
5
+ require File.dirname(__FILE__) + "/models/node"
6
+
7
+ class XmlTextCommandHandler
8
+ include CommandHandler
9
+
10
+ def can_handle?(parent, command_symbol, *args, &block)
11
+ (parent == nil or parent.is_a?(Node)) and
12
+ (command_symbol.to_s == "text") and
13
+ ((args.size == 1) and (args[0].is_a?(String))) and
14
+ !block
15
+ end
16
+
17
+ def do_handle(parent, command_symbol, *args, &block)
18
+ parent.children << args[0] if parent
19
+ args[0]
20
+ end
21
+
22
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "test/unit"
5
+ require File.dirname(__FILE__) + "/../src/swt"
6
+
7
+ class GlimmerTest < Test::Unit::TestCase
8
+ include Glimmer
9
+
10
+ include_package 'org.eclipse.swt'
11
+ include_package 'org.eclipse.swt.widgets'
12
+ include_package 'org.eclipse.swt.layout'
13
+
14
+ def teardown
15
+ @target.display.dispose if @target.display
16
+ end
17
+
18
+ def test_shell_with_default_layout
19
+ @target = shell {
20
+ composite(border | no_focus) {
21
+ }
22
+ }
23
+
24
+ assert_equal 1, @target.widget.children.size
25
+ assert_instance_of Composite, @target.widget.children[0]
26
+ composite_widget = @target.widget.children[0]
27
+ assert_has_style SWT::NO_FOCUS, composite_widget
28
+ assert_has_style SWT::BORDER, composite_widget
29
+ end
30
+
31
+ def assert_has_style(style, widget)
32
+ assert_equal style, widget.getStyle & style
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,236 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "test/unit"
5
+ require File.dirname(__FILE__) + "/../src/swt"
6
+
7
+ class GlimmerDataBindingTest < Test::Unit::TestCase
8
+ include Glimmer
9
+
10
+ include_package 'org.eclipse.swt'
11
+ include_package 'org.eclipse.swt.widgets'
12
+ include_package 'org.eclipse.swt.layout'
13
+
14
+ def teardown
15
+ @target.display.dispose if @target.display
16
+ end
17
+
18
+ class Person
19
+ attr_accessor :name, :age, :adult
20
+ end
21
+
22
+ def test_text_widget_data_binding_string_property
23
+ person = Person.new
24
+ person.name = "Bruce Ting"
25
+
26
+ @target = shell {
27
+ composite {
28
+ @text = text {
29
+ text bind(person, :name)
30
+ }
31
+ }
32
+ }
33
+
34
+ assert_equal "Bruce Ting", @text.widget.getText
35
+
36
+ person.name = "Lady Butterfly"
37
+ assert_equal "Lady Butterfly", @text.widget.getText
38
+
39
+ @text.widget.setText("Allen Cork")
40
+ assert_equal "Allen Cork", person.name
41
+ end
42
+
43
+ def test_text_widget_data_binding_fixnum_property
44
+ person = Person.new
45
+ person.age = 15
46
+
47
+ @target = shell {
48
+ composite {
49
+ @text = text {
50
+ text bind(person, :age, :fixnum)
51
+ }
52
+ }
53
+ }
54
+
55
+ assert_equal "15", @text.widget.getText
56
+
57
+ person.age = 27
58
+ assert_equal "27", @text.widget.getText
59
+
60
+ @text.widget.setText("30")
61
+ assert_equal 30, person.age
62
+ end
63
+
64
+ def test_label_widget_data_binding_string_property
65
+ person = Person.new
66
+ person.name = "Bruce Ting"
67
+
68
+ @target = shell {
69
+ composite {
70
+ @label = label {
71
+ text bind(person, :name)
72
+ }
73
+ }
74
+ }
75
+
76
+ assert_equal "Bruce Ting", @label.widget.getText
77
+
78
+ person.name = "Lady Butterfly"
79
+ assert_equal "Lady Butterfly", @label.widget.getText
80
+ end
81
+
82
+ def test_checkbox_widget_data_binding_boolean_property
83
+ person = Person.new
84
+ person.adult = true
85
+
86
+ @target = shell {
87
+ composite {
88
+ @check_box = button(SWT::CHECK) {
89
+ selection bind(person, :adult)
90
+ }
91
+ }
92
+ }
93
+
94
+ assert_equal true, @check_box.widget.getSelection
95
+
96
+ person.adult = false
97
+ assert_equal false, @check_box.widget.getSelection
98
+
99
+ @check_box.widget.setSelection(true)
100
+ @check_box.widget.notifyListeners(SWT::Selection, nil)
101
+ assert_equal true, person.adult
102
+ end
103
+
104
+ def test_radio_widget_data_binding_boolean_property
105
+ person = Person.new
106
+ person.adult = true
107
+
108
+ @target = shell {
109
+ composite {
110
+ @radio = button(SWT::RADIO) {
111
+ selection bind(person, :adult)
112
+ }
113
+ }
114
+ }
115
+
116
+ assert_equal true, @radio.widget.getSelection
117
+
118
+ person.adult = false
119
+ assert_equal false, @radio.widget.getSelection
120
+
121
+ @radio.widget.setSelection(true)
122
+ @radio.widget.notifyListeners(SWT::Selection, nil)
123
+ assert_equal true, person.adult
124
+ end
125
+
126
+ def test_spinner_widget_data_binding_fixnum_property
127
+ person = Person.new
128
+ person.age = 17
129
+
130
+ @target = shell {
131
+ composite {
132
+ @spinner = spinner {
133
+ selection bind(person, :age)
134
+ }
135
+ }
136
+ }
137
+
138
+ assert_equal 17, @spinner.widget.getSelection
139
+
140
+ person.age = 20
141
+ assert_equal 20, @spinner.widget.getSelection
142
+
143
+ @spinner.widget.setSelection(34)
144
+ @spinner.widget.notifyListeners(SWT::Selection, nil)
145
+ assert_equal 34, person.age
146
+ end
147
+
148
+ def test_widget_data_binding_enablement
149
+ person = Person.new
150
+ person.adult = true
151
+
152
+ @target = shell {
153
+ composite {
154
+ @text = text {
155
+ enabled bind(person, :adult)
156
+ }
157
+ }
158
+ }
159
+
160
+ assert_equal true, @text.widget.isEnabled
161
+
162
+ person.adult = false
163
+ assert_equal false, @text.widget.isEnabled
164
+ end
165
+
166
+ def test_multiple_widget_data_binding_enablement_to_same_model_property
167
+ person = Person.new
168
+ person.adult = true
169
+
170
+ @target = shell {
171
+ composite {
172
+ @text = text {
173
+ enabled bind(person, :adult)
174
+ }
175
+ @text2 = text {
176
+ enabled bind(person, :adult)
177
+ }
178
+ @text3 = text {
179
+ enabled bind(person, :adult)
180
+ }
181
+ }
182
+ }
183
+
184
+ assert_equal true, @text.widget.isEnabled
185
+ assert_equal true, @text2.widget.isEnabled
186
+ assert_equal true, @text3.widget.isEnabled
187
+
188
+ person.adult = false
189
+ assert_equal false, @text.widget.isEnabled
190
+ assert_equal false, @text2.widget.isEnabled
191
+ assert_equal false, @text3.widget.isEnabled
192
+ end
193
+
194
+ def test_multiple_widget_data_bindings_to_different_model_properties
195
+ person = Person.new
196
+ person.name = "Nancy"
197
+ person.age = 15
198
+ person.adult = true
199
+
200
+ @target = shell {
201
+ composite {
202
+ @label = label {
203
+ text bind(person, :name)
204
+ }
205
+ @text = text {
206
+ text bind(person, :age, :fixnum)
207
+ }
208
+ @check_box = button(SWT::CHECK) {
209
+ selection bind(person, :adult)
210
+ }
211
+ }
212
+ }
213
+
214
+ assert_equal "Nancy", @label.widget.getText
215
+ assert_equal "15", @text.widget.getText
216
+ assert_equal true, @check_box.widget.getSelection
217
+
218
+ person.name = "Drew"
219
+ assert_equal "Drew", @label.widget.getText
220
+
221
+ person.age = 27
222
+ assert_equal "27", @text.widget.getText
223
+
224
+ person.adult = false
225
+ assert_equal false, @check_box.widget.getSelection
226
+
227
+ @text.widget.setText("30")
228
+ assert_equal 30, person.age
229
+
230
+ @check_box.widget.setSelection(true)
231
+ @check_box.widget.notifyListeners(SWT::Selection, nil)
232
+ assert_equal true, person.adult
233
+ end
234
+
235
+ end
236
+