187
205
""" Handles the **selection** event.
190
self._tree.setCurrentItem(self._object_info(selection)[2])
209
if (not isinstance(selection, basestring) and
210
isinstance(selection, collections.Iterable)):
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))
218
tree.selectionModel().select(item_selection,
219
QtGui.QItemSelectionModel.ClearAndSelect)
221
tree.setCurrentItem(self._object_info(selection)[2])
223
from traitsui.api import raise_to_debug
194
226
#---------------------------------------------------------------------------
195
227
# Handles the 'selected' trait being changed:
254
291
tree = self._tree
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)
300
object, node = self._node_for( self.old_value )
301
old_nid = self._get_object_nid( object, node.get_children_id(object) )
303
self._delete_node(old_nid)
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()
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)
269
315
self._map[ id( object ) ] = [ ( node.get_children_id(object), nid ) ]
270
316
self._add_listeners( node, object )
288
338
return self._tree
340
def _get_brush(self, color) :
341
if isinstance(color, SequenceTypes):
342
q_color = QtGui.QColor(*color)
344
q_color = QtGui.QColor(color)
345
return QtGui.QBrush(q_color)
348
def _set_column_labels(self, nid, column_labels):
349
""" Set the column labels.
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)
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
#---------------------------------------------------------------------------
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.
373
def __init__(self, *args, **kwargs):
374
self.size_map = collections.defaultdict(lambda:QtCore.QSize(1,21))
375
QtGui.QStyledItemDelegate.__init__(self, *args, **kwargs)
377
def sizeHint(self, option, index):
378
""" returns area taken by the text. """
379
return self.size_map[self.editor._tree.itemFromIndex(index)]
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)
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
394
rect = painter.drawText(option.rect.left() + iconwidth,
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)
405
#---------------------------------------------------------------------------
406
# Create a TreeWidgetItem as per word wrap policy and set icon,tooltip
407
#---------------------------------------------------------------------------
409
def _create_item(self, nid, node, object, index=None):
410
""" Create a new TreeWidgetItem as per word_wrap policy.
412
Index is the index of the new node in the parent:
413
None implies append the child to the end. """
415
cnid = QtGui.QTreeWidgetItem(nid)
417
cnid = QtGui.QTreeWidgetItem()
418
nid.insertChild(index, cnid)
419
if self.factory.word_wrap:
420
item = self.ItemDelegate()
422
self._tree.setItemDelegate(item)
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))
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))
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.
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 )
444
#---------------------------------------------------------------------------
445
# Inserts a new node to the specified node:
446
#---------------------------------------------------------------------------
448
def _insert_node ( self, nid, index, node, object ):
449
""" Inserts a new node before a specified index into the children of the
452
cnid = self._create_item(nid, node, object, index)
302
454
has_children = self._has_children(node, object)
303
455
self._set_node_data( cnid, ( False, node, object ) )
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]):
495
expanded, node, object = self._get_node_data(nid)
496
except AttributeError:
497
# The node has already been deleted.
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]):
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 ]
356
513
self._tree.takeTopLevelItem(self._tree.indexOfTopLevelItem(nid))
1074
1246
return can_rename
1248
def _is_droppable ( self, node, object, add_object, for_insert ):
1249
""" Returns whether a given object is droppable on the node.
1251
if for_insert and (not node.can_insert( object )):
1254
return node.can_add( object, add_object )
1256
def _drop_object ( self, node, object, dropped_object, make_copy = True ):
1257
""" Returns a droppable version of a specified object.
1259
new_object = node.drop_object( object, dropped_object )
1260
if (new_object is not dropped_object) or (not make_copy):
1263
return copy.deepcopy( new_object )
1076
1265
#----- pyface.action 'controller' interface implementation: --------------------
1078
1267
#---------------------------------------------------------------------------
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)
1389
1579
self._tree.blockSignals(blk)
1581
def _column_labels_updated(self, object, name, new):
1582
""" Handles the column labels of an object being changed.
1584
# Prevent the itemChanged() signal from being emitted.
1585
blk = self._tree.blockSignals(True)
1588
for name2, nid in self._map[ id( object ) ]:
1591
node = self._get_node_data( nid )[1]
1592
# Just do all of them at once. The number of columns should be
1594
self._set_column_labels(nid, node.get_column_labels(object))
1596
self._tree.blockSignals(blk)
1391
1598
#-- UI preference save/restore interface ---------------------------------------
1393
1600
#---------------------------------------------------------------------------
1436
1652
QtGui.QTreeWidget.__init__(self, parent)
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)
1664
self.setHeaderHidden(True)
1666
self.setAlternatingRowColors(editor.factory.alternating_row_colors)
1667
padding = editor.factory.vertical_padding
1669
self.setStyleSheet("""
1672
padding-bottom: %spx;
1674
""" % (padding, padding))
1443
1676
if editor.factory.selection_mode == 'extended':
1444
1677
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
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)
1451
QtCore.SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
1452
editor._on_item_clicked)
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)
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)
1464
1688
self._editor = editor
1465
1689
self._dragging = None
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)
1467
1700
def startDrag(self, actions):
1468
1701
""" Reimplemented to start the drag of a tree widget item.