ruby_mvc 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
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 'active_record'
27
+
28
+ require 'ruby_mvc/models/ar_row_model'
29
+ require 'ruby_mvc/models/ar_table_model'
30
+ require 'ruby_mvc/views/ar_form_view'
31
+ require 'ruby_mvc/views/ar_type_editor'
32
+ require 'ruby_mvc/views/ar_web_type_list'
33
+ require 'ruby_mvc/views/ar_web_model_view'
34
+
35
+ module RubyMVC
36
+
37
+ class ActiveRecordModelRegistry < Hash
38
+ def model(etk, options = {})
39
+ key = etk
40
+ key = etk.to_s.to_sym if !etk.is_a? Symbol
41
+ if has_key? key
42
+ self[key]
43
+ else
44
+ self[key] = Models::ActiveRecordTableModel.new(etk, options)
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.model(*args, &block)
50
+ @ar_models ||= ActiveRecordModelRegistry.new
51
+ @ar_models.model(etk, options)
52
+ end
53
+
54
+ class ActiveRecordTemplateRegistry < Hash
55
+ def template(etk, title = nil, options = {}, &block)
56
+ if title.is_a? Hash
57
+ options = title
58
+ title = options[:title]
59
+ end
60
+ key = etk
61
+ key = etk.to_s.to_sym if !etk.is_a? Symbol
62
+ if block
63
+ obj = Models::ViewModelTemplate.new(options, &block)
64
+ obj.title = title || etk.to_s
65
+ self[key] = obj
66
+ else
67
+ self[key]
68
+ end
69
+ end
70
+ end
71
+
72
+ def self.template(*args, &block)
73
+ @ar_templates ||= ActiveRecordTemplateRegistry.new
74
+ @ar_templates.template(*args, &block)
75
+ end
76
+
77
+ def template(*args, &block)
78
+ RubyMVC.template(*args, &block)
79
+ end
80
+
81
+ def model(*args, &block)
82
+ RubyMVC.model(*args, &block)
83
+ end
84
+ end
@@ -25,4 +25,5 @@
25
25
 
26
26
  require 'ruby_mvc/controllers/action'
27
27
  require 'ruby_mvc/controllers/action_group'
28
+ require 'ruby_mvc/controllers/action_provider'
28
29
  require 'ruby_mvc/controllers/app_controller'
@@ -1,7 +1,7 @@
1
1
  #--
2
2
  ######################################################################
3
3
  #
4
- # Copyright 2011 Andrew S. Townley
4
+ # Copyright 2011-2012 Andrew S. Townley
5
5
  #
6
6
  # Permission to use, copy, modify, and disribute this software for
7
7
  # any purpose with or without fee is hereby granted, provided that
@@ -17,13 +17,27 @@
17
17
  # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
18
  # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
19
  #
20
- # File: ar_support.rb
21
- # Created: Mon 12 Dec 2011 06:49:00 CST
20
+ # File: action_provider.rb
21
+ # Created: Sat 14 Jan 2012 13:16:53 GMT
22
22
  #
23
23
  #####################################################################
24
24
  #++
25
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
+ module RubyMVC
27
+
28
+ # This module is used to provide actions to toolkit widget
29
+ # implementations for appropriate rendering based on the
30
+ # widget type.
31
+
32
+ module ActionProvider
33
+ attr_reader :actions
34
+
35
+ def action(key, options = {}, &block)
36
+ @actions ||= ActionGroup.new
37
+ a = Action.new(key, options, &block)
38
+ @actions << a
39
+ a
40
+ end
41
+ end
42
+
43
+ end
@@ -42,7 +42,16 @@ module RubyMVC
42
42
  def link_activated(sender, link)
43
43
  puts "#link_activated(#{sender}, #{link})"
44
44
  uri = URI.parse(link)
45
- params = CGI.parse(uri.query) if uri.query
45
+
46
+ if uri.query
47
+ params = CGI.parse(uri.query)
48
+ params.each do |k, v|
49
+ if v && v.size == 1
50
+ params[k] = v.first
51
+ end
52
+ end
53
+ end
54
+
46
55
  m = RubyMVC.method_name(uri.path).to_sym
47
56
  if self.respond_to? m
48
57
  self.send(m, sender, link, params)
@@ -23,9 +23,7 @@
23
23
  #####################################################################
24
24
  #++
25
25
 
26
- require 'active_record'
27
- require 'ruby_mvc/models/ar_table_model'
28
- require 'ruby_mvc/views/ar_support'
26
+ require 'ruby_mvc/ar_support'
29
27
 
30
28
  module RubyMVC
31
29
 
