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