Coverage for src/robotide/preferences/editors.py: 18%

294 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-06 10:40 +0100

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 

16from os.path import abspath, dirname, join 1ab

17import builtins 1ab

18import wx 1ab

19from wx.lib.masked import NumCtrl 1ab

20 

21from .settings import RideSettings 1ab

22from ..ui import preferences_dialogs as pdiag 1ab

23from robotide.ui.preferences_dialogs import PreferencesPanel 1ab

24 

25from ..widgets import Label 1ab

26from .managesettingsdialog import SaveLoadSettings 1ab

27from functools import lru_cache 1ab

28 

29try: # import installed version first 1ab

30 from pygments.lexers import robotframework as robotframeworklexer 1ab

31except ImportError: # Pygments is not installed 

32 robotframeworklexer = None 

33 

34_ = wx.GetTranslation # To keep linter/code analyser happy 1ab

35builtins.__dict__['_'] = wx.GetTranslation 1ab

36 

37 

38ID_SAVELOADSETTINGS = wx.NewIdRef() 1ab

39ID_LOAD = 5551 1ab

40ID_SAVE = 5552 1ab

41ID_CANCEL = -1 1ab

42TEXT_BACKGROUND = _('Text background') 1ab

43LIGHT_GRAY = 'light gray' 1ab

44FIXED_FONT = 'fixed font' 1ab

45 

46 

47@lru_cache(maxsize=2) 1ab

48def read_fonts(fixed=False): 1ab

49 """Returns list with fixed width fonts""" 

50 f = wx.FontEnumerator() 

51 f.EnumerateFacenames() 

52 names = f.GetFacenames(fixedWidthOnly=fixed) 

53 names = [n for n in names if not n.startswith('@')] 

54 names.sort() 

55 return names 

56 

57 

58def set_colors(element, bk_color, fg_color): 1ab

59 element.SetBackgroundColour(bk_color) 

60 # element.SetOwnBackgroundColour(bk_color) 

61 element.SetForegroundColour(fg_color) 

62 # element.SetOwnForegroundColour(fg_color) 

63 

64 

65class EditorPreferences(PreferencesPanel): 1ab

66 

67 def __init__(self, settings, *args, **kwargs): 1ab

68 super(EditorPreferences, self).__init__(*args, **kwargs) 

69 self._settings = settings 

70 self._color_pickers = [] 

71 self.name = None 

72 

73 self._gsettings = RideSettings() 

74 self.settings = self._gsettings['General'] 

75 

76 # what would make this UI much more usable is if there were a 

77 # preview window in the dialog that showed all the colors. I 

78 # don't have the time to do that right now, so this will have 

79 # to suffice. 

80 

81 font_editor = self._create_font_editor() 

82 colors_sizer = self.create_colors_sizer() 

83 main_sizer = wx.FlexGridSizer(rows=6, cols=1, vgap=10, hgap=10) 

84 buttons_sizer = wx.BoxSizer(orient=wx.HORIZONTAL) 

85 reset = wx.Button(self, wx.ID_ANY, _('Reset colors to default')) 

86 saveloadsettings = wx.Button(self, ID_SAVELOADSETTINGS, _('Save or Load settings')) 

87 set_colors(reset, self.secondary_background_color, self.secondary_foreground_color) 

88 set_colors(saveloadsettings, self.secondary_background_color, self.secondary_foreground_color) 

89 main_sizer.Add(font_editor) 

90 main_sizer.Add(colors_sizer) 

91 buttons_sizer.Add(reset) 

92 buttons_sizer.AddSpacer(10) 

93 buttons_sizer.Add(saveloadsettings) 

94 main_sizer.Add(buttons_sizer) 

95 self.SetSizer(main_sizer) 

96 self.Bind(wx.EVT_BUTTON, self.on_reset) 

97 self.Bind(wx.EVT_BUTTON, self.on_save_load_settings) 

98 

99 def on_save_load_settings(self, event): 1ab

100 raise NotImplementedError('Implement me') 

101 

102 def on_reset(self, event): 1ab

103 if not self.name: 

104 self.name = "Grid" 

105 defaults = self._read_defaults() 

106 for picker in self._color_pickers: 

107 picker.SetColour(defaults[picker.key]) 

108 

109 def _read_defaults(self, plugin=False): 1ab

110 settings = [s.strip() for s in open(self._get_path(), 'r').readlines()] 

111 name = ('[[%s]]' if plugin else '[%s]') % self.name 

112 start_index = settings.index(name) + 1 

113 defaults = {} 

114 for line in settings[start_index:]: 

115 if line.startswith('['): 

116 break 

117 if not line or line.startswith(';') or line.startswith('#'): 

118 continue 

119 key, value = [s.strip().strip('\'') for s in line.split("=")] 

