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