Coverage for src/robotide/preferences/general.py: 40%

201 statements  

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

1# Copyright 2020- Robot Framework Foundation 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15from functools import lru_cache 1bc

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

17import builtins 1bc

18import wx 1bc

19 

20from ..ui.preferences_dialogs import (boolean_editor, PreferencesPanel, IntegerChoiceEditor, SpinChoiceEditor, 1bc

21 StringChoiceEditor, PreferencesColorPicker) 

22from .managesettingsdialog import SaveLoadSettings 1bc

23try: 1bc

24 from robot.conf import languages 1bc

25except ImportError: 

26 languages = None 

27 

28_ = wx.GetTranslation # To keep linter/code analyser happy 1bc

29builtins.__dict__['_'] = wx.GetTranslation 1bc

30 

31ID_APPLY_TO_PANEL = wx.NewIdRef() 1bc

32ID_RESET = wx.NewIdRef() 1bc

33ID_SAVELOADSETTINGS = wx.NewIdRef() 1bc

34ID_LOAD = 5551 1bc

35ID_SAVE = 5552 1bc

36ID_CANCEL = -1 1bc

37LIGHT_GRAY = "light gray" 1bc

38FIXED_FONT = 'fixed font' 1bc

39 

40 

41@lru_cache(maxsize=2) 1bc

42def read_fonts(fixed=False): 1bc

43 """Returns list with fixed width fonts""" 

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 

52@lru_cache(maxsize=2) 1bc

53def read_languages(): 1bc

54 """Returns list with translatqble languages""" 

55 if languages: 

56 from . import Languages 

57 names = [n for n in Languages.names] 

58 else: 

59 names = [('English', 'en'), ('Portuguese', 'pt')] 

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

61 names.sort() 

62 return names 

63 

64 

65def set_colors(element, bk_color, fg_color): 1bc

66 element.SetBackgroundColour(bk_color) 1a

67 # element.SetOwnBackgroundColour(bk_color) 

68 element.SetForegroundColour(fg_color) 1a

69 # element.SetOwnForegroundColour(fg_color) 

70 

71 

72class GeneralPreferences(PreferencesPanel): 1bc

73 

74 def __init__(self, settings, *args, **kwargs): 1bc

75 super(GeneralPreferences, self).__init__(*args, **kwargs) 1a

76 self._settings = settings 1a

77 self._color_pickers = [] 1a

78 self.name = 'General' 1a

79 self._apply_to_panels = self._settings.get('apply to panels', False) 1a

80 self.background_color = self.settings['background'] 1a

81 self.foreground_color = self.settings['foreground'] 1a

82 self.sbackground_color = self.settings['secondary background'] 1a

83 self.sforeground_color = self.settings['secondary foreground'] 1a

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

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

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

87 # to suffice. 

88 

89 # print(f"DEBUG: preferences/general.py GeneralPeferences settings_path={self._settings._default_path}") 

90 ui_language = self._select_ui_language() 1a

91 font_editor = self._create_font_editor() 1a

92 colors_sizer = self.create_colors_sizer() 1a

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

94 buttons_sizer = wx.BoxSizer(orient=wx.HORIZONTAL) 1a

95 reset = wx.Button(self, ID_RESET, _('Reset colors to default')) 1a

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

97 self.cb_apply_to_panels = wx.CheckBox(self, ID_APPLY_TO_PANEL, 1a

98 label=_("Apply to Project and File Explorer panels")) 

99 self.cb_apply_to_panels.Enable() 1a

100 self.cb_apply_to_panels.SetValue(self._apply_to_panels) 1a

101 set_colors(self.cb_apply_to_panels, self.background_color, self.foreground_color) 1a

102 set_colors(reset, self.sbackground_color, self.sforeground_color) 1a

103 set_colors(saveloadsettings, self.sbackground_color, self.sforeground_color) 1a

104 # set_colors(ui_language, Colour(self.color_background), Colour(self.color_foreground)) 

105 main_sizer.Add(font_editor) 1a

106 main_sizer.Add(colors_sizer) 1a

107 main_sizer.Add(self.cb_apply_to_panels) 1a

108 buttons_sizer.Add(reset) 1a

109 buttons_sizer.AddSpacer(10) 1a

110 buttons_sizer.Add(saveloadsettings) 1a

111 main_sizer.Add(buttons_sizer) 1a

112 main_sizer.AddSpacer(10) 1a

113 main_sizer.Add(ui_language) 1a

114 self.SetSizerAndFit(main_sizer) 1a

115 self.Bind(wx.EVT_BUTTON, self.on_reset) 1a

116 self.Bind(wx.EVT_BUTTON, self.on_save_load_settings) 1a

117 self.Bind(wx.EVT_CHECKBOX, self.on_check_box, self.cb_apply_to_panels) 1a

118 

119 def on_check_box(self, event): 1bc

120 self._apply_to_panels = event.IsChecked() 

121 self._settings.set('apply to panels', self._apply_to_panels) 

122 # print(f"DEBUG: Preferences Checkbox set {str(self._apply_to_panels)}") 

123 

124 def on_reset(self, event): 1bc

125 if event.GetId() != ID_RESET: 

126 event.Skip() 

127 return 

128 defaults = self._read_defaults() 

129 for picker in self._color_pickers: 

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

131 # self.Refresh() 

132 

133 def on_save_load_settings(self, event): 1bc

134 if event.GetId() != ID_SAVELOADSETTINGS: 

135 event.Skip() 

136 return 

