lib/clevic/qt/table_view.rb in clevic-0.13.0.b9 vs lib/clevic/qt/table_view.rb in clevic-0.13.0.b10

- old
+ new

@@ -12,54 +12,54 @@ # The view class # TODO not sure if we still need override_next_index and friends class TableView < Qt::TableView include ActionBuilder - + # status_text is emitted when this object was to display something in the status bar # filter_status is emitted when the filtering changes. Param is true for filtered, false for not filtered. signals 'status_text_signal(QString)', 'filter_status_signal(bool)' - + def emit_filter_status( bool ) emit filter_status_signal( bool ) end - + def emit_status_text( string ) emit status_text_signal( string ) end - + # arg is: # - an instance of Clevic::View # - an instance of TableModel 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.context_menu_policy = Qt::ActionsContextMenu end - + 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 @@ -67,11 +67,11 @@ puts "#{model.entity_view.class.name}: #{e.message}" puts e.backtrace end end end - + # return a collection of collections of TableIndex objects # indicating the indices of the current selection def selected_rows rows = [] selection_model.selection.each do |selection_range| @@ -81,100 +81,100 @@ end end end rows end - + def status_text( msg ) emit status_text( msg ) end - + def open_editor edit( current_index ) delegate = item_delegate( current_index ) delegate.full_edit end - + def itemDelegate( model_index ) @pre_delegate_index = model_index super end - + # set the size of the column from the sample def auto_size_column( col, sample ) self.set_column_width( col, column_size( col, sample ).width ) end def metrics @metrics = Qt::FontMetrics.new( font ) end - + # set the size of the column from the string value of the data # mostly copied from qheaderview.cpp:2301 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 - + # make sure row size is correct # show error messages for data 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 - + def show_error( msg ) error_message = Qt::ErrorMessage.new( self ) error_message.show_message( msg ) error_message.show end - + # and override this because the Qt bindings don't call # setModel otherwise def model=( model ) setModel( model ) resize_columns end - + def moveCursor( cursor_action, modifiers ) # TODO use this as a preload indicator super end @@ -188,16 +188,16 @@ self ) msg.exec msg end - + def keyPressEvent( event ) handle_key_press( event ) super end - + def set_model_data( table_index, value ) model.setData( table_index, value.to_variant, Qt::PasteRole ) end # save the entity in the row of the given index @@ -206,33 +206,33 @@ def show_error( msg ) error_message = Qt::ErrorMessage.new( self ) error_message.show_message( msg ) error_message.show end - + # work around situation where an ItemDelegate is open # when the surrouding tab is changed, but the right events # don't arrive. def hideEvent( event ) # can't call super here, for some reason. Qt binding says method not found. # super @hiding = true end - + # work around situation where an ItemDelegate is open # when the surrouding tab is changed, but the right events # don't arrive. def showEvent( event ) super @hiding = false end - + def focusOutEvent( event ) super #~ save_current_row end - + # 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. @@ -242,11 +242,11 @@ rescue puts $!.message puts $!.backtrace show_error "Error saving data from #{editor.inspect}: #{$!.message}" end - + # bool QAbstractItemView::edit ( const QModelIndex & index, EditTrigger trigger, QEvent * event ) 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}" @@ -254,15 +254,15 @@ 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.message}", e.backtrace end - + attr_accessor :before_edit_index attr_reader :next_index def next_index=( other_index ) if $options[:debug] puts "debug trace only - not a rescue" @@ -270,49 +270,49 @@ puts "next index to #{other_index.inspect}" puts end @next_index = other_index end - + # 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. def next_index!( model_index ) self.current_index = self.next_index = model_index end - + # override to prevent tab pressed from editing next field # also takes into account that override_next_index may have been called 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 - + # 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. def find_table_view( entity_model_or_view ) @@ -320,11 +320,11 @@ 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 - + # 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. @@ -332,10 +332,10 @@ # are being built. def with_table_view( entity_model_or_view, &block ) tv = find_table_view( entity_model_or_view ) yield( tv ) unless tv.nil? end - + # 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 def raise_widget # the tab's parent is a StackedWiget, and its parent is TabWidget