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
@@ -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
|