lib/clevic/field.rb in clevic-0.13.0.b3 vs lib/clevic/field.rb in clevic-0.13.0.b5

- old
+ new

@@ -1,8 +1,10 @@ require 'gather' require 'clevic/sampler.rb' require 'clevic/generic_format.rb' +require 'clevic/dataset_roller.rb' +require 'clevic/many_field.rb' module Clevic =begin rdoc This defines a field in the UI, and how it hooks up to a field in the DB. @@ -134,11 +136,11 @@ ## # An Enumerable of allowed values for restricted fields. If each yields # two values (like it does for a Hash), the # first will be stored in the db, and the second displayed in the UI. - # If it's a proc, it must return an Enumerable as above. + # If it's a proc, that must return an Enumerable as above. property :set ## # When this is true, only the values in the combo may be entered. # Otherwise the text-entry part of the combo can be used to enter @@ -148,33 +150,50 @@ ## # Only for the distinct field type. The values will be sorted either with the # most used values first (:frequency => true) or in # alphabetical order (:description => true). + # FIXME re-implement this with Dataset property :frequency, :description ## # Default value for this field for new records. # Can be a Proc or a value. A value will just be # set, a proc will be executed with the entity as a parameter. property :default ## # The property used for finding the field, ie by TableModel#field_column. - # Defaults to the attribute. + # Defaults to the attribute. If there are several display fields based on + # one db field, their attribute will be the same, but their id must be different. property :id ## # Called when the data in this field changes. # Either a proc( clevic_view, table_view, model_index ) or a symbol # for a method( view, model_index ) on the Clevic::View object. property :notify_data_changed + + ## + # This is the dataset of related objects. + # Called in configuration for a field that works with a relationship. + # dataset.filter( :blah => 'etc' ).order( :interesting_field ) + def dataset + dataset_roller + end + # TODO Still getting the Builder/Built conflict + def dataset_roller + # related class if it's an association, entity_class otherwise + @dataset_roller ||= DatasetRoller.new( ( association? ? related_class : entity_class ).dataset ) + end + # The list of properties for ActiveRecord options. # There are actually from ActiveRecord::Base.VALID_FIND_OPTIONS, but it's protected. # Each element becomes a property. - # TODO remove these? That will destroy the migration path. + # TODO deprecate these + # TODO warn or raise if these are used together with a dataset call AR_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from, :lock ] AR_FIND_OPTIONS.each{|x| property x} # Return a list of find options and their values, but only # if the values are not nil @@ -186,10 +205,14 @@ end ha end end + # The model object (eg TableModel) this field is part of. + # Set to TableModel by ModelBuilder#build + attr_accessor :model + # The UI delegate class for the field. The delegate class knows how to create a UI # for this field using whatever GUI toolkit is selected attr_accessor :delegate # The attribute on the AR entity that forms the basis for this field. @@ -241,40 +264,10 @@ default_edit_format! default_alignment! default_display! if association? end - # x_to_many fields are by definition collections of other entities - def many( &block ) - if block - many_view( &block ) - else - many_view do |mb| - # TODO should fetch this from one of the field definitions - mb.plain related_attribute - end - end - end - - def many_builder - @many_view.builder - end - - def many_fields - many_builder.fields - end - - # return an instance of Clevic::View that represents the many items - # for this field - def many_view( &block ) - @many_view ||= View.new( :entity_class => related_class, &block ) - end - - # The model object (eg TableModel) this field is part of. - # Set to TableModel by ModelBuilder#build - attr_accessor :model - # Return the attribute value for the given Object Relational Model instance, or nil # if entity is nil. Will call transform_attribute. def value_for( entity ) begin return nil if entity.nil? @@ -313,17 +306,10 @@ # ModelColumn object def meta entity_class.meta[attribute] end - # return the type of this attribute. Usually one of :string, :integer, :float - # or some entity class - # TODO remove - def attribute_type - meta.type - end - # return true if this field can be used in a filter # virtual fields (ie those that don't exist in this field's # table) can't be used to filter on. def filterable? !meta.nil? @@ -335,11 +321,11 @@ end # return the class object of a related class if this is a relational # field, otherwise nil def related_class - return nil unless entity_class.meta.has_key?( attribute ) + return nil unless association? && entity_class.meta.has_key?( attribute ) @related_class ||= eval( entity_class.meta[attribute].class_name || attribute.to_s.classify ) end # return an array of the various attribute parts def attribute_path @@ -361,29 +347,27 @@ # Called by Clevic::Model to format the edit value. def do_edit_format( value ) do_generic_format( edit_format, value ) end - # Return a sample for the field which can be used to size the UI field widget. + # Set or return a sample for the field which can be used to size the UI field widget. def sample( *args ) if !args.empty? @sample = args.first self else if @sample.nil? - if meta.type == :boolean - @sample = self.label - else - begin - @sample ||= Sampler.new( entity_class, attribute, display ) do |value| - do_format( value ) - end.compute - rescue - puts $! - ensure - # if we don't know how to figure it out from the data, just return the label size - @sample ||= self.label - end + begin + @sample ||= Sampler.new( self ) do |value| + do_format( value ) + end.compute + rescue + puts "for #{entity_class.name}" + puts $!.message + puts $!.backtrace + ensure + # if we don't know how to figure it out from the data, just return the label size + @sample ||= self.label end end @sample end end