@@ -0,0 +1,62 @@
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_row_model.rb
21
+ # Created: Thu 12 Jan 2012 16:47:20 GMT
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Models
28
+
29
+ # This class provides a Model adapter implementation for
30
+ # ActiveRecordBase class instances.
31
+
32
+ class ActiveRecordRowModel < Model
33
+ def initialize(row, options = {})
34
+ options[:data] = row
35
+ super(options)
36
+ end
37
+
38
+ def entity_type
39
+ @data.class
40
+ end
41
+
42
+ def keys
43
+ @data.attributes.keys.collect { |k| k.to_sym }
44
+ end
45
+
46
+ # This method provides information about inter-model links
47
+ # to provide built-in support for master-detail types of
48
+ # relationships between models.
49
+
50
+ def link_labels
51
+ # FIXME: should probably implement this intelligently to
52
+ # do some introspection magic
53
+ {}
54
+ end
55
+
56
+ def size
57
+ @data.attributes.keys.size
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -33,7 +33,7 @@ module Models
33
33
  # the rows matching a particular query.
34
34
 
35
35
  class ActiveRecordTableModel < TableModel
36
- attr_reader :keys
36
+ attr_reader :keys, :entity_type
37
37
 
38
38
  def initialize(entity_type, options = {})
39
39
  super()
@@ -118,18 +118,18 @@ module Models
118
118
  end
119
119
 
120
120
  def size
121
- puts "idx.size: #{@row_idx.size}"
121
+ # puts "idx.size: #{@row_idx.size}"
122
122
  [_rows.count, @row_idx.size].max
123
123
  end
124
124
 
125
125
  protected
126
126
  def _rows
127
- if @filter
127
+ if @filter && !@rows
128
128
  x = @entity_type.where(@filter)
129
129
  else
130
130
  x = @rows || @entity_type.find(:all)
131
131
  end
132
- puts "working with #{x.count} rows"
132
+ # puts "working with #{x.count} rows"
133
133
  x
134
134
  end
135
135
  end
@@ -79,6 +79,14 @@ module Models
79
79
  end
80
80
  end
81
81
 
82
+ # This method provides information about inter-model links
83
+ # to provide built-in support for master-detail types of
84
+ # relationships between models.
85
+
86
+ def link_labels
87
+ {}
88
+ end
89
+
82
90
  # This method is used to check whether a property key is
83
91
  # editable or not
84
92
 
@@ -43,6 +43,8 @@ module Models
43
43
  # may be accessed.
44
44
 
45
45
  class ViewModelTemplate
46
+ include ActionProvider
47
+
46
48
  attr_accessor :title
47
49
 
48
50
  # When the ViewModelTemplate is initialized, it requires a set
@@ -52,8 +54,10 @@ module Models
52
54
  def initialize(options = {}, &block)
53
55
  @options = options
54
56
  @labels = []
57
+ @link_labels = []
55
58
  @options[:editable] ||= {}
56
59
  @options[:properties] ||= []
60
+ @options[:links] ||= []
57
61
  self.instance_eval(&block) if block
58
62
  end
59
63
 
@@ -68,6 +72,10 @@ module Models
68
72
  @labels
69
73
  end
70
74
 
75
+ def link_labels
76
+ @link_labels
77
+ end
78
+
71
79
  # Implement the Model#is_editable? method in terms of the
72
80
  # template definition. If the template doesn't further
73
81
  # restrict the behavior, the model's definition is used
@@ -94,7 +102,7 @@ module Models
94
102
  # through the view.
95
103
 
96
104
  def property(key, options = {})
97
- puts "options: #{options.inspect}"
105
+ # puts "options: #{options.inspect}"
98
106
  key = key.to_sym
99
107
 
100
108
  if false == options[:show]
@@ -117,6 +125,32 @@ module Models
117
125
  end
118
126
  end
119
127
 
128
+ # This method is used to declare a linked property for the
129
+ # model and make it available to the view
130
+
131
+ def link(key, options = {})
132
+ key = key.to_sym
133
+
134
+ if false == options[:show]
135
+ show = false
136
+ else
137
+ show = true
138
+ end
139
+
140
+ editable(key, false) if false == options[:editable]
141
+
142
+ if show && !@options[:links].include?(key)
143
+ @options[:links] << key
144
+ l = options[:alias] || key.to_s.capitalize
145
+ @link_labels << options.merge({ :key => key, :label => l })
146
+ elsif !show
147
+ @options[:links].delete(key)
148
+ @link_labels.delete_if do |k|
149
+ k[:key] == key
150
+ end
151
+ end
152
+ end
153
+
120
154
  # This method is used to apply the template to a specific,
