clevic 0.13.0.b3 → 0.13.0.b5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/History.txt +21 -0
  2. data/Manifest.txt +91 -85
  3. data/README.txt +33 -18
  4. data/Rakefile +2 -3
  5. data/TODO +8 -14
  6. data/bin/clevic +18 -20
  7. data/lib/clevic.rb +7 -1
  8. data/lib/clevic/action_builder.rb +4 -1
  9. data/lib/clevic/ar_methods.rb +72 -57
  10. data/lib/clevic/attribute_list.rb +4 -0
  11. data/lib/clevic/cache_table.rb +43 -69
  12. data/lib/clevic/dataset_roller.rb +22 -0
  13. data/lib/clevic/delegate.rb +11 -5
  14. data/lib/clevic/delegates/combo_delegate.rb +156 -0
  15. data/lib/clevic/delegates/distinct_delegate.rb +48 -0
  16. data/lib/clevic/delegates/relational_delegate.rb +59 -0
  17. data/lib/clevic/delegates/set_delegate.rb +31 -0
  18. data/lib/clevic/field.rb +39 -55
  19. data/lib/clevic/field_valuer.rb +23 -10
  20. data/lib/clevic/filter_command.rb +22 -36
  21. data/lib/clevic/framework.rb +37 -0
  22. data/lib/clevic/generic_format.rb +5 -1
  23. data/lib/clevic/many_field.rb +28 -3
  24. data/lib/clevic/model_builder.rb +27 -32
  25. data/lib/clevic/ordered_dataset.rb +45 -0
  26. data/lib/clevic/qt.rb +4 -1
  27. data/lib/clevic/qt/action_builder.rb +9 -1
  28. data/lib/clevic/qt/browser.rb +1 -1
  29. data/lib/clevic/qt/clipboard.rb +3 -3
  30. data/lib/clevic/qt/combo_delegate.rb +25 -89
  31. data/lib/clevic/qt/delegate.rb +25 -0
  32. data/lib/clevic/qt/distinct_delegate.rb +5 -23
  33. data/lib/clevic/qt/extensions.rb +8 -1
  34. data/lib/clevic/qt/qt_combo_box.rb +58 -0
  35. data/lib/clevic/qt/relational_delegate.rb +18 -58
  36. data/lib/clevic/qt/set_delegate.rb +4 -34
  37. data/lib/clevic/qt/simplest_delegate.rb +19 -0
  38. data/lib/clevic/qt/table_model.rb +10 -10
  39. data/lib/clevic/qt/table_view.rb +7 -23
  40. data/lib/clevic/qt/text_delegate.rb +2 -2
  41. data/lib/clevic/qt/ui/browser_ui.rb +1 -1
  42. data/lib/clevic/qt/ui/search_dialog_ui.rb +1 -1
  43. data/lib/clevic/rails_models_loaders.rb +13 -0
  44. data/lib/clevic/record.rb +2 -2
  45. data/lib/clevic/sampler.rb +85 -39
  46. data/lib/clevic/sequel_ar_adapter.rb +1 -28
  47. data/lib/clevic/sequel_clevic.rb +68 -0
  48. data/lib/clevic/sequel_meta.rb +1 -13
  49. data/lib/clevic/subclasses.rb +18 -0
  50. data/lib/clevic/swing.rb +2 -1
  51. data/lib/clevic/swing/action.rb +27 -3
  52. data/lib/clevic/swing/action_builder.rb +0 -2
  53. data/lib/clevic/swing/browser.rb +1 -10
  54. data/lib/clevic/swing/combo_delegate.rb +45 -133
  55. data/lib/clevic/swing/delegate.rb +2 -0
  56. data/lib/clevic/swing/distinct_delegate.rb +2 -14
  57. data/lib/clevic/swing/relational_delegate.rb +2 -20
  58. data/lib/clevic/swing/set_delegate.rb +13 -28
  59. data/lib/clevic/swing/table_view.rb +1 -1
  60. data/lib/clevic/table_model.rb +3 -4
  61. data/lib/clevic/table_searcher.rb +10 -31
  62. data/lib/clevic/table_view.rb +97 -43
  63. data/lib/clevic/ui/browser_ui.rb +133 -0
  64. data/lib/clevic/ui/search_dialog_ui.rb +106 -0
  65. data/lib/clevic/version.rb +2 -2
  66. data/models/accounts_models.rb +24 -21
  67. data/models/times_models.rb +34 -28
  68. data/models/times_psql_models.rb +9 -3
  69. data/models/times_sqlite_models.rb +24 -1
  70. data/sql/times_sqlite.sql +3 -3
  71. data/tasks/clevic.rake +2 -2
  72. data/test/test_cache_table.rb +9 -19
  73. data/test/test_table_searcher.rb +2 -5
  74. metadata +95 -91
  75. data/lib/clevic/order_attribute.rb +0 -63
  76. data/lib/clevic/qt/boolean_delegate.rb +0 -8
  77. data/lib/clevic/qt/delegates.rb +0 -1
  78. data/lib/clevic/qt/item_delegate.rb +0 -66
  79. data/lib/clevic/sql_dialects.rb +0 -33
  80. data/tasks/website.rake +0 -25
  81. data/test/test_order_attribute.rb +0 -62
  82. data/test/test_sql_dialects.rb +0 -77
