Class: Clevic::TableView
- Includes:
- ActionBuilder
- Defined in:
- lib/clevic/table_view.rb,
lib/clevic/qt/table_view.rb,
lib/clevic/swing/table_view.rb,
lib/clevic/table_view_paste.rb
Overview
The view class
Defined Under Namespace
Classes: EmptyAction
Instance Attribute Summary collapse
-
#before_edit_index ⇒ Object
Returns the value of attribute before_edit_index.
-
#filters ⇒ Object
the current stack of filter commands.
-
#jtable ⇒ Object
readonly
Returns the value of attribute jtable.
-
#next_index ⇒ Object
set next_index for certain operations.
-
#object_name ⇒ Object
Returns the value of attribute object_name.
Instance Method Summary collapse
-
#action_triggered(&block) ⇒ Object
hook for the sanity_check_xxx methods called for the actions set up by ActionBuilder it just wraps the action block/method in a catch block for :insane.
-
#add_action(action) ⇒ Object
collect actions for the popup menu.
- #add_map(key_string, action = empty_action) ⇒ Object
-
#auto_size_attribute(attribute, sample) ⇒ Object
alternative access for auto_size_column.
-
#auto_size_column(col, sample) ⇒ Object
set the size of the column from the sample.
-
#busy_cursor(&block) ⇒ Object
show a busy cursor, do the block, back to normal cursor return value of block.
- #clipboard ⇒ Object
-
#closeEditor(editor, end_edit_hint) ⇒ Object
override to prevent tab pressed from editing next field also takes into account that override_next_index may have been called.
-
#column_size(col, data) ⇒ Object
set the size of the column from the string value of the data mostly copied from qheaderview.cpp:2301.
-
#column_width(col, data) ⇒ Object
calculate the size of the column from the string value of the data.
-
#commitData(editor) ⇒ Object
this is the only method that is called when an itemDelegate is open and the tabs are changed.
-
#confirm_dialog(question, title) ⇒ Object
returns the Qt::MessageBox.
- #connect_view_signals(entity_view) ⇒ Object
-
#copy_current_selection ⇒ Object
copy current selection to clipboard as CSV TODO add text/csv, text/tab-separated-values, text/html as well as text/plain.
-
#current_index ⇒ Object
return a SwingTableIndex for the current cursor position TODO optimise so we don’t keep creating a new index, only if a selection changed event has occurred.
-
#current_index=(table_index) ⇒ Object
move the cursor & selection to the specified table_index.
-
#current_selection_csv ⇒ Object
return the current selection as csv.
-
#currentChanged(current_index, previous_index) ⇒ Object
save record whenever its row is exited make this work with framework.
-
#delete_cells ⇒ Object
Ask if multiple cell delete is OK, then replace contents of selected cells with nil.
-
#delete_multiple_cells?(question = 'Are you sure you want to delete multiple cells?', &block) ⇒ Boolean
ask the question in a dialog.
- #delete_rows ⇒ Object
-
#delete_selection ⇒ Object
Delete the current selection.
- #ditto ⇒ Object
- #ditto_left ⇒ Object
- #ditto_right ⇒ Object
-
#edit(table_index) ⇒ Object
called from the framework-independent part to edit a cell.
-
#emit_filter_status(bool = nil, ¬ifier_block) ⇒ Object
emit whether the view is filtered or not.
-
#emit_status_text(msg = nil, ¬ifier_block) ⇒ Object
If msg is provided, yield to stored block.
- #empty_action ⇒ Object
-
#field_column(field) ⇒ Object
find the row index for the given field id (symbol).
-
#filter_by_current ⇒ Object
toggle the filter, based on current selection.
- #filter_by_dataset(message = nil, &dataset_block) ⇒ Object
-
#filter_by_indexes(indexes) ⇒ Object
Filter by the value in the current index.
-
#filter_by_options(args) ⇒ Object
This is used by entity view classes.
- #filter_message ⇒ Object
- #filter_status_listeners ⇒ Object
- #filtered? ⇒ Boolean
-
#find ⇒ Object
display a search dialog, and find the entered text.
- #find_next ⇒ Object
-
#find_table_view(entity_model_or_view) ⇒ Object
find the TableView instance for the given entity_view or entity_model.
-
#fix_input_map ⇒ Object
This puts empty actions in the local keyboard map so that the generic keyboard map doesn’t catch them and prevent our menu actions from being triggered TODO I’m sure this isn’t the right way to do this.
- #focusOutEvent(event) ⇒ Object
-
#framework_init(arg, &block) ⇒ Object
Called from the gui-framework adapter code in this class arg is: - an instance of Clevic::View - an instance of TableModel.
-
#handle_key_press(event) ⇒ Object
handle certain key combinations that aren’t shortcuts TODO what is returned from here?.
-
#hideEvent(event) ⇒ Object
work around situation where an ItemDelegate is open when the surrouding tab is changed, but the right events don’t arrive.
-
#init_actions(entity_view) ⇒ Object
called from framework_init.
-
#initialize(arg, &block) ⇒ TableView
constructor
arg is: - an instance of Clevic::View - an instance of TableModel.
- #insert_current_date ⇒ Object
- #itemDelegate(model_index) ⇒ Object
- #keyPressEvent(event) ⇒ Object
-
#last_cell? ⇒ Boolean
is current_index on the bottom_right cell?.
-
#last_row? ⇒ Boolean
is current_index on the last row?.
- #map ⇒ Object
- #metrics ⇒ Object
- #model ⇒ Object
-
#model=(model) ⇒ Object
forward to @jtable also handle model#emit_data_error.
-
#model_actions ⇒ Object
return menu actions for the model, or an empty array if there aren’t any.
- #moveCursor(cursor_action, modifiers) ⇒ Object
-
#new_row ⇒ Object
Add a new row and move to it, provided we’re not in a read-only view.
-
#next_index!(model_index) ⇒ Object
set and move to index.
- #open_editor ⇒ Object
-
#override_next_index(model_index) ⇒ Object
This is to allow entity model UI handlers to tell the view whence to move the cursor when the current editor closes (see closeEditor).
-
#paste ⇒ Object
get something from the clipboard and put it at the current selection intended to be called by action / keyboard / menu handlers.
-
#paste_array(arr) ⇒ Object
Paste array to either a single selection or a matching multiple selection TODO Check for rectangularness, ie csv_arr.map{|row| row.size}.uniq.size == 1.
-
#paste_html ⇒ Object
Paste suitable html to the selection Check for presence of tr tags, and make sure there are no colspan or rowspan attributes on td tags.
-
#paste_text ⇒ Object
LATER probably need a PasteParser or something, to figure out if a file is tsv or csv Try tsv first, because number formats often have embedded ‘,’.
-
#paste_to_index(top_left_index, csv_arr) ⇒ Object
Paste an array to the index, replacing whatever is at that index and whatever is at other indices matching the size of the pasted csv array.
-
#paste_value_to_selection(value) ⇒ Object
set all indexes in the selection to the value.
-
#pluralize(count, singular, plural = nil) ⇒ Object
copied from actionpack.
- #popup_menu ⇒ Object
-
#raise_widget ⇒ Object
make this window visible if it’s in a TabWidget TODO doesn’t really belong here because TableView will not always be in a TabWidget context.
-
#refresh ⇒ Object
force a complete reload of the current tab’s data.
-
#request_focus ⇒ Object
kind-of override of requestFocus, but it will probably only work from Ruby.
-
#resize_columns ⇒ Object
resize all fields based on heuristics rather than iterating through the entire data model.
-
#restore_entity(&block) ⇒ Object
Save the current entity, do something, then restore the cursor position to the entity if possible.
- #sanity_check_ditto ⇒ Object
- #sanity_check_read_only ⇒ Object
- #sanity_check_read_only_table ⇒ Object
-
#sanity_check_types(from, to) ⇒ Object
from and to are ModelIndex instances.
- #save_current_rows ⇒ Object
-
#save_row(index) ⇒ Object
save the entity in the row of the given index actually, model.save will check if the record is really changed before writing to DB.
-
#search(search_criteria) ⇒ Object
search_criteria must respond to: * search_text * whole_words? * direction ( :forward, :backward ) * from_start?.
- #search_dialog ⇒ Object
-
#select_entity(entity, column = nil) ⇒ Object
Move to the row for the given entity and the given column.
-
#selected_rows ⇒ Object
return a collection of collections of SwingTableIndex objects indicating the indices of the current selection.
- #selected_rows_or_current ⇒ Object
- #selection_model ⇒ Object
-
#selection_or_current ⇒ Object
return an array of the current selection, or the current index in an array if the selection is empty.
-
#set_current_unless_override(model_index) ⇒ Object
Call set_current_index with next_index ( from override_next_index ) or model_index, in that order.
- #set_model_data(table_index, value) ⇒ Object
-
#setModel(model) ⇒ Object
make sure row size is correct show error messages for data.
-
#show_error(msg, title = "Error") ⇒ Object
save the entity in the row of the given index actually, model.save will check if the record is really changed before writing to DB.
-
#showEvent(event) ⇒ Object
work around situation where an ItemDelegate is open when the surrouding tab is changed, but the right events don’t arrive.
- #status_text(msg) ⇒ Object
- #status_text_listeners ⇒ Object
- #title ⇒ Object
- #trim_middle(value, max = 40) ⇒ Object
- #unfilter ⇒ Object
- #unfilter_action ⇒ Object
-
#update_filter_status_bar ⇒ Object
update status bar with a message of all filters concatenated.
- #wait_cursor ⇒ Object
-
#with_table_view(entity_model_or_view) {|tv| ... } ⇒ Object
execute the block with the TableView instance currently handling the entity_model_or_view.
Methods included from ActionBuilder
#action, #action_method_or_block, #build_actions, #create_action, #create_key_sequence, #group_names, included, #list, #separator
Constructor Details
#initialize(arg, &block) ⇒ TableView
arg is:
-
an instance of Clevic::View
-
an instance of TableModel
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/clevic/qt/table_view.rb', line 33 def initialize( arg, parent = nil, &block ) # need the empty block here, otherwise Qt bindings grab &block super( parent ) {} framework_init( arg, &block ) # see closeEditor @next_index = nil # set some Qt things self.horizontal_header.movable = false # TODO might be useful to allow movable vertical rows, # but need to change the shortcut ideas of next and previous rows self.vertical_header.movable = false self.vertical_header.default_alignment = Qt::AlignTop | Qt::AlignRight self.sorting_enabled = false # set fonts # TODO leave this here, but commented so we can see how to do it # properly later. #~ Qt::Font.new( font.family, font.point_size * 5 / 6 ).tap do |fnt| #~ self.font = fnt #~ self.horizontal_header.font = fnt #~ end self. = Qt::ActionsContextMenu end |
Instance Attribute Details
#before_edit_index ⇒ Object
Returns the value of attribute before_edit_index.
264 265 266 |
# File 'lib/clevic/qt/table_view.rb', line 264 def before_edit_index @before_edit_index end |
#filters ⇒ Object
the current stack of filter commands
19 20 21 |
# File 'lib/clevic/table_view.rb', line 19 def filters @filtered ||= [] end |
#jtable ⇒ Object (readonly)
Returns the value of attribute jtable.
195 196 197 |
# File 'lib/clevic/swing/table_view.rb', line 195 def jtable @jtable end |
#next_index ⇒ Object
set next_index for certain operations. Is only activated when to_next_index is called.
651 652 653 |
# File 'lib/clevic/table_view.rb', line 651 def next_index @next_index end |
#object_name ⇒ Object
Returns the value of attribute object_name.
56 57 58 |
# File 'lib/clevic/table_view.rb', line 56 def object_name @object_name end |
Instance Method Details
#action_triggered(&block) ⇒ Object
hook for the sanity_check_xxx methods called for the actions set up by ActionBuilder it just wraps the action block/method in a catch block for :insane. Will also catch exceptions thrown in actions to make core application more robust to model & view errors.
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/clevic/table_view.rb', line 77 def action_triggered( &block ) catch :insane do yield end rescue Exception => e puts puts "#{model.entity_view.class.name}: #{e.}" puts e.backtrace end |
#add_action(action) ⇒ Object
collect actions for the popup menu
384 385 386 |
# File 'lib/clevic/swing/table_view.rb', line 384 def add_action( action ) ( @context_actions ||= [] ) << action end |
#add_map(key_string, action = empty_action) ⇒ Object
160 161 162 |
# File 'lib/clevic/swing/table_view.rb', line 160 def add_map( key_string, action = empty_action ) map.put( javax.swing.KeyStroke.getKeyStroke( key_string ), action ) end |
#auto_size_attribute(attribute, sample) ⇒ Object
alternative access for auto_size_column
331 332 333 |
# File 'lib/clevic/table_view.rb', line 331 def auto_size_attribute( attribute, sample ) auto_size_column( model.attributes.index( attribute ), sample ) end |
#auto_size_column(col, sample) ⇒ Object
set the size of the column from the sample
103 104 105 |
# File 'lib/clevic/qt/table_view.rb', line 103 def auto_size_column( col, sample ) self.set_column_width( col, column_size( col, sample ).width ) end |
#busy_cursor(&block) ⇒ Object
show a busy cursor, do the block, back to normal cursor return value of block
374 375 376 |
# File 'lib/clevic/swing/table_view.rb', line 374 def busy_cursor( &block ) override_cursor( Qt::BusyCursor, &block ) end |
#clipboard ⇒ Object
134 135 136 137 |
# File 'lib/clevic/table_view.rb', line 134 def clipboard # Clipboard will be a framework-specific class @clipboard = Clipboard.new end |
#closeEditor(editor, end_edit_hint) ⇒ Object
override to prevent tab pressed from editing next field also takes into account that override_next_index may have been called
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/clevic/qt/table_view.rb', line 285 def closeEditor( editor, end_edit_hint ) if $options[:debug] puts "end_edit_hint: #{Qt::AbstractItemDelegate.constants.find {|x| Qt::AbstractItemDelegate.const_get(x) == end_edit_hint } }" puts "next_index: #{next_index.inspect}" end subsequent_index = case end_edit_hint when Qt::AbstractItemDelegate.EditNextItem super( editor, Qt::AbstractItemDelegate.NoHint ) before_edit_index.choppy { |i| i.column += 1 } when Qt::AbstractItemDelegate.EditPreviousItem super( editor, Qt::AbstractItemDelegate.NoHint ) before_edit_index.choppy { |i| i.column -= 1 } else super nil end unless subsequent_index.nil? puts "subsequent_index: #{subsequent_index.inspect}" if $options[:debug] # TODO all this really does is reset next_index set_current_unless_override( next_index || subsequent_index || before_edit_index ) self.before_edit_index = nil end end |
#column_size(col, data) ⇒ Object
set the size of the column from the string value of the data mostly copied from qheaderview.cpp:2301
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/clevic/qt/table_view.rb', line 113 def column_size( col, data ) opt = Qt::StyleOptionHeader.new # fetch font size opt.fontMetrics = metrics opt.rect = opt.fontMetrics.bounding_rect( data.to_s ) # set data opt.text = data.to_s opt.section = case when col == 0 Qt::StyleOptionHeader::Beginning when col > 0 && col < model.fields.size - 1 Qt::StyleOptionHeader::Middle when col == model.fields.size - 1 Qt::StyleOptionHeader::End end size = Qt::Size.new( opt.fontMetrics.width( data.to_s ), opt.fontMetrics.height ) # final parameter could be header section style.sizeFromContents( Qt::Style::CT_HeaderSection, opt, size ) end |
#column_width(col, data) ⇒ Object
calculate the size of the column from the string value of the data
292 293 294 |
# File 'lib/clevic/swing/table_view.rb', line 292 def column_width( col, data ) @jtable.getFontMetrics( @jtable.font ).stringWidth( data.to_s ) + 5 end |
#commitData(editor) ⇒ Object
this is the only method that is called when an itemDelegate is open and the tabs are changed. Work around situation where an ItemDelegate is open when the surrouding tab is changed, but the right events don’t arrive.
239 240 241 242 243 244 245 246 |
# File 'lib/clevic/qt/table_view.rb', line 239 def commitData( editor ) super save_current_row if @hiding rescue puts $!. puts $!.backtrace show_error "Error saving data from #{editor.inspect}: #{$!.}" end |
#confirm_dialog(question, title) ⇒ Object
returns the Qt::MessageBox
182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/clevic/qt/table_view.rb', line 182 def confirm_dialog( question, title ) msg = Qt::MessageBox.new( Qt::MessageBox::Question, title, question, Qt::MessageBox::Yes | Qt::MessageBox::No, self ) msg.exec msg end |
#connect_view_signals(entity_view) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/clevic/qt/table_view.rb', line 61 def connect_view_signals( entity_view ) model.connect SIGNAL( 'dataChanged ( const QModelIndex &, const QModelIndex & )' ) do |top_left, bottom_right| begin entity_view.notify_data_changed( self, top_left, bottom_right ) rescue Exception => e puts puts "#{model.entity_view.class.name}: #{e.}" puts e.backtrace end end end |
#copy_current_selection ⇒ Object
copy current selection to clipboard as CSV TODO add text/csv, text/tab-separated-values, text/html as well as text/plain
141 142 143 |
# File 'lib/clevic/table_view.rb', line 141 def copy_current_selection clipboard.text = current_selection_csv end |
#current_index ⇒ Object
return a SwingTableIndex for the current cursor position TODO optimise so we don’t keep creating a new index, only if a selection changed event has occurred
364 365 366 |
# File 'lib/clevic/swing/table_view.rb', line 364 def current_index model.create_index( @jtable.selected_row, @jtable.selected_column ) end |
#current_index=(table_index) ⇒ Object
move the cursor & selection to the specified table_index
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/clevic/swing/table_view.rb', line 335 def current_index=( table_index ) @jtable.selection_model.clear_selection @jtable.setColumnSelectionInterval( table_index.column, table_index.column ) @jtable.setRowSelectionInterval( table_index.row, table_index.row ) # x position. Should be sum of widths of all columns up to the beginning of this one # ie not including this one, hence the -1 xpos = (0..table_index.column-1).inject(0) do |sum,column_index| sum + @jtable.column_model.getColumn( column_index ).width end rect = java.awt.Rectangle.new( xpos, # y position @jtable.row_height * table_index.row, # width of this column @jtable.column_model.getColumn( table_index.column ).width, # height @jtable.row_height ) @jtable.scrollRectToVisible( rect ) end |
#current_selection_csv ⇒ Object
return the current selection as csv
146 147 148 149 150 151 152 |
# File 'lib/clevic/table_view.rb', line 146 def current_selection_csv buffer = StringIO.new selected_rows.each do |row| buffer << row.map {|index| index.edit_value }.to_csv end buffer.string end |
#currentChanged(current_index, previous_index) ⇒ Object
save record whenever its row is exited make this work with framework
481 482 483 484 485 486 487 |
# File 'lib/clevic/table_view.rb', line 481 def currentChanged( current_index, previous_index ) if previous_index.valid? && current_index.row != previous_index.row self.next_index = nil save_row( previous_index ) end super end |
#delete_cells ⇒ Object
Ask if multiple cell delete is OK, then replace contents of selected cells with nil.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/clevic/table_view.rb', line 375 def delete_cells delete_multiple_cells? do cells_deleted = false # do delete selection_model.selected_indexes.each do |index| index.attribute_value = nil cells_deleted = true end # deletes were done, so call data_changed if cells_deleted # save affected rows selection_model.row_indexes.each do |row_index| save_row( model.create_index( row_index, 0 ) ) end # emit data changed for all ranges selection_model.ranges.each do |selection_range| model.data_changed( selection_range ) end end end end |
#delete_multiple_cells?(question = 'Are you sure you want to delete multiple cells?', &block) ⇒ Boolean
ask the question in a dialog. If the user says yes, execute the block
359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/clevic/table_view.rb', line 359 def delete_multiple_cells?( question = 'Are you sure you want to delete multiple cells?', &block ) sanity_check_read_only # go ahead with delete if there's only 1 cell, or the user says OK delete_ok = if selection_model.selected_indexes.size > 1 confirm_dialog( question, "Multiple Delete" ).accepted? else true end yield if delete_ok end |
#delete_rows ⇒ Object
400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/clevic/table_view.rb', line 400 def delete_rows delete_multiple_cells?( "Are you sure you want to delete #{selection_model.row_indexes.size} rows?" ) do begin model.remove_rows( selection_model.row_indexes ) rescue puts $!. puts $!.backtrace show_error $!. end end end |
#delete_selection ⇒ Object
Delete the current selection. If it’s a set of rows, just delete them. If it’s a rectangular selection, set the cells to nil. TODO make sure all affected rows are saved.
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/clevic/table_view.rb', line 254 def delete_selection busy_cursor do begin sanity_check_read_only # TODO translate from ModelIndex objects to row indices puts "#{__FILE__}:#{__LINE__}:implement vertical_header for delete_selection" #~ rows = vertical_header.selection_model.selected_rows.map{|x| x.row} rows = [] unless rows.empty? # header rows are selected, so delete them model.remove_rows( rows ) else # otherwise various cells are selected, so delete the cells delete_cells end rescue show_error $!. end end end |
#ditto ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/clevic/table_view.rb', line 180 def ditto sanity_check_ditto sanity_check_read_only selection_model.selected_indexes.each do |index| one_up_index = index.choppy { |i| i.row -= 1 } previous_value = one_up_index.attribute_value if index.attribute_value != previous_value index.attribute_value = previous_value model.data_changed( index ) end end end |
#ditto_left ⇒ Object
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/clevic/table_view.rb', line 215 def ditto_left sanity_check_ditto sanity_check_read_only unless current_index.column > 0 emit_status_text( 'No column to the left' ) else one_up_left = current_index.choppy { |i| i.row -= 1; i.column -= 1 } sanity_check_types( one_up_left, current_index ) current_index.attribute_value = one_up_left.attribute_value model.data_changed( current_index ) end end |
#ditto_right ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/clevic/table_view.rb', line 202 def ditto_right sanity_check_ditto sanity_check_read_only if current_index.column >= model.column_count - 1 emit_status_text( 'No column to the right' ) else one_up_right = current_index.choppy {|i| i.row -= 1; i.column += 1 } sanity_check_types( one_up_right, current_index ) current_index.attribute_value = one_up_right.attribute_value model.data_changed( current_index ) end end |
#edit(table_index) ⇒ Object
called from the framework-independent part to edit a cell
249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/clevic/qt/table_view.rb', line 249 def edit( model_index, trigger = nil, event = nil ) self.before_edit_index = model_index #~ puts "edit model_index: #{model_index.inspect}" #~ puts "trigger: #{trigger.inspect}" #~ puts "event: #{event.inspect}" if trigger.nil? && event.nil? super( model_index ) else super( model_index, trigger, event ) end rescue Exception => e raise RuntimeError, "#{model.entity_view.class.name}.#{model_index.field.id}: #{e.}", e.backtrace end |
#emit_filter_status(bool = nil, ¬ifier_block) ⇒ Object
emit whether the view is filtered or not
265 266 267 |
# File 'lib/clevic/swing/table_view.rb', line 265 def emit_filter_status( bool ) emit filter_status_signal( bool ) end |
#emit_status_text(msg = nil, ¬ifier_block) ⇒ Object
If msg is provided, yield to stored block. If block is provided, store it for later.
250 251 252 |
# File 'lib/clevic/swing/table_view.rb', line 250 def emit_status_text( string ) emit status_text_signal( string ) end |
#empty_action ⇒ Object
156 157 158 |
# File 'lib/clevic/swing/table_view.rb', line 156 def empty_action @empty_action ||= EmptyAction.new end |
#field_column(field) ⇒ Object
find the row index for the given field id (symbol)
63 64 65 |
# File 'lib/clevic/table_view.rb', line 63 def field_column( field ) raise "use model.field_column( field )" end |
#filter_by_current ⇒ Object
toggle the filter, based on current selection.
490 491 492 |
# File 'lib/clevic/table_view.rb', line 490 def filter_by_current filter_by_indexes( selection_or_current ) end |
#filter_by_dataset(message = nil, &dataset_block) ⇒ Object
544 545 546 547 548 549 550 551 552 553 |
# File 'lib/clevic/table_view.rb', line 544 def filter_by_dataset( = nil, &dataset_block ) # TODO clean this up and make it work AND for multiple columns, OR for multiple rows self.filters << FilterCommand.new( self, , &dataset_block ) # try to end up on the same entity, even after the filter restore_entity { filters.last.doit } # make sure status bar shows status end |
#filter_by_indexes(indexes) ⇒ Object
Filter by the value in the current index. indexes is a collection of TableIndex instances
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/clevic/table_view.rb', line 557 def filter_by_indexes( indexes ) case when indexes.empty? emit_status_text( "No field selected for filter" ) when !indexes.first.field.filterable? emit_status_text( "Can't filter on #{indexes.first.field.label}" ) when indexes.size > 1 emit_status_text( "Can't do multiple selection filters yet" ) when indexes.first.entity.new_record? emit_status_text( "Can't filter on a new row" ) else = "#{indexes.first.field_name} = #{indexes.first.display_value}" filter_by_dataset( ) do |dataset| indexes.first.field.with do |field| if field.association? dataset.filter( field..keys => indexes.first.attribute_value.andand.pk ) else dataset.filter( indexes.first.field_name.to_sym => indexes.first.attribute_value ) end end end end filtered? end |
#filter_by_options(args) ⇒ Object
This is used by entity view classes. Keep it as a compatibility / deprecated option?
496 497 498 499 500 501 502 |
# File 'lib/clevic/table_view.rb', line 496 def ( args ) puts "#{self.class.name}#filter_by_options is deprecated. Use filter_by_dataset( message, &block ) instead." filter_by_dataset( "#{args.inspect}" ) do |dataset| dataset.translate( args ) end end |
#filter_message ⇒ Object
533 534 535 |
# File 'lib/clevic/table_view.rb', line 533 def "Filter: " + filters.map( &:message ).join(' / ') unless filters.empty? end |
#filter_status_listeners ⇒ Object
260 261 262 |
# File 'lib/clevic/swing/table_view.rb', line 260 def filter_status_listeners @filter_status_listeners ||= Set.new end |
#filtered? ⇒ Boolean
24 |
# File 'lib/clevic/table_view.rb', line 24 def filtered?; !filters.empty?; end |
#find ⇒ Object
display a search dialog, and find the entered text
281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/clevic/table_view.rb', line 281 def find result = search_dialog.exec( current_index.display_value ) busy_cursor do case when result.accepted? search( search_dialog ) when result.rejected? puts "Don't search" else puts "unknown dialog result #{result}" end end end |
#find_next ⇒ Object
296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/clevic/table_view.rb', line 296 def find_next # yes, this must be an @ otherwise it lazy-creates # and will never be nil if @search_dialog.nil? emit_status_text( 'No previous find' ) else busy_cursor do save_from_start = search_dialog.from_start? search_dialog.from_start = false search( search_dialog ) search_dialog.from_start = save_from_start end end end |
#find_table_view(entity_model_or_view) ⇒ Object
find the TableView instance for the given entity_view or entity_model. Return nil if no match found. TODO doesn’t really belong here because TableView will not always be in a TabWidget context.
318 319 320 321 322 323 324 |
# File 'lib/clevic/qt/table_view.rb', line 318 def find_table_view( entity_model_or_view ) parent.children.find do |x| if x.is_a? TableView x.model.entity_view.class == entity_model_or_view || x.model.entity_class == entity_model_or_view end end end |
#fix_input_map ⇒ Object
This puts empty actions in the local keyboard map so that the generic keyboard map doesn’t catch them and prevent our menu actions from being triggered TODO I’m sure this isn’t the right way to do this.
172 173 174 175 176 177 178 |
# File 'lib/clevic/swing/table_view.rb', line 172 def fix_input_map add_map 'ctrl pressed C' add_map 'ctrl pressed V' add_map 'meta pressed V' add_map 'ctrl pressed X' add_map 'pressed DEL' end |
#focusOutEvent(event) ⇒ Object
229 230 231 232 |
# File 'lib/clevic/qt/table_view.rb', line 229 def focusOutEvent( event ) super #~ save_current_row end |
#framework_init(arg, &block) ⇒ Object
Called from the gui-framework adapter code in this class arg is:
-
an instance of Clevic::View
-
an instance of TableModel
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/clevic/table_view.rb', line 30 def framework_init( arg, &block ) # the model/entity_class/builder case when arg.is_a?( TableModel ) self.model = arg init_actions( arg.entity_view ) when arg.is_a?( Clevic::View ) model_builder = arg.define_ui model_builder.exec_ui_block( &block ) # make sure the TableView has a fully-populated TableModel # self.model is necessary to invoke the GUI layer self.model = model_builder.build( self ) self.object_name = arg. # connect data_changed signals for the entity_class to respond connect_view_signals( arg ) init_actions( arg ) else raise "Don't know what to do with #{arg.inspect}" end end |
#handle_key_press(event) ⇒ Object
handle certain key combinations that aren’t shortcuts TODO what is returned from here?
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/clevic/table_view.rb', line 414 def handle_key_press( event ) begin # call to entity class for shortcuts begin view_result = model.entity_view.notify_key_press( self, event, current_index ) return view_result unless view_result.nil? rescue Exception => e puts e.backtrace show_error( "Error in shortcut handler for #{model.entity_view.name}: #{e.}" ) end # thrown by the sanity_check_xxx methods catch :insane do case # on the last row, and down is pressed # add a new row when event.down? && last_row? new_row # on the right-bottom cell, and tab is pressed # then add a new row when event.tab? && last_cell? new_row # add new record and go to it # TODO this is actually a shortcut when event.ctrl? && event.return? new_row else #~ puts event.inspect end end rescue Exception => e puts e.backtrace puts e. show_error( "handle_key_press #{__FILE__}:#{__LINE__} error in #{current_index.attribute.to_s}: \"#{e.}\"" ) end end |
#hideEvent(event) ⇒ Object
work around situation where an ItemDelegate is open when the surrouding tab is changed, but the right events don’t arrive.
215 216 217 218 219 |
# File 'lib/clevic/qt/table_view.rb', line 215 def hideEvent( event ) # can't call super here, for some reason. Qt binding says method not found. # super @hiding = true end |
#init_actions(entity_view) ⇒ Object
called from framework_init
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/clevic/table_view.rb', line 90 def init_actions( entity_view ) # add model actions, if they're defined list( :model ) do |ab| entity_view.define_actions( self, ab ) separator unless collect_actions.empty? end # list of actions in the edit menu list( :edit ) do action :action_save, '&Save', :shortcut => 'Ctrl+S', :method => :save_current_rows #~ action :action_cut, 'Cu&t', :shortcut => 'Ctrl+X', :method => :cut_current_selection action :action_copy, '&Copy', :shortcut => 'Ctrl+C', :method => :copy_current_selection action :action_paste, '&Paste', :shortcut => 'Ctrl+V', :method => :paste action :action_delete, '&Delete', :shortcut => 'Del', :method => :delete_selection separator action :action_ditto, 'D&itto', :shortcut => 'Ctrl+\'', :method => :ditto, :tool_tip => 'Copy same field from previous record' action :action_ditto_right, 'Ditto Ri&ght', :shortcut => 'Ctrl+]', :method => :ditto_right, :tool_tip => 'Copy field one to right from previous record' action :action_ditto_left, '&Ditto L&eft', :shortcut => 'Ctrl+[', :method => :ditto_left, :tool_tip => 'Copy field one to left from previous record' action :action_insert_date, 'Insert Date', :shortcut => 'Ctrl+;', :method => :insert_current_date action :action_open_editor, '&Open Editor', :shortcut => 'F4', :method => :open_editor separator action :action_row, 'New Ro&w', :shortcut => 'Ctrl+N', :method => :new_row action :action_refresh, '&Refresh', :shortcut => 'Ctrl+R', :method => :refresh action :action_delete_rows, 'Delete Rows', :shortcut => 'Ctrl+Delete', :method => :delete_rows if $options[:debug] action :action_dump, 'Du&mp', :shortcut => 'Ctrl+Shift+D' do puts model.collection[current_index.row].inspect end end end separator # list of actions for search list( :search ) do action :action_find, '&Find', :shortcut => 'Ctrl+F', :method => :find action :action_find_next, 'Find &Next', :shortcut => 'Ctrl+G', :method => :find_next action :action_filter, 'Fil&ter', :shortcut => 'Ctrl+L', :method => :filter_by_current action :action_unfilter, '&Un-Filter', :enabled => false, :shortcut => 'Ctrl+K', :method => :unfilter #~ action :action_highlight, '&Highlight', :visible => false, :shortcut => 'Ctrl+H' end end |
#insert_current_date ⇒ Object
228 229 230 231 232 |
# File 'lib/clevic/table_view.rb', line 228 def insert_current_date sanity_check_read_only current_index.attribute_value = Time.now model.data_changed( current_index ) end |
#itemDelegate(model_index) ⇒ Object
97 98 99 100 |
# File 'lib/clevic/qt/table_view.rb', line 97 def itemDelegate( model_index ) @pre_delegate_index = model_index super end |
#keyPressEvent(event) ⇒ Object
194 195 196 197 |
# File 'lib/clevic/qt/table_view.rb', line 194 def keyPressEvent( event ) handle_key_press( event ) super end |
#last_cell? ⇒ Boolean
is current_index on the bottom_right cell?
341 342 343 |
# File 'lib/clevic/table_view.rb', line 341 def last_cell? current_index.row == model.row_count - 1 && current_index.column == model.column_count - 1 end |
#last_row? ⇒ Boolean
is current_index on the last row?
336 337 338 |
# File 'lib/clevic/table_view.rb', line 336 def last_row? current_index.row == model.row_count - 1 end |
#map ⇒ Object
164 165 166 |
# File 'lib/clevic/swing/table_view.rb', line 164 def map @map ||= jtable.getInputMap( javax.swing.JComponent::WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ) end |
#metrics ⇒ Object
107 108 109 |
# File 'lib/clevic/qt/table_view.rb', line 107 def metrics @metrics = Qt::FontMetrics.new( font ) end |
#model ⇒ Object
316 317 318 |
# File 'lib/clevic/swing/table_view.rb', line 316 def model @jtable.model end |
#model=(model) ⇒ Object
forward to @jtable also handle model#emit_data_error
171 172 173 174 |
# File 'lib/clevic/qt/table_view.rb', line 171 def model=( model ) setModel( model ) resize_columns end |
#model_actions ⇒ Object
return menu actions for the model, or an empty array if there aren’t any
68 69 70 |
# File 'lib/clevic/table_view.rb', line 68 def model_actions @model_actions ||= [] end |
#moveCursor(cursor_action, modifiers) ⇒ Object
176 177 178 179 |
# File 'lib/clevic/qt/table_view.rb', line 176 def moveCursor( cursor_action, modifiers ) # TODO use this as a preload indicator super end |
#new_row ⇒ Object
Add a new row and move to it, provided we’re not in a read-only view.
244 245 246 247 248 249 |
# File 'lib/clevic/table_view.rb', line 244 def new_row sanity_check_read_only_table model.add_new_item selection_model.clear self.current_index = model.create_index( model.row_count - 1, 0 ) end |
#next_index!(model_index) ⇒ Object
set and move to index. Leave index value in next_index so that it’s not overridden later. TODO All this next_index stuff is becoming a horrible hack.
279 280 281 |
# File 'lib/clevic/qt/table_view.rb', line 279 def next_index!( model_index ) self.current_index = self.next_index = model_index end |
#open_editor ⇒ Object
234 235 236 237 238 239 240 241 |
# File 'lib/clevic/table_view.rb', line 234 def open_editor # tell the table to edit here edit( current_index ) # tell the editing component to do full edit, eg if it's a combo # box to open the list. current_index.field.delegate.full_edit end |
#override_next_index(model_index) ⇒ Object
This is to allow entity model UI handlers to tell the view whence to move the cursor when the current editor closes (see closeEditor). TODO not used?
657 658 659 |
# File 'lib/clevic/table_view.rb', line 657 def override_next_index( model_index ) self.next_index = model_index end |
#paste ⇒ Object
get something from the clipboard and put it at the current selection intended to be called by action / keyboard / menu handlers
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/clevic/table_view_paste.rb', line 12 def paste busy_cursor do sanity_check_read_only # Try text/html then text/plain as tsv or csv # LATER maybe use the java-native-application at some point for # cut'n'paste internally? case when clipboard.html? paste_html when clipboard.text? paste_text else raise PasteError, "clipboard has neither text nor html, so can't paste" end end rescue PasteError => e show_error e. end |
#paste_array(arr) ⇒ Object
Paste array to either a single selection or a matching multiple selection TODO Check for rectangularness, ie csv_arr.map{|row| row.size}.uniq.size == 1
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/clevic/table_view_paste.rb', line 109 def paste_array( arr ) if selection_model.single_cell? # only one cell selected, so paste like a spreadsheet selected_index = selection_model.selected_indexes.first if arr.size == 0 or ( arr.size == 1 and arr.first.size == 0 ) # empty array, so just clear the current selection selected_index.attribute_value = nil else paste_to_index( selected_index, arr ) end else if arr.size == 1 && arr.first.size == 1 # single value to multiple selection paste_value_to_selection arr.first.first else if selection_model.ranges.size != 1 raise PasteError, "Can't paste tabular data to multiple selection." end if selection_model.ranges.first.height != arr.size raise PasteError, "Height of paste area (#{selection_model.ranges.first.height}) doesn't match height of data (#{arr.size})." end if selection_model.ranges.first.width != arr.first.size raise PasteError, "Width of paste area (#{selection_model.ranges.first.width}) doesn't match width of data (#{arr.first.size})." end # size is the same, so do the paste paste_to_index( selected_index, arr ) end end end |
#paste_html ⇒ Object
Paste suitable html to the selection Check for presence of tr tags, and make sure there are no colspan or rowspan attributes on td tags.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/clevic/table_view_paste.rb', line 35 def paste_html emit_status_text "Fetching data." html = clipboard.html # This should really be factored out somewhere and tested thoroughly emit_status_text "Analysing data." doc = if html.is_a? Hpricot::Doc html else Hpricot.parse( html ) end # call the plain text paste if we don't have tabular data if doc.search( "//tr" ).size == 0 paste_text else # throw exception if there are [col|row]span > 1 spans = doc.search( "//td[@rowspan > 1 || @colspan > 1]" ) if spans.size > 0 # make an itemised list of cell_list = spans.map{|x| "- #{x.inner_text}"}.join("\n") raise PasteError, <<-EOF Pasting will not work because source contains spanning cells. If the source is a spreadsheet, you probably have merged cells somewhere. Split them, and try copy and paste again. Cells contain #{cell_list} EOF end # run through the tabular data and convert to simple array emit_status_text "Pasting data." ary = ( doc / :tr ).map do |row| ( row / :td ).map do |cell| # trim leading and trailing \r\n\t # check for br unless cell.search( '//br' ).empty? # treat br as separate lines cell.search('//text()').map( &:to_s ).join("\n") else # otherwise just join text elements cell.search( '//text()' ).join('') end.gsub( /^[\r\n\t]*/, '').gsub( /[\r\n\t]*$/, '') end end paste_array ary end end |
#paste_text ⇒ Object
LATER probably need a PasteParser or something, to figure out if a file is tsv or csv Try tsv first, because number formats often have embedded ‘,’. if tsv doesn’t work, try with csv and test for rectangularness otherwise assume it’s one string. TODO could also heuristically check paste selection area
93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/clevic/table_view_paste.rb', line 93 def paste_text text = clipboard.text case text when /\t/ paste_array( CSV.parse( text, :col_sep => "\t" ) ) # assume multi-line text, or text with commas, is csv when /[,\n]/ paste_array( CSV.parse( text, :col_sep => ',' ) ) else paste_value_to_selection( text ) end end |
#paste_to_index(top_left_index, csv_arr) ⇒ Object
Paste an array to the index, replacing whatever is at that index and whatever is at other indices matching the size of the pasted csv array. Create new rows if there aren’t enough.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/clevic/table_view_paste.rb', line 161 def paste_to_index( top_left_index, csv_arr ) csv_arr_size = csv_arr.size csv_arr.each_with_index do |row,row_index| # append row if we need one model.add_new_item if top_left_index.row + row_index >= model.row_count row.each_with_index do |field, field_index| unless top_left_index.column + field_index >= model.column_count # do paste cell_index = top_left_index.choppy {|i| i.row += row_index; i.column += field_index } emit_status_text( "pasted #{row_index+1} of #{csv_arr_size}") begin cell_index.text_value = field rescue puts $!. puts $!.backtrace show_error( $!. ) end else emit_status_text( "#{pluralize( top_left_index.column + field_index, 'column' )} for pasting data is too large. Truncating." ) end end # save records to db via view, so we get error messages save_row( top_left_index.choppy {|i| i.row += row_index; i.column = 0 } ) end # make the gui refresh model.data_changed do |change| change.top_left = top_left_index change.bottom_right = top_left_index.choppy do |i| i.row += csv_arr.size - 1 i.column += csv_arr.first.size - 1 end end end |
#paste_value_to_selection(value) ⇒ Object
set all indexes in the selection to the value
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/clevic/table_view_paste.rb', line 143 def paste_value_to_selection( value ) selection_model.selected_indexes.each do |index| index.text_value = value # save records to db via view, so we get error messages save_row( index ) end # notify of changed data model.data_changed do |change| sorted = selection_model.selected_indexes.sort change.top_left = sorted.first change.bottom_right = sorted.last end end |
#pluralize(count, singular, plural = nil) ⇒ Object
copied from actionpack
354 355 356 |
# File 'lib/clevic/table_view.rb', line 354 def pluralize(count, singular, plural = nil) "#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize)) end |
#popup_menu ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/clevic/swing/table_view.rb', line 180 def @popup_menu ||= javax.swing.JPopupMenu.new.tap do || model_actions.each do |action| << action.clone.tap{|a| a.shortcut = nil} end # now do the generic edit items edit_actions.each do |action| << action.clone.tap{|a| a.shortcut = nil} end .pack end end |
#raise_widget ⇒ Object
make this window visible if it’s in a TabWidget TODO doesn’t really belong here because TableView will not always be in a TabWidget context. Should emit a signal which is a request to raise
341 342 343 344 345 |
# File 'lib/clevic/qt/table_view.rb', line 341 def # the tab's parent is a StackedWiget, and its parent is TabWidget = parent.parent . = self if .class == Qt::TabWidget end |
#refresh ⇒ Object
force a complete reload of the current tab’s data
312 313 314 315 316 317 318 |
# File 'lib/clevic/table_view.rb', line 312 def refresh busy_cursor do restore_entity do model.reload_data end end end |
#request_focus ⇒ Object
kind-of override of requestFocus, but it will probably only work from Ruby
223 224 225 |
# File 'lib/clevic/swing/table_view.rb', line 223 def request_focus @jtable.request_focus end |
#resize_columns ⇒ Object
resize all fields based on heuristics rather than iterating through the entire data model
347 348 349 350 351 |
# File 'lib/clevic/table_view.rb', line 347 def resize_columns model.fields.each_with_index do |field, index| auto_size_column( index, field.sample ) end end |
#restore_entity(&block) ⇒ Object
Save the current entity, do something, then restore the cursor position to the entity if possible. Return the result of the block.
507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/clevic/table_view.rb', line 507 def restore_entity( &block ) save_entity = current_index.entity unless save_entity.nil? save_entity.save if save_entity.changed? save_index = current_index end retval = yield # find the entity if possible select_entity( save_entity, save_index.column ) unless save_entity.nil? retval end |
#sanity_check_ditto ⇒ Object
154 155 156 157 158 159 |
# File 'lib/clevic/table_view.rb', line 154 def sanity_check_ditto if current_index.row == 0 emit_status_text( 'No previous record to copy.' ) throw :insane end end |
#sanity_check_read_only ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/clevic/table_view.rb', line 161 def sanity_check_read_only if current_index.field.read_only? emit_status_text( 'Can\'t copy into read-only field.' ) elsif current_index.entity.readonly? emit_status_text( 'Can\'t copy into read-only record.' ) else sanity_check_read_only_table return end throw :insane end |
#sanity_check_read_only_table ⇒ Object
173 174 175 176 177 178 |
# File 'lib/clevic/table_view.rb', line 173 def sanity_check_read_only_table if model.read_only? emit_status_text( 'Can\'t modify a read-only table.' ) throw :insane end end |
#sanity_check_types(from, to) ⇒ Object
from and to are ModelIndex instances. Throws :insane if their fields don’t have the same attribute_type.
195 196 197 198 199 200 |
# File 'lib/clevic/table_view.rb', line 195 def sanity_check_types( from, to ) unless from.field..type == to.field..type emit_status_text( 'Incompatible data' ) throw :insane end end |
#save_current_rows ⇒ Object
454 455 456 457 458 |
# File 'lib/clevic/table_view.rb', line 454 def save_current_rows selection_model.row_indexes.each do |row_index| save_row( model.create_index( row_index, 0 ) ) end end |
#save_row(index) ⇒ Object
save the entity in the row of the given index actually, model.save will check if the record is really changed before writing to DB.
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
# File 'lib/clevic/table_view.rb', line 463 def save_row( index ) if !index.nil? && index.valid? && index.entity saved = model.save( index ) if !saved # construct error message(s) msg = index.entity.errors.map do |field, errors| abbr_value = trim_middle( index.entity.send(field) ) "#{field} (#{abbr_value}) #{errors.join(',')}" end.join( "\n" ) show_error( "Validation Errors: #{index.rc} #{msg}" ) end saved end end |
#search(search_criteria) ⇒ Object
search_criteria must respond to:
-
search_text
-
whole_words?
-
direction ( :forward, :backward )
-
from_start?
620 621 622 623 624 625 626 627 628 629 |
# File 'lib/clevic/table_view.rb', line 620 def search( search_criteria ) indexes = model.search( current_index, search_criteria ) if indexes.size > 0 emit_status_text( "Found #{search_criteria.search_text} at row #{indexes.first.row}" ) selection_model.clear self.current_index = indexes.first else emit_status_text( "No match found for #{search_criteria.search_text}" ) end end |
#search_dialog ⇒ Object
276 277 278 |
# File 'lib/clevic/table_view.rb', line 276 def search_dialog @search_dialog ||= SearchDialog.new( self ) end |
#select_entity(entity, column = nil) ⇒ Object
Move to the row for the given entity and the given column. If column is a symbol, field_column will be called to find the integer index.
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'lib/clevic/table_view.rb', line 589 def select_entity( entity, column = nil ) # sanity check that the entity can actually be found raise "entity is nil" if entity.nil? unless entity.is_a?( model.entity_class ) raise "entity #{entity.class.name} does not match class #{model.entity_class.name}" end # find the row for the saved entity found_row = busy_cursor do model.collection.index_for_entity( entity ) end # create a new index and move to it unless found_row.nil? if column.is_a? Symbol column = model.field_column( column ) elsif column.nil? column = 0 else raise "column #{column} does not exist" if column >= model.fields.size end selection_model.clear self.current_index = model.create_index( found_row, column || 0 ) end end |
#selected_rows ⇒ Object
return a collection of collections of SwingTableIndex objects indicating the indices of the current selection
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/clevic/qt/table_view.rb', line 75 def selected_rows rows = [] selection_model.selection.each do |selection_range| (selection_range.top..selection_range.bottom).each do |row| rows << (selection_range.top_left.column..selection_range.bottom_right.column).map do |col| model.create_index( row, col ) end end end rows end |
#selected_rows_or_current ⇒ Object
326 327 328 |
# File 'lib/clevic/table_view.rb', line 326 def selected_rows_or_current indexes_or_current( selection_model.row_indexes.map{|row| model.create_index( row, 0 ) } ) end |
#selection_model ⇒ Object
330 331 332 |
# File 'lib/clevic/swing/table_view.rb', line 330 def selection_model SelectionModel.new( self ) end |
#selection_or_current ⇒ Object
return an array of the current selection, or the current index in an array if the selection is empty
322 323 324 |
# File 'lib/clevic/table_view.rb', line 322 def selection_or_current indexes_or_current( selection_model.selected_indexes ) end |
#set_current_unless_override(model_index) ⇒ Object
Call set_current_index with next_index ( from override_next_index ) or model_index, in that order. Set next_index to nil afterwards.
663 664 665 666 |
# File 'lib/clevic/table_view.rb', line 663 def set_current_unless_override( model_index ) set_current_index( @next_index || model_index ) self.next_index = nil end |
#set_model_data(table_index, value) ⇒ Object
199 200 201 |
# File 'lib/clevic/qt/table_view.rb', line 199 def set_model_data( table_index, value ) model.setData( table_index, value.to_variant, Qt::PasteRole ) end |
#setModel(model) ⇒ Object
make sure row size is correct show error messages for data
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/clevic/qt/table_view.rb', line 143 def setModel( model ) # must do this otherwise model gets garbage collected @model = model # make sure we get nice spacing vertical_header.default_section_size = metrics.height vertical_header.minimum_section_size = metrics.height super # set delegates model.fields.each_with_index do |field, index| set_item_delegate_for_column( index, field.delegate ) end # data errors model.connect( SIGNAL( 'data_error(QModelIndex, QVariant, QString)' ) ) do |index,variant,msg| show_error( "Incorrect value '#{variant.value}' entered for field [#{index.attribute.to_s}].\nMessage was: #{msg}" ) end end |
#show_error(msg, title = "Error") ⇒ Object
save the entity in the row of the given index actually, model.save will check if the record is really changed before writing to DB.
206 207 208 209 210 |
# File 'lib/clevic/qt/table_view.rb', line 206 def show_error( msg ) = Qt::ErrorMessage.new( self ) .( msg ) .show end |
#showEvent(event) ⇒ Object
work around situation where an ItemDelegate is open when the surrouding tab is changed, but the right events don’t arrive.
224 225 226 227 |
# File 'lib/clevic/qt/table_view.rb', line 224 def showEvent( event ) super @hiding = false end |
#status_text(msg) ⇒ Object
87 88 89 |
# File 'lib/clevic/qt/table_view.rb', line 87 def status_text( msg ) emit status_text( msg ) end |
#status_text_listeners ⇒ Object
244 245 246 |
# File 'lib/clevic/swing/table_view.rb', line 244 def status_text_listeners @status_text_listeners ||= Set.new end |
#title ⇒ Object
58 59 60 |
# File 'lib/clevic/table_view.rb', line 58 def title @title ||= model.entity_view.title end |
#trim_middle(value, max = 40) ⇒ Object
296 297 298 299 300 301 302 |
# File 'lib/clevic/swing/table_view.rb', line 296 def trim_middle( value, max = 40 ) if value && value.length > max "#{value[0..(max/2-2)]}...#{value[-(max/2-2)..-1]}" else value end end |
#unfilter ⇒ Object
522 523 524 525 526 527 |
# File 'lib/clevic/table_view.rb', line 522 def unfilter restore_entity do filters.pop.undo end end |
#unfilter_action ⇒ Object
529 530 531 |
# File 'lib/clevic/table_view.rb', line 529 def unfilter_action search_actions.find{|a| a.object_name == 'action_unfilter' } end |
#update_filter_status_bar ⇒ Object
update status bar with a message of all filters concatenated
538 539 540 541 542 |
# File 'lib/clevic/table_view.rb', line 538 def emit_status_text( ) emit_filter_status( filtered? ) unfilter_action.enabled = filtered? end |
#wait_cursor ⇒ Object
368 369 370 |
# File 'lib/clevic/swing/table_view.rb', line 368 def wait_cursor @wait_cursor ||= java.awt.Cursor.new( java.awt.Cursor::WAIT_CURSOR ) end |
#with_table_view(entity_model_or_view) {|tv| ... } ⇒ Object
execute the block with the TableView instance currently handling the entity_model_or_view. Don’t execute the block if nothing is found. TODO doesn’t really belong here because TableView will not always be in a TabWidget context. TODO put it in a module and add the module when the tab widgets are being built.
333 334 335 336 |
# File 'lib/clevic/qt/table_view.rb', line 333 def with_table_view( entity_model_or_view, &block ) tv = find_table_view( entity_model_or_view ) yield( tv ) unless tv.nil? end |