121
155
  # concrete model instance, creating a clone of the
122
156
  # template in the process so that multiple different
@@ -33,11 +33,13 @@ module RubyMVC
33
33
 
34
34
  def render(widget, row, col)
35
35
  lk = col[:hl_label_key] || col[:key]
36
+ # puts "LK: #{lk.inspect}; row: #{row.inspect}"
36
37
  text = row[lk]
37
- val = row[col[:key]]
38
+ href = col[:href]
39
+ val = row[col[:href_key] || col[:key]]
38
40
  tagz {
39
- td_ {
40
- a_ text, :href => "#{col[:href]}#{val}"
41
+ td_(:valign => "top") {
42
+ a_ text, :href => "#{href}#{val}"
41
43
  }
42
44
  }
43
45
  end
@@ -27,6 +27,14 @@ module RubyMVC
27
27
  module Toolkit
28
28
 
29
29
  class Dialog < Widget
30
+ # this signal is triggered after the dialog has been
31
+ # processed modally and will return one of a range of
32
+ # response codes, depending on the type of the dialog.
33
+ #
34
+ # The standard response codes are :accept or :cancel
35
+
36
+ signal "response"
37
+
30
38
  def add(w)
31
39
  # FIXME: this is a cheezy way to do this...
32
40
  if w.is_a? RubyMVC::Views::FormView
@@ -27,6 +27,7 @@ module RubyMVC
27
27
  module Toolkit
28
28
  module WxRuby
29
29
  class Dialog < Wx::Dialog
30
+ include SignalHandler
30
31
  include Common
31
32
  Toolkit::Dialog.peer_class = self
32
33
 
@@ -64,12 +65,26 @@ module RubyMVC
64
65
  self.sizer.fit(self)
65
66
  end
66
67
 
68
+ def add_view(view)
69
+ sizer = Wx::BoxSizer.new(Wx::VERTICAL)
70
+ view.peer.reparent(self)
71
+ sizer.add(view.peer, 1, Wx::EXPAND|Wx::ALL, 5)
72
+ sizer.add(@buttons, 0, Wx::ALIGN_RIGHT|Wx::ALL, 5)
73
+ self.sizer = sizer
74
+ layout
75
+ end
76
+
67
77
  def show
68
78
  self.centre
69
79
  if @modal
70
- if Wx::ID_OK == self.show_modal()
80
+ case self.show_modal()
81
+ when Wx::ID_OK, Wx::ID_YES
71
82
  @wxform.submit if @wxform
83
+ resp = :accept
84
+ else
85
+ resp = :cancel
72
86
  end
87
+ signal_emit("response", self, resp)
73
88
  else
74
89
  sel.show()
75
90
  end
@@ -51,7 +51,7 @@ module RubyMVC
51
51
  def build(parent, form)
52
52
  @form = form
53
53
  form.layout do |key, label, val, editor, disabled|
54
- puts "key: #{key}; disabled: #{disabled}"
54
+ # puts "key: #{key}; disabled: #{disabled}"
55
55
  case(editor)
56
56
  when :textarea
57
57
  w = build_textfield(parent, label, val, true)
@@ -32,7 +32,7 @@ module RubyMVC
32
32
  Toolkit::GridView.peer_class = self
33
33
 
34
34
  def initialize(options = {})
35
- puts "options: #{options.inspect}"
35
+ # puts "options: #{options.inspect}"
36
36
  super(WxRuby.parent(options), options[:id] || -1)
37
37
  if false == options[:show_row_labels]
38
38
  set_row_label_size(0)
@@ -58,7 +58,13 @@ module RubyMVC
58
58
  # puts "Event alt: #{e.alt_down}; ctrl: #{e.control_down}; brc: #{e.get_bottom_right_coords}; bottom: #{e.get_bottom_row}; left: #{e.get_left_col}; right: #{e.get_right_col}; tlc: #{e.get_top_left_coords}; top: #{e.get_top_row}; meta: #{e.meta_down}; selecting: #{e.selecting}; shift: #{e.shift_down}"
59
59
  top = e.get_top_row
60
60
  bottom = e.get_bottom_row
61
- sel = []
61
+ if e.meta_down || e.shift_down
62
+ # extending the selection
63
+ sel = @selected_rows.clone
64
+ else
65
+ # reset the selection
66
+ sel = []
67
+ end
62
68
  top.upto(bottom) do |i|
63
69
  sel << i
64
70
  end
@@ -80,18 +86,18 @@ module RubyMVC
80
86
  # Grid displaying it. Kinda defeats the point...
81
87
 
82
88
  @model.signal_connect("rows-inserted") do |s, i, r|
83
- puts "refresh rows-inserted"
89
+ # puts "refresh rows-inserted"
84
90
  @gm = GridModel.new(model)
85
91
  set_table(@gm, Wx::Grid::GridSelectRows, false)
86
92
  end
87
93
  @model.signal_connect("rows-removed") do |s, i, r|
88
- puts "refresh rows-removed"
94
+ # puts "refresh rows-removed"
89
95
  @gm = GridModel.new(model)
90
96
  selected_rows.delete(i)
91
97
  set_table(@gm, Wx::Grid::GridSelectRows, false)
92
98
  end
93
99
  @model.signal_connect("row-changed") do |s, i, r|
94
- puts "refresh row-changed"
100
+ # puts "refresh row-changed"
95
101
  @gm = GridModel.new(model)
96
102
  set_table(@gm, Wx::Grid::GridSelectRows, false)
97
103
  end
@@ -111,6 +111,7 @@ module RubyMVC
111
111
 
112
112
  protected
113
113
  def load_entry(entry)
114
+ # puts "ENTRY: #{entry.inspect}"
114
115
  if html = entry[:content]
115
116
  set_page(html)
116
117
  else
@@ -137,11 +137,21 @@ module Toolkit
137
137
  end
138
138
 
139
139
  def signal_emit(signal, *args)
140
+ # FIXME: there's a few things wrong with this now that
141
+ # we've changed to support multiple signal handlers.
142
+ # Registration/deregistration should be cleaner, but
143
+ # then we'd be using an observer pattern vs the signal
144
+ # handler. Anyway, with multiple registered handlers,
145
+ # if the signal is vetoable, then it should throw a veto
146
+ # exception or something.
147
+
140
148
  self.class.valid_signal! signal if self.class.respond_to? :signals
141
149
  signals = (@signals ||= {})
150
+ rval = nil
142
151
  (signals[signal] ||= []).each do |proc|
143
- proc.call(*args) if !proc.nil?
152
+ (rval = proc.call(*args)) if !proc.nil?
144
153
  end
154
+ rval
145
155
  end
146
156
  end
147
157
 
@@ -103,7 +103,7 @@ module RubyMVC
103
103
 
104
104
  def connect_peer_signals
105
105
  self.class.signals.each do |s, opts|
106
- puts "connecting signal '#{peer}##{s}' to #{self}"
106
+ # puts "connecting signal '#{peer}##{s}' to #{self}"
107
107
  peer.signal_connect(s) do |*args|
108
108
  args[0] = self
109
109
  signal_emit(s, *args)
@@ -35,7 +35,8 @@ module Views
35
35
  super((@template ? @template.apply(@model) : @model), options)
36
36
  signal_connect("row-edit") do |s, m, i, r|
37
37
  app.dialog(:title => options[:editor_title], :parent => parent) do |dlg|
38
- form = FormView.new((@template ? @template.apply(r) : r), &block)
38
+ fm = (@template ? @template.apply(r) : Models::ActiveRecordRowModel.new(r))
39
+ form = FormView.new(fm, &block)
39
40
  form.signal_connect("form-submit") do |form, d|
40
41
  begin
41
42
  r.save!
@@ -27,9 +27,24 @@ module RubyMVC
27
27
  module Views
28
28
 
29
29
  class ActiveRecordWebModelView < WebModelView
30
+ signal "add-child"
31
+ signal "add-child-link"
30
32
  signal "row-edit"
31
33
  signal "row-delete", :vetoable => true
32
34
 
35
+ # This signal is triggered when the view needs to render
36
+ # an action link for one of the linked models. Currently
37
+ # supported command keys are:
38
+ #
39
+ # - :link_edit - return a hash with the href to edit the
40
+ # link entries
41
+ #
42
+ # In each case, the arguments sent are the view, the
43
+ # command key, the model and the label entry being
44
+ # rendered.
45
+
46
+ signal "action-link"
47
+
33
48
  def initialize(row, options = {})
34
49
  super
35
50
 
@@ -40,18 +55,137 @@ module Views
40
55
  # action(:delete, :label => "Delete", :icon => :stock_delete) do
41
56
  # signal_emit("row-delete", self, row)
42
57
  # end
58
+
59
+ begin
60
+ if @model.children
61
+ action(:add_child, :label => "Add Child", :icon => :stock_new) do
62
+ signal_emit("add-child", self, row)
63
+ end
64
+
65
+ action(:add_child_link, :label => "Add Child Link", :icon => :stock_new) do
66
+ signal_emit("add-child-link", self, row)
67
+ end
68
+ end
69
+ rescue NoMethodError
70
+ # we ignore this on purpose
71
+ end
43
72
  end
44
73
 
45
74
  def render
46
- html = super
75
+ # FIXME: this isn't the way to properly test for
76
+ # ancestry, but we need it right now. Needs to have a
77
+ # review/revisit of the way things are nested. It's
78
+ # evolving a little organically at the moment
79
+ # (2012-01-12: ast)
80
+
47
81
  tagz {
48
- tagz.concat html
49
- tagz.concat render_links
82
+ render_parent
83
+ super
84
+ render_links
50
85
  }
51
86
  end
52
87
 
53
88
  protected
89
+ def render_parent
90
+ # FIXME: this is really screwed up and shouldn't really
91
+ # work this way
92
+ # puts "#render_ancestry"
93
+ begin
94
+ @model.reload
95
+ kidz = @model.subtree[1..-1]
96
+ # puts "Ancestors: " << kidz.inspect
97
+ tagz {
98
+ if cmd = signal_emit("action-link", self, :parent_edit, @model, {})
99
+ cmd2 = signal_emit("action-link", self, :unparent, @model, {})
100
+ h3_("Parent ") {
101
+ font_(:size => "2") {
102
+ a_ cmd.delete(:text), cmd
103
+ tagz.push " "
104
+ a_ cmd2.delete(:text), cmd2 if cmd2
105
+ }
106
+ }
107
+ end
108
+ if parent = @model.parent
109
+ # puts "parent: #{parent.inspect}"
110
+ et = parent.class
111
+ pm = Models::ActiveRecordTableModel.new(et, :rows => [ parent ])
112
+ if tmpl = RubyMVC.template(et)
113
+ pm = tmpl.apply(pm)
114
+ end
115
+ tagz.push WebContentTableView.new(pm).render
116
+ end
117
+ }
118
+ rescue NoMethodError => e
119
+ puts "warning: #{e}"
120
+ # puts e.backtrace
121
+ end
122
+ end
123
+
54
124
  def render_links
125
+ # puts "#render_links"
126
+
127
+ tagz {
128
+ # render children first
129
+ render_children
130
+
131
+ return if @model.link_labels.size == 0
132
+
133
+ # render other links
134
+ @model.link_labels.each do |l|
135
+ links = @model.send(l[:key], true)
136
+ edits = []
137
+ cmds = [ :linked_edit ]
138
+ if l.has_key? :link_entity
139
+ cmds.insert(0, :add_link)
140
+ cmds.insert(0, :add_linked)
141
+ cmds << :link_edit
142
+ end
143
+
144
+ cmds.each do |cmd|
145
+ edits << signal_emit("action-link", self, cmd, @model, l)
146
+ end
147
+ let = l[:entity_type]
148
+ h3_("#{let} links (#{links.size})") {
149
+ if edits.size > 0
150
+ font_(:size => "2") {
151
+ edits.each do |cmd|
152
+ tagz.push " "
153
+ a_ cmd.delete(:text), cmd
154
+ end
155
+ }
156
+ end
157
+ }
158
+ if links.size > 0
159
+ lm = Models::ActiveRecordTableModel.new(let, :rows => links)
160
+ if tmpl = RubyMVC.template(let)
161
+ lm = tmpl.apply(lm)
162
+ end
163
+ tagz.push WebContentTableView.new(lm).render
164
+ end
165
+ end
166
+ }
167
+ end
168
+
169
+ def render_children
170
+ begin
171
+ # puts "MODEL HAS CHILDREN? #{@model.has_children?}: #{@model.inspect}"
172
+ if @model.has_children?
173
+ kidz = @model.children
174
+ # puts "Children: " << kidz.inspect
175
+ et = kidz.first.class
176
+ km = Models::ActiveRecordTableModel.new(et, :rows => kidz)
177
+ if tmpl = RubyMVC.template(et)
178
+ km = tmpl.apply(km)
179
+ end
180
+ tagz {
181
+ h3_("Child #{et.to_s.pluralize}")
182
+ tagz.push WebContentTableView.new(km).render
183
+ }
184
+ end
185
+ rescue NoMethodError => e
186
+ puts "warning: #{e}"
187
+ # puts e.backtrace
188
+ end
55
189
  end
56
190
  end
57
191
 
@@ -27,6 +27,8 @@ module RubyMVC
27
27
  module Views
28
28
 
29
29
  class ActiveRecordWebTypeList < WebContentTableView
30
+ signal "add-row"
31
+
30
32
  def initialize(entity_type, options = {}, &block)
31
33
  @model = Models::ActiveRecordTableModel.new(entity_type, options)
32
34
  if options.is_a? Hash
@@ -36,7 +38,12 @@ module Views
36
38
  options = {}
37
39
  end
38
40
  super((@template ? @template.apply(@model) : @model), options)
39
- action(:edit, :label => "Edit", :icon => :stock_edit, &block)
41
+
42
+ action(:add, :label => "Add #{entity_type}", :icon => :stock_new) do
43
+ signal_emit("add-row", self, entity_type)
44
+ end
45
+
46
+ action(:edit, :label => "Edit", :icon => :stock_edit, &block)
40
47
  end
41
48
  end
42
49
 
@@ -85,7 +85,7 @@ module Views
85
85
  widget.signal_connect("navigation-requested") do |s, h, t|
86
86
  puts "BrowserView#navigation-requested: #{h}"
87
87
  if (c = self.controller)
88
- puts "forwarding to controller: #{c}"
88
+ # puts "forwarding to controller: #{c}"
89
89
  c.link_activated(s, h)
90
90
  end
91
91
  end
@@ -115,7 +115,7 @@ module Views
115
115
  end
116
116
 
117
117
  def reload
118
- if location && v = location[:view]
118
+ if location && (v = location[:view])
119
119
  load(v, location[:uri])
120
120
  else
121
121
  super
@@ -144,10 +144,10 @@ module Views
144
144
  # place)
145
145
 
146
146
  if (vc = view.controller) && vc != self.controller
147
- puts "assigned new controller from WebContentView: #{vc}"
147
+ # puts "assigned new controller from WebContentView: #{vc}"
148
148
  self.controller = vc
149
149
  else
150
- puts "no controller defined for #{view}"
150
+ # puts "no controller defined for #{view}"
151
151
  end
152
152
 
153
153
  # add any content actions
@@ -59,7 +59,7 @@ module Views
59
59
  :enable => :select_multi,
60
60
  :icon => :stock_delete
61
61
  ) do
