glimmer 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
data/bin/girb_runner.rb CHANGED
@@ -1 +1,3 @@
1
+ require 'puts_debuggerer'
2
+
1
3
  include Glimmer
data/lib/glimmer.rb CHANGED
@@ -8,6 +8,7 @@ require "facets"
8
8
  require "super_module"
9
9
  require "logger"
10
10
  require "java"
11
+ require "nested_inherited_jruby_include_package"
11
12
  require_relative "glimmer/parent"
12
13
  require_relative "glimmer/swt_packages" #TODO move into SWT namespace
13
14
  require_relative "glimmer/swt/custom_widget"
@@ -1,8 +1,13 @@
1
1
  module Glimmer
2
+ # rename to keyword handler
3
+
2
4
  module CommandHandler
3
5
  def can_handle?(parent, command_symbol, *args, &block)
4
6
  raise "must be implemented by a class"
5
7
  end
8
+
9
+ # TODO rename do_handle to just handle
10
+
6
11
  def do_handle(parent, command_symbol, *args, &block)
7
12
  raise "must be implemented by a class"
8
13
  end
@@ -14,10 +14,11 @@ module Glimmer
14
14
  return @next_chain_link.handle(parent, command_symbol, *args, &block)
15
15
  else
16
16
  # TODO see if we need a better response here (e.g. dev mode error raising vs production mode silent failure)
17
- # Glimmer.logger.error "Command: #{command_symbol} cannot be handled!"
18
- Glimmer.logger.debug "Command: #{command_symbol} cannot be handled!"
19
- # raise "Command: #{command_symbol} cannot be handled!"
20
- nil
17
+ message = "Glimmer keyword #{command_symbol} with args #{args} cannot be handled"
18
+ message += " inside parent #{parent.inspect}" if parent
19
+ message += "! Check the validity of the code."
20
+ # Glimmer.logger.error message
21
+ raise message
21
22
  end
22
23
  end
23
24
  end
@@ -1,4 +1,5 @@
1
1
  require_relative "command_handler_chain_factory"
2
+ require_relative "swt/command_handlers/observe_command_handler"
2
3
  require_relative "swt/command_handlers/color_command_handler"
3
4
  require_relative "swt/command_handlers/display_command_handler"
4
5
  require_relative "swt/command_handlers/shell_command_handler"
@@ -22,6 +23,7 @@ require_relative "swt/command_handlers/custom_widget_command_handler"
22
23
  module Glimmer
23
24
  # edit to add more command handlers and extend Glimmer
