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.
- data/History.txt +21 -0
- data/Manifest.txt +91 -85
- data/README.txt +33 -18
- data/Rakefile +2 -3
- data/TODO +8 -14
- data/bin/clevic +18 -20
- data/lib/clevic.rb +7 -1
- data/lib/clevic/action_builder.rb +4 -1
- data/lib/clevic/ar_methods.rb +72 -57
- data/lib/clevic/attribute_list.rb +4 -0
- data/lib/clevic/cache_table.rb +43 -69
- data/lib/clevic/dataset_roller.rb +22 -0
- data/lib/clevic/delegate.rb +11 -5
- data/lib/clevic/delegates/combo_delegate.rb +156 -0
- data/lib/clevic/delegates/distinct_delegate.rb +48 -0
- data/lib/clevic/delegates/relational_delegate.rb +59 -0
- data/lib/clevic/delegates/set_delegate.rb +31 -0
- data/lib/clevic/field.rb +39 -55
- data/lib/clevic/field_valuer.rb +23 -10
- data/lib/clevic/filter_command.rb +22 -36
- data/lib/clevic/framework.rb +37 -0
- data/lib/clevic/generic_format.rb +5 -1
- data/lib/clevic/many_field.rb +28 -3
- data/lib/clevic/model_builder.rb +27 -32
- data/lib/clevic/ordered_dataset.rb +45 -0
- data/lib/clevic/qt.rb +4 -1
- data/lib/clevic/qt/action_builder.rb +9 -1
- data/lib/clevic/qt/browser.rb +1 -1
- data/lib/clevic/qt/clipboard.rb +3 -3
- data/lib/clevic/qt/combo_delegate.rb +25 -89
- data/lib/clevic/qt/delegate.rb +25 -0
- data/lib/clevic/qt/distinct_delegate.rb +5 -23
- data/lib/clevic/qt/extensions.rb +8 -1
- data/lib/clevic/qt/qt_combo_box.rb +58 -0
- data/lib/clevic/qt/relational_delegate.rb +18 -58
- data/lib/clevic/qt/set_delegate.rb +4 -34
- data/lib/clevic/qt/simplest_delegate.rb +19 -0
- data/lib/clevic/qt/table_model.rb +10 -10
- data/lib/clevic/qt/table_view.rb +7 -23
- data/lib/clevic/qt/text_delegate.rb +2 -2
- data/lib/clevic/qt/ui/browser_ui.rb +1 -1
- data/lib/clevic/qt/ui/search_dialog_ui.rb +1 -1
- data/lib/clevic/rails_models_loaders.rb +13 -0
- data/lib/clevic/record.rb +2 -2
- data/lib/clevic/sampler.rb +85 -39
- data/lib/clevic/sequel_ar_adapter.rb +1 -28
- data/lib/clevic/sequel_clevic.rb +68 -0
- data/lib/clevic/sequel_meta.rb +1 -13
- data/lib/clevic/subclasses.rb +18 -0
- data/lib/clevic/swing.rb +2 -1
- data/lib/clevic/swing/action.rb +27 -3
- data/lib/clevic/swing/action_builder.rb +0 -2
- data/lib/clevic/swing/browser.rb +1 -10
- data/lib/clevic/swing/combo_delegate.rb +45 -133
- data/lib/clevic/swing/delegate.rb +2 -0
- data/lib/clevic/swing/distinct_delegate.rb +2 -14
- data/lib/clevic/swing/relational_delegate.rb +2 -20
- data/lib/clevic/swing/set_delegate.rb +13 -28
- data/lib/clevic/swing/table_view.rb +1 -1
- data/lib/clevic/table_model.rb +3 -4
- data/lib/clevic/table_searcher.rb +10 -31
- data/lib/clevic/table_view.rb +97 -43
- data/lib/clevic/ui/browser_ui.rb +133 -0
- data/lib/clevic/ui/search_dialog_ui.rb +106 -0
- data/lib/clevic/version.rb +2 -2
- data/models/accounts_models.rb +24 -21
- data/models/times_models.rb +34 -28
- data/models/times_psql_models.rb +9 -3
- data/models/times_sqlite_models.rb +24 -1
- data/sql/times_sqlite.sql +3 -3
- data/tasks/clevic.rake +2 -2
- data/test/test_cache_table.rb +9 -19
- data/test/test_table_searcher.rb +2 -5
- metadata +95 -91
- data/lib/clevic/order_attribute.rb +0 -63
- data/lib/clevic/qt/boolean_delegate.rb +0 -8
- data/lib/clevic/qt/delegates.rb +0 -1
- data/lib/clevic/qt/item_delegate.rb +0 -66
- data/lib/clevic/sql_dialects.rb +0 -33
- data/tasks/website.rake +0 -25
- data/test/test_order_attribute.rb +0 -62
- 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
|
data/lib/clevic/swing/browser.rb
CHANGED
@@ -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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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'
|
@@ -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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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 )
|
data/lib/clevic/table_model.rb
CHANGED
@@ -140,9 +140,9 @@ class TableModel
|
|
140
140
|
emit_data_error( index, nil, $!.message )
|
141
141
|
end
|
142
142
|
|
143
|
-
def reload_data(
|
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(
|
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
|
-
|
155
|
+
cache_table.dataset,
|
157
156
|
search_criteria,
|
158
157
|
start_index.field
|
159
158
|
)
|