Ejemplo n.º 1
0
class CameraMotorToolsBrick(BlissWidget):
    def __init__(self, parent, name):
        BlissWidget.__init__(self, parent, name)
        """
        variables
        """
        self.YBeam = None
        self.ZBeam = None
        self.YSize = None
        self.ZSize = None

        self.view = None
        self.firstCall = True
        self.motorArrived = 0

        self.__mosaicView, self.__mosaicDraw = None, None
        """
        property
        """
        self.addProperty("Hor. Motor", "string", "")
        self.horMotHwo = None

        self.addProperty("Vert. Motor", "string", "")
        self.verMotHwo = None

        #self.addProperty("Focus Motor","string","")
        #self.focusMotHwo = None

        #self.addProperty("Focus min step","float",0.05)
        #self.focusMinStep = None

        self.addProperty("Move To", "combo", ("none", "toolbar", "popup"),
                         "none")
        self.movetoMode = None
        self.movetoAction = None

        self.addProperty("Move to color when activate", "combo",
                         ("none", "blue", "green", "yellow", "red", "orange"),
                         "none")
        self.movetoColorWhenActivate = None

        self.addProperty("Limits", "combo", ("none", "toolbar", "popup"),
                         "none")
        self.limitsMode = None
        self.limitsAction = None

        self.addProperty("Measure", "combo", ("none", "toolbar", "popup"),
                         "none")
        self.measureMode = None
        self.measureAction = None

        self.addProperty("Focus", "combo", ("none", "toolbar", "popup"),
                         "none")
        self.focusMode = None
        self.focusAction = None
        self.focusState = None
        self.focusDrawingRectangle = None
        self.focusPointSelected = None

        self.__movetoActionMosaic = None
        """
        Signal
        """
        self.defineSignal('getView', ())
        self.defineSignal('getMosaicView', ())
        self.defineSignal('getCalibration', ())
        self.defineSignal('getBeamPosition', ())
        self.defineSignal('getImage', ())
        self.defineSignal('moveDone', ())
        self.defineSignal('mosaicImageSelected', ())
        """
        Slot
        """
        self.defineSlot('beamPositionChanged', ())
        self.defineSlot('pixelCalibrationChanged', ())
        self.defineSlot('setMoveToMode', ())
        self.defineSlot('setLimitsDisplay', ())
        self.defineSlot('setMoveToState', ())
        """
        widgets - NO APPEARANCE
        """
        self.setFixedSize(0, 0)

    def propertyChanged(self, prop, oldValue, newValue):
        if prop == "Hor. Motor":
            if self.horMotHwo is not None:
                self.disconnect(self.horMotHwo, qt.PYSIGNAL('positionChanged'),
                                self.setHorizontalPosition)
                self.disconnect(self.horMotHwo, qt.PYSIGNAL("limitsChanged"),
                                self.setHorizontalLimits)

            self.horMotHwo = self.getHardwareObject(newValue)

            if self.horMotHwo is not None:
                self.connect(self.horMotHwo, qt.PYSIGNAL('positionChanged'),
                             self.setHorizontalPosition)
                self.connect(self.horMotHwo, qt.PYSIGNAL("limitsChanged"),
                             self.setHorizontalLimits)

        elif prop == "Vert. Motor":
            if self.verMotHwo is not None:
                self.disconnect(self.verMotHwo, qt.PYSIGNAL('positionChanged'),
                                self.setVerticalPosition)
                self.disconnect(self.verMotHwo, qt.PYSIGNAL("limitsChanged"),
                                self.setVerticalLimits)

            self.verMotHwo = self.getHardwareObject(newValue)

            if self.verMotHwo is not None:
                self.connect(self.verMotHwo, qt.PYSIGNAL('positionChanged'),
                             self.setVerticalPosition)
                self.connect(self.verMotHwo, qt.PYSIGNAL("limitsChanged"),
                             self.setVerticalLimits)
        #elif prop == "Focus Motor":
        #    if self.focusMotHwo is not None:
        #        self.disconnect(self.focusMotHwo,qt.PYSIGNAL('positionChanged'),
        #                        self.setFocusPosition)
        #        self.disconnect(self.focusMotHwo,qt.PYSIGNAL('limitsChanged'),
        #                        self.setFocusLimits)

        #    self.focusMotHwo = self.getHardwareObject(newValue)
        #    self.focusState = FocusState(self,self.focusMotHwo)

        #    if self.focusMotHwo is not None:
        #        self.connect(self.focusMotHwo,qt.PYSIGNAL('positionChanged'),
        #                     self.setFocusPosition)
        #        self.connect(self.focusMotHwo,qt.PYSIGNAL('limitsChanged'),
        #                     self.setFocusLimits)
        #        self.connect(self.focusMotHwo, qt.PYSIGNAL("moveDone"),
        #                     self.focusMoveFinished)
        elif prop == "Move To":
            self.movetoMode = _enumTranslate[newValue]
        elif prop == "Limits":
            self.limitsMode = _enumTranslate[newValue]
        elif prop == "Focus":
            self.focusMode = _enumTranslate[newValue]
        elif prop == "Measure":
            self.measureMode = _enumTranslate[newValue]
        elif prop == "Focus min step":
            self.focusMinStep = newValue
        elif prop == "Move to color when activate":
            if newValue == "none":
                self.movetoColorWhenActivate = None
            else:
                self.movetoColorWhenActivate = newValue
        if not self.firstCall:
            self.configureAction()

    def run(self):
        """
        get view
        """
        view = {}
        self.emit(qt.PYSIGNAL("getView"), (view, ))
        try:
            self.drawing = view["drawing"]
            self.view = view["view"]
        except:
            print "No View"
        """
        get calibration
        """
        calib = {}
        self.emit(qt.PYSIGNAL("getCalibration"), (calib, ))
        try:
            # in all this brick we work with pixel calibration in mm
            self.YSize = calib["ycalib"]
            self.ZSize = calib["zcalib"]
            if calib["ycalib"] is not None and calib["zcalib"] is not None:
                self.YSize = self.YSize * 1000
                self.ZSize = self.ZSize * 1000
        except:
            print "No Calibration"
        """
        get beam position
        """
        position = {}
        self.emit(qt.PYSIGNAL("getBeamPosition"), (position, ))
        try:
            self.YBeam = position["ybeam"]
            self.ZBeam = position["zbeam"]
        except:
            print "No Beam Position"
        """
        get mosaic view
        """
        mosaicView = {}
        self.emit(qt.PYSIGNAL('getMosaicView'), (mosaicView, ))
        try:
            self.__mosaicView = mosaicView['view']
            self.__mosaicDraw = mosaicView['drawing']
        except KeyError:
            self.__mosaicView, self.__mosaicDraw = None, None

        self.configureAction()

        self.firstCall = False

    def configureAction(self):
        """
        Move To action
        """
        if self.movetoMode is not None:
            if self.movetoAction is None:
                """
                create action
                """
                self.movetoAction = QubSelectPointAction(
                    name='Move to Beam',
                    place=self.movetoMode,
                    actionInfo='Move to Beam',
                    group='Tools')
                self.connect(self.movetoAction, qt.PYSIGNAL("StateChanged"),
                             self.movetoStateChanged)
                self.connect(self.movetoAction, qt.PYSIGNAL("PointSelected"),
                             self.pointSelected)

                if self.view is not None:
                    self.view.addAction(self.movetoAction)
                    self.oldMoveToActionColor = self.movetoAction.paletteBackgroundColor(
                    )

        else:
            if self.movetoAction is not None:
                """
                remove action
                """
                if self.view is not None:
                    self.view.delAction(self.movetoAction)
                """
                del action from view
                """
                self.disconnect(self.movetoAction,
                                qt.PYSIGNAL("PointSelected"),
                                self.pointSelected)
                self.movetoAction = None
        """
        Limits action
        """
        if self.limitsMode is not None:
            if self.limitsAction is None:
                """
                create action
                """
                self.limitsAction = QubRulerAction(name='Motor Limits',
                                                   place=self.limitsMode,
                                                   group='Tools')

                if self.view is not None:
                    self.view.addAction(self.limitsAction)
            """
            configure action
            """
            if self.horMotHwo is not None:
                mne = self.horMotHwo.getMotorMnemonic()
                self.limitsAction.setLabel(QubRulerAction.HORIZONTAL, 0, mne)

            if self.verMotHwo is not None:
                mne = self.verMotHwo.getMotorMnemonic()
                self.limitsAction.setLabel(QubRulerAction.VERTICAL, 0, mne)

        else:
            if self.limitsAction is not None:
                """
                remove action
                """
                if self.view is not None:
                    self.view.delAction(self.limitsAction)
                """
                del action from view
                """
                self.limitsAction = None

        if self.measureMode is not None:
            if self.measureAction is None:
                self.measureAction = QubOpenDialogAction(
                    parent=self,
                    name='measure',
                    iconName='measure',
                    label='Measure',
                    group='Tools',
                    place=self.measureMode)
                self.measureAction.setConnectCallBack(self._measure_dialog_new)
                logging.getLogger().info("setting measure mode")
                if self.view is not None:
                    logging.getLogger().info("adding action")
                    self.view.addAction(self.measureAction)
        else:
            if self.measureAction is not None:
                if self.view is not None:
                    self.view.delAction(self.measureAction)
                self.measureAction = None

        if self.movetoMode is not None:
            if self.__movetoActionMosaic is not None:
                self.__mosaicView.delAction(self.__movetoActionMosaic)
                self.disconnect(self.__movetoActionMosaic,
                                qt.PYSIGNAL("PointSelected"),
                                self.__mosaicPointSelected)
                self.diconnect(self.__movetoActionMosaic,
                               qt.PYSIGNAL("StateChanged"),
                               self.__movetoMosaicStateChanged)
                self.__movetoActionMosaic = None

            if self.__mosaicView is not None:
                self.__movetoActionMosaic = QubSelectPointAction(
                    name='Move to Beam',
                    place=self.movetoMode,
                    actionInfo='Move to Beam',
                    mosaicMode=True,
                    residualMode=True,
                    group='Tools')
                self.connect(self.__movetoActionMosaic,
                             qt.PYSIGNAL("PointSelected"),
                             self.__mosaicPointSelected)
                self.connect(self.__movetoActionMosaic,
                             qt.PYSIGNAL("StateChanged"),
                             self.__movetoMosaicStateChanged)

                self.__mosaicView.addAction(self.__movetoActionMosaic)
                self.__oldMoveToMosaicActionColor = self.__movetoActionMosaic.paletteBackgroundColor(
                )

        if self.focusMode is not None:
            if self.focusAction is None:
                self.focusAction = QubToggleAction(label='Autofocus',
                                                   name='autofocus',
                                                   place=self.focusMode,
                                                   group='Tools',
                                                   autoConnect=True)
                qt.QObject.connect(self.focusAction,
                                   qt.PYSIGNAL('StateChanged'),
                                   self.showFocusGrab)

            if self.view and self.drawing:
                self.focusDrawingRectangle, _ = QubAddDrawing(
                    self.drawing, QubPointDrawingMgr,
                    QubCanvasHomotheticRectangle)
                self.focusDrawingRectangle.setDrawingEvent(
                    QubMoveNPressed1Point)
                self.focusDrawingRectangle.setKeyPressedCallBack(
                    self.focusRawKeyPressed)

                qt.QObject.connect(self.drawing,
                                   qt.PYSIGNAL("ForegroundColorChanged"),
                                   self.focusDrawingRectangle.setColor)
                self.focusDrawingRectangle.setEndDrawCallBack(
                    self.setFocusPointSelected)
                self.focusRectangleSize = 12
                self.focusDrawingRectangle.setWidthNHeight(
                    self.focusRectangleSize, self.focusRectangleSize)
                self.view.addAction(self.focusAction)

        elif self.view is not None:
            self.view.delAction(self.focusAction)
            self.focusDrawingRectangle = None

    def _measure_dialog_new(self, openDialogAction, aQubImage):
        if self.YSize is not None and self.ZSize is not None:
            self.__measureDialog = QubMeasureListDialog(
                self,
                canvas=aQubImage.canvas(),
                matrix=aQubImage.matrix(),
                eventMgr=aQubImage)
            self.__measureDialog.setXPixelSize(self.YSize / 1000.0)
            self.__measureDialog.setYPixelSize(self.ZSize / 1000.0)
            self.__measureDialog.connect(aQubImage,
                                         qt.PYSIGNAL("ForegroundColorChanged"),
                                         self.__measureDialog.setDefaultColor)
            openDialogAction.setDialog(self.__measureDialog)

    def setHorizontalPosition(self, newPosition):
        if self.limitsAction is not None:
            self.limitsAction.setCursorPosition(QubRulerAction.HORIZONTAL, 0,
                                                newPosition)

    def setHorizontalLimits(self, limit):
        if self.limitsAction is not None:
            self.limitsAction.setLimits(QubRulerAction.HORIZONTAL, 0, limit[0],
                                        limit[1])

    def setVerticalPosition(self, newPosition):
        if self.limitsAction is not None:
            self.limitsAction.setCursorPosition(QubRulerAction.VERTICAL, 0,
                                                newPosition)

    def setVerticalLimits(self, limit):
        if self.limitsAction is not None:
            self.limitsAction.setLimits(QubRulerAction.VERTICAL, 0, limit[0],
                                        limit[1])

    #def setFocusLimits(self,limit) :
    #    self.focusState.setLimit(limit)

    #def setFocusPosition(self,newPosition) :
    #    self.focusState.newPosition(newPosition)

    #def focusMoveFinished(self, ver, mne):
    #    self.focusState.endMovement(ver)

    #def focusRawKeyPressed(self,keyevent) :
    #    key = keyevent.key()
    #    if key == qt.Qt.Key_Plus:
    #        self.focusRectangleSize += 3
    #        if self.focusRectangleSize > 99:
    #            self.focusRectangleSize = 99
    #    elif key == qt.Qt.Key_Minus:
    #        self.focusRectangleSize -= 3
    #        if self.focusRectangleSize < 12:
    #            self.focusRectangleSize = 12
    #    else: return
    #
    #    self.focusDrawingRectangle.setWidthNHeight(self.focusRectangleSize,self.focusRectangleSize)

    #def showFocusGrab(self,state) :
    #    self.focusPointSelected = None
    #    if state:
    #        self.focusDrawingRectangle.startDrawing()
    #    else:
    #        self.focusDrawingRectangle.stopDrawing()
    #        self.focusDrawingRectangle.hide()
    #        self.focusPointSelected = None

    #def setFocusPointSelected(self,drawingMgr) :
    #    self.focusPointSelected = drawingMgr.point()
    #    if self.focusMotHwo is not None:
    #        self.focusState.start()

    def beamPositionChanged(self, beamy, beamz):
        self.YBeam = beamy
        self.ZBeam = beamz

    def pixelCalibrationChanged(self, sizey, sizez):
        if sizey is not None:
            self.YSize = sizey * 1000
            try:
                self.__measureDialog.setXPixelSize(sizey)
            except:
                pass
        else:
            self.YSize = None

        if sizez is not None:
            self.ZSize = sizez * 1000
            try:
                self.__measureDialog.setYPixelSize(sizez)
            except:
                pass
        else:
            self.ZSize = None

    def setMoveToState(self, state):
        if self.movetoAction is not None:
            self.movetoAction.setState(state)

    def movetoStateChanged(self, state):
        if self.movetoColorWhenActivate:
            if state:
                self.movetoAction.setPaletteBackgroundColor(
                    qt.QColor(self.movetoColorWhenActivate))
            else:
                self.movetoAction.setPaletteBackgroundColor(
                    self.oldMoveToActionColor)

    def pointSelected(self, drawingMgr):
        if self.horMotHwo is not None and self.verMotHwo is not None:
            if  self.YSize is not None and \
                self.ZSize is not None and \
                self.YBeam is not None and \
                self.ZBeam is not None :

                self.drawingMgr = drawingMgr

                (y, z) = drawingMgr.point()

                self.drawingMgr.stopDrawing()

                sign = 1
                if self.horMotHwo.unit < 0:
                    sign = -1
                movetoy = -sign * (self.YBeam - y) * self.YSize

                sign = 1
                if self.verMotHwo.unit < 0:
                    sign = -1
                movetoz = -sign * (self.ZBeam - z) * self.ZSize

                self.motorArrived = 0

                self.connect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                             self.moveFinished)
                self.connect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                             self.moveFinished)

                self.horMotHwo.moveRelative(movetoy)
                self.verMotHwo.moveRelative(movetoz)

    def __movetoMosaicStateChanged(self, state):
        if self.movetoColorWhenActivate:
            if state:
                self.__movetoActionMosaic.setPaletteBackgroundColor(
                    qt.QColor(self.movetoColorWhenActivate))
            else:
                self.__movetoActionMosaic.setPaletteBackgroundColor(
                    self.__oldMoveToMosaicActionColor)

    def __mosaicPointSelected(self, drawingMgr):
        point = drawingMgr.mosaicPoints()
        try:
            point = point[0]
            beamY, beamZ = point.refPoint
            YSize, ZSize = point.calibration
            horMotorPos, verMotorPos = point.absPoint
            y, z = point.point
            imageId = point.imageId
        except TypeError:
            return  # The click wasn't on image

        self.drawingMgr = drawingMgr

        drawingMgr.stopDrawing()

        sign = 1
        if self.horMotHwo.unit < 0:
            sign = -1
        movetoy = horMotorPos - sign * (beamY - y) * YSize

        sign = 1
        if self.verMotHwo.unit < 0:
            sign = -1
        movetoz = verMotorPos - sign * (beamZ - z) * ZSize

        self.motorArrived = 0

        self.connect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                     self.moveFinished)
        self.connect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                     self.moveFinished)

        self.horMotHwo.move(movetoy)
        self.verMotHwo.move(movetoz)

        self.emit(qt.PYSIGNAL("mosaicImageSelected"), (imageId, ))

    def moveFinished(self, ver, mne):
        if mne == self.horMotHwo.getMotorMnemonic():
            self.disconnect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                            self.moveFinished)
            self.motorArrived = self.motorArrived + 1

        if mne == self.verMotHwo.getMotorMnemonic():
            self.disconnect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                            self.moveFinished)
            self.motorArrived = self.motorArrived + 1

        if self.motorArrived == 2:
            self.drawingMgr.startDrawing()
            self.motorArrived = 0
            self.emit(qt.PYSIGNAL("moveDone"), (self.YBeam, self.ZBeam))