@@ -24,9 +24,7 @@ module ActionBuilder
24
24
  # connect the action to some code
25
25
  if options.has_key?( :method )
26
26
  action.handler do |event|
27
- puts "#{__FILE__}:#{__LINE__}:action.name: #{action.name.inspect}"
28
27
  action_triggered do
29
- # active is from Qt checkbox-menu-items
30
28
  send_args = [ options[:method], options.has_key?( :checkable ) ? action.menu_item.selected? : nil ].compact
31
29
  send( *send_args )
32
30
  end
@@ -9,8 +9,6 @@ The main application class. Display one tabs for each descendant of Clevic::View
9
9
  in Clevic::View.order. DefaultView classes created by Clevic::Record are included.
10
10
  =end
11
11
  class Browser < javax.swing.JFrame
12
- #~ slots *%w{dump() refresh_table() filter_by_current(bool) next_tab() previous_tab()}
13
-
14
12
  attr_reader :menu_edit, :menu_search, :menu_table
15
13
 
16
14
  def initialize
@@ -104,8 +102,6 @@ class Browser < javax.swing.JFrame
104
102
 
105
103
  # tab navigation
106
104
  tables_tab.add_change_listener do |change_event|
107
- puts "change_event: #{change_event.source.inspect}"
108
- puts "change_event.source.selected_index: #{change_event.source.selected_index.inspect}"
109
105
  current_changed
110
106
  # TODO tell exiting tab to save currently editing row/cell
111
107
  end
@@ -247,12 +243,7 @@ class Browser < javax.swing.JFrame
247
243
  # update the tab, so there's a visual indication of filtering
248
244
  filter_title = ( tab.filtered? ? '| ' : '' ) + tab.title
249
245
  tables_tab.set_title_at( tables_tab.selected_index, filter_title )
250
-
251
- if tab.filtered?
252
- tables_tab.set_tool_tip_text_at( tables_tab.selected_index, tab.filtered.status_message )
253
- else
254
- tables_tab.set_tool_tip_text_at( tables_tab.selected_index, nil )
255
- end
246
+ tables_tab.set_tool_tip_text_at( tables_tab.selected_index, tab.filter_message )
256
247
  end
257
248
  end
258
249
 
@@ -6,11 +6,19 @@ module Clevic
6
6
  # all this just to format a display item...
7
7
  # .... and work around various other Swing stupidities
8
8
  class ComboBox < javax.swing.JComboBox
9
+ attr_accessor :delegate
10
+
9
11
  def initialize( field )
10
12
  super()
11
13
  @field = field
12
14
  end
13
15
 
16
+ # For Clevic::ComboDelegate to call
17
+ def no_insert=( bool )
18
+ # Swing doesn't have combo policies like Qt.
19
+ # From what I can see, anyway.
20
+ end
21
+
14
22
  # set to true by processKeyBinding when a character
15
23
  # key is pressed. Used by the autocomplete code.
16
24
  attr_reader :typing
@@ -52,11 +60,6 @@ class ComboDelegate < Delegate
52
60
  @autocompleting = false
53
61
  end
54
62
 
55
- # Return the GUI component / widget that is displayed when editing.
56
- # Usually this will be a combo box widget, but it can be a text editor
57
- # in some cases.
58
- attr_reader :editor
59
-
60
63
  def combo_class
61
64
  ComboBox
62
65
  end
@@ -66,7 +69,7 @@ class ComboDelegate < Delegate
66
69
  true
67
70
  end
