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 from os.path import abspath, dirname, join
17 
18 import wx
19 from wx import Colour
20 from wx.lib.masked import NumCtrl
21 
22 # from .. import widgets
23 from ..ui.preferences_dialogs import (PreferencesPanel, SpinChoiceEditor, IntegerChoiceEditor, boolean_editor,
24  StringChoiceEditor, PreferencesColorPicker)
25 from ..widgets import Label
26 from .managesettingsdialog import SaveLoadSettings
27 from ..context import IS_WINDOWS
28 
29 try: # import installed version first
30  from pygments.lexers import robotframework as robotframeworklexer
31 except ImportError: # Pygments is not installed
32  robotframeworklexer = None
33 
34 ID_SAVELOADSETTINGS = wx.NewId()
35 ID_LOAD = 5551
36 ID_SAVE = 5552
37 ID_CANCEL = -1
38 
39 from functools import lru_cache
40 
41 @lru_cache(maxsize=2)
42 
43 def ReadFonts(fixed=False):
44  f = wx.FontEnumerator()
45  f.EnumerateFacenames()
46  names = f.GetFacenames(fixedWidthOnly=fixed)
47  names = [n for n in names if not n.startswith('@')]
48  names.sort()
49  return names
50 
51 
53 
54  def __init__(self, settings, *args, **kwargs):
55  super(EditorPreferences, self).__init__(*args, **kwargs)
56  self._settings_settings = settings
57  self._color_pickers_color_pickers = []
58 
59  # what would make this UI much more usable is if there were a
60  # preview window in the dialog that showed all the colors. I
61  # don't have the time to do that right now, so this will have
62  # to suffice.
63 
64  font_editor = self._create_font_editor_create_font_editor()
65  colors_sizer = self.create_colors_sizercreate_colors_sizer()
66  main_sizer = wx.FlexGridSizer(rows=6, cols=1, vgap=10, hgap=10)
67  buttons_sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
68  reset = wx.Button(self, wx.ID_ANY, 'Reset colors to default')
69  saveloadsettings = wx.Button(self, ID_SAVELOADSETTINGS, 'Save or Load settings')
70  main_sizer.Add(font_editor)
71  main_sizer.Add(colors_sizer)
72  buttons_sizer.Add(reset)
73  buttons_sizer.AddSpacer(10)
74  buttons_sizer.Add(saveloadsettings)
75  main_sizer.Add(buttons_sizer)
76  self.SetSizer(main_sizer)
77  self.Bind(wx.EVT_BUTTON, self.OnResetOnReset)
78  self.Bind(wx.EVT_BUTTON, self.OnSaveLoadSettingsOnSaveLoadSettings)
79 
80  def OnSaveLoadSettings(self, event):
81  raise NotImplementedError('Implement me')
82 
83  def OnReset(self, event):
84  defaults = self._read_defaults_read_defaults()
85  for picker in self._color_pickers_color_pickers:
86  picker.SetColour(defaults[picker.key])
87 
88  def _read_defaults(self, plugin=False):
89  settings = [s.strip() for s in open(self._get_path_get_path(), 'r').readlines()]
90  name = ('[[%s]]' if plugin else '[%s]') % self.name
91  start_index = settings.index(name) + 1
92  defaults = {}
93  for line in settings[start_index:]:
94  if line.startswith('['):
95  break
96  if not line:
97  continue
98  key, value = [s.strip().strip('\'') for s in line.split("=")]
99  defaults[key] = value
100  return defaults
101 
102  def _get_path(self):
103  return join(dirname(abspath(__file__)), 'settings.cfg')
104 
107  self._settings_settings, 'font size', 'Font Size',
108  [str(i) for i in range(8, 16)])
109  sizer = wx.FlexGridSizer(rows=3, cols=2, vgap=10, hgap=30)
110  l_size = f.label(self)
111  if IS_WINDOWS:
112  background_color = Colour("light gray")
113  foreground_color = Colour("black")
114  l_size.SetBackgroundColour(background_color)
115  l_size.SetOwnBackgroundColour(background_color)
116  l_size.SetForegroundColour(foreground_color)
117  l_size.SetOwnForegroundColour(foreground_color)
118  sizer.AddMany([l_size, f.chooser(self)])
119  fixed_font = False
120  if 'zoom factor' in self._settings_settings:
121  z = SpinChoiceEditor(
122  self._settings_settings, 'zoom factor', 'Zoom Factor', (-10, 20))
123  l_zoom = z.label(self)
124  if IS_WINDOWS:
125  l_zoom.SetForegroundColour(foreground_color)
126  l_zoom.SetBackgroundColour(background_color)
127  l_zoom.SetOwnBackgroundColour(background_color)
128  l_zoom.SetOwnForegroundColour(foreground_color)
129  sizer.AddMany([l_zoom, z.chooser(self)])
130  if 'fixed font' in self._settings_settings:
131  l_ff, editor = boolean_editor(self, self._settings_settings, 'fixed font', 'Use fixed width font')
132  if IS_WINDOWS:
133  l_ff.SetForegroundColour(foreground_color)
134  l_ff.SetBackgroundColour(background_color)
135  l_ff.SetOwnBackgroundColour(background_color)
136  l_ff.SetOwnForegroundColour(foreground_color)
137  sizer.AddMany([l_ff, editor])
138  fixed_font = self._settings_settings['fixed font']
139  if 'font face' in self._settings_settings:
140  s = StringChoiceEditor(self._settings_settings, 'font face', 'Font Face', ReadFonts(fixed_font))
141  l_font = s.label(self)
142  if IS_WINDOWS:
143  l_font.SetForegroundColour(foreground_color)
144  l_font.SetBackgroundColour(background_color)
145  l_font.SetOwnBackgroundColour(background_color)
146  l_font.SetOwnForegroundColour(foreground_color)
147  sizer.AddMany([l_font, s.chooser(self)])
148  return sizer
149 
151  raise NotImplementedError('Implement me')
152 
153 
155  location = ("Text Editor",)
156  title = "Text Editor Settings"
157  name = "Text Edit"
158 
159  def __init__(self, settings, *args, **kwargs):
160  super(TextEditorPreferences, self).__init__(
161  settings[self.namename], *args, **kwargs)
162 
164  container = wx.GridBagSizer()
165  column = 0
166  row = 0
167  if robotframeworklexer:
168  settings = (
169  ('argument', 'Argument foreground'),
170  ('comment', 'Comment foreground'),
171  ('error', 'Error foreground'),
172  ('gherkin', 'Gherkin keyword foreground'),
173  ('heading', 'Heading foreground'),
174  ('import', 'Import foreground'),
175  ('variable', 'Variable foreground'),
176  ('tc_kw_name', 'Keyword definition foreground'),
177  ('separator', 'Separator'),
178  ('setting', 'Setting foreground'),
179  ('syntax', 'Syntax characters'),
180  ('background', 'Text background'),
181  )
182  else:
183  settings = (
184  ('setting', 'Text foreground'),
185  ('background', 'Text background'),
186  )
187  if IS_WINDOWS:
188  background_color = Colour("light gray")
189  foreground_color = Colour("black")
190  for settings_key, label_text in settings:
191  if column == 4:
192  column = 0
193  row += 1
194  label = wx.StaticText(self, wx.ID_ANY, label_text)
195  if IS_WINDOWS:
196  label.SetForegroundColour(foreground_color)
197  label.SetBackgroundColour(background_color)
198  label.SetOwnBackgroundColour(background_color)
199  label.SetOwnForegroundColour(foreground_color)
200  button = PreferencesColorPicker(
201  self, wx.ID_ANY, self._settings_settings, settings_key)
202  container.Add(button, (row, column),
203  flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4)
204  self._color_pickers_color_pickers.append(button)
205  column += 1
206  container.Add(label, (row, column),
207  flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=8)
208  column += 1
209  return container
210 
211  def OnSaveLoadSettings(self, event):
212  if event.GetId() != ID_SAVELOADSETTINGS:
213  event.Skip()
214  return
215  save_settings_dialog = SaveLoadSettings(self, self._settings_settings)
216  save_settings_dialog.CenterOnParent()
217  value = save_settings_dialog.ShowModal()
218  # print(f"DEBUG: Value returned by SaveLoadSettings: {value}")
219  for picker in self._color_pickers_color_pickers:
220  picker.SetColour(self._settings_settings[picker.key])
221 
222  def OnReset(self, event):
223  defaults = self._read_defaults_read_defaults()
224  for picker in self._color_pickers_color_pickers:
225  picker.SetColour(defaults[picker.key])
226 
227 
229  location = ("Grid Editor",)
230  title = "Grid Editor Settings"
231  name = "Grid"
232 
233  def __init__(self, settings, *args, **kwargs):
234  super(GridEditorPreferences, self).__init__(
235  settings[self.namename], *args, **kwargs)
236  self.Sizer.Add(self._create_grid_config_editor_create_grid_config_editor())
237 
239  settings = self._settings_settings
240  sizer = wx.FlexGridSizer(rows=6, cols=2, vgap=10, hgap=10)
241  l_col_size = self._label_for_label_for('Default column size')
242  if IS_WINDOWS:
243  background_color = Colour("light gray")
244  foreground_color = Colour("black")
245  l_col_size.SetForegroundColour(foreground_color)
246  l_col_size.SetBackgroundColour(background_color)
247  l_col_size.SetOwnBackgroundColour(background_color)
248  l_col_size.SetOwnForegroundColour(foreground_color)
249  sizer.Add(l_col_size)
250  sizer.Add(self._number_editor_number_editor(settings, 'col size'))
251  l_auto_size, editor = boolean_editor(self, settings, 'auto size cols', 'Auto size columns')
252  if IS_WINDOWS:
253  l_auto_size.SetForegroundColour(foreground_color)
254  l_auto_size.SetBackgroundColour(background_color)
255  l_auto_size.SetOwnBackgroundColour(background_color)
256  l_auto_size.SetOwnForegroundColour(foreground_color)
257  sizer.AddMany([l_auto_size, editor])
258  l_max_size = self._label_for_label_for('Max column size\n(applies when auto size is on)')
259  if IS_WINDOWS:
260  l_max_size.SetForegroundColour(foreground_color)
261  l_max_size.SetBackgroundColour(background_color)
262  l_max_size.SetOwnBackgroundColour(background_color)
263  l_max_size.SetOwnForegroundColour(foreground_color)
264  sizer.Add(l_max_size)
265  sizer.Add(self._number_editor_number_editor(settings, 'max col size'))
266  l_word_wrap, editor = boolean_editor(self, settings, 'word wrap', 'Word wrap and auto size rows')
267  if IS_WINDOWS:
268  l_word_wrap.SetForegroundColour(foreground_color)
269  l_word_wrap.SetBackgroundColour(background_color)
270  l_word_wrap.SetOwnBackgroundColour(background_color)
271  l_word_wrap.SetOwnForegroundColour(foreground_color)
272  sizer.AddMany([l_word_wrap, editor])
273  return sizer
274 
275  def _label_for(self, name):
276  label = ('%s: ' % name).capitalize()
277  return Label(self, label=label)
278 
279  def _number_editor(self, settings, name):
280  initial_value = settings[name]
281  editor = NumCtrl(self, value=initial_value, integerWidth=3, allowNone=True)
282  """
283  editor.SetBackgroundColour(Colour(200, 222, 40))
284  editor.SetOwnBackgroundColour(Colour(200, 222, 40))
285  editor.SetForegroundColour(Colour(7, 0, 70))
286  editor.SetOwnForegroundColour(Colour(7, 0, 70))
287  """
288  editor.Bind(wx.EVT_TEXT, lambda evt: self._set_value_set_value(editor, name))
289  return editor
290 
291  def _set_value(self, editor, name):
292  # Guard against dead object
293  if editor:
294  value = editor.GetValue()
295  if value is not None:
296  self._settings_settings.set(name, int(value))
297 
299  colors_sizer = wx.GridBagSizer()
300  self._create_foreground_pickers_create_foreground_pickers(colors_sizer)
301  self._create_background_pickers_create_background_pickers(colors_sizer)
302  return colors_sizer
303 
304  def _create_foreground_pickers(self, colors_sizer):
305  row = 0
306  for key, label in (
307  ('text user keyword', 'User Keyword Foreground'),
308  ('text library keyword', 'Library Keyword Foreground'),
309  ('text variable', 'Variable Foreground'),
310  ('text unknown variable', 'Unknown Variable Foreground'),
311  ('text commented', 'Comments Foreground'),
312  ('text string', 'Default Foreground'),
313  ('text empty', 'Empty Foreground'),
314  ):
315  lbl = wx.StaticText(self, wx.ID_ANY, label)
316  if IS_WINDOWS:
317  background_color = Colour("light gray")
318  foreground_color = Colour("black")
319  lbl.SetForegroundColour(foreground_color)
320  lbl.SetBackgroundColour(background_color)
321  lbl.SetOwnBackgroundColour(background_color)
322  lbl.SetOwnForegroundColour(foreground_color)
324  self, wx.ID_ANY, self._settings_settings, key)
325  self._color_pickers_color_pickers.append(btn)
326  colors_sizer.Add(btn, (row, 2),
327  flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4)
328  colors_sizer.Add(lbl, (row, 3),
329  flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=4)
330  row += 1
331 
332  def _create_background_pickers(self, colors_sizer):
333  row = 0
334  if IS_WINDOWS:
335  background_color = Colour("light gray")
336  foreground_color = Colour("black")
337  for key, label in (
338  ('background assign', 'Variable Background'),
339  ('background keyword', 'Keyword Background'),
340  ('background mandatory', 'Mandatory Field Background'),
341  ('background optional', 'Optional Field Background'),
342  ('background must be empty', 'Mandatory Empty Field Background'),
343  ('background unknown', 'Unknown Background'),
344  ('background error', 'Error Background'),
345  ('background highlight', 'Highlight Background')
346  ):
347  lbl = wx.StaticText(self, wx.ID_ANY, label)
348  if IS_WINDOWS:
349  lbl.SetForegroundColour(foreground_color)
350  lbl.SetBackgroundColour(background_color)
351  lbl.SetOwnBackgroundColour(background_color)
352  lbl.SetOwnForegroundColour(foreground_color)
354  self, wx.ID_ANY, self._settings_settings, key)
355  self._color_pickers_color_pickers.append(btn)
356  colors_sizer.Add(btn, (row, 0),
357  flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4)
358  colors_sizer.Add(lbl, (row, 1),
359  flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=4)
360  row += 1
361 
362  def OnSaveLoadSettings(self, event):
363  if event.GetId() != ID_SAVELOADSETTINGS:
364  event.Skip()
365  return
366  save_settings_dialog = SaveLoadSettings(self, self._settings_settings)
367  save_settings_dialog.CenterOnParent()
368  value = save_settings_dialog.ShowModal()
369  # print(f"DEBUG: Value returned by SaveLoadSettings: {value}")
370  for picker in self._color_pickers_color_pickers:
371  picker.SetColour(self._settings_settings[picker.key])
372 
373 
375  location = ("Test Runner",)
376  title = "Test Runner Settings"
377  name = "Test Runner"
378 
379  def __init__(self, settings, *args, **kwargs):
380  super(TestRunnerPreferences, self).__init__(
381  settings['Plugins'][self.namename], *args, **kwargs)
382  self.Sizer.Add(self._create_test_runner_config_editor_create_test_runner_config_editor())
383 
385  self._settings_settings.get('confirm run', True)
386  self._settings_settings.get('use colors', False)
387  settings = self._settings_settings
388  sizer = wx.FlexGridSizer(rows=6, cols=2, vgap=10, hgap=10)
389  from sys import platform
390  if platform.endswith('win32'):
391  add_colors = "-C ansi"
392  else:
393  add_colors = "-C on"
394  l_usecolor, usecolor = boolean_editor(self, settings, 'use colors',
395  f"Shows console colors set by {add_colors} ")
396  l_confirm, editor = boolean_editor(self, settings, 'confirm run',
397  'Asks for confirmation to run all tests if none selected ')
398  if IS_WINDOWS:
399  background_color = Colour("light gray")
400  foreground_color = Colour("black")
401  l_confirm.SetForegroundColour(foreground_color)
402  l_confirm.SetBackgroundColour(background_color)
403  l_confirm.SetOwnBackgroundColour(background_color)
404  l_confirm.SetOwnForegroundColour(foreground_color)
405  l_usecolor.SetForegroundColour(foreground_color)
406  l_usecolor.SetBackgroundColour(background_color)
407  l_usecolor.SetOwnBackgroundColour(background_color)
408  l_usecolor.SetOwnForegroundColour(foreground_color)
409  sizer.AddMany([l_usecolor, usecolor])
410  sizer.AddMany([l_confirm, editor])
411  return sizer
412 
414  container = wx.GridBagSizer()
415  row = 0
416  column = 0
417  if IS_WINDOWS:
418  background_color = Colour("light gray")
419  foreground_color = Colour("black")
420  for settings_key, label_text in (
421  ('foreground', 'Text foreground'),
422  ('background', 'Text background'),
423  ('error', 'Error foreground'),
424  ('fail color', 'Fail foreground'),
425  ('pass color', 'Pass foreground'),
426  ('skip color', 'Skip foreground'),
427  ):
428  if column == 4:
429  column = 0
430  row += 1
431  label = wx.StaticText(self, wx.ID_ANY, label_text)
432  if IS_WINDOWS:
433  label.SetForegroundColour(foreground_color)
434  label.SetBackgroundColour(background_color)
435  label.SetOwnBackgroundColour(background_color)
436  label.SetOwnForegroundColour(foreground_color)
437  button = PreferencesColorPicker(
438  self, wx.ID_ANY, self._settings_settings, settings_key)
439  container.Add(button, (row, column),
440  flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4)
441  self._color_pickers_color_pickers.append(button)
442  column += 1
443  container.Add(label, (row, column),
444  flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=8)
445  column += 1
446  return container
447 
448  def OnSaveLoadSettings(self, event):
449  if event.GetId() != ID_SAVELOADSETTINGS:
450  event.Skip()
451  return
452  save_settings_dialog = SaveLoadSettings(self, self._settings_settings)
453  save_settings_dialog.CenterOnParent()
454  value = save_settings_dialog.ShowModal()
455  # print(f"DEBUG: Value returned by SaveLoadSettings: {value}")
456  for picker in self._color_pickers_color_pickers:
457  picker.SetColour(self._settings_settings[picker.key])
458 
459  def OnReset(self, event):
460  defaults = self._read_defaults_read_defaults(plugin=True)
461  for picker in self._color_pickers_color_pickers:
462  picker.SetColour(defaults[picker.key])
def __init__(self, settings, *args, **kwargs)
Definition: editors.py:54
def _read_defaults(self, plugin=False)
Definition: editors.py:88
def _create_foreground_pickers(self, colors_sizer)
Definition: editors.py:304
def _create_background_pickers(self, colors_sizer)
Definition: editors.py:332
def __init__(self, settings, *args, **kwargs)
Definition: editors.py:233
def __init__(self, settings, *args, **kwargs)
Definition: editors.py:379
def __init__(self, settings, *args, **kwargs)
Definition: editors.py:159
A colored button that opens a color picker dialog.
Base class for all preference panels used by PreferencesDialog.
def abspath(path, case_normalize=False)
Replacement for os.path.abspath with some enhancements and bug fixes.
Definition: robotpath.py:87
def ReadFonts(fixed=False)
Returns list with fixed width fonts.
Definition: editors.py:43
def boolean_editor(parent, settings, name, label, help='')