2 This table model allows an ActiveRecord or ActiveResource to be used as a
3 basis for a Qt::AbstractItemModel for viewing in a Qt::TreeView. Example
6 app = Qt::Application.new(ARGV)
7 agencies = TravelAgency.find(:all)
8 model = ActiveItemModel.new(agencies)
9 tree = Qt::TreeView.new
14 Written by Richard Dale and Silvio Fonseca
20 #require "active_record"
21 #require "active_support"
22 #require "active_resource"
27 attr_reader :childItems, :resource, :itemData
29 def initialize(item, keys, parent = nil, prefix="")
34 if @resource.respond_to? :attributes
35 @resource.attributes.inject(@itemData = {}) do |data, a|
36 if a[1].respond_to? :attributes
37 TreeItem.new(a[1], @keys, self, prefix + a[0] + ".")
39 data[prefix + a[0]] = a[1]
48 @parentItem.appendChild(self)
53 @childItems.push(item)
57 return @childItems[row]
61 return @childItems.length
65 return @itemData.length
69 return Qt::Variant.new(@itemData[@keys[column]])
78 return @parentItem.childItems.index(self)
85 class ActiveItemModel < Qt::AbstractItemModel
86 def initialize(collection, columns=nil)
88 @collection = collection
89 @keys = build_keys([], @collection.first.attributes)
90 @keys.inject(@labels = {}) do |labels, k|
91 labels[k] = k.humanize.gsub(/\./, ' ')
95 @rootItem = TreeItem.new(@labels, @keys)
96 @collection.each do |row|
97 TreeItem.new(row, @keys, @rootItem)
101 def build_keys(keys, attrs, prefix="")
102 attrs.inject(keys) do |cols, a|
103 if a[1].respond_to? :attributes
104 build_keys(cols, a[1].attributes, prefix + a[0] + ".")
106 cols << prefix + a[0]
111 def columnCount(parent)
113 return parent.internalPointer.columnCount
115 return @rootItem.columnCount
119 def data(index, role)
121 return Qt::Variant.new
124 if role != Qt::DisplayRole
125 return Qt::Variant.new
128 item = index.internalPointer
129 return item.data(index.column)
132 def setData(index, variant, role=Qt::EditRole)
133 if index.valid? and role == Qt::EditRole
134 raise "invalid column #{index.column}" if (index.column < 0 ||
135 index.column >= @keys.size)
137 att = @keys[index.column]
138 item = index.internalPointer
140 if ! item.itemData.has_key? att
144 value = variant.value
146 if value.class.name == "Qt::Date"
147 value = Date.new(value.year, value.month, value.day)
148 elsif value.class.name == "Qt::Time"
149 value = Time.new(value.hour, value.min, value.sec)
152 att.gsub!(/.*\.(.*)/, '\1')
153 # Don't allow the primary key to be changed
158 eval("item.resource.attributes['%s'] = value" % att)
160 emit dataChanged(index, index)
169 return Qt::ItemIsEnabled
172 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable
175 def headerData(section, orientation, role)
176 if orientation == Qt::Horizontal && role == Qt::DisplayRole
177 return Qt::Variant.new(@labels[@keys[section]])
180 return Qt::Variant.new
183 def index(row, column, parent)
185 parentItem = @rootItem
187 parentItem = parent.internalPointer
190 @childItem = parentItem.child(row)
192 return createIndex(row, column, @childItem)
194 return Qt::ModelIndex.new
200 return Qt::ModelIndex.new
203 childItem = index.internalPointer
204 parentItem = childItem.parent
206 if parentItem == @rootItem
207 return Qt::ModelIndex.new
210 return createIndex(parentItem.row, 0, parentItem)
215 parentItem = @rootItem
217 parentItem = parent.internalPointer
220 return parentItem.childCount