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.
- 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
@@ -0,0 +1,25 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
class Delegate < Qt::ItemDelegate
|
4
|
+
# Figure out where to put the editor widget, taking into
|
5
|
+
# account the sizes of the headers
|
6
|
+
# TODO most of the subclasses are probably the same as this
|
7
|
+
def updateEditorGeometry( editor, style_option_view_item, model_index )
|
8
|
+
rect = style_option_view_item.rect
|
9
|
+
rect.set_width( [editor.size_hint.width,rect.width].max )
|
10
|
+
rect.set_height( editor.size_hint.height )
|
11
|
+
editor.set_geometry( rect )
|
12
|
+
end
|
13
|
+
|
14
|
+
# This catches the event that begins the edit process.
|
15
|
+
def editorEvent( event, model, style_option_view_item, model_index )
|
16
|
+
# See qt Clevic::TableView
|
17
|
+
parent.respond_to?( "before_edit_index=" ) && parent.before_edit_index = model_index
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'clevic/delegate'
|
@@ -1,35 +1,17 @@
|
|
1
1
|
require 'clevic/qt/combo_delegate.rb'
|
2
|
+
require 'clevic/qt/simplest_delegate.rb'
|
2
3
|
|
3
4
|
module Clevic
|
4
5
|
|
5
|
-
# Provide a list of all values in this field,
|
6
|
-
# and allow new values to be entered.
|
7
|
-
# :frequency can be set as an option. Boolean. If it's true
|
8
|
-
# the options are sorted in order of most frequently used first.
|
9
6
|
class DistinctDelegate < ComboDelegate
|
7
|
+
include SimplestDelegate
|
10
8
|
|
11
|
-
|
12
|
-
# works except when there is a '' in the column
|
13
|
-
entity_class.adaptor.count( attribute.to_s, find_options ) > 0
|
14
|
-
end
|
15
|
-
|
16
|
-
def populate_current( editor, model_index )
|
17
|
-
# already done in the SQL query in populate, so don't even check
|
18
|
-
end
|
19
|
-
|
20
|
-
def populate( editor, model_index )
|
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, model_index.attribute_value, field.description, field.frequency, find_options ) do |row|
|
25
|
-
value = row[attribute]
|
26
|
-
editor.add_item( value, value.to_variant )
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
9
|
+
# This might be unnecessary.
|
30
10
|
def translate_from_editor_text( editor, text )
|
31
11
|
text
|
32
12
|
end
|
33
13
|
end
|
34
14
|
|
35
15
|
end
|
16
|
+
|
17
|
+
require 'clevic/delegates/distinct_delegate.rb'
|
data/lib/clevic/qt/extensions.rb
CHANGED
@@ -13,7 +13,13 @@ module Qt
|
|
13
13
|
def full_edit
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
|
+
class KeyEvent
|
18
|
+
def inspect
|
19
|
+
"<Qt::KeyEvent text=#{text} key=#{key}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
17
23
|
# This provides a bunch of methods to get easy access to the entity
|
18
24
|
# and it's values directly from the index without having to keep
|
19
25
|
# asking the model and jumping through other unncessary hoops
|
@@ -44,4 +50,5 @@ module Qt
|
|
44
50
|
class MessageBox
|
45
51
|
include Clevic::AcceptReject
|
46
52
|
end
|
53
|
+
|
47
54
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Qt
|
2
|
+
# Implement the methods needed for ComboBox to work with the
|
3
|
+
# various Clevic::Delegate classes.
|
4
|
+
class ComboBox
|
5
|
+
def no_insert=( bool )
|
6
|
+
self.insert_policy = Qt::ComboBox::NoInsert if bool
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<( item )
|
10
|
+
text, data = item_to_editor( item )
|
11
|
+
add_item( text, data.to_variant )
|
12
|
+
end
|
13
|
+
|
14
|
+
def include?( item )
|
15
|
+
text, data = item_to_editor( item )
|
16
|
+
find_data( data.to_variant ) != -1
|
17
|
+
end
|
18
|
+
|
19
|
+
def selected_item=( item )
|
20
|
+
text, data = item_to_editor( item )
|
21
|
+
self.current_index = find_data( data.to_variant )
|
22
|
+
end
|
23
|
+
|
24
|
+
def selected_item
|
25
|
+
delegate.editor_to_item( item_data( self.current_index ).value )
|
26
|
+
end
|
27
|
+
|
28
|
+
# wrapper for the delegate method so we don't have
|
29
|
+
# to keep checking for nil values
|
30
|
+
def item_to_editor( item )
|
31
|
+
if item
|
32
|
+
delegate.item_to_editor( item )
|
33
|
+
else
|
34
|
+
['', nil ]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# wrapper for the delegate method so we don't have
|
39
|
+
# to keep checking for nil values
|
40
|
+
def editor_to_item( data )
|
41
|
+
if data
|
42
|
+
delegate.editor_to_item( data )
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adding these to Qt::Widget as the superclass
|
50
|
+
# doesn't work for some reason.
|
51
|
+
class ComboBox
|
52
|
+
attr_accessor :delegate
|
53
|
+
end
|
54
|
+
|
55
|
+
class LineEdit
|
56
|
+
attr_accessor :delegate
|
57
|
+
end
|
58
|
+
end
|
@@ -9,79 +9,39 @@ module Clevic
|
|
9
9
|
# The ids of the model objects are stored in the item data
|
10
10
|
# and the item text is fetched from them using attribute_path.
|
11
11
|
class RelationalDelegate < ComboDelegate
|
12
|
-
def
|
13
|
-
|
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
|
-
end
|
19
|
-
|
20
|
-
def needs_combo?
|
21
|
-
field.related_class.adaptor.count( :conditions => find_options[:conditions] ) > 0
|
12
|
+
def item_to_editor( item )
|
13
|
+
[ field.transform_attribute( item ), item.pk.to_variant ]
|
22
14
|
end
|
23
15
|
|
24
|
-
def
|
25
|
-
|
16
|
+
def editor_to_item( data )
|
17
|
+
entity.related_class[ data ]
|
26
18
|
end
|
27
19
|
|
28
|
-
#
|
29
|
-
def
|
30
|
-
|
31
|
-
# and it makes sense. This is to make sure that if the list
|
32
|
-
# is filtered, we always have the current value if the filter
|
33
|
-
# excludes it
|
34
|
-
unless model_index.nil?
|
35
|
-
item = model_index.attribute_value
|
36
|
-
if item
|
37
|
-
item_index = editor.find_data( item.id.to_variant )
|
38
|
-
if item_index == -1
|
39
|
-
add_to_list( editor, model_index, item )
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def populate( editor, model_index )
|
46
|
-
# add set of all possible related entities
|
47
|
-
field.related_class.adaptor.find( :all, find_options ).each do |x|
|
48
|
-
add_to_list( editor, model_index, x )
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def add_to_list( editor, model_index, item )
|
53
|
-
editor.add_item( model_index.field.transform_attribute( item ), item.id.to_variant )
|
54
|
-
end
|
55
|
-
|
56
|
-
# send data to the editor
|
57
|
-
def setEditorData( editor, model_index )
|
58
|
-
if is_combo?( editor )
|
20
|
+
# called by Qt when it wants to give the delegate an index to edit
|
21
|
+
def setEditorData( editor_widget, model_index )
|
22
|
+
if is_combo?( editor_widget )
|
59
23
|
unless model_index.attribute_value.nil?
|
60
|
-
|
24
|
+
editor_widget.selected_item = model_index.attribute_value
|
61
25
|
end
|
62
|
-
|
26
|
+
editor_widget.line_edit.andand.select_all
|
63
27
|
end
|
64
28
|
end
|
65
29
|
|
66
|
-
#
|
67
|
-
def
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
# return an AR entity object
|
72
|
-
def translate_from_editor_text( editor, text )
|
73
|
-
item_index = editor.find_text( text )
|
30
|
+
# return an entity object, given a text selection
|
31
|
+
def translate_from_editor_text( editor_widget, text )
|
32
|
+
item_index = editor_widget.find_text( text )
|
74
33
|
|
75
|
-
# fetch record id from
|
76
|
-
item_data =
|
34
|
+
# fetch record id from editor_widget item_data
|
35
|
+
item_data = editor_widget.item_data( item_index )
|
77
36
|
if item_data.valid?
|
78
37
|
# get the entity it refers to, if there is one
|
79
|
-
#
|
80
|
-
|
81
|
-
field.related_class.adaptor.find( item_data.to_int )
|
38
|
+
# return nil if nil was passed or the entity wasn't found
|
39
|
+
field.related_class[ item_data.to_int ]
|
82
40
|
end
|
83
41
|
end
|
84
42
|
|
85
43
|
end
|
86
44
|
|
87
45
|
end
|
46
|
+
|
47
|
+
require 'clevic/delegates/relational_delegate.rb'
|
@@ -1,44 +1,14 @@
|
|
1
1
|
require 'clevic/qt/combo_delegate.rb'
|
2
|
+
require 'clevic/qt/simplest_delegate.rb'
|
2
3
|
|
3
4
|
module Clevic
|
4
5
|
|
5
6
|
# A Combo box which allows a set of values. May or may not
|
6
7
|
# be restricted to the set.
|
7
8
|
class SetDelegate < ComboDelegate
|
8
|
-
|
9
|
-
def initialize( field )
|
10
|
-
raise "RestrictedDelegate 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 populate( editor, model_index )
|
23
|
-
field.set_for( model_index.entity ).each do |item|
|
24
|
-
if item.is_a?( Array )
|
25
|
-
# this is a hash-like set, so use key as db value
|
26
|
-
# and value as display value
|
27
|
-
editor.add_item( item.last, item.first.to_variant )
|
28
|
-
else
|
29
|
-
editor.add_item( item, item.to_variant )
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def createEditor( parent_widget, style_option_view_item, model_index )
|
35
|
-
editor = super
|
36
|
-
|
37
|
-
# the set is provided, so never insert things
|
38
|
-
editor.insert_policy = Qt::ComboBox::NoInsert
|
39
|
-
editor
|
40
|
-
end
|
41
|
-
|
9
|
+
include SimplestDelegate
|
42
10
|
end
|
43
11
|
|
44
12
|
end
|
13
|
+
|
14
|
+
require 'clevic/delegates/set_delegate'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
# These methods are common between SetDelegate and DistinctDelegate
|
4
|
+
module SimplestDelegate
|
5
|
+
def item_to_editor( item )
|
6
|
+
if item.is_a?( Array )
|
7
|
+
[ item.last, item.first ]
|
8
|
+
else
|
9
|
+
[ item, item ]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def editor_to_item( data )
|
15
|
+
data.value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'Qt4'
|
2
1
|
require 'date'
|
3
2
|
|
4
3
|
require 'andand'
|
@@ -86,7 +85,7 @@ class TableModel < Qt::AbstractTableModel
|
|
86
85
|
retval = item_boolean_flags
|
87
86
|
end
|
88
87
|
|
89
|
-
unless model_index.field.read_only? ||
|
88
|
+
unless model_index.field.read_only? || read_only?
|
90
89
|
retval |= qt_item_is_editable.to_i
|
91
90
|
end
|
92
91
|
retval
|
@@ -101,12 +100,8 @@ class TableModel < Qt::AbstractTableModel
|
|
101
100
|
when Qt::Horizontal
|
102
101
|
labels[section]
|
103
102
|
when Qt::Vertical
|
104
|
-
#
|
105
|
-
|
106
|
-
collection[section].id
|
107
|
-
else
|
108
|
-
section
|
109
|
-
end
|
103
|
+
# display record number. Object id is in tooltip.
|
104
|
+
section+1
|
110
105
|
end
|
111
106
|
|
112
107
|
when qt_text_alignment_role
|
@@ -128,8 +123,12 @@ class TableModel < Qt::AbstractTableModel
|
|
128
123
|
case
|
129
124
|
when !collection[section].errors.empty?
|
130
125
|
'Invalid data'
|
131
|
-
when collection[section].
|
126
|
+
when collection[section].modified?
|
132
127
|
'Unsaved changes'
|
128
|
+
else
|
129
|
+
if collection.cached_at?( section )
|
130
|
+
collection[section].pk.inspect
|
131
|
+
end
|
133
132
|
end
|
134
133
|
end
|
135
134
|
|
@@ -198,7 +197,7 @@ class TableModel < Qt::AbstractTableModel
|
|
198
197
|
|
199
198
|
when qt_foreground_role
|
200
199
|
index.field.foreground_for( index.entity ) ||
|
201
|
-
if index.field.read_only? ||
|
200
|
+
if index.field.read_only? || read_only?
|
202
201
|
Qt::Color.new( 'dimgray' )
|
203
202
|
end
|
204
203
|
|
@@ -271,6 +270,7 @@ class TableModel < Qt::AbstractTableModel
|
|
271
270
|
# user-defined role
|
272
271
|
# TODO this only works with single-dotted paths
|
273
272
|
when qt_paste_role
|
273
|
+
puts "WARNING Qt::PasteRole Deprecated"
|
274
274
|
if index.meta.type == :association
|
275
275
|
field = index.field
|
276
276
|
candidates = field.related_class.find( :all, :conditions => [ "#{field.attribute_path[1]} = ?", variant.value ] )
|
data/lib/clevic/qt/table_view.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'Qt4'
|
3
1
|
require 'fastercsv'
|
4
2
|
require 'qtext/action_builder.rb'
|
5
|
-
|
6
3
|
require 'clevic/model_builder.rb'
|
7
4
|
require 'clevic/filter_command.rb'
|
8
5
|
|
@@ -46,10 +43,12 @@ class TableView < Qt::TableView
|
|
46
43
|
self.sorting_enabled = false
|
47
44
|
|
48
45
|
# set fonts
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
# TODO leave this here, but commented so we can see how to do it
|
47
|
+
# properly later.
|
48
|
+
#~ Qt::Font.new( font.family, font.point_size * 5 / 6 ).tap do |fnt|
|
49
|
+
#~ self.font = fnt
|
50
|
+
#~ self.horizontal_header.font = fnt
|
51
|
+
#~ end
|
53
52
|
|
54
53
|
self.context_menu_policy = Qt::ActionsContextMenu
|
55
54
|
end
|
@@ -205,21 +204,6 @@ class TableView < Qt::TableView
|
|
205
204
|
error_message.show
|
206
205
|
end
|
207
206
|
|
208
|
-
# This is to allow entity model UI handlers to tell the view
|
209
|
-
# whence to move the cursor when the current editor closes
|
210
|
-
# (see closeEditor).
|
211
|
-
# TODO not used?
|
212
|
-
def override_next_index( model_index )
|
213
|
-
self.next_index = model_index
|
214
|
-
end
|
215
|
-
|
216
|
-
# Call set_current_index with next_index ( from override_next_index )
|
217
|
-
# or model_index, in that order. Set next_index to nil afterwards.
|
218
|
-
def set_current_unless_override( model_index )
|
219
|
-
set_current_index( @next_index || model_index )
|
220
|
-
self.next_index = nil
|
221
|
-
end
|
222
|
-
|
223
207
|
# work around situation where an ItemDelegate is open
|
224
208
|
# when the surrouding tab is changed, but the right events
|
225
209
|
# don't arrive.
|
@@ -269,7 +253,7 @@ class TableView < Qt::TableView
|
|
269
253
|
end
|
270
254
|
|
271
255
|
rescue Exception => e
|
272
|
-
raise RuntimeError, "#{model.entity_view.class.name}.#{model_index.field.id}: #{e.message}",
|
256
|
+
raise RuntimeError, "#{model.entity_view.class.name}.#{model_index.field.id}: #{e.message}", e.backtrace
|
273
257
|
end
|
274
258
|
|
275
259
|
attr_accessor :before_edit_index
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'clevic/qt/
|
1
|
+
require 'clevic/qt/delegate.rb'
|
2
2
|
|
3
3
|
module Clevic
|
4
4
|
|
5
|
-
class TextDelegate <
|
5
|
+
class TextDelegate < Delegate
|
6
6
|
|
7
7
|
# Doesn't do anything useful yet, but I'm leaving
|
8
8
|
# it here so I don't have to change other code.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
=begin
|
2
2
|
** Form generated from reading ui file 'browser.ui'
|
3
3
|
**
|
4
|
-
** Created: Mon Jan
|
4
|
+
** Created: Mon Jan 31 16:10:23 2011
|
5
5
|
** by: Qt User Interface Compiler version 4.5.1
|
6
6
|
**
|
7
7
|
** WARNING! All changes made in this file will be lost when recompiling ui file!
|