Robot Framework Integrated Development Environment (RIDE)
editors.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 import wx
17 from wx import Colour
18 
19 from .settingeditors import (
20  DocumentationEditor, SettingEditor, TagsEditor,
21  ImportSettingListEditor, VariablesListEditor, MetadataListEditor)
22 from .. import robotapi, context
23 from ..controller.settingcontrollers import (
24  DocumentationController, VariableController, TagsController)
25 from ..publish import (
26  RideItemSettingsChanged, RideInitFileRemoved, RideFileNameChanged)
27 from ..usages.UsageRunner import ResourceFileUsages
28 from ..widgets import (
29  ButtonWithHandler, Label, HeaderLabel, HorizontalSizer, HtmlWindow)
30 
31 
32 class WelcomePage(HtmlWindow):
33  undo = cut = copy = paste = delete = comment = uncomment = save \
34  = show_content_assist = tree_item_selected = lambda *args: None
35 
36  def __init__(self, parent):
37  HtmlWindow.__init__(self, parent, text=context.ABOUT_RIDE)
38 
39  def close(self):
40  self.Show(False)
41 
42  def destroy(self):
43  self.closeclose()
44  self.Destroy()
45 
46 
47 
48 class EditorPanel(wx.Panel):
49  # TODO: Move outside default editor package, document
50  name = doc = ''
51  title = None
52  undo = cut = copy = paste = delete = comment = uncomment = save \
53  = show_content_assist = lambda self: None
54 
55  def __init__(self, plugin, parent, controller, tree):
56  wx.Panel.__init__(self, parent)
57  from ..preferences import RideSettings
58 
61  _settings = RideSettings()
62  self.general_settingsgeneral_settings = _settings['General']
63  self.color_backgroundcolor_background = self.general_settingsgeneral_settings.get('background', 'light grey')
64  self.color_foregroundcolor_foreground = self.general_settingsgeneral_settings.get('foreground', 'black')
65  self.color_secondary_backgroundcolor_secondary_background = self.general_settingsgeneral_settings.get('secondary background', 'light grey')
66  self.color_secondary_foregroundcolor_secondary_foreground = self.general_settingsgeneral_settings.get('secondary foreground', 'black')
67  self.color_background_helpcolor_background_help = self.general_settingsgeneral_settings.get('background help', (240, 242, 80))
68  self.color_foreground_textcolor_foreground_text = self.general_settingsgeneral_settings.get('foreground text', (7, 0, 70))
69  self.font_facefont_face = self.general_settingsgeneral_settings.get('font face', '')
70  self.font_sizefont_size = self.general_settingsgeneral_settings.get('font size', 11)
71  self.SetBackgroundColour(Colour(self.color_backgroundcolor_background))
72  self.SetForegroundColour(Colour(self.color_foregroundcolor_foreground))
73  self.pluginplugin = plugin
74  self.controllercontroller = controller
75  self._tree_tree = tree
76 
77  def tree_item_selected(self, item):
78  pass
79 
80 
81 class _RobotTableEditor(EditorPanel):
82  name = 'table'
83  doc = 'table editor'
84 
87  _settings_open_id = 'robot table settings open'
88 
89  def __init__(self, plugin, parent, controller, tree):
90  EditorPanel.__init__(self, plugin, parent, controller, tree)
91  self.sizersizer = wx.BoxSizer(wx.VERTICAL)
92  self.Bind(wx.EVT_IDLE, self.OnIdleOnIdle)
93  self.SetSizer(self.sizersizer)
94  if self.titletitle:
95  self.sizersizer.Add(self._create_header_create_header(self.titletitle),
96  0, wx.EXPAND | wx.ALL, 5)
97  # self.sizer.Add((0, 10)) # DEBUG why this?
98  self._editors_editors = []
99  self._reset_last_show_tooltip_reset_last_show_tooltip()
100  self._populate()
101  self.pluginplugin.subscribe(self._settings_changed_settings_changed, RideItemSettingsChanged)
102 
104  if self._settings_open_id_settings_open_id not in self.pluginplugin.global_settings:
105  return False
106  return self.pluginplugin.global_settings[self._settings_open_id_settings_open_id]
107 
109  self.pluginplugin.global_settings[self._settings_open_id_settings_open_id] = \
110  self._settings_settings.IsExpanded()
111 
112  def _settings_changed(self, message):
113  if message.item == self.controllercontroller:
114  for editor in self._editors_editors:
115  editor.update_value()
116 
117  def OnIdle(self, event):
118  if self._last_shown_tooltip_last_shown_tooltip and self._mouse_outside_tooltip_mouse_outside_tooltip():
119  self._last_shown_tooltip_last_shown_tooltip.hide()
120  self._reset_last_show_tooltip_reset_last_show_tooltip()
121 
123  mx, my = wx.GetMousePosition()
124  tx, ty = self._last_shown_tooltip_last_shown_tooltip.screen_position
125  dx, dy = self._last_shown_tooltip_last_shown_tooltip.size
126  return (mx < tx or mx > tx+dx) or (my < ty or my > ty+dy)
127 
128  def tooltip_allowed(self, tooltip):
129  if wx.GetMouseState().ControlDown() or \
130  self._last_shown_tooltip_last_shown_tooltip is tooltip:
131  return False
132  self._last_shown_tooltip_last_shown_tooltip = tooltip
133  return True
134 
136  self._last_shown_tooltip_last_shown_tooltip = None
137 
138  def close(self):
139  self.pluginplugin.unsubscribe(
140  self._settings_changed_settings_changed, RideItemSettingsChanged)
141  self.Unbind(wx.EVT_MOTION)
142  self.Show(False)
143 
144  def destroy(self):
145  self.closeclose()
146  self.DestroyLater()
147 
148  def _create_header(self, text, readonly=False):
149  if readonly:
150  text += ' (READ ONLY)'
151  self._title_display_title_display = HeaderLabel(self, text)
152  return self._title_display_title_display
153 
154  def _add_settings(self):
155  self._settings_settings = self._create_settings_create_settings()
156  self._restore_settings_open_status_restore_settings_open_status()
157  self._editors_editors.append(self._settings_settings)
158  self.sizersizer.Add(self._settings_settings, 0, wx.ALL | wx.EXPAND, 2)
159 
160  def _create_settings(self):
161  settings = Settings(self)
162  settings.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self._collabsible_changed_collabsible_changed)
163  settings.build(self.controllercontroller.settings, self.pluginplugin, self._tree_tree)
164  return settings
165 
167  if self._should_settings_be_open_should_settings_be_open():
168  self._settings_settings.Expand()
169  wx.CallAfter(self._collabsible_changed_collabsible_changed)
170  else:
171  self._settings_settings.Collapse()
172  self.GetSizer().Layout()
173  self.Refresh()
174  self.Parent.GetSizer().Layout()
175  self.Parent.Refresh()
176 
177  def _collabsible_changed(self, event=None):
178  self._store_settings_open_status_store_settings_open_status()
179  self.GetSizer().Layout()
180  self.Refresh()
181  if event:
182  event.Skip()
183 
184 
185  def highlight_cell(self, obj, row, column):
186  if isinstance(obj, robotapi.Setting):
187  setting_editor = self._get_settings_editor_get_settings_editor(obj)
188  if setting_editor and hasattr(setting_editor, "highlight"):
189  setting_editor.highlight(column)
190  elif row >= 0 and column >= 0:
191  self.kweditor.select(row, column)
192 
193 
196  def _get_settings_editor(self, setting):
197  for child in self.GetChildren():
198  if isinstance(child, SettingEditor):
199  if child._item == setting:
200  return child
201  return None
202 
203  def highlight(self, text, expand=True):
204  for editor in self._editors_editors:
205  editor.highlight(text, expand=expand)
206 
207 
208 class Settings(wx.CollapsiblePane):
209  BORDER = 2
210 
211  def __init__(self, parent):
212  wx.CollapsiblePane.__init__(
213  self, parent, wx.ID_ANY, 'Settings',
214  style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE)
215  from ..preferences import RideSettings
216 
219  _settings = RideSettings()
220  self.general_settingsgeneral_settings = _settings['General']
221  self.color_backgroundcolor_background = self.general_settingsgeneral_settings.get('background', 'light grey')
222  self.color_foregroundcolor_foreground = self.general_settingsgeneral_settings.get('foreground', 'black')
223  self.color_secondary_backgroundcolor_secondary_background = self.general_settingsgeneral_settings.get('secondary background', 'light grey')
224  self.color_secondary_foregroundcolor_secondary_foreground = self.general_settingsgeneral_settings.get('secondary foreground', 'black')
225  self.color_background_helpcolor_background_help = self.general_settingsgeneral_settings.get('background help', (240, 242, 80))
226  self.color_foreground_textcolor_foreground_text = self.general_settingsgeneral_settings.get('foreground text', (7, 0, 70))
227  self.font_facefont_face = self.general_settingsgeneral_settings.get('font face', '')
228  self.font_sizefont_size = self.general_settingsgeneral_settings.get('font size', 11)
229  self.SetBackgroundColour(Colour(self.color_backgroundcolor_background))
230  self.SetForegroundColour(Colour(self.color_foregroundcolor_foreground))
231  self._sizer_sizer = wx.BoxSizer(wx.VERTICAL)
232  self._editors_editors = []
233  self.Bind(wx.EVT_SIZE, self._recalc_size_recalc_size)
234 
235  def Expand(self):
236  wx.CollapsiblePane.Expand(self)
237 
238  def GetPane(self):
239  pane = wx.CollapsiblePane.GetPane(self)
240  """
241  pane.SetBackgroundColour(Colour(200, 222, 40))
242  pane.SetOwnBackgroundColour(Colour(200, 222, 40))
243  pane.SetForegroundColour(Colour(7, 0, 70))
244  pane.SetOwnForegroundColour(Colour(7, 0, 70))
245  """
246  pane.tooltip_allowed = self.GetParent().tooltip_allowed
247  return pane
248 
249  def close(self):
250  for editor in self._editors_editors:
251  editor.close()
252 
253  def update_value(self):
254  for editor in self._editors_editors:
255  editor.update_value()
256 
257  def create_editor_for(self, controller, plugin, tree):
258  editor_cls = self._get_editor_class_get_editor_class(controller)
259  return editor_cls(self.GetPaneGetPane(), controller, plugin, tree)
260 
261  def _get_editor_class(self, controller):
262  if isinstance(controller, DocumentationController):
263  return DocumentationEditor
264  if isinstance(controller, TagsController):
265  return TagsEditor
266  return SettingEditor
267 
268  def build(self, settings, plugin, tree):
269  for setting in settings:
270  editor = self.create_editor_forcreate_editor_for(setting, plugin, tree)
271  """
272  editor.SetBackgroundColour(Colour(200, 222, 40))
273  editor.SetOwnBackgroundColour(Colour(200, 222, 40))
274  editor.SetForegroundColour(Colour(7, 0, 70))
275  editor.SetOwnForegroundColour(Colour(7, 0, 70))
276  """
277  self._sizer_sizer.Add(editor, 0, wx.ALL | wx.EXPAND, self.BORDERBORDER)
278  self._editors_editors.append(editor)
279  editor.Refresh()
280  self.GetPaneGetPane().SetSizer(self._sizer_sizer)
281 
282  def _recalc_size(self, event=None):
283  expand_button_height = 34
284  total_height = 0
285  if self.IsExpanded():
286  for editor in self._editors_editors:
287  total_height += editor.BestSize[1]
288  total_height += 2 * self.BORDERBORDER + 1
289  self.SetSizeHints(-1, total_height + expand_button_height)
290  if event:
291  event.Skip()
292 
293  def highlight(self, text, expand=True):
294  match = False
295  for editor in self._editors_editors:
296  if editor.contains(text):
297  editor.highlight(text)
298  match = True
299  else:
300  editor.clear_highlight()
301  if match and expand:
302  self.ExpandExpand()
303  self.Parent.GetSizer().Layout()
304 
305 
307 
308  def __init__(self, *args):
309  _RobotTableEditor.__init__(self, *args)
310  self.pluginplugin.subscribe(
311  self._update_source_and_name_update_source_and_name, RideFileNameChanged)
312 
313  def _update_source(self, message=None):
314  self._source_source.SetValue(self.controllercontroller.data.source)
315 
316  def _update_source_and_name(self, message):
317  self._title_display_title_display.SetLabel(self.controllercontroller.name)
318  self._update_source_update_source()
319 
320  def tree_item_selected(self, item):
321  if isinstance(item, VariableController):
322  self._var_editor_var_editor.select(item.name)
323 
324  def _populate(self):
325  datafile = self.controllercontroller.data
326  header = self._create_header_create_header(
327  datafile.name, not self.controllercontroller.is_modifiable())
328  self.sizersizer.Add(header, 0, wx.EXPAND | wx.ALL, 5)
329  self.sizersizer.Add(self._create_source_label_create_source_label(datafile.source), 0, wx.EXPAND | wx.ALL, 1)
330  self.sizersizer.Add((0, 10))
331  self._add_settings_add_settings()
332  self._add_import_settings_add_import_settings()
333  self._add_variable_table_add_variable_table()
334 
335  def _create_source_label(self, source):
336  sizer = wx.BoxSizer(wx.HORIZONTAL)
337  sizer.Add((5, 0))
338  sizer.Add(Label(self, label='Source', size=(context.SETTING_LABEL_WIDTH,
339  context.SETTING_ROW_HEIGHT)))
340  self._source_source = wx.TextCtrl(self, style=wx.TE_READONLY | wx.NO_BORDER)
341  self._source_source.SetBackgroundColour(Colour(self.color_backgroundcolor_background))
342  self._source_source.SetForegroundColour(Colour(self.color_foregroundcolor_foreground))
343 
344  self._source_source.SetValue(source)
345  self._source_source.SetMaxSize(wx.Size(-1, context.SETTING_ROW_HEIGHT))
346  sizer.Add(self._source_source, 1, wx.EXPAND)
347  return sizer
348 
350  import_editor = ImportSettingListEditor(self, self._tree_tree, self.controllercontroller.imports)
351  self.sizersizer.Add(import_editor, 1, wx.EXPAND)
352  self._editors_editors_editors.append(import_editor)
353 
355  self._var_editor_var_editor = VariablesListEditor(self, self._tree_tree, self.controllercontroller.variables)
356  self.sizersizer.Add(self._var_editor_var_editor, 1, wx.EXPAND)
357  self._editors_editors_editors.append(self._var_editor_var_editor)
358 
359  def close(self):
360  self.pluginplugin.unsubscribe(self._update_source_and_name_update_source_and_name, RideFileNameChanged)
361  for editor in self._editors_editors_editors:
362  editor.close()
363  self._editors_editors_editors = []
364  _RobotTableEditor.close(self)
365 
366  # Stubs so that ctrl+d ctrl+i don't throw exceptions
367  delete_rows = insert_rows = lambda s: None
368 
369 
370 class FindUsagesHeader(HorizontalSizer):
371 
372  def __init__(self, parent, header, usages_callback, color_foreground, color_background):
373  HorizontalSizer.__init__(self)
374  self._header_header = HeaderLabel(parent, header)
375  self.add_expanding(self._header_header)
376  self.add(ButtonWithHandler(parent, 'Find Usages', usages_callback, color_secondary_foreground=color_foreground,
377  color_secondary_background=color_background))
378 
379  def SetLabel(self, label):
380  self._header_header.SetLabel(label)
381 
382 
384 
387  _settings_open_id = 'resource file settings open'
388 
389  def _create_header(self, text, readonly=False):
390  if readonly:
391  text += ' (READ ONLY)'
392 
393  def cb(event):
394  ResourceFileUsages(self.controllercontroller, self._tree_tree.highlight).show()
395  self._title_display_title_display_title_display = FindUsagesHeader(self, text, cb, color_foreground=self.color_secondary_foregroundcolor_secondary_foreground,
396  color_background=self.color_secondary_backgroundcolor_secondary_background)
397  return self._title_display_title_display_title_display
398 
399 
401 
404  _settings_open_id = 'test case file settings open'
405 
406  def _populate(self):
407  _FileEditor._populate(self)
408  self.sizersizer.Add((0, 10))
409  self._add_metadata_add_metadata()
410 
411  def _add_metadata(self):
412  metadata_editor = MetadataListEditor(self, self._tree_tree, self.controllercontroller.metadata)
413  self.sizersizer.Add(metadata_editor, 1, wx.EXPAND)
414  self._editors_editors_editors.append(metadata_editor)
415 
416 
418 
421  _settings_open_id = 'init file settings open'
422 
423  def _populate(self):
424  TestCaseFileEditor._populate(self)
425  self.pluginplugin.subscribe(self._init_file_removed_init_file_removed, RideInitFileRemoved)
426 
427  def _init_file_removed(self, message):
428  for setting, editor in zip(self.controllercontroller.settings, self._editors_editors_editors):
429  editor.refresh(setting)
430 
431  def close(self):
432  self.pluginplugin.unsubscribe(self._init_file_removed_init_file_removed, RideInitFileRemoved)
433  super().close()
Base class for all editor panels.
Definition: editors.py:48
def tree_item_selected(self, item)
Definition: editors.py:77
def __init__(self, plugin, parent, controller, tree)
Definition: editors.py:55
def __init__(self, parent, header, usages_callback, color_foreground, color_background)
Definition: editors.py:372
def _init_file_removed(self, message)
Definition: editors.py:427
def _create_header(self, text, readonly=False)
Definition: editors.py:389
def build(self, settings, plugin, tree)
Definition: editors.py:268
def _get_editor_class(self, controller)
Definition: editors.py:261
def create_editor_for(self, controller, plugin, tree)
Definition: editors.py:257
def __init__(self, parent)
Definition: editors.py:211
def _recalc_size(self, event=None)
Definition: editors.py:282
def highlight(self, text, expand=True)
Definition: editors.py:293
def __init__(self, parent)
Definition: editors.py:36
def _update_source_and_name(self, message)
Definition: editors.py:316
def tree_item_selected(self, item)
Definition: editors.py:320
def _update_source(self, message=None)
Definition: editors.py:313
def _create_source_label(self, source)
Definition: editors.py:335
def __init__(self, plugin, parent, controller, tree)
Definition: editors.py:89
def highlight(self, text, expand=True)
Definition: editors.py:203
def _create_header(self, text, readonly=False)
Definition: editors.py:148
def _get_settings_editor(self, setting)
Return the settings editor for the given setting object.
Definition: editors.py:196
def highlight_cell(self, obj, row, column)
Highlight the given object at the given row and column.
Definition: editors.py:185
def _collabsible_changed(self, event=None)
Definition: editors.py:177