reactive-wx 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|