68
71
 
69
- def create_combo_box
72
+ def create_combo_box( *args )
70
73
  # create a new combo class each time, otherwise
71
74
  # we have to get into managing cleaning out the model
72
75
  # and so on
@@ -88,12 +91,6 @@ class ComboDelegate < Delegate
88
91
  @original_renderer.getListCellRendererComponent(jlist, display_for( value ), index, selected, cell_has_focus)
89
92
  end
90
93
 
91
- # Return a string to be shown to the user.
92
- # model_value is an item stored in the combo box model.
93
- def display_for( model_value )
94
- field.transform_attribute( model_value )
95
- end
96
-
97
94
  # return a new text editor. This is for distinct_delegate when there
98
95
  # are no other values to choose from.
99
96
  # TODO move into distinct_delegate then?
@@ -105,79 +102,44 @@ class ComboDelegate < Delegate
105
102
 
106
103
  # Some GUIs (Qt) can just set this. Swing can't.
107
104
  def configure_prefix
108
- end
109
-
110
- # TODO kinda redundant because all combos must be editable
111
- # to support prefix matching
112
- def configure_editable
113
- editor.editable = true
114
- end
115
-
116
- # Create a GUI widget and fill it with the possible values.
117
- def init_component( cell_editor = nil )
118
- if needs_combo?
119
- @editor = create_combo_box
120
-
121
- # add all entries from population
122
- population.each do |item|
123
- editor << item
124
- end
125
-
126
- # create a nil entry
127
- add_nil_item if allow_null?
128
-
129
- # allow prefix matching from the keyboard
130
- configure_prefix
131
-
132
- # don't allow text editing if restricted
133
- configure_editable
134
-
135
- # set the correct value in the list
136
- select_current
137
-
138
- # pick up events from editor
139
- # but only after all the other config, otherwise we get
140
- # events triggered by the setup, which isn't helpful.
141
- editor.editor.editor_component.document.add_document_listener do |event|
142
- # don't do anything if autocomplete manipulations are in progress
143
- unless @autocompleting || !editor.typing
144
- if event.type == javax.swing.event.DocumentEvent::EventType::REMOVE
145
- invoke_later do
146
- repopulate
147
- end
148
- else
149
- # only suggest on inserts and updates. Not on deletes.
150
- filter_prefix( editor.editor.item )
105
+ # pick up events from editor
106
+ # but only after all the other config, otherwise we get
107
+ # events triggered by the setup, which isn't helpful.
108
+ editor.editor.editor_component.document.add_document_listener do |event|
109
+ # don't do anything if autocomplete manipulations are in progress
110
+ unless @autocompleting || !editor.typing
111
+ if event.type == javax.swing.event.DocumentEvent::EventType::REMOVE
112
+ invoke_later do
113
+ repopulate
151
114
  end
115
+ else
116
+ # only suggest on inserts and updates. Not on deletes.
117
+ filter_prefix( editor.editor.item )
152
118
  end
153
119
  end
154
-
155
- # catch the enter key action event
156
- editor.editor.editor_component.add_action_listener do |event|
157
- cell_editor.andand.stopCellEditing
158
- end
159
-
160
- # set initial focus and selection in edit part of combo
161
- editor.editor.editor_component.with do |text_edit|
162
- unless text_edit.text.nil?
163
- # highlight the suggested match, and leave caret
164
- # at the end of the selected text
165
- text_edit.caret_position = 0
166
- text_edit.move_caret_position( text_edit.text.length )
167
- text_edit.request_focus_in_window
168
- end
169
- end
170
-
171
- else
172
- @editor =
173
- if restricted?
174
- show_message( empty_set_message )
175
- nil
176
- else
177
- line_editor( edit_value )
120
+ end
121
+ end
122
+
123
+ def framework_setup( *args )
124
+ # turn on typing the the text field of the combo
125
+ # otherwise prefix matching doesn't work
126
+ editor.editable = true
127
+
128
+ # catch the enter key action event
129
+ editor.editor.editor_component.add_action_listener do |event|
130
+ cell_editor.andand.stopCellEditing
131
+ end
132
+
133
+ # set initial focus and selection in edit part of combo
134
+ editor.editor.editor_component.with do |text_edit|
135
+ unless text_edit.text.nil?
136
+ # highlight the suggested match, and leave caret
137
+ # at the end of the selected text
138
+ text_edit.caret_position = 0
139
+ text_edit.move_caret_position( text_edit.text.length )
140
+ text_edit.request_focus_in_window
178
141
  end
