On 2/2/07, Kelly Burkhart <[EMAIL PROTECTED]> wrote:
Is it possible to select a portion of text within a cell in a
QTreeView (or QTableView)?  I would like to treat one column of cells
as lines of text from which I can select text just like selecting in
an editor.  I do not need to select from multiple lines.

Any ideas on how this can be done?

The attached is what I came up with.  It's not what I thought I wanted
when I started, but I think functionally it is better.

-- You can select arbitrary cells and on X11 middle-click and the cell
contents are pasted in a sensible way.
-- You can select arbitrary cells, <copy> or <cut>, then paste the
contents somewhere else.  (widget is read-only so cut doesn't modify
the contents)
-- You can double click on a cell and select text within a cell and
paste in the usual way.

If any of you see any lossage I'd love to hear it.  I feel like to
some extent I've stumbled through this.  ;-)

One bit that may cause problems is the TstTreeView.copySelection
method.  In X11, it is called on every change to the view selection
and could get quite expensive if a big region is selected.

-K
#!/usr/bin/env python

import sys
import os
from PyQt4 import QtGui, QtCore

class TstModel( QtCore.QAbstractTableModel ):
    
    def __init__( self ):
        QtCore.QAbstractTableModel.__init__(self)

        self._header = ( 'col0', 'col1', 'col2' )
        self._items = [ ('item0', 'item0', 'item0'),
                        ('how do','i select', 'just >this text< from this item'),
                        ('how do','i select', 'what does a multi\nline cell look like?'),
                        ('how do','i select', 'what does a multi\nline cell\nlook\nlike?'),
                        ('item2','item2','item2') ]

    def rowCount( self, parent ):
        if not parent.isValid():
            return len(self._items)
        return 0

    def columnCount( self, parent ):
        return len(self._header)

    def data( self, index, role ):
        if not index.isValid() or role not in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
            return QtCore.QVariant()

        row = index.row()
        col = index.column()
        
        if row < 0 or row >= len(self._items) or col < 0 or col >= len(self._header):
            return QtCore.QVariant()

        return QtCore.QVariant(self._items[row][col])

    def headerData( self, section, orientation, role ):
        if orientation == QtCore.Qt.Horizontal and role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
            return QtCore.QVariant( self._header[section] )

        return QtCore.QVariant()

    def flags( self, index ):
        return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable

class TstTreeView( QtGui.QTreeView ):
    def __init__( self, model ):
        QtGui.QTreeView.__init__(self)
        self.setWindowTitle('TstTreeView')
        self.setModel(model)
        self.setRootIsDecorated(False)
        self.setSortingEnabled(False)
        self.setSelectionBehavior( QtGui.QAbstractItemView.SelectItems )
        self.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection )
        self.resize( 600, 200 )
        self.setItemDelegate( RowDelegate(self) )

        self._supportsSelection = QtGui.QApplication.clipboard().supportsSelection()

    def selectionChanged( self, selected, deselected ):
        QtGui.QTreeView.selectionChanged( self, selected, deselected )
        self.copySelection( QtGui.QClipboard.Selection )

    def keyPressEvent( self, event ):
        if event.matches( QtGui.QKeySequence.Cut ) or event.matches( QtGui.QKeySequence.Copy ):
            self.copySelection( QtGui.QClipboard.Clipboard )
        else:
            QtGui.QTreeView.keyPressEvent( self, event )

    def copySelection( self, mode ):
        if mode == QtGui.QClipboard.Selection and not self._supportsSelection:
            return
        
        maxCol = 0
        sel = []
        for index in self.selectionModel().selectedIndexes():
            if maxCol < index.column():
                maxCol = index.column()
            sel.append( (index.row(), index.column(), index ) )
        sel.sort()

        selectionText = ''
        for item in sel:
            data = self.model().data( item[2], QtCore.Qt.DisplayRole ).toString()
            data.replace('\n', '\\n')
            selectionText += data
            if item[1] == maxCol:
                selectionText += '\n'
            else:
                selectionText += '\t'

        QtGui.QApplication.clipboard().setText( selectionText, mode )

class RowDelegate( QtGui.QItemDelegate ):
    def __init__(self, parent=0):
        QtGui.QItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        rval = QtGui.QItemDelegate.createEditor(self,parent,option,index)
        rval.setReadOnly(True)
        return rval

class Tst:
    def run( self ):
        app = QtGui.QApplication(sys.argv)
        tm = TstModel()
        tv1 = TstTreeView( tm )
        tv1.show()
        
        app.connect(app, QtCore.SIGNAL('lastWindowClosed()'), app, QtCore.SLOT('quit()'))
        sys.exit(app.exec_())

if __name__ == "__main__":
    tst = Tst()
    tst.run()

_______________________________________________
PyKDE mailing list    [email protected]
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

Reply via email to