glimmer-dsl-swt 0.1.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 (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