Ejemplo n.º 2
0
class CameraMotorToolsBrick(BlissWidget):
    def __init__(self, parent, name):
        BlissWidget.__init__(self, parent, name)
        
        """
        variables
        """
        self.YBeam = None
        self.ZBeam = None
        self.YSize = None
        self.ZSize = None
        
        self.view = None
        self.firstCall = True
        self.motorArrived = 0

        self.__mosaicView,self.__mosaicDraw = None,None

        """
        property
        """
        self.addProperty("Hor. Motor", "string", "")
        self.horMotHwo = None
        
        self.addProperty("Vert. Motor", "string", "")
        self.verMotHwo = None

        #self.addProperty("Focus Motor","string","")
        #self.focusMotHwo = None

        #self.addProperty("Focus min step","float",0.05)
        #self.focusMinStep = None
        
        self.addProperty("Move To", "combo",
                         ("none", "toolbar", "popup"), "none")
        self.movetoMode = None
        self.movetoAction = None

        self.addProperty("Move to color when activate","combo",
                         ("none","blue","green","yellow","red","orange"),"none")
        self.movetoColorWhenActivate = None
        
        self.addProperty("Limits", "combo",
                         ("none", "toolbar", "popup"), "none")
        self.limitsMode = None
        self.limitsAction = None

        self.addProperty("Measure", "combo", ("none", "toolbar", "popup"), "none")
        self.measureMode = None
        self.measureAction = None

        self.addProperty("Focus","combo",
                         ("none", "toolbar", "popup"), "none")
        self.focusMode = None
        self.focusAction = None
        self.focusState = None
        self.focusDrawingRectangle = None
        self.focusPointSelected = None
        
        self.__movetoActionMosaic = None
        
        """
        Signal
        """
        self.defineSignal('getView',())
        self.defineSignal('getMosaicView',())
        self.defineSignal('getCalibration',())
        self.defineSignal('getBeamPosition',())
        self.defineSignal('getImage',())
        self.defineSignal('moveDone', ())
        self.defineSignal('mosaicImageSelected', ())
        """
        Slot
        """
        self.defineSlot('beamPositionChanged',())
        self.defineSlot('pixelCalibrationChanged',())
        self.defineSlot('setMoveToMode',())
        self.defineSlot('setLimitsDisplay',())
        self.defineSlot('setMoveToState',())

        """
        widgets - NO APPEARANCE
        """
        self.setFixedSize(0, 0)
                        
               
    def propertyChanged(self, prop, oldValue, newValue):
        if prop == "Hor. Motor":
            if self.horMotHwo is not None:
                self.disconnect(self.horMotHwo, qt.PYSIGNAL('positionChanged'),
                                self.setHorizontalPosition)
                self.disconnect(self.horMotHwo, qt.PYSIGNAL("limitsChanged"),
                                self.setHorizontalLimits)

            self.horMotHwo = self.getHardwareObject(newValue)
            
            if self.horMotHwo is not None:
                self.connect(self.horMotHwo, qt.PYSIGNAL('positionChanged'),
                             self.setHorizontalPosition)
                self.connect(self.horMotHwo, qt.PYSIGNAL("limitsChanged"),
                             self.setHorizontalLimits)

        elif prop == "Vert. Motor":
            if self.verMotHwo is not None:
                self.disconnect(self.verMotHwo, qt.PYSIGNAL('positionChanged'),
                                self.setVerticalPosition)
                self.disconnect(self.verMotHwo, qt.PYSIGNAL("limitsChanged"),
                                self.setVerticalLimits)

            self.verMotHwo = self.getHardwareObject(newValue)
            
            if self.verMotHwo is not None:
                self.connect(self.verMotHwo, qt.PYSIGNAL('positionChanged'),
                             self.setVerticalPosition)
                self.connect(self.verMotHwo, qt.PYSIGNAL("limitsChanged"),
                             self.setVerticalLimits)
        #elif prop == "Focus Motor":
        #    if self.focusMotHwo is not None:
        #        self.disconnect(self.focusMotHwo,qt.PYSIGNAL('positionChanged'),
        #                        self.setFocusPosition)
        #        self.disconnect(self.focusMotHwo,qt.PYSIGNAL('limitsChanged'),
        #                        self.setFocusLimits)

        #    self.focusMotHwo = self.getHardwareObject(newValue)
        #    self.focusState = FocusState(self,self.focusMotHwo)
            
        #    if self.focusMotHwo is not None:
        #        self.connect(self.focusMotHwo,qt.PYSIGNAL('positionChanged'),
        #                     self.setFocusPosition)
        #        self.connect(self.focusMotHwo,qt.PYSIGNAL('limitsChanged'),
        #                     self.setFocusLimits)
        #        self.connect(self.focusMotHwo, qt.PYSIGNAL("moveDone"),
        #                     self.focusMoveFinished)
        elif prop == "Move To": self.movetoMode = _enumTranslate[newValue]
        elif prop == "Limits": self.limitsMode = _enumTranslate[newValue]
        elif prop == "Focus": self.focusMode = _enumTranslate[newValue]
        elif prop == "Measure": self.measureMode = _enumTranslate[newValue]
        elif prop == "Focus min step": self.focusMinStep = newValue
        elif prop == "Move to color when activate" :
            if newValue == "none" :
                self.movetoColorWhenActivate = None
            else:
                self.movetoColorWhenActivate = newValue
        if not self.firstCall:
            self.configureAction()
            
    def run(self):
        """
        get view
        """
        view = {}
        self.emit(qt.PYSIGNAL("getView"), (view,))
        try:
            self.drawing = view["drawing"]
            self.view = view["view"]        
        except:
            print "No View"
        
        """
        get calibration
        """
        calib = {}
        self.emit(qt.PYSIGNAL("getCalibration"), (calib,))
        try:
            # in all this brick we work with pixel calibration in mm
            self.YSize = calib["ycalib"]
            self.ZSize = calib["zcalib"]
            if calib["ycalib"] is not None and calib["zcalib"] is not None:
                self.YSize = self.YSize * 1000
                self.ZSize = self.ZSize * 1000
        except:
            print "No Calibration"
            
        """
        get beam position
        """
        position = {}
        self.emit(qt.PYSIGNAL("getBeamPosition"), (position,))
        try:
            self.YBeam = position["ybeam"]
            self.ZBeam = position["zbeam"]
        except:
            print "No Beam Position"

        """
        get mosaic view
        """
        mosaicView = {}
        self.emit(qt.PYSIGNAL('getMosaicView'),(mosaicView,))
        try:
            self.__mosaicView = mosaicView['view']
            self.__mosaicDraw = mosaicView['drawing']
        except KeyError:
            self.__mosaicView,self.__mosaicDraw = None,None
            
        self.configureAction()
        
        self.firstCall = False
    
    def configureAction(self):
        """
        Move To action
        """
        if self.movetoMode is not None:
            if self.movetoAction is None:
                """
                create action
                """
                self.movetoAction = QubSelectPointAction(name='Move to Beam',
                                                         place=self.movetoMode,
                                                         actionInfo = 'Move to Beam',
                                                         group='Tools')
                self.connect(self.movetoAction,qt.PYSIGNAL("StateChanged"),self.movetoStateChanged)
                self.connect(self.movetoAction, qt.PYSIGNAL("PointSelected"),
                             self.pointSelected)
                
                if self.view is not None:
                    self.view.addAction(self.movetoAction)
                    self.oldMoveToActionColor = self.movetoAction.paletteBackgroundColor()

        else:
            if self.movetoAction is not None:
                """
                remove action
                """
                if self.view is not None:
                    self.view.delAction(self.movetoAction)
                    
                """
                del action from view
                """
                self.disconnect(self.movetoAction, qt.PYSIGNAL("PointSelected"),
                                self.pointSelected)
                self.movetoAction = None
        """
        Limits action
        """
        if self.limitsMode is not None:
            if self.limitsAction is None:
                """
                create action
                """
                self.limitsAction = QubRulerAction(name='Motor Limits',
                                                   place=self.limitsMode,
                                                   group='Tools')
                    
                if self.view is not None:
                    self.view.addAction(self.limitsAction)
                
            """
            configure action
            """
            if self.horMotHwo is not None:
                mne = self.horMotHwo.getMotorMnemonic()
                self.limitsAction.setLabel(QubRulerAction.HORIZONTAL,0,mne)

            if self.verMotHwo is not None:
                mne = self.verMotHwo.getMotorMnemonic()
                self.limitsAction.setLabel(QubRulerAction.VERTICAL,0, mne)
                
        else:
            if self.limitsAction is not None:
                """
                remove action
                """
                if self.view is not None:
                    self.view.delAction(self.limitsAction)
                    
                """
                del action from view
                """
                self.limitsAction = None

        if self.measureMode is not None:
                if self.measureAction is None:
                        self.measureAction = QubOpenDialogAction(parent=self, name='measure', iconName='measure', label='Measure', group='Tools', place=self.measureMode)
                        self.measureAction.setConnectCallBack(self._measure_dialog_new)
                        logging.getLogger().info("setting measure mode")
                        if self.view is not None:
                                logging.getLogger().info("adding action")
                                self.view.addAction(self.measureAction)
        else:
                if self.measureAction is not None:
                        if self.view is not None:
                                self.view.delAction(self.measureAction)
                        self.measureAction = None

        if self.movetoMode is not None:
            if self.__movetoActionMosaic is not None:
                self.__mosaicView.delAction(self.__movetoActionMosaic)
                self.disconnect(self.__movetoActionMosaic, qt.PYSIGNAL("PointSelected"),
                                self.__mosaicPointSelected)
                self.diconnect(self.__movetoActionMosaic,qt.PYSIGNAL("StateChanged"),
                               self.__movetoMosaicStateChanged)
                self.__movetoActionMosaic = None
                
            if self.__mosaicView is not None :
                self.__movetoActionMosaic = QubSelectPointAction(name='Move to Beam',
                                                                 place=self.movetoMode,
                                                                 actionInfo = 'Move to Beam',
                                                                 mosaicMode = True,
                                                                 residualMode = True,
                                                                 group='Tools')
                self.connect(self.__movetoActionMosaic, qt.PYSIGNAL("PointSelected"),
                             self.__mosaicPointSelected)
                self.connect(self.__movetoActionMosaic,qt.PYSIGNAL("StateChanged"),
                             self.__movetoMosaicStateChanged)

                self.__mosaicView.addAction(self.__movetoActionMosaic)
                self.__oldMoveToMosaicActionColor = self.__movetoActionMosaic.paletteBackgroundColor()

        if self.focusMode is not None:
            if self.focusAction is None:
                self.focusAction = QubToggleAction(label='Autofocus',name='autofocus',place=self.focusMode,
                                                   group='Tools',autoConnect = True)
                qt.QObject.connect(self.focusAction,qt.PYSIGNAL('StateChanged'),self.showFocusGrab)

            if self.view and self.drawing :
                self.focusDrawingRectangle,_ = QubAddDrawing(self.drawing,QubPointDrawingMgr,QubCanvasHomotheticRectangle)
                self.focusDrawingRectangle.setDrawingEvent(QubMoveNPressed1Point)
                self.focusDrawingRectangle.setKeyPressedCallBack(self.focusRawKeyPressed)

                qt.QObject.connect(self.drawing,qt.PYSIGNAL("ForegroundColorChanged"),self.focusDrawingRectangle.setColor)
                self.focusDrawingRectangle.setEndDrawCallBack(self.setFocusPointSelected)
                self.focusRectangleSize = 12
                self.focusDrawingRectangle.setWidthNHeight(self.focusRectangleSize,self.focusRectangleSize)
                self.view.addAction(self.focusAction)
                
        elif self.view is not None:
            self.view.delAction(self.focusAction)
            self.focusDrawingRectangle = None
    
    def _measure_dialog_new(self,openDialogAction,aQubImage) :
        if  self.YSize is not None and self.ZSize is not None:
            self.__measureDialog = QubMeasureListDialog(self,
                                                      canvas=aQubImage.canvas(),
                                                      matrix=aQubImage.matrix(),
                                                      eventMgr=aQubImage)
            self.__measureDialog.setXPixelSize(self.YSize/1000.0)
            self.__measureDialog.setYPixelSize(self.ZSize/1000.0)
            self.__measureDialog.connect(aQubImage, qt.PYSIGNAL("ForegroundColorChanged"),
                                       self.__measureDialog.setDefaultColor)
            openDialogAction.setDialog(self.__measureDialog)
        
    def setHorizontalPosition(self, newPosition):
        if self.limitsAction is not None:        
            self.limitsAction.setCursorPosition(QubRulerAction.HORIZONTAL, 0,
                                                newPosition)
          
    def setHorizontalLimits(self, limit):
        if self.limitsAction is not None:        
            self.limitsAction.setLimits(QubRulerAction.HORIZONTAL, 0,
                                        limit[0], limit[1])
             
    def setVerticalPosition(self, newPosition):
        if self.limitsAction is not None:        
            self.limitsAction.setCursorPosition(QubRulerAction.VERTICAL, 0,
                                                newPosition)

    def setVerticalLimits(self, limit):
        if self.limitsAction is not None:        
            self.limitsAction.setLimits(QubRulerAction.VERTICAL, 0,
                                        limit[0], limit[1])
         
    #def setFocusLimits(self,limit) :
    #    self.focusState.setLimit(limit)

    #def setFocusPosition(self,newPosition) :
    #    self.focusState.newPosition(newPosition)

    #def focusMoveFinished(self, ver, mne):
    #    self.focusState.endMovement(ver)

    #def focusRawKeyPressed(self,keyevent) :
    #    key = keyevent.key()
    #    if key == qt.Qt.Key_Plus:
    #        self.focusRectangleSize += 3
    #        if self.focusRectangleSize > 99:
    #            self.focusRectangleSize = 99
    #    elif key == qt.Qt.Key_Minus:
    #        self.focusRectangleSize -= 3
    #        if self.focusRectangleSize < 12:
    #            self.focusRectangleSize = 12
    #    else: return
    #    
    #    self.focusDrawingRectangle.setWidthNHeight(self.focusRectangleSize,self.focusRectangleSize)
    
    #def showFocusGrab(self,state) :
    #    self.focusPointSelected = None
    #    if state:
    #        self.focusDrawingRectangle.startDrawing()
    #    else:
    #        self.focusDrawingRectangle.stopDrawing()
    #        self.focusDrawingRectangle.hide()
    #        self.focusPointSelected = None
            
    #def setFocusPointSelected(self,drawingMgr) :
    #    self.focusPointSelected = drawingMgr.point()
    #    if self.focusMotHwo is not None:
    #        self.focusState.start()
            
    def beamPositionChanged(self, beamy, beamz):
        self.YBeam = beamy
        self.ZBeam = beamz
    
    def pixelCalibrationChanged(self, sizey, sizez):
        if sizey is not None:
            self.YSize = sizey * 1000
            try:
                self.__measureDialog.setXPixelSize(sizey)
            except:
                pass
        else:
            self.YSize = None
        
        if sizez is not None:
            self.ZSize = sizez * 1000
            try:
                self.__measureDialog.setYPixelSize(sizez)
            except:
                pass
        else:
            self.ZSize = None

    def setMoveToState(self,state):
        if self.movetoAction is not None:
            self.movetoAction.setState(state)

    def movetoStateChanged(self,state) :
        if self.movetoColorWhenActivate:
            if state:
                self.movetoAction.setPaletteBackgroundColor(qt.QColor(self.movetoColorWhenActivate))
            else:
                self.movetoAction.setPaletteBackgroundColor(self.oldMoveToActionColor)
        
    def pointSelected(self, drawingMgr):
        if self.horMotHwo is not None and self.verMotHwo is not None:
            if  self.YSize is not None and \
                self.ZSize is not None and \
                self.YBeam is not None and \
                self.ZBeam is not None :
                
                self.drawingMgr =  drawingMgr 
                   
                (y, z) = drawingMgr.point()
                
                self.drawingMgr.stopDrawing()

                sign = 1
                if self.horMotHwo.unit < 0:
                    sign = -1
                movetoy = - sign*(self.YBeam - y) * self.YSize

                sign = 1
                if self.verMotHwo.unit < 0:
                    sign = -1
                movetoz = - sign*(self.ZBeam - z) * self.ZSize
                
                self.motorArrived = 0
            
                self.connect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                             self.moveFinished)
                self.connect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                             self.moveFinished)

                self.horMotHwo.moveRelative(movetoy)
                self.verMotHwo.moveRelative(movetoz)
    def __movetoMosaicStateChanged(self,state):
        if self.movetoColorWhenActivate:
            if state:
                self.__movetoActionMosaic.setPaletteBackgroundColor(qt.QColor(self.movetoColorWhenActivate))
            else:
                self.__movetoActionMosaic.setPaletteBackgroundColor(self.__oldMoveToMosaicActionColor)

    def __mosaicPointSelected(self,drawingMgr) :
        point = drawingMgr.mosaicPoints()
        try:
            point = point[0]
            beamY,beamZ = point.refPoint
            YSize,ZSize = point.calibration
            horMotorPos,verMotorPos = point.absPoint
            y,z = point.point
            imageId = point.imageId
        except TypeError: return        # The click wasn't on image

        self.drawingMgr = drawingMgr
        
        drawingMgr.stopDrawing()

        sign = 1
        if self.horMotHwo.unit < 0:
            sign = -1
        movetoy = horMotorPos - sign*(beamY - y) * YSize

        sign = 1
        if self.verMotHwo.unit < 0:
            sign = -1
        movetoz = verMotorPos - sign*(beamZ - z) * ZSize

        self.motorArrived = 0
        
        self.connect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                     self.moveFinished)
        self.connect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                     self.moveFinished)

        self.horMotHwo.move(movetoy)
        self.verMotHwo.move(movetoz)

        self.emit(qt.PYSIGNAL("mosaicImageSelected"), (imageId,))


    def moveFinished(self, ver, mne):
        if mne == self.horMotHwo.getMotorMnemonic():
            self.disconnect(self.horMotHwo, qt.PYSIGNAL("moveDone"),
                            self.moveFinished)
            self.motorArrived = self.motorArrived + 1
            
        if mne == self.verMotHwo.getMotorMnemonic():
            self.disconnect(self.verMotHwo, qt.PYSIGNAL("moveDone"),
                            self.moveFinished)
            self.motorArrived = self.motorArrived + 1
                        
        if self.motorArrived == 2:
            self.drawingMgr.startDrawing()
            self.motorArrived = 0
            self.emit(qt.PYSIGNAL("moveDone"), (self.YBeam, self.ZBeam))
Ejemplo n.º 3
0
class SoleilHutchMenuBrick(BlissWidget):
    SNAPSHOT_FORMATS = ('png', 'jpeg')

    def __init__(self, *args):
        BlissWidget.__init__(self, *args)

        self.minidiff = None
        self.beamInfo = None
        self.sampleChanger = None
        self.collectObj = None
        self.queue_hwobj = None
        self.beam_position = [30, 30]
        self.beam_size = [0.04, 0.02]
        self.beam_shape = "Rectangular"
        self.pixels_per_mm = [0, 0]
        self.slitbox = None
        self.sampleChanger = None
        self.queue_hwobj = None
        self._bx, self._by = (0, 0)

        #self.allowMoveToBeamCentring = False

        # Define properties
        self.addProperty('minidiff', 'string', '')
        self.addProperty('beamInfo', 'string', '')
        self.addProperty('dataCollect', 'string', '')
        self.addProperty('beamInfo', 'string', '')
        # self.addProperty('slitbox','string','')
        self.addProperty('samplechanger', 'string', '')
        self.addProperty('extraCommands', 'string', '')
        self.addProperty('extraCommandsIcons', 'string', '')
        self.addProperty('icons', 'string', '')
        self.addProperty('label', 'string', 'Sample centring')
        #self.addProperty('displaySlitbox', 'boolean', True)
        self.addProperty('displayBeam', 'boolean', True)
        self.addProperty('queue', 'string', '/queue')
        self.addProperty('useMDPhases', 'boolean', True)

        # Define signals and slots
        self.defineSignal('enableMinidiff', ())
        self.defineSignal('centringStarted', ())
        self.defineSignal('centringAccepted', ())
        self.defineSignal('getView', ())
        self.defineSignal('beamPositionChanged', ())
        self.defineSignal('calibrationChanged', ())
        self.defineSignal('newCentredPos', ())
        #self.defineSignal('setMoveToBeamState', ())
        self.defineSlot('setDirectory', ())
        self.defineSlot('setPrefix', ())
        #self.defineSlot('movedToBeam', ())
        self.defineSlot('startCentring', ())
        self.defineSlot('rejectCentring', ())
        self.defineSlot('setSample', ())
        #self.defineSlot('enableAutoStartLoopCentring', ())
        self.defineSlot('getSnapshot', ())

        self.sampleCentreBox = QVBox(self)
        # self.sampleCentreBox.setInsideMargin(11)
        # self.sampleCentreBox.setInsideSpacing(0)

        # self.modeBox=QVButtonGroup(self.sampleCentreBox)
        # self.modeBox.setFrameShape(self.modeBox.NoFrame)
        # self.modeBox.setInsideMargin(0)
        # self.modeBox.setInsideSpacing(0)
        # QObject.connect(self.modeBox,SIGNAL('clicked(int)'),self.centringModeChanged)
        #self.userConfirmsButton=QCheckBox("User confirms", self.sampleCentreBox)
        # self.userConfirmsButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
        # self.userConfirmsButton.setChecked(True)

        self.buttonsBox = QVBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)

        self.buttonCentre = MenuButton(self.buttonsBox, "Centre")
        self.buttonCentre.setMinimumSize(QSize(75, 50))
        self.connect(
            self.buttonCentre,
            PYSIGNAL('executeCommand'),
            self.centreSampleClicked)
        self.connect(
            self.buttonCentre,
            PYSIGNAL('cancelCommand'),
            self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(75, 50))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept, SIGNAL('clicked()'), self.acceptClicked)
        self.standardColor = None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(75, 50))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject, SIGNAL('clicked()'), self.rejectClicked)

        # HorizontalSpacer4(self.sampleCentreBox)

        self.extraCommands = CommandMenuBrick.CommandMenuBrick(self.sampleCentreBox)
        self.extraCommands['showBorder'] = False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(75, 50))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot, SIGNAL('clicked()'), self.saveSnapshot)

        #self.buttonToogleMDPhase = QToolButton(self.sampleCentreBox)
        # self.buttonToogleMDPhase.setUsesTextLabel(True)
        #self.buttonToogleMDPhase.setTextLabel("MD phase")
        # self.buttonToogleMDPhase.setMinimumSize(QSize(75,50))
        #self.buttonToogleMDPhase.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        # QObject.connect(self.buttonToogleMDPhase,SIGNAL('clicked()'),self.toogleMDPhase)
        # self.buttonToogleMDPhase.hide()

        # HorizontalSpacer3(self.sampleCentreBox)

        self.centringButtons = []
        self.defaultBackgroundColor = None
        self.insideDataCollection = False
        self.currentCentring = None
        self.isMoving = False
        self.isShooting = False
        self.directory = "/tmp"
        self.prefix = "snapshot"
        self.fileIndex = 1
        self.formatType = "png"

        self.clickedPoints = []
        self.selectedSamples = None

        # Layout
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        QHBoxLayout(self)
        self.layout().addWidget(self.sampleCentreBox)

        self.instanceSynchronize("")

        self.resetMethods = {MiniDiff.MiniDiff.MANUAL3CLICK_MODE: self.manualCentreReset,
                             MiniDiff.MiniDiff.C3D_MODE: self.automaticCentreReset}
        # MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamReset}
        self.successfulMethods = {MiniDiff.MiniDiff.MANUAL3CLICK_MODE: None,
                                  MiniDiff.MiniDiff.C3D_MODE: self.automaticCentreSuccessful}
        # MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamSuccessful}

        self.sampleCentreBox.hide()

        self.sampleCentreBox = QHBox(self)
        self.buttonsBox = QHBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)
        self.sampleCentreBox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonsBox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        self.layout().addWidget(self.sampleCentreBox)

        self.buttonCentre = MenuButton(self.buttonsBox, "Centre")
        self.buttonCentre.setMinimumSize(QSize(50, 40))
        self.connect(
            self.buttonCentre,
            PYSIGNAL('executeCommand'),
            self.centreSampleClicked)
        self.connect(
            self.buttonCentre,
            PYSIGNAL('cancelCommand'),
            self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(50, 40))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept, SIGNAL('clicked()'), self.acceptClicked)
        self.standardColor = None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(50, 40))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject, SIGNAL('clicked()'), self.rejectClicked)

        self.extraCommands = CommandMenuBrick.CommandMenuBrick(self.sampleCentreBox)
        self.extraCommands['showBorder'] = False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(50, 40))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot, SIGNAL('clicked()'), self.saveSnapshot)

        self.buttonBeamPosition = QToolButton(self.sampleCentreBox)
        self.buttonBeamPosition.setUsesTextLabel(True)
        self.buttonBeamPosition.setTextLabel("BeamPosition")
        self.buttonBeamPosition.setMinimumSize(QSize(50, 40))
        self.buttonBeamPosition.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonBeamPosition.setPixmap(Icons.load("green_led"))
        QObject.connect(
            self.buttonBeamPosition,
            SIGNAL('clicked()'),
            self.beamPositionCheck)

        self.buttonApertureAlign = QToolButton(self.sampleCentreBox)
        self.buttonApertureAlign.setUsesTextLabel(True)
        self.buttonApertureAlign.setTextLabel("ApertureAlign")
        self.buttonApertureAlign.setMinimumSize(QSize(50, 40))
        self.buttonApertureAlign.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonApertureAlign.setPixmap(Icons.load("Align"))
        QObject.connect(
            self.buttonApertureAlign,
            SIGNAL('clicked()'),
            self.apertureAlign)

    def beamPositionCheck(self):
        self.minidiff.beamPositionCheck()

    def apertureAlign(self):
        self.minidiff.apertureAlign()

    def enableAutoStartLoopCentring(self, enable):
        if self.minidiff is not None:
            self.minidiff.enableAutoStartLoopCentring(enable)

    def propertyChanged(self, propertyName, oldValue, newValue):
        #print "HutchMenuBrick.propertyChanged",property,newValue
        if propertyName == 'minidiff':
            if self.minidiff is not None:
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('zoomMotorPredefinedPositionChanged'),
                    self.zoomPositionChanged)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('minidiffReady'),
                    self.miniDiffReady)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('minidiffNotReady'),
                    self.miniDiffNotReady)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('minidiffStateChanged'),
                    self.miniDiffStateChanged)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringStarted'),
                    self.centringStarted)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringSuccessful'),
                    self.centringSuccessful)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringFailed'),
                    self.centringFailed)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringMoving'),
                    self.centringMoving)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringInvalid'),
                    self.centringInvalid)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringSnapshots'),
                    self.centringSnapshots)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('progressMessage'),
                    self.miniDiffMessage)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('newAutomaticCentringPoint'),
                    self.drawAutoCentringPoint)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('zoomMotorPredefinedPositionChanged'),
                    self.zoomPositionChanged)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL('centringAccepted'),
                    self.centringAccepted)
            self.minidiff = self.getHardwareObject(newValue)
            if self.minidiff is not None:
                self.connect(
                    self.minidiff,
                    PYSIGNAL('zoomMotorPredefinedPositionChanged'),
                    self.zoomPositionChanged)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('minidiffReady'),
                    self.miniDiffReady)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('minidiffNotReady'),
                    self.miniDiffNotReady)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('minidiffStateChanged'),
                    self.miniDiffStateChanged)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringStarted'),
                    self.centringStarted)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringSuccessful'),
                    self.centringSuccessful)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringFailed'),
                    self.centringFailed)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringMoving'),
                    self.centringMoving)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringInvalid'),
                    self.centringInvalid)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringSnapshots'),
                    self.centringSnapshots)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('progressMessage'),
                    self.miniDiffMessage)
                self.connect(
                    self.minidiff,
                    "newAutomaticCentringPoint",
                    self.drawAutoCentringPoint)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('zoomMotorPredefinedPositionChanged'),
                    self.zoomPositionChanged)
                self.connect(
                    self.minidiff,
                    PYSIGNAL('centringAccepted'),
                    self.centringAccepted)

                if self.minidiff.isReady():
                    self.miniDiffReady()
                else:
                    self.miniDiffNotReady()
            else:
                self.miniDiffNotReady()
        # elif propertyName=='slitbox':
        #    if self.slitbox is not None:
        #        for role in ('s1v', 's2v', 's1h', 's2h'):
        #          m = self.slitbox.getDeviceByRole(role)
        #          m.disconnect('stateChanged', self.slitsPositionChanged)
        #    self.slitbox=self.getHardwareObject(newValue)
        #    if self.slitbox is not None:
        #        for role in ('s1v', 's2v', 's1h', 's2h'):
        #          m = self.slitbox.getDeviceByRole(role)
        #          m.connect("stateChanged", self.slitsPositionChanged)
        #    #self.slitsPositionChanged()
        elif propertyName == "beamInfo":
            if self.beamInfo is not None:
                self.disconnect(
                    self.beamInfo,
                    PYSIGNAL('beamInfoChanged'),
                    self.beamInfoChanged)
                self.disconnect(
                    self.beamInfo,
                    PYSIGNAL('beamPosChanged'),
                    self.beamPosChanged)
            self.beamInfo = self.getHardwareObject(newValue)
            if self.beamInfo is not None:
                self.connect(
                    self.beamInfo,
                    PYSIGNAL('beamInfoChanged'),
                    self.beamInfoChanged)
                self.connect(
                    self.beamInfo,
                    PYSIGNAL('beamPosChanged'),
                    self.beamPosChanged)

        elif propertyName == "samplechanger":
            self.sampleChanger = self.getHardwareObject(newValue)
        elif propertyName == "dataCollect":
            self.collectObj = self.getHardwareObject(newValue)
        elif propertyName == 'icons':
            self.setIcons(newValue)
        elif propertyName == 'label':
            pass  # self.sampleCentreBox.setTitle(newValue)
        elif propertyName == 'extraCommands':
            self.extraCommands['mnemonic'] = newValue
        elif propertyName == 'extraCommandsIcons':
            self.extraCommands['icons'] = newValue
        elif propertyName == 'queue':
            self.queue_hwobj = self.getHardwareObject(newValue)
        else:
            BlissWidget.propertyChanged(self, propertyName, oldValue, newValue)

    def setIcons(self, icons):
        icons_list = icons.split()
        try:
            self.buttonCentre.setIcons(icons_list[0], icons_list[1])
        except IndexError:
            pass
        try:
            self.buttonAccept.setPixmap(Icons.load(icons_list[2]))
        except IndexError:
            pass
        try:
            self.buttonSnapshot.setPixmap(Icons.load(icons_list[3]))
        except IndexError:
            pass
        try:
            self.buttonReject.setPixmap(Icons.load(icons_list[4]))
        except IndexError:
            pass

    def setDirectory(self, directory):
        self.directory = str(directory)
        self.fileIndex = 1

    def setPrefix(self, prefix):
        self.prefix = str(prefix)
        self.fileIndex = 1

    def setSample(self, samples_list):
        self.selectedSamples = samples_list
        try:
            blsampleid = int(self.selectedSamples[0][0])
        except BaseException:
            blsampleid = None
        try:
            self.minidiff.setSampleInfo({"blsampleid": blsampleid})
        except BaseException:
            pass

    def emitWidgetSynchronize(self):
        # mode=self.modeBox.selectedId()
        points = self.clickedPoints
        #self.emit(PYSIGNAL("widgetSynchronize"),( (mode,points), ))
        self.emit(PYSIGNAL("widgetSynchronize"), ((points), ))

    def widgetSynchronize(self, state):
        # centring_method=state[0]
        # clicked_points=state[1]
        clicked_points = state[0]
        # self.modeBox.setButton(centring_method)
        if len(clicked_points):
            point = clicked_points[-1]
            self.__point.startDrawing()
            self.__point.show()
            self.__point.setPoint(point[0], point[1])
            self.__point.stopDrawing()
        else:
            self.__point.hide()

    def startCentring(self):
        # this is called from another brick, not by user
        self.insideDataCollection = True
        self.centreSampleClicked()

    def rejectCentring(self):
        self.cancelCentringClicked(reject=True)

    def acceptCentring(self):
        self.acceptClicked()

    def centreSampleClicked(self):
        self.minidiff.startCentringMethod(self.minidiff.MANUAL3CLICK_MODE)

    def saveSnapshot(self):
        formats = ""
        for format in SoleilHutchMenuBrick.SNAPSHOT_FORMATS:
            formats += "*.%s " % format
        formats = formats.strip()

        current_filename = os.path.join(self.directory, self.prefix)
        current_filename = current_filename + \
            '_%d%s%s' % (self.fileIndex, os.path.extsep, self.formatType)
        filename = str(QFileDialog.getSaveFileName(current_filename, "Images (%s)" % formats,
                                                   self, None, "Choose a filename to save under", None, False))
        if len(filename):
            image_type = os.path.splitext(filename)[1].strip('.').upper()
            try:
                matrix = self.__drawing.matrix()
                zoom = 1
                if matrix is not None:
                    zoom = matrix.m11()
                img = self.__drawing.getPPP()
                logging.getLogger().info("Saving snapshot : %s", filename)
                QubImageSave.save(
                    filename,
                    img,
                    self.__drawing.canvas(),
                    zoom,
                    image_type)
            except BaseException:
                logging.getLogger().exception("HutchMenuBrick: error saving snapshot!")
                logging.getLogger().error("HutchMenuBrick: error saving snapshot!")
            else:
                self.formatType = image_type.lower()
                self.fileIndex += 1

    def centredPositionSnapshot(self):
        matrix = self.__drawing.matrix()

        zoom = 1
        if matrix is not None:
            zoom = matrix.m11()

        img = self.__drawing.getPPP()
        fd, name = tempfile.mkstemp()
        os.close(fd)

        QubImageSave.save(name, img, self.__drawing.canvas(), zoom, "JPEG")

        f = open(name, "r")
        imgcopy = f.read()
        f.close()
        os.unlink(name)

        return imgcopy

    def getSnapshot(self, img):
        logging.getLogger().debug("Taking snapshot for centred position")
        img['data'] = self.centredPositionSnapshot()

    def cancelCentringClicked(self, reject=False):
        #print "CANCELCENTRINGCLICKED",reject
        self.minidiff.cancelCentringMethod(reject=reject)

    def acceptClicked(self):
        if self.standardColor is not None:
            self.buttonAccept.setPaletteBackgroundColor(self.standardColor)
        #logging.info("disabling accept because accept was clicked")
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        self.minidiff.acceptCentring()

    def rejectClicked(self):
        if self.standardColor is not None:
            self.buttonReject.setPaletteBackgroundColor(self.standardColor)
        #logging.info("disabling accept because reject was clicked")
        self.buttonReject.setEnabled(False)
        self.buttonAccept.setEnabled(False)
        self.minidiff.rejectCentring()
        self.insideDataCollection = False

    def centringMoving(self):
        self.isMoving = True
        logging.info("disabling accept because centring is moving ")
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringInvalid(self):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(None)
        logging.info("disabling accept because centring is invalid ")
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringAccepted(self, state, centring_status):
        logging.info("Centring has been accepted")
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)
        logging.info("disabling accept because centring has been accepted ")
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        if self.insideDataCollection:
            self.insideDataCollection = False
            self.emit(PYSIGNAL("centringAccepted"), (state, centring_status))

        if self.beamInfo is not None:
            beam_info = self.beamInfo.get_beam_info()
            if beam_info is not None:
                beam_info['size_x'] = beam_info['size_x'] * self.pixels_per_mm[0]
                beam_info['size_y'] = beam_info['size_y'] * self.pixels_per_mm[1]
            self.emit(PYSIGNAL("newCentredPos"), (state, centring_status, beam_info))
            #self.emit(PYSIGNAL("newCentredPos"), (state, centring_status))

        if self.queue_hwobj.is_executing():
            self.setEnabled(False)

    def centringSnapshots(self, state):
        if state is None:
            self.isShooting = True
            self.sampleCentreBox.setEnabled(False)
        else:
            self.isShooting = False
            self.sampleCentreBox.setEnabled(True)

    def centringStarted(self, method, flexible):
        self.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (False,))
        if self.insideDataCollection:
            self.emit(PYSIGNAL("centringStarted"), ())

        self.isCentring = True
        self.isMoving = False
        self.isShooting = False
        """
        for but in self.centringButtons:
            if str(but.text())==method:
                if self.defaultBackgroundColor is None:
                    self.defaultBackgroundColor=but.paletteBackgroundColor()
                but.setPaletteBackgroundColor(QWidget.yellow)
                self.currentCentring=but
                break
        """
        self.currentCentring = CentringMethod(method)
        self.buttonCentre.commandStarted()
        logging.info("disabling accept because centring has been started ")
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

        if method == MiniDiff.MiniDiff.MANUAL3CLICK_MODE:
            self.__point.startDrawing()
            self.__helpLine.startDrawing()
            self.__pointer.startDrawing()

    def drawAutoCentringPoint(self, x, y):
        if -1 in (x, y):
            self.__autoCentringPoint.hide()
            return
        self.__autoCentringPoint.startDrawing()
        self.__autoCentringPoint.setPoint(x, y)
        self.__autoCentringPoint.stopDrawing()
        self.__autoCentringPoint.show()

    def centringSuccessful(self, method, centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        #logging.info("HutchMenuBrick:  centringSuccesful received")

        self.clickedPoints = []
        self.emitWidgetSynchronize()

        self.buttonCentre.commandDone()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring = None

        self.buttonAccept.setEnabled(True)
        self.buttonReject.setEnabled(True)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor = self.buttonAccept.paletteBackgroundColor()
            self.buttonAccept.setPaletteBackgroundColor(widget_colors.LIGHT_GREEN)
            self.buttonReject.setPaletteBackgroundColor(widget_colors.LIGHT_RED)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.isMoving = False
        self.sampleCentreBox.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            successful_method = self.successfulMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                successful_method()
            except BaseException:
                pass

    def centringFailed(self, method, centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        self.clickedPoints = []
        self.emitWidgetSynchronize()

        self.buttonCentre.commandFailed()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring = None

        logging.info("disabling accept because centing failed")
        self.buttonAccept.setEnabled(False)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor = self.buttonAccept.paletteBackgroundColor()
            self.buttonReject.setEnabled(True)
            self.buttonReject.setPaletteBackgroundColor(QWidget.red)
        else:
            self.buttonReject.setEnabled(False)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            reset_method = self.resetMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                reset_method()
            except BaseException:
                pass

    # def movedToBeam(self,x,y):
    #    pass

    def manualCentreReset(self):
        self.resetPoints()

    def automaticCentreReset(self):
        if not self.userConfirmsButton.isChecked():
            self.rejectCentring()

    def automaticCentreSuccessful(self):
        if not self.userConfirmsButton.isChecked():
            self.acceptCentring()

    # def moveToBeamSuccessful(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    # def moveToBeamReset(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    def __endDrawingPoint(self, drawingManager):
        x, y = drawingManager.point()
        self.imageClicked(x, y, x, y)

    # Handler for clicking the video when doing the 3-click centring
    def imageClicked(self, x, y, xi, yi):
        #print "HutchMenuBrick.imageClicked",self.minidiff,self.manualCentering
        if self.currentCentring is not None and str(self.currentCentring.text(
        )) == MiniDiff.MiniDiff.MANUAL3CLICK_MODE and self.minidiff.isReady():
            try:
                points = self.minidiff.imageClicked(x, y, xi, yi)
            except StopIteration:
                pass
            else:
                self.addPoint(x, y, xi, yi)

    # Signals a new point in the 3-click centering
    def addPoint(self, x, y, xi, yi):
        self.clickedPoints.append((x, y, xi, yi))
        self.emitWidgetSynchronize()

    # Resets the points in the 3-click centering
    def resetPoints(self):
        self.clickedPoints = []
        self.emitWidgetSynchronize()

    # Displays a message
    def showMessageToUser(self, message=None):
        #print "showMessage",message
        try:
            self.__drawing.setInfo(message)
        except BaseException:
            pass

    def connectNotify(self, signalName):
        print "..... HutchMenuBrick:connectNotify  ", signalName
        if signalName == 'beamPositionChanged':
            if self.minidiff and self.minidiff.isReady() and self.beamInfo is not None:
                self.beam_position = self.beamInfo.get_beam_position()
                self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],
                                                            self.beam_position[1],
                                                            self.beam_size[0],
                                                            self.beam_size[1]))
            # if self.minidiff and self.minidiff.isReady():
            #    beam_xc = self.minidiff.getBeamPosX()
            #    beam_yc = self.minidiff.getBeamPosY()
            #    pxmmy=self.minidiff.pixelsPerMmY
            #    pxmmz=self.minidiff.pixelsPerMmZ