179
142
  end
180
- editor
181
143
  end
182
144
 
183
145
  # Recreate the model and fill it with anything in population that
@@ -260,77 +222,27 @@ class ComboDelegate < Delegate
260
222
  editor.hide_popup if is_combo?
261
223
  end
262
224
 
263
- # returns true if the editor allows values outside of a predefined
264
- # range, false otherwise.
265
- def restricted?
266
- false
267
- end
268
-
269
- # TODO fetch this from the model definition
270
- def allow_null?
271
- true
272
- end
273
-
274
- # Subclasses should override this to fill the combo box
275
- # list with values.
276
- # TODO resolve whether the current item is included, even
277
- # if it isn't in the population already, ie it's excluded
278
- # by date or something like that.
279
- def population
280
- raise "subclass responsibility"
281
- end
282
-
283
- # return true if this delegate needs a combo, false otherwise
284
- def needs_combo?
285
- raise "subclass responsibility"
286
- end
287
-
288
225
  def is_combo?
289
226
  # Assume we're a combo if we don't have an editor yet, otherwise
290
227
  # check
291
228
  editor.nil? || editor.is_a?( javax.swing.JComboBox )
292
229
  end
293
230
 
294
- # return true if this field has no data (needs_combo? is false)
295
- # and is at the same time restricted (ie needs data from somewhere else)
296
- def empty_set?
297
- !needs_combo? && restricted?
298
- end
299
-
300
- # the message to display if the set is empty, and
301
- # the delegate is restricted to a predefined set.
302
- def empty_set_message
303
- raise "subclass responsibility"
304
- end
305
-
306
- # if this delegate has an empty set, return the message, otherwise
307
- # return nil.
308
- def if_empty_message
309
- empty_set_message if empty_set?
310
- end
311
-
312
- def add_nil_item
313
- editor << nil unless editor.include?( nil )
314
- end
315
-
316
- def select_current
317
- editor.selected_item = attribute_value
318
- end
319
-
320
231
  def value
321
232
  # editor could be either a combo or a line (DistinctDelegate with no values yet)
322
233
  if is_combo?
323
234
  if restricted?
324
235
  editor.selected_item
325
236
  else
326
- puts "#{__FILE__}:#{__LINE__}:get the editor's text field value. Take away this output when we know it works. Ie when this gets printed."
327
237
  editor.editor.item
328
238
  end
329
239
  else
330
- puts "#{__FILE__}:#{__LINE__}:line item value: #{editor.text}"
240
+ puts "#{__FILE__}:#{__LINE__}:line item value: #{editor.text}. Take this away when it's printed."
331
241
  editor.text
332
242
  end
333
243
  end
334
244
  end
335
245
 
336
246
  end
247
+
248
+ require 'clevic/delegates/combo_delegate.rb'
@@ -8,6 +8,8 @@ module Clevic
8
8
  @message_receivers = Set.new
9
9
  end
10
10
 
11
+ # FIXME this must actually show a message, and
12
+ # the Qt code must use it too
11
13
  def show_message( msg, &block )
12
14
  if block_given?
13
15
  @message_receivers << block
@@ -7,24 +7,12 @@ module Clevic
7
7
  # :frequency can be set as an option. Boolean. If it's true
8
8
  # the options are sorted in order of most frequently used first.
9
9
  class DistinctDelegate < ComboDelegate
10
- def needs_combo?
11
- # works except when there is a '' in the column
12
- entity_class.adaptor.count( attribute.to_s, find_options ) > 0
13
- end
14
-
15
10
  # strings are stored in the model
16
11
  def display_for( model_value )
17
12
  model_value
18
13
  end
19
-
20
- def population
21
- # we only use the first column, so use the second
22
- # column to sort by, since SQL requires the order by clause
23
- # to be in the select list where distinct is involved
24
- entity_class.adaptor.attribute_list( attribute, attribute_value, field.description, field.frequency, find_options ) do |row|
25
- row[attribute]
26
- end
27
- end
28
14
  end
29
15
 
30
16
  end
17
+
18
+ require 'clevic/delegates/distinct_delegate'
@@ -11,10 +11,6 @@ module Clevic
11
11
  class RelationalDelegate < ComboDelegate
12
12
  def initialize( field )
13
13
  super