62
- puts "rows: #{widget.selected_rows.inspect}"
62
+ # puts "rows: #{widget.selected_rows.inspect}"
63
63
  widget.selected_rows.reverse_each do |i|
64
64
  model.remove_row(i)
65
65
  end
@@ -76,7 +76,7 @@ module Views
76
76
  end
77
77
 
78
78
  widget.signal_connect("row-selection-changed") do |s, m, rows|
79
- puts "selection changed: #{rows.inspect}"
79
+ # puts "selection changed: #{rows.inspect}"
80
80
  @actions.each do |a|
81
81
  a.selection(s, m, rows)
82
82
  end
@@ -87,8 +87,8 @@ module Views
87
87
  signal_emit("row-edit", self, model, r, row)
88
88
  end
89
89
 
90
- puts "self.class.signals: #{self.class.signals.keys.inspect}"
91
- puts "widget.class.signals: #{widget.class.signals.keys.inspect}"
90
+ # puts "self.class.signals: #{self.class.signals.keys.inspect}"
91
+ # puts "widget.class.signals: #{widget.class.signals.keys.inspect}"
92
92
  end
93
93
  end
94
94
 
@@ -25,23 +25,20 @@
25
25
 
26
26
  module RubyMVC
27
27
  module Views
28
-
28
+
29
29
  class View < RubyMVC::Toolkit::AbstractWidget
