filter_children_model.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Willow Garage, Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 #
33 # Author: Isaac Saito
34 
35 from __future__ import division
36 
37 from python_qt_binding.QtCore import Qt, Signal
38 try:
39  from python_qt_binding.QtCore import QSortFilterProxyModel # Qt 5
40 except ImportError:
41  from python_qt_binding.QtGui import QSortFilterProxyModel # Qt 4
42 
43 from rqt_reconfigure import logging
44 from rqt_reconfigure.treenode_qstditem import TreenodeQstdItem
45 
46 
47 class FilterChildrenModel(QSortFilterProxyModel):
48  """
49  Extending QSortFilterProxyModel, this provides methods to filter children
50  tree nodes.
51 
52  QSortFilterProxyModel filters top-down direction starting from the
53  top-level of tree, and once a node doesn't hit the query it gets disabled.
54  Filtering with this class reflects the result from the bottom node.
55 
56  Ex.
57  #TODO example needed here
58  """
59 
60  # Emitted when parameters filtered. int indicates the order/index of
61  # params displayed.
62  sig_filtered = Signal(int)
63 
64  def __init__(self, parent):
65  super(FilterChildrenModel, self).__init__(parent)
66 
67  # :Key: Internal ID of QModelIndex of each treenode.
68  # :Value: TreenodeStatus
69  # self._treenodes = OrderedDict()
70 
71  self._parent = parent
72  self._toplv_parent_prev = None
73 
74  def filterAcceptsRow(self, src_row, src_parent_qmindex):
75  """
76  Overridden.
77 
78  Terminology:
79  "Treenode" is deliberately used to avoid confusion with "Node" in ROS.
80 
81  :type src_row: int
82  :type src_parent_qmindex: QModelIndex
83  """
84  logging.debug('filerAcceptRow 1')
85  return self._filter_row_recur(src_row, src_parent_qmindex)
86 
87  def _filter_row_recur(self, src_row, src_parent_qmindex):
88  """
89  :type src_row: int
90  :type src_parent_qmindex: QModelIndex
91  """
92  _src_model = self.sourceModel()
93  curr_qmindex = _src_model.index(src_row, 0, src_parent_qmindex)
94  curr_qitem = _src_model.itemFromIndex(curr_qmindex)
95 
96  if isinstance(curr_qitem, TreenodeQstdItem):
97  # If selectable ROS Node, get GRN name
98  nodename_fullpath = curr_qitem.get_raw_param_name()
99  text_filter_target = nodename_fullpath
100  logging.debug(' Nodename full={} '.format(nodename_fullpath))
101  else:
102  # If ReadonlyItem, this means items are the parameters, not a part
103  # of node name. So, get param name.
104  text_filter_target = curr_qitem.data(Qt.DisplayRole)
105 
106  regex = self.filterRegExp()
107  pos_hit = regex.indexIn(text_filter_target)
108  if pos_hit >= 0: # Query hit.
109  logging.debug('curr data={} row={} col={}'.format(
110  curr_qmindex.data(), curr_qmindex.row(), curr_qmindex.column()
111  ))
112 
113  # Set all subsequent treenodes True
114  logging.debug(
115  ' FCModel.filterAcceptsRow'
116  ' src_row={} parent row={} data={} filterRegExp={}'.format(
117  src_row, src_parent_qmindex.row(),
118  src_parent_qmindex.data(), regex))
119 
120  # If the index is the terminal treenode, parameters that hit
121  # the query are displayed at the root tree.
122  _child_index = curr_qmindex.child(0, 0)
123  if ((not _child_index.isValid()) and
124  (isinstance(curr_qitem, TreenodeQstdItem))):
125  self._show_params_view(src_row, curr_qitem)
126 
127  # Once we find a treenode that hits the query, no need to further
128  # traverse since what this method wants to know with the given
129  # index is whether the given index is supposed to be shown or not.
130  # Thus, just return True here.
131  return True
132 
133  if not isinstance(curr_qitem, TreenodeQstdItem):
134  return False # If parameters, no need for recursive filtering.
135 
136  # Evaluate children recursively.
137  row_child = 0
138  while True:
139  child_qmindex = curr_qmindex.child(row_child, 0)
140  if child_qmindex.isValid():
141  flag = self._filter_row_recur(row_child, curr_qmindex)
142  if flag:
143  return True
144  else:
145  return False
146  row_child += 1
147  return False
148 
149  def _show_params_view(self, src_row, curr_qitem):
150  """
151  :type curr_qitem: QStandardItem
152  """
153  logging.debug('_show_params_view data={}'.format(
154  curr_qitem.data(Qt.DisplayRole)
155  ))
156  curr_qitem.enable_param_items()
157 
158  def _get_toplevel_parent_recur(self, qmindex):
159  p = qmindex.parent()
160  if p.isValid():
161  self._get_toplevel_parent(p)
162  return p
163 
164  def filterAcceptsColumn(self, source_column, source_parent):
165  """
166  Overridden.
167 
168  Doing nothing really since columns are not in use.
169 
170  :type source_column: int
171  :type source_parent: QModelIndex
172  """
173  logging.debug('FCModel.filterAcceptsCol source_col={} '.format(
174  source_column) + 'parent col={} row={} data={}'.format(
175  source_parent.column(), source_parent.row(),
176  source_parent.data()))
177  return True
178 
179  def set_filter(self, filter_):
180  self._filter = filter_
181 
182  # If filtered text is '' (0-length str), invalidate current
183  # filtering, in the hope of making filtering process faster.
184  if filter_.get_text == '':
185  self.invalidate()
186  logging.info('filter invalidated.')
187 
188  # By calling setFilterRegExp, filterAccepts* methods get kicked.
189  self.setFilterRegExp(self._filter.get_regexp())
def filterAcceptsColumn(self, source_column, source_parent)
def _filter_row_recur(self, src_row, src_parent_qmindex)


rqt_reconfigure
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Wed Jul 10 2019 04:02:40