120 defaults[key] = value 

121 return defaults 

122 

123 @staticmethod 1ab

124 def _get_path(): 1ab

125 return join(dirname(abspath(__file__)), 'settings.cfg') 

126 

127 def _create_font_editor(self): 1ab

128 f = pdiag.IntegerChoiceEditor( 

129 self._settings, 'font size', _('Font Size'), 

130 [str(i) for i in range(8, 16)]) 

131 sizer = wx.FlexGridSizer(rows=4, cols=2, vgap=10, hgap=30) 

132 l_size = f.label(self) 

133 set_colors(l_size, self.background_color, self.foreground_color) 

134 sizer.AddMany([l_size, f.chooser(self)]) 

135 fixed_font = False 

136 if 'zoom factor' in self._settings: 

137 z = pdiag.SpinChoiceEditor( 

138 self._settings, 'zoom factor', _('Zoom Factor'), (-10, 20)) 

139 l_zoom = z.label(self) 

140 set_colors(l_zoom, self.background_color, self.foreground_color) 

141 sizer.AddMany([l_zoom, z.chooser(self)]) 

142 if FIXED_FONT in self._settings: 

143 l_ff, editor = pdiag.boolean_editor(self, self._settings, FIXED_FONT, _('Use fixed width font')) 

144 set_colors(l_ff, self.background_color, self.foreground_color) 

145 sizer.AddMany([l_ff, editor]) 

146 fixed_font = self._settings[FIXED_FONT] 

147 if 'font face' in self._settings: 

148 s = pdiag.StringChoiceEditor(self._settings, 'font face', _('Font Face'), read_fonts(fixed_font)) 

149 l_font = s.label(self) 

150 set_colors(l_font, self.background_color, self.foreground_color) 

151 sizer.AddMany([l_font, s.chooser(self)]) 

152 return sizer 

153 

154 def create_colors_sizer(self): 1ab

155 raise NotImplementedError('Implement me') 

156 

157 

158class TextEditorPreferences(EditorPreferences): 1ab

159 location = (_("Text Editor"),) 1ab

160 

161 def __init__(self, settings, *args, **kwargs): 1ab

162 self.location = (_("Text Editor"),) 

163 self.title = _("Text Editor Settings") 

164 self.name = "Text Edit" 

165 super(TextEditorPreferences, self).__init__(settings[self.name], *args, **kwargs) 

166 self.Sizer.Add(self._create_text_config_editor()) 

167 

168 def create_colors_sizer(self): 1ab

169 container = wx.GridBagSizer() 

170 column = 0 

171 row = 0 

172 if robotframeworklexer: 

173 settings = ( 

174 ('argument', _('Argument foreground')), 

175 ('comment', _('Comment foreground')), 

176 ('error', _('Error foreground')), 

177 ('gherkin', _('Gherkin keyword foreground')), 

178 ('heading', _('Heading foreground')), 

179 ('import', _('Import foreground')), 

180 ('variable', _('Variable foreground')), 

181 ('tc_kw_name', _('Keyword definition foreground')), 

182 ('keyword', _('Keyword call foreground')), 

183 ('separator', _('Separator')), 

184 ('setting', _('Setting foreground')), 

185 ('syntax', _('Syntax characters')), 

186 ('background', TEXT_BACKGROUND), 

187 ) 

188 else: 

189 settings = ( 

190 ('setting', _('Text foreground')), 

191 ('background', TEXT_BACKGROUND), 

192 ) 

193 for settings_key, label_text in settings: 

194 if column == 4: 

195 column = 0 

196 row += 1 

197 label = wx.StaticText(self, wx.ID_ANY, label_text) 

198 set_colors(label, self.background_color, self.foreground_color) 

199 button = pdiag.PreferencesColorPicker( 

200 self, wx.ID_ANY, self._settings, settings_key) 

201 container.Add(button, (row, column), 

202 flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) 

203 self._color_pickers.append(button) 

204 column += 1 

205 container.Add(label, (row, column), 

206 flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=8) 

207 column += 1 

208 return container 

209 

210 def on_save_load_settings(self, event): 1ab

211 if event.GetId() != ID_SAVELOADSETTINGS: 

212 event.Skip() 

213 return 

214 save_settings_dialog = SaveLoadSettings(self, self._settings) 

215 save_settings_dialog.CenterOnParent() 

216 save_settings_dialog.ShowModal() 

217 for picker in self._color_pickers: 

218 picker.SetColour(self._settings[picker.key]) 

219 

220 def on_reset(self, event): 1ab

221 if not self.name: 

222 self.name = "Text Edit" 

223 defaults = self._read_defaults() 

224 for picker in self._color_pickers: 

225 picker.SetColour(defaults[picker.key]) 

226 

227 def _create_text_config_editor(self): 1ab

