clevic 0.13.0.b9 → 0.13.0.b10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/History.txt +3 -0
  2. data/lib/clevic/action_builder.rb +16 -16
  3. data/lib/clevic/ar_methods.rb +22 -22
  4. data/lib/clevic/attribute_list.rb +5 -5
  5. data/lib/clevic/cache_table.rb +18 -18
  6. data/lib/clevic/dataset_roller.rb +3 -3
  7. data/lib/clevic/default_view.rb +4 -4
  8. data/lib/clevic/delegate.rb +8 -8
  9. data/lib/clevic/delegates/combo_delegate.rb +22 -22
  10. data/lib/clevic/delegates/distinct_delegate.rb +5 -5
  11. data/lib/clevic/delegates/relational_delegate.rb +6 -6
  12. data/lib/clevic/delegates/set_delegate.rb +3 -3
  13. data/lib/clevic/dirty.rb +1 -1
  14. data/lib/clevic/emitter.rb +3 -3
  15. data/lib/clevic/extensions.rb +4 -4
  16. data/lib/clevic/field.rb +68 -68
  17. data/lib/clevic/field_valuer.rb +26 -26
  18. data/lib/clevic/filter_command.rb +6 -6
  19. data/lib/clevic/framework.rb +3 -3
  20. data/lib/clevic/generic_format.rb +2 -2
  21. data/lib/clevic/many_field.rb +3 -3
  22. data/lib/clevic/model_builder.rb +88 -84
  23. data/lib/clevic/model_column.rb +13 -13
  24. data/lib/clevic/ordered_dataset.rb +7 -7
  25. data/lib/clevic/qt/action_builder.rb +3 -3
  26. data/lib/clevic/qt/browser.rb +28 -28
  27. data/lib/clevic/qt/clipboard.rb +5 -5
  28. data/lib/clevic/qt/combo_delegate.rb +12 -12
  29. data/lib/clevic/qt/distinct_delegate.rb +1 -1
  30. data/lib/clevic/qt/extensions.rb +4 -4
  31. data/lib/clevic/qt/qt_combo_box.rb +7 -7
  32. data/lib/clevic/qt/relational_delegate.rb +5 -5
  33. data/lib/clevic/qt/search_dialog.rb +15 -15
  34. data/lib/clevic/qt/simplest_delegate.rb +2 -2
  35. data/lib/clevic/qt/table_model.rb +46 -46
  36. data/lib/clevic/qt/table_view.rb +48 -48
  37. data/lib/clevic/qt/text_delegate.rb +9 -9
  38. data/lib/clevic/rails_models_loaders.rb +3 -3
  39. data/lib/clevic/record.rb +8 -8
  40. data/lib/clevic/sampler.rb +6 -6
  41. data/lib/clevic/sequel_ar_adapter.rb +22 -22
  42. data/lib/clevic/sequel_clevic.rb +10 -10
  43. data/lib/clevic/sequel_meta.rb +5 -5
  44. data/lib/clevic/sequel_naked.rb +4 -4
  45. data/lib/clevic/swing/action.rb +20 -20
  46. data/lib/clevic/swing/action_builder.rb +2 -2
  47. data/lib/clevic/swing/boolean_delegate.rb +3 -3
  48. data/lib/clevic/swing/browser.rb +37 -37
  49. data/lib/clevic/swing/cell_editor.rb +13 -13
  50. data/lib/clevic/swing/cell_renderer.rb +7 -7
  51. data/lib/clevic/swing/clipboard.rb +19 -19
  52. data/lib/clevic/swing/combo_delegate.rb +26 -26
  53. data/lib/clevic/swing/confirm_dialog.rb +7 -7
  54. data/lib/clevic/swing/delegate.rb +4 -4
  55. data/lib/clevic/swing/extensions.rb +24 -24
  56. data/lib/clevic/swing/field.rb +1 -1
  57. data/lib/clevic/swing/relational_delegate.rb +2 -2
  58. data/lib/clevic/swing/row_header.rb +32 -32
  59. data/lib/clevic/swing/search_dialog.rb +31 -31
  60. data/lib/clevic/swing/selection_model.rb +12 -12
  61. data/lib/clevic/swing/swing_table_index.rb +6 -6
  62. data/lib/clevic/swing/table_model.rb +30 -30
  63. data/lib/clevic/swing/table_view.rb +54 -54
  64. data/lib/clevic/swing/table_view_focus.rb +4 -4
  65. data/lib/clevic/swing/tag_delegate.rb +14 -14
  66. data/lib/clevic/swing/tag_editor.rb +4 -4
  67. data/lib/clevic/swing/text_area_delegate.rb +6 -6
  68. data/lib/clevic/swing/text_delegate.rb +4 -4
  69. data/lib/clevic/table_index.rb +14 -14
  70. data/lib/clevic/table_model.rb +30 -30
  71. data/lib/clevic/table_searcher.rb +19 -19
  72. data/lib/clevic/table_view.rb +92 -92
  73. data/lib/clevic/table_view_paste.rb +19 -19
  74. data/lib/clevic/version.rb +1 -1
  75. data/lib/clevic/view.rb +22 -22
  76. data/models/accounts_models.rb +10 -10
  77. data/models/examples.rb +2 -2
  78. data/models/times_models.rb +32 -32
  79. data/models/values_models.rb +2 -2
  80. data/test/test_cache_table.rb +15 -15
  81. data/test/test_helper.rb +7 -7
  82. data/test/test_model_index_extensions.rb +6 -6
  83. data/test/test_table_model.rb +6 -6
  84. data/test/test_table_searcher.rb +25 -25
  85. metadata +33 -35
