| 1 | ## Copyright 2005, 2006, 2007, 2008 Virginia Polytechnic Institute and State University |
|---|
| 2 | ## |
|---|
| 3 | ## This file is part of the OSSIE Waveform Application Visualization Environment |
|---|
| 4 | ## |
|---|
| 5 | ## WaveDash is free software; you can redistribute it and/or modify |
|---|
| 6 | ## it under the terms of the GNU General Public License as published by |
|---|
| 7 | ## the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | ## (at your option) any later version. |
|---|
| 9 | ## |
|---|
| 10 | ## WaveDash is distributed in the hope that it will be useful, but WITHOUT ANY |
|---|
| 11 | ## WARRANTY; without even the implied warranty of |
|---|
| 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | ## GNU General Public License for more details. |
|---|
| 14 | ## |
|---|
| 15 | ## You should have received a copy of the GNU General Public License |
|---|
| 16 | ## along with OSSIE WaveDash; if not, write to the Free Software |
|---|
| 17 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | |
|---|
| 19 | import wx |
|---|
| 20 | import os |
|---|
| 21 | import WaveformModel |
|---|
| 22 | import WavedashUtils as utils |
|---|
| 23 | from wx.lib import scrolledpanel |
|---|
| 24 | from WaveformModel import WaveformListener |
|---|
| 25 | from ComponentModel import ComponentListener |
|---|
| 26 | from PropertyModel import PropertyListener |
|---|
| 27 | |
|---|
| 28 | OSSIE_WAVEAPP_DIMENSION = (600,600) |
|---|
| 29 | OSSIE_TITLE = 'Ossie WaveDash' |
|---|
| 30 | START_ICON_FILE = "/resources/start.png" |
|---|
| 31 | STOP_ICON_FILE = "/resources/stop.png" |
|---|
| 32 | UNINSTALL_ICON_FILE = "/resources/LET-U.jpg" |
|---|
| 33 | NAMINGSERVICE_ICON_FILE = "/resources/network.png" |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | |
|---|
| 37 | class WavedashView(wx.Frame, WaveformListener, |
|---|
| 38 | ComponentListener, PropertyListener ): |
|---|
| 39 | """ This is top level frame that acts as primary UI """ |
|---|
| 40 | def __init__(self, controller, amodel): |
|---|
| 41 | wx.Frame.__init__(self, parent=None, id=-1, title=OSSIE_TITLE ) |
|---|
| 42 | # size = OSSIE_WAVEAPP_DIMENSION) |
|---|
| 43 | #Create the model and register the frame to the listeners of |
|---|
| 44 | #Waveform, Component and Property Models. |
|---|
| 45 | |
|---|
| 46 | self.controller = controller |
|---|
| 47 | self.model = amodel |
|---|
| 48 | self.model.addWaveformListener(self) |
|---|
| 49 | self.model.addComponentListener(self) |
|---|
| 50 | self.model.addPropertyListener(self) |
|---|
| 51 | |
|---|
| 52 | self.toolbar = None |
|---|
| 53 | self.createToolBar() |
|---|
| 54 | |
|---|
| 55 | #notebook to hold the waveform panels |
|---|
| 56 | self.mainPanel = wx.Panel(self) |
|---|
| 57 | self.notebook = wx.Notebook(self.mainPanel) |
|---|
| 58 | #bind notebook to page changed event |
|---|
| 59 | self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnNbPageChange, self.notebook) |
|---|
| 60 | |
|---|
| 61 | #sizers to manage the notebook |
|---|
| 62 | self.nbSizer = wx.BoxSizer() |
|---|
| 63 | self.nbSizer.Add(self.notebook, 1, wx.EXPAND) |
|---|
| 64 | self.mainPanel.SetSizer(self.nbSizer) |
|---|
| 65 | |
|---|
| 66 | self.statusBar = None |
|---|
| 67 | self.createMenus() |
|---|
| 68 | |
|---|
| 69 | |
|---|
| 70 | self.wpanels = [] # this list holds the panel objects of the installed waveforms |
|---|
| 71 | self.prpPopupMenus = {} #this dict is of the form {'wPanelRef':{window, popUpMenu}} |
|---|
| 72 | self.compPopupMenus = {} |
|---|
| 73 | self.tempProp = None |
|---|
| 74 | self.tempComp = None |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | self.SetSize(OSSIE_WAVEAPP_DIMENSION) |
|---|
| 78 | self.Center() |
|---|
| 79 | |
|---|
| 80 | |
|---|
| 81 | def createToolBar(self): |
|---|
| 82 | self.toolbar = self.CreateToolBar() |
|---|
| 83 | rsize = (20, 20) |
|---|
| 84 | refreshImg = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR, rsize) |
|---|
| 85 | refresh = self.toolbar.AddSimpleTool(-1,refreshImg ,shortHelpString="Refresh") |
|---|
| 86 | self.Bind(wx.EVT_TOOL, self.OnRefresh, refresh) |
|---|
| 87 | |
|---|
| 88 | root = __file__ |
|---|
| 89 | if os.path.islink (root): |
|---|
| 90 | root = os.path.realpath (root) |
|---|
| 91 | root = os.path.dirname (os.path.abspath (root)) |
|---|
| 92 | |
|---|
| 93 | selectNSIcon = wx.Image(root + NAMINGSERVICE_ICON_FILE, wx.BITMAP_TYPE_ANY).ConvertToBitmap() |
|---|
| 94 | selectNS = self.toolbar.AddSimpleTool(-1, selectNSIcon, shortHelpString="Configure Naming Service address") |
|---|
| 95 | |
|---|
| 96 | startIcon = wx.Image(root + START_ICON_FILE, wx.BITMAP_TYPE_ANY).ConvertToBitmap() |
|---|
| 97 | stopIcon = wx.Image(root + STOP_ICON_FILE, wx.BITMAP_TYPE_ANY).ConvertToBitmap() |
|---|
| 98 | uninstallIcon = wx.Image(root + UNINSTALL_ICON_FILE, wx.BITMAP_TYPE_ANY).ConvertToBitmap() |
|---|
| 99 | start = self.toolbar.AddSimpleTool(-1, startIcon, shortHelpString="Start waveform") |
|---|
| 100 | stop = self.toolbar.AddSimpleTool(-1, stopIcon, shortHelpString="Stop Waveform") |
|---|
| 101 | uninstall = self.toolbar.AddSimpleTool(-1, uninstallIcon, shortHelpString="Uninstall waveform") |
|---|
| 102 | |
|---|
| 103 | self.Bind(wx.EVT_TOOL, self.OnStart, start) |
|---|
| 104 | self.Bind(wx.EVT_TOOL, self.OnStop, stop) |
|---|
| 105 | self.Bind(wx.EVT_TOOL, self.OnUninstall, uninstall) |
|---|
| 106 | self.Bind(wx.EVT_TOOL, self.OnSelectNS, selectNS) |
|---|
| 107 | |
|---|
| 108 | def OnStart(self, event): |
|---|
| 109 | activeWform = self.model.getActiveWaveform() |
|---|
| 110 | if activeWform is None: |
|---|
| 111 | utils.showMessage("Start Failed!!! No waveform is running now", |
|---|
| 112 | utils.NON_FATAL) |
|---|
| 113 | return |
|---|
| 114 | status = self.controller.startWaveform(activeWform.getName()) |
|---|
| 115 | |
|---|
| 116 | def OnStop(self, event): |
|---|
| 117 | activeWform = self.model.getActiveWaveform() |
|---|
| 118 | if activeWform is None: |
|---|
| 119 | utils.showMessage("Stop Failed!!! No waveform is running now", |
|---|
| 120 | utils.NON_FATAL) |
|---|
| 121 | return |
|---|
| 122 | status = self.controller.stopWaveform(activeWform.getName()) |
|---|
| 123 | |
|---|
| 124 | def OnUninstall(self, event): |
|---|
| 125 | selWform = self.model.getActiveWaveform() |
|---|
| 126 | if selWform is None: |
|---|
| 127 | utils.showMessage("Uninstall Failed!!! No waveform is running now", |
|---|
| 128 | utils.NON_FATAL) |
|---|
| 129 | return |
|---|
| 130 | |
|---|
| 131 | success = self.model.removeWaveform(selWform) |
|---|
| 132 | |
|---|
| 133 | def OnSelectNS(self, event): |
|---|
| 134 | self.controller.selectNS() |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | def createMenus(self): |
|---|
| 138 | menuBar = wx.MenuBar() |
|---|
| 139 | #These features are not yet implemented in 0.7.3 |
|---|
| 140 | # fileMenu = wx.Menu() |
|---|
| 141 | # openLayout = fileMenu.Append(-1, '&Open Layout') |
|---|
| 142 | # saveLayout = fileMenu.Append(-1, '&Save Layout') |
|---|
| 143 | # saveLayoutAs = fileMenu.Append(-1, 'S&ave Layout As') |
|---|
| 144 | # exit = fileMenu.Append(-1, 'E&xit\tCtrl-Q') |
|---|
| 145 | # |
|---|
| 146 | # self.Bind(wx.EVT_MENU, self.OnOpenLayout, openLayout) |
|---|
| 147 | # self.Bind(wx.EVT_MENU, self.OnSaveLayout, saveLayout) |
|---|
| 148 | # self.Bind(wx.EVT_MENU, self.OnSaveLayoutAs, saveLayoutAs) |
|---|
| 149 | # self.Bind(wx.EVT_MENU, self.OnExit, exit) |
|---|
| 150 | # |
|---|
| 151 | waveformsMenu = wx.Menu() |
|---|
| 152 | componentsMenu = wx.Menu() |
|---|
| 153 | |
|---|
| 154 | # preferencesMenu = wx.Menu() |
|---|
| 155 | # widgetSettings = preferencesMenu.Append(-1, '&Widget Settings') |
|---|
| 156 | # self.Bind(wx.EVT_MENU, self.OnWidgetSettings,widgetSettings) |
|---|
| 157 | # |
|---|
| 158 | helpMenu = wx.Menu() |
|---|
| 159 | about = helpMenu.Append(-1,'&About') |
|---|
| 160 | self.Bind(wx.EVT_MENU, self.OnAbout, about) |
|---|
| 161 | |
|---|
| 162 | # menuBar.Append(fileMenu, '&File') |
|---|
| 163 | menuBar.Append(waveformsMenu, '&Waveforms') |
|---|
| 164 | #waveformsMenu.AppendSeparator() |
|---|
| 165 | menuBar.Append(componentsMenu, '&Components') |
|---|
| 166 | #menuBar.Append(preferencesMenu, '&Preferences') |
|---|
| 167 | menuBar.Append(helpMenu, '&Help') |
|---|
| 168 | |
|---|
| 169 | self.SetMenuBar(menuBar) |
|---|
| 170 | |
|---|
| 171 | def createWaveformPanel(self, parent, waveform, preview = False): |
|---|
| 172 | |
|---|
| 173 | wPanel = scrolledpanel.ScrolledPanel(parent, -1, name=waveform.getName()) |
|---|
| 174 | wSizer = wx.BoxSizer(wx.VERTICAL) |
|---|
| 175 | componentList = waveform.getAllComponents() |
|---|
| 176 | |
|---|
| 177 | for component in componentList: |
|---|
| 178 | cPanel = self.createComponentPanel(wPanel,component, preview) |
|---|
| 179 | wSizer.Add(cPanel, 0, wx.ALIGN_LEFT | wx.GROW, 10) |
|---|
| 180 | |
|---|
| 181 | wPanel.SetSizer(wSizer) |
|---|
| 182 | wPanel.SetupScrolling(True, True, 20, 20) |
|---|
| 183 | |
|---|
| 184 | #No need to add the panels to the wpanels list when preview is On |
|---|
| 185 | if preview is False: |
|---|
| 186 | self.wpanels.append(wPanel) |
|---|
| 187 | |
|---|
| 188 | wSizer.Fit(wPanel) |
|---|
| 189 | return wPanel |
|---|
| 190 | |
|---|
| 191 | def createComponentPanel(self, wPanel, component, preview = False): |
|---|
| 192 | cPanel = wx.Panel(wPanel, -1, name=component.getName()) |
|---|
| 193 | sbox = wx.StaticBox(cPanel, -1, component.getName()) |
|---|
| 194 | sboxSizer = wx.StaticBoxSizer(sbox, wx.VERTICAL) |
|---|
| 195 | prpWidgetList = [] |
|---|
| 196 | |
|---|
| 197 | if not component.isVisible(): |
|---|
| 198 | cPanel.Hide() |
|---|
| 199 | |
|---|
| 200 | propertyList = component.getAllProperties() |
|---|
| 201 | #properites of a component are laid on the component panel using a gridbag sizer |
|---|
| 202 | #Each widget takes one cell except a Slider which spans across multiple columns |
|---|
| 203 | |
|---|
| 204 | for property in propertyList: |
|---|
| 205 | widget = property.getWidget() |
|---|
| 206 | |
|---|
| 207 | plabel = wx.StaticText(cPanel, -1, property.getName(), name = property.getName()) |
|---|
| 208 | pWindow = self.mapWidgetToWindow(cPanel, property, widget) |
|---|
| 209 | pWindow.SetToolTipString(property.getDesc()) |
|---|
| 210 | |
|---|
| 211 | if not property.isVisible(): |
|---|
| 212 | plabel.Hide() |
|---|
| 213 | pWindow.Hide() |
|---|
| 214 | |
|---|
| 215 | if preview is True: |
|---|
| 216 | #Don't allow any manipulation on properties in Preview form. |
|---|
| 217 | pWindow.Enable(False) |
|---|
| 218 | |
|---|
| 219 | #Create a popup menu for this property |
|---|
| 220 | self.attachPopupMenuToProp(wPanel, pWindow, property) |
|---|
| 221 | |
|---|
| 222 | windowType = pWindow.__class__ |
|---|
| 223 | eventType = wx.EVT_KILL_FOCUS |
|---|
| 224 | |
|---|
| 225 | #Find the type of event corresponding to the window in use |
|---|
| 226 | if windowType is wx.TextCtrl or windowType is wx.SpinCtrl: |
|---|
| 227 | pWindow.Bind(wx.EVT_TEXT_ENTER, self.OnPropValueChanged, pWindow) |
|---|
| 228 | pWindow.Bind(wx.EVT_KILL_FOCUS, self.OnPropValueChanged, pWindow) |
|---|
| 229 | elif windowType is wx.Slider: |
|---|
| 230 | pWindow.Bind(wx.EVT_COMMAND_SCROLL, self.OnPropValueChanged, pWindow) |
|---|
| 231 | elif windowType is wx.CheckBox: |
|---|
| 232 | pWindow.Bind(wx.EVT_CHECKBOX, self.OnPropValueChanged, pWindow) |
|---|
| 233 | |
|---|
| 234 | #checkbox has a label associated with itself. so no need to add separate label |
|---|
| 235 | if pWindow.__class__ is wx.CheckBox: |
|---|
| 236 | plabel.SetLabel("") |
|---|
| 237 | |
|---|
| 238 | prpWidgetList.append(plabel) |
|---|
| 239 | prpWidgetList.append(pWindow) |
|---|
| 240 | |
|---|
| 241 | #prpWidgetList contains the label and widgets for all the properties of this component |
|---|
| 242 | #addPropToCompSizer creates a new gridbagsizer and adds the labels and widgets contained |
|---|
| 243 | #in the prpWidgetList |
|---|
| 244 | |
|---|
| 245 | gbagSizer = self.addPropToCompSizer(prpWidgetList) |
|---|
| 246 | |
|---|
| 247 | sboxSizer.SetMinSize(gbagSizer.GetMinSize()) |
|---|
| 248 | sboxSizer.Add(gbagSizer, 1, wx.ALIGN_CENTER | wx.EXPAND, 10) |
|---|
| 249 | cPanel.SetSizer(sboxSizer) |
|---|
| 250 | |
|---|
| 251 | #After layingout the widgets (labels & controls) for all the properties, |
|---|
| 252 | #attach a popupmenu at component level. i.e. for each component panel |
|---|
| 253 | |
|---|
| 254 | self.attachPopupToComponent(component, cPanel) |
|---|
| 255 | return cPanel |
|---|
| 256 | |
|---|
| 257 | def addPropToCompSizer(self, propList): |
|---|
| 258 | #IMPORTANT NOTE: proplist should have items in the following way. |
|---|
| 259 | #[label, window, label, window, label, window, .... ] |
|---|
| 260 | index = 0 |
|---|
| 261 | gridSizer = wx.GridSizer(2,4,5,5) |
|---|
| 262 | |
|---|
| 263 | while (index < len(propList) ): |
|---|
| 264 | plabel = propList[index] |
|---|
| 265 | pWindow = propList[index+1] |
|---|
| 266 | |
|---|
| 267 | #if the windows are hidden, don't add them to the sizer. |
|---|
| 268 | #They will be added when the user select the properties again. |
|---|
| 269 | if (not plabel.IsShown()) or (not pWindow.IsShown()): |
|---|
| 270 | index = index + 2 |
|---|
| 271 | continue |
|---|
| 272 | gridSizer.Add(plabel, 0) |
|---|
| 273 | gridSizer.Add(pWindow, 0) |
|---|
| 274 | index = index + 2 |
|---|
| 275 | return gridSizer |
|---|
| 276 | |
|---|
| 277 | def attachPopupToComponent(self, component, cPanel): |
|---|
| 278 | cPopup = wx.Menu(title='') |
|---|
| 279 | moveUp = cPopup.Append(wx.NewId(), 'Move up') |
|---|
| 280 | moveDown = cPopup.Append(wx.NewId(), 'Move Down') |
|---|
| 281 | save = cPopup.Append(wx.NewId(), 'Save') |
|---|
| 282 | saveAs = cPopup.Append(wx.NewId(), 'Save As') |
|---|
| 283 | |
|---|
| 284 | #save and saveAs will be implemented in next release.disable for now |
|---|
| 285 | save.Enable(False) |
|---|
| 286 | saveAs.Enable(False) |
|---|
| 287 | |
|---|
| 288 | prpMenu = wx.Menu() |
|---|
| 289 | #All properties are enabled by default. |
|---|
| 290 | prpList = component.getAllProperties() |
|---|
| 291 | for prp in prpList: |
|---|
| 292 | chkMenuItem = prpMenu.AppendCheckItem(wx.NewId(), prp.getName()) |
|---|
| 293 | chkMenuItem.Check(True) |
|---|
| 294 | self.Bind(wx.EVT_MENU, self.OnPropertySelect, chkMenuItem) |
|---|
| 295 | |
|---|
| 296 | cPopup.AppendMenu(wx.NewId(), 'Properties', prpMenu) |
|---|
| 297 | |
|---|
| 298 | wPanel = cPanel.GetParent() |
|---|
| 299 | |
|---|
| 300 | if self.compPopupMenus.has_key(wPanel): |
|---|
| 301 | cPanelDict = self.compPopupMenus[wPanel] |
|---|
| 302 | if cPanelDict.has_key(cPanel.GetName()) is False: |
|---|
| 303 | cPanelDict[str(cPanel.GetName())] = cPopup |
|---|
| 304 | else: |
|---|
| 305 | self.compPopupMenus[wPanel] = {cPanel.GetName():cPopup} |
|---|
| 306 | |
|---|
| 307 | self.Bind(wx.EVT_MENU, self.OnComponentMoveUp, moveUp) |
|---|
| 308 | self.Bind(wx.EVT_MENU, self.OnComponentMoveDown, moveDown) |
|---|
| 309 | |
|---|
| 310 | cPanel.Bind(wx.EVT_RIGHT_DOWN, self.OnComponentRightClick) |
|---|
| 311 | |
|---|
| 312 | |
|---|
| 313 | def OnComponentRightClick(self, event): |
|---|
| 314 | src = event.GetEventObject() |
|---|
| 315 | curWPanel = self.getCurrentPanel() |
|---|
| 316 | #Storing the reference to current component panel in a temp variable |
|---|
| 317 | #This temp will be used to map the context menu and the component menu in |
|---|
| 318 | #the event handler for PropertySelect and other items in Context menu also. |
|---|
| 319 | |
|---|
| 320 | self.tempComp = src |
|---|
| 321 | for wpanel in self.compPopupMenus.keys(): |
|---|
| 322 | if wpanel is curWPanel: |
|---|
| 323 | windowDict = self.compPopupMenus[wpanel] |
|---|
| 324 | src.PopupMenu(windowDict[str(src.GetName())]) |
|---|
| 325 | |
|---|
| 326 | def attachPopupMenuToProp(self, wPanel, window, property): |
|---|
| 327 | pSubMenu = wx.Menu(title='') |
|---|
| 328 | #default = property.getWidget() |
|---|
| 329 | default = self.controller.getDefaultWidget(property.getType()) |
|---|
| 330 | optList = self.controller.getOptionalWidgets(property.getType()) |
|---|
| 331 | |
|---|
| 332 | mItem = pSubMenu.AppendRadioItem(wx.NewId(), default.type) |
|---|
| 333 | self.Bind(wx.EVT_MENU, self.PropPopupHandler, id = mItem.GetId()) |
|---|
| 334 | for optWidget in optList: |
|---|
| 335 | mItem = pSubMenu.AppendRadioItem(wx.NewId(), optWidget.type) |
|---|
| 336 | self.Bind(wx.EVT_MENU, self.PropPopupHandler, id = mItem.GetId()) |
|---|
| 337 | if property.getWidget().type == optWidget.type: |
|---|
| 338 | mItem.Check(True) |
|---|
| 339 | |
|---|
| 340 | pSubMenu.AppendSeparator() |
|---|
| 341 | configure = pSubMenu.Append(wx.NewId(), 'Configure') |
|---|
| 342 | self.Bind(wx.EVT_MENU, self.PropConfigureHandler, id = configure.GetId()) |
|---|
| 343 | |
|---|
| 344 | #Configure shuold be enabled only for slider and spin buttons. |
|---|
| 345 | #If other options are enabled, then disable the Configure Menu Item |
|---|
| 346 | self.propPopUpUpdate(pSubMenu) |
|---|
| 347 | |
|---|
| 348 | chgMenu = wx.Menu(title='') |
|---|
| 349 | chgMenuItem = wx.MenuItem(chgMenu, wx.NewId(), 'Change To', subMenu = pSubMenu) |
|---|
| 350 | chgMenu.AppendItem(chgMenuItem) |
|---|
| 351 | |
|---|
| 352 | #Associate the pop Menu wit the window |
|---|
| 353 | cpRef = property.getParent().getName() + '/' + property.getName() |
|---|
| 354 | |
|---|
| 355 | if self.prpPopupMenus.has_key(wPanel): |
|---|
| 356 | subDict = self.prpPopupMenus[wPanel] |
|---|
| 357 | if subDict.has_key(cpRef) is False: |
|---|
| 358 | subDict[cpRef] = chgMenu |
|---|
| 359 | else: |
|---|
| 360 | self.prpPopupMenus[wPanel] = {cpRef:chgMenu} |
|---|
| 361 | |
|---|
| 362 | window.Bind(wx.EVT_RIGHT_DOWN, self.OnPropRightClick) |
|---|
| 363 | |
|---|
| 364 | def OnPropRightClick(self, event): |
|---|
| 365 | src = event.GetEventObject() |
|---|
| 366 | curPanel = self.getCurrentPanel() |
|---|
| 367 | #The widget(actual wxPython windows) on which the Popupmenu is invoked is |
|---|
| 368 | #stored in a temp variable to access it later during the events generated |
|---|
| 369 | #by PopUpMenu |
|---|
| 370 | |
|---|
| 371 | self.tempProp = src |
|---|
| 372 | for wpanel in self.prpPopupMenus.keys(): |
|---|
| 373 | if wpanel is curPanel: |
|---|
| 374 | |
|---|
| 375 | #=============================================================================== |
|---|
| 376 | # A pop-up menu is associated with each property. the member variable prpPopupMenus |
|---|
| 377 | # is a hash object indexed by waveform names. Value of a hash object points to another |
|---|
| 378 | # hash which indexes the popup menus by component_name/property_name. |
|---|
| 379 | #=============================================================================== |
|---|
| 380 | |
|---|
| 381 | windowDict = self.prpPopupMenus[wpanel] |
|---|
| 382 | cpRef = src.GetParent().GetName() + '/' + src.GetName() |
|---|
| 383 | src.GetParent().PopupMenu(windowDict[cpRef]) |
|---|
| 384 | |
|---|
| 385 | |
|---|
| 386 | def PropPopupHandler(self, event): |
|---|
| 387 | srcId = event.GetId() |
|---|
| 388 | mItems = event.GetEventObject().GetMenuItems() |
|---|
| 389 | |
|---|
| 390 | #Enable the configure option only slider and spin box to set their min and |
|---|
| 391 | #max values. |
|---|
| 392 | |
|---|
| 393 | self.propPopUpUpdate(event.GetEventObject()) |
|---|
| 394 | |
|---|
| 395 | for mItem in mItems: |
|---|
| 396 | if mItem.GetId() == srcId: |
|---|
| 397 | #self.tempProp is set to identify the property when Popupmenu is invoked. |
|---|
| 398 | property = self.tempProp |
|---|
| 399 | component = property.GetParent() |
|---|
| 400 | wform = component.GetParent() |
|---|
| 401 | self.model.changePropertyWidget(component.GetName(), |
|---|
| 402 | property.GetName(), mItem.GetItemLabel()) |
|---|
| 403 | |
|---|
| 404 | def PropConfigureHandler(self, event): |
|---|
| 405 | propertyCtrl = self.tempProp |
|---|
| 406 | cPanel = propertyCtrl.GetParent() |
|---|
| 407 | wPanel = cPanel.GetParent() |
|---|
| 408 | |
|---|
| 409 | #Get reference to the property thruogh its compnent and waveform. |
|---|
| 410 | #Then, get the widget reference from the property |
|---|
| 411 | wform = self.model.getActiveWaveform() |
|---|
| 412 | component = wform.getComponent(cPanel.GetName()) |
|---|
| 413 | property = component.findPropertyByName(propertyCtrl.GetName()) |
|---|
| 414 | |
|---|
| 415 | widget = property.getWidget() |
|---|
| 416 | |
|---|
| 417 | if propertyCtrl.__class__ is wx.SpinCtrl \ |
|---|
| 418 | or propertyCtrl.__class__ is wx.Slider: |
|---|
| 419 | curMin, curMax = property.getRange() |
|---|
| 420 | curValue = property.getValue() |
|---|
| 421 | #curMin = widget.getMin() |
|---|
| 422 | #curMax = widget.getMax() |
|---|
| 423 | title = 'Widget Configuration' |
|---|
| 424 | confDialog = utils.ConfigureWidget(self, title, curValue) |
|---|
| 425 | confDialog.setMin(curMin) |
|---|
| 426 | confDialog.setMax(curMax) |
|---|
| 427 | |
|---|
| 428 | confDialog.ShowModal() |
|---|
| 429 | |
|---|
| 430 | #Get the new min and max once the dialog is destroyed in the |
|---|
| 431 | #event handlers of Ok and Cancel defined in ConfigureWidget |
|---|
| 432 | newMin = confDialog.getMin() |
|---|
| 433 | newMax = confDialog.getMax() |
|---|
| 434 | |
|---|
| 435 | #No need to udpate the model if the values are not changed |
|---|
| 436 | if (newMin == curMin) and (newMax == curMax): |
|---|
| 437 | return |
|---|
| 438 | else: |
|---|
| 439 | # the newMin and newMax values will be updated to the range attribute of the property |
|---|
| 440 | status = self.model.configurePropertyWidget(cPanel.GetName(), propertyCtrl.GetName(), newMin, newMax) |
|---|
| 441 | if status is False: |
|---|
| 442 | utils.showMessage("Invalid range of values (" + str(newMin) + "," + str(newMax) + ")" , utils.NON_FATAL) |
|---|
| 443 | return |
|---|
| 444 | |
|---|
| 445 | def propPopUpUpdate(self, menu): |
|---|
| 446 | menuItems = menu.GetMenuItems() |
|---|
| 447 | confItemId = menu.FindItem('Configure') |
|---|
| 448 | confItem = menu.FindItemById(confItemId) |
|---|
| 449 | confItem.Enable(False) |
|---|
| 450 | |
|---|
| 451 | for mItem in menuItems: |
|---|
| 452 | if mItem.GetItemLabel() == "spin" or mItem.GetItemLabel() == "slider": |
|---|
| 453 | if mItem.IsChecked(): |
|---|
| 454 | confItem.Enable(True) |
|---|
| 455 | |
|---|
| 456 | def mapWidgetToWindow(self, parent, property, widget): |
|---|
| 457 | window = None |
|---|
| 458 | label = None |
|---|
| 459 | pValue = property.getValue() |
|---|
| 460 | |
|---|
| 461 | widgetType = widget.type |
|---|
| 462 | |
|---|
| 463 | if widgetType == "text": |
|---|
| 464 | window = wx.TextCtrl(parent, -1, str(pValue), style = wx.TE_PROCESS_ENTER) |
|---|
| 465 | elif widgetType == "spin": |
|---|
| 466 | minV, maxV = property.getRange() |
|---|
| 467 | window = wx.SpinCtrl(parent, -1, str(pValue), min = minV, max = maxV, style = wx.TE_PROCESS_ENTER) |
|---|
| 468 | elif widgetType == "slider": |
|---|
| 469 | minV, maxV = property.getRange() |
|---|
| 470 | if widget.parameters["style"] == "HORIZONTAL": |
|---|
| 471 | styleV = wx.SL_HORIZONTAL | wx.SL_LABELS |
|---|
| 472 | elif widget.parameters["style"] == "VERTICAL": |
|---|
| 473 | styleV = wx.SL_VERTICAL | wx.SL_LABELS |
|---|
| 474 | window = wx.Slider(parent, -1, int(pValue), minValue = minV, maxValue = maxV, style = styleV, size=(120,35)) |
|---|
| 475 | elif widgetType == "checkbox": |
|---|
| 476 | window = wx.CheckBox(parent, -1, property.getName()) |
|---|
| 477 | elif widgetType == "listbox": |
|---|
| 478 | if (pValue is not None) and (type(pValue) is list): |
|---|
| 479 | window = wx.TextCtrl(parent, -1, str(pValue)) |
|---|
| 480 | else: |
|---|
| 481 | window = wx.TextCtrl(parent, -1, str(None)) |
|---|
| 482 | else: |
|---|
| 483 | window = wx.TextCtrl(parent, -1, str(pValue)) |
|---|
| 484 | |
|---|
| 485 | if window is not None: |
|---|
| 486 | window.SetName(property.getName()) |
|---|
| 487 | return window |
|---|
| 488 | |
|---|
| 489 | def OnPropValueChanged(self, event): |
|---|
| 490 | src = event.GetEventObject() |
|---|
| 491 | prp = src.GetName() |
|---|
| 492 | comp = src.GetParent().GetName() |
|---|
| 493 | wName = src.GetParent().GetParent().GetName() |
|---|
| 494 | wform = self.model.getWaveform(wName, WaveformModel.INSTANCE_WAVEFORM) |
|---|
| 495 | #This event is triggered whenever a property widget loses its focus. |
|---|
| 496 | #A widget loses its focus when the user switch to another widget in the same window |
|---|
| 497 | #or select a different waveform. |
|---|
| 498 | if wform is None: |
|---|
| 499 | #if event triggered as a result of object destroy or from Waveform Preview Dialog |
|---|
| 500 | #then no need to update the value. Just return |
|---|
| 501 | return |
|---|
| 502 | |
|---|
| 503 | compRef = wform.getComponent(comp) |
|---|
| 504 | prpRef = compRef.findPropertyByName(prp) |
|---|
| 505 | curVal = self.formatWidgetToModel(src.GetValue(), prpRef.getType()) |
|---|
| 506 | preVal = prpRef.getValue() |
|---|
| 507 | if curVal is not None: |
|---|
| 508 | |
|---|
| 509 | #if both the values are equal then no need to call configure() |
|---|
| 510 | if preVal == curVal: |
|---|
| 511 | return |
|---|
| 512 | else: |
|---|
| 513 | status = self.model.configure(wName, comp, prp, curVal) |
|---|
| 514 | #leave the text box as it is if status is True |
|---|
| 515 | #if the configure operation failed, revert the text value to the value stored in |
|---|
| 516 | #the model. |
|---|
| 517 | if status is False: |
|---|
| 518 | msg = "Could not configure " + prp |
|---|
| 519 | utils.showMessage(msg, utils.NON_FATAL) |
|---|
| 520 | self.formatModelToWidget(src, preVal) |
|---|
| 521 | #src.SetValue(str(preVal)) |
|---|
| 522 | |
|---|
| 523 | else: |
|---|
| 524 | msg = "Invalid value for %s/%s" % (comp, prp) + "\nEnter only '" + prpRef.getType()[1] + "' values" |
|---|
| 525 | msg = msg + "\nFor sequence types, enter values separated by comma" |
|---|
| 526 | msg = msg + " and enclosed within [] e.g. [10,20,30]" |
|---|
| 527 | |
|---|
| 528 | utils.showMessage(msg, utils.NON_FATAL) |
|---|
| 529 | self.formatModelToWidget(src, preVal) |
|---|
| 530 | self.Layout() |
|---|
| 531 | |
|---|
| 532 | def formatModelToWidget(self, widget, value): |
|---|
| 533 | if widget.__class__ is wx.TextCtrl: |
|---|
| 534 | widget.SetValue(str(value)) |
|---|
| 535 | elif widget.__class__ is wx.SpinCtrl: |
|---|
| 536 | widget.SetValue(int(value)) |
|---|
| 537 | elif widget.__class__ is wx.Slider: |
|---|
| 538 | widget.SetValue(int(value)) |
|---|
| 539 | elif widget.__class__ is wx.CheckBox: |
|---|
| 540 | if value == "True" or value == 1: |
|---|
| 541 | widget.SetValue(True) |
|---|
| 542 | else: |
|---|
| 543 | widget.SetValue(False) |
|---|
| 544 | |
|---|
| 545 | |
|---|
| 546 | def formatWidgetToModel(self, curVal, propType): |
|---|
| 547 | """ Converts the string literal into the suitable data type |
|---|
| 548 | as configured for the property""" |
|---|
| 549 | val = None |
|---|
| 550 | #propType is a tuple containing the (xmlType,datatype) |
|---|
| 551 | #e.g. ('simple','short') |
|---|
| 552 | xmlType = propType[0] |
|---|
| 553 | dtype = propType[1] |
|---|
| 554 | try: |
|---|
| 555 | if (xmlType == "simple"): |
|---|
| 556 | if dtype == "short" or dtype == "ushort": |
|---|
| 557 | val = int(curVal) |
|---|
| 558 | elif dtype == "int" or dtype == "uint": |
|---|
| 559 | val = int(curVal) |
|---|
| 560 | elif dtype == "long" or dtype == "ulong": |
|---|
| 561 | val = long(curVal) |
|---|
| 562 | elif dtype == "double" or dtype == "float": |
|---|
| 563 | val = float(curVal) |
|---|
| 564 | elif dtype == "char": |
|---|
| 565 | val = str(curVal) |
|---|
| 566 | elif type == "boolean": |
|---|
| 567 | val = curVal |
|---|
| 568 | elif dtype == "string": |
|---|
| 569 | val = str(curVal) |
|---|
| 570 | else: |
|---|
| 571 | val = None |
|---|
| 572 | #sequence values are represented as list of values separated |
|---|
| 573 | #by a comma. e.g. '[10,20,30]' |
|---|
| 574 | |
|---|
| 575 | elif (xmlType == "simplesequence"): |
|---|
| 576 | if dtype == "float": |
|---|
| 577 | val = [] |
|---|
| 578 | #strip the open and close bracket |
|---|
| 579 | listVal = curVal.lstrip('[') |
|---|
| 580 | listVal = listVal.rstrip(']') |
|---|
| 581 | for lVal in listVal.split(','): |
|---|
| 582 | val.append(float(lVal)) |
|---|
| 583 | if dtype == "string": |
|---|
| 584 | val = [] |
|---|
| 585 | #strip the open and close bracket |
|---|
| 586 | listVal = curVal.lstrip('[') |
|---|
| 587 | listVal = listVal.rstrip(']') |
|---|
| 588 | for lVal in listVal.split(','): |
|---|
| 589 | val.append(str(lVal)) |
|---|
| 590 | if dtype == "short" or dtype == "int": |
|---|
| 591 | val = [] |
|---|
| 592 | #strip the open and close bracket |
|---|
| 593 | listVal = curVal.lstrip('[') |
|---|
| 594 | listVal = listVal.rstrip(']') |
|---|
| 595 | for lVal in listVal.split(','): |
|---|
| 596 | val.append(int(lVal)) |
|---|
| 597 | |
|---|
| 598 | except(ValueError): |
|---|
| 599 | val = None |
|---|
| 600 | |
|---|
| 601 | return val |
|---|
| 602 | |
|---|
| 603 | def AddToWaveformsMenu(self, newWaveform, type): |
|---|
| 604 | wMenu = self.FindMenuInMenuBar('Waveforms') |
|---|
| 605 | |
|---|
| 606 | if type == WaveformModel.SYSTEM_WAVEFORM: |
|---|
| 607 | wSubMenu = wx.Menu() |
|---|
| 608 | install = wSubMenu.Append(-1, 'Install') |
|---|
| 609 | installAndStart = wSubMenu.Append(-1, 'Install and Start') |
|---|
| 610 | viewWform = wSubMenu.Append(-1, 'Preview') |
|---|
| 611 | properties = wSubMenu.Append(-1, 'Properties') |
|---|
| 612 | |
|---|
| 613 | wMenu.InsertMenu(0,-1, newWaveform, wSubMenu) #insert at the start of the list |
|---|
| 614 | |
|---|
| 615 | self.Bind(wx.EVT_MENU, self.OnWaveformInstall, install) |
|---|
| 616 | self.Bind(wx.EVT_MENU, self.OnWaveformInstallAndStart, installAndStart) |
|---|
| 617 | self.Bind(wx.EVT_MENU, self.OnWaveformPreview, viewWform) |
|---|
| 618 | self.Bind(wx.EVT_MENU, self.OnWaveformProperties, properties) |
|---|
| 619 | |
|---|
| 620 | def AddToComponentsMenu(self, newComponent, isVisible): |
|---|
| 621 | cMenu = self.FindMenuInMenuBar('Components') |
|---|
| 622 | citem = cMenu.AppendCheckItem(-1, newComponent) |
|---|
| 623 | self.Bind(wx.EVT_MENU, self.OnComponentMenuClick, citem) |
|---|
| 624 | |
|---|
| 625 | if isVisible: |
|---|
| 626 | citem.Check(True) |
|---|
| 627 | |
|---|
| 628 | def OnWaveformInstall(self, event): |
|---|
| 629 | chosenMenu = event.GetEventObject() |
|---|
| 630 | parent = chosenMenu.GetParent() |
|---|
| 631 | |
|---|
| 632 | for mItem in parent.GetMenuItems(): |
|---|
| 633 | if mItem.GetSubMenu() is chosenMenu: |
|---|
| 634 | self.controller.installWaveform(mItem.GetItemLabel(), False) |
|---|
| 635 | break |
|---|
| 636 | |
|---|
| 637 | def OnWaveformInstallAndStart(self, event): |
|---|
| 638 | chosenMenu = event.GetEventObject() |
|---|
| 639 | parent = chosenMenu.GetParent() |
|---|
| 640 | |
|---|
| 641 | for mItem in parent.GetMenuItems(): |
|---|
| 642 | if mItem.GetSubMenu() is chosenMenu: |
|---|
| 643 | self.controller.installWaveform(mItem.GetItemLabel(), True) |
|---|
| 644 | break |
|---|
| 645 | |
|---|
| 646 | def OnPropertySelect(self, event): |
|---|
| 647 | srcId = event.GetId() |
|---|
| 648 | pMenu = event.GetEventObject() |
|---|
| 649 | mItemList = pMenu.GetMenuItems() |
|---|
| 650 | for mItem in mItemList: |
|---|
| 651 | if srcId == mItem.GetId(): |
|---|
| 652 | propName = mItem.GetItemLabel() |
|---|
| 653 | #self.tempComp has the reference to the component panel on which |
|---|
| 654 | #the context menu is invoked in ComponentRightClick Handler |
|---|
| 655 | compName = self.tempComp.GetName() |
|---|
| 656 | self.model.updatePropertyState(compName, propName, mItem.IsChecked()) |
|---|
| 657 | break |
|---|
| 658 | |
|---|
| 659 | def OnComponentMoveUp(self, event): |
|---|
| 660 | compName = self.tempComp.GetName() |
|---|
| 661 | wformName = self.tempComp.GetParent().GetName() |
|---|
| 662 | self.model.moveComponentUp(wformName, compName) |
|---|
| 663 | |
|---|
| 664 | def OnComponentMoveDown(self, event): |
|---|
| 665 | compName = self.tempComp.GetName() |
|---|
| 666 | wformName = self.tempComp.GetParent().GetName() |
|---|
| 667 | self.model.moveComponentDown(wformName, compName) |
|---|
| 668 | |
|---|
| 669 | |
|---|
| 670 | def OnWaveformPreview(self, event): |
|---|
| 671 | chosenMenu = event.GetEventObject() |
|---|
| 672 | parent = chosenMenu.GetParent() |
|---|
| 673 | |
|---|
| 674 | for mItem in parent.GetMenuItems(): |
|---|
| 675 | if mItem.GetSubMenu() is chosenMenu: |
|---|
| 676 | wformName = mItem.GetItemLabel() |
|---|
| 677 | waveform = self.model.getWaveform(wformName, WaveformModel.SYSTEM_WAVEFORM) |
|---|
| 678 | title = 'Preview - ' + wformName |
|---|
| 679 | |
|---|
| 680 | previewFrame = wx.Frame(self, -1, title, OSSIE_WAVEAPP_DIMENSION) |
|---|
| 681 | wPanel = self.createWaveformPanel(previewFrame, waveform, preview = True) |
|---|
| 682 | wPanel.Show() |
|---|
| 683 | previewFrame.Show() |
|---|
| 684 | break |
|---|
| 685 | |
|---|
| 686 | def OnWaveformProperties(self, event): |
|---|
| 687 | chosenMenu = event.GetEventObject() |
|---|
| 688 | parent = chosenMenu.GetParent() |
|---|
| 689 | |
|---|
| 690 | for mItem in parent.GetMenuItems(): |
|---|
| 691 | if mItem.GetSubMenu() is chosenMenu: |
|---|
| 692 | wformName = mItem.GetItemLabel() |
|---|
| 693 | wformObj = self.model.getWaveform(wformName, WaveformModel.SYSTEM_WAVEFORM) |
|---|
| 694 | print str(wformObj) |
|---|
| 695 | title = wformName + " - Properties" |
|---|
| 696 | wformProperties = str(wformObj) |
|---|
| 697 | dlg = wx.MessageDialog(None, wformProperties, title, wx.OK | wx.ICON_INFORMATION) |
|---|
| 698 | try: |
|---|
| 699 | dlg.ShowModal() |
|---|
| 700 | finally: |
|---|
| 701 | dlg.Destroy() |
|---|
| 702 | |
|---|
| 703 | #Event Handler for page change. Update the active waveform on each page change |
|---|
| 704 | def OnNbPageChange(self, event): |
|---|
| 705 | pageId = event.GetSelection() |
|---|
| 706 | #GetPage() returns the reference to waveform panel object |
|---|
| 707 | wPanel = self.notebook.GetPage(pageId) |
|---|
| 708 | #update active waveform in the model |
|---|
| 709 | self.model.setActiveWaveform(wPanel.GetName()) |
|---|
| 710 | |
|---|
| 711 | def OnComponentMenuClick(self, event): |
|---|
| 712 | cMenu = event.GetEventObject() |
|---|
| 713 | mItemList = cMenu.GetMenuItems() |
|---|
| 714 | for mItem in mItemList: |
|---|
| 715 | self.model.updateComponentState(mItem.GetItemLabel(), mItem.IsChecked()) |
|---|
| 716 | |
|---|
| 717 | def UpdateComponentMenu(self, wform): |
|---|
| 718 | |
|---|
| 719 | componentList = wform.getAllComponents() |
|---|
| 720 | compMenu = self.FindMenuInMenuBar('Components') |
|---|
| 721 | #clear the existing items in Component Menu |
|---|
| 722 | for mItem in compMenu.GetMenuItems(): |
|---|
| 723 | compMenu.DeleteItem(mItem) |
|---|
| 724 | |
|---|
| 725 | #Now update the component Menu wit the components of currently selected waveform |
|---|
| 726 | for component in componentList: |
|---|
| 727 | self.AddToComponentsMenu(component.getName(), component.isVisible()) |
|---|
| 728 | |
|---|
| 729 | #listeners of WaveformListener interface |
|---|
| 730 | def waveformAdded(self, event): |
|---|
| 731 | wform = event.getSource() |
|---|
| 732 | #create the panel only if it is a instance waveform. |
|---|
| 733 | #For system waveform, just add it to the menu |
|---|
| 734 | wType = wform.getType() |
|---|
| 735 | if wType == WaveformModel.INSTANCE_WAVEFORM: |
|---|
| 736 | wPanel = self.createWaveformPanel(self.notebook, wform) |
|---|
| 737 | self.notebook.AddPage(wPanel, wform.getName()) |
|---|
| 738 | |
|---|
| 739 | self.AddToWaveformsMenu(wform.getName(), wType) |
|---|
| 740 | |
|---|
| 741 | def waveformRemoved(self, event): |
|---|
| 742 | |
|---|
| 743 | srcWform = event.getSource() |
|---|
| 744 | #if waveform removed is a SYSTEM_WAVEFORM, i.e. the one found in /sdr/dom/waveforms, |
|---|
| 745 | #remove the waveform from the Waveforms Menu |
|---|
| 746 | if srcWform is not None and srcWform.getType() == WaveformModel.SYSTEM_WAVEFORM: |
|---|
| 747 | wformsMenu = self.FindMenuInMenuBar('Waveforms') |
|---|
| 748 | menuItems = wformsMenu.GetMenuItems() |
|---|
| 749 | for mItem in menuItems: |
|---|
| 750 | if mItem.GetItemLabel() == srcWform.getName(): |
|---|
| 751 | wformsMenu.DeleteItem(mItem) |
|---|
| 752 | break |
|---|
| 753 | return |
|---|
| 754 | |
|---|
| 755 | curPanelId = self.notebook.GetSelection() |
|---|
| 756 | curPanel = self.notebook.GetCurrentPage() |
|---|
| 757 | wformName = curPanel.GetName() |
|---|
| 758 | self.wpanels.remove(curPanel) |
|---|
| 759 | #remove the panel from the notebook |
|---|
| 760 | self.notebook.RemovePage(curPanelId) |
|---|
| 761 | #destroy the waveform panel object |
|---|
| 762 | curPanel.Destroy() |
|---|
| 763 | |
|---|
| 764 | msg = ("%s Uninstalled !" % wformName) |
|---|
| 765 | utils.showMessage(msg, utils.INFO) |
|---|
| 766 | |
|---|
| 767 | #AdvanceSelection() sets the next available page active |
|---|
| 768 | #and trigger EVT_NOTEBOOK_PAGE_CHANGED event. The event |
|---|
| 769 | #handler OnNbPageChange() would be called that sets the |
|---|
| 770 | #active waveform thruogh model.SetActiveWaveform() |
|---|
| 771 | |
|---|
| 772 | self.notebook.AdvanceSelection(True) |
|---|
| 773 | |
|---|
| 774 | #if no running waveforms on the system? |
|---|
| 775 | if self.notebook.GetPageCount() == 0: |
|---|
| 776 | compMenu = self.FindMenuInMenuBar('Components') |
|---|
| 777 | #clear the existing items in Component Menu |
|---|
| 778 | for mItem in compMenu.GetMenuItems(): |
|---|
| 779 | compMenu.DeleteItem(mItem) |
|---|
| 780 | self.model.setActiveWaveform(None) |
|---|
| 781 | self.SetSize(OSSIE_WAVEAPP_DIMENSION) |
|---|
| 782 | #notebook.AdvanceSelection() will not trigger PAGE_CHANGED event if there is |
|---|
| 783 | #only one panel left. Hence, set the active form explicitly. |
|---|
| 784 | elif self.notebook.GetPageCount() == 1: |
|---|
| 785 | nextActiveWform = self.notebook.GetCurrentPage().GetName() |
|---|
| 786 | self.model.setActiveWaveform(nextActiveWform) |
|---|
| 787 | |
|---|
| 788 | def waveformSelected(self, event): |
|---|
| 789 | wform = event.getSource() |
|---|
| 790 | #If no waveform is there, just update the title and status Bar and return |
|---|
| 791 | if wform is None: |
|---|
| 792 | self.SetTitle(OSSIE_TITLE) |
|---|
| 793 | #self.updateStatusBar() |
|---|
| 794 | return |
|---|
| 795 | self.SetTitle(OSSIE_TITLE + ' (' + wform.getName() + ')') |
|---|
| 796 | #Component menu needs to be updated per waveform basis. |
|---|
| 797 | self.UpdateComponentMenu(wform) |
|---|
| 798 | self.Layout() |
|---|
| 799 | |
|---|
| 800 | def componentStateChanged(self, cEvent): |
|---|
| 801 | """ A listener method of ComponentListener class that is triggerred |
|---|
| 802 | whenever a component is selected/deselected in the Component Menu""" |
|---|
| 803 | |
|---|
| 804 | wPanel = self.getCurrentPanel() |
|---|
| 805 | cPanelList = wPanel.GetChildren() |
|---|
| 806 | wPanelSizer = wPanel.GetSizer() |
|---|
| 807 | componentList = self.model.getActiveWaveform().getAllComponents() |
|---|
| 808 | |
|---|
| 809 | #Detach all the existing panels from the sizer |
|---|
| 810 | for cPanel in cPanelList: |
|---|
| 811 | if wPanelSizer.GetItem(cPanel) != None: |
|---|
| 812 | wPanelSizer.Detach(cPanel) |
|---|
| 813 | cPanel.Hide() |
|---|
| 814 | |
|---|
| 815 | #Update the sizer to be inline with the order of components in Waveform Model |
|---|
| 816 | for cmp in componentList: |
|---|
| 817 | if cmp.isVisible(): |
|---|
| 818 | #print cmp.getPosition() |
|---|
| 819 | for cPanel in cPanelList: |
|---|
| 820 | if cPanel.GetName() == cmp.getName(): |
|---|
| 821 | wPanelSizer.Add(cPanel, 0, wx.ALL | wx.EXPAND, 5) |
|---|
| 822 | cPanel.Show() |
|---|
| 823 | break |
|---|
| 824 | |
|---|
| 825 | wPanelSizer.Layout() |
|---|
| 826 | wPanel.Refresh() |
|---|
| 827 | |
|---|
| 828 | def propertyStateChanged(self, event): |
|---|
| 829 | property = event.getSource() |
|---|
| 830 | component = property.getParent() |
|---|
| 831 | wPanel = self.getCurrentPanel() |
|---|
| 832 | cPanel = wPanel.FindWindowByName(component.getName()) |
|---|
| 833 | cPanelSizer = cPanel.GetSizer() |
|---|
| 834 | #Component Panel sizer is a static box sizer. ACtual widgets are contained in a |
|---|
| 835 | #gridbag sizer which in turn contained in this static box sizer |
|---|
| 836 | |
|---|
| 837 | cgsizer = cPanelSizer.GetChildren()[0].GetSizer() |
|---|
| 838 | propWidgetsList = cgsizer.GetChildren() |
|---|
| 839 | |
|---|
| 840 | #propWidgetsList stores the list of labels and widgets of properties in SizerItem format. |
|---|
| 841 | #Get the actual window from the SizerItem object before acting on the window |
|---|
| 842 | |
|---|
| 843 | #removing all the widgets contained in the sizer |
|---|
| 844 | for prpWid in propWidgetsList: |
|---|
| 845 | #prpWid is of type wx.SizerItem. Use GetWindow() to get the window tracked by this SizerItem |
|---|
| 846 | actW = prpWid.GetWindow() |
|---|
| 847 | if cgsizer.GetItem(actW) != None: |
|---|
| 848 | cgsizer.Detach(actW) |
|---|
| 849 | actW.Hide() |
|---|
| 850 | |
|---|
| 851 | prpList = component.getAllProperties() |
|---|
| 852 | propWidgetsList = cPanel.GetChildren() |
|---|
| 853 | |
|---|
| 854 | #NOTE: The while loop inside the for loop iterates over the children of |
|---|
| 855 | #the component panel. Since StaticBoxSizer is used to layout the properties, |
|---|
| 856 | #the first child of the component panel (cPanel) will always be the StaticBox |
|---|
| 857 | #object which should not be added to the gridbagsizer in addPropToCompSizer |
|---|
| 858 | #method. Hence, iterating from 1 to length of the propWidgetsList. |
|---|
| 859 | # (see the value of index ) |
|---|
| 860 | |
|---|
| 861 | newPrpList = [] |
|---|
| 862 | index = 1 |
|---|
| 863 | for prp in prpList: |
|---|
| 864 | if prp.isVisible(): |
|---|
| 865 | index = 1 |
|---|
| 866 | while ( index < (len(propWidgetsList)) ): |
|---|
| 867 | actW = propWidgetsList[index] |
|---|
| 868 | |
|---|
| 869 | if actW.GetName() == prp.getName(): |
|---|
| 870 | newPrpList.append(actW) |
|---|
| 871 | actW.Show() |
|---|
| 872 | index = index + 1 |
|---|
| 873 | |
|---|
| 874 | newCgSizer = self.addPropToCompSizer(newPrpList) |
|---|
| 875 | cPanelSizer.Remove(cgsizer) |
|---|
| 876 | cPanelSizer.Add(newCgSizer, 1, wx.ALIGN_CENTER | wx.EXPAND, 10) |
|---|
| 877 | cPanelSizer.Layout() |
|---|
| 878 | wPanel.GetSizer().Layout() |
|---|
| 879 | |
|---|
| 880 | |
|---|
| 881 | def propertyWidgetChanged(self, event): |
|---|
| 882 | property = event.getSource() |
|---|
| 883 | compRef = property.getParent() |
|---|
| 884 | wPanel = self.getCurrentPanel() |
|---|
| 885 | # DO NOT CALL replaceComponentPanel() DIRECTLY FROM HERE AS IT INVOLVES |
|---|
| 886 | # A CALL TO window.Destroy() METHOD. THIS METHOD IS STILL IN THE CONTEXT |
|---|
| 887 | # OF EVENT HANDLER INVOKED AS A RESULT OF RIGHT CLICK ON PROPERTY WIDGET. |
|---|
| 888 | # CALLING replaceComponentPanel() DIRECTLY FROM HERE WOULD **CRASH** THE |
|---|
| 889 | # APPLICATION. |
|---|
| 890 | |
|---|
| 891 | wx.CallAfter(self.replaceComponentPanel, wPanel, compRef ) |
|---|
| 892 | |
|---|
| 893 | def propertyRangeChanged(self, event): |
|---|
| 894 | propertyCtrl = self.tempProp |
|---|
| 895 | propRef = event.getSource() |
|---|
| 896 | newMin, newMax = propRef.getRange() |
|---|
| 897 | propertyCtrl.SetRange(newMin, newMax) |
|---|
| 898 | |
|---|
| 899 | #if GUI widget's current value is changed because new min, max values |
|---|
| 900 | #we have to update the new value to the model as well. |
|---|
| 901 | curWidVal = self.formatWidgetToModel(propertyCtrl.GetValue(), propRef.getType()) |
|---|
| 902 | preVal = propRef.getValue() |
|---|
| 903 | if preVal == curWidVal: |
|---|
| 904 | pass |
|---|
| 905 | else: |
|---|
| 906 | pName = propertyCtrl.GetName() |
|---|
| 907 | cName = propertyCtrl.GetParent().GetName() |
|---|
| 908 | wName = propertyCtrl.GetParent().GetParent().GetName() |
|---|
| 909 | |
|---|
| 910 | status = self.model.configure(wName, cName, pName, curWidVal) |
|---|
| 911 | #leave the text box as it is if status is True |
|---|
| 912 | #if the configure operation failed, revert the text value to the value stored in |
|---|
| 913 | #the model. |
|---|
| 914 | if status is False: |
|---|
| 915 | msg = "Could not configure " + pName |
|---|
| 916 | utils.showMessage(msg, utils.NON_FATAL) |
|---|
| 917 | self.formatModelToWidget(propertyCtrl, preVal) |
|---|
| 918 | |
|---|
| 919 | return |
|---|
| 920 | # if propertyCtrl.__class__ is wx.SpinCtrl: |
|---|
| 921 | # propertyCtrl.SetRange(newMin, newMax) |
|---|
| 922 | # if propertyCtrl.__class__ is wx.Slider: |
|---|
| 923 | # propertyCtrl.SetMin(newMin) |
|---|
| 924 | # propertyCtrl.SetMax(newMax) |
|---|
| 925 | |
|---|
| 926 | def FindMenuInMenuBar(self, title): |
|---|
| 927 | pos = self.GetMenuBar().FindMenu(title) |
|---|
| 928 | return self.GetMenuBar().GetMenu(pos) |
|---|
| 929 | |
|---|
| 930 | def getCurrentPanel(self): |
|---|
| 931 | return self.notebook.GetCurrentPage() |
|---|
| 932 | |
|---|
| 933 | def replaceComponentPanel(self, wPanel, component): |
|---|
| 934 | |
|---|
| 935 | # Find the component to be replaced from the children list of current |
|---|
| 936 | # active waveform panel. Replace the Old component panel in the waveform |
|---|
| 937 | # panel's sizer with the compnent panel created new and then destroy the |
|---|
| 938 | # old component panel |
|---|
| 939 | # |
|---|
| 940 | oldCPanel = wPanel.FindWindowByName(component.getName()) |
|---|
| 941 | newCPanel = self.createComponentPanel(wPanel, component) |
|---|
| 942 | wSizer = wPanel.GetSizer() |
|---|
| 943 | wSizer.Replace(oldCPanel, newCPanel) |
|---|
| 944 | |
|---|
| 945 | wSizer.Fit(wPanel) |
|---|
| 946 | wPanel.SetSizer(wSizer) |
|---|
| 947 | wSizer.Layout() |
|---|
| 948 | oldCPanel.Destroy() |
|---|
| 949 | |
|---|
| 950 | def OnRefresh(self, event): |
|---|
| 951 | |
|---|
| 952 | self.controller.refresh() |
|---|
| 953 | |
|---|
| 954 | def waveformRefresh(self, event): |
|---|
| 955 | wformsTobeRemoved = event.getSource() |
|---|
| 956 | wformMenu = self.FindMenuInMenuBar('Waveforms') |
|---|
| 957 | |
|---|
| 958 | for wformName in wformsTobeRemoved: |
|---|
| 959 | wPanel = self.getWaveformPanel(wformName) |
|---|
| 960 | self.wpanels.remove(wPanel) |
|---|
| 961 | self.compPopupMenus.pop(wPanel) |
|---|
| 962 | self.prpPopupMenus.pop(wPanel) |
|---|
| 963 | wPanel.Destroy() |
|---|
| 964 | |
|---|
| 965 | #update the menu display |
|---|
| 966 | menuItems = wformMenu.GetMenuItems() |
|---|
| 967 | |
|---|
| 968 | #remove the selected waveform from the menu list |
|---|
| 969 | for mItem in menuItems: |
|---|
| 970 | if mItem.GetItemLabel() == wformName : |
|---|
| 971 | wformMenu.RemoveItem(mItem) |
|---|
| 972 | mItem.Destroy() |
|---|
| 973 | break |
|---|
| 974 | |
|---|
| 975 | for wPanel in self.wpanels: |
|---|
| 976 | cPanelList = wPanel.GetChildren() |
|---|
| 977 | wformRef = self.model.getWaveform(wPanel.GetName(), WaveformModel.INSTANCE_WAVEFORM) |
|---|
| 978 | for cPanel in cPanelList: |
|---|
| 979 | compRef = wformRef.getComponent(cPanel.GetName()) |
|---|
| 980 | prpList = compRef.getAllProperties() |
|---|
| 981 | prpWidgetList = cPanel.GetChildren() |
|---|
| 982 | |
|---|
| 983 | for prpW in prpWidgetList: |
|---|
| 984 | if type(prpW) is wx.TextCtrl: |
|---|
| 985 | prpW.SetValue(str(compRef.findPropertyByName(prpW.GetName()).getValue())) |
|---|
| 986 | elif type(prpW) is wx.SpinCtrl: |
|---|
| 987 | prpW.SetValue(int(compRef.findPropertyByName(prpW.GetName()).getValue())) |
|---|
| 988 | elif type(prpW) is wx.Slider: |
|---|
| 989 | prpW.SetValue(int(compRef.findPropertyByName(prpW.GetName()).getValue())) |
|---|
| 990 | |
|---|
| 991 | if (self.model.getActiveWaveform() is None): |
|---|
| 992 | nextActiveWform = None |
|---|
| 993 | #make the first available waveform active |
|---|
| 994 | menuItems = wformMenu.GetMenuItems() |
|---|
| 995 | for mItem in menuItems: |
|---|
| 996 | if mItem.IsCheckable(): |
|---|
| 997 | mItem.Check() |
|---|
| 998 | nextActiveWform = mItem.GetItemLabel() |
|---|
| 999 | break |
|---|
| 1000 | |
|---|
| 1001 | #no running waveforms on the system |
|---|
| 1002 | if nextActiveWform is None: |
|---|
| 1003 | self.SetSize(OSSIE_WAVEAPP_DIMENSION) |
|---|
| 1004 | return |
|---|
| 1005 | self.model.setActiveWaveform(nextActiveWform) |
|---|
| 1006 | |
|---|
| 1007 | def getWaveformPanel(self, wformName): |
|---|
| 1008 | for wPanel in self.wpanels: |
|---|
| 1009 | if (wformName == wPanel.GetName()): |
|---|
| 1010 | return wPanel |
|---|
| 1011 | |
|---|
| 1012 | |
|---|
| 1013 | def OnOpenLayout(self, event): |
|---|
| 1014 | pass |
|---|
| 1015 | def OnSaveLayout(self, event): |
|---|
| 1016 | self.model.waveformToXML() |
|---|
| 1017 | pass |
|---|
| 1018 | def OnSaveLayoutAs(self, event): |
|---|
| 1019 | pass |
|---|
| 1020 | def OnExit(self, event): |
|---|
| 1021 | pass |
|---|
| 1022 | def OnWidgetSettings(self, event): |
|---|
| 1023 | pass |
|---|
| 1024 | def OnAbout(self, event): |
|---|
| 1025 | pass |
|---|
| 1026 | |
|---|