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

Revision 10014, 42.9 KB (checked in by deepan, 3 years ago)

corrected min,max configuration issue for GUI widgets

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        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   
Note: See TracBrowser for help on using the browser.