228 settings = self._settings 

229 sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=10, hgap=10) 

230 l_auto_suggest, editor = pdiag.boolean_editor(self, settings, 'enable auto suggestions', 

231 _('Enable auto suggestions')) 

232 set_colors(l_auto_suggest, self.background_color, self.foreground_color) 

233 sizer.AddMany([l_auto_suggest, editor]) 

234 return sizer 

235 

236 

237class GridEditorPreferences(EditorPreferences): 1ab

238 location = (_("Grid Editor"),) 1ab

239 

240 def __init__(self, settings, *args, **kwargs): 1ab

241 self.location = (_("Grid Editor"),) 

242 self.title = _("Grid Editor Settings") 

243 self.name = "Grid" 

244 super(GridEditorPreferences, self).__init__( 

245 settings[self.name], *args, **kwargs) 

246 self.Sizer.Add(self._create_grid_config_editor()) 

247 

248 def _create_grid_config_editor(self): 1ab

249 settings = self._settings 

250 sizer = wx.FlexGridSizer(rows=6, cols=2, vgap=10, hgap=10) 

251 l_col_size = self._label_for(_('Default column size')) 

252 set_colors(l_col_size, self.background_color, self.foreground_color) 

253 sizer.Add(l_col_size) 

254 sizer.Add(self._number_editor(settings, 'col size')) 

255 l_auto_size, editor = pdiag.boolean_editor(self, settings, 'auto size cols', _('Auto size columns')) 

256 set_colors(l_auto_size, self.background_color, self.foreground_color) 

257 sizer.AddMany([l_auto_size, editor]) 

258 l_max_size = self._label_for(_('Max column size\n(applies when auto size is on)')) 

259 set_colors(l_max_size, self.background_color, self.foreground_color) 

260 sizer.Add(l_max_size) 

261 sizer.Add(self._number_editor(settings, 'max col size')) 

262 l_word_wrap, editor = pdiag.boolean_editor(self, settings, 'word wrap', _('Word wrap and auto size rows')) 

263 set_colors(l_word_wrap, self.background_color, self.foreground_color) 

264 sizer.AddMany([l_word_wrap, editor]) 

265 l_auto_suggest, editor = pdiag.boolean_editor(self, settings, 'enable auto suggestions', 

266 _('Enable auto suggestions')) 

267 set_colors(l_auto_suggest, self.background_color, self.foreground_color) 

268 sizer.AddMany([l_auto_suggest, editor]) 

269 return sizer 

270 

271 def _label_for(self, name): 1ab

272 label = ('%s: ' % name).capitalize() 

273 return Label(self, label=label) 

274 

275 def _number_editor(self, settings, name): 1ab

276 initial_value = settings[name] 

277 editor = NumCtrl(self, value=initial_value, integerWidth=3, allowNone=True) 

278 set_colors(editor, self.background_color, self.foreground_color) 

279 editor.Bind(wx.EVT_TEXT, lambda evt: self._set_value(editor, name)) 

280 return editor 

281 

282 def _set_value(self, editor, name): 1ab

283 # Guard against dead object 

284 if editor: 

285 value = editor.GetValue() 

286 if value is not None: 

287 self._settings.set(name, int(value)) 

288 

289 def create_colors_sizer(self): 1ab

290 colors_sizer = wx.GridBagSizer() 

291 self._create_foreground_pickers(colors_sizer) 

292 self._create_background_pickers(colors_sizer) 

293 return colors_sizer 

294 

295 def _create_foreground_pickers(self, colors_sizer): 1ab

296 row = 0 

297 for key, label in ( 

298 ('text user keyword', _('User Keyword Foreground')), 

299 ('text library keyword', _('Library Keyword Foreground')), 

300 ('text variable', _('Variable Foreground')), 

301 ('text unknown variable', _('Unknown Variable Foreground')), 

302 ('text commented', _('Comments Foreground')), 

303 ('text string', _('Default Foreground')), 

304 ('text empty', _('Empty Foreground')), 

305 ): 

306 lbl = wx.StaticText(self, wx.ID_ANY, label) 

307 set_colors(lbl, self.background_color, self.foreground_color) 

308 btn = pdiag.PreferencesColorPicker( 

309 self, wx.ID_ANY, self._settings, key) 

310 self._color_pickers.append(btn) 

311 colors_sizer.Add(btn, (row, 2), 

312 flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) 

313 colors_sizer.Add(lbl, (row, 3), 

314 flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=4) 

315 row += 1 

316 

317 def _create_background_pickers(self, colors_sizer): 1ab

318 row = 0 

