~ubuntu-branches/ubuntu/raring/wxwidgets2.8/raring

« back to all changes in this revision

Viewing changes to wxPython/wx/lib/agw/customtreectrl.py

  • Committer: Package Import Robot
  • Author(s): Stéphane Graber
  • Date: 2012-01-07 13:59:25 UTC
  • mfrom: (1.1.9) (5.1.10 sid)
  • Revision ID: package-import@ubuntu.com-20120107135925-2601miy9ullcon9j
Tags: 2.8.12.1-6ubuntu1
* Resync from Debian, changes that were kept:
  - debian/rules: re-enable mediactrl. This allows libwx_gtk2u_media-2.8 to be
    built, as this is required by some applications (LP: #632984)
  - debian/control: Build-dep on libxt-dev for mediactrl.
  - Patches
    + fix-bashism-in-example
* Add conflict on python-wxgtk2.8 (<< 2.8.12.1-6ubuntu1~) to python-wxversion
  to guarantee upgrade ordering when moving from pycentral to dh_python2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
# Inspired By And Heavily Based On wxGenericTreeCtrl.
4
4
#
5
5
# Andrea Gavana, @ 17 May 2006
6
 
# Latest Revision: 14 Apr 2010, 12.00 GMT
 
6
# Latest Revision: 21 Jun 2011, 22.00 GMT
7
7
#
8
8
#
9
9
# TODO List
12
12
# No Limit In What Could Be Added To This Class. The First Things That Comes
13
13
# To My Mind Are:
14
14
#
15
 
# 1. Implement The Style TR_EXTENDED (I Have Never Used It, But It May Be Useful).
16
 
#
17
 
# 2. Add Support For 3-State CheckBoxes (Is That Really Useful?).
18
 
#
19
 
# 3. Try To Implement A More Flicker-Free Background Image In Cases Like
 
15
# 1. Try To Implement A More Flicker-Free Background Image In Cases Like
20
16
#    Centered Or Stretched Image (Now CustomTreeCtrl Supports Only Tiled
21
17
#    Background Images).
22
18
#
23
 
# 4. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl
 
19
# 2. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl
24
20
#    Suddenly Expands/Collapses The Nodes On Mouse Click While The Native Control
25
21
#    Has Some Kind Of "Smooth" Expanding/Collapsing, Like A Wave. I Don't Even
26
22
#    Know Where To Start To Do That.
27
23
#
28
 
# 5. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite
 
24
# 3. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite
29
25
#    Fast, But We Should See On Slower Machines.
30
26
#
31
27
#
58
54
 
59
55
* CheckBox-type items: checkboxes are easy to handle, just selected or unselected
60
56
  state with no particular issues in handling the item's children;
 
57
* Added support for 3-state value checkbox items;
61
58
* RadioButton-type items: since I elected to put radiobuttons in CustomTreeCtrl, I
62
59
  needed some way to handle them, that made sense. So, I used the following approach:
63
60
  
77
74
* Whatever non-toplevel widget can be attached next to an item;
78
75
* Possibility to horizontally align the widgets attached to tree items on the
79
76
  same tree level.
 
77
* Possibility to align the widgets attached to tree items to the rightmost edge of CustomTreeCtrl;
80
78
* Default selection style, gradient (horizontal/vertical) selection style and Windows
81
79
  Vista selection style;
82
80
* Customized drag and drop images built on the fly;
84
82
* Setting the CustomTreeCtrl check/radio item icons to a personalized imagelist;
85
83
* Changing the style of the lines that connect the items (in terms of `wx.Pen` styles);
86
84
* Using an image as a CustomTreeCtrl background (currently only in "tile" mode);
 
85
* Adding images to any item in the leftmost area of the CustomTreeCtrl client window.
87
86
 
88
87
And a lot more. Check the demo for an almost complete review of the functionalities.
89
88
 
101
100
- ``TR_AUTO_CHECK_PARENT``: automatically checks/unchecks the item parent;
102
101
- ``TR_AUTO_TOGGLE_CHILD``: automatically toggles the item children.
103
102
 
104
 
And a style you can use to force the horizontal alignment of all the widgets
 
103
And two styles you can use to force the horizontal alignment of all the widgets
105
104
attached to the tree items:
106
105
 
107
 
- ``TR_ALIGN_WINDOWS``: aligns horizontally the windows belongiing to the item on the
 
106
- ``TR_ALIGN_WINDOWS``: aligns horizontally the windows belonging to the item on the
108
107
  same tree level.
109
 
 
 
108
- ``TR_ALIGN_WINDOWS_RIGHT``: aligns to the rightmost position the windows belonging
 
109
  to the item on the same tree level.
110
110
    
111
111
All the methods available in `wx.TreeCtrl` are also available in CustomTreeCtrl.
112
112
 
168
168
``TR_AUTO_TOGGLE_CHILD``            0x8000 Only meaningful foe checkbox-type items: when a parent item is checked/unchecked its children are toggled accordingly.
169
169
``TR_AUTO_CHECK_PARENT``           0x10000 Only meaningful foe checkbox-type items: when a child item is checked/unchecked its parent item is checked/unchecked as well.
170
170
``TR_ALIGN_WINDOWS``               0x20000 Flag used to align windows (in items with windows) at the same horizontal position.
 
171
``TR_ALIGN_WINDOWS_RIGHT``         0x40000 Flag used to align windows (in items with windows) to the rightmost edge of `CustomTreeCtrl`.
171
172
============================== =========== ==================================================
172
173
 
173
174
 
211
212
 
212
213
CustomTreeCtrl is distributed under the wxPython license. 
213
214
 
214
 
Latest Revision: Andrea Gavana @ 14 Apr 2010, 12.00 GMT
 
215
Latest Revision: Andrea Gavana @ 21 Jun 2011, 22.00 GMT
215
216
 
216
 
Version 2.1
 
217
Version 2.4
217
218
 
218
219
"""
219
220
 
220
221
# Version Info
221
 
__version__ = "2.1"
 
222
__version__ = "2.4"
222
223
 
223
224
import wx
224
225
from wx.lib.expando import ExpandoTextCtrl
234
235
# been clicked/moved)
235
236
_DELAY = 500
236
237
 
 
238
# wxPython version string
 
239
_VERSION_STRING = wx.VERSION_STRING
 
240
 
237
241
# ----------------------------------------------------------------------------
238
242
# Constants
239
243
# ----------------------------------------------------------------------------
246
250
 
247
251
TreeItemIcon_Checked = 0             # check button,     checked
248
252
TreeItemIcon_NotChecked = 1          # check button, not checked
249
 
TreeItemIcon_Flagged = 2             # radio button,     selected
250
 
TreeItemIcon_NotFlagged = 3          # radio button, not selected
 
253
TreeItemIcon_Undetermined = 2        # check button, undetermined
 
254
TreeItemIcon_Flagged = 3             # radio button,     selected
 
255
TreeItemIcon_NotFlagged = 4          # radio button, not selected
251
256
 
252
257
# ----------------------------------------------------------------------------
253
258
# CustomTreeCtrl flags
298
303
""" its parent item is checked/unchecked as well. """
299
304
TR_ALIGN_WINDOWS = 0x20000                                     # to align windows horizontally for items at the same level
300
305
""" Flag used to align windows (in items with windows) at the same horizontal position. """
 
306
TR_ALIGN_WINDOWS_RIGHT = 0x40000                               # to align windows to the rightmost edge of CustomTreeCtrl
 
307
""" Flag used to align windows (in items with windows) to the rightmost edge of `CustomTreeCtrl`."""
301
308
 
302
309
TR_DEFAULT_STYLE = wx.TR_DEFAULT_STYLE                         # default style for the tree control
303
310
""" The set of flags that are closest to the defaults for the native control for a""" \
493
500
    are dealing with.
494
501
 
495
502
    :param `style`: the main L{CustomTreeCtrl} window style flag;
496
 
    :param `shiftDown`: ``True`` if the ``Shift`` has is pressed, ``False`` otherwise;
497
 
    :param `ctrlDown`: ``True`` if the ``Ctrl`` has is pressed, ``False`` otherwise;
 
503
    :param `shiftDown`: ``True`` if the ``Shift`` key is pressed, ``False`` otherwise;
 
504
    :param `ctrlDown`: ``True`` if the ``Ctrl`` key is pressed, ``False`` otherwise;
498
505
    """
499
506
 
500
507
    is_multiple = (style & TR_MULTIPLE) != 0
861
868
        return self._evtKey.GetKeyCode()
862
869
 
863
870
    
864
 
    def SetKeyEvent(self, evt):
 
871
    def SetKeyEvent(self, event):
865
872
        """
866
873
        Sets the keyboard data (for ``EVT_TREE_KEY_DOWN`` event only).
867
874
 
868
875
        :param `event`: a L{TreeEvent} event to be processed.
869
876
        """
870
877
 
871
 
        self._evtKey = evt
 
878
        self._evtKey = event
872
879
        
873
880
 
874
881
    def GetLabel(self):
997
1004
        
998
1005
    
999
1006
# -----------------------------------------------------------------------------
1000
 
# Auxiliary Classes: TreeRenameTimer
 
1007
# Auxiliary Classes: TreeEditTimer
1001
1008
# -----------------------------------------------------------------------------
1002
1009
 
1003
 
class TreeRenameTimer(wx.Timer):
 
1010
class TreeEditTimer(wx.Timer):
1004
1011
    """ Timer used for enabling in-place edit."""
1005
1012
 
1006
1013
    def __init__(self, owner):
1018
1025
    def Notify(self):
1019
1026
        """ The timer has expired. """
1020
1027
 
1021
 
        self._owner.OnRenameTimer()
 
1028
        self._owner.OnEditTimer()
1022
1029
 
1023
1030
 
1024
1031
# -----------------------------------------------------------------------------
1128
1135
            # needs to be notified that the user decided
1129
1136
            # not to change the tree item label, and that
1130
1137
            # the edit has been cancelled
1131
 
            self._owner.OnRenameCancelled(self._itemEdited)
 
1138
            self._owner.OnCancelEdit(self._itemEdited)
1132
1139
            return True
1133
1140
 
1134
 
        if not self._owner.OnRenameAccept(self._itemEdited, value):
 
1141
        if not self._owner.OnAcceptEdit(self._itemEdited, value):
1135
1142
            # vetoed by the user
1136
1143
            return False
1137
1144
 
1147
1154
        if not self._finished:        
1148
1155
            self._finished = True
1149
1156
            self._owner.SetFocusIgnoringChildren()
1150
 
            self._owner.ResetTextControl()
 
1157
            self._owner.ResetEditControl()
1151
1158
        
1152
1159
 
1153
1160
    def OnChar(self, event):
1160
1167
        keycode = event.GetKeyCode()
1161
1168
        shiftDown = event.ShiftDown()
1162
1169
 
1163
 
        if keycode == wx.WXK_RETURN:
 
1170
        if keycode in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
1164
1171
            if shiftDown:
1165
1172
                event.Skip()
1166
1173
            else:
1219
1226
            # focus problems:
1220
1227
            
1221
1228
            if not self.AcceptChanges():
1222
 
                self._owner.OnRenameCancelled(self._itemEdited)
 
1229
                self._owner.OnCancelEdit(self._itemEdited)
1223
1230
        
1224
1231
        # We must let the native text control handle focus, too, otherwise
1225
1232
        # it could have problems with the cursor (e.g., in wxGTK).
1229
1236
    def StopEditing(self):
1230
1237
        """Suddenly stops the editing."""
1231
1238
 
1232
 
        self._owner.OnRenameCancelled(self._itemEdited)
 
1239
        self._owner.OnCancelEdit(self._itemEdited)
1233
1240
        self.Finish()
1234
1241
        
1235
1242
    
1338
1345
        self._images[TreeItemIcon_Expanded] = _NO_IMAGE
1339
1346
        self._images[TreeItemIcon_SelectedExpanded] = _NO_IMAGE
1340
1347
 
1341
 
        self._checkedimages = [None, None, None, None]
 
1348
        self._checkedimages = [None, None, None, None, None]
 
1349
        self._leftimage = _NO_IMAGE
1342
1350
 
1343
1351
        self._x = 0             # (virtual) offset from top
1344
1352
        self._y = 0             # (virtual) offset from left
1353
1361
        self._isItalic = False      # render the label in italic font
1354
1362
        self._ownsAttr = False      # delete attribute when done
1355
1363
        self._type = ct_type        # item type: 0=normal, 1=check, 2=radio
1356
 
        self._checked = False       # only meaningful for check and radio
 
1364
        self._is3State = False      # true for 3-state checkbox items
 
1365
        self._checked = 0           # only meaningful for check and radio items
1357
1366
        self._enabled = True        # flag to enable/disable an item
1358
1367
        self._hypertext = False     # indicates if the item is hypertext
1359
1368
        self._visited = False       # visited state for an hypertext item
1362
1371
            # do not construct the array for normal items
1363
1372
            self._checkedimages[TreeItemIcon_Checked] = 0
1364
1373
            self._checkedimages[TreeItemIcon_NotChecked] = 1
1365
 
            self._checkedimages[TreeItemIcon_Flagged] = 2
1366
 
            self._checkedimages[TreeItemIcon_NotFlagged] = 3
 
1374
            self._checkedimages[TreeItemIcon_Undetermined] = 2
 
1375
            self._checkedimages[TreeItemIcon_Flagged] = 3
 
1376
            self._checkedimages[TreeItemIcon_NotFlagged] = 4
1367
1377
        
1368
1378
        if parent:
1369
1379
            if parent.GetType() == 2 and not parent.IsChecked():
1380
1390
        """
1381
1391
        Returns whether the item is ok or not.
1382
1392
 
1383
 
        :note: This method simply returns ``True``, it has been added for
 
1393
        :note: This method always returns ``True``, it has been added for
1384
1394
         backward compatibility with the wxWidgets C++ implementation.
1385
1395
        """
1386
1396
        
1430
1440
         ================================= ========================
1431
1441
         ``TreeItemIcon_Checked``          To get the checkbox checked item image
1432
1442
         ``TreeItemIcon_NotChecked``       To get the checkbox unchecked item image
 
1443
         ``TreeItemIcon_Undetermined``     To get the checkbox undetermined state item image
1433
1444
         ``TreeItemIcon_Flagged``          To get the radiobutton checked image
1434
1445
         ``TreeItemIcon_NotFlagged``       To get the radiobutton unchecked image
1435
1446
         ================================= ========================
1438
1449
        """
1439
1450
 
1440
1451
        return self._checkedimages[which]
1441
 
        
 
1452
 
 
1453
 
 
1454
    def GetLeftImage(self):
 
1455
        """
 
1456
        Returns the leftmost image associated to this item, i.e. the image on the
 
1457
        leftmost part of the client area of L{CustomTreeCtrl}.
 
1458
        """
 
1459
 
 
1460
        return self._leftimage
 
1461
    
1442
1462
 
1443
1463
    def GetData(self):
1444
1464
        """Returns the data associated to this item."""
1458
1478
 
1459
1479
        self._images[which] = image
1460
1480
 
 
1481
 
 
1482
    def SetLeftImage(self, image):
 
1483
        """
 
1484
        Sets the item leftmost image, i.e. the image associated to the item on the leftmost
 
1485
        part of the L{CustomTreeCtrl} client area.
 
1486
 
 
1487
        :param `image`: an index within the left image list specifying the image to
 
1488
         use for the item in the leftmost part of the client area.
 
1489
        """
 
1490
 
 
1491
        self._leftimage = image
 
1492
 
1461
1493
        
1462
1494
    def SetData(self, data):
1463
1495
        """
1500
1532
        
1501
1533
 
1502
1534
    def GetX(self):
1503
 
        """Returns the x position on an item. """
 
1535
        """Returns the `x` position on an item, in logical coordinates. """
1504
1536
 
1505
1537
        return self._x 
1506
1538
 
1507
1539
 
1508
1540
    def GetY(self):
1509
 
        """Returns the y position on an item. """
 
1541
        """Returns the `y` position on an item, in logical coordinates. """
1510
1542
 
1511
1543
        return self._y 
1512
1544
 
1513
1545
 
1514
1546
    def SetX(self, x):
1515
1547
        """
1516
 
        Sets the x position on an item.
 
1548
        Sets the `x` position on an item, in logical coordinates.
1517
1549
 
1518
1550
        :param `x`: an integer specifying the x position of the item.
1519
1551
        """
1523
1555
 
1524
1556
    def SetY(self, y):
1525
1557
        """
1526
 
        Sets the y position on an item.
 
1558
        Sets the `y` position on an item, in logical coordinates.
1527
1559
 
1528
1560
        :param `y`: an integer specifying the y position of the item.
1529
1561
        """
1789
1821
        return not self._isCollapsed 
1790
1822
 
1791
1823
 
 
1824
    def GetValue(self):
 
1825
        """
 
1826
        Returns whether the item is checked or not.
 
1827
 
 
1828
        :note: This is meaningful only for checkbox-like and radiobutton-like items.
 
1829
        """
 
1830
 
 
1831
        if self.Is3State():
 
1832
            return self.Get3StateValue()
 
1833
        
 
1834
        return self._checked        
 
1835
 
 
1836
 
 
1837
    def Get3StateValue(self):
 
1838
        """
 
1839
        Gets the state of a 3-state checkbox item.
 
1840
 
 
1841
        :return: ``wx.CHK_UNCHECKED`` when the checkbox is unchecked, ``wx.CHK_CHECKED``
 
1842
         when it is checked and ``wx.CHK_UNDETERMINED`` when it's in the undetermined
 
1843
         state. 
 
1844
 
 
1845
        :note: This method raises an exception when the function is used with a 2-state
 
1846
         checkbox item.
 
1847
 
 
1848
        :note: This method is meaningful only for checkbox-like items.
 
1849
        """
 
1850
 
 
1851
        if not self.Is3State():
 
1852
            raise Exception("Get3StateValue can only be used with 3-state checkbox items.")
 
1853
 
 
1854
        return self._checked        
 
1855
 
 
1856
 
 
1857
    def Is3State(self):
 
1858
        """
 
1859
        Returns whether or not the checkbox item is a 3-state checkbox.
 
1860
 
 
1861
        :return: ``True`` if this checkbox is a 3-state checkbox, ``False`` if it's a
 
1862
         2-state checkbox item.
 
1863
 
 
1864
        :note: This method is meaningful only for checkbox-like items.
 
1865
        """
 
1866
 
 
1867
        return self._is3State
 
1868
    
 
1869
 
 
1870
    def Set3StateValue(self, state):
 
1871
        """
 
1872
        Sets the checkbox item to the given `state`.
 
1873
 
 
1874
        :param `state`: can be one of: ``wx.CHK_UNCHECKED`` (check is off), ``wx.CHK_CHECKED``
 
1875
         (check is on) or ``wx.CHK_UNDETERMINED`` (check is mixed).
 
1876
 
 
1877
        :note: This method raises an exception when the checkbox item is a 2-state checkbox
 
1878
         and setting the state to ``wx.CHK_UNDETERMINED``.
 
1879
 
 
1880
        :note: This method is meaningful only for checkbox-like items.
 
1881
        """
 
1882
 
 
1883
        if not self._is3State and state == wx.CHK_UNDETERMINED:
 
1884
            raise Exception("Set3StateValue can only be used with 3-state checkbox items.")
 
1885
 
 
1886
        self._checked = state
 
1887
 
 
1888
 
 
1889
    def Set3State(self, allow):
 
1890
        """
 
1891
        Sets whether the item has a 3-state value checkbox assigned to it or not.
 
1892
 
 
1893
        :param `allow`: ``True`` to set an item as a 3-state checkbox, ``False`` to set it
 
1894
         to a 2-state checkbox.
 
1895
 
 
1896
        :return: ``True`` if the change was successful, ``False`` otherwise.
 
1897
 
 
1898
        :note: This method is meaningful only for checkbox-like items.
 
1899
        """
 
1900
 
 
1901
        if self._type != 1:
 
1902
            return False
 
1903
 
 
1904
        self._is3State = allow
 
1905
        return True
 
1906
            
 
1907
 
1792
1908
    def IsChecked(self):
1793
1909
        """
 
1910
        This is just a maybe more readable synonym for L{GetValue}.
1794
1911
        Returns whether the item is checked or not.
1795
1912
 
1796
1913
        :note: This is meaningful only for checkbox-like and radiobutton-like items.
1797
1914
        """
1798
1915
 
1799
 
        return self._checked
 
1916
        return self.GetValue()
1800
1917
 
1801
1918
 
1802
1919
    def Check(self, checked=True):
2104
2221
        if self._type == 0:
2105
2222
            return None
2106
2223
 
2107
 
        if self.IsChecked():
 
2224
        checked = self.IsChecked()
 
2225
        
 
2226
        if checked > 0:
2108
2227
            if self._type == 1:     # Checkbox
2109
 
                return self._checkedimages[TreeItemIcon_Checked]
 
2228
                if checked == wx.CHK_CHECKED:
 
2229
                    return self._checkedimages[TreeItemIcon_Checked]
 
2230
                else:
 
2231
                    return self._checkedimages[TreeItemIcon_Undetermined]                    
2110
2232
            else:                   # Radiobutton
2111
2233
                return self._checkedimages[TreeItemIcon_Flagged]
2112
2234
        else:
2165
2287
         ``TR_AUTO_TOGGLE_CHILD``            0x8000 Only meaningful foe checkbox-type items: when a parent item is checked/unchecked its children are toggled accordingly.
2166
2288
         ``TR_AUTO_CHECK_PARENT``           0x10000 Only meaningful foe checkbox-type items: when a child item is checked/unchecked its parent item is checked/unchecked as well.
2167
2289
         ``TR_ALIGN_WINDOWS``               0x20000 Flag used to align windows (in items with windows) at the same horizontal position.
 
2290
         ``TR_ALIGN_WINDOWS_RIGHT``         0x40000 Flag used to align windows (in items with windows) to the rightmost edge of `CustomTreeCtrl`.
2168
2291
         ============================== =========== ==================================================
2169
2292
 
2170
2293
        :param `validator`: window validator;
2194
2317
        self._hilightUnfocusedBrush2 = wx.Brush(backcolour)
2195
2318
 
2196
2319
        # image list for icons
2197
 
        self._imageListNormal = self._imageListButtons = self._imageListState = self._imageListCheck = None
2198
 
        self._ownsImageListNormal = self._ownsImageListButtons = self._ownsImageListState = False
 
2320
        self._imageListNormal = self._imageListButtons = self._imageListState = self._imageListCheck = self._imageListLeft = None
 
2321
        self._ownsImageListNormal = self._ownsImageListButtons = self._ownsImageListState = self._ownsImageListLeft = False
2199
2322
 
2200
2323
        # Drag and drop initial settings
2201
2324
        self._dragCount = 0
2205
2328
        self._dragImage = None
2206
2329
        self._underMouse = None
2207
2330
 
2208
 
        # TextCtrl initial settings for editable items        
2209
 
        self._textCtrl = None
2210
 
        self._renameTimer = None
 
2331
        # EditCtrl initial settings for editable items        
 
2332
        self._editCtrl = None
 
2333
        self._editTimer = None
2211
2334
 
2212
2335
        # This one allows us to handle Freeze() and Thaw() calls        
2213
2336
        self._freezeCount = 0
2288
2411
 
2289
2412
        # A constant to use my translation of RendererNative.DrawTreeItemButton
2290
2413
        # if the wxPython version is less than 2.6.2.1.
2291
 
        if wx.VERSION_STRING < "2.6.2.1":
 
2414
        if _VERSION_STRING < "2.6.2.1":
2292
2415
            self._drawingfunction = DrawTreeItemButton
2293
2416
        else:
2294
2417
            self._drawingfunction = wx.RendererNative.Get().DrawTreeItemButton
2360
2483
 
2361
2484
        # Here there may be something I miss... do I have to destroy
2362
2485
        # something else?
2363
 
        if self._renameTimer and self._renameTimer.IsRunning():
2364
 
            self._renameTimer.Stop()
2365
 
            del self._renameTimer
2366
 
            self._renameTimer = None
 
2486
        if self._editTimer and self._editTimer.IsRunning():
 
2487
            self._editTimer.Stop()
 
2488
            del self._editTimer
 
2489
            self._editTimer = None
2367
2490
 
2368
2491
        if self._findTimer and self._findTimer.IsRunning():
2369
2492
            self._findTimer.Stop()
2392
2515
        
2393
2516
        render = wx.RendererNative.Get()
2394
2517
 
2395
 
        if checked:
 
2518
        if checked == wx.CHK_CHECKED:
2396
2519
            flag = wx.CONTROL_CHECKED
 
2520
        elif checked == wx.CHK_UNDETERMINED:
 
2521
            flag = wx.CONTROL_UNDETERMINED
2397
2522
        else:
2398
2523
            flag = 0
2399
2524
 
2403
2528
        if checkbox:
2404
2529
            render.DrawCheckBox(self, mdc, (0, 0, x, y), flag)
2405
2530
        else:
2406
 
            render.DrawRadioButton(self, mdc, (0, 0, x, y), flag)
 
2531
            if _VERSION_STRING < "2.9":
 
2532
                render.DrawRadioButton(self, mdc, (0, 0, x, y), flag)
 
2533
            else:
 
2534
                render.DrawRadioBitmap(self, mdc, (0, 0, x, y), flag)
2407
2535
 
2408
2536
        mdc.SelectObject(wx.NullBitmap)
2409
2537
        bmp.SetMaskColour(mask)
2562
2690
        return item.IsChecked()
2563
2691
 
2564
2692
 
 
2693
    def GetItem3StateValue(self, item):
 
2694
        """
 
2695
        Gets the state of a 3-state checkbox item.
 
2696
 
 
2697
        :param `item`: an instance of L{GenericTreeItem}.
 
2698
 
 
2699
        :return: ``wx.CHK_UNCHECKED`` when the checkbox is unchecked, ``wx.CHK_CHECKED``
 
2700
         when it is checked and ``wx.CHK_UNDETERMINED`` when it's in the undetermined
 
2701
         state. 
 
2702
 
 
2703
        :note: This method raises an exception when the function is used with a 2-state
 
2704
         checkbox item.
 
2705
 
 
2706
        :note: This method is meaningful only for checkbox-like items.
 
2707
        """
 
2708
 
 
2709
        return item.Get3StateValue()
 
2710
 
 
2711
 
 
2712
    def IsItem3State(self, item):
 
2713
        """
 
2714
        Returns whether or not the checkbox item is a 3-state checkbox.
 
2715
 
 
2716
        :param `item`: an instance of L{GenericTreeItem}.
 
2717
 
 
2718
        :return: ``True`` if this checkbox is a 3-state checkbox, ``False`` if it's a
 
2719
         2-state checkbox item.
 
2720
 
 
2721
        :note: This method is meaningful only for checkbox-like items.
 
2722
        """
 
2723
 
 
2724
        return item.Is3State()
 
2725
    
 
2726
 
 
2727
    def SetItem3StateValue(self, item, state):
 
2728
        """
 
2729
        Sets the checkbox item to the given `state`.
 
2730
 
 
2731
        :param `item`: an instance of L{GenericTreeItem};
 
2732
        :param `state`: can be one of: ``wx.CHK_UNCHECKED`` (check is off), ``wx.CHK_CHECKED``
 
2733
         (check is on) or ``wx.CHK_UNDETERMINED`` (check is mixed).
 
2734
 
 
2735
        :note: This method raises an exception when the checkbox item is a 2-state checkbox
 
2736
         and setting the state to ``wx.CHK_UNDETERMINED``.
 
2737
 
 
2738
        :note: This method is meaningful only for checkbox-like items.
 
2739
        """
 
2740
 
 
2741
        item.Set3StateValue(state)
 
2742
 
 
2743
 
 
2744
    def SetItem3State(self, item, allow):
 
2745
        """
 
2746
        Sets whether the item has a 3-state value checkbox assigned to it or not.
 
2747
 
 
2748
        :param `item`: an instance of L{GenericTreeItem};
 
2749
        :param `allow`: ``True`` to set an item as a 3-state checkbox, ``False`` to set it
 
2750
         to a 2-state checkbox.
 
2751
 
 
2752
        :return: ``True`` if the change was successful, ``False`` otherwise.
 
2753
 
 
2754
        :note: This method is meaningful only for checkbox-like items.
 
2755
        """
 
2756
 
 
2757
        return item.Set3State(allow)
 
2758
    
 
2759
 
2565
2760
    def CheckItem2(self, item, checked=True, torefresh=False):
2566
2761
        """
2567
2762
        Used internally to avoid ``EVT_TREE_ITEM_CHECKED`` events.
2614
2809
        events ``EVT_TREE_ITEM_CHECKING`` and ``EVT_TREE_ITEM_CHECKED``.
2615
2810
 
2616
2811
        :param `item`: an instance of L{GenericTreeItem};
2617
 
        :param `checked`: ``True`` to check an item, ``False`` to uncheck it.
 
2812
        :param `checked`: for a radiobutton-type item, ``True`` to check it, ``False``
 
2813
         to uncheck it. For a checkbox-type item, it can be one of ``wx.CHK_UNCHECKED``
 
2814
         when the checkbox is unchecked, ``wx.CHK_CHECKED`` when it is checked and
 
2815
         ``wx.CHK_UNDETERMINED`` when it's in the undetermined state.
2618
2816
        """
2619
2817
 
2620
2818
        # Should we raise an error here?!?        
2639
2837
        if self.GetEventHandler().ProcessEvent(e):
2640
2838
            # Blocked by user
2641
2839
            return 
2642
 
        
2643
 
        item.Check(checked)
 
2840
 
 
2841
        if item.Is3State():
 
2842
            item.Set3StateValue(checked)
 
2843
        else:
 
2844
            item.Check(checked)
 
2845
            
2644
2846
        dc = wx.ClientDC(self)
2645
2847
        self.RefreshLine(item)
2646
2848
 
2867
3069
        
2868
3070
        :see: The L{__init__} method for the `agwStyle` parameter description.
2869
3071
        """
2870
 
 
 
3072
        
2871
3073
        # Do not try to expand the root node if it hasn't been created yet
2872
3074
        if self._anchor and not self.HasAGWFlag(TR_HIDE_ROOT) and agwStyle & TR_HIDE_ROOT:
2873
3075
        
2890
3092
 
2891
3093
 
2892
3094
    def GetAGWWindowStyleFlag(self):
2893
 
        """Returns the L{CustomTreeCtrl} style."""
 
3095
        """
 
3096
        Returns the L{CustomTreeCtrl} style.
 
3097
 
 
3098
        :see: The L{__init__} method for a list of possible style flags.
 
3099
        """
2894
3100
 
2895
3101
        return self._agwStyle
2896
3102
    
2935
3141
        return item.GetImage(which)
2936
3142
 
2937
3143
 
 
3144
    def GetItemLeftImage(self, item):
 
3145
        """
 
3146
        Returns the item leftmost image, i.e. the image associated to the item on the leftmost
 
3147
        part of the L{CustomTreeCtrl} client area.
 
3148
 
 
3149
        :param `item`: an instance of L{GenericTreeItem}.
 
3150
        """
 
3151
 
 
3152
        return item.GetLeftImage()
 
3153
 
 
3154
 
2938
3155
    def GetPyData(self, item):
2939
3156
        """
2940
3157
        Returns the data associated to an item.
3024
3241
        self.RefreshLine(item)
3025
3242
 
3026
3243
 
 
3244
    def SetItemLeftImage(self, item, image):
 
3245
        """
 
3246
        Sets the item leftmost image, i.e. the image associated to the item on the leftmost
 
3247
        part of the L{CustomTreeCtrl} client area.
 
3248
 
 
3249
        :param `item`: an instance of L{GenericTreeItem};
 
3250
        :param `image`: an index within the left image list specifying the image to
 
3251
         use for the item in the leftmost part of the client area.
 
3252
        """
 
3253
 
 
3254
        item.SetLeftImage(image)
 
3255
 
 
3256
        dc = wx.ClientDC(self)
 
3257
        self.CalculateSize(item, dc)
 
3258
        self.RefreshLine(item)
 
3259
 
 
3260
 
3027
3261
    def SetPyData(self, item, data):
3028
3262
        """
3029
3263
        Sets the data associated to an item.
3882
4116
        return lastGoodItem
3883
4117
 
3884
4118
 
3885
 
    def ResetTextControl(self):
3886
 
        """ Called by L{TreeTextCtrl} when it marks itself for deletion. """
 
4119
    def ResetEditControl(self):
 
4120
        """ Called by L{EditCtrl} when it marks itself for deletion. """
3887
4121
 
3888
 
        self._textCtrl.Destroy()
3889
 
        self._textCtrl = None
 
4122
        if self._editCtrl is not None:
 
4123
            self._editCtrl.Destroy()
 
4124
            self._editCtrl = None
3890
4125
 
3891
4126
        self.CalculatePositions()
3892
4127
        self.Refresh()
4102
4337
        return self.DoInsertItem(parentId, index+1, text, ct_type, wnd, image, selImage, data)
4103
4338
 
4104
4339
 
4105
 
    def InsertItemByIndex(self, parentId, before, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
 
4340
    def InsertItemByIndex(self, parentId, idPrevious, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
4106
4341
        """
4107
4342
        Inserts an item after the given previous.
4108
4343
 
4109
4344
        :param `parentId`: an instance of L{GenericTreeItem} representing the
4110
4345
         item's parent;
4111
 
        :param `before`: the index at which we should insert the new item;
 
4346
        :param `idPrevious`: the index at which we should insert the new item;
4112
4347
        :param `text`: the item text label;
4113
4348
        :param `ct_type`: the item type (see L{SetItemType} for a list of valid
4114
4349
         item types);
4127
4362
            # should we give a warning here?
4128
4363
            return self.AddRoot(text, ct_type, wnd, image, selImage, data)
4129
4364
        
4130
 
        return self.DoInsertItem(parentId, before, text, ct_type, wnd, image, selImage, data)
 
4365
        return self.DoInsertItem(parentId, idPrevious, text, ct_type, wnd, image, selImage, data)
4131
4366
 
4132
4367
 
4133
4368
    def InsertItem(self, parentId, input, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
4213
4448
        :param `item`: an instance of L{GenericTreeItem}.
4214
4449
        """
4215
4450
 
4216
 
        if self._textCtrl != None and item != self._textCtrl.item() and self.IsDescendantOf(item, self._textCtrl.item()):
4217
 
            self._textCtrl.StopEditing()
 
4451
        if self._editCtrl != None and item != self._editCtrl.item() and self.IsDescendantOf(item, self._editCtrl.item()):
 
4452
            self._editCtrl.StopEditing()
4218
4453
        
4219
4454
        if item != self._key_current and self.IsDescendantOf(item, self._key_current):
4220
4455
            self._key_current = None
4250
4485
 
4251
4486
        self._dirty = True     # do this first so stuff below doesn't cause flicker
4252
4487
 
4253
 
        if self._textCtrl != None and self.IsDescendantOf(item, self._textCtrl.item()):
 
4488
        if self._editCtrl != None and self.IsDescendantOf(item, self._editCtrl.item()):
4254
4489
            # can't delete the item being edited, cancel editing it first
4255
 
            self._textCtrl.StopEditing()
 
4490
            self._editCtrl.StopEditing()
4256
4491
        
4257
4492
        parent = item.GetParent()
4258
4493
 
4502
4737
        Selects all the children of the given item.
4503
4738
 
4504
4739
        :param `item`: an instance of L{GenericTreeItem}.
 
4740
 
 
4741
        :note: This method can be used only if L{CustomTreeCtrl} has the ``TR_MULTIPLE`` or ``TR_EXTENDED``
 
4742
         style set.        
4505
4743
        """
4506
4744
 
4507
4745
        if not self.HasAGWFlag(TR_MULTIPLE) and not self.HasAGWFlag(TR_EXTENDED):
4529
4767
 
4530
4768
 
4531
4769
    def SelectAll(self):
4532
 
        """ Selects all the item in the tree. """
 
4770
        """
 
4771
        Selects all the item in the tree.
 
4772
 
 
4773
        :note: This method can be used only if L{CustomTreeCtrl} has the ``TR_MULTIPLE`` or ``TR_EXTENDED``
 
4774
         style set.
 
4775
        """
4533
4776
 
4534
4777
        if not self.HasAGWFlag(TR_MULTIPLE) and not self.HasAGWFlag(TR_EXTENDED):
4535
4778
            raise Exception("SelectAll can be used only with multiple selection enabled.")
4592
4835
        :param `item1`: an instance of L{GenericTreeItem}, representing the first
4593
4836
         item in the range to select;
4594
4837
        :param `item2`: an instance of L{GenericTreeItem}, representing the last
4595
 
         item in the range to select.        
 
4838
         item in the range to select.
 
4839
 
 
4840
        :note: This method can be used only if L{CustomTreeCtrl} has the ``TR_MULTIPLE`` or ``TR_EXTENDED``
 
4841
         style set.         
4596
4842
        """
 
4843
 
 
4844
        if not self.HasAGWFlag(TR_MULTIPLE) and not self.HasAGWFlag(TR_EXTENDED):
 
4845
            raise Exception("SelectItemRange can be used only with multiple selection enabled.")
4597
4846
        
4598
4847
        self._select_me = None
4599
4848
 
4739
4988
        """
4740
4989
        Returns a list of selected items.
4741
4990
 
4742
 
        :note: This method can be used only if L{CustomTreeCtrl} has the ``TR_MULTIPLE``
 
4991
        :note: This method can be used only if L{CustomTreeCtrl} has the ``TR_MULTIPLE`` or ``TR_EXTENDED``
4743
4992
         style set.
4744
4993
        """
4745
4994
 
4903
5152
        return self._imageListCheck        
4904
5153
 
4905
5154
 
 
5155
    def GetLeftImageList(self):
 
5156
        """
 
5157
        Returns the image list for L{CustomTreeCtrl} filled with images to be used on
 
5158
        the leftmost part of the client area. Any item can have a leftmost image associated
 
5159
        with it.
 
5160
        """
 
5161
 
 
5162
        return self._imageListLeft
 
5163
 
 
5164
 
4906
5165
    def CalculateLineHeight(self):
4907
5166
        """ Calculates the height of a line. """
4908
5167
 
4950
5209
 
4951
5210
                if height > self._lineHeight:
4952
5211
                    self._lineHeight = height
 
5212
 
 
5213
        if self._imageListLeft:
 
5214
        
 
5215
            # Calculate a self._lineHeight value from the leftmost image sizes.
 
5216
            # May be toggle off. Then CustomTreeCtrl will spread when
 
5217
            # necessary (which might look ugly).
 
5218
            n = self._imageListLeft.GetImageCount()
 
5219
 
 
5220
            for i in xrange(n):
 
5221
            
 
5222
                width, height = self._imageListLeft.GetSize(i)
 
5223
 
 
5224
                if height > self._lineHeight:
 
5225
                    self._lineHeight = height
4953
5226
        
4954
5227
        if self._lineHeight < 30:
4955
5228
            self._lineHeight += 2                 # at least 2 pixels
4984
5257
                bmp = imageList.GetBitmap(ii)
4985
5258
                newbmp = MakeDisabledBitmap(bmp)
4986
5259
                self._grayedImageList.Add(newbmp)
 
5260
 
 
5261
 
 
5262
    def SetLeftImageList(self, imageList):
 
5263
        """
 
5264
        Sets the image list for L{CustomTreeCtrl} filled with images to be used on
 
5265
        the leftmost part of the client area. Any item can have a leftmost image associated
 
5266
        with it.
 
5267
 
 
5268
        :param `imageList`: an instance of `wx.ImageList`.
 
5269
        """
 
5270
 
 
5271
        self._imageListLeft = imageList
 
5272
        self._ownsImageListLeft = False
 
5273
        self._dirty = True
 
5274
        
 
5275
        # Don't do any drawing if we're setting the list to NULL,
 
5276
        # since we may be in the process of deleting the tree control.
 
5277
        if imageList:
 
5278
            self.CalculateLineHeight()
 
5279
 
 
5280
            # We gray out the image list to use the grayed icons with disabled items
 
5281
            sz = imageList.GetSize(0)
 
5282
            self._grayedImageListLeft = wx.ImageList(sz[0], sz[1], True, 0)
 
5283
 
 
5284
            for ii in xrange(imageList.GetImageCount()):
 
5285
                bmp = imageList.GetBitmap(ii)
 
5286
                newbmp = MakeDisabledBitmap(bmp)
 
5287
                self._grayedImageListLeft.Add(newbmp)
4987
5288
        
4988
5289
 
4989
5290
    def SetStateImageList(self, imageList):
5053
5354
                                                         enabled=False,
5054
5355
                                                         x=sizex, y=sizey))
5055
5356
 
 
5357
            self._imageListCheck.Add(self.GetControlBmp(checkbox=True,
 
5358
                                                        checked=2,
 
5359
                                                        enabled=True,
 
5360
                                                        x=sizex, y=sizey))
 
5361
            self._grayedCheckList.Add(self.GetControlBmp(checkbox=True,
 
5362
                                                         checked=2,
 
5363
                                                         enabled=False,
 
5364
                                                         x=sizex, y=sizey))
5056
5365
 
5057
5366
            # Get the Radio Buttons
5058
5367
            self._imageListCheck.Add(self.GetControlBmp(checkbox=False,
5123
5432
        self._ownsImageListButtons = True
5124
5433
 
5125
5434
 
 
5435
    def AssignLeftImageList(self, imageList):
 
5436
        """
 
5437
        Assigns the image list for L{CustomTreeCtrl} filled with images to be used on
 
5438
        the leftmost part of the client area. Any item can have a leftmost image associated
 
5439
        with it.
 
5440
 
 
5441
        :param `imageList`: an instance of `wx.ImageList`.
 
5442
        """
 
5443
 
 
5444
        self.SetLeftImageList(imageList)
 
5445
        self._ownsImageListLeft = True
 
5446
 
 
5447
 
5126
5448
# -----------------------------------------------------------------------------
5127
5449
# helpers
5128
5450
# -----------------------------------------------------------------------------
5347
5669
 
5348
5670
        image = item.GetCurrentImage()
5349
5671
        checkimage = item.GetCurrentCheckedImage()
 
5672
        leftimage = _NO_IMAGE
 
5673
        
 
5674
        if self._imageListLeft:
 
5675
            leftimage = item.GetLeftImage()
 
5676
            
5350
5677
        image_w, image_h = 0, 0
5351
5678
 
5352
5679
        if image != _NO_IMAGE:
5366
5693
        else:
5367
5694
            wcheck, hcheck = 0, 0
5368
5695
 
 
5696
        if leftimage != _NO_IMAGE:
 
5697
            l_image_w, l_image_h = self._imageListLeft.GetSize(leftimage)
 
5698
            
5369
5699
        total_h = self.GetLineHeight(item)
5370
5700
        drawItemBackground = False
5371
5701
            
5501
5831
                         item.GetY() + ((total_h > hcheck) and [(total_h-hcheck)/2] or [0])[0],
5502
5832
                         wx.IMAGELIST_DRAW_TRANSPARENT)
5503
5833
 
 
5834
        if leftimage != _NO_IMAGE:
 
5835
            if item.IsEnabled():
 
5836
                imglist = self._imageListLeft
 
5837
            else:
 
5838
                imglist = self._grayedImageListLeft
 
5839
 
 
5840
            imglist.Draw(leftimage, dc,
 
5841
                         4,
 
5842
                         item.GetY() + ((total_h > l_image_h) and [(total_h-l_image_h)/2] or [0])[0],
 
5843
                         wx.IMAGELIST_DRAW_TRANSPARENT)
 
5844
 
5504
5845
        dc.SetBackgroundMode(wx.TRANSPARENT)
5505
5846
        extraH = ((total_h > text_h) and [(total_h - text_h)/2] or [0])[0]
5506
5847
 
5524
5865
            if item.GetHeight() > item.GetWindowSize()[1]:
5525
5866
                ya += (item.GetHeight() - item.GetWindowSize()[1])/2
5526
5867
 
5527
 
            if align and level in self.absoluteWindows:
5528
 
                wndx = self.absoluteWindows[level] + item.GetX() + 2
 
5868
            if align == 1:
 
5869
                # Horizontal alignment of windows
 
5870
                if level in self.absoluteWindows:
 
5871
                    wndx = self.absoluteWindows[level] + item.GetX() + 2
 
5872
                    
 
5873
            elif align == 2:
 
5874
                # Rightmost alignment of windows
 
5875
                wndx = self.GetClientSize().x - item.GetWindowSize().x - 2
5529
5876
                
5530
5877
            if not wnd.IsShown():
5531
5878
                wnd.Show()
5545
5892
        :param `dc`: an instance of `wx.DC`;
5546
5893
        :param `level`: the item level in the tree hierarchy;
5547
5894
        :param `y`: the current vertical position in the `wx.PyScrolledWindow`;
5548
 
        :param `align`: ``True`` if we want to align windows (in items with windows)
5549
 
         at the same horizontal position.
 
5895
        :param `align`: an integer specifying the alignment type:
 
5896
 
 
5897
         =============== =========================================
 
5898
         `align` Value   Description
 
5899
         =============== =========================================
 
5900
                0        No horizontal alignment of windows (in items with windows).
 
5901
                1        Windows (in items with windows) are aligned at the same horizontal position.
 
5902
                2        Windows (in items with windows) are aligned at the rightmost edge of L{CustomTreeCtrl}.
 
5903
         =============== =========================================
 
5904
 
5550
5905
        """
5551
5906
 
5552
5907
        x = level*self._indent
 
5908
 
 
5909
        left_image_list = 0
 
5910
        if self._imageListLeft:
 
5911
            left_image_list += self._imageListLeft.GetBitmap(0).GetWidth()
 
5912
            
 
5913
        x += left_image_list
5553
5914
        
5554
5915
        if not self.HasAGWFlag(TR_HIDE_ROOT):
5555
5916
        
5641
6002
                # draw the horizontal line here
5642
6003
                dc.SetPen(self._dottedPen)
5643
6004
                x_start = x
5644
 
                if x > self._indent:
 
6005
                if x > self._indent+left_image_list:
5645
6006
                    x_start -= self._indent
5646
6007
                elif self.HasAGWFlag(TR_LINES_AT_ROOT):
5647
6008
                    x_start = 3
5772
6133
        dc.SetFont(self._normalFont)
5773
6134
        dc.SetPen(self._dottedPen)
5774
6135
 
5775
 
        align = self.HasAGWFlag(TR_ALIGN_WINDOWS)            
 
6136
        align = 0
 
6137
        
 
6138
        if self.HasAGWFlag(TR_ALIGN_WINDOWS):
 
6139
            align = 1
 
6140
        elif self.HasAGWFlag(TR_ALIGN_WINDOWS_RIGHT):
 
6141
            align = 2
 
6142
            
5776
6143
        y = 2
5777
6144
        self.PaintLevel(self._anchor, dc, 0, y, align)
5778
6145
 
5784
6151
        :param `event`: a `wx.SizeEvent` event to be processed.
5785
6152
        """
5786
6153
 
5787
 
        self.RefreshSelected()
 
6154
        if self.HasAGWFlag(TR_ALIGN_WINDOWS_RIGHT) and self._itemWithWindow:
 
6155
            self.RefreshItemWithWindows()
 
6156
        else:
 
6157
            self.RefreshSelected()
 
6158
            
5788
6159
        event.Skip()
5789
6160
        
5790
6161
 
5881
6252
 
5882
6253
        if self._current is None or self._key_current is None:
5883
6254
        
5884
 
            event.Skip()
5885
 
            return
 
6255
            self._current = self._key_current = self.GetFirstVisibleItem()
5886
6256
        
5887
6257
        # how should the selection work for this event?
5888
6258
        is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetAGWWindowStyleFlag(),
5925
6295
            event.SetEventObject(self)
5926
6296
            self.GetEventHandler().ProcessEvent(event)
5927
6297
                
5928
 
        elif keyCode in [wx.WXK_RETURN, wx.WXK_SPACE]:
 
6298
        elif keyCode in [wx.WXK_RETURN, wx.WXK_SPACE, wx.WXK_NUMPAD_ENTER]:
5929
6299
 
5930
6300
            if not self.IsItemEnabled(self._current):
5931
6301
                event.Skip()
5938
6308
                self.GetEventHandler().ProcessEvent(event)
5939
6309
 
5940
6310
                if keyCode == wx.WXK_SPACE and self.GetItemType(self._current) > 0:
5941
 
                    checked = not self.IsItemChecked(self._current)
 
6311
                    if self.IsItem3State(self._current):
 
6312
                        checked = self.GetItem3StateValue(self._current)
 
6313
                        checked = (checked+1)%3
 
6314
                    else:
 
6315
                        checked = not self.IsItemChecked(self._current)
 
6316
                        
5942
6317
                    self.CheckItem(self._current, checked)
5943
6318
        
5944
6319
            # in any case, also generate the normal key event for this key,
6263
6638
            else:
6264
6639
                wx.YieldIfNeeded()
6265
6640
 
6266
 
        if self._textCtrl != None and item != self._textCtrl.item():
6267
 
            self._textCtrl.StopEditing()
 
6641
        if self._editCtrl != None and item != self._editCtrl.item():
 
6642
            self._editCtrl.StopEditing()
6268
6643
 
6269
 
        self._textCtrl = TreeTextCtrl(self, item=item)
6270
 
        self._textCtrl.SetFocus()
 
6644
        self._editCtrl = TreeTextCtrl(self, item=item)
 
6645
        self._editCtrl.SetFocus()
6271
6646
 
6272
6647
 
6273
6648
    def GetEditControl(self):
6277
6652
        simultaneously).
6278
6653
        """
6279
6654
        
6280
 
        return self._textCtrl
6281
 
 
6282
 
 
6283
 
    def OnRenameAccept(self, item, value):
 
6655
        return self._editCtrl
 
6656
 
 
6657
 
 
6658
    def OnAcceptEdit(self, item, value):
6284
6659
        """
6285
 
        Called by L{TreeTextCtrl}, to accept the changes and to send the
 
6660
        Called by L{EditCtrl}, to accept the changes and to send the
6286
6661
        ``EVT_TREE_END_LABEL_EDIT`` event.
6287
6662
 
6288
6663
        :param `item`: an instance of L{GenericTreeItem};
6298
6673
        return not self.GetEventHandler().ProcessEvent(le) or le.IsAllowed()
6299
6674
    
6300
6675
 
6301
 
    def OnRenameCancelled(self, item):
 
6676
    def OnCancelEdit(self, item):
6302
6677
        """
6303
 
        Called by L{TreeTextCtrl}, to cancel the changes and to send the
 
6678
        Called by L{EditCtrl}, to cancel the changes and to send the
6304
6679
        ``EVT_TREE_END_LABEL_EDIT`` event.
6305
6680
 
6306
6681
        :param `item`: an instance of L{GenericTreeItem}.        
6316
6691
        self.GetEventHandler().ProcessEvent(le)
6317
6692
 
6318
6693
 
6319
 
    def OnRenameTimer(self):
6320
 
        """ The timer for renaming has expired. Start editing. """
 
6694
    def OnEditTimer(self):
 
6695
        """ The timer for editing has expired. Start editing. """
6321
6696
        
6322
6697
        self.Edit(self._current)
6323
6698
 
6341
6716
        underMouseChanged = underMouse != self._underMouse
6342
6717
 
6343
6718
        if underMouse and (flags & TREE_HITTEST_ONITEM) and not event.LeftIsDown() and \
6344
 
           not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
 
6719
           not self._isDragging and (not self._editTimer or not self._editTimer.IsRunning()):
6345
6720
            underMouse = underMouse
6346
6721
        else:
6347
6722
            underMouse = None
6356
6731
        # Determines what item we are hovering over and need a tooltip for
6357
6732
        hoverItem = thisItem
6358
6733
 
6359
 
        # We do not want a tooltip if we are dragging, or if the rename timer is running
6360
 
        if underMouseChanged and not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
 
6734
        # We do not want a tooltip if we are dragging, or if the edit timer is running
 
6735
        if underMouseChanged and not self._isDragging and (not self._editTimer or not self._editTimer.IsRunning()):
6361
6736
            
6362
6737
            if hoverItem is not None:
6363
6738
                # Ask the tree control what tooltip (if any) should be shown
6522
6897
            self._dragCount = 0
6523
6898
 
6524
6899
            if item == None:
6525
 
                if self._textCtrl != None and item != self._textCtrl.item():
6526
 
                    self._textCtrl.StopEditing()
 
6900
                if self._editCtrl != None and item != self._editCtrl.item():
 
6901
                    self._editCtrl.StopEditing()
6527
6902
                return  # we hit the blank area
6528
6903
 
6529
6904
            if event.RightDown():
6530
6905
                
6531
 
                if self._textCtrl != None and item != self._textCtrl.item():
6532
 
                    self._textCtrl.StopEditing()
 
6906
                if self._editCtrl != None and item != self._editCtrl.item():
 
6907
                    self._editCtrl.StopEditing()
6533
6908
 
6534
6909
                self._hasFocus = True
6535
6910
                self.SetFocusIgnoringChildren()
6570
6945
                
6571
6946
                    if item == self._current and (flags & TREE_HITTEST_ONITEMLABEL) and self.HasAGWFlag(TR_EDIT_LABELS):
6572
6947
                    
6573
 
                        if self._renameTimer:
 
6948
                        if self._editTimer:
6574
6949
                        
6575
 
                            if self._renameTimer.IsRunning():
 
6950
                            if self._editTimer.IsRunning():
6576
6951
                                
6577
 
                                self._renameTimer.Stop()
 
6952
                                self._editTimer.Stop()
6578
6953
                        
6579
6954
                        else:
6580
6955
                        
6581
 
                            self._renameTimer = TreeRenameTimer(self)
 
6956
                            self._editTimer = TreeEditTimer(self)
6582
6957
                        
6583
 
                        self._renameTimer.Start(_DELAY, True)
 
6958
                        self._editTimer.Start(_DELAY, True)
6584
6959
                    
6585
6960
                    self._lastOnSame = False
6586
6961
                
6588
6963
            else: # !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
6589
6964
 
6590
6965
                if not item or not item.IsEnabled():
6591
 
                    if self._textCtrl != None and item != self._textCtrl.item():
6592
 
                        self._textCtrl.StopEditing()
 
6966
                    if self._editCtrl != None and item != self._editCtrl.item():
 
6967
                        self._editCtrl.StopEditing()
6593
6968
                    return
6594
6969
 
6595
 
                if self._textCtrl != None and item != self._textCtrl.item():
6596
 
                    self._textCtrl.StopEditing()
 
6970
                if self._editCtrl != None and item != self._editCtrl.item():
 
6971
                    self._editCtrl.StopEditing()
6597
6972
 
6598
6973
                self._hasFocus = True
6599
6974
                self.SetFocusIgnoringChildren()
6618
6993
                    if event.LeftDown():
6619
6994
                        if flags & TREE_HITTEST_ONITEM and self.HasAGWFlag(TR_FULL_ROW_HIGHLIGHT):
6620
6995
                            self.DoSelectItem(item, not self.HasAGWFlag(TR_MULTIPLE))
6621
 
                        self.CheckItem(item, not self.IsItemChecked(item))
 
6996
 
 
6997
                        if self.IsItem3State(item):
 
6998
                            checked = self.GetItem3StateValue(item)
 
6999
                            checked = (checked+1)%3
 
7000
                        else:
 
7001
                            checked = not self.IsItemChecked(item)
 
7002
                            
 
7003
                        self.CheckItem(item, checked)
6622
7004
                        
6623
7005
                    return                                            
6624
7006
 
6649
7031
                if event.LeftDClick():
6650
7032
                
6651
7033
                    # double clicking should not start editing the item label
6652
 
                    if self._renameTimer:
6653
 
                        self._renameTimer.Stop()
 
7034
                    if self._editTimer:
 
7035
                        self._editTimer.Stop()
6654
7036
 
6655
7037
                    self._lastOnSame = False
6656
7038
 
6707
7089
#        event.Skip()        
6708
7090
 
6709
7091
 
6710
 
    def CalculateSize(self, item, dc, level=-1, align=False):
 
7092
    def CalculateSize(self, item, dc, level=-1, align=0):
6711
7093
        """
6712
7094
        Calculates overall position and size of an item.
6713
7095
 
6714
7096
        :param `item`: an instance of L{GenericTreeItem};
6715
7097
        :param `dc`: an instance of `wx.DC`;
6716
7098
        :param `level`: the item level in the tree hierarchy;
6717
 
        :param `align`: ``True`` if we want to align windows (in items with windows)
6718
 
         at the same horizontal position.
 
7099
        :param `align`: an integer specifying the alignment type:
 
7100
 
 
7101
         =============== =========================================
 
7102
         `align` Value   Description
 
7103
         =============== =========================================
 
7104
                0        No horizontal alignment of windows (in items with windows).
 
7105
                1        Windows (in items with windows) are aligned at the same horizontal position.
 
7106
                2        Windows (in items with windows) are aligned at the rightmost edge of L{CustomTreeCtrl}.
 
7107
         =============== =========================================
 
7108
 
6719
7109
        """
6720
7110
 
6721
7111
        attr = item.GetAttributes()
6772
7162
            totalHeight = max(total_h, item.GetWindowSize()[1])
6773
7163
 
6774
7164
        if level >= 0 and wnd:
6775
 
            if not align:
 
7165
            if align == 0:
6776
7166
                if level in self.absoluteWindows:
6777
7167
                    self.absoluteWindows[level] = max(self.absoluteWindows[level], image_w+text_w+wcheck+2)
6778
7168
                else:
6779
7169
                    self.absoluteWindows[level] = image_w+text_w+wcheck+2
6780
 
            else:
 
7170
            elif align == 1:
6781
7171
                self.absoluteWindows[level] = max(self.absoluteWindows[level], image_w+text_w+wcheck+2)
6782
7172
                                        
6783
7173
        item.SetWidth(totalWidth)
6784
7174
        item.SetHeight(totalHeight)
6785
7175
 
6786
7176
 
6787
 
    def CalculateLevel(self, item, dc, level, y, align=False):
 
7177
    def CalculateLevel(self, item, dc, level, y, align=0):
6788
7178
        """
6789
7179
        Calculates the level of an item inside the tree hierarchy.
6790
7180
 
6792
7182
        :param `dc`: an instance of `wx.DC`;
6793
7183
        :param `level`: the item level in the tree hierarchy;
6794
7184
        :param `y`: the current vertical position inside the `wx.PyScrolledWindow`;
6795
 
        :param `align`: ``True`` if we want to align windows (in items with windows)
6796
 
         at the same horizontal position.
 
7185
        :param `align`: an integer specifying the alignment type:
 
7186
 
 
7187
         =============== =========================================
 
7188
         `align` Value   Description
 
7189
         =============== =========================================
 
7190
                0        No horizontal alignment of windows (in items with windows).
 
7191
                1        Windows (in items with windows) are aligned at the same horizontal position.
 
7192
                2        Windows (in items with windows) are aligned at the rightmost edge of L{CustomTreeCtrl}.
 
7193
         =============== =========================================
 
7194
 
6797
7195
        """
6798
7196
 
6799
7197
        x = level*self._indent
6850
7248
        y = 2
6851
7249
        y = self.CalculateLevel(self._anchor, dc, 0, y) # start recursion
6852
7250
        
6853
 
        if self.HasAGWFlag(TR_ALIGN_WINDOWS):
 
7251
        if self.HasAGWFlag(TR_ALIGN_WINDOWS) or self.HasAGWFlag(TR_ALIGN_WINDOWS_RIGHT):
 
7252
            align = (self.HasAGWFlag(TR_ALIGN_WINDOWS) and [1] or [2])[0]
6854
7253
            y = 2
6855
 
            y = self.CalculateLevel(self._anchor, dc, 0, y, align=True) # start recursion
 
7254
            y = self.CalculateLevel(self._anchor, dc, 0, y, align) # start recursion
6856
7255
 
6857
7256
 
6858
7257
    def RefreshSubtree(self, item):
6928
7327
            self.RefreshSelectedUnder(child)
6929
7328
    
6930
7329
 
 
7330
    def RefreshItemWithWindows(self, item=None):
 
7331
        """
 
7332
        Refreshes the items with which a window is associated.
 
7333
 
 
7334
        :param `item`: an instance of L{GenericTreeItem}. If `item` is ``None``, then the
 
7335
         recursive refresh starts from the root node.
 
7336
         
 
7337
        :note: This method is called only if the style ``TR_ALIGN_WINDOWS_RIGHT`` is used.
 
7338
        """
 
7339
 
 
7340
        if self._freezeCount:
 
7341
            return
 
7342
 
 
7343
        if item is None:
 
7344
            if self._anchor:
 
7345
                self.RefreshItemWithWindows(self._anchor)
 
7346
                return
 
7347
 
 
7348
        wnd = item.GetWindow()            
 
7349
        if wnd and wnd.IsShown():
 
7350
            self.RefreshLine(item)
 
7351
 
 
7352
        children = item.GetChildren()
 
7353
        for child in children:
 
7354
            self.RefreshItemWithWindows(child)
 
7355
 
 
7356
 
6931
7357
    def Freeze(self):
6932
7358
        """
6933
7359
        Freeze L{CustomTreeCtrl}.