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.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +47 -0
- data/RUBY_VERSION +1 -0
- data/VERSION +1 -0
- data/bin/girb +10 -0
- data/bin/girb_runner.rb +13 -0
- data/bin/glimmer +5 -0
- data/icons/scaffold_app.icns +0 -0
- data/lib/ext/glimmer.rb +13 -0
- data/lib/ext/glimmer/config.rb +18 -0
- data/lib/glimmer-dsl-swt.rb +12 -0
- data/lib/glimmer/data_binding/list_selection_binding.rb +52 -0
- data/lib/glimmer/data_binding/model_binding.rb +248 -0
- data/lib/glimmer/data_binding/observable.rb +21 -0
- data/lib/glimmer/data_binding/observable_array.rb +107 -0
- data/lib/glimmer/data_binding/observable_model.rb +108 -0
- data/lib/glimmer/data_binding/observable_widget.rb +17 -0
- data/lib/glimmer/data_binding/observer.rb +124 -0
- data/lib/glimmer/data_binding/shine.rb +23 -0
- data/lib/glimmer/data_binding/table_items_binding.rb +56 -0
- data/lib/glimmer/data_binding/tree_items_binding.rb +71 -0
- data/lib/glimmer/data_binding/widget_binding.rb +33 -0
- data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
- data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
- data/lib/glimmer/dsl/swt/color_expression.rb +19 -0
- data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
- data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
- data/lib/glimmer/dsl/swt/custom_widget_expression.rb +39 -0
- data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
- data/lib/glimmer/dsl/swt/dialog_expression.rb +26 -0
- data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
- data/lib/glimmer/dsl/swt/dsl.rb +34 -0
- data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
- data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
- data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
- data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
- data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
- data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
- data/lib/glimmer/dsl/swt/message_box_expression.rb +29 -0
- data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
- data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
- data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
- data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
- data/lib/glimmer/dsl/swt/shell_expression.rb +25 -0
- data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
- data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
- data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
- data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
- data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
- data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
- data/lib/glimmer/dsl/swt/widget_expression.rb +35 -0
- data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
- data/lib/glimmer/launcher.rb +196 -0
- data/lib/glimmer/package.rb +57 -0
- data/lib/glimmer/rake_task.rb +62 -0
- data/lib/glimmer/scaffold.rb +582 -0
- data/lib/glimmer/swt/color_proxy.rb +53 -0
- data/lib/glimmer/swt/display_proxy.rb +88 -0
- data/lib/glimmer/swt/font_proxy.rb +72 -0
- data/lib/glimmer/swt/layout_data_proxy.rb +84 -0
- data/lib/glimmer/swt/layout_proxy.rb +82 -0
- data/lib/glimmer/swt/menu_proxy.rb +101 -0
- data/lib/glimmer/swt/message_box_proxy.rb +48 -0
- data/lib/glimmer/swt/packages.rb +13 -0
- data/lib/glimmer/swt/shell_proxy.rb +152 -0
- data/lib/glimmer/swt/swt_proxy.rb +106 -0
- data/lib/glimmer/swt/tab_item_proxy.rb +65 -0
- data/lib/glimmer/swt/table_proxy.rb +150 -0
- data/lib/glimmer/swt/tree_proxy.rb +120 -0
- data/lib/glimmer/swt/widget_listener_proxy.rb +34 -0
- data/lib/glimmer/swt/widget_proxy.rb +489 -0
- data/lib/glimmer/ui/custom_shell.rb +45 -0
- data/lib/glimmer/ui/custom_widget.rb +244 -0
- data/lib/glimmer/util/proc_tracker.rb +16 -0
- data/vendor/swt/linux/swt.jar +0 -0
- data/vendor/swt/mac/swt.jar +0 -0
- data/vendor/swt/windows/swt.jar +0 -0
- metadata +307 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'glimmer/swt/swt_proxy'
|
2
|
+
require 'glimmer/swt/widget_proxy'
|
3
|
+
require 'glimmer/swt/display_proxy'
|
4
|
+
require 'glimmer/swt/shell_proxy'
|
5
|
+
|
6
|
+
module Glimmer
|
7
|
+
module SWT
|
8
|
+
# Proxy for org.eclipse.swt.widgets.Shell
|
9
|
+
#
|
10
|
+
# Follows the Proxy Design Pattern
|
11
|
+
class MessageBoxProxy
|
12
|
+
include_package 'org.eclipse.swt.widgets'
|
13
|
+
|
14
|
+
attr_reader :swt_widget
|
15
|
+
|
16
|
+
def initialize(parent, style)
|
17
|
+
parent = parent.swt_widget if parent.respond_to?(:swt_widget) && parent.swt_widget.is_a?(Shell)
|
18
|
+
@swt_widget = MessageBox.new(parent, style)
|
19
|
+
end
|
20
|
+
|
21
|
+
def open
|
22
|
+
@swt_widget.open
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO refactor the following methods to put in a JavaBean mixin or somethin (perhaps contribute to OSS project too)
|
26
|
+
|
27
|
+
def attribute_setter(attribute_name)
|
28
|
+
"set#{attribute_name.to_s.camelcase(:upper)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def attribute_getter(attribute_name)
|
32
|
+
"get#{attribute_name.to_s.camelcase(:upper)}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_attribute?(attribute_name, *args)
|
36
|
+
@swt_widget.respond_to?(attribute_setter(attribute_name), args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_attribute(attribute_name, *args)
|
40
|
+
@swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_attribute(attribute_name)
|
44
|
+
@swt_widget.send(attribute_getter(attribute_name))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module SWT
|
3
|
+
# This contains Java imports of SWT Java packages
|
4
|
+
module Packages
|
5
|
+
include_package 'org.eclipse.swt'
|
6
|
+
include_package 'org.eclipse.swt.widgets'
|
7
|
+
include_package 'org.eclipse.swt.layout'
|
8
|
+
include_package 'org.eclipse.swt.graphics'
|
9
|
+
include_package 'org.eclipse.swt.browser'
|
10
|
+
include_package 'org.eclipse.swt.custom'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'glimmer/swt/swt_proxy'
|
2
|
+
require 'glimmer/swt/widget_proxy'
|
3
|
+
require 'glimmer/swt/display_proxy'
|
4
|
+
require 'glimmer/swt/swt_proxy'
|
5
|
+
|
6
|
+
module Glimmer
|
7
|
+
module SWT
|
8
|
+
# Proxy for org.eclipse.swt.widgets.Shell
|
9
|
+
#
|
10
|
+
# Follows the Proxy Design Pattern
|
11
|
+
class ShellProxy < WidgetProxy
|
12
|
+
include_package 'org.eclipse.swt.widgets'
|
13
|
+
include_package 'org.eclipse.swt.layout'
|
14
|
+
|
15
|
+
WIDTH_MIN = 130
|
16
|
+
HEIGHT_MIN = 0
|
17
|
+
|
18
|
+
attr_reader :opened_before
|
19
|
+
alias opened_before? opened_before
|
20
|
+
|
21
|
+
# Instantiates ShellProxy with same arguments expected by SWT Shell
|
22
|
+
# if swt_widget keyword arg was passed, then it is assumed the shell has already been instantiated
|
23
|
+
# and the proxy wraps it instead of creating a new one.
|
24
|
+
def initialize(*args, swt_widget: nil)
|
25
|
+
if swt_widget
|
26
|
+
@swt_widget = swt_widget
|
27
|
+
else
|
28
|
+
if args.first.is_a?(ShellProxy)
|
29
|
+
args[0] = args[0].swt_widget
|
30
|
+
end
|
31
|
+
style_args = args.select {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
|
32
|
+
if style_args.any?
|
33
|
+
style_arg_start_index = args.index(style_args.first)
|
34
|
+
style_arg_last_index = args.index(style_args.last)
|
35
|
+
args[style_arg_start_index..style_arg_last_index] = SWTProxy[style_args]
|
36
|
+
end
|
37
|
+
if args.first.nil? || (!args.first.is_a?(Display) && !args.first.is_a?(Shell))
|
38
|
+
@display = DisplayProxy.instance.swt_display
|
39
|
+
args = [@display] + args
|
40
|
+
end
|
41
|
+
args = args.compact
|
42
|
+
@swt_widget = Shell.new(*args)
|
43
|
+
@swt_widget.setLayout(FillLayout.new)
|
44
|
+
@swt_widget.setMinimumSize(WIDTH_MIN, HEIGHT_MIN)
|
45
|
+
on_event_show do
|
46
|
+
Thread.new do
|
47
|
+
sleep(0.25)
|
48
|
+
async_exec do
|
49
|
+
@swt_widget.setActive unless @swt_widget.isDisposed
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@display ||= @swt_widget.getDisplay
|
55
|
+
end
|
56
|
+
|
57
|
+
# Centers shell within monitor it is in
|
58
|
+
def center
|
59
|
+
primary_monitor = @display.getPrimaryMonitor()
|
60
|
+
monitor_bounds = primary_monitor.getBounds()
|
61
|
+
shell_bounds = @swt_widget.getBounds()
|
62
|
+
location_x = monitor_bounds.x + (monitor_bounds.width - shell_bounds.width) / 2
|
63
|
+
location_y = monitor_bounds.y + (monitor_bounds.height - shell_bounds.height) / 2
|
64
|
+
@swt_widget.setLocation(location_x, location_y)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Opens shell and starts SWT's UI thread event loop
|
68
|
+
def open
|
69
|
+
if @opened_before
|
70
|
+
@swt_widget.setVisible(true)
|
71
|
+
# notify_observers('visible')
|
72
|
+
else
|
73
|
+
@opened_before = true
|
74
|
+
@swt_widget.pack
|
75
|
+
center
|
76
|
+
@swt_widget.open
|
77
|
+
start_event_loop
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias show open
|
81
|
+
|
82
|
+
def hide
|
83
|
+
@swt_widget.setVisible(false)
|
84
|
+
end
|
85
|
+
|
86
|
+
def close
|
87
|
+
@swt_widget.close
|
88
|
+
end
|
89
|
+
|
90
|
+
def visible?
|
91
|
+
@swt_widget.isDisposed ? false : @swt_widget.isVisible
|
92
|
+
end
|
93
|
+
|
94
|
+
# Setting to true opens/shows shell. Setting to false hides the shell.
|
95
|
+
def visible=(visibility)
|
96
|
+
visibility ? show : hide
|
97
|
+
end
|
98
|
+
|
99
|
+
def pack
|
100
|
+
@swt_widget.pack
|
101
|
+
end
|
102
|
+
|
103
|
+
def pack_same_size
|
104
|
+
bounds = @swt_widget.getBounds
|
105
|
+
if OS.mac?
|
106
|
+
@swt_widget.pack
|
107
|
+
@swt_widget.setBounds(bounds)
|
108
|
+
elsif OS.windows? || OS::Underlying.windows?
|
109
|
+
minimum_size = @swt_widget.getMinimumSize
|
110
|
+
@swt_widget.setMinimumSize(bounds.width, bounds.height)
|
111
|
+
listener = on_control_resized { @swt_widget.setBounds(bounds) }
|
112
|
+
@swt_widget.pack
|
113
|
+
@swt_widget.removeControlListener(listener.swt_listener)
|
114
|
+
@swt_widget.setMinimumSize(minimum_size)
|
115
|
+
elsif OS.linux?
|
116
|
+
@swt_widget.layout(true, true)
|
117
|
+
@swt_widget.setBounds(bounds)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def content(&block)
|
122
|
+
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShellExpression.new, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
# (happens as part of `#open`)
|
126
|
+
# Starts SWT Event Loop.
|
127
|
+
#
|
128
|
+
# You may learn more about the SWT Event Loop here:
|
129
|
+
# https://help.eclipse.org/2019-12/nftopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/Display.html
|
130
|
+
# This method is not needed except in rare circumstances where there is a need to start the SWT Event Loop before opening the shell.
|
131
|
+
def start_event_loop
|
132
|
+
until @swt_widget.isDisposed
|
133
|
+
@display.sleep unless @display.readAndDispatch
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_observer(observer, property_name)
|
138
|
+
case property_name.to_s
|
139
|
+
when 'visible?' #TODO see if you must handle non-? version and/or move elsewhere
|
140
|
+
visibility_notifier = proc do
|
141
|
+
observer.call(visible?)
|
142
|
+
end
|
143
|
+
on_event_show(&visibility_notifier)
|
144
|
+
on_event_hide(&visibility_notifier)
|
145
|
+
on_event_close(&visibility_notifier)
|
146
|
+
else
|
147
|
+
super
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'glimmer/error'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module SWT # TODO Consider making this the class below to ease calling it
|
5
|
+
# Proxy for org.eclipse.swt.SWT
|
6
|
+
#
|
7
|
+
# Follows the Proxy Design Pattern
|
8
|
+
class SWTProxy
|
9
|
+
class << self
|
10
|
+
java_import 'org.eclipse.swt.SWT'
|
11
|
+
|
12
|
+
ERROR_INVALID_STYLE = " is an invalid SWT style! Please choose a style from org.eclipse.swt.SWT class constants."
|
13
|
+
REGEX_SYMBOL_NEGATIVITY = /^([^!]+)(!)?$/
|
14
|
+
|
15
|
+
# Gets SWT constants as if calling SWT::CONSTANT where constant is
|
16
|
+
# passed in as a lower case symbol
|
17
|
+
def [](*symbols)
|
18
|
+
symbols = symbols.first if symbols.size == 1 && symbols.first.is_a?(Array)
|
19
|
+
result = symbols.compact.map do |symbol|
|
20
|
+
constant(symbol).tap do |constant_value|
|
21
|
+
raise Error, symbol.to_s + ERROR_INVALID_STYLE unless constant_value.is_a?(Integer)
|
22
|
+
end
|
23
|
+
end.reduce do |output, constant_value|
|
24
|
+
if constant_value < 0
|
25
|
+
output & constant_value
|
26
|
+
else
|
27
|
+
output | constant_value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
result.nil? ? SWT::NONE : result
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns SWT style integer value for passed in symbol or allows
|
34
|
+
# passed in object to pass through (e.g. Integer). This makes is convenient
|
35
|
+
# to use symbols or actual SWT style integers in Glimmer
|
36
|
+
# Does not raise error for invalid values. Just lets them pass as is.
|
37
|
+
# (look into [] operator if you want an error raised on invalid values)
|
38
|
+
def constant(symbol)
|
39
|
+
return symbol unless symbol.is_a?(Symbol) || symbol.is_a?(String)
|
40
|
+
symbol_string, negative = extract_symbol_string_negativity(symbol)
|
41
|
+
swt_constant_symbol = symbol_string.downcase == symbol_string ? symbol_string.upcase.to_sym : symbol_string.to_sym
|
42
|
+
bit_value = SWT.const_get(swt_constant_symbol)
|
43
|
+
negative ? ~bit_value : bit_value
|
44
|
+
rescue => e
|
45
|
+
begin
|
46
|
+
# Glimmer::Config.logger&.debug(e.full_message)
|
47
|
+
alternative_swt_constant_symbol = SWT.constants.find {|c| c.to_s.upcase == swt_constant_symbol.to_s.upcase}
|
48
|
+
bit_value = SWT.const_get(alternative_swt_constant_symbol)
|
49
|
+
negative ? ~bit_value : bit_value
|
50
|
+
rescue => e
|
51
|
+
# Glimmer::Config.logger&.debug(e.full_message)
|
52
|
+
bit_value = Glimmer::SWT::SWTProxy::EXTRA_STYLES[swt_constant_symbol]
|
53
|
+
if bit_value
|
54
|
+
negative ? ~bit_value : bit_value
|
55
|
+
else
|
56
|
+
symbol
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_symbol_string_negativity(symbol)
|
62
|
+
if symbol.is_a?(Symbol) || symbol.is_a?(String)
|
63
|
+
symbol_negativity_match = symbol.to_s.match(REGEX_SYMBOL_NEGATIVITY)
|
64
|
+
symbol = symbol_negativity_match[1]
|
65
|
+
negative = !!symbol_negativity_match[2]
|
66
|
+
[symbol, negative]
|
67
|
+
else
|
68
|
+
negative = symbol < 0
|
69
|
+
[symbol, negative]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def negative?(symbol)
|
74
|
+
extract_symbol_string_negativity(symbol)[1]
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_constant?(symbol)
|
78
|
+
return false unless symbol.is_a?(Symbol) || symbol.is_a?(String)
|
79
|
+
constant(symbol).is_a?(Integer)
|
80
|
+
end
|
81
|
+
|
82
|
+
def constantify_args(args)
|
83
|
+
args.map {|arg| constant(arg)}
|
84
|
+
end
|
85
|
+
|
86
|
+
# Deconstructs a style integer into symbols
|
87
|
+
# Useful for debugging
|
88
|
+
def deconstruct(integer)
|
89
|
+
SWT.constants.reduce([]) do |found, c|
|
90
|
+
constant_value = SWT.const_get(c) rescue -1
|
91
|
+
is_found = constant_value.is_a?(Integer) && (constant_value & integer) == constant_value
|
92
|
+
is_found ? found += [c] : found
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def include?(swt_constant, *symbols)
|
97
|
+
swt_constant & self[symbols] == self[symbols]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
EXTRA_STYLES = {
|
102
|
+
NO_RESIZE: self[:shell_trim, :resize!, :max!]
|
103
|
+
}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'glimmer/swt/widget_proxy'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module SWT
|
5
|
+
# Proxy for org.eclipse.swt.widgets.TabItem
|
6
|
+
#
|
7
|
+
# Functions differently from other widget proxies.
|
8
|
+
#
|
9
|
+
# Glimmer instantiates an SWT Composite alongside the SWT TabItem
|
10
|
+
# and returns it for `#swt_widget` to allow adding widgets into it.
|
11
|
+
#
|
12
|
+
# In order to get the SWT TabItem object, one must call `#swt_tab_item`.
|
13
|
+
#
|
14
|
+
# Behind the scenes, this creates a tab item widget proxy separately from a composite that
|
15
|
+
# is set as the control of the tab item and `#swt_widget`.
|
16
|
+
#
|
17
|
+
# In order to retrieve the tab item widget proxy, one must call `#widget_proxy`
|
18
|
+
#
|
19
|
+
# Follows the Proxy Design Pattern
|
20
|
+
class TabItemProxy < WidgetProxy
|
21
|
+
include_package 'org.eclipse.swt.widgets'
|
22
|
+
|
23
|
+
attr_reader :widget_proxy, :swt_tab_item
|
24
|
+
|
25
|
+
def initialize(parent, style, &contents)
|
26
|
+
super("composite", parent, style, &contents)
|
27
|
+
@widget_proxy = SWT::WidgetProxy.new('tab_item', parent, style)
|
28
|
+
@swt_tab_item = @widget_proxy.swt_widget
|
29
|
+
@widget_proxy.swt_widget.control = self.swt_widget
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_attribute?(attribute_name, *args)
|
33
|
+
if attribute_name.to_s == "text"
|
34
|
+
true
|
35
|
+
else
|
36
|
+
super(attribute_name, *args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_attribute(attribute_name, *args)
|
41
|
+
attribute_name
|
42
|
+
if attribute_name.to_s == "text"
|
43
|
+
text_value = args[0]
|
44
|
+
@swt_tab_item.setText text_value
|
45
|
+
else
|
46
|
+
super(attribute_name, *args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_attribute(attribute_name)
|
51
|
+
if attribute_name.to_s == "text"
|
52
|
+
@swt_tab_item.getText
|
53
|
+
else
|
54
|
+
super(attribute_name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def dispose
|
59
|
+
swt_tab_item.setControl(nil)
|
60
|
+
swt_widget.dispose
|
61
|
+
swt_tab_item.dispose
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'glimmer/swt/widget_proxy'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module SWT
|
5
|
+
class TableProxy < Glimmer::SWT::WidgetProxy
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
module TableListenerEvent
|
9
|
+
def table_item
|
10
|
+
table_item_and_column_index[:table_item]
|
11
|
+
end
|
12
|
+
|
13
|
+
def column_index
|
14
|
+
table_item_and_column_index[:column_index]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def table_item_and_column_index
|
20
|
+
@table_item_and_column_index ||= find_table_item_and_column_index
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_table_item_and_column_index
|
24
|
+
{}.tap do |result|
|
25
|
+
if respond_to?(:x) && respond_to?(:y)
|
26
|
+
result[:table_item] = widget.getItems.detect do |ti|
|
27
|
+
result[:column_index] = widget.getColumnCount.times.to_a.detect do |ci|
|
28
|
+
ti.getBounds(ci).contains(x, y)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :table_editor, :table_editor_text_proxy
|
37
|
+
attr_accessor :column_properties
|
38
|
+
|
39
|
+
def initialize(underscored_widget_name, parent, args)
|
40
|
+
super
|
41
|
+
@table_editor = TableEditor.new(swt_widget)
|
42
|
+
@table_editor.horizontalAlignment = SWTProxy[:left]
|
43
|
+
@table_editor.grabHorizontal = true
|
44
|
+
@table_editor.minimumHeight = 20
|
45
|
+
end
|
46
|
+
|
47
|
+
# Performs a search for table items matching block condition
|
48
|
+
# If no condition block is passed, returns all table items
|
49
|
+
# Returns a Java TableItem array to easily set as selection on org.eclipse.swt.Table if needed
|
50
|
+
def search(&condition)
|
51
|
+
swt_widget.getItems.select {|item| condition.nil? || condition.call(item)}.to_java(TableItem)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns all table items including descendants
|
55
|
+
def all_table_items
|
56
|
+
search
|
57
|
+
end
|
58
|
+
|
59
|
+
def widget_property_listener_installers
|
60
|
+
super.merge({
|
61
|
+
Java::OrgEclipseSwtWidgets::Table => {
|
62
|
+
selection: lambda do |observer|
|
63
|
+
on_widget_selected { |selection_event|
|
64
|
+
observer.call(@swt_widget.getSelection)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
},
|
68
|
+
})
|
69
|
+
end
|
70
|
+
|
71
|
+
def edit_in_progress?
|
72
|
+
!!@edit_in_progress
|
73
|
+
end
|
74
|
+
|
75
|
+
def edit_selected_table_item(column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
76
|
+
edit_table_item(swt_widget.getSelection.first, column_index, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
|
77
|
+
end
|
78
|
+
|
79
|
+
def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
80
|
+
return if table_item.nil?
|
81
|
+
content {
|
82
|
+
@table_editor_text_proxy = text {
|
83
|
+
focus true
|
84
|
+
text table_item.getText(column_index)
|
85
|
+
action_taken = false
|
86
|
+
cancel = lambda {
|
87
|
+
@table_editor_text_proxy.swt_widget.dispose
|
88
|
+
@table_editor_text_proxy = nil
|
89
|
+
after_cancel&.call
|
90
|
+
@edit_in_progress = false
|
91
|
+
}
|
92
|
+
action = lambda { |event|
|
93
|
+
if !action_taken && !@edit_in_progress
|
94
|
+
action_taken = true
|
95
|
+
@edit_in_progress = true
|
96
|
+
new_text = @table_editor_text_proxy.swt_widget.getText
|
97
|
+
if new_text == table_item.getText(column_index)
|
98
|
+
cancel.call
|
99
|
+
else
|
100
|
+
before_write&.call
|
101
|
+
table_item.setText(column_index, new_text)
|
102
|
+
model = table_item.getData
|
103
|
+
model.send("#{column_properties[column_index]}=", new_text) # makes table update itself, so must search for selected table item again
|
104
|
+
edited_table_item = search { |ti| ti.getData == model }.first
|
105
|
+
swt_widget.showItem(edited_table_item)
|
106
|
+
@table_editor_text_proxy.swt_widget.dispose
|
107
|
+
@table_editor_text_proxy = nil
|
108
|
+
after_write&.call(edited_table_item)
|
109
|
+
@edit_in_progress = false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
}
|
113
|
+
on_focus_lost(&action)
|
114
|
+
on_key_pressed { |key_event|
|
115
|
+
if key_event.keyCode == swt(:cr)
|
116
|
+
action.call(key_event)
|
117
|
+
elsif key_event.keyCode == swt(:esc)
|
118
|
+
cancel.call
|
119
|
+
end
|
120
|
+
}
|
121
|
+
}
|
122
|
+
@table_editor_text_proxy.swt_widget.selectAll
|
123
|
+
}
|
124
|
+
@table_editor.setEditor(@table_editor_text_proxy.swt_widget, table_item, column_index)
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_listener(underscored_listener_name, &block)
|
128
|
+
enhanced_block = lambda do |event|
|
129
|
+
event.extend(TableListenerEvent)
|
130
|
+
block.call(event)
|
131
|
+
end
|
132
|
+
super(underscored_listener_name, &enhanced_block)
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def property_type_converters
|
138
|
+
super.merge({
|
139
|
+
selection: lambda do |value|
|
140
|
+
if value.is_a?(Array)
|
141
|
+
search {|ti| value.include?(ti.getData) }
|
142
|
+
else
|
143
|
+
search {|ti| ti.getData == value}
|
144
|
+
end
|
145
|
+
end,
|
146
|
+
})
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|