clevic 0.12.0 → 0.13.0.b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/History.txt +10 -0
  2. data/Manifest.txt +209 -30
  3. data/README.txt +16 -20
  4. data/Rakefile +8 -8
  5. data/TODO +6 -7
  6. data/bin/clevic +12 -73
  7. data/lib/clevic/action_builder.rb +168 -0
  8. data/lib/clevic/ar_methods.rb +120 -0
  9. data/lib/clevic/attribute_list.rb +56 -0
  10. data/lib/clevic/cache_table.rb +60 -37
  11. data/lib/clevic/default_view.rb +3 -16
  12. data/lib/clevic/delegate.rb +46 -0
  13. data/lib/clevic/emitter.rb +38 -0
  14. data/lib/clevic/extensions.rb +61 -114
  15. data/lib/clevic/field.rb +159 -228
  16. data/lib/clevic/field_valuer.rb +165 -0
  17. data/lib/clevic/filter_command.rb +2 -6
  18. data/lib/clevic/generic_format.rb +52 -0
  19. data/lib/clevic/{ui → icons}/icon.png +0 -0
  20. data/lib/clevic/many_field.rb +7 -0
  21. data/lib/clevic/model_builder.rb +234 -146
  22. data/lib/clevic/model_column.rb +61 -13
  23. data/lib/clevic/order_attribute.rb +10 -0
  24. data/lib/clevic/qt.rb +35 -0
  25. data/lib/clevic/qt/action_builder.rb +47 -0
  26. data/lib/clevic/qt/boolean_delegate.rb +8 -0
  27. data/lib/clevic/{browser.rb → qt/browser.rb} +35 -14
  28. data/lib/clevic/qt/clipboard.rb +35 -0
  29. data/lib/clevic/qt/combo_delegate.rb +198 -0
  30. data/lib/clevic/qt/delegates.rb +1 -0
  31. data/lib/clevic/qt/distinct_delegate.rb +35 -0
  32. data/lib/clevic/qt/extensions.rb +52 -0
  33. data/lib/clevic/qt/field.rb +18 -0
  34. data/lib/clevic/{item_delegate.rb → qt/item_delegate.rb} +8 -4
  35. data/lib/clevic/qt/relational_delegate.rb +87 -0
  36. data/lib/clevic/{search_dialog.rb → qt/search_dialog.rb} +1 -11
  37. data/lib/clevic/qt/set_delegate.rb +44 -0
  38. data/lib/clevic/qt/table_model.rb +331 -0
  39. data/lib/clevic/qt/table_view.rb +344 -0
  40. data/lib/clevic/qt/text_area_delegate.rb +8 -0
  41. data/lib/clevic/{text_delegate.rb → qt/text_delegate.rb} +6 -4
  42. data/lib/clevic/{ui → qt/ui}/.gitignore +0 -0
  43. data/lib/clevic/{ui → qt/ui}/browser.ui +0 -0
  44. data/lib/clevic/{ui → qt/ui}/search_dialog.ui +0 -0
  45. data/lib/clevic/rails_models_loaders.rb +56 -0
  46. data/lib/clevic/record.rb +2 -17
  47. data/lib/clevic/sampler.rb +81 -0
  48. data/lib/clevic/sequel_ar_adapter.rb +215 -0
  49. data/lib/clevic/sequel_length_validation.rb +23 -0
  50. data/lib/clevic/sequel_meta.rb +65 -0
  51. data/lib/clevic/sequel_naked.rb +30 -0
  52. data/lib/clevic/swing.rb +38 -0
  53. data/lib/clevic/swing/action.rb +125 -0
  54. data/lib/clevic/swing/action_builder.rb +47 -0
  55. data/lib/clevic/swing/boolean_delegate.rb +26 -0
  56. data/lib/clevic/swing/browser.rb +282 -0
  57. data/lib/clevic/swing/cell_editor.rb +95 -0
  58. data/lib/clevic/swing/cell_renderer.rb +44 -0
  59. data/lib/clevic/swing/clipboard.rb +135 -0
  60. data/lib/clevic/swing/combo_delegate.rb +336 -0
  61. data/lib/clevic/swing/confirm_dialog.rb +57 -0
  62. data/lib/clevic/swing/delegate.rb +40 -0
  63. data/lib/clevic/swing/distinct_delegate.rb +30 -0
  64. data/lib/clevic/swing/extensions.rb +274 -0
  65. data/lib/clevic/swing/field.rb +35 -0
  66. data/lib/clevic/swing/relational_delegate.rb +48 -0
  67. data/lib/clevic/swing/row_header.rb +210 -0
  68. data/lib/clevic/swing/search_dialog.rb +230 -0
  69. data/lib/clevic/swing/selection_model.rb +90 -0
  70. data/lib/clevic/swing/set_delegate.rb +41 -0
  71. data/lib/clevic/swing/swing_table_index.rb +43 -0
  72. data/lib/clevic/swing/table_model.rb +200 -0
  73. data/lib/clevic/swing/table_view.rb +385 -0
  74. data/lib/clevic/swing/table_view_focus.rb +47 -0
  75. data/lib/clevic/swing/tag_delegate.rb +127 -0
  76. data/lib/clevic/swing/tag_editor.rb +101 -0
  77. data/lib/clevic/swing/text_area_delegate.rb +46 -0
  78. data/lib/clevic/swing/text_delegate.rb +31 -0
  79. data/lib/clevic/swing/ui/build.xml +74 -0
  80. data/lib/clevic/swing/ui/dist/README.TXT +33 -0
  81. data/lib/clevic/swing/ui/dist/lib/swing-layout-1.0.3.jar +0 -0
  82. data/lib/clevic/swing/ui/manifest.mf +3 -0
  83. data/lib/clevic/swing/ui/nbproject/build-impl.xml +731 -0
  84. data/lib/clevic/swing/ui/nbproject/genfiles.properties +8 -0
  85. data/lib/clevic/swing/ui/nbproject/private/config.properties +0 -0
  86. data/lib/clevic/swing/ui/nbproject/private/private.properties +6 -0
  87. data/lib/clevic/swing/ui/nbproject/private/private.xml +4 -0
  88. data/lib/clevic/swing/ui/nbproject/project.properties +70 -0
  89. data/lib/clevic/swing/ui/nbproject/project.xml +14 -0
  90. data/lib/clevic/swing/ui/src/SearchDialog.form +158 -0
  91. data/lib/clevic/swing/ui/src/SearchDialog.java +163 -0
  92. data/lib/clevic/swing/ui/src/TagEditor.form +106 -0
  93. data/lib/clevic/swing/ui/src/TagEditor.java +108 -0
  94. data/lib/clevic/swing/ui/src/resources/SearchDialog.properties +0 -0
  95. data/lib/clevic/table_index.rb +100 -0
  96. data/lib/clevic/table_model.rb +54 -425
  97. data/lib/clevic/table_searcher.rb +113 -116
  98. data/lib/clevic/table_view.rb +171 -399
  99. data/lib/clevic/table_view_paste.rb +199 -0
  100. data/lib/clevic/version.rb +3 -2
  101. data/lib/clevic/view.rb +94 -43
  102. data/models/accounts_models.rb +13 -13
  103. data/models/minimal_models.rb +5 -9
  104. data/models/times_models.rb +19 -14
  105. data/models/times_psql_models.rb +10 -0
  106. data/models/times_sqlite_models.rb +1 -8
  107. data/models/values_models.rb +2 -8
  108. data/tasks/clevic.rake +1 -1
  109. data/tasks/rdoc.rake +1 -5
  110. data/tasks/website.rake +1 -1
  111. data/test/test_cache_table.rb +15 -29
  112. data/test/test_helper.rb +14 -83
  113. data/test/test_order_attribute.rb +1 -1
  114. data/test/test_table_model.rb +0 -21
  115. data/test/test_table_searcher.rb +67 -61
  116. metadata +262 -78
  117. data/lib/clevic.rb +0 -4
  118. data/lib/clevic/db_options.rb +0 -112
  119. data/lib/clevic/delegates.rb +0 -386
