clevic 0.13.0.b3 → 0.13.0.b5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  )