ruby_mvc 0.0.1 → 0.0.2

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 (68) hide show
  1. data/README.md +14 -0
  2. data/lib/ruby_mvc.rb +3 -1
  3. data/lib/ruby_mvc/application.rb +52 -2
  4. data/lib/ruby_mvc/controllers.rb +28 -0
  5. data/lib/ruby_mvc/controllers/action.rb +93 -0
  6. data/lib/ruby_mvc/controllers/action_group.rb +70 -0
  7. data/lib/ruby_mvc/controllers/app_controller.rb +4 -2
  8. data/lib/ruby_mvc/controllers/rails_controller.rb +2 -0
  9. data/lib/ruby_mvc/models.rb +2 -0
  10. data/lib/ruby_mvc/models/ar_table_model.rb +133 -0
  11. data/lib/ruby_mvc/models/array_table_model.rb +81 -13
  12. data/lib/ruby_mvc/models/keyed_array_table_model.rb +1 -1
  13. data/lib/ruby_mvc/models/model.rb +129 -0
  14. data/lib/ruby_mvc/models/table_model.rb +107 -10
  15. data/lib/ruby_mvc/models/view_model_template.rb +140 -0
  16. data/lib/ruby_mvc/renderers.rb +1 -0
  17. data/lib/ruby_mvc/renderers/html4_table_model_renderer.rb +7 -6
  18. data/lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb +47 -0
  19. data/lib/ruby_mvc/toolkit.rb +5 -1
  20. data/lib/ruby_mvc/toolkit/browser_history.rb +115 -0
  21. data/lib/ruby_mvc/toolkit/dialog.rb +12 -1
  22. data/lib/ruby_mvc/toolkit/frame.rb +3 -1
  23. data/lib/ruby_mvc/toolkit/grid_view.rb +46 -0
  24. data/lib/ruby_mvc/toolkit/messagebox.rb +32 -0
  25. data/lib/ruby_mvc/toolkit/peers/wxruby.rb +5 -0
  26. data/lib/ruby_mvc/toolkit/peers/wxruby/app.rb +23 -2
  27. data/lib/ruby_mvc/toolkit/peers/wxruby/common.rb +11 -1
  28. data/lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb +82 -0
  29. data/lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb +108 -0
  30. data/lib/ruby_mvc/toolkit/peers/wxruby/frame.rb +85 -1
  31. data/lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb +79 -0
  32. data/lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb +117 -0
  33. data/lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb +58 -0
  34. data/lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb +40 -10
  35. data/lib/ruby_mvc/toolkit/property_change_notifier.rb +46 -0
  36. data/lib/ruby_mvc/toolkit/signal_handler.rb +149 -0
  37. data/lib/ruby_mvc/toolkit/web_view.rb +1 -1
  38. data/lib/ruby_mvc/toolkit/widget.rb +13 -6
  39. data/lib/ruby_mvc/views.rb +8 -59
  40. data/lib/ruby_mvc/views/{ar_type_list.rb → ar_form_view.rb} +10 -13
  41. data/lib/ruby_mvc/views/ar_support.rb +29 -0
  42. data/lib/ruby_mvc/views/ar_type_editor.rb +17 -28
  43. data/lib/ruby_mvc/views/ar_web_model_view.rb +59 -0
  44. data/lib/ruby_mvc/views/ar_web_type_list.rb +44 -0
  45. data/lib/ruby_mvc/views/browser_view.rb +185 -0
  46. data/lib/ruby_mvc/views/form_view.rb +111 -0
  47. data/lib/ruby_mvc/views/grid_table_view.rb +96 -0
  48. data/lib/ruby_mvc/views/table_view.rb +0 -39
  49. data/lib/ruby_mvc/views/view.rb +121 -0
  50. data/lib/ruby_mvc/views/web_content_table_view.rb +40 -0
  51. data/lib/ruby_mvc/views/{web_view.rb → web_content_view.rb} +17 -28
  52. data/lib/ruby_mvc/views/web_model_view.rb +67 -0
  53. data/ruby_mvc.gemspec +1 -1
  54. data/sample/browser_view.rb +57 -0
  55. data/sample/form.rb +59 -0
  56. data/sample/form2.rb +63 -0
  57. data/sample/grid_table_view.rb +68 -0
  58. data/sample/grid_view.rb +44 -0
  59. data/sample/grid_view2.rb +57 -0
  60. data/sample/test.html +1 -0
  61. data/sample/test2.html +33 -0
  62. data/sample/web_view.rb +4 -0
  63. data/test/unit/models/test_array_table_model.rb +19 -3
  64. data/test/unit/models/test_keyed_array_table_model.rb +3 -2
  65. data/test/unit/models/test_model.rb +88 -0
  66. metadata +39 -20
  67. data/lib/ruby_mvc/toolkit/notification.rb +0 -202
  68. data/lib/ruby_mvc/views/ar_model_editor.rb +0 -84
