ruby_mvc 0.0.3 → 0.0.4

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.
@@ -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