@@ -12,7 +12,7 @@ class TableView
12
12
  def paste
13
13
  busy_cursor do
14
14
  sanity_check_read_only
15
-
15
+
16
16
  # Try text/html then text/plain as tsv or csv
17
17
  # LATER maybe use the java-native-application at some point for
18
18
  # cut'n'paste internally?
@@ -28,14 +28,14 @@ class TableView
28
28
  rescue PasteError => e
29
29
  show_error e.message
30
30
  end
31
-
31
+
32
32
  # Paste suitable html to the selection
33
33
  # Check for presence of tr tags, and make sure there are no colspan or rowspan attributes
34
34
  # on td tags.
35
35
  def paste_html
36
36
  emit_status_text "Fetching data."
37
37
  html = clipboard.html
38
-
38
+
39
39
  # This should really be factored out somewhere and tested thoroughly
40
40
  emit_status_text "Analysing data."
41
41
  doc =
@@ -44,7 +44,7 @@ class TableView
44
44
  else
45
45
  Hpricot.parse( html )
46
46
  end
47
-
47
+
48
48
  # call the plain text paste if we don't have tabular data
49
49
  if doc.search( "//tr" ).size == 0
50
50
  paste_text
@@ -62,13 +62,13 @@ class TableView
62
62
  #{cell_list}
63
63
  EOF
64
64
  end
65
-
65
+
66
66
  # run through the tabular data and convert to simple array
67
67
  emit_status_text "Pasting data."
68
68
  ary = ( doc / :tr ).map do |row|
69
69
  ( row / :td ).map do |cell|
70
70
  # trim leading and trailing \r\n\t
71
-
71
+
72
72
  # check for br
73
73
  unless cell.search( '//br' ).empty?
74
74
  # treat br as separate lines
@@ -79,11 +79,11 @@ class TableView
79
79
  end.gsub( /^[\r\n\t]*/, '').gsub( /[\r\n\t]*$/, '')
80
80
  end
81
81
  end
82
-
82
+
83
83
  paste_array ary
84
84
  end
85
85
  end
86
-
86
+
87
87
  # LATER probably need a PasteParser or something, to figure
88
88
  # out if a file is tsv or csv
89
89
  # Try tsv first, because number formats often have embedded ','.
@@ -92,7 +92,7 @@ class TableView
92
92
  # TODO could also heuristically check paste selection area
93
93
  def paste_text
94
94
  text = clipboard.text
95
-
95
+
96
96
  case text
97
97
  when /\t/
98
98
  paste_array( CSV.parse( text, :col_sep => "\t" ) )
@@ -103,7 +103,7 @@ class TableView
103
103
  paste_value_to_selection( text )
104
104
  end
105
105
  end
106
-
106
+
107
107
  # Paste array to either a single selection or a matching multiple selection
108
108
  # TODO Check for rectangularness, ie csv_arr.map{|row| row.size}.uniq.size == 1
109
109
  def paste_array( arr )
@@ -124,21 +124,21 @@ class TableView
124
124
  if selection_model.ranges.size != 1
125
125
  raise PasteError, "Can't paste tabular data to multiple selection."
126
126
  end
127
-
127
+
128
128
  if selection_model.ranges.first.height != arr.size