@@ -0,0 +1,29 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: ar_support.rb
21
+ # Created: Mon 12 Dec 2011 06:49:00 CST
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ require 'ruby_mvc/views/ar_form_view'
27
+ require 'ruby_mvc/views/ar_type_editor'
28
+ require 'ruby_mvc/views/ar_web_type_list'
29
+ require 'ruby_mvc/views/ar_web_model_view'
@@ -26,36 +26,25 @@
26
26
  module RubyMVC
27
27
  module Views
28
28
 
29
- class ActiveRecordTypeEditor < View
30
- include RubyMVC::LinkDispatcher
31
-
32
- def initialize(type, options = {}, &block)
33
- ctrl = options[:controller] = options[:controller] || self
34
- super(options, &block)
35
- @type = type
36
- @list = active_record_type_list type
37
- para link("New...") {
38
- ctrl.link_activated(self, "/create_instance")
39
- }
40
- end
41
-
42
- def create_instance(sender, link)
43
- debug("create instance of type #{@type}")
44
- obj = @type.new
45
- window do
46
- stack do
47
- obj.description = "Some text"
48
- editor = active_record_model_editor obj
49
- flow :margin_left => 0, :left => "-25%" do
50
- button "Cancel", :align => "right" do
51
- close
52
- end
53
- button "Save", :align => "right" do
54
- editor.save
55
- close
29
+ class ActiveRecordTypeEditor < GridTableView
30
+ def initialize(app, parent, entity_type, options = {}, &block)
31
+ options[:editable] = false
32
+ options[:show_row_labels] = false
33
+ @model = Models::ActiveRecordTableModel.new(entity_type)
34
+ @template = options[:template]
35
+ super((@template ? @template.apply(@model) : @model), options)
36
+ signal_connect("row-edit") do |s, m, i, r|
37
+ app.dialog(:title => options[:editor_title], :parent => parent) do |dlg|
38
+ form = FormView.new((@template ? @template.apply(r) : r), &block)
39
+ form.signal_connect("form-submit") do |form, d|
40
+ begin
41
+ r.save!
42
+ m.update_row(i, r)
43
+ rescue ActiveRecord::RecordInvalid => e
44
+ app.error(e, :title => "Validation Error", :parent => dlg)
56
45
  end
57
- debug("created buttons")
58
46
  end
47
+ dlg.add form
59
48
  end
60
49
  end
61
50
  end
