~ubuntu-branches/ubuntu/utopic/python-traitsui/utopic

« back to all changes in this revision

Viewing changes to traitsui/qt4/tree_editor.py

  • Committer: Package Import Robot
  • Author(s): Varun Hiremath
  • Date: 2012-04-23 16:05:43 UTC
  • mfrom: (3.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20120423160543-bgafgw04y68arfjn
Tags: 4.1.0-1
* New upstream release
* Bump Standards-Version to 3.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#-------------------------------------------------------------------------------
18
18
 
19
19
import copy
 
20
import collections
 
21
import logging
20
22
 
21
23
from pyface.qt import QtCore, QtGui
22
24
 
23
25
from pyface.resource_manager import resource_manager
 
26
from pyface.timer.api import do_later
24
27
from traits.api import Any, Event
25
28
from traits.trait_base import enumerate
26
29
from traitsui.api import TreeNode, ObjectTreeNode, MultiTreeNode
30
33
 
31
34
from clipboard import clipboard, PyMimeData
32
35
from editor import Editor
33
 
from helper import open_fbi, pixmap_cache
 
36
from helper import pixmap_cache
 
37
 
 
38
logger = logging.getLogger(__name__)
34
39
 
35
40
#-------------------------------------------------------------------------------
36
41
#  The core tree node menu actions:
37
42
#-------------------------------------------------------------------------------
 
43
from traitsui.ui_traits import SequenceTypes
 
44
 
38
45
 
39
46
NewAction    = 'NewAction'
40
47
CopyAction   = Action( name         = 'Copy',
73
80
    # The currently selected object
74
81
    selected = Any
75
82
 
 
83
    # The event fired when a tree node is activated by double clicking or
 
84
    # pressing the Enter key on a node.
 
85
    activated = Event
 
86
 
76
87
    # The event fired when a tree node is clicked on:
77
88
    click = Event
78
89
 
82
93
    # The event fired when the application wants to veto an operation:
83
94
    veto = Event
84
95
 
 
96
    # The vent fired when the application wants to refresh the viewport.
 
97
    refresh = Event
 
98
 
85
99
    #---------------------------------------------------------------------------
86
100
    #  Finishes initializing the editor by creating the underlying toolkit
87
101
    #  widget:
108
122
                    factory._editor = self
109
123
 
110
124
                    # Create the trait editor panel:
111
 
                    self.control = QtGui.QWidget()
112
 
                    parent.addWidget(self.control)
 
125
                    self.control = sa = QtGui.QScrollArea()
 
126
                    sa.setFrameShape(QtGui.QFrame.NoFrame)
 
127
                    sa.setWidgetResizable(True)
113
128
                    self.control._node_ui = self.control._editor_nid = None
114
129
 
115
130
                    # Check to see if there are any existing editors that are
151
166
 
152
167
                self._editor = sa = QtGui.QScrollArea()
153
168
                sa.setFrameShape(QtGui.QFrame.NoFrame)
 
169
                sa.setWidgetResizable(True)
154
170
                sa._node_ui = sa._editor_nid = None
155
171
 
156
172
                if factory.orientation == 'horizontal':
174
190
        self._undoable = []
175
191
 
176
192
        # Synchronize external object traits with the editor:
 
193
        self.sync_value( factory.refresh,  'refresh' )
177
194
        self.sync_value( factory.selected, 'selected' )
 
195
        self.sync_value( factory.activated,'activated', 'to' )
178
196
        self.sync_value( factory.click,    'click',  'to' )
179
197
        self.sync_value( factory.dclick,   'dclick', 'to' )
180
198
        self.sync_value( factory.veto,     'veto',   'from' )
187
205
        """ Handles the **selection** event.
188
206
        """
189
207
        try:
190
 
            self._tree.setCurrentItem(self._object_info(selection)[2])
 
208
            tree = self._tree
 
209
            if (not isinstance(selection, basestring) and
 
210
                isinstance(selection, collections.Iterable)):
 
211
 
 
212
                item_selection = QtGui.QItemSelection()
 
213
                for sel in selection:
 
214
                    item = self._object_info(sel)[2]
 
215
                    idx = tree.indexFromItem(item)
 
216
                    item_selection.append(QtGui.QItemSelectionRange(idx))
 
217
 
 
218
                tree.selectionModel().select(item_selection,
 
219
                    QtGui.QItemSelectionModel.ClearAndSelect)
 
220
            else:
 
221
                tree.setCurrentItem(self._object_info(selection)[2])
191
222
        except:
192
 
            pass
 
223
            from traitsui.api import raise_to_debug
 
224
            raise_to_debug()
193
225
 
194
226
    #---------------------------------------------------------------------------
195
227
    #  Handles the 'selected' trait being changed:
210
242
        """
211
243
        self._veto = True
212
244
 
 
245
    def _refresh_changed ( self ):
 
246
        """ Update the viewport.
 
247
        """
 
248
        self._tree.viewport().update()
 
249
 
213
250
    #---------------------------------------------------------------------------
214
251
    #  Disposes of the contents of an editor:
215
252
    #---------------------------------------------------------------------------
252
289
            editor.
253
290
        """
254
291
        tree = self._tree
 
292
        if tree is None:
 
293
            return
255
294
        saved_state = {}
256
295
 
 
296
        object, node = self._node_for( self.old_value )
 
297
        old_nid = self._get_object_nid( object, node.get_children_id(object))
 
298
        if old_nid: self._delete_node(old_nid)
 
299
 
 
300
        object, node = self._node_for( self.old_value )
 
301
        old_nid = self._get_object_nid( object, node.get_children_id(object) )
 
302
        if old_nid:
 
303
            self._delete_node(old_nid)
 
304
 
257
305
        tree.clear()
 
306
        self._map = {}
258
307
 
259
308
        object, node = self._node_for( self.value )
260
309
        if node is not None:
261
310
            if self.factory.hide_root:
262
311
                nid = tree.invisibleRootItem()
263
312
            else:
264
 
                nid = QtGui.QTreeWidgetItem(tree)
265
 
                nid.setText(0, node.get_label(object))
266
 
                nid.setIcon(0, self._get_icon(node, object))
267
 
                nid.setToolTip(0, node.get_tooltip(object))
 
313
                nid = self._create_item(tree, node, object)
268
314
 
269
315
            self._map[ id( object ) ] = [ ( node.get_children_id(object), nid ) ]
270
316
            self._add_listeners( node, object )
276
322
                    tree.setCurrentItem(nid)
277
323
 
278
324
            self.expand_levels( nid, self.factory.auto_open, False )
 
325
        ncolumns = self._tree.columnCount()
 
326
        if ncolumns > 1:
 
327
            for i in range(ncolumns):
 
328
                self._tree.resizeColumnToContents(i)
279
329
        # FIXME: Clear the current editor (if any)...
280
330
 
281
331
    #---------------------------------------------------------------------------
287
337
        """
288
338
        return self._tree
289
339
 
 
340
    def _get_brush(self, color) :
 
341
        if isinstance(color, SequenceTypes):
 
342
            q_color = QtGui.QColor(*color)
 
343
        else:
 
344
            q_color = QtGui.QColor(color)
 
345
        return QtGui.QBrush(q_color)
 
346
 
 
347
 
 
348
    def _set_column_labels(self, nid, column_labels):
 
349
        """ Set the column labels.
 
350
        """
 
351
        for i, (header, label) in enumerate(map(None,
 
352
            self.factory.column_headers[1:], column_labels), 1):
 
353
            if header is not None and label is not None:
 
354
                nid.setText(i, label)
 
355
 
 
356
    #---------------------------------------------------------------------------
 
357
        color = node.get_background(object)
 
358
        if color : nid.setBackground(0, self._get_brush(color))
 
359
        color = node.get_foreground(object)
 
360
        if color : nid.setForeground(0, self._get_brush(color))
 
361
    #  Private Delegate class to do drawing in case of wrapped text labels
 
362
    #---------------------------------------------------------------------------
 
363
 
 
364
    class ItemDelegate(QtGui.QStyledItemDelegate):
 
365
        """ A delegate class to draw wrapped text labels """
 
366
        # FIXME: sizeHint() should return the size required by the label,
 
367
        # which is dependent on the width available, which is different for
 
368
        # each item due to the nested tree structure. However the option.rect
 
369
        # argument available to the sizeHint() is invalid (width=-1) so as a
 
370
        # hack sizeHintChanged is emitted in paint() and the size of drawn
 
371
        # text is returned, as paint() gets a valid option.rect argument.
 
372
 
 
373
        def __init__(self, *args, **kwargs):
 
374
            self.size_map = collections.defaultdict(lambda:QtCore.QSize(1,21))
 
375
            QtGui.QStyledItemDelegate.__init__(self, *args, **kwargs)
 
376
 
 
377
        def sizeHint(self, option, index):
 
378
            """ returns area taken by the text. """
 
379
            return self.size_map[self.editor._tree.itemFromIndex(index)]
 
380
 
 
381
        def paint(self, painter, option, index):
 
382
            """ Do the actual drawing of the text """
 
383
            # For icon and highlights during selection etc
 
384
            super(self.__class__, self).paint(painter, option, index)
 
385
 
 
386
            item = self.editor._tree.itemFromIndex(index)
 
387
            expanded, node, object = self.editor._get_node_data(item)
 
388
            text = node.get_label(object)
 
389
            textrect = option.rect
 
390
            if self.editor.factory.show_icons:
 
391
                iconwidth = 24 # FIXME: get width from actual
 
392
            else:
 
393
                iconwidth = 0
 
394
            rect = painter.drawText(option.rect.left() + iconwidth,
 
395
                                    option.rect.top(),
 
396
                                    option.rect.width() - iconwidth,
 
397
                                    option.rect.height(),
 
398
                                    QtCore.Qt.TextWordWrap, text)
 
399
            # Need to set the appropriate sizeHint of the item.
 
400
            if self.size_map[item] != rect.size():
 
401
                self.size_map[item] = rect.size()
 
402
                do_later(self.sizeHintChanged.emit, index)
 
403
 
 
404
 
 
405
    #---------------------------------------------------------------------------
 
406
    #  Create a TreeWidgetItem as per word wrap policy and set icon,tooltip
 
407
    #---------------------------------------------------------------------------
 
408
 
 
409
    def _create_item(self, nid, node, object, index=None):
 
410
        """ Create  a new TreeWidgetItem as per word_wrap policy.
 
411
 
 
412
        Index is the index of the new node in the parent:
 
413
            None implies append the child to the end. """
 
414
        if index is None:
 
415
            cnid = QtGui.QTreeWidgetItem(nid)
 
416
        else:
 
417
            cnid = QtGui.QTreeWidgetItem()
 
418
            nid.insertChild(index, cnid)
 
419
        if self.factory.word_wrap:
 
420
            item = self.ItemDelegate()
 
421
            item.editor = self
 
422
            self._tree.setItemDelegate(item)
 
423
        else:
 
424
            cnid.setText(0, node.get_label(object))
 
425
        cnid.setIcon(0, self._get_icon(node, object))
 
426
        cnid.setToolTip(0, node.get_tooltip(object))
 
427
        return cnid
 
428
 
 
429
    def _set_label(self, nid, text, col=0):
 
430
        """ Set the label of the specified item """
 
431
        if not self.factory.word_wrap or col!=0:
 
432
            expanded, node, object = self._get_node_data(nid)
 
433
            nid.setText(col, node.get_label(object))
 
434
 
290
435
    #---------------------------------------------------------------------------
291
436
    #  Appends a new node to the specified node:
292
437
    #---------------------------------------------------------------------------
294
439
    def _append_node ( self, nid, node, object ):
295
440
        """ Appends a new node to the specified node.
296
441
        """
297
 
        cnid = QtGui.QTreeWidgetItem(nid)
298
 
        cnid.setText(0, node.get_label(object))
299
 
        cnid.setIcon(0, self._get_icon(node, object))
300
 
        cnid.setToolTip(0, node.get_tooltip(object))
 
442
        return self._insert_node( nid, None, node, object )
 
443
 
 
444
    #---------------------------------------------------------------------------
 
445
    #  Inserts a new node to the specified node:
 
446
    #---------------------------------------------------------------------------
 
447
 
 
448
    def _insert_node ( self, nid, index, node, object ):
 
449
        """ Inserts a new node before a specified index into the children of the
 
450
            specified node.
 
451
        """
 
452
        cnid = self._create_item(nid, node, object, index)
301
453
 
302
454
        has_children = self._has_children(node, object)
303
455
        self._set_node_data( cnid, ( False, node, object ) )
339
491
            del pnid._dummy
340
492
            return
341
493
 
342
 
        expanded, node, object = self._get_node_data(nid)
343
 
        id_object = id(object)
344
 
        object_info = self._map[id_object]
345
 
        for i, info in enumerate(object_info):
346
 
            # QTreeWidgetItem does not have an equal operator, so use id()
347
 
            if id(nid) == id(info[1]):
348
 
                del object_info[i]
349
 
                break
 
494
        try:
 
495
            expanded, node, object = self._get_node_data(nid)
 
496
        except AttributeError:
 
497
            # The node has already been deleted.
 
498
            pass
 
499
        else:
 
500
            id_object = id(object)
 
501
            object_info = self._map[id_object]
 
502
            for i, info in enumerate(object_info):
 
503
                # QTreeWidgetItem does not have an equal operator, so use id()
 
504
                if id(nid) == id(info[1]):
 
505
                    del object_info[i]
 
506
                    break
350
507
 
351
 
        if len( object_info ) == 0:
352
 
            self._remove_listeners( node, object )
353
 
            del self._map[ id_object ]
 
508
            if len( object_info ) == 0:
 
509
                self._remove_listeners( node, object )
 
510
                del self._map[ id_object ]
354
511
 
355
512
        if pnid is None:
356
513
            self._tree.takeTopLevelItem(self._tree.indexOfTopLevelItem(nid))
468
625
            node.when_children_changed(  object, self._children_updated,  False)
469
626
 
470
627
        node.when_label_changed( object, self._label_updated, False )
 
628
        node.when_column_labels_change(object, self._column_labels_updated, False)
471
629
 
472
630
    #---------------------------------------------------------------------------
473
631
    #  Removes any event listeners from a specified object:
481
639
            node.when_children_changed(  object, self._children_updated,  True )
482
640
 
483
641
        node.when_label_changed( object, self._label_updated, True )
 
642
        node.when_column_labels_change(object, self._column_labels_updated, False)
484
643
 
485
644
    #---------------------------------------------------------------------------
486
645
    #  Returns the tree node data for a specified object in the form
834
993
        self.dclick = object
835
994
 
836
995
    #---------------------------------------------------------------------------
 
996
    #  Handles a tree item being activated:
 
997
    #---------------------------------------------------------------------------
 
998
 
 
999
    def _on_item_activated(self, nid, col):
 
1000
        """ Handles a tree item being activated.
 
1001
        """
 
1002
        _, node, object = self._get_node_data(nid)
 
1003
 
 
1004
        # Fire the 'activated' event with the clicked on object as value:
 
1005
        self.activated = object
 
1006
 
 
1007
    #---------------------------------------------------------------------------
837
1008
    #  Handles a tree node being selected:
838
1009
    #---------------------------------------------------------------------------
839
1010
 
889
1060
            if object is not None:
890
1061
                # Try to chain the undo history to the main undo history:
891
1062
                view = node.get_view( object )
892
 
                if view is None:
893
 
                    view = object.trait_view()
 
1063
                if view is None or isinstance(view, str) :
 
1064
                    view = object.trait_view(view)
 
1065
 
894
1066
                if (self.ui.history is not None) or (view.kind == 'subpanel'):
895
1067
                    ui = object.edit_traits( parent = editor,
896
1068
                                             view   = view,
1073
1245
 
1074
1246
        return can_rename
1075
1247
 
 
1248
    def _is_droppable ( self, node, object, add_object, for_insert ):
 
1249
        """ Returns whether a given object is droppable on the node.
 
1250
        """
 
1251
        if for_insert and (not node.can_insert( object )):
 
1252
            return False
 
1253
 
 
1254
        return node.can_add( object, add_object )
 
1255
 
 
1256
    def _drop_object ( self, node, object, dropped_object, make_copy = True ):
 
1257
        """ Returns a droppable version of a specified object.
 
1258
        """
 
1259
        new_object = node.drop_object( object, dropped_object )
 
1260
        if (new_object is not dropped_object) or (not make_copy):
 
1261
            return new_object
 
1262
 
 
1263
        return copy.deepcopy( new_object )
 
1264
 
1076
1265
#----- pyface.action 'controller' interface implementation: --------------------
1077
1266
 
1078
1267
    #---------------------------------------------------------------------------
1103
1292
        """ Returns whether the action should be defined in the user interface.
1104
1293
        """
1105
1294
        if action.defined_when != '':
1106
 
            try:
1107
 
                if not eval( action.defined_when, globals(), self._context ):
1108
 
                    return False
1109
 
            except:
1110
 
                open_fbi()
 
1295
            if not eval( action.defined_when, globals(), self._context ):
 
1296
                return False
1111
1297
 
1112
1298
        if action.visible_when != '':
1113
 
            try:
1114
 
                if not eval( action.visible_when, globals(), self._context ):
1115
 
                    return False
1116
 
            except:
1117
 
                open_fbi()
 
1299
            if not eval( action.visible_when, globals(), self._context ):
 
1300
                return False
1118
1301
 
1119
1302
        return True
1120
1303
 
1155
1338
                        'info':    info,
1156
1339
                        'handler': handler } )
1157
1340
            except:
1158
 
                # fixme: Should the exception be logged somewhere?
1159
 
                pass
 
1341
                from traitsui.api import raise_to_debug
 
1342
                raise_to_debug()
1160
1343
            return
1161
1344
 
1162
1345
        method = getattr( handler, method_name, None )
1184
1367
            try:
1185
1368
                if not eval( condition, globals(), self._context ):
1186
1369
                    value = False
1187
 
            except:
1188
 
                open_fbi()
 
1370
            except Exception as e:
 
1371
                logger.warning("Exception (%s) raised when evaluating the "
 
1372
                               "condition %s. Returning True." % (e,condition))
1189
1373
            setattr( object, trait, value )
1190
1374
 
1191
1375
#----- Menu event handlers: ----------------------------------------------------
1276
1460
            if new_label != '':
1277
1461
                node.set_label(object, new_label)
1278
1462
            else:
1279
 
                nid.setText(col, old_label)
 
1463
                self._set_label(nid, old_label, col)
1280
1464
 
1281
1465
    #---------------------------------------------------------------------------
1282
1466
    #  Adds a new object to the current node:
1342
1526
        start = event.index
1343
1527
        n     = len( event.added )
1344
1528
        end   = start + len( event.removed )
1345
 
        tree                = self._tree
 
1529
        tree  = self._tree
1346
1530
 
1347
1531
        for expanded, node, nid in self._object_info_for( object, name ):
1348
1532
            children = node.get_children( object )
1349
1533
 
1350
1534
            # If the new children aren't all at the end, remove/add them all:
1351
 
            if (n > 0) and ((start + n) != len( children )):
1352
 
                self._children_replaced( object, name, event )
1353
 
                return
 
1535
            #if (n > 0) and ((start + n) != len( children )):
 
1536
            #    self._children_replaced( object, name, event )
 
1537
            #    return
1354
1538
 
1355
1539
            # Only add/remove the changes if the node has already been expanded:
1356
1540
            if expanded:
1358
1542
                for cnid in self._nodes_for( nid )[ start: end ]:
1359
1543
                    self._delete_node( cnid )
1360
1544
 
 
1545
                remaining = n - len( event.removed )
 
1546
                child_index = 0
1361
1547
                # Add all of the children that were added:
1362
1548
                for child in event.added:
1363
1549
                    child, child_node = self._node_for( child )
1364
1550
                    if child_node is not None:
1365
 
                        self._append_node( nid, child_node, child )
 
1551
                        insert_index = (start + child_index) if \
 
1552
                                        (start <= remaining) else None
 
1553
                        self._insert_node( nid, insert_index, child_node,
 
1554
                                        child )
 
1555
                        child_index += 1
1366
1556
 
1367
1557
            # Try to expand the node (if requested):
1368
1558
            if node.can_auto_open( object ):
1383
1573
            if nid not in nids:
1384
1574
                nids[ nid ] = None
1385
1575
                node = self._get_node_data( nid )[1]
1386
 
                nid.setText(0, node.get_label(object))
 
1576
                self._set_label(nid, node.get_label(object), 0)
1387
1577
                self._update_icon(nid)
1388
1578
 
1389
1579
        self._tree.blockSignals(blk)
1390
1580
 
 
1581
    def _column_labels_updated(self, object, name, new):
 
1582
        """  Handles the column labels of an object being changed.
 
1583
        """
 
1584
        # Prevent the itemChanged() signal from being emitted.
 
1585
        blk = self._tree.blockSignals(True)
 
1586
 
 
1587
        nids = {}
 
1588
        for name2, nid in self._map[ id( object ) ]:
 
1589
            if nid not in nids:
 
1590
                nids[ nid ] = None
 
1591
                node = self._get_node_data( nid )[1]
 
1592
                # Just do all of them at once. The number of columns should be
 
1593
                # small.
 
1594
                self._set_column_labels(nid, node.get_column_labels(object))
 
1595
 
 
1596
        self._tree.blockSignals(blk)
 
1597
 
1391
1598
#-- UI preference save/restore interface ---------------------------------------
1392
1599
 
1393
1600
    #---------------------------------------------------------------------------
1406
1613
                structure = prefs
1407
1614
 
1408
1615
            self.control.restoreState(structure)
 
1616
        header = self._tree.header()
 
1617
        self.setExpandsOnDoubleClick(editor.factory.expands_on_dclick)
 
1618
 
 
1619
        if header is not None and 'column_state' in prefs:
 
1620
            header.restoreState(prefs['column_state'])
1409
1621
 
1410
1622
    #---------------------------------------------------------------------------
1411
1623
    #  Returns any user preference information associated with the editor:
1414
1626
    def save_prefs ( self ):
1415
1627
        """ Returns any user preference information associated with the editor.
1416
1628
        """
 
1629
        prefs = {}
1417
1630
        if isinstance(self.control, QtGui.QSplitter):
1418
 
            return {'structure': str(self.control.saveState())}
 
1631
            prefs['structure'] = str(self.control.saveState())
 
1632
        header = self._tree.header()
 
1633
        if header is not None:
 
1634
            prefs['column_state'] = str(header.saveState())
1419
1635
 
1420
 
        return None
 
1636
        return prefs
1421
1637
 
1422
1638
#-- End UI preference save/restore interface -----------------------------------
1423
1639
 
1435
1651
        """
1436
1652
        QtGui.QTreeWidget.__init__(self, parent)
1437
1653
 
1438
 
        self.header().hide()
1439
1654
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
1440
1655
        self.setDragEnabled(True)
1441
1656
        self.setAcceptDrops(True)
 
1657
        # Set up headers if necessary.
 
1658
        column_count = len(editor.factory.column_headers)
 
1659
        if column_count > 0:
 
1660
            self.setHeaderHidden(False)
 
1661
            self.setColumnCount(column_count)
 
1662
            self.setHeaderLabels(editor.factory.column_headers)
 
1663
        else:
 
1664
            self.setHeaderHidden(True)
 
1665
 
 
1666
        self.setAlternatingRowColors(editor.factory.alternating_row_colors)
 
1667
        padding = editor.factory.vertical_padding
 
1668
        if padding > 0:
 
1669
            self.setStyleSheet("""
 
1670
            QTreeView::item {
 
1671
                padding-top: %spx;
 
1672
                padding-bottom: %spx;
 
1673
            }
 
1674
            """ % (padding, padding))
1442
1675
 
1443
1676
        if editor.factory.selection_mode == 'extended':
1444
1677
            self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
1445
1678
 
1446
 
        self.connect(self, QtCore.SIGNAL('itemExpanded(QTreeWidgetItem *)'),
1447
 
                editor._on_item_expanded)
1448
 
        self.connect(self, QtCore.SIGNAL('itemCollapsed(QTreeWidgetItem *)'),
1449
 
                editor._on_item_collapsed)
1450
 
        self.connect(self,
1451
 
                QtCore.SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
1452
 
                editor._on_item_clicked)
1453
 
        self.connect(self,
1454
 
                QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'),
1455
 
                editor._on_item_dclicked)
1456
 
        self.connect(self, QtCore.SIGNAL('itemSelectionChanged()'),
1457
 
                editor._on_tree_sel_changed)
1458
 
        self.connect(self, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
1459
 
                editor._on_context_menu)
1460
 
        self.connect(self,
1461
 
                QtCore.SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
1462
 
                editor._on_nid_changed)
 
1679
        self.itemExpanded.connect(editor._on_item_expanded)
 
1680
        self.itemCollapsed.connect(editor._on_item_collapsed)
 
1681
        self.itemClicked.connect(editor._on_item_clicked)
 
1682
        self.itemDoubleClicked.connect(editor._on_item_dclicked)
 
1683
        self.itemActivated.connect(editor._on_item_activated)
 
1684
        self.itemSelectionChanged.connect(editor._on_tree_sel_changed)
 
1685
        self.customContextMenuRequested.connect(editor._on_context_menu)
 
1686
        self.itemChanged.connect(editor._on_nid_changed)
1463
1687
 
1464
1688
        self._editor = editor
1465
1689
        self._dragging = None
1466
1690
 
 
1691
    def resizeEvent(self, event):
 
1692
        """ Overridden to emit sizeHintChanged() of items for word wrapping """
 
1693
        if self._editor.factory.word_wrap:
 
1694
            for i in range(self.topLevelItemCount()):
 
1695
                mi = self.indexFromItem(self.topLevelItem(i))
 
1696
                id = self.itemDelegate(mi)
 
1697
                id.sizeHintChanged.emit(mi)
 
1698
        super(self.__class__, self).resizeEvent(event)
 
1699
 
1467
1700
    def startDrag(self, actions):
1468
1701
        """ Reimplemented to start the drag of a tree widget item.
1469
1702
        """
1557
1790
        # See if the model will accept a drop.
1558
1791
        data = PyMimeData.coerce(e.mimeData()).instance()
1559
1792
 
1560
 
        if not node._is_droppable(object, data, insert):
 
1793
        if not self._editor._is_droppable(node, object, data, insert):
1561
1794
            return
1562
1795
 
1563
1796
        e.acceptProposedAction()
1583
1816
        _, node, object = editor._get_node_data(nid)
1584
1817
 
1585
1818
        if e.proposedAction() == QtCore.Qt.MoveAction:
1586
 
            if not node._is_droppable( object, data, False ):
 
1819
            if not self._editor._is_droppable(node, object, data, False ):
1587
1820
                return
1588
1821
 
1589
1822
            if dragging is not None:
1590
 
                data = node._drop_object( object, data, False )
 
1823
                data = self._editor._drop_object( node, object, data, False )
1591
1824
                if data is not None:
1592
1825
                    try:
1593
1826
                        editor._begin_undo()
1597
1830
                    finally:
1598
1831
                        editor._end_undo()
1599
1832
            else:
1600
 
                data = node._drop_object( object, data )
 
1833
                data = self._editor._drop_object( node, object, data, True )
1601
1834
                if data is not None:
1602
1835
                    editor._undoable_append( node, object, data, False )
1603
1836
        else:
1604
1837
            to_node, to_object, to_index = editor._node_index( nid )
1605
1838
            if to_node is not None:
1606
1839
                if dragging is not None:
1607
 
                    data = node._drop_object( to_object, data, False )
 
1840
                    data = self._editor._drop_object( node, to_object, data, False )
1608
1841
                    if data is not None:
1609
1842
                        from_node, from_object, from_index = \
1610
1843
                            editor._node_index( dragging )
1620
1853
                        finally:
1621
1854
                            editor._end_undo()
1622
1855
                else:
1623
 
                    data = to_node._drop_object( to_object, data )
 
1856
                    data = self._editor._drop_object( to_node, to_object, data, True )
1624
1857
                    if data is not None:
1625
1858
                        editor._undoable_insert( to_node, to_object, to_index,
1626
1859
                                               data, False )