data/lib/clevic/record.rb CHANGED
@@ -3,32 +3,22 @@ require 'clevic/default_view.rb'
3
3
 
4
4
  module Clevic
5
5
 
6
- # include this in ActiveRecord::Base instances to
6
+ # include this in Sequel::Model classes to
7
7
  # get embedded view definitions. See ModelBuilder.
8
8
  #
9
9
  # A Clevic::Default#{model}View class will be created. If
10
10
  # a define_ui block is not specified in the entity class,
11
11
  # a default UI will be created.
12
12
  module Record
13
- # TODO not sure if these are necessary here anymore?
14
- def self.db_options=( db_options )
15
- @db_options = db_options
16
- end
17
-
18
- def self.db_options
19
- @db_options
20
- end
21
-
22
13
  module ClassMethods
23
14
  def default_view_class_name
24
15
  "::Clevic::Default#{name.gsub('::','')}View"
25
16
  end
26
17
 
27
- #TODO will have to fix modules here
28
18
  def create_view_class
29
19
  # create the default view class
30
20
  # Don't use Class.new because even if you assign
31
- # the result to a contstant, there are still anonymous classes
21
+ # the result to a constant, there are still anonymous classes
32
22
  # hanging around, which gives weird results with Clevic::View.subclasses.
33
23
  st,line = <<-EOF, __LINE__