#
#                self.emit(PYSIGNAL("beamPositionChanged"), (beam_xc, beam_yc,
#                                                            self._bx, self._by))
        elif signalName == 'calibrationChanged':
            if self.minidiff and self.minidiff.isReady():
                try:
                    #self.emit(PYSIGNAL("calibrationChanged"), (1e3/self.minidiff.pixelsPerMmY, 1e3/self.minidiff.pixelsPerMmZ))
                    self.emit(
                        PYSIGNAL("calibrationChanged"),
                        (1e3 / self.pixels_per_mm[0],
                         1e3 / self.pixels_per_mm[1]))
                except BaseException:
                    pass

    # Event when the minidiff is in ready state
    def miniDiffReady(self):
        try:
            self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
            if self.beamInfo is not None:
                self.beam_position = self.beamInfo.get_beam_position()
        except BaseException:
            import traceback
            logging.getLogger().error("error on minidiff ready %s", traceback.format_exc())
            self.pixels_per_mm = [None, None]
            # pxmmy=None
            # pxmmz=None

        # if pxmmy is not None and pxmmz is not None:
        if self.beamInfo is not None:
            if self.pixels_per_mm[0] is not None and self.pixels_per_mm[1] is not None:
                self.sampleCentreBox.setEnabled(True)
                self.updateBeam()
                #self.emit(PYSIGNAL("beamPositionChanged"), (beam_xc, beam_yc, self._bx, self._by))
                self.emit(
                    PYSIGNAL("beamPositionChanged"),
                    (self.beam_position[0],
                     self.beam_position[1],
                     self.beam_size[0],
                        self.beam_size[1]))
        else:
            self.miniDiffNotReady()

    # Event when the minidiff is in notready state
    def miniDiffNotReady(self):
        #import pdb; pdb.set_trace()
        try:
            self.__beam.hide()
        except AttributeError:
            pass
        if not self.buttonCentre.executing:
            self.sampleCentreBox.setEnabled(False)

    def miniDiffStateChanged(self, state):
        if self.buttonCentre.executing or self.isMoving or self.isShooting:
            return
        try:
            self.sampleCentreBox.setEnabled(state == self.minidiff.phiMotor.READY)
        except BaseException:
            pass

    # Displays a message (signaled from the minidiff hardware object)
    def miniDiffMessage(self, msg=None):
        #print "MINIDIFF MESSAGE!!!",msg
        self.showMessageToUser(msg)

    # Update both zoom and slits when started
    def run(self):
        logging.getLogger().info("HucthMenuBrick runs")
        if self.minidiff is not None:
            zoom = self.minidiff.zoomMotor
            if zoom is not None:
                if zoom.isReady():
                    self.zoomPositionChanged(zoom.getCurrentPositionName(), 0)

        keys = {}
        self.emit(PYSIGNAL('getView'), (keys,))
        self.__drawing = keys.get('drawing', None)
        self.__view = keys.get('view', None)
        if self.minidiff is not None:
            self.minidiff._drawing = self.__drawing

        try:
            self.__point, _ = QubAddDrawing(
                self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__point.setEndDrawCallBack(self.__endDrawingPoint)
            self.__point.setColor(Qt.yellow)

            self.__autoCentringPoint, _ = QubAddDrawing(
                self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__autoCentringPoint.setColor(Qt.green)

            self.__helpLine, _ = QubAddDrawing(
                self.__drawing, QubPointDrawingMgr, QubCanvasVLine)
            self.__helpLine.setAutoDisconnectEvent(True)
            self.__helpLine.setExclusive(False)
            self.__helpLine.setColor(Qt.yellow)

            logging.getLogger().info("HutchMenuBrick help line OK")

            self.__rectangularBeam, _ = QubAddDrawing(
                self.__drawing, QubContainerDrawingMgr, QubCanvasSlitbox)
            self.__rectangularBeam.set_xMid_yMid(
                self.beam_position[0], self.beam_position[1])
            self.__rectangularBeam.show()
            self.__rectangularBeam.setSlitboxSize(0, 0)
            self.__rectangularBeam.setColor(Qt.red)
            self.__rectangularBeam.setSlitboxPen(QPen(Qt.blue))
            #self.beam_position = self.beamInfo.get_beam_position()

            logging.getLogger().info("HutchMenuBrick rectangular beam OK")

            self.__beam, _ = QubAddDrawing(
                self.__drawing, QubContainerDrawingMgr, QubCanvasBeam)
            self.__beam.setPen(QPen(Qt.blue))
            self.__beam.hide()

            logging.getLogger().info("HutchMenuBrick beam setPen successful")

            self.__pointer, _, _ = QubAddDrawing(
                self.__drawing, QubPointDrawingMgr, QubCanvasHLine, QubCanvasVLine)
            self.__pointer.setDrawingEvent(QubMoveNPressed1Point)
            self.__pointer.setExclusive(False)
            self.__pointer.setColor(Qt.yellow)

            logging.getLogger().info("HutchMenuBrick runs. pointer successful")

            self.__scale, scale = QubAddDrawing(
                self.__drawing, QubContainerDrawingMgr, QubCanvasScale)
            self.sx = self.__scale.setXPixelSize
            self.sy = self.__scale.setYPixelSize
            self.__scale.show()
            logging.getLogger().info("HutchMenuBrick runs. Scale just changed")
            try:
                self.__scale.setXPixelSize(self.__scaleX)
                self.__scale.setYPixelSize(self.__scaleY)
            except AttributeError:
                pass
            else:
                self.emit(PYSIGNAL("calibrationChanged"),
                          (self.__scaleX, self.__scaleY))
                # self.slitsPositionChanged()
                logging.getLogger().info("HutchMenuBrick runs. It will now update the beam drawing")
                self.__rectangularBeam.set_xMid_yMid(
                    self.beam_position[0], self.beam_position[1])
                logging.getLogger().info(
                    "HutchMenuBrick setting rectangular beam xMid, yMid to %s, %s" %
                    (self.beam_position[0], self.beam_position[1]))
                self.updateBeam(force=True)
        except BaseException:
            import traceback
            logging.getLogger().debug("HutchMenuBrick: problem starting up display")
            logging.getLogger().exception(traceback.format_exc())
        else:
            logging.getLogger().info("HucthMenuBrick runs cool")

    def _drawBeam(self):
        try:
            self.__rectangularBeam.show()
            # if None in (self._by, self._bx):
            if None in self.beam_size:
                return
            #bx = self._bx
            #by = self._by
            # pxmmy=self.minidiff.pixelsPerMmY
            # pxmmz=self.minidiff.pixelsPerMmZ
            # if self._bshape == "rectangular":
            #  self.__rectangularBeam.setSlitboxSize(bx*pxmmy, by*pxmmz)
            if self.beam_shape == "rectangular":
                self.__rectangularBeam.setSlitboxSize(self.beam_size[0] * self.pixels_per_mm[0],
                                                      self.beam_size[1] * self.pixels_per_mm[1])
                self.__beam.hide()
            else:
                self.__rectangularBeam.setSlitboxSize(0, 0)
                self.__beam.setSize(self.beam_size[0] * self.pixels_per_mm[0],
                                    self.beam_size[1] * self.pixels_per_mm[1])
                logging.getLogger().info("beam drawn with size %s " % str(self.beam_size))
                #self.__beam.setSize(bx*pxmmy, by*pxmmz)
                self.__beam.show()
        except BaseException:
            pass

    def _updateBeam(self, ret):
        logging.info("UPDATE BEAM %s", ret)
        self._bx = float(ret["size_x"])
        self._bshape = ret["shape"]
        self._by = float(ret["size_y"])
        self._drawBeam()

    def updateBeam(self, force=False):
        logging.getLogger().info("updating beam ")

        if self.minidiff is None:
            return

        if self["displayBeam"]:
            if not self.minidiff.isReady():
                time.sleep(0.2)
            #beam_x = self.minidiff.getBeamPosX()
            #beam_y = self.minidiff.getBeamPosY()
            try:
                logging.getLogger().info("self %s" % str(self))
                self.__rectangularBeam.set_xMid_yMid(
                    self.beam_position[0], self.beam_position[1])
                logging.getLogger().info("rectangle drawn at position %s " % str(self.beam_position))
                # self.__rectangularBeam.set_xMid_yMid(beam_x,beam_y)
            except AttributeError:
                import traceback
                logging.getLogger().info("update beam failed 1" + traceback.format_exc())
                pass
            try:
                self.__beam.move(self.beam_position[0], self.beam_position[1])
                self._drawBeam()
            except AttributeError:
                logging.getLogger().info("update beam failed 2")
                import traceback
                logging.getLogger().info("update beam failed 2" + traceback.format_exc())

    def beamPosChanged(self, position):
        logging.getLogger().info(
            "hutch menu brick. Beam position chagned.  It is %s" %
            str(position))
        self.beam_position = position
        self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],
                                                    self.beam_position[1],
                                                    self.beam_size[0],
                                                    self.beam_size[1]))
        self.updateBeam(True)

    def beamInfoChanged(self, beam_info):
        logging.getLogger().info(
            "hutch menu brick. Beam info chagned.  It is %s" %
            str(beam_info))
        self.beam_size = (beam_info["size_x"], beam_info["size_y"])
        self.beam_shape = beam_info["shape"]
        self.updateBeam(True)

    # Zoom changed: update pixels per mm
    def zoomPositionChanged(self, position, offset):
        pxmmy, pxmmz, pxsize_y, pxsize_z = None, None, None, None
        print "** HutchMenuBrick: zoomPositionChanged", position, offset
        if offset is None:
            # unknown zoom pos.
            try:
                self.__scale.hide()
                self.__rectangularBeam.hide()
                self.__beam.hide()
            except AttributeError:
                print "&&& zoomPositionChanged AttributeError"
                self.__scaleX = None
                self.__scaleY = None
        else:
            if self.minidiff is not None:
                # pxmmy=self.minidiff.pixelsPerMmY
                # pxmmz=self.minidiff.pixelsPerMmZ
                self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                if self.pixels_per_mm[0] is not None and self.pixels_per_mm[1] is not None:
                    pxsize_y = 1e-3 / self.pixels_per_mm[0]
                    pxsize_z = 1e-3 / self.pixels_per_mm[1]

                try:
                    self.sx(pxsize_y)
                    self.sy(pxsize_z)
                except AttributeError:
                    self.__scaleX = pxsize_y
                    self.__scaleY = pxsize_z
                else:
                    self.emit(PYSIGNAL("calibrationChanged"), (pxsize_y, pxsize_z))
                    self.updateBeam(True)
                    # self._drawBeam()
                    self.__scale.show()

    # Slits changed: update beam size
    def slitsPositionChanged(self, *args):
        if self.minidiff is None or self.slitbox is None or self.minidiff.pixelsPerMmY is None or self.minidiff.pixelsPerMmZ is None:
            pass
        else:
            self.updateBeam(force=True)
