Esempio n. 1
0
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.set_title("Explore Inspector")

        layout = QtGui.QVBoxLayout()
        layout.setMargin(2)
        layout.setSpacing(3)

        self.controller = None
        self.pe_properties = QParamExpProperties()
        p_prop_group = QtGui.QGroupBox(self.pe_properties.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.pe_properties)
        p_prop_group.setLayout(g_layout)
        layout.addWidget(p_prop_group)
        self.virtual_cell = QVirtualCellWindow()
        v_cell_group = QtGui.QGroupBox(self.virtual_cell.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.virtual_cell)
        v_cell_group.setLayout(g_layout)
        layout.addWidget(v_cell_group)
        self.setLayout(layout)
        self.addButtonsToToolbar()
Esempio n. 2
0
    def __init__(self, parent=None):
        """ QParameterExplorationTab(parent: QWidget)
                                    -> QParameterExplorationTab
        Make it a main window with dockable area and a
        QParameterExplorationTable
        
        """
        QDockContainer.__init__(self, parent)
        self.setWindowTitle('Parameter Exploration')
        self.toolWindow().setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
        self.toolWindow().hide()

        self.peWidget = QParameterExplorationWidget()
        self.setCentralWidget(self.peWidget)
        self.connect(self.peWidget.table,
                     QtCore.SIGNAL('exploreChange(bool)'),
                     self.exploreChange)

        self.paramView = QParameterView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.paramView.toolWindow())
        
        self.annotatedPipelineView = QAnnotatedPipelineView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.annotatedPipelineView.toolWindow())
        
        self.virtualCell = QVirtualCellWindow(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.virtualCell.toolWindow())
        
        self.controller = None
        self.currentVersion = -1
Esempio n. 3
0
    def __init__(self, parent=None):
        """ QParameterExplorationTab(parent: QWidget)
                                    -> QParameterExplorationTab
        Make it a main window with dockable area and a
        QParameterExplorationTable
        
        """
        QDockContainer.__init__(self, parent)
        self.setWindowTitle('Parameter Exploration')
        self.toolWindow().setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
        self.toolWindow().hide()

        self.peWidget = QParameterExplorationWidget()
        self.setCentralWidget(self.peWidget)
        self.connect(self.peWidget.table,
                     QtCore.SIGNAL('exploreChange(bool)'),
                     self.exploreChange)

        self.paramView = QParameterView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.paramView.toolWindow())
        
        self.annotatedPipelineView = QAnnotatedPipelineView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.annotatedPipelineView.toolWindow())
        
        self.virtualCell = QVirtualCellWindow(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.virtualCell.toolWindow())
        
        self.controller = None
        self.currentVersion = -1
Esempio n. 4
0
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.set_title("Explore Inspector")

        layout = QtGui.QVBoxLayout()
        layout.setMargin(2)
        layout.setSpacing(3)

        self.pe_properties = QParamExpProperties()
        p_prop_group = QtGui.QGroupBox(self.pe_properties.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.pe_properties)
        p_prop_group.setLayout(g_layout)
        layout.addWidget(p_prop_group)
        self.virtual_cell = QVirtualCellWindow()
        v_cell_group = QtGui.QGroupBox(self.virtual_cell.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.virtual_cell)
        v_cell_group.setLayout(g_layout)
        layout.addWidget(v_cell_group)
        self.setLayout(layout)
        self.addButtonsToToolbar()