129
129
  raise PasteError, "Height of paste area (#{selection_model.ranges.first.height}) doesn't match height of data (#{arr.size})."
130
130
  end
131
-
131
+
132
132
  if selection_model.ranges.first.width != arr.first.size
133
133
  raise PasteError, "Width of paste area (#{selection_model.ranges.first.width}) doesn't match width of data (#{arr.first.size})."
134
134
  end
135
-
135
+
136
136
  # size is the same, so do the paste
137
137
  paste_to_index( selected_index, arr )
138
138
  end
139
139
  end
140
140
  end
141
-
141
+
142
142
  # set all indexes in the selection to the value
143
143
  def paste_value_to_selection( value )
144
144
  selection_model.selected_indexes.each do |index|
@@ -146,7 +146,7 @@ class TableView
146
146
  # save records to db via view, so we get error messages
147
147
  save_row( index )
148
148
  end
149
-
149
+
150
150
  # notify of changed data
151
151
  model.data_changed do |change|
152
152
  sorted = selection_model.selected_indexes.sort
@@ -154,7 +154,7 @@ class TableView
154
154
  change.bottom_right = sorted.last
155
155
  end
156
156
  end
157
-
157
+
158
158
  # Paste an array to the index, replacing whatever is at that index
159
159
  # and whatever is at other indices matching the size of the pasted
160
160
  # csv array. Create new rows if there aren't enough.
@@ -163,7 +163,7 @@ class TableView
163
163
  csv_arr.each_with_index do |row,row_index|
164
164
  # append row if we need one
165
165
  model.add_new_item if top_left_index.row + row_index >= model.row_count
166
-
166
+
167
167
  row.each_with_index do |field, field_index|
168
168
  unless top_left_index.column + field_index >= model.column_count
169
169
  # do paste
@@ -183,7 +183,7 @@ class TableView
183
183
  # save records to db via view, so we get error messages
184
184
  save_row( top_left_index.choppy {|i| i.row += row_index; i.column = 0 } )
185
185
  end
186
-
186
+
187
187
  # make the gui refresh
188
188
  model.data_changed do |change|
189
189
  change.top_left = top_left_index
@@ -193,7 +193,7 @@ class TableView
193
193
  end
194
194
  end
195
195
  end
196
-
196
+
197
197
  end
198
198
 
199
199
  end
@@ -3,7 +3,7 @@ module Clevic #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 13
5
5
  TINY = 0
6
- PRE = 'b9'
6
+ PRE = 'b10'
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
  end
data/lib/clevic/view.rb CHANGED
@@ -5,28 +5,28 @@ module Clevic
5
5
  # This contains the definition of a particular view of an entity.
6
6
  # See Clevic::ModelBuilder.
7
7
  class View
8
-
8
+
9
9
  class << self
10
10
  def define_ui_block( &block )
11
11
  @define_ui_block ||= block
12
12
  end
13
-
13
+
14
14
  def order
15
15
  @order ||= []
16
16
  end
17
-
17
+
18
18
  # sometimes order has duplicates. So this is all unique
19
19
  # defined views in order of definition, or as specified.
20
20
  def views
21
21
  order.uniq
22
22
  end
23
-
23
+
24
24
  def []( view_name )
25
25
  order.find do |view|
26
26
  view.name =~ /#{view_name.to_s}/i
27
27
  end
28
28
  end
29
-
29
+
30
30
  # Handle situations where the array passed to
31
31
  # Clevic::View.order has entity_class
32
32
  # objects in it. In other words, if there is one, pass back it's
@@ -40,7 +40,7 @@ module Clevic
40
40
  end
41
41
  end
42
42
  end
43
-
43
+
44
44
  def entity_class( *args )
45
45
  if args.size == 0
46
46
  @entity_class || raise( "entity_class not specified for #{name}" )
@@ -48,11 +48,11 @@ module Clevic
48
48
  self.entity_class = args.first
49
49
  end
50
50
  end
51
-
51
+
52
52
  def entity_class=( some_class )
53
53
  @entity_class = some_class
54
54
  end
55
-
55
+
56
56
  def widget_name( *args )
57
57
  if args.size == 0
58
58
  # the class name by default
@@ -62,7 +62,7 @@ module Clevic
62
62
  end
63
63
  end
64
64
  end
65
-
65
+
66
66
  # args can be anything that has a writer method. Often this
67
67
  # will be entity_class
68
68
  # block contains the ModelBuilder DSL
@@ -74,33 +74,33 @@ module Clevic
74
74
  end
