Package gui :: Package components :: Module base_list
[hide private]
[frames] | no frames]

Source Code for Module gui.components.base_list

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009-2011 Michael Bieri                                       # 
  4  # Copyright (C) 2010-2012 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax.                                     # 
  7  #                                                                             # 
  8  # relax is free software; you can redistribute it and/or modify               # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation; either version 2 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # relax is distributed in the hope that it will be useful,                    # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with relax; if not, write to the Free Software                        # 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 21  #                                                                             # 
 22  ############################################################################### 
 23   
 24  # Module docstring. 
 25  """Module containing the base GUI element for listing things.""" 
 26   
 27  # Python module imports. 
 28  import wx 
 29  import wx.lib.buttons 
 30   
 31  # relax module imports. 
 32  from status import Status; status = Status() 
 33  from user_functions.data import Uf_info; uf_info = Uf_info() 
 34   
 35  # relax GUI module imports. 
 36  from gui.components.menu import build_menu_item 
 37  from gui.fonts import font 
 38  from gui.misc import add_border 
 39  from gui.string_conv import str_to_gui 
 40  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 41   
 42   
43 -class Base_list(object):
44 """The GUI element for listing the software used in the analysis.""" 45
46 - def __init__(self, gui=None, parent=None, box=None, id=None, proportion=0, button_placement='default'):
47 """Build the base list GUI element. 48 49 @keyword gui: The main GUI object. 50 @type gui: wx.Frame instance 51 @keyword parent: The parent GUI element that this is to be attached to. 52 @type parent: wx object 53 @keyword box: The box sizer to pack this GUI component into. 54 @type box: wx.BoxSizer instance 55 @keyword id: A unique identification string. This is used to register the update method with the GUI user function observer object. 56 @type id: str 57 @keyword proportion: The window proportion parameter. 58 @type proportion: bool 59 @keyword button_placement: Override the button visibility and placement. The value of 'default' will leave the buttons at the default setting. The value of 'top' will place the buttons at the top, 'bottom' will place them at the bottom, and None will turn off the buttons. 60 @type button_placement: str or None 61 """ 62 63 # Store the arguments. 64 self.gui = gui 65 self.parent = parent 66 self.proportion = proportion 67 68 # Variables to be overridden. 69 self.title = "" 70 self.spacing = 5 71 self.border = 5 72 self.observer_base_name = None 73 self.columns = [] 74 self.button_placement = None 75 self.button_size = (120, 40) 76 self.button_spacing = 5 77 self.button_info = [] 78 self.popup_menus = [] 79 80 # Override these base values. 81 self.setup() 82 83 # Button placement second override on initialisation. 84 if button_placement != 'default': 85 self.button_placement = button_placement 86 87 # First create a panel (to allow for tooltips on the buttons). 88 self.panel = wx.Panel(self.parent) 89 box.Add(self.panel, self.proportion, wx.ALL|wx.EXPAND, 0) 90 91 # Add a sizer to the panel. 92 panel_sizer = wx.BoxSizer(wx.VERTICAL) 93 self.panel.SetSizer(panel_sizer) 94 95 # A static box to hold all the widgets, and its sizer. 96 self.data_box = wx.StaticBox(self.panel, -1) 97 self.set_box_label() 98 self.data_box.SetFont(font.subtitle) 99 sub_sizer = wx.StaticBoxSizer(self.data_box, wx.VERTICAL) 100 101 # Add the sizer to the static box and the static box to the main box. 102 panel_sizer.Add(sub_sizer, self.proportion, wx.ALL|wx.EXPAND, 0) 103 104 # Add a border. 105 box_centre = add_border(sub_sizer, border=self.border) 106 107 # Add buttons to the top. 108 if self.button_placement == 'top': 109 self.add_buttons(box_centre) 110 box_centre.AddSpacer(self.spacing) 111 112 # Initialise the element. 113 self.init_element(box_centre) 114 115 # Build the element. 116 self.build_element() 117 118 # Add buttons to the bottom. 119 if self.button_placement == 'bottom': 120 box_centre.AddSpacer(self.spacing) 121 self.add_buttons(box_centre) 122 123 # Initialise observer name. 124 if self.observer_base_name: 125 self.name = '%s: %s' % (self.observer_base_name, id) 126 else: 127 self.name = id 128 129 # Register the element for updating when a user function completes. 130 self.observer_register()
131 132
133 - def Enable(self, enable=True):
134 """Enable or disable the element. 135 136 @keyword enable: The flag specifying if the element should be enabled or disabled. 137 @type enable: bool 138 """ 139 140 # Call the buttons' methods. 141 for i in range(len(self.button_info)): 142 # Get the button. 143 button = getattr(self, self.button_info[i]['object']) 144 145 # Call the botton's method. 146 button.Enable(enable)
147 148
149 - def add_buttons(self, sizer):
150 """Add the buttons for manipulating the data. 151 152 @param sizer: The sizer element to pack the buttons into. 153 @type sizer: wx.BoxSizer instance 154 """ 155 156 # Button Sizer 157 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 158 sizer.Add(button_sizer, 0, wx.ALL|wx.EXPAND, 0) 159 160 # Loop over the buttons. 161 for i in range(len(self.button_info)): 162 # The button. 163 button = wx.lib.buttons.ThemedGenBitmapTextButton(self.panel, -1, None, self.button_info[i]['label']) 164 button.SetBitmapLabel(wx.Bitmap(self.button_info[i]['icon'])) 165 166 # Format. 167 button.SetFont(font.normal) 168 button.SetMinSize(self.button_size) 169 170 # Add to the sizer. 171 button_sizer.Add(button, 0, 0, 0) 172 173 # Bind the method. 174 self.parent.Bind(wx.EVT_BUTTON, self.button_info[i]['method'], button) 175 176 # Set the tooltip. 177 button.SetToolTipString(self.button_info[i]['tooltip']) 178 179 # Store as a class object. 180 setattr(self, self.button_info[i]['object'], button) 181 182 # Spacing. 183 if self.button_spacing: 184 button_sizer.AddSpacer(self.button_spacing)
185 186
187 - def build_element(self):
188 """Build the grid.""" 189 190 # Execution lock, so do nothing. 191 if status.exec_lock.locked(): 192 return 193 194 # Build the GUI element in a thread safe way. 195 wx.CallAfter(self.build_element_safe)
196 197
198 - def build_element_safe(self):
199 """Build the spectra listing GUI element in a thread safe wx.CallAfter call.""" 200 201 # First freeze the element, so that the GUI element doesn't update until the end. 202 self.element.Freeze() 203 204 # Update the label if needed. 205 self.set_box_label() 206 207 # Delete the previous data. 208 self.element.DeleteAllItems() 209 210 # Update the data. 211 self.update_data() 212 213 # Size the columns. 214 self.size_cols() 215 216 # Post a size event to get the scroll panel to update correctly. 217 event = wx.PyCommandEvent(wx.EVT_SIZE.typeId, self.parent.GetId()) 218 wx.PostEvent(self.parent.GetEventHandler(), event) 219 220 # Set the minimum height. 221 if not self.proportion: 222 # The number of rows. 223 n = self.element.GetItemCount() 224 225 # Size of the header, plus a bit. 226 head = self.height_char + 10 227 228 # Size of the table central element. 229 centre = (self.height_char + 6) * n 230 231 # Size of the scrollbar for the end of the table. 232 foot = wx.SystemSettings_GetMetric(wx.SYS_HSCROLL_Y) 233 234 # Sum. 235 height = head + centre + foot 236 237 # Set the minimum size, and force a redraw. 238 self.element.SetMinSize((-1, height)) 239 self.element.Layout() 240 241 # Unfreeze. 242 self.element.Thaw()
243 244
245 - def delete(self):
246 """Unregister the class.""" 247 248 # Unregister the observer methods. 249 self.observer_register(remove=True)
250 251
252 - def init_element(self, sizer):
253 """Initialise the GUI element. 254 255 @param sizer: The sizer element to pack the element into. 256 @type sizer: wx.BoxSizer instance 257 """ 258 259 # The list. 260 self.element = wx.ListCtrl(self.panel, -1, style=wx.BORDER_SUNKEN|wx.LC_REPORT) 261 262 # Initialise the columns. 263 for i in range(len(self.columns)): 264 self.element.InsertColumn(i, str_to_gui(self.columns[i])) 265 266 # Properties. 267 self.element.SetFont(font.normal) 268 269 # Store the base heights. 270 self.height_char = self.element.GetCharHeight() 271 272 # Bind some events. 273 self.element.Bind(wx.EVT_SIZE, self.resize) 274 self.element.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.on_right_click) # For wxMSW! 275 self.element.Bind(wx.EVT_RIGHT_UP, self.on_right_click) # For wxGTK! 276 277 # Add list to sizer. 278 sizer.Add(self.element, self.proportion, wx.ALL|wx.EXPAND, 0)
279 280
281 - def is_complete(self):
282 """Base method which always returns True. 283 284 @return: The answer to the question. 285 @rtype: bool 286 """ 287 288 # Assume everything is complete. 289 return True
290 291
292 - def observer_register(self, remove=False):
293 """Register and unregister methods with the observer objects. 294 295 @keyword remove: If set to True, then the methods will be unregistered. 296 @type remove: False 297 """ 298 299 # Register. 300 if not remove: 301 status.observers.gui_uf.register(self.name, self.build_element) 302 status.observers.pipe_alteration.register(self.name, self.build_element) 303 304 # Unregister. 305 else: 306 status.observers.gui_uf.unregister(self.name) 307 status.observers.pipe_alteration.unregister(self.name)
308 309
310 - def on_right_click(self, event):
311 """Pop up menu for the right click. 312 313 @param event: The wx event. 314 @type event: wx event 315 """ 316 317 # No popup menus defined. 318 if self.popup_menus == []: 319 return 320 321 # Execution lock, so do nothing. 322 if status.exec_lock.locked(): 323 return 324 325 # Initialise the menu. 326 menu = wx.Menu() 327 328 # Loop over the menu items. 329 for i in range(len(self.popup_menus)): 330 # Alias. 331 info = self.popup_menus[i] 332 333 # Add the menu item. 334 menu.AppendItem(build_menu_item(menu, id=info['id'], text=info['text'], icon=info['icon'])) 335 336 # Bind clicks. 337 self.element.Bind(wx.EVT_MENU, info['method'], id=info['id']) 338 339 # Pop up the menu. 340 if status.show_gui: 341 self.element.PopupMenu(menu) 342 menu.Destroy()
343 344
345 - def resize(self, event):
346 """Catch the resize to allow the element to be resized. 347 348 @param event: The wx event. 349 @type event: wx event 350 """ 351 352 # Set the column sizes. 353 self.size_cols() 354 355 # Continue with the normal resizing. 356 event.Skip()
357 358
359 - def set_box_label(self):
360 """Set the label of the StaticBox.""" 361 362 # Set the label. 363 self.data_box.SetLabel(self.title)
364 365
366 - def size_cols(self):
367 """Set the column sizes.""" 368 369 # The element size. 370 x, y = self.element.GetSize() 371 372 # Number of columns. 373 n = self.element.GetColumnCount() 374 375 # Set to equal sizes. 376 if n == 0: 377 width = x 378 else: 379 width = int(x / n) 380 381 # Set the column sizes. 382 for i in range(n): 383 self.element.SetColumnWidth(i, width)
384