591
591
def __init__(self, *args):
592
592
treewidget.TreeFilterProxyModel.__init__(self, *args)
593
593
self.text_to_match = None
594
self._interesting = None
595
self._all_data_loaded = False
596
self._text_match_count = 0
598
595
def setTextToMatch(self, text):
599
596
self.text_to_match = text
600
self._update_interesting()
601
597
self.invalidateFilter()
603
def _update_interesting(self):
604
if not self.text_to_match:
605
self._interesting = None
607
text = self.text_to_match
608
interesting = set([''])
610
for path in self._iter_paths():
611
if path.find(text) >= 0:
612
interesting.add(path)
613
directories.update(parent_directories(path))
614
self._text_match_count = len(interesting)
615
interesting.update(directories)
616
#print "\ninteresting for %s ...\n%s\n" % (text,
617
# "\n".join(sorted(interesting)))
618
self._interesting = interesting
620
def _iter_paths(self):
621
# The source model loads data lazily. We need everything loaded
622
# to find the complete set of paths though
623
self._ensure_all_data_loaded()
624
return iter(self.source_model.inventory_data_by_path.keys())
626
def _ensure_all_data_loaded(self):
627
if self._all_data_loaded:
629
model = self.source_model
630
for id in range(0, len(model.inventory_data)):
631
self._load_dirs(model, id)
632
self._all_data_loaded = True
634
def _load_dirs(self, model, id):
635
item_data = model.inventory_data[id]
636
if item_data.item.kind == "directory":
637
if item_data.children_ids is None:
638
# This locks and unlocks the tree each time.
639
# I wonder how that impacts performance?
641
for child_id in item_data.children_ids:
642
self._load_dirs(model, child_id)
644
def filterAcceptsRow(self, source_row, source_parent):
645
result = treewidget.TreeFilterProxyModel.filterAcceptsRow(
646
self, source_row, source_parent)
647
if result and self._interesting:
648
# Apply the text filter (matches found earlier)
649
path, kind = self._get_path_info(source_row, source_parent)
650
result = path in self._interesting
653
def _get_path_info(self, source_row, source_parent):
654
"""Return path, kind for a model item."""
655
model = self.source_model
656
parent_id = source_parent.internalId()
657
children_ids = model.inventory_data[parent_id].children_ids
658
# Why is this check required?
659
if len(children_ids) <= source_row:
661
id = children_ids[source_row]
662
data = model.inventory_data[id]
663
return data.path, data.item.kind
665
def text_match_count(self):
666
"""Number of items matching text or 0 if unknown.
668
Note: The number is across the WHOLE tree, not just those displayed
669
after applying the combined filtering.
599
def filter_id(self, id, item_data):
600
"""Determines wether a item should be displayed.
602
* True: Show the item
603
* False: Donot show the item
604
* None: Show the item if there are any children that are visible.
671
return self._text_match_count
606
show = treewidget.TreeFilterProxyModel.filter_id(self, id, item_data)
607
if self.text_to_match and show:
608
if item_data.path.find(self.text_to_match) >=1:
674
614
class _QBrowseTreeWidget(treewidget.TreeWidget):
675
615
"""Subclass the standard QBzr TreeWidget to patch in more features.
781
721
# Automatically expand the tree if the match count is small.
782
722
# The number could be configurable one day provided the doc
783
723
# was very clear about potential vs actual match counts
784
matches = self._tree_viewer.tree_filter_model.text_match_count()
786
self._tree_viewer.expandAll()
724
parents = [QtCore.QModelIndex()] # start at the root
727
while parents and expanded <= 15:
728
for parent in parents:
729
matches = self._tree_viewer.tree_filter_model.rowCount(parent)
730
if matches and matches <= 5:
731
self._tree_viewer.expand(parent)
732
if (self._tree_viewer.isExpanded(parent) or
733
parent == QtCore.QModelIndex()):
735
for i in range(matches):
737
self._tree_viewer.tree_filter_model.index(i, 0, parent))
738
parents = next_parents
787
739
# Reset our memory wrt what's expanded. This is perhaps a little
788
740
# heavy handed wrt text matching as that isn't remembered across
789
741
# tree switches. (Then again, perhaps it should be.)