319 for key, label in ( 

320 ('background assign', _('Variable Background')), 

321 ('background keyword', _('Keyword Background')), 

322 ('background mandatory', _('Mandatory Field Background')), 

323 ('background optional', _('Optional Field Background')), 

324 ('background must be empty', _('Mandatory Empty Field Background')), 

325 ('background unknown', _('Unknown Background')), 

326 ('background error', _('Error Background')), 

327 ('background highlight', _('Highlight Background')) 

328 ): 

329 lbl = wx.StaticText(self, wx.ID_ANY, label) 

330 set_colors(lbl, self.background_color, self.foreground_color) 

331 btn = pdiag.PreferencesColorPicker( 

332 self, wx.ID_ANY, self._settings, key) 

333 self._color_pickers.append(btn) 

334 colors_sizer.Add(btn, (row, 0), 

335 flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) 

336 colors_sizer.Add(lbl, (row, 1), 

337 flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=4) 

338 row += 1 

339 

340 def on_save_load_settings(self, event): 1ab

341 if event.GetId() != ID_SAVELOADSETTINGS: 

342 event.Skip() 

343 return 

344 save_settings_dialog = SaveLoadSettings(self, self._settings) 

345 save_settings_dialog.CenterOnParent() 

346 save_settings_dialog.ShowModal() 

347 for picker in self._color_pickers: 

348 picker.SetColour(self._settings[picker.key]) 

349 

350 

351class TestRunnerPreferences(EditorPreferences): 1ab

352 location = (_("Test Runner"),) 1ab

353 

354 def __init__(self, settings, *args, **kwargs): 1ab

355 self.location = (_("Test Runner"),) 

356 self.title = _("Test Runner Settings") 

357 self.name = "Test Runner" 

358 super(TestRunnerPreferences, self).__init__( 

359 settings['Plugins'][self.name], *args, **kwargs) 

360 help_color = wx.StaticText(self, wx.ID_ANY, _("Colors will be active after next RIDE restart.")) 

361 set_colors(help_color, self.background_color, self.foreground_color) 

362 self.Sizer.Add(help_color) 

363 self.Sizer.Add(self._create_test_runner_config_editor()) 

364 

365 def _create_test_runner_config_editor(self): 1ab

366 self._settings.get('confirm run', True) 

367 self._settings.get('use colors', False) 

368 settings = self._settings 

369 sizer = wx.FlexGridSizer(rows=6, cols=2, vgap=10, hgap=10) 

370 from sys import platform 

371 if platform.endswith('win32'): 

372 add_colors = "-C ansi" 

373 else: 

374 add_colors = "-C on" 

375 l_usecolor, usecolor = pdiag.boolean_editor(self, settings, 'use colors', 

376 f"{_('Shows console colors set by')} {add_colors} ") 

377 l_confirm, editor = pdiag.boolean_editor(self, settings, 'confirm run', 

378 _('Asks for confirmation to run all tests if none selected ')) 

379 set_colors(l_confirm, self.background_color, self.foreground_color) 

380 set_colors(l_usecolor, self.background_color, self.foreground_color) 

381 sizer.AddMany([l_usecolor, usecolor]) 

382 sizer.AddMany([l_confirm, editor]) 

383 return sizer 

384 

385 def create_colors_sizer(self): 1ab

386 container = wx.GridBagSizer() 

387 row = 0 

388 column = 0 

389 for settings_key, label_text in ( 

390 ('foreground', _('Text foreground')), 

391 ('background', TEXT_BACKGROUND), 

392 ('error', _('Error foreground')), 

393 ('fail color', _('Fail foreground')), 

394 ('pass color', _('Pass foreground')), 

395 ('skip color', _('Skip foreground')), 

396 ): 

397 if column == 4: 

398 column = 0 

399 row += 1 

400 label = wx.StaticText(self, wx.ID_ANY, label_text) 

401 set_colors(label, self.background_color, self.foreground_color) 

402 button = pdiag.PreferencesColorPicker( 

403 self, wx.ID_ANY, self._settings, settings_key) 

404 container.Add(button, (row, column), 

405 flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) 

406 self._color_pickers.append(button) 

407 column += 1 

408 container.Add(label, (row, column), 

409 flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=8) 

410 column += 1 

411 return container 

412 

413 def on_save_load_settings(self, event): 1ab

414 if event.GetId() != ID_SAVELOADSETTINGS: 

415 event.Skip() 

416 return 

417 save_settings_dialog = SaveLoadSettings(self, self._settings) 

418 save_settings_dialog.CenterOnParent() 

419 save_settings_dialog.ShowModal() 

420 for picker in self._color_pickers: 

421 picker.SetColour(self._settings[picker.key]) 

422 

423 def on_reset(self, event): 1ab

424 if not self.name: 

425 self.name = "Test Runner" 

426 defaults = self._read_defaults(plugin=True) 

427 for picker in self._color_pickers: 

428 picker.SetColour(defaults[picker.key])