class CameraOffLineImageManagerBrick(BlissWidget):
    def __init__(self,parent,name,**keys) :
        BlissWidget.__init__(self,parent,name)
        self.__hMotor = None
        self.__vMotor = None
        self.__motor_pos_save = []
        self.__master_motor = None
        self.__masterPosition2Item = weakref.WeakValueDictionary()
        self.__currentCalib = None
        self.__currentBeamPos = None
        self.__camDecompNPlug = None
        self.mosaicView = None
        self.drawing = None
        self.__saveImageTreeDirName = '.'
        self.__imageMosaicPosition = None
                       ####### Property #######
        self.addProperty('horizontal','string','')
        self.addProperty('vertical','string','')
        self.addProperty('save_motors','string','')
        self.addProperty('master_motor','string','')
        self.addProperty('focus_motor','string','')
        self.addProperty('live_camera','string','')
        self.addProperty("formatString", "formatString", "###.##")
                        ####### SIGNAL #######
        self.defineSignal("getImage",())
        self.defineSignal('getView',())
        self.defineSignal('getMosaicView',())
                         ####### SLOT #######
        self.defineSlot("ChangePixelCalibration", ())
        self.defineSlot("ChangeBeamPosition", ())
        self.defineSlot('setMosaicImageSelected',())
        
        self.__widgetTree = self.loadUIFile('CameraOffLineImageManager.ui')
        self.__frame = self.__widgetTree.child('__frame')
        self.__frame.reparent(self,qt.QPoint(0,0))
        layout = qt.QHBoxLayout(self)
        layout.addWidget(self.__frame)
        
        snapButton = self.child('__snapShoot')
        iconSet = qt.QIconSet(loadIcon("snapshot.png"))
        snapButton.setIconSet(iconSet)
        qt.QObject.connect(snapButton,qt.SIGNAL('clicked()'),self.__snapCBK)

        liveCheckBox = self.child('__liveCheckBox')
        liveCheckBox.hide()
        qt.QObject.connect(liveCheckBox,qt.SIGNAL('toggled(bool)'),self.__liveOnOff)
        

        self.__imageList = self.child('__imageList')
        self.__imageList.setSelectionMode(qt.QListView.Extended)
        self.__imageList.setSortColumn(-1)
        self.__popUpMenu = qt.QPopupMenu(self)
        self.__popUpMenu.insertItem('layer up',self.__layerUp)
        self.__popUpMenu.insertItem('layer down',self.__layerDown)
        self.__popUpMenu.insertItem('remove',self.__removeImage)

        self.__popUpMenu.insertSeparator()
        self.__popUpMenu.insertItem('load',self.__loadImageTree)
        self.__popUpMenu.insertItem('save',self.__saveImageTree)

        qt.QObject.connect(self.__imageList,qt.SIGNAL('rightButtonPressed(QListViewItem*,const QPoint &,int)'),
                           self.__popUpDisplay)

    def propertyChanged(self,propertyName,oldValue,newValue) :
        if propertyName == 'horizontal' :
            if self.__hMotor:
                self.disconnect(self.__hMotor, qt.PYSIGNAL("positionChanged"), self.__hMotorPositionChanged)
            self.__hMotor = self.getHardwareObject(newValue)
            self.connect(self.__hMotor, qt.PYSIGNAL("positionChanged"), self.__hMotorPositionChanged)
            self.connect(self.__hMotor,qt.PYSIGNAL("limitsChanged"),self.__hMotorLimitsChanged)
        elif propertyName == 'vertical' :
            if self.__vMotor:
                self.disconnect(self.__vMotor, qt.PYSIGNAL("positionChanged"), self.__vMotorPositionChanged)
            self.__vMotor = self.getHardwareObject(newValue)
            self.connect(self.__vMotor, qt.PYSIGNAL("positionChanged"), self.__vMotorPositionChanged)
            self.connect(self.__vMotor,qt.PYSIGNAL("limitsChanged"),self.__vMotorLimitsChanged)

        elif propertyName == 'save_motors' :
            equipment = self.getHardwareObject(newValue)
            self.__motor_pos_save = []
            if equipment :
                try:
                    ho = equipment['motors']
                except KeyError:
                    print(equipment.userName(), 'is not an Equipment : no <motors> section.')
                    return
                for motor in ho.getDevices() :
                    self.__motor_pos_save.append(motor)

                #Refresh Tree column
                nbColumn = self.__imageList.columns()
                for columnId in range(1,self.__imageList.columns()) :
                    self.__imageList.removeColumn(columnId)
                for motor in self.__motor_pos_save:
                    self.__imageList.addColumn(motor.userName())
        elif propertyName == 'master_motor':
            if self.__master_motor is not None:
                self.__imageList.takeItem(self.__masterControler)
            self.__master_motor = self.getHardwareObject(newValue)
            if self.__master_motor is not None:
                self.__masterControler = qt.QCheckListItem(self.__imageList,self.__master_motor.userName())
                self.__masterControler.setSelectable(False)
                self.__masterControler.setOpen(True)
        elif propertyName == 'focus_motor':
            self.__focus_motor = self.getHardwareObject(newValue)
            moveFocusCheckBox = self.child('__moveFocusCheckBox')
            if self.__focus_motor is not None:
                moveFocusCheckBox.show()
            else:
                moveFocusCheckBox.hide()
        elif propertyName == 'live_camera' :
            if self.__camDecompNPlug :
                camera,decomp,_ = self.__camDecompNPlug
                self.disconnect(camera,qt.PYSIGNAL('imageReceived'),decomp.putData)
                self.__camDecompNPlug = None
                
            camera = self.getHardwareObject(newValue)
            liveCheckBox = self.child('__liveCheckBox')
            if camera is not None:
                decomp = QubStdData2Image()
                plug = _LiveImagePlug(self)
                decomp.plug(plug)

                imageInfo = camera.imageType()
                if imageInfo and imageInfo.type() == 'bayer': imType = decomp.BAYER_RG
                elif imageInfo and imageInfo.type() == 'raw': imType = decomp.RAW
                else: imType = decomp.STANDARD # JPEG
                decomp.setImageType(imType)

                self.__camDecompNPlug = camera,decomp,plug

                liveCheckBox.show()
            else:
                liveCheckBox.hide()
        elif propertyName == 'formatString':
            self._formatString = self['formatString']
            
    def ChangePixelCalibration(self,sizeX,sizeY) :
        if sizeX is not None and sizeY is not None:
            motorXUnit = self.__hMotor.getProperty('unit')
            if motorXUnit is None : motorXUnit = 1e-3

            motorYUnit = self.__vMotor.getProperty('unit')
            if motorYUnit is None : motorYUnit = 1e-3

            self.__currentCalib = sizeX / motorXUnit,sizeY / motorYUnit

            if self.__camDecompNPlug :
                camera,decomp,plug = self.__camDecompNPlug
                plug.setPixelCalibration(*self.__currentCalib)
        else:
            self.__currentCalib = None
            
    def ChangeBeamPosition(self,x,y) :
        self.__currentBeamPos = x,y
        if self.__camDecompNPlug :
            camera,decomp,plug = self.__camDecompNPlug
            plug.setBeamPosition(*self.__currentBeamPos)

    def setMosaicImageSelected(self,imageSelectedID) :
        moveFocusCheckBox = self.child('__moveFocusCheckBox')
        if moveFocusCheckBox.isChecked() :
            position = self.__focus_motor.getPosition()
            def _recursfind(item,lookinId) :
                while item:
                    if id(item) == lookinId:
                        return item
                    else:
                        returnItem = _recursfind(item.firstChild(),lookinId)
                        if returnItem: return returnItem
                        item = item.nextSibling()
            item = _recursfind(self.__imageList.firstChild(),imageSelectedID)
            try:
                if item and item.focusMotorPosition != position:
                    self.__focus_motor.move(item.focusMotorPosition)
            except AttributeError:
                pass
    def __displayMotorsPositionUnderMouse(self,drawingManager) :
        point = drawingManager.mosaicPoints()
        try:
            point = point[0]
            beamY,beamZ = point.refPoint
            YSize,ZSize = point.calibration
            horMotorPos,verMotorPos = point.absPoint
            y,z = point.point
            imageId = point.imageId
        except TypeError: return
        movetoy = horMotorPos - (beamY - y) * YSize
        movetoz = verMotorPos - (beamZ - z) * ZSize

        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(QubRulerAction.HORIZONTAL,1,
                                                         movetoy)
            self.__imageMosaicPosition.setCursorPosition(QubRulerAction.VERTICAL,1,
                                                         movetoz)
            self.__mouseMotorPosition.setXValue(movetoy)
            self.__mouseMotorPosition.setYValue(movetoz)
            
    def __hMotorPositionChanged(self,position) :
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(QubRulerAction.HORIZONTAL, 0,
                                                         position)
            self.__currentMotorPosition.setXValue(position)
            
        if self.__camDecompNPlug :
            camera,decomp,plug = self.__camDecompNPlug
            plug.setHMotorPosition(position)
            
    def __hMotorLimitsChanged(self,limit) :
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,0,
                                                 *limit)
            self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,1,
                                                 *limit)
        
    def __vMotorPositionChanged(self,position) :
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(QubRulerAction.VERTICAL, 0,
                                                         position)
            self.__currentMotorPosition.setYValue(position)
        if self.__camDecompNPlug :
            camera,decomp,plug = self.__camDecompNPlug
            plug.setVMotorPosition(position)

    def __vMotorLimitsChanged(self,limit) :
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,0,
                                                 *limit)
            self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,1,
                                                 *limit)
        
    def __getMasterItem(self,position = None) :
        if self.__master_motor is not None:
            if position is None:
                position = self.__master_motor.getPosition()
            try:
                master_item = self.__masterPosition2Item[position]
            except KeyError:
                positionString = self._formatString % position
                master_item = _MasterCheckItem(self.__masterControler,'p_%d (%s)' % (len(self.__masterPosition2Item),positionString))
                self.__masterPosition2Item[position] = master_item
        else:
            master_item = self.__imageList
            position = None
        return master_item,position
        
    def __snapCBK(self) :
        key = {}
        self.emit(qt.PYSIGNAL('getImage'),(key,))
        image = key.get('image',None)
        if image:
            master_item,position = self.__getMasterItem()
            if self.__focus_motor is not None:
                focusPosition = self.__focus_motor.getPosition()
            else:
                focusPosition = None
            try:
                item = _CheckItem(master_item,'image',self,image,
                                  self.__currentBeamPos,self.__currentCalib,
                                  self.__hMotor,self.__vMotor,self.__motor_pos_save,position,focusPosition)
            except:
                logging.getLogger().error('CameraOffLineImageManager : Spec not connected')

        else:
            logging.getLogger().error('CameraOffLineImageManager : getImage is not connected to CameraOffLineImageManager!!!')

    def __liveOnOff(self,state) :
        camera,decomp,plug = self.__camDecompNPlug
        if state:
            self.connect(camera,qt.PYSIGNAL('imageReceived'),decomp.putData)
            plug.show()
        else:
            self.disconnect(camera,qt.PYSIGNAL('imageReceived'),decomp.putData)
            plug.hide()

    def __saveImageTree(self,i) :
        pickleObjects = []
        self.__saveImageRecurse(self.__imageList.firstChild(),pickleObjects)
        if pickleObjects:
            fullpathname = qt.QFileDialog.getSaveFileName(self.__saveImageTreeDirName,'Camera mosaic (*.mosaic)',self,
                                                          'Save mosaic images',
                                                          "Choose a filename to save under")
            if fullpathname:
                fullpathname = fullpathname.latin1()
                self.__saveImageTreeDirName,fname = os.path.split(fullpathname)
                filename,ext = os.path.splitext(fname)
                fullpathname = os.path.join(self.__saveImageTreeDirName,'%s.mosaic' % filename)
                pickle.dump(pickleObjects,file(fullpathname,'w'))
        else:
            errorMess = qt.QErrorMessage(self)
            errorMess.message('Nothing to Save!!!')

    def __loadImageTree(self,i) :
        fullpathname = qt.QFileDialog.getOpenFileName(self.__saveImageTreeDirName,'Camera mosaic (*.mosaic)',self,
                                                      'Load mosaic images',
                                                      "Load a image tree")
        if fullpathname:
            fullpathname = fullpathname.latin1()
            self.__imageList.selectAll(True)
            self.__removeImage(0)
            for saveItem in pickle.load(file(fullpathname)):
              master_item,position = self.__getMasterItem(saveItem.masterPosition)
              _CheckItem(master_item,saveItem,self)
            
    def __saveImageRecurse(self,item,pickleObjects) :
        while item:
            NextItem = item.nextSibling()
            try: pickleObjects.append(item.getSavePickleObject())
            except AttributeError: pass
            self.__saveImageRecurse(item.firstChild(),pickleObjects)
            item = NextItem

    @_foreachSelectedItems
    def __removeImage(self,item,i)  :
        try:
            item.parent().takeItem(item)
        except AttributeError:
            self.__imageList.takeItem(item)
        return True
    @_foreachSelectedItems
    def __layerUp(self,item,i) :
        item.layerUp()

    @_foreachSelectedItems
    def __layerDown(self,item,i) :
        item.layerDown()

    def __popUpDisplay(self,item,point,columnid) :
        self.__popUpMenu.exec_loop(point)

    def run(self) :
        key = {}
        self.emit(qt.PYSIGNAL('getView'),(key,))
        try:
            view = key['view']
            drawing = key['drawing']

            self.__snapAction = QubToolButtonAction(name='MosaicSnap',iconName='snapshot',toolButtonStyle = True,
                                                    place='toolbar',
                                                    group='image',autoConnect = True)
            qt.QObject.connect(self.__snapAction,qt.PYSIGNAL('ButtonPressed'),self.__snapCBK)
            view.addAction([self.__snapAction])
        except KeyError:
            logging.getLogger().error('getView is not connected to CameraOffLineImageManager!!!')
            


        mosaicKey = {}
        self.emit(qt.PYSIGNAL('getMosaicView'),(mosaicKey,))
        try:
            self.mosaicView = mosaicKey['view']
            self.drawing = mosaicKey['drawing']
            class _openDialog(QubOpenDialogAction) :
                def __init__(self,*args,**keys) :
                    QubOpenDialogAction.__init__(self,*args,**keys)
                def setCanvas(self,canvas) :
                    self.__canvas = canvas
                    
                def _showDialog(self) :
                    if self._dialog.exec_loop() == qt.QDialog.Accepted :
                        file_path = self._dialog.selectedFile().ascii()
                        dirName,file_name = os.path.split(file_path)
                        base,ext = os.path.splitext(file_name)
                        QubImageSave.save(os.path.join(dirName,'%s.svg' % base),None,self.__canvas,1,'svg',True)
                        
            self.__saveMosaicAction = _openDialog(parent=self,label='Save image',name="save", iconName='save',group="admin")
            saveMosaicDialogue = qt.QFileDialog('.','Mosaic Images (*.svg)',self,'Save mosaic Images',True)
            saveMosaicDialogue.setMode(saveMosaicDialogue.AnyFile)
            self.__saveMosaicAction.setDialog(saveMosaicDialogue)
            self.__saveMosaicAction.setCanvas(self.drawing.canvas())

            self.__imageMosaicPosition = QubRulerAction(name='Motor Position',
                                                        place='toolbar',
                                                        group='Tools')

            self.__mouseMotorPosition = _MouseOrMotorPosition(name='mouse motor position',
                                                              place='statusbar',
                                                              group='info',
                                                              mouseFlag = True)
            
            self.__currentMotorPosition = _MouseOrMotorPosition(name='current motor position',
                                                                place='statusbar',
                                                                group='info')
            
            self.mosaicView.addAction([self.__imageMosaicPosition,self.__saveMosaicAction,
                                       self.__currentMotorPosition,self.__mouseMotorPosition])
            
            if self.__vMotor is not None:
                self.__imageMosaicPosition.setLabel(QubRulerAction.VERTICAL,0,self.__vMotor.getMotorMnemonic())
                self.__imageMosaicPosition.setCursorPosition(QubRulerAction.VERTICAL, 0,
                                                             self.__vMotor.getPosition())
                limits = self.__vMotor.getLimits()
                self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,0,
                                                     *limits)
                self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,1,
                                                     *limits)

                self.__imageMosaicPosition.setLabel(QubRulerAction.VERTICAL,1, '')
                for label in [self.__mouseMotorPosition,self.__currentMotorPosition] :
                    label.setMotyName(self.__vMotor.getMotorMnemonic())
                    label.setYValue(self.__vMotor.getPosition())
                                        
            if self.__hMotor is not None:
                self.__imageMosaicPosition.setLabel(QubRulerAction.HORIZONTAL,0,self.__hMotor.getMotorMnemonic())
                limits = self.__hMotor.getLimits()
                self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,0,
                                                     *limits)
                self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,1,
                                                     *limits)
                
                self.__imageMosaicPosition.setCursorPosition(QubRulerAction.HORIZONTAL, 0,
                                                             self.__hMotor.getPosition())
                self.__imageMosaicPosition.setLabel(QubRulerAction.HORIZONTAL,1,'')

                for label in [self.__mouseMotorPosition,self.__currentMotorPosition] :
                    label.setMotxName(self.__hMotor.getMotorMnemonic())
                    label.setXValue(self.__hMotor.getPosition())
                    
            for ruler in self.__imageMosaicPosition._QubRulerAction__ruler:
                ruler.setZ(99)          # upper layer

            #Add a follow mulot
            class _MouseFollow(_DrawingEventNDrawingMgr) :
                def __init__(self,aDrawingMgr,oneShot,**keys) :
                    _DrawingEventNDrawingMgr.__init__(self,aDrawingMgr,False)
                    
                def mouseMove(self,x,y) :
                    d = self._drawingMgr()
                    if d:
                        d.move(x,y)
                        d.endDraw()
            self.__followPointMouse,_ = QubAddDrawing(self.drawing,QubMosaicPointDrawingMgr,QubCanvasTarget)
            self.__followPointMouse.setDrawingEvent(_MouseFollow)
            self.__followPointMouse.setExclusive(False)
            self.__followPointMouse.startDrawing()
            self.__followPointMouse.setEndDrawCallBack(self.__displayMotorsPositionUnderMouse)
        except KeyError: pass

        if self.__camDecompNPlug:
            camera,decomp,plug = self.__camDecompNPlug
            try:
                plug.addImage()
                try:
                    plug.move(self.__hMotor.getPosition(),self.__vMotor.getPosition())
                except: pass
                else:
                    try:
                        plug.setCalibration(*self.__currentCalib)
                        plug.setBeamPosition(*self.__currentBeamPos)
                    except (AttributeError,TypeError) :
                        pass
            except AttributeError:
                liveCheckBox = self.child('__liveCheckBox')
                liveCheckBox.hide()