75
75
  end
76
76
  end
77
-
77
+
78
78
  # use block from constructor, or class ui block from eg Clevic::Record
79
79
  def define_ui_block
80
80
  @define_ui_block || self.class.define_ui_block
81
81
  end
82
-
82
+
83
83
  # For descendants to override easily
84
84
  def entity_class
85
85
  @entity_class || self.class.entity_class
86
86
  end
87
87
  attr_writer :entity_class
88
-
88
+
89
89
  # The title to display, eg in a tab
90
90
  def title
91
91
  @title || self.class.name
92
92
  end
93
93
  attr_writer :title
94
-
94
+
95
95
  def fields
96
96
  @fields ||= define_ui.fields
97
97
  end
98
-
98
+
99
99
  # used by the framework-specific code to name widgets
100
100
  def widget_name
101
101
  @widget_name || self.class.widget_name
102
102
  end
103
-
103
+
104
104
  def model_builder( value = nil, &block )
105
105
  if value.nil?
106
106
  @model_builder ||= ModelBuilder.new( self )
@@ -110,7 +110,7 @@ module Clevic
110
110
  end
111
111
  end
112
112
  attr_writer :model_builder
113
-
113
+
114
114
  # return a default UI constructed from model metadata
115
115
  def define_ui
116
116
  if define_ui_block.nil?
@@ -123,23 +123,23 @@ module Clevic
123
123
  model_builder( &define_ui_block )
124
124
  end
125
125
  end
126
-
126
+
127
127
  # callback for view/model specific actions
128
128
  def define_actions( table_view, action_builder )
129
129
  end
130
-
130
+
131
131
  # callback for notify
132
132
  def notify_field( table_view, model_index )
133
133
  ndc = model_index.field.notify_data_changed
134
134
  case ndc
135
135
  when Proc
136
136
  ndc.call( self, table_view, model_index )
137
-
137
+
138
138
  when Symbol
139
139
  send( ndc, table_view, model_index )
140
140
  end
141
141
  end
142
-
142
+
143
143
  # Define data changed events. Default is to call notify_data_changed
144
144
  # for each field in the rectangular area defined by top_left and bottom_right
145
145
  # (which are include Clevic::TableIndex)
@@ -157,10 +157,10 @@ module Clevic
157
157
  end
158
158
  end
159
159
  end
160
-
160
+
161
161
  # callback for key presses
162
162
  def notify_key_press( table_view, key_press_event, current_model_index )
163
163
  end
164
-
164
+
165
165
  end
166
166
  end
@@ -16,9 +16,9 @@ db.test_connection
16
16
  class Entry < Sequel::Model
17
17
  many_to_one :debit, :class_name => 'Account', :key => :debit_id
18
18
  many_to_one :credit, :class_name => 'Account', :key => :credit_id
19
-
19
+
20
20
  include Clevic::Record
21
-
21
+
22
22
  define_ui do
23
23
  plain :date, :sample => '88-WWW-99'
24
24
  distinct :supplier do |f|
@@ -28,7 +28,7 @@ class Entry < Sequel::Model
28
28
  f.notify_data_changed = lambda do |entity_view, table_view, model_index|
29
29
  if model_index.entity.credit.nil? && model_index.entity.debit.nil?
30
30
  entity_view.update_from_description( model_index )
31
-
31
+
32
32
  # move edit cursor to amount field
33
33
  table_view.selection_model.clear
34
34
  table_view.override_next_index( model_index.choppy( :column => :amount ) )
@@ -43,10 +43,10 @@ class Entry < Sequel::Model
43
43
  plain :cheque_number
44
44
  plain :active, :sample => 'WW'
45
45
  plain :vat, :label => 'VAT', :sample => 'WW', :tooltip => 'Does this include VAT?'
46
-
46
+
47
47
  dataset.order( :date, :id )
48
48
  end
49
-
49
+
50
50
  # Copy the values for the credit and debit fields
51
51
  # from the previous similar entry with a similar description
52
52
  def self.update_from_description( current_index )
@@ -56,13 +56,13 @@ class Entry < Sequel::Model
56
56
  filter( current_index.attribute.to_sym => current_index.attribute_value ). \
57
57
  order( :date.desc ). \
58
58
  first
59
-
59
+
60
60
  if similar != nil
61
61
  # set the values
62
62
  current_index.entity.debit = similar.debit
63
63
  current_index.entity.credit = similar.credit
64
64
  current_index.entity.category = similar.category
