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,11 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ module CommandHandler
5
+ def can_handle?(parent, command_symbol, *args, &block)
6
+ raise "must be implemented by a class"
7
+ end
8
+ def do_handle(parent, command_symbol, *args, &block)
9
+ raise "must be implemented by a class"
10
+ end
11
+ end
@@ -0,0 +1,23 @@
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_chain_link"
5
+
6
+ class CommandHandlerChainFactory
7
+ @@last_chain_link = nil
8
+ @@chain = nil
9
+
10
+ def self.set_command_handlers(*command_handler_array)
11
+ command_handler_array.each do |command_handler|
12
+ puts "Loading #{command_handler.class.to_s}..."
13
+ chain_link = CommandHandlerChainLink.new(command_handler)
14
+ @@last_chain_link.chain_to(chain_link) if @@last_chain_link
15
+ @@last_chain_link = chain_link
16
+ @@chain = chain_link unless @@chain
17
+ end
18
+ end
19
+
20
+ def self.chain
21
+ @@chain
22
+ end
23
+ 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
+ class CommandHandlerChainLink
5
+ def initialize(command_handler)
6
+ @command_handler = command_handler
7
+ end
8
+ def chain_to(next_chain_link)
9
+ @next_chain_link = next_chain_link
10
+ end
11
+ def handle(parent, command_symbol, *args, &block)
12
+ if (@command_handler.can_handle?(parent, command_symbol, *args, &block))
13
+ puts "#{@command_handler.class.to_s} will handle command: #{command_symbol} with arguments #{args}"
14
+ return @command_handler.do_handle(parent, command_symbol, *args, &block)
15
+ elsif @next_chain_link
16
+ return @next_chain_link.handle(parent, command_symbol, *args, &block)
17
+ else
18
+ puts "Command: #{command_symbol} cannot be handled!"
19
+ return nil
20
+ end
21
+ end
22
+ 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 File.dirname(__FILE__) + "/command_handler_chain_factory"
5
+ require File.dirname(__FILE__) + "/command_handlers/shell_command_handler"
6
+ require File.dirname(__FILE__) + "/command_handlers/widget_listener_command_handler"
7
+ require File.dirname(__FILE__) + "/command_handlers/bind_command_handler"
8
+ require File.dirname(__FILE__) + "/command_handlers/table_items_data_binding_command_handler"
9
+ require File.dirname(__FILE__) + "/command_handlers/table_column_properties_data_binding_command_handler"
10
+ require File.dirname(__FILE__) + "/command_handlers/data_binding_command_handler"
11
+ require File.dirname(__FILE__) + "/command_handlers/widget_method_command_handler"
12
+ require File.dirname(__FILE__) + "/command_handlers/widget_command_handler"
13
+ require File.dirname(__FILE__) + "/command_handlers/swt_constant_command_handler"
14
+
15
+ # edit to add more command handlers and extend Glimmer
16
+ CommandHandlerChainFactory.set_command_handlers(
17
+ ShellCommandHandler.new,
18
+ WidgetListenerCommandHandler.new,
19
+ BindCommandHandler.new,
20
+ TableItemsDataBindingCommandHandler.new,
21
+ TableColumnPropertiesDataBindingCommandHandler.new,
22
+ DataBindingCommandHandler.new,
23
+ WidgetMethodCommandHandler.new,
24
+ WidgetCommandHandler.new,
25
+ SwtConstantCommandHandler.new #at the bottom to avoid stealing commands from other command handlers
26
+ )
@@ -0,0 +1,29 @@
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/r_widget"
6
+ require File.dirname(__FILE__) + "/models/model_observer"
7
+
8
+ class BindCommandHandler
9
+ include CommandHandler
10
+
11
+ include_package 'org.eclipse.swt.widgets'
12
+
13
+ def can_handle?(parent, command_symbol, *args, &block)
14
+ parent.is_a?(RWidget) and
15
+ command_symbol.to_s == "bind" and
16
+ (((args.size == 2) and
17
+ (args[1].is_a?(Symbol) or args[1].is_a?(String))) or
18
+ ((args.size == 3) and
19
+ (args[1].is_a?(Symbol) or args[1].is_a?(String)) and
20
+ (args[2].is_a?(Symbol) or args[2].is_a?(String)))) and
21
+ block == nil
22
+ end
23
+
24
+ def do_handle(parent, command_symbol, *args, &block)
25
+ property_type = args[2] if (args.size == 3)
26
+ ModelObserver.new(args[0], args[1].to_s, property_type)
27
+ end
28
+
29
+ end
@@ -0,0 +1,64 @@
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/r_widget"
6
+ require File.dirname(__FILE__) + "/models/observable_model"
7
+ require File.dirname(__FILE__) + "/models/model_observer"
8
+ require File.dirname(__FILE__) + "/models/widget_observer"
9
+
10
+ class DataBindingCommandHandler
11
+ extend Glimmer
12
+ include CommandHandler
13
+
14
+ include_package 'org.eclipse.swt.widgets'
15
+
16
+ @@widget_data_binders = {
17
+ Java::OrgEclipseSwtWidgets::Text => {
18
+ :text => Proc.new do |rwidget, model_observer|
19
+ add_contents(rwidget) {
20
+ on_modify_text { |modify_event|
21
+ model_observer.update(rwidget.widget.getText)
22
+ }
23
+ }
24
+ end,
25
+ },
26
+ Java::OrgEclipseSwtWidgets::Button => {
27
+ :selection => Proc.new do |rwidget, model_observer|
28
+ add_contents(rwidget) {
29
+ on_widget_selected { |selection_event|
30
+ model_observer.update(rwidget.widget.getSelection)
31
+ }
32
+ }
33
+ end
34
+ },
35
+ Java::OrgEclipseSwtWidgets::Spinner => {
36
+ :selection => Proc.new do |rwidget, model_observer|
37
+ add_contents(rwidget) {
38
+ on_widget_selected { |selection_event|
39
+ model_observer.update(rwidget.widget.getSelection)
40
+ }
41
+ }
42
+ end
43
+ }
44
+ }
45
+
46
+ def can_handle?(parent, command_symbol, *args, &block)
47
+ parent.is_a?(RWidget) and
48
+ args.size == 1 and
49
+ args[0].is_a?(ModelObserver)
50
+ end
51
+
52
+ def do_handle(parent, command_symbol, *args, &block)
53
+ model_observer = args[0]
54
+ widget_observer = WidgetObserver.new(parent, command_symbol.to_s)
55
+ widget_observer.update(model_observer.evaluate_property)
56
+ model = model_observer.model
57
+ model.extend ObservableModel unless model.is_a?(ObservableModel)
58
+ model.add_observer(model_observer.property_name, widget_observer)
59
+ widget_data_binder_map = @@widget_data_binders[parent.widget.class]
60
+ widget_data_binder = widget_data_binder_map[command_symbol.to_s.to_sym] if widget_data_binder_map
61
+ widget_data_binder.call(parent, model_observer) if widget_data_binder
62
+ end
63
+
64
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class ModelObserver
5
+ attr_reader :model, :property_name, :property_type
6
+ @@property_type_converters = {
7
+ :undefined => Proc.new { |value| value },
8
+ :fixnum => Proc.new { |string_value| string_value.to_i }
9
+ #TODO check what other types are needed
10
+ }
11
+ def initialize(model, property_name, property_type)
12
+ property_type = :undefined unless property_type
13
+ @model = model
14
+ @property_name = property_name
15
+ @property_type = property_type
16
+ end
17
+ def update(value)
18
+ converted_value = @@property_type_converters[@property_type].call(value)
19
+ @model.send(@property_name + "=", converted_value) unless evaluate_property == converted_value
20
+ end
21
+ def evaluate_property
22
+ @model.send(@property_name)
23
+ end
24
+ end
25
+
@@ -0,0 +1,46 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ module ObservableArray
5
+
6
+ def add_observer(element_properties, observer)
7
+ property_observer_list << observer
8
+ each do |element|
9
+ element_properties.each do |property|
10
+ element.extend(ObservableModel) unless element.is_a?(ObservableModel)
11
+ element.add_observer(property, observer)
12
+ end
13
+ end
14
+ end
15
+
16
+ def property_observer_list
17
+ @property_observer_list = [] unless @property_observer_list
18
+ @property_observer_list
19
+ end
20
+
21
+ def notify_observers
22
+ property_observer_list.each {|observer| observer.update}
23
+ end
24
+
25
+ def self.extend_object(array)
26
+ array.instance_eval("alias original_add <<")
27
+ array.instance_eval "def <<(value) \n self.original_add(value); notify_observers; \nend"
28
+
29
+ notify_observers_on_invokation(array, "delete", 1)
30
+ notify_observers_on_invokation(array, "delete_at", 1)
31
+ notify_observers_on_invokation(array, "clear")
32
+
33
+ super
34
+ end
35
+
36
+ def self.notify_observers_on_invokation(model, method, argument_count=0)
37
+ model.instance_eval "alias original_#{method} #{method}\n"
38
+ arguments = ""
39
+ for index in 1..argument_count
40
+ arguments += "argument" + index.to_s + ","
41
+ end
42
+ arguments = arguments[0..-2]
43
+ model.instance_eval "def #{method}(#{arguments}) \n self.original_#{method}(#{arguments}); notify_observers; \nend"
44
+ end
45
+
46
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ module ObservableModel
5
+
6
+ def add_observer(property_name, observer)
7
+ property_observer_list(property_name) << observer
8
+ end
9
+
10
+ def property_observer_hash
11
+ @property_observers = Hash.new unless @property_observers
12
+ @property_observers
13
+ end
14
+
15
+ def property_observer_list(property_name)
16
+ property_observer_hash[property_name.to_sym] = [] unless property_observer_hash[property_name.to_sym]
17
+ property_observer_hash[property_name.to_sym]
18
+ end
19
+
20
+ def notify_observers(property_name)
21
+ property_observer_list(property_name).each {|observer| observer.update(send(property_name))}
22
+ end
23
+
24
+ def self.extend_object(model)
25
+ super
26
+ model.methods.each do |method|
27
+ setter_method_pattern = /^\w+=$/
28
+ if (method.match(setter_method_pattern))
29
+ getter_method = method[0, method.length - 1]
30
+ model.instance_eval "alias original_#{method} #{method}\n"
31
+ model.instance_eval "def #{method}(value) \n self.original_#{method}(value); notify_observers('#{getter_method}'); \nend"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class RRunnable
5
+ include java.lang.Runnable
6
+
7
+ def initialize(&block)
8
+ @block = block
9
+ end
10
+
11
+ def run
12
+ @block.call
13
+ end
14
+ end
@@ -0,0 +1,27 @@
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__) + "/r_widget"
5
+
6
+ class RShell < RWidget
7
+ include_package 'org.eclipse.swt.layout'
8
+ include_package 'org.eclipse.swt.widgets'
9
+
10
+ attr_reader :display
11
+
12
+ def initialize(display = Display.new)
13
+ @display = display
14
+ @widget = Shell.new(@display)
15
+ @widget.setLayout(FillLayout.new)
16
+ end
17
+
18
+ def open
19
+ @widget.pack
20
+ @widget.open
21
+ until @widget.isDisposed
22
+ @display.sleep unless @display.readAndDispatch
23
+ end
24
+ @display.dispose
25
+ end
26
+
27
+ end
@@ -0,0 +1,146 @@
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__) + "/r_widget_listener"
5
+ require File.dirname(__FILE__) + "/r_runnable"
6
+
7
+ class RWidget
8
+ require File.dirname(__FILE__) + "/r_widget_packages"
9
+
10
+ include Parent
11
+
12
+ attr_reader :widget
13
+
14
+ #TODO externalize
15
+ @@default_styles = {
16
+ "text" => SWT::BORDER,
17
+ "table" => SWT::BORDER,
18
+ "spinner" => SWT::BORDER,
19
+ "button" => SWT::PUSH,
20
+ }
21
+
22
+ #TODO externalize
23
+ @@default_initializers = {
24
+ "composite" => Proc.new {|composite| composite.setLayout(GridLayout.new) },
25
+ "table" => Proc.new do |table|
26
+ table.setHeaderVisible(true)
27
+ table.setLinesVisible(true)
28
+ end,
29
+ "table_column" => Proc.new { |table_column| table_column.setWidth(80) },
30
+ "group" => Proc.new {|group| group.setLayout(GridLayout.new) },
31
+ }
32
+
33
+ def initialize(underscored_widget_name, parent, style, &contents)
34
+ style = default_style(underscored_widget_name) unless style
35
+ @widget = eval underscored_widget_name.to_s.camelcase(true) + '.new(parent, style)'
36
+ @@default_initializers[underscored_widget_name].call(@widget) if @@default_initializers[underscored_widget_name]
37
+ end
38
+
39
+ def default_style(underscored_widget_name)
40
+ style = @@default_styles[underscored_widget_name] if @@default_styles[underscored_widget_name]
41
+ style = SWT::NONE unless style
42
+ style
43
+ end
44
+
45
+ def respond_to?(method_symbol, *args)
46
+ @widget.respond_to?("set" + method_symbol.to_s.camelcase(true), args)
47
+ end
48
+
49
+ def method_missing(method_symbol, *args)
50
+ statement_to_eval = "@widget.send('set' + method_symbol.to_s.camelcase(true)"
51
+ statement_to_eval << expand_arguments(args)
52
+ statement_to_eval << ")"
53
+ eval statement_to_eval
54
+ end
55
+
56
+ def expand_arguments(args)
57
+ expanded_args = ""
58
+ index = 0
59
+ args.each do
60
+ expanded_args << ", args[#{index}]"
61
+ index += 1
62
+ end
63
+ expanded_args
64
+ end
65
+
66
+ def self.widget_exists?(underscored_widget_name)
67
+ begin
68
+ eval underscored_widget_name.camelcase(true)
69
+ true
70
+ rescue NameError
71
+ false
72
+ end
73
+ end
74
+
75
+ def widget_listener_exists?(underscored_listener_name)
76
+ listener_method_name = underscored_listener_name.camelcase()
77
+ @widget.getClass.getMethods.each do |widget_method|
78
+ if widget_method.getName.match(/add.*Listener/)
79
+ widget_method.getParameterTypes.each do |listener_type|
80
+ listener_type.getMethods.each do |listener_method|
81
+ if (listener_method.getName.match(listener_method_name))
82
+ return true
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ return false
89
+ end
90
+
91
+ def can_add_listener?(underscored_listener_name)
92
+ listener_method_name = underscored_listener_name.camelcase()
93
+ @widget.getClass.getMethods.each do |widget_method|
94
+ if widget_method.getName.match(/add.*Listener/)
95
+ widget_method.getParameterTypes.each do |listener_type|
96
+ listener_type.getMethods.each do |listener_method|
97
+ if (listener_method.getName.match(listener_method_name))
98
+ return true
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ return false
105
+ end
106
+
107
+ def add_listener(underscored_listener_name, &block)
108
+ listener_method_name = underscored_listener_name.camelcase()
109
+ @widget.getClass.getMethods.each do |widget_method|
110
+ if widget_method.getName.match(/add.*Listener/)
111
+ widget_method.getParameterTypes.each do |listener_type|
112
+ listener_type.getMethods.each do |listener_method|
113
+ if (listener_method.getName.match(listener_method_name))
114
+ listener_class = Class.new(Object)
115
+ listener_class.send :include, (eval listener_type.to_s)
116
+ listener = listener_class.new
117
+ listener_type.getMethods.each do |t_method|
118
+ eval "def listener.#{t_method.getName}(event) end"
119
+ end
120
+ def listener.block=(block)
121
+ @block = block
122
+ end
123
+ listener.block=block
124
+ eval "def listener.#{listener_method.getName}(event) @block.call(event) if @block end"
125
+ @widget.send(widget_method.getName, listener)
126
+ return RWidgetListener.new(listener)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def process_block(block)
135
+ block.call(@widget)
136
+ end
137
+
138
+ def async_exec(&block)
139
+ @widget.getDisplay.asyncExec(RRunnable.new(&block))
140
+ end
141
+
142
+ def sync_exec(&block)
143
+ @widget.getDisplay.syncExec(RRunnable.new(&block))
144
+ end
145
+
146
+ end