Robot Framework Integrated Development Environment (RIDE)
editor.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 
32 
33 import wx
34 from wx import Colour
35 from wx.lib.scrolledpanel import ScrolledPanel
36 
37 from .settings import RideSettings
38 
39 # any more than TREE_THRESHOLD panels when style is "auto" forces
40 # the UI into showing a hierarchical tree
41 TREE_THRESHOLD = 5
42 
43 
44 
45 class PreferenceEditor(wx.Dialog):
46  def __init__(self, parent, title, preferences, style="auto"):
47  wx.Dialog.__init__(self, parent, wx.ID_ANY, title, size=(850, 660),
48  style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE)
49  # set Left to Right direction (while we don't have localization)
50  self.SetLayoutDirection(wx.Layout_LeftToRight)
51  self.Bind(wx.EVT_CLOSE, self.OnCloseOnClose)
52  self._current_panel_current_panel = None
53  self._panels_panels = []
54  self._settings_settings = preferences.settings
55  self._general_settings_general_settings = self._settings_settings['General']
56  self.fontfont = self.GetFont()
57  self.fontfont.SetFaceName(self._general_settings_general_settings['font face'])
58  self.fontfont.SetPointSize(self._general_settings_general_settings['font size'])
59  self.SetFont(self.fontfont)
60  self.SetBackgroundColour(Colour(self._general_settings_general_settings['background']))
61  self.SetOwnBackgroundColour(Colour(self._general_settings_general_settings['secondary background']))
62  self.SetForegroundColour(Colour(self._general_settings_general_settings['foreground']))
63  self.SetOwnForegroundColour(Colour(self._general_settings_general_settings['secondary foreground']))
64  self._closing_closing = False
65 
66  panels = preferences.preference_panels
67  if style not in ("tree","notebook","single","auto"):
68  raise Exception("invalid style; must be one of 'tree','notebook','single' or 'auto'")
69 
70  if style == "tree" or (style == "auto" and len(panels) > TREE_THRESHOLD):
71  self._sw_sw = wx.SplitterWindow(self, wx.ID_ANY, style=wx.SP_LIVE_UPDATE|wx.SP_3D)
72  self._tree_tree = wx.TreeCtrl(self._sw_sw, wx.ID_ANY,
73  style=wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS)
74  # create a single container which will hold all of the
75  # preference panels
76  self._container_container = PanelContainer(self._sw_sw, wx.ID_ANY)
77  self._sw_sw.SplitVertically(self._tree_tree, self._container_container, 210)
78  sizer = wx.BoxSizer(wx.VERTICAL)
79  sizer.Add(self._sw_sw, 1, wx.EXPAND)
80  self._tree_tree.SetFont(self.fontfont)
81  self._tree_tree.SetBackgroundColour(Colour(self._general_settings_general_settings['background']))
82  self._tree_tree.SetOwnBackgroundColour(Colour(self._general_settings_general_settings['secondary background']))
83  self._tree_tree.SetForegroundColour(Colour(self._general_settings_general_settings['foreground']))
84  self._tree_tree.SetOwnForegroundColour(Colour(self._general_settings_general_settings['secondary foreground']))
85  self._tree_tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeSelectionOnTreeSelection)
86  self._populate_tree_populate_tree(panels)
87  self._tree_tree.SelectItem(self._tree_tree.GetFirstChild(self._tree_tree.GetRootItem())[0])
88  self.SetSizer(sizer)
89 
90  elif style == "notebook" or (style == "auto" and len(panels) > 1):
91  # the tabs appear in alphabetical order based on their
92  # location. This has the pleasant side effect of "General"
93  # coming before "Plugins", but if some plugin adds a
94  # location of ("aaa","me first!") it will come before
95  # "General". I need some way to order them, though maybe
96  # just special-casing "General" to come first might be
97  # good enough?
98  self._notebook_notebook = wx.Notebook(self)
99  for panel_class in sorted(panels, key=lambda p: p.location):
100  # for a notebook, each notebook page gets a container,
101  # and that container will only show one panel
102  container = PanelContainer(self._notebook_notebook)
103  panel = container.AddPanel(panel_class)
104  container.ShowPanel(panel)
105  self._notebook_notebook.AddPage(container, panel.GetTitle())
106  sizer = wx.BoxSizer(wx.VERTICAL)
107  sizer.Add(self._notebook_notebook, 1, wx.EXPAND)
108  self.SetSizer(sizer)
109 
110  else:
111  self._container_container = PanelContainer(self, wx.ID_ANY)
112  sizer = wx.BoxSizer(wx.VERTICAL)
113  sizer.Add(self._container_container, 1, wx.EXPAND)
114  self.SetSizer(sizer)
115 
116  panel = self._container_container.AddPanel(panels[0])
117  self._container_container.ShowPanel(panel)
118 
119  def OnClose(self, evt):
120  self._closing_closing = True
121  evt.Skip()
122 
123 
127  def OnTreeSelection(self, event):
128  # On Windows, closing the Dialog causes tree selection events to be
129  # triggered. This is a workaround to ignore those events, which might
130  # try to access dead objects.
131  if self._closing_closing:
132  return
133  instance_or_class = self._tree_tree.GetItemData(event.GetItem())
134  if isinstance(instance_or_class, wx.Panel):
135  panel = instance_or_class
136  else:
137  # not an instance, assume it's a class
138  panel = self._container_container.AddPanel(instance_or_class, self._settings_settings)
139  self._panels_panels.append(panel)
140  self._tree_tree.SetItemData(event.GetItem(), panel)
141  self._container_container.ShowPanel(panel)
142 
143 
149  def _populate_tree(self, panels):
150  self._tree_tree.AddRoot("Root")
151  for panel_class in panels:
152  location = panel_class.location
153  if not isinstance(location, tuple):
154  # location should be a tuple, but it's easy to accidentally
155  # make it not a tuple (eg: ("Plugins")). This fixes that.
156  location = (location,)
157  item = self._get_item_get_item(location)
158  self._tree_tree.SetItemData(item, panel_class)
159  self._tree_tree.ExpandAll()
160 
161  def _get_item(self, location):
162  item = self._tree_tree.GetRootItem()
163  for text in location:
164  item = self._get_child_item_get_child_item(item, text)
165  return item
166 
167 
173  def _get_child_item(self, parent, text):
174  if self._tree_tree.ItemHasChildren(parent):
175  item, cookie = self._tree_tree.GetFirstChild(parent)
176  while item:
177  if self._tree_tree.GetItemText(item).strip().lower() == text.strip().lower():
178  return item
179  item, cookie = self._tree_tree.GetNextChild(parent, cookie)
180  # if we get here we didn't find the item
181  item = self._tree_tree.AppendItem(parent, text)
182  return item
183 
184  def _get_children(self, parent):
185  if self._tree_tree.ItemHasChildren(parent):
186  item, cookie = self._tree_tree.GetFirstChild(parent)
187  while item:
188  yield item
189  item, cookie = self._tree_tree.GetNextChild(parent, cookie)
190 
191 
192 
200 class PanelContainer(wx.Panel):
201  def __init__(self, *args, **kwargs):
202  super(PanelContainer, self).__init__(*args, **kwargs)
203 
204  self._current_panel_current_panel = None
205  self._settings_settings = RideSettings()
206  self.settingssettings = self._settings_settings['General']
207  self.titletitle = wx.StaticText(self, label="Your message here")
208  self.panels_containerpanels_container = ScrolledPanel(self, wx.ID_ANY, style=wx.TAB_TRAVERSAL)
209  self.panels_containerpanels_container.SetupScrolling()
210  sizer = wx.BoxSizer(wx.VERTICAL)
211  sizer.Add(self.titletitle, 0, wx.TOP|wx.LEFT|wx.EXPAND, 4)
212  sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 4)
213  sizer.Add(self.panels_containerpanels_container,1, wx.EXPAND)
214  self.SetSizer(sizer)
215  self.panels_containerpanels_container.SetSizer(wx.BoxSizer(wx.VERTICAL))
216 
217  font = self.titletitle.GetFont()
218  font.SetFaceName(self.settingssettings['font face'])
219  font.SetPointSize(self.settingssettings['font size'])
220  font.MakeLarger()
221  self.titletitle.SetFont(font)
222  self.titletitle.SetForegroundColour(self.settingssettings['foreground'])
223  self.titletitle.SetBackgroundColour(self.settingssettings['background'])
224  self.SetForegroundColour(self.settingssettings['foreground'])
225  self.SetBackgroundColour(self.settingssettings['background'])
226 
227 
228  def AddPanel(self, panel_class, settings):
229  panel = panel_class(parent=self.panels_containerpanels_container, settings=settings)
230  self.panels_containerpanels_container.GetSizer().Add(panel, 1, wx.EXPAND)
231  return panel
232 
233 
234  def ShowPanel(self, panel):
235  if self._current_panel_current_panel is not None:
236  self._current_panel_current_panel.Hide()
237  self._current_panel_current_panel = panel
238  self.SetForegroundColour(self.settingssettings['foreground'])
239  self.SetBackgroundColour(self.settingssettings['background'])
240  panel.SetForegroundColour(self.settingssettings['foreground'])
241  panel.SetBackgroundColour(self.settingssettings['background'])
242  panel.Show()
243  sizer = self.panels_containerpanels_container.GetSizer()
244  item = sizer.GetItem(panel)
245  title = getattr(panel, "title", panel.location[-1])
246  self.SetTitleSetTitle(title)
247  font = self.titletitle.GetFont()
248  font.SetFaceName(self.settingssettings['font face'])
249  font.SetPointSize(self.settingssettings['font size'])
250  self.SetFont(font)
251  font.MakeLarger()
252  self.titletitle.SetFont(font)
253  self.titletitle.SetForegroundColour(self.settingssettings['foreground'])
254  self.titletitle.SetBackgroundColour(self.settingssettings['background'])
255  if item is None:
256  sizer.Add(panel, 1, wx.EXPAND)
257  sizer.Layout()
258 
259 
260  def SetTitle(self, title):
261  self.titletitle.SetLabel(title)
This contains a preference panel.
Definition: editor.py:200
def SetTitle(self, title)
Set the title of the panel.
Definition: editor.py:260
def __init__(self, *args, **kwargs)
Definition: editor.py:201
def AddPanel(self, panel_class, settings)
Add a panel to the dialog.
Definition: editor.py:228
def ShowPanel(self, panel)
Arrange for the given panel to be shown.
Definition: editor.py:234
A dialog for showing the preference panels.
Definition: editor.py:45
def OnTreeSelection(self, event)
Show panel that corresponds to selected tree item.
Definition: editor.py:127
def _get_child_item(self, parent, text)
Returns the tree item with the given text under the given parent.
Definition: editor.py:173
def __init__(self, parent, title, preferences, style="auto")
Definition: editor.py:46
def _populate_tree(self, panels)
Recreate the hierarchical tree of preferences panels.
Definition: editor.py:149