24
25
  CommandHandlerChainFactory.def_dsl(:swt,
26
+ SWT::CommandHandlers::ObserveCommandHandler.new,
25
27
  SWT::CommandHandlers::DisplayCommandHandler.new,
26
28
  SWT::CommandHandlers::ShellCommandHandler.new,
27
29
  SWT::CommandHandlers::LayoutDataCommandHandler.new,
@@ -1,5 +1,6 @@
1
1
  require File.dirname(__FILE__) + "/../../command_handler"
2
2
  require File.dirname(__FILE__) + "/../custom_widget"
3
+ require File.dirname(__FILE__) + "/../custom_shell"
3
4
  require File.dirname(__FILE__) + "/../g_widget"
4
5
 
5
6
  module Glimmer
@@ -9,8 +10,9 @@ module Glimmer
9
10
  include CommandHandler
10
11
 
11
12
  def can_handle?(parent, command_symbol, *args, &block)
12
- (parent.is_a?(GWidget) || parent.is_a?(CustomWidget)) and
13
- CustomWidget.for(command_symbol)
13
+ custom_widget_class = CustomWidget.for(command_symbol)
14
+ custom_widget_class and
15
+ (parent.is_a?(GWidget) || parent.is_a?(CustomWidget) || custom_widget_class.ancestors.include?(CustomShell))
14
16
  end
15
17
 
16
18
  def do_handle(parent, command_symbol, *args, &block)
@@ -16,7 +16,6 @@ module Glimmer
16
16
  #
17
17
  # Depends on BindCommandHandler
18
18
  class DataBindingCommandHandler
19
- extend Glimmer
20
19
  include CommandHandler
21
20
 
22
21
  include_package 'org.eclipse.swt.widgets'
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + "/../../command_handler"
2
+
3
+ module Glimmer
4
+ module SWT
5
+ module CommandHandlers
6
+ class ObserveCommandHandler
7
+ REGEX_NESTED_OR_INDEXED_PROPERTY = /([^\[]+)(\[[^\]]+\])?/
8
+ include CommandHandler
9
+
10
+ def can_handle?(parent, command_symbol, *args, &block)
11
+ command_symbol.to_s == "observe" and
12
+ (
13
+ (
14
+ (args.size == 2) and
15
+ (
16
+ args[1].is_a?(Symbol) or
17
+ args[1].is_a?(String)
18
+ )
19
+ )
20
+ ) and
21
+ !block.nil?
22
+ end
23
+
24
+ def do_handle(parent, command_symbol, *args, &block)
25
+ observer = Observer.proc(&block)
26
+ if args[1].to_s.match(REGEX_NESTED_OR_INDEXED_PROPERTY)
27
+ observer.observe(ModelBinding.new(args[0], args[1]))
28
+ else
29
+ observer.observe(args[0], args[1])
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -8,10 +8,10 @@ module Glimmer
8
8
 
9
9
  def can_handle?(parent, command_symbol, *args, &block)
10
10
  parent.respond_to?(:set_attribute) and
11
- parent.respond_to?(:has_attribute?) and
12
- args.size > 0 and
13
- block == nil and
14
- parent.has_attribute?(command_symbol, *args)
11
+ parent.respond_to?(:has_attribute?) and
12
+ args.size > 0 and
13
+ block == nil and
14
+ parent.has_attribute?(command_symbol, *args)
15
15
  end
16
16
 
17
17
  def do_handle(parent, command_symbol, *args, &block)
@@ -5,6 +5,8 @@ require File.dirname(__FILE__) + "/../custom_widget"
5
5
  module Glimmer
6
6
  module SWT
7
7
  module CommandHandlers
8
+ # TODO rename to observation command handler (or keyword handler)
9
+
8
10
  class WidgetListenerCommandHandler
9
11
  include CommandHandler
10
12
 
@@ -14,18 +16,19 @@ module Glimmer
14
16
  widget_parentage = (parent.is_a?(GWidget) || parent.is_a?(CustomWidget))
15
17
  Glimmer.logger.debug "parent is a widget: #{widget_parentage}"
16
18
  return unless widget_parentage
17
- Glimmer.logger.debug "on listener?: " + (command_symbol.to_s[0,3] == "on_").to_s
18
- return unless command_symbol.to_s[0,3] == "on_"
19
- Glimmer.logger.debug "command symbol is longer than 3: " + (command_symbol.to_s.length > 3).to_s
20
- return unless command_symbol.to_s.length > 3
21
- Glimmer.logger.debug "args are 0?: " + (args.size == 0).to_s
22
- return unless args.size == 0
23
- Glimmer.logger.debug "can add listener? " + (parent.can_add_listener?(command_symbol.to_s[3, command_symbol.to_s.length])).to_s
24
- parent.can_add_listener?(command_symbol.to_s[3, command_symbol.to_s.length])
19
+ Glimmer.logger.debug "keyword starts with on_: #{command_symbol.to_s.start_with?('on_')}"
20
+ return unless command_symbol.to_s.start_with?('on_')
21
+ Glimmer.logger.debug "args are empty?: #{args.empty?}"
22
+ return unless args.empty?
23
+ Glimmer.logger.debug "block exists?: #{!block.nil?}"
24
+ return unless !block.nil?
25
+ result = parent.can_handle_observation_request?(command_symbol.to_s)
26
+ Glimmer.logger.debug "can add listener? #{result}"
27
+ result
25
28
  end
26
29
 
27
30
  def do_handle(parent, command_symbol, *args, &block)
28
- parent.add_listener(command_symbol.to_s[3, command_symbol.to_s.length], &block)
31
+ parent.handle_observation_request(command_symbol.to_s, &block)
29
32
  ListenerParent.new #TODO refactor and move to models
30
33
  end
31
34
 
@@ -0,0 +1,45 @@
1
+ require 'super_module'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ module CustomShell
6
+ include SuperModule
7
+ include Glimmer::SWT::CustomWidget
8
+
9
+ def initialize(parent, *swt_constants, options, &content)
10
+ super
11
+ raise 'Invalid custom shell body root! Must be a shell or another custom shell.' unless body_root.is_a?(GShell) || body_root.is_a?(CustomShell)
12
+ end
13
+
14
+ # Classes may override
15
+ def open
16
+ body_root.open
17
+ end
18
+
19
+ # DO NOT OVERRIDE. JUST AN ALIAS FOR `#open`. OVERRIDE `#open` INSTEAD.
20
+ def show
21
+ open
22
+ end
23
+
24
+ def close
25
+ body_root.close
26
+ end
27
+
28
+ def hide
29
+ body_root.hide
30
+ end
31
+
32
+ def visible?
33
+ body_root.visible?
34
+ end
35
+
36
+ def center
37
+ body_root.center
38
+ end
39
+
40
+ def start_event_loop
41
+ body_root.start_event_loop
42
+ end
43
+ end
44
+ end
45
+ end
@@ -58,6 +58,16 @@ module Glimmer
58
58
  end_eval
59
59
  end
60
60
  end
61
+
62
+ def before_body(&block)
63
+ @before_body_blocks ||= []
64
+ @before_body_blocks << block
65
+ end
66
+
67
+ def after_body(&block)
68
+ @after_body_blocks ||= []
69
+ @after_body_blocks << block
70
+ end
61
71
  end
62
72
 
63
73
  attr_reader :body_root, :widget, :parent, :swt_style, :options, :content
@@ -68,7 +78,9 @@ module Glimmer
68
78
  options ||= {}
69
79
  @options = self.class.options.merge(options)
70
80
  @content = ProcTracker.new(content) if content
81
+ execute_hooks('before_body')
71
82
  @body_root = body
83
+ execute_hooks('after_body')
72
84
  @widget = @body_root.widget
73
85
  end
74
86
 
@@ -76,16 +88,26 @@ module Glimmer
76
88
  raise 'Not implemented!'
77
89
  end
78
90
 
79
- # TODO consider using delegators
80
-
81
- def can_add_listener?(underscored_listener_name)
82
- @body_root.can_add_listener?(underscored_listener_name)
91
+ def can_handle_observation_request?(observation_request)
92
+ result = false
93
+ if observation_request.start_with?('on_updated_')
94
+ property = observation_request.sub(/^on_updated_/, '')
95
+ result = can_add_observer?(property)
96
+ end
97
+ result || body_root&.can_handle_observation_request?(observation_request)
83
98
  end
84
99
 
85
- # TODO clean up difference between add_listener and add_observer
100
+ def handle_observation_request(observation_request, &block)
101
+ if observation_request.start_with?('on_updated_')
102
+ property = observation_request.sub(/^on_updated_/, '')
103
+ add_observer(Observer::Proc.new(&block), property) if can_add_observer?(property)
104
+ else
105
+ body_root.handle_observation_request(observation_request, &block)
106
+ end
107
+ end
86
108
 
87
- def add_listener(underscored_listener_name, &block)
88
- @body_root.add_listener(underscored_listener_name, &block)
109
+ def can_add_observer?(attribute_name)
110
+ respond_to?(attribute_name) || @body_root.can_add_observer?(attribute_name)
89
111
  end
90
112
 
91
113
  def add_observer(observer, attribute_name)
@@ -121,11 +143,53 @@ module Glimmer
121
143
  "#{attribute_name}="
122
144
  end
123
145
 
146
+ # TODO see if it is worth it to eliminate duplication of method_missing
147
+ # from GWidget using a module
148
+
149
+ def method_missing(method, *args, &block)
150
+ method_name = method.to_s
151
+ if can_handle_observation_request?(method_name)
152
+ handle_observation_request(method_name, &block)
153
+ else
154
+ super
155
+ end
156
+ end
157
+
124
158
  def process_block(block)
125
159
  if block.source_location == @content&.__getobj__.source_location
126
- @content.call unless @content.called?
160
+ @content.call(self) unless @content.called?
127
161
  else
128
- block.call
162
+ block.call(self)
163
+ end
164
+ end
165
+
166
+ def has_style?(style)
167
+ (swt_style & GSWT[style]) == GSWT[style]
168
+ end
169
+
170
+ # TODO see if it is worth it to eliminate duplication of async_exec/sync_exec
171
+ # delegation to GDisplay, via a module
172
+
173
+ def async_exec(&block)
174
+ GDisplay.instance.async_exec(&block)
175
+ end
176
+
177
+ def sync_exec(&block)
178
+ GDisplay.instance.sync_exec(&block)
179
+ end
180
+
181
+ def add_content(&block)
182
+ body_root.add_content(&block)
183
+ end
184
+
185
+ private
186
+
187
+ def execute_hooks(hook_name)
188
+ self.class.instance_variable_get("@#{hook_name}_blocks")&.each_with_index do |hook_block, i|
189
+ hook_block_number = i + 1
190
+ self.class.define_method("__#{hook_name}#{hook_block_number}", hook_block)
191
+ send("__#{hook_name}#{hook_block_number}")
192
+ self.class.send(:undef_method, "__#{hook_name}#{hook_block_number}")
129
193
  end
130
194
  end
131
195
  end
@@ -23,6 +23,14 @@ module Glimmer
23
23
  def dispose
24
24
  @display.dispose
25
25
  end
26
+
27
+ def async_exec(&block)
28
+ @display.asyncExec(GRunnable.new(&block))
29
+ end
30
+
31
+ def sync_exec(&block)
32
+ @display.syncExec(GRunnable.new(&block))
33
+ end
26
34
  end
27
35
  end
28
36
  end
@@ -7,8 +7,6 @@ module Glimmer
7
7
  FONT_STYLES = [:normal, :bold, :italic]
8
8
  include_package 'org.eclipse.swt.graphics'
9
9
 
10
- extend Glimmer
11
-
12
10
  attr_reader :g_widget
13
11
  attr_accessor :display
14
12
 
@@ -17,11 +15,9 @@ module Glimmer
17
15
  @instances ||= {}
18
16
  unless @instances[g_widget]
19
17
  @instances[g_widget] = new(g_widget)
20
- add_contents(g_widget) {
21
- on_widget_disposed { |dispose_event|
22
- @instances.delete(g_widget)
23
- }
24
- }
18
+ g_widget.on_widget_disposed do |dispose_event|
19
+ @instances.delete(g_widget)
20
+ end
25
21
  end
26
22
  @instances[g_widget]
27
23
  end
@@ -46,7 +46,7 @@ module Glimmer
46
46
  end
47
47
 
48
48
  def process_block(block)
49
- block.call(@layout)
49
+ block.call(self)
50
50
  end
51
51
 
52
52
  def has_attribute?(attribute_name, *args)
@@ -24,7 +24,7 @@ module Glimmer
24
24
  end
25
25
 
26
26
  def process_block(block)
27
- block.call(@layout)
27
+ block.call(self)
28
28
  end
29
29
 
30
30
  def swt_layout_data_class
@@ -10,7 +10,8 @@ module Glimmer
10
10
  include_package 'org.eclipse.swt.layout'
11
11
  include_package 'org.eclipse.swt.widgets'
12
12
 
13
- attr_reader :display
13
+ attr_reader :display, :opened_before
14
+ alias opened_before? opened_before
14
15
 
15
16
  # Instantiates shell with same arguments expected by SWT Shell
16
17
  def initialize(*args)
@@ -37,10 +38,44 @@ module Glimmer
37
38
 
38
39
  # Opens shell and starts SWT's UI thread event loop
39
40
  def open
40
- @widget.pack
41
- center
42
- @widget.open
43
- start_event_loop
41
+ if @opened_before
42
+ @widget.setVisible(true)
43
+ # notify_observers('visible')
44
+ else
45
+ @opened_before = true
46
+ @widget.pack
47
+ center
48
+ @widget.open
49
+ # NOTE: the following line runs after scheduled sync exec events,
50
+ # but ensures visible status is only updated upon true visibility
51
+ # async_exec do
52
+ # notify_observers('visible')
53
+ # end
54
+ start_event_loop
55
+ end
56
+ end
57
+ alias show open
58
+
59
+ def hide
60
+ @widget.setVisible(false)
61
+ # notify_observers('visible')
62
+ end
63
+
64
+ def close
65
+ @widget.close
66
+ # notify_observers('visible')
67
+ end
68
+
69
+ # TODO implement and notify_observers('visible') based on open and hide
70
+
71
+ def visible?
72
+ @widget.isDisposed ? false : @widget.isVisible
73
+ end
74
+
75
+ # TODO evaluate if this is needed
76
+
77
+ def visible=(visibility)
78
+ visibility ? show : hide
44
79
  end
45
80
 
46
81
  def start_event_loop
@@ -49,6 +84,23 @@ module Glimmer
49
84
  end
50
85
  @display.dispose
51
86
  end
87
+
88
+ def add_observer(observer, property_name)
89
+ case property_name.to_s
90
+ when 'visible?'
91
+ @widget.addListener(GSWT[:show]) do |event|
92
+ observer.call(visible?)
93
+ end
94
+ @widget.addListener(GSWT[:hide]) do |event|
95
+ observer.call(visible?)
96
+ end
97
+ @widget.addListener(GSWT[:close]) do |event|
98
+ observer.call(visible?)
99
+ end
100
+ else
101
+ super
102
+ end
103
+ end
52
104
  end
53
105
  end
54
106
  end