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
@@ -0,0 +1,210 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
# TODO Weirdness with deleting a row. Takes a long time to get back to user
|
4
|
+
# TODO TextArea not working.
|
5
|
+
# TODO make sure a click in the main table when a row selection is active selects the main table cell
|
6
|
+
# TODO allow for clevic/table_view to access the row selection for deletes
|
7
|
+
class RowHeaderModel < javax.swing.table.AbstractTableModel
|
8
|
+
# Need a Clevic::TableModel here because the underlying
|
9
|
+
# connection isn't always the same instance. Because of
|
10
|
+
# CacheTable#renew
|
11
|
+
def initialize( table_model )
|
12
|
+
super()
|
13
|
+
@table_model = table_model
|
14
|
+
|
15
|
+
# re-fire events
|
16
|
+
table_model.add_table_model_listener do |event|
|
17
|
+
fireTableChanged( event )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# override TableModel method
|
22
|
+
def getRowCount
|
23
|
+
@table_model.getRowCount
|
24
|
+
end
|
25
|
+
|
26
|
+
# override TableModel method
|
27
|
+
def getColumnCount
|
28
|
+
1
|
29
|
+
end
|
30
|
+
|
31
|
+
# override TableModel method
|
32
|
+
def getColumnName( column_index )
|
33
|
+
"row"
|
34
|
+
end
|
35
|
+
|
36
|
+
def getColumnClass( column_index )
|
37
|
+
java.lang.Object
|
38
|
+
end
|
39
|
+
|
40
|
+
def isCellEditable( row_index, column_index )
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def getValueAt( row_index, column_index )
|
45
|
+
row_index+1
|
46
|
+
end
|
47
|
+
|
48
|
+
def id_value( row_index, column_index )
|
49
|
+
if @table_model.collection.cached_at?( row_index )
|
50
|
+
"#{row_index+1} [id=#{@table_model.collection[row_index].id}]"
|
51
|
+
else
|
52
|
+
row_index+1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def setValueAt( value, row_index, column_index )
|
57
|
+
raise "Can't set values in the row header"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# The JTable used to display a row header, and allow row selection.
|
62
|
+
# Also handles highlighting rows for different states, eg validation errors
|
63
|
+
# or unsaved.
|
64
|
+
# TODO need to add exceptions thrown by a Model.save to the error list in the model
|
65
|
+
class RowHeader < javax.swing.JTable
|
66
|
+
# for reloading and ease of testing
|
67
|
+
# should probably fix this in Kernel or Module or Class
|
68
|
+
unless ancestors.include?( javax.swing.table.TableCellRenderer )
|
69
|
+
include javax.swing.table.TableCellRenderer
|
70
|
+
end
|
71
|
+
|
72
|
+
# The Clevic::TableView instance
|
73
|
+
attr_reader :table_view
|
74
|
+
|
75
|
+
# this will add a row header to the passed table_view
|
76
|
+
def initialize( table_view )
|
77
|
+
@table_view = table_view
|
78
|
+
super( RowHeaderModel.new( table_view.model ) )
|
79
|
+
self.font = table_view.font
|
80
|
+
self.grid_color = java.awt.Color::white
|
81
|
+
|
82
|
+
# user header renderer for all cells
|
83
|
+
set_default_renderer( java.lang.Object, table_header.default_renderer )
|
84
|
+
|
85
|
+
# set the width
|
86
|
+
column_width = table_view.column_width( 0, " #{row_count}" )
|
87
|
+
column_model.column( 0 ).preferred_width = column_width
|
88
|
+
|
89
|
+
# This is a workaround either for OSX, or java-1.5.0_19-b02-306
|
90
|
+
self.minimum_size = java.awt.Dimension.new( column_width, minimum_size.height )
|
91
|
+
|
92
|
+
# put a count above the row number header
|
93
|
+
@count_label = javax.swing.JLabel.new( row_count.to_s ).tap do |count_label|
|
94
|
+
count_label.font = self.font
|
95
|
+
count_label.horizontal_alignment = javax.swing.JComponent::CENTER_ALIGNMENT
|
96
|
+
table_view.set_corner( javax.swing.ScrollPaneConstants::UPPER_LEFT_CORNER, count_label )
|
97
|
+
|
98
|
+
# make sure count label is updated when the model changes
|
99
|
+
model.add_table_model_listener do |event|
|
100
|
+
count_label.text = row_count.to_s
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# insert into the row header side of the scrollpane
|
105
|
+
table_view.row_header = javax.swing.JViewport.new.tap do |vp|
|
106
|
+
vp.view = self
|
107
|
+
# make sure size is passed along to viewport
|
108
|
+
vp.preferred_size = preferred_size
|
109
|
+
end
|
110
|
+
|
111
|
+
row_selection_handlers
|
112
|
+
end
|
113
|
+
|
114
|
+
# Transfer row header selection to full row selections in the main
|
115
|
+
# table. Also clear the row header selection if a main table
|
116
|
+
# selection happens.
|
117
|
+
def row_selection_handlers
|
118
|
+
# add a selection listener to select data table rows
|
119
|
+
selection_model.addListSelectionListener do |list_event|
|
120
|
+
process_list_selection( list_event )
|
121
|
+
end
|
122
|
+
|
123
|
+
# selections in the main table must clear any selections
|
124
|
+
# in the row header, ie self
|
125
|
+
table_view.jtable.selection_model.addListSelectionListener do |event|
|
126
|
+
selection_model.clear_selection unless row_header_selecting
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# guard to make sure changes to main table selection don't feed back.
|
131
|
+
def row_header_selecting( &block )
|
132
|
+
if block_given?
|
133
|
+
begin
|
134
|
+
@row_header_selecting = true
|
135
|
+
yield
|
136
|
+
ensure
|
137
|
+
@row_header_selecting = false
|
138
|
+
end
|
139
|
+
else
|
140
|
+
@row_header_selecting
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def process_list_selection( event )
|
145
|
+
# tell the main table handler we're busy
|
146
|
+
row_header_selecting do
|
147
|
+
# clear main table selection and start again
|
148
|
+
table_view.jtable.selection_model.clear_selection
|
149
|
+
|
150
|
+
# select the whole row in main table. Subsequent row selections will also
|
151
|
+
# select the whole row. What a broken API.
|
152
|
+
table_view.jtable.setColumnSelectionInterval( table_view.model.fields.size-1, 0 )
|
153
|
+
|
154
|
+
selected_rows.each do |row|
|
155
|
+
table_view.jtable.selection_model.addSelectionInterval( row, row )
|
156
|
+
end
|
157
|
+
|
158
|
+
# make sure the keyboard focus is on the latest selected row
|
159
|
+
table_view.jtable.selection_model.addSelectionInterval( selection_model.lead_selection_index, selection_model.lead_selection_index )
|
160
|
+
|
161
|
+
# make sure main table gets focus again
|
162
|
+
table_view.request_focus
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# return self so that getTableCellRendererComponent is called
|
167
|
+
def getCellRenderer( row, column )
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
# Implementation of TableCellRenderer
|
172
|
+
# return renderer Component
|
173
|
+
def getTableCellRendererComponent(jtable, value,is_selected,has_focus,row,column)
|
174
|
+
item = table_view.model.collection[row]
|
175
|
+
renderer = get_default_renderer( java.lang.Object ).getTableCellRendererComponent(jtable,value,is_selected,has_focus,row,column)
|
176
|
+
|
177
|
+
case
|
178
|
+
# no highlighting for an empty item
|
179
|
+
when item.nil?
|
180
|
+
renderer.background = java.awt.Color::yellow
|
181
|
+
renderer.opaque = true
|
182
|
+
renderer.tool_tip_text = "deleted elsewhere"
|
183
|
+
|
184
|
+
# there's a validation error
|
185
|
+
when item.errors && !item.errors.empty?
|
186
|
+
renderer.background = java.awt.Color::orange
|
187
|
+
renderer.opaque = true
|
188
|
+
renderer.tool_tip_text = "validation errors"
|
189
|
+
|
190
|
+
# record isn't saved yet
|
191
|
+
when item.changed?
|
192
|
+
renderer.background = java.awt.Color::yellow
|
193
|
+
renderer.opaque = true
|
194
|
+
renderer.tool_tip_text = "row not saved"
|
195
|
+
|
196
|
+
when is_selected
|
197
|
+
renderer.background = javax.swing.UIManager.get 'Table.selectionBackground'
|
198
|
+
renderer.tool_tip_text = "id=#{item.id}"
|
199
|
+
|
200
|
+
else
|
201
|
+
renderer.tool_tip_text = "id=#{item.id}"
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
renderer
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'clevic/extensions.rb'
|
2
|
+
require 'clevic/swing/extensions.rb'
|
3
|
+
|
4
|
+
module Clevic
|
5
|
+
class SearchDialog < javax.swing.JDialog
|
6
|
+
def initialize( parent = nil, modal = true )
|
7
|
+
if parent
|
8
|
+
# JDK 5 barfs on this
|
9
|
+
super(parent)
|
10
|
+
else
|
11
|
+
super()
|
12
|
+
end
|
13
|
+
|
14
|
+
init_controls
|
15
|
+
init_layout
|
16
|
+
|
17
|
+
self.default_close_operation = javax.swing.WindowConstants::HIDE_ON_CLOSE
|
18
|
+
self.name = "SearchDialog"
|
19
|
+
self.modal = modal
|
20
|
+
self.title = "Search"
|
21
|
+
|
22
|
+
# Enter triggers Ok button
|
23
|
+
root_pane.default_button = ok_button
|
24
|
+
|
25
|
+
# TODO finish this for Esc key to close dialog
|
26
|
+
#~ esc = javax.swing.KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 )
|
27
|
+
#~ root_pane.registerKeyboardAction( actionListener, stroke, javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW )
|
28
|
+
end
|
29
|
+
|
30
|
+
# after the dialog, this will be either accepted or rejected
|
31
|
+
attr_reader :status
|
32
|
+
|
33
|
+
def from_start?
|
34
|
+
from_start.selected
|
35
|
+
end
|
36
|
+
|
37
|
+
def from_start=( value )
|
38
|
+
from_start.selected = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def regex?
|
42
|
+
regex.selected
|
43
|
+
end
|
44
|
+
|
45
|
+
def whole_words?
|
46
|
+
whole_words.selected
|
47
|
+
end
|
48
|
+
|
49
|
+
def forwards?
|
50
|
+
forwards.selected
|
51
|
+
end
|
52
|
+
|
53
|
+
def backwards?
|
54
|
+
backwards.selected
|
55
|
+
end
|
56
|
+
|
57
|
+
# return either :backwards or :forwards
|
58
|
+
def direction
|
59
|
+
return :forwards if forwards?
|
60
|
+
return :backwards if backwards?
|
61
|
+
raise "direction not known"
|
62
|
+
end
|
63
|
+
|
64
|
+
# show the dialog, wait for close,
|
65
|
+
# return an object that understands rejected? and accepted?
|
66
|
+
def exec( text = '' )
|
67
|
+
self.search_text = text
|
68
|
+
search_combo.request_focus
|
69
|
+
search_combo.editor.select_all
|
70
|
+
|
71
|
+
# modal dialog, so this will wait
|
72
|
+
show
|
73
|
+
|
74
|
+
# remember previous searches
|
75
|
+
unless search_combo.include?( search_text )
|
76
|
+
search_combo << search_text
|
77
|
+
end
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def search_text=( value )
|
83
|
+
search_combo.editor.item = value.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def search_text
|
87
|
+
search_combo.editor.item
|
88
|
+
end
|
89
|
+
|
90
|
+
def accepted?
|
91
|
+
status == :accept
|
92
|
+
end
|
93
|
+
|
94
|
+
def accept!
|
95
|
+
@status = :accept
|
96
|
+
end
|
97
|
+
|
98
|
+
def rejected?
|
99
|
+
status == :reject
|
100
|
+
end
|
101
|
+
|
102
|
+
def reject!
|
103
|
+
@status = :reject
|
104
|
+
end
|
105
|
+
|
106
|
+
attr_reader :search_label, :search_combo
|
107
|
+
attr_reader :from_start, :whole_words, :regex
|
108
|
+
attr_reader :forwards, :backwards
|
109
|
+
attr_reader :ok_button, :cancel_button
|
110
|
+
|
111
|
+
def init_controls
|
112
|
+
@search_label = javax.swing.JLabel.new( "Search" ).tap do |search_label|
|
113
|
+
search_label.text = "Search"
|
114
|
+
search_label.name = "search_label"
|
115
|
+
end
|
116
|
+
|
117
|
+
@search_combo = javax.swing.JComboBox.new.tap do |search_combo|
|
118
|
+
search_combo.editable = true
|
119
|
+
search_combo.name = "search_combo"
|
120
|
+
end
|
121
|
+
|
122
|
+
@from_start = javax.swing.JCheckBox.new.tap do |from_start|
|
123
|
+
from_start.mnemonic = 'S'
|
124
|
+
from_start.text = "From Start"
|
125
|
+
from_start.name = "from_start"
|
126
|
+
end
|
127
|
+
|
128
|
+
@regex = javax.swing.JCheckBox.new.tap do |regex|
|
129
|
+
regex.mnemonic = 'R'
|
130
|
+
regex.text = "Regular Expression"
|
131
|
+
regex.name = "regex"
|
132
|
+
end
|
133
|
+
|
134
|
+
@whole_words = javax.swing.JCheckBox.new.tap do |whole_words|
|
135
|
+
whole_words.mnemonic = 'W'
|
136
|
+
whole_words.text = "Whole words"
|
137
|
+
whole_words.name = "whole_words"
|
138
|
+
end
|
139
|
+
|
140
|
+
@forwards = javax.swing.JRadioButton.new.tap do |forwards|
|
141
|
+
forwards.mnemonic = 'F'
|
142
|
+
forwards.text = "Forwards"
|
143
|
+
forwards.name = "forwards"
|
144
|
+
forwards.selected = true
|
145
|
+
end
|
146
|
+
|
147
|
+
@backwards = javax.swing.JRadioButton.new.tap do |backwards|
|
148
|
+
backwards.mnemonic = 'B'
|
149
|
+
backwards.text = "Backwards"
|
150
|
+
backwards.name = "backwards"
|
151
|
+
end
|
152
|
+
|
153
|
+
@ok_button = javax.swing.JButton.new.tap do |ok_button|
|
154
|
+
ok_button.mnemonic = 'O'
|
155
|
+
ok_button.text = "Ok"
|
156
|
+
ok_button.name = "ok_button"
|
157
|
+
ok_button.add_action_listener do |event|
|
158
|
+
hide
|
159
|
+
accept!
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
@cancel_button = javax.swing.JButton.new.tap do |cancel_button|
|
164
|
+
cancel_button.mnemonic = 'C'
|
165
|
+
cancel_button.text = "Cancel"
|
166
|
+
cancel_button.name = "cancel_button"
|
167
|
+
cancel_button.add_action_listener do |event|
|
168
|
+
hide
|
169
|
+
reject!
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# this was originally Java from NetBeans, so it's really ugly.
|
175
|
+
# Note that for 1.5 compatibility, we have to use org.jdesktop.layout.GroupLayout
|
176
|
+
# and include swing-layout-1.0.3.jar
|
177
|
+
def init_layout
|
178
|
+
content_pane.layout = org.jdesktop.layout.GroupLayout.new( content_pane ).tap do |layout|
|
179
|
+
getContentPane().setLayout(layout);
|
180
|
+
layout.setHorizontalGroup( \
|
181
|
+
layout.createParallelGroup(org.jdesktop.layout.GroupLayout::LEADING) \
|
182
|
+
.add(layout.createSequentialGroup() \
|
183
|
+
.addContainerGap() \
|
184
|
+
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout::LEADING) \
|
185
|
+
.add(layout.createSequentialGroup() \
|
186
|
+
.add(21, 21, 21) \
|
187
|
+
.add(search_label) \
|
188
|
+
.addPreferredGap(org.jdesktop.layout.LayoutStyle::RELATED) \
|
189
|
+
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout::LEADING, false) \
|
190
|
+
.add(search_combo, 0, 192, java.lang.Short::MAX_VALUE) \
|
191
|
+
.add(from_start, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, java.lang.Short::MAX_VALUE) \
|
192
|
+
.add(regex, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, java.lang.Short::MAX_VALUE) \
|
193
|
+
.add(whole_words, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, java.lang.Short::MAX_VALUE) \
|
194
|
+
.add(forwards, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, java.lang.Short::MAX_VALUE) \
|
195
|
+
.add(backwards))) \
|
196
|
+
.add(layout.createSequentialGroup() \
|
197
|
+
.add(ok_button) \
|
198
|
+
.addPreferredGap(org.jdesktop.layout.LayoutStyle::RELATED, 160, java.lang.Short::MAX_VALUE) \
|
199
|
+
.add(cancel_button))) \
|
200
|
+
.add(16, 16, 16)) \
|
201
|
+
);
|
202
|
+
layout.setVerticalGroup(
|
203
|
+
layout.createParallelGroup(org.jdesktop.layout.GroupLayout::LEADING) \
|
204
|
+
.add(org.jdesktop.layout.GroupLayout::TRAILING, layout.createSequentialGroup() \
|
205
|
+
.addContainerGap(23, java.lang.Short::MAX_VALUE) \
|
206
|
+
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout::BASELINE) \
|
207
|
+
.add(search_combo, org.jdesktop.layout.GroupLayout::PREFERRED_SIZE, org.jdesktop.layout.GroupLayout::DEFAULT_SIZE, org.jdesktop.layout.GroupLayout::PREFERRED_SIZE) \
|
208
|
+
.add(search_label)) \
|
209
|
+
.add(18, 18, 18) \
|
210
|
+
.add(from_start) \
|
211
|
+
.addPreferredGap(org.jdesktop.layout.LayoutStyle::RELATED) \
|
212
|
+
.add(regex) \
|
213
|
+
.addPreferredGap(org.jdesktop.layout.LayoutStyle::RELATED) \
|
214
|
+
.add(whole_words) \
|
215
|
+
.add(18, 18, 18) \
|
216
|
+
.add(forwards) \
|
217
|
+
.addPreferredGap(org.jdesktop.layout.LayoutStyle::RELATED) \
|
218
|
+
.add(backwards) \
|
219
|
+
.add(18, 18, 18) \
|
220
|
+
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout::BASELINE) \
|
221
|
+
.add(ok_button) \
|
222
|
+
.add(cancel_button)) \
|
223
|
+
.add(20, 20, 20)) \
|
224
|
+
);
|
225
|
+
end
|
226
|
+
pack
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Clevic
|
2
|
+
|
3
|
+
=begin
|
4
|
+
QItemSelectionRange contains information about a range of selected items in a
|
5
|
+
model. A range of items is a contiguous array of model items, extending to
|
6
|
+
cover a number of adjacent rows and columns with a common parent item; this
|
7
|
+
can be visualized as a two-dimensional block of cells in a table
|
8
|
+
|
9
|
+
file:///usr/share/doc/qt-4.6.2/html/qitemselectionrange.html#details
|
10
|
+
=end
|
11
|
+
class SelectionRange
|
12
|
+
# row_range and column_range are Range objects
|
13
|
+
def initialize( row_range, column_range )
|
14
|
+
@row_range = row_range
|
15
|
+
@column_range = column_range
|
16
|
+
end
|
17
|
+
|
18
|
+
def height
|
19
|
+
@row_range.distance
|
20
|
+
end
|
21
|
+
|
22
|
+
def width
|
23
|
+
@column_range.distance
|
24
|
+
end
|
25
|
+
|
26
|
+
def top_left
|
27
|
+
SwingTableIndex.new( nil, @row_range.first, @column_range.first )
|
28
|
+
end
|
29
|
+
|
30
|
+
def bottom_right
|
31
|
+
SwingTableIndex.new( nil, @row_range.last, @column_range.last )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class SelectionModel
|
36
|
+
def initialize( table_view )
|
37
|
+
@table_view = table_view
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :table_view
|
41
|
+
|
42
|
+
def jtable
|
43
|
+
@table_view.jtable
|
44
|
+
end
|
45
|
+
|
46
|
+
# return a collection of selection ranges
|
47
|
+
def ranges
|
48
|
+
rv = []
|
49
|
+
jtable.selected_rows.to_a.group.each do |row_group|
|
50
|
+
jtable.selected_columns.to_a.group.each do |column_group|
|
51
|
+
rv << SelectionRange.new( row_group.range, column_group.range )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rv
|
55
|
+
end
|
56
|
+
|
57
|
+
def single_cell?
|
58
|
+
jtable.selected_row_count == 1 && jtable.selected_column_count == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def selected?( row, column )
|
62
|
+
selected_indexes.first.with do |index|
|
63
|
+
index.row == row &&
|
64
|
+
index.column == column
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# return an array of integer indexes for currently selected rows
|
69
|
+
def row_indexes
|
70
|
+
jtable.selected_rows.to_a
|
71
|
+
end
|
72
|
+
|
73
|
+
def clear
|
74
|
+
jtable.clear_selection
|
75
|
+
end
|
76
|
+
|
77
|
+
# return the full set of selected indexes, ordered
|
78
|
+
# by row then column
|
79
|
+
def selected_indexes
|
80
|
+
indexes = []
|
81
|
+
jtable.selected_rows.each do |row_index|
|
82
|
+
jtable.selected_columns.each do |column_index|
|
83
|
+
indexes << table_view.model.create_index( row_index, column_index )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
indexes
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|