Exemplo n.º 1
0
class TaurusMacroExecutorWidget(TaurusWidget):
    def __init__(self, parent=None, designMode=False):
        TaurusWidget.__init__(self, parent, designMode)
        self.setObjectName(self.__class__.__name__)

        self._doorName = ""
        self._macroId = None
        self.setLayout(Qt.QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.addToFavouritesAction = Qt.QAction(
            getThemeIcon("software-update-available"), "Add to favourites",
            self)
        self.connect(self.addToFavouritesAction, Qt.SIGNAL("triggered()"),
                     self.onAddToFavourites)
        self.addToFavouritesAction.setToolTip("Add to favourites")
        self.stopMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_stop.svg"), "Stop macro", self)
        self.connect(self.stopMacroAction, Qt.SIGNAL("triggered()"),
                     self.onStopMacro)
        self.stopMacroAction.setToolTip("Stop macro")
        self.pauseMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_pause.svg"), "Pause macro", self)
        self.connect(self.pauseMacroAction, Qt.SIGNAL("triggered()"),
                     self.onPauseMacro)
        self.pauseMacroAction.setToolTip("Pause macro")
        self.playMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_start.svg"), "Start macro", self)
        self.connect(self.playMacroAction, Qt.SIGNAL("triggered()"),
                     self.onPlayMacro)
        self.playMacroAction.setToolTip("Start macro")
        actionsLayout = Qt.QHBoxLayout()
        actionsLayout.setContentsMargins(0, 0, 0, 0)
        addToFavouritsButton = Qt.QToolButton()
        addToFavouritsButton.setDefaultAction(self.addToFavouritesAction)
        self.addToFavouritesAction.setEnabled(False)
        actionsLayout.addWidget(addToFavouritsButton)

        self.macroComboBox = MacroComboBox(self)
        self.macroComboBox.setUseParentModel(True)
        self.macroComboBox.setModelColumn(0)
        actionsLayout.addWidget(self.macroComboBox)
        stopMacroButton = Qt.QToolButton()
        stopMacroButton.setDefaultAction(self.stopMacroAction)
        actionsLayout.addWidget(stopMacroButton)
        pauseMacroButton = Qt.QToolButton()
        pauseMacroButton.setDefaultAction(self.pauseMacroAction)
        actionsLayout.addWidget(pauseMacroButton)
        self.playMacroButton = Qt.QToolButton()
        self.playMacroButton.setDefaultAction(self.playMacroAction)
        actionsLayout.addWidget(self.playMacroButton)
        self.disableControlActions()
        self.doorStateLed = TaurusLed(self)
        actionsLayout.addWidget(self.doorStateLed)
        self.layout().addLayout(actionsLayout)

        splitter = Qt.QSplitter(self)
        self.layout().addWidget(splitter)
        splitter.setOrientation(Qt.Qt.Vertical)

        self._paramEditorModel = ParamEditorModel()
        self.stackedWidget = Qt.QStackedWidget()
        self.standardMacroParametersEditor = StandardMacroParametersEditor(
            self.stackedWidget)
        self.stackedWidget.addWidget(self.standardMacroParametersEditor)
        self.customMacroParametersEditor = None
        splitter.addWidget(self.stackedWidget)

        self._favouritesBuffer = None
        self.favouritesMacrosEditor = FavouritesMacrosEditor(self)
        self.registerConfigDelegate(self.favouritesMacrosEditor)
        self.favouritesMacrosEditor.setUseParentModel(True)
        self.favouritesMacrosEditor.setFocusPolicy(Qt.Qt.NoFocus)

        self._historyBuffer = None
        self.historyMacrosViewer = HistoryMacrosViewer(self)
        self.registerConfigDelegate(self.historyMacrosViewer)
        self.historyMacrosViewer.setUseParentModel(True)
        self.historyMacrosViewer.setFocusPolicy(Qt.Qt.NoFocus)

        self.tabMacroListsWidget = Qt.QTabWidget(self)
        self.tabMacroListsWidget.addTab(self.favouritesMacrosEditor,
                                        "Favourite list")
        self.tabMacroListsWidget.addTab(self.historyMacrosViewer,
                                        "History Viewer")
        splitter.addWidget(self.tabMacroListsWidget)

        self._isHistoryMacro = False
        self.macroProgressBar = MacroProgressBar(self)
        self.layout().addWidget(self.macroProgressBar)

        #spockCommandLabel = Qt.QLabel("Spock command:", self)
        #spockCommandLabel.setFont(Qt.QFont("Courier",9))
        self.spockCommand = SpockCommandWidget("Spock", self)
        self.spockCommand.setSizePolicy(Qt.QSizePolicy.Expanding,
                                        Qt.QSizePolicy.Minimum)
        self.spockCommand.setUseParentModel(True)
        spockCommandLayout = Qt.QHBoxLayout()
        spockCommandLayout.setContentsMargins(0, 0, 0, 0)
        #spockCommandLayout.addWidget(spockCommandLabel)
        spockCommandLayout.addWidget(self.spockCommand)
        self.layout().addLayout(spockCommandLayout)
        self.connect(self.macroComboBox,
                     Qt.SIGNAL("currentIndexChanged(QString)"),
                     self.onMacroComboBoxChanged)
        self.connect(self.favouritesMacrosEditor.list,
                     Qt.SIGNAL("favouriteSelected"), self.onFavouriteSelected)
        self.connect(self.historyMacrosViewer.list,
                     Qt.SIGNAL("historySelected"), self.onHistorySelected)

        self.connect(self.spockCommand, Qt.SIGNAL("pressedReturn"),
                     self.onPlayMacro)
        self.connect(self.spockCommand, Qt.SIGNAL("spockComboBox"),
                     self.setComboBoxItem)
        self.connect(self.spockCommand, Qt.SIGNAL("elementUp"),
                     self.setHistoryUp)
        self.connect(self.spockCommand, Qt.SIGNAL("elementDown"),
                     self.setHistoryDown)
        self.connect(self.spockCommand, Qt.SIGNAL("setHistoryFocus"),
                     self.setHistoryFocus)
        self.connect(self.spockCommand, Qt.SIGNAL("expandTree"),
                     self.standardMacroParametersEditor.tree.expandAll)

    def macroId(self):
        return self._macroId

    def contextMenuEvent(self, event):
        menu = Qt.QMenu()
        action = menu.addAction(getThemeIcon("view-refresh"),
                                "Check door state", self.checkDoorState)
        menu.exec_(event.globalPos())

    def checkDoorState(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            self.stopMacroAction.setEnabled(True)
        elif doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(True)

    def setMacroId(self, macroId):
        self._macroId = macroId

    def doorName(self):
        return self._doorName

    def setDoorName(self, doorName):
        self._doorName = doorName

    def setFavouritesBuffer(self, favouritesMacro):
        self._favouritesBuffer = favouritesMacro

    #History Widget
    def setHistoryUp(self):
        self.setHistoryFocus()
        self.historyMacrosViewer.listElementUp()

    def setHistoryDown(self):
        self.setHistoryFocus()
        self.historyMacrosViewer.listElementDown()

    def setHistoryFocus(self):
        self.tabMacroListsWidget.setCurrentWidget(self.historyMacrosViewer)
        #self.historyMacrosViewer.setFocus()

    def historyBuffer(self):
        return self._historyBuffer

    def setHistoryBuffer(self, favouritesMacro):
        self._historyBuffer = favouritesMacro

    def favouritesBuffer(self):
        return self._favouritesBuffer

    def paramEditorModel(self):
        return self._paramEditorModel

    def setParamEditorModel(self, paramEditorModel):
        self._paramEditorModel = paramEditorModel

    def setComboBoxItem(self, macroName):
        self.macroComboBox.selectMacro(macroName)

    def onMacroComboBoxChanged(self, macroName):
        macroName = str(macroName)
        if macroName == "":
            macroName, macroNode = None, None
            #            macroNode = macro.MacroNode(name="")
            self.playMacroAction.setEnabled(False)
            self.addToFavouritesAction.setEnabled(False)
        else:
            if self._isHistoryMacro:
                macroNode = self.historyBuffer()
                self.setHistoryBuffer(None)
                self.favouritesMacrosEditor.list.clearSelection()
            else:
                macroNode = self.favouritesBuffer()
                self.setFavouritesBuffer(None)
                self.historyMacrosViewer.list.clearSelection()
            self._isHistoryMacro = False

            if macroNode is None:
                macroNode = self.getModelObj().getMacroNodeObj(macroName)

            self.playMacroAction.setEnabled(True)
            self.addToFavouritesAction.setEnabled(True)

        self.paramEditorModel().setRoot(macroNode)
        self.spockCommand.setModel(self.paramEditorModel())
        if self.stackedWidget.count() == 2:
            self.stackedWidget.removeWidget(self.customMacroParametersEditor)
            self.customMacroParametersEditor.setParent(None)
        self.customMacroParametersEditor = ParamEditorManager().getMacroEditor(
            macroName, self.stackedWidget)
        if self.customMacroParametersEditor:
            self.customMacroParametersEditor.setModel(self.paramEditorModel())
            self.stackedWidget.addWidget(self.customMacroParametersEditor)
            self.stackedWidget.setCurrentWidget(
                self.customMacroParametersEditor)
        else:
            self.standardMacroParametersEditor.setModel(
                self.paramEditorModel())

        self.emit(Qt.SIGNAL("macroNameChanged"), macroName)

    def onFavouriteSelected(self, macroNode):
        self.setFavouritesBuffer(macroNode)
        name = ""
        if not macroNode is None:
            name = macroNode.name()
        self._isHistoryMacro = False
        self.macroComboBox.selectMacro(name)

    def onHistorySelected(self, macroNode):
        self.setHistoryBuffer(macroNode)
        name = ""
        if not macroNode is None:
            name = macroNode.name()
        self._isHistoryMacro = True
        self.macroComboBox.selectMacro(name)

    def onAddToFavourites(self):
        self.favouritesMacrosEditor.addMacro(
            deepcopy(self.paramEditorModel().root()))

    def addToHistory(self):
        self.historyMacrosViewer.addMacro(
            deepcopy(self.paramEditorModel().root()))

    def onDoorChanged(self, doorName):
        self.setDoorName(doorName)
        if self.doorName() == "":
            self.doorStateLed.setModel(None)
            return
        self.doorStateLed.setModel(self.doorName() + "/State")
        door = Device(doorName)
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON:
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
        elif doorState == PyTango.DevState.STANDBY:
            self.playMacroAction.setText("Resume macro")
            self.playMacroAction.setToolTip("Resume macro")

    def onPlayMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
            self.setFocus()
            paramEditorModel = self.paramEditorModel()
            macroNode = paramEditorModel.root()
            id = macroNode.assignId()
            self.setMacroId(id)
            params, alerts = macroNode.toRun()
            xmlString = paramEditorModel.toXmlString()
            if len(alerts) > 0:
                Qt.QMessageBox.warning(self, "Macro parameters warning",
                                       alerts)
                return
            door.runMacro(xmlString)
            self.addToHistory()


#            door.runMacro(str(macroNode.name()), params)
        elif doorState == PyTango.DevState.STANDBY:
            door.command_inout("ResumeMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while starting/resuming macro",
                "It was not possible to start/resume macro, because state of the door was different than ON/STANDBY"
            )

    def onStopMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()

        if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
            door.command_inout("StopMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while stopping macro",
                "It was not possible to stop macro, because state of the door was different than RUNNING or STANDBY"
            )

    def onPauseMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()

        if doorState == PyTango.DevState.RUNNING:
            door.command_inout("PauseMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while pausing macro",
                "It was not possible to pause macro, because state of the door was different than RUNNING"
            )

    def onMacroStatusUpdated(self, data):
        macro = data[0]
        if macro is None: return
        data = data[1][0]
        state, range, step, id = data["state"], data["range"], data[
            "step"], data["id"]
        if id is None: return
        id = int(id)
        if id != self.macroId(): return
        macroName = macro.name
        shortMessage = ""
        if state == "start":
            self.emit(Qt.SIGNAL("macroStarted"), "DoorOutput")
            self.macroProgressBar.setRange(range[0], range[1])
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            self.stopMacroAction.setEnabled(True)
            self.emit(Qt.SIGNAL("plotablesFilterChanged"), None)
            self.emit(Qt.SIGNAL("plotablesFilterChanged"),
                      standardPlotablesFilter)
            shortMessage = "Macro %s started." % macroName
        elif state == "pause":
            self.playMacroAction.setText("Resume macro")
            self.playMacroAction.setToolTip("Resume macro")
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            shortMessage = "Macro %s paused." % macroName
        elif state == "resume":
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            shortMessage = "Macro %s resumed." % macroName
        elif state == "stop" or state == "finish":
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s finished." % macroName
        elif state == "exception":
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s error." % macroName
            exc_value, exc_stack = data['exc_value'], data['exc_stack']
            exceptionDialog = TaurusMessageBox(MacroRunException, exc_value,
                                               exc_stack)
            exceptionDialog.exec_()
        elif state == "abort":
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s stopped." % macroName
        elif state == "step":
            shortMessage = "Macro %s at %d %% of progress." % (macroName, step)
        self.emit(Qt.SIGNAL("shortMessageEmitted"), shortMessage)
        self.macroProgressBar.setValue(step)

    def disableControlActions(self):
        self.pauseMacroAction.setEnabled(False)
        self.stopMacroAction.setEnabled(False)
        self.playMacroAction.setEnabled(False)

    def setModel(self, model):
        oldModelObj = self.getModelObj()
        if oldModelObj is not None:
            self.disconnect(oldModelObj, Qt.SIGNAL("macrosUpdated"),
                            self.macroComboBox.onMacrosUpdated)
        TaurusWidget.setModel(self, model)
        newModelObj = self.getModelObj()
        self.connect(newModelObj, Qt.SIGNAL("macrosUpdated"),
                     self.macroComboBox.onMacrosUpdated)

    @classmethod
    def getQtDesignerPluginInfo(cls):
        return {
            'container': False,
            'group': 'Taurus Sardana',
            'module': 'taurus.qt.qtgui.extra_macroexecutor',
            'icon': ':/designer/frame.png'
        }
Exemplo n.º 2
0
class TaurusSequencerWidget(TaurusWidget):

    macroStarted = Qt.pyqtSignal('QString')
    plotablesFilterChanged = Qt.pyqtSignal(object)
    currentMacroChanged = Qt.pyqtSignal(object)
    macroNameChanged = Qt.pyqtSignal('QString')
    shortMessageEmitted = Qt.pyqtSignal('QString')
    sequenceEmpty = Qt.pyqtSignal()

    def __init__(self, parent=None, designMode=False):
        TaurusWidget.__init__(self, parent, designMode)
        # list representing all macros ids (all from sequence) currently
        # executed
        self._macroIds = []
        self._sequencesPath = str(Qt.QDir.homePath())
        self._sequenceModel = MacroSequenceTreeModel()

        self.registerConfigProperty(
            "sequencesPath", "setSequencesPath", "sequencesPath")

        self.setLayout(Qt.QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        splitter = Qt.QSplitter()
        self.layout().addWidget(splitter)
        splitter.setOrientation(Qt.Qt.Vertical)

        sequenceEditor = TaurusWidget()
        splitter.addWidget(sequenceEditor)
        sequenceEditor.setUseParentModel(True)
        sequenceEditor.setLayout(Qt.QVBoxLayout())
        sequenceEditor.layout().setContentsMargins(0, 0, 0, 0)

        self.tree = MacroSequenceTree(sequenceEditor)
        self.sequenceProxyModel = MacroSequenceProxyModel()
        self.sequenceProxyModel.setSourceModel(self._sequenceModel)
        self.tree.setModel(self.sequenceProxyModel)
        self.tree.setItemDelegate(SequenceEditorDelegate(self.tree))

        actionsLayout = Qt.QHBoxLayout()
        actionsLayout.setContentsMargins(0, 0, 0, 0)
        self.newSequenceAction = Qt.QAction(
            getThemeIcon("document-new"), "New", self)
        self.newSequenceAction.triggered.connect(self.onNewSequence)
        self.newSequenceAction.setToolTip("New sequence")
        self.newSequenceAction.setEnabled(False)
        newSequenceButton = Qt.QToolButton()
        newSequenceButton.setDefaultAction(self.newSequenceAction)
        actionsLayout.addWidget(newSequenceButton)

        self.openSequenceAction = Qt.QAction(
            getThemeIcon("document-open"), "Open...", self)
        self.openSequenceAction.triggered.connect(self.onOpenSequence)
        self.openSequenceAction.setToolTip("Open sequence...")
        openSequenceButton = Qt.QToolButton()
        openSequenceButton.setDefaultAction(self.openSequenceAction)
        actionsLayout.addWidget(openSequenceButton)

        self.saveSequenceAction = Qt.QAction(
            getThemeIcon("document-save"), "Save...", self)
        self.saveSequenceAction.triggered.connect(self.onSaveSequence)
        self.saveSequenceAction.setToolTip("Save sequence...")
        self.saveSequenceAction.setEnabled(False)
        saveSequenceButton = Qt.QToolButton()
        saveSequenceButton.setDefaultAction(self.saveSequenceAction)
        actionsLayout.addWidget(saveSequenceButton)

        self.stopSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_stop.svg"), "Stop", self)
        self.stopSequenceAction.triggered.connect(self.onStopSequence)
        self.stopSequenceAction.setToolTip("Stop sequence")
        stopSequenceButton = Qt.QToolButton()
        stopSequenceButton.setDefaultAction(self.stopSequenceAction)
        actionsLayout.addWidget(stopSequenceButton)

        self.pauseSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_pause.svg"), "Pause", self)
        self.pauseSequenceAction.triggered.connect(self.onPauseSequence)
        self.pauseSequenceAction.setToolTip("Pause sequence")
        pauseSequenceButton = Qt.QToolButton()
        pauseSequenceButton.setDefaultAction(self.pauseSequenceAction)
        actionsLayout.addWidget(pauseSequenceButton)

        self.playSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_start.svg"), "Play", self)
        self.playSequenceAction.triggered.connect(self.onPlaySequence)
        self.playSequenceAction.setToolTip("Play sequence")
        playSequenceButton = Qt.QToolButton()
        playSequenceButton.setDefaultAction(self.playSequenceAction)
        actionsLayout.addWidget(playSequenceButton)

        self.doorStateLed = TaurusLed(self)
        actionsLayout.addWidget(self.doorStateLed)

        #@todo this feature will be replaced by checkboxes in the
        # sequence tree view indicating clearing of the plot after execution
        self.fullSequencePlotCheckBox = Qt.QCheckBox(
            "Full sequence plot", self)
        self.fullSequencePlotCheckBox.toggled.connect(self.setFullSequencePlot)
        self.fullSequencePlotCheckBox.setChecked(True)
        actionsLayout.addWidget(self.fullSequencePlotCheckBox)

        spacerItem = Qt.QSpacerItem(
            0, 0, Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Fixed)
        actionsLayout.addItem(spacerItem)

        sequenceEditor.layout().addLayout(actionsLayout)

        macroLayout = Qt.QHBoxLayout()
        macroLayout.setContentsMargins(0, 0, 0, 0)
        macroLabel = Qt.QLabel("Macro:")
        macroLayout.addWidget(macroLabel)
        self.macroComboBox = MacroComboBox(self)
        self.macroComboBox.setUseParentModel(True)
        self.macroComboBox.setModelColumn(0)
        self.macroComboBox.setSizePolicy(
            Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum)
        macroLayout.addWidget(self.macroComboBox)

        self.addMacroAction = Qt.QAction(
            getThemeIcon("list-add"), "Add macro...", self)
        self.addMacroAction.triggered.connect(self.onAdd)
        self.addMacroAction.setToolTip(
            "Clicking this button will add selected macro")
        self.addMacroAction.setEnabled(False)
        addButton = Qt.QToolButton()
        addButton.setDefaultAction(self.addMacroAction)
        macroLayout.addWidget(addButton)

        sequenceEditor.layout().addLayout(macroLayout)

        sequenceLayout = Qt.QHBoxLayout()
        sequenceLayout.addWidget(self.tree)

        layout = Qt.QVBoxLayout()
        delButton = Qt.QToolButton()
        delButton.setDefaultAction(self.tree.deleteAction)
        delButton.setEnabled(False)
        layout.addWidget(delButton)
        upButton = Qt.QToolButton()
        upButton.setDefaultAction(self.tree.moveUpAction)
        upButton.setEnabled(False)
        layout.addWidget(upButton)
        downButton = Qt.QToolButton()
        downButton.setDefaultAction(self.tree.moveDownAction)
        downButton.setEnabled(False)
        layout.addWidget(downButton)
        leftButton = Qt.QToolButton()
        leftButton.setDefaultAction(self.tree.moveLeftAction)
        leftButton.setEnabled(False)
        layout.addWidget(leftButton)
        rightButton = Qt.QToolButton()
        rightButton.setDefaultAction(self.tree.moveRightAction)
        rightButton.setEnabled(False)
        layout.addWidget(rightButton)
        spacerItem = Qt.QSpacerItem(
            0, 40, Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Expanding)
        layout.addItem(spacerItem)
        sequenceLayout.addLayout(layout)
        sequenceEditor.layout().addLayout(sequenceLayout)

        self.parametersProxyModel = MacroParametersProxyModel()
        self.parametersProxyModel.setSourceModel(self._sequenceModel)

        self.stackedWidget = Qt.QStackedWidget()
        splitter.addWidget(self.stackedWidget)
        self.standardMacroParametersEditor = StandardMacroParametersEditor(
            self.stackedWidget)
        self.standardMacroParametersEditor.setModel(self.parametersProxyModel)
        self.standardMacroParametersEditor.tree.setItemDelegate(
            ParamEditorDelegate(self.standardMacroParametersEditor.tree))
        self.stackedWidget.addWidget(self.standardMacroParametersEditor)
        self.customMacroParametersEditor = None

        self.macroComboBox.currentIndexChanged.connect(
            self.onMacroComboBoxChanged)
        self.tree.macroChanged.connect(self.setMacroParametersRootIndex)

    def contextMenuEvent(self, event):
        menu = Qt.QMenu()
        action = menu.addAction(getThemeIcon(
            "view-refresh"), "Check door state", self.checkDoorState)
        menu.exec_(event.globalPos())

    def checkDoorState(self):
        """Method used by "Check door state" action (available in the context
        menu). It is a workaround for situations when the event notification
        about the macro status does not reach the sequencer widget."""

        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            self.stopSequenceAction.setEnabled(True)
        elif doorState in (PyTango.DevState.ON, PyTango.DevState.ALARM):
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(True)

    def doorName(self):
        return self._doorName

    def setDoorName(self, doorName):
        self._doorName = doorName

    def firstMacroId(self):
        return self._firstMacroId

    def setFirstMacroId(self, firstMacroId):
        self._firstMacroId = firstMacroId

    def lastMacroId(self):
        return self._lastMacroId

    def setLastMacroId(self, lastMacroId):
        self._lastMacroId = lastMacroId

    def macroIds(self):
        return self._macroIds

    def setMacroIds(self, macroIds):
        self._macroIds = macroIds

    def emitExecutionStarted(self):
        return self._emitExecutionStarted

    def setEmitExecutionStarted(self, yesNo):
        self._emitExecutionStarted = yesNo

    def sequencesPath(self):
        return self._sequencesPath

    def setSequencesPath(self, sequencesPath):
        self._sequencesPath = sequencesPath

    def isFullSequencePlot(self):
        return self._fullSequencePlot

    def setFullSequencePlot(self, fullSequencePlot):
        self._fullSequencePlot = fullSequencePlot

    def onNewSequence(self):
        if Qt.QMessageBox.question(self,
                                   "New sequence",
                                   "Do you want to save existing sequence?",
                                   Qt.QMessageBox.Yes,
                                   Qt.QMessageBox.No) == Qt.QMessageBox.Yes:
            self.onSaveSequence()
        self.tree.clearTree()
        self.newSequenceAction.setEnabled(False)
        self.saveSequenceAction.setEnabled(False)
        self.currentMacroChanged.emit(None)

    def loadFile(self, fileName):
        if fileName == "":
            return
        #@todo: reset macroComboBox to index 0
        try:
            file = open(fileName, 'r')
            string = file.read()
            if fileName.endswith('.xml'):
                root = self.fromXmlString(string)
            else:
                root = self.fromPlainText(string)
            self._sequenceModel.setRoot(root)
            self.sequenceProxyModel.invalidateFilter()
            self.tree.expandAll()
            self.tree.expanded()
            self.parametersProxyModel.setMacroIndex(None)
            self.parametersProxyModel.invalidateFilter()

            if not self._sequenceModel.isEmpty():
                self.newSequenceAction.setEnabled(True)
                self.saveSequenceAction.setEnabled(True)
                self.playSequenceAction.setEnabled(True)
        except IOError:
            Qt.QMessageBox.warning(
                self,
                "Error while loading macros sequence",
                "There was a problem while reading from file: %s" % fileName)
            file = None
            self.tree.clearTree()
            self.newSequenceAction.setEnabled(False)
            self.saveSequenceAction.setEnabled(False)
        except:
            self.tree.clearTree()
            self.playSequenceAction.setEnabled(False)
            self.newSequenceAction.setEnabled(False)
            self.saveSequenceAction.setEnabled(False)
            raise
        finally:
            if not file is None:
                file.close()
            self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1]))

        self.currentMacroChanged.emit(None)

    def onOpenSequence(self):
        if not self._sequenceModel.isEmpty():
            if Qt.QMessageBox.question(
                    self,
                    "Open sequence",
                    "Do you want to save existing sequence?",
                    Qt.QMessageBox.Yes,
                    Qt.QMessageBox.No) == Qt.QMessageBox.Yes:
                self.onSaveSequence()
                self.tree.clearTree()

        sequencesPath = self.sequencesPath()
        fileName, _ = compat.getOpenFileName(
            self,
            "Choose a sequence to open...",
            sequencesPath,
            "*")
        self.loadFile(fileName)


    def onSaveSequence(self):
        sequencesPath = self.sequencesPath()
        if sequencesPath == "":
            sequencesPath = str(Qt.QDir.homePath())

        sequencesPath = os.path.join(sequencesPath, "Untitled.xml")
        fileName, _ = compat.getSaveFileName(
            self,
            "Choose a sequence file name...",
            sequencesPath,
            "*.xml")
        if fileName == "":
            return
        try:
            file = open(fileName, "w")
            file.write(self.tree.toXmlString(pretty=True, withId=False))
            self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1]))
        except Exception as e:
            Qt.QMessageBox.warning(
                self,
                "Error while saving macros sequence",
                "There was a problem while writing to the file: %s" %
                fileName)
            print e
        finally:
            if not file is None:
                file.close()

    def onPlaySequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if (doorState == PyTango.DevState.ON or
                doorState == PyTango.DevState.ALARM):
            first, last, ids = self.tree.prepareMacroIds()
            self.setFirstMacroId(first)
            self.setLastMacroId(last)
            self.setMacroIds(ids)
            self.tree.prepareMacroProgresses()
            self.setEmitExecutionStarted(True)
            door.runMacro(self.tree.toXmlString())
        elif doorState == PyTango.DevState.STANDBY:
            door.command_inout("ResumeMacro")
        else:
            Qt.QMessageBox.warning(
                self,
                "Error while starting/resuming sequence",
                "It was not possible to start/resume sequence, "
                "because state of the door was different than ON/STANDBY")

    def onStopSequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
            door.command_inout("StopMacro")
        else:
            Qt.QMessageBox.warning(
                self,
                "Error while stopping sequence",
                "It was not possible to stop sequence, "
                "because state of the door was different than "
                "RUNNING or STANDBY")

    def onPauseSequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            door.command_inout("PauseMacro")
        else:
            Qt.QMessageBox.warning(
                self,
                "Error while pausing sequence",
                "It was not possible to pause sequence, "
                "because state of the door was different than RUNNING")

    def onMacroStatusUpdated(self, data):
        macro = data[0]
        if macro is None:
            return
        data = data[1][0]
        state, range, step, id = str(data["state"]), data[
            "range"], data["step"], data["id"]
        if id is None:
            return
        id = int(id)
        if not id in self.macroIds():
            return
        macroName = macro.name
        shortMessage = ""
        if state == "start":
            #@todo: Check this signal because it doesn't work,
            # emitExecutionStarted is not set!!!
            if self.emitExecutionStarted():
                self.macroStarted.emit("DoorOutput")
            self.tree.setRangeForMacro(id, range)
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            self.stopSequenceAction.setEnabled(True)
            if id == self.firstMacroId():
                self.plotablesFilterChanged.emit(None)
                self.plotablesFilterChanged.emit(standardPlotablesFilter)
                shortMessage = "Sequence started."
            elif not self.isFullSequencePlot():
                self.plotablesFilterChanged.emit(None)
            shortMessage += " Macro %s started." % macroName
        elif state == "pause":
            self.playSequenceAction.setText("Resume sequence")
            self.playSequenceAction.setToolTip("Resume sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            shortMessage = "Macro %s paused." % macroName
        elif state == "resume":
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            shortMessage = "Macro %s resumed." % macroName
        elif state == "stop" or state == "finish":
            shortMessage = "Macro %s finished." % macroName
            if id == self.lastMacroId():
                self.playSequenceAction.setEnabled(True)
                self.pauseSequenceAction.setEnabled(False)
                self.stopSequenceAction.setEnabled(False)
                shortMessage += " Sequence finished."
        elif state == 'exception':
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
            shortMessage = "Macro %s error." % macroName
            exc_value, exc_stack = data['exc_value'], data['exc_stack']
            exceptionDialog = TaurusMessageBox(
                MacroRunException, exc_value, exc_stack)
            exceptionDialog.exec_()
        elif state == 'abort':
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
            shortMessage = "Macro %s stopped." % macroName
        elif state == "step":
            shortMessage = "Macro %s at %d %% of progress." % (macroName,
                                                               step)
        self.shortMessageEmitted.emit(shortMessage)
        self.tree.setProgressForMacro(id, step)

    def onDoorChanged(self, doorName):
        self.setDoorName(doorName)
        if self.doorName() == "":
            self.doorStateLed.setModel(None)
            return
        self.doorStateLed.setModel(self.doorName() + "/State")
        door = Device(doorName)
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON:
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playSequenceAction.setText("Resume sequence")
            self.playSequenceAction.setToolTip("Resume sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(True)

    def setMacroParametersRootIndex(self, sourceIndex):
        parametersModel = self.standardMacroParametersEditor.tree.model()
        parametersModel.setMacroIndex(sourceIndex)
        parametersModel.invalidateFilter()
        proxyIndex = parametersModel.mapFromSource(sourceIndex)

        macroNode = sourceIndex.internalPointer()
        macroName = macroNode.name()

        if self.stackedWidget.count() == 2:
            self.stackedWidget.removeWidget(self.customMacroParametersEditor)
            self.customMacroParametersEditor.setParent(None)
        self.customMacroParametersEditor = \
            ParamEditorManager().getMacroEditor(macroName)
        if self.customMacroParametersEditor:
            self.customMacroParametersEditor.setModel(parametersModel)
            self.customMacroParametersEditor.setRootIndex(proxyIndex)
            self.stackedWidget.addWidget(self.customMacroParametersEditor)
            self.stackedWidget.setCurrentWidget(
                self.customMacroParametersEditor)
        else:
            self.standardMacroParametersEditor.tree.setRootIndex(proxyIndex)
            self.standardMacroParametersEditor.tree.expandAll()

    def onMacroComboBoxChanged(self):
        macroName = str(self.macroComboBox.currentText())
        if macroName == "":
            self.addMacroAction.setEnabled(False)
        else:
            self.addMacroAction.setEnabled(True)
        self.macroNameChanged.emit(macroName)

    def onAdd(self):
        macroName = str(self.macroComboBox.currentText())
        macroNode = self.getModelObj().getMacroNodeObj(macroName)
        self.tree.addMacro(macroNode)
        self.saveSequenceAction.setEnabled(True)
        self.playSequenceAction.setEnabled(True)

    def isEmptySequence(self):
        return len(self.tree.root()) == 0

    def isMacroSelected(self):
        return len(self.tree.selectedIndexes()) == 2

    def emptySequence(self):
        self.tree.clearTree()
        self.disableButtons()
        self.currentMacroChanged.emit(None)
        self.sequenceEmpty.emit()

    def fromXmlString(self, xmlString):
        newRoot = self.tree.fromXmlString(xmlString)
        macroServerObj = self.getModelObj()
        for macroNode in newRoot.allMacros():
            macroServerObj.fillMacroNodeAdditionalInfos(macroNode)
        return newRoot

    def fromPlainText(self, plainText):
        newRoot = self.tree.fromPlainText(plainText)
        macroServerObj = self.getModelObj()
        error_line = 0
        for macroNode in newRoot.allMacros():
            error_line += 1
            try:
                macroServerObj.recreateMacroNodeAndFillAdditionalInfos(
                    macroNode)
            except Exception as e:
                Qt.QMessageBox.warning(self,
                                       "Error while parsing the sequence",
                                       "Sequence line number %d contains "
                                       "the following error:\n %s\n "
                                       "The sequence will not be loaded"
                                       % (error_line, e))
                raise e
        return newRoot

    def setModel(self, model):
        oldModelObj = self.getModelObj()
        if oldModelObj is not None:
            oldModelObj.macrosUpdated.disconnect(
                self.macroComboBox.onMacrosUpdated)
        TaurusWidget.setModel(self, model)
        newModelObj = self.getModelObj()
        newModelObj.macrosUpdated.connect(self.macroComboBox.onMacrosUpdated)

    @classmethod
    def getQtDesignerPluginInfo(cls):
        return {'container': False,
                'group': 'Taurus Sardana',
                'module': 'taurus.qt.qtgui.extra_macroexecutor',
                'icon': ':/designer/frame.png'}
Exemplo n.º 3
0
class TaurusSequencerWidget(TaurusWidget):

    macroStarted = Qt.pyqtSignal('QString')
    plotablesFilterChanged = Qt.pyqtSignal(object)
    currentMacroChanged = Qt.pyqtSignal(object)
    macroNameChanged = Qt.pyqtSignal('QString')
    shortMessageEmitted = Qt.pyqtSignal('QString')
    sequenceEmpty = Qt.pyqtSignal()

    def __init__(self, parent=None, designMode=False):
        TaurusWidget.__init__(self, parent, designMode)
        # list representing all macros ids (all from sequence) currently
        # executed
        self._macroIds = []
        self._sequencesPath = str(Qt.QDir.homePath())
        self._sequenceModel = MacroSequenceTreeModel()

        self.registerConfigProperty("sequencesPath", "setSequencesPath",
                                    "sequencesPath")

        self.setLayout(Qt.QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        splitter = Qt.QSplitter()
        self.layout().addWidget(splitter)
        splitter.setOrientation(Qt.Qt.Vertical)

        sequenceEditor = TaurusWidget()
        splitter.addWidget(sequenceEditor)
        sequenceEditor.setUseParentModel(True)
        sequenceEditor.setLayout(Qt.QVBoxLayout())
        sequenceEditor.layout().setContentsMargins(0, 0, 0, 0)

        self.tree = MacroSequenceTree(sequenceEditor)
        self.sequenceProxyModel = MacroSequenceProxyModel()
        self.sequenceProxyModel.setSourceModel(self._sequenceModel)
        self.tree.setModel(self.sequenceProxyModel)
        self.tree.setItemDelegate(SequenceEditorDelegate(self.tree))

        actionsLayout = Qt.QHBoxLayout()
        actionsLayout.setContentsMargins(0, 0, 0, 0)
        self.newSequenceAction = Qt.QAction(getThemeIcon("document-new"),
                                            "New", self)
        self.newSequenceAction.triggered.connect(self.onNewSequence)
        self.newSequenceAction.setToolTip("New sequence")
        self.newSequenceAction.setEnabled(False)
        newSequenceButton = Qt.QToolButton()
        newSequenceButton.setDefaultAction(self.newSequenceAction)
        actionsLayout.addWidget(newSequenceButton)

        self.openSequenceAction = Qt.QAction(getThemeIcon("document-open"),
                                             "Open...", self)
        self.openSequenceAction.triggered.connect(self.onOpenSequence)
        self.openSequenceAction.setToolTip("Open sequence...")
        openSequenceButton = Qt.QToolButton()
        openSequenceButton.setDefaultAction(self.openSequenceAction)
        actionsLayout.addWidget(openSequenceButton)

        self.saveSequenceAction = Qt.QAction(getThemeIcon("document-save"),
                                             "Save...", self)
        self.saveSequenceAction.triggered.connect(self.onSaveSequence)
        self.saveSequenceAction.setToolTip("Save sequence...")
        self.saveSequenceAction.setEnabled(False)
        saveSequenceButton = Qt.QToolButton()
        saveSequenceButton.setDefaultAction(self.saveSequenceAction)
        actionsLayout.addWidget(saveSequenceButton)

        self.stopSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_stop.svg"), "Stop", self)
        self.stopSequenceAction.triggered.connect(self.onStopSequence)
        self.stopSequenceAction.setToolTip("Stop sequence")
        stopSequenceButton = Qt.QToolButton()
        stopSequenceButton.setDefaultAction(self.stopSequenceAction)
        actionsLayout.addWidget(stopSequenceButton)

        self.pauseSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_pause.svg"), "Pause", self)
        self.pauseSequenceAction.triggered.connect(self.onPauseSequence)
        self.pauseSequenceAction.setToolTip("Pause sequence")
        pauseSequenceButton = Qt.QToolButton()
        pauseSequenceButton.setDefaultAction(self.pauseSequenceAction)
        actionsLayout.addWidget(pauseSequenceButton)

        self.playSequenceAction = Qt.QAction(
            getIcon(":/actions/media_playback_start.svg"), "Play", self)
        self.playSequenceAction.triggered.connect(self.onPlaySequence)
        self.playSequenceAction.setToolTip("Play sequence")
        playSequenceButton = Qt.QToolButton()
        playSequenceButton.setDefaultAction(self.playSequenceAction)
        actionsLayout.addWidget(playSequenceButton)

        self.doorStateLed = TaurusLed(self)
        actionsLayout.addWidget(self.doorStateLed)

        #@todo this feature will be replaced by checkboxes in the
        # sequence tree view indicating clearing of the plot after execution
        self.fullSequencePlotCheckBox = Qt.QCheckBox("Full sequence plot",
                                                     self)
        self.fullSequencePlotCheckBox.toggled.connect(self.setFullSequencePlot)
        self.fullSequencePlotCheckBox.setChecked(True)
        actionsLayout.addWidget(self.fullSequencePlotCheckBox)

        spacerItem = Qt.QSpacerItem(0, 0, Qt.QSizePolicy.Expanding,
                                    Qt.QSizePolicy.Fixed)
        actionsLayout.addItem(spacerItem)

        sequenceEditor.layout().addLayout(actionsLayout)

        macroLayout = Qt.QHBoxLayout()
        macroLayout.setContentsMargins(0, 0, 0, 0)
        macroLabel = Qt.QLabel("Macro:")
        macroLayout.addWidget(macroLabel)
        self.macroComboBox = MacroComboBox(self)
        self.macroComboBox.setUseParentModel(True)
        self.macroComboBox.setModelColumn(0)
        self.macroComboBox.setSizePolicy(Qt.QSizePolicy.Expanding,
                                         Qt.QSizePolicy.Minimum)
        macroLayout.addWidget(self.macroComboBox)

        self.addMacroAction = Qt.QAction(getThemeIcon("list-add"),
                                         "Add macro...", self)
        self.addMacroAction.triggered.connect(self.onAdd)
        self.addMacroAction.setToolTip(
            "Clicking this button will add selected macro")
        self.addMacroAction.setEnabled(False)
        addButton = Qt.QToolButton()
        addButton.setDefaultAction(self.addMacroAction)
        macroLayout.addWidget(addButton)

        sequenceEditor.layout().addLayout(macroLayout)

        sequenceLayout = Qt.QHBoxLayout()
        sequenceLayout.addWidget(self.tree)

        layout = Qt.QVBoxLayout()
        delButton = Qt.QToolButton()
        delButton.setDefaultAction(self.tree.deleteAction)
        delButton.setEnabled(False)
        layout.addWidget(delButton)
        upButton = Qt.QToolButton()
        upButton.setDefaultAction(self.tree.moveUpAction)
        upButton.setEnabled(False)
        layout.addWidget(upButton)
        downButton = Qt.QToolButton()
        downButton.setDefaultAction(self.tree.moveDownAction)
        downButton.setEnabled(False)
        layout.addWidget(downButton)
        leftButton = Qt.QToolButton()
        leftButton.setDefaultAction(self.tree.moveLeftAction)
        leftButton.setEnabled(False)
        layout.addWidget(leftButton)
        rightButton = Qt.QToolButton()
        rightButton.setDefaultAction(self.tree.moveRightAction)
        rightButton.setEnabled(False)
        layout.addWidget(rightButton)
        spacerItem = Qt.QSpacerItem(0, 40, Qt.QSizePolicy.Fixed,
                                    Qt.QSizePolicy.Expanding)
        layout.addItem(spacerItem)
        sequenceLayout.addLayout(layout)
        sequenceEditor.layout().addLayout(sequenceLayout)

        self.parametersProxyModel = MacroParametersProxyModel()
        self.parametersProxyModel.setSourceModel(self._sequenceModel)

        self.stackedWidget = Qt.QStackedWidget()
        splitter.addWidget(self.stackedWidget)
        self.standardMacroParametersEditor = StandardMacroParametersEditor(
            self.stackedWidget)
        self.standardMacroParametersEditor.setModel(self.parametersProxyModel)
        self.standardMacroParametersEditor.tree.setItemDelegate(
            ParamEditorDelegate(self.standardMacroParametersEditor.tree))
        self.stackedWidget.addWidget(self.standardMacroParametersEditor)
        self.customMacroParametersEditor = None

        self.macroComboBox.currentIndexChanged.connect(
            self.onMacroComboBoxChanged)
        self.tree.macroChanged.connect(self.setMacroParametersRootIndex)

    def contextMenuEvent(self, event):
        menu = Qt.QMenu()
        action = menu.addAction(getThemeIcon("view-refresh"),
                                "Check door state", self.checkDoorState)
        menu.exec_(event.globalPos())

    def checkDoorState(self):
        """Method used by "Check door state" action (available in the context
        menu). It is a workaround for situations when the event notification
        about the macro status does not reach the sequencer widget."""

        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            self.stopSequenceAction.setEnabled(True)
        elif doorState in (PyTango.DevState.ON, PyTango.DevState.ALARM):
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(True)

    def doorName(self):
        return self._doorName

    def setDoorName(self, doorName):
        self._doorName = doorName

    def firstMacroId(self):
        return self._firstMacroId

    def setFirstMacroId(self, firstMacroId):
        self._firstMacroId = firstMacroId

    def lastMacroId(self):
        return self._lastMacroId

    def setLastMacroId(self, lastMacroId):
        self._lastMacroId = lastMacroId

    def macroIds(self):
        return self._macroIds

    def setMacroIds(self, macroIds):
        self._macroIds = macroIds

    def emitExecutionStarted(self):
        return self._emitExecutionStarted

    def setEmitExecutionStarted(self, yesNo):
        self._emitExecutionStarted = yesNo

    def sequencesPath(self):
        return self._sequencesPath

    def setSequencesPath(self, sequencesPath):
        self._sequencesPath = sequencesPath

    def isFullSequencePlot(self):
        return self._fullSequencePlot

    def setFullSequencePlot(self, fullSequencePlot):
        self._fullSequencePlot = fullSequencePlot

    def onNewSequence(self):
        if Qt.QMessageBox.question(self, "New sequence",
                                   "Do you want to save existing sequence?",
                                   Qt.QMessageBox.Yes,
                                   Qt.QMessageBox.No) == Qt.QMessageBox.Yes:
            self.onSaveSequence()
        self.tree.clearTree()
        self.newSequenceAction.setEnabled(False)
        self.saveSequenceAction.setEnabled(False)
        self.currentMacroChanged.emit(None)

    def loadFile(self, fileName):
        if fileName == "":
            return
        #@todo: reset macroComboBox to index 0
        try:
            file = open(fileName, 'r')
            string = file.read()
            if fileName.endswith('.xml'):
                root = self.fromXmlString(string)
            else:
                root = self.fromPlainText(string)
            self._sequenceModel.setRoot(root)
            self.sequenceProxyModel.invalidateFilter()
            self.tree.expandAll()
            self.tree.expanded()
            self.parametersProxyModel.setMacroIndex(None)
            self.parametersProxyModel.invalidateFilter()

            if not self._sequenceModel.isEmpty():
                self.newSequenceAction.setEnabled(True)
                self.saveSequenceAction.setEnabled(True)
                self.playSequenceAction.setEnabled(True)
        except IOError:
            Qt.QMessageBox.warning(
                self, "Error while loading macros sequence",
                "There was a problem while reading from file: %s" % fileName)
            file = None
            self.tree.clearTree()
            self.newSequenceAction.setEnabled(False)
            self.saveSequenceAction.setEnabled(False)
        except:
            self.tree.clearTree()
            self.playSequenceAction.setEnabled(False)
            self.newSequenceAction.setEnabled(False)
            self.saveSequenceAction.setEnabled(False)
            raise
        finally:
            if not file is None:
                file.close()
            self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1]))

        self.currentMacroChanged.emit(None)

    def onOpenSequence(self):
        if not self._sequenceModel.isEmpty():
            if Qt.QMessageBox.question(
                    self, "Open sequence",
                    "Do you want to save existing sequence?",
                    Qt.QMessageBox.Yes,
                    Qt.QMessageBox.No) == Qt.QMessageBox.Yes:
                self.onSaveSequence()
                self.tree.clearTree()

        sequencesPath = self.sequencesPath()
        fileName, _ = compat.getOpenFileName(self,
                                             "Choose a sequence to open...",
                                             sequencesPath, "*")
        self.loadFile(fileName)

    def onSaveSequence(self):
        sequencesPath = self.sequencesPath()
        if sequencesPath == "":
            sequencesPath = str(Qt.QDir.homePath())

        sequencesPath = os.path.join(sequencesPath, "Untitled.xml")
        fileName, _ = compat.getSaveFileName(self,
                                             "Choose a sequence file name...",
                                             sequencesPath, "*.xml")
        if fileName == "":
            return
        try:
            file = open(fileName, "w")
            file.write(self.tree.toXmlString(pretty=True, withId=False))
            self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1]))
        except Exception as e:
            Qt.QMessageBox.warning(
                self, "Error while saving macros sequence",
                "There was a problem while writing to the file: %s" % fileName)
            print e
        finally:
            if not file is None:
                file.close()

    def onPlaySequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if (doorState == PyTango.DevState.ON
                or doorState == PyTango.DevState.ALARM):
            first, last, ids = self.tree.prepareMacroIds()
            self.setFirstMacroId(first)
            self.setLastMacroId(last)
            self.setMacroIds(ids)
            self.tree.prepareMacroProgresses()
            self.setEmitExecutionStarted(True)
            door.runMacro(self.tree.toXmlString())
        elif doorState == PyTango.DevState.STANDBY:
            door.command_inout("ResumeMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while starting/resuming sequence",
                "It was not possible to start/resume sequence, "
                "because state of the door was different than ON/STANDBY")

    def onStopSequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
            door.command_inout("StopMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while stopping sequence",
                "It was not possible to stop sequence, "
                "because state of the door was different than "
                "RUNNING or STANDBY")

    def onPauseSequence(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            door.command_inout("PauseMacro")
        else:
            Qt.QMessageBox.warning(
                self, "Error while pausing sequence",
                "It was not possible to pause sequence, "
                "because state of the door was different than RUNNING")

    def onMacroStatusUpdated(self, data):
        macro = data[0]
        if macro is None:
            return
        data = data[1][0]
        state, range, step, id = str(
            data["state"]), data["range"], data["step"], data["id"]
        if id is None:
            return
        id = int(id)
        if not id in self.macroIds():
            return
        macroName = macro.name
        shortMessage = ""
        if state == "start":
            #@todo: Check this signal because it doesn't work,
            # emitExecutionStarted is not set!!!
            if self.emitExecutionStarted():
                self.macroStarted.emit("DoorOutput")
            self.tree.setRangeForMacro(id, range)
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            self.stopSequenceAction.setEnabled(True)
            if id == self.firstMacroId():
                self.plotablesFilterChanged.emit(None)
                self.plotablesFilterChanged.emit(standardPlotablesFilter)
                shortMessage = "Sequence started."
            elif not self.isFullSequencePlot():
                self.plotablesFilterChanged.emit(None)
            shortMessage += " Macro %s started." % macroName
        elif state == "pause":
            self.playSequenceAction.setText("Resume sequence")
            self.playSequenceAction.setToolTip("Resume sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            shortMessage = "Macro %s paused." % macroName
        elif state == "resume":
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(True)
            shortMessage = "Macro %s resumed." % macroName
        elif state == "stop" or state == "finish":
            shortMessage = "Macro %s finished." % macroName
            if id == self.lastMacroId():
                self.playSequenceAction.setEnabled(True)
                self.pauseSequenceAction.setEnabled(False)
                self.stopSequenceAction.setEnabled(False)
                shortMessage += " Sequence finished."
        elif state == 'exception':
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
            shortMessage = "Macro %s error." % macroName
            exc_value, exc_stack = data['exc_value'], data['exc_stack']
            exceptionDialog = TaurusMessageBox(MacroRunException, exc_value,
                                               exc_stack)
            exceptionDialog.exec_()
        elif state == 'abort':
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
            shortMessage = "Macro %s stopped." % macroName
        elif state == "step":
            shortMessage = "Macro %s at %d %% of progress." % (macroName, step)
        self.shortMessageEmitted.emit(shortMessage)
        self.tree.setProgressForMacro(id, step)

    def onDoorChanged(self, doorName):
        self.setDoorName(doorName)
        if self.doorName() == "":
            self.doorStateLed.setModel(None)
            return
        self.doorStateLed.setModel(self.doorName() + "/State")
        door = Device(doorName)
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON:
            self.playSequenceAction.setText("Start sequence")
            self.playSequenceAction.setToolTip("Start sequence")
            self.playSequenceAction.setEnabled(False)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playSequenceAction.setText("Resume sequence")
            self.playSequenceAction.setToolTip("Resume sequence")
            self.playSequenceAction.setEnabled(True)
            self.pauseSequenceAction.setEnabled(False)
            self.stopSequenceAction.setEnabled(True)

    def setMacroParametersRootIndex(self, sourceIndex):
        parametersModel = self.standardMacroParametersEditor.tree.model()
        parametersModel.setMacroIndex(sourceIndex)
        parametersModel.invalidateFilter()
        proxyIndex = parametersModel.mapFromSource(sourceIndex)

        macroNode = sourceIndex.internalPointer()
        macroName = macroNode.name()

        if self.stackedWidget.count() == 2:
            self.stackedWidget.removeWidget(self.customMacroParametersEditor)
            self.customMacroParametersEditor.setParent(None)
        self.customMacroParametersEditor = \
            ParamEditorManager().getMacroEditor(macroName)
        if self.customMacroParametersEditor:
            self.customMacroParametersEditor.setModel(parametersModel)
            self.customMacroParametersEditor.setRootIndex(proxyIndex)
            self.stackedWidget.addWidget(self.customMacroParametersEditor)
            self.stackedWidget.setCurrentWidget(
                self.customMacroParametersEditor)
        else:
            self.standardMacroParametersEditor.tree.setRootIndex(proxyIndex)
            self.standardMacroParametersEditor.tree.expandAll()

    def onMacroComboBoxChanged(self):
        macroName = str(self.macroComboBox.currentText())
        if macroName == "":
            self.addMacroAction.setEnabled(False)
        else:
            self.addMacroAction.setEnabled(True)
        self.macroNameChanged.emit(macroName)

    def onAdd(self):
        macroName = str(self.macroComboBox.currentText())
        macroNode = self.getModelObj().getMacroNodeObj(macroName)
        self.tree.addMacro(macroNode)
        self.saveSequenceAction.setEnabled(True)
        self.playSequenceAction.setEnabled(True)

    def isEmptySequence(self):
        return len(self.tree.root()) == 0

    def isMacroSelected(self):
        return len(self.tree.selectedIndexes()) == 2

    def emptySequence(self):
        self.tree.clearTree()
        self.disableButtons()
        self.currentMacroChanged.emit(None)
        self.sequenceEmpty.emit()

    def fromXmlString(self, xmlString):
        newRoot = self.tree.fromXmlString(xmlString)
        macroServerObj = self.getModelObj()
        for macroNode in newRoot.allMacros():
            macroServerObj.fillMacroNodeAdditionalInfos(macroNode)
        return newRoot

    def fromPlainText(self, plainText):
        newRoot = self.tree.fromPlainText(plainText)
        macroServerObj = self.getModelObj()
        error_line = 0
        for macroNode in newRoot.allMacros():
            error_line += 1
            try:
                macroServerObj.recreateMacroNodeAndFillAdditionalInfos(
                    macroNode)
            except Exception as e:
                Qt.QMessageBox.warning(
                    self, "Error while parsing the sequence",
                    "Sequence line number %d contains "
                    "the following error:\n %s\n "
                    "The sequence will not be loaded" % (error_line, e))
                raise e
        return newRoot

    def setModel(self, model):
        oldModelObj = self.getModelObj()
        if oldModelObj is not None:
            oldModelObj.macrosUpdated.disconnect(
                self.macroComboBox.onMacrosUpdated)
        TaurusWidget.setModel(self, model)
        newModelObj = self.getModelObj()
        newModelObj.macrosUpdated.connect(self.macroComboBox.onMacrosUpdated)

    @classmethod
    def getQtDesignerPluginInfo(cls):
        return {
            'container': False,
            'group': 'Taurus Sardana',
            'module': 'taurus.qt.qtgui.extra_macroexecutor',
            'icon': ':/designer/frame.png'
        }
Exemplo n.º 4
0
class TaurusMacroExecutorWidget(TaurusWidget):

    doorChanged = Qt.pyqtSignal('QString')
    macroNameChanged = Qt.pyqtSignal('QString')
    macroStarted = Qt.pyqtSignal('QString')
    plotablesFilterChanged = Qt.pyqtSignal(object)
    shortMessageEmitted = Qt.pyqtSignal('QString')

    def __init__(self, parent=None, designMode=False):
        TaurusWidget.__init__(self, parent, designMode)
        self.setObjectName(self.__class__.__name__)

        self._doorName = ""
        self._macroId = None
        self.setLayout(Qt.QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.addToFavouritesAction = Qt.QAction(getThemeIcon(
            "software-update-available"), "Add to favourites", self)
        self.addToFavouritesAction.triggered.connect(self.onAddToFavourites)
        self.addToFavouritesAction.setToolTip("Add to favourites")
        self.stopMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_stop.svg"), "Stop macro", self)
        self.stopMacroAction.triggered.connect(self.onStopMacro)
        self.stopMacroAction.setToolTip("Stop macro")
        self.pauseMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_pause.svg"), "Pause macro", self)
        self.pauseMacroAction.triggered.connect(self.onPauseMacro)
        self.pauseMacroAction.setToolTip("Pause macro")
        self.playMacroAction = Qt.QAction(
            getIcon(":/actions/media_playback_start.svg"), "Start macro", self)
        self.playMacroAction.triggered.connect(self.onPlayMacro)
        self.playMacroAction.setToolTip("Start macro")
        actionsLayout = Qt.QHBoxLayout()
        actionsLayout.setContentsMargins(0, 0, 0, 0)
        addToFavouritsButton = Qt.QToolButton()
        addToFavouritsButton.setDefaultAction(self.addToFavouritesAction)
        self.addToFavouritesAction.setEnabled(False)
        actionsLayout.addWidget(addToFavouritsButton)

        self.macroComboBox = MacroComboBox(self)
        self.macroComboBox.setUseParentModel(True)
        self.macroComboBox.setModelColumn(0)
        actionsLayout.addWidget(self.macroComboBox)
        stopMacroButton = Qt.QToolButton()
        stopMacroButton.setDefaultAction(self.stopMacroAction)
        actionsLayout.addWidget(stopMacroButton)
        pauseMacroButton = Qt.QToolButton()
        pauseMacroButton.setDefaultAction(self.pauseMacroAction)
        actionsLayout.addWidget(pauseMacroButton)
        self.playMacroButton = Qt.QToolButton()
        self.playMacroButton.setDefaultAction(self.playMacroAction)
        actionsLayout.addWidget(self.playMacroButton)
        self.disableControlActions()
        self.doorStateLed = TaurusLed(self)
        actionsLayout.addWidget(self.doorStateLed)
        self.layout().addLayout(actionsLayout)

        splitter = Qt.QSplitter(self)
        self.layout().addWidget(splitter)
        splitter.setOrientation(Qt.Qt.Vertical)

        self._paramEditorModel = ParamEditorModel()
        self.stackedWidget = Qt.QStackedWidget()
        self.standardMacroParametersEditor = StandardMacroParametersEditor(
            self.stackedWidget)
        self.stackedWidget.addWidget(self.standardMacroParametersEditor)
        self.customMacroParametersEditor = None
        splitter.addWidget(self.stackedWidget)

        self._favouritesBuffer = None
        self.favouritesMacrosEditor = FavouritesMacrosEditor(self)
        self.registerConfigDelegate(self.favouritesMacrosEditor)
        self.favouritesMacrosEditor.setUseParentModel(True)
        self.favouritesMacrosEditor.setFocusPolicy(Qt.Qt.NoFocus)

        self._historyBuffer = None
        self.historyMacrosViewer = HistoryMacrosViewer(self)
        self.registerConfigDelegate(self.historyMacrosViewer)
        self.historyMacrosViewer.setUseParentModel(True)
        self.historyMacrosViewer.setFocusPolicy(Qt.Qt.NoFocus)

        self.tabMacroListsWidget = Qt.QTabWidget(self)
        self.tabMacroListsWidget.addTab(
            self.favouritesMacrosEditor, "Favourite list")
        self.tabMacroListsWidget.addTab(
            self.historyMacrosViewer, "History Viewer")
        splitter.addWidget(self.tabMacroListsWidget)
        # Due to a limitation in the useParentModel architecture of Taurus,
        # the parent of historyMacrosViewer and favouritesMacrosEditor
        # must be recalculated. See more details in the taurus snippet code [1]
        # [1] https://raw.githubusercontent.com/taurus-org/taurus/develop/doc/source/devel/examples/parentmodel_issue_demo.py
        self.historyMacrosViewer.recheckTaurusParent()
        self.favouritesMacrosEditor.recheckTaurusParent()

        self._isHistoryMacro = False
        self.macroProgressBar = MacroProgressBar(self)
        self.layout().addWidget(self.macroProgressBar)

        #spockCommandLabel = Qt.QLabel("Spock command:", self)
        # spockCommandLabel.setFont(Qt.QFont("Courier",9))
        self.spockCommand = SpockCommandWidget("Spock", self)
        self.spockCommand.setSizePolicy(
            Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum)
        self.spockCommand.setUseParentModel(True)
        spockCommandLayout = Qt.QHBoxLayout()
        spockCommandLayout.setContentsMargins(0, 0, 0, 0)
        # spockCommandLayout.addWidget(spockCommandLabel)
        spockCommandLayout.addWidget(self.spockCommand)
        self.layout().addLayout(spockCommandLayout)

        self.macroComboBox.currentIndexChanged['QString'].connect(
            self.onMacroComboBoxChanged)
        self.favouritesMacrosEditor.list.favouriteSelected.connect(
            self.onFavouriteSelected)
        self.historyMacrosViewer.list.historySelected.connect(
            self.onHistorySelected)

        self.spockCommand.pressedReturn.connect(self.onPlayMacro)
        self.spockCommand.spockComboBox.connect(self.setComboBoxItem)
        self.spockCommand.elementUp.connect(self.setHistoryUp)
        self.spockCommand.elementDown.connect(self.setHistoryDown)
        self.spockCommand.expandTree.connect(
            self.standardMacroParametersEditor.tree.expandAll)

    def macroId(self):
        return self._macroId

    def contextMenuEvent(self, event):
        menu = Qt.QMenu()
        action = menu.addAction(getThemeIcon(
            "view-refresh"), "Check door state", self.checkDoorState)
        menu.exec_(event.globalPos())

    def checkDoorState(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.RUNNING:
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            self.stopMacroAction.setEnabled(True)
        elif doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
        elif doorState == PyTango.DevState.STANDBY:
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(True)

    def setMacroId(self, macroId):
        self._macroId = macroId

    def doorName(self):
        return self._doorName

    def setDoorName(self, doorName):
        self._doorName = doorName

    def setFavouritesBuffer(self, favouritesMacro):
        self._favouritesBuffer = favouritesMacro

    # History Widget
    def setHistoryUp(self):
        self.setHistoryFocus()
        self.historyMacrosViewer.listElementUp()

    def setHistoryDown(self):
        self.setHistoryFocus()
        self.historyMacrosViewer.listElementDown()

    def setHistoryFocus(self):
        self.tabMacroListsWidget.setCurrentWidget(self.historyMacrosViewer)
        # self.historyMacrosViewer.setFocus()

    def historyBuffer(self):
        return self._historyBuffer

    def setHistoryBuffer(self, favouritesMacro):
        self._historyBuffer = favouritesMacro

    def favouritesBuffer(self):
        return self._favouritesBuffer

    def paramEditorModel(self):
        return self._paramEditorModel

    def setParamEditorModel(self, paramEditorModel):
        self._paramEditorModel = paramEditorModel

    def setComboBoxItem(self, macroName):
        self.macroComboBox.selectMacro(macroName)

    @Qt.pyqtSlot('QString')
    def onMacroComboBoxChanged(self, macroName):
        macroName = str(macroName)
        if macroName == "":
            macroName, macroNode = None, None
#            macroNode = macro.MacroNode(name="")
            self.playMacroAction.setEnabled(False)
            self.addToFavouritesAction.setEnabled(False)
        else:
            if self._isHistoryMacro:
                macroNode = self.historyBuffer()
                self.setHistoryBuffer(None)
                self.favouritesMacrosEditor.list.clearSelection()
            else:
                macroNode = self.favouritesBuffer()
                self.setFavouritesBuffer(None)
                self.historyMacrosViewer.list.clearSelection()
            self._isHistoryMacro = False

            if macroNode is None:
                macroNode = self.getModelObj().getMacroNodeObj(macroName)

            self.playMacroAction.setEnabled(True)
            self.addToFavouritesAction.setEnabled(True)

        self.paramEditorModel().setRoot(macroNode)
        self.spockCommand.setModel(self.paramEditorModel())
        if self.stackedWidget.count() == 2:
            self.stackedWidget.removeWidget(self.customMacroParametersEditor)
            self.customMacroParametersEditor.setParent(None)
        self.customMacroParametersEditor = ParamEditorManager(
        ).getMacroEditor(macroName, self.stackedWidget)
        if self.customMacroParametersEditor:
            self.customMacroParametersEditor.setModel(self.paramEditorModel())
            self.stackedWidget.addWidget(self.customMacroParametersEditor)
            self.stackedWidget.setCurrentWidget(
                self.customMacroParametersEditor)
        else:
            self.standardMacroParametersEditor.setModel(
                self.paramEditorModel())

        self.macroNameChanged.emit(macroName)

    def onFavouriteSelected(self, macroNode):
        self.setFavouritesBuffer(macroNode)
        name = ""
        if not macroNode is None:
            name = macroNode.name()
        self._isHistoryMacro = False
        self.macroComboBox.selectMacro(name)

    def onHistorySelected(self, macroNode):
        self.setHistoryBuffer(macroNode)
        name = ""
        if not macroNode is None:
            name = macroNode.name()
        self._isHistoryMacro = True
        self.macroComboBox.selectMacro(name)

    def onAddToFavourites(self):
        self.favouritesMacrosEditor.addMacro(
            deepcopy(self.paramEditorModel().root()))

    def addToHistory(self):
        self.historyMacrosViewer.addMacro(
            deepcopy(self.paramEditorModel().root()))

    def onDoorChanged(self, doorName):
        self.setDoorName(doorName)
        if self.doorName() == "":
            self.doorStateLed.setModel(None)
            return
        self.doorStateLed.setModel(self.doorName() + "/State")
        door = Device(doorName)
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON:
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
        elif doorState == PyTango.DevState.STANDBY:
            self.playMacroAction.setText("Resume macro")
            self.playMacroAction.setToolTip("Resume macro")

    def onPlayMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()
        if doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
            self.setFocus()
            paramEditorModel = self.paramEditorModel()
            macroNode = paramEditorModel.root()
            id = macroNode.assignId()
            self.setMacroId(id)
            params, alerts = macroNode.toRun()
            xmlString = paramEditorModel.toXmlString()
            if len(alerts) > 0:
                Qt.QMessageBox.warning(
                    self, "Macro parameters warning", alerts)
                return
            door.runMacro(xmlString)
            self.addToHistory()
#            door.runMacro(str(macroNode.name()), params)
        elif doorState == PyTango.DevState.STANDBY:
            door.command_inout("ResumeMacro")
        else:
            Qt.QMessageBox.warning(self, "Error while starting/resuming macro",
                                   "It was not possible to start/resume macro, because state of the door was different than ON/STANDBY")

    def onStopMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()

        if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
            door.command_inout("StopMacro")
        else:
            Qt.QMessageBox.warning(self, "Error while stopping macro",
                                   "It was not possible to stop macro, because state of the door was different than RUNNING or STANDBY")

    def onPauseMacro(self):
        door = Device(self.doorName())
        try:
            doorState = door.state()
        except TypeError:
            # TODO: For Taurus 4 adaptation
            doorState = door.getState()

        if doorState == PyTango.DevState.RUNNING:
            door.command_inout("PauseMacro")
        else:
            Qt.QMessageBox.warning(self, "Error while pausing macro",
                                   "It was not possible to pause macro, because state of the door was different than RUNNING")

    def onMacroStatusUpdated(self, data):
        macro = data[0]
        if macro is None:
            return
        data = data[1][0]
        state, range, step, id = data["state"], data[
            "range"], data["step"], data["id"]
        if id is None:
            return
        id = int(id)
        if id != self.macroId():
            return
        macroName = macro.name
        shortMessage = ""
        if state == "start":
            self.macroStarted.emit("DoorOutput")
            self.macroProgressBar.setRange(range[0], range[1])
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            self.stopMacroAction.setEnabled(True)
            self.plotablesFilterChanged.emit(None)
            self.plotablesFilterChanged.emit(standardPlotablesFilter)
            shortMessage = "Macro %s started." % macroName
        elif state == "pause":
            self.playMacroAction.setText("Resume macro")
            self.playMacroAction.setToolTip("Resume macro")
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            shortMessage = "Macro %s paused." % macroName
        elif state == "resume":
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
            self.playMacroAction.setEnabled(False)
            self.pauseMacroAction.setEnabled(True)
            shortMessage = "Macro %s resumed." % macroName
        elif state == "stop" or state == "finish":
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s finished." % macroName
        elif state == "exception":
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s error." % macroName
            exc_value, exc_stack = data['exc_value'], data['exc_stack']
            exceptionDialog = TaurusMessageBox(
                MacroRunException, exc_value, exc_stack)
            exceptionDialog.exec_()
        elif state == "abort":
            self.playMacroAction.setText("Start macro")
            self.playMacroAction.setToolTip("Start macro")
            self.playMacroAction.setEnabled(True)
            self.pauseMacroAction.setEnabled(False)
            self.stopMacroAction.setEnabled(False)
            shortMessage = "Macro %s stopped." % macroName
        elif state == "step":
            shortMessage = "Macro %s at %d %% of progress." % (macroName, step)
        self.shortMessageEmitted.emit(shortMessage)
        self.macroProgressBar.setValue(step)

    def disableControlActions(self):
        self.pauseMacroAction.setEnabled(False)
        self.stopMacroAction.setEnabled(False)
        self.playMacroAction.setEnabled(False)

    def setModel(self, model):
        oldModelObj = self.getModelObj()
        if oldModelObj is not None:
            # TODO: check if macrosUpdated signal exists
            oldModelObj.macrosUpdated.disconnect(
                self.macroComboBox.onMacrosUpdated)
        TaurusWidget.setModel(self, model)
        newModelObj = self.getModelObj()
        newModelObj.macrosUpdated.connect(
            self.macroComboBox.onMacrosUpdated)

    @classmethod
    def getQtDesignerPluginInfo(cls):
        return {'container': False,
                'group': 'Taurus Sardana',
                'module': 'taurus.qt.qtgui.extra_macroexecutor',
                'icon': ':/designer/frame.png'}