Clevic

RDoc | Rubyforge Project

Screenshot of a fully defined UI with the foreign-key dropdown in place.
Tabs contain the two tables.

See RDoc for feature list.
See ModelBuilder for how to define views.

Screenshot

Code for minimal UI definition. Clevic will create a fairly sensible
UI from the DB metadata.


require 'clevic.rb'

# see sql/accounts.sql for schema

# db connection
Clevic::DbOptions.connect do
  database 'accounts_test'
  adapter :postgresql
  username 'accounts'
end

# minimal definition to get combo boxes to show up
class Entry < ActiveRecord::Base
  include Clevic::Record
  belongs_to :debit, :class_name => 'Account', :foreign_key => 'debit_id'
  belongs_to :credit, :class_name => 'Account', :foreign_key => 'credit_id'
end

# minimal definition to get sensible values in combo boxes
class Account < ActiveRecord::Base
  include Clevic::Record
  def to_s; name; end
end

Code for a full definition. The Entry model has some code to
update the credit and debit fields when the new item description
is found in the table.


require 'clevic.rb'

# db connection
Clevic::DbOptions.connect( $options ) do
  # use a different db for testing, so real data doesn't get broken.
  if options[:database].nil? || options[:database].empty?
    database( debug? ? :accounts_test : :accounts )
  else
    database options[:database]
  end
  adapter :postgresql
  username 'accounts'
end

class Entry < ActiveRecord::Base
  belongs_to :debit, :class_name => 'Account', :foreign_key => 'debit_id'
  belongs_to :credit, :class_name => 'Account', :foreign_key => 'credit_id'
  
  include Clevic::Record
  
  define_ui do
    plain       :date, :sample => '88-WWW-99'
    distinct    :description, :conditions => "now() - date <= '1 year'", :sample => 'm' * 26
    relational  :debit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
    relational  :credit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
    plain       :amount, :sample => 999999.99
    distinct    :category
    plain       :cheque_number
    plain       :active, :sample => 'WW'
    plain       :vat, :label => 'VAT', :sample => 'WW', :tooltip => 'Does this include VAT?'
    
    records     :order => 'date, id'
  end
  
  # called when data is changed in the UI
  def self.data_changed( top_left, bottom_right, view )
    if top_left == bottom_right
      update_credit_debit( top_left, view )
    else
      puts "top_left: #{top_left.inspect}"
      puts "bottom_right: #{bottom_right.inspect}"
      puts "can't do data_changed for a range"
    end
  end
  
  # check that the current field is :descriptions, then
  # copy the values for the credit and debit fields
  # from the previous similar entry
  def self.update_credit_debit( current_index, view )
    return unless current_index.valid?
    current_field = current_index.attribute
    if current_field == :description
      # most recent entry, ordered in reverse
      similar = self.find(
        :first,
        :conditions => ["#{current_field} = ?", current_index.attribute_value],
        :order => 'date desc'
      )
      if similar != nil
        # set the values
        current_index.entity.debit = similar.debit
        current_index.entity.credit = similar.credit
        current_index.entity.category = similar.category
        
        # emit signal to update view from top_left to bottom_right
        top_left_index = current_index.choppy( :column => 0 )
        bottom_right_index = current_index.choppy( :column => view.model.column_count - 1 )
        view.dataChanged( top_left_index, bottom_right_index )
        
        # move edit cursor to amount field
        view.selection_model.clear
        view.override_next_index( current_index.choppy( :column => view.field_column( :amount ) ) )
      end
    end
  end
end

class Account < ActiveRecord::Base
  has_many :debits, :class_name => 'Entry', :foreign_key => 'debit_id'
  has_many :credits, :class_name => 'Entry', :foreign_key => 'credit_id'
  
  include Clevic::Record
  
  # define how fields are displayed
  define_ui do
    plain       :name
    restricted  :vat, :label => 'VAT', :set => %w{ yes no all }
    restricted  :account_type, :set => %w{Account Asset Assets Expenses Income Liability Opening Balance Personal Tax VAT}
    plain       :pastel_number, :alignment => Qt::AlignRight, :label => 'Pastel'
    plain       :fringe, :format => "%.1f"
    plain       :active
    
    records  :order => 'name,account_type'
  end
end