Esempio n. 5
0
class QParameterExplorationTab(QDockContainer, QToolWindowInterface):
    """
    QParameterExplorationTab is a tab containing different widgets
    related to parameter exploration
    
    """
    explorationId = 0
    
    def __init__(self, parent=None):
        """ QParameterExplorationTab(parent: QWidget)
                                    -> QParameterExplorationTab
        Make it a main window with dockable area and a
        QParameterExplorationTable
        
        """
        QDockContainer.__init__(self, parent)
        self.setWindowTitle('Parameter Exploration')
        self.toolWindow().setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
        self.toolWindow().hide()

        self.peWidget = QParameterExplorationWidget()
        self.setCentralWidget(self.peWidget)
        self.connect(self.peWidget.table,
                     QtCore.SIGNAL('exploreChange(bool)'),
                     self.exploreChange)

        self.paramView = QParameterView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.paramView.toolWindow())
        
        self.annotatedPipelineView = QAnnotatedPipelineView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.annotatedPipelineView.toolWindow())
        
        self.virtualCell = QVirtualCellWindow(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.virtualCell.toolWindow())
        
        self.controller = None
        self.currentVersion = -1

    def addViewActionsToMenu(self, menu):
        """addViewActionsToMenu(menu: QMenu) -> None
        Add toggle view actions to menu
        
        """
        menu.addAction(self.paramView.toolWindow().toggleViewAction())
        menu.addAction(self.annotatedPipelineView.toolWindow().toggleViewAction())
        menu.addAction(self.virtualCell.toolWindow().toggleViewAction())

    def removeViewActionsFromMenu(self, menu):
        """removeViewActionsFromMenu(menu: QMenu) -> None
        Remove toggle view actions from menu
        
        """
        menu.removeAction(self.paramView.toolWindow().toggleViewAction())
        menu.removeAction(self.annotatedPipelineView.toolWindow().toggleViewAction())
        menu.removeAction(self.virtualCell.toolWindow().toggleViewAction())
        
    def setController(self, controller):
        """ setController(controller: VistrailController) -> None
        Assign a controller to the parameter exploration tab
        
        """
        self.controller = controller

    def getParameterExploration(self):
        """ getParameterExploration() -> string
        Generates an XML string that represents the current
        parameter exploration, and which can be loaded with
        setParameterExploration().
        
        """
        # Construct xml for persisting parameter exploration
        escape_dict = { "'":"'", '"':'"', '\n':'
' }
        timestamp = strftime(current_time(), '%Y-%m-%d %H:%M:%S')
        # TODO: For now, we use the timestamp as the 'name' - Later, we should set 'name' based on a UI input field
        xml = '\t<paramexp dims="%s" layout="%s" date="%s" name="%s">' % (str(self.peWidget.table.label.getCounts()), str(self.virtualCell.getConfiguration()[2]), timestamp, timestamp)
        for i in xrange(self.peWidget.table.layout().count()):
            pEditor = self.peWidget.table.layout().itemAt(i).widget()
            if pEditor and isinstance(pEditor, QParameterSetEditor):
                firstParam = True
                for paramWidget in pEditor.paramWidgets:
                    paramInfo = paramWidget.param
                    interpolator = paramWidget.editor.stackedEditors.currentWidget()
                    intType = interpolator.exploration_name
                    # Write function tag prior to the first parameter of the function
                    if firstParam:
                        xml += '\n\t\t<function id="%s" alias="%s" name="%s">' % (paramInfo.parent_id, paramInfo.is_alias, pEditor.info[0])
                        firstParam = False
                    # Write parameter tag
                    xml += '\n\t\t\t<param id="%s" dim="%s" interp="%s"' % (paramInfo.id, paramWidget.getDimension(), intType)
                    if intType == 'Linear Interpolation':
                        xml += ' min="%s" max="%s"' % (interpolator.fromEdit.get_value(), interpolator.toEdit.get_value())
                    elif intType == 'List':
                        xml += ' values="%s"' % escape(str(interpolator._str_values), escape_dict)
                    elif intType == 'User-defined Function':
                        xml += ' code="%s"' % escape(interpolator.function, escape_dict)
                    xml += '/>'
                xml += '\n\t\t</function>'
        xml += '\n\t</paramexp>'
        return xml

    def setParameterExploration(self, xmlString):
        """ setParameterExploration(xmlString: string) -> None
        Sets the current parameter exploration to the one
        defined by 'xmlString'.
        
        """
        if not xmlString:
            return
        # Parse/validate the xml
        try:
            xmlDoc = parseString(xmlString).documentElement
        except Exception:
            debug.critical("Parameter Exploration load failed because of "
                           "invalid XML:\n\n%s" % xmlString)
            return
        # Set the exploration dimensions
        dims = literal_eval(xmlDoc.attributes['dims'].value)
        self.peWidget.table.label.setCounts(dims)
        # Set the virtual cell layout
        layout = literal_eval(xmlDoc.attributes['layout'].value)
        self.virtualCell.setConfiguration(layout)
        # Populate parameter exploration window with stored functions and aliases
        for f in xmlDoc.getElementsByTagName('function'):
            # Retrieve function attributes
            f_id = long(f.attributes['id'].value)
            f_name = str(f.attributes['name'].value)
            f_is_alias = (str(f.attributes['alias'].value) == 'True')
            # Search the parameter treeWidget for this function and add it directly
            newEditor = None
            for tidx in xrange(self.paramView.treeWidget.topLevelItemCount()):
                moduleItem = self.paramView.treeWidget.topLevelItem(tidx)
                for cidx in xrange(moduleItem.childCount()):
                    paramInfo = moduleItem.child(cidx).parameter
                    name, params = paramInfo
                    if params[0].parent_id == f_id and params[0].is_alias == f_is_alias:
                        newEditor = self.peWidget.table.addParameter(paramInfo)
            # Retrieve params for this function and set their values in the UI
            if newEditor:
                for p in f.getElementsByTagName('param'):
                    # Locate the param in the newly added param editor and set values
                    p_id = long(p.attributes['id'].value)
                    for paramWidget in newEditor.paramWidgets:
                        if paramWidget.param.id == p_id:
                            # Set Parameter Dimension (radio button)
                            p_dim = int(p.attributes['dim'].value)
                            paramWidget.setDimension(p_dim)
                            # Set Interpolator Type (dropdown list)
                            p_intType = str(p.attributes['interp'].value)
                            paramWidget.editor.selectInterpolator(p_intType)
                            # Set Interpolator Value(s)
                            interpolator = paramWidget.editor.stackedEditors.currentWidget()
                            if p_intType == 'Linear Interpolation':
                                # Set min/max
                                p_min = str(p.attributes['min'].value)
                                p_max = str(p.attributes['max'].value)
                                interpolator.fromEdit.setText(p_min)
                                interpolator.toEdit.setText(p_max)
                            elif p_intType == 'List':
                                p_values = str(p.attributes['values'].value)
                                # Set internal list structure
                                interpolator._str_values = \
                                        literal_eval(p_values)
                                # Update UI list
                                if interpolator.type == 'String':
                                    interpolator.listValues.setText(p_values)
                                else:
                                    interpolator.listValues.setText(p_values.replace("'", "").replace('"', ''))
                            elif p_intType == 'User-defined Function':
                                # Set function code
                                p_code = str(p.attributes['code'].value)
                                interpolator.function = p_code

    def showEvent(self, event):
        """ showEvent(event: QShowEvent) -> None
        Update the tab when it is shown
        
        """
        if self.currentVersion!=self.controller.current_version:
            self.currentVersion = self.controller.current_version
            # Update the virtual cell
            pipeline = self.controller.current_pipeline
            self.virtualCell.updateVirtualCell(pipeline)

            # Now we need to inspect the parameter list
            self.paramView.treeWidget.updateFromPipeline(pipeline)

            # Update the annotated ids
            self.annotatedPipelineView.updateAnnotatedIds(pipeline)

            # Update the parameter exploration table
            self.peWidget.updatePipeline(pipeline)

            # Update the UI with the most recent parameter exploration
            # TODO: For now, we just strip the root tags since there's only one
            #       exploration - Later we should parse the root tree and select
            #       the active exploration based on date, or user choice
            xmlString = self.controller.vistrail.get_paramexp(self.currentVersion)
            if xmlString is not None:
                striplen = len("<paramexps>")
                xmlString = xmlString[striplen:-(striplen+1)].strip()
                self.setParameterExploration(xmlString)

    def performParameterExploration(self):
        """ performParameterExploration() -> None        
        Perform the exploration by collecting a list of actions
        corresponding to each dimension
        
        """
        registry = get_module_registry()
        actions = self.peWidget.table.collectParameterActions()
        spreadsheet_pkg = '%s.spreadsheet' % get_vistrails_default_pkg_prefix()
        # Set the annotation to persist the parameter exploration
        # TODO: For now, we just replace the existing exploration - Later we should append them.
        xmlString = "<paramexps>\n" + self.getParameterExploration() + "\n</paramexps>"
        self.controller.vistrail.set_paramexp(self.currentVersion, xmlString)
        self.controller.set_changed(True)

        if self.controller.current_pipeline and actions:
            explorer = ActionBasedParameterExploration()
            (pipelines, performedActions) = explorer.explore(
                self.controller.current_pipeline, actions)
            
            dim = [max(1, len(a)) for a in actions]
            if (registry.has_module(spreadsheet_pkg, 'CellLocation') and
                registry.has_module(spreadsheet_pkg, 'SheetReference')):
                modifiedPipelines = self.virtualCell.positionPipelines(
                    'PE#%d %s' % (QParameterExplorationTab.explorationId,
                                  self.controller.name),
                    dim[2], dim[1], dim[0], pipelines, self.controller)
            else:
                modifiedPipelines = pipelines

            mCount = []
            for p in modifiedPipelines:
                if len(mCount)==0:
                    mCount.append(0)
                else:
                    mCount.append(len(p.modules)+mCount[len(mCount)-1])
                
            # Now execute the pipelines
            totalProgress = sum([len(p.modules) for p in modifiedPipelines])
            progress = QtGui.QProgressDialog('Performing Parameter '
                                             'Exploration...',
                                             '&Cancel',
                                             0, totalProgress)
            progress.setWindowTitle('Parameter Exploration')
            progress.setWindowModality(QtCore.Qt.WindowModal)
            progress.show()

            QParameterExplorationTab.explorationId += 1
            interpreter = get_default_interpreter()
            for pi in xrange(len(modifiedPipelines)):
                progress.setValue(mCount[pi])
                QtCore.QCoreApplication.processEvents()
                if progress.wasCanceled():
                    break
                def moduleExecuted(objId):
                    if not progress.wasCanceled():
                        #progress.setValue(progress.value()+1)
                        #the call above was crashing when used by multithreaded
                        #code, replacing with the call below (thanks to Terence
                        #for submitting this fix). 
                        QtCore.QMetaObject.invokeMethod(progress, "setValue", 
                                        QtCore.Q_ARG(int,progress.value()+1))
                        QtCore.QCoreApplication.processEvents()
                kwargs = {'locator': self.controller.locator,
                          'current_version': self.controller.current_version,
                          'view': self.controller.current_pipeline_scene,
                          'module_executed_hook': [moduleExecuted],
                          'reason': 'Parameter Exploration',
                          'actions': performedActions[pi],
                          }
                interpreter.execute(modifiedPipelines[pi], **kwargs)
            progress.setValue(totalProgress)

    def exploreChange(self, notEmpty):
        """ exploreChange(notEmpty: bool) -> None
        echo the signal
        
        """
        self.emit(QtCore.SIGNAL('exploreChange(bool)'), notEmpty)
Esempio n. 6
0
class QParamExploreInspector(QtGui.QWidget, QVistrailsPaletteInterface):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.set_title("Explore Inspector")

        layout = QtGui.QVBoxLayout()
        layout.setMargin(2)
        layout.setSpacing(3)

        self.pe_properties = QParamExpProperties()
        p_prop_group = QtGui.QGroupBox(self.pe_properties.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.pe_properties)
        p_prop_group.setLayout(g_layout)
        layout.addWidget(p_prop_group)
        self.virtual_cell = QVirtualCellWindow()
        v_cell_group = QtGui.QGroupBox(self.virtual_cell.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.virtual_cell)
        v_cell_group.setLayout(g_layout)
        layout.addWidget(v_cell_group)
        self.setLayout(layout)
        self.addButtonsToToolbar()

    def addButtonsToToolbar(self):
        # Add the back/forward exploration buttons
        self.versionsLabel = QtGui.QLabel('Exploration: 0/0')
        self.toolWindow().toolbar.insertWidget(self.toolWindow().pinAction,
                                               self.versionsLabel)
        self.pe_properties.versionsLabel = weakref.proxy(self.versionsLabel)
        self.backAction = QtGui.QAction(
            QtGui.QIcon(CurrentTheme.LEFT_ARROW_PIXMAP),
            'Go to Previous Exploration', None, triggered=self.backPressed)
        self.toolWindow().toolbar.insertAction(self.toolWindow().pinAction,
                                               self.backAction)
        self.pe_properties.backAction = weakref.proxy(self.backAction)
        self.forwardAction = QtGui.QAction(
            QtGui.QIcon(CurrentTheme.RIGHT_ARROW_PIXMAP),
            'Got to Next Exploration', None, triggered=self.forwardPressed)
        self.toolWindow().toolbar.insertAction(self.toolWindow().pinAction,
                                               self.forwardAction)
        self.pe_properties.forwardAction = weakref.proxy(self.forwardAction)

    def set_controller(self, controller):
        self.controller = controller
        self.pe_properties.updateController(controller)
        if self.controller is not None:
            self.set_pipeline(self.controller.current_pipeline)
        else:
            self.set_pipeline(None)

    def set_pipeline(self, pipeline):
        self.pipeline = pipeline
        self.virtual_cell.updateVirtualCell(pipeline)
        self.stateChanged()

    def stateChanged(self):
        self.pe_properties.updateVersion()

    def set_exploration(self, pe = None):
        self.stateChanged()

    def backPressed(self):
        self.pe_properties.goBack()

    def forwardPressed(self):
        self.pe_properties.goForward()
Esempio n. 7
0
class QParamExploreInspector(QtGui.QWidget, QVistrailsPaletteInterface):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.set_title("Explore Inspector")

        layout = QtGui.QVBoxLayout()
        layout.setMargin(2)
        layout.setSpacing(3)

        self.controller = None
        self.pe_properties = QParamExpProperties()
        p_prop_group = QtGui.QGroupBox(self.pe_properties.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.pe_properties)
        p_prop_group.setLayout(g_layout)
        layout.addWidget(p_prop_group)
        self.virtual_cell = QVirtualCellWindow()
        v_cell_group = QtGui.QGroupBox(self.virtual_cell.windowTitle())
        g_layout = QtGui.QVBoxLayout()
        g_layout.setMargin(0)
        g_layout.setSpacing(0)
        g_layout.addWidget(self.virtual_cell)
        v_cell_group.setLayout(g_layout)
        layout.addWidget(v_cell_group)
        self.setLayout(layout)
        self.addButtonsToToolbar()

    def addButtonsToToolbar(self):
        # Add the back/forward exploration buttons
        self.versionsLabel = QtGui.QLabel('Exploration: 0/0')
        self.toolWindow().toolbar.insertWidget(self.toolWindow().pinAction,
                                               self.versionsLabel)
        self.pe_properties.versionsLabel = weakref.proxy(self.versionsLabel)
        self.backAction = QtGui.QAction(
            QtGui.QIcon(CurrentTheme.LEFT_ARROW_PIXMAP),
            'Go to Previous Exploration', None, triggered=self.backPressed)
        self.toolWindow().toolbar.insertAction(self.toolWindow().pinAction,
                                               self.backAction)
        self.pe_properties.backAction = weakref.proxy(self.backAction)
        self.forwardAction = QtGui.QAction(
            QtGui.QIcon(CurrentTheme.RIGHT_ARROW_PIXMAP),
            'Got to Next Exploration', None, triggered=self.forwardPressed)
        self.toolWindow().toolbar.insertAction(self.toolWindow().pinAction,
                                               self.forwardAction)
        self.pe_properties.forwardAction = weakref.proxy(self.forwardAction)

    def set_controller(self, controller):
        if self.controller == controller:
            return
        self.controller = controller
        self.pe_properties.updateController(controller)
        if self.controller is not None:
            self.set_pipeline(self.controller.current_pipeline)
        else:
            self.set_pipeline(None)

    def set_pipeline(self, pipeline):
        self.pipeline = pipeline
        self.virtual_cell.updateVirtualCell(pipeline)
        self.stateChanged()

    def stateChanged(self):
        self.pe_properties.updateVersion()

    def backPressed(self):
        self.pe_properties.goBack()

    def forwardPressed(self):
        self.pe_properties.goForward()
Esempio n. 8
0
class QParameterExplorationTab(QDockContainer, QToolWindowInterface):
    """
    QParameterExplorationTab is a tab containing different widgets
    related to parameter exploration
    
    """
    explorationId = 0
    
    def __init__(self, parent=None):
        """ QParameterExplorationTab(parent: QWidget)
                                    -> QParameterExplorationTab
        Make it a main window with dockable area and a
        QParameterExplorationTable
        
        """
        QDockContainer.__init__(self, parent)
        self.setWindowTitle('Parameter Exploration')
        self.toolWindow().setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
        self.toolWindow().hide()

        self.peWidget = QParameterExplorationWidget()
        self.setCentralWidget(self.peWidget)
        self.connect(self.peWidget.table,
                     QtCore.SIGNAL('exploreChange(bool)'),
                     self.exploreChange)

        self.paramView = QParameterView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.paramView.toolWindow())
        
        self.annotatedPipelineView = QAnnotatedPipelineView(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.annotatedPipelineView.toolWindow())
        
        self.virtualCell = QVirtualCellWindow(self)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.virtualCell.toolWindow())
        
        self.controller = None
        self.currentVersion = -1

    def addViewActionsToMenu(self, menu):
        """addViewActionsToMenu(menu: QMenu) -> None
        Add toggle view actions to menu
        
        """
        menu.addAction(self.paramView.toolWindow().toggleViewAction())
        menu.addAction(self.annotatedPipelineView.toolWindow().toggleViewAction())
        menu.addAction(self.virtualCell.toolWindow().toggleViewAction())

    def removeViewActionsFromMenu(self, menu):
        """removeViewActionsFromMenu(menu: QMenu) -> None
        Remove toggle view actions from menu
        
        """
        menu.removeAction(self.paramView.toolWindow().toggleViewAction())
        menu.removeAction(self.annotatedPipelineView.toolWindow().toggleViewAction())
        menu.removeAction(self.virtualCell.toolWindow().toggleViewAction())
        
    def setController(self, controller):
        """ setController(controller: VistrailController) -> None
        Assign a controller to the parameter exploration tab
        
        """
        self.controller = controller

    def getParameterExploration(self):
        """ getParameterExploration() -> string
        Generates an XML string that represents the current
        parameter exploration, and which can be loaded with
        setParameterExploration().
        
        """
        # Construct xml for persisting parameter exploration
        escape_dict = { "'":"&apos;", '"':'&quot;', '\n':'&#xa;' }
        timestamp = strftime(current_time(), '%Y-%m-%d %H:%M:%S')
        # TODO: For now, we use the timestamp as the 'name' - Later, we should set 'name' based on a UI input field
        xml = '\t<paramexp dims="%s" layout="%s" date="%s" name="%s">' % (str(self.peWidget.table.label.getCounts()), str(self.virtualCell.getConfiguration()[2]), timestamp, timestamp)
        for i in xrange(self.peWidget.table.layout().count()):
            pEditor = self.peWidget.table.layout().itemAt(i).widget()
            if pEditor and isinstance(pEditor, QParameterSetEditor):
                firstParam = True
                for paramWidget in pEditor.paramWidgets:
                    paramInfo = paramWidget.param
                    interpolator = paramWidget.editor.stackedEditors.currentWidget()
                    intType = interpolator.exploration_name
                    # Write function tag prior to the first parameter of the function
                    if firstParam:
                        xml += '\n\t\t<function id="%s" alias="%s" name="%s">' % (paramInfo.parent_id, paramInfo.is_alias, pEditor.info[0])
                        firstParam = False
                    # Write parameter tag
                    xml += '\n\t\t\t<param id="%s" dim="%s" interp="%s"' % (paramInfo.id, paramWidget.getDimension(), intType)
                    if intType == 'Linear Interpolation':
                        xml += ' min="%s" max="%s"' % (interpolator.fromEdit.get_value(), interpolator.toEdit.get_value())
                    elif intType == 'List':
                        xml += ' values="%s"' % escape(str(interpolator._str_values), escape_dict)
                    elif intType == 'User-defined Function':
                        xml += ' code="%s"' % escape(interpolator.function, escape_dict)
                    xml += '/>'
                xml += '\n\t\t</function>'
        xml += '\n\t</paramexp>'
        return xml

    def setParameterExploration(self, xmlString):
        """ setParameterExploration(xmlString: string) -> None
        Sets the current parameter exploration to the one
        defined by 'xmlString'.
        
        """
        if not xmlString:
            return
        # Parse/validate the xml
        try:
            xmlDoc = parseString(xmlString).documentElement
        except Exception:
            debug.critical("Parameter Exploration load failed because of "
                           "invalid XML:\n\n%s" % xmlString)
            return
        # Set the exploration dimensions
        dims = literal_eval(xmlDoc.attributes['dims'].value)
        self.peWidget.table.label.setCounts(dims)
        # Set the virtual cell layout
        layout = literal_eval(xmlDoc.attributes['layout'].value)
        self.virtualCell.setConfiguration(layout)
        # Populate parameter exploration window with stored functions and aliases
        for f in xmlDoc.getElementsByTagName('function'):
            # Retrieve function attributes
            f_id = long(f.attributes['id'].value)
            f_is_alias = (str(f.attributes['alias'].value) == 'True')
            # Search the parameter treeWidget for this function and add it directly
            newEditor = None
            for tidx in xrange(self.paramView.treeWidget.topLevelItemCount()):
                moduleItem = self.paramView.treeWidget.topLevelItem(tidx)
                for cidx in xrange(moduleItem.childCount()):
                    paramInfo = moduleItem.child(cidx).parameter
                    name, params = paramInfo
                    if params[0].parent_id == f_id and params[0].is_alias == f_is_alias:
                        newEditor = self.peWidget.table.addParameter(paramInfo)
            # Retrieve params for this function and set their values in the UI
            if newEditor:
                for p in f.getElementsByTagName('param'):
                    # Locate the param in the newly added param editor and set values
                    p_id = long(p.attributes['id'].value)
                    for paramWidget in newEditor.paramWidgets:
                        if paramWidget.param.id == p_id:
                            # Set Parameter Dimension (radio button)
                            p_dim = int(p.attributes['dim'].value)
                            paramWidget.setDimension(p_dim)
                            # Set Interpolator Type (dropdown list)
                            p_intType = str(p.attributes['interp'].value)
                            paramWidget.editor.selectInterpolator(p_intType)
                            # Set Interpolator Value(s)
                            interpolator = paramWidget.editor.stackedEditors.currentWidget()
                            if p_intType == 'Linear Interpolation':
                                # Set min/max
                                p_min = str(p.attributes['min'].value)
                                p_max = str(p.attributes['max'].value)
                                interpolator.fromEdit.setText(p_min)
                                interpolator.toEdit.setText(p_max)
                            elif p_intType == 'List':
                                p_values = str(p.attributes['values'].value)
                                # Set internal list structure
                                interpolator._str_values = \
                                        literal_eval(p_values)
                                # Update UI list
                                if interpolator.type == 'String':
                                    interpolator.listValues.setText(p_values)
                                else:
                                    interpolator.listValues.setText(p_values.replace("'", "").replace('"', ''))
                            elif p_intType == 'User-defined Function':
                                # Set function code
                                p_code = str(p.attributes['code'].value)
                                interpolator.function = p_code

    def showEvent(self, event):
        """ showEvent(event: QShowEvent) -> None
        Update the tab when it is shown
        
        """
        if self.currentVersion!=self.controller.current_version:
            self.currentVersion = self.controller.current_version
            # Update the virtual cell
            pipeline = self.controller.current_pipeline
            self.virtualCell.updateVirtualCell(pipeline)

            # Now we need to inspect the parameter list
            self.paramView.treeWidget.updateFromPipeline(pipeline)

            # Update the annotated ids
            self.annotatedPipelineView.updateAnnotatedIds(pipeline)

            # Update the parameter exploration table
            self.peWidget.updatePipeline(pipeline)

            # Update the UI with the most recent parameter exploration
            # TODO: For now, we just strip the root tags since there's only one
            #       exploration - Later we should parse the root tree and select
            #       the active exploration based on date, or user choice
            xmlString = self.controller.vistrail.get_paramexp(self.currentVersion)
            if xmlString is not None:
                striplen = len("<paramexps>")
                xmlString = xmlString[striplen:-(striplen+1)].strip()
                self.setParameterExploration(xmlString)

    def performParameterExploration(self):
        """ performParameterExploration() -> None        
        Perform the exploration by collecting a list of actions
        corresponding to each dimension
        
        """
        registry = get_module_registry()
        actions = self.peWidget.table.collectParameterActions()
        spreadsheet_pkg = 'org.vistrails.vistrails.spreadsheet'
        # Set the annotation to persist the parameter exploration
        # TODO: For now, we just replace the existing exploration - Later we should append them.
        xmlString = "<paramexps>\n" + self.getParameterExploration() + "\n</paramexps>"
        self.controller.vistrail.set_paramexp(self.currentVersion, xmlString)
        self.controller.set_changed(True)

        if self.controller.current_pipeline and actions:
            explorer = ActionBasedParameterExploration()
            (pipelines, performedActions) = explorer.explore(
                self.controller.current_pipeline, actions)
            
            dim = [max(1, len(a)) for a in actions]
            if (registry.has_module(spreadsheet_pkg, 'CellLocation') and
                registry.has_module(spreadsheet_pkg, 'SheetReference')):
                modifiedPipelines = self.virtualCell.positionPipelines(
                    'PE#%d %s' % (QParameterExplorationTab.explorationId,
                                  self.controller.name),
                    dim[2], dim[1], dim[0], pipelines, self.controller)
            else:
                modifiedPipelines = pipelines

            mCount = []
            for p in modifiedPipelines:
                if len(mCount)==0:
                    mCount.append(0)
                else:
                    mCount.append(len(p.modules)+mCount[len(mCount)-1])
                
            # Now execute the pipelines
            totalProgress = sum([len(p.modules) for p in modifiedPipelines])
            progress = QtGui.QProgressDialog('Performing Parameter '
                                             'Exploration...',
                                             '&Cancel',
                                             0, totalProgress)
            progress.setWindowTitle('Parameter Exploration')
            progress.setWindowModality(QtCore.Qt.WindowModal)
            progress.show()

            QParameterExplorationTab.explorationId += 1
            interpreter = get_default_interpreter()
            for pi in xrange(len(modifiedPipelines)):
                progress.setValue(mCount[pi])
                QtCore.QCoreApplication.processEvents()
                if progress.wasCanceled():
                    break
                def moduleExecuted(objId):
                    if not progress.wasCanceled():
                        #progress.setValue(progress.value()+1)
                        #the call above was crashing when used by multithreaded
                        #code, replacing with the call below (thanks to Terence
                        #for submitting this fix). 
                        QtCore.QMetaObject.invokeMethod(progress, "setValue", 
                                        QtCore.Q_ARG(int,progress.value()+1))
                        QtCore.QCoreApplication.processEvents()
                kwargs = {'locator': self.controller.locator,
                          'current_version': self.controller.current_version,
                          'view': self.controller.current_pipeline_scene,
                          'module_executed_hook': [moduleExecuted],
                          'reason': 'Parameter Exploration',
                          'actions': performedActions[pi],
                          }
                interpreter.execute(modifiedPipelines[pi], **kwargs)
            progress.setValue(totalProgress)

    def exploreChange(self, notEmpty):
        """ exploreChange(notEmpty: bool) -> None
        echo the signal
        
        """
        self.emit(QtCore.SIGNAL('exploreChange(bool)'), notEmpty)