30
- attr_reader :actions
30
+ include ActionProvider
31
31
  attr_accessor :controller
32
32
 
33
33
  def initialize(options = {})
34
- @actions = ActionGroup.new
35
34
  @options = options
36
35
  self.controller = options[:controller]
37
36
  (options[:actions] || []).each { |a| @actions << a }
38
37
  end
39
38
 
40
39
  protected
41
- def action(key, options = {}, &block)
42
- a = Action.new(key, options, &block)
43
- @actions << a
44
- a
40
+ def options
41
+ @options
45
42
  end
46
43
  end
47
44
 
@@ -73,7 +70,7 @@ module RubyMVC
73
70
  # widgets.
74
71
 
75
72
  def widget(*args, &block)
76
- puts "Set widget for #{self}: #{args.inspect}"
73
+ # puts "Set widget for #{self}: #{args.inspect}"
77
74
  @widget_def = { :args => args, :block => block }
78
75
  end
79
76
  end
@@ -96,11 +93,11 @@ module RubyMVC
96
93
  # appropriately manage signal registration
97
94
 
98
95
  def signal_connect(signal, &b)
99
- puts "Widget class: #{@widget.class}"
96
+ # puts "Widget class: #{@widget.class}"
100
97
  if @widget.class.valid_signal? signal
