home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1728 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  37.4 KB  |  1,124 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import ipipe
  5. import os
  6. import webbrowser
  7. import urllib
  8. from IPython import ipapi
  9. import wx
  10. import wx.grid as wx
  11. import wx.html as wx
  12.  
  13. try:
  14.     sorted
  15. except NameError:
  16.     from ipipe import sorted
  17.  
  18.  
  19. try:
  20.     set
  21. except:
  22.     from sets import Set as set
  23.  
  24. __all__ = [
  25.     'igrid']
  26. help = '\n<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />\n<link rel="stylesheet" href="igrid_help.css" type="text/css" />\n<title>igrid help</title>\n</head>\n<body>\n<h1>igrid help</h1>\n\n\n<h2>Commands</h2>\n\n\n<h3>pick (P)</h3>\n<p>Pick the whole row (object is available as "_")</p>\n\n<h3>pickattr (Shift-P)</h3>\n<p>Pick the attribute under the cursor</p>\n\n<h3>pickallattrs (Shift-C)</h3>\n<p>Pick the complete column under the cursor (i.e. the attribute under the\ncursor) from all currently fetched objects. These attributes will be returned\nas a list.</p>\n\n<h3>pickinput (I)</h3>\n<p>Pick the current row as next input line in IPython. Additionally the row is stored as "_"</p>\n\n<h3>pickinputattr (Shift-I)</h3>\n<p>Pick the attribute under the cursor as next input line in IPython. Additionally the row is stored as "_"</p>\n\n<h3>enter (E)</h3>\n<p>Enter the object under the cursor. (what this mean depends on the object\nitself, i.e. how it implements iteration). This opens a new browser \'level\'.</p>\n\n<h3>enterattr (Shift-E)</h3>\n<p>Enter the attribute under the cursor.</p>\n\n<h3>detail (D)</h3>\n<p>Show a detail view of the object under the cursor. This shows the name,\ntype, doc string and value of the object attributes (and it might show more\nattributes than in the list view, depending on the object).</p>\n\n<h3>detailattr (Shift-D)</h3>\n<p>Show a detail view of the attribute under the cursor.</p>\n\n<h3>pickrows (M)</h3>\n<p>Pick multiple selected rows (M)</p>\n\n<h3>pickrowsattr (CTRL-M)</h3>\n<p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>\n\n<h3>find (CTRL-F)</h3>\n<p>Find text</p>\n\n<h3>find_expression (CTRL-Shift-F)</h3>\n<p>Find entries matching an expression</p>\n\n<h3>find_next (F3)</h3>\n<p>Find next occurrence</p>\n\n<h3>find_previous (Shift-F3)</h3>\n<p>Find previous occurrence</p>\n\n<h3>sortattrasc (V)</h3>\n<p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>\n\n<h3>sortattrdesc (Shift-V)</h3>\n<p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>\n\n<h3>refresh_once (R, F5)</h3>\n<p>Refreshes the display by restarting the iterator</p>\n\n<h3>refresh_every_second</h3>\n<p>Refreshes the display by restarting the iterator every second until stopped by stop_refresh.</p>\n\n<h3>refresh_interval</h3>\n<p>Refreshes the display by restarting the iterator every X ms (X is a custom interval set by the user) until stopped by stop_refresh.</p>\n\n<h3>stop_refresh</h3>\n<p>Stops all refresh timers.</p>\n\n<h3>leave (Backspace, DEL, X)</h3>\n<p>Close current tab (and all the tabs to the right of the current one).</h3>\n\n<h3>quit (ESC,Q)</h3>\n<p>Quit igrid and return to the IPython prompt.</p>\n\n\n<h2>Navigation</h2>\n\n\n<h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>\n\n<h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>\n\n<h3>Move the cursor one column to the left (<)</h3>\n\n<h3>Move the cursor one column to the right (>)</h3>\n\n<h3>Jump to the first row in the current column (CTRL-Up)</h3>\n\n<h3>Jump to the last row in the current column (CTRL-Down)</h3>\n\n</body>\n</html>\n\n'
  27.  
  28. class IGridRenderer(wx.grid.PyGridCellRenderer):
  29.     
  30.     def __init__(self, table):
  31.         self.maxchars = 200
  32.         self.table = table
  33.         self.colormap = ((0, 0, 0), (174, 0, 0), (0, 174, 0), (174, 174, 0), (0, 0, 174), (174, 0, 174), (0, 174, 174), (64, 64, 64))
  34.         wx.grid.PyGridCellRenderer.__init__(self)
  35.  
  36.     
  37.     def _getvalue(self, row, col):
  38.         
  39.         try:
  40.             value = self.table._displayattrs[col].value(self.table.items[row])
  41.             (align, width, text) = ipipe.xformat(value, 'cell', self.maxchars)
  42.         except Exception:
  43.             exc = None
  44.             (align, width, text) = ipipe.xformat(exc, 'cell', self.maxchars)
  45.  
  46.         return (align, text)
  47.  
  48.     
  49.     def GetBestSize(self, grid, attr, dc, row, col):
  50.         text = grid.GetCellValue(row, col)
  51.         (align, text) = self._getvalue(row, col)
  52.         dc.SetFont(attr.GetFont())
  53.         (w, h) = dc.GetTextExtent(str(text))
  54.         return wx.Size(min(w + 2, 600), h + 2)
  55.  
  56.     
  57.     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
  58.         text = grid.GetCellValue(row, col)
  59.         (align, text) = self._getvalue(row, col)
  60.         if isSelected:
  61.             bg = grid.GetSelectionBackground()
  62.         else:
  63.             bg = [
  64.                 'white',
  65.                 (240, 240, 240)][row % 2]
  66.         dc.SetTextBackground(bg)
  67.         dc.SetBrush(wx.Brush(bg, wx.SOLID))
  68.         dc.SetPen(wx.TRANSPARENT_PEN)
  69.         dc.SetFont(attr.GetFont())
  70.         dc.DrawRectangleRect(rect)
  71.         dc.SetClippingRect(rect)
  72.         if align == -1:
  73.             (width, height) = dc.GetTextExtent(str(text))
  74.             x = rect[0] + 1
  75.             y = rect[1] + 0.5 * (rect[3] - height)
  76.             for style, part in text:
  77.                 if isSelected:
  78.                     fg = grid.GetSelectionForeground()
  79.                 else:
  80.                     fg = self.colormap[style.fg]
  81.                 dc.SetTextForeground(fg)
  82.                 (w, h) = dc.GetTextExtent(part)
  83.                 dc.DrawText(part, x, y)
  84.                 x += w
  85.             
  86.         elif align == 0:
  87.             (width, height) = dc.GetTextExtent(str(text))
  88.             x = rect[0] + 0.5 * (rect[2] - width)
  89.             y = rect[1] + 0.5 * (rect[3] - height)
  90.             for style, part in text:
  91.                 if isSelected:
  92.                     fg = grid.GetSelectionForeground()
  93.                 else:
  94.                     fg = self.colormap[style.fg]
  95.                 dc.SetTextForeground(fg)
  96.                 (w, h) = dc.GetTextExtent(part)
  97.                 dc.DrawText(part, x, y)
  98.                 x += w
  99.             
  100.         else:
  101.             (width, height) = dc.GetTextExtent(str(text))
  102.             x = rect[0] + rect[2] - 1
  103.             y = rect[1] + 0.5 * (rect[3] - height)
  104.             for style, part in reversed(text):
  105.                 (w, h) = dc.GetTextExtent(part)
  106.                 x -= w
  107.                 if isSelected:
  108.                     fg = grid.GetSelectionForeground()
  109.                 else:
  110.                     fg = self.colormap[style.fg]
  111.                 dc.SetTextForeground(fg)
  112.                 dc.DrawText(part, x, y)
  113.             
  114.         dc.DestroyClippingRegion()
  115.  
  116.     
  117.     def Clone(self):
  118.         return IGridRenderer(self.table)
  119.  
  120.  
  121.  
  122. class IGridTable(wx.grid.PyGridTableBase):
  123.     
  124.     def __init__(self, input, fontsize, *attrs):
  125.         wx.grid.PyGridTableBase.__init__(self)
  126.         self.input = input
  127.         self.iterator = ipipe.xiter(input)
  128.         self.items = []
  129.         self.attrs = [ ipipe.upgradexattr(attr) for attr in attrs ]
  130.         self._displayattrs = self.attrs[:]
  131.         self._displayattrset = set(self.attrs)
  132.         self.fontsize = fontsize
  133.         self._fetch(1)
  134.         self.timer = wx.Timer()
  135.         self.timer.Bind(wx.EVT_TIMER, self.refresh_content)
  136.  
  137.     
  138.     def GetAttr(self, *args):
  139.         attr = wx.grid.GridCellAttr()
  140.         attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
  141.         return attr
  142.  
  143.     
  144.     def GetNumberRows(self):
  145.         return len(self.items)
  146.  
  147.     
  148.     def GetNumberCols(self):
  149.         return len(self._displayattrs)
  150.  
  151.     
  152.     def GetColLabelValue(self, col):
  153.         if col < len(self._displayattrs):
  154.             return self._displayattrs[col].name()
  155.         return ''
  156.  
  157.     
  158.     def GetRowLabelValue(self, row):
  159.         return str(row)
  160.  
  161.     
  162.     def IsEmptyCell(self, row, col):
  163.         return False
  164.  
  165.     
  166.     def _append(self, item):
  167.         self.items.append(item)
  168.         if not self.attrs:
  169.             for attr in ipipe.xattrs(item):
  170.                 attr = ipipe.upgradexattr(attr)
  171.                 if attr not in self._displayattrset:
  172.                     self._displayattrs.append(attr)
  173.                     self._displayattrset.add(attr)
  174.                     continue
  175.             
  176.         
  177.  
  178.     
  179.     def _fetch(self, count):
  180.         have = len(self.items)
  181.         while self.iterator is not None and have < count:
  182.             
  183.             try:
  184.                 item = self.iterator.next()
  185.             except StopIteration:
  186.                 self.iterator = None
  187.                 break
  188.                 continue
  189.                 except (KeyboardInterrupt, SystemExit):
  190.                     raise 
  191.                     continue
  192.                     except Exception:
  193.                         exc = None
  194.                         have += 1
  195.                         self._append(exc)
  196.                         self.iterator = None
  197.                         break
  198.                         continue
  199.                     else:
  200.                         have += 1
  201.                         self._append(item)
  202.                     None<EXCEPTION MATCH>Exception
  203.                 return None
  204.  
  205.  
  206.     
  207.     def GetValue(self, row, col):
  208.         sizing_needed = False
  209.         had_cols = len(self._displayattrs)
  210.         had_rows = len(self.items)
  211.         if row == had_rows - 1 and self.iterator is not None:
  212.             self._fetch(row + 20)
  213.             sizing_needed = True
  214.         
  215.         have_rows = len(self.items)
  216.         have_cols = len(self._displayattrs)
  217.         if have_rows > had_rows:
  218.             msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
  219.             self.GetView().ProcessTableMessage(msg)
  220.             sizing_needed = True
  221.         
  222.         if row >= have_rows:
  223.             return ''
  224.         if have_cols != had_cols:
  225.             msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - had_cols)
  226.             self.GetView().ProcessTableMessage(msg)
  227.             sizing_needed = True
  228.         
  229.         if sizing_needed:
  230.             self.GetView().AutoSizeColumns(False)
  231.         
  232.         return ''
  233.  
  234.     
  235.     def SetValue(self, row, col, value):
  236.         pass
  237.  
  238.     
  239.     def refresh_content(self, event):
  240.         msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
  241.         self.GetView().ProcessTableMessage(msg)
  242.         self.iterator = ipipe.xiter(self.input)
  243.         self.items = []
  244.         self.attrs = []
  245.         self._fetch(1)
  246.         if self.items:
  247.             msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
  248.             self.GetView().ProcessTableMessage(msg)
  249.             self.GetValue(0, 0)
  250.             item = self.items[0]
  251.             self.GetView().AutoSizeColumns(False)
  252.             panel = self.GetView().GetParent()
  253.             nb = panel.GetParent()
  254.             current = nb.GetSelection()
  255.             if nb.GetPage(current) == panel:
  256.                 self.GetView().set_footer(item)
  257.             
  258.         
  259.  
  260.  
  261.  
  262. class IGridGrid(wx.grid.Grid):
  263.     
  264.     def __init__(self, panel, input, *attrs):
  265.         wx.grid.Grid.__init__(self, panel)
  266.         fontsize = 9
  267.         self.input = input
  268.         self.table = IGridTable(self.input, fontsize, *attrs)
  269.         self.SetTable(self.table, True)
  270.         self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
  271.         self.SetDefaultRenderer(IGridRenderer(self.table))
  272.         self.EnableEditing(False)
  273.         self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
  274.         self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
  275.         self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.cell_leftclicked)
  276.         self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
  277.         self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
  278.         self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
  279.         self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
  280.         self.current_selection = set()
  281.         self.maxchars = 200
  282.  
  283.     
  284.     def on_label_leftclick(self, event):
  285.         event.Skip()
  286.  
  287.     
  288.     def error_output(self, text):
  289.         wx.Bell()
  290.         frame = self.GetParent().GetParent().GetParent()
  291.         frame.SetStatusText(str(text))
  292.  
  293.     
  294.     def _on_selected_range(self, event):
  295.         if event.Selecting():
  296.             self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow() + 1))
  297.         else:
  298.             for index in xrange(event.GetTopRow(), event.GetBottomRow() + 1):
  299.                 self.current_selection.discard(index)
  300.             
  301.         event.Skip()
  302.  
  303.     
  304.     def _on_selected_cell(self, event):
  305.         self.current_selection = set([
  306.             event.GetRow()])
  307.         event.Skip()
  308.  
  309.     
  310.     def sort(self, key, reverse = False):
  311.         row = self.GetGridCursorRow()
  312.         col = self.GetGridCursorCol()
  313.         curitem = self.table.items[row]
  314.         
  315.         def realkey(item):
  316.             
  317.             try:
  318.                 return key(item)
  319.             except (KeyboardInterrupt, SystemExit):
  320.                 raise 
  321.             except Exception:
  322.                 return None
  323.  
  324.  
  325.         
  326.         try:
  327.             self.table.items = ipipe.deque(sorted(self.table.items, key = realkey, reverse = reverse))
  328.         except TypeError:
  329.             (None,)
  330.             exc = (None,)
  331.             self.error_output('Exception encountered: %s' % exc)
  332.             return None
  333.  
  334.         for i, item in enumerate(self.table.items):
  335.             if item is curitem:
  336.                 self.SetGridCursor(i, col)
  337.                 self.MakeCellVisible(i, col)
  338.                 self.Refresh()
  339.                 continue
  340.             (None,)
  341.         
  342.  
  343.     
  344.     def sortattrasc(self):
  345.         col = self.GetGridCursorCol()
  346.         attr = self.table._displayattrs[col]
  347.         frame = self.GetParent().GetParent().GetParent()
  348.         if attr is ipipe.noitem:
  349.             self.error_output('no column under cursor')
  350.             return None
  351.         frame.SetStatusText('sort by %s (ascending)' % attr.name())
  352.         
  353.         def key(item):
  354.             
  355.             try:
  356.                 return attr.value(item)
  357.             except (KeyboardInterrupt, SystemExit):
  358.                 raise 
  359.             except Exception:
  360.                 return None
  361.  
  362.  
  363.         self.sort(key)
  364.  
  365.     
  366.     def sortattrdesc(self):
  367.         col = self.GetGridCursorCol()
  368.         attr = self.table._displayattrs[col]
  369.         frame = self.GetParent().GetParent().GetParent()
  370.         if attr is ipipe.noitem:
  371.             self.error_output('no column under cursor')
  372.             return None
  373.         frame.SetStatusText('sort by %s (descending)' % attr.name())
  374.         
  375.         def key(item):
  376.             
  377.             try:
  378.                 return attr.value(item)
  379.             except (KeyboardInterrupt, SystemExit):
  380.                 raise 
  381.             except Exception:
  382.                 return None
  383.  
  384.  
  385.         self.sort(key, reverse = True)
  386.  
  387.     
  388.     def label_doubleclicked(self, event):
  389.         row = event.GetRow()
  390.         col = event.GetCol()
  391.         if col == -1:
  392.             self.enter(row)
  393.         
  394.  
  395.     
  396.     def _getvalue(self, row, col):
  397.         
  398.         try:
  399.             value = self.table._displayattrs[col].value(self.table.items[row])
  400.             (align, width, text) = ipipe.xformat(value, 'cell', self.maxchars)
  401.         except IndexError:
  402.             raise IndexError
  403.         except Exception:
  404.             exc = None
  405.             (align, width, text) = ipipe.xformat(exc, 'cell', self.maxchars)
  406.  
  407.         return text
  408.  
  409.     
  410.     def searchexpression(self, searchexp, startrow = None, search_forward = True):
  411.         frame = self.GetParent().GetParent().GetParent()
  412.         if searchexp:
  413.             if search_forward:
  414.                 if not startrow:
  415.                     row = self.GetGridCursorRow() + 1
  416.                 else:
  417.                     row = startrow + 1
  418.                 while True:
  419.                     
  420.                     try:
  421.                         foo = self.table.GetValue(row, 0)
  422.                         item = self.table.items[row]
  423.                         
  424.                         try:
  425.                             globals = ipipe.getglobals(None)
  426.                             if eval(searchexp, globals, ipipe.AttrNamespace(item)):
  427.                                 self.SetGridCursor(row, 0)
  428.                                 self.MakeCellVisible(row, 0)
  429.                                 break
  430.                         except (KeyboardInterrupt, SystemExit):
  431.                             raise 
  432.                         except Exception:
  433.                             exc = None
  434.                             frame.SetStatusText(str(exc))
  435.                             wx.Bell()
  436.                             break
  437.  
  438.                     except IndexError:
  439.                         return None
  440.  
  441.                     row += 1
  442.             elif not startrow:
  443.                 row = self.GetGridCursorRow() - 1
  444.             else:
  445.                 row = startrow - 1
  446.             while True:
  447.                 
  448.                 try:
  449.                     foo = self.table.GetValue(row, 0)
  450.                     item = self.table.items[row]
  451.                     
  452.                     try:
  453.                         globals = ipipe.getglobals(None)
  454.                         if eval(searchexp, globals, ipipe.AttrNamespace(item)):
  455.                             self.SetGridCursor(row, 0)
  456.                             self.MakeCellVisible(row, 0)
  457.                             break
  458.                     except (KeyboardInterrupt, SystemExit):
  459.                         raise 
  460.                     except Exception:
  461.                         exc = None
  462.                         frame.SetStatusText(str(exc))
  463.                         wx.Bell()
  464.                         break
  465.  
  466.                 except IndexError:
  467.                     return None
  468.  
  469.                 row -= 1
  470.         
  471.  
  472.     
  473.     def search(self, searchtext, startrow = None, startcol = None, search_forward = True):
  474.         searchtext = searchtext.lower()
  475.         if search_forward:
  476.             if startrow is not None and startcol is not None:
  477.                 row = startrow
  478.             else:
  479.                 startcol = self.GetGridCursorCol() + 1
  480.                 row = self.GetGridCursorRow()
  481.                 if startcol >= self.GetNumberCols():
  482.                     startcol = 0
  483.                     row += 1
  484.                 
  485.             while True:
  486.                 for col in xrange(startcol, self.table.GetNumberCols()):
  487.                     
  488.                     try:
  489.                         foo = self.table.GetValue(row, col)
  490.                         text = self._getvalue(row, col)
  491.                         if searchtext in text.string().lower():
  492.                             self.SetGridCursor(row, col)
  493.                             self.MakeCellVisible(row, col)
  494.                             return None
  495.                     continue
  496.                     except IndexError:
  497.                         return None
  498.                     
  499.  
  500.                 
  501.                 startcol = 0
  502.                 row += 1
  503.                 continue
  504.                 None<EXCEPTION MATCH>IndexError
  505.         elif startrow is not None and startcol is not None:
  506.             row = startrow
  507.         else:
  508.             startcol = self.GetGridCursorCol() - 1
  509.             row = self.GetGridCursorRow()
  510.             if startcol < 0:
  511.                 startcol = self.GetNumberCols() - 1
  512.                 row -= 1
  513.             
  514.         while True:
  515.             for col in xrange(startcol, -1, -1):
  516.                 
  517.                 try:
  518.                     foo = self.table.GetValue(row, col)
  519.                     text = self._getvalue(row, col)
  520.                     if searchtext in text.string().lower():
  521.                         self.SetGridCursor(row, col)
  522.                         self.MakeCellVisible(row, col)
  523.                         return None
  524.                 continue
  525.                 except IndexError:
  526.                     return None
  527.                 
  528.  
  529.             
  530.             startcol = self.table.GetNumberCols() - 1
  531.             row -= 1
  532.             continue
  533.             None<EXCEPTION MATCH>IndexError
  534.  
  535.     
  536.     def key_pressed(self, event):
  537.         frame = self.GetParent().GetParent().GetParent()
  538.         frame.SetStatusText('')
  539.         sh = event.ShiftDown()
  540.         ctrl = event.ControlDown()
  541.         keycode = event.GetKeyCode()
  542.         if keycode == ord('P'):
  543.             row = self.GetGridCursorRow()
  544.             if sh:
  545.                 col = self.GetGridCursorCol()
  546.                 self.pickattr(row, col)
  547.             else:
  548.                 self.pick(row)
  549.         elif keycode == ord('M'):
  550.             if ctrl:
  551.                 col = self.GetGridCursorCol()
  552.                 self.pickrowsattr(sorted(self.current_selection), col)
  553.             else:
  554.                 self.pickrows(sorted(self.current_selection))
  555.         elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord('X')):
  556.             if not ctrl:
  557.                 pass
  558.             if not sh:
  559.                 self.delete_current_notebook()
  560.             elif keycode in (ord('E'), ord('\r')):
  561.                 row = self.GetGridCursorRow()
  562.                 if sh:
  563.                     col = self.GetGridCursorCol()
  564.                     self.enterattr(row, col)
  565.                 else:
  566.                     self.enter(row)
  567.             elif keycode == ord('E') and ctrl:
  568.                 row = self.GetGridCursorRow()
  569.                 self.SetGridCursor(row, self.GetNumberCols() - 1)
  570.             elif (keycode == wx.WXK_HOME or keycode == ord('A')) and ctrl:
  571.                 row = self.GetGridCursorRow()
  572.                 self.SetGridCursor(row, 0)
  573.             elif keycode == ord('C') and sh:
  574.                 col = self.GetGridCursorCol()
  575.                 attr = self.table._displayattrs[col]
  576.                 result = []
  577.                 for i in xrange(self.GetNumberRows()):
  578.                     result.append(self.table._displayattrs[col].value(self.table.items[i]))
  579.                 
  580.                 self.quit(result)
  581.             elif keycode in (wx.WXK_ESCAPE, ord('Q')):
  582.                 if not ctrl:
  583.                     pass
  584.                 if not sh:
  585.                     self.quit()
  586.                 elif keycode == ord('<'):
  587.                     row = self.GetGridCursorRow()
  588.                     col = self.GetGridCursorCol()
  589.                     if not event.ShiftDown():
  590.                         newcol = col - 1
  591.                         if newcol >= 0:
  592.                             self.SetGridCursor(row, col - 1)
  593.                         
  594.                     else:
  595.                         newcol = col + 1
  596.                         if newcol < self.GetNumberCols():
  597.                             self.SetGridCursor(row, col + 1)
  598.                         
  599.                 elif keycode == ord('D'):
  600.                     col = self.GetGridCursorCol()
  601.                     row = self.GetGridCursorRow()
  602.                     if not sh:
  603.                         self.detail(row, col)
  604.                     else:
  605.                         self.detail_attr(row, col)
  606.                 elif keycode == ord('F') and ctrl:
  607.                     if sh:
  608.                         frame.enter_searchexpression(event)
  609.                     else:
  610.                         frame.enter_searchtext(event)
  611.                 elif keycode == wx.WXK_F3:
  612.                     if sh:
  613.                         frame.find_previous(event)
  614.                     else:
  615.                         frame.find_next(event)
  616.                 elif keycode == ord('V'):
  617.                     if sh:
  618.                         self.sortattrdesc()
  619.                     else:
  620.                         self.sortattrasc()
  621.                 elif keycode == wx.WXK_DOWN:
  622.                     row = self.GetGridCursorRow()
  623.                     
  624.                     try:
  625.                         item = self.table.items[row + 1]
  626.                     except IndexError:
  627.                         item = self.table.items[row]
  628.  
  629.                     self.set_footer(item)
  630.                     event.Skip()
  631.                 elif keycode == wx.WXK_UP:
  632.                     row = self.GetGridCursorRow()
  633.                     if row >= 1:
  634.                         item = self.table.items[row - 1]
  635.                     else:
  636.                         item = self.table.items[row]
  637.                     self.set_footer(item)
  638.                     event.Skip()
  639.                 elif keycode == wx.WXK_RIGHT:
  640.                     row = self.GetGridCursorRow()
  641.                     item = self.table.items[row]
  642.                     self.set_footer(item)
  643.                     event.Skip()
  644.                 elif keycode == wx.WXK_LEFT:
  645.                     row = self.GetGridCursorRow()
  646.                     item = self.table.items[row]
  647.                     self.set_footer(item)
  648.                     event.Skip()
  649.                 elif keycode == ord('R') or keycode == wx.WXK_F5:
  650.                     self.table.refresh_content(event)
  651.                 elif keycode == ord('I'):
  652.                     row = self.GetGridCursorRow()
  653.                     if not sh:
  654.                         self.pickinput(row)
  655.                     else:
  656.                         col = self.GetGridCursorCol()
  657.                         self.pickinputattr(row, col)
  658.                 else:
  659.                     event.Skip()
  660.  
  661.     
  662.     def delete_current_notebook(self):
  663.         panel = self.GetParent()
  664.         nb = panel.GetParent()
  665.         current = nb.GetSelection()
  666.         count = nb.GetPageCount()
  667.         if count > 1:
  668.             for i in xrange(count - 1, current - 1, -1):
  669.                 nb.DeletePage(i)
  670.             
  671.             nb.GetCurrentPage().grid.SetFocus()
  672.         else:
  673.             frame = nb.GetParent()
  674.             frame.SetStatusText('This is the last level!')
  675.  
  676.     
  677.     def _doenter(self, value, *attrs):
  678.         panel = self.GetParent()
  679.         nb = panel.GetParent()
  680.         frame = nb.GetParent()
  681.         current = nb.GetSelection()
  682.         count = nb.GetPageCount()
  683.         
  684.         try:
  685.             if current + 1 == count and value is not self.input:
  686.                 frame._add_notebook(value, *attrs)
  687.             elif value != self.input:
  688.                 for i in xrange(count - 1, current, -1):
  689.                     nb.DeletePage(i)
  690.                 
  691.                 frame._add_notebook(value)
  692.         except TypeError:
  693.             exc = None
  694.             if exc.__class__.__module__ == 'exceptions':
  695.                 msg = '%s: %s' % (exc.__class__.__name__, exc)
  696.             else:
  697.                 msg = '%s.%s: %s' % (exc.__class__.__module__, exc.__class__.__name__, exc)
  698.             frame.SetStatusText(msg)
  699.  
  700.  
  701.     
  702.     def enterattr(self, row, col):
  703.         
  704.         try:
  705.             attr = self.table._displayattrs[col]
  706.             value = attr.value(self.table.items[row])
  707.         except Exception:
  708.             exc = None
  709.             self.error_output(str(exc))
  710.  
  711.         self._doenter(value)
  712.  
  713.     
  714.     def set_footer(self, item):
  715.         frame = self.GetParent().GetParent().GetParent()
  716.         []([]([ str(text) for style, text in ipipe.xformat(item, 'footer', 20)[2] ]), 0)
  717.  
  718.     
  719.     def enter(self, row):
  720.         
  721.         try:
  722.             value = self.table.items[row]
  723.         except Exception:
  724.             exc = None
  725.             self.error_output(str(exc))
  726.  
  727.         self._doenter(value)
  728.  
  729.     
  730.     def detail(self, row, col):
  731.         
  732.         try:
  733.             attr = self.table._displayattrs[col]
  734.             item = self.table.items[row]
  735.         except Exception:
  736.             exc = None
  737.             self.error_output(str(exc))
  738.  
  739.         attrs = [ ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, 'detail') ]
  740.         self._doenter(attrs)
  741.  
  742.     
  743.     def detail_attr(self, row, col):
  744.         
  745.         try:
  746.             attr = self.table._displayattrs[col]
  747.             item = attr.value(self.table.items[row])
  748.         except Exception:
  749.             exc = None
  750.             self.error_output(str(exc))
  751.  
  752.         attrs = [ ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, 'detail') ]
  753.         self._doenter(attrs)
  754.  
  755.     
  756.     def quit(self, result = None):
  757.         frame = self.GetParent().GetParent().GetParent()
  758.         if frame.helpdialog:
  759.             frame.helpdialog.Destroy()
  760.         
  761.         app = frame.parent
  762.         if app is not None:
  763.             app.result = result
  764.         
  765.         frame.Close()
  766.         frame.Destroy()
  767.  
  768.     
  769.     def cell_doubleclicked(self, event):
  770.         self.enterattr(event.GetRow(), event.GetCol())
  771.         event.Skip()
  772.  
  773.     
  774.     def cell_leftclicked(self, event):
  775.         row = event.GetRow()
  776.         item = self.table.items[row]
  777.         self.set_footer(item)
  778.         event.Skip()
  779.  
  780.     
  781.     def pick(self, row):
  782.         
  783.         try:
  784.             value = self.table.items[row]
  785.         except Exception:
  786.             exc = None
  787.             self.error_output(str(exc))
  788.  
  789.         self.quit(value)
  790.  
  791.     
  792.     def pickinput(self, row):
  793.         
  794.         try:
  795.             value = self.table.items[row]
  796.         except Exception:
  797.             exc = None
  798.             self.error_output(str(exc))
  799.  
  800.         api = ipapi.get()
  801.         api.set_next_input(str(value))
  802.         self.quit(value)
  803.  
  804.     
  805.     def pickinputattr(self, row, col):
  806.         
  807.         try:
  808.             attr = self.table._displayattrs[col]
  809.             value = attr.value(self.table.items[row])
  810.         except Exception:
  811.             exc = None
  812.             self.error_output(str(exc))
  813.  
  814.         api = ipapi.get()
  815.         api.set_next_input(str(value))
  816.         self.quit(value)
  817.  
  818.     
  819.     def pickrows(self, rows):
  820.         
  821.         try:
  822.             value = [ self.table.items[row] for row in rows ]
  823.         except Exception:
  824.             exc = None
  825.             self.error_output(str(exc))
  826.  
  827.         self.quit(value)
  828.  
  829.     
  830.     def pickrowsattr(self, rows, col):
  831.         values = []
  832.         
  833.         try:
  834.             attr = self.table._displayattrs[col]
  835.             for row in rows:
  836.                 
  837.                 try:
  838.                     values.append(attr.value(self.table.items[row]))
  839.                 continue
  840.                 except (SystemExit, KeyboardInterrupt):
  841.                     raise 
  842.                     continue
  843.                     except Exception:
  844.                         raise 
  845.                         continue
  846.                     
  847.                 except Exception:
  848.                     None<EXCEPTION MATCH>(SystemExit, KeyboardInterrupt)
  849.                     exc = None<EXCEPTION MATCH>(SystemExit, KeyboardInterrupt)
  850.                     self.error_output(str(exc))
  851.                 except:
  852.                     None<EXCEPTION MATCH>(SystemExit, KeyboardInterrupt)
  853.  
  854.                 self.quit(values)
  855.                 return None
  856.  
  857.  
  858.     
  859.     def pickattr(self, row, col):
  860.         
  861.         try:
  862.             attr = self.table._displayattrs[col]
  863.             value = attr.value(self.table.items[row])
  864.         except Exception:
  865.             exc = None
  866.             self.error_output(str(exc))
  867.  
  868.         self.quit(value)
  869.  
  870.  
  871.  
  872. class IGridPanel(wx.Panel):
  873.     
  874.     def __init__(self, parent, input, *attrs):
  875.         wx.Panel.__init__(self, parent, -1)
  876.         self.grid = IGridGrid(self, input, *attrs)
  877.         self.grid.FitInside()
  878.         sizer = wx.BoxSizer(wx.VERTICAL)
  879.         sizer.Add(self.grid, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 10)
  880.         self.SetSizer(sizer)
  881.         sizer.Fit(self)
  882.         sizer.SetSizeHints(self)
  883.  
  884.  
  885.  
  886. class IGridHTMLHelp(wx.Frame):
  887.     
  888.     def __init__(self, parent, title, size):
  889.         wx.Frame.__init__(self, parent, -1, title, size = size)
  890.         html = wx.html.HtmlWindow(self)
  891.         if 'gtk2' in wx.PlatformInfo:
  892.             html.SetStandardFonts()
  893.         
  894.         html.SetPage(help)
  895.  
  896.  
  897.  
  898. class IGridFrame(wx.Frame):
  899.     maxtitlelen = 30
  900.     
  901.     def __init__(self, parent, input):
  902.         title = []([ str(text) for style, text in ipipe.xformat(input, 'header', 20)[2] ])
  903.         wx.Frame.__init__(self, None, title = title, size = (640, 480))
  904.         self.menubar = wx.MenuBar()
  905.         self.menucounter = 100
  906.         self.m_help = wx.Menu()
  907.         self.m_search = wx.Menu()
  908.         self.m_sort = wx.Menu()
  909.         self.m_refresh = wx.Menu()
  910.         self.notebook = wx.Notebook(self, -1, style = 0)
  911.         self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
  912.         self.statusbar.SetFieldsCount(2)
  913.         self.SetStatusWidths([
  914.             -1,
  915.             200])
  916.         self.parent = parent
  917.         self._add_notebook(input)
  918.         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  919.         self.makemenu(self.m_sort, '&Sort (asc)\tV', 'Sort ascending', self.sortasc)
  920.         self.makemenu(self.m_sort, 'Sort (&desc)\tShift-V', 'Sort descending', self.sortdesc)
  921.         self.makemenu(self.m_help, '&Help\tF1', 'Help', self.display_help)
  922.         self.makemenu(self.m_search, '&Find text\tCTRL-F', 'Find text', self.enter_searchtext)
  923.         self.makemenu(self.m_search, 'Find by &expression\tCTRL-Shift-F', 'Find by expression', self.enter_searchexpression)
  924.         self.makemenu(self.m_search, 'Find &next\tF3', 'Find next', self.find_next)
  925.         self.makemenu(self.m_search, 'Find &previous\tShift-F3', 'Find previous', self.find_previous)
  926.         self.makemenu(self.m_refresh, '&Refresh once \tF5', 'Refresh once', self.refresh_once)
  927.         self.makemenu(self.m_refresh, 'Refresh every &1s', 'Refresh every second', self.refresh_every_second)
  928.         self.makemenu(self.m_refresh, 'Refresh every &X seconds', 'Refresh every X seconds', self.refresh_interval)
  929.         self.makemenu(self.m_refresh, '&Stop all refresh timers', 'Stop refresh timers', self.stop_refresh)
  930.         self.menubar.Append(self.m_search, '&Find')
  931.         self.menubar.Append(self.m_sort, '&Sort')
  932.         self.menubar.Append(self.m_refresh, '&Refresh')
  933.         self.menubar.Append(self.m_help, '&Help')
  934.         self.SetMenuBar(self.menubar)
  935.         self.searchtext = ''
  936.         self.searchexpression = ''
  937.         self.helpdialog = None
  938.         self.refresh_interval = 1000
  939.         self.SetStatusText('Refreshing inactive', 1)
  940.  
  941.     
  942.     def refresh_once(self, event):
  943.         table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
  944.         table.refresh_content(event)
  945.  
  946.     
  947.     def refresh_interval(self, event):
  948.         table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
  949.         dlg = wx.TextEntryDialog(self, 'Enter refresh interval (milliseconds):', 'Refresh timer:', defaultValue = str(self.refresh_interval))
  950.         if dlg.ShowModal() == wx.ID_OK:
  951.             
  952.             try:
  953.                 milliseconds = int(dlg.GetValue())
  954.             except ValueError:
  955.                 exc = None
  956.                 self.SetStatusText(str(exc))
  957.  
  958.             table.timer.Start(milliseconds = milliseconds, oneShot = False)
  959.             self.SetStatusText('Refresh timer set to %s ms' % milliseconds)
  960.             self.SetStatusText('Refresh interval: %s ms' % milliseconds, 1)
  961.             self.refresh_interval = milliseconds
  962.         
  963.         dlg.Destroy()
  964.  
  965.     
  966.     def stop_refresh(self, event):
  967.         for i in xrange(self.notebook.GetPageCount()):
  968.             nb = self.notebook.GetPage(i)
  969.             nb.grid.table.timer.Stop()
  970.             self.SetStatusText('Refreshing inactive', 1)
  971.         
  972.  
  973.     
  974.     def refresh_every_second(self, event):
  975.         table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
  976.         table.timer.Start(milliseconds = 1000, oneShot = False)
  977.         self.SetStatusText('Refresh interval: 1000 ms', 1)
  978.  
  979.     
  980.     def sortasc(self, event):
  981.         grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
  982.         grid.sortattrasc()
  983.  
  984.     
  985.     def sortdesc(self, event):
  986.         grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
  987.         grid.sortattrdesc()
  988.  
  989.     
  990.     def find_previous(self, event):
  991.         grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
  992.         if self.searchtext:
  993.             row = grid.GetGridCursorRow()
  994.             col = grid.GetGridCursorCol()
  995.             self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
  996.             if col - 1 >= 0:
  997.                 grid.search(self.searchtext, row, col - 1, False)
  998.             else:
  999.                 grid.search(self.searchtext, row - 1, grid.table.GetNumberCols() - 1, False)
  1000.         elif self.searchexpression:
  1001.             self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
  1002.             grid.searchexpression(searchexp = self.searchexpression, search_forward = False)
  1003.         else:
  1004.             self.SetStatusText('No search yet: please enter search-text or -expression')
  1005.  
  1006.     
  1007.     def find_next(self, event):
  1008.         grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
  1009.         if self.searchtext != '':
  1010.             row = grid.GetGridCursorRow()
  1011.             col = grid.GetGridCursorCol()
  1012.             self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
  1013.             if col + 1 < grid.table.GetNumberCols():
  1014.                 grid.search(self.searchtext, row, col + 1)
  1015.             else:
  1016.                 grid.search(self.searchtext, row + 1, 0)
  1017.         elif self.searchexpression != '':
  1018.             self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
  1019.             grid.searchexpression(searchexp = self.searchexpression)
  1020.         else:
  1021.             self.SetStatusText('No search yet: please enter search-text or -expression')
  1022.  
  1023.     
  1024.     def display_help(self, event):
  1025.         if self.helpdialog:
  1026.             self.helpdialog.Destroy()
  1027.         
  1028.         self.helpdialog = IGridHTMLHelp(None, title = 'Help', size = wx.Size(600, 400))
  1029.         self.helpdialog.Show()
  1030.  
  1031.     
  1032.     def display_help_in_browser(self, event):
  1033.         filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), 'igrid_help.html')))
  1034.         if not filename.startswith('file'):
  1035.             filename = 'file:' + filename
  1036.         
  1037.         webbrowser.open(filename, new = 1, autoraise = True)
  1038.  
  1039.     
  1040.     def enter_searchexpression(self, event):
  1041.         dlg = wx.TextEntryDialog(self, 'Find:', 'Find matching expression:', defaultValue = self.searchexpression)
  1042.         if dlg.ShowModal() == wx.ID_OK:
  1043.             self.searchexpression = dlg.GetValue()
  1044.             self.searchtext = ''
  1045.             self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
  1046.             self.notebook.GetPage(self.notebook.GetSelection()).grid.searchexpression(self.searchexpression)
  1047.         
  1048.         dlg.Destroy()
  1049.  
  1050.     
  1051.     def makemenu(self, menu, label, help, cmd):
  1052.         menu.Append(self.menucounter, label, help)
  1053.         self.Bind(wx.EVT_MENU, cmd, id = self.menucounter)
  1054.         self.menucounter += 1
  1055.  
  1056.     
  1057.     def _add_notebook(self, input, *attrs):
  1058.         panel = IGridPanel(self.notebook, input, *attrs)
  1059.         text = str(ipipe.xformat(input, 'header', self.maxtitlelen)[2])
  1060.         if len(text) >= self.maxtitlelen:
  1061.             text = text[:self.maxtitlelen].rstrip('.') + '...'
  1062.         
  1063.         self.notebook.AddPage(panel, text, True)
  1064.         panel.grid.SetFocus()
  1065.         self.Layout()
  1066.  
  1067.     
  1068.     def OnCloseWindow(self, event):
  1069.         self.Destroy()
  1070.  
  1071.     
  1072.     def enter_searchtext(self, event):
  1073.         dlg = wx.TextEntryDialog(self, 'Find:', 'Find in list', defaultValue = self.searchtext)
  1074.         if dlg.ShowModal() == wx.ID_OK:
  1075.             self.searchtext = dlg.GetValue()
  1076.             self.searchexpression = ''
  1077.             self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
  1078.             self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext)
  1079.         
  1080.         dlg.Destroy()
  1081.  
  1082.  
  1083.  
  1084. class App(wx.App):
  1085.     
  1086.     def __init__(self, input):
  1087.         self.input = input
  1088.         self.result = None
  1089.         wx.App.__init__(self)
  1090.  
  1091.     
  1092.     def OnInit(self):
  1093.         frame = IGridFrame(self, self.input)
  1094.         frame.Show()
  1095.         self.SetTopWindow(frame)
  1096.         frame.Raise()
  1097.         return True
  1098.  
  1099.  
  1100.  
  1101. class igrid(ipipe.Display):
  1102.     if wx.VERSION < (2, 7):
  1103.         
  1104.         def display(self):
  1105.             
  1106.             try:
  1107.                 frame = IGridFrame(None, self.input)
  1108.                 frame.Show()
  1109.                 frame.Raise()
  1110.             except wx.PyNoAppError:
  1111.                 app = App(self.input)
  1112.                 app.MainLoop()
  1113.                 return app.result
  1114.  
  1115.  
  1116.     else:
  1117.         
  1118.         def display(self):
  1119.             app = App(self.input)
  1120.             app.MainLoop()
  1121.             return app.result
  1122.  
  1123.  
  1124.