Ejemplo n.º 5
0
class HutchMenuBrick(BlissWidget):
    SNAPSHOT_FORMATS = ("png", "jpeg")

    def __init__(self, *args):
        BlissWidget.__init__(self, *args)

        self.minidiff = None
        self.beamInfo = None
        self.sampleChanger = None
        self.collectObj = None
        self.queue_hwobj = None
        self.beam_position = None
        self.beam_size = None
        self.beam_shape = None
        self.pixels_per_mm = None
        # self.allowMoveToBeamCentring = False

        # Define properties
        self.addProperty("beamInfo", "string", "")
        self.addProperty("minidiff", "string", "")
        self.addProperty("dataCollect", "string", "")
        self.addProperty("samplechanger", "string", "")
        self.addProperty("extraCommands", "string", "")
        self.addProperty("extraCommandsIcons", "string", "")
        self.addProperty("icons", "string", "")
        self.addProperty("label", "string", "Sample centring")
        self.addProperty("displayBeam", "boolean", True)
        self.addProperty("queue", "string", "/queue")
        self.addProperty("useMDPhases", "boolean", False)

        # Define signals and slots
        self.defineSignal("enableMinidiff", ())
        self.defineSignal("centringStarted", ())
        self.defineSignal("centringAccepted", ())
        self.defineSignal("getView", ())
        self.defineSignal("beamPositionChanged", ())
        self.defineSignal("calibrationChanged", ())
        self.defineSignal("newCentredPos", ())
        # self.defineSignal('setMoveToBeamState', ())
        self.defineSlot("setDirectory", ())
        self.defineSlot("setPrefix", ())
        # self.defineSlot('movedToBeam', ())
        self.defineSlot("startCentring", ())
        self.defineSlot("rejectCentring", ())
        self.defineSlot("setSample", ())
        # self.defineSlot('enableAutoStartLoopCentring', ())
        self.defineSlot("getSnapshot", ())

        self.sampleCentreBox = QVBox(self)
        self.buttonsBox = QVBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)

        self.buttonCentre = MenuButton(self.buttonsBox, "Centre")
        self.buttonCentre.setMinimumSize(QSize(75, 50))
        self.connect(self.buttonCentre, PYSIGNAL("executeCommand"),
                     self.centreSampleClicked)
        self.connect(self.buttonCentre, PYSIGNAL("cancelCommand"),
                     self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(75, 50))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept, SIGNAL("clicked()"),
                        self.acceptClicked)
        self.standardColor = None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(75, 50))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject, SIGNAL("clicked()"),
                        self.rejectClicked)

        # HorizontalSpacer4(self.sampleCentreBox)

        self.extraCommands = CommandMenuBrick.CommandMenuBrick(
            self.sampleCentreBox)
        self.extraCommands["showBorder"] = False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(75, 50))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot, SIGNAL("clicked()"),
                        self.saveSnapshot)

        self.buttonToogleMDPhase = QToolButton(self.sampleCentreBox)
        self.buttonToogleMDPhase.setUsesTextLabel(True)
        self.buttonToogleMDPhase.setTextLabel("MD phase")
        self.buttonToogleMDPhase.setMinimumSize(QSize(75, 50))
        self.buttonToogleMDPhase.setSizePolicy(QSizePolicy.Fixed,
                                               QSizePolicy.Fixed)
        QObject.connect(self.buttonToogleMDPhase, SIGNAL("clicked()"),
                        self.toggleMDPhase)
        self.buttonToogleMDPhase.hide()

        # HorizontalSpacer3(self.sampleCentreBox)

        self.centringButtons = []
        self.defaultBackgroundColor = None
        self.insideDataCollection = False
        self.currentCentring = None
        self.isMoving = False
        self.isShooting = False
        self.directory = "/tmp"
        self.prefix = "snapshot"
        self.fileIndex = 1
        self.formatType = "png"

        self.clickedPoints = []
        self.selectedSamples = None

        # Layout
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        QHBoxLayout(self)
        self.layout().addWidget(self.sampleCentreBox)

        self.instanceSynchronize("")

        self.resetMethods = None
        self.successfulMethods = None

    def enableAutoStartLoopCentring(self, enable):
        if self.minidiff is not None:
            self.minidiff.enableAutoStartLoopCentring(enable)

    def propertyChanged(self, propertyName, oldValue, newValue):
        if propertyName == "beamInfo":
            if self.beamInfo is not None:
                self.disconnect(self.beamInfo, PYSIGNAL("beamInfoChanged"),
                                self.beamInfoChanged)
                self.disconnect(self.beamInfo, PYSIGNAL("beamPosChanged"),
                                self.beamPosChanged)
            self.beamInfo = self.getHardwareObject(newValue)
            if self.beamInfo is not None:
                self.connect(self.beamInfo, PYSIGNAL("beamInfoChanged"),
                             self.beamInfoChanged)
                self.connect(self.beamInfo, PYSIGNAL("beamPosChanged"),
                             self.beamPosChanged)
        elif propertyName == "minidiff":
            if self.minidiff is not None:
                self.disconnect(self.minidiff, PYSIGNAL("minidiffReady"),
                                self.miniDiffReady)
                self.disconnect(self.minidiff, PYSIGNAL("minidiffNotReady"),
                                self.miniDiffNotReady)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL("minidiffStateChanged"),
                    self.miniDiffStateChanged,
                )
                self.disconnect(self.minidiff, PYSIGNAL("centringStarted"),
                                self.centringStarted)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL("centringSuccessful"),
                    self.centringSuccessful,
                )
                self.disconnect(self.minidiff, PYSIGNAL("centringAccepted"),
                                self.centringAccepted)
                self.disconnect(self.minidiff, PYSIGNAL("centringFailed"),
                                self.centringFailed)
                self.disconnect(self.minidiff, PYSIGNAL("centringMoving"),
                                self.centringMoving)
                self.disconnect(self.minidiff, PYSIGNAL("centringInvalid"),
                                self.centringInvalid)
                self.disconnect(self.minidiff, PYSIGNAL("centringSnapshots"),
                                self.centringSnapshots)
                self.disconnect(self.minidiff, PYSIGNAL("progressMessage"),
                                self.miniDiffMessage)
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL("newAutomaticCentringPoint"),
                    self.drawAutoCentringPoint,
                )
                self.disconnect(
                    self.minidiff,
                    PYSIGNAL("zoomMotorPredefinedPositionChanged"),
                    self.zoomPositionChanged,
                )
            self.minidiff = self.getHardwareObject(newValue)

            if self.minidiff is not None:
                self.connect(self.minidiff, PYSIGNAL("minidiffReady"),
                             self.miniDiffReady)
                self.connect(self.minidiff, PYSIGNAL("minidiffNotReady"),
                             self.miniDiffNotReady)
                self.connect(
                    self.minidiff,
                    PYSIGNAL("minidiffStateChanged"),
                    self.miniDiffStateChanged,
                )
                self.connect(self.minidiff, PYSIGNAL("centringStarted"),
                             self.centringStarted)
                self.connect(
                    self.minidiff,
                    PYSIGNAL("centringSuccessful"),
                    self.centringSuccessful,
                )
                self.connect(self.minidiff, PYSIGNAL("centringAccepted"),
                             self.centringAccepted)
                self.connect(self.minidiff, PYSIGNAL("centringFailed"),
                             self.centringFailed)
                self.connect(self.minidiff, PYSIGNAL("centringMoving"),
                             self.centringMoving)
                self.connect(self.minidiff, PYSIGNAL("centringInvalid"),
                             self.centringInvalid)
                self.connect(self.minidiff, PYSIGNAL("centringSnapshots"),
                             self.centringSnapshots)
                self.connect(self.minidiff, PYSIGNAL("progressMessage"),
                             self.miniDiffMessage)
                self.connect(
                    self.minidiff,
                    PYSIGNAL("newAutomaticCentringPoint"),
                    self.drawAutoCentringPoint,
                )
                self.connect(
                    self.minidiff,
                    PYSIGNAL("zoomMotorPredefinedPositionChanged"),
                    self.zoomPositionChanged,
                )

                if self.minidiff.isReady():
                    self.miniDiffReady()
                else:
                    self.miniDiffNotReady()

                self.resetMethods = {
                    self.minidiff.MANUAL3CLICK_MODE: self.manualCentreReset,
                    self.minidiff.C3D_MODE: self.automaticCentreReset,
                }
                # MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamReset}
                self.successfulMethods = {
                    self.minidiff.MANUAL3CLICK_MODE: None,
                    self.minidiff.C3D_MODE: self.automaticCentreSuccessful,
                }
                # MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamSuccessful}
            else:
                self.miniDiffNotReady()
        elif propertyName == "samplechanger":
            self.sampleChanger = self.getHardwareObject(newValue)
        elif propertyName == "dataCollect":
            self.collectObj = self.getHardwareObject(newValue)
        elif propertyName == "icons":
            self.setIcons(newValue)
        elif propertyName == "label":
            pass  # self.sampleCentreBox.setTitle(newValue)
        elif propertyName == "extraCommands":
            self.extraCommands["mnemonic"] = newValue
        elif propertyName == "extraCommandsIcons":
            self.extraCommands["icons"] = newValue
        elif propertyName == "queue":
            self.queue_hwobj = self.getHardwareObject(newValue)
            self.queue_hwobj.connect("queue_execution_finished", self.enable)
            self.queue_hwobj.connect("queue_stopped", self.enable)
        elif propertyName == "useMDPhases":
            if newValue:
                self.buttonToogleMDPhase.show()
            else:
                self.buttonToogleMDPhase.hide()
        else:
            BlissWidget.propertyChanged(self, propertyName, oldValue, newValue)

    def enable(self, *args):
        self.setEnabled(True)

    def disable(self, *args):
        self.setEnabled(False)

    def setIcons(self, icons):
        icons_list = icons.split()
        try:
            self.buttonCentre.setIcons(icons_list[0], icons_list[1])
        except IndexError:
            pass
        try:
            self.buttonAccept.setPixmap(Icons.load(icons_list[2]))
        except IndexError:
            pass
        try:
            self.buttonSnapshot.setPixmap(Icons.load(icons_list[3]))
        except IndexError:
            pass
        try:
            self.buttonReject.setPixmap(Icons.load(icons_list[4]))
        except IndexError:
            pass
        try:
            self.buttonToogleMDPhase.setPixmap(Icons.load(icons_list[5]))
        except IndexError:
            pass

    def setDirectory(self, directory):
        self.directory = str(directory)
        self.fileIndex = 1

    def setPrefix(self, prefix):
        self.prefix = str(prefix)
        self.fileIndex = 1

    def setSample(self, samples_list):
        self.selectedSamples = samples_list
        try:
            blsampleid = int(self.selectedSamples[0][0])
        except BaseException:
            blsampleid = None
        try:
            self.minidiff.setSampleInfo({"blsampleid": blsampleid})
        except BaseException:
            pass

    def emitWidgetSynchronize(self):
        # mode=self.modeBox.selectedId()
        points = self.clickedPoints
        # self.emit(PYSIGNAL("widgetSynchronize"),( (mode,points), ))
        self.emit(PYSIGNAL("widgetSynchronize"), ((points), ))

    def widgetSynchronize(self, state):
        # centring_method=state[0]
        # clicked_points=state[1]
        clicked_points = state[0]
        # self.modeBox.setButton(centring_method)
        if len(clicked_points):
            point = clicked_points[-1]
            self.__point.startDrawing()
            self.__point.show()
            self.__point.setPoint(point[0], point[1])
            self.__point.stopDrawing()
        else:
            self.__point.hide()

    def startCentring(self):
        # this is called from another brick, not by user
        self.insideDataCollection = True
        self.centreSampleClicked()

    def rejectCentring(self):
        self.cancelCentringClicked(reject=True)

    def acceptCentring(self):
        self.acceptClicked()

    def centreSampleClicked(self):
        self.minidiff.startCentringMethod(self.minidiff.MANUAL3CLICK_MODE)

    def saveSnapshot(self):
        formats = ""
        for format in HutchMenuBrick.SNAPSHOT_FORMATS:
            formats += "*.%s " % format
        formats = formats.strip()

        current_filename = os.path.join(self.directory, self.prefix)
        current_filename = current_filename + "_%d%s%s" % (
            self.fileIndex,
            os.path.extsep,
            self.formatType,
        )
        filename = str(
            QFileDialog.getSaveFileName(
                current_filename,
                "Images (%s)" % formats,
                self,
                None,
                "Choose a filename to save under",
                None,
                False,
            ))
        if len(filename):
            image_type = os.path.splitext(filename)[1].strip(".").upper()
            try:
                matrix = self.__drawing.matrix()
                zoom = 1
                if matrix is not None:
                    zoom = matrix.m11()
                img = self.__drawing.getPPP()
                logging.getLogger().info("Saving snapshot : %s", filename)
                QubImageSave.save(filename, img, self.__drawing.canvas(), zoom,
                                  image_type)
            except BaseException:
                logging.getLogger().exception(
                    "HutchMenuBrick: error saving snapshot!")
                logging.getLogger().error(
                    "HutchMenuBrick: error saving snapshot!")
            else:
                self.formatType = image_type.lower()
                self.fileIndex += 1

    def centredPositionSnapshot(self):
        matrix = self.__drawing.matrix()

        zoom = 1
        if matrix is not None:
            zoom = matrix.m11()

        img = self.__drawing.getPPP()
        fd, name = tempfile.mkstemp()
        os.close(fd)

        QubImageSave.save(name, img, self.__drawing.canvas(), zoom, "JPEG")

        f = open(name, "r")
        imgcopy = f.read()
        f.close()
        os.unlink(name)

        return imgcopy

    def getSnapshot(self, img):
        logging.getLogger().debug("Taking snapshot for centred position")
        img["data"] = self.centredPositionSnapshot()

    def cancelCentringClicked(self, reject=False):
        # print "CANCELCENTRINGCLICKED",reject
        self.minidiff.cancelCentringMethod(reject=reject)

    def acceptClicked(self):
        if self.standardColor is not None:
            self.buttonAccept.setPaletteBackgroundColor(self.standardColor)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        self.minidiff.acceptCentring()

    def rejectClicked(self):
        if self.standardColor is not None:
            self.buttonReject.setPaletteBackgroundColor(self.standardColor)
        self.buttonReject.setEnabled(False)
        self.buttonAccept.setEnabled(False)
        self.minidiff.rejectCentring()
        self.insideDataCollection = False

    def centringMoving(self):
        self.isMoving = True
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringInvalid(self):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(None)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringAccepted(self, state, centring_status):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        if self.insideDataCollection:
            self.insideDataCollection = False
            self.emit(PYSIGNAL("centringAccepted"), (state, centring_status))

        beam_info = self.beamInfo.get_beam_info()
        if beam_info is not None:
            beam_info["size_x"] = beam_info["size_x"] * self.pixels_per_mm[0]
            beam_info["size_y"] = beam_info["size_y"] * self.pixels_per_mm[1]
        self.emit(PYSIGNAL("newCentredPos"),
                  (state, centring_status, beam_info))

        if self.queue_hwobj.is_executing():
            self.disable()

    def centringSnapshots(self, state):
        if state is None:
            self.isShooting = True
            self.sampleCentreBox.setEnabled(False)
        else:
            self.isShooting = False
            self.sampleCentreBox.setEnabled(True)

    def centringStarted(self, method, flexible):
        self.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (False, ))
        if self.insideDataCollection:
            self.emit(PYSIGNAL("centringStarted"), ())

        self.isCentring = True
        self.isMoving = False
        self.isShooting = False
        """
        for but in self.centringButtons:
            if str(but.text())==method:
                if self.defaultBackgroundColor is None:
                    self.defaultBackgroundColor=but.paletteBackgroundColor()
                but.setPaletteBackgroundColor(QWidget.yellow)
                self.currentCentring=but
                break
        """
        self.currentCentring = CentringMethod(method)
        self.buttonCentre.commandStarted()
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

        if method == self.minidiff.MANUAL3CLICK_MODE:
            self.__point.startDrawing()
            self.__helpLine.startDrawing()
            self.__pointer.startDrawing()

    def drawAutoCentringPoint(self, x, y):
        if -1 in (x, y):
            self.__autoCentringPoint.hide()
            return
        self.__autoCentringPoint.startDrawing()
        self.__autoCentringPoint.setPoint(x, y)
        self.__autoCentringPoint.stopDrawing()
        self.__autoCentringPoint.show()

    def centringSuccessful(self, method, centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        self.clickedPoints = []
        self.emitWidgetSynchronize()

        self.buttonCentre.commandDone()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring = None

        self.buttonAccept.setEnabled(True)
        self.buttonReject.setEnabled(True)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor = self.buttonAccept.paletteBackgroundColor()
            self.buttonAccept.setPaletteBackgroundColor(
                widget_colors.LIGHT_GREEN)
            self.buttonReject.setPaletteBackgroundColor(
                widget_colors.LIGHT_RED)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.isMoving = False
        self.sampleCentreBox.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (True, ))

        try:
            successful_method = self.successfulMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                successful_method()
            except BaseException:
                pass

    def centringFailed(self, method, centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        self.clickedPoints = []
        self.emitWidgetSynchronize()

        self.buttonCentre.commandFailed()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring = None

        self.buttonAccept.setEnabled(False)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor = self.buttonAccept.paletteBackgroundColor()
            self.buttonReject.setEnabled(True)
            self.buttonReject.setPaletteBackgroundColor(QWidget.red)
        else:
            self.buttonReject.setEnabled(False)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.emit(PYSIGNAL("enableMinidiff"), (True, ))

        try:
            reset_method = self.resetMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                reset_method()
            except BaseException:
                pass

    # def movedToBeam(self,x,y):
    #    pass

    def manualCentreReset(self):
        self.resetPoints()

    def automaticCentreReset(self):
        if not self.userConfirmsButton.isChecked():
            self.rejectCentring()

    def automaticCentreSuccessful(self):
        if not self.userConfirmsButton.isChecked():
            self.acceptCentring()

    # def moveToBeamSuccessful(self):
    # self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    # def moveToBeamReset(self):
    # self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    def __endDrawingPoint(self, drawingManager):
        x, y = drawingManager.point()
        self.imageClicked(x, y, x, y)

    # Handler for clicking the video when doing the 3-click centring
    def imageClicked(self, x, y, xi, yi):
        if (self.currentCentring is not None and str(
                self.currentCentring.text()) == self.minidiff.MANUAL3CLICK_MODE
                and self.minidiff.isReady()):
            try:
                points = self.minidiff.imageClicked(x, y, xi, yi)
            except StopIteration:
                pass
            else:
                self.addPoint(x, y, xi, yi)

    # Signals a new point in the 3-click centering
    def addPoint(self, x, y, xi, yi):
        self.clickedPoints.append((x, y, xi, yi))
        self.emitWidgetSynchronize()

    # Resets the points in the 3-click centering
    def resetPoints(self):
        self.clickedPoints = []
        self.emitWidgetSynchronize()

    # Displays a message
    def showMessageToUser(self, message=None):
        try:
            self.__drawing.setInfo(message)
        except BaseException:
            pass

    def connectNotify(self, signalName):
        if signalName == "beamPositionChanged":
            if self.minidiff and self.beamInfo:
                if self.minidiff.isReady():
                    self.beam_position = self.beamInfo.get_beam_position()
                    self.emit(
                        PYSIGNAL("beamPositionChanged"),
                        (
                            self.beam_position[0],
                            self.beam_position[1],
                            self.beam_size[0],
                            self.beam_size[1],
                        ),
                    )
        elif signalName == "calibrationChanged":
            if self.minidiff and self.minidiff.isReady():
                try:
                    self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                    self.emit(
                        PYSIGNAL("calibrationChanged"),
                        (1e3 / self.pixels_per_mm[0],
                         1e3 / self.pixels_per_mm[1]),
                    )
                except BaseException:
                    pass

    # Event when the minidiff is in ready state
    def miniDiffReady(self):
        try:
            self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
        except BaseException:
            self.pixels_per_mm = [None, None]

        if self.pixels_per_mm[0] is not None and self.pixels_per_mm[
                1] is not None:
            self.beam_position = self.beamInfo.get_beam_position()
            self.beam_size = self.beamInfo.get_beam_size()
            self.sampleCentreBox.setEnabled(True)
            self.updateBeam()
            self.emit(
                PYSIGNAL("beamPositionChanged"),
                (
                    self.beam_position[0],
                    self.beam_position[1],
                    self.beam_size[0],
                    self.beam_size[1],
                ),
            )
        else:
            self.miniDiffNotReady()

    # Event when the minidiff is in notready state
    def miniDiffNotReady(self):
        try:
            self.__beam.hide()
        except AttributeError:
            pass
        if not self.buttonCentre.executing:
            self.sampleCentreBox.setEnabled(False)

    def miniDiffStateChanged(self, state):
        if self.buttonCentre.executing or self.isMoving or self.isShooting:
            return
        try:
            self.sampleCentreBox.setEnabled(
                state == self.minidiff.phiMotor.READY)
        except BaseException:
            pass

    # Displays a message (signaled from the minidiff hardware object)
    def miniDiffMessage(self, msg=None):
        self.showMessageToUser(msg)

    # Update both zoom and slits when started
    def run(self):
        if self.minidiff is not None:
            zoom = self.minidiff.zoomMotor
            if zoom is not None:
                if zoom.isReady():
                    self.zoomPositionChanged(zoom.getCurrentPositionName(), 0)

        keys = {}
        self.emit(PYSIGNAL("getView"), (keys, ))
        self.__drawing = keys.get("drawing", None)
        self.__view = keys.get("view", None)
        if self.minidiff is not None:
            self.minidiff._drawing = self.__drawing

        try:
            self.__point, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr,
                                            QubCanvasTarget)
            self.__point.setEndDrawCallBack(self.__endDrawingPoint)
            self.__point.setColor(Qt.yellow)

            self.__autoCentringPoint, _ = QubAddDrawing(
                self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__autoCentringPoint.setColor(Qt.green)

            self.__helpLine, _ = QubAddDrawing(self.__drawing,
                                               QubPointDrawingMgr,
                                               QubCanvasVLine)
            self.__helpLine.setAutoDisconnectEvent(True)
            self.__helpLine.setExclusive(False)
            self.__helpLine.setColor(Qt.yellow)

            self.__rectangularBeam, _ = QubAddDrawing(self.__drawing,
                                                      QubContainerDrawingMgr,
                                                      QubCanvasSlitbox)
            self.__rectangularBeam.show()
            self.__rectangularBeam.setSlitboxSize(0, 0)
            self.__rectangularBeam.setColor(Qt.red)
            self.__rectangularBeam.setSlitboxPen(QPen(Qt.blue))

            self.__beam, _ = QubAddDrawing(self.__drawing,
                                           QubContainerDrawingMgr,
                                           QubCanvasBeam)
            self.__beam.setPen(QPen(Qt.blue))
            self.__beam.hide()

            self.__pointer, _, _ = QubAddDrawing(self.__drawing,
                                                 QubPointDrawingMgr,
                                                 QubCanvasHLine,
                                                 QubCanvasVLine)
            self.__pointer.setDrawingEvent(QubMoveNPressed1Point)
            self.__pointer.setExclusive(False)
            self.__pointer.setColor(Qt.yellow)

            self.__scale, scale = QubAddDrawing(self.__drawing,
                                                QubContainerDrawingMgr,
                                                QubCanvasScale)
            self.sx = self.__scale.setXPixelSize
            self.sy = self.__scale.setYPixelSize
            self.__scale.show()

            try:
                self.__scale.setXPixelSize(self.__scaleX)
                self.__scale.setYPixelSize(self.__scaleY)
            except AttributeError:
                pass
            else:
                self.emit(PYSIGNAL("calibrationChanged"),
                          (self.__scaleX, self.__scaleY))
                self.updateBeam(force=True)
        except BaseException:
            logging.getLogger().exception(
                "HutchMenuBrick: problem starting up display")

    def _drawBeam(self):
        if None in (self.beam_size, self.beam_shape):
            self.beam_position = self.beamInfo.get_beam_position()
            self.beam_size = self.beamInfo.get_beam_size()

        if True:
            self.__rectangularBeam.show()
            if None in self.beam_size:
                return
            if self.beam_shape == "rectangular":
                self.__rectangularBeam.setSlitboxSize(
                    self.beam_size[0] * self.pixels_per_mm[0],
                    self.beam_size[1] * self.pixels_per_mm[1],
                )
                self.__beam.hide()
            else:
                self.__rectangularBeam.setSlitboxSize(0, 0)
                self.__beam.setSize(
                    self.beam_size[0] * self.pixels_per_mm[0],
                    self.beam_size[1] * self.pixels_per_mm[1],
                )
                self.__beam.show()

    def updateBeam(self, force=False):
        if self["displayBeam"]:
            # if self.minidiff:
            #  if not self.minidiff.isReady(): time.sleep(0.2)
            try:
                self.__rectangularBeam.set_xMid_yMid(self.beam_position[0],
                                                     self.beam_position[1])
            except AttributeError:
                pass
            try:
                self.__beam.move(self.beam_position[0], self.beam_position[1])
                self._drawBeam()
                # try:
                #  self._updateBeam(self.beamInfo.get_beam_info())
                # except:
                #  logging.getLogger().exception("Could not get beam size: cannot display beam")
                #  self.__beam.hide()
            except AttributeError:
                pass

    def beamPosChanged(self, position):
        self.beam_position = position
        self.emit(
            PYSIGNAL("beamPositionChanged"),
            (
                self.beam_position[0],
                self.beam_position[1],
                self.beam_size[0],
                self.beam_size[1],
            ),
        )
        self.updateBeam(True)

    def beamInfoChanged(self, beam_info):
        try:
            self.beam_position = self.beamInfo.get_beam_position()
        except BaseException:
            pass
        self.beam_size = (beam_info["size_x"], beam_info["size_y"])
        self.beam_shape = beam_info["shape"]
        self.emit(
            PYSIGNAL("beamPositionChanged"),
            (
                self.beam_position[0],
                self.beam_position[1],
                self.beam_size[0],
                self.beam_size[1],
            ),
        )
        self.updateBeam(True)

    # Zoom changed: update pixels per mm
    def zoomPositionChanged(self, position, offset):
        pxmmy, pxmmz, pxsize_y, pxsize_z = None, None, None, None

        if offset is None:
            # unknown zoom pos.
            try:
                self.__scale.hide()
                self.__rectangularBeam.hide()
                self.__beam.hide()
            except AttributeError:
                self.__scaleX = None
                self.__scaleY = None
        else:
            if self.minidiff is not None:
                self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                if (self.pixels_per_mm[0] is not None
                        and self.pixels_per_mm[1] is not None):
                    pxsize_y = 1e-3 / self.pixels_per_mm[0]
                    pxsize_z = 1e-3 / self.pixels_per_mm[1]
                try:
                    self.sx(pxsize_y)
                    self.sy(pxsize_z)
                except AttributeError:
                    self.__scaleX = pxsize_y
                    self.__scaleY = pxsize_z
                else:
                    self.emit(PYSIGNAL("calibrationChanged"),
                              (pxsize_y, pxsize_z))
                    self.updateBeam(True)
                    self.__scale.show()

    def toggleMDPhase(self):
        if self.minidiff is not None:
            self.minidiff.togglePhase()
Ejemplo n.º 6
0
class HutchMenuBrick(BlissWidget):
    SNAPSHOT_FORMATS = ('png', 'jpeg')

    def __init__(self, *args):
        BlissWidget.__init__(self, *args)

        self.minidiff = None
        self.beamInfo = None
        self.sampleChanger=None
        self.collectObj = None
        self.queue_hwobj = None
        self.beam_position = None
        self.beam_size = None
        self.beam_shape = None
        self.pixels_per_mm = None
        #self.allowMoveToBeamCentring = False

        # Define properties
        self.addProperty('beamInfo', 'string', '')
        self.addProperty('minidiff','string','')
        self.addProperty('dataCollect','string','')
        self.addProperty('samplechanger','string','')
        self.addProperty('extraCommands','string','')
        self.addProperty('extraCommandsIcons','string','')
        self.addProperty('icons','string','')
        self.addProperty('label','string','Sample centring')
        self.addProperty('displayBeam', 'boolean', True)
        self.addProperty('queue', 'string', '/queue')
        self.addProperty('useMDPhases', 'boolean', False)

        # Define signals and slots
        self.defineSignal('enableMinidiff',())
        self.defineSignal('centringStarted',())
        self.defineSignal('centringAccepted',())
        self.defineSignal('getView',())
        self.defineSignal('beamPositionChanged', ())
        self.defineSignal('calibrationChanged', ())
        self.defineSignal('newCentredPos', ())
        #self.defineSignal('setMoveToBeamState', ())
        self.defineSlot('setDirectory',())
        self.defineSlot('setPrefix',())
        #self.defineSlot('movedToBeam', ())
        self.defineSlot('startCentring', ())
        self.defineSlot('rejectCentring', ())
        self.defineSlot('setSample',())
        #self.defineSlot('enableAutoStartLoopCentring', ())
        self.defineSlot('getSnapshot',())
        
        self.sampleCentreBox=QVBox(self)
        self.buttonsBox=QVBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)

        self.buttonCentre=MenuButton(self.buttonsBox,"Centre")
        self.buttonCentre.setMinimumSize(QSize(75,50))
        self.connect(self.buttonCentre,PYSIGNAL('executeCommand'),self.centreSampleClicked)
        self.connect(self.buttonCentre,PYSIGNAL('cancelCommand'),self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(75,50))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept,SIGNAL('clicked()'),self.acceptClicked)
        self.standardColor=None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(75,50))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject,SIGNAL('clicked()'),self.rejectClicked)

        #HorizontalSpacer4(self.sampleCentreBox)

        self.extraCommands=CommandMenuBrick.CommandMenuBrick(self.sampleCentreBox)
        self.extraCommands['showBorder']=False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(75,50))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot,SIGNAL('clicked()'),self.saveSnapshot)


        self.buttonToogleMDPhase = QToolButton(self.sampleCentreBox)
        self.buttonToogleMDPhase.setUsesTextLabel(True)
        self.buttonToogleMDPhase.setTextLabel("MD phase")
        self.buttonToogleMDPhase.setMinimumSize(QSize(75,50))
        self.buttonToogleMDPhase.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonToogleMDPhase,SIGNAL('clicked()'),self.toggleMDPhase)
        self.buttonToogleMDPhase.hide()

        #HorizontalSpacer3(self.sampleCentreBox)

        self.centringButtons=[]
        self.defaultBackgroundColor=None
        self.insideDataCollection=False        
        self.currentCentring = None
        self.isMoving=False
        self.isShooting=False
        self.directory="/tmp"
        self.prefix="snapshot"
        self.fileIndex=1
        self.formatType="png"

        self.clickedPoints=[]
        self.selectedSamples=None

        # Layout
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        QHBoxLayout(self)        
        self.layout().addWidget(self.sampleCentreBox)

        self.instanceSynchronize("")

        self.resetMethods = None
        self.successfulMethods = None

    def enableAutoStartLoopCentring(self, enable):
        if self.minidiff is not None:
           self.minidiff.enableAutoStartLoopCentring(enable)

    def propertyChanged(self,propertyName,oldValue,newValue):
        if propertyName=="beamInfo":
            if self.beamInfo is not None:
                self.disconnect(self.beamInfo,PYSIGNAL('beamInfoChanged'), self.beamInfoChanged)
                self.disconnect(self.beamInfo,PYSIGNAL('beamPosChanged'), self.beamPosChanged)
            self.beamInfo=self.getHardwareObject(newValue)
            if self.beamInfo is not None:
                self.connect(self.beamInfo,PYSIGNAL('beamInfoChanged'), self.beamInfoChanged)
                self.connect(self.beamInfo,PYSIGNAL('beamPosChanged'), self.beamPosChanged)
        elif propertyName=='minidiff':
            if self.minidiff is not None:
                self.disconnect(self.minidiff,PYSIGNAL('minidiffReady'),self.miniDiffReady)
                self.disconnect(self.minidiff,PYSIGNAL('minidiffNotReady'),self.miniDiffNotReady)
                self.disconnect(self.minidiff,PYSIGNAL('minidiffStateChanged'),self.miniDiffStateChanged)
                self.disconnect(self.minidiff,PYSIGNAL('centringStarted'),self.centringStarted)
                self.disconnect(self.minidiff,PYSIGNAL('centringSuccessful'),self.centringSuccessful)
                self.disconnect(self.minidiff,PYSIGNAL('centringAccepted'),self.centringAccepted)
                self.disconnect(self.minidiff,PYSIGNAL('centringFailed'),self.centringFailed)
                self.disconnect(self.minidiff,PYSIGNAL('centringMoving'),self.centringMoving)
                self.disconnect(self.minidiff,PYSIGNAL('centringInvalid'),self.centringInvalid)
                self.disconnect(self.minidiff,PYSIGNAL('centringSnapshots'),self.centringSnapshots)
                self.disconnect(self.minidiff,PYSIGNAL('progressMessage'),self.miniDiffMessage)
                self.disconnect(self.minidiff,PYSIGNAL('newAutomaticCentringPoint'),self.drawAutoCentringPoint)
                self.disconnect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'), self.zoomPositionChanged)
            self.minidiff=self.getHardwareObject(newValue)
          
            if self.minidiff is not None:
                self.connect(self.minidiff,PYSIGNAL('minidiffReady'),self.miniDiffReady)
                self.connect(self.minidiff,PYSIGNAL('minidiffNotReady'),self.miniDiffNotReady)
                self.connect(self.minidiff,PYSIGNAL('minidiffStateChanged'),self.miniDiffStateChanged)
                self.connect(self.minidiff,PYSIGNAL('centringStarted'),self.centringStarted)
                self.connect(self.minidiff,PYSIGNAL('centringSuccessful'),self.centringSuccessful)
                self.connect(self.minidiff,PYSIGNAL('centringAccepted'),self.centringAccepted)
                self.connect(self.minidiff,PYSIGNAL('centringFailed'),self.centringFailed)
                self.connect(self.minidiff,PYSIGNAL('centringMoving'),self.centringMoving)
                self.connect(self.minidiff,PYSIGNAL('centringInvalid'),self.centringInvalid)
                self.connect(self.minidiff,PYSIGNAL('centringSnapshots'),self.centringSnapshots)
                self.connect(self.minidiff,PYSIGNAL('progressMessage'),self.miniDiffMessage)
                self.connect(self.minidiff,PYSIGNAL('newAutomaticCentringPoint'),self.drawAutoCentringPoint)
                self.connect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'),self.zoomPositionChanged)

                if self.minidiff.isReady():
                    self.miniDiffReady()
                else:
                    self.miniDiffNotReady()

                self.resetMethods={self.minidiff.MANUAL3CLICK_MODE:self.manualCentreReset,
                                   self.minidiff.C3D_MODE:self.automaticCentreReset}
                                   #MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamReset}
                self.successfulMethods={self.minidiff.MANUAL3CLICK_MODE:None,
                                        self.minidiff.C3D_MODE:self.automaticCentreSuccessful}
                                            #MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamSuccessful}
            else:
                self.miniDiffNotReady()
        elif propertyName=="samplechanger":
            self.sampleChanger=self.getHardwareObject(newValue)
        elif propertyName=="dataCollect":
            self.collectObj=self.getHardwareObject(newValue)
        elif propertyName == 'icons':
            self.setIcons(newValue)
        elif propertyName=='label':
          pass #self.sampleCentreBox.setTitle(newValue)
        elif propertyName=='extraCommands':
            self.extraCommands['mnemonic']=newValue
        elif propertyName=='extraCommandsIcons':
            self.extraCommands['icons']=newValue
        elif propertyName=='queue':
            self.queue_hwobj = self.getHardwareObject(newValue)
            self.queue_hwobj.connect("queue_execution_finished", self.enable)
            self.queue_hwobj.connect("queue_stopped", self.enable)
        elif propertyName=='useMDPhases':
            if newValue:
                self.buttonToogleMDPhase.show()
            else:
                self.buttonToogleMDPhase.hide()
        else:
            BlissWidget.propertyChanged(self,propertyName,oldValue,newValue)

    def enable(self, *args):
        self.setEnabled(True)

    def disable(self, *args):
        self.setEnabled(False)

    def setIcons(self,icons):
        icons_list=icons.split()
        try:
            self.buttonCentre.setIcons(icons_list[0],icons_list[1])
        except IndexError:
            pass
        try:
            self.buttonAccept.setPixmap(Icons.load(icons_list[2]))
        except IndexError:
            pass
        try:
            self.buttonSnapshot.setPixmap(Icons.load(icons_list[3]))
        except IndexError:
            pass
        try:
            self.buttonReject.setPixmap(Icons.load(icons_list[4]))
        except IndexError:
            pass
        try:
            self.buttonToogleMDPhase.setPixmap(Icons.load(icons_list[5]))
        except IndexError:
            pass


    def setDirectory(self,directory):
        self.directory=str(directory)
        self.fileIndex=1

    def setPrefix(self,prefix):
        self.prefix=str(prefix)
        self.fileIndex=1

    def setSample(self,samples_list):
        self.selectedSamples = samples_list
        try:
          blsampleid=int(self.selectedSamples[0][0])
        except:
          blsampleid=None
        try:
          self.minidiff.setSampleInfo({"blsampleid":blsampleid})
        except:
          pass

    def emitWidgetSynchronize(self):
        #mode=self.modeBox.selectedId()
        points=self.clickedPoints
        #self.emit(PYSIGNAL("widgetSynchronize"),( (mode,points), ))
        self.emit(PYSIGNAL("widgetSynchronize"),( (points), ))

    def widgetSynchronize(self,state):
        #centring_method=state[0]
        #clicked_points=state[1]
        clicked_points=state[0]
        #self.modeBox.setButton(centring_method)
        if len(clicked_points):
            point=clicked_points[-1]
            self.__point.startDrawing()
            self.__point.show()
            self.__point.setPoint(point[0],point[1])
            self.__point.stopDrawing()
        else:
            self.__point.hide()

    def startCentring(self):
        # this is called from another brick, not by user
        self.insideDataCollection=True
        self.centreSampleClicked()

    def rejectCentring(self):
        self.cancelCentringClicked(reject=True)

    def acceptCentring(self):
        self.acceptClicked()

    def centreSampleClicked(self):
        self.minidiff.startCentringMethod(self.minidiff.MANUAL3CLICK_MODE)

    def saveSnapshot(self):
        formats=""
        for format in HutchMenuBrick.SNAPSHOT_FORMATS:
            formats+="*.%s " % format
        formats=formats.strip()

        current_filename=os.path.join(self.directory, self.prefix)
        current_filename=current_filename + '_%d%s%s' % (self.fileIndex, os.path.extsep, self.formatType)
        filename=str(QFileDialog.getSaveFileName(current_filename,"Images (%s)" % formats,\
            self,None,"Choose a filename to save under",None,False))
        if len(filename):
            image_type=os.path.splitext(filename)[1].strip('.').upper()
            try:
                matrix = self.__drawing.matrix()
                zoom = 1
                if matrix is not None:
                    zoom = matrix.m11()
                img = self.__drawing.getPPP()
                logging.getLogger().info("Saving snapshot : %s", filename)
                QubImageSave.save(filename, img, self.__drawing.canvas(), zoom, image_type)
            except:
                logging.getLogger().exception("HutchMenuBrick: error saving snapshot!")
                logging.getLogger().error("HutchMenuBrick: error saving snapshot!")
            else:
                self.formatType=image_type.lower()
                self.fileIndex+=1


    def centredPositionSnapshot(self):
        matrix = self.__drawing.matrix()

        zoom = 1
        if matrix is not None:
            zoom = matrix.m11()

        img = self.__drawing.getPPP()
        fd, name = tempfile.mkstemp()
        os.close(fd)

        QubImageSave.save(name, img, self.__drawing.canvas(), zoom, "JPEG")

        f = open(name, "r")
        imgcopy = f.read()
        f.close()
        os.unlink(name)

        return imgcopy


    def getSnapshot(self, img):
        logging.getLogger().debug("Taking snapshot for centred position")
        img['data'] = self.centredPositionSnapshot()
    

    def cancelCentringClicked(self,reject=False):
        #print "CANCELCENTRINGCLICKED",reject
        self.minidiff.cancelCentringMethod(reject=reject)

    def acceptClicked(self):
        if self.standardColor is not None:
            self.buttonAccept.setPaletteBackgroundColor(self.standardColor)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        self.minidiff.acceptCentring()

    def rejectClicked(self):
        if self.standardColor is not None:
            self.buttonReject.setPaletteBackgroundColor(self.standardColor)
        self.buttonReject.setEnabled(False)
        self.buttonAccept.setEnabled(False)
        self.minidiff.rejectCentring()
        self.insideDataCollection=False

    def centringMoving(self):
        self.isMoving=True
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringInvalid(self):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(None)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringAccepted(self,state,centring_status):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        if self.insideDataCollection:
          self.insideDataCollection = False
          self.emit(PYSIGNAL("centringAccepted"), (state,centring_status))

        beam_info = self.beamInfo.get_beam_info()        
        if beam_info is not None:
            beam_info['size_x'] = beam_info['size_x'] * self.pixels_per_mm[0]
            beam_info['size_y'] = beam_info['size_y'] * self.pixels_per_mm[1]
        self.emit(PYSIGNAL("newCentredPos"), (state, centring_status, beam_info))

        if self.queue_hwobj.is_executing():
            self.disable()

    def centringSnapshots(self,state):
        if state is None:
            self.isShooting=True
            self.sampleCentreBox.setEnabled(False)
        else:
            self.isShooting=False
            self.sampleCentreBox.setEnabled(True)

    def centringStarted(self,method,flexible):
        self.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (False,))
        if self.insideDataCollection:
          self.emit(PYSIGNAL("centringStarted"), ())

        self.isCentring=True
        self.isMoving=False
        self.isShooting=False
        """
        for but in self.centringButtons:
            if str(but.text())==method:
                if self.defaultBackgroundColor is None:
                    self.defaultBackgroundColor=but.paletteBackgroundColor()
                but.setPaletteBackgroundColor(QWidget.yellow)
                self.currentCentring=but
                break
        """
        self.currentCentring = CentringMethod(method)
        self.buttonCentre.commandStarted()
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

        if method == self.minidiff.MANUAL3CLICK_MODE:
            self.__point.startDrawing()
            self.__helpLine.startDrawing()
            self.__pointer.startDrawing()

    def drawAutoCentringPoint(self, x,y):
      if -1 in (x,y):
        self.__autoCentringPoint.hide()
        return
      self.__autoCentringPoint.startDrawing()
      self.__autoCentringPoint.setPoint(x,y)
      self.__autoCentringPoint.stopDrawing()
      self.__autoCentringPoint.show()
      
    def centringSuccessful(self,method,centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        self.clickedPoints=[]
        self.emitWidgetSynchronize()

        self.buttonCentre.commandDone()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring=None

        self.buttonAccept.setEnabled(True)
        self.buttonReject.setEnabled(True)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor=self.buttonAccept.paletteBackgroundColor()
            self.buttonAccept.setPaletteBackgroundColor(widget_colors.LIGHT_GREEN)
            self.buttonReject.setPaletteBackgroundColor(widget_colors.LIGHT_RED)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.isMoving=False
        self.sampleCentreBox.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            successful_method=self.successfulMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                successful_method()
            except:
                pass

    def centringFailed(self,method,centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()
       
        self.clickedPoints=[]
        self.emitWidgetSynchronize()


        self.buttonCentre.commandFailed()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring=None

        self.buttonAccept.setEnabled(False)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor=self.buttonAccept.paletteBackgroundColor()
            self.buttonReject.setEnabled(True)
            self.buttonReject.setPaletteBackgroundColor(QWidget.red)
        else:
            self.buttonReject.setEnabled(False)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            reset_method=self.resetMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                reset_method()
            except:
                pass

    #def movedToBeam(self,x,y):
    #    pass

    def manualCentreReset(self):
        self.resetPoints()

    def automaticCentreReset(self):
        if not self.userConfirmsButton.isChecked():
           self.rejectCentring()

    def automaticCentreSuccessful(self):
        if not self.userConfirmsButton.isChecked():
           self.acceptCentring()

    #def moveToBeamSuccessful(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    #def moveToBeamReset(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    def __endDrawingPoint(self,drawingManager) :
        x,y = drawingManager.point()
        self.imageClicked(x,y,x,y)

    # Handler for clicking the video when doing the 3-click centring
    def imageClicked(self,x,y,xi,yi):
        if self.currentCentring is not None\
        and str(self.currentCentring.text()) == self.minidiff.MANUAL3CLICK_MODE\
        and self.minidiff.isReady():
            try:
                points=self.minidiff.imageClicked(x,y,xi,yi)
            except StopIteration:
                pass
            else:
                self.addPoint(x,y,xi,yi)
 
    # Signals a new point in the 3-click centering
    def addPoint(self,x,y,xi,yi):
        self.clickedPoints.append((x,y,xi,yi))
        self.emitWidgetSynchronize()

    # Resets the points in the 3-click centering
    def resetPoints(self):
        self.clickedPoints=[]
        self.emitWidgetSynchronize()

    # Displays a message
    def showMessageToUser(self,message=None):
        try:
            self.__drawing.setInfo(message)
        except:
            pass

    def connectNotify(self, signalName):
        if signalName=='beamPositionChanged':
            if self.minidiff and self.beamInfo:
                if self.minidiff.isReady():
                    self.beam_position = self.beamInfo.get_beam_position()
                    self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
                                                                self.beam_position[1],
                                                                self.beam_size[0],\
                                                                self.beam_size[1]))
        elif signalName=='calibrationChanged':
            if self.minidiff and self.minidiff.isReady():
                try:
                    self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                    self.emit(PYSIGNAL("calibrationChanged"), (1e3 / self.pixels_per_mm[0],\
                                                               1e3 / self.pixels_per_mm[1]))                             
                except:
                    pass

    # Event when the minidiff is in ready state
    def miniDiffReady(self):
        try:
            self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
        except:
            self.pixels_per_mm = [None, None] 
        
        if self.pixels_per_mm[0] is not None\
        and self.pixels_per_mm[1] is not None:
            self.beam_position = self.beamInfo.get_beam_position()        
            self.beam_size = self.beamInfo.get_beam_size()
            self.sampleCentreBox.setEnabled(True)
            self.updateBeam()
            self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
                                                        self.beam_position[1],
                                                        self.beam_size[0],\
                                                        self.beam_size[1]))
        else:
            self.miniDiffNotReady()

    # Event when the minidiff is in notready state
    def miniDiffNotReady(self):
        try:
          self.__beam.hide()
        except AttributeError:
          pass
        if not self.buttonCentre.executing:
           self.sampleCentreBox.setEnabled(False)

    def miniDiffStateChanged(self,state):
        if self.buttonCentre.executing or self.isMoving or self.isShooting:
            return
        try:
            self.sampleCentreBox.setEnabled(state == self.minidiff.phiMotor.READY)
        except:
            pass

    # Displays a message (signaled from the minidiff hardware object)
    def miniDiffMessage(self,msg=None):
        self.showMessageToUser(msg)

    # Update both zoom and slits when started
    def run(self):
        if self.minidiff is not None:
            zoom=self.minidiff.zoomMotor
            if zoom is not None:
                if zoom.isReady():
                    self.zoomPositionChanged(zoom.getCurrentPositionName(),0)

        keys = {}
        self.emit(PYSIGNAL('getView'),(keys,))
        self.__drawing = keys.get('drawing',None)
        self.__view = keys.get('view',None)
        if self.minidiff is not None:
          self.minidiff._drawing = self.__drawing

        try:
            self.__point, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__point.setEndDrawCallBack(self.__endDrawingPoint)
            self.__point.setColor(Qt.yellow)
            
            self.__autoCentringPoint, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__autoCentringPoint.setColor(Qt.green)

            self.__helpLine, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasVLine)
            self.__helpLine.setAutoDisconnectEvent(True)
            self.__helpLine.setExclusive(False)
            self.__helpLine.setColor(Qt.yellow)

            self.__rectangularBeam, _ = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasSlitbox)
            self.__rectangularBeam.show()
            self.__rectangularBeam.setSlitboxSize(0,0)
            self.__rectangularBeam.setColor(Qt.red)
            self.__rectangularBeam.setSlitboxPen(QPen(Qt.blue))

            self.__beam, _ = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasBeam) 
            self.__beam.setPen(QPen(Qt.blue))
            self.__beam.hide()

            self.__pointer, _, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasHLine, QubCanvasVLine)
            self.__pointer.setDrawingEvent(QubMoveNPressed1Point)
            self.__pointer.setExclusive(False)
            self.__pointer.setColor(Qt.yellow)

            self.__scale, scale = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasScale)
            self.sx = self.__scale.setXPixelSize
            self.sy = self.__scale.setYPixelSize
            self.__scale.show()

            try:
                self.__scale.setXPixelSize(self.__scaleX)
                self.__scale.setYPixelSize(self.__scaleY)
            except AttributeError:
                pass
            else:
                self.emit(PYSIGNAL("calibrationChanged"), (self.__scaleX, self.__scaleY))
                self.updateBeam(force=True)
        except:
            logging.getLogger().exception("HutchMenuBrick: problem starting up display")

    def _drawBeam(self):
        if None in (self.beam_size, self.beam_shape):
            self.beam_position = self.beamInfo.get_beam_position()        
            self.beam_size = self.beamInfo.get_beam_size()
         
        if True:
          self.__rectangularBeam.show()
          if None in self.beam_size:
            return
          if self.beam_shape == "rectangular":
            self.__rectangularBeam.setSlitboxSize(self.beam_size[0] * self.pixels_per_mm[0],\
                                                  self.beam_size[1] * self.pixels_per_mm[1])
            self.__beam.hide()
          else:
            self.__rectangularBeam.setSlitboxSize(0,0)
            self.__beam.setSize(self.beam_size[0] * self.pixels_per_mm[0],\
                                self.beam_size[1] * self.pixels_per_mm[1])
            self.__beam.show()

    def updateBeam(self,force=False):
        if self["displayBeam"]:
              #if self.minidiff:
              #  if not self.minidiff.isReady(): time.sleep(0.2)
              try:
                 self.__rectangularBeam.set_xMid_yMid(self.beam_position[0],
                                                      self.beam_position[1])
              except AttributeError:
                 pass
              try:
                self.__beam.move(self.beam_position[0], self.beam_position[1])
                self._drawBeam()
                #try:
                #  self._updateBeam(self.beamInfo.get_beam_info())
                #except:
                #  logging.getLogger().exception("Could not get beam size: cannot display beam")
                #  self.__beam.hide()
              except AttributeError:
                pass
    
    def beamPosChanged(self, position):
        self.beam_position = position
        self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
                                                    self.beam_position[1],
                                                    self.beam_size[0],\
                                                    self.beam_size[1]))
        self.updateBeam(True)

    def beamInfoChanged(self, beam_info):
        try:
          self.beam_position = self.beamInfo.get_beam_position()
        except:
          pass
        self.beam_size = (beam_info["size_x"], beam_info["size_y"])
        self.beam_shape = beam_info["shape"]
        self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
                                                    self.beam_position[1],
                                                    self.beam_size[0],\
                                                    self.beam_size[1]))
            self.updateBeam(True)
