ruby_mvc 0.0.1 → 0.0.2

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