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.
- data/History.txt +10 -0
- data/Manifest.txt +209 -30
- data/README.txt +16 -20
- data/Rakefile +8 -8
- data/TODO +6 -7
- data/bin/clevic +12 -73
- data/lib/clevic/action_builder.rb +168 -0
- data/lib/clevic/ar_methods.rb +120 -0
- data/lib/clevic/attribute_list.rb +56 -0
- data/lib/clevic/cache_table.rb +60 -37
- data/lib/clevic/default_view.rb +3 -16
- data/lib/clevic/delegate.rb +46 -0
- data/lib/clevic/emitter.rb +38 -0
- data/lib/clevic/extensions.rb +61 -114
- data/lib/clevic/field.rb +159 -228
- data/lib/clevic/field_valuer.rb +165 -0
- data/lib/clevic/filter_command.rb +2 -6
- data/lib/clevic/generic_format.rb +52 -0
- data/lib/clevic/{ui → icons}/icon.png +0 -0
- data/lib/clevic/many_field.rb +7 -0
- data/lib/clevic/model_builder.rb +234 -146
- data/lib/clevic/model_column.rb +61 -13
- data/lib/clevic/order_attribute.rb +10 -0
- data/lib/clevic/qt.rb +35 -0
- data/lib/clevic/qt/action_builder.rb +47 -0
- data/lib/clevic/qt/boolean_delegate.rb +8 -0
- data/lib/clevic/{browser.rb → qt/browser.rb} +35 -14
- data/lib/clevic/qt/clipboard.rb +35 -0
- data/lib/clevic/qt/combo_delegate.rb +198 -0
- data/lib/clevic/qt/delegates.rb +1 -0
- data/lib/clevic/qt/distinct_delegate.rb +35 -0
- data/lib/clevic/qt/extensions.rb +52 -0
- data/lib/clevic/qt/field.rb +18 -0
- data/lib/clevic/{item_delegate.rb → qt/item_delegate.rb} +8 -4
- data/lib/clevic/qt/relational_delegate.rb +87 -0
- data/lib/clevic/{search_dialog.rb → qt/search_dialog.rb} +1 -11
- data/lib/clevic/qt/set_delegate.rb +44 -0
- data/lib/clevic/qt/table_model.rb +331 -0
- data/lib/clevic/qt/table_view.rb +344 -0
- data/lib/clevic/qt/text_area_delegate.rb +8 -0
- data/lib/clevic/{text_delegate.rb → qt/text_delegate.rb} +6 -4
- data/lib/clevic/{ui → qt/ui}/.gitignore +0 -0
- data/lib/clevic/{ui → qt/ui}/browser.ui +0 -0
- data/lib/clevic/{ui → qt/ui}/search_dialog.ui +0 -0
- data/lib/clevic/rails_models_loaders.rb +56 -0
- data/lib/clevic/record.rb +2 -17
- data/lib/clevic/sampler.rb +81 -0
- data/lib/clevic/sequel_ar_adapter.rb +215 -0
- data/lib/clevic/sequel_length_validation.rb +23 -0
- data/lib/clevic/sequel_meta.rb +65 -0
- data/lib/clevic/sequel_naked.rb +30 -0
- data/lib/clevic/swing.rb +38 -0
- data/lib/clevic/swing/action.rb +125 -0
- data/lib/clevic/swing/action_builder.rb +47 -0
- data/lib/clevic/swing/boolean_delegate.rb +26 -0
- data/lib/clevic/swing/browser.rb +282 -0
- data/lib/clevic/swing/cell_editor.rb +95 -0
- data/lib/clevic/swing/cell_renderer.rb +44 -0
- data/lib/clevic/swing/clipboard.rb +135 -0
- data/lib/clevic/swing/combo_delegate.rb +336 -0
- data/lib/clevic/swing/confirm_dialog.rb +57 -0
- data/lib/clevic/swing/delegate.rb +40 -0
- data/lib/clevic/swing/distinct_delegate.rb +30 -0
- data/lib/clevic/swing/extensions.rb +274 -0
- data/lib/clevic/swing/field.rb +35 -0
- data/lib/clevic/swing/relational_delegate.rb +48 -0
- data/lib/clevic/swing/row_header.rb +210 -0
- data/lib/clevic/swing/search_dialog.rb +230 -0
- data/lib/clevic/swing/selection_model.rb +90 -0
- data/lib/clevic/swing/set_delegate.rb +41 -0
- data/lib/clevic/swing/swing_table_index.rb +43 -0
- data/lib/clevic/swing/table_model.rb +200 -0
- data/lib/clevic/swing/table_view.rb +385 -0
- data/lib/clevic/swing/table_view_focus.rb +47 -0
- data/lib/clevic/swing/tag_delegate.rb +127 -0
- data/lib/clevic/swing/tag_editor.rb +101 -0
- data/lib/clevic/swing/text_area_delegate.rb +46 -0
- data/lib/clevic/swing/text_delegate.rb +31 -0
- data/lib/clevic/swing/ui/build.xml +74 -0
- data/lib/clevic/swing/ui/dist/README.TXT +33 -0
- data/lib/clevic/swing/ui/dist/lib/swing-layout-1.0.3.jar +0 -0
- data/lib/clevic/swing/ui/manifest.mf +3 -0
- data/lib/clevic/swing/ui/nbproject/build-impl.xml +731 -0
- data/lib/clevic/swing/ui/nbproject/genfiles.properties +8 -0
- data/lib/clevic/swing/ui/nbproject/private/config.properties +0 -0
- data/lib/clevic/swing/ui/nbproject/private/private.properties +6 -0
- data/lib/clevic/swing/ui/nbproject/private/private.xml +4 -0
- data/lib/clevic/swing/ui/nbproject/project.properties +70 -0
- data/lib/clevic/swing/ui/nbproject/project.xml +14 -0
- data/lib/clevic/swing/ui/src/SearchDialog.form +158 -0
- data/lib/clevic/swing/ui/src/SearchDialog.java +163 -0
- data/lib/clevic/swing/ui/src/TagEditor.form +106 -0
- data/lib/clevic/swing/ui/src/TagEditor.java +108 -0
- data/lib/clevic/swing/ui/src/resources/SearchDialog.properties +0 -0
- data/lib/clevic/table_index.rb +100 -0
- data/lib/clevic/table_model.rb +54 -425
- data/lib/clevic/table_searcher.rb +113 -116
- data/lib/clevic/table_view.rb +171 -399
- data/lib/clevic/table_view_paste.rb +199 -0
- data/lib/clevic/version.rb +3 -2
- data/lib/clevic/view.rb +94 -43
- data/models/accounts_models.rb +13 -13
- data/models/minimal_models.rb +5 -9
- data/models/times_models.rb +19 -14
- data/models/times_psql_models.rb +10 -0
- data/models/times_sqlite_models.rb +1 -8
- data/models/values_models.rb +2 -8
- data/tasks/clevic.rake +1 -1
- data/tasks/rdoc.rake +1 -5
- data/tasks/website.rake +1 -1
- data/test/test_cache_table.rb +15 -29
- data/test/test_helper.rb +14 -83
- data/test/test_order_attribute.rb +1 -1
- data/test/test_table_model.rb +0 -21
- data/test/test_table_searcher.rb +67 -61
- metadata +262 -78
- data/lib/clevic.rb +0 -4
- data/lib/clevic/db_options.rb +0 -112
- data/lib/clevic/delegates.rb +0 -386
data/lib/clevic/model_column.rb
CHANGED
@@ -1,23 +1,71 @@
|
|
1
1
|
=begin rdoc
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
in ModelIndex.
|
2
|
+
Field metadata class. Includes information for type, reflections etc.
|
3
|
+
|
4
|
+
Also, it eases the migration from AR to Sequel, which returns metadata as
|
5
|
+
a hash instead of a class.
|
7
6
|
=end
|
8
7
|
class ModelColumn
|
9
|
-
|
8
|
+
# these are from AR
|
9
|
+
attr_accessor :primary, :scale, :sql_type, :name, :precision, :default, :type, :meta
|
10
10
|
|
11
|
-
|
11
|
+
attr_writer :limit
|
12
|
+
|
13
|
+
# if it's not here, it's probably from Sequel, so figure it out from
|
14
|
+
# the db_type
|
15
|
+
def limit
|
16
|
+
unless @limit
|
17
|
+
db_type =~ /\((\d+)\)/
|
18
|
+
@limit = $1.to_i
|
19
|
+
end
|
20
|
+
@limit
|
21
|
+
end
|
22
|
+
|
23
|
+
# these are from Sequel::Model.columns_hash
|
24
|
+
attr_accessor :ruby_default, :primary_key, :allow_null, :db_type
|
25
|
+
|
26
|
+
# sequel::Model.reflections
|
27
|
+
attr_accessor :key, :eager_block, :type, :eager_grapher, :before_add, :model, :graph_join_type, :class_name, :before_remove, :eager_loader, :uses_composite_keys, :order_eager_graph, :dataset, :cartesian_product_number, :after_add, :cache, :keys, :after_remove, :extend, :graph_conditions, :name, :orig_opts, :after_load, :before_set, :after_set, :reciprocal, :reciprocal_type
|
28
|
+
|
29
|
+
# for many_to_one targets
|
30
|
+
attr_accessor :primary_keys
|
31
|
+
|
32
|
+
# TODO not sure where these are from
|
33
|
+
attr_accessor :order, :class, :conditions
|
34
|
+
|
35
|
+
# For Sequel many_to_many
|
36
|
+
attr_accessor :left_key,
|
37
|
+
:left_keys,
|
38
|
+
:right_key,
|
39
|
+
:right_keys,
|
40
|
+
:left_primary_key,
|
41
|
+
:left_primary_keys,
|
42
|
+
:uses_left_composite_keys,
|
43
|
+
:uses_right_composite_keys,
|
44
|
+
:cartesian_product_number,
|
45
|
+
:join_table,
|
46
|
+
:left_key_alias,
|
47
|
+
:graph_join_table_conditions,
|
48
|
+
:graph_join_table_join_type
|
49
|
+
|
50
|
+
# added by us
|
51
|
+
attr_accessor :association
|
52
|
+
def association?; association; end
|
53
|
+
|
54
|
+
def initialize( name, hash )
|
55
|
+
@hash = hash
|
56
|
+
@hash.each do |key,value|
|
57
|
+
send( "#{key}=", value )
|
58
|
+
end
|
59
|
+
|
60
|
+
# must be after hash so it takes precedence
|
12
61
|
@name = name
|
13
|
-
@type = type
|
14
|
-
@meta = meta
|
15
62
|
end
|
16
63
|
|
17
|
-
# return the underlying field name, ie "#{attribute}_id" if
|
18
|
-
# it's an association
|
19
|
-
alias_method :old_name, :name
|
20
64
|
def name
|
21
|
-
@
|
65
|
+
@name
|
66
|
+
end
|
67
|
+
|
68
|
+
def related_class
|
69
|
+
@related_class ||= eval class_name
|
22
70
|
end
|
23
71
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
=begin rdoc
|
2
2
|
Store the SQL order_by attributes with ascending and descending values
|
3
3
|
=end
|
4
|
+
# TODO don't use this anymore
|
4
5
|
class OrderAttribute
|
5
6
|
attr_reader :direction, :attribute
|
6
7
|
|
@@ -50,4 +51,13 @@ class OrderAttribute
|
|
50
51
|
self.direction == other.direction and
|
51
52
|
self.attribute == other.attribute
|
52
53
|
end
|
54
|
+
|
55
|
+
# return -1 for desc, 1 for asc
|
56
|
+
def to_i
|
57
|
+
case direction
|
58
|
+
when :asc; 1
|
59
|
+
when :desc; -1
|
60
|
+
else; raise "unknown direction #{direction}"
|
61
|
+
end
|
62
|
+
end
|
53
63
|
end
|
data/lib/clevic/qt.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
=begin
|
2
|
+
Require this file to do Clevic in Qt
|
3
|
+
=end
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
# require these first, so TableModel and TableView get the correct ancestors
|
8
|
+
require 'clevic/qt/table_model.rb'
|
9
|
+
require 'clevic/qt/table_view.rb'
|
10
|
+
( Pathname.new( __FILE__ ).parent + 'qt' ).children.grep( /.rb$/ ).each do |child|
|
11
|
+
require child.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
# now require the generic parts
|
15
|
+
require 'clevic/table_model'
|
16
|
+
require 'clevic/table_view'
|
17
|
+
require 'clevic.rb'
|
18
|
+
|
19
|
+
module Clevic
|
20
|
+
|
21
|
+
def self.tahoma
|
22
|
+
if @font.nil?
|
23
|
+
@font =
|
24
|
+
begin
|
25
|
+
found = java.awt.GraphicsEnvironment.local_graphics_environment.all_fonts.select {|f| f.font_name == "Tahoma"}.first
|
26
|
+
found.deriveFont( 13.0 )
|
27
|
+
java.awt.Font.new( 'DialogInput', java.awt.Font::PLAIN, 13 )
|
28
|
+
rescue
|
29
|
+
java.awt.Font.new( 'DialogInput', java.awt.Font::PLAIN, 13 )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
@font
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
module ActionBuilder
|
4
|
+
# Create a new separator and add a new separator.
|
5
|
+
def separator
|
6
|
+
Qt::Action.new( parent ) do |action|
|
7
|
+
action.separator = true
|
8
|
+
add_action action
|
9
|
+
collect_actions << action
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_action( &block )
|
14
|
+
Qt::Action.new( parent, &block )
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO move this into Action, like the swing adapter
|
18
|
+
def create_key_sequence( sequence )
|
19
|
+
Qt::KeySequence.new( sequence )
|
20
|
+
end
|
21
|
+
|
22
|
+
# set up the code to be executed when an action is triggered,
|
23
|
+
def action_method_or_block( qt_action, options, &block )
|
24
|
+
signal_name = "triggered(#{options.has_key?( :checkable ) ? 'bool' : ''})"
|
25
|
+
|
26
|
+
# connect the action to some code
|
27
|
+
if options.has_key?( :method )
|
28
|
+
qt_action.connect SIGNAL( signal_name ) do |active|
|
29
|
+
action_triggered do
|
30
|
+
send_args = [ options[:method], options.has_key?( :checkable ) ? active : nil ].compact
|
31
|
+
send( *send_args )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
unless block.nil?
|
36
|
+
action_triggered do
|
37
|
+
qt_action.connect SIGNAL( signal_name ) do |active|
|
38
|
+
yield( active )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'clevic/search_dialog.rb'
|
2
|
-
require 'clevic/ui/browser_ui.rb'
|
1
|
+
require 'clevic/qt/search_dialog.rb'
|
2
|
+
require 'clevic/qt/ui/browser_ui.rb'
|
3
3
|
require 'clevic/table_view.rb'
|
4
4
|
require 'clevic.rb'
|
5
5
|
|
@@ -23,8 +23,8 @@ class Browser < Qt::Widget
|
|
23
23
|
@layout.setup_ui( main_window )
|
24
24
|
|
25
25
|
# set icon. MUST come after call to setup_ui
|
26
|
-
icon_path = Pathname.new( __FILE__ ).parent + "
|
27
|
-
raise "icon.png not found" unless icon_path.file?
|
26
|
+
icon_path = Pathname.new( __FILE__ ).parent + "../icons/icon.png"
|
27
|
+
Kernel::raise "icon.png not found" unless icon_path.file?
|
28
28
|
main_window.window_icon = Qt::Icon.new( icon_path.realpath.to_s )
|
29
29
|
|
30
30
|
# add the tables tab
|
@@ -52,8 +52,7 @@ class Browser < Qt::Widget
|
|
52
52
|
|
53
53
|
# Set the main window title to the name of the database, if we can find it.
|
54
54
|
def database_name
|
55
|
-
|
56
|
-
#~ table_view.model.db_options.database
|
55
|
+
table_view.model.entity_class.db.url rescue ''
|
57
56
|
end
|
58
57
|
|
59
58
|
def update_menus
|
@@ -128,18 +127,18 @@ class Browser < Qt::Widget
|
|
128
127
|
|
129
128
|
# Add all existing model objects as tabs, one each
|
130
129
|
views.each do |view_class|
|
131
|
-
view = view_class.new
|
132
|
-
unless view.entity_class.table_exists?
|
133
|
-
puts "No table for #{view.entity_class.inspect}"
|
134
|
-
next
|
135
|
-
end
|
136
|
-
|
137
130
|
begin
|
131
|
+
view = view_class.new
|
132
|
+
unless view.entity_class.table_exists?
|
133
|
+
puts "No table for #{view.entity_class.inspect}"
|
134
|
+
next
|
135
|
+
end
|
136
|
+
|
138
137
|
# create the the table_view and the table_model for the entity_class
|
139
138
|
tab = Clevic::TableView.new( view )
|
140
139
|
|
141
140
|
# show status messages
|
142
|
-
tab.connect( SIGNAL( '
|
141
|
+
tab.connect( SIGNAL( 'status_text_signal(QString)' ) ) { |msg| @layout.statusbar.show_message( msg, 10000 ) }
|
143
142
|
|
144
143
|
# add a new tab
|
145
144
|
tables_tab.add_tab( tab, translate( tab.title ) )
|
@@ -153,7 +152,7 @@ class Browser < Qt::Widget
|
|
153
152
|
@layout.menu_model.add_action( action )
|
154
153
|
|
155
154
|
# handle filter status changed, so we can provide a visual indication
|
156
|
-
tab.connect SIGNAL( '
|
155
|
+
tab.connect SIGNAL( 'filter_status_signal(bool)' ) do |status|
|
157
156
|
# update the tab, so there's a visual indication of filtering
|
158
157
|
filter_title = ( tab.filtered ? '| ' : '' ) + translate( tab.title )
|
159
158
|
tables_tab.set_tab_text( tables_tab.current_index, filter_title )
|
@@ -171,6 +170,28 @@ class Browser < Qt::Widget
|
|
171
170
|
def save_all
|
172
171
|
tables_tab.tabs.each {|x| x.save_row( x.current_index ) }
|
173
172
|
end
|
173
|
+
|
174
|
+
def self.run( args )
|
175
|
+
# load model files
|
176
|
+
raise "no model definition file specified" if args.empty?
|
177
|
+
args.each { |arg| load_models( Pathname.new( arg ) ) }
|
178
|
+
|
179
|
+
app = Qt::Application.new( args )
|
180
|
+
|
181
|
+
# show UI
|
182
|
+
main_window = Qt::MainWindow.new
|
183
|
+
browser = Clevic::Browser.new( main_window )
|
184
|
+
# this must come after Clevic::Browser.new
|
185
|
+
main_window.show
|
186
|
+
# make sure any partially edited records are saved when the window is closed
|
187
|
+
app.connect( SIGNAL('lastWindowClosed()') ) { browser.save_all }
|
188
|
+
begin
|
189
|
+
app.exec
|
190
|
+
rescue
|
191
|
+
puts $!.message
|
192
|
+
puts $!.backtrace
|
193
|
+
end
|
194
|
+
end
|
174
195
|
end
|
175
196
|
|
176
197
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
# see swing clipboard if you need a stream with io/like
|
4
|
+
|
5
|
+
# Clevic wrapper for Qt::Application::clipboard
|
6
|
+
class Clipboard
|
7
|
+
def system
|
8
|
+
Qt::Application::clipboard
|
9
|
+
end
|
10
|
+
|
11
|
+
def text=( value )
|
12
|
+
system.text = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def text
|
16
|
+
system.text
|
17
|
+
end
|
18
|
+
|
19
|
+
def text?
|
20
|
+
system.mime_data.has_text
|
21
|
+
end
|
22
|
+
|
23
|
+
def html?
|
24
|
+
system.mime_data.has_html
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO figure out why Qt never has anything other than text
|
28
|
+
# could be because the event loop isn't running when testing
|
29
|
+
# from irb
|
30
|
+
def html
|
31
|
+
system.mime_data.html
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'clevic/qt/item_delegate.rb'
|
2
|
+
|
3
|
+
module Clevic
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
Base class for other delegates using Combo boxes. Emit focus out signals,
|
7
|
+
because ComboBox stupidly doesn't.
|
8
|
+
|
9
|
+
Generally these will be created using a Clevic::ModelBuilder.
|
10
|
+
=end
|
11
|
+
class ComboDelegate < Clevic::ItemDelegate
|
12
|
+
def initialize( field )
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
# Convert Qt:: constants from the integer value to a string value.
|
17
|
+
def hint_string( hint )
|
18
|
+
hs = String.new
|
19
|
+
Qt::AbstractItemDelegate.constants.each do |x|
|
20
|
+
hs = x if eval( "Qt::AbstractItemDelegate::#{x}.to_i" ) == hint.to_i
|
21
|
+
end
|
22
|
+
hs
|
23
|
+
end
|
24
|
+
|
25
|
+
def dump_editor_state( editor )
|
26
|
+
if $options[:debug]
|
27
|
+
puts "#{self.class.name}"
|
28
|
+
puts "editor.completer.completion_count: #{editor.completer.completion_count}"
|
29
|
+
puts "editor.completer.current_completion: #{editor.completer.current_completion}"
|
30
|
+
puts "editor.find_text( editor.completer.current_completion ): #{editor.find_text( editor.completer.current_completion )}"
|
31
|
+
puts "editor.current_text: #{editor.current_text}"
|
32
|
+
puts "editor.count: #{editor.count}"
|
33
|
+
puts "editor.completer.current_row: #{editor.completer.current_row}"
|
34
|
+
puts "editor.item_data( editor.current_index ): #{editor.item_data( editor.current_index ).inspect}"
|
35
|
+
puts
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# open the combo box, just like if f4 was pressed
|
40
|
+
def full_edit
|
41
|
+
if is_combo?( @editor )
|
42
|
+
@editor.show_popup
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# returns true if the editor allows values outside of a predefined
|
47
|
+
# range, false otherwise.
|
48
|
+
def restricted?
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO fetch this from the model definition
|
53
|
+
def allow_null?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
# Subclasses should override this to fill the combo box
|
58
|
+
# list with values.
|
59
|
+
def populate( editor, model_index )
|
60
|
+
raise "subclass responsibility"
|
61
|
+
end
|
62
|
+
|
63
|
+
# return true if this delegate needs a combo, false otherwise
|
64
|
+
def needs_combo?
|
65
|
+
raise "subclass responsibility"
|
66
|
+
end
|
67
|
+
|
68
|
+
def is_combo?( editor )
|
69
|
+
editor.class == Qt::ComboBox
|
70
|
+
end
|
71
|
+
|
72
|
+
# return true if this field has no data (needs_combo? is false)
|
73
|
+
# and is at the same time restricted (ie needs data from somewhere else)
|
74
|
+
def empty_set?
|
75
|
+
!needs_combo? && restricted?
|
76
|
+
end
|
77
|
+
|
78
|
+
# the message to display if the set is empty, and
|
79
|
+
# the delegate is restricted to a predefined set.
|
80
|
+
def empty_set_message
|
81
|
+
raise "subclass responsibility"
|
82
|
+
end
|
83
|
+
|
84
|
+
# if this delegate has an empty set, return the message, otherwise
|
85
|
+
# return nil.
|
86
|
+
def if_empty_message
|
87
|
+
if empty_set?
|
88
|
+
empty_set_message
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def populate_current( editor, model_index )
|
93
|
+
# add the current entry, if it isn't there already
|
94
|
+
# TODO add it in the correct order
|
95
|
+
if ( editor.find_data( model_index.display_value.to_variant ) == -1 )
|
96
|
+
editor.add_item( model_index.display_value, model_index.display_value.to_variant )
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_nil_item( editor )
|
101
|
+
if ( editor.find_data( nil.to_variant ) == -1 )
|
102
|
+
editor.add_item( '', nil.to_variant )
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Override the Qt method. Create a ComboBox widget and fill it with the possible values.
|
107
|
+
def createEditor( parent_widget, style_option_view_item, model_index )
|
108
|
+
if needs_combo?
|
109
|
+
@editor = Qt::ComboBox.new( parent_widget )
|
110
|
+
|
111
|
+
# subclasses fill in the rest of the entries
|
112
|
+
populate( @editor, model_index )
|
113
|
+
|
114
|
+
# add the current item, if it isn't there already
|
115
|
+
populate_current( @editor, model_index )
|
116
|
+
|
117
|
+
# create a nil entry
|
118
|
+
add_nil_item( @editor ) if allow_null?
|
119
|
+
|
120
|
+
# allow prefix matching from the keyboard
|
121
|
+
@editor.editable = true
|
122
|
+
|
123
|
+
# don't insert if restricted
|
124
|
+
@editor.insert_policy = Qt::ComboBox::NoInsert if restricted?
|
125
|
+
else
|
126
|
+
@editor =
|
127
|
+
if restricted?
|
128
|
+
emit parent.status_text( empty_set_message )
|
129
|
+
nil
|
130
|
+
else
|
131
|
+
Qt::LineEdit.new( model_index.edit_value, parent_widget )
|
132
|
+
end
|
133
|
+
end
|
134
|
+
@editor
|
135
|
+
end
|
136
|
+
|
137
|
+
# Override the Qt::ItemDelegate method.
|
138
|
+
def updateEditorGeometry( editor, style_option_view_item, model_index )
|
139
|
+
rect = style_option_view_item.rect
|
140
|
+
|
141
|
+
# ask the editor for how much space it wants, and set the editor
|
142
|
+
# to that size when it displays in the table
|
143
|
+
rect.set_width( [editor.size_hint.width,rect.width].max ) if is_combo?( editor )
|
144
|
+
editor.set_geometry( rect )
|
145
|
+
end
|
146
|
+
|
147
|
+
# Override the Qt method to send data to the editor from the model.
|
148
|
+
def setEditorData( editor, model_index )
|
149
|
+
if is_combo?( editor )
|
150
|
+
editor.current_index = editor.find_data( model_index.attribute_value.to_variant )
|
151
|
+
editor.line_edit.select_all if editor.editable
|
152
|
+
else
|
153
|
+
editor.text = model_index.edit_value
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# This translates the text from the editor into something that is
|
158
|
+
# stored in an underlying model. Intended to be overridden by subclasses.
|
159
|
+
def translate_from_editor_text( editor, text )
|
160
|
+
index = editor.find_text( text )
|
161
|
+
|
162
|
+
if index == -1
|
163
|
+
text unless restricted?
|
164
|
+
else
|
165
|
+
editor.item_data( index ).value
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Send the data from the editor to the model. The data will
|
170
|
+
# be translated by translate_from_editor_text,
|
171
|
+
def setModelData( editor, abstract_item_model, model_index )
|
172
|
+
if is_combo?( editor )
|
173
|
+
dump_editor_state( editor )
|
174
|
+
value =
|
175
|
+
if editor.completer.current_row == -1
|
176
|
+
# item doesn't exist in the list, add it if not restricted
|
177
|
+
editor.current_text unless restricted?
|
178
|
+
elsif editor.completer.completion_count == editor.count
|
179
|
+
# selection from drop down. if it's empty, we want a nil
|
180
|
+
editor.current_text
|
181
|
+
else
|
182
|
+
# there is a matching completion, so use it
|
183
|
+
editor.completer.current_completion
|
184
|
+
end
|
185
|
+
|
186
|
+
if value != nil
|
187
|
+
model_index.attribute_value = translate_from_editor_text( editor, value )
|
188
|
+
end
|
189
|
+
|
190
|
+
else
|
191
|
+
model_index.attribute_value = editor.text
|
192
|
+
end
|
193
|
+
abstract_item_model.data_changed( model_index )
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|