reactive-wx 0.2.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.
- data/LICENSE +20 -0
- data/Manifest +45 -0
- data/README +22 -0
- data/Rakefile +5 -0
- data/lib/reactive-wx.rb +19 -0
- data/lib/reactive-wx/accessors.rb +15 -0
- data/lib/reactive-wx/accessors/control_with_items.rb +22 -0
- data/lib/reactive-wx/accessors/date_picker_ctrl.rb +17 -0
- data/lib/reactive-wx/accessors/text_ctrl.rb +17 -0
- data/lib/reactive-wx/binder.rb +49 -0
- data/lib/reactive-wx/default_handler.rb +50 -0
- data/lib/reactive-wx/helpers.rb +10 -0
- data/lib/reactive-wx/helpers/asset_helper.rb +21 -0
- data/lib/reactive-wx/helpers/exception_helper.rb +82 -0
- data/lib/reactive-wx/helpers/forms.rb +40 -0
- data/lib/reactive-wx/request.rb +13 -0
- data/lib/reactive-wx/wx_ext.rb +42 -0
- data/lib/reactive-wx/wx_ext/arranger.rb +33 -0
- data/lib/reactive-wx/wx_ext/aui_toolbar.rb +22 -0
- data/lib/reactive-wx/wx_ext/event_binder.rb +11 -0
- data/lib/reactive-wx/wx_ext/form_grid_sizer.rb +54 -0
- data/lib/reactive-wx/wx_ext/message_dialog.rb +62 -0
- data/lib/reactive-wx/wx_ext/panel_dialog.rb +14 -0
- data/lib/reactive-wx/wx_ext/semi_modal.rb +233 -0
- data/lib/reactive-wx/wx_ext/toolbar.rb +29 -0
- data/lib/reactive-wx/wx_ext/window.rb +16 -0
- data/reactive_app_generators/wx/USAGE +6 -0
- data/reactive_app_generators/wx/templates/application_helper.wx.rb +8 -0
- data/reactive_app_generators/wx/templates/layout.wx.erb +2 -0
- data/reactive_app_generators/wx/templates/main_controller.rb +10 -0
- data/reactive_app_generators/wx/templates/main_helper.wx.rb +9 -0
- data/reactive_app_generators/wx/templates/run.wx.erb +22 -0
- data/reactive_app_generators/wx/templates/show.wx.erb +2 -0
- data/reactive_app_generators/wx/wx_generator.rb +54 -0
- data/reactive_generators/view/USAGE +11 -0
- data/reactive_generators/view/templates/create.wx.rb +0 -0
- data/reactive_generators/view/templates/delete.wx.rb +0 -0
- data/reactive_generators/view/templates/destroy.wx.rb +0 -0
- data/reactive_generators/view/templates/edit.wx.rb +0 -0
- data/reactive_generators/view/templates/index.wx.rb +0 -0
- data/reactive_generators/view/templates/layout.wx.rb +0 -0
- data/reactive_generators/view/templates/new.wx.rb +0 -0
- data/reactive_generators/view/templates/show.wx.rb +0 -0
- data/reactive_generators/view/templates/update.wx.rb +0 -0
- data/reactive_generators/view/view_generator.rb +25 -0
- metadata +134 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Pascal Hurni
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
LICENSE
|
2
|
+
Manifest
|
3
|
+
README
|
4
|
+
Rakefile
|
5
|
+
lib/reactive-wx.rb
|
6
|
+
lib/reactive-wx/accessors.rb
|
7
|
+
lib/reactive-wx/accessors/control_with_items.rb
|
8
|
+
lib/reactive-wx/accessors/date_picker_ctrl.rb
|
9
|
+
lib/reactive-wx/accessors/text_ctrl.rb
|
10
|
+
lib/reactive-wx/binder.rb
|
11
|
+
lib/reactive-wx/default_handler.rb
|
12
|
+
lib/reactive-wx/helpers.rb
|
13
|
+
lib/reactive-wx/helpers/asset_helper.rb
|
14
|
+
lib/reactive-wx/helpers/exception_helper.rb
|
15
|
+
lib/reactive-wx/helpers/forms.rb
|
16
|
+
lib/reactive-wx/request.rb
|
17
|
+
lib/reactive-wx/wx_ext.rb
|
18
|
+
lib/reactive-wx/wx_ext/arranger.rb
|
19
|
+
lib/reactive-wx/wx_ext/aui_toolbar.rb
|
20
|
+
lib/reactive-wx/wx_ext/event_binder.rb
|
21
|
+
lib/reactive-wx/wx_ext/form_grid_sizer.rb
|
22
|
+
lib/reactive-wx/wx_ext/message_dialog.rb
|
23
|
+
lib/reactive-wx/wx_ext/panel_dialog.rb
|
24
|
+
lib/reactive-wx/wx_ext/semi_modal.rb
|
25
|
+
lib/reactive-wx/wx_ext/toolbar.rb
|
26
|
+
lib/reactive-wx/wx_ext/window.rb
|
27
|
+
reactive_app_generators/wx/USAGE
|
28
|
+
reactive_app_generators/wx/templates/application_helper.wx.rb
|
29
|
+
reactive_app_generators/wx/templates/layout.wx.erb
|
30
|
+
reactive_app_generators/wx/templates/main_controller.rb
|
31
|
+
reactive_app_generators/wx/templates/main_helper.wx.rb
|
32
|
+
reactive_app_generators/wx/templates/run.wx.erb
|
33
|
+
reactive_app_generators/wx/templates/show.wx.erb
|
34
|
+
reactive_app_generators/wx/wx_generator.rb
|
35
|
+
reactive_generators/view/USAGE
|
36
|
+
reactive_generators/view/templates/create.wx.rb
|
37
|
+
reactive_generators/view/templates/delete.wx.rb
|
38
|
+
reactive_generators/view/templates/destroy.wx.rb
|
39
|
+
reactive_generators/view/templates/edit.wx.rb
|
40
|
+
reactive_generators/view/templates/index.wx.rb
|
41
|
+
reactive_generators/view/templates/layout.wx.rb
|
42
|
+
reactive_generators/view/templates/new.wx.rb
|
43
|
+
reactive_generators/view/templates/show.wx.rb
|
44
|
+
reactive_generators/view/templates/update.wx.rb
|
45
|
+
reactive_generators/view/view_generator.rb
|
data/README
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
== reactive-wx
|
2
|
+
|
3
|
+
This plugin is an output handler for wx code.
|
4
|
+
It therefore runs code targeted for the wxWidgets toolkit using its ruby port
|
5
|
+
named wxRuby.
|
6
|
+
|
7
|
+
It is required to run on the client-side of the Reactive application.
|
8
|
+
|
9
|
+
Version:: 0.2.0
|
10
|
+
Author:: Pascal Hurni
|
11
|
+
Email:: phi@ruby-reactive.org
|
12
|
+
Homepage:: http://www.ruby-reactive.org
|
13
|
+
|
14
|
+
== Description
|
15
|
+
|
16
|
+
Adds
|
17
|
+
|
18
|
+
== Requirements
|
19
|
+
|
20
|
+
* reactive-core >=0.2.0
|
21
|
+
* wxruby >=1.9.6
|
22
|
+
* wx_sugar >= 0.1.19
|
data/Rakefile
ADDED
data/lib/reactive-wx.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Reactive::Initializer.init :wx do
|
2
|
+
require 'wx'
|
3
|
+
require 'wx_sugar'
|
4
|
+
require 'reactive-wx/wx_ext'
|
5
|
+
|
6
|
+
require 'reactive-wx/request'
|
7
|
+
require 'reactive-wx/binder'
|
8
|
+
require 'reactive-wx/default_handler'
|
9
|
+
require 'reactive-wx/accessors'
|
10
|
+
require 'reactive-wx/helpers'
|
11
|
+
|
12
|
+
Reactive::OutputHandler::Base.register_output_handler(:wx, Reactive::WxOutput::DefaultHandler)
|
13
|
+
|
14
|
+
# every event handler may do requests
|
15
|
+
Wx::EvtHandler.send(:include, Reactive::WxOutput::Binder)
|
16
|
+
|
17
|
+
# We want the ::Wx namespace to be directly available for our handlers
|
18
|
+
Reactive::OutputHandler::Base.helper(:wx, ::Wx)
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'reactive-wx/accessors/text_ctrl'
|
2
|
+
require 'reactive-wx/accessors/control_with_items'
|
3
|
+
require 'reactive-wx/accessors/date_picker_ctrl'
|
4
|
+
|
5
|
+
module Reactive::WxOutput
|
6
|
+
module Accessors # :nodoc: all
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Introduces orthogonality to access control's data.
|
11
|
+
# The majority of controls expose a #get_value method, but some don't.
|
12
|
+
# These modules defines such a method to access the data.
|
13
|
+
Wx::ControlWithItems.send(:include, Reactive::WxOutput::Accessors::ControlWithItems)
|
14
|
+
Wx::TextCtrl.send(:include, Reactive::WxOutput::Accessors::TextCtrl)
|
15
|
+
Wx::DatePickerCtrl.send(:include, Reactive::WxOutput::Accessors::DatePickerCtrl) if defined? Wx::DatePickerCtrl
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Reactive
|
2
|
+
module WxOutput
|
3
|
+
module Accessors
|
4
|
+
|
5
|
+
# The data is identified by the related item_data (Wx) filled before
|
6
|
+
module ControlWithItems
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def set_data(id)
|
10
|
+
if index = find {|i| get_item_data(i) == id}
|
11
|
+
set_selection(index)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_data
|
16
|
+
get_item_data(get_selection)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'reactive-wx/helpers/forms'
|
2
|
+
|
3
|
+
module Reactive
|
4
|
+
module WxOutput
|
5
|
+
|
6
|
+
module Binder
|
7
|
+
include Helpers::FormsHelper
|
8
|
+
|
9
|
+
# Let Reactive do the request
|
10
|
+
# The hash argument may be of three forms:
|
11
|
+
# * Direct form: a record (for CRUD actions, the action is known by asking the record: CREATE => new_record?, UPDATE => changed?, DELETE => marked_for_destruction?, SHOW => none of them)
|
12
|
+
# You may override the action by passing an :action entry in the options. A special action named :save will auto-determine the :create or :update state.
|
13
|
+
# * Simple form: a params hash with at least entries for :controller and :action
|
14
|
+
# * Complex form: a hash with a :link entry
|
15
|
+
# TODO: Refactor this new_params creation process
|
16
|
+
def do_request(*args)
|
17
|
+
hash = args.extract_options!
|
18
|
+
record = args.first
|
19
|
+
if record.class.respond_to?(:meta) && record.class.meta.is_a?(MetaModel::Model)
|
20
|
+
options = hash
|
21
|
+
new_params = hash.merge(:model => record)
|
22
|
+
else
|
23
|
+
# params may be of two forms, a simple params hash or a complex hash with embedded hashes. To distinguish: if the hash contains a :link key it is a complex one.
|
24
|
+
params, options = hash.has_key?(:link) ? [hash[:link], hash] : [hash, {}]
|
25
|
+
new_params = params.dup
|
26
|
+
|
27
|
+
# handle forms params
|
28
|
+
new_params.update(forms_to_params(options[:forms]))
|
29
|
+
|
30
|
+
# handle late update of params
|
31
|
+
# return false unless handle_late_tag(options[:late], new_params, wx_event)
|
32
|
+
|
33
|
+
end
|
34
|
+
# set up the request
|
35
|
+
request = Request.new(new_params)
|
36
|
+
request.local_assigns = options[:locals]
|
37
|
+
|
38
|
+
# let the request run
|
39
|
+
Dispatcher::Base.dispatch(request)
|
40
|
+
end
|
41
|
+
|
42
|
+
# def handle_late_tag(tag, params, wx_event)
|
43
|
+
# return true if tag.nil?
|
44
|
+
# tag.call(params, wx_event)
|
45
|
+
# end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Reactive
|
2
|
+
module WxOutput
|
3
|
+
# The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a
|
4
|
+
# bunch of intimate details and uses it to report a very precise exception message.
|
5
|
+
class HandlerError < Error #:nodoc:
|
6
|
+
include Reactive::TemplateError
|
7
|
+
end
|
8
|
+
|
9
|
+
class DefaultHandler < Reactive::OutputHandler::Base
|
10
|
+
cattr_reader :handler_name # We are the default handler, so our name is nil!
|
11
|
+
|
12
|
+
include Binder
|
13
|
+
|
14
|
+
def default_treatment
|
15
|
+
:run
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
copy_ivars(response.variables)
|
20
|
+
instance_eval("#{locals_code}\n#{response.body}", request_name, 0)
|
21
|
+
rescue Exception => e
|
22
|
+
if HandlerError === e
|
23
|
+
e.sub_template_of(request_name)
|
24
|
+
raise e
|
25
|
+
else
|
26
|
+
raise HandlerError.new(request_name, response.body, e)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def copy_ivars(variables)
|
33
|
+
variables.each {|name, value| instance_variable_set("@#{name}", value)}
|
34
|
+
end
|
35
|
+
|
36
|
+
def locals_code
|
37
|
+
@local_assigns = {}
|
38
|
+
code = "local_assigns = @local_assigns;"
|
39
|
+
if request.respond_to? :local_assigns
|
40
|
+
if request.local_assigns
|
41
|
+
@local_assigns = request.local_assigns
|
42
|
+
code <<request.local_assigns.keys.map { |key| "#{key} = @local_assigns[:#{key}];" }.join
|
43
|
+
end
|
44
|
+
end
|
45
|
+
code
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Load helper modules
|
2
|
+
helpers_dir = "#{File.dirname(__FILE__)}/helpers"
|
3
|
+
Dir.entries(helpers_dir).sort.each do |file|
|
4
|
+
next unless file =~ /^([a-z][a-z_]*_helper).rb$/
|
5
|
+
require File.join(helpers_dir, file)
|
6
|
+
helper_module_name = $1.camelize
|
7
|
+
if Reactive::WxOutput::Helpers.const_defined?(helper_module_name)
|
8
|
+
Reactive::OutputHandler::Base.helper(:wx, Reactive::WxOutput::Helpers.const_get(helper_module_name))
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Reactive::WxOutput
|
2
|
+
module Helpers
|
3
|
+
module AssetHelper
|
4
|
+
|
5
|
+
class AssetArtProvider < Wx::ArtProvider
|
6
|
+
include Reactive::WxOutput::Binder
|
7
|
+
|
8
|
+
def create_bitmap(id, client, size)
|
9
|
+
unless id =~ /^wx/
|
10
|
+
begin
|
11
|
+
Wx::Bitmap.new(do_request(:asset => id, :kind => :ui), Wx::BITMAP_TYPE_ANY)
|
12
|
+
rescue Reactive::Dispatcher::AssetNotFound => e
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Reactive::WxOutput
|
2
|
+
module Helpers
|
3
|
+
module ExceptionHelper
|
4
|
+
|
5
|
+
def show_exception_dialog(exception)
|
6
|
+
send("show_#{Reactive.configuration.environment}_exception_dialog", exception)
|
7
|
+
end
|
8
|
+
|
9
|
+
def show_production_exception_dialog(exception)
|
10
|
+
# TODO
|
11
|
+
show_development_exception_dialog(exception)
|
12
|
+
end
|
13
|
+
|
14
|
+
def show_test_exception_dialog(exception)
|
15
|
+
# Tests should trap all exception, so re-raise it if it is not handled!
|
16
|
+
raise exception
|
17
|
+
end
|
18
|
+
|
19
|
+
def show_development_exception_dialog(exception)
|
20
|
+
dialog = WxExtensions::PanelDialog.new(nil, :style => Wx::DEFAULT_DIALOG_STYLE | Wx::RESIZE_BORDER) do |dialog|
|
21
|
+
html_win = Wx::HtmlWindow.new(dialog)
|
22
|
+
html_win.set_page(a=htmlize_exception(exception))
|
23
|
+
html_win
|
24
|
+
end
|
25
|
+
dialog.show_modal
|
26
|
+
dialog.destroy
|
27
|
+
end
|
28
|
+
|
29
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
30
|
+
def h(html)
|
31
|
+
sanitize_latin1(html).to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| HTML_ESCAPE[special] }
|
32
|
+
end
|
33
|
+
|
34
|
+
def sanitize_latin1(text)
|
35
|
+
text.gsub(/[\x80-\xFF]/, '_')
|
36
|
+
end
|
37
|
+
|
38
|
+
def htmlize_trace(exception)
|
39
|
+
"<pre>#{exception.clean_backtrace.map{|line| line.sub(/:in (.+)/, ":in <font color=\"red\">\\1</font>")}.join("\n")}</pre>"
|
40
|
+
end
|
41
|
+
|
42
|
+
def htmlize_request(exception)
|
43
|
+
end
|
44
|
+
|
45
|
+
def htmlize_exception(exception)
|
46
|
+
if exception.respond_to? :template_error
|
47
|
+
<<EOS
|
48
|
+
<h1>
|
49
|
+
#{h exception.original_exception.class.to_s } in
|
50
|
+
#{request.params[:controller] ? h(request.params[:controller].capitalize) : ''}##{h request.params[:action] }
|
51
|
+
</h1>
|
52
|
+
|
53
|
+
<p>
|
54
|
+
Showing <i>#{h exception.file_name }</i> where line <b>##{h exception.line_number }</b> raised:
|
55
|
+
<pre><code>#{h exception.message }</code></pre>
|
56
|
+
</p>
|
57
|
+
|
58
|
+
<p>Extracted source (around line <b>##{h exception.line_number }</b>):
|
59
|
+
<pre><code>#{h exception.source_extract }</code></pre></p>
|
60
|
+
|
61
|
+
<p>#{h exception.sub_template_message }</p>
|
62
|
+
|
63
|
+
#{htmlize_trace(exception.original_exception || exception)}
|
64
|
+
#{htmlize_request(exception)}
|
65
|
+
EOS
|
66
|
+
else
|
67
|
+
<<EOS
|
68
|
+
<h1>
|
69
|
+
#{h exception.class.to_s}
|
70
|
+
#{request.params[:controller] ? h('in ' + request.params[:controller].humanize + 'Controller' + (request.params[:action] ? '#' + request.params[:action] : '')) : ''}
|
71
|
+
</h1>
|
72
|
+
<pre>#{h exception.clean_message}</pre>
|
73
|
+
|
74
|
+
#{htmlize_trace(exception)}
|
75
|
+
#{htmlize_request(exception)}
|
76
|
+
EOS
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Reactive::WxOutput
|
2
|
+
|
3
|
+
class InvalidForm < Reactive::OutputHandler::Error
|
4
|
+
end
|
5
|
+
|
6
|
+
module Helpers
|
7
|
+
module FormsHelper
|
8
|
+
|
9
|
+
def forms_to_params(forms)
|
10
|
+
forms = [forms] unless forms.is_a?(Array)
|
11
|
+
forms.compact.inject({}) do |params, form|
|
12
|
+
form_name, container = form_name_and_container(form)
|
13
|
+
params.update(form_name => form_to_param(container))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def form_to_param(container)
|
18
|
+
form_param = {}
|
19
|
+
container.get_children.each {|child| next unless child.get_name =~ /^[\da-z_]+$/ ;form_param[child.get_name] = child.get_data} #TODO: Handle sub-children recursively
|
20
|
+
form_param
|
21
|
+
end
|
22
|
+
|
23
|
+
def form_name_and_container(form)
|
24
|
+
case form
|
25
|
+
when ::Wx::Window
|
26
|
+
raise InvalidForm, "Window #{form} has no name!" unless name = form.get_name
|
27
|
+
[name, form]
|
28
|
+
when String
|
29
|
+
raise InvalidForm, "No window named #{form}" unless win = ::Wx::Window.find_window_by_name(form, self)
|
30
|
+
[form, win]
|
31
|
+
when Hash
|
32
|
+
form.to_a
|
33
|
+
else
|
34
|
+
raise InvalidForm, "Unhandled param, passed form: #{form.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|