@@ -0,0 +1,59 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011-2012 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: ar_web_model_view.rb
21
+ # Created: Mon 9 Jan 2012 22:45:05 GMT
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Views
28
+
29
+ class ActiveRecordWebModelView < WebModelView
30
+ signal "row-edit"
31
+ signal "row-delete", :vetoable => true
32
+
33
+ def initialize(row, options = {})
34
+ super
35
+
36
+ action(:edit, :label => "Edit", :icon => :stock_edit) do
37
+ signal_emit("row-edit", self, row)
38
+ end
39
+
40
+ # action(:delete, :label => "Delete", :icon => :stock_delete) do
41
+ # signal_emit("row-delete", self, row)
42
+ # end
43
+ end
44
+
45
+ def render
46
+ html = super
47
+ tagz {
48
+ tagz.concat html
49
+ tagz.concat render_links
50
+ }
51
+ end
52
+
53
+ protected
54
+ def render_links
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,44 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011-2012 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: ar_web_type_list.rb
21
+ # Created: Mon 9 Jan 2012 15:56:18 GMT
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Views
28
+
29
+ class ActiveRecordWebTypeList < WebContentTableView
30
+ def initialize(entity_type, options = {}, &block)
31
+ @model = Models::ActiveRecordTableModel.new(entity_type)
32
+ if options.is_a? Hash
33
+ @template = options[:template]
34
+ else
35
+ @template = options
36
+ options = {}
37
+ end
38
+ super((@template ? @template.apply(@model) : @model), options)
39
+ action(:edit, :label => "Edit", :icon => :stock_edit, &block)
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,185 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: browser_view.rb
21
+ # Created: Mon 2 Jan 2012 22:44:26 CET
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Views
28
+
29
+ # This class is slightly different at the moment as it
30
+ # really should have a HypermediaContentModel instance that
31
+ # feeds it vs. being explicitly driven by the client. This
32
+ # should be addressed better in a future version.
33
+
34
+ class BrowserView < PeerView
35
+ widget Toolkit::WebView
36
+
37
+ def initialize(options = {}, &block)
38
+ super
39
+
40
+ class << action(:back,
41
+ :label => "Back", :icon => :stock_back, :widget => widget) do
42
+ go_back
43
+ end
44
+
45
+ def sensitive
46
+ x = @options[:widget].can_go_back?
47
+ property_changed(:sensitive, @sensitive, x)
48
+ @sensitive = x
49
+ end
50
+ end
51
+
52
+ class << action(:forward,
53
+ :label => "Forward", :icon => :stock_forward, :widget => widget) do
54
+ go_forward
55
+ end
56
+
57
+ def sensitive
58
+ x = @options[:widget].can_go_forward?
59
+ property_changed(:sensitive, @sensitive, x)
60
+ @sensitive = x
61
+ end
62
+ end
63
+
64
+ class << action(:reload,
65
+ :label => "Reload", :icon => :stock_reload, :widget => widget) do
66
+ reload
67
+ end
68
+
69
+ def sensitive
70
+ w = @options[:widget]
71
+ x = (!w.location.nil? && "" != w.location)
72
+ property_changed(:sensitive, @sensitive, x)
73
+ @sensitive = x
74
+ end
75
+ end
76
+
77
+ widget.signal_connect("load-finished") do
78
+ # puts "load-finished #{widget.location}"
79
+ # FIXME: this is a hack, but it's the only way for now
80
+ @actions.each { |a| a.selection(self, nil, nil); a.sensitive }
81
+ # puts "back? #{widget.can_go_back?}"
82
+ # puts "forward? #{widget.can_go_forward?}"
83
+ end
84
+
85
+ widget.signal_connect("navigation-requested") do |s, h, t|
86
+ puts "BrowserView#navigation-requested: #{h}"
87
+ if (c = self.controller)
88
+ puts "forwarding to controller: #{c}"
89
+ c.link_activated(s, h)
90
+ end
91
+ end
92
+ end
93
+
94
+ def go_forward
95
+ reset_actions
96
+ widget.go_forward
97
+ append_actions((location || {})[:actions])
98
+ end
99
+
100
+ def go_back
101
+ reset_actions
102
+ widget.go_back
103
+ append_actions((location || {})[:actions])
104
+ end
105
+
106
+ def open(uri)
107
+ reset_actions
108
+ widget.open(uri)
109
+ end
110
+
111
+ def load_html(*args)
112
+ reset_actions
113
+ # puts "#load_html: " << args.inspect
114
+ widget.load_html(*args)
115
+ end
116
+
117
+ def reload
118
+ if location && v = location[:view]
119
+ load(v, location[:uri])
120
+ else
121
+ super
122
+ end
123
+ end
124
+
125
+ def append_html(*args, &block)
126
+ widget.append_html(*args, &block)
127
+ end
128
+
129
+ def load(view, uri = nil)
130
+ if !view.is_a? WebContentView
131
+ raise ArgumentError, "view must currently be a WebContentView instance"
132
+ end
133
+
134
+ # FIXME: need action support in the history management
135
+ # too so that actions are appropriately added/removed
136
+ # during forward/backward navigation requests
137
+
138
+ load_html(view.render, uri || view.uri)
139
+ widget.location[:view] = view
140
+
141
+ # If our view provides a different controller, then we
142
+ # need to defer link handling to that controller instead
143
+ # of ours (which probably wasn't defined in the first
144
+ # place)
145
+
146
+ if (vc = view.controller) && vc != self.controller
147
+ puts "assigned new controller from WebContentView: #{vc}"
148
+ self.controller = vc
149
+ else
150
+ puts "no controller defined for #{view}"
151
+ end
152
+
153
+ # add any content actions
154
+ append_actions(view.actions)
155
+ end
156
+
157
+ def add(view)
158
+ if !view.is_a? WebContentView
159
+ raise ArgumentError, "view must currently be a WebContentView instance"
160
+ end
161
+
162
+ append_html(view.render)
163
+
164
+ # FIXME: this should really be done, but we need to be a bit
165
+ # more sophisticated in the way we manage it
166
+ # append_actions(view.actions)
167
+ end
168
+
169
+ private
170
+ def append_actions(actions)
171
+ return if !actions
172
+
173
+ location[:actions] = actions if location
174
+ frame.merge_actions(actions)
175
+ end
176
+
177
+ def reset_actions
178
+ if location && (ca = location[:actions])
179
+ frame.unmerge_actions(ca)
180
+ end
181
+ end
182
+ end
183
+
184
+ end
185
+ end
@@ -0,0 +1,111 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: form_view.rb
21
+ # Created: Fri 30 Dec 2011 14:48:46 CET
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Views
28
+
29
+ # FormView instances are an abstract representation of a
30
+ # form-based editor for model instances. It is deliberately
31
+ # modelled on HTML forms where possible.
32
+
33
+ class FormView < View
34
+ # This signal is emitted by the hosting widget when the
35
+ # form has been submitted. The block is passed arguments
36
+ # for the form and the model (or model proxy) being used.
37
+
38
+ signal "form-submit", :vetoable => true
39
+
40
+ # This signal is emitted by the hosting widget when the
41
+ # form has been reset.
42
+
43
+ signal "form-reset"
44
+
45
+ def initialize(model, &block)
46
+ @model = model
47
+ @editors = {}
48
+ @validators = {}
49
+ @disabled = {}
50
+ self.instance_eval(&block) if block
51
+ end
52
+
53
+ def editor(key, editor)
54
+ @editors[key.to_sym] = editor
55
+ end
56
+
57
+ # This method sets a validator block for the given key.
58
+ # More than one validator can be initialized for each
59
+ # property key
60
+
61
+ def validator(key, &block)
62
+ return if !block
63
+ vals = (@validators[key.to_sym] ||= [])
64
+ vals << block
65
+ end
66
+
67
+ # This method is used to ensure that the specified model
68
+ # key field appears, but is disabled. This can also be
69
+ # done via the model by ensuring editable is false.
70
+
71
+ def disabled(key, val = true)
72
+ @disabled[key.to_sym] = val
73
+ end
74
+
75
+ # This method is used by the concrete hosting widget to
76
+ # iterate through the form field definitions so that it
77
+ # can create the actual UI form.
78
+
79
+ def layout(&block)
80
+ @model.labels.each do |l|
81
+ k = l[:key]
82
+ if (@disabled.has_key?(k) && @disabled[k]) \
83
+ || !@model.is_editable?(k)
84
+ disabled = true
85
+ else
86
+ disabled = false
87
+ end
88
+ block.call(k, l[:label], @model[k], @editors[k] || l[:editor], disabled)
89
+ end
90
+ end
91
+
92
+ # This method is called when the form should be saved to
93
+ # the underlying model.
94
+
95
+ def submit(values)
96
+ values.each do |k, v|
97
+ @model[k] = v if @model.is_editable? k
98
+ end
99
+ signal_emit("form-submit", self, @model)
100
+ end
101
+
102
+ def reset(&block)
103
+ @model.keys.each do |k|
104
+ block.call(k, @model[k])
105
+ end
106
+ signal_emit("form-reset", self, @model)
107
+ end
108
+ end
109
+
110
+ end
111
+ end