101
98
  @widget.signal_connect(signal, &b)
102
99
  else
103
- puts "super"
100
+ # puts "super"
104
101
  super
105
102
  end
106
103
  end
@@ -31,8 +31,13 @@ module Views
31
31
 
32
32
  class WebContentTableView < WebContentView
33
33
  def render
34
+ html = ""
35
+ if t = @options[:title]
36
+ html << "<h2>" << t << "</h2>"
37
+ end
38
+
34
39
  r = @options[:renderer] || Renderers::Html4TableModelRenderer
35
- r.render(@model, @options)
40
+ html << r.render(@model, @options)
36
41
  end
37
42
  end
38
43
 
@@ -30,6 +30,7 @@ module Views
30
30
  include Tagz
31
31
 
32
32
  def initialize(row, options = {})
33
+ @model_type = row.class
33
34
  if options.is_a? Hash
34
35
  @template = options[:template]
35
36
  else
@@ -46,7 +47,8 @@ module Views
46
47
  protected
47
48
  def render_properties
48
49
  tagz {
49
- table_(:border => 0, :cellspacing => 3) {
50
+ h2_(@model_type)
51
+ table_(:border => 1, :cellspacing => 0) {
50
52
  @model.labels.each do |l|
51
53
  k = l[:key]
52
54
  tr_ {
data/ruby_mvc.gemspec CHANGED
@@ -27,7 +27,7 @@ require 'rake'
27
27
 
28
28
  Gem::Specification.new do |s|
29
29
  s.name = "ruby_mvc"
30
- s.version = "0.0.3"
30
+ s.version = "0.0.4"
31
31
  s.summary = "Ruby MVC"
32
32
  s.description = "A simple, cross-platform MVC framework for Ruby"
33
33
  s.authors = [ "Andrew S. Townley" ]
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ruby_mvc
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.3
5
+ version: 0.0.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andrew S. Townley
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-01-10 00:00:00 Z
13
+ date: 2012-01-14 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
16
  description: A simple, cross-platform MVC framework for Ruby
@@ -22,75 +22,77 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - lib/ruby_mvc/application.rb
26
- - lib/ruby_mvc/controllers/action.rb
27
- - lib/ruby_mvc/controllers/action_group.rb
28
- - lib/ruby_mvc/controllers/app_controller.rb
29
- - lib/ruby_mvc/controllers/rails_controller.rb
30
- - lib/ruby_mvc/controllers.rb
31
- - lib/ruby_mvc/models/ar_table_model.rb
32
- - lib/ruby_mvc/models/array_table_model.rb
33
- - lib/ruby_mvc/models/keyed_array_table_model.rb
34
- - lib/ruby_mvc/models/model.rb
35
- - lib/ruby_mvc/models/table_model.rb
36
- - lib/ruby_mvc/models/view_model_template.rb
25
+ - lib/ruby_mvc/views/ar_type_editor.rb
26
+ - lib/ruby_mvc/views/ar_web_type_list.rb
27
+ - lib/ruby_mvc/views/web_content_table_view.rb
28
+ - lib/ruby_mvc/views/ar_web_model_view.rb
29
+ - lib/ruby_mvc/views/web_content_view.rb
30
+ - lib/ruby_mvc/views/table_view.rb
31
+ - lib/ruby_mvc/views/form_view.rb
32
+ - lib/ruby_mvc/views/view.rb
33
+ - lib/ruby_mvc/views/browser_view.rb
34
+ - lib/ruby_mvc/views/web_model_view.rb
35
+ - lib/ruby_mvc/views/grid_table_view.rb
36
+ - lib/ruby_mvc/views/ar_form_view.rb
37
+ - lib/ruby_mvc/wx.rb
38
+ - lib/ruby_mvc/toolkit.rb
37
39
  - lib/ruby_mvc/models.rb
38
- - lib/ruby_mvc/module.rb
39
- - lib/ruby_mvc/renderers/html4_table_model_renderer.rb
40
- - lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb
41
- - lib/ruby_mvc/renderers.rb
42
- - lib/ruby_mvc/toolkit/app.rb
43
- - lib/ruby_mvc/toolkit/browser_history.rb
44
- - lib/ruby_mvc/toolkit/dialog.rb
45
- - lib/ruby_mvc/toolkit/frame.rb
46
- - lib/ruby_mvc/toolkit/grid_view.rb
47
- - lib/ruby_mvc/toolkit/messagebox.rb
48
- - lib/ruby_mvc/toolkit/peers/wxruby/app.rb
49
- - lib/ruby_mvc/toolkit/peers/wxruby/box_layout.rb
50
40
  - lib/ruby_mvc/toolkit/peers/wxruby/common.rb
41
+ - lib/ruby_mvc/toolkit/peers/wxruby/box_layout.rb
42
+ - lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb
51
43
  - lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb
44
+ - lib/ruby_mvc/toolkit/peers/wxruby/app.rb
52
45
  - lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb
53
46
  - lib/ruby_mvc/toolkit/peers/wxruby/frame.rb
54
- - lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb
55
- - lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb
56
- - lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb
57
47
  - lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb
48
+ - lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb
49
+ - lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb
58
50
  - lib/ruby_mvc/toolkit/peers/wxruby.rb
59
- - lib/ruby_mvc/toolkit/property_change_notifier.rb
51
+ - lib/ruby_mvc/toolkit/grid_view.rb
52
+ - lib/ruby_mvc/toolkit/dialog.rb
53
+ - lib/ruby_mvc/toolkit/app.rb
60
54
  - lib/ruby_mvc/toolkit/signal_handler.rb
55
+ - lib/ruby_mvc/toolkit/frame.rb
56
+ - lib/ruby_mvc/toolkit/browser_history.rb
61
57
  - lib/ruby_mvc/toolkit/web_view.rb
58
+ - lib/ruby_mvc/toolkit/messagebox.rb
62
59
  - lib/ruby_mvc/toolkit/widget.rb
63
- - lib/ruby_mvc/toolkit.rb
64
- - lib/ruby_mvc/views/ar_form_view.rb
65
- - lib/ruby_mvc/views/ar_support.rb
66
- - lib/ruby_mvc/views/ar_type_editor.rb
67
- - lib/ruby_mvc/views/ar_web_model_view.rb
68
- - lib/ruby_mvc/views/ar_web_type_list.rb
69
- - lib/ruby_mvc/views/browser_view.rb
70
- - lib/ruby_mvc/views/form_view.rb
71
- - lib/ruby_mvc/views/grid_table_view.rb
72
- - lib/ruby_mvc/views/table_view.rb
73
- - lib/ruby_mvc/views/view.rb
74
- - lib/ruby_mvc/views/web_content_table_view.rb
75
- - lib/ruby_mvc/views/web_content_view.rb
76
- - lib/ruby_mvc/views/web_model_view.rb
60
+ - lib/ruby_mvc/toolkit/property_change_notifier.rb
61
+ - lib/ruby_mvc/controllers/app_controller.rb
62
+ - lib/ruby_mvc/controllers/action_provider.rb
63
+ - lib/ruby_mvc/controllers/action_group.rb
64
+ - lib/ruby_mvc/controllers/action.rb
65
+ - lib/ruby_mvc/controllers/rails_controller.rb
66
+ - lib/ruby_mvc/models/view_model_template.rb
67
+ - lib/ruby_mvc/models/table_model.rb
68
+ - lib/ruby_mvc/models/keyed_array_table_model.rb
69
+ - lib/ruby_mvc/models/model.rb
70
+ - lib/ruby_mvc/models/ar_row_model.rb
71
+ - lib/ruby_mvc/models/ar_table_model.rb
72
+ - lib/ruby_mvc/models/array_table_model.rb
73
+ - lib/ruby_mvc/module.rb
74
+ - lib/ruby_mvc/ar_support.rb
75
+ - lib/ruby_mvc/controllers.rb
76
+ - lib/ruby_mvc/renderers/html4_table_model_renderer.rb
77
+ - lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb
78
+ - lib/ruby_mvc/application.rb
77
79
  - lib/ruby_mvc/views.rb
78
- - lib/ruby_mvc/wx.rb
80
+ - lib/ruby_mvc/renderers.rb
79
81
  - lib/ruby_mvc.rb
80
- - sample/browser_view.rb
81
- - sample/form.rb
82
82
  - sample/form2.rb
83
- - sample/frame.rb
84
- - sample/grid_table_view.rb
83
+ - sample/test2.html
85
84
  - sample/grid_view.rb
86
85
  - sample/grid_view2.rb
86
+ - sample/form.rb
87
+ - sample/frame.rb
88
+ - sample/web_view.rb
87
89
  - sample/mvc.rb
90
+ - sample/browser_view.rb
88
91
  - sample/test.html
89
- - sample/test2.html
90
- - sample/web_view.rb
92
+ - sample/grid_table_view.rb
93
+ - test/unit/models/test_model.rb
91
94
  - test/unit/models/test_array_table_model.rb
92
95
  - test/unit/models/test_keyed_array_table_model.rb
93
- - test/unit/models/test_model.rb
94
96
  - test/unit/test_array_table_model.rb
95
97
  - LICENSE
96
98
  - README.md