14
- unless find_options[:conditions].nil?
15
- find_options[:conditions].gsub!( /true/, field.related_class.adaptor.quoted_true )
16
- find_options[:conditions].gsub!( /false/, field.related_class.adaptor.quoted_false )
17
- end
18
14
  end
19
15
 
20
16
  # use the Clevic::ComboBox class because JCombobox is remarkably stupid
@@ -23,22 +19,6 @@ class RelationalDelegate < ComboDelegate
23
19
  ComboBox
24
20
  end
25
21
 
26
- def needs_combo?
27
- field.related_class.adaptor.count( :conditions => find_options[:conditions] ) > 0
28
- end
29
-
30
- def empty_set_message
31
- "There must be records in #{field.related_class.name.humanize} for this field to be editable."
32
- end
33
-
34
- def population
35
- # add set of all possible related entities,
36
- # including the currently selected entity
37
- ary = field.related_class.adaptor.find( :all, find_options )
38
- ary << attribute_value unless ary.include?( attribute_value )
39
- ary
40
- end
41
-
42
22
  # don't allow new values
43
23
  def restricted?
44
24
  true
@@ -46,3 +26,5 @@ class RelationalDelegate < ComboDelegate
46
26
  end
47
27
 
48
28
  end
29
+
30
+ require 'clevic/delegates/relational_delegate.rb'
@@ -5,37 +5,22 @@ module Clevic
5
5
  # A Combo box which allows a set of values. May or may not
6
6
  # be restricted to the set.
7
7
  class SetDelegate < ComboDelegate
8
- # options must contain a :set => [ ... ] to specify the set of values.
9
- def initialize( field )
10
- raise "SetDelegate must have a :set in options" if field.set.nil?
11
- super
12
- end
13
-
14
- def needs_combo?
15
- true
16
- end
17
-
18
- def restricted?
19
- field.restricted || false
20
- end
21
-
22
- def population
23
- field.set_for( entity ).map do |item|
24
- if item.is_a?( Array )
25
- puts "#{__FILE__}:#{__LINE__}:probably can't deal with item: #{item.inspect}"
26
- # this is a hash-like set, so use key as db value
27
- # and value as display value
28
- class << item
29
- def toString; last; end
30
- end
31
- else
32
- class << item
33
- def toString; self; end
34
- end
8
+ def item_to_editor( item )
9
+ if item.is_a?( Array )
10
+ puts "#{__FILE__}:#{__LINE__}:probably can't deal with item: #{item.inspect}"
11
+ # this is a hash-like set, so use key as db value
12
+ # and value as display value
13
+ class << item
14
+ def toString; last; end
15
+ end
16
+ else
17
+ class << item
18
+ def toString; self; end
35
19
  end
36
- item
37
20
  end
38
21
  end
39
22
  end
40
23
 
41
24
  end
25
+
26
+ require 'clevic/delegates/set_delegate.rb'
@@ -286,7 +286,7 @@ class TableView < javax.swing.JScrollPane
286
286
 
287
287
  # calculate the size of the column from the string value of the data
288
288
  def column_width( col, data )
289
- @jtable.getFontMetrics( @jtable.font).stringWidth( data ) + 5
289
+ @jtable.getFontMetrics( @jtable.font ).stringWidth( data.to_s ) + 5
290
290
  end
291
291
 
292
292
  def trim_middle( value, max = 40 )
@@ -140,9 +140,9 @@ class TableModel
140
140
  emit_data_error( index, nil, $!.message )
141
141
  end
142
142
 
143
- def reload_data( options = nil )
143
+ def reload_data( dataset = nil, &dataset_block )
144
144
  # renew cache. All records will be dropped and reloaded.
145
- self.collection = self.cache_table.renew( options )
145
+ self.collection = self.cache_table.renew( dataset, &dataset_block )
146
146
  # tell the UI we had a major data change
147
147
  reset
148
148
  end
@@ -151,9 +151,8 @@ class TableModel
151
151
  # at the moment this only returns the first index found
152
152
  # TODO could handle dataset creation better
153
153
  def search( start_index, search_criteria )
154
- ordered_dataset = entity_class.dataset.order( *cache_table.order_attributes.map{|oa| oa.attribute.to_sym.send( oa.direction ) } )
155
154
  searcher = TableSearcher.new(
156
- ordered_dataset,
155
+ cache_table.dataset,
157
156
  search_criteria,
158
157
  start_index.field
159
158
  )