glimmer-dsl-swt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +47 -0
  4. data/RUBY_VERSION +1 -0
  5. data/VERSION +1 -0
  6. data/bin/girb +10 -0
  7. data/bin/girb_runner.rb +13 -0
  8. data/bin/glimmer +5 -0
  9. data/icons/scaffold_app.icns +0 -0
  10. data/lib/ext/glimmer.rb +13 -0
  11. data/lib/ext/glimmer/config.rb +18 -0
  12. data/lib/glimmer-dsl-swt.rb +12 -0
  13. data/lib/glimmer/data_binding/list_selection_binding.rb +52 -0
  14. data/lib/glimmer/data_binding/model_binding.rb +248 -0
  15. data/lib/glimmer/data_binding/observable.rb +21 -0
  16. data/lib/glimmer/data_binding/observable_array.rb +107 -0
  17. data/lib/glimmer/data_binding/observable_model.rb +108 -0
  18. data/lib/glimmer/data_binding/observable_widget.rb +17 -0
  19. data/lib/glimmer/data_binding/observer.rb +124 -0
  20. data/lib/glimmer/data_binding/shine.rb +23 -0
  21. data/lib/glimmer/data_binding/table_items_binding.rb +56 -0
  22. data/lib/glimmer/data_binding/tree_items_binding.rb +71 -0
  23. data/lib/glimmer/data_binding/widget_binding.rb +33 -0
  24. data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
  25. data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
  26. data/lib/glimmer/dsl/swt/color_expression.rb +19 -0
  27. data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
  28. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
  29. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +39 -0
  30. data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
  31. data/lib/glimmer/dsl/swt/dialog_expression.rb +26 -0
  32. data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
  33. data/lib/glimmer/dsl/swt/dsl.rb +34 -0
  34. data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
  35. data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
  36. data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
  37. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
  38. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
  39. data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
  40. data/lib/glimmer/dsl/swt/message_box_expression.rb +29 -0
  41. data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
  42. data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
  43. data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
  44. data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
  45. data/lib/glimmer/dsl/swt/shell_expression.rb +25 -0
  46. data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
  47. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
  48. data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
  49. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
  50. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
  51. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
  52. data/lib/glimmer/dsl/swt/widget_expression.rb +35 -0
  53. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
  54. data/lib/glimmer/launcher.rb +196 -0
  55. data/lib/glimmer/package.rb +57 -0
  56. data/lib/glimmer/rake_task.rb +62 -0
  57. data/lib/glimmer/scaffold.rb +582 -0
  58. data/lib/glimmer/swt/color_proxy.rb +53 -0
  59. data/lib/glimmer/swt/display_proxy.rb +88 -0
  60. data/lib/glimmer/swt/font_proxy.rb +72 -0
  61. data/lib/glimmer/swt/layout_data_proxy.rb +84 -0
  62. data/lib/glimmer/swt/layout_proxy.rb +82 -0
  63. data/lib/glimmer/swt/menu_proxy.rb +101 -0
  64. data/lib/glimmer/swt/message_box_proxy.rb +48 -0
  65. data/lib/glimmer/swt/packages.rb +13 -0
  66. data/lib/glimmer/swt/shell_proxy.rb +152 -0
  67. data/lib/glimmer/swt/swt_proxy.rb +106 -0
  68. data/lib/glimmer/swt/tab_item_proxy.rb +65 -0
  69. data/lib/glimmer/swt/table_proxy.rb +150 -0
  70. data/lib/glimmer/swt/tree_proxy.rb +120 -0
  71. data/lib/glimmer/swt/widget_listener_proxy.rb +34 -0
  72. data/lib/glimmer/swt/widget_proxy.rb +489 -0
  73. data/lib/glimmer/ui/custom_shell.rb +45 -0
  74. data/lib/glimmer/ui/custom_widget.rb +244 -0
  75. data/lib/glimmer/util/proc_tracker.rb +16 -0
  76. data/vendor/swt/linux/swt.jar +0 -0
  77. data/vendor/swt/mac/swt.jar +0 -0
  78. data/vendor/swt/windows/swt.jar +0 -0
  79. metadata +307 -0
