glimmer 0.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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