34
24
  class #{default_view_class_name} < Clevic::DefaultView
@@ -60,11 +50,6 @@ module Clevic
60
50
 
61
51
  # create the default view class
62
52
  base.create_view_class
63
-
64
- # DbOptions instance
65
- db_options = nil
66
- found = ObjectSpace.each_object( Clevic::DbOptions ){|x| db_options = x}
67
- @db_options = db_options
68
53
  end
69
54
  end
70
55
 
@@ -0,0 +1,81 @@
1
+ require 'clevic/generic_format.rb'
2
+ require 'andand'
3
+
4
+ module Clevic
5
+
6
+ # Calculate a string sample for a particular Field
7
+ class Sampler
8
+ def initialize( entity_class, field_name, display, &block )
9
+ @entity_class = entity_class
10
+ @field_name = field_name
11
+ @display = display
12
+ @format_block = block
13
+ end
14
+
15
+ attr_reader :entity_class, :field_name, :display
16
+
17
+ def meta
18
+ @meta ||= entity_class.meta[field_name]
19
+ end
20
+
21
+ # return a string which is representative of the width of the field
22
+ def compute
23
+ case meta.type
24
+ when :string, :text
25
+ string_sample
26
+
27
+ when :date, :time, :datetime, :timestamp
28
+ date_time_sample
29
+
30
+ when :numeric, :decimal, :integer, :float
31
+ numeric_sample
32
+
33
+ # TODO return a width, or something like that
34
+ when :boolean; 'W'
35
+
36
+ when :many_to_one
37
+ related_sample
38
+
39
+ else
40
+ if meta.type != NilClass
41
+ raise "Sampler#compute can't figure out sample for #{entity_class.name}.#{field_name} because it's a #{meta.type.inspect}"
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ def do_format( value )
48
+ @format_block.call( value )
49
+ end
50
+
51
+ # default to max length of 20
52
+ def string_sample
53
+ 'N' * ( entity_class.max( :length.sql_function( field_name ) ).andand.to_i || 20 )
54
+ end
55
+
56
+ def date_time_sample
57
+ sample_date = entity_class \
58
+ .filter( ~{ field_name => nil } ) \
59
+ .select( field_name ) \
60
+ .limit(1) \
61
+ .single_value
62
+ ;
63
+ # replace all letters with 'N'
64
+ do_format( sample_date || Date.today ).gsub( /[[:alpha:]]/, 'N' )
65
+ end
66
+
67
+ def numeric_sample
68
+ max = entity_class.max( field_name )
69
+ min = entity_class.min( field_name )
70
+ max_length = [ do_format( min ).to_s, do_format( max ).to_s ].map( &:length ).max
71
+ '9' * ( max_length || 5 )
72
+ end
73
+
74
+ def related_sample
75
+ if display.respond_to?( :to_sym )
76
+ Sampler.new( eval( meta.class_name ), display.to_sym, nil, &@format_block ).compute
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,215 @@
1
+ require 'sequel'
2
+
3
+ # remove dependency on this and active_support unless they're really needed
4
+ require 'clevic/ar_methods.rb'
5
+ require 'clevic/attribute_list.rb'
6
+
7
+ module Clevic
8
+ class SequelAdaptor
9
+ def initialize( entity_class )
10
+ @entity_class = entity_class
11
+ @entity_class.plugin :ar_methods
12
+ end
13
+
14
+ def quoted_false
15
+ @entity_class.dataset.boolean_constant_sql( false )
16
+ end
17
+
18
+ def quoted_true
19
+ @entity_class.dataset.boolean_constant_sql( true )
20
+ end
21
+
22
+ def count( *args )
23
+ @entity_class.count_ar( *args )
24
+ end
25
+
26
+ def find( *args )
27
+ @entity_class.find_ar( *args )
28
+ end
29
+
30
+ def attribute_list( attribute, attribute_value, by_description, by_frequency, find_options, &block )
31
+ lister = AttributeList.new( @entity_class, attribute, attribute_value, find_options )
32
+ ds = lister.dataset( by_description, by_frequency )
33
+ ds.map( &block )
34
+ end
35
+ end
36
+
37
+ class ActiveRecordAdaptor
38
+ def initialize( entity_class )
39
+ @entity_class = entity_class
40
+ end
41
+
42
+ def quoted_false
43
+ @entity_class.connection.quoted_false
44
+ end
45
+
46
+ def quoted_true
47
+ @entity_class.connection.quoted_true
48
+ end
49
+
50
+ # options is a hash
51
+ def count( attribute = nil, options = {} )
52
+ @entity_class.count( attribute, options )
53
+ end
54
+
55
+ def find( options )
56
+ @entity_class.find( :all, options )
57
+ end
58
+
59
+ def query_order_description( attribute, attribute_value, find_options )
60
+ <<-EOF
61
+ select distinct #{attribute.to_s}, lower(#{attribute.to_s})
62
+ from #{@entity_class.table_name}
63
+ where (#{find_options[:conditions] || '1=1'})
64
+ or #{@entity_class.connection.quote_column_name( attribute.to_s )} = #{@entity_class.connection.quote( attribute_value )}
65
+ order by lower(#{attribute.to_s})
66
+ EOF
67
+ end
68
+
69
+ def query_order_frequency( attribute, attribute_value, find_options )
70
+ <<-EOF
71
+ select distinct #{attribute.to_s}, count(#{attribute.to_s})
72
+ from #{entity_class.table_name}
73
+ where (#{find_options[:conditions] || '1=1'})
74
+ or #{@entity_class.connection.quote_column_name( attribute.to_s )} = #{@entity_class.connection.quote( attribute_value )}
75
+ group by #{attribute.to_s}
76
+ order by count(#{attribute.to_s}) desc
77
+ EOF
78
+ end
79
+
80
+ # values are passed as row objects to block
81
+ def attribute_list( attribute, attribute_value, by_description, by_frequency, find_options, &block )
82
+ query =
83
+ case
84
+ when by_description
85
+ entity_class.adaptor.query_order_description( attribute, attribute_value, find_options )
86
+ when by_frequency
87
+ entity_class.adaptor.query_order_frequency( attribute, attribute_value, find_options )
88
+ else
89
+ entity_class.adaptor.query_order_frequency( attribute, attribute_value, find_options )
90
+ end
91
+
92
+ entity_class.connection.execute( query ).each( &block )
93
+ end
94
+ end
95
+ end
96
+
97
+ if defined? ActiveRecord
98
+ module ActiveRecord
99
+ class Base
100
+ # checks to see if attribute_sym is either in the column
101
+ # name list, or in the set of reflections.
102
+ def self.has_attribute?( attribute_sym )
103
+ if column_names.include?( attribute_sym.to_s )
104
+ true
105
+ elsif reflections.has_key?( attribute_sym )
106
+ true
107
+ else
108
+ false
109
+ end
110
+ end
111
+
112
+ def self.attribute_names
113
+ ( column_names + reflections.keys.map {|sym| sym.to_s} ).sort
114
+ end
115
+
116
+ def adaptor
117
+ @adaptor ||= Clevic::ActiveRecordAdaptor.new( self )
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ module Sequel
124
+ class Model
125
+ class << self
126
+ def translate_options( options )
127
+ options[:key] = options[:foreign_key].andand.to_sym
128
+ options.delete( :foreign_key )
129
+
130
+ options[:class] = options[:class_name].andand.to_sym
131
+ options.delete( :class_name )
132
+ options
133
+ end
134
+
135
+ def belongs_to( name, options = nil, &block )
136
+ # work around possible Sequel bug
137
+ if options.nil?
138
+ many_to_one( name, &block )
139
+ else
140
+ many_to_one( name, translate_options( options ), &block )
141
+ end
142
+ end
143
+
144
+ def has_many( name, options = nil, &block )
145
+ # work around possible Sequel bug
146
+ if options.nil?
147
+ one_to_many( name, &block )
148
+ else
149
+ one_to_many( name, translate_options( options ), &block )
150
+ end
151
+ end
152
+
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
+ def has_attribute?( attribute )
166
+ column_names.include?( attribute )
167
+ end
168
+
169
+ def attribute_names
170
+ columns
171
+ end
172
+
173
+ def columns_hash
174
+ db_schema
175
+ end
176
+
177
+ # return a class containing various db methods. Not sure
178
+ # if this is the right way to do it, but at least this way
179
+ # the model class namespace doesn't get filled up with crud
180
+ def adaptor
181
+ @adaptor ||= Clevic::SequelAdaptor.new( self )
182
+ end
183
+ end
184
+
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
+ module Associations
202
+ class ManyToOneAssociationReflection
203
+ # return class for this side of the association
204
+ def class_name
205
+ self[:class_name]
206
+ end
207
+
208
+ # return class for the other side of the association
209
+ def klass
210
+ eval class_name
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,23 @@
1
+ require 'sequel'
2
+
3
+ =begin
4
+ This validates that strings going into varchar fields display meaningful
5
+ warnings instead of incomprenensible native RDBMS errors.
6
+ =end
7
+
8
+ class Sequel::Model
9
+ def self.varchar_columns
10
+ @varchar_columns ||= columns.select do |col|
11
+ db_type = db_schema[col][:db_type]
12
+ db_type =~ /var/ && db_type =~ /char/
13
+ end
14
+ end
15
+
16
+ def validate
17
+ super
18
+ self.class.varchar_columns.each do |column|
19
+ limit = self.class.meta[column].limit
20
+ errors.add( column, "is longer than #{limit}" ) if self[column] && self[column].length > limit
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ require 'sequel'
2
+ require 'clevic/model_column.rb'
3
+
4
+ module Sequel
5
+ module Plugins
6
+ module Meta
7
+ # plugin :meta calls this.
8
+ # model is the model class. The rest is whatever options are
9
+ # in the plugin call
10
+ # plugin :meta
11
+ def self.configure(model, options = {})
12
+ model.instance_eval do
13
+ # store model-related stuff here
14
+ end
15
+ end
16
+
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
+ def meta
32
+ if @meta.nil?
33
+ @meta = {}
34
+ db_schema.each do |key,value|
35
+ @meta[key] = ModelColumn.new( key, value.merge( :association => false ) )
36
+ end
37
+
38
+ association_reflections.each do |key,value|
39
+ @meta[key] = ModelColumn.new( key, value.merge( :association => true ) )
40
+ end
41
+ end
42
+ @meta
43
+ end
44
+
45
+ # reload from current metadata
46
+ def meta!
47
+ @meta = nil
48
+ meta
49
+ end
50
+
51
+ # column and relations, but not keys for defined relations
52
+ def attributes
53
+ meta.reject do |column,model_column|
54
+ meta.values.map( &:keys ).include?( [ column ] )
55
+ end
56
+ end
57
+ end
58
+
59
+ module InstanceMethods
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ Sequel::Model.plugin :meta
@@ -0,0 +1,30 @@
1
+ require 'sequel'
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # Fix the naked call to do the following:
6
+ # - remove the row_proc
7
+ # - remove the model method, or make it return nil
8
+ # - fix the destroy method. Not sure what this means right now.
9
+ module Naked
10
+ def self.configure(model, options = {})
11
+ model.instance_eval do
12
+ # store model-related stuff here
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def inherited(subclass)
18
+ super
19
+ end
20
+
21
+ def naked( *args )
22
+
23
+ end
24
+ end
25
+
26
+ module InstanceMethods
27
+ end
28
+ end
29
+ end
30
+ end