Guest User

UltimateListCtrl

a guest
Oct 25th, 2011
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 277.02 KB | None | 0 0
  1. # --------------------------------------------------------------------------------- #
  2. # ULTIMATELISTCTRL wxPython IMPLEMENTATION
  3. # Inspired by and heavily based on the wxWidgets C++ generic version of wxListCtrl.
  4. #
  5. # Andrea Gavana, @ 08 May 2009
  6. # Latest Revision: 22 May 2009, 09.00 GMT
  7. #
  8. #
  9. # TODO List
  10. #
  11. # 1)  Subitem selection;
  12. # 2)  Watermark? (almost, does not work very well :-( );
  13. # 3)  Groups? (Maybe, check ObjectListView);
  14. # 4)  Scrolling items as headers and footers;
  15. # 5)  Alpha channel for text/background of items;
  16. # 6)  Custom renderers for headers/footers;
  17. # 7)  Fading in and out on mouse motion (a la Windows Vista Aero);
  18. # 8)  Sub-text for headers/footers (grey text below the header/footer text);
  19. # 9)  Fixing the columns to the left or right side of the control layout;
  20. # 10) Skins for header and scrollbars.
  21. #
  22. #
  23. # For all kind of problems, requests of enhancements and bug reports, please
  24. # write to me at:
  25. #
  26. #
  27. # Or, obviously, to the wxPython mailing list!!!
  28. #
  29. #
  30. # End Of Comments
  31. # --------------------------------------------------------------------------------- #
  32.  
  33.  
  34. """
  35. Description
  36. ===========
  37.  
  38. UltimateListCtrl is a class that mimics the behaviour of wx.ListCtrl, withc almost
  39. the same base functionalities plus some more enhancements. This class does
  40. not rely on the native control, as it is a full owner-drawn list control.
  41.  
  42. In addition to the standard wx.ListCtrl behaviour this class supports:
  43.  
  44.  
  45. Appearance
  46. ^^^^^^^^^^
  47.  
  48. * Multiple images for items/subitems;
  49. * Font, colour, background, custom renderers and formatting for items and subitems;
  50. * Ability to add persistent data to an item using SetPyData and GetPyData: the data
  51.  can be any Python object and not necessarily an integer as in wx.ListCtrl;
  52. * CheckBox-type items and subitems;
  53. * RadioButton-type items and subitems;
  54. * Overflowing items/subitems, a la wxGrid, i.e. an item/subitem may overwrite neighboring
  55.  items/subitems if its text would not normally fit in the space allotted to it;
  56. * Hyperlink-type items and subitems: they look like an hyperlink, with the proper mouse
  57.  cursor on hovering;
  58. * Multiline text items and subitems;
  59. * Variable row heights depending on the item/subitem kind/text/window;
  60. * User defined item/subitem renderers: these renderer classes *must* implement the methods
  61.  `DrawSubItem`, `GetLineHeight` and `GetSubItemWidth` (see the demo);
  62. * Enabling/disabling items (together with their plain or grayed out icons);
  63. * Whatever non-toplevel widget can be attached next to an item/subitem;
  64. * Column headers are fully customizable in terms of icons, colour, font, alignment etc...;
  65. * Column headers can have their own checkbox/radiobutton;
  66. * Column footers are fully customizable in terms of icons, colour, font, alignment etc...;
  67. * Column footers can have their own checkbox/radiobutton;
  68. * Ability to hide/show columns;
  69. * Default selection style, gradient (horizontal/vertical) selection style and Windows
  70.  Vista selection style.
  71.  
  72.  
  73. Styles
  74. ^^^^^^
  75.  
  76. * A ULC_TILE style, in which each item appears as a full-sized icon with a label of
  77.  one or more lines beside it (partially implemented);
  78.  
  79.  
  80. Extra Styles
  81. ^^^^^^^^^^^^
  82.  
  83. * ULC_NO_HIGHLIGHT: No highlight when an item is selected;
  84. * ULC_STICKY_HIGHLIGHT: Items are selected by simply hovering on them, with no need to
  85.  click on them;
  86. * ULC_STICKY_NOSELEVENT: Don't send a selection event when using ULC_STICKY_HIGHLIGHT
  87.  extra style;
  88. * ULC_SEND_LEFTCLICK: Send a left click event when an item is selected;
  89. * ULC_AUTO_CHECK_CHILD: When a column header has a checkbox associated, auto-check all
  90.  the subitems in that column;
  91. * ULC_AUTO_TOGGLE_CHILD: When a column header has a checkbox associated, toggle all
  92.  the subitems in that column;
  93. * ULC_SHOW_TOOLTIPS: Show tooltips for ellipsized items/subitems (text too long to be
  94.  shown in the available space) containing the full item/subitem text;
  95. * ULC_HOT_TRACKING: Enable hot tracking of items on mouse motion;
  96. * ULC_BORDER_SELECT: Changes border color whan an item is selected, instead of
  97.  highlighting the item;
  98. * ULC_TRACK_SELECT: Enables hot-track selection in a list control. Hot track selection
  99.  means that an item is automatically selected when the cursor remains over the item for
  100.  a certain period of time. The delay is retrieved on Windows using the win32api call
  101.  win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME), and is defaulted to 400ms
  102.  on other platforms. This extra style applies to all views of UltimateListCtrl;
  103. * ULC_HEADER_IN_ALL_VIEWS: Show column headers in all view modes;
  104. * ULC_NO_FULL_ROW_SELECT: When an item is selected, the only the item in the first column
  105.  is highlighted;
  106. * ULC_FOOTER: Show a footer too (only when header is present);
  107.  
  108.  
  109. And a lot more. Check the demo for an almost complete review of the functionalities.
  110.  
  111.  
  112. Events
  113. ======
  114.  
  115. All the events supported by wx.ListCtrl are also available in UltimateListCtrl.
  116.  
  117. Plus, UltimateListCtrl supports the events related to the checkbutton-type items, subitems
  118. and column headers/footers:
  119.  
  120.  - EVT_LIST_ITEM_CHECKING: an item/subitem is being checked;
  121.  - EVT_LIST_ITEM_CHECKED: an item/subitem has been checked;
  122.  - EVT_LIST_COL_CHECKING: a column header is being checked;
  123.  - EVT_LIST_COL_CHECKED: a column header has being checked;
  124.  - EVT_LIST_FOOTER_CHECKING: a column footer is being checked;
  125.  - EVT_LIST_FOOTER_CHECKED: a column footer has being checked.
  126.  
  127. And to hyperlink-type items:
  128.  
  129.  - EVT_LIST_ITEM_HYPERLINK: an hyperlink item has been clicked.
  130.  
  131. And footer-related events:
  132.  
  133.  - EVT_LIST_FOOTER_CLICK: the user left-clicked on a column footer;
  134.  - EVT_LIST_FOOTER_RIGHT_CLICK: the user right-clicked on a column footer.
  135.  
  136. Plus the following specialized events:
  137.  
  138.  - EVT_LIST_ITEM_LEFT_CLICK: send a left-click event after an item is selected;
  139.  - EVT_LIST_END_DRAG: notify an end-drag operation.
  140.  
  141.  
  142. Supported Platforms
  143. ===================
  144.  
  145. UltimateListCtrl has been tested on the following platforms:
  146.  * Windows (Windows XP);
  147.  
  148.  
  149. Latest Revision: Andrea Gavana @ 22 May 2009, 09.00 GMT
  150. Version 0.2
  151. """
  152.  
  153. import wx
  154. import math
  155. import bisect
  156. import types
  157. import zlib
  158. import cStringIO
  159.  
  160. from wx.lib.expando import ExpandoTextCtrl
  161.  
  162. # Version Info
  163. __version__ = "0.2"
  164.  
  165.  
  166. # ----------------------------------------------------------------------------
  167. # UltimateListCtrl constants
  168. # ----------------------------------------------------------------------------
  169.  
  170. # style flags (compatible with wx.ListCtrl, except for ULC_TILE)
  171. ULC_VRULES                  = wx.LC_VRULES
  172. ULC_HRULES                  = wx.LC_HRULES
  173.  
  174. ULC_ICON                    = wx.LC_ICON
  175. ULC_SMALL_ICON              = wx.LC_SMALL_ICON
  176. ULC_LIST                    = wx.LC_LIST
  177. ULC_REPORT                  = wx.LC_REPORT
  178. ULC_TILE                    = 0x10000
  179.  
  180. ULC_ALIGN_TOP               = wx.LC_ALIGN_TOP
  181. ULC_ALIGN_LEFT              = wx.LC_ALIGN_LEFT
  182. ULC_AUTOARRANGE             = wx.LC_AUTOARRANGE
  183. ULC_VIRTUAL                 = wx.LC_VIRTUAL
  184. ULC_EDIT_LABELS             = wx.LC_EDIT_LABELS
  185. ULC_NO_HEADER               = wx.LC_NO_HEADER
  186. ULC_NO_SORT_HEADER          = wx.LC_NO_SORT_HEADER
  187. ULC_SINGLE_SEL              = wx.LC_SINGLE_SEL
  188. ULC_SORT_ASCENDING          = wx.LC_SORT_ASCENDING
  189. ULC_SORT_DESCENDING         = wx.LC_SORT_DESCENDING
  190.  
  191. # Extra styles
  192. ULC_NO_HIGHLIGHT            = 0x0001
  193. ULC_STICKY_HIGHLIGHT        = 0x0002
  194. ULC_STICKY_NOSELEVENT       = 0x0004
  195. ULC_SEND_LEFTCLICK          = 0x0008
  196. ULC_HAS_VARIABLE_ROW_HEIGHT = 0x0010
  197.  
  198. ULC_AUTO_CHECK_CHILD    = 0x0020  # only meaningful for checkboxes
  199. ULC_AUTO_TOGGLE_CHILD   = 0x0040  # only meaningful for checkboxes
  200. ULC_AUTO_CHECK_PARENT   = 0x0080  # only meaningful for checkboxes
  201. ULC_SHOW_TOOLTIPS       = 0x0100  # shows tooltips on items with ellipsis (...)
  202. ULC_HOT_TRACKING        = 0x0200  # enable hot tracking on mouse motion
  203. ULC_BORDER_SELECT       = 0x0400  # changes border color whan an item is selected, instead of highlighting the item
  204. ULC_TRACK_SELECT        = 0x0800  # Enables hot-track selection in a list control. Hot track selection means that an item
  205.                                   # is automatically selected when the cursor remains over the item for a certain period
  206.                                   # of time. The delay is retrieved on Windows using the win32api call
  207.                                   # win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME), and is defaulted to 400ms
  208.                                   # on other platforms. This style applies to all styles of UltimateListCtrl.
  209. ULC_HEADER_IN_ALL_VIEWS = 0x1000  # Show column headers in all view modes
  210. ULC_NO_FULL_ROW_SELECT  = 0x2000  # When an item is selected, the only the item in the first column is highlighted
  211. ULC_FOOTER              = 0x4000  # Show a footer too (only when header is present)
  212.  
  213. ULC_MASK_TYPE  = ULC_ICON | ULC_SMALL_ICON | ULC_LIST | ULC_REPORT | ULC_TILE
  214. ULC_MASK_ALIGN = ULC_ALIGN_TOP | ULC_ALIGN_LEFT
  215. ULC_MASK_SORT  = ULC_SORT_ASCENDING | ULC_SORT_DESCENDING
  216.  
  217. # for compatibility only
  218. ULC_USER_TEXT = ULC_VIRTUAL
  219.  
  220. # Omitted because
  221. #  (a) too much detail
  222. #  (b) not enough style flags
  223. #  (c) not implemented anyhow in the generic version
  224. #
  225. # ULC_NO_SCROLL
  226. # ULC_NO_LABEL_WRAP
  227. # ULC_OWNERDRAW_FIXED
  228. # ULC_SHOW_SEL_ALWAYS
  229.  
  230. # Mask flags to tell app/GUI what fields of UltimateListItem are valid
  231. ULC_MASK_STATE         =      wx.LIST_MASK_STATE
  232. ULC_MASK_TEXT          =      wx.LIST_MASK_TEXT
  233. ULC_MASK_IMAGE         =      wx.LIST_MASK_IMAGE
  234. ULC_MASK_DATA          =      wx.LIST_MASK_DATA
  235. ULC_SET_ITEM           =      wx.LIST_SET_ITEM
  236. ULC_MASK_WIDTH         =      wx.LIST_MASK_WIDTH
  237. ULC_MASK_FORMAT        =      wx.LIST_MASK_FORMAT
  238. ULC_MASK_FONTCOLOUR    =      0x0080
  239. ULC_MASK_FONT          =      0x0100
  240. ULC_MASK_BACKCOLOUR    =      0x0200
  241. ULC_MASK_KIND          =      0x0400
  242. ULC_MASK_ENABLE        =      0x0800
  243. ULC_MASK_CHECK         =      0x1000
  244. ULC_MASK_HYPERTEXT     =      0x2000
  245. ULC_MASK_WINDOW        =      0x4000
  246. ULC_MASK_PYDATA        =      0x8000
  247. ULC_MASK_SHOWN         =      0x10000
  248. ULC_MASK_RENDERER      =      0x20000
  249. ULC_MASK_OVERFLOW      =      0x40000
  250. ULC_MASK_FOOTER_TEXT   =      0x80000
  251. ULC_MASK_FOOTER_IMAGE  =      0x100000
  252. ULC_MASK_FOOTER_FORMAT =      0x200000
  253. ULC_MASK_FOOTER_FONT   =      0x400000
  254. ULC_MASK_FOOTER_CHECK  =      0x800000
  255. ULC_MASK_FOOTER_KIND   =      0x1000000
  256.  
  257. # State flags for indicating the state of an item
  258. ULC_STATE_DONTCARE    =   wx.LIST_STATE_DONTCARE
  259. ULC_STATE_DROPHILITED =   wx.LIST_STATE_DROPHILITED      # MSW only
  260. ULC_STATE_FOCUSED     =   wx.LIST_STATE_FOCUSED
  261. ULC_STATE_SELECTED    =   wx.LIST_STATE_SELECTED
  262. ULC_STATE_CUT         =   wx.LIST_STATE_CUT              # MSW only
  263. ULC_STATE_DISABLED    =   wx.LIST_STATE_DISABLED         # OS2 only
  264. ULC_STATE_FILTERED    =   wx.LIST_STATE_FILTERED         # OS2 only
  265. ULC_STATE_INUSE       =   wx.LIST_STATE_INUSE            # OS2 only
  266. ULC_STATE_PICKED      =   wx.LIST_STATE_PICKED           # OS2 only
  267. ULC_STATE_SOURCE      =   wx.LIST_STATE_SOURCE           # OS2 only
  268.  
  269. # Hit test flags, used in HitTest
  270. ULC_HITTEST_ABOVE           = wx.LIST_HITTEST_ABOVE            # Above the client area.
  271. ULC_HITTEST_BELOW           = wx.LIST_HITTEST_BELOW            # Below the client area.
  272. ULC_HITTEST_NOWHERE         = wx.LIST_HITTEST_NOWHERE          # In the client area but below the last item.
  273. ULC_HITTEST_ONITEMICON      = wx.LIST_HITTEST_ONITEMICON       # On the bitmap associated with an item.
  274. ULC_HITTEST_ONITEMLABEL     = wx.LIST_HITTEST_ONITEMLABEL      # On the label (string) associated with an item.
  275. ULC_HITTEST_ONITEMRIGHT     = wx.LIST_HITTEST_ONITEMRIGHT      # In the area to the right of an item.
  276. ULC_HITTEST_ONITEMSTATEICON = wx.LIST_HITTEST_ONITEMSTATEICON  # On the state icon for a tree view item that is in a user-defined state.
  277. ULC_HITTEST_TOLEFT          = wx.LIST_HITTEST_TOLEFT           # To the left of the client area.
  278. ULC_HITTEST_TORIGHT         = wx.LIST_HITTEST_TORIGHT          # To the right of the client area.
  279. ULC_HITTEST_ONITEMCHECK     = 0x1000                           # On the checkbox (if any)
  280.  
  281. ULC_HITTEST_ONITEM = ULC_HITTEST_ONITEMICON | ULC_HITTEST_ONITEMLABEL | ULC_HITTEST_ONITEMSTATEICON | ULC_HITTEST_ONITEMCHECK
  282.  
  283. # Flags for GetNextItem (MSW only except ULC_NEXT_ALL)
  284. ULC_NEXT_ABOVE = wx.LIST_NEXT_ABOVE         # Searches for an item above the specified item
  285. ULC_NEXT_ALL   = wx.LIST_NEXT_ALL           # Searches for subsequent item by index
  286. ULC_NEXT_BELOW = wx.LIST_NEXT_BELOW         # Searches for an item below the specified item
  287. ULC_NEXT_LEFT  = wx.LIST_NEXT_LEFT          # Searches for an item to the left of the specified item
  288. ULC_NEXT_RIGHT = wx.LIST_NEXT_RIGHT         # Searches for an item to the right of the specified item
  289.  
  290. # Alignment flags for Arrange (MSW only except ULC_ALIGN_LEFT)
  291. ULC_ALIGN_DEFAULT      = wx.LIST_ALIGN_DEFAULT
  292. ULC_ALIGN_LEFT         = wx.LIST_ALIGN_LEFT
  293. ULC_ALIGN_TOP          = wx.LIST_ALIGN_TOP
  294. ULC_ALIGN_SNAP_TO_GRID = wx.LIST_ALIGN_SNAP_TO_GRID
  295.  
  296. # Column format (MSW only except ULC_FORMAT_LEFT)
  297. ULC_FORMAT_LEFT   = wx.LIST_FORMAT_LEFT
  298. ULC_FORMAT_RIGHT  = wx.LIST_FORMAT_RIGHT
  299. ULC_FORMAT_CENTRE = wx.LIST_FORMAT_CENTRE
  300. ULC_FORMAT_CENTER = ULC_FORMAT_CENTRE
  301.  
  302. # Autosize values for SetColumnWidth
  303. ULC_AUTOSIZE = wx.LIST_AUTOSIZE
  304. ULC_AUTOSIZE_USEHEADER = wx.LIST_AUTOSIZE_USEHEADER      # partly supported by generic version
  305.  
  306. # Flag values for GetItemRect
  307. ULC_RECT_BOUNDS = wx.LIST_RECT_BOUNDS
  308. ULC_RECT_ICON   = wx.LIST_RECT_ICON
  309. ULC_RECT_LABEL  = wx.LIST_RECT_LABEL
  310.  
  311. # Flag values for FindItem (MSW only)
  312. ULC_FIND_UP    = wx.LIST_FIND_UP
  313. ULC_FIND_DOWN  = wx.LIST_FIND_DOWN
  314. ULC_FIND_LEFT  = wx.LIST_FIND_LEFT
  315. ULC_FIND_RIGHT = wx.LIST_FIND_RIGHT
  316.  
  317. # Items/subitems rect
  318. ULC_GETSUBITEMRECT_WHOLEITEM = wx.LIST_GETSUBITEMRECT_WHOLEITEM
  319.  
  320. # ----------------------------------------------------------------------------
  321. # UltimateListCtrl event macros
  322. # ----------------------------------------------------------------------------
  323.  
  324. wxEVT_COMMAND_LIST_BEGIN_DRAG = wx.wxEVT_COMMAND_LIST_BEGIN_DRAG
  325. wxEVT_COMMAND_LIST_BEGIN_RDRAG = wx.wxEVT_COMMAND_LIST_BEGIN_RDRAG
  326. wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
  327. wxEVT_COMMAND_LIST_END_LABEL_EDIT = wx.wxEVT_COMMAND_LIST_END_LABEL_EDIT
  328. wxEVT_COMMAND_LIST_DELETE_ITEM = wx.wxEVT_COMMAND_LIST_DELETE_ITEM
  329. wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS = wx.wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
  330. wxEVT_COMMAND_LIST_ITEM_SELECTED = wx.wxEVT_COMMAND_LIST_ITEM_SELECTED
  331. wxEVT_COMMAND_LIST_ITEM_DESELECTED = wx.wxEVT_COMMAND_LIST_ITEM_DESELECTED
  332. wxEVT_COMMAND_LIST_KEY_DOWN = wx.wxEVT_COMMAND_LIST_KEY_DOWN
  333. wxEVT_COMMAND_LIST_INSERT_ITEM = wx.wxEVT_COMMAND_LIST_INSERT_ITEM
  334. wxEVT_COMMAND_LIST_COL_CLICK = wx.wxEVT_COMMAND_LIST_COL_CLICK
  335. wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
  336. wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
  337. wxEVT_COMMAND_LIST_ITEM_ACTIVATED = wx.wxEVT_COMMAND_LIST_ITEM_ACTIVATED
  338. wxEVT_COMMAND_LIST_CACHE_HINT = wx.wxEVT_COMMAND_LIST_CACHE_HINT
  339. wxEVT_COMMAND_LIST_COL_RIGHT_CLICK = wx.wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
  340. wxEVT_COMMAND_LIST_COL_BEGIN_DRAG = wx.wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
  341. wxEVT_COMMAND_LIST_COL_DRAGGING = wx.wxEVT_COMMAND_LIST_COL_DRAGGING
  342. wxEVT_COMMAND_LIST_COL_END_DRAG = wx.wxEVT_COMMAND_LIST_COL_END_DRAG
  343. wxEVT_COMMAND_LIST_ITEM_FOCUSED = wx.wxEVT_COMMAND_LIST_ITEM_FOCUSED
  344.  
  345. wxEVT_COMMAND_LIST_FOOTER_CLICK = wx.NewEventType()
  346. wxEVT_COMMAND_LIST_FOOTER_RIGHT_CLICK = wx.NewEventType()
  347. wxEVT_COMMAND_LIST_FOOTER_CHECKING = wx.NewEventType()
  348. wxEVT_COMMAND_LIST_FOOTER_CHECKED = wx.NewEventType()
  349.  
  350. wxEVT_COMMAND_LIST_ITEM_LEFT_CLICK = wx.NewEventType()
  351. wxEVT_COMMAND_LIST_ITEM_CHECKING = wx.NewEventType()
  352. wxEVT_COMMAND_LIST_ITEM_CHECKED = wx.NewEventType()
  353. wxEVT_COMMAND_LIST_ITEM_HYPERLINK = wx.NewEventType()
  354. wxEVT_COMMAND_LIST_END_DRAG = wx.NewEventType()
  355. wxEVT_COMMAND_LIST_COL_CHECKING = wx.NewEventType()
  356. wxEVT_COMMAND_LIST_COL_CHECKED = wx.NewEventType()
  357.  
  358. EVT_LIST_BEGIN_DRAG = wx.EVT_LIST_BEGIN_DRAG
  359. EVT_LIST_BEGIN_RDRAG = wx.EVT_LIST_BEGIN_RDRAG
  360. EVT_LIST_BEGIN_LABEL_EDIT = wx.EVT_LIST_BEGIN_LABEL_EDIT
  361. EVT_LIST_END_LABEL_EDIT = wx.EVT_LIST_END_LABEL_EDIT
  362. EVT_LIST_DELETE_ITEM = wx.EVT_LIST_DELETE_ITEM
  363. EVT_LIST_DELETE_ALL_ITEMS = wx.EVT_LIST_DELETE_ALL_ITEMS
  364. EVT_LIST_KEY_DOWN = wx.EVT_LIST_KEY_DOWN
  365. EVT_LIST_INSERT_ITEM = wx.EVT_LIST_INSERT_ITEM
  366. EVT_LIST_COL_CLICK = wx.EVT_LIST_COL_CLICK
  367. EVT_LIST_COL_RIGHT_CLICK = wx.EVT_LIST_COL_RIGHT_CLICK
  368. EVT_LIST_COL_BEGIN_DRAG = wx.EVT_LIST_COL_BEGIN_DRAG
  369. EVT_LIST_COL_END_DRAG = wx.EVT_LIST_COL_END_DRAG
  370. EVT_LIST_COL_DRAGGING = wx.EVT_LIST_COL_DRAGGING
  371. EVT_LIST_ITEM_SELECTED = wx.EVT_LIST_ITEM_SELECTED
  372. EVT_LIST_ITEM_DESELECTED = wx.EVT_LIST_ITEM_DESELECTED
  373. EVT_LIST_ITEM_RIGHT_CLICK = wx.EVT_LIST_ITEM_RIGHT_CLICK
  374. EVT_LIST_ITEM_MIDDLE_CLICK = wx.EVT_LIST_ITEM_MIDDLE_CLICK
  375. EVT_LIST_ITEM_ACTIVATED = wx.EVT_LIST_ITEM_ACTIVATED
  376. EVT_LIST_ITEM_FOCUSED = wx.EVT_LIST_ITEM_FOCUSED
  377. EVT_LIST_CACHE_HINT = wx.EVT_LIST_CACHE_HINT
  378.  
  379. EVT_LIST_ITEM_LEFT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_LEFT_CLICK, 1)
  380. EVT_LIST_ITEM_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_CHECKING, 1)
  381. EVT_LIST_ITEM_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_CHECKED, 1)
  382. EVT_LIST_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_HYPERLINK, 1)
  383. EVT_LIST_END_DRAG = wx.PyEventBinder(wxEVT_COMMAND_LIST_END_DRAG, 1)
  384. EVT_LIST_COL_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_COL_CHECKING, 1)
  385. EVT_LIST_COL_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_COL_CHECKED, 1)
  386.  
  387. EVT_LIST_FOOTER_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CLICK, 1)
  388. EVT_LIST_FOOTER_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_RIGHT_CLICK, 1)
  389. EVT_LIST_FOOTER_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CHECKING, 1)
  390. EVT_LIST_FOOTER_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CHECKED, 1)
  391.  
  392. # NOTE: If using the wxExtListBox visual attributes works everywhere then this can
  393. # be removed, as well as the #else case below.
  394.  
  395. _USE_VISATTR = 0
  396.  
  397.  
  398. # ----------------------------------------------------------------------------
  399. # Constants
  400. # ----------------------------------------------------------------------------
  401.  
  402. SCROLL_UNIT_X = 15
  403. SCROLL_UNIT_Y = 15
  404.  
  405. # the spacing between the lines (in report mode)
  406. LINE_SPACING = 0
  407.  
  408. # extra margins around the text label
  409. EXTRA_WIDTH = 4
  410. EXTRA_HEIGHT = 4
  411.  
  412. if wx.Platform == "__WXGTK__":
  413.     EXTRA_HEIGHT = 6
  414.  
  415. # margin between the window and the items
  416. EXTRA_BORDER_X = 2
  417. EXTRA_BORDER_Y = 2
  418.  
  419. # offset for the header window
  420. HEADER_OFFSET_X = 1
  421. HEADER_OFFSET_Y = 1
  422.  
  423. # margin between rows of icons in [small] icon view
  424. MARGIN_BETWEEN_ROWS = 6
  425.  
  426. # when autosizing the columns, add some slack
  427. AUTOSIZE_COL_MARGIN = 10
  428.  
  429. # default and minimal widths for the header columns
  430. WIDTH_COL_DEFAULT = 80
  431. WIDTH_COL_MIN = 10
  432.  
  433. # the space between the image and the text in the report mode
  434. IMAGE_MARGIN_IN_REPORT_MODE = 5
  435.  
  436. # the space between the image and the text in the report mode in header
  437. HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2
  438.  
  439. # and the width of the icon, if any
  440. MARGIN_BETWEEN_TEXT_AND_ICON = 2
  441.  
  442. # Background Image Style
  443. _StyleTile = 0
  444. _StyleStretch = 1
  445.  
  446. # Windows Vista Colours
  447. _rgbSelectOuter = wx.Colour(170, 200, 245)
  448. _rgbSelectInner = wx.Colour(230, 250, 250)
  449. _rgbSelectTop = wx.Colour(210, 240, 250)
  450. _rgbSelectBottom = wx.Colour(185, 215, 250)
  451. _rgbNoFocusTop = wx.Colour(250, 250, 250)
  452. _rgbNoFocusBottom = wx.Colour(235, 235, 235)
  453. _rgbNoFocusOuter = wx.Colour(220, 220, 220)
  454. _rgbNoFocusInner = wx.Colour(245, 245, 245)
  455.  
  456. # Mouse hover time for track selection
  457. HOVER_TIME = 400
  458. if wx.Platform == "__WXMSW__":
  459.     try:
  460.         import win32gui, win32con
  461.         HOVER_TIME = win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME)
  462.     except ImportError:
  463.         pass
  464.  
  465.  
  466. # Utility method
  467. def to_list(input):
  468.  
  469.     if isinstance(input, types.ListType):
  470.         return input
  471.     elif isinstance(input, types.IntType):
  472.         return [input]
  473.     else:
  474.         raise Exception("Invalid parameter passed to `to_list`: only integers and list are accepted.")
  475.        
  476.  
  477. def CheckVariableRowHeight(listCtrl, text):
  478.  
  479.     if not listCtrl.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  480.         if "\n" in text:
  481.             raise Exception("Multiline text items are not allowed without the ULC_HAS_VARIABLE_ROW_HEIGHT extra style.")
  482.  
  483.  
  484. def CreateListItem(itemOrId, col):
  485.  
  486.     if type(itemOrId) == types.IntType:
  487.         item = UltimateListItem()
  488.         item._itemId = itemOrId
  489.         item._col = col
  490.     else:
  491.         item = itemOrId
  492.  
  493.     return item
  494.  
  495.  
  496. def GrayOut(anImage):
  497.     """
  498.    Convert the given image (in place) to a grayed-out version,
  499.    appropriate for a 'disabled' appearance.
  500.    """
  501.    
  502.     factor = 0.7        # 0 < f < 1.  Higher Is Grayer
  503.    
  504.     if anImage.HasMask():
  505.         maskColour = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
  506.     else:
  507.         maskColour = None
  508.        
  509.     data = map(ord, list(anImage.GetData()))
  510.  
  511.     for i in range(0, len(data), 3):
  512.        
  513.         pixel = (data[i], data[i+1], data[i+2])
  514.         pixel = MakeGray(pixel, factor, maskColour)
  515.  
  516.         for x in range(3):
  517.             data[i+x] = pixel[x]
  518.  
  519.     anImage.SetData(''.join(map(chr, data)))
  520.    
  521.     return anImage
  522.  
  523.  
  524. def MakeGray((r,g,b), factor, maskColour):
  525.     """
  526.    Make a pixel grayed-out. If the pixel matches the maskcolour, it won't be
  527.    changed.
  528.    """
  529.    
  530.     if (r,g,b) != maskColour:
  531.         return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
  532.     else:
  533.         return (r,g,b)
  534.  
  535.  
  536. #----------------------------------------------------------------------
  537. def GetdragcursorData():
  538.     return zlib.decompress(
  539. "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\xa2@,\xcf\xc1\
  540. \x06$9z\xda>\x00)\xce\x02\x8f\xc8b\x06\x06na\x10fd\x985G\x02(\xd8W\xe2\x1aQ\
  541. \xe2\x9c\x9f\x9b\x9b\x9aW\xc2\x90\xec\x11\xe4\xab\x90\x9cQ\x9a\x97\x9d\x93\
  542. \x9a\xa7`l\xa4\x90\x99\x9e\x97_\x94\x9a\xc2\xeb\x18\xec\xec\xe9i\xa5\xa0\xa7\
  543. W\xa5\xaa\x07\x01P:7\x1eH\xe4\xe8\xe9\xd9\x808\x11\xbc\x1e\xae\x11V\n\x06@`\
  544. \xeehd\n\xa2-\x0c,\x8cA\xb4\x9b\t\x94o\xe2b\x08\xa2\xcd\\L\xdd@\xb4\xab\x85\
  545. \x993\x886v\xb6p\x02\xd1\x86N\xa6\x16\x12\xf7~\xdf\x05\xbal\xa9\xa7\x8bcH\
  546. \xc5\x9c3W9\xb9\x1a\x14\x04X/\xec\xfc\xbft\xed\x02\xa5\xf4\xc2m\xfa*<N\x17??\
  547. \x0frqy\x9c\xd3\xb2f5\xaf\x89\x8f9Gk\xbc\x08\xa7\xbf\x06\x97\x98\x06S\xd8E\
  548. \xbd\x9cE\xb2\x15\x9da\x89\xe2k\x0f\x9c\xb6|\x1a\xea\x14X\x1d6G\x83E\xe7\x9c\
  549. \x1dO\xa8\xde\xb6\x84l\x15\x9eS\xcf\xc2tf\x15\xde\xf7\xb5\xb2]\xf0\x96+\xf5@\
  550. D\x90\x1d\xef19_\xf5\xde5y\xb6+\xa7\xdeZ\xfbA\x9bu\x9f`\xffD\xafYn\xf6\x9eW\
  551. \xeb>\xb6\x7f\x98\\U\xcb\xf5\xd5\xcb\x9a'\xe7\xf4\xd7\x0b\xba\x9e\xdb\x17E\
  552. \xfdf\x97Z\xcb\xcc\xc0\xf0\xff?3\xc3\x92\xabN\x8arB\xc7\x8f\x03\x1d\xcc\xe0\
  553. \xe9\xea\xe7\xb2\xce)\xa1\t\x00B7|\x00" )
  554.  
  555. def GetdragcursorBitmap():
  556.     return wx.BitmapFromImage(GetdragcursorImage())
  557.  
  558. def GetdragcursorImage():
  559.     stream = cStringIO.StringIO(GetdragcursorData())
  560.     return wx.ImageFromStream(stream)
  561.  
  562.  
  563. class SelectionStore(object):
  564.  
  565.     def __init__(self):
  566.  
  567.         # the array of items whose selection state is different from default
  568.         self._itemsSel = []
  569.         # the default state: normally, False (i.e. off) but maybe set to true if
  570.         # there are more selected items than non selected ones - this allows to
  571.         # handle selection of all items efficiently
  572.         self._defaultState = False
  573.         # the total number of items we handle
  574.         self._count  = 0
  575.  
  576.     # special case of SetItemCount(0)
  577.     def Clear(self):
  578.  
  579.         self._itemsSel = []
  580.         self._count = 0
  581.         self._defaultState = False
  582.  
  583.     # return the total number of selected items
  584.     def GetSelectedCount(self):
  585.  
  586.         return (self._defaultState and [self._count - len(self._itemsSel)] or [len(self._itemsSel)])[0]
  587.  
  588.  
  589.     def IsSelected(self, item):
  590.  
  591.         isSel = item in self._itemsSel
  592.  
  593.         # if the default state is to be selected, being in m_itemsSel means that
  594.         # the item is not selected, so we have to inverse the logic
  595.         return (self._defaultState and [not isSel] or [isSel])[0]
  596.  
  597.  
  598.     def SelectItem(self, item, select=True):
  599.  
  600.         # search for the item ourselves as like this we get the index where to
  601.         # insert it later if needed, so we do only one search in the array instead
  602.         # of two (adding item to a sorted array requires a search)
  603.         index = bisect.bisect_right(self._itemsSel, item)
  604.         isSel = index < len(self._itemsSel) and self._itemsSel[index] == item
  605.  
  606.         if select != self._defaultState:
  607.            
  608.             if item not in self._itemsSel:
  609.                 bisect.insort_right(self._itemsSel, item)
  610.                 return True
  611.        
  612.         else: # reset to default state
  613.        
  614.             if item in self._itemsSel:
  615.                 self._itemsSel.remove(item)
  616.                 return True
  617.            
  618.         return False
  619.  
  620.  
  621.     def SelectRange(self, itemFrom, itemTo, select=True):
  622.  
  623.         # 100 is hardcoded but it shouldn't matter much: the important thing is
  624.         # that we don't refresh everything when really few (e.g. 1 or 2) items
  625.         # change state
  626.         MANY_ITEMS = 100
  627.  
  628.         # many items (> half) changed state
  629.         itemsChanged = []        
  630.  
  631.         # are we going to have more [un]selected items than the other ones?
  632.         if itemTo - itemFrom > self._count/2:
  633.  
  634.             if select != self._defaultState:
  635.            
  636.                 # the default state now becomes the same as 'select'
  637.                 self._defaultState = select
  638.  
  639.                 # so all the old selections (which had state select) shouldn't be
  640.                 # selected any more, but all the other ones should
  641.                 selOld = self._itemsSel[:]
  642.                 self._itemsSel = []
  643.  
  644.                 # TODO: it should be possible to optimize the searches a bit
  645.                 #       knowing the possible range
  646.  
  647.                 for item in xrange(itemFrom):
  648.                     if item not in selOld:
  649.                         self._itemsSel.append(item)
  650.                
  651.                 for item in xrange(itemTo + 1, self._count):
  652.                     if item not in selOld:
  653.                         self._itemsSel.append(item)
  654.  
  655.             else: # select == self._defaultState
  656.            
  657.                 # get the inclusive range of items between itemFrom and itemTo
  658.                 count = len(self._itemsSel)
  659.                 start = bisect.bisect_right(self._itemsSel, itemFrom)
  660.                 end = bisect.bisect_right(self._itemsSel, itemTo)
  661.  
  662.                 if start == count or self._itemsSel[start] < itemFrom:
  663.                     start += 1
  664.                
  665.                 if end == count or self._itemsSel[end] > itemTo:
  666.                     end -= 1
  667.                    
  668.                 if start <= end:
  669.                
  670.                     # delete all of them (from end to avoid changing indices)
  671.                     for i in xrange(end, start-1, -1):
  672.                         if itemsChanged:
  673.                             if len(itemsChanged) > MANY_ITEMS:
  674.                                 # stop counting (see comment below)
  675.                                 itemsChanged = []
  676.                             else:                            
  677.                                 itemsChanged.append(self._itemsSel[i])
  678.                            
  679.                         self._itemsSel.pop(i)
  680.                 else:
  681.                     self._itemsSel = []
  682.  
  683.         else: # "few" items change state
  684.        
  685.             if itemsChanged:
  686.                 itemsChanged = []
  687.  
  688.             # just add the items to the selection
  689.             for item in xrange(itemFrom, itemTo+1):
  690.                 if self.SelectItem(item, select) and itemsChanged:
  691.                     itemsChanged.append(item)
  692.                     if len(itemsChanged) > MANY_ITEMS:
  693.                         # stop counting them, we'll just eat gobs of memory
  694.                         # for nothing at all - faster to refresh everything in
  695.                         # this case
  696.                         itemsChanged = []
  697.  
  698.         # we set it to None if there are many items changing state
  699.         return itemsChanged
  700.  
  701.  
  702.     def OnItemDelete(self, item):
  703.  
  704.         count = len(self._itemsSel)
  705.         i = bisect.bisect_right(self._itemsSel, item)
  706.  
  707.         if i < count and self._itemsSel[i] == item:
  708.             # this item itself was in m_itemsSel, remove it from there
  709.             self._itemsSel.pop(i)
  710.  
  711.             count -= 1
  712.        
  713.         # and adjust the index of all which follow it
  714.         while i < count:
  715.  
  716.             i += 1        
  717.             self._itemsSel[i] -= 1
  718.        
  719.  
  720.     def SetItemCount(self, count):
  721.  
  722.         # forget about all items whose indices are now invalid if the size
  723.         # decreased
  724.         if count < self._count:
  725.             for i in xrange(len(self._itemsSel), 0, -1):
  726.                 if self._itemsSel[i - 1] >= count:
  727.                     self._itemsSel.pop(i - 1)
  728.            
  729.         # remember the new number of items
  730.         self._count = count
  731.  
  732.  
  733. # ----------------------------------------------------------------------------
  734. # UltimateListItemAttr: a structure containing the visual attributes of an item
  735. # ----------------------------------------------------------------------------
  736.  
  737. class UltimateListItemAttr(object):
  738.  
  739.     def __init__(self, colText=wx.NullColour, colBack=wx.NullColour, font=wx.NullFont,
  740.                  enabled=True, footerColText=wx.NullColour, footerColBack=wx.NullColour,
  741.                  footerFont=wx.NullFont):
  742.  
  743.         self._colText = colText
  744.         self._colBack = colBack
  745.         self._font = font
  746.         self._enabled = enabled
  747.  
  748.         self._footerColText = footerColText
  749.         self._footerColBack = footerColBack
  750.         self._footerFont = footerFont
  751.  
  752.  
  753.     # setters
  754.     def SetTextColour(self, colText):
  755.  
  756.         self._colText = colText
  757.  
  758.  
  759.     def SetBackgroundColour(self, colBack):
  760.  
  761.         self._colBack = colBack
  762.  
  763.  
  764.     def SetFont(self, font):
  765.  
  766.         self._font = font
  767.  
  768.  
  769.     def Enable(self, enable=True):
  770.  
  771.         self._enabled = enable        
  772.  
  773.  
  774.     def SetFooterTextColour(self, colText):
  775.  
  776.         self._footerColText = colText
  777.  
  778.  
  779.     def SetFooterBackgroundColour(self, colBack):
  780.  
  781.         self._footerColBack = colBack
  782.  
  783.  
  784.     def SetFooterFont(self, font):
  785.  
  786.         self._footerFont = font
  787.  
  788.  
  789.     # accessors
  790.     def HasTextColour(self):
  791.  
  792.         return self._colText.Ok()
  793.  
  794.  
  795.     def HasBackgroundColour(self):
  796.  
  797.         return self._colBack.Ok()
  798.  
  799.  
  800.     def HasFont(self):
  801.  
  802.         return self._font.Ok()
  803.  
  804.  
  805.     def HasFooterTextColour(self):
  806.  
  807.         return self._footerColText.Ok()
  808.  
  809.  
  810.     def HasFooterBackgroundColour(self):
  811.  
  812.         return self._footerColBack.Ok()
  813.  
  814.  
  815.     def HasFooterFont(self):
  816.  
  817.         return self._footerFont.Ok()
  818.  
  819.  
  820.     # getters
  821.     def GetTextColour(self):
  822.  
  823.         return self._colText
  824.  
  825.  
  826.     def GetBackgroundColour(self):
  827.  
  828.         return self._colBack
  829.  
  830.  
  831.     def GetFont(self):
  832.  
  833.         return self._font
  834.  
  835.  
  836.     def GetFooterTextColour(self):
  837.  
  838.         return self._footerColText
  839.  
  840.  
  841.     def GetFooterBackgroundColour(self):
  842.  
  843.         return self._footerColBack
  844.  
  845.  
  846.     def GetFooterFont(self):
  847.  
  848.         return self._footerFont
  849.  
  850.  
  851.     def IsEnabled(self):
  852.  
  853.         return self._enabled        
  854.  
  855. # ----------------------------------------------------------------------------
  856. # UltimateListItem: the item or column info, used to exchange data with UltimateListCtrl
  857. # ----------------------------------------------------------------------------
  858.  
  859. class UltimateListItem(wx.Object):
  860.  
  861.     def __init__(self, item=None):
  862.  
  863.         if not item:
  864.             self.Init()
  865.             self._attr = None
  866.         else:
  867.             self._mask = item._mask              # Indicates what fields are valid
  868.             self._itemId = item._itemId          # The zero-based item position
  869.             self._col = item._col                # Zero-based column, if in report mode
  870.             self._state = item._state            # The state of the item
  871.             self._stateMask = item._stateMask    # Which flags of self._state are valid (uses same flags)
  872.             self._text = item._text              # The label/header text
  873.             self._image = item._image[:]         # The zero-based indexes into an image list
  874.             self._data = item._data              # App-defined data
  875.             self._pyData = item._pyData          # Python-specific data
  876.             self._format = item._format          # left, right, centre
  877.             self._width = item._width            # width of column
  878.             self._colour = item._colour          # item text colour
  879.             self._font = item._font              # item font
  880.             self._checked = item._checked        # The checking state for the item (if kind > 0)
  881.             self._kind = item._kind              # Whether it is a normal, checkbox-like or a radiobutton-like item
  882.             self._enabled = item._enabled        # Whether the item is enabled or not
  883.             self._hypertext = item._hypertext    # indicates if the item is hypertext
  884.             self._visited = item._visited        # visited state for an hypertext item
  885.             self._wnd = item._wnd
  886.             self._windowenabled = item._windowenabled
  887.             self._windowsize = item._windowsize
  888.             self._isColumnShown = item._isColumnShown
  889.             self._customRenderer = item._customRenderer
  890.             self._overFlow = item._overFlow
  891.             self._footerChecked = item._footerChecked
  892.             self._footerFormat = item._footerFormat
  893.             self._footerImage = item._footerImage
  894.             self._footerKind = item._footerKind
  895.             self._footerText = item._footerText
  896.             self._expandWin = item._expandWin
  897.             self._attr = None
  898.  
  899.             # copy list item attributes
  900.             if item.HasAttributes():
  901.                 self._attr = item.GetAttributes()[:]
  902.  
  903.     # resetting
  904.     def Clear(self):
  905.  
  906.         self.Init()
  907.         self._text = ""
  908.         self.ClearAttributes()
  909.  
  910.  
  911.     def ClearAttributes(self):
  912.  
  913.         if self._attr:
  914.             del self._attr
  915.             self._attr = None
  916.  
  917.     # setters
  918.     def SetMask(self, mask):
  919.  
  920.         self._mask = mask
  921.  
  922.  
  923.     def SetId(self, id):
  924.  
  925.         self._itemId = id
  926.  
  927.  
  928.     def SetColumn(self, col):
  929.  
  930.         self._col = col
  931.  
  932.  
  933.     def SetState(self, state):
  934.  
  935.         self._mask |= ULC_MASK_STATE
  936.         self._state = state
  937.         self._stateMask |= state
  938.  
  939.  
  940.     def SetStateMask(self, stateMask):
  941.  
  942.         self._stateMask = stateMask
  943.  
  944.  
  945.     def SetText(self, text):
  946.  
  947.         self._mask |= ULC_MASK_TEXT
  948.         self._text = text
  949.  
  950.  
  951.     def SetImage(self, image):
  952.  
  953.         self._mask |= ULC_MASK_IMAGE
  954.         self._image = to_list(image)
  955.  
  956.  
  957.     def SetData(self, data):
  958.        
  959.         self._mask |= ULC_MASK_DATA
  960.         self._data = data
  961.  
  962.  
  963.     def SetPyData(self, pyData):
  964.  
  965.         self._mask |= ULC_MASK_PYDATA
  966.         self._pyData = pyData
  967.        
  968.  
  969.     def SetWidth(self, width):
  970.  
  971.         self._mask |= ULC_MASK_WIDTH
  972.         self._width = width
  973.  
  974.  
  975.     def SetAlign(self, align):
  976.  
  977.         self._mask |= ULC_MASK_FORMAT
  978.         self._format = align
  979.  
  980.  
  981.     def SetTextColour(self, colText):
  982.  
  983.         self.Attributes().SetTextColour(colText)
  984.  
  985.  
  986.     def SetBackgroundColour(self, colBack):
  987.  
  988.         self.Attributes().SetBackgroundColour(colBack)
  989.  
  990.  
  991.     def SetFont(self, font):
  992.  
  993.         self.Attributes().SetFont(font)
  994.  
  995.  
  996.     def SetFooterTextColour(self, colText):
  997.  
  998.         self.Attributes().SetFooterTextColour(colText)
  999.  
  1000.  
  1001.     def SetFooterBackgroundColour(self, colBack):
  1002.  
  1003.         self.Attributes().SetFooterBackgroundColour(colBack)
  1004.  
  1005.  
  1006.     def SetFooterFont(self, font):
  1007.  
  1008.         self.Attributes().SetFooterFont(font)
  1009.  
  1010.  
  1011.     def Enable(self, enable=True):
  1012.  
  1013.         self.Attributes().Enable(enable)        
  1014.  
  1015.     # accessors
  1016.     def GetMask(self):
  1017.  
  1018.         return self._mask
  1019.  
  1020.  
  1021.     def GetId(self):
  1022.  
  1023.         return self._itemId
  1024.  
  1025.  
  1026.     def GetColumn(self):
  1027.  
  1028.         return self._col
  1029.  
  1030.  
  1031.     def GetState(self):
  1032.  
  1033.         return self._state & self._stateMask
  1034.  
  1035.  
  1036.     def GetText(self):
  1037.  
  1038.         return self._text
  1039.  
  1040.  
  1041.     def GetImage(self):
  1042.  
  1043.         return self._image
  1044.  
  1045.  
  1046.     def GetData(self):
  1047.  
  1048.         return self._data
  1049.  
  1050.  
  1051.     def GetPyData(self):
  1052.  
  1053.         return self._pyData
  1054.    
  1055.  
  1056.     def GetWidth(self):
  1057.  
  1058.         return self._width
  1059.  
  1060.  
  1061.     def GetAlign(self):
  1062.  
  1063.         return self._format
  1064.  
  1065.  
  1066.     def GetAttributes(self):
  1067.  
  1068.         return self._attr
  1069.  
  1070.  
  1071.     def HasAttributes(self):
  1072.  
  1073.         return self._attr != None
  1074.  
  1075.  
  1076.     def GetTextColour(self):
  1077.  
  1078.         return (self.HasAttributes() and [self._attr.GetTextColour()] or [wx.NullColour])[0]
  1079.  
  1080.  
  1081.     def GetBackgroundColour(self):
  1082.  
  1083.         return (self.HasAttributes() and [self._attr.GetBackgroundColour()] or [wx.NullColour])[0]
  1084.  
  1085.  
  1086.     def GetFont(self):
  1087.  
  1088.         return (self.HasAttributes() and [self._attr.GetFont()] or [wx.NullFont])[0]
  1089.  
  1090.  
  1091.     def IsEnabled(self):
  1092.        
  1093.         return (self.HasAttributes() and [self._attr.IsEnabled()] or [True])[0]
  1094.    
  1095.     # creates self._attr if we don't have it yet
  1096.     def Attributes(self):
  1097.  
  1098.         if not self._attr:
  1099.             self._attr = UltimateListItemAttr()
  1100.  
  1101.         return self._attr
  1102.  
  1103.  
  1104.     def SetKind(self, kind):
  1105.  
  1106.         self._mask |= ULC_MASK_KIND
  1107.         self._kind = kind
  1108.        
  1109.  
  1110.     def GetKind(self):
  1111.  
  1112.         return self._kind
  1113.    
  1114.  
  1115.     def IsChecked(self):
  1116.         """Returns whether the item is checked or not."""
  1117.  
  1118.         return self._checked
  1119.  
  1120.  
  1121.     def Check(self, checked=True):
  1122.         """Check an item. Meaningful only for check and radio items."""
  1123.  
  1124.         self._mask |= ULC_MASK_CHECK
  1125.         self._checked = checked
  1126.  
  1127.  
  1128.     def IsShown(self):
  1129.  
  1130.         return self._isColumnShown
  1131.    
  1132.  
  1133.     def SetShown(self, shown=True):
  1134.  
  1135.         self._mask |= ULC_MASK_SHOWN
  1136.         self._isColumnShown = shown
  1137.  
  1138.        
  1139.     def SetHyperText(self, hyper=True):
  1140.         """Sets whether the item is hypertext or not."""
  1141.        
  1142.         self._mask |= ULC_MASK_HYPERTEXT
  1143.         self._hypertext = hyper
  1144.  
  1145.  
  1146.     def SetVisited(self, visited=True):
  1147.         """Sets whether an hypertext item was visited or not."""
  1148.  
  1149.         self._mask |= ULC_MASK_HYPERTEXT
  1150.         self._visited = visited
  1151.  
  1152.  
  1153.     def GetVisited(self):
  1154.         """Returns whether an hypertext item was visited or not."""
  1155.  
  1156.         return self._visited        
  1157.  
  1158.  
  1159.     def IsHyperText(self):
  1160.         """Returns whether the item is hypetext or not."""
  1161.  
  1162.         return self._hypertext
  1163.  
  1164.  
  1165.     def SetWindow(self, wnd, expand=False):
  1166.         """Sets the window associated to the item."""
  1167.  
  1168.         self._mask |= ULC_MASK_WINDOW
  1169.         self._wnd = wnd
  1170.  
  1171.         listCtrl = wnd.GetParent()
  1172.         wnd.Reparent(listCtrl._mainWin)
  1173.  
  1174.         if wnd.GetSizer():      # the window is a complex one hold by a sizer
  1175.             size = wnd.GetBestSize()
  1176.         else:                   # simple window, without sizers
  1177.             size = wnd.GetSize()
  1178.  
  1179.         # We have to bind the wx.EVT_SET_FOCUS for the associated window
  1180.         # No other solution to handle the focus changing from an item in
  1181.         # CustomTreeCtrl and the window associated to an item
  1182.         # Do better strategies exist?
  1183.         self._wnd.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)        
  1184.         self._windowsize = size
  1185.        
  1186.         # The window is enabled only if the item is enabled                
  1187.         self._wnd.Enable(self._enabled)
  1188.         self._windowenabled = self._enabled
  1189.         self._expandWin = expand
  1190.  
  1191.         listCtrl._mainWin._hasWindows = True
  1192.         listCtrl._mainWin._itemWithWindow.append(self)  
  1193.        
  1194.  
  1195.     def GetWindow(self):
  1196.         """Returns the window associated to the item."""
  1197.  
  1198.         return self._wnd        
  1199.  
  1200.  
  1201.     def DeleteWindow(self):
  1202.         """Deletes the window associated to the item (if any)."""
  1203.  
  1204.         if self._wnd:
  1205.             listCtrl = self._wnd.GetParent()            
  1206.             if self in listCtrl._itemWithWindow:
  1207.                 listCtrl._itemWithWindow.remove(self)        
  1208.             self._wnd.Destroy()
  1209.             self._wnd = None
  1210.        
  1211.  
  1212.     def GetWindowEnabled(self):
  1213.         """Returns whether the associated window is enabled or not."""
  1214.  
  1215.         if not self._wnd:
  1216.             raise Exception("\nERROR: This Item Has No Window Associated")
  1217.  
  1218.         return self._windowenabled
  1219.  
  1220.  
  1221.     def SetWindowEnabled(self, enable=True):
  1222.         """Sets whether the associated window is enabled or not."""
  1223.  
  1224.         if not self._wnd:
  1225.             raise Exception("\nERROR: This Item Has No Window Associated")
  1226.  
  1227.         self._windowenabled = enable
  1228.         self._wnd.Enable(enable)
  1229.  
  1230.  
  1231.     def GetWindowSize(self):
  1232.         """Returns the associated window size."""
  1233.        
  1234.         return self._windowsize        
  1235.  
  1236.  
  1237.     def SetCustomRenderer(self, renderer):
  1238.  
  1239.         self._mask |= ULC_MASK_RENDERER
  1240.         self._customRenderer = renderer
  1241.  
  1242.  
  1243.     def GetCustomRenderer(self):
  1244.  
  1245.         return self._customRenderer
  1246.    
  1247.  
  1248.     def SetOverFlow(self, over=True):
  1249.  
  1250.         self._mask |= ULC_MASK_OVERFLOW
  1251.         self._overFlow = over
  1252.  
  1253.  
  1254.     def GetOverFlow(self):
  1255.  
  1256.         return self._overFlow
  1257.    
  1258.        
  1259.     def Init(self):
  1260.  
  1261.         self._mask = 0
  1262.         self._itemId = 0
  1263.         self._col = 0
  1264.         self._state = 0
  1265.         self._stateMask = 0
  1266.         self._image = []
  1267.         self._data = 0
  1268.         self._pyData = None
  1269.         self._text = ""
  1270.  
  1271.         self._format = ULC_FORMAT_CENTRE
  1272.         self._width = 0
  1273.  
  1274.         self._colour = wx.Colour(0, 0, 0)
  1275.         self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  1276.  
  1277.         self._kind = 0
  1278.         self._checked = False
  1279.  
  1280.         self._hypertext = False    # indicates if the item is hypertext
  1281.         self._visited = False      # visited state for an hypertext item
  1282.  
  1283.         self._wnd = None
  1284.         self._windowenabled = False
  1285.         self._windowsize = wx.Size()
  1286.         self._isColumnShown = True
  1287.  
  1288.         self._customRenderer = None
  1289.         self._overFlow = False
  1290.         self._footerChecked = False
  1291.         self._footerFormat = ULC_FORMAT_CENTRE
  1292.         self._footerImage = []
  1293.         self._footerKind = 0
  1294.         self._footerText = ""
  1295.         self._expandWin = False
  1296.  
  1297.  
  1298.     def SetFooterKind(self, kind):
  1299.  
  1300.         self._mask |= ULC_MASK_FOOTER_KIND
  1301.         self._footerKind = kind
  1302.        
  1303.  
  1304.     def GetFooterKind(self):
  1305.  
  1306.         return self._footerKind
  1307.    
  1308.  
  1309.     def IsFooterChecked(self):
  1310.         """Returns whether the item is checked or not."""
  1311.  
  1312.         return self._footerChecked
  1313.  
  1314.  
  1315.     def CheckFooter(self, checked=True):
  1316.         """Check an item. Meaningful only for check and radio items."""
  1317.  
  1318.         self._mask |= ULC_MASK_FOOTER_CHECK
  1319.         self._footerChecked = checked
  1320.  
  1321.  
  1322.     def GetFooterFormat(self):
  1323.  
  1324.         return self._footerFormat
  1325.  
  1326.  
  1327.     def SetFooterFormat(self, format):
  1328.  
  1329.         self._mask |= ULC_MASK_FOOTER_FORMAT
  1330.         self._footerFormat = format
  1331.  
  1332.  
  1333.     def GetFooterText(self):
  1334.  
  1335.         return self._footerText
  1336.  
  1337.  
  1338.     def SetFooterText(self, text):
  1339.        
  1340.         self._mask |= ULC_MASK_FOOTER_TEXT
  1341.         self._footerText = text
  1342.  
  1343.  
  1344.     def GetFooterImage(self):
  1345.  
  1346.         return self._footerImage
  1347.  
  1348.  
  1349.     def SetFooterImage(self, image):
  1350.  
  1351.         self._mask |= ULC_MASK_FOOTER_IMAGE
  1352.         self._footerImage = to_list(image)
  1353.  
  1354.  
  1355.     def GetFooterTextColour(self):
  1356.  
  1357.         return (self.HasAttributes() and [self._attr.GetFooterTextColour()] or [wx.NullColour])[0]
  1358.  
  1359.  
  1360.     def GetFooterBackgroundColour(self):
  1361.  
  1362.         return (self.HasAttributes() and [self._attr.GetFooterBackgroundColour()] or [wx.NullColour])[0]
  1363.  
  1364.  
  1365.     def GetFooterFont(self):
  1366.  
  1367.         return (self.HasAttributes() and [self._attr.GetFooterFont()] or [wx.NullFont])[0]
  1368.  
  1369.  
  1370.     def SetFooterAlign(self, align):
  1371.  
  1372.         self._mask |= ULC_MASK_FOOTER_FORMAT
  1373.         self._footerFormat = align
  1374.  
  1375.  
  1376.     def GetFooterAlign(self):
  1377.  
  1378.         return self._footerFormat
  1379.    
  1380.  
  1381.     def OnSetFocus(self, event):
  1382.         """Handles the wx.EVT_SET_FOCUS event for the associated window."""
  1383.  
  1384.         listCtrl = self._wnd.GetParent()
  1385.         select = listCtrl.GetItemState(self._itemId, ULC_STATE_SELECTED)
  1386.  
  1387.         # If the window is associated to an item that currently is selected
  1388.         # (has focus) we don't kill the focus. Otherwise we do it.
  1389.         if not select:
  1390.             listCtrl._hasFocus = False
  1391.         else:
  1392.             listCtrl._hasFocus = True
  1393.  
  1394.         listCtrl.SetFocus()
  1395.            
  1396.         event.Skip()
  1397.  
  1398. # ----------------------------------------------------------------------------
  1399. # ListEvent - the event class for the UltimateListCtrl notifications
  1400. # ----------------------------------------------------------------------------
  1401.  
  1402. class CommandListEvent(wx.PyCommandEvent):
  1403.  
  1404.     def __init__(self, commandTypeOrEvent=None, winid=0):
  1405.  
  1406.         if type(commandTypeOrEvent) == types.IntType:
  1407.  
  1408.             wx.PyCommandEvent.__init__(self, commandTypeOrEvent, winid)
  1409.  
  1410.             self.m_code = 0
  1411.             self.m_oldItemIndex = 0
  1412.             self.m_itemIndex = 0
  1413.             self.m_col = 0
  1414.             self.m_pointDrag = wx.Point()
  1415.             self.m_item = UltimateListItem()
  1416.             self.m_editCancelled = False
  1417.  
  1418.         else:
  1419.  
  1420.             wx.PyCommandEvent.__init__(self, commandTypeOrEvent.GetEventType(), commandTypeOrEvent.GetId())
  1421.             self.m_code = commandTypeOrEvent.m_code
  1422.             self.m_oldItemIndex = commandTypeOrEvent.m_oldItemIndex
  1423.             self.m_itemIndex = commandTypeOrEvent.m_itemIndex
  1424.             self.m_col = commandTypeOrEvent.m_col
  1425.             self.m_pointDrag = commandTypeOrEvent.m_pointDrag
  1426.             self.m_item = commandTypeOrEvent.m_item
  1427.             self.m_editCancelled = commandTypeOrEvent.m_editCancelled
  1428.  
  1429.  
  1430.     def GetKeyCode(self):
  1431.  
  1432.         return self.m_code
  1433.  
  1434.  
  1435.     def GetIndex(self):
  1436.  
  1437.         return self.m_itemIndex
  1438.  
  1439.  
  1440.     def GetColumn(self):
  1441.  
  1442.         return self.m_col
  1443.  
  1444.  
  1445.     def GetPoint(self):
  1446.  
  1447.         return self.m_pointDrag
  1448.  
  1449.  
  1450.     def GetLabel(self):
  1451.  
  1452.         return self.m_item._text
  1453.  
  1454.  
  1455.     def GetText(self):
  1456.  
  1457.         return self.m_item._text
  1458.  
  1459.  
  1460.     def GetImage(self):
  1461.  
  1462.         return self.m_item._image
  1463.  
  1464.  
  1465.     def GetData(self):
  1466.  
  1467.         return self.m_item._data
  1468.  
  1469.  
  1470.     def GetMask(self):
  1471.  
  1472.         return self.m_item._mask
  1473.  
  1474.  
  1475.     def GetItem(self):
  1476.  
  1477.         return self.m_item
  1478.  
  1479.  
  1480.     # for wxEVT_COMMAND_LIST_CACHE_HINT only
  1481.     def GetCacheFrom(self):
  1482.  
  1483.         return self.m_oldItemIndex
  1484.  
  1485.  
  1486.     def GetCacheTo(self):
  1487.  
  1488.         return self.m_itemIndex
  1489.  
  1490.  
  1491.     # was label editing canceled? (for wxEVT_COMMAND_LIST_END_LABEL_EDIT only)
  1492.     def IsEditCancelled(self):
  1493.  
  1494.         return self.m_editCancelled
  1495.  
  1496.  
  1497.     def SetEditCanceled(self, editCancelled):
  1498.  
  1499.         self.m_editCancelled = editCancelled
  1500.  
  1501.  
  1502.     def Clone(self):
  1503.  
  1504.         return UltimateListEvent(self)
  1505.  
  1506.  
  1507.  
  1508. # ----------------------------------------------------------------------------
  1509. # TreeEvent is a special class for all events associated with list controls
  1510. #
  1511. # NB: note that not all accessors make sense for all events, see the event
  1512. #     descriptions below
  1513. # ----------------------------------------------------------------------------
  1514.  
  1515. class UltimateListEvent(CommandListEvent):
  1516.    
  1517.     def __init__(self, commandTypeOrEvent=None, winid=0):
  1518.         """
  1519.        Default class constructor.
  1520.        For internal use: do not call it in your code!
  1521.        """
  1522.  
  1523.         CommandListEvent.__init__(self, commandTypeOrEvent, winid)
  1524.  
  1525.         if type(commandTypeOrEvent) == types.IntType:
  1526.             self.notify = wx.NotifyEvent(commandTypeOrEvent, winid)
  1527.         else:
  1528.             self.notify = wx.NotifyEvent(commandTypeOrEvent.GetEventType(), commandTypeOrEvent.GetId())
  1529.  
  1530.        
  1531.     def GetNotifyEvent(self):
  1532.         """Returns the actual wx.NotifyEvent."""
  1533.        
  1534.         return self.notify
  1535.  
  1536.  
  1537.     def IsAllowed(self):
  1538.         """Returns whether the event is allowed or not."""
  1539.  
  1540.         return self.notify.IsAllowed()
  1541.  
  1542.  
  1543.     def Veto(self):
  1544.         """Vetos the event."""
  1545.  
  1546.         self.notify.Veto()
  1547.  
  1548.  
  1549.     def Allow(self):
  1550.         """The event is allowed."""
  1551.  
  1552.         self.notify.Allow()
  1553.  
  1554.        
  1555. # ============================================================================
  1556. # private classes
  1557. # ============================================================================
  1558.  
  1559. #-----------------------------------------------------------------------------
  1560. #  ColWidthInfo (internal)
  1561. #-----------------------------------------------------------------------------
  1562.  
  1563. class ColWidthInfo(object):
  1564.  
  1565.     def __init__(self, w=0, needsUpdate=True):
  1566.  
  1567.         self._nMaxWidth = w
  1568.         self._bNeedsUpdate = needsUpdate
  1569.  
  1570.  
  1571. #-----------------------------------------------------------------------------
  1572. #  UltimateListItemData (internal)
  1573. #-----------------------------------------------------------------------------
  1574.  
  1575. class UltimateListItemData(object):
  1576.  
  1577.     def __init__(self, owner):
  1578.  
  1579.  
  1580.         # the list ctrl we are in
  1581.         self._owner = owner
  1582.         self.Init()
  1583.  
  1584.         # the item coordinates are not used in report mode, instead this pointer
  1585.         # is None and the owner window is used to retrieve the item position and
  1586.         # size
  1587.  
  1588.         if owner.InReportView():
  1589.             self._rect = None
  1590.         else:
  1591.             self._rect = wx.Rect()
  1592.  
  1593.  
  1594.     def SetImage(self, image):
  1595.  
  1596.         self._image = to_list(image)
  1597.  
  1598.  
  1599.     def SetData(self, data):
  1600.  
  1601.         self._data = data
  1602.  
  1603.  
  1604.     def HasText(self):
  1605.  
  1606.         return self._text != ""
  1607.  
  1608.  
  1609.     def GetText(self):
  1610.  
  1611.         return self._text
  1612.  
  1613.  
  1614.     def GetBackgroundColour(self):
  1615.  
  1616.         return self._backColour
  1617.    
  1618.  
  1619.     def GetColour(self):
  1620.  
  1621.         return self._colour
  1622.  
  1623.  
  1624.     def GetFont(self):
  1625.  
  1626.         return (self._hasFont and [self._font] or [wx.NullFont])[0]
  1627.  
  1628.  
  1629.     def SetText(self, text):
  1630.  
  1631.         self._text = text
  1632.  
  1633.  
  1634.     def SetColour(self, colour):
  1635.  
  1636.         if colour == wx.NullColour:
  1637.             self._hasColour = False
  1638.             del self._colour
  1639.             return
  1640.        
  1641.         self._hasColour = True
  1642.         self._colour = colour
  1643.  
  1644.  
  1645.     def SetFont(self, font):
  1646.  
  1647.         if font == wx.NullFont:
  1648.             self._hasFont = False
  1649.             del self._font
  1650.             return
  1651.        
  1652.         self._hasFont = True
  1653.         self._font = font
  1654.  
  1655.  
  1656.     def SetBackgroundColour(self, colour):
  1657.  
  1658.         if colour == wx.NullColour:
  1659.             self._hasBackColour = False
  1660.             del self._backColour
  1661.             return
  1662.        
  1663.         self._hasBackColour = True
  1664.         self._backColour = colour
  1665.        
  1666.  
  1667.     # we can't use empty string for measuring the string width/height, so
  1668.     # always return something
  1669.     def GetTextForMeasuring(self):
  1670.  
  1671.         s = self.GetText()
  1672.         if not s.strip():
  1673.             s = 'H'
  1674.  
  1675.         return s
  1676.  
  1677.  
  1678.     def GetImage(self):
  1679.  
  1680.         return self._image
  1681.  
  1682.  
  1683.     def HasImage(self):
  1684.  
  1685.         return len(self._image) > 0
  1686.  
  1687.  
  1688.     def SetKind(self, kind):
  1689.  
  1690.         self._kind = kind
  1691.        
  1692.  
  1693.     def GetKind(self):
  1694.  
  1695.         return self._kind
  1696.    
  1697.  
  1698.     def IsChecked(self):
  1699.         """Returns whether the item is checked or not."""
  1700.  
  1701.         return self._checked
  1702.  
  1703.  
  1704.     def Check(self, checked=True):
  1705.         """Check an item. Meaningful only for check and radio items."""
  1706.  
  1707.         self._checked = checked
  1708.        
  1709.  
  1710.     def SetHyperText(self, hyper=True):
  1711.         """Sets whether the item is hypertext or not."""
  1712.        
  1713.         self._hypertext = hyper
  1714.  
  1715.  
  1716.     def SetVisited(self, visited=True):
  1717.         """Sets whether an hypertext item was visited or not."""
  1718.  
  1719.         self._visited = visited
  1720.  
  1721.  
  1722.     def GetVisited(self):
  1723.         """Returns whether an hypertext item was visited or not."""
  1724.  
  1725.         return self._visited        
  1726.  
  1727.  
  1728.     def IsHyperText(self):
  1729.         """Returns whether the item is hypetext or not."""
  1730.  
  1731.         return self._hypertext
  1732.  
  1733.  
  1734.     def SetWindow(self, wnd, expand=False):
  1735.         """Sets the window associated to the item."""
  1736.  
  1737.         self._mask |= ULC_MASK_WINDOW
  1738.         self._wnd = wnd
  1739.  
  1740.         if wnd.GetSizer():      # the window is a complex one hold by a sizer
  1741.             size = wnd.GetBestSize()
  1742.         else:                   # simple window, without sizers
  1743.             size = wnd.GetSize()
  1744.  
  1745.         # We have to bind the wx.EVT_SET_FOCUS for the associated window
  1746.         # No other solution to handle the focus changing from an item in
  1747.         # CustomTreeCtrl and the window associated to an item
  1748.         # Do better strategies exist?
  1749.         self._windowsize = size
  1750.        
  1751.         # The window is enabled only if the item is enabled                
  1752.         self._wnd.Enable(self._enabled)
  1753.         self._windowenabled = self._enabled
  1754.         self._expandWin = expand
  1755.  
  1756.  
  1757.     def GetWindow(self):
  1758.         """Returns the window associated to the item."""
  1759.  
  1760.         return self._wnd        
  1761.  
  1762.  
  1763.     def DeleteWindow(self):
  1764.         """Deletes the window associated to the item (if any)."""
  1765.  
  1766.         if self._wnd:
  1767.             self._wnd.Destroy()
  1768.             self._wnd = None
  1769.        
  1770.  
  1771.     def GetWindowEnabled(self):
  1772.         """Returns whether the associated window is enabled or not."""
  1773.  
  1774.         if not self._wnd:
  1775.             raise Exception("\nERROR: This Item Has No Window Associated")
  1776.  
  1777.         return self._windowenabled
  1778.  
  1779.  
  1780.     def SetWindowEnabled(self, enable=True):
  1781.         """Sets whether the associated window is enabled or not."""
  1782.  
  1783.         if not self._wnd:
  1784.             raise Exception("\nERROR: This Item Has No Window Associated")
  1785.  
  1786.         self._windowenabled = enable
  1787.         self._wnd.Enable(enable)
  1788.  
  1789.  
  1790.     def GetWindowSize(self):
  1791.         """Returns the associated window size."""
  1792.        
  1793.         return self._windowsize        
  1794.  
  1795.    
  1796.     def SetAttr(self, attr):
  1797.  
  1798.         self._attr = attr
  1799.  
  1800.  
  1801.     def GetAttr(self):
  1802.  
  1803.         return self._attr
  1804.  
  1805.  
  1806.     def HasColour(self):
  1807.  
  1808.         return self._hasColour
  1809.  
  1810.  
  1811.     def HasFont(self):
  1812.  
  1813.         return self._hasFont
  1814.  
  1815.  
  1816.     def HasBackgroundColour(self):
  1817.  
  1818.         return self._hasBackColour
  1819.  
  1820.  
  1821.     def SetCustomRenderer(self, renderer):
  1822.  
  1823.         self._mask |= ULC_MASK_RENDERER
  1824.         self._customRenderer = renderer
  1825.  
  1826.  
  1827.     def GetCustomRenderer(self):
  1828.  
  1829.         return self._customRenderer
  1830.    
  1831.  
  1832.     def SetOverFlow(self, over=True):
  1833.  
  1834.         self._mask |= ULC_MASK_OVERFLOW
  1835.         self._overFlow = over
  1836.  
  1837.  
  1838.     def GetOverFlow(self):
  1839.  
  1840.         return self._overFlow
  1841.    
  1842.  
  1843.     def Init(self):
  1844.  
  1845.         # the item image or -1
  1846.         self._image = []
  1847.         # user data associated with the item
  1848.         self._data = 0
  1849.         self._pyData = None
  1850.         self._colour = wx.Colour(0, 0, 0)
  1851.         self._hasColour = False
  1852.         self._hasFont = False
  1853.         self._hasBackColour = False
  1854.         self._text = ""
  1855.  
  1856.         # kind = 0: normal item
  1857.         # kind = 1: checkbox-type item
  1858.         self._kind = 0
  1859.         self._checked = False
  1860.  
  1861.         self._enabled = True
  1862.        
  1863.         # custom attributes or None
  1864.         self._attr = None
  1865.  
  1866.         self._hypertext = False
  1867.         self._visited = False
  1868.  
  1869.         self._wnd = None
  1870.         self._windowenabled = True
  1871.         self._windowsize = wx.Size()
  1872.         self._isColumnShown = True
  1873.         self._customRenderer = None
  1874.         self._overFlow = False
  1875.         self._expandWin = False
  1876.  
  1877.  
  1878.     def SetItem(self, info):
  1879.  
  1880.         if info._mask & ULC_MASK_TEXT:
  1881.             CheckVariableRowHeight(self._owner, info._text)
  1882.             self.SetText(info._text)
  1883.  
  1884.         if info._mask & ULC_MASK_KIND:
  1885.             self._kind = info._kind
  1886.  
  1887.         if info._mask & ULC_MASK_CHECK:
  1888.             self._checked = info._checked
  1889.  
  1890.         if info._mask & ULC_MASK_ENABLE:
  1891.             self._enabled = info._enabled
  1892.            
  1893.         if info._mask & ULC_MASK_IMAGE:
  1894.             self._image = info._image[:]
  1895.  
  1896.         if info._mask & ULC_MASK_DATA:
  1897.             self._data = info._data
  1898.  
  1899.         if info._mask & ULC_MASK_PYDATA:
  1900.             self._pyData = info._pyData
  1901.        
  1902.         if info._mask & ULC_MASK_HYPERTEXT:
  1903.             self._hypertext = info._hypertext
  1904.             self._visited = info._visited
  1905.            
  1906.         if info._mask & ULC_MASK_FONTCOLOUR:
  1907.             self.SetColour(info.GetTextColour())
  1908.  
  1909.         if info._mask & ULC_MASK_FONT:
  1910.             self.SetFont(info.GetFont())
  1911.  
  1912.         if info._mask & ULC_MASK_BACKCOLOUR:
  1913.             self.SetBackgroundColour(info.GetBackgroundColour())
  1914.  
  1915.         if info._mask & ULC_MASK_WINDOW:
  1916.             self._wnd = info._wnd
  1917.             self._windowenabled = info._windowenabled
  1918.             self._windowsize = info._windowsize
  1919.             self._expandWin = info._expandWin
  1920.  
  1921.         if info._mask & ULC_MASK_SHOWN:
  1922.             self._isColumnShown = info._isColumnShown
  1923.  
  1924.         if info._mask & ULC_MASK_RENDERER:
  1925.             self._customRenderer = info._customRenderer
  1926.  
  1927.         if info._mask & ULC_MASK_OVERFLOW:
  1928.             self._overFlow = info._overFlow
  1929.            
  1930.         if info.HasAttributes():
  1931.  
  1932.             if self._attr:
  1933.                 self._attr = info.GetAttributes()
  1934.             else:
  1935.                 self._attr = UltimateListItemAttr(info.GetTextColour(), info.GetBackgroundColour(),
  1936.                                                   info.GetFont(), info.IsEnabled(), info.GetFooterTextColour(),
  1937.                                                   info.GetFooterBackgroundColour(), info.GetFooterFont())
  1938.  
  1939.         if self._rect:
  1940.  
  1941.             self._rect.x = -1
  1942.             self._rect.y = -1
  1943.             self._rect.height = 0
  1944.             self._rect.width = info._width
  1945.  
  1946.  
  1947.     def SetPosition(self, x, y):
  1948.  
  1949.         self._rect.x = x
  1950.         self._rect.y = y
  1951.  
  1952.  
  1953.     def SetSize(self, width, height):
  1954.  
  1955.         if width != -1:
  1956.             self._rect.width = width
  1957.         if height != -1:
  1958.             self._rect.height = height
  1959.  
  1960.  
  1961.     def IsHit(self, x, y):
  1962.  
  1963.         return wx.Rect(self.GetX(), self.GetY(), self.GetWidth(), self.GetHeight()).Contains((x, y))
  1964.  
  1965.  
  1966.     def GetX(self):
  1967.  
  1968.         return self._rect.x
  1969.  
  1970.  
  1971.     def GetY(self):
  1972.  
  1973.         return self._rect.y
  1974.  
  1975.  
  1976.     def GetWidth(self):
  1977.  
  1978.         return self._rect.width
  1979.  
  1980.  
  1981.     def GetHeight(self):
  1982.  
  1983.         return self._rect.height
  1984.  
  1985.  
  1986.     def GetItem(self, info):
  1987.  
  1988.         mask = info._mask
  1989.         if not mask:
  1990.             # by default, get everything for backwards compatibility
  1991.             mask = -1
  1992.  
  1993.         if mask & ULC_MASK_TEXT:
  1994.             info._text = self._text
  1995.         if mask & ULC_MASK_IMAGE:
  1996.             info._image = self._image[:]
  1997.         if mask & ULC_MASK_DATA:
  1998.             info._data = self._data
  1999.         if mask & ULC_MASK_PYDATA:
  2000.             info._pyData = self._pyData
  2001.         if info._mask & ULC_MASK_FONT:
  2002.             info.SetFont(self.GetFont())
  2003.         if mask & ULC_MASK_KIND:
  2004.             info._kind = self._kind
  2005.         if mask & ULC_MASK_CHECK:
  2006.             info._checked = self._checked
  2007.         if mask & ULC_MASK_ENABLE:
  2008.             info._enabled = self._enabled
  2009.         if mask & ULC_MASK_HYPERTEXT:
  2010.             info._hypertext = self._hypertext
  2011.             info._visited = self._visited
  2012.         if mask & ULC_MASK_WINDOW:
  2013.             info._wnd = self._wnd
  2014.             info._windowenabled = self._windowenabled
  2015.             info._windowsize = self._windowsize
  2016.             info._expandWin = self._expandWin
  2017.         if mask & ULC_MASK_SHOWN:
  2018.             info._isColumnShown = self._isColumnShown
  2019.         if mask & ULC_MASK_RENDERER:
  2020.             info._customRenderer = self._customRenderer
  2021.         if mask & ULC_MASK_OVERFLOW:
  2022.             info._overFlow = self._overFlow
  2023.  
  2024.         if self._attr:
  2025.  
  2026.             if self._attr.HasTextColour():
  2027.                 info.SetTextColour(self._attr.GetTextColour())
  2028.             if self._attr.HasBackgroundColour():
  2029.                 info.SetBackgroundColour(self._attr.GetBackgroundColour())
  2030.             if self._attr.HasFont():
  2031.                 info.SetFont(self._attr.GetFont())
  2032.             info.Enable(self._attr.IsEnabled())
  2033.  
  2034.         return info
  2035.  
  2036.  
  2037.     def IsEnabled(self):
  2038.  
  2039.         return self._enabled
  2040.  
  2041.  
  2042.     def Enable(self, enable=True):
  2043.  
  2044.         self._enabled = enable        
  2045.        
  2046.  
  2047. #-----------------------------------------------------------------------------
  2048. #  UltimateListHeaderData (internal)
  2049. #-----------------------------------------------------------------------------
  2050.  
  2051. class UltimateListHeaderData(object):
  2052.  
  2053.     def __init__(self, item=None):
  2054.  
  2055.         self.Init()
  2056.  
  2057.         if item:
  2058.             self.SetItem(item)
  2059.  
  2060.  
  2061.     def HasText(self):
  2062.  
  2063.         return self._text != ""
  2064.  
  2065.  
  2066.     def GetText(self):
  2067.  
  2068.         return self._text
  2069.  
  2070.  
  2071.     def SetText(self, text):
  2072.  
  2073.         self._text = text
  2074.  
  2075.        
  2076.     def GetFont(self):
  2077.  
  2078.         return self._font
  2079.    
  2080.  
  2081.     def Init(self):
  2082.  
  2083.         self._mask = 0
  2084.         self._image = []
  2085.         self._format = 0
  2086.         self._width = 0
  2087.         self._xpos = 0
  2088.         self._ypos = 0
  2089.         self._height = 0
  2090.         self._text = ""
  2091.         self._kind = 0
  2092.         self._checked = False
  2093.         self._font = wx.NullFont
  2094.         self._state = 0
  2095.         self._isColumnShown = True
  2096.  
  2097.         self._footerImage = []
  2098.         self._footerFormat = 0
  2099.         self._footerText = ""
  2100.         self._footerKind = 0
  2101.         self._footerChecked = False
  2102.         self._footerFont = wx.NullFont
  2103.        
  2104.  
  2105.     def SetItem(self, item):
  2106.  
  2107.         self._mask = item._mask
  2108.  
  2109.         if self._mask & ULC_MASK_TEXT:
  2110.             self._text = item._text
  2111.  
  2112.         if self._mask & ULC_MASK_FOOTER_TEXT:
  2113.             self._footerText = item._footerText
  2114.  
  2115.         if self._mask & ULC_MASK_IMAGE:
  2116.             self._image = item._image[:]
  2117.  
  2118.         if self._mask & ULC_MASK_FOOTER_IMAGE:
  2119.             self._footerImage = item._footerImage[:]
  2120.  
  2121.         if self._mask & ULC_MASK_FORMAT:
  2122.             self._format = item._format
  2123.  
  2124.         if self._mask & ULC_MASK_FOOTER_FORMAT:
  2125.             self._footerFormat = item._footerFormat
  2126.  
  2127.         if self._mask & ULC_MASK_WIDTH:
  2128.             self.SetWidth(item._width)
  2129.  
  2130.         if self._mask & ULC_MASK_FONT:
  2131.             self._font = item._font
  2132.  
  2133.         if self._mask & ULC_MASK_FOOTER_FONT:
  2134.             self._footerFont = item._footerFont
  2135.            
  2136.         if self._mask & ULC_MASK_FOOTER_KIND:
  2137.             self._footerKind = item._footerKind
  2138.             self._footerChecked = item._footerChecked
  2139.  
  2140.         if self._mask & ULC_MASK_KIND:
  2141.             self._kind = item._kind
  2142.             self._checked = item._checked
  2143.  
  2144.         if self._mask & ULC_MASK_CHECK:
  2145.             self._kind = item._kind
  2146.             self._checked = item._checked
  2147.  
  2148.         if self._mask & ULC_MASK_FOOTER_CHECK:
  2149.             self._footerKind = item._footerKind
  2150.             self._footerChecked = item._footerChecked
  2151.  
  2152.         if self._mask & ULC_MASK_STATE:
  2153.             self.SetState(item._state)
  2154.  
  2155.         if self._mask & ULC_MASK_SHOWN:
  2156.             self._isColumnShown = item._isColumnShown
  2157.            
  2158.  
  2159.     def SetState(self, flag):
  2160.  
  2161.         self._state = flag
  2162.  
  2163.  
  2164.     def SetPosition(self, x, y):
  2165.  
  2166.         self._xpos = x
  2167.         self._ypos = y
  2168.  
  2169.  
  2170.     def SetHeight(self, h):
  2171.  
  2172.         self._height = h
  2173.  
  2174.  
  2175.     def SetWidth(self, w):
  2176.  
  2177.         self._width = w
  2178.  
  2179.         if self._width < 0:
  2180.             self._width = WIDTH_COL_DEFAULT
  2181.         elif self._width < WIDTH_COL_MIN:
  2182.             self._width = WIDTH_COL_MIN
  2183.  
  2184.  
  2185.     def SetFormat(self, format):
  2186.  
  2187.         self._format = format
  2188.  
  2189.  
  2190.     def SetFooterFormat(self, format):
  2191.  
  2192.         self._footerFormat = format
  2193.        
  2194.  
  2195.     def HasImage(self):
  2196.  
  2197.         return len(self._image) > 0
  2198.  
  2199.  
  2200.     def HasFooterImage(self):
  2201.  
  2202.         return len(self._footerImage) > 0
  2203.    
  2204.  
  2205.     def IsHit(self, x, y):
  2206.  
  2207.         return ((x >= self._xpos) and (x <= self._xpos+self._width) and (y >= self._ypos) and (y <= self._ypos+self._height))
  2208.  
  2209.  
  2210.     def GetItem(self, item):
  2211.  
  2212.         item._mask = self._mask
  2213.         item._text = self._text
  2214.         item._image = self._image[:]
  2215.         item._format = self._format
  2216.         item._width = self._width
  2217.         if self._font:
  2218.             item._font = self._font
  2219.             item.Attributes().SetFont(self._font)
  2220.  
  2221.         item._kind = self._kind
  2222.         item._checked = self._checked
  2223.         item._state = self._state
  2224.         item._isColumnShown = self._isColumnShown
  2225.  
  2226.         item._footerImage = self._footerImage
  2227.         item._footerFormat = self._footerFormat
  2228.         item._footerText = self._footerText
  2229.         item._footerKind = self._footerKind
  2230.         item._footerChecked = self._footerChecked
  2231.         item._footerFont = self._footerFont
  2232.  
  2233.         return item
  2234.  
  2235.  
  2236.     def GetState(self):
  2237.  
  2238.         return self._state
  2239.  
  2240.    
  2241.     def GetImage(self):
  2242.  
  2243.         return self._image
  2244.  
  2245.  
  2246.     def GetFooterImage(self):
  2247.  
  2248.         return self._footerImage
  2249.    
  2250.  
  2251.     def GetWidth(self):
  2252.  
  2253.         return self._width
  2254.  
  2255.  
  2256.     def GetFormat(self):
  2257.  
  2258.         return self._format
  2259.  
  2260.  
  2261.     def GetFooterFormat(self):
  2262.  
  2263.         return self._footerFormat
  2264.  
  2265.  
  2266.     def SetFont(self, font):
  2267.  
  2268.         self._font = font
  2269.        
  2270.  
  2271.     def SetFooterFont(self, font):
  2272.  
  2273.         self._footerFont = font
  2274.  
  2275.  
  2276.     def SetKind(self, kind):
  2277.  
  2278.         self._kind = kind
  2279.        
  2280.  
  2281.     def SetFooterKind(self, kind):
  2282.  
  2283.         self._footerKind = kind
  2284.  
  2285.  
  2286.     def GetKind(self):
  2287.  
  2288.         return self._kind
  2289.    
  2290.  
  2291.     def GetFooterKind(self):
  2292.  
  2293.         return self._footerKind
  2294.  
  2295.  
  2296.     def IsChecked(self):
  2297.         """Returns whether the item is checked or not."""
  2298.  
  2299.         return self._checked
  2300.  
  2301.  
  2302.     def Check(self, checked=True):
  2303.         """Check an item. Meaningful only for check and radio items."""
  2304.  
  2305.         self._checked = checked
  2306.  
  2307.  
  2308.     def IsFooterChecked(self):
  2309.  
  2310.         return self._footerChecked
  2311.  
  2312.  
  2313.     def CheckFooter(self, check=True):
  2314.  
  2315.         self._footerChecked = check
  2316.            
  2317.  
  2318. #-----------------------------------------------------------------------------
  2319. #  GeometryInfo (internal)
  2320. #  this is not used in report view
  2321. #-----------------------------------------------------------------------------
  2322.  
  2323. class GeometryInfo(object):
  2324.  
  2325.     def __init__(self):
  2326.  
  2327.         # total item rect
  2328.         self._rectAll = wx.Rect()
  2329.  
  2330.         # label only
  2331.         self._rectLabel = wx.Rect()
  2332.  
  2333.         # icon only
  2334.         self._rectIcon = wx.Rect()
  2335.  
  2336.         # the part to be highlighted
  2337.         self._rectHighlight = wx.Rect()
  2338.  
  2339.         # the checkbox/radiobutton rect (if any)
  2340.         self._rectCheck = wx.Rect()
  2341.  
  2342.     # extend all our rects to be centered inside the one of given width
  2343.     def ExtendWidth(self, w):
  2344.  
  2345.         if self._rectAll.width > w:
  2346.             raise Exception("width can only be increased")
  2347.  
  2348.         self._rectAll.width = w
  2349.         self._rectLabel.x = self._rectAll.x + (w - self._rectLabel.width)/2
  2350.         self._rectIcon.x = self._rectAll.x + (w - self._rectIcon.width)/2
  2351.         self._rectHighlight.x = self._rectAll.x + (w - self._rectHighlight.width)/2
  2352.  
  2353.  
  2354. #-----------------------------------------------------------------------------
  2355. #  UltimateListLineData (internal)
  2356. #-----------------------------------------------------------------------------
  2357.  
  2358. class UltimateListLineData(object):
  2359.  
  2360.     def __init__(self, owner):
  2361.  
  2362.         # the list of subitems: only may have more than one item in report mode
  2363.         self._items = []
  2364.  
  2365.  
  2366.         # is this item selected? [NB: not used in virtual mode]
  2367.         self._highlighted = False
  2368.  
  2369.         # back pointer to the list ctrl
  2370.         self._owner = owner
  2371.         self._height = self._width = self._x = self._y = -1
  2372.  
  2373.         if self.InReportView():
  2374.  
  2375.             self._gi = None
  2376.  
  2377.         else:
  2378.  
  2379.             self._gi = GeometryInfo()
  2380.  
  2381.         if self.GetMode() in [ULC_REPORT, ULC_TILE] or self.HasExtraMode(ULC_HEADER_IN_ALL_VIEWS):
  2382.             self.InitItems(self._owner.GetColumnCount())
  2383.         else:
  2384.             self.InitItems(1)
  2385.  
  2386.  
  2387.     def GetHeight(self):
  2388.  
  2389.         return self._height
  2390.  
  2391.  
  2392.     def SetHeight(self, height):
  2393.  
  2394.         self._height = height
  2395.  
  2396.  
  2397.     def GetWidth(self):
  2398.  
  2399.         return self._width
  2400.  
  2401.  
  2402.     def SetWidth(self, width):
  2403.  
  2404.         self._width = width
  2405.  
  2406.  
  2407.     def GetX(self):
  2408.  
  2409.         return self._x
  2410.  
  2411.  
  2412.     def SetX(self, x):
  2413.  
  2414.         self._x = x      
  2415.  
  2416.  
  2417.     def GetY(self):
  2418.  
  2419.         return self._y        
  2420.  
  2421.  
  2422.     def SetY(self, y):
  2423.  
  2424.         self._y = y
  2425.  
  2426.  
  2427.     def ResetDimensions(self):
  2428.  
  2429.         self._height = self._width = self._x = self._y = -1        
  2430.  
  2431.    
  2432.     def HasImage(self):
  2433.  
  2434.         return self.GetImage() != []
  2435.  
  2436.  
  2437.     def HasText(self):
  2438.  
  2439.         return self.GetText(0) != ""
  2440.  
  2441.  
  2442.     def IsHighlighted(self):
  2443.  
  2444.         if self.IsVirtual():
  2445.             raise Exception("unexpected call to IsHighlighted")
  2446.  
  2447.         return self._highlighted
  2448.  
  2449.  
  2450.     def GetMode(self):
  2451.  
  2452.         return self._owner.GetListCtrl().GetWindowStyleFlag() & ULC_MASK_TYPE
  2453.  
  2454.  
  2455.     def HasExtraMode(self, mode):
  2456.  
  2457.         return self._owner.GetListCtrl().HasExtraFlag(mode)
  2458.        
  2459.  
  2460.     def InReportView(self):
  2461.  
  2462.         return self._owner.HasFlag(ULC_REPORT)
  2463.  
  2464.  
  2465.     def IsVirtual(self):
  2466.  
  2467.         return self._owner.IsVirtual()
  2468.  
  2469.  
  2470.     def CalculateSize(self, dc, spacing):
  2471.  
  2472.         item = self._items[0]
  2473.         mode = self.GetMode()
  2474.  
  2475.         if mode in [ULC_ICON, ULC_SMALL_ICON]:
  2476.  
  2477.             self._gi._rectAll.width = spacing
  2478.  
  2479.             s = item.GetText()
  2480.  
  2481.             if not s:
  2482.  
  2483.                 lh = -1
  2484.                 self._gi._rectLabel.width = 0
  2485.                 self._gi._rectLabel.height = 0
  2486.  
  2487.             else:
  2488.  
  2489.                 lw, lh = dc.GetTextExtent(s)
  2490.                 lw += EXTRA_WIDTH
  2491.                 lh += EXTRA_HEIGHT
  2492.  
  2493.                 self._gi._rectAll.height = spacing + lh
  2494.  
  2495.                 if lw > spacing:
  2496.                     self._gi._rectAll.width = lw
  2497.  
  2498.                 self._gi._rectLabel.width = lw
  2499.                 self._gi._rectLabel.height = lh
  2500.  
  2501.             if item.HasImage():
  2502.  
  2503.                 w, h = self._owner.GetImageSize(item.GetImage())
  2504.                 self._gi._rectIcon.width = w + 8
  2505.                 self._gi._rectIcon.height = h + 8
  2506.  
  2507.                 if self._gi._rectIcon.width > self._gi._rectAll.width:
  2508.                     self._gi._rectAll.width = self._gi._rectIcon.width
  2509.                 if self._gi._rectIcon.height + lh > self._gi._rectAll.height - 4:
  2510.                     self._gi._rectAll.height = self._gi._rectIcon.height + lh + 4
  2511.  
  2512.             if item.HasText():
  2513.  
  2514.                 self._gi._rectHighlight.width = self._gi._rectLabel.width
  2515.                 self._gi._rectHighlight.height = self._gi._rectLabel.height
  2516.  
  2517.             else:
  2518.  
  2519.                 self._gi._rectHighlight.width = self._gi._rectIcon.width
  2520.                 self._gi._rectHighlight.height = self._gi._rectIcon.height
  2521.  
  2522.         elif mode == ULC_LIST:
  2523.  
  2524.             s = item.GetTextForMeasuring()
  2525.  
  2526.             lw, lh = dc.GetTextExtent(s)
  2527.             lw += EXTRA_WIDTH
  2528.             lh += EXTRA_HEIGHT
  2529.  
  2530.             self._gi._rectLabel.width = lw
  2531.             self._gi._rectLabel.height = lh
  2532.  
  2533.             self._gi._rectAll.width = lw
  2534.             self._gi._rectAll.height = lh
  2535.  
  2536.             if item.HasImage():
  2537.  
  2538.                 w, h = self._owner.GetImageSize(item.GetImage())
  2539.                 h += 4
  2540.                 self._gi._rectIcon.width = w
  2541.                 self._gi._rectIcon.height = h
  2542.  
  2543.                 self._gi._rectAll.width += 4 + w
  2544.  
  2545.                 if h > self._gi._rectAll.height:
  2546.                     self._gi._rectAll.height = h
  2547.  
  2548.             if item.GetKind() in [1, 2]:
  2549.  
  2550.                 w, h = self._owner.GetCheckboxImageSize()
  2551.                 h += 4
  2552.                 self._gi._rectCheck.width = w
  2553.                 self._gi._rectCheck.height = h
  2554.  
  2555.                 self._gi._rectAll.width += 4 + w
  2556.                
  2557.                 if h > self._gi._rectAll.height:
  2558.                     self._gi._rectAll.height = h
  2559.                
  2560.             self._gi._rectHighlight.width = self._gi._rectAll.width
  2561.             self._gi._rectHighlight.height = self._gi._rectAll.height
  2562.  
  2563.         elif mode == ULC_REPORT:
  2564.             raise Exception("unexpected call to SetSize")
  2565.  
  2566.         else:
  2567.             raise Exception("unknown mode")
  2568.  
  2569.  
  2570.     def SetPosition(self, x, y, spacing):
  2571.  
  2572.         item = self._items[0]
  2573.         mode = self.GetMode()
  2574.  
  2575.         if mode in [ULC_ICON, ULC_SMALL_ICON]:
  2576.  
  2577.             self._gi._rectAll.x = x
  2578.             self._gi._rectAll.y = y
  2579.  
  2580.             if item.HasImage():
  2581.  
  2582.                 self._gi._rectIcon.x = self._gi._rectAll.x + 4 + (self._gi._rectAll.width - self._gi._rectIcon.width)/2
  2583.                 self._gi._rectIcon.y = self._gi._rectAll.y + 4
  2584.  
  2585.             if item.HasText():
  2586.  
  2587.                 if self._gi._rectAll.width > spacing:
  2588.                     self._gi._rectLabel.x = self._gi._rectAll.x + 2
  2589.                 else:
  2590.                     self._gi._rectLabel.x = self._gi._rectAll.x + 2 + (spacing/2) - (self._gi._rectLabel.width/2)
  2591.  
  2592.                 self._gi._rectLabel.y = self._gi._rectAll.y + self._gi._rectAll.height + 2 - self._gi._rectLabel.height
  2593.                 self._gi._rectHighlight.x = self._gi._rectLabel.x - 2
  2594.                 self._gi._rectHighlight.y = self._gi._rectLabel.y - 2
  2595.  
  2596.             else:
  2597.  
  2598.                 self._gi._rectHighlight.x = self._gi._rectIcon.x - 4
  2599.                 self._gi._rectHighlight.y = self._gi._rectIcon.y - 4
  2600.  
  2601.         elif mode == ULC_LIST:
  2602.  
  2603.             self._gi._rectAll.x = x
  2604.             self._gi._rectAll.y = y
  2605.  
  2606.             wcheck = hcheck = 0
  2607.            
  2608.             if item.GetKind() in [1, 2]:
  2609.                 wcheck, hcheck = self._owner.GetCheckboxImageSize()
  2610.                 wcheck += 2
  2611.                 self._gi._rectCheck.x = self._gi._rectAll.x + 2
  2612.                 self._gi._rectCheck.y = self._gi._rectAll.y + 2
  2613.                
  2614.             self._gi._rectHighlight.x = self._gi._rectAll.x
  2615.             self._gi._rectHighlight.y = self._gi._rectAll.y
  2616.             self._gi._rectLabel.y = self._gi._rectAll.y + 2
  2617.  
  2618.             if item.HasImage():
  2619.  
  2620.                 self._gi._rectIcon.x = self._gi._rectAll.x + wcheck + 2
  2621.                 self._gi._rectIcon.y = self._gi._rectAll.y + 2
  2622.                 self._gi._rectLabel.x = self._gi._rectAll.x + 6 + self._gi._rectIcon.width + wcheck
  2623.  
  2624.             else:
  2625.  
  2626.                 self._gi._rectLabel.x = self._gi._rectAll.x + 2 + wcheck
  2627.  
  2628.         elif mode == ULC_REPORT:
  2629.             raise Exception("unexpected call to SetPosition")
  2630.  
  2631.         else:
  2632.             raise Exception("unknown mode")
  2633.  
  2634.  
  2635.     def InitItems(self, num):
  2636.  
  2637.         for i in xrange(num):
  2638.             self._items.append(UltimateListItemData(self._owner))
  2639.  
  2640.  
  2641.     def SetItem(self, index, info):
  2642.  
  2643.         item = self._items[index]
  2644.         item.SetItem(info)
  2645.  
  2646.  
  2647.     def GetItem(self, index, info):
  2648.  
  2649.         item = self._items[index]
  2650.         return item.GetItem(info)
  2651.  
  2652.  
  2653.     def GetText(self, index):
  2654.  
  2655.         item = self._items[index]
  2656.         return item.GetText()
  2657.  
  2658.  
  2659.     def SetText(self, index, s):
  2660.  
  2661.         item = self._items[index]
  2662.         item.SetText(s)
  2663.  
  2664.  
  2665.     def SetImage(self, index, image):
  2666.  
  2667.         item = self._items[index]
  2668.         item.SetImage(image)
  2669.  
  2670.  
  2671.     def GetImage(self, index=0):
  2672.  
  2673.         item = self._items[index]
  2674.         return item.GetImage()
  2675.  
  2676.  
  2677.     def Check(self, index, checked=True):
  2678.  
  2679.         item = self._items[index]
  2680.         item.Check(checked)
  2681.  
  2682.  
  2683.     def SetKind(self, index, kind=0):
  2684.  
  2685.         item = self._items[index]
  2686.         item.SetKind(kind)
  2687.                
  2688.  
  2689.     def GetKind(self, index=0):
  2690.  
  2691.         item = self._items[index]
  2692.         return item.GetKind()
  2693.  
  2694.  
  2695.     def IsChecked(self, index):
  2696.  
  2697.         item = self._items[index]
  2698.         return item.IsChecked()
  2699.  
  2700.  
  2701.     def SetColour(self, index, c):
  2702.  
  2703.         item = self._items[index]
  2704.         item.SetColour(c)
  2705.  
  2706.  
  2707.     def GetAttr(self):
  2708.  
  2709.         item = self._items[0]
  2710.         return item.GetAttr()
  2711.  
  2712.  
  2713.     def SetAttr(self, attr):
  2714.  
  2715.         item = self._items[0]
  2716.         item.SetAttr(attr)
  2717.  
  2718.  
  2719.     def SetAttributes(self, dc, attr, highlighted):
  2720.  
  2721.         listctrl = self._owner.GetParent()
  2722.  
  2723.         # fg colour
  2724.         # don't use foreground colour for drawing highlighted items - this might
  2725.         # make them completely invisible (and there is no way to do bit
  2726.         # arithmetics on wxColour, unfortunately)
  2727.  
  2728.         if not self._owner.HasExtraFlag(ULC_BORDER_SELECT) and not self._owner.HasExtraFlag(ULC_NO_FULL_ROW_SELECT):
  2729.             if highlighted:
  2730.                 if wx.Platform == "__WXMAC__":
  2731.                     if self._owner.HasFocus():
  2732.                         colText = wx.WHITE
  2733.                     else:
  2734.                         colText = wx.BLACK
  2735.                 else:
  2736.                     colText = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
  2737.             else:
  2738.                 colText = listctrl.GetForegroundColour()
  2739.         elif attr and attr.HasTextColour():
  2740.             colText = attr.GetTextColour()
  2741.         else:
  2742.             colText = listctrl.GetForegroundColour()
  2743.  
  2744.         dc.SetTextForeground(colText)
  2745.  
  2746.         # font
  2747.         if attr and attr.HasFont():
  2748.             font = attr.GetFont()
  2749.         else:
  2750.             font = listctrl.GetFont()
  2751.  
  2752.         dc.SetFont(font)
  2753.  
  2754.         # bg colour
  2755.         hasBgCol = attr and attr.HasBackgroundColour()
  2756.  
  2757.         if highlighted or hasBgCol:
  2758.             if highlighted:
  2759.                 dc.SetBrush(self._owner.GetHighlightBrush())
  2760.             else:
  2761.                 dc.SetBrush(wx.Brush(attr.GetBackgroundColour(), wx.SOLID))
  2762.  
  2763.             dc.SetPen(wx.TRANSPARENT_PEN)
  2764.  
  2765.             return True
  2766.  
  2767.         return False
  2768.  
  2769.  
  2770.     def Draw(self, line, dc):
  2771.  
  2772.         item = self._items[0]
  2773.         highlighted = self.IsHighlighted()
  2774.  
  2775.         attr = self.GetAttr()
  2776.  
  2777.         useGradient, gradientStyle = self._owner._usegradients, self._owner._gradientstyle
  2778.         useVista = self._owner._vistaselection
  2779.         hasFocus = self._owner._hasFocus
  2780.         borderOnly = self._owner.HasExtraFlag(ULC_BORDER_SELECT)
  2781.         drawn = False
  2782.  
  2783.         if self.SetAttributes(dc, attr, highlighted):
  2784.             drawn = True
  2785.  
  2786.             if not borderOnly:
  2787.  
  2788.                 if useGradient:
  2789.                     if gradientStyle == 0:
  2790.                         # horizontal gradient
  2791.                         self.DrawHorizontalGradient(dc, self._gi._rectAll, hasFocus)
  2792.                     else:
  2793.                         # vertical gradient
  2794.                         self.DrawVerticalGradient(dc, self._gi._rectAll, hasFocus)
  2795.                 elif useVista:
  2796.                     # Vista selection style
  2797.                     self.DrawVistaRectangle(dc, self._gi._rectAll, hasFocus)
  2798.                 else:
  2799.                     if wx.Platform not in ["__WXMAC__", "__WXGTK__"]:
  2800.                         dc.DrawRectangleRect(self._gi._rectHighlight)
  2801.                     else:
  2802.                         if highlighted:
  2803.                             flags = wx.CONTROL_SELECTED
  2804.                             if self._owner.HasFocus() and wx.Platform == "__WXMAC__":
  2805.                                 flags |= wx.CONTROL_FOCUSED
  2806.  
  2807.                             wx.RendererNative.Get().DrawItemSelectionRect(self._owner, dc, self._gi._rectHighlight, flags)
  2808.                         else:
  2809.                             dc.DrawRectangleRect(self._gi._rectHighlight)
  2810.  
  2811.         else:
  2812.  
  2813.             if borderOnly:
  2814.                 dc.SetBrush(wx.WHITE_BRUSH)
  2815.                 dc.SetPen(wx.TRANSPARENT_PEN)
  2816.                 dc.DrawRectangleRect(self._gi._rectAll)
  2817.  
  2818.         if item.GetKind() in [1, 2]:
  2819.             rectCheck = self._gi._rectCheck
  2820.             self._owner.DrawCheckbox(dc, rectCheck.x, rectCheck.y, item.GetKind(), item.IsChecked(), item.IsEnabled())
  2821.  
  2822.         if item.HasImage():
  2823.             # centre the image inside our rectangle, this looks nicer when items
  2824.             # ae aligned in a row
  2825.             rectIcon = self._gi._rectIcon
  2826.             self._owner.DrawImage(item.GetImage()[0], dc, rectIcon.x, rectIcon.y, True)
  2827.  
  2828.         if item.HasText():
  2829.             rectLabel = self._gi._rectLabel
  2830.  
  2831.             dc.SetClippingRect(rectLabel)
  2832.             dc.DrawText(item.GetText(), rectLabel.x, rectLabel.y)
  2833.             dc.DestroyClippingRegion()
  2834.  
  2835.         if self._owner.HasExtraFlag(ULC_HOT_TRACKING):
  2836.             if line == self._owner._newHotCurrent and not drawn:
  2837.                 r = wx.Rect(*self._gi._rectAll)
  2838.                 dc.SetBrush(wx.TRANSPARENT_BRUSH)
  2839.                 dc.SetPen(wx.Pen(wx.NamedColor("orange")))
  2840.                 dc.DrawRoundedRectangleRect(r, 3)
  2841.  
  2842.         if borderOnly and drawn:
  2843.             dc.SetPen(wx.Pen(wx.Colour(0, 191, 255), 2))
  2844.             dc.SetBrush(wx.TRANSPARENT_BRUSH)
  2845.             r = wx.Rect(*self._gi._rectAll)
  2846.             r.x += 1
  2847.             r.y += 1
  2848.             r.width -= 1
  2849.             r.height -= 1
  2850.             dc.DrawRoundedRectangleRect(r, 4)
  2851.            
  2852.  
  2853.     def HideItemWindow(self, item):
  2854.  
  2855.         wnd = item.GetWindow()
  2856.         if wnd and wnd.IsShown():
  2857.             wnd.Hide()
  2858.                
  2859.  
  2860.     def DrawInReportMode(self, dc, line, rect, rectHL, highlighted, current, enabled, oldPN, oldBR):
  2861.  
  2862.         attr = self.GetAttr()
  2863.  
  2864.         useGradient, gradientStyle = self._owner._usegradients, self._owner._gradientstyle
  2865.         useVista = self._owner._vistaselection
  2866.         hasFocus = self._owner._hasFocus
  2867.         borderOnly = self._owner.HasExtraFlag(ULC_BORDER_SELECT)
  2868.         nofullRow = self._owner.HasExtraFlag(ULC_NO_FULL_ROW_SELECT)
  2869.        
  2870.         drawn = False
  2871.         dc.SetBrush(wx.TRANSPARENT_BRUSH)
  2872.  
  2873.         if nofullRow:
  2874.            
  2875.             x = rect.x + HEADER_OFFSET_X
  2876.             y = rect.y
  2877.             height = rect.height
  2878.  
  2879.             for col, item in enumerate(self._items):
  2880.  
  2881.                 width = self._owner.GetColumnWidth(col)
  2882.                 if self._owner.IsColumnShown(col):
  2883.                     paintRect = wx.Rect(x, y, self._owner.GetColumnWidth(col)-2*HEADER_OFFSET_X, rect.height)
  2884.                     break
  2885.  
  2886.                 xOld = x
  2887.                 x += width
  2888.  
  2889.         else:
  2890.  
  2891.             paintRect = wx.Rect(*rectHL)            
  2892.        
  2893.         if self.SetAttributes(dc, attr, highlighted) and enabled:
  2894.            
  2895.             drawn = True
  2896.                                
  2897.             if not borderOnly:
  2898.            
  2899.                 if useGradient:
  2900.                     if gradientStyle == 0:
  2901.                         # horizontal gradient
  2902.                         self.DrawHorizontalGradient(dc, paintRect, hasFocus)
  2903.                     else:
  2904.                         # vertical gradient
  2905.                         self.DrawVerticalGradient(dc, paintRect, hasFocus)
  2906.                 elif useVista:
  2907.                     # Vista selection style
  2908.                     self.DrawVistaRectangle(dc, paintRect, hasFocus)
  2909.                 else:
  2910.                     # Normal selection style
  2911.                     if wx.Platform not in ["__WXGTK__", "__WXMAC__"]:
  2912.                         dc.DrawRectangleRect(paintRect)
  2913.                     else:
  2914.                         if highlighted:
  2915.                             flags = wx.CONTROL_SELECTED
  2916.                             if hasFocus:
  2917.                                 flags |= wx.CONTROL_FOCUSED
  2918.                             if current:
  2919.                                 flags |= wx.CONTROL_CURRENT
  2920.                                
  2921.                             wx.RendererNative.Get().DrawItemSelectionRect(self._owner, dc, paintRect, flags)                        
  2922.                         else:
  2923.                             dc.DrawRectangleRect(paintRect)
  2924.  
  2925.         else:
  2926.    
  2927.             if borderOnly:
  2928.  
  2929.                 dc.SetBrush(wx.WHITE_BRUSH)
  2930.                 dc.SetPen(wx.TRANSPARENT_PEN)
  2931.                 dc.DrawRectangleRect(paintRect)
  2932.  
  2933.         x = rect.x + HEADER_OFFSET_X
  2934.         y = rect.y
  2935.         height = rect.height
  2936.  
  2937.         for col, item in enumerate(self._items):
  2938.  
  2939.             if not self._owner.IsColumnShown(col):
  2940.                 self.HideItemWindow(item)
  2941.                 continue
  2942.            
  2943.             width = self._owner.GetColumnWidth(col)
  2944.             xOld = x
  2945.             x += width
  2946.  
  2947.             if item.GetCustomRenderer():
  2948.                 customRect = wx.Rect(xOld-HEADER_OFFSET_X, rect.y, width, rect.height)
  2949.                 item.GetCustomRenderer().DrawSubItem(dc, customRect, line, highlighted, enabled)
  2950.                 continue
  2951.  
  2952.             overflow = item.GetOverFlow() and item.HasText()
  2953.            
  2954.             if item.GetKind() in [1, 2]:
  2955.                
  2956.                 # We got a checkbox-type item
  2957.                 ix, iy = self._owner.GetCheckboxImageSize()
  2958.                 checked = item.IsChecked()
  2959.                 self._owner.DrawCheckbox(dc, xOld, y + (height-iy+1)/2, item.GetKind(), checked, enabled)
  2960.                 xOld += ix
  2961.                 width -= ix
  2962.                
  2963.             if item.HasImage():
  2964.  
  2965.                 images = item.GetImage()
  2966.                
  2967.                 for img in images:
  2968.                    
  2969.                     ix, iy = self._owner.GetImageSize([img])
  2970.                     self._owner.DrawImage(img, dc, xOld, y + (height-iy)/2, enabled)
  2971.                    
  2972.                     xOld += ix
  2973.                     width -= ix
  2974.  
  2975. ##                if images:
  2976. ##                    width -= IMAGE_MARGIN_IN_REPORT_MODE - MARGIN_BETWEEN_TEXT_AND_ICON
  2977.  
  2978.             wnd = item.GetWindow()
  2979.             xSize = 0
  2980.             if wnd:
  2981.                 xSize, ySize = item.GetWindowSize()
  2982.                 wndx = xOld - HEADER_OFFSET_X + width - xSize - 3
  2983.                 xa, ya = self._owner.CalcScrolledPosition((0, rect.y))
  2984.                 wndx += xa
  2985.                 if rect.height > ySize:
  2986.                     ya += (rect.height - ySize)/2
  2987.  
  2988.             itemRect = wx.Rect(xOld-2*HEADER_OFFSET_X, rect.y, width-xSize-HEADER_OFFSET_X, rect.height)
  2989.             if overflow:
  2990.                 itemRect = wx.Rect(xOld-2*HEADER_OFFSET_X, rect.y, rectHL.width-xSize-HEADER_OFFSET_X, rect.height)
  2991.  
  2992.             dc.SetClippingRect(itemRect)
  2993.            
  2994.             if item.HasBackgroundColour():
  2995.                 dc.SetBrush(wx.Brush(item.GetBackgroundColour()))
  2996.                 dc.SetPen(wx.Pen(item.GetBackgroundColour()))
  2997.                 dc.DrawRectangleRect(itemRect)
  2998.                 dc.SetBrush(oldBR)
  2999.                 dc.SetPen(oldPN)
  3000.  
  3001.             if item.HasText():
  3002.  
  3003.                 coloured = item.HasColour()
  3004.                 oldDC = dc.GetTextForeground()
  3005.                 oldFT = dc.GetFont()
  3006.  
  3007.                 font = item.HasFont()
  3008.  
  3009.                 if not enabled:
  3010.                     dc.SetTextForeground(self._owner.GetDisabledTextColour())
  3011.                 else:
  3012.                     if coloured:
  3013.                         dc.SetTextForeground(item.GetColour())
  3014.  
  3015.                 if item.IsHyperText():
  3016.                     dc.SetFont(self._owner.GetHyperTextFont())
  3017.                     if item.GetVisited():
  3018.                         dc.SetTextForeground(self._owner.GetHyperTextVisitedColour())
  3019.                     else:
  3020.                         dc.SetTextForeground(self._owner.GetHyperTextNewColour())
  3021.                 else:
  3022.                     if font:
  3023.                         dc.SetFont(item.GetFont())
  3024.  
  3025.                 itemRect = wx.Rect(itemRect.x+MARGIN_BETWEEN_TEXT_AND_ICON, itemRect.y, itemRect.width-8, itemRect.height)                    
  3026.                 self.DrawTextFormatted(dc, item.GetText(), line, col, itemRect, overflow)
  3027.  
  3028.                 if coloured:
  3029.                     dc.SetTextForeground(oldDC)
  3030.  
  3031.                 if font:
  3032.                     dc.SetFont(oldFT)
  3033.  
  3034.             dc.DestroyClippingRegion()
  3035.  
  3036.             if wnd:
  3037.                 if not wnd.IsShown():
  3038.                     wnd.Show()
  3039.                    
  3040.                 if item._expandWin:
  3041.                     if wnd.GetRect() != itemRect:
  3042.                         wRect = wx.Rect(*itemRect)
  3043.                         wRect.x += 2
  3044.                         wRect.width = width - 8
  3045.                         wRect.y += 2
  3046.                         wRect.height -= 4
  3047.                         wnd.SetRect(wRect)
  3048.                 else:
  3049.                     if wnd.GetPosition() != (wndx, ya):
  3050.                         wnd.SetPosition((wndx, ya))
  3051.  
  3052.         if self._owner.HasExtraFlag(ULC_HOT_TRACKING):
  3053.             if line == self._owner._newHotCurrent and not drawn:
  3054.                 r = wx.Rect(*paintRect)
  3055.                 r.y += 1
  3056.                 r.height -= 1
  3057.                 dc.SetBrush(wx.TRANSPARENT_BRUSH)
  3058.                 dc.SetPen(wx.Pen(wx.NamedColor("orange")))
  3059.                 dc.DrawRoundedRectangleRect(r, 3)
  3060.                 dc.SetPen(oldPN)
  3061.  
  3062.         if borderOnly and drawn:
  3063.             dc.SetPen(wx.Pen(wx.Colour(0, 191, 255), 2))
  3064.             dc.SetBrush(wx.TRANSPARENT_BRUSH)
  3065.             rect = wx.Rect(*paintRect)
  3066.             rect.y += 1
  3067.             rect.height -= 1
  3068.             dc.DrawRoundedRectangleRect(rect, 3)
  3069.             dc.SetPen(oldPN)
  3070.            
  3071.  
  3072.     def DrawTextFormatted(self, dc, text, row, col, itemRect, overflow):
  3073.  
  3074.         # determine if the string can fit inside the current width
  3075.         w, h, dummy = dc.GetMultiLineTextExtent(text)
  3076.         width = itemRect.width
  3077.  
  3078.         shortItems = self._owner._shortItems
  3079.         tuples = (row, col)
  3080.  
  3081.         # it can, draw it using the items alignment
  3082.         item = self._owner.GetColumn(col)
  3083.         align = item.GetAlign()
  3084.  
  3085.         if align == ULC_FORMAT_RIGHT:
  3086.             textAlign = wx.ALIGN_RIGHT
  3087.         elif align == ULC_FORMAT_CENTER:
  3088.             textAlign = wx.ALIGN_CENTER
  3089.         else:
  3090.             textAlign = wx.ALIGN_LEFT
  3091.  
  3092.         if w <= width:
  3093.            
  3094.             if tuples in shortItems:
  3095.                 shortItems.remove(tuples)
  3096.  
  3097.             dc.DrawLabel(text, itemRect, textAlign|wx.ALIGN_CENTER_VERTICAL)
  3098.            
  3099.         else: # otherwise, truncate and add an ellipsis if possible
  3100.  
  3101.             if tuples not in shortItems:
  3102.                 shortItems.append(tuples)
  3103.                
  3104.             # determine the base width
  3105.             ellipsis = "..."
  3106.             base_w, h = dc.GetTextExtent(ellipsis)
  3107.  
  3108.             # continue until we have enough space or only one character left
  3109.  
  3110.             newText = text.split("\n")
  3111.             theText = ""
  3112.  
  3113.             for text in newText:
  3114.            
  3115.                 lenText = len(text)
  3116.                 drawntext = text
  3117.                 w, dummy = dc.GetTextExtent(text)
  3118.  
  3119.                 while lenText > 1:
  3120.  
  3121.                     if w + base_w <= width:
  3122.                         break
  3123.  
  3124.                     w_c, h_c = dc.GetTextExtent(drawntext[-1])
  3125.                     drawntext = drawntext[0:-1]
  3126.                     lenText -= 1
  3127.                     w -= w_c
  3128.                
  3129.                 # if still not enough space, remove ellipsis characters
  3130.                 while len(ellipsis) > 0 and w + base_w > width:
  3131.                     ellipsis = ellipsis[0:-1]
  3132.                     base_w, h = dc.GetTextExtent(ellipsis)
  3133.  
  3134.                 theText += drawntext + ellipsis + "\n"
  3135.  
  3136.             theText = theText.rstrip()
  3137.             # now draw the text                
  3138.             dc.DrawLabel(theText, itemRect, textAlign|wx.ALIGN_CENTER_VERTICAL)
  3139.  
  3140.  
  3141.     def DrawVerticalGradient(self, dc, rect, hasfocus):
  3142.         """Gradient fill from colour 1 to colour 2 from top to bottom."""
  3143.  
  3144.         oldpen = dc.GetPen()
  3145.         oldbrush = dc.GetBrush()
  3146.         dc.SetPen(wx.TRANSPARENT_PEN)
  3147.  
  3148.         # calculate gradient coefficients
  3149.         if hasfocus:
  3150.             col2 = self._owner._secondcolour
  3151.             col1 = self._owner._firstcolour
  3152.         else:
  3153.             col2 = self._owner._highlightUnfocusedBrush.GetColour()
  3154.             col1 = self._owner._highlightUnfocusedBrush2.GetColour()
  3155.  
  3156.         r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
  3157.         r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
  3158.  
  3159.         flrect = float(rect.height)
  3160.  
  3161.         rstep = float((r2 - r1)) / flrect
  3162.         gstep = float((g2 - g1)) / flrect
  3163.         bstep = float((b2 - b1)) / flrect
  3164.  
  3165.         rf, gf, bf = 0, 0, 0
  3166.        
  3167.         for y in xrange(rect.y, rect.y + rect.height):
  3168.             currCol = (r1 + rf, g1 + gf, b1 + bf)                
  3169.             dc.SetBrush(wx.Brush(currCol, wx.SOLID))
  3170.             dc.DrawRectangle(rect.x, y, rect.width, 1)
  3171.             rf = rf + rstep
  3172.             gf = gf + gstep
  3173.             bf = bf + bstep
  3174.        
  3175.         dc.SetPen(oldpen)
  3176.         dc.SetBrush(wx.TRANSPARENT_BRUSH)
  3177.         dc.DrawRectangleRect(rect)
  3178.         dc.SetBrush(oldbrush)
  3179.  
  3180.  
  3181.     def DrawHorizontalGradient(self, dc, rect, hasfocus):
  3182.         """Gradient fill from colour 1 to colour 2 from left to right."""
  3183.  
  3184.         oldpen = dc.GetPen()
  3185.         oldbrush = dc.GetBrush()
  3186.         dc.SetPen(wx.TRANSPARENT_PEN)
  3187.  
  3188.         # calculate gradient coefficients
  3189.  
  3190.         if hasfocus:
  3191.             col2 = self._owner._secondcolour
  3192.             col1 = self._owner._firstcolour
  3193.         else:
  3194.             col2 = self._owner._highlightUnfocusedBrush.GetColour()
  3195.             col1 = self._owner._highlightUnfocusedBrush2.GetColour()
  3196.  
  3197.         r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
  3198.         r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
  3199.  
  3200.         flrect = float(rect.width)
  3201.  
  3202.         rstep = float((r2 - r1)) / flrect
  3203.         gstep = float((g2 - g1)) / flrect
  3204.         bstep = float((b2 - b1)) / flrect
  3205.  
  3206.         rf, gf, bf = 0, 0, 0
  3207.  
  3208.         for x in xrange(rect.x, rect.x + rect.width):
  3209.             currCol = (int(r1 + rf), int(g1 + gf), int(b1 + bf))
  3210.             dc.SetBrush(wx.Brush(currCol, wx.SOLID))
  3211.             dc.DrawRectangle(x, rect.y, 1, rect.height)
  3212.             rf = rf + rstep
  3213.             gf = gf + gstep
  3214.             bf = bf + bstep
  3215.  
  3216.         dc.SetPen(oldpen)
  3217.         dc.SetBrush(wx.TRANSPARENT_BRUSH)
  3218.         dc.DrawRectangleRect(rect)
  3219.         dc.SetBrush(oldbrush)
  3220.        
  3221.  
  3222.     def DrawVistaRectangle(self, dc, rect, hasfocus):
  3223.         """Draw the selected item(s) with the Windows Vista style."""
  3224.  
  3225.         if hasfocus:
  3226.            
  3227.             outer = _rgbSelectOuter
  3228.             inner = _rgbSelectInner
  3229.             top = _rgbSelectTop
  3230.             bottom = _rgbSelectBottom
  3231.  
  3232.         else:
  3233.            
  3234.             outer = _rgbNoFocusOuter
  3235.             inner = _rgbNoFocusInner
  3236.             top = _rgbNoFocusTop
  3237.             bottom = _rgbNoFocusBottom
  3238.  
  3239.         oldpen = dc.GetPen()
  3240.         oldbrush = dc.GetBrush()
  3241.  
  3242.         bdrRect = wx.Rect(*rect.Get())
  3243.         filRect = wx.Rect(*rect.Get())
  3244.         filRect.Deflate(1,1)
  3245.        
  3246.         r1, g1, b1 = int(top.Red()), int(top.Green()), int(top.Blue())
  3247.         r2, g2, b2 = int(bottom.Red()), int(bottom.Green()), int(bottom.Blue())
  3248.  
  3249.         flrect = float(filRect.height)
  3250.         if flrect < 1:
  3251.             flrect = self._owner._lineHeight
  3252.  
  3253.         rstep = float((r2 - r1)) / flrect
  3254.         gstep = float((g2 - g1)) / flrect
  3255.         bstep = float((b2 - b1)) / flrect
  3256.  
  3257.         rf, gf, bf = 0, 0, 0
  3258.         dc.SetPen(wx.TRANSPARENT_PEN)
  3259.        
  3260.         for y in xrange(filRect.y, filRect.y + filRect.height):
  3261.             currCol = (r1 + rf, g1 + gf, b1 + bf)
  3262.             dc.SetBrush(wx.Brush(currCol, wx.SOLID))
  3263.             dc.DrawRectangle(filRect.x, y, filRect.width, 1)
  3264.             rf = rf + rstep
  3265.             gf = gf + gstep
  3266.             bf = bf + bstep
  3267.        
  3268.         dc.SetBrush(wx.TRANSPARENT_BRUSH)
  3269.         dc.SetPen(wx.Pen(outer))
  3270.         dc.DrawRoundedRectangleRect(bdrRect, 3)
  3271.         bdrRect.Deflate(1, 1)
  3272.         dc.SetPen(wx.Pen(inner))
  3273.         dc.DrawRoundedRectangleRect(bdrRect, 2)
  3274.  
  3275.         dc.SetPen(oldpen)
  3276.         dc.SetBrush(oldbrush)
  3277.  
  3278.        
  3279.     def Highlight(self, on):
  3280.  
  3281.         if on == self._highlighted:
  3282.             return False
  3283.  
  3284.         self._highlighted = on
  3285.  
  3286.         return True
  3287.  
  3288.  
  3289.     def ReverseHighlight(self):
  3290.  
  3291.         self.Highlight(not self.IsHighlighted())
  3292.  
  3293.  
  3294.  
  3295. #-----------------------------------------------------------------------------
  3296. #  UltimateListHeaderWindow (internal)
  3297. #-----------------------------------------------------------------------------
  3298.  
  3299. class UltimateListHeaderWindow(wx.PyControl):
  3300.  
  3301.     def __init__(self, win, id, owner, pos=wx.DefaultPosition,
  3302.                  size=wx.DefaultSize, style=0, validator=wx.DefaultValidator,
  3303.                  name="UltimateListCtrlcolumntitles", isFooter=False):
  3304.  
  3305.         wx.PyControl.__init__(self, win, id, pos, size, style|wx.NO_BORDER, validator, name)
  3306.  
  3307.         self._isFooter = isFooter
  3308.         self._owner = owner
  3309.         self._currentCursor = wx.NullCursor
  3310.         self._resizeCursor = wx.StockCursor(wx.CURSOR_SIZEWE)
  3311.         self._isDragging = False
  3312.  
  3313.         # column being resized or -1
  3314.         self._column = -1
  3315.  
  3316.         # divider line position in logical (unscrolled) coords
  3317.         self._currentX = 0
  3318.  
  3319.         # minimal position beyond which the divider line can't be dragged in
  3320.         # logical coords
  3321.         self._minX = 0
  3322.  
  3323.         # needs refresh
  3324.         self._dirty = False
  3325.         self._hasFont = False
  3326.         self._sendSetColumnWidth = False
  3327.         self._colToSend = -1
  3328.         self._widthToSend = 0
  3329.         self._leftDown = False
  3330.         self._enter = False
  3331.         self._currentColumn = -1
  3332.  
  3333.         self.Bind(wx.EVT_PAINT, self.OnPaint)
  3334.         self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
  3335.         self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
  3336.         self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
  3337.         self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
  3338.         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
  3339.  
  3340.         if _USE_VISATTR:
  3341.  
  3342.             attr = wx.Panel.GetClassDefaultAttributes()
  3343.             self.SetOwnForegroundColour(attr.colFg)
  3344.             self.SetOwnBackgroundColour(attr.colBg)
  3345.             if not self._hasFont:
  3346.                 self.SetOwnFont(attr.font)
  3347.  
  3348.         else:
  3349.  
  3350.             self.SetOwnForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT))
  3351.             self.SetOwnBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
  3352.  
  3353.             if not self._hasFont:
  3354.                 self.SetOwnFont(wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT))
  3355.  
  3356.  
  3357.     def DoGetBestSize(self):
  3358.  
  3359.         w, h, d, dummy = self.GetFullTextExtent("Hg")
  3360.         maxH = self.GetTextHeight()
  3361.         nativeH = wx.RendererNative.Get().GetHeaderButtonHeight(self.GetParent())
  3362.  
  3363.         if not self._isFooter:
  3364.             maxH = max(max(h, maxH), nativeH)
  3365.             maxH += d
  3366.             self.GetParent()._headerHeight = maxH
  3367.         else:
  3368.             maxH = max(h, nativeH)
  3369.             maxH += d
  3370.             self.GetParent()._footerHeight = maxH
  3371.            
  3372.         return wx.Size(200, maxH)
  3373.  
  3374.  
  3375.     def IsColumnShown(self, column):
  3376.  
  3377.         if column < 0 or column >= self._owner.GetColumnCount():
  3378.             raise Exception("Invalid column")
  3379.  
  3380.         return self._owner.IsColumnShown(column)
  3381.  
  3382.    
  3383.     # shift the DC origin to match the position of the main window horz
  3384.     # scrollbar: this allows us to always use logical coords
  3385.     def AdjustDC(self, dc):
  3386.  
  3387.         xpix, dummy = self._owner.GetScrollPixelsPerUnit()
  3388.         x, dummy = self._owner.GetViewStart()
  3389.  
  3390.         # account for the horz scrollbar offset
  3391.         dc.SetDeviceOrigin(-x*xpix, 0)
  3392.  
  3393.  
  3394.     def GetTextHeight(self):
  3395.  
  3396.         maxH = 0
  3397.         numColumns = self._owner.GetColumnCount()
  3398.         dc = wx.ClientDC(self)
  3399.         for i in xrange(numColumns):
  3400.            
  3401.             if not self.IsColumnShown(i):
  3402.                 continue
  3403.  
  3404.             item = self._owner.GetColumn(i)
  3405.             if item.GetFont().IsOk():
  3406.                 dc.SetFont(item.GetFont())
  3407.             else:
  3408.                 dc.SetFont(self.GetFont())
  3409.                        
  3410.             wLabel, hLabel, dummy = dc.GetMultiLineTextExtent(item.GetText())
  3411.             maxH = max(maxH, hLabel)
  3412.  
  3413.         return maxH
  3414.    
  3415.    
  3416.     def OnPaint(self, event):
  3417.  
  3418.         dc = wx.BufferedPaintDC(self)
  3419.         # width and height of the entire header window
  3420.         w, h = self.GetClientSize()
  3421.         w, dummy = self._owner.CalcUnscrolledPosition(w, 0)
  3422.         dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)))
  3423.         dc.SetPen(wx.TRANSPARENT_PEN)
  3424.         dc.DrawRectangle(0, -1, w, h+2)
  3425.        
  3426.         self.PrepareDC(dc)
  3427.         self.AdjustDC(dc)
  3428.  
  3429.         dc.SetBackgroundMode(wx.TRANSPARENT)
  3430.         dc.SetTextForeground(self.GetForegroundColour())
  3431.  
  3432.         x = HEADER_OFFSET_X
  3433.  
  3434.         numColumns = self._owner.GetColumnCount()
  3435.         item = UltimateListItem()
  3436.         renderer = wx.RendererNative.Get()
  3437.         enabled = self.GetParent().IsEnabled()
  3438.         virtual = self._owner.IsVirtual()
  3439.         isFooter = self._isFooter
  3440.  
  3441.         for i in xrange(numColumns):
  3442.  
  3443.             if x >= w:
  3444.                 break
  3445.  
  3446.             if not self.IsColumnShown(i):
  3447.                 continue # do next column if not shown
  3448.            
  3449.             item = self._owner.GetColumn(i)
  3450.             wCol = item._width
  3451.  
  3452.             cw = wCol
  3453.             ch = h
  3454.  
  3455.             flags = 0
  3456.             if not enabled:
  3457.                 flags |= wx.CONTROL_DISABLED
  3458.  
  3459.             # NB: The code below is not really Mac-specific, but since we are close
  3460.             # to 2.8 release and I don't have time to test on other platforms, I
  3461.             # defined this only for wxMac. If this behavior is desired on
  3462.             # other platforms, please go ahead and revise or remove the #ifdef.
  3463.  
  3464.             if "__WXMAC__" in wx.PlatformInfo:
  3465.                 if not virtual and item._mask & ULC_MASK_STATE and item._state & ULC_STATE_SELECTED:
  3466.                     flags |= wx.CONTROL_SELECTED
  3467.            
  3468.             if i == 0:
  3469.                flags |= wx.CONTROL_SPECIAL # mark as first column
  3470.  
  3471.             if i == self._currentColumn:
  3472.                 if self._leftDown:
  3473.                     flags |= wx.CONTROL_PRESSED
  3474.                 else:
  3475.                     if self._enter:
  3476.                         flags |= wx.CONTROL_CURRENT
  3477.            
  3478.             # the width of the rect to draw: make it smaller to fit entirely
  3479.             # inside the column rect
  3480.  
  3481.             renderer.DrawHeaderButton(self, dc,
  3482.                                       wx.Rect(x-1, HEADER_OFFSET_Y-1, cw-1, ch),
  3483.                                       flags)
  3484.  
  3485.             # see if we have enough space for the column label
  3486.             if isFooter:
  3487.                 if item.GetFooterFont().IsOk():
  3488.                     dc.SetFont(item.GetFooterFont())
  3489.                 else:
  3490.                     dc.SetFont(self.GetFont())
  3491.             else:
  3492.                 if item.GetFont().IsOk():
  3493.                     dc.SetFont(item.GetFont())
  3494.                 else:
  3495.                     dc.SetFont(self.GetFont())
  3496.  
  3497.             wcheck = hcheck = 0
  3498.             kind = (isFooter and [item.GetFooterKind()] or [item.GetKind()])[0]
  3499.             checked = (isFooter and [item.IsFooterChecked()] or [item.IsChecked()])[0]
  3500.            
  3501.             if kind in [1, 2]:
  3502.                 # We got a checkbox-type item
  3503.                 ix, iy = self._owner.GetCheckboxImageSize()
  3504.                 # We draw it on the left, always
  3505.                 self._owner.DrawCheckbox(dc, x + HEADER_OFFSET_X, HEADER_OFFSET_Y + (h - 4 - iy)/2, kind, checked, enabled)
  3506.                 wcheck += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  3507.                 cw -= ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  3508.  
  3509.             # for this we need the width of the text
  3510.             text = (isFooter and [item.GetFooterText()] or [item.GetText()])[0]
  3511.             wLabel, hLabel, dummy = dc.GetMultiLineTextExtent(text)
  3512.             wLabel += 2*EXTRA_WIDTH
  3513.  
  3514.             # and the width of the icon, if any
  3515.             image = (isFooter and [item._footerImage] or [item._image])[0]
  3516.  
  3517.             if image:
  3518.                 imageList = self._owner._small_image_list
  3519.                 if imageList:
  3520.                     for img in image:
  3521.                         ix, iy = imageList.GetSize(img)
  3522.                         wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  3523.  
  3524.             else:
  3525.  
  3526.                 imageList = None
  3527.  
  3528.             # ignore alignment if there is not enough space anyhow
  3529.             align = (isFooter and [item.GetFooterAlign()] or [item.GetAlign()])[0]                                                          
  3530.             align = (wLabel < cw and [align] or [ULC_FORMAT_LEFT])[0]
  3531.  
  3532.             if align == ULC_FORMAT_LEFT:
  3533.                 xAligned = x + wcheck
  3534.  
  3535.             elif align == ULC_FORMAT_RIGHT:
  3536.                 xAligned = x + cw - wLabel - HEADER_OFFSET_X
  3537.  
  3538.             elif align == ULC_FORMAT_CENTER:
  3539.                 xAligned = x + wcheck + (cw - wLabel)/2
  3540.  
  3541.             # if we have an image, draw it on the right of the label
  3542.             if imageList:
  3543.                 for indx, img in enumerate(image):
  3544.                     imageList.Draw(img, dc,
  3545.                                    xAligned + wLabel - (ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE)*(indx+1),
  3546.                                    HEADER_OFFSET_Y + (h - 4 - iy)/2,
  3547.                                    wx.IMAGELIST_DRAW_TRANSPARENT)
  3548.  
  3549.                     cw -= ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  3550.  
  3551.             # draw the text clipping it so that it doesn't overwrite the column
  3552.             # boundary
  3553.             dc.SetClippingRegion(x, HEADER_OFFSET_Y, cw, h - 4)
  3554.             self.DrawTextFormatted(dc, text, wx.Rect(xAligned+EXTRA_WIDTH, HEADER_OFFSET_Y, cw-EXTRA_WIDTH, h-4))
  3555.            
  3556.             x += wCol
  3557.             dc.DestroyClippingRegion()
  3558.  
  3559.         # Fill in what's missing to the right of the columns, otherwise we will
  3560.         # leave an unpainted area when columns are removed (and it looks better)
  3561.         if x < w:
  3562.             renderer.DrawHeaderButton(self, dc, wx.Rect(x, HEADER_OFFSET_Y, w - x, h), wx.CONTROL_DIRTY) # mark as last column
  3563.  
  3564.  
  3565.     def DrawTextFormatted(self, dc, text, rect):
  3566.  
  3567.         # determine if the string can fit inside the current width
  3568.         w, h, dummy = dc.GetMultiLineTextExtent(text)
  3569.         width = rect.width
  3570.  
  3571.         if w <= width:
  3572.            
  3573.             dc.DrawLabel(text, rect, wx.ALIGN_CENTER_VERTICAL)
  3574.  
  3575.         else:
  3576.            
  3577.             # determine the base width
  3578.             ellipsis = "..."
  3579.             base_w, h = dc.GetTextExtent(ellipsis)
  3580.  
  3581.             # continue until we have enough space or only one character left
  3582.  
  3583.             newText = text.split("\n")
  3584.             theText = ""
  3585.  
  3586.             for text in newText:
  3587.            
  3588.                 lenText = len(text)
  3589.                 drawntext = text
  3590.                 w, dummy = dc.GetTextExtent(text)
  3591.  
  3592.                 while lenText > 1:
  3593.  
  3594.                     if w + base_w <= width:
  3595.                         break
  3596.  
  3597.                     w_c, h_c = dc.GetTextExtent(drawntext[-1])
  3598.                     drawntext = drawntext[0:-1]
  3599.                     lenText -= 1
  3600.                     w -= w_c
  3601.                
  3602.                 # if still not enough space, remove ellipsis characters
  3603.                 while len(ellipsis) > 0 and w + base_w > width:
  3604.                     ellipsis = ellipsis[0:-1]
  3605.                     base_w, h = dc.GetTextExtent(ellipsis)
  3606.  
  3607.                 theText += drawntext + ellipsis + "\n"
  3608.  
  3609.             theText = theText.rstrip()
  3610.             dc.DrawLabel(theText, rect, wx.ALIGN_CENTER_VERTICAL)
  3611.    
  3612.  
  3613.     def OnInternalIdle(self):
  3614.  
  3615.         wx.PyControl.OnInternalIdle(self)
  3616.  
  3617.         if self._isFooter:
  3618.             return
  3619.        
  3620.         if self._sendSetColumnWidth:
  3621.             self._owner.SetColumnWidth(self._colToSend, self._widthToSend)
  3622.             self._sendSetColumnWidth = False
  3623.  
  3624.    
  3625.     def DrawCurrent(self):
  3626.  
  3627.         self._sendSetColumnWidth = True
  3628.         self._colToSend = self._column
  3629.         self._widthToSend = self._currentX - self._minX
  3630.  
  3631.  
  3632.     def OnMouse(self, event):
  3633.  
  3634.         # we want to work with logical coords
  3635.         x, dummy = self._owner.CalcUnscrolledPosition(event.GetX(), 0)
  3636.         y = event.GetY()
  3637.  
  3638.         columnX, columnY = x, y        
  3639.  
  3640.         if self._isDragging:
  3641.  
  3642.             self.SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition())
  3643.  
  3644.             # we don't draw the line beyond our window, but we allow dragging it
  3645.             # there
  3646.  
  3647.             w, dummy = self.GetClientSize()
  3648.             w, dummy = self._owner.CalcUnscrolledPosition(w, 0)            
  3649.             w -= 6
  3650.  
  3651.             # erase the line if it was drawn
  3652.             if self._currentX < w:
  3653.                 self.DrawCurrent()
  3654.  
  3655.             if event.ButtonUp():
  3656.  
  3657.                 self.ReleaseMouse()
  3658.                 self._isDragging = False
  3659.                 self._dirty = True
  3660.                 self._owner.SetColumnWidth(self._column, self._currentX - self._minX)
  3661.                 self.SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition())
  3662.  
  3663.             else:
  3664.  
  3665.                 if x > self._minX + 7:
  3666.                     self._currentX = x
  3667.                 else:
  3668.                     self._currentX = self._minX + 7
  3669.  
  3670.                 # draw in the new location
  3671.                 if self._currentX < w:
  3672.                     self.DrawCurrent()
  3673.  
  3674.         else: # not dragging
  3675.  
  3676.             self._minX = 0
  3677.             hit_border = False
  3678.  
  3679.             # end of the current column
  3680.             xpos = 0
  3681.  
  3682.             # find the column where this event occurred
  3683.             countCol = self._owner.GetColumnCount()
  3684.             broken = False
  3685.  
  3686.             for col in xrange(countCol):
  3687.  
  3688.                 if not self.IsColumnShown(col):
  3689.                     continue
  3690.                
  3691.                 xpos += self._owner.GetColumnWidth(col)
  3692.                 self._column = col
  3693.  
  3694.                 if abs(x-xpos) < 3 and y < 22:
  3695.                     # near the column border
  3696.                     hit_border = True
  3697.                     broken = True
  3698.                     break
  3699.  
  3700.                 if x < xpos:
  3701.                     # inside the column
  3702.                     broken = True
  3703.                     break
  3704.  
  3705.                 self._minX = xpos
  3706.  
  3707.             if not broken:
  3708.                 self._column = -1
  3709.  
  3710.             if event.LeftUp():
  3711.                 self._leftDown = False
  3712.                 self.Refresh()
  3713.                
  3714.             if event.LeftDown() or event.RightUp():
  3715.  
  3716.                 if hit_border and event.LeftDown():
  3717.  
  3718.                     if not self._isFooter:
  3719.  
  3720.                         if self.SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG,
  3721.                                               event.GetPosition()):
  3722.  
  3723.                             self._isDragging = True
  3724.                             self._currentX = x
  3725.                             self.CaptureMouse()
  3726.                             self.DrawCurrent()
  3727.  
  3728.                     #else: column resizing was vetoed by the user code
  3729.  
  3730.                 else: # click on a column
  3731.  
  3732.                      # record the selected state of the columns
  3733.                     if event.LeftDown():
  3734.                        
  3735.                         for i in xrange(self._owner.GetColumnCount()):
  3736.  
  3737.                             if not self.IsColumnShown(col):
  3738.                                 continue
  3739.                            
  3740.                             colItem = self._owner.GetColumn(i)
  3741.                             state = colItem.GetState()
  3742.  
  3743.                             if i == self._column:
  3744.                                 colItem.SetState(state | ULC_STATE_SELECTED)
  3745.                                 theX = x
  3746.                             else:
  3747.                                 colItem.SetState(state & ~ULC_STATE_SELECTED)
  3748.  
  3749.                             self._leftDown = True
  3750.                             self._owner.SetColumn(i, colItem)
  3751.                             x += self._owner.GetColumnWidth(i)
  3752.  
  3753.                         if self.HandleColumnCheck(self._column, event.GetPosition()):
  3754.                             return
  3755.  
  3756.                     if not self._isFooter:
  3757.                         self.SendListEvent((event.LeftDown() and [wxEVT_COMMAND_LIST_COL_CLICK] or \
  3758.                                             [wxEVT_COMMAND_LIST_COL_RIGHT_CLICK])[0], event.GetPosition())
  3759.                     else:
  3760.                         self.SendListEvent((event.LeftDown() and [wxEVT_COMMAND_LIST_FOOTER_CLICK] or \
  3761.                                             [wxEVT_COMMAND_LIST_FOOTER_RIGHT_CLICK])[0], event.GetPosition())
  3762.                        
  3763.                     self._leftDown = True
  3764.                     self._currentColumn = self._column
  3765.  
  3766.             elif event.Moving():
  3767.  
  3768.                 setCursor = False
  3769.  
  3770.                 if not self._isFooter:
  3771.                     if hit_border:
  3772.  
  3773.                         setCursor = self._currentCursor == wx.STANDARD_CURSOR
  3774.                         self._currentCursor = self._resizeCursor
  3775.  
  3776.                     else:
  3777.  
  3778.                         setCursor = self._currentCursor != wx.STANDARD_CURSOR
  3779.                         self._currentCursor = wx.STANDARD_CURSOR
  3780.  
  3781.                 if setCursor:
  3782.                     self.SetCursor(self._currentCursor)
  3783.                 else:
  3784.                     column = self.HitTestColumn(columnX, columnY)
  3785.                     self._enter = True
  3786.                     self._currentColumn = column                    
  3787.                     self._leftDown = wx.GetMouseState().LeftDown()
  3788.  
  3789.                     self.Refresh()                                            
  3790.  
  3791.             elif event.ButtonDClick():                
  3792.  
  3793.                 self.HandleColumnCheck(self._column, event.GetPosition())
  3794.                
  3795.  
  3796.     def HandleColumnCheck(self, column, pos):
  3797.  
  3798.         if column < 0 or column >= self._owner.GetColumnCount():
  3799.             return False
  3800.        
  3801.         colItem = self._owner.GetColumn(column)
  3802.         # Let's see if it is a checkbox-type item
  3803.  
  3804.         kind = (self._isFooter and [colItem.GetFooterKind()] or [colItem.GetKind()])[0]
  3805.         if kind not in [1, 2]:
  3806.             return False
  3807.  
  3808.         x = HEADER_OFFSET_X
  3809.        
  3810.         for i in xrange(self._owner.GetColumnCount()):
  3811.  
  3812.             if not self.IsColumnShown(i):
  3813.                 continue
  3814.  
  3815.             if i == self._column:
  3816.                 theX = x
  3817.                 break
  3818.             x += self._owner.GetColumnWidth(i)
  3819.  
  3820.         parent = self.GetParent()
  3821.        
  3822.         w, h = self.GetClientSize()
  3823.         ix, iy = self._owner.GetCheckboxImageSize()
  3824.         rect = wx.Rect(theX + HEADER_OFFSET_X, HEADER_OFFSET_Y + (h - 4 - iy)/2, ix, iy)
  3825.        
  3826.         if rect.Contains(pos):
  3827.             # User clicked on the checkbox
  3828.             evt = (self._isFooter and [wxEVT_COMMAND_LIST_FOOTER_CHECKING] or [wxEVT_COMMAND_LIST_COL_CHECKING])[0]
  3829.             if self.SendListEvent(evt, pos):
  3830.                 # No veto for the item checking
  3831.                 if self._isFooter:
  3832.                     isChecked = colItem.IsFooterChecked()
  3833.                     colItem.CheckFooter(not isChecked)                    
  3834.                 else:
  3835.                     isChecked = colItem.IsChecked()
  3836.                     colItem.Check(not isChecked)
  3837.                    
  3838.                 self._owner.SetColumn(column, colItem)
  3839.                 evt = (self._isFooter and [wxEVT_COMMAND_LIST_FOOTER_CHECKED] or [wxEVT_COMMAND_LIST_COL_CHECKED])[0]
  3840.                 self.SendListEvent(evt, pos)
  3841.                 self.RefreshRect(rect)
  3842.  
  3843.                 if self._isFooter:
  3844.                     return True
  3845.                
  3846.                 if parent.HasExtraFlag(ULC_AUTO_CHECK_CHILD):
  3847.                     self._owner.AutoCheckChild(isChecked, self._column)
  3848.                 elif parent.HasExtraFlag(ULC_AUTO_TOGGLE_CHILD):
  3849.                     self._owner.AutoToggleChild(self._column)
  3850.  
  3851.                 return True
  3852.  
  3853.         return False
  3854.  
  3855.  
  3856.     def OnEnterWindow(self, event):
  3857.  
  3858.         x, y = self._owner.CalcUnscrolledPosition(*self.ScreenToClient(wx.GetMousePosition()))
  3859.         column = self.HitTestColumn(x, y)
  3860.  
  3861.         self._leftDown = wx.GetMouseState().LeftDown()
  3862.         self._enter = column >= 0 and column < self._owner.GetColumnCount()
  3863.         self._currentColumn = column
  3864.         self.Refresh()
  3865.  
  3866.  
  3867.     def OnLeaveWindow(self, event):
  3868.  
  3869.         self._enter = False
  3870.         self._leftDown = False
  3871.        
  3872.         self._currentColumn = -1
  3873.         self.Refresh()
  3874.  
  3875.  
  3876.     def HitTestColumn(self, x, y):
  3877.        
  3878.         xOld = 0
  3879.        
  3880.         for i in xrange(self._owner.GetColumnCount()):
  3881.             if not self.IsColumnShown(i):
  3882.                 continue
  3883.                            
  3884.             xOld += self._owner.GetColumnWidth(i)
  3885.             if x <= xOld:
  3886.                 return i
  3887.  
  3888.         return -1            
  3889.                
  3890.        
  3891.     def OnSetFocus(self, event):
  3892.  
  3893.         self._owner.SetFocusIgnoringChildren()
  3894.         self._owner.Update()
  3895.  
  3896.  
  3897.     def SendListEvent(self, eventType, pos):
  3898.  
  3899.         parent = self.GetParent()
  3900.         le = UltimateListEvent(eventType, parent.GetId())
  3901.         le.SetEventObject(parent)
  3902.         le.m_pointDrag = pos
  3903.  
  3904.         # the position should be relative to the parent window, not
  3905.         # this one for compatibility with MSW and common sense: the
  3906.         # user code doesn't know anything at all about this header
  3907.         # window, so why should it get positions relative to it?
  3908.         le.m_pointDrag.y -= self.GetSize().y
  3909.  
  3910.         le.m_col = self._column
  3911.         return (not parent.GetEventHandler().ProcessEvent(le) or le.IsAllowed())
  3912.  
  3913.  
  3914.     def GetOwner(self):
  3915.  
  3916.         return self._owner
  3917.  
  3918.  
  3919.  
  3920. #-----------------------------------------------------------------------------
  3921. #  UltimateListRenameTimer (internal)
  3922. #-----------------------------------------------------------------------------
  3923.  
  3924. class UltimateListRenameTimer(wx.Timer):
  3925.     """Timer used for enabling in-place edit."""
  3926.  
  3927.     def __init__(self, owner):
  3928.         """
  3929.        Default class constructor.
  3930.        For internal use: do not call it in your code!
  3931.        """
  3932.        
  3933.         wx.Timer.__init__(self)
  3934.         self._owner = owner        
  3935.  
  3936.  
  3937.     def Notify(self):
  3938.         """The timer has expired."""
  3939.  
  3940.         self._owner.OnRenameTimer()
  3941.        
  3942.  
  3943. #-----------------------------------------------------------------------------
  3944. #  UltimateListTextCtrl (internal)
  3945. #-----------------------------------------------------------------------------
  3946.  
  3947. class UltimateListTextCtrl(ExpandoTextCtrl):
  3948.  
  3949.     def __init__(self, owner, itemEdit):
  3950.  
  3951.         self._startValue = owner.GetItemText(itemEdit)
  3952.         self._currentValue = self._startValue
  3953.        
  3954.         self._itemEdited = itemEdit
  3955.  
  3956.         self._owner = owner
  3957.         self._finished = False
  3958.         self._aboutToFinish = False
  3959.  
  3960.         rectLabel = owner.GetLineLabelRect(itemEdit)
  3961.         rectLabel.x, rectLabel.y = self._owner.CalcScrolledPosition(rectLabel.x, rectLabel.y)
  3962.         xSize, ySize = rectLabel.width + 10, rectLabel.height
  3963.  
  3964.         expandoStyle = wx.WANTS_CHARS
  3965.         if wx.Platform in ["__WXGTK__", "__WXMAC__"]:
  3966.             expandoStyle |= wx.SIMPLE_BORDER
  3967.         else:
  3968.             expandoStyle |= wx.SUNKEN_BORDER
  3969.            
  3970.         ExpandoTextCtrl.__init__(self, owner, -1, self._startValue, wx.Point(rectLabel.x, rectLabel.y),
  3971.                                  wx.Size(xSize, ySize), expandoStyle)
  3972.  
  3973.         self.Bind(wx.EVT_CHAR, self.OnChar)
  3974.         self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
  3975.         self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
  3976.  
  3977.  
  3978.     def AcceptChanges(self):
  3979.         """Accepts/refuses the changes made by the user."""
  3980.  
  3981.         value = self.GetValue()
  3982.  
  3983.         if value == self._startValue:
  3984.             # nothing changed, always accept
  3985.             # when an item remains unchanged, the owner
  3986.             # needs to be notified that the user decided
  3987.             # not to change the tree item label, and that
  3988.             # the edit has been cancelled
  3989.             self._owner.OnRenameCancelled(self._itemEdited)
  3990.             return True
  3991.  
  3992.         if not self._owner.OnRenameAccept(self._itemEdited, value):
  3993.             # vetoed by the user
  3994.             return False
  3995.  
  3996.         # accepted, do rename the item
  3997.         self._owner.SetItemText(self._itemEdited, value)
  3998.        
  3999.         if value.count("\n") != self._startValue.count("\n"):
  4000.             self._owner.ResetLineDimensions()
  4001.             self._owner.Refresh()
  4002.        
  4003.         return True
  4004.  
  4005.  
  4006.     def Finish(self):
  4007.         """Finish editing."""
  4008.  
  4009.         try:
  4010.             if not self._finished:
  4011.                 self._finished = True
  4012.                 self._owner.SetFocusIgnoringChildren()
  4013.                 self._owner.ResetTextControl()
  4014.         except wx.PyDeadObjectError:
  4015.             return
  4016.        
  4017.  
  4018.     def OnChar(self, event):
  4019.         """Handles the wx.EVT_CHAR event for UltimateListTextCtrl."""
  4020.  
  4021.         keycode = event.GetKeyCode()
  4022.         shiftDown = event.ShiftDown()
  4023.  
  4024.         if keycode in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
  4025.             if shiftDown:
  4026.                 event.Skip()
  4027.             else:
  4028.                 self._aboutToFinish = True
  4029.                 self.SetValue(self._currentValue)
  4030.                 # Notify the owner about the changes
  4031.                 self.AcceptChanges()
  4032.                 # Even if vetoed, close the control (consistent with MSW)
  4033.                 wx.CallAfter(self.Finish)
  4034.  
  4035.         elif keycode == wx.WXK_ESCAPE:
  4036.             self.StopEditing()
  4037.  
  4038.         else:
  4039.             event.Skip()
  4040.    
  4041.  
  4042.     def OnKeyUp(self, event):
  4043.         """Handles the wx.EVT_KEY_UP event for UltimateListTextCtrl."""
  4044.  
  4045.         if not self._finished:
  4046.  
  4047.             # auto-grow the textctrl:
  4048.             parentSize = self._owner.GetSize()
  4049.             myPos = self.GetPosition()
  4050.             mySize = self.GetSize()
  4051.  
  4052.             dc = wx.ClientDC(self)
  4053.             sx, sy, dummy = dc.GetMultiLineTextExtent(self.GetValue() + "M")
  4054.  
  4055.             if myPos.x + sx > parentSize.x:
  4056.                 sx = parentSize.x - myPos.x
  4057.             if mySize.x > sx:
  4058.                 sx = mySize.x
  4059.                
  4060.             self.SetSize((sx, -1))
  4061.             self._currentValue = self.GetValue()
  4062.  
  4063.         event.Skip()
  4064.  
  4065.  
  4066.     def OnKillFocus(self, event):
  4067.         """Handles the wx.EVT_KILL_FOCUS event for UltimateListTextCtrl."""
  4068.        
  4069.         if not self._finished and not self._aboutToFinish:
  4070.        
  4071.             # We must finish regardless of success, otherwise we'll get
  4072.             # focus problems:
  4073.            
  4074.             if not self.AcceptChanges():
  4075.                 self._owner.OnRenameCancelled(self._itemEdited)
  4076.        
  4077.         # We must let the native text control handle focus, too, otherwise
  4078.         # it could have problems with the cursor (e.g., in wxGTK).
  4079.         event.Skip()
  4080.         wx.CallAfter(self.Finish)
  4081.  
  4082.  
  4083.     def StopEditing(self):
  4084.         """Suddenly stops the editing."""
  4085.  
  4086.         self._owner.OnRenameCancelled(self._itemEdited)
  4087.         self.Finish()
  4088.  
  4089.  
  4090. #-----------------------------------------------------------------------------
  4091. #  UltimateListMainWindow (internal)
  4092. #-----------------------------------------------------------------------------
  4093.  
  4094. class UltimateListMainWindow(wx.PyScrolledWindow):
  4095.  
  4096.     def __init__(self, parent, id, pos=wx.DefaultPosition,
  4097.                  size=wx.DefaultSize, style=0, name="listctrlmainwindow"):
  4098.  
  4099.         wx.PyScrolledWindow.__init__(self, parent, id, pos, size, style|wx.HSCROLL|wx.VSCROLL, name)
  4100.  
  4101.         # the list of column objects
  4102.         self._columns = []
  4103.  
  4104.         # the array of all line objects for a non virtual list control (for the
  4105.         # virtual list control we only ever use self._lines[0])
  4106.         self._lines = []
  4107.  
  4108.         # currently focused item or -1
  4109.         self._current = -1
  4110.  
  4111.         # the number of lines per page
  4112.         self._linesPerPage = 0
  4113.  
  4114.         # this flag is set when something which should result in the window
  4115.         # redrawing happens (i.e. an item was added or deleted, or its appearance
  4116.         # changed) and OnPaint() doesn't redraw the window while it is set which
  4117.         # allows to minimize the number of repaintings when a lot of items are
  4118.         # being added. The real repainting occurs only after the next OnIdle()
  4119.         # call
  4120.         self._dirty = False
  4121.         self._parent = parent
  4122.         self.Init()
  4123.  
  4124.         self._highlightBrush = wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT), wx.SOLID)
  4125.        
  4126.         btnshadow = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
  4127.         self._highlightUnfocusedBrush = wx.Brush(btnshadow, wx.SOLID)
  4128.         r, g, b = btnshadow.Red(), btnshadow.Green(), btnshadow.Blue()
  4129.         backcolour = (max((r >> 1) - 20, 0),
  4130.                       max((g >> 1) - 20, 0),
  4131.                       max((b >> 1) - 20, 0))
  4132.         backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
  4133.         self._highlightUnfocusedBrush2 = wx.Brush(backcolour)
  4134.        
  4135.         self.SetScrollbars(0, 0, 0, 0, 0, 0)
  4136.  
  4137.         attr = wx.ListCtrl.GetClassDefaultAttributes()
  4138.         self.SetOwnForegroundColour(attr.colFg)
  4139.         self.SetOwnBackgroundColour(attr.colBg)        
  4140.         self.SetOwnFont(attr.font)
  4141.  
  4142.         self.Bind(wx.EVT_PAINT, self.OnPaint)
  4143.         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
  4144.         self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
  4145.         self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
  4146.         self.Bind(wx.EVT_CHAR, self.OnChar)
  4147.         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
  4148.         self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)        
  4149.         self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
  4150.         self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
  4151.         self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
  4152.         self.Bind(wx.EVT_TIMER, self.OnHoverTimer, self._hoverTimer)
  4153.        
  4154.  
  4155.     def Init(self):
  4156.  
  4157.         self._dirty = True
  4158.         self._countVirt = 0
  4159.         self._lineFrom = None
  4160.         self._lineTo = - 1
  4161.         self._linesPerPage = 0
  4162.  
  4163.         self._headerWidth = 0
  4164.         self._lineHeight = 0
  4165.  
  4166.         self._small_image_list = None
  4167.         self._normal_image_list = None
  4168.  
  4169.         self._small_spacing = 30
  4170.         self._normal_spacing = 40
  4171.  
  4172.         self._hasFocus = False
  4173.         self._dragCount = 0
  4174.         self._isCreated = False
  4175.  
  4176.         self._lastOnSame = False
  4177.         self._renameTimer = UltimateListRenameTimer(self)
  4178.         self._textctrl = None
  4179.  
  4180.         self._current = -1
  4181.         self._lineLastClicked = -1
  4182.         self._lineSelectSingleOnUp = -1
  4183.         self._lineBeforeLastClicked = -1
  4184.  
  4185.         self._dragStart = wx.Point(-1, -1)
  4186.         self._aColWidths = []
  4187.  
  4188.         self._selStore = SelectionStore()
  4189.         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  4190.  
  4191.         # Background image settings
  4192.         self._backgroundImage = None
  4193.         self._imageStretchStyle = _StyleTile
  4194.  
  4195.         # Disabled items colour        
  4196.         self._disabledColour = wx.Colour(180, 180, 180)
  4197.  
  4198.         # Gradient selection colours        
  4199.         self._firstcolour = colour= wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
  4200.         self._secondcolour = wx.WHITE
  4201.         self._usegradients = False
  4202.         self._gradientstyle = 1   # Vertical Gradient
  4203.  
  4204.         # Vista Selection Styles
  4205.         self._vistaselection = False
  4206.  
  4207.         self.SetImageListCheck(16, 16)        
  4208.        
  4209.         # Disabled items colour        
  4210.         self._disabledColour = wx.Colour(180, 180, 180)
  4211.  
  4212.         # Hyperlinks things
  4213.         normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
  4214.         self._hypertextfont = wx.Font(normalFont.GetPointSize(), normalFont.GetFamily(),
  4215.                                       normalFont.GetStyle(), wx.NORMAL, True,
  4216.                                       normalFont.GetFaceName(), normalFont.GetEncoding())
  4217.         self._hypertextnewcolour = wx.BLUE
  4218.         self._hypertextvisitedcolour = wx.Colour(200, 47, 200)
  4219.         self._isonhyperlink = False
  4220.  
  4221.         self._itemWithWindow = []
  4222.         self._hasWindows = False
  4223.         self._shortItems = []
  4224.  
  4225.         self._isDragging = False
  4226.         self._cursor = wx.STANDARD_CURSOR
  4227.  
  4228.         image = GetdragcursorImage()
  4229.  
  4230.         # since this image didn't come from a .cur file, tell it where the hotspot is
  4231.         image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 1)
  4232.         image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 1)
  4233.  
  4234.         # make the image into a cursor
  4235.         self._dragCursor = wx.CursorFromImage(image)
  4236.         self._dragItem = None
  4237.         self._dropTarget = None
  4238.  
  4239.         self._oldHotCurrent = None
  4240.         self._newHotCurrent = None
  4241.  
  4242.         self._waterMark = None
  4243.  
  4244.         self._hoverTimer = wx.Timer(self, wx.ID_ANY)
  4245.         self._hoverItem = -1
  4246.  
  4247.  
  4248.     def GetMainWindowOfCompositeControl(self):
  4249.  
  4250.         return self.GetParent()
  4251.  
  4252.  
  4253.     def DoGetBestSize(self):
  4254.  
  4255.         return wx.Size(100, 80)
  4256.    
  4257.  
  4258.     def HasFlag(self, flag):
  4259.  
  4260.         return self._parent.HasFlag(flag)
  4261.  
  4262.  
  4263.     def HasExtraFlag(self, flag):
  4264.  
  4265.         return self._parent.HasExtraFlag(flag)
  4266.    
  4267.  
  4268.     def IsColumnShown(self, column):
  4269.  
  4270.         return self.GetColumn(column).IsShown()
  4271.  
  4272.  
  4273.     # return True if this is a virtual list control
  4274.     def IsVirtual(self):
  4275.  
  4276.         return self.HasFlag(ULC_VIRTUAL)
  4277.  
  4278.  
  4279.     # return True if the control is in report mode
  4280.     def InReportView(self):
  4281.  
  4282.         return self.HasFlag(ULC_REPORT)
  4283.  
  4284.  
  4285.     def InTileView(self):
  4286.  
  4287.         return self.HasFlag(ULC_TILE)        
  4288.  
  4289.     # return True if we are in single selection mode, False if multi sel
  4290.     def IsSingleSel(self):
  4291.  
  4292.         return self.HasFlag(ULC_SINGLE_SEL)
  4293.  
  4294.  
  4295.     def HasFocus(self):
  4296.  
  4297.         return self._hasFocus
  4298.  
  4299.    
  4300.     # do we have a header window?
  4301.     def HasHeader(self):
  4302.  
  4303.         if (self.InReportView() or self.InTileView()) and not self.HasFlag(ULC_NO_HEADER):
  4304.             return True
  4305.         if self.HasExtraFlag(ULC_HEADER_IN_ALL_VIEWS):
  4306.             return True
  4307.  
  4308.         return False
  4309.  
  4310.  
  4311.     # do we have a footer window?
  4312.     def HasFooter(self):
  4313.  
  4314.         if self.HasHeader() and self.HasExtraFlag(ULC_FOOTER):
  4315.             return True
  4316.  
  4317.         return False
  4318.  
  4319.  
  4320.     # toggle the line state and refresh it
  4321.     def ReverseHighlight(self, line):
  4322.  
  4323.         self.HighlightLine(line, not self.IsHighlighted(line))
  4324.         self.RefreshLine(line)
  4325.  
  4326.  
  4327.     # get the size of the total line rect
  4328.     def GetLineSize(self, line):
  4329.  
  4330.         return self.GetLineRect(line).GetSize()
  4331.  
  4332.  
  4333.     # bring the current item into view
  4334.     def MoveToFocus(self):
  4335.  
  4336.         self.MoveToItem(self._current)
  4337.  
  4338.  
  4339.     def GetColumnCount(self):
  4340.  
  4341.         return len(self._columns)
  4342.  
  4343.  
  4344.     def GetItemText(self, item):
  4345.  
  4346.         info = UltimateListItem()
  4347.         info._mask = ULC_MASK_TEXT
  4348.         info._itemId = item
  4349.         info = self.GetItem(info)
  4350.  
  4351.         return info._text
  4352.  
  4353.  
  4354.     def SetItemText(self, item, value):
  4355.  
  4356.         info = UltimateListItem()
  4357.         info._mask = ULC_MASK_TEXT
  4358.         info._itemId = item
  4359.         info._text = value
  4360.  
  4361.         self.SetItem(info)
  4362.  
  4363.  
  4364.     def IsEmpty(self):
  4365.  
  4366.         return self.GetItemCount() == 0
  4367.  
  4368.  
  4369.     def ResetCurrent(self):
  4370.  
  4371.         self.ChangeCurrent(-1)
  4372.  
  4373.  
  4374.     def HasCurrent(self):
  4375.  
  4376.         return self._current != -1
  4377.  
  4378.  
  4379.     # override base class virtual to reset self._lineHeight when the font changes
  4380.     def SetFont(self, font):
  4381.  
  4382.         if not wx.PyScrolledWindow.SetFont(self, font):
  4383.             return False
  4384.  
  4385.         self._lineHeight = 0
  4386.         self.ResetLineDimensions()
  4387.  
  4388.         return True
  4389.  
  4390.  
  4391.     def ResetLineDimensions(self, force=False):
  4392.  
  4393.         if (self.HasFlag(ULC_REPORT) and self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT) and not self.IsVirtual()) or force:
  4394.             for l in xrange(self.GetItemCount()):
  4395.                 line = self.GetLine(l)
  4396.                 line.ResetDimensions()
  4397.        
  4398.     # these are for UltimateListLineData usage only
  4399.     # get the backpointer to the list ctrl
  4400.     def GetListCtrl(self):
  4401.  
  4402.         return self.GetParent()
  4403.  
  4404.  
  4405.     # get the brush to use for the item highlighting
  4406.     def GetHighlightBrush(self):
  4407.  
  4408.         return (self._hasFocus and [self._highlightBrush] or [self._highlightUnfocusedBrush])[0]
  4409.  
  4410.  
  4411.     # get the line data for the given index
  4412.     def GetLine(self, n):
  4413.  
  4414.         if self.IsVirtual():
  4415.  
  4416.             self.CacheLineData(n)
  4417.             n = 0
  4418.  
  4419.         return self._lines[n]
  4420.  
  4421.  
  4422.     # force us to recalculate the range of visible lines
  4423.     def ResetVisibleLinesRange(self, reset=False):
  4424.  
  4425.         self._lineFrom = -1
  4426.         if self.IsShownOnScreen() and reset:
  4427.             self.ResetLineDimensions()
  4428.  
  4429.  
  4430.     # get the colour to be used for drawing the rules
  4431.     def GetRuleColour(self):
  4432.  
  4433.         return wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DLIGHT)
  4434.  
  4435.  
  4436.     def CacheLineData(self, line):
  4437.  
  4438.         listctrl = self.GetListCtrl()
  4439.         ld = self.GetDummyLine()
  4440.  
  4441.         countCol = self.GetColumnCount()
  4442.         for col in xrange(countCol):
  4443.             ld.SetText(col, listctrl.OnGetItemText(line, col))
  4444.             ld.SetImage(col, listctrl.OnGetItemColumnImage(line, col))
  4445.             kind = listctrl.OnGetItemColumnKind(line, col)
  4446.             ld.SetKind(col, kind)
  4447.             if kind > 0:
  4448.                 ld.Check(col, listctrl.OnGetItemColumnCheck(line, col))
  4449.  
  4450.         ld.SetAttr(listctrl.OnGetItemAttr(line))
  4451.  
  4452.  
  4453.     def GetDummyLine(self):
  4454.  
  4455.         if self.IsEmpty():
  4456.             raise Exception("invalid line index")
  4457.  
  4458.         if not self.IsVirtual():
  4459.             raise Exception("GetDummyLine() shouldn't be called")
  4460.  
  4461.         # we need to recreate the dummy line if the number of columns in the
  4462.         # control changed as it would have the incorrect number of fields
  4463.         # otherwise
  4464.         if len(self._lines) > 0 and len(self._lines[0]._items) != self.GetColumnCount():
  4465.             self._lines = []
  4466.  
  4467.         if not self._lines:
  4468.             line = UltimateListLineData(self)
  4469.             self._lines.append(line)
  4470.  
  4471.         return self._lines[0]
  4472.  
  4473.  
  4474. # ----------------------------------------------------------------------------
  4475. # line geometry (report mode only)
  4476. # ----------------------------------------------------------------------------
  4477.  
  4478.     def GetLineHeight(self, item=None):
  4479.  
  4480.         # we cache the line height as calling GetTextExtent() is slow
  4481.  
  4482.         if item is None or not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  4483.            
  4484.             if not self._lineHeight:
  4485.                 dc = wx.ClientDC(self)
  4486.                 dc.SetFont(self.GetFont())
  4487.  
  4488.                 dummy, y = dc.GetTextExtent("H")
  4489.                 if self._small_image_list and self._small_image_list.GetImageCount():
  4490.                     iw, ih = self._small_image_list.GetSize(0)
  4491.                     y = max(y, ih)
  4492.  
  4493.                 y += EXTRA_HEIGHT
  4494.                 self._lineHeight = y + LINE_SPACING
  4495.  
  4496.             return self._lineHeight
  4497.                
  4498.         else:
  4499.  
  4500.             line = self.GetLine(item)
  4501.             LH = line.GetHeight()
  4502.             if LH != -1:
  4503.                 return LH
  4504.  
  4505.             dc = wx.ClientDC(self)
  4506.            
  4507.             allTextY = 0
  4508.            
  4509.             for col, items in enumerate(line._items):
  4510.  
  4511.                 if items.GetCustomRenderer():
  4512.                     allTextY = max(allTextY, items.GetCustomRenderer().GetLineHeight())
  4513.                     continue
  4514.  
  4515.                 if items.HasFont():
  4516.                     dc.SetFont(items.GetFont())
  4517.                 else:
  4518.                     dc.SetFont(self.GetFont())
  4519.  
  4520.                 text_x, text_y, dummy = dc.GetMultiLineTextExtent(items.GetText())
  4521.                 allTextY = max(text_y, allTextY)
  4522.  
  4523.                 if items.GetWindow():
  4524.                     xSize, ySize = items.GetWindowSize()
  4525.                     allTextY = max(allTextY, ySize)
  4526.  
  4527.                 if self._small_image_list and self._small_image_list.GetImageCount():
  4528.                     for img in items._image:
  4529.                         iw, ih = self._small_image_list.GetSize(img)
  4530.                         allTextY = max(allTextY, ih)
  4531.  
  4532.             allTextY += EXTRA_HEIGHT
  4533.             line.SetHeight(allTextY)
  4534.  
  4535.             return allTextY
  4536.  
  4537.  
  4538.     def GetLineY(self, line):
  4539.  
  4540.         if self.IsVirtual():
  4541.             return LINE_SPACING + line*self.GetLineHeight()
  4542.        
  4543.         lineItem = self.GetLine(line)
  4544.         lineY = lineItem.GetY()
  4545.         if lineY != -1:
  4546.             return lineY
  4547.        
  4548.         lineY = 0
  4549.         for l in xrange(line):
  4550.             lineY += self.GetLineHeight(l)
  4551.  
  4552.         lineItem.SetY(LINE_SPACING + lineY)
  4553.         return LINE_SPACING + lineY
  4554.  
  4555.  
  4556.     def GetLineRect(self, line):
  4557.  
  4558.         if not self.InReportView():
  4559.             return self.GetLine(line)._gi._rectAll
  4560.  
  4561.         rect = wx.Rect(HEADER_OFFSET_X, self.GetLineY(line), self.GetHeaderWidth(), self.GetLineHeight(line))
  4562.         return rect
  4563.  
  4564.  
  4565.     def GetLineLabelRect(self, line):
  4566.  
  4567.         if not self.InReportView():
  4568.             return self.GetLine(line)._gi._rectLabel
  4569.  
  4570.         image_x = 0
  4571.         item = self.GetLine(line)
  4572.         if item.HasImage():
  4573.             ix, iy = self.GetImageSize(item.GetImage())
  4574.             image_x = ix
  4575.  
  4576.         if item.GetKind() in [1, 2]:
  4577.             image_x += self.GetCheckboxImageSize()[0]
  4578.            
  4579.         rect = wx.Rect(image_x + HEADER_OFFSET_X, self.GetLineY(line), self.GetColumnWidth(0) - image_x, self.GetLineHeight(line))
  4580.         return rect
  4581.    
  4582.  
  4583.     def GetLineIconRect(self, line):
  4584.  
  4585.         if not self.InReportView():
  4586.             return self.GetLine(line)._gi._rectIcon
  4587.  
  4588.         ld = self.GetLine(line)
  4589.  
  4590.         image_x = HEADER_OFFSET_X
  4591.         if ld.GetKind() in [1, 2]:
  4592.             image_x += self.GetCheckboxImageSize()[0]
  4593.            
  4594.         rect = wx.Rect(image_x, self.GetLineY(line), *self.GetImageSize(ld.GetImage()))
  4595.         return rect
  4596.  
  4597.  
  4598.     def GetLineCheckboxRect(self, line):
  4599.  
  4600.         if not self.InReportView():
  4601.             return self.GetLine(line)._gi._rectCheck
  4602.        
  4603.         ld = self.GetLine(line)
  4604.         LH = self.GetLineHeight(line)
  4605.         wcheck, hcheck = self.GetCheckboxImageSize()
  4606.         rect = wx.Rect(HEADER_OFFSET_X, self.GetLineY(line) + LH/2 - hcheck/2, wcheck, hcheck)
  4607.         return rect
  4608.    
  4609.  
  4610.     def GetLineHighlightRect(self, line):
  4611.  
  4612.         return (self.InReportView() and [self.GetLineRect(line)] or [self.GetLine(line)._gi._rectHighlight])[0]
  4613.  
  4614.  
  4615.     def HitTestLine(self, line, x, y):
  4616.  
  4617.         ld = self.GetLine(line)
  4618.  
  4619.         if self.InReportView() and not self.IsVirtual():
  4620.  
  4621.             lineY = self.GetLineY(line)
  4622.             xstart = HEADER_OFFSET_X
  4623.            
  4624.             for col, item in enumerate(ld._items):
  4625.  
  4626.                 width = self.GetColumnWidth(col)
  4627.                 xOld = xstart
  4628.                 xstart += width
  4629.                 ix = 0
  4630.  
  4631.                 if (line, col) in self._shortItems:
  4632.                     rect = wx.Rect(xOld, lineY, width, self.GetLineHeight(line))
  4633.                     if rect.Contains((x, y)):
  4634.                         newItem = self.GetParent().GetItem(line, col)
  4635.                         return newItem, ULC_HITTEST_ONITEM
  4636.                
  4637.                 if item.GetKind() in [1, 2]:
  4638.                     # We got a checkbox-type item
  4639.                     ix, iy = self.GetCheckboxImageSize()
  4640.                     LH = self.GetLineHeight(line)
  4641.                     rect = wx.Rect(xOld, lineY + LH/2 - iy/2, ix, iy)
  4642.                     if rect.Contains((x, y)):
  4643.                         newItem = self.GetParent().GetItem(line, col)
  4644.                         return newItem, ULC_HITTEST_ONITEMCHECK
  4645.                    
  4646.                 if item.IsHyperText():
  4647.                     start, end = self.GetItemTextSize(item)
  4648.                     rect = wx.Rect(xOld+start, lineY, end, self.GetLineHeight(line))
  4649.                     if rect.Contains((x, y)):
  4650.                         newItem = self.GetParent().GetItem(line, col)
  4651.                         return newItem, ULC_HITTEST_ONITEMLABEL
  4652.                    
  4653.                     xOld += ix
  4654.                
  4655.         if ld.HasImage() and self.GetLineIconRect(line).Contains((x, y)):
  4656.             return self.GetParent().GetItem(line), ULC_HITTEST_ONITEMICON
  4657.        
  4658.         # VS: Testing for "ld.HasText() || InReportView()" instead of
  4659.         #     "ld.HasText()" is needed to make empty lines in report view
  4660.         #     possible
  4661.         if ld.HasText() or self.InReportView():
  4662.             if self.InReportView():
  4663.                 rect = self.GetLineRect(line)
  4664.             else:
  4665.                 checkRect = self.GetLineCheckboxRect(line)
  4666.                 if checkRect.Contains((x, y)):
  4667.                     return self.GetParent().GetItem(line), ULC_HITTEST_ONITEMCHECK
  4668.  
  4669.                 rect = self.GetLineLabelRect(line)
  4670.                
  4671.         if rect.Contains((x, y)):
  4672.             return self.GetParent().GetItem(line), ULC_HITTEST_ONITEMLABEL
  4673.  
  4674.         rect = self.GetLineRect(line)
  4675.         if rect.Contains((x, y)):
  4676.             return self.GetParent().GetItem(line), ULC_HITTEST_ONITEM
  4677.  
  4678.         return None, 0
  4679.  
  4680.  
  4681. # ----------------------------------------------------------------------------
  4682. # highlight (selection) handling
  4683. # ----------------------------------------------------------------------------
  4684.  
  4685.     def IsHighlighted(self, line):
  4686.  
  4687.         if self.IsVirtual():
  4688.  
  4689.             return self._selStore.IsSelected(line)
  4690.  
  4691.         else: # !virtual
  4692.  
  4693.             ld = self.GetLine(line)
  4694.             return ld.IsHighlighted()
  4695.  
  4696.  
  4697.     def HighlightLines(self, lineFrom, lineTo, highlight=True):
  4698.  
  4699.         if self.IsVirtual():
  4700.             linesChanged = self._selStore.SelectRange(lineFrom, lineTo, highlight)
  4701.             if not linesChanged:
  4702.                 # many items changed state, refresh everything
  4703.                 self.RefreshLines(lineFrom, lineTo)
  4704.  
  4705.             else: # only a few items changed state, refresh only them
  4706.  
  4707.                 for n in xrange(len(linesChanged)):
  4708.                     self.RefreshLine(linesChanged[n])
  4709.  
  4710.         else: # iterate over all items in non report view
  4711.  
  4712.             for line in xrange(lineFrom, lineTo+1):
  4713.                 if self.HighlightLine(line, highlight):
  4714.                     self.RefreshLine(line)
  4715.  
  4716.  
  4717.     def HighlightLine(self, line, highlight=True):
  4718.  
  4719.         changed = False
  4720.  
  4721.         if self.IsVirtual():
  4722.  
  4723.             changed = self._selStore.SelectItem(line, highlight)
  4724.  
  4725.         else: # !virtual
  4726.  
  4727.             ld = self.GetLine(line)
  4728.             changed = ld.Highlight(highlight)
  4729.  
  4730.         dontNotify = self.HasExtraFlag(ULC_STICKY_HIGHLIGHT) and self.HasExtraFlag(ULC_STICKY_NOSELEVENT)
  4731.  
  4732.         if changed and not dontNotify:
  4733.             self.SendNotify(line, (highlight and [wxEVT_COMMAND_LIST_ITEM_SELECTED] or [wxEVT_COMMAND_LIST_ITEM_DESELECTED])[0])
  4734.  
  4735.         return changed
  4736.  
  4737.  
  4738.     def RefreshLine(self, line):
  4739.  
  4740.         if self.InReportView():
  4741.  
  4742.             visibleFrom, visibleTo = self.GetVisibleLinesRange()
  4743.             if line < visibleFrom or line > visibleTo:
  4744.                 return
  4745.  
  4746.         rect = self.GetLineRect(line)
  4747.         rect.x, rect.y  = self.CalcScrolledPosition(rect.x, rect.y)
  4748.         self.RefreshRect(rect)
  4749.  
  4750.  
  4751.     def RefreshLines(self, lineFrom, lineTo):
  4752.  
  4753.         if self.InReportView():
  4754.  
  4755.             visibleFrom, visibleTo = self.GetVisibleLinesRange()
  4756.  
  4757.             if lineFrom < visibleFrom:
  4758.                 lineFrom = visibleFrom
  4759.             if lineTo > visibleTo:
  4760.                 lineTo = visibleTo
  4761.  
  4762.             rect = wx.Rect()
  4763.             rect.x = 0
  4764.             rect.y = self.GetLineY(lineFrom)
  4765.             rect.width = self.GetClientSize().x
  4766.             rect.height = self.GetLineY(lineTo) - rect.y + self.GetLineHeight(lineTo)
  4767.  
  4768.             rect.x, rect.y  = self.CalcScrolledPosition(rect.x, rect.y)
  4769.             self.RefreshRect(rect)
  4770.  
  4771.         else: # !report
  4772.  
  4773.             # TODO: this should be optimized...
  4774.             for line in xrange(lineFrom, lineTo+1):
  4775.                 self.RefreshLine(line)
  4776.  
  4777.  
  4778.     def RefreshAfter(self, lineFrom):
  4779.  
  4780.         if self.InReportView():
  4781.  
  4782.             visibleFrom, visibleTo = self.GetVisibleLinesRange()
  4783.  
  4784.             if lineFrom < visibleFrom:
  4785.                 lineFrom = visibleFrom
  4786.             elif lineFrom > visibleTo:
  4787.                 return
  4788.  
  4789.             rect = wx.Rect()
  4790.             rect.x = 0
  4791.             rect.y = self.GetLineY(lineFrom)
  4792.             rect.x, rect.y  = self.CalcScrolledPosition(rect.x, rect.y)
  4793.  
  4794.             size = self.GetClientSize()
  4795.             rect.width = size.x
  4796.             # refresh till the bottom of the window
  4797.             rect.height = size.y - rect.y
  4798.  
  4799.             self.RefreshRect(rect)
  4800.  
  4801.         else: # !report
  4802.  
  4803.             # TODO: how to do it more efficiently?
  4804.             self._dirty = True
  4805.  
  4806.  
  4807.     def RefreshSelected(self):
  4808.  
  4809.         if self.IsEmpty():
  4810.             return
  4811.  
  4812.         if self.InReportView():
  4813.  
  4814.             fromm, to = self.GetVisibleLinesRange()
  4815.  
  4816.         else: # !virtual
  4817.  
  4818.             fromm = 0
  4819.             to = self.GetItemCount() - 1
  4820.  
  4821.         if self.HasCurrent() and self._current >= fromm and self._current <= to:
  4822.             self.RefreshLine(self._current)
  4823.  
  4824.         for line in xrange(fromm, to+1):
  4825.             # NB: the test works as expected even if self._current == -1
  4826.             if line != self._current and self.IsHighlighted(line):
  4827.                 self.RefreshLine(line)
  4828.  
  4829.  
  4830.     def HideWindows(self):
  4831.         """Hides the windows associated to the items. Used internally."""
  4832.        
  4833.         for child in self._itemWithWindow:
  4834.             wnd = child.GetWindow()
  4835.             if wnd:
  4836.                 wnd.Hide()
  4837.  
  4838.  
  4839.     def OnPaint(self, event):
  4840.  
  4841.         # Note: a wxPaintDC must be constructed even if no drawing is
  4842.         # done (a Windows requirement).
  4843.         dc = wx.BufferedPaintDC(self)
  4844.        
  4845.         dc.SetBackgroundMode(wx.TRANSPARENT)
  4846.        
  4847.         self.PrepareDC(dc)
  4848.  
  4849.         dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
  4850.         dc.SetPen(wx.TRANSPARENT_PEN)
  4851.         dc.Clear()
  4852.        
  4853.         self.TileBackground(dc)
  4854.         self.PaintWaterMark(dc)
  4855.  
  4856.         if self.IsEmpty():
  4857.             # nothing to draw or not the moment to draw it
  4858.             return
  4859.        
  4860.         if self._dirty:
  4861.             # delay the repainting until we calculate all the items positions
  4862.             self.RecalculatePositions(False)
  4863.  
  4864.         useVista, useGradient = self._vistaselection, self._usegradients
  4865.         dev_x, dev_y = self.CalcScrolledPosition(0, 0)
  4866.  
  4867.         dc.SetFont(self.GetFont())
  4868.        
  4869.         if self.InReportView():
  4870.             visibleFrom, visibleTo = self.GetVisibleLinesRange()
  4871.        
  4872.             # mrcs: draw additional items
  4873.             if visibleFrom > 0:
  4874.                 visibleFrom -= 1
  4875.  
  4876.             if visibleTo < self.GetItemCount() - 1:
  4877.                 visibleTo += 1
  4878.  
  4879.             xOrig = dc.LogicalToDeviceX(0)
  4880.             yOrig = dc.LogicalToDeviceY(0)
  4881.  
  4882.             # tell the caller cache to cache the data
  4883.             if self.IsVirtual():
  4884.  
  4885.                 evCache = UltimateListEvent(wxEVT_COMMAND_LIST_CACHE_HINT, self.GetParent().GetId())
  4886.                 evCache.SetEventObject(self.GetParent())
  4887.                 evCache.m_oldItemIndex = visibleFrom
  4888.                 evCache.m_itemIndex = visibleTo
  4889.                 self.GetParent().GetEventHandler().ProcessEvent(evCache)
  4890.  
  4891.             no_highlight = self.HasExtraFlag(ULC_NO_HIGHLIGHT)
  4892.  
  4893.             for line in xrange(visibleFrom, visibleTo+1):
  4894.                 rectLine = self.GetLineRect(line)
  4895.  
  4896.                 if not self.IsExposed(rectLine.x + xOrig, rectLine.y + yOrig, rectLine.width, rectLine.height):
  4897.                     # don't redraw unaffected lines to avoid flicker
  4898.                     continue
  4899.  
  4900.                 theLine = self.GetLine(line)
  4901.                 enabled = theLine.GetItem(0, CreateListItem(line, 0)).IsEnabled()
  4902.                 oldPN, oldBR = dc.GetPen(), dc.GetBrush()
  4903.                 theLine.DrawInReportMode(dc, line, rectLine,
  4904.                                          self.GetLineHighlightRect(line),
  4905.                                          self.IsHighlighted(line) and not no_highlight,
  4906.                                          line==self._current, enabled, oldPN, oldBR)
  4907.  
  4908.             if self.HasFlag(ULC_HRULES):
  4909.                 pen = wx.Pen(self.GetRuleColour(), 1, wx.SOLID)
  4910.                 clientSize = self.GetClientSize()
  4911.  
  4912.                 # Don't draw the first one
  4913.                 start = (visibleFrom > 0 and [visibleFrom] or [1])[0]
  4914.  
  4915.                 dc.SetPen(pen)
  4916.                 dc.SetBrush(wx.TRANSPARENT_BRUSH)
  4917.                 for i in xrange(start, visibleTo+1):
  4918.                     lineY = self.GetLineY(i)
  4919.                     dc.DrawLine(0 - dev_x, lineY, clientSize.x - dev_x, lineY)
  4920.  
  4921.                 # Draw last horizontal rule
  4922.                 if visibleTo == self.GetItemCount() - 1:
  4923.                     lineY = self.GetLineY(visibleTo) + self.GetLineHeight(visibleTo)
  4924.                     dc.SetPen(pen)
  4925.                     dc.SetBrush(wx.TRANSPARENT_BRUSH)
  4926.                     dc.DrawLine(0 - dev_x, lineY, clientSize.x - dev_x , lineY)
  4927.  
  4928.             # Draw vertical rules if required
  4929.             if self.HasFlag(ULC_VRULES) and not self.IsEmpty():
  4930.                 pen = wx.Pen(self.GetRuleColour(), 1, wx.SOLID)
  4931.  
  4932.                 firstItemRect = self.GetItemRect(visibleFrom)
  4933.                 lastItemRect = self.GetItemRect(visibleTo)
  4934.                 x = firstItemRect.GetX()
  4935.                 dc.SetPen(pen)
  4936.                 dc.SetBrush(wx.TRANSPARENT_BRUSH)
  4937.                 for col in xrange(self.GetColumnCount()):
  4938.                    
  4939.                     if not self.IsColumnShown(col):
  4940.                         continue
  4941.  
  4942.                     colWidth = self.GetColumnWidth(col)
  4943.                     x += colWidth
  4944.                    
  4945.                     x_pos = x - dev_x
  4946.                     if col < self.GetColumnCount()-1:
  4947.                         x_pos -= 2
  4948.  
  4949.                     dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y, x_pos, lastItemRect.GetBottom() + 1 - dev_y)
  4950.  
  4951.  
  4952.         else: # !report
  4953.  
  4954.             for i in xrange(self.GetItemCount()):
  4955.                 self.GetLine(i).Draw(i, dc)
  4956.  
  4957.         if wx.Platform not in ["__WXMAC__", "__WXGTK__"]:
  4958.             # Don't draw rect outline under Mac at all.
  4959.             # Draw it elsewhere on GTK
  4960.             if self.HasCurrent():
  4961.                 if self._hasFocus and not self.HasExtraFlag(ULC_NO_HIGHLIGHT) and not useVista and not useGradient \
  4962.                    and not self.HasExtraFlag(ULC_BORDER_SELECT) and not self.HasExtraFlag(ULC_NO_FULL_ROW_SELECT):
  4963.                     dc.SetPen(wx.BLACK_PEN)
  4964.                     dc.SetBrush(wx.TRANSPARENT_BRUSH)
  4965.                     dc.DrawRectangleRect(self.GetLineHighlightRect(self._current))
  4966.  
  4967.        
  4968.     def OnEraseBackground(self, event):
  4969.  
  4970.         pass
  4971.    
  4972.  
  4973.     def TileBackground(self, dc):
  4974.         """Tiles the background image to fill all the available area."""
  4975.  
  4976.         if not self._backgroundImage:
  4977.             return
  4978.  
  4979.         if self._imageStretchStyle != _StyleTile:
  4980.             # Can we actually do something here (or in OnPaint()) To Handle
  4981.             # background images that are stretchable or always centered?
  4982.             # I tried but I get enormous flickering...
  4983.             return
  4984.  
  4985.         sz = self.GetClientSize()
  4986.         w = self._backgroundImage.GetWidth()
  4987.         h = self._backgroundImage.GetHeight()
  4988.  
  4989.         x = 0
  4990.  
  4991.         while x < sz.width:
  4992.             y = 0
  4993.  
  4994.             while y < sz.height:
  4995.                 dc.DrawBitmap(self._backgroundImage, x, y, True)
  4996.                 y = y + h
  4997.  
  4998.             x = x + w
  4999.  
  5000.  
  5001.     def PaintWaterMark(self, dc):
  5002.  
  5003.         if not self._waterMark:
  5004.             return
  5005.  
  5006.         width, height = self.CalcUnscrolledPosition(*self.GetClientSize())
  5007.        
  5008.         bitmapW = self._waterMark.GetWidth()
  5009.         bitmapH = self._waterMark.GetHeight()
  5010.  
  5011.         x = width - bitmapW - 5
  5012.         y = height - bitmapH - 5
  5013.  
  5014.         dc.DrawBitmap(self._waterMark, x, y, True)
  5015.        
  5016.        
  5017.     def HighlightAll(self, on=True):
  5018.  
  5019.         if self.IsSingleSel():
  5020.  
  5021.             if on:
  5022.                 raise Exception("can't do this in a single sel control")
  5023.  
  5024.             # we just have one item to turn off
  5025.             if self.HasCurrent() and self.IsHighlighted(self._current):
  5026.                 self.HighlightLine(self._current, False)
  5027.                 self.RefreshLine(self._current)
  5028.  
  5029.         else: # multi sel
  5030.             if not self.IsEmpty():
  5031.                 self.HighlightLines(0, self.GetItemCount() - 1, on)
  5032.  
  5033.  
  5034.     def OnChildFocus(self, event):
  5035.  
  5036.         # Do nothing here.  This prevents the default handler in wxScrolledWindow
  5037.         # from needlessly scrolling the window when the edit control is
  5038.         # dismissed.  See ticket #9563.
  5039.  
  5040.         pass
  5041.    
  5042.  
  5043.     def SendNotify(self, line, command, point=wx.DefaultPosition):
  5044.  
  5045.         bRet = True
  5046.         le = UltimateListEvent(command, self.GetParent().GetId())
  5047.         le.SetEventObject(self.GetParent())
  5048.         le.m_itemIndex = line
  5049.  
  5050.         # set only for events which have position
  5051.         if point != wx.DefaultPosition:
  5052.             le.m_pointDrag = point
  5053.  
  5054.         # don't try to get the line info for virtual list controls: the main
  5055.         # program has it anyhow and if we did it would result in accessing all
  5056.         # the lines, even those which are not visible now and this is precisely
  5057.         # what we're trying to avoid
  5058.         if not self.IsVirtual():
  5059.  
  5060.             if line != -1:
  5061.                 self.GetLine(line).GetItem(0, le.m_item)
  5062.  
  5063.             #else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event
  5064.  
  5065.             #else: there may be no more such item
  5066.  
  5067.         self.GetParent().GetEventHandler().ProcessEvent(le)
  5068.         bRet = le.IsAllowed()
  5069.  
  5070.         return bRet
  5071.  
  5072.  
  5073.     def ChangeCurrent(self, current):
  5074.  
  5075.         self._current = current
  5076.  
  5077.         # as the current item changed, we shouldn't start editing it when the
  5078.         # "slow click" timer expires as the click happened on another item
  5079.         if self._renameTimer.IsRunning():
  5080.             self._renameTimer.Stop()
  5081.        
  5082.         self.SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED)
  5083.  
  5084.  
  5085.     def EditLabel(self, item):
  5086.  
  5087.         if item < 0 or item >= self.GetItemCount():
  5088.             raise Exception("wrong index in UltimateListCtrl.EditLabel()")
  5089.  
  5090.         le = UltimateListEvent(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, self.GetParent().GetId())
  5091.         le.SetEventObject(self.GetParent())
  5092.         le.m_itemIndex = item
  5093.         data = self.GetLine(item)
  5094.         le.m_item = data.GetItem(0, le.m_item)
  5095.  
  5096.         self._textctrl = UltimateListTextCtrl(self, item)
  5097.  
  5098.         if self.GetParent().GetEventHandler().ProcessEvent(le) and not le.IsAllowed():
  5099.             # vetoed by user code
  5100.             return
  5101.  
  5102.         # We have to call this here because the label in question might just have
  5103.         # been added and no screen update taken place.
  5104.         if self._dirty:
  5105.             wx.SafeYield()
  5106.             # Pending events dispatched by wx.SafeYield might have changed the item
  5107.             # count
  5108.             if item >= self.GetItemCount():
  5109.                 return None
  5110.  
  5111.         # modified
  5112.         self._textctrl.SetFocus()
  5113.  
  5114.         return self._textctrl
  5115.  
  5116.  
  5117.     def OnRenameTimer(self):
  5118.  
  5119.         if not self.HasCurrent():
  5120.             raise Exception("unexpected rename timer")
  5121.  
  5122.         self.EditLabel(self._current)
  5123.  
  5124.  
  5125.     def OnRenameAccept(self, itemEdit, value):
  5126.  
  5127.         le = UltimateListEvent(wxEVT_COMMAND_LIST_END_LABEL_EDIT, self.GetParent().GetId())
  5128.         le.SetEventObject(self.GetParent())
  5129.         le.m_itemIndex = itemEdit
  5130.  
  5131.         data = self.GetLine(itemEdit)
  5132.  
  5133.         le.m_item = data.GetItem(0, le.m_item)
  5134.         le.m_item._text = value
  5135.        
  5136.         return not self.GetParent().GetEventHandler().ProcessEvent(le) or le.IsAllowed()
  5137.  
  5138.  
  5139.     def OnRenameCancelled(self, itemEdit):
  5140.  
  5141.         # let owner know that the edit was cancelled
  5142.         le = UltimateListEvent(wxEVT_COMMAND_LIST_END_LABEL_EDIT, self.GetParent().GetId())
  5143.         le.SetEditCanceled(True)
  5144.  
  5145.         le.SetEventObject(self.GetParent())
  5146.         le.m_itemIndex = itemEdit
  5147.  
  5148.         data = self.GetLine(itemEdit)
  5149.         le.m_item = data.GetItem(0, le.m_item)
  5150.  
  5151.         self.GetEventHandler().ProcessEvent(le)
  5152.  
  5153.  
  5154.     def OnMouse(self, event):
  5155.  
  5156.         if wx.Platform == "__WXMAC__":
  5157.             # On wxMac we can't depend on the EVT_KILL_FOCUS event to properly
  5158.             # shutdown the edit control when the mouse is clicked elsewhere on the
  5159.             # listctrl because the order of events is different (or something like
  5160.             # that,) so explicitly end the edit if it is active.
  5161.             if event.LeftDown() and self._textctrl:
  5162.                 self._textctrl.AcceptChanges()
  5163.                 self._textctrl.Finish()
  5164.  
  5165.         if event.LeftDown():
  5166.             self.SetFocusIgnoringChildren()
  5167.  
  5168.         event.SetEventObject(self.GetParent())
  5169.         if self.GetParent().GetEventHandler().ProcessEvent(event) :
  5170.             return
  5171.  
  5172.         if event.GetEventType() == wx.wxEVT_MOUSEWHEEL:
  5173.             # let the base handle mouse wheel events.
  5174.             self.Refresh()
  5175.             event.Skip()
  5176.             return
  5177.  
  5178.         if not self.HasCurrent() or self.IsEmpty():
  5179.             if event.RightDown():
  5180.                 self.SendNotify(-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition())
  5181.  
  5182.                 evtCtx = wx.ContextMenuEvent(wx.EVT_CONTEXT_MENU, self.GetParent().GetId(),
  5183.                                              self.ClientToScreen(event.GetPosition()))
  5184.                 evtCtx.SetEventObject(self.GetParent())
  5185.                 self.GetParent().GetEventHandler().ProcessEvent(evtCtx)
  5186.  
  5187.             return
  5188.  
  5189.         if self._dirty:
  5190.             return
  5191.  
  5192.         if not (event.Dragging() or event.ButtonDown() or event.LeftUp() or \
  5193.                 event.ButtonDClick() or event.Moving() or event.RightUp()):
  5194.             return
  5195.  
  5196.         x = event.GetX()
  5197.         y = event.GetY()
  5198.         x, y = self.CalcUnscrolledPosition(x, y)
  5199.  
  5200.         # where did we hit it (if we did)?
  5201.         hitResult = 0
  5202.         newItem = None
  5203.         count = self.GetItemCount()
  5204.  
  5205.         if self.InReportView():
  5206.             if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  5207.                 current = y/self.GetLineHeight()
  5208.                 if current < count:
  5209.                     newItem, hitResult = self.HitTestLine(current, x, y)
  5210.                 else:
  5211.                     return
  5212.             else:
  5213.                 for current in xrange(count):
  5214.                     newItem, hitResult = self.HitTestLine(current, x, y)
  5215.                     if hitResult:
  5216.                         break
  5217.         else:
  5218.             # TODO: optimize it too! this is less simple than for report view but
  5219.             #       enumerating all items is still not a way to do it!!
  5220.             for current in xrange(count):
  5221.                 newItem, hitResult = self.HitTestLine(current, x, y)
  5222.                 if hitResult:
  5223.                     break
  5224.  
  5225.         theItem = None
  5226.        
  5227.         if not self.IsVirtual():
  5228.             theItem = CreateListItem(current, 0)
  5229.             theItem = self.GetItem(theItem)
  5230.        
  5231.         if event.GetEventType() == wx.wxEVT_MOTION and not event.Dragging():
  5232.  
  5233.             if current >= 0 and current < count and self.HasExtraFlag(ULC_TRACK_SELECT) and not self._hoverTimer.IsRunning():
  5234.                 self._hoverItem = current
  5235.                 self._hoverTimer.Start(HOVER_TIME, wx.TIMER_ONE_SHOT)
  5236.                
  5237.             if newItem and newItem.IsHyperText() and (hitResult & ULC_HITTEST_ONITEMLABEL) and theItem and theItem.IsEnabled():
  5238.                 self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
  5239.                 self._isonhyperlink = True
  5240.             else:
  5241.                 if self._isonhyperlink:
  5242.                     self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
  5243.                     self._isonhyperlink = False
  5244.  
  5245.             if self.HasExtraFlag(ULC_STICKY_HIGHLIGHT) and hitResult:
  5246.                 if not self.IsHighlighted(current):
  5247.                     self.HighlightAll(False)
  5248.                     self.ChangeCurrent(current)
  5249.                     self.ReverseHighlight(self._current)
  5250.  
  5251.             if self.HasExtraFlag(ULC_SHOW_TOOLTIPS):
  5252.                 if newItem and hitResult & ULC_HITTEST_ONITEM:                
  5253.                     if (newItem._itemId, newItem._col) in self._shortItems:
  5254.                         text = newItem.GetText()
  5255.                         if self.GetToolTip() and self.GetToolTip().GetTip() != text:                            
  5256.                             self.SetToolTipString(text)
  5257.                     else:
  5258.                         self.SetToolTipString("")    
  5259.                 else:
  5260.                     self.SetToolTipString("")
  5261.  
  5262.             if self.HasExtraFlag(ULC_HOT_TRACKING):
  5263.                 if hitResult:
  5264.                     if self._oldHotCurrent != current:                        
  5265.                         if self._oldHotCurrent is not None:
  5266.                             self.RefreshLine(self._oldHotCurrent)
  5267.                         self._newHotCurrent = current
  5268.                         self.RefreshLine(self._newHotCurrent)
  5269.                         self._oldHotCurrent = current
  5270.                
  5271.             event.Skip()
  5272.             return
  5273.  
  5274.         if event.Dragging():
  5275.            
  5276.             if not self._isDragging:
  5277.  
  5278.                 if self._lineLastClicked == -1 or not hitResult or not theItem or not theItem.IsEnabled():
  5279.                     return
  5280.  
  5281.                 if self._dragCount == 0:
  5282.                     # we have to report the raw, physical coords as we want to be
  5283.                     # able to call HitTest(event.m_pointDrag) from the user code to
  5284.                     # get the item being dragged
  5285.                     self._dragStart = event.GetPosition()
  5286.  
  5287.                 self._dragCount += 1
  5288.  
  5289.                 if self._dragCount != 3:
  5290.                     return
  5291.  
  5292.                 command = (event.RightIsDown() and [wxEVT_COMMAND_LIST_BEGIN_RDRAG] or [wxEVT_COMMAND_LIST_BEGIN_DRAG])[0]
  5293.                 le = UltimateListEvent(command, self.GetParent().GetId())
  5294.                 le.SetEventObject(self.GetParent())
  5295.                 le.m_itemIndex = self._lineLastClicked
  5296.                 le.m_pointDrag = self._dragStart
  5297.                 self.GetParent().GetEventHandler().ProcessEvent(le)
  5298.  
  5299.                 # we're going to drag this item
  5300.                 self._isDragging = True
  5301.                 self._dragItem = current
  5302.  
  5303.                 # remember the old cursor because we will change it while
  5304.                 # dragging
  5305.                 self._oldCursor = self._cursor
  5306.                 self.SetCursor(self._dragCursor)
  5307.                    
  5308.             else:
  5309.  
  5310.                 if current != self._dropTarget:
  5311.                    
  5312.                     self.SetCursor(self._dragCursor)
  5313.                     # unhighlight the previous drop target
  5314.                     if self._dropTarget is not None:
  5315.                         self.RefreshLine(self._dropTarget)
  5316.  
  5317.                     move = current
  5318.                     if self._dropTarget:
  5319.                         move = (current > self._dropTarget and [current+1] or [current-1])[0]
  5320.  
  5321.                     self._dropTarget = current
  5322.                     self.MoveToItem(move)
  5323.  
  5324.                 else:
  5325.  
  5326.                     if self._dragItem == current:
  5327.                         self.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))                    
  5328.  
  5329.             if self.HasFlag(ULC_REPORT) and self._dragItem != current:
  5330.                 self.DrawDnDArrow()
  5331.  
  5332.             return
  5333.        
  5334.         else:
  5335.            
  5336.             self._dragCount = 0
  5337.  
  5338.         if theItem and not theItem.IsEnabled():
  5339.             self.DragFinish(event)
  5340.             event.Skip()
  5341.             return
  5342.  
  5343.         if not hitResult:
  5344.             # outside of any item
  5345.             if event.RightDown():
  5346.                 self.SendNotify(-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition())
  5347.                 evtCtx = wx.ContextMenuEvent(wx.EVT_CONTEXT_MENU, self.GetParent().GetId(),
  5348.                                              self.ClientToScreen(event.GetPosition()))
  5349.                 evtCtx.SetEventObject(self.GetParent())
  5350.                 self.GetParent().GetEventHandler().ProcessEvent(evtCtx)
  5351.             else:
  5352.                 self.HighlightAll(False)
  5353.                 self.DragFinish(event)
  5354.  
  5355.             return
  5356.  
  5357.         forceClick = False
  5358.         if event.ButtonDClick():
  5359.             if self._renameTimer.IsRunning():
  5360.                 self._renameTimer.Stop()
  5361.                
  5362.             self._lastOnSame = False
  5363.  
  5364.             if current == self._lineLastClicked:
  5365.                 self.SendNotify(current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
  5366.  
  5367.                 if newItem and newItem.GetKind() in [1, 2] and (hitResult & ULC_HITTEST_ONITEMCHECK):
  5368.                     self.CheckItem(newItem, not self.IsItemChecked(newItem))
  5369.  
  5370.                 return
  5371.  
  5372.             else:
  5373.  
  5374.                 # The first click was on another item, so don't interpret this as
  5375.                 # a double click, but as a simple click instead
  5376.                 forceClick = True
  5377.  
  5378.         if event.LeftUp():
  5379.  
  5380.             if self.DragFinish(event):
  5381.                 return
  5382.             if self._lineSelectSingleOnUp != - 1:
  5383.                 # select single line
  5384.                 self.HighlightAll(False)
  5385.                 self.ReverseHighlight(self._lineSelectSingleOnUp)
  5386.  
  5387.             if self._lastOnSame:
  5388.                 if (current == self._current) and (hitResult == ULC_HITTEST_ONITEMLABEL) and self.HasFlag(ULC_EDIT_LABELS):
  5389.                     if not self.InReportView() or self.GetLineLabelRect(current).Contains((x, y)):
  5390.                         # This wx.SYS_DCLICK_MSEC is not yet wrapped in wxPython...
  5391.                         # dclick = wx.SystemSettings.GetMetric(wx.SYS_DCLICK_MSEC)
  5392.                         # m_renameTimer->Start(dclick > 0 ? dclick : 250, True)
  5393.                         self._renameTimer.Start(250, True)
  5394.  
  5395.             self._lastOnSame = False
  5396.             self._lineSelectSingleOnUp = -1
  5397.  
  5398.         elif event.RightUp():
  5399.            
  5400.             if self.DragFinish(event):
  5401.                 return
  5402.                
  5403.         else:
  5404.  
  5405.             # This is necessary, because after a DnD operation in
  5406.             # from and to ourself, the up event is swallowed by the
  5407.             # DnD code. So on next non-up event (which means here and
  5408.             # now) self._lineSelectSingleOnUp should be reset.
  5409.             self._lineSelectSingleOnUp = -1
  5410.  
  5411.         if event.RightDown():
  5412.  
  5413.             if self.SendNotify(current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition()):
  5414.                 self._lineBeforeLastClicked = self._lineLastClicked
  5415.                 self._lineLastClicked = current
  5416.                 # If the item is already selected, do not update the selection.
  5417.                 # Multi-selections should not be cleared if a selected item is clicked.
  5418.  
  5419.                 if not self.IsHighlighted(current):
  5420.                     self.HighlightAll(False)
  5421.                     self.ChangeCurrent(current)
  5422.                     self.ReverseHighlight(self._current)
  5423.  
  5424.                 # Allow generation of context menu event
  5425.                 event.Skip()
  5426.  
  5427.         elif event.MiddleDown():
  5428.             self.SendNotify(current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
  5429.  
  5430.         elif event.LeftDown() or forceClick:
  5431.             self._lineBeforeLastClicked = self._lineLastClicked
  5432.             self._lineLastClicked = current
  5433.  
  5434.             oldCurrent = self._current
  5435.             oldWasSelected = self.IsHighlighted(self._current)
  5436.  
  5437.             cmdModifierDown = event.CmdDown()
  5438.             if self.IsSingleSel() or not (cmdModifierDown or event.ShiftDown()):
  5439.                 if self.IsSingleSel() or not self.IsHighlighted(current):
  5440.                     self.HighlightAll(False)
  5441.                     self.ChangeCurrent(current)
  5442.                     self.ReverseHighlight(self._current)
  5443.                    
  5444.                 else: # multi sel & current is highlighted & no mod keys
  5445.                     self._lineSelectSingleOnUp = current
  5446.                     self.ChangeCurrent(current) # change focus
  5447.  
  5448.             else: # multi sel & either ctrl or shift is down
  5449.                 if cmdModifierDown:
  5450.                     self.ChangeCurrent(current)
  5451.                     self.ReverseHighlight(self._current)
  5452.  
  5453.                 elif event.ShiftDown():
  5454.                     self.ChangeCurrent(current)
  5455.                     lineFrom, lineTo = oldCurrent, current
  5456.  
  5457.                     if lineTo < lineFrom:
  5458.                         lineTo = lineFrom
  5459.                         lineFrom = self._current
  5460.  
  5461.                     self.HighlightLines(lineFrom, lineTo)
  5462.  
  5463.                 else: # !ctrl, !shift
  5464.  
  5465.                     # test in the enclosing if should make it impossible
  5466.                     raise Exception("how did we get here?")
  5467.            
  5468.             if newItem:
  5469.                 if event.LeftDown():
  5470.                     if newItem.GetKind() in [1, 2] and (hitResult & ULC_HITTEST_ONITEMCHECK):                    
  5471.                         self.CheckItem(newItem, not self.IsItemChecked(newItem))
  5472.                     if newItem.IsHyperText():
  5473.                         self.SetItemVisited(newItem, True)
  5474.                         self.HandleHyperLink(newItem)
  5475.                    
  5476.             if self._current != oldCurrent:
  5477.                 self.RefreshLine(oldCurrent)
  5478.  
  5479.             # forceClick is only set if the previous click was on another item
  5480.             self._lastOnSame = not forceClick and (self._current == oldCurrent) and oldWasSelected
  5481.  
  5482.             if self.HasExtraFlag(ULC_STICKY_HIGHLIGHT) and self.HasExtraFlag(ULC_STICKY_NOSELEVENT) and self.HasExtraFlag(ULC_SEND_LEFTCLICK):
  5483.                 self.SendNotify(current, wxEVT_COMMAND_LIST_ITEM_LEFT_CLICK, event.GetPosition())
  5484.  
  5485.  
  5486.     def DrawDnDArrow(self):
  5487.        
  5488.         dc = wx.ClientDC(self)
  5489.         lineY = self.GetLineY(self._dropTarget)
  5490.         width = self.GetTotalWidth()
  5491.        
  5492.         dc.SetPen(wx.Pen(wx.BLACK, 2))
  5493.         x, y = self.CalcScrolledPosition(HEADER_OFFSET_X, lineY+2*HEADER_OFFSET_Y)
  5494.  
  5495.         tri1 = [wx.Point(x+1, y-2), wx.Point(x+1, y+4), wx.Point(x+4, y+1)]
  5496.         tri2 = [wx.Point(x+width-1, y-2), wx.Point(x+width-1, y+4), wx.Point(x+width-4, y+1)]
  5497.         dc.DrawPolygon(tri1)
  5498.         dc.DrawPolygon(tri2)
  5499.        
  5500.         dc.DrawLine(x, y+1, width, y+1)
  5501.        
  5502.  
  5503.     def DragFinish(self, event):
  5504.  
  5505.         if not self._isDragging:
  5506.             return False
  5507.        
  5508.         self._isDragging = False
  5509.         self._dragCount = 0
  5510.         self._dragItem = None
  5511.         self.SetCursor(self._oldCursor)
  5512.         self.Refresh()
  5513.  
  5514.         le = UltimateListEvent(wxEVT_COMMAND_LIST_END_DRAG, self.GetParent().GetId())
  5515.         le.SetEventObject(self.GetParent())
  5516.         le.m_itemIndex = self._dropTarget
  5517.         le.m_pointDrag = event.GetPosition()
  5518.         self.GetParent().GetEventHandler().ProcessEvent(le)
  5519.  
  5520.         return True
  5521.    
  5522.  
  5523.     def HandleHyperLink(self, item):
  5524.         """
  5525.        Handles the hyperlink items. Put in a separate method to avoid repetitive
  5526.        calls to the same code spread aound the file.
  5527.        """
  5528.  
  5529.         if self.IsItemHyperText(item):
  5530.             self.SendNotify(item._itemId, wxEVT_COMMAND_LIST_ITEM_HYPERLINK)
  5531.  
  5532.  
  5533.     def OnHoverTimer(self, event):
  5534.  
  5535.         x, y = self.ScreenToClient(wx.GetMousePosition())
  5536.         x, y = self.CalcUnscrolledPosition(x, y)
  5537.         item, hitResult = self.HitTestLine(self._hoverItem, x, y)
  5538.  
  5539.         if item and item._itemId == self._hoverItem:
  5540.             if not self.IsHighlighted(self._hoverItem):
  5541.                
  5542.                 dontNotify = self.HasExtraFlag(ULC_STICKY_HIGHLIGHT) and self.HasExtraFlag(ULC_STICKY_NOSELEVENT)
  5543.                 if not dontNotify:
  5544.                     self.SendNotify(self._hoverItem, wxEVT_COMMAND_LIST_ITEM_SELECTED)
  5545.            
  5546.                 self.HighlightAll(False)
  5547.                 self.ChangeCurrent(self._hoverItem)
  5548.                 self.ReverseHighlight(self._current)
  5549.  
  5550.  
  5551.     def MoveToItem(self, item):
  5552.  
  5553.         if item == -1:
  5554.             return
  5555.  
  5556.         if item >= self.GetItemCount():
  5557.             item = self.GetItemCount() - 1
  5558.            
  5559.         rect = self.GetLineRect(item)
  5560.         client_w, client_h = self.GetClientSize()
  5561.         hLine = self.GetLineHeight(item)
  5562.  
  5563.         view_x = SCROLL_UNIT_X*self.GetScrollPos(wx.HORIZONTAL)
  5564.         view_y = hLine*self.GetScrollPos(wx.VERTICAL)
  5565.  
  5566.         if self.InReportView():
  5567.  
  5568.             # the next we need the range of lines shown it might be different, so
  5569.             # recalculate it
  5570.             self.ResetVisibleLinesRange()
  5571.  
  5572.             if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):            
  5573.  
  5574.                 if rect.y < view_y:
  5575.                     self.Scroll(-1, rect.y/hLine)
  5576.                 if rect.y+rect.height+5 > view_y+client_h:
  5577.                     self.Scroll(-1, (rect.y+rect.height-client_h+hLine)/hLine)
  5578.  
  5579.                 if wx.Platform == "__WXMAC__":
  5580.                     # At least on Mac the visible lines value will get reset inside of
  5581.                     # Scroll *before* it actually scrolls the window because of the
  5582.                     # Update() that happens there, so it will still have the wrong value.
  5583.                     # So let's reset it again and wait for it to be recalculated in the
  5584.                     # next paint event.  I would expect this problem to show up in wxGTK
  5585.                     # too but couldn't duplicate it there.  Perhaps the order of events
  5586.                     # is different...  --Robin
  5587.                     self.ResetVisibleLinesRange()
  5588.        
  5589.             else:
  5590.  
  5591.                 view_y = SCROLL_UNIT_Y*self.GetScrollPos(wx.VERTICAL)
  5592.                 start_y, height = rect.y, rect.height
  5593.  
  5594.                 if start_y < view_y:
  5595.                     while start_y > view_y:
  5596.                         start_y -= SCROLL_UNIT_Y
  5597.  
  5598.                     self.Scroll(-1, start_y/SCROLL_UNIT_Y)
  5599.                    
  5600.                 if start_y + height > view_y + client_h:
  5601.                     while start_y + height < view_y + client_h:
  5602.                         start_y += SCROLL_UNIT_Y
  5603.  
  5604.                     self.Scroll(-1, (start_y+height-client_h+SCROLL_UNIT_Y)/SCROLL_UNIT_Y)
  5605.                    
  5606.         else: # !report
  5607.  
  5608.  
  5609.             sx = sy = -1
  5610.  
  5611.             if rect.x-view_x < 5:
  5612.                 sx = (rect.x - 5)/SCROLL_UNIT_X
  5613.             if rect.x+rect.width-5 > view_x+client_w:
  5614.                 sx = (rect.x + rect.width - client_w + SCROLL_UNIT_X)/SCROLL_UNIT_X
  5615.  
  5616.             if rect.y-view_y < 5:
  5617.                 sy = (rect.y - 5)/hLine
  5618.             if rect.y + rect.height - 5 > view_y + client_h:
  5619.                 sy = (rect.y + rect.height - client_h + hLine)/hLine
  5620.  
  5621.             self.Scroll(sx, sy)
  5622.        
  5623.  
  5624. # ----------------------------------------------------------------------------
  5625. # keyboard handling
  5626. # ----------------------------------------------------------------------------
  5627.  
  5628.     def GetNextActiveItem(self, item, down=True):
  5629.         """Returns the next active item. Used Internally at present. """
  5630.  
  5631.         count = self.GetItemCount()
  5632.         initialItem = item
  5633.        
  5634.         while 1:
  5635.             if item >= count or item < 0:
  5636.                 return initialItem
  5637.  
  5638.             listItem = CreateListItem(item, 0)
  5639.             listItem = self.GetItem(listItem, 0)
  5640.             if listItem.IsEnabled():
  5641.                 return item
  5642.            
  5643.             item = (down and [item+1] or [item-1])[0]
  5644.  
  5645.  
  5646.     def OnArrowChar(self, newCurrent, event):
  5647.  
  5648.         oldCurrent = self._current
  5649.         newCurrent = self.GetNextActiveItem(newCurrent, newCurrent > oldCurrent)
  5650.        
  5651.         # in single selection we just ignore Shift as we can't select several
  5652.         # items anyhow
  5653.         if event.ShiftDown() and not self.IsSingleSel():
  5654.  
  5655.             self.ChangeCurrent(newCurrent)
  5656.  
  5657.             # refresh the old focus to remove it
  5658.             self.RefreshLine(oldCurrent)
  5659.  
  5660.             # select all the items between the old and the new one
  5661.             if oldCurrent > newCurrent:
  5662.                 newCurrent = oldCurrent
  5663.                 oldCurrent = self._current
  5664.  
  5665.             self.HighlightLines(oldCurrent, newCurrent)
  5666.  
  5667.         else: # !shift
  5668.  
  5669.             # all previously selected items are unselected unless ctrl is held
  5670.             # in a multi-selection control
  5671.             if not event.ControlDown() or self.IsSingleSel():
  5672.                 self.HighlightAll(False)
  5673.  
  5674.             self.ChangeCurrent(newCurrent)
  5675.  
  5676.             # refresh the old focus to remove it
  5677.             self.RefreshLine(oldCurrent)
  5678.  
  5679.             if not event.ControlDown() or self.IsSingleSel():
  5680.                 self.HighlightLine(self._current, True)
  5681.  
  5682.         self.RefreshLine(self._current)
  5683.         self.MoveToFocus()
  5684.  
  5685.  
  5686.     def OnKeyDown(self, event):
  5687.  
  5688.         parent = self.GetParent()
  5689.  
  5690.         # we propagate the key event upwards
  5691.         ke = wx.KeyEvent(event.GetEventType())
  5692.  
  5693.         ke.SetEventObject(parent)
  5694.         if parent.GetEventHandler().ProcessEvent(ke):
  5695.             return
  5696.  
  5697.         event.Skip()
  5698.    
  5699.  
  5700.     def OnKeyUp(self, event):
  5701.  
  5702.         parent = self.GetParent()
  5703.  
  5704.         # we propagate the key event upwards
  5705.         ke = wx.KeyEvent(event.GetEventType())
  5706.  
  5707.         ke.SetEventObject(parent)
  5708.         if parent.GetEventHandler().ProcessEvent(ke):
  5709.             return
  5710.  
  5711.         event.Skip()
  5712.                
  5713.  
  5714.     def OnChar(self, event):
  5715.  
  5716.         parent = self.GetParent()
  5717.  
  5718.         # we send a list_key event up        
  5719.         if self.HasCurrent():
  5720.             le = UltimateListEvent(wxEVT_COMMAND_LIST_KEY_DOWN, self.GetParent().GetId())
  5721.             le.m_itemIndex = self._current
  5722.             le.m_item = self.GetLine(self._current).GetItem(0, le.m_item)
  5723.             le.m_code = event.GetKeyCode()
  5724.             le.SetEventObject(parent)
  5725.             parent.GetEventHandler().ProcessEvent(le)
  5726.  
  5727.         keyCode = event.GetKeyCode()
  5728.         if  keyCode not in [wx.WXK_UP, wx.WXK_DOWN, wx.WXK_RIGHT, wx.WXK_LEFT, \
  5729.                             wx.WXK_PAGEUP, wx.WXK_PAGEDOWN, wx.WXK_END, wx.WXK_HOME]:
  5730.  
  5731.             # propagate the char event upwards
  5732.             ke = wx.KeyEvent(event.GetEventType())
  5733.             ke.SetEventObject(parent)
  5734.             if parent.GetEventHandler().ProcessEvent(ke):
  5735.                 return
  5736.        
  5737.         if event.GetKeyCode() == wx.WXK_TAB:
  5738.             nevent = wx.NavigationKeyEvent()
  5739.             nevent.SetWindowChange(event.ControlDown())
  5740.             nevent.SetDirection(not event.ShiftDown())
  5741.             nevent.SetEventObject(self.GetParent().GetParent())
  5742.             nevent.SetCurrentFocus(self._parent)
  5743.             if self.GetParent().GetParent().GetEventHandler().ProcessEvent(nevent):
  5744.                 return
  5745.  
  5746.         # no item . nothing to do
  5747.         if not self.HasCurrent():
  5748.             event.Skip()
  5749.             return
  5750.  
  5751.         keyCode = event.GetKeyCode()
  5752.        
  5753.         if keyCode == wx.WXK_UP:
  5754.             if self._current > 0:
  5755.                 self.OnArrowChar(self._current - 1, event)
  5756.                 if self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  5757.                     self._dirty = True
  5758.  
  5759.         elif keyCode == wx.WXK_DOWN:
  5760.             if self._current < self.GetItemCount() - 1:
  5761.                 self.OnArrowChar(self._current + 1, event)
  5762.                 if self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  5763.                     self._dirty = True
  5764.  
  5765.         elif keyCode == wx.WXK_END:
  5766.             if not self.IsEmpty():
  5767.                 self.OnArrowChar(self.GetItemCount() - 1, event)
  5768.                 self._dirty = True
  5769.  
  5770.         elif keyCode == wx.WXK_HOME:
  5771.             if not self.IsEmpty():
  5772.                 self.OnArrowChar(0, event)
  5773.                 self._dirty = True
  5774.  
  5775.         elif keyCode == wx.WXK_PRIOR:
  5776.             steps = (self.InReportView() and [self._linesPerPage - 1] or [self._current % self._linesPerPage])[0]
  5777.             index = self._current - steps
  5778.            
  5779.             if index < 0:
  5780.                 index = 0
  5781.  
  5782.             self.OnArrowChar(index, event)
  5783.             self._dirty = True
  5784.  
  5785.         elif keyCode == wx.WXK_NEXT:
  5786.  
  5787.             steps = (self.InReportView() and [self._linesPerPage - 1] or [self._linesPerPage - (self._current % self._linesPerPage) - 1])[0]
  5788.             index = self._current + steps
  5789.             count = self.GetItemCount()
  5790.            
  5791.             if index >= count:
  5792.                 index = count - 1
  5793.  
  5794.             self.OnArrowChar(index, event)
  5795.             self._dirty = True
  5796.  
  5797.         elif keyCode == wx.WXK_LEFT:
  5798.             if not self.InReportView():
  5799.  
  5800.                 index = self._current - self._linesPerPage
  5801.                 if index < 0:
  5802.                     index = 0
  5803.  
  5804.                 self.OnArrowChar(index, event)
  5805.  
  5806.         elif keyCode == wx.WXK_RIGHT:
  5807.             if not self.InReportView():
  5808.  
  5809.                 index = self._current + self._linesPerPage
  5810.                 count = self.GetItemCount()
  5811.                
  5812.                 if index >= count:
  5813.                     index = count - 1
  5814.  
  5815.                 self.OnArrowChar(index, event)
  5816.  
  5817.         elif keyCode == wx.WXK_SPACE:
  5818.             if self.IsSingleSel():
  5819.  
  5820.                 if event.ControlDown():
  5821.                     self.ReverseHighlight(self._current)
  5822.                 else: # normal space press
  5823.                     self.SendNotify(self._current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
  5824.  
  5825.             else:
  5826.                 # select it in ReverseHighlight() below if unselected
  5827.                 self.ReverseHighlight(self._current)
  5828.  
  5829.         elif keyCode in [wx.WXK_RETURN, wx.WXK_EXECUTE, wx.WXK_NUMPAD_ENTER]:
  5830.             self.SendNotify(self._current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
  5831.  
  5832.         else:
  5833.             event.Skip()
  5834.  
  5835.  
  5836. # ----------------------------------------------------------------------------
  5837. # focus handling
  5838. # ----------------------------------------------------------------------------
  5839.  
  5840.     def OnSetFocus(self, event):
  5841.  
  5842.         if self.GetParent():
  5843.             event = wx.FocusEvent(wx.wxEVT_SET_FOCUS, self.GetParent().GetId())
  5844.             event.SetEventObject(self.GetParent())
  5845.             if self.GetParent().GetEventHandler().ProcessEvent(event):
  5846.                 return
  5847.  
  5848.         # wxGTK sends us EVT_SET_FOCUS events even if we had never got
  5849.         # EVT_KILL_FOCUS before which means that we finish by redrawing the items
  5850.         # which are already drawn correctly resulting in horrible flicker - avoid
  5851.         # it
  5852.         if not self._hasFocus:
  5853.             self._hasFocus = True
  5854.             self.Refresh()
  5855.  
  5856.  
  5857.     def OnKillFocus(self, event):
  5858.  
  5859.         if self.GetParent():
  5860.             event = wx.FocusEvent(wx.wxEVT_KILL_FOCUS, self.GetParent().GetId())
  5861.             event.SetEventObject(self.GetParent())
  5862.             if self.GetParent().GetEventHandler().ProcessEvent(event):
  5863.                 return
  5864.  
  5865.         self._hasFocus = False
  5866.         self.Refresh()
  5867.  
  5868.  
  5869.     def DrawImage(self, index, dc, x, y, enabled):
  5870.  
  5871.         if self.HasFlag(ULC_ICON) and self._normal_image_list:
  5872.             imgList = (enabled and [self._normal_image_list] or [self._normal_grayed_image_list])[0]
  5873.             imgList.Draw(index, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  5874.  
  5875.         elif self.HasFlag(ULC_SMALL_ICON) and self._small_image_list:
  5876.             imgList = (enabled and [self._small_image_list] or [self._small_grayed_image_list])[0]
  5877.             imgList.Draw(index, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  5878.  
  5879.         elif self.HasFlag(ULC_LIST) and self._small_image_list:
  5880.             imgList = (enabled and [self._small_image_list] or [self._small_grayed_image_list])[0]
  5881.             imgList.Draw(index, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  5882.  
  5883.         elif self.InReportView() and self._small_image_list:
  5884.             imgList = (enabled and [self._small_image_list] or [self._small_grayed_image_list])[0]
  5885.             imgList.Draw(index, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  5886.  
  5887.  
  5888.     def DrawCheckbox(self, dc, x, y, kind, checked, enabled):
  5889.  
  5890.         imgList = (enabled and [self._image_list_check] or [self._grayed_check_list])[0]
  5891.         if kind == 1:
  5892.             # checkbox
  5893.             index = (checked and [0] or [1])[0]
  5894.         else:
  5895.             # radiobutton
  5896.             index = (checked and [2] or [3])[0]
  5897.  
  5898.         imgList.Draw(index, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  5899.            
  5900.  
  5901.     def GetCheckboxImageSize(self):
  5902.  
  5903.         bmp = self._image_list_check.GetBitmap(0)
  5904.         return bmp.GetWidth(), bmp.GetHeight()
  5905.    
  5906.  
  5907.     def GetImageSize(self, index):
  5908.  
  5909.         width = height = 0
  5910.  
  5911.         if self.HasFlag(ULC_ICON) and self._normal_image_list:
  5912.  
  5913.             for indx in index:
  5914.                 w, h = self._normal_image_list.GetSize(indx)
  5915.                 width += w + MARGIN_BETWEEN_TEXT_AND_ICON
  5916.                 height = max(height, h)
  5917.  
  5918.         elif self.HasFlag(ULC_SMALL_ICON) and self._small_image_list:
  5919.  
  5920.             for indx in index:
  5921.                 w, h = self._small_image_list.GetSize(indx)
  5922.                 width += w + MARGIN_BETWEEN_TEXT_AND_ICON
  5923.                 height = max(height, h)
  5924.  
  5925.         elif self.HasFlag(ULC_LIST) and self._small_image_list:
  5926.  
  5927.             for indx in index:
  5928.                 w, h = self._small_image_list.GetSize(indx)
  5929.                 width += w + MARGIN_BETWEEN_TEXT_AND_ICON
  5930.                 height = max(height, h)
  5931.  
  5932.         elif self.InReportView() and self._small_image_list:
  5933.  
  5934.             for indx in index:
  5935.                 w, h = self._small_image_list.GetSize(indx)
  5936.                 width += w + MARGIN_BETWEEN_TEXT_AND_ICON
  5937.                 height = max(height, h)
  5938.  
  5939.         return width, height
  5940.  
  5941.  
  5942.     def GetTextLength(self, s):
  5943.  
  5944.         dc = wx.ClientDC(self)
  5945.         dc.SetFont(self.GetFont())
  5946.  
  5947.         lw, lh, dummy = dc.GetMultiLineTextExtent(s)
  5948.  
  5949.         return lw + AUTOSIZE_COL_MARGIN
  5950.  
  5951.  
  5952.     def SetImageList(self, imageList, which):
  5953.  
  5954.         self._dirty = True
  5955.  
  5956.         # calc the spacing from the icon size
  5957.         width = height = 0    
  5958.         if imageList and imageList.GetImageCount():
  5959.             width, height = imageList.GetSize(0)
  5960.  
  5961.         if which == wx.IMAGE_LIST_NORMAL:
  5962.             self._normal_image_list = imageList
  5963.             self._normal_grayed_image_list = wx.ImageList(width, height, True, 0)
  5964.  
  5965.             for ii in xrange(imageList.GetImageCount()):
  5966.                 bmp = imageList.GetBitmap(ii)
  5967.                 image = wx.ImageFromBitmap(bmp)
  5968.                 image = GrayOut(image)
  5969.                 newbmp = wx.BitmapFromImage(image)
  5970.                 self._normal_grayed_image_list.Add(newbmp)
  5971.  
  5972.             self._normal_spacing = width + 8
  5973.  
  5974.         if which == wx.IMAGE_LIST_SMALL:
  5975.             self._small_image_list = imageList
  5976.             self._small_spacing = width + 14
  5977.  
  5978.             self._small_grayed_image_list = wx.ImageList(width, height, True, 0)
  5979.  
  5980.             for ii in xrange(imageList.GetImageCount()):
  5981.                 bmp = imageList.GetBitmap(ii)
  5982.                 image = wx.ImageFromBitmap(bmp)
  5983.                 image = GrayOut(image)
  5984.                 newbmp = wx.BitmapFromImage(image)
  5985.                 self._small_grayed_image_list.Add(newbmp)
  5986.  
  5987.         self._lineHeight = 0  # ensure that the line height will be recalc'd        
  5988.         self.ResetLineDimensions()
  5989.  
  5990.  
  5991.     def SetImageListCheck(self, sizex, sizey, imglist=None):
  5992.         """Sets the check image list."""
  5993.  
  5994.         # Image list to hold disabled versions of each control
  5995.         self._grayed_check_list = wx.ImageList(sizex, sizey, True, 0)
  5996.  
  5997.         if imglist is None:
  5998.            
  5999.             self._image_list_check = wx.ImageList(sizex, sizey)
  6000.  
  6001.             # Get the Checkboxes
  6002.             self._image_list_check.Add(self.GetControlBmp(checkbox=True,
  6003.                                                           checked=True,
  6004.                                                           enabled=True,
  6005.                                                           x=sizex, y=sizey))
  6006.             self._grayed_check_list.Add(self.GetControlBmp(checkbox=True,
  6007.                                                            checked=True,
  6008.                                                            enabled=False,
  6009.                                                            x=sizex, y=sizey))
  6010.  
  6011.             self._image_list_check.Add(self.GetControlBmp(checkbox=True,
  6012.                                                           checked=False,
  6013.                                                           enabled=True,
  6014.                                                           x=sizex, y=sizey))
  6015.             self._grayed_check_list.Add(self.GetControlBmp(checkbox=True,
  6016.                                                            checked=False,
  6017.                                                            enabled=False,
  6018.                                                            x=sizex, y=sizey))
  6019.             # Get the Radio Buttons
  6020.             self._image_list_check.Add(self.GetControlBmp(checkbox=False,
  6021.                                                           checked=True,
  6022.                                                           enabled=True,
  6023.                                                           x=sizex, y=sizey))
  6024.             self._grayed_check_list.Add(self.GetControlBmp(checkbox=False,
  6025.                                                            checked=True,
  6026.                                                            enabled=False,
  6027.                                                            x=sizex, y=sizey))
  6028.  
  6029.             self._image_list_check.Add(self.GetControlBmp(checkbox=False,
  6030.                                                           checked=False,
  6031.                                                           enabled=True,
  6032.                                                           x=sizex, y=sizey))
  6033.             self._grayed_check_list.Add(self.GetControlBmp(checkbox=False,
  6034.                                                            checked=False,
  6035.                                                            enabled=False,
  6036.                                                            x=sizex, y=sizey))
  6037.         else:
  6038.  
  6039.             sizex, sizey = imglist.GetSize(0)
  6040.             self._image_list_check = imglist
  6041.  
  6042.             for ii in xrange(self._image_list_check.GetImageCount()):
  6043.                
  6044.                 bmp = self._image_list_check.GetBitmap(ii)
  6045.                 image = wx.ImageFromBitmap(bmp)
  6046.                 image = GrayOut(image)
  6047.                 newbmp = wx.BitmapFromImage(image)
  6048.                 self._grayed_check_list.Add(newbmp)
  6049.  
  6050.         self._dirty = True
  6051.  
  6052.         if imglist:
  6053.             self.RecalculatePositions()
  6054.  
  6055.  
  6056.     def GetControlBmp(self, checkbox=True, checked=False,
  6057.                       enabled=True, x=16, y=16):
  6058.         """Get a native looking checkbox or radio button bitmap
  6059.        @keyword checkbox: Get a checkbox=True, radiobutton=False
  6060.        @keyword checked: contorl is marked or not
  6061.  
  6062.        """
  6063.         bmp = wx.EmptyBitmap(x, y)
  6064.         mdc = wx.MemoryDC(bmp)
  6065.         dc = wx.GCDC(mdc)
  6066.         render = wx.RendererNative.Get()
  6067.  
  6068.         if checked:
  6069.             flag = wx.CONTROL_CHECKED
  6070.         else:
  6071.             flag = 0
  6072.  
  6073.         if not enabled:
  6074.             flag |= wx.CONTROL_DISABLED
  6075.  
  6076.         if checkbox:
  6077.             render.DrawCheckBox(self, mdc, (0, 0, x, y), flag)
  6078.         else:
  6079.             render.DrawRadioButton(self, mdc, (0, 0, x, y), flag)
  6080.  
  6081.         mdc.SelectObject(wx.NullBitmap)
  6082.         return bmp
  6083.  
  6084.  
  6085.     def SetItemSpacing(self, spacing, isSmall=False):
  6086.  
  6087.         self._dirty = True
  6088.        
  6089.         if isSmall:
  6090.             self._small_spacing = spacing
  6091.         else:
  6092.             self._normal_spacing = spacing
  6093.  
  6094.  
  6095.     def GetItemSpacing(self, isSmall=False):
  6096.  
  6097.         return (isSmall and [self._small_spacing] or [self._normal_spacing])[0]
  6098.  
  6099.  
  6100. # ----------------------------------------------------------------------------
  6101. # columns
  6102. # ----------------------------------------------------------------------------
  6103.  
  6104.     def SetColumn(self, col, item):
  6105.  
  6106.         column = self._columns[col]
  6107.  
  6108.         if item._width == ULC_AUTOSIZE_USEHEADER:
  6109.             item._width = self.GetTextLength(item._text)
  6110.  
  6111.         column.SetItem(item)
  6112.  
  6113.         headerWin = self.GetListCtrl()._headerWin
  6114.         if headerWin:
  6115.             headerWin._dirty = True
  6116.  
  6117.         self._dirty = True
  6118.  
  6119.         # invalidate it as it has to be recalculated
  6120.         self._headerWidth = 0
  6121.  
  6122.  
  6123.     def SetColumnWidth(self, col, width):
  6124.  
  6125.         if col < 0:
  6126.             raise Exception("invalid column index")
  6127.  
  6128.         if not self.InReportView() and not self.InTileView() and not self.HasExtraFlag(ULC_HEADER_IN_ALL_VIEWS):
  6129.             raise Exception("SetColumnWidth() can only be called in report/tile modes or with the ULC_HEADER_IN_ALL_VIEWS extra flag set.")
  6130.  
  6131.         self._dirty = True
  6132.         headerWin = self.GetListCtrl()._headerWin
  6133.         footerWin = self.GetListCtrl()._footerWin
  6134.        
  6135.         if headerWin:
  6136.             headerWin._dirty = True
  6137.  
  6138.         if footerWin:
  6139.             footerWin._dirty = True
  6140.  
  6141.         column = self._columns[col]
  6142.         count = self.GetItemCount()
  6143.  
  6144.         if width == ULC_AUTOSIZE_USEHEADER:
  6145.  
  6146.             width = self.GetTextLength(column.GetText())
  6147.             width += 2*EXTRA_WIDTH
  6148.  
  6149.             if column.GetKind() in [1, 2]:
  6150.                 ix, iy = self._owner.GetCheckboxImageSize()
  6151.                 width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  6152.                
  6153.             # check for column header's image availability
  6154.             images = column.GetImage()
  6155.             for img in images:
  6156.                 if self._small_image_list:
  6157.                     ix, iy = self._small_image_list.GetSize(img)
  6158.                     width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE
  6159.  
  6160.         elif width == ULC_AUTOSIZE:
  6161.  
  6162.             if self.IsVirtual() or not self.InReportView():
  6163.                 # TODO: determine the max width somehow...
  6164.                 width = WIDTH_COL_DEFAULT
  6165.  
  6166.             else: # !virtual
  6167.  
  6168.                 maxW = AUTOSIZE_COL_MARGIN
  6169.  
  6170.                 #  if the cached column width isn't valid then recalculate it
  6171.                 if self._aColWidths[col]._bNeedsUpdate:
  6172.  
  6173.                     for i in xrange(count):
  6174.  
  6175.                         line = self.GetLine(i)
  6176.                         itemData = line._items[col]
  6177.                         item = UltimateListItem()
  6178.  
  6179.                         item = itemData.GetItem(item)
  6180.                         itemWidth = self.GetItemWidthWithImage(item)
  6181.                         if itemWidth > maxW and not item._overFlow:
  6182.                             maxW = itemWidth
  6183.                            
  6184.                     self._aColWidths[col]._bNeedsUpdate = False
  6185.                     self._aColWidths[col]._nMaxWidth = maxW
  6186.  
  6187.                 maxW = self._aColWidths[col]._nMaxWidth
  6188.                 width = maxW + AUTOSIZE_COL_MARGIN
  6189.  
  6190.         column.SetWidth(width)
  6191.  
  6192.         # invalidate it as it has to be recalculated
  6193.         self._headerWidth = 0
  6194.         self._footerWidth = 0
  6195.  
  6196.         if footerWin:
  6197.             footerWin.Refresh()
  6198.  
  6199.  
  6200.     def GetHeaderWidth(self):
  6201.  
  6202.         if not self._headerWidth:
  6203.  
  6204.             count = self.GetColumnCount()
  6205.             for col in xrange(count):
  6206.  
  6207.                 if not self.IsColumnShown(col):
  6208.                     continue
  6209.                
  6210.                 self._headerWidth += self.GetColumnWidth(col)
  6211.  
  6212.         if self.HasExtraFlag(ULC_FOOTER):
  6213.             self._footerWidth = self._headerWidth
  6214.            
  6215.         return self._headerWidth
  6216.  
  6217.  
  6218.     def GetColumn(self, col):
  6219.  
  6220.         item = UltimateListItem()
  6221.         column = self._columns[col]                
  6222.         item = column.GetItem(item)
  6223.  
  6224.         return item
  6225.    
  6226.  
  6227.     def GetColumnWidth(self, col):
  6228.  
  6229.         column = self._columns[col]
  6230.         return column.GetWidth()
  6231.  
  6232.  
  6233.     def GetTotalWidth(self):
  6234.  
  6235.         width = 0
  6236.         for column in self._columns:
  6237.             width += column.GetWidth()
  6238.  
  6239.         return width            
  6240.  
  6241. # ----------------------------------------------------------------------------
  6242. # item state
  6243. # ----------------------------------------------------------------------------
  6244.  
  6245.     def SetItem(self, item):
  6246.  
  6247.         id = item._itemId
  6248.        
  6249.         if id < 0 or id >= self.GetItemCount():
  6250.             raise Exception("invalid item index in SetItem")
  6251.  
  6252.         if not self.IsVirtual():
  6253.  
  6254.             line = self.GetLine(id)
  6255.             line.SetItem(item._col, item)
  6256.  
  6257.             # Set item state if user wants
  6258.             if item._mask & ULC_MASK_STATE:
  6259.                 self.SetItemState(item._itemId, item._state, item._state)
  6260.  
  6261.             if self.InReportView():
  6262.  
  6263.                 #  update the Max Width Cache if needed
  6264.                 width = self.GetItemWidthWithImage(item)
  6265.  
  6266.                 if width > self._aColWidths[item._col]._nMaxWidth:
  6267.                     self._aColWidths[item._col]._nMaxWidth = width
  6268.                     self._aColWidths[item._col]._bNeedsUpdate = True
  6269.  
  6270.         if self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  6271.             line.ResetDimensions()
  6272.  
  6273.         # update the item on screen
  6274.         if self.InReportView():
  6275.             rectItem = self.GetItemRect(id)
  6276.             self.RefreshRect(rectItem)
  6277.            
  6278.  
  6279.     def SetItemStateAll(self, state, stateMask):
  6280.  
  6281.         if self.IsEmpty():
  6282.             return
  6283.  
  6284.         # first deal with selection
  6285.         if stateMask & ULC_STATE_SELECTED:
  6286.  
  6287.             # set/clear select state
  6288.             if self.IsVirtual():
  6289.  
  6290.                 # optimized version for virtual listctrl.
  6291.                 self._selStore.SelectRange(0, self.GetItemCount() - 1, state==ULC_STATE_SELECTED)
  6292.                 self.Refresh()
  6293.  
  6294.             elif state & ULC_STATE_SELECTED:
  6295.  
  6296.                 count = self.GetItemCount()
  6297.                 for i in xrange(count):
  6298.                     self.SetItemState(i, ULC_STATE_SELECTED, ULC_STATE_SELECTED)
  6299.                    
  6300.             else:
  6301.  
  6302.                 # clear for non virtual (somewhat optimized by using GetNextItem())
  6303.                 i = -1
  6304.                 while 1:
  6305.                     i += 1
  6306.                     if self.GetNextItem(i, ULC_NEXT_ALL, ULC_STATE_SELECTED) == -1:
  6307.                         break
  6308.  
  6309.                     self.SetItemState(i, 0, ULC_STATE_SELECTED)
  6310.  
  6311.         if self.HasCurrent() and state == 0 and stateMask & ULC_STATE_FOCUSED:
  6312.  
  6313.             # unfocus all: only one item can be focussed, so clearing focus for
  6314.             # all items is simply clearing focus of the focussed item.
  6315.             self.SetItemState(self._current, state, stateMask)
  6316.  
  6317.         #(setting focus to all items makes no sense, so it is not handled here.)
  6318.  
  6319.  
  6320.     def SetItemState(self, litem, state, stateMask):
  6321.  
  6322.         if litem == -1:
  6323.             self.SetItemStateAll(state, stateMask)
  6324.             return
  6325.  
  6326.         if litem < 0 or litem >= self.GetItemCount():
  6327.             raise Exception("invalid item index in SetItemState")
  6328.  
  6329.         oldCurrent = self._current
  6330.         item = litem    # safe because of the check above
  6331.  
  6332.         # do we need to change the focus?
  6333.         if stateMask & ULC_STATE_FOCUSED:
  6334.  
  6335.             if state & ULC_STATE_FOCUSED:
  6336.  
  6337.                 # don't do anything if this item is already focused
  6338.                 if item != self._current:
  6339.  
  6340.                     self.ChangeCurrent(item)
  6341.  
  6342.                     if oldCurrent != - 1:
  6343.  
  6344.                         if self.IsSingleSel():
  6345.  
  6346.                             self.HighlightLine(oldCurrent, False)
  6347.  
  6348.                         self.RefreshLine(oldCurrent)
  6349.  
  6350.                     self.RefreshLine(self._current)
  6351.  
  6352.             else: # unfocus
  6353.  
  6354.                 # don't do anything if this item is not focused
  6355.                 if item == self._current:
  6356.  
  6357.                     self.ResetCurrent()
  6358.  
  6359.                     if self.IsSingleSel():
  6360.  
  6361.                         # we must unselect the old current item as well or we
  6362.                         # might end up with more than one selected item in a
  6363.                         # single selection control
  6364.                         self.HighlightLine(oldCurrent, False)
  6365.  
  6366.                     self.RefreshLine(oldCurrent)
  6367.  
  6368.         # do we need to change the selection state?
  6369.         if stateMask & ULC_STATE_SELECTED:
  6370.  
  6371.             on = (state & ULC_STATE_SELECTED) != 0
  6372.  
  6373.             if self.IsSingleSel():
  6374.  
  6375.                 if on:
  6376.  
  6377.                     # selecting the item also makes it the focused one in the
  6378.                     # single sel mode
  6379.                     if self._current != item:
  6380.  
  6381.                         self.ChangeCurrent(item)
  6382.  
  6383.                         if oldCurrent != - 1:
  6384.  
  6385.                             self.HighlightLine(oldCurrent, False)
  6386.                             self.RefreshLine(oldCurrent)
  6387.  
  6388.                 else: # off
  6389.  
  6390.                     # only the current item may be selected anyhow
  6391.                     if item != self._current:
  6392.                         return
  6393.  
  6394.             if self.HighlightLine(item, on):
  6395.                 self.RefreshLine(item)
  6396.  
  6397.  
  6398.     def GetItemState(self, item, stateMask):
  6399.  
  6400.         if item < 0 or item >= self.GetItemCount():
  6401.             raise Exception("invalid item index in GetItemState")
  6402.  
  6403.         ret = ULC_STATE_DONTCARE
  6404.  
  6405.         if stateMask & ULC_STATE_FOCUSED:
  6406.             if item == self._current:
  6407.                 ret |= ULC_STATE_FOCUSED
  6408.  
  6409.         if stateMask & ULC_STATE_SELECTED:
  6410.             if self.IsHighlighted(item):
  6411.                 ret |= ULC_STATE_SELECTED
  6412.  
  6413.         return ret
  6414.  
  6415.  
  6416.     def GetItem(self, item, col=0):
  6417.  
  6418.         if item._itemId < 0 or item._itemId >= self.GetItemCount():
  6419.             raise Exception("invalid item index in GetItem")
  6420.  
  6421.         line = self.GetLine(item._itemId)
  6422.         item = line.GetItem(col, item)
  6423.        
  6424.         # Get item state if user wants it
  6425.         if item._mask & ULC_MASK_STATE:
  6426.             item._state = self.GetItemState(item._itemId, ULC_STATE_SELECTED | ULC_STATE_FOCUSED)
  6427.  
  6428.         return item
  6429.  
  6430.  
  6431.     def CheckItem(self, item, checked=True, sendEvent=True):
  6432.         """
  6433.        Actually checks/uncheks an item, sending (eventually) the two
  6434.        events EVT_LIST_ITEM_CHECKING/EVT_LIST_ITEM_CHECKED.
  6435.        """
  6436.  
  6437.         # Should we raise an error here?!?        
  6438.         if item.GetKind() == 0 or not item.IsEnabled():
  6439.             return
  6440.  
  6441.         if sendEvent:
  6442.            
  6443.             parent = self.GetParent()
  6444.             le = UltimateListEvent(wxEVT_COMMAND_LIST_ITEM_CHECKING, parent.GetId())
  6445.             le.m_itemIndex = item._itemId
  6446.             le.m_item = item
  6447.             le.SetEventObject(parent)
  6448.            
  6449.             if parent.GetEventHandler().ProcessEvent(le):
  6450.                 # Blocked by user
  6451.                 return
  6452.        
  6453.         item.Check(checked)
  6454.         self.SetItem(item)
  6455.         self.RefreshLine(item._itemId)
  6456.  
  6457.         if not sendEvent:
  6458.             return
  6459.        
  6460.         le = UltimateListEvent(wxEVT_COMMAND_LIST_ITEM_CHECKED, parent.GetId())
  6461.         le.m_itemIndex = item._itemId
  6462.         le.m_item = item
  6463.         le.SetEventObject(parent)
  6464.         parent.GetEventHandler().ProcessEvent(le)
  6465.  
  6466.  
  6467.     def AutoCheckChild(self, isChecked, column):
  6468.  
  6469.         for indx in xrange(self.GetItemCount()):
  6470.             item = CreateListItem(indx, column)
  6471.             newItem = self.GetItem(item, column)
  6472.             self.CheckItem(newItem, not isChecked, False)
  6473.        
  6474.  
  6475.     def AutoToggleChild(self, column):
  6476.  
  6477.         for indx in xrange(self.GetItemCount()):
  6478.             item = CreateListItem(indx, column)
  6479.             newItem = self.GetItem(item, column)
  6480.  
  6481.             if newItem.GetKind() != 1:
  6482.                 continue
  6483.            
  6484.             self.CheckItem(newItem, not item.IsChecked(), False)
  6485.  
  6486.  
  6487.     def IsItemChecked(self, item):
  6488.         """Returns whether an item is checked or not."""
  6489.  
  6490.         item = self.GetItem(item, item._col)
  6491.         return item.IsChecked()
  6492.  
  6493.  
  6494.     def IsItemEnabled(self, item):
  6495.         """Returns whether an item is enabled or not."""
  6496.  
  6497.         item = self.GetItem(item, item._col)
  6498.         return item.IsEnabled()
  6499.  
  6500.  
  6501.     def EnableItem(self, item, enable=True):
  6502.  
  6503.         item = self.GetItem(item, 0)
  6504.         if item.IsEnabled() == enable:
  6505.             return False
  6506.  
  6507.         item.Enable(enable)
  6508.  
  6509.         wnd = item.GetWindow()
  6510.         # Handles the eventual window associated to the item        
  6511.         if wnd:
  6512.             wnd.Enable(enable)
  6513.        
  6514.         self.SetItem(item)
  6515.  
  6516.         return True
  6517.    
  6518.                
  6519.     def GetItemKind(self, item):
  6520.  
  6521.         item = self.GetItem(item, item._col)
  6522.         return item.GetKind()
  6523.                
  6524.  
  6525.     def SetItemKind(self, item, kind):
  6526.  
  6527.         item = self.GetItem(item, item._col)
  6528.         item.SetKind(kind)
  6529.         self.SetItem(item)
  6530.  
  6531.         return True
  6532.    
  6533.  
  6534.     def IsItemHyperText(self, item):
  6535.         """Returns whether an item is hypertext or not."""
  6536.        
  6537.         item = self.GetItem(item, item._col)
  6538.         return item.IsHyperText()
  6539.  
  6540.  
  6541.     def SetItemHyperText(self, item, hyper=True):
  6542.  
  6543.         item = self.GetItem(item, item._col)
  6544.         item.SetHyperText(hyper)
  6545.         self.SetItem(item)
  6546.  
  6547.         return True
  6548.    
  6549.  
  6550.     def GetHyperTextFont(self):
  6551.         """Returns the font used to render an hypertext item."""
  6552.  
  6553.         return self._hypertextfont        
  6554.  
  6555.  
  6556.     def SetHyperTextFont(self, font):
  6557.         """Sets the font used to render an hypertext item."""
  6558.  
  6559.         self._hypertextfont = font
  6560.         self._dirty = True
  6561.        
  6562.  
  6563.     def SetHyperTextNewColour(self, colour):
  6564.         """Sets the colour used to render a non-visited hypertext item."""
  6565.  
  6566.         self._hypertextnewcolour = colour
  6567.         self._dirty = True
  6568.  
  6569.  
  6570.     def GetHyperTextNewColour(self):
  6571.         """Returns the colour used to render a non-visited hypertext item."""
  6572.  
  6573.         return self._hypertextnewcolour
  6574.  
  6575.  
  6576.     def SetHyperTextVisitedColour(self, colour):
  6577.         """Sets the colour used to render a visited hypertext item."""
  6578.  
  6579.         self._hypertextvisitedcolour = colour
  6580.         self._dirty = True
  6581.  
  6582.  
  6583.     def GetHyperTextVisitedColour(self):
  6584.         """Returns the colour used to render a visited hypertext item."""
  6585.  
  6586.         return self._hypertextvisitedcolour
  6587.  
  6588.  
  6589.     def SetItemVisited(self, item, visited=True):
  6590.         """Sets whether an hypertext item was visited."""
  6591.  
  6592.         newItem = self.GetItem(item, item._col)
  6593.         newItem.SetVisited(visited)
  6594.         self.SetItem(newItem)
  6595.         self.RefreshLine(item)
  6596.  
  6597.         return True
  6598.  
  6599.  
  6600.     def GetItemVisited(self, item):
  6601.         """Returns whether an hypertext item was visited."""
  6602.  
  6603.         item = self.GetItem(item, item._col)
  6604.         return item.GetVisited()
  6605.  
  6606.  
  6607.     def GetItemWindow(self, item):
  6608.         """Returns the window associated to the item (if any)."""
  6609.  
  6610.         item = self.GetItem(item, item._col)
  6611.         return item.GetWindow()
  6612.  
  6613.  
  6614.     def SetItemWindow(self, item, wnd, expand=False):
  6615.         """Sets the window for the given item"""
  6616.  
  6617.         if not self.InReportView() and not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  6618.             raise Exception("Widgets are only allowed in repotr mode and with the ULC_HAS_VARIABLE_ROW_HEIGHT extra style.")
  6619.        
  6620.         item = self.GetItem(item, item._col)
  6621.  
  6622.         if wnd is not None:
  6623.             self._hasWindows = True
  6624.             if item not in self._itemWithWindow:
  6625.                 self._itemWithWindow.append(item)
  6626.             else:
  6627.                 self.DeleteItemWindow(item)
  6628.         else:
  6629.             self.DeleteItemWindow(item)
  6630.  
  6631.         item.SetWindow(wnd, expand)
  6632.         self.SetItem(item)
  6633.         self.RecalculatePositions()
  6634.         self.Refresh()
  6635.        
  6636.  
  6637.     def DeleteItemWindow(self, item):
  6638.         """Deletes the window associated to an item (if any). """
  6639.  
  6640.         if item.GetWindow() is None:
  6641.             return
  6642.  
  6643.         item.DeleteWindow()
  6644.         if item in self._itemWithWindow:
  6645.             self._itemWithWindow.remove(item)
  6646.  
  6647.         self.SetItem(item)
  6648.         self.RecalculatePositions()
  6649.        
  6650.  
  6651.     def GetItemWindowEnabled(self, item):
  6652.         """Returns whether the window associated to the item is enabled."""
  6653.  
  6654.         item = self.GetItem(item, item._col)
  6655.         return item.GetWindowEnabled()
  6656.  
  6657.  
  6658.     def SetItemWindowEnabled(self, item, enable=True):
  6659.         """Enables/disables the window associated to the item."""
  6660.  
  6661.         item = self.GetItem(item, item._col)
  6662.         item.SetWindowEnabled(enable)
  6663.         self.SetItem(item)
  6664.         self.Refresh()
  6665.        
  6666.  
  6667.     def GetItemCustomRenderer(self, item):
  6668.  
  6669.         item = self.GetItem(item, item._col)
  6670.         return item.GetCustomRenderer()
  6671.  
  6672.  
  6673.     def SetItemCustomRenderer(self, item, renderer=None):
  6674.  
  6675.         item = self.GetItem(item, item._col)
  6676.         item.SetCustomRenderer(renderer)
  6677.         self.SetItem(item)
  6678.         self.ResetLineDimensions()
  6679.         self.Refresh()
  6680.  
  6681.  
  6682.     def GetItemOverFlow(self, item):
  6683.  
  6684.         item = self.GetItem(item, item._col)
  6685.         return item.GetOverFlow()
  6686.  
  6687.  
  6688.     def SetItemOverFlow(self, item, over=True):
  6689.  
  6690.         item = self.GetItem(item, item._col)
  6691.         item.SetOverFlow(over)
  6692.         self.SetItem(item)
  6693.         self.Refresh()
  6694.  
  6695.  
  6696. # ----------------------------------------------------------------------------
  6697. # item count
  6698. # ----------------------------------------------------------------------------
  6699.  
  6700.     def GetItemCount(self):
  6701.  
  6702.         return (self.IsVirtual() and [self._countVirt] or [len(self._lines)])[0]
  6703.  
  6704.  
  6705.     def SetItemCount(self, count):
  6706.  
  6707.         self._selStore.SetItemCount(count)
  6708.         self._countVirt = count
  6709.  
  6710.         self.ResetVisibleLinesRange()
  6711.  
  6712.         # scrollbars must be reset
  6713.         self._dirty = True
  6714.  
  6715.  
  6716.     def GetSelectedItemCount(self):
  6717.  
  6718.         # deal with the quick case first
  6719.         if self.IsSingleSel():
  6720.             return (self.HasCurrent() and [self.IsHighlighted(self._current)] or [False])[0]
  6721.  
  6722.         # virtual controls remmebers all its selections itself
  6723.         if self.IsVirtual():
  6724.             return self._selStore.GetSelectedCount()
  6725.  
  6726.         # TODO: we probably should maintain the number of items selected even for
  6727.         #       non virtual controls as enumerating all lines is really slow...
  6728.         countSel = 0
  6729.         count = self.GetItemCount()
  6730.         for line in xrange(count):
  6731.             if self.GetLine(line).IsHighlighted():
  6732.                 countSel += 1
  6733.  
  6734.         return countSel
  6735.  
  6736.  
  6737. # ----------------------------------------------------------------------------
  6738. # item position/size
  6739. # ----------------------------------------------------------------------------
  6740.  
  6741.     def GetViewRect(self):
  6742.  
  6743.         if self.HasFlag(ULC_LIST):
  6744.             raise Exception("UltimateListCtrl.GetViewRect() not implemented for list view")
  6745.  
  6746.         # we need to find the longest/tallest label
  6747.         xMax = yMax = 0
  6748.         count = self.GetItemCount()
  6749.        
  6750.         if count:
  6751.             for i in xrange(count):
  6752.                 # we need logical, not physical, coordinates here, so use
  6753.                 # GetLineRect() instead of GetItemRect()
  6754.                 r = self.GetLineRect(i)
  6755.                 x, y = r.GetRight(), r.GetBottom()
  6756.  
  6757.                 if x > xMax:
  6758.                     xMax = x
  6759.                 if y > yMax:
  6760.                     yMax = y
  6761.  
  6762.         # some fudge needed to make it look prettier
  6763.         xMax += 2*EXTRA_BORDER_X
  6764.         yMax += 2*EXTRA_BORDER_Y
  6765.  
  6766.         # account for the scrollbars if necessary
  6767.         sizeAll = self.GetClientSize()
  6768.         if xMax > sizeAll.x:
  6769.             yMax += wx.SystemSettings.GetMetric(wx.SYS_HSCROLL_Y)
  6770.         if yMax > sizeAll.y:
  6771.             xMax += wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X)
  6772.  
  6773.         return wx.Rect(0, 0, xMax, yMax)
  6774.  
  6775.  
  6776.     def GetSubItemRect(self, item, subItem):
  6777.  
  6778.         if not self.InReportView() and subItem == ULC_GETSUBITEMRECT_WHOLEITEM:
  6779.             raise Exception("GetSubItemRect only meaningful in report view")
  6780.  
  6781.         if item < 0 or item >= self.GetItemCount():
  6782.             raise Exception("invalid item in GetSubItemRect")
  6783.  
  6784.         # ensure that we're laid out, otherwise we could return nonsense
  6785.         if self._dirty:
  6786.             self.RecalculatePositions(True)
  6787.            
  6788.         rect = self.GetLineRect(item)
  6789.  
  6790.         # Adjust rect to specified column
  6791.         if subItem != ULC_GETSUBITEMRECT_WHOLEITEM:
  6792.             if subItem < 0 or subItem >= self.GetColumnCount():
  6793.                 raise Exception("invalid subItem in GetSubItemRect")
  6794.  
  6795.             for i in xrange(subItem):
  6796.                 rect.x += self.GetColumnWidth(i)
  6797.  
  6798.             rect.width = self.GetColumnWidth(subItem)
  6799.  
  6800.         rect.x, rect.y = self.CalcScrolledPosition(rect.x, rect.y)
  6801.         return rect
  6802.  
  6803.        
  6804.     def GetItemRect(self, item):
  6805.  
  6806.         return self.GetSubItemRect(item, ULC_GETSUBITEMRECT_WHOLEITEM)
  6807.    
  6808.  
  6809.     def GetItemPosition(self, item):
  6810.  
  6811.         rect = self.GetItemRect(item)
  6812.         return wx.Point(rect.x, rect.y)
  6813.  
  6814.  
  6815. # ----------------------------------------------------------------------------
  6816. # geometry calculation
  6817. # ----------------------------------------------------------------------------
  6818.  
  6819.     def RecalculatePositions(self, noRefresh=False):
  6820.  
  6821.         count = self.GetItemCount()
  6822.  
  6823.         if self.HasFlag(ULC_ICON) and self._normal_image_list:
  6824.             iconSpacing = self._normal_spacing
  6825.         elif self.HasFlag(ULC_SMALL_ICON) and self._small_image_list:
  6826.             iconSpacing = self._small_spacing
  6827.         else:
  6828.             iconSpacing = 0
  6829.  
  6830.         # Note that we do not call GetClientSize() here but
  6831.         # GetSize() and subtract the border size for sunken
  6832.         # borders manually. This is technically incorrect,
  6833.         # but we need to know the client area's size WITHOUT
  6834.         # scrollbars here. Since we don't know if there are
  6835.         # any scrollbars, we use GetSize() instead. Another
  6836.         # solution would be to call SetScrollbars() here to
  6837.         # remove the scrollbars and call GetClientSize() then,
  6838.         # but this might result in flicker and - worse - will
  6839.         # reset the scrollbars to 0 which is not good at all
  6840.         # if you resize a dialog/window, but don't want to
  6841.         # reset the window scrolling. RR.
  6842.         # Furthermore, we actually do NOT subtract the border
  6843.         # width as 2 pixels is just the extra space which we
  6844.         # need around the actual content in the window. Other-
  6845.         # wise the text would e.g. touch the upper border. RR.
  6846.         clientWidth, clientHeight = self.GetSize()
  6847.  
  6848.         if self.InReportView():
  6849.  
  6850.             self.ResetVisibleLinesRange()
  6851.            
  6852.             if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  6853.                 # all lines have the same height and we scroll one line per step
  6854.  
  6855.                 lineHeight = self.GetLineHeight()
  6856.                 entireHeight = count*lineHeight + LINE_SPACING
  6857.                 decrement = 0
  6858.                 if entireHeight > self.GetClientSize()[1]:
  6859.                     decrement = SCROLL_UNIT_X
  6860.  
  6861.                 self._linesPerPage = clientHeight/lineHeight
  6862.  
  6863.                 self.SetScrollbars(SCROLL_UNIT_X, lineHeight,
  6864.                                    (self.GetHeaderWidth()-decrement)/SCROLL_UNIT_X,
  6865.                                    (entireHeight + lineHeight - 1)/lineHeight,
  6866.                                    self.GetScrollPos(wx.HORIZONTAL),
  6867.                                    self.GetScrollPos(wx.VERTICAL),
  6868.                                    True)
  6869.  
  6870.             else:
  6871.  
  6872.                 if count > 0:
  6873.                     entireHeight = self.GetLineY(count-1) + self.GetLineHeight(count-1) + LINE_SPACING
  6874.                     lineFrom, lineTo = self.GetVisibleLinesRange()
  6875.                     self._linesPerPage = lineTo - lineFrom + 1
  6876.                 else:
  6877.                     lineHeight = self.GetLineHeight()
  6878.                     entireHeight = count*lineHeight + LINE_SPACING
  6879.                     self._linesPerPage = clientHeight/lineHeight
  6880.  
  6881.                 decrement = 0
  6882.                 if entireHeight > self.GetClientSize()[1]:
  6883.                     decrement = SCROLL_UNIT_X
  6884.                    
  6885.                 self.SetScrollbars(SCROLL_UNIT_X, SCROLL_UNIT_Y,
  6886.                                    (self.GetHeaderWidth()-decrement)/SCROLL_UNIT_X,
  6887.                                    (entireHeight + SCROLL_UNIT_Y - 1)/SCROLL_UNIT_Y,
  6888.                                    self.GetScrollPos(wx.HORIZONTAL),
  6889.                                    self.GetScrollPos(wx.VERTICAL),
  6890.                                    True)
  6891.  
  6892.         else: # !report
  6893.  
  6894.             dc = wx.ClientDC(self)
  6895.             dc.SetFont(self.GetFont())
  6896.  
  6897.             lineHeight = self.GetLineHeight()
  6898.  
  6899.             # we have 3 different layout strategies: either layout all items
  6900.             # horizontally/vertically (ULC_ALIGN_XXX styles explicitly given) or
  6901.             # to arrange them in top to bottom, left to right (don't ask me why
  6902.             # not the other way round...) order
  6903.             if self.HasFlag(ULC_ALIGN_LEFT | ULC_ALIGN_TOP):
  6904.                
  6905.                 x = EXTRA_BORDER_X
  6906.                 y = EXTRA_BORDER_Y
  6907.                 widthMax = 0
  6908.  
  6909.                 for i in xrange(count):
  6910.  
  6911.                     line = self.GetLine(i)
  6912.                     line.CalculateSize(dc, iconSpacing)
  6913.                     line.SetPosition(x, y, iconSpacing)
  6914.  
  6915.                     sizeLine = self.GetLineSize(i)
  6916.  
  6917.                     if self.HasFlag(ULC_ALIGN_TOP):
  6918.  
  6919.                         if sizeLine.x > widthMax:
  6920.                             widthMax = sizeLine.x
  6921.  
  6922.                         y += sizeLine.y
  6923.  
  6924.                     else: # ULC_ALIGN_LEFT
  6925.  
  6926.                         x += sizeLine.x + MARGIN_BETWEEN_ROWS
  6927.  
  6928.                 if self.HasFlag(ULC_ALIGN_TOP):
  6929.  
  6930.                     # traverse the items again and tweak their sizes so that they are
  6931.                     # all the same in a row
  6932.                     for i in xrange(count):
  6933.  
  6934.                         line = self.GetLine(i)
  6935.                         line._gi.ExtendWidth(widthMax)
  6936.  
  6937.                 self.SetScrollbars(SCROLL_UNIT_X, lineHeight,
  6938.                                    (x + SCROLL_UNIT_X)/SCROLL_UNIT_X,
  6939.                                    (y + lineHeight)/lineHeight,
  6940.                                    self.GetScrollPos(wx.HORIZONTAL),
  6941.                                    self.GetScrollPos(wx.VERTICAL),
  6942.                                    True)
  6943.  
  6944.             else: # "flowed" arrangement, the most complicated case
  6945.  
  6946.                 # at first we try without any scrollbars, if the items don't fit into
  6947.                 # the window, we recalculate after subtracting the space taken by the
  6948.                 # scrollbar
  6949.  
  6950.                 entireWidth = 0
  6951.  
  6952.                 for tries in xrange(2):
  6953.  
  6954.                     entireWidth = 2*EXTRA_BORDER_X
  6955.  
  6956.                     if tries == 1:
  6957.  
  6958.                         # Now we have decided that the items do not fit into the
  6959.                         # client area, so we need a scrollbar
  6960.                         entireWidth += SCROLL_UNIT_X
  6961.  
  6962.                     x = EXTRA_BORDER_X
  6963.                     y = EXTRA_BORDER_Y
  6964.                     maxWidthInThisRow = 0
  6965.  
  6966.                     self._linesPerPage = 0
  6967.                     currentlyVisibleLines = 0
  6968.  
  6969.                     for i in xrange(count):
  6970.  
  6971.                         currentlyVisibleLines += 1
  6972.                         line = self.GetLine(i)
  6973.                         line.CalculateSize(dc, iconSpacing)
  6974.                         line.SetPosition(x, y, iconSpacing)
  6975.  
  6976.                         sizeLine = self.GetLineSize(i)
  6977.  
  6978.                         if maxWidthInThisRow < sizeLine.x:
  6979.                             maxWidthInThisRow = sizeLine.x
  6980.  
  6981.                         y += sizeLine.y
  6982.                         if currentlyVisibleLines > self._linesPerPage:
  6983.                             self._linesPerPage = currentlyVisibleLines
  6984.  
  6985.                         if y + sizeLine.y >= clientHeight:
  6986.  
  6987.                             currentlyVisibleLines = 0
  6988.                             y = EXTRA_BORDER_Y
  6989.                             maxWidthInThisRow += MARGIN_BETWEEN_ROWS
  6990.                             x += maxWidthInThisRow
  6991.                             entireWidth += maxWidthInThisRow
  6992.                             maxWidthInThisRow = 0
  6993.  
  6994.                         # We have reached the last item.
  6995.                         if i == count - 1:
  6996.                             entireWidth += maxWidthInThisRow
  6997.  
  6998.                         if tries == 0 and entireWidth + SCROLL_UNIT_X > clientWidth:
  6999.                             clientHeight -= wx.SystemSettings.GetMetric(wx.SYS_HSCROLL_Y)
  7000.                             self._linesPerPage = 0
  7001.                             break
  7002.  
  7003.                         if i == count - 1:
  7004.                             break  # Everything fits, no second try required.
  7005.  
  7006.                 self.SetScrollbars(SCROLL_UNIT_X, lineHeight,
  7007.                                    (entireWidth + SCROLL_UNIT_X)/SCROLL_UNIT_X,
  7008.                                    0,
  7009.                                    self.GetScrollPos(wx.HORIZONTAL),
  7010.                                    0,
  7011.                                    True)
  7012.  
  7013.         self._dirty = False
  7014.         if not noRefresh:
  7015.             # FIXME: why should we call it from here?
  7016.             self.UpdateCurrent()
  7017.             self.RefreshAll()
  7018.  
  7019.  
  7020.     def RefreshAll(self):
  7021.  
  7022.         self._dirty = False
  7023.         self.Refresh()
  7024.  
  7025.         headerWin = self.GetListCtrl()._headerWin
  7026.         if headerWin and headerWin._dirty:
  7027.             headerWin._dirty = False
  7028.             headerWin.Refresh()
  7029.  
  7030.  
  7031.     def UpdateCurrent(self):
  7032.  
  7033.         if not self.HasCurrent() and not self.IsEmpty():
  7034.             self.ChangeCurrent(0)
  7035.  
  7036.  
  7037.     def GetNextItem(self, item, geometry=ULC_NEXT_ALL, state=ULC_STATE_DONTCARE):
  7038.  
  7039.         ret = item
  7040.         maxI = self.GetItemCount()
  7041.  
  7042.         # notice that we start with the next item (or the first one if item == -1)
  7043.         # and this is intentional to allow writing a simple loop to iterate over
  7044.         # all selected items
  7045.         ret += 1
  7046.        
  7047.         if ret == maxI:
  7048.             # this is not an error because the index was ok initially, just no
  7049.             # such item
  7050.             return -1
  7051.  
  7052.         if not state:
  7053.             # any will do
  7054.             return ret
  7055.  
  7056.         for line in xrange(ret, maxI):
  7057.             if state & ULC_STATE_FOCUSED and line == self._current:
  7058.                 return line
  7059.  
  7060.             if state & ULC_STATE_SELECTED and self.IsHighlighted(line):
  7061.                 return line
  7062.  
  7063.         return -1
  7064.  
  7065.  
  7066. # ----------------------------------------------------------------------------
  7067. # deleting stuff
  7068. # ----------------------------------------------------------------------------
  7069.  
  7070.     def DeleteItem(self, lindex):
  7071.  
  7072.         count = self.GetItemCount()
  7073.         if lindex < 0 or lindex >= self.GetItemCount():
  7074.             raise Exception("invalid item index in DeleteItem")
  7075.  
  7076.         # we don't need to adjust the index for the previous items
  7077.         if self.HasCurrent() and self._current >= lindex:
  7078.  
  7079.             # if the current item is being deleted, we want the next one to
  7080.             # become selected - unless there is no next one - so don't adjust
  7081.             # self._current in this case
  7082.             if self._current != lindex or self._current == count - 1:
  7083.                 self._current -= 1
  7084.  
  7085.         if self.InReportView():
  7086.  
  7087.             #  mark the Column Max Width cache as dirty if the items in the line
  7088.             #  we're deleting contain the Max Column Width
  7089.             line = self.GetLine(lindex)
  7090.             item = UltimateListItem()
  7091.            
  7092.             for i in xrange(len(self._columns)):
  7093.                 itemData = line._items[i]
  7094.                 item = itemData.GetItem(item)
  7095.                 itemWidth = self.GetItemWidthWithImage(item)
  7096.  
  7097.                 if itemWidth >= self._aColWidths[i]._nMaxWidth:
  7098.                     self._aColWidths[i]._bNeedsUpdate = True
  7099.  
  7100.                 if item.GetWindow():
  7101.                     self.DeleteItemWindow(item)
  7102.  
  7103.             self.ResetVisibleLinesRange(True)
  7104.             self._current = -1
  7105.  
  7106.         self.SendNotify(lindex, wxEVT_COMMAND_LIST_DELETE_ITEM)
  7107.        
  7108.         if self.IsVirtual():
  7109.             self._countVirt -= 1
  7110.             self._selStore.OnItemDelete(lindex)
  7111.  
  7112.         else:
  7113.             self._lines.pop(lindex)
  7114.  
  7115.         # we need to refresh the (vert) scrollbar as the number of items changed
  7116.         self._dirty = True        
  7117.         self._lineHeight = 0
  7118.         self.ResetLineDimensions(True)
  7119.         self.RecalculatePositions()
  7120.         self.RefreshAfter(lindex)
  7121.  
  7122.  
  7123.     def DeleteColumn(self, col):
  7124.  
  7125.         self._columns.pop(col)
  7126.         self._dirty = True
  7127.  
  7128.         if not self.IsVirtual():
  7129.             # update all the items
  7130.             for i in xrange(len(self._lines)):
  7131.                 line = self.GetLine(i)
  7132.                 line._items.pop(col)
  7133.  
  7134.         if self.InReportView():   #  we only cache max widths when in Report View
  7135.             self._aColWidths.pop(col)
  7136.            
  7137.         # invalidate it as it has to be recalculated
  7138.         self._headerWidth = 0
  7139.  
  7140.  
  7141.     def DoDeleteAllItems(self):
  7142.  
  7143.         if self.IsEmpty():
  7144.             # nothing to do - in particular, don't send the event
  7145.             return
  7146.  
  7147.         self.ResetCurrent()
  7148.  
  7149.         # to make the deletion of all items faster, we don't send the
  7150.         # notifications for each item deletion in this case but only one event
  7151.         # for all of them: this is compatible with wxMSW and documented in
  7152.         # DeleteAllItems() description
  7153.  
  7154.         event = UltimateListEvent(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, self.GetParent().GetId())
  7155.         event.SetEventObject(self.GetParent())
  7156.         self.GetParent().GetEventHandler().ProcessEvent(event)
  7157.  
  7158.         if self.IsVirtual():
  7159.             self._countVirt = 0
  7160.             self._selStore.Clear()
  7161.  
  7162.         if self.InReportView():
  7163.             self.ResetVisibleLinesRange(True)
  7164.             for i in xrange(len(self._aColWidths)):
  7165.                 self._aColWidths[i]._bNeedsUpdate = True
  7166.  
  7167.         for item in self._itemWithWindow:
  7168.             wnd = item.GetWindow()
  7169.             wnd.Destroy()
  7170.  
  7171.         self._lines = []
  7172.         self._itemWithWindow = []
  7173.         self._hasWindows = False
  7174.  
  7175.  
  7176.     def DeleteAllItems(self):
  7177.  
  7178.         self.DoDeleteAllItems()
  7179.         self.RecalculatePositions()
  7180.  
  7181.  
  7182.     def DeleteEverything(self):
  7183.  
  7184.         self._columns = []
  7185.         self._aColWidths = []
  7186.  
  7187.         self.DeleteAllItems()
  7188.  
  7189.  
  7190. # ----------------------------------------------------------------------------
  7191. # scanning for an item
  7192. # ----------------------------------------------------------------------------
  7193.  
  7194.     def EnsureVisible(self, index):
  7195.  
  7196.         if index < 0 or index >= self.GetItemCount():
  7197.             raise Exception("invalid item index in EnsureVisible")
  7198.  
  7199.         # We have to call this here because the label in question might just have
  7200.         # been added and its position is not known yet
  7201.         if self._dirty:
  7202.             self.RecalculatePositions(True)
  7203.  
  7204.         self.MoveToItem(index)
  7205.  
  7206.  
  7207.     def FindItem(self, start, string, partial=False):
  7208.  
  7209.         if start < 0:
  7210.             start = 0
  7211.  
  7212.         str_upper = string.upper()
  7213.         count = self.GetItemCount()
  7214.  
  7215.         for i in xrange(start, count):
  7216.             line = self.GetLine(i)
  7217.             text = line.GetText(0)
  7218.             line_upper = text.upper()
  7219.             if not partial:
  7220.                 if line_upper == str_upper:
  7221.                     return i
  7222.             else:
  7223.                 if line_upper.find(str_upper) == 0:
  7224.                     return i
  7225.  
  7226.         return wx.NOT_FOUND
  7227.  
  7228.  
  7229.     def FindItemData(self, start, data):
  7230.  
  7231.         if start < 0:
  7232.             start = 0
  7233.  
  7234.         count = self.GetItemCount()
  7235.        
  7236.         for i in xrange(start, count):
  7237.             line = self.GetLine(i)
  7238.             item = UltimateListItem()
  7239.             item = line.GetItem(0, item)
  7240.            
  7241.             if item._data == data:
  7242.                 return i
  7243.  
  7244.         return wx.NOT_FOUND
  7245.  
  7246.  
  7247.     def FindItemAtPos(self, pt):
  7248.  
  7249.         topItem, dummy = self.GetVisibleLinesRange()
  7250.         p = self.GetItemPosition(self.GetItemCount()-1)
  7251.        
  7252.         if p.y == 0:
  7253.             return topItem
  7254.  
  7255.         id = int(math.floor(pt.y*float(self.GetItemCount()-topItem-1)/p.y+topItem))
  7256.        
  7257.         if id >= 0 and id < self.GetItemCount():
  7258.             return id
  7259.  
  7260.         return wx.NOT_FOUND
  7261.  
  7262.  
  7263.     def HitTest(self, x, y):
  7264.  
  7265.         x, y = self.CalcUnscrolledPosition(x, y)
  7266.         count = self.GetItemCount()
  7267.  
  7268.         if self.InReportView():
  7269.             if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  7270.                 current = y/self.GetLineHeight()
  7271.                 if current < count:
  7272.                     newItem, flags = self.HitTestLine(current, x, y)
  7273.                     if flags:
  7274.                         return current, flags
  7275.             else:
  7276.                 for current in xrange(self._lineFrom, count):
  7277.                     newItem, flags = self.HitTestLine(current, x, y)
  7278.                     if flags:
  7279.                         return current, flags
  7280.            
  7281.         else:
  7282.             # TODO: optimize it too! this is less simple than for report view but
  7283.             #       enumerating all items is still not a way to do it!!
  7284.             for current in xrange(count):
  7285.                 newItem, flags = self.HitTestLine(current, x, y)
  7286.                 if flags:
  7287.                     return current, flags
  7288.  
  7289.         return wx.NOT_FOUND, None
  7290.  
  7291.  
  7292. # ----------------------------------------------------------------------------
  7293. # adding stuff
  7294. # ----------------------------------------------------------------------------
  7295.  
  7296.     def InsertItem(self, item):
  7297.  
  7298.         if self.IsVirtual():
  7299.             raise Exception("can't be used with virtual control")
  7300.  
  7301.         count = self.GetItemCount()
  7302.         if item._itemId < 0:
  7303.             raise Exception("invalid item index")
  7304.  
  7305.         CheckVariableRowHeight(self, item._text)
  7306.            
  7307.         if item._itemId > count:
  7308.             item._itemId = count
  7309.  
  7310.         id = item._itemId
  7311.         self._dirty = True
  7312.  
  7313.         if self.InReportView():
  7314.             self.ResetVisibleLinesRange(True)
  7315.  
  7316.             # calculate the width of the item and adjust the max column width
  7317.             pWidthInfo = self._aColWidths[item.GetColumn()]
  7318.             width = self.GetItemWidthWithImage(item)
  7319.             item.SetWidth(width)
  7320.            
  7321.             if width > pWidthInfo._nMaxWidth:
  7322.                 pWidthInfo._nMaxWidth = width
  7323.  
  7324.         line = UltimateListLineData(self)
  7325.         line.SetItem(item._col, item)
  7326.  
  7327.         self._lines.insert(id, line)
  7328.         self._dirty = True
  7329.  
  7330.         # If an item is selected at or below the point of insertion, we need to
  7331.         # increment the member variables because the current row's index has gone
  7332.         # up by one
  7333.         if self.HasCurrent() and self._current >= id:
  7334.             self._current += 1
  7335.  
  7336.         self.SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM)
  7337.         self.RefreshLines(id, self.GetItemCount() - 1)
  7338.  
  7339.  
  7340.     def InsertColumn(self, col, item):
  7341.  
  7342.         self._dirty = True
  7343.  
  7344.         if self.InReportView() or self.InTileView() or self.HasExtraFlag(ULC_HEADER_IN_ALL_VIEWS):
  7345.  
  7346.             if item._width == ULC_AUTOSIZE_USEHEADER:
  7347.                 item._width = self.GetTextLength(item._text)
  7348.  
  7349.             column = UltimateListHeaderData(item)
  7350.             colWidthInfo = ColWidthInfo()
  7351.  
  7352.             insert = (col >= 0) and (col < len(self._columns))
  7353.                
  7354.             if insert:
  7355.                 self._columns.insert(col, column)
  7356.                 self._aColWidths.insert(col, colWidthInfo)
  7357.  
  7358.             else:
  7359.  
  7360.                 self._columns.append(column)
  7361.                 self._aColWidths.append(colWidthInfo)
  7362.  
  7363.             if not self.IsVirtual():
  7364.  
  7365.                 # update all the items
  7366.                 for i in xrange(len(self._lines)):
  7367.                     line = self.GetLine(i)
  7368.                     data = UltimateListItemData(self)
  7369.                     if insert:
  7370.                         line._items.insert(col, data)
  7371.                     else:
  7372.                         line._items.append(data)
  7373.  
  7374.             # invalidate it as it has to be recalculated
  7375.             self._headerWidth = 0
  7376.  
  7377.  
  7378.     def GetItemWidthWithImage(self, item):
  7379.  
  7380.         if item.GetCustomRenderer():
  7381.             return item.GetCustomRenderer().GetSubItemWidth()
  7382.  
  7383.         width = 0
  7384.         dc = wx.ClientDC(self)
  7385.  
  7386.         if item.GetFont().IsOk():
  7387.             font = item.GetFont()
  7388.         else:
  7389.             font = self.GetFont()
  7390.            
  7391.         dc.SetFont(font)
  7392.  
  7393.         if item.GetKind() in [1, 2]:
  7394.             ix, iy = self.GetCheckboxImageSize()
  7395.             width += ix
  7396.  
  7397.         if item.GetImage():
  7398.             ix, iy = self.GetImageSize(item.GetImage())
  7399.             width += ix + IMAGE_MARGIN_IN_REPORT_MODE
  7400.  
  7401.         if item.GetText():
  7402.             w, h, dummy = dc.GetMultiLineTextExtent(item.GetText())
  7403.             width += w
  7404.  
  7405.         if item.GetWindow():
  7406.             width += item._windowsize.x + 5
  7407.  
  7408.         return width
  7409.  
  7410.  
  7411.     def GetItemTextSize(self, item):
  7412.  
  7413.         width = ix = iy = start = end = 0
  7414.         dc = wx.ClientDC(self)
  7415.  
  7416.         if item.HasFont():
  7417.             font = item.GetFont()
  7418.         else:
  7419.             font = self.GetFont()
  7420.            
  7421.         dc.SetFont(font)
  7422.  
  7423.         if item.GetKind() in [1, 2]:
  7424.             ix, iy = self.GetCheckboxImageSize()
  7425.             start += ix
  7426.  
  7427.         if item.GetImage():
  7428.             ix, iy = self.GetImageSize(item.GetImage())
  7429.             start += ix + IMAGE_MARGIN_IN_REPORT_MODE
  7430.  
  7431.         if item.GetText():
  7432.             w, h, dummy = dc.GetMultiLineTextExtent(item.GetText())
  7433.             end = w
  7434.  
  7435.         return start, end
  7436.  
  7437.  
  7438. # ----------------------------------------------------------------------------
  7439. # sorting
  7440. # ----------------------------------------------------------------------------
  7441.  
  7442.     def OnCompareItems(self, line1, line2):
  7443.         """
  7444.        Override this function in the derived class to change the sort order of the items
  7445.        in the UltimateListCtrl. The function should return a negative, zero or positive
  7446.        value if the first item is less than, equal to or greater than the second one.
  7447.  
  7448.        The base class version compares items by their index.
  7449.        """
  7450.  
  7451.         item = UltimateListItem()
  7452.         item1 = line1.GetItem(0, item)
  7453.         item = UltimateListItem()
  7454.         item2 = line2.GetItem(0, item)
  7455.        
  7456.         data1 = item1._data
  7457.         data2 = item2._data
  7458.  
  7459.         if self.__func:
  7460.             return self.__func(data1, data2)
  7461.         else:
  7462.             return cmp(data1, data2)
  7463.  
  7464.  
  7465.     def SortItems(self, func):
  7466.  
  7467.         self.HighlightAll(False)
  7468.         self.ResetCurrent()
  7469.  
  7470.         if self._hasWindows:
  7471.             self.HideWindows()
  7472.  
  7473.         if not func:
  7474.             self.__func = None
  7475.             self._lines.sort(self.OnCompareItems)
  7476.         else:
  7477.             self.__func = func
  7478.             self._lines.sort(self.OnCompareItems)
  7479.        
  7480.         if self.IsShownOnScreen():
  7481.             self._dirty = True
  7482.             self._lineHeight = 0
  7483.             self.ResetLineDimensions(True)
  7484.  
  7485.         self.RecalculatePositions(True)
  7486.  
  7487.  
  7488. # ----------------------------------------------------------------------------
  7489. # scrolling
  7490. # ----------------------------------------------------------------------------
  7491.  
  7492.     def OnScroll(self, event):
  7493.  
  7494.         event.Skip()
  7495.  
  7496.         # update our idea of which lines are shown when we redraw the window the
  7497.         # next time
  7498.         self.ResetVisibleLinesRange()
  7499.        
  7500.         if self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  7501.             wx.CallAfter(self.RecalculatePositions, True)
  7502.  
  7503.         if event.GetOrientation() == wx.HORIZONTAL:
  7504.             lc = self.GetListCtrl()
  7505.  
  7506.             if self.HasHeader():
  7507.                 lc._headerWin.Refresh()
  7508.                 lc._headerWin.Update()
  7509.                
  7510.             if self.HasFooter():
  7511.                 lc._footerWin.Refresh()
  7512.                 lc._footerWin.Update()
  7513.                
  7514.        
  7515.     def GetCountPerPage(self):
  7516.  
  7517.         if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  7518.             if not self._linesPerPage:
  7519.                 self._linesPerPage = self.GetClientSize().y/self.GetLineHeight()
  7520.  
  7521.             return self._linesPerPage
  7522.  
  7523.         visibleFrom, visibleTo = self.GetVisibleLinesRange()
  7524.         self._linesPerPage = visibleTo - visibleFrom + 1
  7525.            
  7526.         return self._linesPerPage
  7527.  
  7528.  
  7529.     def GetVisibleLinesRange(self):
  7530.  
  7531.         if not self.InReportView():
  7532.             raise Exception("this is for report mode only")
  7533.  
  7534.         if self._lineFrom == -1:
  7535.            
  7536.             count = self.GetItemCount()
  7537.            
  7538.             if count:
  7539.  
  7540.                 if self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  7541.  
  7542.                     view_x, view_y = self.GetViewStart()
  7543.                     view_y *= SCROLL_UNIT_Y
  7544.  
  7545.                     for i in xrange(0, count):
  7546.                         rc = self.GetLineY(i)
  7547.                         if rc > view_y:
  7548.                             self._lineFrom = i - 1
  7549.                             break
  7550.  
  7551.                     if self._lineFrom < 0:
  7552.                         self._lineFrom = 0
  7553.                                            
  7554.                     self._lineTo = self._lineFrom                        
  7555.                     clientWidth, clientHeight = self.GetClientSize()
  7556.                    
  7557.                     for i in xrange(self._lineFrom, count):
  7558.                         rc = self.GetLineY(i) + self.GetLineHeight(i)
  7559.                         if rc > view_y + clientHeight - 5:
  7560.                             break
  7561.                         self._lineTo += 1
  7562.  
  7563.                 else:
  7564.                    
  7565.                     # No variable row height
  7566.                     self._lineFrom = self.GetScrollPos(wx.VERTICAL)
  7567.  
  7568.                     # this may happen if SetScrollbars() hadn't been called yet
  7569.                     if self._lineFrom >= count:
  7570.                         self._lineFrom = count - 1
  7571.  
  7572.                     self._lineTo = self._lineFrom + self._linesPerPage
  7573.  
  7574.                 # we redraw one extra line but this is needed to make the redrawing
  7575.                 # logic work when there is a fractional number of lines on screen
  7576.                 if self._lineTo >= count:
  7577.                     self._lineTo = count - 1
  7578.  
  7579.             else: # empty control
  7580.  
  7581.                 self._lineFrom = -1
  7582.                 self._lineTo = -1
  7583.  
  7584.         return self._lineFrom, self._lineTo
  7585.  
  7586.  
  7587.     def ResetTextControl(self):
  7588.         """Called by UltimateListTextCtrl when it marks itself for deletion."""
  7589.  
  7590.         self._textctrl.Destroy()
  7591.         self._textctrl = None
  7592.  
  7593.         self.RecalculatePositions()
  7594.         self.Refresh()
  7595.  
  7596.  
  7597.     def SetFirstGradientColour(self, colour=None):
  7598.         """Sets the first gradient colour."""
  7599.        
  7600.         if colour is None:
  7601.             colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
  7602.  
  7603.         self._firstcolour = colour
  7604.         if self._usegradients:
  7605.             self.RefreshSelected()
  7606.            
  7607.  
  7608.     def SetSecondGradientColour(self, colour=None):
  7609.         """Sets the second gradient colour."""
  7610.  
  7611.         if colour is None:
  7612.             # No colour given, generate a slightly darker from the
  7613.             # UltimateListCtrl background colour
  7614.             colour = self.GetBackgroundColour()
  7615.             r, g, b = int(colour.Red()), int(colour.Green()), int(colour.Blue())
  7616.             colour = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
  7617.             colour = wx.Colour(colour[0], colour[1], colour[2])
  7618.  
  7619.         self._secondcolour = colour
  7620.  
  7621.         if self._usegradients:
  7622.             self.RefreshSelected()
  7623.  
  7624.  
  7625.     def GetFirstGradientColour(self):
  7626.         """Returns the first gradient colour."""
  7627.        
  7628.         return self._firstcolour
  7629.  
  7630.  
  7631.     def GetSecondGradientColour(self):
  7632.         """Returns the second gradient colour."""
  7633.        
  7634.         return self._secondcolour
  7635.  
  7636.  
  7637.     def EnableSelectionGradient(self, enable=True):
  7638.         """Globally enables/disables drawing of gradient selection."""
  7639.  
  7640.         self._usegradients = enable
  7641.         self._vistaselection = False
  7642.         self.RefreshSelected()
  7643.        
  7644.  
  7645.     def SetGradientStyle(self, vertical=0):
  7646.         """
  7647.        Sets the gradient style:
  7648.        0: horizontal gradient
  7649.        1: vertical gradient
  7650.        """
  7651.  
  7652.         # 0 = Horizontal, 1 = Vertical
  7653.         self._gradientstyle = vertical
  7654.  
  7655.         if self._usegradients:
  7656.             self.RefreshSelected()
  7657.  
  7658.  
  7659.     def GetGradientStyle(self):
  7660.         """
  7661.        Returns the gradient style:
  7662.        0: horizontal gradient
  7663.        1: vertical gradient
  7664.        """
  7665.  
  7666.         return self._gradientstyle
  7667.  
  7668.  
  7669.     def EnableSelectionVista(self, enable=True):
  7670.         """Globally enables/disables drawing of Windows Vista selection."""
  7671.  
  7672.         self._usegradients = False
  7673.         self._vistaselection = enable
  7674.         self.RefreshSelected()
  7675.  
  7676.  
  7677.     def SetBackgroundImage(self, image):
  7678.         """Sets the UltimateListCtrl background image (can be None)."""
  7679.  
  7680.         self._backgroundImage = image
  7681.         self.Refresh()
  7682.        
  7683.  
  7684.     def GetBackgroundImage(self):
  7685.         """Returns the UltimateListCtrl background image (can be None)."""
  7686.  
  7687.         return self._backgroundImage
  7688.  
  7689.  
  7690.     def SetWaterMark(self, watermark):
  7691.         """Sets the UltimateListCtrl watermark image (can be None)."""
  7692.  
  7693.         self._waterMark = watermark
  7694.         self.Refresh()
  7695.        
  7696.  
  7697.     def GetWaterMark(self):
  7698.         """Returns the UltimateListCtrl watermark image (can be None)."""
  7699.  
  7700.         return self._waterMark
  7701.    
  7702.  
  7703.     def SetDisabledTextColour(self, colour):
  7704.         """Sets the items disabled colour."""
  7705.        
  7706.         # Disabled items colour        
  7707.         self._disabledColour = colour
  7708.         self.Refresh()
  7709.  
  7710.  
  7711.     def GetDisabledTextColour(self):
  7712.         """Returns the items disabled colour."""
  7713.  
  7714.         return self._disabledColour
  7715.  
  7716.  
  7717.     def ScrollList(self, dx, dy):
  7718.  
  7719.         if not self.InReportView():
  7720.             # TODO: this should work in all views but is not implemented now
  7721.             return False
  7722.  
  7723.         top, bottom = self.GetVisibleLinesRange()
  7724.  
  7725.         if bottom == -1:
  7726.             return 0
  7727.  
  7728.         self.ResetVisibleLinesRange()
  7729.  
  7730.         if not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  7731.             hLine = self.GetLineHeight()
  7732.             self.Scroll(-1, top + dy/hLine)
  7733.         else:
  7734.             self.Scroll(-1, top + dy/SCROLL_UNIT_Y)
  7735.  
  7736.         if wx.Platform == "__WXMAC__":
  7737.             # see comment in MoveToItem() for why we do this
  7738.             self.ResetVisibleLinesRange()
  7739.  
  7740.         return True
  7741.    
  7742. # -------------------------------------------------------------------------------------
  7743. # UltimateListCtrl
  7744. # -------------------------------------------------------------------------------------
  7745.  
  7746. class UltimateListCtrl(wx.PyControl):
  7747.  
  7748.     def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
  7749.                  style=0, extraStyle=0, validator=wx.DefaultValidator, name="UltimateListCtrl"):
  7750.  
  7751.         self._imageListNormal = None
  7752.         self._imageListSmall = None
  7753.         self._imageListState = None
  7754.  
  7755.         if not style & ULC_MASK_TYPE:
  7756.             raise Exception("UltimateListCtrl style should have exactly one mode bit set")
  7757.  
  7758.         if not (style & ULC_REPORT) and extraStyle & ULC_HAS_VARIABLE_ROW_HEIGHT:
  7759.             raise Exception("Extra Style ULC_HAS_VARIABLE_ROW_HEIGHT can only be used in report, non-virtual mode")
  7760.  
  7761.         if extraStyle & ULC_STICKY_HIGHLIGHT and extraStyle & ULC_TRACK_SELECT:
  7762.             raise Exception("Extra styles ULC_STICKY_HIGHLIGHT and ULC_TRACK_SELECT can not be combined")
  7763.  
  7764.         if style & ULC_NO_HEADER and extraStyle & ULC_HEADER_IN_ALL_VIEWS:
  7765.             raise Exception("Style ULC_NO_HEADER and extra style ULC_HEADER_IN_ALL_VIEWS can not be combined")
  7766.  
  7767.         wx.PyControl.__init__(self, parent, id, pos, size, style|wx.CLIP_CHILDREN, validator, name)
  7768.  
  7769.         self._mainWin = None
  7770.         self._headerWin = None
  7771.         self._footerWin = None
  7772.        
  7773.         self._headerHeight = wx.RendererNative.Get().GetHeaderButtonHeight(self)
  7774.         self._footerHeight = self._headerHeight
  7775.  
  7776.         if wx.Platform == "__WXGTK__":
  7777.             style &= ~wx.BORDER_MASK
  7778.             style |= wx.BORDER_THEME
  7779.         else:
  7780.             if style & wx.BORDER_THEME:
  7781.                 style -= wx.BORDER_THEME
  7782.  
  7783.         self._extraStyle = extraStyle
  7784.         if style & wx.SUNKEN_BORDER:
  7785.             style -= wx.SUNKEN_BORDER
  7786.            
  7787.         self._mainWin = UltimateListMainWindow(self, wx.ID_ANY, wx.Point(0, 0), size, style)
  7788.  
  7789.         sizer = wx.BoxSizer(wx.VERTICAL)
  7790.         sizer.Add(self._mainWin, 1, wx.GROW)
  7791.         self.SetSizer(sizer)
  7792.  
  7793.         self.Bind(wx.EVT_SIZE, self.OnSize)
  7794.         self.CreateOrDestroyHeaderWindowAsNeeded()
  7795.         self.CreateOrDestroyFooterWindowAsNeeded()
  7796.  
  7797.         self.SetInitialSize(size)
  7798.         wx.CallAfter(self.Layout)
  7799.        
  7800.  
  7801.     def CreateOrDestroyHeaderWindowAsNeeded(self):
  7802.  
  7803.         needs_header = self.HasHeader()
  7804.         has_header = self._headerWin is not None
  7805.         if needs_header == has_header:
  7806.             return
  7807.  
  7808.         if needs_header:
  7809.  
  7810.             self._headerWin = UltimateListHeaderWindow(self, wx.ID_ANY, self._mainWin,
  7811.                                                        wx.Point(0, 0),
  7812.                                                        wx.Size(self.GetClientSize().x, self._headerHeight),
  7813.                                                        wx.TAB_TRAVERSAL, isFooter=False)
  7814.  
  7815.             # ----------------------------------------------------
  7816.             # How do you translate all this blah-blah to wxPython?
  7817.             # ----------------------------------------------------
  7818.             #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
  7819.             #        wxFont font
  7820.             #if wxOSX_USE_ATSU_TEXT
  7821.             #        font.MacCreateFromThemeFont( kThemeSmallSystemFont )
  7822.             #else
  7823.             #        font.MacCreateFromUIFont( kCTFontSystemFontType )
  7824.             #endif
  7825.             #        m_headerWin->SetFont( font )
  7826.             #endif
  7827.  
  7828.             self.GetSizer().Prepend(self._headerWin, 0, wx.GROW)
  7829.  
  7830.         else:
  7831.  
  7832.             self.GetSizer().Detach(self._headerWin)
  7833.             self._headerWin.Destroy()
  7834.             self._headerWin = None
  7835.            
  7836.  
  7837.     def CreateOrDestroyFooterWindowAsNeeded(self):
  7838.  
  7839.         needs_footer = self.HasFooter()
  7840.         has_footer = self._footerWin is not None
  7841.         if needs_footer == has_footer:
  7842.             return
  7843.  
  7844.         if needs_footer:
  7845.  
  7846.             self._footerWin = UltimateListHeaderWindow(self, wx.ID_ANY, self._mainWin,
  7847.                                                        wx.Point(0, 0),
  7848.                                                        wx.Size(self.GetClientSize().x, self._footerHeight),
  7849.                                                        wx.TAB_TRAVERSAL, isFooter=True)
  7850.  
  7851.             # ----------------------------------------------------
  7852.             # How do you translate all this blah-blah to wxPython?
  7853.             # ----------------------------------------------------
  7854.             #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
  7855.             #        wxFont font
  7856.             #if wxOSX_USE_ATSU_TEXT
  7857.             #        font.MacCreateFromThemeFont( kThemeSmallSystemFont )
  7858.             #else
  7859.             #        font.MacCreateFromUIFont( kCTFontSystemFontType )
  7860.             #endif
  7861.             #        m_headerWin->SetFont( font )
  7862.             #endif
  7863.  
  7864.             self.GetSizer().Add(self._footerWin, 0, wx.GROW)
  7865.  
  7866.         else:
  7867.  
  7868.             self.GetSizer().Detach(self._footerWin)
  7869.             self._footerWin.Destroy()
  7870.             self._footerWin = None
  7871.  
  7872.  
  7873.     def HasHeader(self):
  7874.  
  7875.         return self._mainWin.HasHeader()
  7876.    
  7877.  
  7878.     def HasFooter(self):
  7879.  
  7880.         return self._mainWin.HasFooter()
  7881.  
  7882.  
  7883.     def GetDefaultBorder(self):
  7884.  
  7885.         return wx.BORDER_THEME
  7886.  
  7887.  
  7888.     def SetSingleStyle(self, style, add=True):
  7889.  
  7890.         if style & ULC_VIRTUAL:
  7891.             raise Exception("ULC_VIRTUAL can't be [un]set")
  7892.        
  7893.         flag = self.GetWindowStyle()
  7894.  
  7895.         if add:
  7896.  
  7897.             if style & ULC_MASK_TYPE:
  7898.                 flag &= ~(ULC_MASK_TYPE | ULC_VIRTUAL)
  7899.             if style & ULC_MASK_ALIGN:
  7900.                 flag &= ~ULC_MASK_ALIGN
  7901.             if style & ULC_MASK_SORT:
  7902.                 flag &= ~ULC_MASK_SORT
  7903.  
  7904.         if add:
  7905.             flag |= style
  7906.         else:
  7907.             flag &= ~style
  7908.  
  7909.         # some styles can be set without recreating everything (as happens in
  7910.         # SetWindowStyleFlag() which calls ListMainWindow.DeleteEverything())
  7911.         if not style & ~(ULC_HRULES | ULC_VRULES):
  7912.             self.Refresh()
  7913.             wx.PyControl.SetWindowStyleFlag(self, flag)
  7914.         else:
  7915.             self.SetWindowStyleFlag(flag)
  7916.  
  7917.  
  7918.     def SetExtraStyle(self, style):
  7919.  
  7920.         if style & ULC_HAS_VARIABLE_ROW_HEIGHT and not self.HasFlag(ULC_REPORT):
  7921.             raise Exception("ULC_HAS_VARIABLE_ROW_HEIGHT extra style can be used only in report mode")
  7922.        
  7923.         self._extraStyle = style
  7924.        
  7925.         if style & ULC_HAS_VARIABLE_ROW_HEIGHT:
  7926.             self._mainWin.ResetLineDimensions()
  7927.             self._mainWin.ResetVisibleLinesRange()
  7928.  
  7929.         self.CreateOrDestroyFooterWindowAsNeeded()
  7930.  
  7931.         self.GetSizer().Layout()
  7932.         self.Refresh()
  7933.  
  7934.  
  7935.     def SetWindowStyleFlag(self, flag):
  7936.  
  7937.         if self._mainWin:
  7938.  
  7939.             self.CreateOrDestroyHeaderWindowAsNeeded()
  7940.             self.GetSizer().Layout()
  7941.            
  7942.         wx.PyControl.SetWindowStyleFlag(self, flag)
  7943.  
  7944.  
  7945.     def GetColumn(self, col):
  7946.  
  7947.         return self._mainWin.GetColumn(col)
  7948.  
  7949.  
  7950.     def SetColumn(self, col, item):
  7951.  
  7952.         self._mainWin.SetColumn(col, item)
  7953.         return True
  7954.  
  7955.  
  7956.     def GetColumnWidth(self, col):
  7957.  
  7958.         return self._mainWin.GetColumnWidth(col)
  7959.  
  7960.  
  7961.     def SetColumnWidth(self, col, width):
  7962.  
  7963.         self._mainWin.SetColumnWidth(col, width)
  7964.         return True
  7965.  
  7966.  
  7967.     def GetCountPerPage(self):
  7968.  
  7969.         return self._mainWin.GetCountPerPage()  # different from Windows ?
  7970.  
  7971.  
  7972.     def GetItem(self, itemOrId, col=0):
  7973.  
  7974.         item = CreateListItem(itemOrId, col)
  7975.         return self._mainWin.GetItem(item, col)
  7976.  
  7977.  
  7978.     def SetItem(self, info):
  7979.  
  7980.         self._mainWin.SetItem(info)
  7981.         return True
  7982.  
  7983.  
  7984.     def SetStringItem(self, index, col, label, imageIds=[], it_kind=0):
  7985.  
  7986.         info = UltimateListItem()
  7987.         info._text = label
  7988.         info._mask = ULC_MASK_TEXT
  7989.  
  7990.         if it_kind:
  7991.             info._mask |= ULC_MASK_KIND
  7992.             info._kind = it_kind
  7993.            
  7994.         info._itemId = index        
  7995.         info._col = col
  7996.  
  7997.         for ids in to_list(imageIds):
  7998.             if ids > -1:
  7999.                 info._image.append(ids)
  8000.  
  8001.         if info._image:
  8002.             info._mask |= ULC_MASK_IMAGE
  8003.  
  8004.         self._mainWin.SetItem(info)
  8005.         return index
  8006.  
  8007.  
  8008.     def GetItemState(self, item, stateMask):
  8009.  
  8010.         return self._mainWin.GetItemState(item, stateMask)
  8011.  
  8012.  
  8013.     def SetItemState(self, item, state, stateMask):
  8014.  
  8015.         self._mainWin.SetItemState(item, state, stateMask)
  8016.         return True
  8017.  
  8018.  
  8019.     def SetItemImage(self, item, image, selImage=-1):
  8020.  
  8021.         return self.SetItemColumnImage(item, 0, image)
  8022.  
  8023.  
  8024.     def SetItemColumnImage(self, item, column, image):
  8025.  
  8026.         info = UltimateListItem()
  8027.         info._image = to_list(image)
  8028.         info._mask = ULC_MASK_IMAGE
  8029.         info._itemId = item
  8030.         info._col = column
  8031.         self._mainWin.SetItem(info)
  8032.        
  8033.         return True
  8034.  
  8035.  
  8036.     def GetItemText(self, item):
  8037.  
  8038.         return self._mainWin.GetItemText(item)
  8039.  
  8040.  
  8041.     def SetItemText(self, item, str):
  8042.  
  8043.         self._mainWin.SetItemText(item, str)
  8044.  
  8045.  
  8046.     def GetItemData(self, item):
  8047.  
  8048.         info = UltimateListItem()
  8049.         info._mask = ULC_MASK_DATA
  8050.         info._itemId = item
  8051.         self._mainWin.GetItem(info)
  8052.         return info._data
  8053.  
  8054.  
  8055.     def SetItemData(self, item, data):
  8056.  
  8057.         info = UltimateListItem()
  8058.         info._mask = ULC_MASK_DATA
  8059.         info._itemId = item
  8060.         info._data = data
  8061.         self._mainWin.SetItem(info)
  8062.         return True
  8063.  
  8064.  
  8065.     def GetItemPyData(self, item):
  8066.  
  8067.         info = UltimateListItem()
  8068.         info._mask = ULC_MASK_PYDATA
  8069.         info._itemId = item
  8070.         self._mainWin.GetItem(info)
  8071.         return info._pyData
  8072.  
  8073.  
  8074.     def SetItemPyData(self, item, pyData):
  8075.  
  8076.         info = UltimateListItem()
  8077.         info._mask = ULC_MASK_PYDATA
  8078.         info._itemId = item
  8079.         info._pyData = pyData
  8080.         self._mainWin.SetItem(info)
  8081.         return True
  8082.    
  8083.  
  8084.     SetPyData = SetItemPyData
  8085.     GetPyData = GetItemPyData
  8086.  
  8087.  
  8088.     def GetViewRect(self):
  8089.  
  8090.         return self._mainWin.GetViewRect()
  8091.  
  8092.  
  8093.     def GetItemRect(self, item, code=ULC_RECT_BOUNDS):
  8094.  
  8095.         return self.GetSubItemRect(item, ULC_GETSUBITEMRECT_WHOLEITEM, code)
  8096.  
  8097.  
  8098.     def GetSubItemRect(self, item, subItem, code):
  8099.  
  8100.         rect = self._mainWin.GetSubItemRect(item, subItem)
  8101.         if self._mainWin.HasHeader():
  8102.             rect.y += self._headerHeight + 1
  8103.  
  8104.         return rect
  8105.  
  8106.  
  8107.     def GetItemPosition(self, item):
  8108.  
  8109.         return self._mainWin.GetItemPosition(item)
  8110.  
  8111.  
  8112.     def SetItemPosition(item, pos):
  8113.  
  8114.         return False
  8115.  
  8116.  
  8117.     def GetItemCount(self):
  8118.  
  8119.         return self._mainWin.GetItemCount()
  8120.  
  8121.  
  8122.     def GetColumnCount(self):
  8123.  
  8124.         return self._mainWin.GetColumnCount()
  8125.  
  8126.  
  8127.     def SetItemSpacing(self, spacing, isSmall=False):
  8128.  
  8129.         self._mainWin.SetItemSpacing(spacing, isSmall)
  8130.  
  8131.  
  8132.     def GetItemSpacing(self, isSmall=False):
  8133.  
  8134.         return self._mainWin.GetItemSpacing(isSmall)
  8135.  
  8136.  
  8137.     def SetItemTextColour(self, item, col):
  8138.  
  8139.         info = UltimateListItem()
  8140.         info._itemId = item
  8141.         info.SetTextColour(col)
  8142.         self._mainWin.SetItem(info)
  8143.  
  8144.  
  8145.     def GetItemTextColour(self, item):
  8146.  
  8147.         info = UltimateListItem()
  8148.         info._itemId = item
  8149.         info = self._mainWin.GetItem(info)
  8150.        
  8151.         return info.GetTextColour()
  8152.  
  8153.  
  8154.     def SetItemBackgroundColour(self, item, col):
  8155.  
  8156.         info = UltimateListItem()
  8157.         info._itemId = item
  8158.         info.SetBackgroundColour(col)
  8159.         self._mainWin.SetItem(info)
  8160.  
  8161.  
  8162.     def GetItemBackgroundColour(self, item):
  8163.  
  8164.         info = UltimateListItem()
  8165.         info._itemId = item
  8166.         info = self._mainWin.GetItem(info)
  8167.         return info.GetBackgroundColour()
  8168.  
  8169.  
  8170.     def SetItemFont(self, item, f):
  8171.  
  8172.         info = UltimateListItem()
  8173.         info._itemId = item
  8174.         info.SetFont(f)
  8175.         self._mainWin.SetItem(info)
  8176.  
  8177.  
  8178.     def GetItemFont(self, item):
  8179.  
  8180.         info = UltimateListItem()
  8181.         info._itemId = item
  8182.         info = self._mainWin.GetItem(info)
  8183.         return info.GetFont()
  8184.  
  8185.  
  8186.     def GetSelectedItemCount(self):
  8187.  
  8188.         return self._mainWin.GetSelectedItemCount()
  8189.  
  8190.  
  8191.     def GetTextColour(self):
  8192.  
  8193.         return self.GetForegroundColour()
  8194.  
  8195.  
  8196.     def SetTextColour(self, col):
  8197.  
  8198.         self.SetForegroundColour(col)
  8199.  
  8200.  
  8201.     def GetTopItem(self):
  8202.  
  8203.         top, dummy = self._mainWin.GetVisibleLinesRange()
  8204.         return top
  8205.  
  8206.  
  8207.     def GetNextItem(self, item, geometry=ULC_NEXT_ALL, state=ULC_STATE_DONTCARE):
  8208.  
  8209.         return self._mainWin.GetNextItem(item, geometry, state)
  8210.  
  8211.  
  8212.     def GetImageList(self, which):
  8213.  
  8214.         if which == wx.IMAGE_LIST_NORMAL:
  8215.             return self._imageListNormal
  8216.  
  8217.         elif which == wx.IMAGE_LIST_SMALL:
  8218.             return self._imageListSmall
  8219.  
  8220.         elif which == wx.IMAGE_LIST_STATE:
  8221.             return self._imageListState
  8222.  
  8223.         return None
  8224.  
  8225.  
  8226.     def SetImageList(self, imageList, which):
  8227.  
  8228.         if which == wx.IMAGE_LIST_NORMAL:
  8229.             self._imageListNormal = imageList
  8230.  
  8231.         elif which == wx.IMAGE_LIST_SMALL:
  8232.             self._imageListSmall = imageList
  8233.  
  8234.         elif which == wx.IMAGE_LIST_STATE:
  8235.             self._imageListState = imageList
  8236.  
  8237.         self._mainWin.SetImageList(imageList, which)
  8238.  
  8239.  
  8240.     def AssignImageList(self, imageList, which):
  8241.  
  8242.         self.SetImageList(imageList, which)
  8243.  
  8244.  
  8245.     def Arrange(self, flag):
  8246.  
  8247.         return 0
  8248.  
  8249.  
  8250.     def DeleteItem(self, item):
  8251.  
  8252.         self._mainWin.DeleteItem(item)
  8253.         return True
  8254.  
  8255.  
  8256.     def DeleteAllItems(self):
  8257.  
  8258.         self._mainWin.DeleteAllItems()
  8259.         return True
  8260.  
  8261.  
  8262.     def DeleteAllColumns(self):
  8263.  
  8264.         count = len(self._mainWin._columns)
  8265.         for n in xrange(count):
  8266.             self.DeleteColumn(0)
  8267.  
  8268.         return True
  8269.  
  8270.  
  8271.     def ClearAll(self):
  8272.  
  8273.         self._mainWin.DeleteEverything()
  8274.  
  8275.  
  8276.     def DeleteColumn(self, col):
  8277.  
  8278.         self._mainWin.DeleteColumn(col)
  8279.         return True
  8280.  
  8281.  
  8282.     def EditLabel(self, item):
  8283.  
  8284.         self._mainWin.EditLabel(item)
  8285.  
  8286.  
  8287.     def EnsureVisible(self, item):
  8288.  
  8289.         self._mainWin.EnsureVisible(item)
  8290.         return True
  8291.  
  8292.  
  8293.     def FindItem(self, start, str, partial=False):
  8294.  
  8295.         return self._mainWin.FindItem(start, str, partial)
  8296.  
  8297.  
  8298.     def FindItemData(self, start, data):
  8299.  
  8300.         return self._mainWin.FindItemData(start, data)
  8301.  
  8302.  
  8303.     def FindItemAtPos(self, start, pt, direction):
  8304.  
  8305.         return self._mainWin.FindItemAtPos(pt)
  8306.  
  8307.  
  8308.     def HitTest(self, pointOrTuple):
  8309.  
  8310.         if isinstance(pointOrTuple, wx.Point):
  8311.             x, y = pointOrTuple.x, pointOrTuple.y
  8312.         else:
  8313.             x, y = pointOrTuple
  8314.  
  8315.         return self._mainWin.HitTest(x, y)
  8316.  
  8317.  
  8318.     def InsertItem(self, info):
  8319.  
  8320.         self._mainWin.InsertItem(info)
  8321.         return info._itemId
  8322.  
  8323.  
  8324.     def InsertStringItem(self, index, label, it_kind=0):
  8325.  
  8326.         info = UltimateListItem()
  8327.         info._text = label
  8328.         info._mask = ULC_MASK_TEXT
  8329.  
  8330.         if it_kind:
  8331.             info._mask |= ULC_MASK_KIND
  8332.             info._kind = it_kind
  8333.  
  8334.         info._itemId = index
  8335.         return self.InsertItem(info)
  8336.  
  8337.  
  8338.     def InsertImageItem(self, index, imageIds, it_kind=0):
  8339.  
  8340.         info = UltimateListItem()
  8341.         info._mask = ULC_MASK_IMAGE
  8342.  
  8343.         if it_kind:
  8344.             info._mask |= ULC_MASK_KIND
  8345.             info._kind = it_kind
  8346.        
  8347.         info._image = to_list(imageIds)
  8348.         info._itemId = index
  8349.        
  8350.         return self.InsertItem(info)
  8351.  
  8352.  
  8353.     def InsertImageStringItem(self, index, label, imageIds, it_kind=0):
  8354.  
  8355.         info = UltimateListItem()
  8356.         info._text = label
  8357.         info._image = to_list(imageIds)
  8358.         info._mask = ULC_MASK_TEXT | ULC_MASK_IMAGE
  8359.  
  8360.         if it_kind:
  8361.             info._mask |= ULC_MASK_KIND
  8362.             info._kind = it_kind
  8363.        
  8364.         info._itemId = index
  8365.         return self.InsertItem(info)
  8366.  
  8367.  
  8368.     def InsertColumnInfo(self, col, item):
  8369.  
  8370.         if not self._mainWin.InReportView() and not self.HasExtraFlag(ULC_HEADER_IN_ALL_VIEWS) and \
  8371.            not self._mainWin.InTileView():
  8372.             raise Exception("Can't add column in non report/tile modes or without the ULC_HEADER_IN_ALL_VIEWS extra style set")
  8373.  
  8374.         self._mainWin.InsertColumn(col, item)
  8375.         if self._headerWin:
  8376.             self._headerWin.Refresh()
  8377.  
  8378.         return 0
  8379.  
  8380.  
  8381.     def InsertColumn(self, col, heading, format=ULC_FORMAT_LEFT, width=-1):
  8382.  
  8383.         item = UltimateListItem()
  8384.         item._mask = ULC_MASK_TEXT | ULC_MASK_FORMAT | ULC_MASK_FONT
  8385.         item._text = heading
  8386.        
  8387.         if width >= -2:
  8388.             item._mask |= ULC_MASK_WIDTH
  8389.             item._width = width
  8390.  
  8391.         item._format = format
  8392.  
  8393.         return self.InsertColumnInfo(col, item)
  8394.  
  8395.  
  8396.     def IsColumnShown(self, column):
  8397.  
  8398.         if self._headerWin:
  8399.             return self._mainWin.IsColumnShown(column)
  8400.  
  8401.         raise Exception("Showing/hiding columns works only with the header shown")
  8402.  
  8403.  
  8404.     def SetColumnShown(self, column, shown=True):
  8405.  
  8406.         col = self.GetColumn(column)
  8407.         col._mask |= ULC_MASK_SHOWN
  8408.         col.SetShown(shown)
  8409.         self._mainWin.SetColumn(column, col)
  8410.         self.Update()
  8411.  
  8412.        
  8413.     def ScrollList(self, dx, dy):
  8414.  
  8415.         return self._mainWin.ScrollList(dx, dy)
  8416.  
  8417.  
  8418. # Sort items.
  8419. # func is a function which takes 3 long arguments: item1, item2, data.
  8420. # The return value is a negative number if the first item should precede the second
  8421. # item, a positive number of the second item should precede the first,
  8422. # or zero if the two items are equivalent.
  8423.  
  8424.     def SortItems(self, func=None):
  8425.  
  8426.         self._mainWin.SortItems(func)
  8427.        
  8428.         return True
  8429.        
  8430.            
  8431. # ----------------------------------------------------------------------------
  8432. # event handlers
  8433. # ----------------------------------------------------------------------------
  8434.  
  8435.     def OnSize(self, event):
  8436.  
  8437.         if not self.IsShownOnScreen():
  8438.             return
  8439.        
  8440.         if not self._mainWin:
  8441.             return
  8442.  
  8443.         # We need to override OnSize so that our scrolled
  8444.         # window a) does call Layout() to use sizers for
  8445.         # positioning the controls but b) does not query
  8446.         # the sizer for their size and use that for setting
  8447.         # the scrollable area as set that ourselves by
  8448.         # calling SetScrollbar() further down.
  8449.  
  8450.         self.Layout()
  8451.        
  8452.         self._mainWin.ResetVisibleLinesRange(True)
  8453.         self._mainWin.RecalculatePositions()
  8454.         self._mainWin.AdjustScrollbars()
  8455.  
  8456.         if self._headerWin:
  8457.             self._headerWin.Refresh()
  8458.            
  8459.         if self._footerWin:
  8460.             self._footerWin.Refresh()
  8461.  
  8462.  
  8463.     def OnInternalIdle(self):
  8464.  
  8465.         wx.PyControl.OnInternalIdle(self)
  8466.  
  8467.         # do it only if needed
  8468.         if self._mainWin._dirty:
  8469.             self._mainWin._shortItems = []
  8470.             self._mainWin.RecalculatePositions()
  8471.  
  8472.  
  8473. # ----------------------------------------------------------------------------
  8474. # font/colours
  8475. # ----------------------------------------------------------------------------
  8476.  
  8477.     def SetBackgroundColour(self, colour):
  8478.  
  8479.         if self._mainWin:
  8480.             self._mainWin.SetBackgroundColour(colour)
  8481.             self._mainWin._dirty = True
  8482.  
  8483.         return True
  8484.  
  8485.  
  8486.     def SetForegroundColour(self, colour):
  8487.  
  8488.         if not wx.PyControl.SetForegroundColour(self, colour):
  8489.             return False
  8490.  
  8491.         if self._mainWin:
  8492.             self._mainWin.SetForegroundColour(colour)
  8493.             self._mainWin._dirty = True
  8494.  
  8495.         if self._headerWin:
  8496.             self._headerWin.SetForegroundColour(colour)
  8497.  
  8498.         return True
  8499.  
  8500.  
  8501.     def SetFont(self, font):
  8502.  
  8503.         if not wx.PyControl.SetFont(self, font):
  8504.             return False
  8505.  
  8506.         if self._mainWin:
  8507.             self._mainWin.SetFont(font)
  8508.             self._mainWin._dirty = True
  8509.  
  8510.         if self._headerWin:
  8511.             self._headerWin.SetFont(font)
  8512.  
  8513.         self.Refresh()
  8514.  
  8515.         return True
  8516.  
  8517.  
  8518.     def GetClassDefaultAttributes(self, variant):
  8519.  
  8520.         attr = wx.VisualAttributes()
  8521.         attr.colFg = wx.SystemSettings.GetColour(wx.SYS_COLOUR_LISTBOXTEXT)
  8522.         attr.colBg = wx.SystemSettings.GetColour(wx.SYS_COLOUR_LISTBOX)
  8523.         attr.font  = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  8524.         return attr
  8525.  
  8526.  
  8527.     def GetScrolledWin(self):
  8528.  
  8529.         return self._headerWin.GetOwner()
  8530.  
  8531.  
  8532. # ----------------------------------------------------------------------------
  8533. # methods forwarded to self._mainWin
  8534. # ----------------------------------------------------------------------------
  8535.  
  8536.     def SetDropTarget(self, dropTarget):
  8537.  
  8538.         self._mainWin.SetDropTarget(dropTarget)
  8539.  
  8540.  
  8541.     def GetDropTarget(self):
  8542.  
  8543.         return self._mainWin.GetDropTarget()
  8544.  
  8545.  
  8546.     def SetCursor(self, cursor):
  8547.  
  8548.         return (self._mainWin and [self._mainWin.SetCursor(cursor)] or [False])[0]
  8549.  
  8550.  
  8551.     def GetBackgroundColour(self):
  8552.  
  8553.         return (self._mainWin and [self._mainWin.GetBackgroundColour()] or [wx.NullColour])[0]
  8554.  
  8555.  
  8556.     def GetForegroundColour(self):
  8557.  
  8558.         return (self._mainWin and [self._mainWin.GetForegroundColour()] or [wx.NullColour])[0]
  8559.  
  8560.  
  8561.     def PopupMenu(self, menu, pos=wx.DefaultPosition):
  8562.  
  8563.         return self._mainWin.PopupMenu(menu, pos)
  8564.  
  8565.  
  8566.     def ClientToScreen(self, x, y):
  8567.  
  8568.         return self._mainWin.ClientToScreen(x, y)
  8569.  
  8570.  
  8571.     def ScreenToClient(self, x, y):
  8572.  
  8573.         return self._mainWin.ScreenToClient(x, y)
  8574.  
  8575.  
  8576.     def SetFocus(self):
  8577.  
  8578.         # The test in window.cpp fails as we are a composite
  8579.         # window, so it checks against "this", but not self._mainWin.
  8580.         if wx.Window.FindFocus() != self:
  8581.             self._mainWin.SetFocusIgnoringChildren()
  8582.  
  8583.  
  8584.     def DoGetBestSize(self):
  8585.  
  8586.         # Something is better than nothing...
  8587.         # 100x80 is what the MSW version will get from the default
  8588.         # wx.Control.DoGetBestSize
  8589.         return wx.Size(100, 80)
  8590.  
  8591.  
  8592. # ----------------------------------------------------------------------------
  8593. # virtual list control support
  8594. # ----------------------------------------------------------------------------
  8595.  
  8596.     def OnGetItemText(self, item, col):
  8597.  
  8598.         # this is a pure virtual function, in fact - which is not really pure
  8599.         # because the controls which are not virtual don't need to implement it
  8600.         raise Exception("UltimateListCtrl.OnGetItemText not supposed to be called")
  8601.  
  8602.  
  8603.     def OnGetItemImage(self, item):
  8604.  
  8605.         if self.GetImageList(wx.IMAGE_LIST_SMALL):
  8606.             raise Exception("List control has an image list, OnGetItemImage should be overridden.")
  8607.  
  8608.         return []
  8609.  
  8610.  
  8611.     def OnGetItemColumnImage(self, item, column=0):
  8612.  
  8613.         if column == 0:
  8614.             return self.OnGetItemImage(item)
  8615.  
  8616.         return []
  8617.  
  8618.  
  8619.     def OnGetItemAttr(self, item):
  8620.  
  8621.         if item < 0 or item > self.GetItemCount():
  8622.             raise Exception("Invalid item index in OnGetItemAttr()")
  8623.  
  8624.         # no attributes by default
  8625.         return None
  8626.  
  8627.  
  8628.     def OnGetItemCheck(self, item):
  8629.  
  8630.         return []
  8631.  
  8632.  
  8633.     def OnGetItemColumnCheck(self, item, column=0):
  8634.  
  8635.         if column == 0:
  8636.             return self.OnGetItemCheck(item)
  8637.  
  8638.         return []        
  8639.  
  8640.  
  8641.     def OnGetItemKind(self, item):
  8642.  
  8643.         return 0
  8644.  
  8645.  
  8646.     def OnGetItemColumnKind(self, item, column=0):
  8647.  
  8648.         if column == 0:
  8649.             return self.OnGetItemKind(item)
  8650.  
  8651.         return 0
  8652.    
  8653.  
  8654.     def SetItemCount(self, count):
  8655.  
  8656.         if not self._mainWin.IsVirtual():
  8657.             raise Exception("This is for virtual controls only")
  8658.  
  8659.         self._mainWin.SetItemCount(count)
  8660.  
  8661.  
  8662.     def RefreshItem(self, item):
  8663.  
  8664.         self._mainWin.RefreshLine(item)
  8665.  
  8666.  
  8667.     def RefreshItems(self, itemFrom, itemTo):
  8668.  
  8669.         self._mainWin.RefreshLines(itemFrom, itemTo)
  8670.  
  8671.  
  8672. #
  8673. # Generic UltimateListCtrl is more or less a container for two other
  8674. # windows which drawings are done upon. These are namely
  8675. # 'self._headerWin' and 'self._mainWin'.
  8676. # Here we override 'virtual wxWindow::Refresh()' to mimic the
  8677. # behaviour UltimateListCtrl has under wxMSW.
  8678. #
  8679.  
  8680.     def Refresh(self, eraseBackground=True, rect=None):
  8681.  
  8682.         if not rect:
  8683.  
  8684.             # The easy case, no rectangle specified.
  8685.             if self._headerWin:
  8686.                 self._headerWin.Refresh(eraseBackground)
  8687.  
  8688.             if self._mainWin:
  8689.                 self._mainWin.Refresh(eraseBackground)
  8690.  
  8691.         else:
  8692.  
  8693.             # Refresh the header window
  8694.             if self._headerWin:
  8695.  
  8696.                 rectHeader = self._headerWin.GetRect()
  8697.                 rectHeader.Intersect(rect)
  8698.                 if rectHeader.GetWidth() and rectHeader.GetHeight():
  8699.                     x, y = self._headerWin.GetPosition()
  8700.                     rectHeader.OffsetXY(-x, -y)
  8701.                     self._headerWin.Refresh(eraseBackground, rectHeader)
  8702.  
  8703.             # Refresh the main window
  8704.             if self._mainWin:
  8705.  
  8706.                 rectMain = self._mainWin.GetRect()
  8707.                 rectMain.Intersect(rect)
  8708.                 if rectMain.GetWidth() and rectMain.GetHeight():
  8709.                     x, y = self._mainWin.GetPosition()
  8710.                     rectMain.OffsetXY(-x, -y)
  8711.                     self._mainWin.Refresh(eraseBackground, rectMain)
  8712.  
  8713.  
  8714.     def Update(self):
  8715.  
  8716.         self._mainWin.ResetVisibleLinesRange(True)
  8717.         wx.PyControl.Update(self)
  8718.  
  8719.  
  8720.     def GetEditControl(self):
  8721.  
  8722.         retval = None
  8723.  
  8724.         if self._mainWin:
  8725.             retval = self._mainWin.GetEditControl()
  8726.  
  8727.         return retval
  8728.  
  8729.  
  8730.     def Select(self, idx, on=1):
  8731.         '''[de]select an item'''
  8732.  
  8733.         item = CreateListItem(idx, 0)
  8734.         item = self._mainWin.GetItem(item, 0)
  8735.         if not item.IsEnabled():
  8736.             return
  8737.  
  8738.         if on:
  8739.             state = ULC_STATE_SELECTED
  8740.         else:
  8741.             state = 0
  8742.  
  8743.                    
  8744.         self.SetItemState(idx, state, ULC_STATE_SELECTED)
  8745.  
  8746.  
  8747.     def Focus(self, idx):
  8748.         '''Focus and show the given item'''
  8749.  
  8750.         self.SetItemState(idx, ULC_STATE_FOCUSED, ULC_STATE_FOCUSED)
  8751.         self.EnsureVisible(idx)
  8752.  
  8753.  
  8754.     def GetFocusedItem(self):
  8755.         '''get the currently focused item or -1 if none'''
  8756.         return self.GetNextItem(-1, ULC_NEXT_ALL, ULC_STATE_FOCUSED)
  8757.  
  8758.  
  8759.     def GetFirstSelected(self, *args):
  8760.         '''return first selected item, or -1 when none'''
  8761.         return self.GetNextSelected(-1)
  8762.  
  8763.  
  8764.     def GetNextSelected(self, item):
  8765.         '''return subsequent selected items, or -1 when no more'''
  8766.         return self.GetNextItem(item, ULC_NEXT_ALL, ULC_STATE_SELECTED)
  8767.  
  8768.  
  8769.     def IsSelected(self, idx):
  8770.         '''return True if the item is selected'''
  8771.         return (self.GetItemState(idx, ULC_STATE_SELECTED) & ULC_STATE_SELECTED) != 0
  8772.  
  8773.  
  8774.     def IsItemChecked(self, itemOrId, col=0):
  8775.  
  8776.         item = CreateListItem(itemOrId, col)
  8777.         return self._mainWin.IsItemChecked(item)
  8778.  
  8779.  
  8780.     def IsItemEnabled(self, itemOrId, col=0):
  8781.  
  8782.         item = CreateListItem(itemOrId, col)        
  8783.         return self._mainWin.IsItemEnabled(item)
  8784.  
  8785.  
  8786.     def GetItemKind(self, itemOrId, col=0):
  8787.         """
  8788.        Returns the item type:
  8789.        0: normal
  8790.        1: checkbox item
  8791.        2: radiobutton item
  8792.        """
  8793.        
  8794.         item = CreateListItem(itemOrId, col)
  8795.         return self._mainWin.GetItemKind(item)
  8796.  
  8797.  
  8798.     def SetItemKind(self, itemOrId, col=0, kind=0):
  8799.  
  8800.         item = CreateListItem(itemOrId, col)
  8801.         return self._mainWin.SetItemKind(item, kind)
  8802.    
  8803.  
  8804.     def EnableItem(self, itemOrId, col=0, enable=True):
  8805.  
  8806.         item = CreateListItem(itemOrId, col)
  8807.         return self._mainWin.EnableItem(item, enable)
  8808.        
  8809.  
  8810.     def IsItemHyperText(self, itemOrId, col=0):
  8811.         """Returns whether an item is hypertext or not."""
  8812.        
  8813.         item = CreateListItem(itemOrId, col)
  8814.         return self._mainWin.IsItemHyperText(item)
  8815.  
  8816.  
  8817.     def SetItemHyperText(self, itemOrId, col=0):
  8818.         """Returns whether an item is hypertext or not."""
  8819.        
  8820.         item = CreateListItem(itemOrId, col)
  8821.         return self._mainWin.SetItemHyperText(item)
  8822.  
  8823.  
  8824.     def SetColumnImage(self, col, image):
  8825.         item = self.GetColumn(col)
  8826.         # preserve all other attributes too
  8827.  
  8828.         item.SetMask(ULC_MASK_STATE      |
  8829.                      ULC_MASK_TEXT       |
  8830.                      ULC_MASK_IMAGE      |
  8831.                      ULC_MASK_DATA       |
  8832.                      ULC_SET_ITEM        |
  8833.                      ULC_MASK_WIDTH      |
  8834.                      ULC_MASK_FORMAT     |
  8835.                      ULC_MASK_FONTCOLOUR |
  8836.                      ULC_MASK_FONT       |
  8837.                      ULC_MASK_BACKCOLOUR |
  8838.                      ULC_MASK_KIND       |
  8839.                      ULC_MASK_CHECK      
  8840.                      )
  8841.         item.SetImage(image)
  8842.         self.SetColumn(col, item)
  8843.  
  8844.     def ClearColumnImage(self, col):
  8845.         self.SetColumnImage(col, -1)
  8846.  
  8847.     def Append(self, entry):
  8848.         '''Append an item to the list control.  The entry parameter should be a
  8849.           sequence with an item for each column'''
  8850.         if len(entry):
  8851.             if wx.USE_UNICODE:
  8852.                 cvtfunc = unicode
  8853.             else:
  8854.                 cvtfunc = str
  8855.             pos = self.GetItemCount()
  8856.             self.InsertStringItem(pos, cvtfunc(entry[0]))
  8857.             for i in range(1, len(entry)):
  8858.                 self.SetStringItem(pos, i, cvtfunc(entry[i]))
  8859.             return pos
  8860.  
  8861.  
  8862.     def SetFirstGradientColour(self, colour=None):
  8863.         """Sets the first gradient colour."""
  8864.        
  8865.         self._mainWin.SetFirstGradientColour(colour)
  8866.        
  8867.  
  8868.     def SetSecondGradientColour(self, colour=None):
  8869.         """Sets the second gradient colour."""
  8870.  
  8871.         self._mainWin.SetSecondGradientColour(colour)
  8872.  
  8873.  
  8874.     def GetFirstGradientColour(self):
  8875.         """Returns the first gradient colour."""
  8876.        
  8877.         return self._mainWin.GetFirstGradientColour()
  8878.  
  8879.  
  8880.     def GetSecondGradientColour(self):
  8881.         """Returns the second gradient colour."""
  8882.        
  8883.         return self._mainWin.GetSecondGradientColour()
  8884.  
  8885.  
  8886.     def EnableSelectionGradient(self, enable=True):
  8887.         """Globally enables/disables drawing of gradient selection."""
  8888.  
  8889.         self._mainWin.EnableSelectionGradient(enable)
  8890.        
  8891.  
  8892.     def SetGradientStyle(self, vertical=0):
  8893.         """
  8894.        Sets the gradient style:
  8895.        0: horizontal gradient
  8896.        1: vertical gradient
  8897.        """
  8898.  
  8899.         self._mainWin.SetGradientStyle(vertical)
  8900.  
  8901.  
  8902.     def GetGradientStyle(self):
  8903.         """
  8904.        Returns the gradient style:
  8905.        0: horizontal gradient
  8906.        1: vertical gradient
  8907.        """
  8908.  
  8909.         return self._mainWin.GetGradientStyle()
  8910.  
  8911.  
  8912.     def EnableSelectionVista(self, enable=True):
  8913.         """Globally enables/disables drawing of Windows Vista selection."""
  8914.  
  8915.         self._mainWin.EnableSelectionVista(enable)
  8916.  
  8917.  
  8918.     def SetBackgroundImage(self, image=None):
  8919.         """Sets the UltimateListCtrl background image (can be None)."""
  8920.  
  8921.         self._mainWin.SetBackgroundImage(image)
  8922.        
  8923.  
  8924.     def GetBackgroundImage(self):
  8925.         """Returns the UltimateListCtrl background image (can be None)."""
  8926.  
  8927.         return self._mainWin.GetBackgroundImage()
  8928.  
  8929.  
  8930.     def SetWaterMark(self, watermark=None):
  8931.         """Sets the UltimateListCtrl watermark image (can be None)."""
  8932.  
  8933.         self._mainWin.SetWaterMark(watermark)
  8934.        
  8935.  
  8936.     def GetWaterMark(self):
  8937.         """Returns the UltimateListCtrl watermark image (can be None)."""
  8938.  
  8939.         return self._mainWin.GetWaterMark()
  8940.  
  8941.  
  8942.     def SetDisabledTextColour(self, colour):
  8943.         """Sets the items disabled colour."""
  8944.  
  8945.         self._mainWin.SetDisabledTextColour(colour)
  8946.  
  8947.  
  8948.     def GetDisabledTextColour(self):
  8949.         """Returns the items disabled colour."""
  8950.  
  8951.         return self._mainWin.GetDisabledTextColour()
  8952.  
  8953.  
  8954.     def GetHyperTextFont(self):
  8955.         """Returns the font used to render an hypertext item."""
  8956.  
  8957.         return self._mainWin.GetHyperTextFont()
  8958.  
  8959.  
  8960.     def SetHyperTextFont(self, font):
  8961.         """Sets the font used to render an hypertext item."""
  8962.  
  8963.         self._mainWin.SetHyperTextFont(font)
  8964.        
  8965.  
  8966.     def SetHyperTextNewColour(self, colour):
  8967.         """Sets the colour used to render a non-visited hypertext item."""
  8968.  
  8969.         self._mainWin.SetHyperTextNewColour(colour)
  8970.        
  8971.  
  8972.     def GetHyperTextNewColour(self):
  8973.         """Returns the colour used to render a non-visited hypertext item."""
  8974.  
  8975.         return self._mainWin.GetHyperTextNewColour()
  8976.  
  8977.  
  8978.     def SetHyperTextVisitedColour(self, colour):
  8979.         """Sets the colour used to render a visited hypertext item."""
  8980.  
  8981.         self._mainWin.SetHyperTextVisitedColour(colour)
  8982.        
  8983.  
  8984.     def GetHyperTextVisitedColour(self):
  8985.         """Returns the colour used to render a visited hypertext item."""
  8986.  
  8987.         return self._mainWin.GetHyperTextVisitedColour()
  8988.  
  8989.  
  8990.     def SetItemVisited(self, itemOrId, col=0, visited=True):
  8991.         """Sets whether an hypertext item was visited."""
  8992.  
  8993.         item = CreateListItem(itemOrId, col)
  8994.         return self._mainWin.SetItemVisited(item, visited)
  8995.    
  8996.  
  8997.     def GetItemVisited(self, itemOrId, col=0):
  8998.         """Returns whether an hypertext item was visited."""
  8999.  
  9000.         item = CreateListItem(itemOrId, col)
  9001.         return self._mainWin.GetItemVisited(item)
  9002.  
  9003.  
  9004.     def GetItemWindow(self, itemOrId, col=0):
  9005.         """Returns the window associated to the item (if any)."""
  9006.  
  9007.         item = CreateListItem(itemOrId, col)
  9008.         return self._mainWin.GetItemWindow(item)
  9009.  
  9010.  
  9011.     def SetItemWindow(self, itemOrId, col=0, wnd=None, expand=False):
  9012.         """Sets the window for the given item"""
  9013.  
  9014.         item = CreateListItem(itemOrId, col)
  9015.         return self._mainWin.SetItemWindow(item, wnd, expand)
  9016.        
  9017.  
  9018.     def DeleteItemWindow(self, itemOrId, col=0):
  9019.         """Deletes the window associated to an item (if any). """
  9020.  
  9021.         item = CreateListItem(itemOrId, col)
  9022.         return self._mainWin.DeleteItemWindow(item)
  9023.        
  9024.  
  9025.     def GetItemWindowEnabled(self, itemOrId, col=0):
  9026.         """Returns whether the window associated to the item is enabled."""
  9027.  
  9028.         item = CreateListItem(itemOrId, col)
  9029.         return self._mainWin.GetItemWindowEnabled(item)
  9030.  
  9031.  
  9032.     def SetItemWindowEnabled(self, itemOrId, col=0, enable=True):
  9033.         """Enables/disables the window associated to the item."""
  9034.  
  9035.         item = CreateListItem(itemOrId, col)
  9036.         return self._mainWin.SetItemWindowEnabled(item, enable)
  9037.  
  9038.  
  9039.     def GetItemCustomRenderer(self, itemOrId, col=0):
  9040.  
  9041.         item = CreateListItem(itemOrId, col)
  9042.         return self._mainWin.GetItemCustomRenderer(item)
  9043.  
  9044.  
  9045.     def SetItemCustomRenderer(self, itemOrId, col=0, renderer=None):
  9046.  
  9047.         if not self.HasFlag(ULC_REPORT) or not self.HasExtraFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
  9048.             raise Exception("Custom renderers can be used on with style = ULC_REPORT and extraStyle = ULC_HAS_VARIABLE_ROW_HEIGHT")
  9049.        
  9050.         item = CreateListItem(itemOrId, col)
  9051.         return self._mainWin.SetItemCustomRenderer(item, renderer)
  9052.  
  9053.  
  9054.     def SetItemOverFlow(self, itemOrId, col=0, over=True):
  9055.  
  9056.         if not self.HasFlag(ULC_REPORT) or self._mainWin.IsVirtual():
  9057.             raise Exception("Overflowing items can be used only in report, non-virtual mode")
  9058.  
  9059.         item = CreateListItem(itemOrId, col)
  9060.         return self._mainWin.SetItemOverFlow(item, over)
  9061.                
  9062.  
  9063.     def GetItemOverFlow(self, itemOrId, col=0):
  9064.  
  9065.         item = CreateListItem(itemOrId, col)
  9066.         return self._mainWin.GetItemOverFlow(item)
  9067.  
  9068.  
  9069.     def HasExtraFlag(self, flag):
  9070.  
  9071.         return self._extraStyle & flag
  9072.  
  9073.  
  9074.     def IsVirtual(self):
  9075.  
  9076.         return self._mainWin.IsVirtual()
  9077.  
  9078.    
  9079.  
  9080.  
Add Comment
Please, Sign In to add comment