65
-
65
+
66
66
  # emit signal to that whole row has changed
67
67
  current_index.model.data_changed do |change|
68
68
  change.top_left = current_index.choppy( :column => 0 )
@@ -75,9 +75,9 @@ end
75
75
  class Account < Sequel::Model
76
76
  one_to_many :debits, :class_name => 'Entry', :key => :debit_id, :order => :date
77
77
  one_to_many :credits, :class_name => 'Entry', :key => :credit_id, :order => :date
78
-
78
+
79
79
  include Clevic::Record
80
-
80
+
81
81
  # define how fields are displayed
82
82
  define_ui do
83
83
  plain :name
@@ -86,7 +86,7 @@ class Account < Sequel::Model
86
86
  plain :pastel_number, :alignment => :right, :label => 'Pastel'
87
87
  plain :fringe, :format => "%.1f"
88
88
  plain :active
89
-
89
+
90
90
  dataset.order( :name, :account_type )
91
91
  end
92
92
  end
data/models/examples.rb CHANGED
@@ -31,10 +31,10 @@ See also Clevic::ModelBuilder and Clevic::Field
31
31
 
32
32
  == Work hours database using Sqlite
33
33
  :include:models/times_sqlite_models.rb
34
-
34
+
35
35
  == Work hours database using Postgres
36
36
  :include:models/times_psql_models.rb
37
-
37
+
38
38
  == Work hours database using ActiveRecord style models
39
39
  :include:models/times_ar_style_models.rb
40
40
 
@@ -11,7 +11,7 @@ class Entry < Sequel::Model
11
11
  many_to_one :invoice
12
12
  many_to_one :activity
13
13
  many_to_one :project
14
-
14
+
15
15
  # spans of time more than 8 ours are coloured violet
16
16
  # because they're often the result of typos.
17
17
  def time_color
@@ -19,21 +19,21 @@ class Entry < Sequel::Model
19
19
  # 8 hours
20
20
  'darkviolet' if self.end - start > 8.hours
21
21
  end
22
-
22
+
23
23
  # tooltip for spans of time > 8 hours
24
24
  def time_tooltip
25
25
  return if self.end.nil? || start.nil?
26
26
  'Time interval greater than 8 hours' if self.end - start > 8.hours
27
27
  end
28
-
28
+
29
29
  define_ui do
30
30
  plain :date, :sample => '28-WWW-08'
31
-
31
+
32
32
  # The project field
33
33
  relational :project do |field|
34
34
  field.display = :project
35
35
  field.dataset.filter( :active => true ).order{ lower(project) }
36
-
36
+
37
37
  # handle data changed events. In this case,
38
38
  # auto-fill-in the invoice field.
39
39
  field.notify_data_changed do |entity_view, table_view, model_index|
@@ -45,31 +45,31 @@ class Entry < Sequel::Model
45
45
  end
46
46
  end
47
47
  end
48
-
48
+
49
49
  relational :invoice do |f|
50
50
  f.display 'invoice_number'
51
51
  f.dataset.filter( :status => 'not sent' ).order( :invoice_number )
52
52
  end
53
-
53
+
54
54
  # call time_color method for foreground color value
55
55
  plain :start, :foreground => :time_color, :tooltip => :time_tooltip
56
-
56
+
57
57
  # another way to call time_color method for foreground color value
58
58
  plain :end, :foreground => lambda{|x| x.time_color}, :tooltip => :time_tooltip
59
-
59
+
60
60
  # multiline text
61
61
  text :description, :sample => 'This is a long string designed to hold lots of data and description'
62
-
62
+
63
63
  relational :activity do |f|
64
64
  f.display 'activity'
65
65
  f.sample 'Troubleshooting'
66
66
  f.dataset.filter( :active => true ).order{ lower(activity) }
67
67
  end
68
-
68
+
69
69
  distinct :module, :tooltip => 'Module or sub-project'
70
70
  plain :charge, :tooltip => 'Is this time billable?'
71
71
  distinct :person, :default => 'John', :tooltip => 'The person who did the work'
72
-
72
+
73
73
  dataset.order( :date, :start, :id )
74
74
  end
75
75
 
@@ -77,11 +77,11 @@ class Entry < Sequel::Model
77
77
  action_builder.action :smart_copy, 'Smart Copy', :shortcut => 'Ctrl+"' do
78
78
  smart_copy( view )
79
79
  end
80
-
80
+
81
81
  action_builder.action :invoice_from_project, 'Invoice from Project', :shortcut => 'Ctrl+Shift+I' do
