Coverage for src/robotide/ui/pluginmanager.py: 22%
127 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 1ab
17import wx 1ab
18from wx import Colour 1ab
19from wx.adv import HyperlinkCtrl 1ab
20from wx.lib.scrolledpanel import ScrolledPanel 1ab
22from ..context import LOG 1ab
23from ..publish import RideLogException 1ab
24from ..widgets import Label, RIDEDialog, ButtonWithHandler 1ab
26_ = wx.GetTranslation # To keep linter/code analyser happy 1ab
27builtins.__dict__['_'] = wx.GetTranslation 1ab
30class PluginManager(object): 1ab
32 def __init__(self, notebook): 1ab
33 self._notebook = notebook
34 self._panel = None
36 def show(self, plugins): 1ab
37 if not self._panel:
38 self._panel = _PluginPanel(self._notebook.GetParent(), plugins, self._show_panel)
39 self._show_panel()
41 def _show_panel(self): 1ab
42 self._panel.Show()
45class _PluginPanel(RIDEDialog): 1ab
47 def __init__(self, notebook, plugins, activation_callback): 1ab
48 RIDEDialog.__init__(self, parent=notebook, title=_("Manage Plugins"), size=(800, 600))
49 self.SetBackgroundColour(Colour(self.color_background))
50 self.SetForegroundColour(Colour(self.color_foreground))
51 sizer = wx.BoxSizer(wx.VERTICAL)
52 sizer.Add(self._create_header(), 0, flag=wx.EXPAND | wx.LEFT |
53 wx.RIGHT | wx.TOP, border=16)
54 sizer.Add(self._create_info_text(), 0,
55 flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=16)
56 sizer.Add(self._create_line(), 0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT)
57 sizer.Add(self._create_body(plugins, activation_callback), 1,
58 flag=wx.EXPAND | wx.ALL, border=16)
59 self.SetSizer(sizer)
60 self.CenterOnParent()
62 def _create_header(self): 1ab
63 header = Label(self, wx.ID_ANY, _("Installed Plugins\n"))
64 self.font = self.GetFont()
65 self.font.SetPointSize(self.font_size)
66 if self.font_face is None:
67 self.font_face = self.font.GetFaceName()
68 else:
69 self.font.SetFaceName(self.font_face)
70 self.SetFont(self.font)
71 header.SetFont(wx.Font(wx.FontInfo(14 if self.font_size<=11 else self.font_size + 3).Bold()))
72 return header
74 def _create_line(self): 1ab
75 return wx.StaticLine(self)
77 def _create_body(self, plugins, activation_callback): 1ab
78 panel = ScrolledPanel(self, wx.ID_ANY, style=wx.TAB_TRAVERSAL | wx.SIZE_AUTO)
79 panel.SetupScrolling()
80 sizer = wx.FlexGridSizer(0, 2, hgap=8, vgap=8)
81 sizer.AddGrowableCol(1, 1)
82 sizer.Add(self._create_label(panel, _('Enabled')), 0, wx.BOTTOM, border=8)
83 sizer.Add(self._create_label(panel, _('Plugin')), 0, wx.BOTTOM | wx.EXPAND, border=8)
84 for plugin in sorted(plugins, key=lambda p: p.name):
85 sizer.Add(_PluginEnablationCheckBox(panel, plugin, activation_callback),
86 flag=wx.ALIGN_LEFT)
87 sizer.Add(_PluginRow(panel, plugin, self.color_background), 0, wx.EXPAND)
88 panel.SetSizer(sizer)
89 return panel
91 def _create_info_text(self): 1ab
92 info = wx.StaticText(self, wx.ID_ANY, _("Info. Enabling and disabling plugins might"
93 " require RIDE restart for menus to work."))
94 info.SetFont(wx.Font(wx.FontInfo(12).Family(wx.FONTFAMILY_SWISS).Bold(False)))
95 return info
97 def _create_label(self, parent, text): 1ab
98 bold_font = self.GetFont()
99 if self.font_face:
100 bold_font.SetFaceName(self.font_face)
101 bold_font.SetWeight(wx.FONTWEIGHT_BOLD)
102 bold_font.SetPointSize(self.font_size)
103 label = Label(parent, wx.ID_ANY, text)
104 label.SetFont(bold_font)
105 return label
108class _PluginEnablationCheckBox(wx.CheckBox): 1ab
110 def __init__(self, parent, plugin, activation_callback): 1ab
111 wx.CheckBox.__init__(self, parent)
112 self.SetValue(plugin.enabled)
113 self.Bind(wx.EVT_CHECKBOX, self.on_check_box)
114 if plugin.error:
115 self.Enable(False)
116 self._plugin = plugin
117 self._callback = activation_callback
119 def on_check_box(self, event): 1ab
120 if event.IsChecked():
121 self._execute(self._plugin.enable)
122 else:
123 self._execute(self._plugin.disable)
124 self._callback()
126 def _execute(self, method): 1ab
127 try:
128 method()
129 except Exception as err:
130 self.SetValue(False)
131 self.Enable(False)
132 msg = 'Failed to %s plugin %s:\n%s\n\nYou should restart RIDE now!' % (method.__name__,
133 self._plugin.name,
134 err)
135 self._plugin.error = err
136 self._plugin.doc = msg
137 LOG.error(msg)
138 RideLogException(message=msg, exception=err, level='ERROR').publish()
141class _PluginRow(wx.Panel): 1ab
143 def __init__(self, parent, plugin, backgound_color): 1ab
144 wx.Panel.__init__(self, parent)
145 sz_head = wx.FlexGridSizer(0, 3, hgap=4, vgap=4)
146 l_name = self._get_name(plugin)
147 sz_head.Add(l_name)
148 b_spacing = Label(self, label=' ')
149 sz_head.Add(b_spacing)
150 if hasattr(plugin, 'on_config_panel'):
151 try:
152 sz_head.Add(ButtonWithHandler(self, _('Settings'), bitmap='wrench.png',
153 color_secondary_background=backgound_color,
154 handler=lambda e: plugin.on_config_panel()),
155 flag=wx.ALIGN_LEFT)
156 except AttributeError:
157 pass
158 sizer = wx.BoxSizer(wx.VERTICAL)
159 sizer.Add(sz_head)
160 for name, value in plugin.metadata.items():
161 sizer.Add(self._get_metadata(name, value))
162 sizer.Add(self._get_description(plugin), 0, wx.EXPAND)
163 self.SetSizer(sizer)
165 def _get_name(self, plugin): 1ab
166 return Label(self, label=plugin.name)
168 def _get_metadata(self, name, value): 1ab
169 sizer = wx.BoxSizer(wx.HORIZONTAL)
170 sizer.Add(Label(self, label='%s: ' % name))
171 if value.split('://')[0] in ['http', 'https']:
172 sizer.Add(HyperlinkCtrl(self, -1, label=value, url=value))
173 else:
174 sizer.Add(Label(self, label=value))
175 return sizer
177 def _get_description(self, plugin): 1ab
178 desc = Label(self, label=plugin.doc)
179 if plugin.error:
180 desc.SetForegroundColour("firebrick")
181 return desc