Coverage for src/robotide/widgets/dialog.py: 52%
156 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
« 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.
16import builtins 1ad
17import webbrowser 1ad
19import wx 1ad
20from wx import html, Colour 1ad
22from . import sizers, ButtonWithHandler 1ad
24_ = wx.GetTranslation # To keep linter/code analyser happy 1ad
25builtins.__dict__['_'] = wx.GetTranslation 1ad
28class HtmlWindow(html.HtmlWindow): 1ad
30 def __init__(self, parent, size=wx.DefaultSize, text=None, color_background=None, color_foreground=None): 1ad
31 html.HtmlWindow.__init__(self, parent, size=size, style=html.HW_DEFAULT_STYLE) 1acghJKLMNObij
32 from ..preferences import RideSettings 1acghJKLMNObij
33 _settings = RideSettings() 1acghJKLMNObij
34 self.general_settings = _settings['General'] 1acghJKLMNObij
35 self.color_background_help = color_background if color_background else self.general_settings['background help'] 1acghJKLMNObij
36 self.color_foreground_text = color_foreground if color_foreground else self.general_settings['foreground text'] 1acghJKLMNObij
37 self.SetBorders(2) 1acghJKLMNObij
38 self.SetStandardFonts(size=9) 1acghJKLMNObij
39 if text: 1acghJKLMNObij
40 self.set_content(text) 1aghbij
41 self.font = self.GetFont() 1acghJKLMNObij
42 self.font.SetFaceName(self.general_settings['font face']) 1acghJKLMNObij
43 self.font.SetPointSize(self.general_settings['font size']) 1acghJKLMNObij
44 self.SetFont(self.font) 1acghJKLMNObij
45 self.Refresh(True) 1acghJKLMNObij
46 self.Bind(wx.EVT_KEY_DOWN, self.on_key_down) 1acghJKLMNObij
47 self.Bind(wx.EVT_CLOSE, self.close) 1acghJKLMNObij
49 def set_content(self, content): 1ad
50 if isinstance(self.color_background_help, tuple): 50 ↛ 51line 50 didn't jump to line 51 because the condition on line 50 was never true1acghbij
51 bgcolor = '#' + ''.join(hex(item)[2:] for item in self.color_background_help)
52 else:
53 bgcolor = self.color_background_help 1acghbij
54 if isinstance(self.color_foreground_text, tuple): 54 ↛ 55line 54 didn't jump to line 55 because the condition on line 54 was never true1acghbij
55 fgcolor = '#' + ''.join(hex(item)[2:] for item in self.color_foreground_text)
56 else:
57 fgcolor = self.color_foreground_text 1acghbij
58 if content.startswith('<table>'): 58 ↛ 59line 58 didn't jump to line 59 because the condition on line 58 was never true1acghbij
59 new_content = content.replace("<table>", f'<div><font color="{fgcolor}"><table>')\
60 .replace("</table>", "</table></font></div>")
61 else:
62 new_content = f'<p><font color="{fgcolor}">' + content + '</font></p>' 1acghbij
63 _content = '<body bgcolor=%s style="color:%s;">%s</body>' % (bgcolor, fgcolor, new_content) 1acghbij
64 self.SetPage(_content) 1acghbij
66 def on_key_down(self, event): 1ad
67 if self._is_copy(event):
68 self._add_selection_to_clipboard()
69 self.Parent.on_key(event)
70 event.Skip()
72 @staticmethod 1ad
73 def _is_copy(event): 1ad
74 return event.GetKeyCode() == ord('C') and event.CmdDown()
76 def _add_selection_to_clipboard(self): 1ad
77 wx.TheClipboard.Open()
78 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText()))
79 wx.TheClipboard.Close()
81 def OnLinkClicked(self, link): # Overrides wx method 1ad
82 webbrowser.open(link.Href)
84 def close(self): 1ad
85 self.Show(False)
86 self.Destroy()
88 def clear(self): 1ad
89 self.SetPage('')
92class RIDEDialog(wx.Dialog): 1ad
94 def __init__(self, title='', parent=None, size=None, style=None, message=None): 1ad
95 size = size or (-1, -1) 1aklmnocbpqrstuvewxyzAfBCDEFGHI
96 style = style | wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER if style else (wx.DEFAULT_DIALOG_STYLE | 1aklmnocbpqrstuvewxyzAfBCDEFGHI
97 wx.RESIZE_BORDER )
98 wx.Dialog.__init__(self, parent=parent, title=title, size=size, style=style) 1aklmnocbpqrstuvewxyzAfBCDEFGHI
99 # set Left to Right direction (while we don't have localization)
100 self.SetLayoutDirection(wx.Layout_LeftToRight) 1aklmnocbpqrstuvewxyzAfBCDEFGHI
101 self.message = message 1aklmnocbpqrstuvewxyzAfBCDEFGHI
102 from ..preferences import RideSettings 1aklmnocbpqrstuvewxyzAfBCDEFGHI
103 _settings = RideSettings() 1aklmnocbpqrstuvewxyzAfBCDEFGHI
104 self.general_settings = _settings['General'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
105 self.font_face = self.general_settings['font face'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
106 self.font_size = self.general_settings['font size'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
107 self.color_background = self.general_settings['background'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
108 self.color_foreground = self.general_settings['foreground'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
109 self.color_secondary_background = self.general_settings['secondary background'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
110 self.color_secondary_foreground = self.general_settings['secondary foreground'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
111 self.color_background_help = self.general_settings['background help'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
112 self.color_foreground_text = self.general_settings['foreground text'] 1aklmnocbpqrstuvewxyzAfBCDEFGHI
113 self.SetBackgroundColour(Colour(self.color_background)) 1aklmnocbpqrstuvewxyzAfBCDEFGHI
114 self.SetForegroundColour(Colour(self.color_foreground)) 1aklmnocbpqrstuvewxyzAfBCDEFGHI
115 if self.message: 115 ↛ 116line 115 didn't jump to line 116 because the condition on line 115 was never true1aklmnocbpqrstuvewxyzAfBCDEFGHI
116 sizer = wx.BoxSizer(wx.VERTICAL)
117 content = wx.StaticText(self, -1, self.message)
118 content.SetBackgroundColour(Colour(self.color_background))
119 content.SetForegroundColour(Colour(self.color_foreground))
120 sizer.Add(content, 0, wx.ALL | wx.EXPAND, 3)
121 sizer.Add(wx.StaticText(self, -1, "\n\n"), 0, wx.ALL, 3)
122 btn_sizer = self._create_buttons_sizer(style)
123 sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER | wx.BOTTOM, 3)
124 self.SetSizer(sizer)
125 sizer.Fit(self)
126 self.Bind(wx.EVT_BUTTON, self.on_button)
127 self.CenterOnParent() 1aklmnocbpqrstuvewxyzAfBCDEFGHI
129 def _create_buttons_sizer(self, style=0): 1ad
130 sizer = wx.BoxSizer(wx.HORIZONTAL)
131 btn_flag = False
132 for btn, bid, label in zip([wx.NO, wx.CANCEL, wx.YES, wx.OK], [wx.ID_NO, wx.ID_CANCEL, wx.ID_YES, wx.ID_OK],
133 [_('No'), _('Cancel'), _('Yes'), _('OK')]):
134 if btn == style & btn:
135 # print(f"DEBUG: dialog.py RIDEDialog _create_buttons_sizer ID={btn} label={label}")
136 button = wx.Button(self, id=bid, label=label)
137 button.SetBackgroundColour(Colour(self.color_secondary_background))
138 button.SetForegroundColour(Colour(self.color_secondary_foreground))
139 sizer.Add(button, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
140 btn_flag = True
141 if not btn_flag:
142 return self._create_buttons_sizer(wx.OK)
143 return sizer
145 def _create_buttons(self, sizer): 1ad
146 buttons = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
147 self.SetBackgroundColour(Colour(self.color_background))
148 self.SetForegroundColour(Colour(self.color_foreground))
149 for item in self.GetChildren():
150 if isinstance(item, (wx.Button, wx.BitmapButton, ButtonWithHandler)):
151 item.SetBackgroundColour(Colour(self.color_secondary_background))
152 # item.SetOwnBackgroundColour(Colour(self.color_secondary_background))
153 item.SetForegroundColour(Colour(self.color_secondary_foreground))
154 # item.SetOwnForegroundColour(Colour(self.color_secondary_foreground))
155 sizer.Add(buttons, flag=wx.ALIGN_CENTER | wx.ALL, border=5)
156 sizer.Fit(self)
158 def _create_horizontal_line(self, sizer): 1ad
159 line = wx.StaticLine(self, size=(20, -1), style=wx.LI_HORIZONTAL)
160 if wx.VERSION < (4, 1, 0):
161 sizer.Add(line, border=5, flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP)
162 else:
163 sizer.Add(line, border=5, flag=wx.GROW | wx.RIGHT | wx.TOP)
164 sizer.Fit(self)
166 def on_button(self, event): 1ad
167 retval = event.GetId()
168 # print(f"DEBUG: dialog.py RIDEDialog on_button ={retval}")
169 if retval in (wx.ID_OK, wx.ID_YES):
170 try:
171 retval = self._execute()
172 except NotImplementedError:
173 pass
174 if retval:
175 self.EndModal(retval)
176 event.Skip()
178 def execute(self): 1ad
179 retval = self.ShowModal() 1ef
180 # print(f"DEBUG: dialog.py RIDEDialog execute RETURN MODAL retval={retval}")
181 if retval in (wx.ID_OK, wx.ID_YES): 181 ↛ 186line 181 didn't jump to line 186 because the condition on line 181 was always true1ef
182 try: 1ef
183 retval = self._execute() 1ef
184 except NotImplementedError:
185 pass
186 self.Destroy() 1ef
187 return retval 1ef
189 def _execute(self): 1ad
190 raise NotImplementedError(self.__class__.__name__)
193class HtmlDialog(RIDEDialog): 1ad
195 def _execute(self): 1ad
196 """ Nothing to execute in this dialog """
197 pass
199 def __init__(self, title, content, padding=0, font_size=-1): 1ad
200 RIDEDialog.__init__(self, title) 1b
201 # set Left to Right direction (while we don't have localization)
202 self.SetLayoutDirection(wx.Layout_LeftToRight) 1b
203 szr = sizers.VerticalSizer() 1b
204 self.SetMinClientSize((200, 300)) 1b
205 self.html_wnd = HtmlWindow(self, text=content) 1b
206 self.html_wnd.SetStandardFonts(size=font_size) 1b
207 szr.add_expanding(self.html_wnd, padding=padding) 1b
208 self.SetSizer(szr) 1b
209 szr.Fit(self) 1b
210 self.Layout() 1b
212 def on_key(self, event): 1ad
213 """ In the event we need to process key events"""
214 pass