Ejemplo n.º 7
0
class SoleilHutchMenuBrick(BlissWidget):
    SNAPSHOT_FORMATS = ('png', 'jpeg')

    def __init__(self, *args):
        BlissWidget.__init__(self, *args)

        self.minidiff = None
        self.beamInfo = None
        self.sampleChanger=None
        self.collectObj = None
        self.queue_hwobj = None
        self.beam_position = [30, 30]
        self.beam_size = [0.04, 0.02]
        self.beam_shape = "Rectangular"
        self.pixels_per_mm = [0, 0]
        self.slitbox  = None
        self.sampleChanger=None
        self.queue_hwobj = None
        self._bx, self._by = (0, 0)

        #self.allowMoveToBeamCentring = False

        # Define properties
        self.addProperty('minidiff','string','')
        self.addProperty('beamInfo', 'string', '')
        self.addProperty('dataCollect','string','')
        self.addProperty('beamInfo','string','')
        #self.addProperty('slitbox','string','')
        self.addProperty('samplechanger','string','')
        self.addProperty('extraCommands','string','')
        self.addProperty('extraCommandsIcons','string','')
        self.addProperty('icons','string','')
        self.addProperty('label','string','Sample centring')
        #self.addProperty('displaySlitbox', 'boolean', True)
        self.addProperty('displayBeam', 'boolean', True)
        self.addProperty('queue', 'string', '/queue')
        self.addProperty('useMDPhases', 'boolean', True)

        # Define signals and slots
        self.defineSignal('enableMinidiff',())
        self.defineSignal('centringStarted',())
        self.defineSignal('centringAccepted',())
        self.defineSignal('getView',())
        self.defineSignal('beamPositionChanged', ())
        self.defineSignal('calibrationChanged', ())
        self.defineSignal('newCentredPos', ())
        #self.defineSignal('setMoveToBeamState', ())
        self.defineSlot('setDirectory',())
        self.defineSlot('setPrefix',())
        #self.defineSlot('movedToBeam', ())
        self.defineSlot('startCentring', ())
        self.defineSlot('rejectCentring', ())
        self.defineSlot('setSample',())
        #self.defineSlot('enableAutoStartLoopCentring', ())
        self.defineSlot('getSnapshot',())
        
        self.sampleCentreBox=QVBox(self)
        #self.sampleCentreBox.setInsideMargin(11)
        #self.sampleCentreBox.setInsideSpacing(0)

        #self.modeBox=QVButtonGroup(self.sampleCentreBox)
        #self.modeBox.setFrameShape(self.modeBox.NoFrame)
        #self.modeBox.setInsideMargin(0)
        #self.modeBox.setInsideSpacing(0)            
        #QObject.connect(self.modeBox,SIGNAL('clicked(int)'),self.centringModeChanged)
        #self.userConfirmsButton=QCheckBox("User confirms", self.sampleCentreBox)
        #self.userConfirmsButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
        #self.userConfirmsButton.setChecked(True)

        self.buttonsBox=QVBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)

        self.buttonCentre=MenuButton(self.buttonsBox,"Centre")
        self.buttonCentre.setMinimumSize(QSize(75,50))
        self.connect(self.buttonCentre,PYSIGNAL('executeCommand'),self.centreSampleClicked)
        self.connect(self.buttonCentre,PYSIGNAL('cancelCommand'),self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(75,50))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept,SIGNAL('clicked()'),self.acceptClicked)
        self.standardColor=None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(75,50))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject,SIGNAL('clicked()'),self.rejectClicked)

        #HorizontalSpacer4(self.sampleCentreBox)

        self.extraCommands=CommandMenuBrick.CommandMenuBrick(self.sampleCentreBox)
        self.extraCommands['showBorder']=False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(75,50))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot,SIGNAL('clicked()'),self.saveSnapshot)

        #self.buttonToogleMDPhase = QToolButton(self.sampleCentreBox)
        #self.buttonToogleMDPhase.setUsesTextLabel(True)
        #self.buttonToogleMDPhase.setTextLabel("MD phase")
        #self.buttonToogleMDPhase.setMinimumSize(QSize(75,50))
        #self.buttonToogleMDPhase.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        #QObject.connect(self.buttonToogleMDPhase,SIGNAL('clicked()'),self.toogleMDPhase)
        #self.buttonToogleMDPhase.hide()

        #HorizontalSpacer3(self.sampleCentreBox)

        self.centringButtons=[]
        self.defaultBackgroundColor=None
        self.insideDataCollection=False        
        self.currentCentring = None
        self.isMoving=False
        self.isShooting=False
        self.directory="/tmp"
        self.prefix="snapshot"
        self.fileIndex=1
        self.formatType="png"

        self.clickedPoints=[]
        self.selectedSamples=None

        # Layout
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        QHBoxLayout(self)        
        self.layout().addWidget(self.sampleCentreBox)

        self.instanceSynchronize("")

        self.resetMethods={MiniDiff.MiniDiff.MANUAL3CLICK_MODE:self.manualCentreReset,
            MiniDiff.MiniDiff.C3D_MODE:self.automaticCentreReset}
            #MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamReset}
        self.successfulMethods={MiniDiff.MiniDiff.MANUAL3CLICK_MODE:None,
            MiniDiff.MiniDiff.C3D_MODE:self.automaticCentreSuccessful}
            #MiniDiff.MiniDiff.MOVE_TO_BEAM_MODE:self.moveToBeamSuccessful}
        
        self.sampleCentreBox.hide()

        self.sampleCentreBox = QHBox(self)
        self.buttonsBox=QHBox(self.sampleCentreBox)
        self.buttonsBox.setSpacing(0)
        self.sampleCentreBox.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
        self.buttonsBox.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)

        self.layout().addWidget(self.sampleCentreBox)

        self.buttonCentre=MenuButton(self.buttonsBox,"Centre")
        self.buttonCentre.setMinimumSize(QSize(50,40))
        self.connect(self.buttonCentre,PYSIGNAL('executeCommand'),self.centreSampleClicked)
        self.connect(self.buttonCentre,PYSIGNAL('cancelCommand'),self.cancelCentringClicked)

        self.buttonAccept = QToolButton(self.buttonsBox)
        self.buttonAccept.setUsesTextLabel(True)
        self.buttonAccept.setTextLabel("Save")
        self.buttonAccept.setMinimumSize(QSize(50,40))
        self.buttonAccept.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonAccept.setEnabled(False)
        QObject.connect(self.buttonAccept,SIGNAL('clicked()'),self.acceptClicked)
        self.standardColor=None

        self.buttonReject = QToolButton(self.buttonsBox)
        self.buttonReject.setUsesTextLabel(True)
        self.buttonReject.setTextLabel("Reject")
        self.buttonReject.setMinimumSize(QSize(50,40))
        self.buttonReject.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonReject.setEnabled(False)
        self.buttonReject.hide()
        QObject.connect(self.buttonReject,SIGNAL('clicked()'),self.rejectClicked)

        self.extraCommands=CommandMenuBrick.CommandMenuBrick(self.sampleCentreBox)
        self.extraCommands['showBorder']=False

        self.buttonSnapshot = QToolButton(self.sampleCentreBox)
        self.buttonSnapshot.setUsesTextLabel(True)
        self.buttonSnapshot.setTextLabel("Snapshot")
        self.buttonSnapshot.setMinimumSize(QSize(50,40))
        self.buttonSnapshot.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        QObject.connect(self.buttonSnapshot,SIGNAL('clicked()'),self.saveSnapshot)

        self.buttonBeamPosition = QToolButton(self.sampleCentreBox)
        self.buttonBeamPosition.setUsesTextLabel(True)
        self.buttonBeamPosition.setTextLabel("BeamPosition")
        self.buttonBeamPosition.setMinimumSize(QSize(50,40))
        self.buttonBeamPosition.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonBeamPosition.setPixmap(Icons.load("green_led"))
        QObject.connect(self.buttonBeamPosition, SIGNAL('clicked()'), self.beamPositionCheck)
        
        self.buttonApertureAlign = QToolButton(self.sampleCentreBox)
        self.buttonApertureAlign.setUsesTextLabel(True)
        self.buttonApertureAlign.setTextLabel("ApertureAlign")
        self.buttonApertureAlign.setMinimumSize(QSize(50,40))
        self.buttonApertureAlign.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.buttonApertureAlign.setPixmap(Icons.load("Align"))
        QObject.connect(self.buttonApertureAlign, SIGNAL('clicked()'), self.apertureAlign)
   
   
    def beamPositionCheck(self):
        self.minidiff.beamPositionCheck()
        
    def apertureAlign(self):
        self.minidiff.apertureAlign()        
        
        
    def enableAutoStartLoopCentring(self, enable):
        if self.minidiff is not None:
           self.minidiff.enableAutoStartLoopCentring(enable)

    def propertyChanged(self,propertyName,oldValue,newValue):
        #print "HutchMenuBrick.propertyChanged",property,newValue
        if propertyName=='minidiff':
            if self.minidiff is not None:
                self.disconnect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'), self.zoomPositionChanged)
                self.disconnect(self.minidiff,PYSIGNAL('minidiffReady'),self.miniDiffReady)
                self.disconnect(self.minidiff,PYSIGNAL('minidiffNotReady'),self.miniDiffNotReady)
                self.disconnect(self.minidiff,PYSIGNAL('minidiffStateChanged'),self.miniDiffStateChanged)
                self.disconnect(self.minidiff,PYSIGNAL('centringStarted'),self.centringStarted)
                self.disconnect(self.minidiff,PYSIGNAL('centringSuccessful'),self.centringSuccessful)
                self.disconnect(self.minidiff,PYSIGNAL('centringFailed'),self.centringFailed)
                self.disconnect(self.minidiff,PYSIGNAL('centringMoving'),self.centringMoving)
                self.disconnect(self.minidiff,PYSIGNAL('centringInvalid'),self.centringInvalid)
                self.disconnect(self.minidiff,PYSIGNAL('centringSnapshots'),self.centringSnapshots)
                self.disconnect(self.minidiff,PYSIGNAL('progressMessage'),self.miniDiffMessage)
                self.disconnect(self.minidiff,PYSIGNAL('newAutomaticCentringPoint'),self.drawAutoCentringPoint)
                self.disconnect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'), self.zoomPositionChanged)
                self.disconnect(self.minidiff,PYSIGNAL('centringAccepted'),self.centringAccepted)
            self.minidiff=self.getHardwareObject(newValue)
            if self.minidiff is not None:
                self.connect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'),self.zoomPositionChanged)
                self.connect(self.minidiff,PYSIGNAL('minidiffReady'),self.miniDiffReady)
                self.connect(self.minidiff,PYSIGNAL('minidiffNotReady'),self.miniDiffNotReady)
                self.connect(self.minidiff,PYSIGNAL('minidiffStateChanged'),self.miniDiffStateChanged)
                self.connect(self.minidiff,PYSIGNAL('centringStarted'),self.centringStarted)
                self.connect(self.minidiff,PYSIGNAL('centringSuccessful'),self.centringSuccessful)
                self.connect(self.minidiff,PYSIGNAL('centringFailed'),self.centringFailed)
                self.connect(self.minidiff,PYSIGNAL('centringMoving'),self.centringMoving)
                self.connect(self.minidiff,PYSIGNAL('centringInvalid'),self.centringInvalid)
                self.connect(self.minidiff,PYSIGNAL('centringSnapshots'),self.centringSnapshots)
                self.connect(self.minidiff,PYSIGNAL('progressMessage'),self.miniDiffMessage)
                self.connect(self.minidiff, "newAutomaticCentringPoint", self.drawAutoCentringPoint)
                self.connect(self.minidiff,PYSIGNAL('zoomMotorPredefinedPositionChanged'),self.zoomPositionChanged)
                self.connect(self.minidiff,PYSIGNAL('centringAccepted'),self.centringAccepted)

                if self.minidiff.isReady():
                    self.miniDiffReady()
                else:
                    self.miniDiffNotReady()
            else:
                self.miniDiffNotReady()
        #elif propertyName=='slitbox':
        #    if self.slitbox is not None:
        #        for role in ('s1v', 's2v', 's1h', 's2h'):
        #          m = self.slitbox.getDeviceByRole(role)
        #          m.disconnect('stateChanged', self.slitsPositionChanged)
        #    self.slitbox=self.getHardwareObject(newValue)
        #    if self.slitbox is not None:
        #        for role in ('s1v', 's2v', 's1h', 's2h'):
        #          m = self.slitbox.getDeviceByRole(role)
        #          m.connect("stateChanged", self.slitsPositionChanged)
        #    #self.slitsPositionChanged()
        elif propertyName=="beamInfo":
            if self.beamInfo is not None:
                self.disconnect(self.beamInfo,PYSIGNAL('beamInfoChanged'), self.beamInfoChanged)
                self.disconnect(self.beamInfo,PYSIGNAL('beamPosChanged'), self.beamPosChanged)
            self.beamInfo=self.getHardwareObject(newValue)
            if self.beamInfo is not None:
                self.connect(self.beamInfo,PYSIGNAL('beamInfoChanged'), self.beamInfoChanged)
                self.connect(self.beamInfo,PYSIGNAL('beamPosChanged'), self.beamPosChanged)

        elif propertyName=="samplechanger":
            self.sampleChanger=self.getHardwareObject(newValue)
        elif propertyName=="dataCollect":
            self.collectObj=self.getHardwareObject(newValue)
        elif propertyName == 'icons':
            self.setIcons(newValue)
        elif propertyName=='label':
          pass #self.sampleCentreBox.setTitle(newValue)
        elif propertyName=='extraCommands':
            self.extraCommands['mnemonic']=newValue
        elif propertyName=='extraCommandsIcons':
            self.extraCommands['icons']=newValue
        elif propertyName=='queue':
            self.queue_hwobj = self.getHardwareObject(newValue)
        else:
            BlissWidget.propertyChanged(self,propertyName,oldValue,newValue)

    def setIcons(self,icons):
        icons_list=icons.split()
        try:
            self.buttonCentre.setIcons(icons_list[0],icons_list[1])
        except IndexError:
            pass
        try:
            self.buttonAccept.setPixmap(Icons.load(icons_list[2]))
        except IndexError:
            pass
        try:
            self.buttonSnapshot.setPixmap(Icons.load(icons_list[3]))
        except IndexError:
            pass
        try:
            self.buttonReject.setPixmap(Icons.load(icons_list[4]))
        except IndexError:
            pass

    def setDirectory(self,directory):
        self.directory=str(directory)
        self.fileIndex=1

    def setPrefix(self,prefix):
        self.prefix=str(prefix)
        self.fileIndex=1

    def setSample(self,samples_list):
        self.selectedSamples = samples_list
        try:
          blsampleid=int(self.selectedSamples[0][0])
        except:
          blsampleid=None
        try:
          self.minidiff.setSampleInfo({"blsampleid":blsampleid})
        except:
          pass

    def emitWidgetSynchronize(self):
        #mode=self.modeBox.selectedId()
        points=self.clickedPoints
        #self.emit(PYSIGNAL("widgetSynchronize"),( (mode,points), ))
        self.emit(PYSIGNAL("widgetSynchronize"),( (points), ))

    def widgetSynchronize(self,state):
        #centring_method=state[0]
        #clicked_points=state[1]
        clicked_points=state[0]
        #self.modeBox.setButton(centring_method)
        if len(clicked_points):
            point=clicked_points[-1]
            self.__point.startDrawing()
            self.__point.show()
            self.__point.setPoint(point[0],point[1])
            self.__point.stopDrawing()
        else:
            self.__point.hide()

    def startCentring(self):
        # this is called from another brick, not by user
        self.insideDataCollection=True
        self.centreSampleClicked()

    def rejectCentring(self):
        self.cancelCentringClicked(reject=True)

    def acceptCentring(self):
        self.acceptClicked()

    def centreSampleClicked(self):
        self.minidiff.startCentringMethod(self.minidiff.MANUAL3CLICK_MODE)

    def saveSnapshot(self):
        formats=""
        for format in SoleilHutchMenuBrick.SNAPSHOT_FORMATS:
            formats+="*.%s " % format
        formats=formats.strip()

        current_filename=os.path.join(self.directory, self.prefix)
        current_filename=current_filename + '_%d%s%s' % (self.fileIndex, os.path.extsep, self.formatType)
        filename=str(QFileDialog.getSaveFileName(current_filename,"Images (%s)" % formats,\
            self,None,"Choose a filename to save under",None,False))
        if len(filename):
            image_type=os.path.splitext(filename)[1].strip('.').upper()
            try:
                matrix = self.__drawing.matrix()
                zoom = 1
                if matrix is not None:
                    zoom = matrix.m11()
                img = self.__drawing.getPPP()
                logging.getLogger().info("Saving snapshot : %s", filename)
                QubImageSave.save(filename, img, self.__drawing.canvas(), zoom, image_type)
            except:
                logging.getLogger().exception("HutchMenuBrick: error saving snapshot!")
                logging.getLogger().error("HutchMenuBrick: error saving snapshot!")
            else:
                self.formatType=image_type.lower()
                self.fileIndex+=1


    def centredPositionSnapshot(self):
        matrix = self.__drawing.matrix()

        zoom = 1
        if matrix is not None:
            zoom = matrix.m11()

        img = self.__drawing.getPPP()
        fd, name = tempfile.mkstemp()
        os.close(fd)

        QubImageSave.save(name, img, self.__drawing.canvas(), zoom, "JPEG")

        f = open(name, "r")
        imgcopy = f.read()
        f.close()
        os.unlink(name)

        return imgcopy


    def getSnapshot(self, img):
        logging.getLogger().debug("Taking snapshot for centred position")
        img['data'] = self.centredPositionSnapshot()
    

    def cancelCentringClicked(self,reject=False):
        #print "CANCELCENTRINGCLICKED",reject
        self.minidiff.cancelCentringMethod(reject=reject)

    def acceptClicked(self):
        if self.standardColor is not None:
            self.buttonAccept.setPaletteBackgroundColor(self.standardColor)
        #logging.info("disabling accept because accept was clicked")  
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        self.minidiff.acceptCentring()

    def rejectClicked(self):
        if self.standardColor is not None:
            self.buttonReject.setPaletteBackgroundColor(self.standardColor)
        #logging.info("disabling accept because reject was clicked")  
        self.buttonReject.setEnabled(False)
        self.buttonAccept.setEnabled(False)
        self.minidiff.rejectCentring()
        self.insideDataCollection=False

    def centringMoving(self):
        self.isMoving=True
        logging.info("disabling accept because centring is moving ")  
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringInvalid(self):
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(None)
        logging.info("disabling accept because centring is invalid ")  
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

    def centringAccepted(self,state,centring_status):
        logging.info("Centring has been accepted")
        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)
        logging.info("disabling accept because centring has been accepted ")  
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)
        if self.insideDataCollection:
          self.insideDataCollection = False
          self.emit(PYSIGNAL("centringAccepted"), (state,centring_status))

        if self.beamInfo is not None:
	   beam_info = self.beamInfo.get_beam_info()	
	   if beam_info is not None:
	       beam_info['size_x'] = beam_info['size_x'] * self.pixels_per_mm[0]
	       beam_info['size_y'] = beam_info['size_y'] * self.pixels_per_mm[1]
           self.emit(PYSIGNAL("newCentredPos"), (state, centring_status, beam_info))
           #self.emit(PYSIGNAL("newCentredPos"), (state, centring_status))

        if self.queue_hwobj.is_executing():
            self.setEnabled(False)

    def centringSnapshots(self,state):
        if state is None:
            self.isShooting=True
            self.sampleCentreBox.setEnabled(False)
        else:
            self.isShooting=False
            self.sampleCentreBox.setEnabled(True)

    def centringStarted(self,method,flexible):
        self.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (False,))
        if self.insideDataCollection:
          self.emit(PYSIGNAL("centringStarted"), ())

        self.isCentring=True
        self.isMoving=False
        self.isShooting=False
        """
        for but in self.centringButtons:
            if str(but.text())==method:
                if self.defaultBackgroundColor is None:
                    self.defaultBackgroundColor=but.paletteBackgroundColor()
                but.setPaletteBackgroundColor(QWidget.yellow)
                self.currentCentring=but
                break
        """
        self.currentCentring = CentringMethod(method)
        self.buttonCentre.commandStarted()
        logging.info("disabling accept because centring has been started ")  
        self.buttonAccept.setEnabled(False)
        self.buttonReject.setEnabled(False)

        if method==MiniDiff.MiniDiff.MANUAL3CLICK_MODE:
            self.__point.startDrawing()
            self.__helpLine.startDrawing()
            self.__pointer.startDrawing()

    def drawAutoCentringPoint(self, x,y):
      if -1 in (x,y):
        self.__autoCentringPoint.hide()
        return
      self.__autoCentringPoint.startDrawing()
      self.__autoCentringPoint.setPoint(x,y)
      self.__autoCentringPoint.stopDrawing()
      self.__autoCentringPoint.show()
      
    def centringSuccessful(self,method,centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()

        #logging.info("HutchMenuBrick:  centringSuccesful received")

        self.clickedPoints=[]
        self.emitWidgetSynchronize()

        self.buttonCentre.commandDone()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring=None

        self.buttonAccept.setEnabled(True)
        self.buttonReject.setEnabled(True)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor=self.buttonAccept.paletteBackgroundColor()
            self.buttonAccept.setPaletteBackgroundColor(widget_colors.LIGHT_GREEN)
            self.buttonReject.setPaletteBackgroundColor(widget_colors.LIGHT_RED)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.isMoving=False
        self.sampleCentreBox.setEnabled(True)
        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            successful_method=self.successfulMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                successful_method()
            except:
                pass

    def centringFailed(self,method,centring_status):
        self.__point.stopDrawing()
        self.__point.hide()
        self.__helpLine.hide()
        self.__helpLine.stopDrawing()
        self.__pointer.stopDrawing()
        self.__pointer.hide()
       
        self.clickedPoints=[]
        self.emitWidgetSynchronize()


        self.buttonCentre.commandFailed()
        if self.currentCentring is not None:
            #    self.currentCentring.setPaletteBackgroundColor(self.defaultBackgroundColor)
            self.currentCentring=None

        logging.info("disabling accept because centing failed")  
        self.buttonAccept.setEnabled(False)
        if self.insideDataCollection:
            if self.standardColor is None:
                self.standardColor=self.buttonAccept.paletteBackgroundColor()
            self.buttonReject.setEnabled(True)
            self.buttonReject.setPaletteBackgroundColor(QWidget.red)
        else:
            self.buttonReject.setEnabled(False)

        if self.collectObj is not None:
            self.collectObj.setCentringStatus(centring_status)

        self.emit(PYSIGNAL("enableMinidiff"), (True,))

        try:
            reset_method=self.resetMethods[method]
        except KeyError as diag:
            pass
        else:
            try:
                reset_method()
            except:
                pass

    #def movedToBeam(self,x,y):
    #    pass

    def manualCentreReset(self):
        self.resetPoints()

    def automaticCentreReset(self):
        if not self.userConfirmsButton.isChecked():
           self.rejectCentring()

    def automaticCentreSuccessful(self):
        if not self.userConfirmsButton.isChecked():
           self.acceptCentring()

    #def moveToBeamSuccessful(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    #def moveToBeamReset(self):
        #self.emit(PYSIGNAL("setMoveToBeamState"), (False,))
    #    pass

    def __endDrawingPoint(self,drawingManager) :
        x,y = drawingManager.point()
        self.imageClicked(x,y,x,y)

    # Handler for clicking the video when doing the 3-click centring
    def imageClicked(self,x,y,xi,yi):
        #print "HutchMenuBrick.imageClicked",self.minidiff,self.manualCentering
        if self.currentCentring is not None and str(self.currentCentring.text())==MiniDiff.MiniDiff.MANUAL3CLICK_MODE and self.minidiff.isReady():
            try:
                points=self.minidiff.imageClicked(x,y,xi,yi)
            except StopIteration:
                pass
            else:
                self.addPoint(x,y,xi,yi)
 
    # Signals a new point in the 3-click centering
    def addPoint(self,x,y,xi,yi):
        self.clickedPoints.append((x,y,xi,yi))
        self.emitWidgetSynchronize()

    # Resets the points in the 3-click centering
    def resetPoints(self):
        self.clickedPoints=[]
        self.emitWidgetSynchronize()

    # Displays a message
    def showMessageToUser(self,message=None):
        #print "showMessage",message
        try:
            self.__drawing.setInfo(message)
        except:
            pass

    def connectNotify(self, signalName):
        print("..... HutchMenuBrick:connectNotify  ", signalName)
        if signalName=='beamPositionChanged':
            if self.minidiff and self.minidiff.isReady() and self.beamInfo is not None:
		self.beam_position = self.beamInfo.get_beam_position()
		self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
							    self.beam_position[1],
                                                            self.beam_size[0],\
							    self.beam_size[1]))
            #if self.minidiff and self.minidiff.isReady():
            #    beam_xc = self.minidiff.getBeamPosX()
            #    beam_yc = self.minidiff.getBeamPosY()
            #    pxmmy=self.minidiff.pixelsPerMmY
            #    pxmmz=self.minidiff.pixelsPerMmZ
