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
@@ -1,7 +1,7 @@
|
|
1
1
|
=begin
|
2
2
|
** Form generated from reading ui file 'search_dialog.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!
|
@@ -1,5 +1,18 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
|
3
|
+
def subclasses( base )
|
4
|
+
classes = []
|
5
|
+
ObjectSpace.each_object( Class ) do |x|
|
6
|
+
if x.ancestors.include?( base )
|
7
|
+
case
|
8
|
+
when x == Clevic.base_entity_class; # don't include this
|
9
|
+
else; classes << x
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
classes.sort{|a,b| a.name <=> b.name}
|
14
|
+
end
|
15
|
+
|
3
16
|
def load_rails_models( root, config, models )
|
4
17
|
# initialize Rails
|
5
18
|
load config / 'environment.rb'
|
data/lib/clevic/record.rb
CHANGED
@@ -30,11 +30,11 @@ module Clevic
|
|
30
30
|
# keep track of the order in which views are
|
31
31
|
# defined, so that can be used as the default ordering
|
32
32
|
# of the views.
|
33
|
-
Clevic::View.order << default_view_class_name
|
33
|
+
Clevic::View.order << eval( default_view_class_name )
|
34
34
|
end
|
35
35
|
|
36
36
|
def default_view_class
|
37
|
-
@default_view_class ||= eval default_view_class_name
|
37
|
+
@default_view_class ||= eval( default_view_class_name )
|
38
38
|
end
|
39
39
|
|
40
40
|
# Need to defer the execution of the view definition block
|
data/lib/clevic/sampler.rb
CHANGED
@@ -3,65 +3,98 @@ require 'andand'
|
|
3
3
|
|
4
4
|
module Clevic
|
5
5
|
|
6
|
-
#
|
6
|
+
# This is used as part of the process of calculating the width
|
7
|
+
# of a field in the UI. Since the font is important, this computes
|
8
|
+
# a string value for a field that can be given to the font metrics
|
9
|
+
# for a framework. Uses various heuristics to compute the string
|
10
|
+
# values for different kinds of fields.
|
7
11
|
class Sampler
|
8
|
-
|
9
|
-
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@format_block = block
|
12
|
+
# display is only used for relational fields
|
13
|
+
def initialize( field, &format_block )
|
14
|
+
@field = field
|
15
|
+
@format_block = format_block
|
13
16
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
attr_reader :field
|
18
|
+
|
19
|
+
def entity_class
|
20
|
+
field.entity_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def field_name
|
24
|
+
field.attribute
|
25
|
+
end
|
26
|
+
|
27
|
+
def display
|
28
|
+
field.display
|
29
|
+
end
|
30
|
+
|
17
31
|
def meta
|
18
|
-
|
32
|
+
field.meta
|
19
33
|
end
|
20
|
-
|
34
|
+
|
21
35
|
# return a string which is representative of the width of the field
|
22
36
|
def compute
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# TODO return a width, or something like that
|
34
|
-
when :boolean; 'W'
|
35
|
-
|
36
|
-
when :many_to_one
|
37
|
-
related_sample
|
38
|
-
|
37
|
+
if field.set
|
38
|
+
# choose the longest value in the set
|
39
|
+
set = field.set_for( entity_class.first )
|
40
|
+
if set.is_a?( Hash )
|
41
|
+
set.values
|
42
|
+
else
|
43
|
+
set
|
44
|
+
end. \
|
45
|
+
max{|a,b| a.to_s.length <=> b.to_s.length }.upcase
|
39
46
|
else
|
40
|
-
|
41
|
-
|
47
|
+
# choose samples based on the type of the field
|
48
|
+
case meta.type
|
49
|
+
when :boolean
|
50
|
+
field.label
|
51
|
+
|
52
|
+
when :string, :text
|
53
|
+
string_sample
|
54
|
+
|
55
|
+
when :date, :time, :datetime, :timestamp
|
56
|
+
date_time_sample
|
57
|
+
|
58
|
+
when :numeric, :decimal, :integer, :float
|
59
|
+
numeric_sample
|
60
|
+
|
61
|
+
# TODO return a width, or something like that
|
62
|
+
when :boolean; 'W'
|
63
|
+
|
64
|
+
when :many_to_one
|
65
|
+
related_sample
|
66
|
+
|
67
|
+
else
|
68
|
+
if meta.type != NilClass
|
69
|
+
raise "Sampler#compute can't figure out sample for #{entity_class.name}.#{field_name} because it's a #{meta.type.inspect}"
|
70
|
+
end
|
42
71
|
end
|
43
|
-
|
44
72
|
end
|
45
73
|
end
|
46
|
-
|
74
|
+
|
47
75
|
def do_format( value )
|
48
76
|
@format_block.call( value )
|
49
77
|
end
|
50
|
-
|
78
|
+
|
51
79
|
# default to max length of 20
|
52
80
|
def string_sample
|
53
81
|
'N' * ( entity_class.max( :length.sql_function( field_name ) ).andand.to_i || 20 )
|
54
82
|
end
|
55
83
|
|
56
|
-
def
|
57
|
-
|
84
|
+
def sample_date_time
|
85
|
+
ds = entity_class \
|
58
86
|
.filter( ~{ field_name => nil } ) \
|
59
87
|
.select( field_name ) \
|
60
|
-
.limit(1)
|
61
|
-
|
62
|
-
|
88
|
+
.limit(1)
|
89
|
+
# can't use single-value here because the typecast_on_load
|
90
|
+
# isn't called unless we access the value via the entity object
|
91
|
+
ds.first.send( field_name )
|
92
|
+
end
|
93
|
+
|
94
|
+
def date_time_sample
|
63
95
|
# replace all letters with 'N'
|
64
|
-
|
96
|
+
# and numbers with 8
|
97
|
+
do_format( sample_date_time || Date.today ).andand.gsub( /[[:alpha:]]/, 'N' ).gsub( /\d/, '8' )
|
65
98
|
end
|
66
99
|
|
67
100
|
def numeric_sample
|
@@ -71,9 +104,22 @@ class Sampler
|
|
71
104
|
'9' * ( max_length || 5 )
|
72
105
|
end
|
73
106
|
|
107
|
+
# Hmm. The first reified exemplar of a relational nested Field
|
108
|
+
class VirtualField
|
109
|
+
def initialize( entity_class, display )
|
110
|
+
@entity_class, @display = entity_class, display
|
111
|
+
end
|
112
|
+
|
113
|
+
def entity_class; @entity_class; end
|
114
|
+
def attribute; @display; end
|
115
|
+
def display; nil; end
|
116
|
+
def meta; @entity_class.meta[attribute]; end
|
117
|
+
def set; nil; end
|
118
|
+
end
|
119
|
+
|
74
120
|
def related_sample
|
75
121
|
if display.respond_to?( :to_sym )
|
76
|
-
Sampler.new( eval( meta.class_name ), display.to_sym
|
122
|
+
Sampler.new( VirtualField.new( eval( meta.class_name ), display.to_sym ), &@format_block ).compute
|
77
123
|
end
|
78
124
|
end
|
79
125
|
end
|
@@ -123,6 +123,7 @@ end
|
|
123
123
|
module Sequel
|
124
124
|
class Model
|
125
125
|
class << self
|
126
|
+
# for translating class methods for relations
|
126
127
|
def translate_options( options )
|
127
128
|
options[:key] = options[:foreign_key].andand.to_sym
|
128
129
|
options.delete( :foreign_key )
|
@@ -150,18 +151,6 @@ module Sequel
|
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
153
|
-
def table_exists?
|
154
|
-
db.table_exists?( implicit_table_name )
|
155
|
-
end
|
156
|
-
|
157
|
-
def column_names
|
158
|
-
columns
|
159
|
-
end
|
160
|
-
|
161
|
-
def reflections
|
162
|
-
association_reflections
|
163
|
-
end
|
164
|
-
|
165
154
|
def has_attribute?( attribute )
|
166
155
|
column_names.include?( attribute )
|
167
156
|
end
|
@@ -182,22 +171,6 @@ module Sequel
|
|
182
171
|
end
|
183
172
|
end
|
184
173
|
|
185
|
-
def readonly?
|
186
|
-
false
|
187
|
-
end
|
188
|
-
|
189
|
-
def changed?
|
190
|
-
modified?
|
191
|
-
end
|
192
|
-
|
193
|
-
def new_record?; new?; end
|
194
|
-
|
195
|
-
class Errors
|
196
|
-
def invalid?( field_name )
|
197
|
-
self.has_key?( field_name )
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
174
|
module Associations
|
202
175
|
class ManyToOneAssociationReflection
|
203
176
|
# return class for this side of the association
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# This is used by Clevic to talk to models. It's here because
|
6
|
+
# I'd rather keep some kind of layer in case it's necessary
|
7
|
+
# to become more pluggable in relation to ORM frameworks.
|
8
|
+
module Clevic
|
9
|
+
def self.configure(model, options = {})
|
10
|
+
model.instance_eval do
|
11
|
+
# store model-related stuff here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# Copy the necessary class instance variables to the subclass.
|
17
|
+
def inherited(subclass)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
# This doesn't really belong here, but I don't want to make
|
22
|
+
# a whole new plugin.
|
23
|
+
def table_exists?
|
24
|
+
db.table_exists?( implicit_table_name )
|
25
|
+
end
|
26
|
+
|
27
|
+
# Hmm, maybe these need to go in a different plugin
|
28
|
+
def column_names
|
29
|
+
columns
|
30
|
+
end
|
31
|
+
|
32
|
+
# Getting heavy enough, yet?
|
33
|
+
def reflections
|
34
|
+
association_reflections
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
# This should also go in another plugin
|
41
|
+
def changed?
|
42
|
+
modified?
|
43
|
+
end
|
44
|
+
|
45
|
+
def readonly?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def new_record?
|
50
|
+
new?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Sequel::Model.plugin :clevic
|
58
|
+
|
59
|
+
# This doesn't seem to work inside the plugin
|
60
|
+
module Sequel
|
61
|
+
class Model
|
62
|
+
class Errors
|
63
|
+
def invalid?( field_name )
|
64
|
+
self.has_key?( field_name )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/clevic/sequel_meta.rb
CHANGED
@@ -15,19 +15,6 @@ module Sequel
|
|
15
15
|
end
|
16
16
|
|
17
17
|
module ClassMethods
|
18
|
-
# Copy the necessary class instance variables to the subclass.
|
19
|
-
def inherited(subclass)
|
20
|
-
super
|
21
|
-
#~ store = @cache_store
|
22
|
-
#~ ttl = @cache_ttl
|
23
|
-
#~ cache_ignore_exceptions = @cache_ignore_exceptions
|
24
|
-
#~ subclass.instance_eval do
|
25
|
-
#~ @cache_store = store
|
26
|
-
#~ @cache_ttl = ttl
|
27
|
-
#~ @cache_ignore_exceptions = cache_ignore_exceptions
|
28
|
-
#~ end
|
29
|
-
end
|
30
|
-
|
31
18
|
def meta
|
32
19
|
if @meta.nil?
|
33
20
|
@meta = {}
|
@@ -54,6 +41,7 @@ module Sequel
|
|
54
41
|
meta.values.map( &:keys ).include?( [ column ] )
|
55
42
|
end
|
56
43
|
end
|
44
|
+
|
57
45
|
end
|
58
46
|
|
59
47
|
module InstanceMethods
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# copied from http://snippets.dzone.com/posts/show/2992
|
2
|
+
class Object
|
3
|
+
def self.subclasses(direct = false)
|
4
|
+
classes = []
|
5
|
+
if direct
|
6
|
+
ObjectSpace.each_object(Class) do |c|
|
7
|
+
next unless c.superclass == self
|
8
|
+
classes << c
|
9
|
+
end
|
10
|
+
else
|
11
|
+
ObjectSpace.each_object(Class) do |c|
|
12
|
+
next unless c.ancestors.include?(self) and (c != self)
|
13
|
+
classes << c
|
14
|
+
end
|
15
|
+
end
|
16
|
+
classes
|
17
|
+
end
|
18
|
+
end
|
data/lib/clevic/swing.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
Require this file to do Clevic in Swing with JRuby
|
3
3
|
=end
|
4
4
|
|
5
|
-
require '
|
5
|
+
require 'clevic/framework'
|
6
6
|
|
7
7
|
# This seems to be required for jruby-1.5.x (at least for 1.5.2)
|
8
8
|
require 'java'
|
@@ -12,6 +12,7 @@ require 'clevic/swing/table_model.rb'
|
|
12
12
|
require 'clevic/swing/table_view.rb'
|
13
13
|
|
14
14
|
# all other files in the swing subdirectory
|
15
|
+
require 'pathname'
|
15
16
|
( Pathname.new( __FILE__ ).parent + 'swing' ).children.grep( /.rb$/ ).each do |child|
|
16
17
|
require child.to_s
|
17
18
|
end
|
data/lib/clevic/swing/action.rb
CHANGED
@@ -4,10 +4,22 @@ module Clevic
|
|
4
4
|
|
5
5
|
class Action
|
6
6
|
include Gather
|
7
|
-
property :shortcut, :method, :handler, :tool_tip, :visible
|
7
|
+
property :shortcut, :method, :handler, :tool_tip, :visible
|
8
|
+
property :name, :text, :checkable, :enabled
|
9
|
+
|
10
|
+
# Needed to enable / disable accelerators on the fly.
|
11
|
+
def enabled=( bool )
|
12
|
+
# test for @menu_item instead of the method to
|
13
|
+
# work around Swing Stupidity. See comments in menu_item.
|
14
|
+
menu_item.enabled = bool unless @menu_item.nil?
|
15
|
+
@enabled = bool
|
16
|
+
end
|
8
17
|
|
9
18
|
def initialize( parent, options = {}, &block )
|
10
19
|
@parent = parent
|
20
|
+
@enabled = true
|
21
|
+
|
22
|
+
# work around the Swing Stupidity detailed in enabled=
|
11
23
|
gather( options, &block )
|
12
24
|
end
|
13
25
|
attr_reader :parent, :menu_item
|
@@ -16,6 +28,10 @@ class Action
|
|
16
28
|
text.gsub( /&/, '' )
|
17
29
|
end
|
18
30
|
|
31
|
+
def object_name
|
32
|
+
name.to_s
|
33
|
+
end
|
34
|
+
|
19
35
|
# find the java.awt.event.KeyEvent::VK constant
|
20
36
|
# for the letter after the &. Then set it on the item's
|
21
37
|
# mnemonic. Because JMenuItem.setMnemonic won't take a nil
|
@@ -41,6 +57,12 @@ class Action
|
|
41
57
|
javax.swing.JMenuItem.new
|
42
58
|
end
|
43
59
|
|
60
|
+
# Menu item always enabled, until later.
|
61
|
+
# Otherwise it prevents the assignment
|
62
|
+
# of an accelerator key. So we have to
|
63
|
+
# work around yet another Swing stupidity.
|
64
|
+
menu_item.enabled = true
|
65
|
+
|
44
66
|
menu_item.text = plain_text
|
45
67
|
menu_item.mnemonic = mnemonic if mnemonic
|
46
68
|
menu_item.accelerator = parse_shortcut( shortcut ) unless shortcut.nil?
|
@@ -48,6 +70,10 @@ class Action
|
|
48
70
|
menu_item.add_action_listener do |event|
|
49
71
|
handler.call( event )
|
50
72
|
end
|
73
|
+
|
74
|
+
# Put this at the end so it doesn't interfere with the
|
75
|
+
# keystroke assignment Swing Stupidity.
|
76
|
+
menu_item.enabled = enabled
|
51
77
|
end
|
52
78
|
@menu_item
|
53
79
|
end
|
@@ -92,7 +118,6 @@ class Action
|
|
92
118
|
|
93
119
|
else
|
94
120
|
keystring = javax.swing.KeyStroke.getKeyStroke( java.lang.Character.new( last.to_char ), modifier_mask ).toString
|
95
|
-
puts "keystring: #{keystring.inspect}"
|
96
121
|
# have to do this conversion for Mac OS X
|
97
122
|
javax.swing.KeyStroke.getKeyStroke( keystring.gsub( /typed/, 'pressed' ) )
|
98
123
|
end
|
@@ -103,7 +128,6 @@ class Action
|
|
103
128
|
raise "too many options for #{sequence}: #{found.inspect}" if found.size != 1
|
104
129
|
javax.swing.KeyStroke.getKeyStroke( eval( "java.awt.event.KeyEvent::#{found.first}" ), modifier_mask )
|
105
130
|
end
|
106
|
-
puts "keystroke: #{keystroke.inspect}"
|
107
131
|
keystroke || raise( "unknown keystroke #{sequence} => #{modifiers.inspect} #{last}" )
|
108
132
|
end
|
109
133
|
end
|