Commits

Anonymous committed a35f2c9

hachoir-wx: Apply patch contributed by genta_hgr to use a virtual ListCtrl for the field view.
This speeds up subsequent loads of large fieldsets considerably.

Comments (0)

Files changed (3)

hachoir-wx/hachoir_wx/field_view/field_view.py

         columns = [_('address'), _('name'), _('type'), _('size'), _('data'), _('description')]
         for name in columns:
             self.append_column(name)
+        self.col_min_width = [len(s) for s in columns]
 
         self.Layout()
         self.Fit()
         self.cols[name] = index
         self.InsertColumn(col = index, heading = name)
 
-    def append_row(self, col_map):
-        index = self.InsertStringItem(maxint, '')
-        for name, value in col_map.iteritems():
-            col_index = self.cols[name]
-            self.SetStringItem(index, col_index, value)
-            self.autosize_column(col_index, value)
-
     def get_selected(self, name):
         return self.GetItem(self.GetFocusedItem(), self.cols[_('name')]).GetText()
 
     def clear(self):
         self.DeleteAllItems()
 
-    def autosize_column(self, col_index, value):
-        item_width = self.GetCharWidth() * (len(value) + 1)
-        self.SetColumnWidth(col_index, max(item_width, self.GetColumnWidth(col_index)))
+    def register_callback(self, cbGetItemText):
+        self.OnGetItemText_imp = cbGetItemText
+
+    def OnGetItemText(self, item, col):
+        return self.OnGetItemText_imp(item, col)
+
+    def get_col_index(self, name):
+       return self.cols[name]
+
+    def get_col_count(self):
+       return len(self.cols)
+
+    def resize_column(self, col_index, width):
+        width = max(self.col_min_width[col_index], width) + 1
+        self.SetColumnWidth(col_index, self.GetCharWidth() * width)

hachoir-wx/hachoir_wx/field_view/field_view_imp.py

     def __init__(self):
         self.addr_func = lambda field: field._getAbsoluteAddress()
         self.format_addr = lambda field: format_addr_hex(self.addr_func(field))
+        
+        self.col_str_table = [
+            lambda f: self.format_addr(f),          # address
+            format_name,                            # name
+            lambda f: f.getFieldType(),             # type
+            lambda f: format_size(f._getSize()),    # size
+            format_data,                            # data
+            format_desc                             # description
+        ]
 
     def on_field_set_ready(self, dispatcher, field_set):
         assert field_set is not None
 
     def on_field_view_ready(self, dispatcher, view):
         assert view is not None
+
+        # register callbacks before activating the field view
+        view.register_callback(cbGetItemText = self.OnGetItemTextImp)
+
         self.view = view
         self.fill_view()
         self.dispatcher.trigger('field_activated', self.fields)
 
     def fill_view(self):
         if self.fields._getParent() is not None:
-            self.view.append_row({ _('name') : '../' })
+            self.has_parent = True
+            self.view.SetItemCount(len(self.fields) + 1)
+        else:
+            self.has_parent = False
+            self.view.SetItemCount(len(self.fields))
 
-        for field in self.fields:
-            map = {
-                _('address') : self.format_addr(field),
-                _('name') : format_name(field),
-                _('type') : field.getFieldType(),
-                _('size') : format_size(field._getSize()),
-                _('data') : format_data(field),
-                _('description'): format_desc(field)
-                }
+        # autosize columns, based on a sample of the rows
+        for col in xrange(self.view.get_col_count()):
+            width = 0
+            func = self.col_str_table[col]
+            # when fields has more than 20 rows, they are probably similar.
+            # Therefore this routine only checks the first 10 rows and last 10 rows.
+            field_count = len(self.fields)
 
-            self.view.append_row(map)
+            if field_count <= 20:
+              field_range = [(0, field_count)]
+            else:
+              field_range = [(0, 10), (field_count - 10, field_count)]
+
+            for begin, end in field_range:
+                for i in xrange(begin, end):
+                    width = max(width, len(func(self.fields[i])))
+
+            self.view.resize_column(col, width)
+
+    def OnGetItemTextImp(self, item, col):
+        if self.has_parent:
+            if item == 0:
+                if col == self.view.get_col_index(_('name')):
+                    return '../'
+                else:
+                    return ''
+            else:
+                item = item - 1
+
+        field = self.fields[item]
+        return self.col_str_table[col](field)
 
     def refill_view(self):
         self.view.clear()

hachoir-wx/hachoir_wx/resource/hachoir_wx.xrc

         </object>
       </object>
       <object class="wxListCtrl" name="field_view" subclass="hachoir_wx.field_view.field_view_t">
-        <style>wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_HRULES|wxLC_VRULES</style>
+        <style>wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VIRTUAL|wxLC_HRULES|wxLC_VRULES</style>
         <font>
           <size>11</size>
           <family>modern</family>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.