@@ -0,0 +1,21 @@
1
+ require 'glimmer/error'
2
+
3
+ module Glimmer
4
+ module DataBinding
5
+ module Observable
6
+ # TODO rename methods to observe/unobserve
7
+ def add_observer(observer, property_or_properties=nil)
8
+ raise Error, 'Not implemented!'
9
+ end
10
+
11
+ def remove_observer(observer, property_or_properties=nil)
12
+ raise Error, 'Not implemented!'
13
+ end
14
+
15
+ # Overriding inspect to avoid printing very long observer hierarchies
16
+ def inspect
17
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)}>"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,107 @@
1
+ require 'set'
2
+
3
+ require_relative 'observable'
4
+
5
+ module Glimmer
6
+ module DataBinding
7
+ # TODO prefix utility methods with double-underscore
8
+ module ObservableArray
9
+ include Observable
10
+
11
+ def add_observer(observer, element_properties=nil)
12
+ return observer if has_observer?(observer) && element_properties.nil?
13
+ property_observer_list << observer
14
+ [element_properties].flatten.compact.each do |property|
15
+ each do |element|
16
+ observer.observe(element, property)
17
+ end
18
+ end
19
+ observer
20
+ end
21
+
22
+ def remove_observer(observer, element_properties=nil)
23
+ property_observer_list.delete(observer)
24
+ [element_properties].flatten.compact.each do |property|
25
+ each do |element|
26
+ observer.unobserve(element, property)
27
+ end
28
+ end
29
+ observer
30
+ end
31
+
32
+ def has_observer?(observer)
33
+ property_observer_list.include?(observer)
34
+ end
35
+
36
+ def property_observer_list
37
+ @property_observer_list ||= Set.new
38
+ end
39
+
40
+ def notify_observers
41
+ property_observer_list.each {|observer| observer.call}
42
+ end
43
+
44
+ def self.extend_object(array)
45
+ # TODO consider alias_method, and define_method instead
46
+
47
+ array.instance_eval("alias __original_add <<")
48
+ array.instance_eval <<-end_eval, __FILE__, __LINE__
49
+ def <<(value)
50
+ self.__original_add(value)
51
+ notify_observers
52
+ end
53
+ end_eval
54
+
55
+ array.instance_eval("alias __original_set_value []=")
56
+ array.instance_eval <<-end_eval, __FILE__, __LINE__
57
+ def []=(index, value)
58
+ old_value = self[index]
59
+ unregister_dependent_observers(old_value)
60
+ self.__original_set_value(index, value)
61
+ notify_observers
62
+ end
63
+ end_eval
64
+
65
+ array.instance_eval("alias __original_delete delete")
66
+ array.instance_eval <<-end_eval, __FILE__, __LINE__
67
+ def delete(value)
68
+ unregister_dependent_observers(value)
69
+ self.__original_delete(value)
70
+ notify_observers
71
+ end
72
+ end_eval
73
+
74
+ array.instance_eval("alias __original_delete_at delete_at")
75
+ array.instance_eval <<-end_eval, __FILE__, __LINE__
76
+ def delete_at(index)
77
+ old_value = self[index]
78
+ unregister_dependent_observers(old_value)
79
+ self.__original_delete_at(index)
80
+ notify_observers
81
+ end
82
+ end_eval
83
+
84
+ array.instance_eval("alias __original_clear clear")
85
+ array.instance_eval <<-end_eval, __FILE__, __LINE__
86
+ def clear
87
+ each do |old_value|
88
+ unregister_dependent_observers(old_value)
89
+ end
90
+ self.__original_clear
91
+ notify_observers
92
+ end
93
+ end_eval
94
+
95
+ super
96
+ end
97
+
98
+ def unregister_dependent_observers(old_value)
99
+ # TODO look into optimizing this
100
+ return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
101
+ property_observer_list.each do |observer|
102
+ observer.unregister_dependents_with_observable(observer.registration_for(self), old_value)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,108 @@
1
+ require 'glimmer'
2
+
3
+ require_relative 'observable'
4
+ require_relative 'observer'
5
+
6
+ module Glimmer
7
+ module DataBinding
8
+ # TODO prefix utility methods with double-underscore
9
+ module ObservableModel
10
+ include Observable
11
+
12
+ class Notifier
13
+ include Observer
14
+ def initialize(observable_model, property_name)
15
+ @observable_model = observable_model
16
+ @property_name = property_name
17
+ end
18
+ def call(new_value=nil)
19
+ @observable_model.notify_observers(@property_name)
20
+ end
21
+ end
22
+
23
+ def add_observer(observer, property_name)
24
+ return observer if has_observer?(observer, property_name)
25
+ property_observer_list(property_name) << observer
26
+ add_property_writer_observers(property_name)
27
+ observer
28
+ end
29
+
30
+ def remove_observer(observer, property_name)
31
+ property_observer_list(property_name).delete(observer)
32
+ end
33
+
34
+ def has_observer?(observer, property_name)
35
+ property_observer_list(property_name).include?(observer)
36
+ end
37
+
38
+ def has_observer_for_any_property?(observer)
39
+ property_observer_hash.values.map(&:to_a).sum.include?(observer)
40
+ end
41
+
42
+ def property_observer_hash
43
+ @property_observers ||= Hash.new
44
+ end
45
+
46
+ def property_observer_list(property_name)
47
+ property_observer_hash[property_name.to_sym] = Set.new unless property_observer_hash[property_name.to_sym]
48
+ property_observer_hash[property_name.to_sym]
49
+ end
50
+
51
+ def notify_observers(property_name)
52
+ property_observer_list(property_name).each {|observer| observer.call(send(property_name))}
53
+ end
54
+ #TODO upon updating values, make sure dependent observers are cleared (not added as dependents here)
55
+
56
+ def add_property_writer_observers(property_name)
57
+ property_writer_name = "#{property_name}="
58
+ method(property_writer_name)
59
+ ensure_array_object_observer(property_name, send(property_name))
60
+ begin
61
+ method("__original_#{property_writer_name}")
62
+ rescue
63
+ # TODO consider alias_method or define_method instead
64
+ instance_eval "alias __original_#{property_writer_name} #{property_writer_name}"
65
+ instance_eval <<-end_eval, __FILE__, __LINE__
66
+ def #{property_writer_name}(value)
67
+ old_value = self.#{property_name}
68
+ unregister_dependent_observers('#{property_name}', old_value)
69
+ self.__original_#{property_writer_name}(value)
70
+ notify_observers('#{property_name}')
71
+ ensure_array_object_observer('#{property_name}', value, old_value)
72
+ end
73
+ end_eval
74
+ end
75
+ rescue => e
76
+ # ignore writing if no property writer exists
77
+ Glimmer::Config.logger&.debug "No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"
78
+ end
79
+
80
+ def unregister_dependent_observers(property_name, old_value)
81
+ # TODO look into optimizing this
82
+ return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
83
+ property_observer_list(property_name).each do |observer|
84
+ observer.unregister_dependents_with_observable(observer.registration_for(self, property_name), old_value)
85
+ end
86
+ end
87
+
88
+ def ensure_array_object_observer(property_name, object, old_object = nil)
89
+ return unless object.is_a?(Array)
90
+ array_object_observer = array_object_observer_for(property_name)
91
+ array_observer_registration = array_object_observer.observe(object)
92
+ property_observer_list(property_name).each do |observer|
93
+ my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
94
+ observer.add_dependent(my_registration => array_observer_registration)
95
+ end
96
+ array_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableArray)
97
+ end
98
+
99
+ def array_object_observer_for(property_name)
100
+ @array_object_observers ||= {}
101
+ unless @array_object_observers.has_key?(property_name)
102
+ @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name)
103
+ end
104
+ @array_object_observers[property_name]
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,17 @@
1
+ module Glimmer
2
+ module DataBinding
3
+ module ObservableWidget
4
+ # TODO see if it is worth it to eliminate duplication of method_missing
5
+ # from WidgetProxy using a module
6
+
7
+ def method_missing(method, *args, &block)
8
+ method_name = method.to_s
9
+ if can_handle_observation_request?(method_name)
10
+ handle_observation_request(method_name, &block)
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,124 @@
1
+ require 'glimmer/error'
2
+
3
+ module Glimmer
4
+ module DataBinding
5
+ # Mixin representing Observer trait from Observer Design Pattern
6
+ # Allows classes to include without interfering with their
7
+ # inheritance hierarchy.
8
+ #
9
+ # Includes a default implementation that can receive an observer block
10
+ # Example: Observer.proc {|new_value| puts new_value}
11
+ # Subclasses may override
12
+ module Observer
13
+ # Observer Proc default implementation that takes an observer block to process updates
14
+ # via call method
15
+ class Proc
16
+ include Observer
17
+
18
+ def initialize(&observer_block)
19
+ @observer_block = observer_block
20
+ end
21
+
22
+ # Called by observables once updates occur sending in the new_value if any
23
+ def call(new_value=nil)
24
+ @observer_block.call(new_value)
25
+ end
26
+ end
27
+
28
+ class Registration < Struct.new(:observer, :observable, :property, keyword_init: true)
29
+ def unregister
30
+ observer.unobserve(observable, property)
31
+ end
32
+ alias unobserve unregister
33
+ end
34
+
35
+ class << self
36
+ def proc(&observer_block)
37
+ Proc.new(&observer_block)
38
+ end
39
+ end
40
+
41
+ def registrations
42
+ @registrations ||= Set.new
43
+ end
44
+
45
+ def registration_for(observable, property = nil)
46
+ Registration.new(observer: self, observable: observable, property: property)
47
+ end
48
+
49
+ # mapping of registrations to dependents
50
+ # {[observable, property] => [[dependent, dependent_observable, dependent_property], ...]}
51
+ def dependents
52
+ @dependents ||= Hash.new
53
+ end
54
+
55
+ def dependents_for(registration)
56
+ dependents[registration] ||= Set.new
57
+ end
58
+
59
+ # registers observer in an observable on a property (optional)
60
+ # observer maintains registration list to unregister later
61
+ def register(observable, property = nil)
62
+ unless observable.is_a?(Observable)
63
+ # TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
64
+ if observable.is_a?(Array)
65
+ observable.extend(ObservableArray)
66
+ else
67
+ observable.extend(ObservableModel)
68
+ end
69
+ end
70
+ observable.add_observer(*[self, property].compact)
71
+ registration_for(observable, property).tap do |registration|
72
+ self.registrations << registration
73
+ end
74
+ end
75
+ alias observe register
76
+
77
+ def unregister(observable, property = nil)
78
+ # TODO optimize performance in the future via indexing and/or making a registration official object/class
79
+ observable.remove_observer(*[self, property].compact)
80
+ registration = registration_for(observable, property)
81
+ dependents_for(registration).each do |dependent|
82
+ dependent.unregister
83
+ remove_dependent(registration => dependent)
84
+ end
85
+ registrations.delete(registration)
86
+ end
87
+ alias unobserve unregister
88
+
89
+ def unregister_dependents_with_observable(registration, dependent_observable)
90
+ thedependents = dependents_for(registration).select do |thedependent|
91
+ thedependent.observable == dependent_observable
92
+ end
93
+ thedependents.each do |thedependent|
94
+ thedependent.unregister
95
+ end
96
+ end
97
+
98
+ # cleans up all registrations in observables
99
+ def unregister_all_observables
100
+ registrations.each do |registration|
101
+ registration.unregister
102
+ end
103
+ end
104
+ alias unobserve_all_observables unregister_all_observables
105
+
106
+ # add dependent observer to unregister when unregistering observer
107
+ def add_dependent(parent_to_dependent_hash)
108
+ registration = parent_to_dependent_hash.keys.first
109
+ dependent = parent_to_dependent_hash.values.first
110
+ dependents_for(registration) << dependent
111
+ end
112
+
113
+ def remove_dependent(parent_to_dependent_hash)
114
+ registration = parent_to_dependent_hash.keys.first
115
+ dependent = parent_to_dependent_hash.values.first
116
+ dependents_for(registration).delete(dependent)
117
+ end
118
+
119
+ def call(new_value)
120
+ raise Error, 'Not implemented!'
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,23 @@
1
+ ## NOTE: Unsupported in Ruby 2 syntax
2
+ #
3
+ # require File.dirname(__FILE__) + "/glimmer"
4
+ #
5
+ # class Array
6
+ # include Glimmer
7
+ #
8
+ # alias original_compare <=>
9
+ #
10
+ # def <=>(other)
11
+ # if (self[0].class.name == "WidgetProxy")
12
+ # content(self[0]) {
13
+ # if (other.size == 2)
14
+ # eval("#{self[1]} bind (other[0], other[1])")
15
+ # elsif (other.size == 3)
16
+ # eval("#{self[1]} bind (other[0], other[1], other[2])")
17
+ # end
18
+ # }
19
+ # else
20
+ # original_compare(other)
21
+ # end
22
+ # end
23
+ # end
@@ -0,0 +1,56 @@
1
+ require 'glimmer/data_binding/observable_array'
2
+ require 'glimmer/data_binding/observable_model'
3
+ require 'glimmer/data_binding/observable'
4
+ require 'glimmer/data_binding/observer'
5
+ require 'glimmer/swt/swt_proxy'
6
+
7
+ module Glimmer
8
+ module DataBinding
9
+ class TableItemsBinding
10
+ include DataBinding::Observable
11
+ include DataBinding::Observer
12
+ include_package 'org.eclipse.swt'
13
+ include_package 'org.eclipse.swt.widgets'
14
+
15
+ def initialize(parent, model_binding, column_properties)
16
+ @table = parent
17
+ @model_binding = model_binding
18
+ @column_properties = column_properties
19
+ if @table.respond_to?(:column_properties=)
20
+ @table.column_properties = @column_properties
21
+ else # assume custom widget
22
+ @table.body_root.column_properties = @column_properties
23
+ end
24
+ call(@model_binding.evaluate_property)
25
+ model = model_binding.base_model
26
+ observe(model, model_binding.property_name_expression)
27
+ @table.on_widget_disposed do |dispose_event|
28
+ unregister_all_observables
29
+ end
30
+ end
31
+
32
+ def call(new_model_collection=nil)
33
+ if new_model_collection and new_model_collection.is_a?(Array)
34
+ observe(new_model_collection, @column_properties)
35
+ @model_collection = new_model_collection
36
+ end
37
+ populate_table(@model_collection, @table, @column_properties)
38
+ end
39
+
40
+ def populate_table(model_collection, parent, column_properties)
41
+ selected_table_item_models = parent.swt_widget.getSelection.map(&:getData)
42
+ parent.swt_widget.removeAll
43
+ model_collection.each do |model|
44
+ table_item = TableItem.new(parent.swt_widget, SWT::SWTProxy[:none])
45
+ for index in 0..(column_properties.size-1)
46
+ table_item.setText(index, model.send(column_properties[index]).to_s)
47
+ end
48
+ table_item.setData(model)
49
+ end
50
+ selected_table_items = parent.search {|item| selected_table_item_models.include?(item.getData) }
51
+ selected_table_items = [parent.swt_widget.getItems.first].to_java(TableItem) if selected_table_items.empty? && !parent.swt_widget.getItems.empty?
52
+ parent.swt_widget.setSelection(selected_table_items) unless selected_table_items.empty?
53
+ end
54
+ end
55
+ end
56
+ end