#
#                self.emit(PYSIGNAL("beamPositionChanged"), (beam_xc, beam_yc,
#                                                            self._bx, self._by))
        elif signalName=='calibrationChanged':
            if self.minidiff and self.minidiff.isReady():
                try:
                    #self.emit(PYSIGNAL("calibrationChanged"), (1e3/self.minidiff.pixelsPerMmY, 1e3/self.minidiff.pixelsPerMmZ))      			
                    self.emit(PYSIGNAL("calibrationChanged"), (1e3/self.pixels_per_mm[0], 1e3/self.pixels_per_mm[1]))
                except:
                    pass

    # Event when the minidiff is in ready state
    def miniDiffReady(self):
        try:
            self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
            if self.beamInfo is not None:
                self.beam_position = self.beamInfo.get_beam_position()	
        except:
            import traceback
            logging.getLogger().error("error on minidiff ready %s", traceback.format_exc())
            self.pixels_per_mm = [None, None]
            #pxmmy=None
            #pxmmz=None 

        #if pxmmy is not None and pxmmz is not None:
        if self.beamInfo is not None:
            if self.pixels_per_mm[0] is not None and self.pixels_per_mm[1] is not None:
                self.sampleCentreBox.setEnabled(True)
                self.updateBeam()
                #self.emit(PYSIGNAL("beamPositionChanged"), (beam_xc, beam_yc, self._bx, self._by))
                self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0], self.beam_position[1], self.beam_size[0], self.beam_size[1]))
        else:
            self.miniDiffNotReady()

    # Event when the minidiff is in notready state
    def miniDiffNotReady(self):
        #import pdb; pdb.set_trace()
        try:
          self.__beam.hide()
        except AttributeError:
          pass
        if not self.buttonCentre.executing:
           self.sampleCentreBox.setEnabled(False)

    def miniDiffStateChanged(self,state):
        if self.buttonCentre.executing or self.isMoving or self.isShooting:
            return
        try:
            self.sampleCentreBox.setEnabled(state==self.minidiff.phiMotor.READY)
        except:
            pass

    # Displays a message (signaled from the minidiff hardware object)
    def miniDiffMessage(self,msg=None):
        #print "MINIDIFF MESSAGE!!!",msg
        self.showMessageToUser(msg)

    # Update both zoom and slits when started
    def run(self):
        logging.getLogger().info("HucthMenuBrick runs")
        if self.minidiff is not None:
            zoom=self.minidiff.zoomMotor
            if zoom is not None:
                if zoom.isReady():
                    self.zoomPositionChanged(zoom.getCurrentPositionName(),0)

        keys = {}
        self.emit(PYSIGNAL('getView'),(keys,))
        self.__drawing = keys.get('drawing',None)
        self.__view = keys.get('view',None)
        if self.minidiff is not None:
          self.minidiff._drawing = self.__drawing

        try:
            self.__point, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__point.setEndDrawCallBack(self.__endDrawingPoint)
            self.__point.setColor(Qt.yellow)
            
            self.__autoCentringPoint, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasTarget)
            self.__autoCentringPoint.setColor(Qt.green)

            self.__helpLine, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasVLine)
            self.__helpLine.setAutoDisconnectEvent(True)
            self.__helpLine.setExclusive(False)
            self.__helpLine.setColor(Qt.yellow)
            
            logging.getLogger().info("HutchMenuBrick help line OK")
            
            self.__rectangularBeam, _ = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasSlitbox)
            self.__rectangularBeam.set_xMid_yMid(self.beam_position[0], self.beam_position[1])
            self.__rectangularBeam.show()
            self.__rectangularBeam.setSlitboxSize(0,0)
            self.__rectangularBeam.setColor(Qt.red)
            self.__rectangularBeam.setSlitboxPen(QPen(Qt.blue))
            #self.beam_position = self.beamInfo.get_beam_position()
            
            logging.getLogger().info("HutchMenuBrick rectangular beam OK")
            
            self.__beam, _ = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasBeam) 
            self.__beam.setPen(QPen(Qt.blue))
            self.__beam.hide()
            
            logging.getLogger().info("HutchMenuBrick beam setPen successful")
            
            self.__pointer, _, _ = QubAddDrawing(self.__drawing, QubPointDrawingMgr, QubCanvasHLine, QubCanvasVLine)
            self.__pointer.setDrawingEvent(QubMoveNPressed1Point)
            self.__pointer.setExclusive(False)
            self.__pointer.setColor(Qt.yellow)
            
            logging.getLogger().info("HutchMenuBrick runs. pointer successful")
            
            self.__scale, scale = QubAddDrawing(self.__drawing, QubContainerDrawingMgr, QubCanvasScale)
            self.sx = self.__scale.setXPixelSize
            self.sy = self.__scale.setYPixelSize
            self.__scale.show()
            logging.getLogger().info("HutchMenuBrick runs. Scale just changed")
            try:
                self.__scale.setXPixelSize(self.__scaleX)
                self.__scale.setYPixelSize(self.__scaleY)
            except AttributeError:
                pass
            else:
                self.emit(PYSIGNAL("calibrationChanged"), (self.__scaleX, self.__scaleY))
                #self.slitsPositionChanged()
                logging.getLogger().info("HutchMenuBrick runs. It will now update the beam drawing")
                self.__rectangularBeam.set_xMid_yMid(self.beam_position[0], self.beam_position[1])
                logging.getLogger().info("HutchMenuBrick setting rectangular beam xMid, yMid to %s, %s" % (self.beam_position[0], self.beam_position[1]))
                self.updateBeam(force=True)
        except:
            import traceback
            logging.getLogger().debug("HutchMenuBrick: problem starting up display")
            logging.getLogger().exception( traceback.format_exc())
        else:
            logging.getLogger().info("HucthMenuBrick runs cool")

    def _drawBeam(self):
        try:
          self.__rectangularBeam.show()
          #if None in (self._by, self._bx):
          if None in self.beam_size:
            return
          #bx = self._bx
          #by = self._by
          #pxmmy=self.minidiff.pixelsPerMmY
          #pxmmz=self.minidiff.pixelsPerMmZ
          #if self._bshape == "rectangular":
          #  self.__rectangularBeam.setSlitboxSize(bx*pxmmy, by*pxmmz)
          if self.beam_shape == "rectangular":
             self.__rectangularBeam.setSlitboxSize(self.beam_size[0] * self.pixels_per_mm[0],\
                                                 self.beam_size[1] * self.pixels_per_mm[1])
             self.__beam.hide()
          else:
            self.__rectangularBeam.setSlitboxSize(0,0)
            self.__beam.setSize(self.beam_size[0] * self.pixels_per_mm[0],\
				self.beam_size[1] * self.pixels_per_mm[1])
            logging.getLogger().info("beam drawn with size %s " % str(self.beam_size))
            #self.__beam.setSize(bx*pxmmy, by*pxmmz)
            self.__beam.show()
        except:
          pass
    
    def _updateBeam(self, ret):
        logging.info("UPDATE BEAM %s", ret)
        self._bx = float(ret["size_x"])
        self._bshape = ret["shape"]
        self._by = float(ret["size_y"])
        self._drawBeam()

    def updateBeam(self,force=False):
        logging.getLogger().info("updating beam " )

        if self.minidiff is None:
              return

        if self["displayBeam"]:
              if not self.minidiff.isReady(): 
                time.sleep(0.2)
              #beam_x = self.minidiff.getBeamPosX()
              #beam_y = self.minidiff.getBeamPosY()
              try:
                 logging.getLogger().info("self %s" % str(self))
                 self.__rectangularBeam.set_xMid_yMid(self.beam_position[0], self.beam_position[1])
                 logging.getLogger().info("rectangle drawn at position %s " % str(self.beam_position))
                 #self.__rectangularBeam.set_xMid_yMid(beam_x,beam_y)
              except AttributeError:
                 import traceback
                 logging.getLogger().info("update beam failed 1" + traceback.format_exc())
                 pass
              try:
                 self.__beam.move(self.beam_position[0], self.beam_position[1])
                 self._drawBeam()
              except AttributeError:
                logging.getLogger().info("update beam failed 2")
                import traceback
                logging.getLogger().info("update beam failed 2" + traceback.format_exc())
    
    def beamPosChanged(self, position):
        logging.getLogger().info("hutch menu brick. Beam position chagned.  It is %s" % str(position))
        self.beam_position = position
        self.emit(PYSIGNAL("beamPositionChanged"), (self.beam_position[0],\
                                                    self.beam_position[1],
                                                    self.beam_size[0],\
                                                    self.beam_size[1]))
        self.updateBeam(True)

    def beamInfoChanged(self, beam_info):
        logging.getLogger().info("hutch menu brick. Beam info chagned.  It is %s" % str(beam_info))
        self.beam_size = (beam_info["size_x"], beam_info["size_y"])
        self.beam_shape = beam_info["shape"]
        self.updateBeam(True)

    # Zoom changed: update pixels per mm
    def zoomPositionChanged(self,position,offset):
        pxmmy, pxmmz, pxsize_y, pxsize_z = None,None,None,None
        print("** HutchMenuBrick: zoomPositionChanged", position,offset)
        if offset is None:
          # unknown zoom pos.
          try:
            self.__scale.hide()
            self.__rectangularBeam.hide()
            self.__beam.hide()
          except AttributeError:
            print("&&& zoomPositionChanged AttributeError")
            self.__scaleX = None
            self.__scaleY = None
        else:
            if self.minidiff is not None:
                #pxmmy=self.minidiff.pixelsPerMmY
                #pxmmz=self.minidiff.pixelsPerMmZ
                self.pixels_per_mm = self.minidiff.get_pixels_per_mm()
                if self.pixels_per_mm[0] is not None and self.pixels_per_mm[1] is not None:
                     pxsize_y = 1e-3 / self.pixels_per_mm[0]
                     pxsize_z = 1e-3 / self.pixels_per_mm[1]

                try:
                    self.sx(pxsize_y)
                    self.sy(pxsize_z)
                except AttributeError:
                    self.__scaleX = pxsize_y
                    self.__scaleY = pxsize_z
                else:
                    self.emit(PYSIGNAL("calibrationChanged"), (pxsize_y, pxsize_z))
                    self.updateBeam(True)
                    #self._drawBeam()
                    self.__scale.show()
            
    # Slits changed: update beam size
    def slitsPositionChanged(self, *args):
        if self.minidiff is None or self.slitbox is None or self.minidiff.pixelsPerMmY is None or self.minidiff.pixelsPerMmZ is None:
            pass
        else:
            self.updateBeam(force=True)
