home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / gui / treelist.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  16.5 KB  |  567 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from __future__ import division
  6. KEEP_STATS = False
  7. app = None
  8. import wx
  9. from wx import WXK_LEFT, WXK_RIGHT, WXK_DOWN, WXK_UP, Rect
  10. from util import Delegate
  11. from logging import getLogger
  12. log = getLogger('treelist')
  13. info = log.info
  14. from gui.textutil import GetFontHeight, default_font
  15. from contextlib import contextmanager
  16.  
  17. expanded_id = lambda obj: u'_'.join([
  18. type(obj).__name__,
  19. obj.name])
  20.  
  21. idfunc = lambda obj: obj.__hash__()
  22.  
  23. def hasChildren(obj):
  24.     
  25.     try:
  26.         iter(obj)
  27.     except:
  28.         return False
  29.  
  30.     return True
  31.  
  32.  
  33. class ListMixin(object):
  34.     
  35.     def __init__(self, listAttrName):
  36.         self._listAttrName = listAttrName
  37.  
  38.     
  39.     def __len__(self):
  40.         return len(self.__dict__[self._listAttrName])
  41.  
  42.     
  43.     def __iter__(self):
  44.         return self.__dict__[self._listAttrName].__iter__()
  45.  
  46.     
  47.     def __getitem__(self, n):
  48.         return self.__dict__[self._listAttrName][n]
  49.  
  50.  
  51.  
  52. class TreeListModel(ListMixin):
  53.     
  54.     def __init__(self, root = None, collapsed = None):
  55.         if not root:
  56.             pass
  57.         self.root = []
  58.         self.collapsed = None if collapsed is not None else set()
  59.         self.flattened_list = []
  60.         self.listeners = []
  61.         self.depths = { }
  62.         self.filters = []
  63.         self.donotexpand = []
  64.         self._expandable_cache = { }
  65.         self.update_list()
  66.         self.expansion_state_changed = Delegate()
  67.         ListMixin.__init__(self, 'flattened_list')
  68.  
  69.     
  70.     def _expandable(self, eltype):
  71.         
  72.         try:
  73.             return self._expandable_cache[eltype]
  74.         except KeyError:
  75.             for i in self.donotexpand:
  76.                 if issubclass(eltype, i):
  77.                     return self._expandable_cache.setdefault(eltype, False)
  78.                     continue
  79.             
  80.             return self._expandable_cache.setdefault(eltype, True)
  81.  
  82.  
  83.     
  84.     def expandable(self, el):
  85.         return self._expandable(el.__class__)
  86.  
  87.     
  88.     def flatten(self, root, collapsed, depths, depth = 0, filters = [], expanded_id = expanded_id):
  89.         lst = [
  90.             root]
  91.         if hasChildren(root):
  92.             for el in root:
  93.                 depths[idfunc(el)] = (depth, root)
  94.                 if expanded_id(el) not in collapsed and self.expandable(el):
  95.                     lst.extend(self.flatten(el, collapsed, depths, depth + 1, filters, expanded_id = expanded_id))
  96.                     continue
  97.                 lst.append(el)
  98.             
  99.         
  100.         return lst
  101.  
  102.     
  103.     def __repr__(self):
  104.         return '<TreeListModel %r>' % self.flattened_list
  105.  
  106.     
  107.     def expand(self, obj):
  108.         i = expanded_id(obj)
  109.         self.collapsed.discard(i)
  110.         self.expansion_state_changed()
  111.         self.update_list()
  112.  
  113.     
  114.     def collapse(self, obj):
  115.         self.collapsed.add(expanded_id(obj))
  116.         self.expansion_state_changed()
  117.         self.update_list()
  118.  
  119.     
  120.     def toggle_expand(self, obj):
  121.         if obj.__class__ not in self.donotexpand:
  122.             if expanded_id(obj) not in self.collapsed:
  123.                 self.collapse(obj)
  124.             elif hasChildren(obj):
  125.                 self.expand(obj)
  126.             
  127.         
  128.  
  129.     
  130.     def is_expanded(self, n):
  131.         return expanded_id(self.flattened_list[n]) not in self.collapsed
  132.  
  133.     
  134.     def parent_of(self, child):
  135.         return self.depths[idfunc(child)][1]
  136.  
  137.     
  138.     def index_of(self, child):
  139.         
  140.         try:
  141.             return None if idfunc(child) in self.indices else -1
  142.         except:
  143.             return -1
  144.  
  145.  
  146.     
  147.     def set_root(self, root):
  148.         self.depths = { }
  149.         self.root = root
  150.         self.update_list()
  151.  
  152.     
  153.     def update_list(self):
  154.         self.flattened_list = self.flatten(self.root, self.collapsed, self.depths, filters = self.filters)[1:]
  155.         self.indices = dict((lambda .0: for c, item in .0:
  156. (idfunc(item), c))(enumerate(self.flattened_list)))
  157.         for l in self.listeners:
  158.             l.list_changed()
  159.         
  160.  
  161.     
  162.     def remove_child(self, child):
  163.         parent = self.depths[idfunc(child)][1]
  164.         parent.remove(child)
  165.         self.update_list()
  166.  
  167.  
  168. if KEEP_STATS:
  169.     from time import clock
  170.  
  171. from cgui import SkinVList as TreeListBase
  172.  
  173. class TreeList(TreeListBase):
  174.     if KEEP_STATS:
  175.         stats = { }
  176.     
  177.     
  178.     def __init__(self, parent, model, id = -1, style = wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE, enable_hover = True):
  179.         self.renderers = { }
  180.         self.renderers_cache = { }
  181.         self.context_menu_handlers = { }
  182.         TreeListBase.__init__(self, parent, id, style)
  183.         self.model = model
  184.         model.listeners.append(self)
  185.         measure = self.OnMeasureItem
  186.         []([ measure(n) for n in xrange(len(self.model)) ])
  187.         Bind = self.Bind
  188.         Bind(wx.EVT_LISTBOX_DCLICK, self.on_doubleclick)
  189.         Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
  190.         Bind(wx.EVT_KEY_DOWN, self.on_key_down)
  191.         self.hoveridx = -1
  192.         self.indent = 10
  193.  
  194.     
  195.     def on_leave_window(self, e):
  196.         self.Hover = -1
  197.         e.Skip(True)
  198.  
  199.     
  200.     def on_motion(self, e):
  201.         self.Hover = self.HitTest(e.Position)
  202.         e.Skip(True)
  203.  
  204.     
  205.     def toggle_expand(self, obj):
  206.         i = self.GetSelection()
  207.         model = self.model
  208.         selected = self.model[i]
  209.         do_select = False
  210.         if i != -1:
  211.             
  212.             try:
  213.                 parent = self.GetParent(model[i])
  214.             except KeyError:
  215.                 pass
  216.  
  217.             p = model.index_of(parent)
  218.             if parent is obj and model.is_expanded(p):
  219.                 self.SetSelection(p)
  220.             else:
  221.                 do_select = True
  222.         
  223.         self.model.toggle_expand(obj)
  224.         if do_select:
  225.             self.SetSelection(model.index_of(selected), keepVisible = False)
  226.         
  227.  
  228.     
  229.     def GetItemRect(self, item, include_children = True):
  230.         if not include_children:
  231.             return TreeListBase.GetItemRect(self, self.model.index_of(item))
  232.         
  233.         model = self.model
  234.         modellen = len(self.model)
  235.         measure = self.OnMeasureItem
  236.         i = model.index_of(item)
  237.         rect = Rect(0, self.GetItemY(i), self.ClientRect.width, measure(i))
  238.         if include_children:
  239.             i += 1
  240.             while i < modellen and self.GetParent(model[i]) is item:
  241.                 rect.height += measure(i)
  242.                 i += 1
  243.                 continue
  244.                 rect
  245.         
  246.         return rect
  247.  
  248.     
  249.     def get_hover(self):
  250.         return self.hoveridx
  251.  
  252.     
  253.     def set_hover(self, i):
  254.         old = self.hoveridx
  255.         self.hoveridx = i
  256.         if i != old:
  257.             if old != -1:
  258.                 self.RefreshLine(old)
  259.             
  260.             if i != -1:
  261.                 self.RefreshLine(i)
  262.             
  263.         
  264.  
  265.     Hover = property(get_hover, set_hover)
  266.     
  267.     def GetSelectedItem(self):
  268.         i = self.GetSelection()
  269.         if i != -1:
  270.             return self.model[i]
  271.         
  272.  
  273.     SelectedItem = property(GetSelectedItem)
  274.     
  275.     def __getitem__(self, i):
  276.         return self.model[i]
  277.  
  278.     
  279.     def GetParent(self, obj):
  280.         return self.model.parent_of(obj)
  281.  
  282.     
  283.     def save_selection(self):
  284.         i = self.GetSelection()
  285.         elem = None
  286.         model = self.model
  287.         if i != -1:
  288.             
  289.             try:
  290.                 elem = model[i]
  291.             except IndexError:
  292.                 elem = None
  293.             except:
  294.                 None<EXCEPTION MATCH>IndexError
  295.             
  296.  
  297.         None<EXCEPTION MATCH>IndexError
  298.         
  299.         try:
  300.             yield None
  301.         finally:
  302.             if elem is not None:
  303.                 TreeList.SetSelection(self, model.index_of(elem), False)
  304.             
  305.  
  306.  
  307.     save_selection = contextmanager(save_selection)
  308.     
  309.     def set_root(self, root):
  310.         self.save_selection().__enter__()
  311.         
  312.         try:
  313.             self.renderers_cache = { }
  314.             self.model.set_root(root)
  315.         finally:
  316.             pass
  317.  
  318.  
  319.     
  320.     def on_key_down(self, e):
  321.         i = self.GetSelection()
  322.         model = self.model
  323.         keycode = e.KeyCode
  324.         modifiers = e.Modifiers
  325.         
  326.         try:
  327.             obj = self.model[i]
  328.         except IndexError:
  329.             obj = None
  330.  
  331.         if keycode == WXK_LEFT:
  332.             if modifiers == wx.MOD_SHIFT:
  333.                 self.collapse_all()
  334.             elif obj is not None and modifiers == wx.MOD_NONE:
  335.                 if model.expandable(obj) and model.is_expanded(i):
  336.                     self.toggle_expand(obj)
  337.                 else:
  338.                     self.select_parent(obj)
  339.             
  340.         elif keycode == WXK_RIGHT:
  341.             if modifiers == wx.MOD_SHIFT:
  342.                 self.expand_all()
  343.             elif obj is not None and modifiers == wx.MOD_NONE:
  344.                 if model.expandable(obj):
  345.                     if not model.is_expanded(i):
  346.                         self.toggle_expand(obj)
  347.                     elif i + 1 < self.GetItemCount() and self.GetParent(model[i + 1]) is obj:
  348.                         self.SetSelection(self.GetSelection() + 1)
  349.                     
  350.                 
  351.             
  352.         elif keycode == WXK_UP:
  353.             sel = self.GetSelection() - 1
  354.             if sel >= 0:
  355.                 self.SetSelection(sel)
  356.             
  357.             return e.Skip(False)
  358.         elif keycode == WXK_DOWN:
  359.             sel = self.GetSelection() + 1
  360.             if sel < self.GetItemCount():
  361.                 self.SetSelection(sel)
  362.             
  363.             return e.Skip(False)
  364.         elif keycode == wx.WXK_PAGEUP:
  365.             self.PageUp()
  366.             self.SetSelection(self.GetFirstVisibleLine())
  367.         elif keycode == wx.WXK_PAGEDOWN:
  368.             self.PageDown()
  369.             self.SetSelection(self.GetFirstVisibleLine())
  370.         
  371.         e.Skip(True)
  372.  
  373.     
  374.     def select_parent(self, obj):
  375.         parent = self.GetParent(obj)
  376.         if parent is not None:
  377.             i = self.model.index_of(parent)
  378.             if i != -1:
  379.                 self.SetSelection(i)
  380.             
  381.         
  382.  
  383.     
  384.     def renderer_for(self, obj):
  385.         
  386.         try:
  387.             k = obj._renderer
  388.         except AttributeError:
  389.             
  390.             try:
  391.                 k = obj.__class__.__name__
  392.             except AttributeError:
  393.                 k = None
  394.             except:
  395.                 None<EXCEPTION MATCH>AttributeError
  396.             
  397.  
  398.             None<EXCEPTION MATCH>AttributeError
  399.  
  400.         return self.renderers.get(k, None)
  401.  
  402.     
  403.     def renderer_for_index(self, n):
  404.         
  405.         try:
  406.             renderer = self.renderers_cache[n]
  407.         except KeyError:
  408.             renderer = self.renderers_cache[n] = self.renderer_for(self.model[n])
  409.  
  410.         return renderer
  411.  
  412.     if KEEP_STATS:
  413.         
  414.         def print_stats(cls):
  415.             avgs = [ (float(total) / float(n), r) for n, total in cls.stats.iteritems() ]
  416.             print 'avg time   renderer'
  417.             print '--------------------------'
  418.             for avg, r in sorted(avgs, reverse = True):
  419.                 print '%.8f' % avg, r
  420.             
  421.  
  422.         print_stats = classmethod(print_stats)
  423.     else:
  424.         
  425.         def print_stats(cls):
  426.             print 'set treelist.KEEP_STATS = True to keep renderer timings'
  427.  
  428.         print_stats = classmethod(print_stats)
  429.     
  430.     hit_test_ex = lambda self, pt, h = TreeListBase.HitTestEx: h(self, *pt)
  431.     collapsedTri = [
  432.         (0, 0),
  433.         (7, 3),
  434.         (0, 7)]
  435.     expandedTri = [
  436.         (0, 0),
  437.         (7, 0),
  438.         (3, 3)]
  439.     
  440.     def hit_test_parent(self, mouse_pos):
  441.         model = self.model
  442.         (i, unused_percent) = self.hit_test_ex(mouse_pos)
  443.         if i == -1:
  444.             return (-1, None)
  445.         
  446.         parent = model.parent_of(model[i])
  447.         j = model.index_of(parent)
  448.         if j != -1:
  449.             rect = self.GetItemRect(parent)
  450.             i = j
  451.         else:
  452.             rect = self.GetItemRect(model[i])
  453.         percent = (mouse_pos.y - rect.y) / rect.height
  454.         return (i, percent)
  455.  
  456.     
  457.     def default_draw(self, dc, rect, n):
  458.         if self.IsSelected(n):
  459.             fg = wx.SYS_COLOUR_HIGHLIGHTTEXT
  460.         else:
  461.             fg = wx.SYS_COLOUR_WINDOWTEXT
  462.         dc.SetTextForeground(wx.SystemSettings_GetColour(fg))
  463.         font = default_font()
  464.         dc.SetFont(font)
  465.         if self.model.is_expanded(n):
  466.             tri = self.expandedTri
  467.         else:
  468.             tri = self.collapsedTri
  469.         dc.SetPen(wx.BLACK_PEN)
  470.         dc.SetBrush(wx.BLACK_BRUSH)
  471.         obj = self.model[n]
  472.         xoffset = self.indent * self.model.depths[idfunc(obj)][0]
  473.         yy = rect.y + rect.height / 2 - 3
  474.         if hasattr(obj, 'expandable'):
  475.             if obj.expandable():
  476.                 []([ (x + rect.x + xoffset, y + yy) for x, y in tri ])
  477.             
  478.         elif hasChildren(obj):
  479.             []([ (x + rect.x + xoffset, y + yy) for x, y in tri ])
  480.         
  481.         icon = getattr(obj, 'icon', None)
  482.         x = rect.x + 20 + xoffset
  483.         if icon:
  484.             dc.DrawBitmap(icon, rect.x + 20, rect.y + (rect.Height / 2 - icon.GetHeight() / 2))
  485.             x += icon.GetWidth() + 10
  486.         
  487.         dc.DrawText(unicode(obj), x, rect.y + (rect.Height / 2 - GetFontHeight(font, dc) / 2))
  488.  
  489.     
  490.     def OnMeasureItem(self, n):
  491.         renderer = self.renderer_for_index(n)
  492.         if renderer:
  493.             return renderer.item_height(self.model[n])
  494.         else:
  495.             return getattr(self.model[n], 'ItemHeight', 20)
  496.  
  497.     
  498.     def OnDrawBackground(self, dc, rect, n, selected = None):
  499.         obj = self.model[n]
  500.         selected = None if selected is None else selected
  501.         renderer = self.renderer_for_index(n)
  502.         
  503.         try:
  504.             drawbg = renderer.draw_background
  505.         except AttributeError:
  506.             
  507.             try:
  508.                 return obj.OnDrawBackground(dc, rect, n, selected)
  509.             except AttributeError:
  510.                 return TreeListBase.OnDrawBackground(self, dc, rect, n)
  511.             except:
  512.                 None<EXCEPTION MATCH>AttributeError
  513.             
  514.  
  515.             None<EXCEPTION MATCH>AttributeError
  516.  
  517.         drawbg(obj, dc, rect, n, selected, self.Hover == n)
  518.  
  519.     
  520.     def OnDrawItem(self, dc, rect, n):
  521.         model = self.model
  522.         obj = model[n]
  523.         selected = self.IsSelected(n)
  524.         
  525.         try:
  526.             depthVal = model.depths[idfunc(obj)][0]
  527.         except KeyError:
  528.             log.warning('KeyError in TreeList.OnDrawItem: %r', obj)
  529.             return 1
  530.  
  531.         draw_args = dict(dc = dc, rect = rect, depth = depthVal, obj = obj, index = n, expanded = model.is_expanded(n), selected = selected, hover = self.Hover == n)
  532.         renderer = self.renderer_for_index(n)
  533.         if renderer:
  534.             if KEEP_STATS:
  535.                 start = clock()
  536.                 renderer.Draw(**draw_args)
  537.                 diff = clock() - start
  538.                 (n, tot) = self.stats.get(k, (0, 0))
  539.                 self.stats[k] = (n + 1, tot + diff)
  540.             else:
  541.                 renderer.Draw(**draw_args)
  542.         else:
  543.             self.default_draw(dc, rect, n)
  544.  
  545.     
  546.     def list_changed(self):
  547.         measure = self.OnMeasureItem
  548.         []([ measure(n) for n in xrange(len(self.model)) ])
  549.  
  550.     
  551.     def on_doubleclick(self, e):
  552.         if e:
  553.             e.Skip(True)
  554.         
  555.         i = self.GetSelection()
  556.         if i != -1:
  557.             self.toggle_expand(self.model[i])
  558.         
  559.  
  560.     
  561.     def on_right_down(self, e):
  562.         i = self.HitTest((e.GetX(), e.GetY()))
  563.         self.SetSelection(i)
  564.         e.Skip(True)
  565.  
  566.  
  567.