82
82
  invoice_from_project( view, view.current_index ) do
83
83
  # execute the block if the invoice is changed
84
-
84
+
85
85
  # save this before selection model is cleared
86
86
  current_index = view.current_index
87
87
  view.selection_model.clear
@@ -89,35 +89,35 @@ class Entry < Sequel::Model
89
89
  end
90
90
  end
91
91
  end
92
-
92
+
93
93
  # do a smart copy from the previous line
94
94
  def self.smart_copy( view )
95
95
  view.sanity_check_read_only
96
96
  view.sanity_check_ditto
97
-
97
+
98
98
  # need a reference to current_index here, because selection_model.clear will
99
99
  # invalidate view.current_index. And anyway, its shorter and easier to read.
100
100
  current_index = view.current_index
101
101
  if current_index.row >= 1
102
102
  # fetch previous item
103
103
  previous_item = view.model.collection[current_index.row - 1]
104
-
104
+
105
105
  # copy the relevant fields
106
106
  current_index.entity.date = previous_item.date if current_index.entity.date.nil?
107
107
  # depends on previous line
108
108
  current_index.entity.start = previous_item.end if current_index.entity.date == previous_item.date
109
-
109
+
110
110
  # copy rest of fields
111
111
  [:project, :invoice, :activity, :module, :charge, :person].each do |attr|
112
112
  current_index.entity.send( "#{attr.to_s}=", previous_item.send( attr ) )
113
113
  end
114
-
114
+
115
115
  # tell view to update
116
116
  view.model.data_changed do |change|
117
117
  change.top_left = current_index.choppy( :column => 0 )
118
118
  change.bottom_right = current_index.choppy( :column => view.model.fields.size - 1 )
119
119
  end
120
-
120
+
121
121
  # move to the first empty time field
122
122
  next_field =
123
123
  if current_index.entity.start.nil?
@@ -125,7 +125,7 @@ class Entry < Sequel::Model
125
125
  else
126
126
  :end
127
127
  end
128
-
128
+
129
129
  # next cursor location
130
130
  view.selection_model.clear
131
131
  view.current_index = current_index.choppy( :column => next_field )
@@ -142,10 +142,10 @@ class Entry < Sequel::Model
142
142
  unless invoice.nil?
143
143
  # make a reference to the invoice
144
144
  current_index.entity.invoice = invoice
145
-
145
+
146
146
  # update view from top_left to bottom_right
147
147
  table_view.model.data_changed( current_index.choppy( :column => :invoice ) )
148
-
148
+
149
149
  unless block.nil?
150
150
  if block.arity == 1
151
151
  block.call( invoice )
@@ -156,14 +156,14 @@ class Entry < Sequel::Model
156
156
  end
157
157
  end
158
158
  end
159
-
159
+
160
160
  end
161
161
 
162
162
  class Invoice < Sequel::Model
163
163
  include Clevic::Record
164
-
164
+
165
165
  one_to_many :entries
166
-
166
+
167
167
  define_ui do
168
168
  plain :date
169
169
  distinct :client
@@ -173,7 +173,7 @@ class Invoice < Sequel::Model
173
173
  plain :quote_date, :format => '%d-%b-%y', :edit_format => '%d-%b-%Y', :tooltip => 'the date and time when the quote was supplied', :default => lambda{|x| DateTime.now}
174
174
  plain :quote_amount
175
175
  plain :description
176
-
176
+
177
177
  dataset.order( :invoice_number )
178
178
  end
179
179
  end
@@ -182,17 +182,17 @@ class Project < Sequel::Model
182
182
  one_to_many :entries
183
183
 
184
184
  include Clevic::Record
185
-
185
+
186
186
  define_ui do
187
187
  plain :project
188
188
  plain :description
189
189
  distinct :client
190
190
  plain :rate
191
191
  plain :active
192
-
192
+
193
193
  dataset.order( :project )
194
194
  end
195
-
195
+
196
196
  # Return the latest invoice for this project
197
197
  # Not part of the UI.
198
198
  def latest_invoice
@@ -207,12 +207,12 @@ class Activity < Sequel::Model
207
207
  one_to_many :entries
208
208
 
209
209
  include Clevic::Record
210
-
210
+
211
211
  # define how fields are displayed
212
212
  define_ui do
213
213
  plain :activity
214
214
  plain :active
215
-
215
+
216
216
  dataset.order( :activity )
217
217
  end
218
218
  end