Robot Framework Integrated Development Environment (RIDE)
dialogsearchtests.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 from functools import (total_ordering, cmp_to_key)
17 
18 import wx
19 from wx import Colour
20 
21 from ..utils import overrides
22 from ..widgets import (RIDEDialog, VerticalSizer, VirtualList, Label,
23  HelpLabel, ImageProvider)
24 from ..widgets.list import ListModel
25 
26 
27 class TestsDialog(RIDEDialog):
28 
29  def __init__(self, fuzzy_search_handler, tag_search_handler, add_to_selected_handler):
30  self._fuzzy_search_handler_fuzzy_search_handler = fuzzy_search_handler
31  self._tag_search_handler_tag_search_handler = tag_search_handler
32  self._add_to_selected_handler_add_to_selected_handler = add_to_selected_handler
33  self._selection_listeners_selection_listeners = []
34  title = "Search Tests"
35  RIDEDialog.__init__(self, title=title, size=(800, 400))
36  # set Left to Right direction (while we don't have localization)
37  self.SetLayoutDirection(wx.Layout_LeftToRight)
38  self.SetBackgroundColour(Colour(self.color_background))
39  self.SetForegroundColour(Colour(self.color_foreground))
40  self.SetSizer(VerticalSizer())
41  self.Sizer.Add(self._create_notebook_create_notebook(), 1, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 3)
42 
43  def _create_notebook(self):
44  self._notebook_notebook = wx.Notebook(self, wx.ID_ANY, style=wx.NB_TOP)
45  self._notebook_notebook.SetBackgroundColour(Colour(self.color_background))
46  self._notebook_notebook.SetForegroundColour(Colour(self.color_foreground))
47  self._notebook_notebook.AddPage(self._text_search_panel_text_search_panel(), 'Search')
48  self._notebook_notebook.AddPage(self._tag_pattern_search_panel_tag_pattern_search_panel(), 'Tag Search')
49  return self._notebook_notebook
50 
51  def _select_page(self, page=0):
52  self._notebook_notebook.ChangeSelection(page)
53 
54  def _text_search_panel(self):
55  panel = wx.Panel(self._notebook_notebook)
56  panel.SetSizer(VerticalSizer())
57  self._add_search_control_add_search_control(panel)
58  self.teststests = _TestSearchListModel([])
59  self.tests_listtests_list = VirtualList(panel, ['Test', 'Tags', 'Source'], self.teststests)
60  self.tests_listtests_list.SetBackgroundColour(Colour(self.color_secondary_background))
61  self.tests_listtests_list.SetForegroundColour(Colour(self.color_secondary_foreground))
62  self.tests_listtests_list.add_selection_listener(self._select_text_search_result_select_text_search_result)
63  panel.Sizer.add_expanding(self.tests_listtests_list)
64  self._fuzzy_results_text_fuzzy_results_text = wx.StaticText(panel, -1, 'Results: ')
65  panel.Sizer.Add(self._fuzzy_results_text_fuzzy_results_text, 0, wx.ALL, 3)
66  return panel
67 
69  panel = wx.Panel(self._notebook_notebook)
70  panel.SetSizer(VerticalSizer())
71  tags_controls_sizer = VerticalSizer()
72  tags_controls_sizer.Add(self._create_include_line_create_include_line(panel), 0, wx.ALL, 3)
73  tags_controls_sizer.Add(self._create_exclude_line_create_exclude_line(panel), 0, wx.ALL, 3)
74  controls_sizer = self._horizontal_sizer_horizontal_sizer()
75  controls_sizer.Add(tags_controls_sizer)
76  controls_sizer.Add(self._create_switch_button_create_switch_button(panel), 0, wx.CENTER, 3)
77  controls_sizer.Add(self._create_tag_search_button_create_tag_search_button(panel), 0, wx.ALL | wx.EXPAND, 3)
78  controls_sizer.Add(self._create_add_to_selected_button_create_add_to_selected_button(panel), 0, wx.ALL | wx.EXPAND, 3)
79  panel.Sizer.Add(controls_sizer)
80  panel.Sizer.Add(self._add_info_text_add_info_text(panel, "Find matches using tag patterns. See RF User "
81  "Guide or 'robot --help' for more information.")
82  , 0, wx.ALL, 3)
83  self._tags_results_tags_results = _TestSearchListModel([])
84  self._tags_list_tags_list = VirtualList(panel, ['Test', 'Tags', 'Source'], self._tags_results_tags_results)
85  self._tags_list_tags_list.SetBackgroundColour(Colour(self.color_secondary_background))
86  self._tags_list_tags_list.SetForegroundColour(Colour(self.color_secondary_foreground))
87  self._tags_list_tags_list.add_selection_listener(self._select_tag_search_result_select_tag_search_result)
88  panel.Sizer.add_expanding(self._tags_list_tags_list)
89  self._tags_results_text_tags_results_text = wx.StaticText(panel, -1, 'Results: ')
90  panel.Sizer.Add(self._tags_results_text_tags_results_text, 0, wx.ALL, 3)
91  return panel
92 
93  def _create_include_line(self, panel):
94  include_line = self._horizontal_sizer_horizontal_sizer()
95  include_line.Add(Label(panel, label='Include', size=(80, -1)))
96  self._tags_to_include_text_tags_to_include_text = wx.TextCtrl(panel, value='', size=(400, -1),
97  style=wx.TE_PROCESS_ENTER|wx.TE_NOHIDESEL)
98  self._tags_to_include_text_tags_to_include_text.SetBackgroundColour(Colour(self.color_secondary_background))
99  self._tags_to_include_text_tags_to_include_text.SetForegroundColour(Colour(self.color_secondary_foreground))
100  self._tags_to_include_text_tags_to_include_text.Bind(wx.EVT_TEXT_ENTER, self.OnSearchTagsOnSearchTags)
101  include_line.Add(self._tags_to_include_text_tags_to_include_text)
102  return include_line
103 
104  def _create_switch_button(self, panel):
105  sizer = self._vertical_sizer_vertical_sizer()
106  img = ImageProvider().SWITCH_FIELDS_ICON
107  button = wx.BitmapButton(panel, -1, img, pos=(10, 20))
108  button.SetBackgroundColour(Colour(self.color_secondary_background))
109  button.SetForegroundColour(Colour(self.color_secondary_foreground))
110  self.Bind(wx.EVT_BUTTON, self.OnSwitchFieldsOnSwitchFields, button)
111  sizer.Add(button)
112  return sizer
113 
114  def _create_exclude_line(self, panel):
115  exclude_line = self._horizontal_sizer_horizontal_sizer()
116  exclude_line.Add(Label(panel, label='Exclude', size=(80, -1)))
117  self._tags_to_exclude_text_tags_to_exclude_text = wx.TextCtrl(panel, value='', size=(400, -1),
118  style=wx.TE_PROCESS_ENTER|wx.TE_NOHIDESEL)
119  self._tags_to_exclude_text_tags_to_exclude_text.SetBackgroundColour(Colour(self.color_secondary_background))
120  self._tags_to_exclude_text_tags_to_exclude_text.SetForegroundColour(Colour(self.color_secondary_foreground))
121  self._tags_to_exclude_text_tags_to_exclude_text.Bind(wx.EVT_TEXT_ENTER, self.OnSearchTagsOnSearchTags)
122  exclude_line.Add(self._tags_to_exclude_text_tags_to_exclude_text)
123  return exclude_line
124 
125  def _create_tag_search_button(self, panel):
126  button = wx.Button(panel, label='Search')
127  button.SetBackgroundColour(Colour(self.color_secondary_background))
128  button.SetForegroundColour(Colour(self.color_secondary_foreground))
129  button.Bind(wx.EVT_BUTTON, self.OnSearchTagsOnSearchTags)
130  return button
131 
132  def OnSearchTags(self, event):
133  self._tag_search_handler_tag_search_handler(self._tags_to_include_text_tags_to_include_text.GetValue(),
134  self._tags_to_exclude_text_tags_to_exclude_text.GetValue())
135 
137  button = wx.Button(panel, label='Add all to selected')
138  button.SetBackgroundColour(Colour(self.color_secondary_background))
139  button.SetForegroundColour(Colour(self.color_secondary_foreground))
140  button.Bind(wx.EVT_BUTTON, self.OnAddToSelectedOnAddToSelected)
141  return button
142 
143  def OnAddToSelected(self, event):
144  self._add_to_selected_handler_add_to_selected_handler(self._get_current_tests_get_current_tests())
145 
146  def OnSearchTests(self, event):
147  self._fuzzy_search_handler_fuzzy_search_handler(self._search_control_search_control.GetValue())
148 
149  def set_search_model(self, search_text, results):
150  results = list(results)
151  self._search_control_search_control.SetValue(search_text)
152  self._fuzzy_results_text_fuzzy_results_text.SetLabel('Results: %d' % len(results))
153  self.teststests._tests = results
154  self._refresh_list_refresh_list(self.tests_listtests_list)
155 
156  def set_tag_search_model(self, include_text, exclude_text, results):
157  results = list(results)
158  self._tags_to_include_text_tags_to_include_text.SetValue(include_text)
159  self._tags_to_exclude_text_tags_to_exclude_text.SetValue(exclude_text)
160  self._tags_results_text_tags_results_text.SetLabel('Results: %d' % len(results))
161  self._tags_results_tags_results._tests = results
162  self._refresh_list_refresh_list(self._tags_list_tags_list)
163 
164  def _refresh_list(self, list):
165  list.refresh()
166  list.Refresh()
167  if list.GetItemCount():
168  list._inform_listeners(0)
169 
170  def _add_info_text(self, panel, text = ""):
171  infopanel = self._horizontal_sizer_horizontal_sizer()
172  infopanel.Add(HelpLabel(panel, "Info. " + text))
173  return infopanel
174 
175  def _add_search_control(self, panel):
176  panel.SetSizer(VerticalSizer())
177  line1 = self._horizontal_sizer_horizontal_sizer()
178  self._add_pattern_filter_add_pattern_filter(line1, panel)
179  fuzzy_search_button = wx.Button(panel, label='Search')
180  fuzzy_search_button.SetBackgroundColour(Colour(self.color_secondary_background))
181  fuzzy_search_button.SetForegroundColour(Colour(self.color_secondary_foreground))
182  fuzzy_search_button.Bind(wx.EVT_BUTTON, self.OnSearchTestsOnSearchTests)
183  line1.Add(fuzzy_search_button, 0, wx.ALL | wx.EXPAND, 3)
184  add_to_selection_button = wx.Button(panel, label='Add all to selected')
185  add_to_selection_button.SetBackgroundColour(Colour(self.color_secondary_background))
186  add_to_selection_button.SetForegroundColour(Colour(self.color_secondary_foreground))
187  add_to_selection_button.Bind(wx.EVT_BUTTON, self.OnAddToSelectedOnAddToSelected)
188  line1.Add(add_to_selection_button, 0, wx.ALL | wx.EXPAND, 3)
189  panel.Sizer.Add(line1, 0, wx.ALL, 3)
190  panel.Sizer.Add(self._add_info_text_add_info_text(panel, "Find matches by test name, "
191  "documentation and/or tag."), 0, wx.ALL, 3)
192  panel.Sizer.Layout()
193 
194  def _horizontal_sizer(self):
195  return wx.BoxSizer(wx.HORIZONTAL)
196 
197  def _vertical_sizer(self):
198  return wx.BoxSizer(wx.VERTICAL)
199 
200  def _add_pattern_filter(self, sizer, parent):
201  self._search_control_search_control = wx.SearchCtrl(parent, value='', size=(200,-1),
202  style=wx.TE_PROCESS_ENTER)
203  self._search_control_search_control.SetBackgroundColour(Colour(self.color_secondary_background))
204  self._search_control_search_control.SetForegroundColour(Colour(self.color_secondary_foreground))
205  self._search_control_search_control.SetDescriptiveText('Search term')
206  wrapped = lambda event: self._fuzzy_search_handler_fuzzy_search_handler(self._search_control_search_control.GetValue())
207  self._search_control_search_control.Bind(wx.EVT_TEXT_ENTER, wrapped)
208  sizer.Add(self._search_control_search_control, 0, wx.ALL, 3)
209 
211  if idx != -1:
212  for listener in self._selection_listeners_selection_listeners:
213  listener(self.teststests[idx])
214 
216  for listener in self._selection_listeners_selection_listeners:
217  listener(self._tags_results_tags_results[idx])
218 
219  def add_selection_listener(self, listener):
220  self._selection_listeners_selection_listeners.append(listener)
221 
222  def _find_index_in_list(self, item, list):
223  if item is None:
224  return 0
225  idx = 0
226  for tc in list:
227  if tc[0] == item:
228  return idx
229  idx += 1
230  return 0
231 
232  def set_focus_to_default_location(self, selected=None):
233  if self._notebook_notebook.GetSelection() == 0:
234  self._set_focus_to_default_location_in_text_search_set_focus_to_default_location_in_text_search(selected)
235  else:
236  self._set_focus_to_default_location_in_tag_search_set_focus_to_default_location_in_tag_search(selected)
237 
239  if self._notebook_notebook.GetSelection() == 0:
240  return [t for t, _ in self.teststests._tests]
241  else:
242  return [test for test, _ in self._tags_results_tags_results._tests]
243 
245  if self.teststests.count:
246  self.tests_listtests_list.Select(self._find_index_in_list_find_index_in_list(selected, self.teststests))
247  self.tests_listtests_list.SetFocus()
248  else:
249  self._search_control_search_control.SetFocus()
250 
252  if self._tags_results_tags_results.count:
253  self._tags_list_tags_list.Select(self._find_index_in_list_find_index_in_list(selected, self._tags_results_tags_results))
254  self._tags_list_tags_list.SetFocus()
255  else:
256  self._tags_to_include_text_tags_to_include_text.SetFocus()
257 
258  def OnSwitchFields(self, event):
259  include_txt = self._tags_to_include_text_tags_to_include_text.GetValue()
260  exclude_txt = self._tags_to_exclude_text_tags_to_exclude_text.GetValue()
261 
262  if len(include_txt.strip()) > 0 or len(exclude_txt.strip()) > 0:
263  self._tags_to_include_text_tags_to_include_text.SetValue(exclude_txt)
264  self._tags_to_exclude_text_tags_to_exclude_text.SetValue(include_txt)
265  self.OnSearchTagsOnSearchTags(event)
266 
267 
268 @total_ordering
270 
271  def __init__(self, tests):
272  self._tests_tests = sorted(tests, key=cmp_to_key(lambda x, y: self.m_cmpm_cmp(x[1], y[1])))
273 
274  @property
275  @overrides(ListModel)
276  count = property
277 
278  def count(self):
279  return len(self._tests_tests)
280 
281  def __getitem__(self, item):
282  return self._tests_tests[item]
283 
284  def item_text(self, row, col):
285  test, match = self._tests_tests[row]
286  if col == 0:
287  return test.name
288  if col == 1:
289  return u', '.join(str(t) for t in test.tags)
290  return test.datafile_controller.longname
291 
292  @staticmethod
293  def m_cmp(a, b):
294  return (a > b) - (a < b)
295 
296  def __eq__(self, other):
297  return self.__class__.__name__.lower() == other.name.lower()
298 
299  def __hash__(self):
300  return hash(repr(self))
301 
302  def __lt__(self, other):
303  return self.__class__.__name__.lower() < other.name.lower()
def __init__(self, fuzzy_search_handler, tag_search_handler, add_to_selected_handler)
def set_tag_search_model(self, include_text, exclude_text, results)