root/ossiedev/trunk/tools/wavedash/src/WavedashView.py @ 10140

Revision 10140, 47.9 KB (checked in by Snyder.Jason, 3 years ago)

changes to allow updating groups of properties at once

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