Ejemplo n.º 8
0
class CameraOffLineImageManagerBrick(BlissWidget):
    def __init__(self, parent, name, **keys):
        BlissWidget.__init__(self, parent, name)
        self.__hMotor = None
        self.__vMotor = None
        self.__motor_pos_save = []
        self.__master_motor = None
        self.__masterPosition2Item = weakref.WeakValueDictionary()
        self.__currentCalib = None
        self.__currentBeamPos = None
        self.__camDecompNPlug = None
        self.mosaicView = None
        self.drawing = None
        self.__saveImageTreeDirName = '.'
        self.__imageMosaicPosition = None
        ####### Property #######
        self.addProperty('horizontal', 'string', '')
        self.addProperty('vertical', 'string', '')
        self.addProperty('save_motors', 'string', '')
        self.addProperty('master_motor', 'string', '')
        self.addProperty('focus_motor', 'string', '')
        self.addProperty('live_camera', 'string', '')
        self.addProperty("formatString", "formatString", "###.##")
        ####### SIGNAL #######
        self.defineSignal("getImage", ())
        self.defineSignal('getView', ())
        self.defineSignal('getMosaicView', ())
        ####### SLOT #######
        self.defineSlot("ChangePixelCalibration", ())
        self.defineSlot("ChangeBeamPosition", ())
        self.defineSlot('setMosaicImageSelected', ())

        self.__widgetTree = self.loadUIFile('CameraOffLineImageManager.ui')
        self.__frame = self.__widgetTree.child('__frame')
        self.__frame.reparent(self, qt.QPoint(0, 0))
        layout = qt.QHBoxLayout(self)
        layout.addWidget(self.__frame)

        snapButton = self.child('__snapShoot')
        iconSet = qt.QIconSet(loadIcon("snapshot.png"))
        snapButton.setIconSet(iconSet)
        qt.QObject.connect(snapButton, qt.SIGNAL('clicked()'), self.__snapCBK)

        liveCheckBox = self.child('__liveCheckBox')
        liveCheckBox.hide()
        qt.QObject.connect(liveCheckBox, qt.SIGNAL('toggled(bool)'),
                           self.__liveOnOff)

        self.__imageList = self.child('__imageList')
        self.__imageList.setSelectionMode(qt.QListView.Extended)
        self.__imageList.setSortColumn(-1)
        self.__popUpMenu = qt.QPopupMenu(self)
        self.__popUpMenu.insertItem('layer up', self.__layerUp)
        self.__popUpMenu.insertItem('layer down', self.__layerDown)
        self.__popUpMenu.insertItem('remove', self.__removeImage)

        self.__popUpMenu.insertSeparator()
        self.__popUpMenu.insertItem('load', self.__loadImageTree)
        self.__popUpMenu.insertItem('save', self.__saveImageTree)

        qt.QObject.connect(
            self.__imageList,
            qt.SIGNAL('rightButtonPressed(QListViewItem*,const QPoint &,int)'),
            self.__popUpDisplay)

    def propertyChanged(self, propertyName, oldValue, newValue):
        if propertyName == 'horizontal':
            if self.__hMotor:
                self.disconnect(self.__hMotor, qt.PYSIGNAL("positionChanged"),
                                self.__hMotorPositionChanged)
            self.__hMotor = self.getHardwareObject(newValue)
            self.connect(self.__hMotor, qt.PYSIGNAL("positionChanged"),
                         self.__hMotorPositionChanged)
            self.connect(self.__hMotor, qt.PYSIGNAL("limitsChanged"),
                         self.__hMotorLimitsChanged)
        elif propertyName == 'vertical':
            if self.__vMotor:
                self.disconnect(self.__vMotor, qt.PYSIGNAL("positionChanged"),
                                self.__vMotorPositionChanged)
            self.__vMotor = self.getHardwareObject(newValue)
            self.connect(self.__vMotor, qt.PYSIGNAL("positionChanged"),
                         self.__vMotorPositionChanged)
            self.connect(self.__vMotor, qt.PYSIGNAL("limitsChanged"),
                         self.__vMotorLimitsChanged)

        elif propertyName == 'save_motors':
            equipment = self.getHardwareObject(newValue)
            self.__motor_pos_save = []
            if equipment:
                try:
                    ho = equipment['motors']
                except KeyError:
                    print equipment.userName(
                    ), 'is not an Equipment : no <motors> section.'
                    return
                for motor in ho.getDevices():
                    self.__motor_pos_save.append(motor)

                #Refresh Tree column
                nbColumn = self.__imageList.columns()
                for columnId in range(1, self.__imageList.columns()):
                    self.__imageList.removeColumn(columnId)
                for motor in self.__motor_pos_save:
                    self.__imageList.addColumn(motor.userName())
        elif propertyName == 'master_motor':
            if self.__master_motor is not None:
                self.__imageList.takeItem(self.__masterControler)
            self.__master_motor = self.getHardwareObject(newValue)
            if self.__master_motor is not None:
                self.__masterControler = qt.QCheckListItem(
                    self.__imageList, self.__master_motor.userName())
                self.__masterControler.setSelectable(False)
                self.__masterControler.setOpen(True)
        elif propertyName == 'focus_motor':
            self.__focus_motor = self.getHardwareObject(newValue)
            moveFocusCheckBox = self.child('__moveFocusCheckBox')
            if self.__focus_motor is not None:
                moveFocusCheckBox.show()
            else:
                moveFocusCheckBox.hide()
        elif propertyName == 'live_camera':
            if self.__camDecompNPlug:
                camera, decomp, _ = self.__camDecompNPlug
                self.disconnect(camera, qt.PYSIGNAL('imageReceived'),
                                decomp.putData)
                self.__camDecompNPlug = None

            camera = self.getHardwareObject(newValue)
            liveCheckBox = self.child('__liveCheckBox')
            if camera is not None:
                decomp = QubStdData2Image()
                plug = _LiveImagePlug(self)
                decomp.plug(plug)

                imageInfo = camera.imageType()
                if imageInfo and imageInfo.type() == 'bayer':
                    imType = decomp.BAYER_RG
                elif imageInfo and imageInfo.type() == 'raw':
                    imType = decomp.RAW
                else:
                    imType = decomp.STANDARD  # JPEG
                decomp.setImageType(imType)

                self.__camDecompNPlug = camera, decomp, plug

                liveCheckBox.show()
            else:
                liveCheckBox.hide()
        elif propertyName == 'formatString':
            self._formatString = self['formatString']

    def ChangePixelCalibration(self, sizeX, sizeY):
        if sizeX is not None and sizeY is not None:
            motorXUnit = self.__hMotor.getProperty('unit')
            if motorXUnit is None: motorXUnit = 1e-3

            motorYUnit = self.__vMotor.getProperty('unit')
            if motorYUnit is None: motorYUnit = 1e-3

            self.__currentCalib = sizeX / motorXUnit, sizeY / motorYUnit

            if self.__camDecompNPlug:
                camera, decomp, plug = self.__camDecompNPlug
                plug.setPixelCalibration(*self.__currentCalib)
        else:
            self.__currentCalib = None

    def ChangeBeamPosition(self, x, y):
        self.__currentBeamPos = x, y
        if self.__camDecompNPlug:
            camera, decomp, plug = self.__camDecompNPlug
            plug.setBeamPosition(*self.__currentBeamPos)

    def setMosaicImageSelected(self, imageSelectedID):
        moveFocusCheckBox = self.child('__moveFocusCheckBox')
        if moveFocusCheckBox.isChecked():
            position = self.__focus_motor.getPosition()

            def _recursfind(item, lookinId):
                while item:
                    if id(item) == lookinId:
                        return item
                    else:
                        returnItem = _recursfind(item.firstChild(), lookinId)
                        if returnItem: return returnItem
                        item = item.nextSibling()

            item = _recursfind(self.__imageList.firstChild(), imageSelectedID)
            try:
                if item and item.focusMotorPosition != position:
                    self.__focus_motor.move(item.focusMotorPosition)
            except AttributeError:
                pass

    def __displayMotorsPositionUnderMouse(self, drawingManager):
        point = drawingManager.mosaicPoints()
        try:
            point = point[0]
            beamY, beamZ = point.refPoint
            YSize, ZSize = point.calibration
            horMotorPos, verMotorPos = point.absPoint
            y, z = point.point
            imageId = point.imageId
        except TypeError:
            return
        movetoy = horMotorPos - (beamY - y) * YSize
        movetoz = verMotorPos - (beamZ - z) * ZSize

        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(
                QubRulerAction.HORIZONTAL, 1, movetoy)
            self.__imageMosaicPosition.setCursorPosition(
                QubRulerAction.VERTICAL, 1, movetoz)
            self.__mouseMotorPosition.setXValue(movetoy)
            self.__mouseMotorPosition.setYValue(movetoz)

    def __hMotorPositionChanged(self, position):
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(
                QubRulerAction.HORIZONTAL, 0, position)
            self.__currentMotorPosition.setXValue(position)

        if self.__camDecompNPlug:
            camera, decomp, plug = self.__camDecompNPlug
            plug.setHMotorPosition(position)

    def __hMotorLimitsChanged(self, limit):
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL, 0,
                                                 *limit)
            self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL, 1,
                                                 *limit)

    def __vMotorPositionChanged(self, position):
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setCursorPosition(
                QubRulerAction.VERTICAL, 0, position)
            self.__currentMotorPosition.setYValue(position)
        if self.__camDecompNPlug:
            camera, decomp, plug = self.__camDecompNPlug
            plug.setVMotorPosition(position)

    def __vMotorLimitsChanged(self, limit):
        if self.__imageMosaicPosition:
            self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL, 0,
                                                 *limit)
            self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL, 1,
                                                 *limit)

    def __getMasterItem(self, position=None):
        if self.__master_motor is not None:
            if position is None:
                position = self.__master_motor.getPosition()
            try:
                master_item = self.__masterPosition2Item[position]
            except KeyError:
                positionString = self._formatString % position
                master_item = _MasterCheckItem(
                    self.__masterControler, 'p_%d (%s)' %
                    (len(self.__masterPosition2Item), positionString))
                self.__masterPosition2Item[position] = master_item
        else:
            master_item = self.__imageList
            position = None
        return master_item, position

    def __snapCBK(self):
        key = {}
        self.emit(qt.PYSIGNAL('getImage'), (key, ))
        image = key.get('image', None)
        if image:
            master_item, position = self.__getMasterItem()
            if self.__focus_motor is not None:
                focusPosition = self.__focus_motor.getPosition()
            else:
                focusPosition = None
            try:
                item = _CheckItem(master_item, 'image', self, image,
                                  self.__currentBeamPos, self.__currentCalib,
                                  self.__hMotor, self.__vMotor,
                                  self.__motor_pos_save, position,
                                  focusPosition)
            except:
                logging.getLogger().error(
                    'CameraOffLineImageManager : Spec not connected')

        else:
            logging.getLogger().error(
                'CameraOffLineImageManager : getImage is not connected to CameraOffLineImageManager!!!'
            )

    def __liveOnOff(self, state):
        camera, decomp, plug = self.__camDecompNPlug
        if state:
            self.connect(camera, qt.PYSIGNAL('imageReceived'), decomp.putData)
            plug.show()
        else:
            self.disconnect(camera, qt.PYSIGNAL('imageReceived'),
                            decomp.putData)
            plug.hide()

    def __saveImageTree(self, i):
        pickleObjects = []
        self.__saveImageRecurse(self.__imageList.firstChild(), pickleObjects)
        if pickleObjects:
            fullpathname = qt.QFileDialog.getSaveFileName(
                self.__saveImageTreeDirName, 'Camera mosaic (*.mosaic)', self,
                'Save mosaic images', "Choose a filename to save under")
            if fullpathname:
                fullpathname = fullpathname.latin1()
                self.__saveImageTreeDirName, fname = os.path.split(
                    fullpathname)
                filename, ext = os.path.splitext(fname)
                fullpathname = os.path.join(self.__saveImageTreeDirName,
                                            '%s.mosaic' % filename)
                pickle.dump(pickleObjects, file(fullpathname, 'w'))
        else:
            errorMess = qt.QErrorMessage(self)
            errorMess.message('Nothing to Save!!!')

    def __loadImageTree(self, i):
        fullpathname = qt.QFileDialog.getOpenFileName(
            self.__saveImageTreeDirName, 'Camera mosaic (*.mosaic)', self,
            'Load mosaic images', "Load a image tree")
        if fullpathname:
            fullpathname = fullpathname.latin1()
            self.__imageList.selectAll(True)
            self.__removeImage(0)
            for saveItem in pickle.load(file(fullpathname)):
                master_item, position = self.__getMasterItem(
                    saveItem.masterPosition)
                _CheckItem(master_item, saveItem, self)

    def __saveImageRecurse(self, item, pickleObjects):
        while item:
            NextItem = item.nextSibling()
            try:
                pickleObjects.append(item.getSavePickleObject())
            except AttributeError:
                pass
            self.__saveImageRecurse(item.firstChild(), pickleObjects)
            item = NextItem

    @_foreachSelectedItems
    def __removeImage(self, item, i):
        try:
            item.parent().takeItem(item)
        except AttributeError:
            self.__imageList.takeItem(item)
        return True

    @_foreachSelectedItems
    def __layerUp(self, item, i):
        item.layerUp()

    @_foreachSelectedItems
    def __layerDown(self, item, i):
        item.layerDown()

    def __popUpDisplay(self, item, point, columnid):
        self.__popUpMenu.exec_loop(point)

    def run(self):
        key = {}
        self.emit(qt.PYSIGNAL('getView'), (key, ))
        try:
            view = key['view']
            drawing = key['drawing']

            self.__snapAction = QubToolButtonAction(name='MosaicSnap',
                                                    iconName='snapshot',
                                                    toolButtonStyle=True,
                                                    place='toolbar',
                                                    group='image',
                                                    autoConnect=True)
            qt.QObject.connect(self.__snapAction, qt.PYSIGNAL('ButtonPressed'),
                               self.__snapCBK)
            view.addAction([self.__snapAction])
        except KeyError:
            logging.getLogger().error(
                'getView is not connected to CameraOffLineImageManager!!!')

        mosaicKey = {}
        self.emit(qt.PYSIGNAL('getMosaicView'), (mosaicKey, ))
        try:
            self.mosaicView = mosaicKey['view']
            self.drawing = mosaicKey['drawing']

            class _openDialog(QubOpenDialogAction):
                def __init__(self, *args, **keys):
                    QubOpenDialogAction.__init__(self, *args, **keys)

                def setCanvas(self, canvas):
                    self.__canvas = canvas

                def _showDialog(self):
                    if self._dialog.exec_loop() == qt.QDialog.Accepted:
                        file_path = self._dialog.selectedFile().ascii()
                        dirName, file_name = os.path.split(file_path)
                        base, ext = os.path.splitext(file_name)
                        QubImageSave.save(
                            os.path.join(dirName, '%s.svg' % base), None,
                            self.__canvas, 1, 'svg', True)

            self.__saveMosaicAction = _openDialog(parent=self,
                                                  label='Save image',
                                                  name="save",
                                                  iconName='save',
                                                  group="admin")
            saveMosaicDialogue = qt.QFileDialog('.', 'Mosaic Images (*.svg)',
                                                self, 'Save mosaic Images',
                                                True)
            saveMosaicDialogue.setMode(saveMosaicDialogue.AnyFile)
            self.__saveMosaicAction.setDialog(saveMosaicDialogue)
            self.__saveMosaicAction.setCanvas(self.drawing.canvas())

            self.__imageMosaicPosition = QubRulerAction(name='Motor Position',
                                                        place='toolbar',
                                                        group='Tools')

            self.__mouseMotorPosition = _MouseOrMotorPosition(
                name='mouse motor position',
                place='statusbar',
                group='info',
                mouseFlag=True)

            self.__currentMotorPosition = _MouseOrMotorPosition(
                name='current motor position', place='statusbar', group='info')

            self.mosaicView.addAction([
                self.__imageMosaicPosition, self.__saveMosaicAction,
                self.__currentMotorPosition, self.__mouseMotorPosition
            ])

            if self.__vMotor is not None:
                self.__imageMosaicPosition.setLabel(
                    QubRulerAction.VERTICAL, 0,
                    self.__vMotor.getMotorMnemonic())
                self.__imageMosaicPosition.setCursorPosition(
                    QubRulerAction.VERTICAL, 0, self.__vMotor.getPosition())
                limits = self.__vMotor.getLimits()
                self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,
                                                     0, *limits)
                self.__imageMosaicPosition.setLimits(QubRulerAction.VERTICAL,
                                                     1, *limits)

                self.__imageMosaicPosition.setLabel(QubRulerAction.VERTICAL, 1,
                                                    '')
                for label in [
                        self.__mouseMotorPosition, self.__currentMotorPosition
                ]:
                    label.setMotyName(self.__vMotor.getMotorMnemonic())
                    label.setYValue(self.__vMotor.getPosition())

            if self.__hMotor is not None:
                self.__imageMosaicPosition.setLabel(
                    QubRulerAction.HORIZONTAL, 0,
                    self.__hMotor.getMotorMnemonic())
                limits = self.__hMotor.getLimits()
                self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,
                                                     0, *limits)
                self.__imageMosaicPosition.setLimits(QubRulerAction.HORIZONTAL,
                                                     1, *limits)

                self.__imageMosaicPosition.setCursorPosition(
                    QubRulerAction.HORIZONTAL, 0, self.__hMotor.getPosition())
                self.__imageMosaicPosition.setLabel(QubRulerAction.HORIZONTAL,
                                                    1, '')

                for label in [
                        self.__mouseMotorPosition, self.__currentMotorPosition
                ]:
                    label.setMotxName(self.__hMotor.getMotorMnemonic())
                    label.setXValue(self.__hMotor.getPosition())

            for ruler in self.__imageMosaicPosition._QubRulerAction__ruler:
                ruler.setZ(99)  # upper layer

            #Add a follow mulot
            class _MouseFollow(_DrawingEventNDrawingMgr):
                def __init__(self, aDrawingMgr, oneShot, **keys):
                    _DrawingEventNDrawingMgr.__init__(self, aDrawingMgr, False)

                def mouseMove(self, x, y):
                    d = self._drawingMgr()
                    if d:
                        d.move(x, y)
                        d.endDraw()

            self.__followPointMouse, _ = QubAddDrawing(
                self.drawing, QubMosaicPointDrawingMgr, QubCanvasTarget)
            self.__followPointMouse.setDrawingEvent(_MouseFollow)
            self.__followPointMouse.setExclusive(False)
            self.__followPointMouse.startDrawing()
            self.__followPointMouse.setEndDrawCallBack(
                self.__displayMotorsPositionUnderMouse)
        except KeyError:
            pass

        if self.__camDecompNPlug:
            camera, decomp, plug = self.__camDecompNPlug
            try:
                plug.addImage()
                try:
                    plug.move(self.__hMotor.getPosition(),
                              self.__vMotor.getPosition())
                except:
                    pass
                else:
                    try:
                        plug.setCalibration(*self.__currentCalib)
                        plug.setBeamPosition(*self.__currentBeamPos)
                    except (AttributeError, TypeError):
                        pass
            except AttributeError:
                liveCheckBox = self.child('__liveCheckBox')
                liveCheckBox.hide()