137 save_settings_dialog = SaveLoadSettings(self, self._settings) # DEBUG self.__class__.__name__ 

138 save_settings_dialog.CenterOnParent() 

139 save_settings_dialog.ShowModal() 

140 # Does not look nice but closes Preferences window, so it comes recolored on next call 

141 # Only working on first use :( 

142 # DEBUG: Only close window when Loading, not when Saving (but return is always 5101) 

143 wx.FindWindowByName(_("RIDE - Preferences")).Close(force=True) 

144 

145 def _reload_settings(self): 1bc

146 import os 

147 from ..context import SETTINGS_DIRECTORY 

148 self._default_path = os.path.join(SETTINGS_DIRECTORY, 'settings.cfg') 

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

150 name = '[General]' 

151 start_index = settings.index(name) + 1 

152 defaults = {} 

153 for line in settings[start_index:]: 

154 if line.startswith('['): 

155 break 

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

157 continue 

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

159 # print(f"DEBUG: Preferences General default value type {type(value)} {value}") 

160 if len(value) > 0 and value[0] == '(' and value[-1] == ')': 

161 from ast import literal_eval as make_tuple 

162 value = make_tuple(value) 

163 defaults[key] = value 

164 self._settings = defaults 

165 

166 for picker in self._color_pickers: 

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

168 self.Refresh(True) 

169 

170 def _read_defaults(self, plugin=False): 1bc

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

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

173 start_index = settings.index(name) + 1 

174 defaults = {} 

175 for line in settings[start_index:]: 

176 if line.startswith('['): 

177 break 

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

179 continue 

180 # print(f"DEBUG: Preferences General RESET default line {line} \nLine Split: {line.split("=")}") 

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

182 # print(f"DEBUG: Preferences General default value type {type(value)} {value}") 

183 if len(value) > 0 and value[0] == '(' and value[-1] == ')': 

184 from ast import literal_eval as make_tuple 

185 value = make_tuple(value) 

186 defaults[key] = value 

187 return defaults 

188 

189 @staticmethod 1bc

190 def _get_path(): 1bc

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

192 

193 def _create_font_editor(self): 1bc

194 f = IntegerChoiceEditor( 1a

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

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

197 sizer = wx.FlexGridSizer(rows=3, cols=2, vgap=10, hgap=30) 1a

198 l_size = f.label(self) 1a

199 set_colors(l_size, self.background_color, self.foreground_color) 1a

200 sizer.AddMany([l_size, f.chooser(self)]) 1a

201 fixed_font = False 1a

202 if 'zoom factor' in self._settings: 202 ↛ 203line 202 didn't jump to line 203 because the condition on line 202 was never true1a

203 z = SpinChoiceEditor( 

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

205 l_zoom = z.label(self) 

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

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

208 if FIXED_FONT in self._settings: 208 ↛ 209line 208 didn't jump to line 209 because the condition on line 208 was never true1a

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

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

211 sizer.AddMany([l_ff, editor]) 

212 fixed_font = self._settings[FIXED_FONT] 

213 if 'font face' in self._settings: 213 ↛ 214line 213 didn't jump to line 214 because the condition on line 213 was never true1a

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

215 l_font = s.label(self) 

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

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

218 sizer.Layout() 1a

219 return sizer 1a

220 

221 def _select_ui_language(self): 1bc

222 sizer = wx.FlexGridSizer(rows=3, cols=2, vgap=10, hgap=30) 1a

223 if 'ui language' in self._settings: 223 ↛ 224line 223 didn't jump to line 224 because the condition on line 223 was never true1a

224 ll = StringChoiceEditor(self._settings, 'ui language', _('Language'), read_languages()) 

225 l_lang = ll.label(self) 

226 set_colors(l_lang, self.background_color, self.foreground_color) 

227 sizer.AddMany([l_lang, ll.chooser(self)]) 

228 sizer.Layout() 1a

229 return sizer 1a

230 

231 def create_colors_sizer(self): 1bc

232 raise NotImplementedError('Implement me') 

233 

234 

235class DefaultPreferences(GeneralPreferences): 1bc

236 location = (_("General"),) 1bc

237 

238 def __init__(self, settings, *args, **kwargs): 1bc

239 self.location = (_("General"),) 

240 self.title = _("General Settings") 

241 self.name = "General" 

242 super(DefaultPreferences, self).__init__(settings[self.name], name_tr=_("General"), *args, **kwargs) 

243 

244 def create_colors_sizer(self): 1bc

245 container = wx.GridBagSizer() 

246 column = 0 

247 row = 0 

248 settings = ( 

249 ('foreground', _('Foreground')), 

250 ('background', _('Background')), 

251 ('secondary foreground', _('Secondary Foreground')), 

252 ('secondary background', _('Secondary Background')), 

253 ('foreground text', _('Text Foreground')), 

254 ('background help', _('Help Background')) 

255 ) 

256 for settings_key, label_text in settings: 

257 if column == 4: 

258 column = 0 

259 row += 1 

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

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

262 button = PreferencesColorPicker( 

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

264 container.Add(button, (row, column), flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) 

265 self._color_pickers.append(button) 

266 column += 1 

267 container.Add(label, (row, column), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=8) 

268 column += 1 

269 return container 

270 

271 def on_reset(self, event): 1bc

272 defaults = self._read_defaults() 

273 for picker in self._color_pickers: 

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

275 # self.Refresh() 

276 wx.FindWindowByName(_("RIDE - Preferences")).Close(force=True)