예제 #1
0
 def __inittoolbar(self):
     """Inicializa la toolbar"""
     self.__boton1 = QToolButton(self.Toolbar)
     self.__boton1.setTextLabel("Abrir fichero")
     iconos = QIconSet()
     iconos.setIconSize(QIconSet.Small, QSize(100, 100))
     iconos.setPixmap(self.__gestortemas.icono_abrir(), QIconSet.Small)
     self.__boton1.setOn(True)
     self.__boton1.setIconSet(iconos)
     self.__boton2 = QToolButton(self.Toolbar)
     self.__boton2.setTextLabel("Guardar en fichero")
     iconos = QIconSet()
     iconos.setIconSize(QIconSet.Small, QSize(100, 100))
     iconos.setPixmap(self.__gestortemas.icono_guardar(), QIconSet.Small)
     self.__boton2.setOn(True)
     self.__boton2.setIconSet(iconos)
     self.__boton3 = QToolButton(self.Toolbar)
     self.__boton3.setTextLabel("Exportar a html")
     iconos = QIconSet()
     iconos.setIconSize(QIconSet.Small, QSize(100, 100))
     iconos.setPixmap(self.__gestortemas.icono_exportar(), QIconSet.Small)
     self.__boton3.setOn(True)
     self.__boton3.setIconSet(iconos)
     self.__boton4 = QToolButton(self.Toolbar)
     self.__boton4.setTextLabel("Mostrar Ventana principal")
     iconos = QIconSet()
     iconos.setIconSize(QIconSet.Small, QSize(100, 100))
     iconos.setPixmap(self.__gestortemas.icono_nueva_ventana(), QIconSet.Small)
     self.__boton4.setOn(True)
     self.__boton4.setIconSet(iconos)
예제 #2
0
    def __init_toolbar(self):
        """Inicializa la toolbar"""
        self.__boton1 = QToolButton(self.Toolbar)
        self.__boton1.setTextLabel("ABRIR")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_abrir(), QIconSet.Small)
#        iconos.setPixmap("images/flechaabajo.png", QIconSet.Automatic, QIconSet.Normal, QIconSet.Off)
        self.__boton1.setOn(True)
        self.__boton1.setIconSet(iconos)
        self.__boton2 = QToolButton(self.Toolbar)
        self.__boton2.setTextLabel("GUARDAR")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_guardar(), QIconSet.Small)
        self.__boton2.setOn(True)
        self.__boton2.setIconSet(iconos)
        self.__boton3 = QToolButton(self.Toolbar)
        self.__boton3.setTextLabel("Ventana Salida")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_nueva_ventana(), QIconSet.Small)
        self.__boton3.setOn(True)
        self.__boton3.setIconSet(iconos)
        self.__boton4 = QToolButton(self.Toolbar)
        self.__boton4.setTextLabel("Mostrar etiquetas")
        self.__boton4.setToggleButton(True)
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_etiquetas(), QIconSet.Small)
        self.__boton4.setIconSet(iconos)
예제 #3
0
class VPrincipal(vprincipal):
    """Ventana principal, hereda de vprincipal, que esta generado por el designer.
    Esta clase es padre de la mayoria de los dialogos, y es la que permite introducir los datos a el usuario"""



    def __init__(self, parent, config, portero, idu, gestorproyectos, gestortemas, gestoroperaciones): 
        """Inicializador de la ventana principal"""
        vprincipal.__init__(self, None)
        #VARIABLES PUBLICAS
        self.parent = parent
        self.__config = config
        self.__gestortemas = gestortemas
        self.__idu = idu
        #Bloque de inicialización de dialogos
        self.__dbuscar = DBuscar(self, "busqueda")
        self.__dconfig = DConfig(config, self)
        self.__dfiltro = DFiltrado(self, self.__idu)
        self.__dayuda = DAyuda(self)
        self.__portero = portero
        self.__gestorproyectos = gestorproyectos
        self.grid = Grid(self, self.__idu, self.__portero)
        self.widgetStack1.addWidget(self.grid)
        self.widgetStack1.raiseWidget(self.grid)

        # Funciones de inicializacion de componentes
        self.__init_toolbar()
        self.mostrar_undo_redo()

        self.setIcon(self.__gestortemas.icono_programa())
        self.__diccionarioarbolmenu = {}
        self.__diccionarioacciones = {}
        self.__colectorfunciones = []
        listalistasetiquetas = [operacion.etiquetas for operacion in gestoroperaciones.values()]
        from Driza import categorias
        arbol = categorias.conv_categorias_arbol("Raiz", listalistasetiquetas)
        self.__conv_arbol_menu(self.Analizar, arbol, self.__diccionarioarbolmenu)
        listaelementosmenu =  self.__lista_etiquetas_menu(self.__diccionarioarbolmenu, [])
        from sets import Set
        for operacion in gestoroperaciones.values():
            for elementofinal in listaelementosmenu:
                if Set(operacion.etiquetas) == Set(elementofinal[1]):
                    accion = QAction(self, "")
                    accion.setText(unicode(operacion.nombre))
                    accion.addTo(elementofinal[0])
                    self.__diccionarioacciones[operacion.nombre] = accion
        self.__atajos()


    #FUNCIONES PUBLICAS
    
    def abrir_proyecto(self, parent = None, filename = None):
        """ Lanza el diálogo de apertura de fichero """
        from Driza.excepciones import FicheroNoExisteException, FicheroErroneoException, FicheroTipoDesconocidoException
        if not parent: 
            parent = self
        if not self.__dproyecto_modificado(): 
            return
        if not filename:
            filtro = ""
            for fmt in SL.extensiones_fichero:
                filtro = filtro + "%s files (*.%s);;" % (fmt, fmt.lower())
            filename = QFileDialog.getOpenFileName(QString.null, filtro, self, None, "Dialogo abrir fichero", "")
            filename = str(filename)
        if filename:
            try:
                self.__gestorproyectos.cargar(filename)
            except FicheroErroneoException:
                QMessageBox.warning(parent, u'Atención', 'El fichero no ha podido ser leido')
            except FicheroTipoDesconocidoException:
                QMessageBox.warning(parent, u'Atención', 'El fichero no ha podido ser leido')
            except FicheroNoExisteException:
                QMessageBox.warning(parent, u'Atención', 'El fichero no ha podido ser leido')
            except AttributeError:
                QErrorMessage(parent, "Error").message(u"Parece que ha intentado cargar un fichero de una versión anterior. Lo siento")
                LOG.exception("excepcion capturada")
            else:
                self.__myUpdate()
                self.grid.myUpdate()
                return True
        return False

    def __myUpdate(self):
        """Acciones de actualizacion"""
        from Driza import VERSION
        if self.__gestorproyectos.fichero:
            nfichero = self.__gestorproyectos.fichero
        else:
            nfichero = "Nuevo fichero"
        self.setCaption("Driza " + VERSION + " - " + nfichero)

    def showEvent(self, event):
        self.__myUpdate()
        vprincipal.showEvent(self, event)

    def closeEvent(self, event):
        """Acciones que se realizaran cuando el usuario cierre la ventana. Guarda el estado de la configuración,
        incluyendo los ficheros recientemente abiertos"""
        if not self.__dproyecto_modificado(): 
            return
        QWidget.closeEvent(self, event)
        if not self.parent.vsalida.isVisible():
            self.__config.guardar()
            qApp.exit(0)
        else:
            self.hide()
    
    def mostrar_undo_redo(self):
        """Determina que botones estan activados y cuales no del submenu de edición"""
        if self.__portero.puedo_undo():
            self.editUndoAction.setEnabled(True)
        else:
            self.editUndoAction.setEnabled(False)

        if self.__portero.puedo_redo():
            self.editRedoAction.setEnabled(True)
        else:
            self.editRedoAction.setEnabled(False)

    #FUNCIONES PRIVADAS

    def __importar(self):
        """Importa los datos de un fichero"""
        if not self.__dproyecto_modificado(): 
            return
        self.parent.dimportartexto.show()

    def __dproyecto_modificado(self):
        """Pregunta en caso de que haya sido modificado el proyecto si desea ser guardado"""
        if not self.__idu.original():
            returncode = QMessageBox.information(self, 'Atencion:', 'El proyecto actual ha sido modificado, desea guardarlo?', 'Guardarlo', 'No guardarlo', 'Volver', 0, 1)
            if returncode == 0:
                self.__guardar()
            elif returncode == 2:
                return False
        return True


    def __dacerca_de(self):
        """Mensaje acerca de"""
        from Driza import VERSION
        separador = "\n----------------------------------\n"
        betatesters = u"Carlos Mestre Gonzalez\n Luis de Bethencourt Guimerá"
        iconos = "Iconos del Tango Desktop Project: http://tango.freedesktop.org/"
        ristra = u"Driza %s es una interfaz estadística\n (C) Néstor Arocha Rodríguez - Tutorizado por Inmaculada luengo Merino\n Distribuido bajo licencia GPL" +\
                separador + "Betatesters:\n" + betatesters + separador +\
                u" Mantenedor del paquete .deb:\n Luis de Bethencourt Guimerá"+ separador + iconos
        QMessageBox.about(self, "Acerca de Driza", ristra % (VERSION))
    
    def __undo(self):
        """Deshace el último cambio"""
        self.__portero.undo()
        self.grid.myUpdate()
        self.mostrar_undo_redo()
    
    def __redo(self):
        """Rehace el último cambio"""
        self.__portero.redo()
        self.grid.myUpdate()
        self.mostrar_undo_redo()

    def __init_toolbar(self):
        """Inicializa la toolbar"""
        self.__boton1 = QToolButton(self.Toolbar)
        self.__boton1.setTextLabel("ABRIR")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_abrir(), QIconSet.Small)
#        iconos.setPixmap("images/flechaabajo.png", QIconSet.Automatic, QIconSet.Normal, QIconSet.Off)
        self.__boton1.setOn(True)
        self.__boton1.setIconSet(iconos)
        self.__boton2 = QToolButton(self.Toolbar)
        self.__boton2.setTextLabel("GUARDAR")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_guardar(), QIconSet.Small)
        self.__boton2.setOn(True)
        self.__boton2.setIconSet(iconos)
        self.__boton3 = QToolButton(self.Toolbar)
        self.__boton3.setTextLabel("Ventana Salida")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_nueva_ventana(), QIconSet.Small)
        self.__boton3.setOn(True)
        self.__boton3.setIconSet(iconos)
        self.__boton4 = QToolButton(self.Toolbar)
        self.__boton4.setTextLabel("Mostrar etiquetas")
        self.__boton4.setToggleButton(True)
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_etiquetas(), QIconSet.Small)
        self.__boton4.setIconSet(iconos)

    def conexiones(self):
        """Funcion llamada en el constructor que almacena todas las conexiones accion-funcion"""
        self.connect(self.archivoSalirAction, SIGNAL("activated()"), self.__salir_programa)
        self.connect(self.fileNewAction, SIGNAL("activated()"), self.__nuevo)
        self.connect(self.fileOpenAction, SIGNAL("activated()"), self.abrir_proyecto)
        self.connect(self.fileSaveAsAction, SIGNAL("activated()"), self.__guardar_como)
        self.connect(self.fileSaveAction, SIGNAL("activated()"), self.__guardar)
        self.connect(self.archivoImportarAction, SIGNAL("activated()"), self.__importar)
        self.connect(self.archivoConfiguracinAction, SIGNAL("activated()"), self.__dconfig.show)
        self.connect(self.datosFiltrarAction, SIGNAL("activated()"), self.__dfiltro.show)
        self.connect(self.modificarCrear_nuevas_variablesAction, SIGNAL("activated()"), self.parent.dcrevar.show)
        self.connect(self.editFindAction, SIGNAL("activated()"), self.__dbuscar.show)
        self.connect(self.editCopyAction, SIGNAL("activated()"), self.__copiar)
        self.connect(self.editCutAction, SIGNAL("activated()"), self.__cortar)
        self.connect(self.editPasteAction, SIGNAL("activated()"), self.__pegar)
        self.connect(self.editUndoAction, SIGNAL("activated()"), self.__undo)
        self.connect(self.editRedoAction, SIGNAL("activated()"), self.__redo)
        self.connect(self.edicinBorrarAction, SIGNAL("activated()"), self.__borrar)
        self.connect(self.edicinInsertarAction, SIGNAL("activated()"), self.__insertar_registro)
        self.connect(self.acerca_deAcerca_deAction, SIGNAL("activated()"), self.__dacerca_de)
        self.connect(self.__boton1, SIGNAL("clicked()"), self.abrir_proyecto)
        self.connect(self.__boton2, SIGNAL("clicked()"), self.__guardar)
        self.connect(self.__boton3, SIGNAL("clicked()"), self.parent.vsalida.show)
        self.connect(self.__boton4, SIGNAL("clicked()"), self.__alternar_etiquetas)
        self.connect(self.ayudaAyudaAction, SIGNAL("activated()"), self.__mostrar_dayuda)
        self.connect(self.PopupMenuEditor_3, SIGNAL("aboutToShow()"), self.__actualizar_recientes)
        for (key, valor) in self.__diccionarioacciones.items():
            self.__colectorfunciones.append(lambda k=key: self.parent.doperaciones.mostrar(k))
            self.connect(valor, SIGNAL("activated()"), self.__colectorfunciones[-1])

    def __atajos(self):
        """Establece los atajos"""
        self.ayudaAyudaAction.setAccel("F1")
        self.acciontab1 = QAction(self, "tabcasos")
        self.connect(self.acciontab1, SIGNAL("activated()"), self.grid.mostrar_t_reg)
        self.acciontab1.setAccel("F2")
        self.acciontab2 = QAction(self, "tabvars")
        self.connect(self.acciontab2, SIGNAL("activated()"), self.grid.mostrar_t_var)
        self.acciontab2.setAccel("F3")
        if self.__diccionarioacciones.has_key("Descriptivo"):
            self.__diccionarioacciones["Descriptivo"].setAccel("F4")
        self.__boton3.setAccel("F5") #Ventana salida
        self.archivoConfiguracinAction.setAccel("F10")
        self.acerca_deAcerca_deAction.setAccel("F12")
        self.archivoSalirAction.setAccel("Ctrl+Q")

    def __copiar(self):
        """Funcion que copia y borra la seleccion"""
        try:
            self.__copiar_privado()
        except AssertionError:
            QMessageBox.warning(self, u'Atención', 'Las operaciones de copiado, cortado y pegado no han sido implementadas')
        else:
            self.grid.borrar_seleccion() 

   #http://www.google.com/codesearch?hl=en&q=+%22qtable%22+%22cut%22+%22paste%22+show:z9otKZeV6U8:R6dK3Cx-dYg:Gh37-3Ie27E&sa=N&cd=48&ct=rc&cs_p=http://mde.abo.fi/confluence/download/attachments/1011/coral-0.9.1.tar.gz&cs_f=coral-0.9.1/coral/modeler/property/propertyeditor.py#a0 
    def __cortar(self):
        """Copia, borra la seleccion y su contenido"""
        from Driza.excepciones import SeleccionIncorrectaException
        try:
            self.grid.verificar_seleccion_registros()
            self.__portero.guardar_estado()
            self.__copiar_privado()
        except SeleccionIncorrectaException:
            QMessageBox.warning(self, u'Atención', 'Solo se permite cortar registros')
        except AssertionError:
            QMessageBox.warning(self, u'Atención', 'Las operaciones de copiado, cortado y pegado no han sido implementadas')
        else:
            self.grid.borrar_seleccion(borrardatos=True)
            self.grid.myUpdate()


    def __pegar(self):
        """Funcion que envuelve a __pegar recogiendo sus excepciones"""
        #TODO Capturar otras excepciones
        try:
            self.__pegar_privado()
        except AssertionError:
            QErrorMessage(self, "Error").message(u"Error desconocido")
            LOG.exception("excepcion capturada en el pegado")


    def __pegar_privado(self):
        """Pega lo que haya sido copiado"""
        clipboard = QApplication.clipboard()
        registro = clipboard.text().latin1()
        lista = eval(registro)
        posrow = self.grid.table1.currentRow()
        poscol = self.grid.table1.currentColumn()
        if len(lista[0]) == self.__idu.n_var():
            poscol = 0 #Copia de registro completo
        else:
            #No permitimos pegar si el pegado implica variables nuevas
            assert(poscol + len(lista[0]) <= self.__idu.n_var())
        self.__portero.guardar_estado() #Guardamos el estado

        #Creamos nuevos registros hasta la posicion del cursor
        if posrow > self.__idu.n_reg():
            for _ in range(self.__idu.n_reg(), posrow):
                self.__idu.ana_reg()
        #Hacemos el pegado efectivo
        i = posrow
        for registro in lista:
            if i >= self.__idu.n_reg(): 
                self.__idu.ana_reg()
            j = poscol
            for campo in registro:
                if campo != None:
                    self.__idu[i][j] = campo
                j += 1
            i += 1
        self.grid.myUpdate()

    def __salir_programa(self):
        """Funcion de salida del programa. Guarda la configuracion"""
        if not self.__dproyecto_modificado(): 
            return
        self.__config.guardar()
        qApp.exit(0)


    def __nuevo(self):
        """Accion realizada cuando el usuario clickea en Nuevo"""
        if not self.__dproyecto_modificado(): 
            return
        self.__idu.borrar_todo()
        self.__gestorproyectos.fichero = None
        self.__myUpdate()
        self.grid.myUpdate()


    
    def __guardar(self):
        """Funcion de guardado del fichero. Si el fichero no es conocido se llama a guardarcomo"""
        if self.__gestorproyectos.fichero:
            self.__gestorproyectos.guardar(sobreescribir = True)
            self.__idu.establecer_original()
        else:
            self.__guardar_como()

    def __guardar_como(self):
        """Abre un diálogo pidiendo el nombre de archivo y guarda en dicho archivo"""
        filtro = ""
        for fmt in SL.extensiones_fichero:
            filtro = filtro+ "%s files (*.%s);;" % (fmt, fmt.lower())
        filename = QFileDialog.getSaveFileName(QString.null, filtro, self)
        filename = str(filename)
        if filename:
            from Driza.excepciones import FicheroExisteException, FicheroTipoDesconocidoException
            import re
            extension = re.compile('.*\..*')
            if not extension.match(filename):
                filename += ".driza"
            try:
                self.__gestorproyectos.guardar(filename)
            except FicheroExisteException, fichero:
                returncode = QMessageBox.information(self, 'Atencion:', 'El fichero' + fichero.fichero + ' ya existe' , 'Sobreescribir', 'Otro nombre', 'Cancelar', 0, 1)
                if returncode == 0:
                    self.__gestorproyectos.guardar(filename, True)
                    self.__idu.establecer_original()
                    self.__myUpdate()
                elif returncode == 1:
                    self.__guardarcomo()
            except FicheroTipoDesconocidoException:
                QMessageBox.warning(self, u'Atención', u'La extensión del fichero es incorrecta.\nPruebe con otra extensión')
                self.__gestorproyectos.fichero = None
            else:
    def setupPanel(self, parentWidget):
        logging.debug('ProstateTRUSNavUltrasound.setupPanel')

        self.connectorNode = self.guideletParent.connectorNode
        self.connectorNodeConnected = False

        collapsibleButton = ctkCollapsibleButton()
        collapsibleButton.setProperty('collapsedHeight', 20)
        setButtonStyle(collapsibleButton, 2.0)
        collapsibleButton.text = "Ultrasound"
        parentWidget.addWidget(collapsibleButton)

        ultrasoundLayout = QFormLayout(collapsibleButton)
        ultrasoundLayout.setContentsMargins(12, 4, 4, 4)
        ultrasoundLayout.setSpacing(4)

        self.connectDisconnectButton = QPushButton("Connect")
        self.connectDisconnectButton.setToolTip(
            "If clicked, connection OpenIGTLink")

        hbox = QHBoxLayout()
        hbox.addWidget(self.connectDisconnectButton)
        ultrasoundLayout.addRow(hbox)

        self.setupIcons()

        self.captureIDSelector = QComboBox()
        self.captureIDSelector.setToolTip("Pick capture device ID")
        self.captureIDSelector.setSizePolicy(QSizePolicy.Expanding,
                                             QSizePolicy.Expanding)

        self.volumeReconstructorIDSelector = QComboBox()
        self.volumeReconstructorIDSelector.setToolTip(
            "Pick volume reconstructor device ID")
        self.volumeReconstructorIDSelector.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.startStopRecordingButton = QPushButton("  Start Recording")
        self.startStopRecordingButton.setCheckable(True)
        self.startStopRecordingButton.setIcon(self.recordIcon)
        self.startStopRecordingButton.setEnabled(False)
        self.startStopRecordingButton.setToolTip("If clicked, start recording")
        self.startStopRecordingButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        recordParametersControlsLayout = QGridLayout()

        self.filenameLabel = self.createLabel("Filename:", visible=False)
        recordParametersControlsLayout.addWidget(self.filenameLabel, 1, 0)

        # Offline Reconstruction
        self.offlineReconstructButton = QPushButton("  Offline Reconstruction")
        self.offlineReconstructButton.setCheckable(True)
        self.offlineReconstructButton.setIcon(self.recordIcon)
        self.offlineReconstructButton.setEnabled(False)
        self.offlineReconstructButton.setToolTip(
            "If clicked, reconstruct recorded volume")
        self.offlineReconstructButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        self.offlineVolumeToReconstructSelector = QComboBox()
        self.offlineVolumeToReconstructSelector.setEditable(True)
        self.offlineVolumeToReconstructSelector.setToolTip(
            "Pick/set volume to reconstruct")
        self.offlineVolumeToReconstructSelector.visible = False

        hbox = QHBoxLayout()
        hbox.addWidget(self.startStopRecordingButton)
        hbox.addWidget(self.offlineReconstructButton)
        ultrasoundLayout.addRow(hbox)

        # Scout scan (record and low resolution reconstruction) and live reconstruction
        # Scout scan part

        self.startStopScoutScanButton = QPushButton(
            "  Scout scan\n  Start recording")
        self.startStopScoutScanButton.setCheckable(True)
        self.startStopScoutScanButton.setIcon(self.recordIcon)
        self.startStopScoutScanButton.setToolTip("If clicked, start recording")
        self.startStopScoutScanButton.setEnabled(False)
        self.startStopScoutScanButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        self.startStopLiveReconstructionButton = QPushButton(
            "  Start live reconstruction")
        self.startStopLiveReconstructionButton.setCheckable(True)
        self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
        self.startStopLiveReconstructionButton.setToolTip(
            "If clicked, start live reconstruction")
        self.startStopLiveReconstructionButton.setEnabled(False)
        self.startStopLiveReconstructionButton.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.displayRoiButton = QToolButton()
        self.displayRoiButton.setCheckable(True)
        self.displayRoiButton.setIcon(self.visibleOffIcon)
        self.displayRoiButton.setToolTip("If clicked, display ROI")

        hbox = QHBoxLayout()
        hbox.addWidget(self.startStopScoutScanButton)
        hbox.addWidget(self.startStopLiveReconstructionButton)
        # hbox.addWidget(self.displayRoiButton)
        ultrasoundLayout.addRow(hbox)

        self.snapshotTimer = QTimer()
        self.snapshotTimer.setSingleShot(True)

        self.onParameterSetSelected()

        return collapsibleButton
class ProstateTRUSNavUltrasound(UltraSound):

    OFFLINE_VOLUME_FILENAME = "RecVol_Reference.mha"
    SCOUT_VOLUME_FILENAME = "ScoutScan.mha"
    LIVE_VOLUME_FILENAME = "LiveReconstructedVolume.mha"

    RECORDING_FILENAME = "Recording.mha"
    SCOUT_RECORDING_FILENAME = "ScoutScanRecording.mha"
    LIVE_RECORDING_FILENAME = LIVE_VOLUME_FILENAME

    SCOUT_VOLUME_NODE_NAME = "ScoutScan"
    OFFLINE_VOLUME_NODE_NAME = "RecVol_Reference"
    LIVE_VOLUME_NODE_NAME = "liveReconstruction"

    APPLY_HOLE_FILLING_FOR_SNAPSHOT = False
    SNAPSHOT_INTERVAL = 3
    OUTPUT_VOLUME_SPACING = 3
    LIVE_OUTPUT_VOLUME_SPACING = 1

    @property
    def roiNode(self):
        return self._roiNode

    @roiNode.setter
    def roiNode(self, node):
        self._roiNode = node
        if node is not None:
            self.startStopLiveReconstructionButton.setEnabled(True)
        else:
            self.startStopLiveReconstructionButton.setEnabled(False)

    def __init__(self, guideletParent):
        UltraSound.__init__(self, guideletParent)

        self.parameterNode = guideletParent.parameterNode
        self.parameterNodeObserver = None
        self._roiNode = None
        self.liveOutputSpacingValue = [
            self.LIVE_OUTPUT_VOLUME_SPACING, self.LIVE_OUTPUT_VOLUME_SPACING,
            self.LIVE_OUTPUT_VOLUME_SPACING
        ]
        self.outputSpacing = [
            self.OUTPUT_VOLUME_SPACING, self.OUTPUT_VOLUME_SPACING,
            self.OUTPUT_VOLUME_SPACING
        ]
        self.roiOrigin = None
        self.roiExtent = None
        self.defaultParameterNode = None
        self.logic = ProstateTRUSNavUltrasoundLogic()

    def setupPanel(self, parentWidget):
        logging.debug('ProstateTRUSNavUltrasound.setupPanel')

        self.connectorNode = self.guideletParent.connectorNode
        self.connectorNodeConnected = False

        collapsibleButton = ctkCollapsibleButton()
        collapsibleButton.setProperty('collapsedHeight', 20)
        setButtonStyle(collapsibleButton, 2.0)
        collapsibleButton.text = "Ultrasound"
        parentWidget.addWidget(collapsibleButton)

        ultrasoundLayout = QFormLayout(collapsibleButton)
        ultrasoundLayout.setContentsMargins(12, 4, 4, 4)
        ultrasoundLayout.setSpacing(4)

        self.connectDisconnectButton = QPushButton("Connect")
        self.connectDisconnectButton.setToolTip(
            "If clicked, connection OpenIGTLink")

        hbox = QHBoxLayout()
        hbox.addWidget(self.connectDisconnectButton)
        ultrasoundLayout.addRow(hbox)

        self.setupIcons()

        self.captureIDSelector = QComboBox()
        self.captureIDSelector.setToolTip("Pick capture device ID")
        self.captureIDSelector.setSizePolicy(QSizePolicy.Expanding,
                                             QSizePolicy.Expanding)

        self.volumeReconstructorIDSelector = QComboBox()
        self.volumeReconstructorIDSelector.setToolTip(
            "Pick volume reconstructor device ID")
        self.volumeReconstructorIDSelector.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.startStopRecordingButton = QPushButton("  Start Recording")
        self.startStopRecordingButton.setCheckable(True)
        self.startStopRecordingButton.setIcon(self.recordIcon)
        self.startStopRecordingButton.setEnabled(False)
        self.startStopRecordingButton.setToolTip("If clicked, start recording")
        self.startStopRecordingButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        recordParametersControlsLayout = QGridLayout()

        self.filenameLabel = self.createLabel("Filename:", visible=False)
        recordParametersControlsLayout.addWidget(self.filenameLabel, 1, 0)

        # Offline Reconstruction
        self.offlineReconstructButton = QPushButton("  Offline Reconstruction")
        self.offlineReconstructButton.setCheckable(True)
        self.offlineReconstructButton.setIcon(self.recordIcon)
        self.offlineReconstructButton.setEnabled(False)
        self.offlineReconstructButton.setToolTip(
            "If clicked, reconstruct recorded volume")
        self.offlineReconstructButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        self.offlineVolumeToReconstructSelector = QComboBox()
        self.offlineVolumeToReconstructSelector.setEditable(True)
        self.offlineVolumeToReconstructSelector.setToolTip(
            "Pick/set volume to reconstruct")
        self.offlineVolumeToReconstructSelector.visible = False

        hbox = QHBoxLayout()
        hbox.addWidget(self.startStopRecordingButton)
        hbox.addWidget(self.offlineReconstructButton)
        ultrasoundLayout.addRow(hbox)

        # Scout scan (record and low resolution reconstruction) and live reconstruction
        # Scout scan part

        self.startStopScoutScanButton = QPushButton(
            "  Scout scan\n  Start recording")
        self.startStopScoutScanButton.setCheckable(True)
        self.startStopScoutScanButton.setIcon(self.recordIcon)
        self.startStopScoutScanButton.setToolTip("If clicked, start recording")
        self.startStopScoutScanButton.setEnabled(False)
        self.startStopScoutScanButton.setSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)

        self.startStopLiveReconstructionButton = QPushButton(
            "  Start live reconstruction")
        self.startStopLiveReconstructionButton.setCheckable(True)
        self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
        self.startStopLiveReconstructionButton.setToolTip(
            "If clicked, start live reconstruction")
        self.startStopLiveReconstructionButton.setEnabled(False)
        self.startStopLiveReconstructionButton.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.displayRoiButton = QToolButton()
        self.displayRoiButton.setCheckable(True)
        self.displayRoiButton.setIcon(self.visibleOffIcon)
        self.displayRoiButton.setToolTip("If clicked, display ROI")

        hbox = QHBoxLayout()
        hbox.addWidget(self.startStopScoutScanButton)
        hbox.addWidget(self.startStopLiveReconstructionButton)
        # hbox.addWidget(self.displayRoiButton)
        ultrasoundLayout.addRow(hbox)

        self.snapshotTimer = QTimer()
        self.snapshotTimer.setSingleShot(True)

        self.onParameterSetSelected()

        return collapsibleButton

    def setupResliceDriver(self):
        layoutManager = slicer.app.layoutManager()
        # Show ultrasound in red view.
        redSlice = layoutManager.sliceWidget('Red')
        redSliceLogic = redSlice.sliceLogic()
        redSliceLogic.GetSliceCompositeNode().SetBackgroundVolumeID(
            self.liveUltrasoundNode_Reference.GetID())

        resliceLogic = slicer.modules.volumereslicedriver.logic()
        if resliceLogic:
            redNode = slicer.util.getNode('vtkMRMLSliceNodeRed')
            redNode.SetSliceResolutionMode(
                slicer.vtkMRMLSliceNode.SliceResolutionMatchVolumes)
            resliceLogic.SetDriverForSlice(
                self.liveUltrasoundNode_Reference.GetID(), redNode)
            resliceLogic.SetModeForSlice(
                6, redNode)  # Transverse mode, default for PLUS ultrasound.
        else:
            logging.warning('Logic not found for Volume Reslice Driver')

    def createCollapsibleButton(self, text, collapsed=False):
        collapsibleButton = ctkCollapsibleButton()
        collapsibleButton.text = text
        collapsibleButton.collapsed = collapsed
        return collapsibleButton

    def createLabel(self, text, visible=True):
        label = QLabel()
        label.setText(text)
        label.visible = visible
        return label

    def setupConnections(self):
        self.startStopRecordingButton.connect(
            'clicked(bool)', self.onStartStopRecordingButtonClicked)
        self.offlineReconstructButton.connect('clicked(bool)',
                                              self.onReconstVolume)
        self.startStopScoutScanButton.connect(
            'clicked(bool)', self.onStartStopScoutScanButtonClicked)
        self.startStopLiveReconstructionButton.connect(
            'clicked(bool)', self.onStartStopLiveReconstructionButtonClicked)
        self.displayRoiButton.connect('clicked(bool)',
                                      self.onDisplayRoiButtonClicked)
        self.captureIDSelector.connect('currentIndexChanged(QString)',
                                       self.updateParameterNodeFromGui)
        self.volumeReconstructorIDSelector.connect(
            'currentIndexChanged(QString)', self.updateParameterNodeFromGui)
        self.offlineVolumeToReconstructSelector.connect(
            'currentIndexChanged(int)', self.updateParameterNodeFromGui)
        self.displayRoiButton.connect('clicked(bool)',
                                      self.updateParameterNodeFromGui)
        self.snapshotTimer.timeout.connect(
            self.onRequestVolumeReconstructionSnapshot)
        self.connectDisconnectButton.connect(
            'clicked(bool)', self.onConnectDisconnectButtonClicked)

    def disconnect(self):
        self.startStopRecordingButton.disconnect(
            'clicked(bool)', self.onStartStopRecordingButtonClicked)
        self.offlineReconstructButton.disconnect('clicked(bool)',
                                                 self.onReconstVolume)
        self.startStopScoutScanButton.disconnect(
            'clicked(bool)', self.onStartStopScoutScanButtonClicked)
        self.startStopLiveReconstructionButton.disconnect(
            'clicked(bool)', self.onStartStopLiveReconstructionButtonClicked)
        self.displayRoiButton.disconnect('clicked(bool)',
                                         self.onDisplayRoiButtonClicked)
        self.captureIDSelector.disconnect('currentIndexChanged(QString)',
                                          self.updateParameterNodeFromGui)
        self.volumeReconstructorIDSelector.disconnect(
            'currentIndexChanged(QString)', self.updateParameterNodeFromGui)
        self.offlineVolumeToReconstructSelector.disconnect(
            'currentIndexChanged(int)', self.updateParameterNodeFromGui)
        self.displayRoiButton.disconnect('clicked(bool)',
                                         self.updateParameterNodeFromGui)
        self.snapshotTimer.timeout.disconnect(
            self.onRequestVolumeReconstructionSnapshot)
        self.connectDisconnectButton.disconnect(
            'clicked(bool)', self.onConnectDisconnectButtonClicked)

    def setupIcons(self):
        self.plusRemoteModuleDirectoryPath = slicer.modules.plusremote.path.replace(
            "PlusRemote.py", "")
        self.recordIcon = QIcon(self.plusRemoteModuleDirectoryPath +
                                '/Resources/Icons/icon_Record.png')
        self.stopIcon = QIcon(self.plusRemoteModuleDirectoryPath +
                              '/Resources/Icons/icon_Stop.png')
        self.waitIcon = QIcon(self.plusRemoteModuleDirectoryPath +
                              '/Resources/Icons/icon_Wait.png')
        self.visibleOffIcon = QIcon(":Icons\VisibleOff.png")
        self.visibleOnIcon = QIcon(":Icons\VisibleOn.png")

    def onParameterSetSelected(self):
        # Set up default values for new nodes
        if self.parameterNode:
            self.plusRemoteLogic.setDefaultParameters(self.parameterNode)
        self.updateGuiFromParameterNode()

    def updateGuiFromParameterNode(self):

        self.parameterVolumeList = {
            'OfflineVolumeToReconstruct':
            self.offlineVolumeToReconstructSelector
        }
        for parameter in self.parameterVolumeList:
            if self.parameterNode.GetParameter(parameter):
                self.parameterVolumeList[parameter].blockSignals(True)
            self.parameterVolumeList[parameter].blockSignals(False)

        if self.parameterNode.GetParameter('CaptureID'):
            self.captureIDSelector.blockSignals(True)
            for i in range(0, self.captureIDSelector.count):
                if self.parameterNode.GetParameter(
                        'CaptureID') == self.captureIDSelector.itemText(i):
                    self.captureIDSelector.setCurrentIndex(
                        int(self.parameterNode.GetParameter('CaptureIdIndex')))
            self.captureIDSelector.blockSignals(False)

        if self.parameterNode.GetParameter('VolumeReconstructor'):
            self.volumeReconstructorIDSelector.blockSignals(True)
            for i in range(0, self.volumeReconstructorIDSelector.count):
                if self.parameterNode.GetParameter(
                        'VolumeReconstructor'
                ) == self.volumeReconstructorIDSelector.itemText(i):
                    self.volumeReconstructorIDSelector.setCurrentIndex(
                        int(
                            self.parameterNode.GetParameter(
                                'VolumeReconstructorIndex')))
            self.volumeReconstructorIDSelector.blockSignals(False)

            self.roiNode = self.parameterNode.GetNthNodeReference('ROI', 0)

    def updateParameterNodeFromGui(self):
        #Update parameter node value to save when user change value in the interface
        if not self.parameterNode:
            return
        self.parametersList = {
            'CaptureID':
            self.captureIDSelector.currentText,
            'CaptureIdIndex':
            self.captureIDSelector.currentIndex,
            'VolumeReconstructor':
            self.volumeReconstructorIDSelector.currentText,
            'VolumeReconstructorIndex':
            self.volumeReconstructorIDSelector.currentIndex,
            'OfflineVolumeToReconstruct':
            self.offlineVolumeToReconstructSelector.currentIndex
        }
        for parameter in self.parametersList:
            self.parameterNode.SetParameter(
                parameter, str(self.parametersList[parameter]))
        if self.roiNode:
            roiNodeID = self.roiNode.GetID()
            self.parameterNode.SetNthNodeReferenceID('ROI', 0, roiNodeID)


#
# Connector observation and actions
#

    def onConnectorNodeConnected(self):
        logging.debug("ProstateTrusUltrasound:onConnectorNodeConnected")
        self.connectorNodeConnected = True
        self.captureIDSelector.setDisabled(False)
        self.volumeReconstructorIDSelector.setDisabled(False)
        self.plusRemoteLogic.getCaptureDeviceIds(
            self.connectorNode.GetID(),
            self.onGetCaptureDeviceCommandResponseReceived)
        self.plusRemoteLogic.getVolumeReconstructorDeviceIds(
            self.connectorNode.GetID(),
            self.onGetVolumeReconstructorDeviceCommandResponseReceived)
        self.connectDisconnectButton.setText("Disconnect")

    def onConnectorNodeDisconnected(self):
        logging.debug("ProstateTrusUltrasound:onConnectorNodeDisconnected")
        self.connectorNodeConnected = False
        self.startStopRecordingButton.setEnabled(False)
        self.startStopScoutScanButton.setEnabled(False)
        self.startStopLiveReconstructionButton.setEnabled(False)
        self.offlineReconstructButton.setEnabled(False)
        self.captureIDSelector.setDisabled(True)
        self.volumeReconstructorIDSelector.setDisabled(True)
        self.connectDisconnectButton.setText("Connect")

    def getLiveVolumeRecNode(self):
        liveVolumeRecNode = slicer.util.getNode(self.LIVE_VOLUME_NODE_NAME)
        return liveVolumeRecNode

    def getOfflineVolumeRecNode(self):
        offlineVolumeRecNode = slicer.util.getNode(
            self.OFFLINE_VOLUME_NODE_NAME)
        return offlineVolumeRecNode

    def getScoutVolumeNode(self):
        scoutScanVolumeNode = slicer.util.getNode(self.SCOUT_VOLUME_NODE_NAME)
        return scoutScanVolumeNode

    def onConnectDisconnectButtonClicked(self):
        if self.connectorNode.GetState(
        ) == slicer.vtkMRMLIGTLConnectorNode.STATE_CONNECTED:
            self.connectorNode.Stop()
        else:
            self.connectorNode.Start()

    def onStartStopRecordingButtonClicked(self):
        if self.startStopRecordingButton.isChecked():
            self.startStopRecordingButton.setText("  Stop Recording")
            self.startStopRecordingButton.setIcon(self.stopIcon)
            self.startStopRecordingButton.setToolTip(
                "If clicked, stop recording")
            self.onStartRecording(self.generateRecordingOutputFilename())
        else:
            self.startStopRecordingButton.setText("  Start Recording")
            self.startStopRecordingButton.setIcon(self.recordIcon)
            self.startStopRecordingButton.setToolTip(
                "If clicked, start recording")
            self.onStopRecording(self.onVolumeRecorded)

    def onStartStopScoutScanButtonClicked(self):
        if self.startStopScoutScanButton.isChecked():
            self.startStopScoutScanButton.setText(
                "  Scout Scan\n  Stop Recording and Reconstruct Recorded Volume"
            )
            self.startStopScoutScanButton.setIcon(self.stopIcon)
            self.startStopScoutScanButton.setToolTip(
                "If clicked, stop recording and reconstruct recorded volume")
            self.onStartRecording(self.generateScoutRecordingOutputFilename())
        else:
            self.onStopRecording(self.onScoutVolumeRecorded)

    def onStartStopLiveReconstructionButtonClicked(self):
        if self.startStopLiveReconstructionButton.isChecked():
            if self.roiNode:
                self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(
                    self.LIVE_OUTPUT_VOLUME_SPACING, self.roiNode)
            self.startStopLiveReconstructionButton.setText(
                "  Stop Live Reconstruction")
            self.startStopLiveReconstructionButton.setIcon(self.stopIcon)
            self.startStopLiveReconstructionButton.setToolTip(
                "If clicked, stop live reconstruction")
            self.onStartRecording(self.getLiveRecordingOutputFilename())
            self.onStartReconstruction()
        else:
            self.startStopLiveReconstructionButton.setText(
                "  Start Live Reconstruction")
            self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
            self.startStopLiveReconstructionButton.setToolTip(
                "If clicked, start live reconstruction")
            self.onStopRecording(self.printCommandResponse)
            self.onStopReconstruction()

    def onDisplayRoiButtonClicked(self):
        if self.displayRoiButton.isChecked():
            self.displayRoiButton.setIcon(self.visibleOnIcon)
            self.displayRoiButton.setToolTip("If clicked, hide ROI")
            if self.roiNode:
                self.roiNode.SetDisplayVisibility(1)
        else:
            self.displayRoiButton.setIcon(self.visibleOffIcon)
            self.displayRoiButton.setToolTip("If clicked, display ROI")
            if self.roiNode:
                self.roiNode.SetDisplayVisibility(0)

    def generateRecordingOutputFilename(self):
        return self.plusRemoteLogic.addTimestampToFilename(
            self.RECORDING_FILENAME)

    def generateScoutRecordingOutputFilename(self):
        return self.plusRemoteLogic.addTimestampToFilename(
            self.SCOUT_RECORDING_FILENAME)

    def getLiveRecordingOutputFilename(self):
        return self.plusRemoteLogic.addTimestampToFilename(
            self.LIVE_RECORDING_FILENAME)

    def getLiveReconstructionOutputFilename(self):
        return self.plusRemoteLogic.addTimestampToFilename(
            self.LIVE_VOLUME_FILENAME)

    def onStartRecording(self, filename):
        self.plusRemoteLogic.startRecording(self.connectorNode.GetID(),
                                            self.captureIDSelector.currentText,
                                            filename,
                                            self.printCommandResponse)

    def onStopRecording(self, callback):
        self.plusRemoteLogic.stopRecording(self.connectorNode.GetID(),
                                           self.captureIDSelector.currentText,
                                           callback)

    def onStartReconstruction(self):
        if self.roiNode:
            self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(
                self.LIVE_OUTPUT_VOLUME_SPACING, self.roiNode)
        self.plusRemoteLogic.startVolumeReconstuction(
            self.connectorNode.GetID(),
            self.volumeReconstructorIDSelector.currentText,
            self.liveOutputSpacingValue, self.roiOrigin, self.roiExtent,
            self.printCommandResponse,
            self.getLiveReconstructionOutputFilename(),
            self.LIVE_VOLUME_NODE_NAME)
        # Set up timer for requesting snapshot
        self.snapshotTimer.start(self.SNAPSHOT_INTERVAL * 1000)

    def onStopReconstruction(self):
        self.snapshotTimer.stop()
        self.plusRemoteLogic.stopVolumeReconstruction(
            self.connectorNode.GetID(),
            self.volumeReconstructorIDSelector.currentText,
            self.onVolumeLiveReconstructed,
            self.getLiveReconstructionOutputFilename(),
            self.LIVE_VOLUME_NODE_NAME)

    def onReconstVolume(self):
        self.offlineReconstructButton.setIcon(self.waitIcon)
        self.offlineReconstructButton.setText(
            "  Offline Reconstruction in progress ...")
        self.offlineReconstructButton.setEnabled(False)
        self.plusRemoteLogic.reconstructRecorded(
            self.connectorNode.GetID(),
            self.volumeReconstructorIDSelector.currentText,
            self.offlineVolumeToReconstructSelector.currentText,
            self.outputSpacing, self.onVolumeReconstructed,
            self.OFFLINE_VOLUME_FILENAME, self.OFFLINE_VOLUME_NODE_NAME)

    def onScoutScanReconstVolume(self):
        self.startStopScoutScanButton.setIcon(self.waitIcon)
        self.startStopScoutScanButton.setText(
            "  Scout Scan\n  Reconstruction in progress ...")
        self.startStopScoutScanButton.setEnabled(False)
        self.plusRemoteLogic.reconstructRecorded(
            self.connectorNode.GetID(),
            self.volumeReconstructorIDSelector.currentText,
            self.lastScoutRecordingOutputFilename, self.outputSpacing,
            self.onScoutVolumeReconstructed, self.SCOUT_VOLUME_FILENAME,
            self.SCOUT_VOLUME_NODE_NAME)

    def onRequestVolumeReconstructionSnapshot(self, stopFlag=""):
        self.plusRemoteLogic.getVolumeReconstructionSnapshot(
            self.connectorNode.GetID(),
            self.volumeReconstructorIDSelector.currentText,
            self.LIVE_VOLUME_FILENAME, self.LIVE_VOLUME_NODE_NAME,
            self.APPLY_HOLE_FILLING_FOR_SNAPSHOT, self.onSnapshotAcquired)

    def executeCommandDelayed(self, method, delay=100):
        # Order of OpenIGTLink message receiving and processing is not guaranteed to be the same
        # therefore we wait a bit to make sure the image message is processed as well
        QTimer.singleShot(delay, method)

    def printCommandResponse(self, command, q):
        statusText = "Command {0} [{1}]: {2}\n".format(
            command.GetCommandName(), command.GetID(),
            command.StatusToString(command.GetStatus()))
        if command.GetResponseMessage():
            statusText = statusText + command.GetResponseMessage()
        elif command.GetResponseText():
            statusText = statusText + command.GetResponseText()
        logging.debug(statusText)

    def onGetCaptureDeviceCommandResponseReceived(self, command, q):
        self.printCommandResponse(command, q)
        if command.GetStatus() != command.CommandSuccess:
            return

        captureDeviceIdsListString = command.GetResponseMessage()
        if captureDeviceIdsListString:
            captureDevicesIdsList = captureDeviceIdsListString.split(",")
        else:
            captureDevicesIdsList = []

        for i in range(0, len(captureDevicesIdsList)):
            if self.captureIDSelector.findText(captureDevicesIdsList[i]) == -1:
                self.captureIDSelector.addItem(captureDevicesIdsList[i])

    def onGetVolumeReconstructorDeviceCommandResponseReceived(
            self, command, q):
        self.printCommandResponse(command, q)
        if command.GetStatus() != command.CommandSuccess:
            return

        volumeReconstructorDeviceIdsListString = command.GetResponseMessage()
        if volumeReconstructorDeviceIdsListString:
            volumeReconstructorDeviceIdsList = volumeReconstructorDeviceIdsListString.split(
                ",")
        else:
            volumeReconstructorDeviceIdsList = []

        self.volumeReconstructorIDSelector.clear()
        self.volumeReconstructorIDSelector.addItems(
            volumeReconstructorDeviceIdsList)
        self.startStopRecordingButton.setEnabled(True)
        self.offlineReconstructButton.setEnabled(True)
        self.startStopScoutScanButton.setEnabled(True)
        if self.roiNode:
            self.startStopLiveReconstructionButton.setEnabled(True)

    def onVolumeRecorded(self, command, q):
        self.printCommandResponse(command, q)
        self.offlineReconstructButton.setEnabled(True)

        volumeToReconstructFileName = os.path.basename(
            command.GetResponseMessage())
        self.offlineVolumeToReconstructSelector.insertItem(
            0, volumeToReconstructFileName)
        self.offlineVolumeToReconstructSelector.setCurrentIndex(0)

    def onScoutVolumeRecorded(self, command, q):
        self.printCommandResponse(command, q)
        self.offlineReconstructButton.setEnabled(True)

        if command.GetStatus() == command.CommandExpired:
            logging.fatal(
                "Scout Volume Recording: Timeout while waiting for volume reconstruction result"
            )
            return

        if command.GetStatus() == command.CommandSuccess:
            self.lastScoutRecordingOutputFilename = os.path.basename(
                command.GetResponseMessage())
            self.onScoutScanReconstVolume()

    def onVolumeReconstructed(self, command, q):
        self.printCommandResponse(command, q)

        self.offlineReconstructButton.setIcon(self.recordIcon)
        self.offlineReconstructButton.setText("Offline Reconstruction")
        self.offlineReconstructButton.setEnabled(True)
        self.offlineReconstructButton.setChecked(False)

        if command.GetStatus() == command.CommandExpired:
            # volume reconstruction command timed out
            logging.fatal(
                "Volume Reconstruction: Timeout while waiting for volume reconstruction result"
            )
            return

        if command.GetStatus() != command.CommandSuccess:
            logging.debug("Volume Reconstruction: " +
                          command.GetResponseMessage())
            return

        self.executeCommandDelayed(self.onVolumeReconstructedFinalize)

    def onVolumeReconstructedFinalize(self):
        applicationLogic = slicer.app.applicationLogic()
        applicationLogic.FitSliceToAll()
        self.guideletParent.showVolumeRendering(self.getOfflineVolumeRecNode())

    def onScoutVolumeReconstructed(self, command, q):
        self.printCommandResponse(command, q)

        if command.GetStatus() == command.CommandExpired:
            logging.fatal(
                "Scout Volume Reconstruction: Timeout while waiting for scout volume reconstruction result"
            )
            return

        self.startStopScoutScanButton.setIcon(self.recordIcon)
        self.startStopScoutScanButton.setText(
            "  Scout Scan\n  Start Recording")
        self.startStopScoutScanButton.setEnabled(True)

        if command.GetStatus() != command.CommandSuccess:
            logging.debug("Scout Volume Reconstruction: " +
                          command.GetResponseMessage())
            return

        self.executeCommandDelayed(self.onScoutVolumeReconstructedFinalize)

    def onScoutVolumeReconstructedFinalize(self):
        # Create and initialize ROI after scout scan because low resolution scout scan is used to set
        # a smaller ROI for the live high resolution reconstruction
        self.roiNode = self.logic.onRoiInitialization(
            self.SCOUT_VOLUME_NODE_NAME, self.roiNode)
        self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(
            self.LIVE_OUTPUT_VOLUME_SPACING, self.roiNode)
        scoutScanVolumeNode = self.getScoutVolumeNode()

        applicationLogic = slicer.app.applicationLogic()
        applicationLogic.FitSliceToAll()

        self.guideletParent.showVolumeRendering(scoutScanVolumeNode)

    def onSnapshotAcquired(self, command, q):
        self.printCommandResponse(command, q)

        if not self.startStopLiveReconstructionButton.isChecked():
            # live volume reconstruction is not active
            return

        self.executeCommandDelayed(self.onSnapshotAcquiredFinalize)

    def onSnapshotAcquiredFinalize(self):
        self.guideletParent.showVolumeRendering(self.getLiveVolumeRecNode())
        self.snapshotTimer.start(self.SNAPSHOT_INTERVAL * 1000)

    def onVolumeLiveReconstructed(self, command, q):
        self.printCommandResponse(command, q)

        if command.GetStatus() == command.CommandExpired:
            logging.fatal(
                "LIVE Volume Reconstruction: Failed to stop volume reconstruction"
            )
            return

        if command.GetStatus() != command.CommandSuccess:
            logging.debug("LIVE Volume Reconstruction " +
                          command.GetResponseMessage())
            return

        self.executeCommandDelayed(self.getLiveVolumeRecNode)

    def onVolumeLiveReconstructedFinalize(self):
        self.guideletParent.showVolumeRendering(self.getLiveVolumeRecNode())
예제 #6
0
class VSalida(VentanaSalida):
    """Ventana que muestra los resultados de las operaciones solicitadas. 
    Permite al usuario exportar o guardar los resultados ya obtenidos"""
    def __init__(self, parent, gestorsalida, gestortemas):
        VentanaSalida.__init__(self)
        #VARIABLES PUBLICAS
        self.parent = parent
        #VARIABLES PRIVADAS
        self.__gestortemas = gestortemas
        self.__gestorsalida = gestorsalida
        self.__contenido = []

        self.__inittoolbar()
        self.__conexiones()

    #FUNCIONES PUBLICAS

    def ana_res(self, objeto):
        """Añade un resultado al dialogo, para ser mostrado"""
        self.__contenido.append(objeto)

    def __myUpdate(self):
        """Actualiza el contenido de la ventana"""
        cadenasalida = ""
        i = 1
        for resultado in self.__contenido:
            cadenasalida += "<a name=" + str(i) + "></a>"
            cadenasalida += resultado.html().encode('iso-8859-1', 'replace')
            i += 1
        self.textBrowser1.setText(cadenasalida, "/tmp")
        self.textBrowser1.scrollToAnchor(str(len(self.__contenido)))
        self.__actualizar_lista()

    def closeEvent( self, event ):
        """Redefinicion del closeEvent de qt"""
        QWidget.closeEvent( self, event )
        if not self.parent.vprincipal.isVisible():
            qApp.exit(0)
        else:
            self.hide()

    def showEvent(self, event):
        """Redefinicion del método show de VentanaSalida, 
        muestra todos los resultados almacenados"""
        self.__myUpdate()
        VentanaSalida.showEvent(self, event)

    #FUNCIONES PRIVADAS

    def __conexiones(self):
        """Bloque de conexiones"""
        self.connect(self.archivoAbrirAction, SIGNAL("activated()"), self.__dabrirfichero)
        self.connect(self.archivoGuardarAction, SIGNAL("activated()"), self.__dguardarfichero)
        self.connect(self.archivoExportarHTMLAction, SIGNAL("activated()"), self.__dexportar)
        self.connect(self.archivoSalirAction, SIGNAL("activated()"), self.hide)
        self.connect(self.__boton1, SIGNAL("clicked()"), self.__dabrirfichero)
        self.connect(self.__boton2, SIGNAL("clicked()"), self.__dguardarfichero)
        self.connect(self.__boton3, SIGNAL("clicked()"), self.__dexportar)
        self.connect(self.__boton4, SIGNAL("clicked()"), self.parent.vprincipal.show)
        self.connect(self.pushButton1, SIGNAL("clicked()"), self.__borrar_elemento)

    def __inittoolbar(self):
        """Inicializa la toolbar"""
        self.__boton1 = QToolButton(self.Toolbar)
        self.__boton1.setTextLabel("Abrir fichero")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_abrir(), QIconSet.Small)
        self.__boton1.setOn(True)
        self.__boton1.setIconSet(iconos)
        self.__boton2 = QToolButton(self.Toolbar)
        self.__boton2.setTextLabel("Guardar en fichero")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_guardar(), QIconSet.Small)
        self.__boton2.setOn(True)
        self.__boton2.setIconSet(iconos)
        self.__boton3 = QToolButton(self.Toolbar)
        self.__boton3.setTextLabel("Exportar a html")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_exportar(), QIconSet.Small)
        self.__boton3.setOn(True)
        self.__boton3.setIconSet(iconos)
        self.__boton4 = QToolButton(self.Toolbar)
        self.__boton4.setTextLabel("Mostrar Ventana principal")
        iconos = QIconSet()
        iconos.setIconSize(QIconSet.Small, QSize(100, 100))
        iconos.setPixmap(self.__gestortemas.icono_nueva_ventana(), QIconSet.Small)
        self.__boton4.setOn(True)
        self.__boton4.setIconSet(iconos)

    def __dabrirfichero(self):        
        """Pregunta al usuario que fichero cargar"""
        filterlist = ""
        for fmt in ["dro"]: #Candidata al fichero de listas
            filterlist = filterlist + "%s files (*.%s);;" % (fmt, fmt.lower())
        nombrefichero = QFileDialog.getOpenFileName(QString.null, filterlist, self, None, "Dialogo abrir fichero", "")
        filename = str(nombrefichero)
        if filename:
            try:
                self.__contenido = self.__gestorsalida.cargar(filename)
            except AttributeError: 
                QErrorMessage(self,"Error").message(u"Error en la carga de fichero, Probablemente versión anterior")
            else:
                self.__myUpdate()

    def __dguardarfichero(self):
        """Pregunta al usuario en que fichero guardar"""
        filterlist = ""
        for fmt in ["dro"]: #Candidata al fichero de listas
            filterlist = filterlist + "%s files (*.%s);;" % (fmt, fmt.lower())
        nombrefichero = QFileDialog.getSaveFileName(QString.null, filterlist, self)
        filename = str(nombrefichero)
        if filename:
            from Driza.excepciones import FicheroExisteException, \
                    FicheroTipoDesconocidoException
            try:
                self.__gestorsalida.guardar(self.__contenido, filename)
            except FicheroExisteException,fichero:
                codigoretorno = QMessageBox.information(self, 'Atencion:', 'El fichero' +\
                        fichero.fichero + ' ya existe' , 'Sobreescribir', \
                        'Otro nombre', 'Cancelar', 0, 1)
                if codigoretorno == 0:
                    self.__gestorsalida.guardar(self.__contenido, filename, True)
                elif codigoretorno == 1:
                    self.__dguardarfichero()
            except FicheroTipoDesconocidoException:
                QMessageBox.warning(self, u'Atención', \
                        u'La extensión del fichero es incorrecta.\nPruebe con otra extensión')
  def setupPanel(self, parentWidget):
    logging.debug('ProstateTRUSNavUltrasound.setupPanel')

    self.connectorNode = self.guideletParent.connectorNode
    self.connectorNodeConnected = False

    collapsibleButton = ctkCollapsibleButton()
    collapsibleButton.setProperty('collapsedHeight', 20)
    setButtonStyle(collapsibleButton, 2.0)
    collapsibleButton.text = "Ultrasound"
    parentWidget.addWidget(collapsibleButton)

    ultrasoundLayout = QFormLayout(collapsibleButton)
    ultrasoundLayout.setContentsMargins(12,4,4,4)
    ultrasoundLayout.setSpacing(4)

    self.connectDisconnectButton = QPushButton("Connect")
    self.connectDisconnectButton.setToolTip("If clicked, connection OpenIGTLink")

    hbox = QHBoxLayout()
    hbox.addWidget(self.connectDisconnectButton)
    ultrasoundLayout.addRow(hbox)

    self.setupIcons()

    self.captureIDSelector = QComboBox()
    self.captureIDSelector.setToolTip("Pick capture device ID")
    self.captureIDSelector.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.volumeReconstructorIDSelector = QComboBox()
    self.volumeReconstructorIDSelector.setToolTip( "Pick volume reconstructor device ID" )
    self.volumeReconstructorIDSelector.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.startStopRecordingButton = QPushButton("  Start Recording")
    self.startStopRecordingButton.setCheckable(True)
    self.startStopRecordingButton.setIcon(self.recordIcon)
    self.startStopRecordingButton.setEnabled(False)
    self.startStopRecordingButton.setToolTip("If clicked, start recording")
    self.startStopRecordingButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    recordParametersControlsLayout = QGridLayout()

    self.filenameLabel = self.createLabel("Filename:", visible=False)
    recordParametersControlsLayout.addWidget(self.filenameLabel, 1, 0)

     # Offline Reconstruction
    self.offlineReconstructButton = QPushButton("  Offline Reconstruction")
    self.offlineReconstructButton.setCheckable(True)
    self.offlineReconstructButton.setIcon(self.recordIcon)
    self.offlineReconstructButton.setEnabled(False)
    self.offlineReconstructButton.setToolTip("If clicked, reconstruct recorded volume")
    self.offlineReconstructButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.offlineVolumeToReconstructSelector = QComboBox()
    self.offlineVolumeToReconstructSelector.setEditable(True)
    self.offlineVolumeToReconstructSelector.setToolTip( "Pick/set volume to reconstruct" )
    self.offlineVolumeToReconstructSelector.visible = False

    hbox = QHBoxLayout()
    hbox.addWidget(self.startStopRecordingButton)
    hbox.addWidget(self.offlineReconstructButton)
    ultrasoundLayout.addRow(hbox)

    # Scout scan (record and low resolution reconstruction) and live reconstruction
    # Scout scan part

    self.startStopScoutScanButton = QPushButton("  Scout scan\n  Start recording")
    self.startStopScoutScanButton.setCheckable(True)
    self.startStopScoutScanButton.setIcon(self.recordIcon)
    self.startStopScoutScanButton.setToolTip("If clicked, start recording")
    self.startStopScoutScanButton.setEnabled(False)
    self.startStopScoutScanButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.startStopLiveReconstructionButton = QPushButton("  Start live reconstruction")
    self.startStopLiveReconstructionButton.setCheckable(True)
    self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
    self.startStopLiveReconstructionButton.setToolTip("If clicked, start live reconstruction")
    self.startStopLiveReconstructionButton.setEnabled(False)
    self.startStopLiveReconstructionButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.displayRoiButton = QToolButton()
    self.displayRoiButton.setCheckable(True)
    self.displayRoiButton.setIcon(self.visibleOffIcon)
    self.displayRoiButton.setToolTip("If clicked, display ROI")

    hbox = QHBoxLayout()
    hbox.addWidget(self.startStopScoutScanButton)
    hbox.addWidget(self.startStopLiveReconstructionButton)
    # hbox.addWidget(self.displayRoiButton)
    ultrasoundLayout.addRow(hbox)

    self.snapshotTimer = QTimer()
    self.snapshotTimer.setSingleShot(True)

    self.onParameterSetSelected()

    return collapsibleButton
class ProstateTRUSNavUltrasound(UltraSound):

  OFFLINE_VOLUME_FILENAME = "RecVol_Reference.mha"
  SCOUT_VOLUME_FILENAME = "ScoutScan.mha"
  LIVE_VOLUME_FILENAME = "LiveReconstructedVolume.mha"

  RECORDING_FILENAME = "Recording.mha"
  SCOUT_RECORDING_FILENAME = "ScoutScanRecording.mha"
  LIVE_RECORDING_FILENAME = LIVE_VOLUME_FILENAME

  SCOUT_VOLUME_NODE_NAME = "ScoutScan"
  OFFLINE_VOLUME_NODE_NAME = "RecVol_Reference"
  LIVE_VOLUME_NODE_NAME = "liveReconstruction"

  APPLY_HOLE_FILLING_FOR_SNAPSHOT = False
  SNAPSHOT_INTERVAL = 3
  OUTPUT_VOLUME_SPACING = 3
  LIVE_OUTPUT_VOLUME_SPACING = 1

  @property
  def roiNode(self):
    return self._roiNode

  @roiNode.setter
  def roiNode(self, node):
    self._roiNode=node
    if node is not None:
      self.startStopLiveReconstructionButton.setEnabled(True)
    else:
      self.startStopLiveReconstructionButton.setEnabled(False)

  def __init__(self, guideletParent):
    UltraSound.__init__(self, guideletParent)

    self.parameterNode = guideletParent.parameterNode
    self.parameterNodeObserver = None
    self._roiNode = None
    self.liveOutputSpacingValue = [self.LIVE_OUTPUT_VOLUME_SPACING, self.LIVE_OUTPUT_VOLUME_SPACING,
                                   self.LIVE_OUTPUT_VOLUME_SPACING]
    self.outputSpacing = [self.OUTPUT_VOLUME_SPACING, self.OUTPUT_VOLUME_SPACING, self.OUTPUT_VOLUME_SPACING]
    self.roiOrigin = None
    self.roiExtent = None
    self.defaultParameterNode = None
    self.logic = ProstateTRUSNavUltrasoundLogic()

  def setupPanel(self, parentWidget):
    logging.debug('ProstateTRUSNavUltrasound.setupPanel')

    self.connectorNode = self.guideletParent.connectorNode
    self.connectorNodeConnected = False

    collapsibleButton = ctkCollapsibleButton()
    collapsibleButton.setProperty('collapsedHeight', 20)
    setButtonStyle(collapsibleButton, 2.0)
    collapsibleButton.text = "Ultrasound"
    parentWidget.addWidget(collapsibleButton)

    ultrasoundLayout = QFormLayout(collapsibleButton)
    ultrasoundLayout.setContentsMargins(12,4,4,4)
    ultrasoundLayout.setSpacing(4)

    self.connectDisconnectButton = QPushButton("Connect")
    self.connectDisconnectButton.setToolTip("If clicked, connection OpenIGTLink")

    hbox = QHBoxLayout()
    hbox.addWidget(self.connectDisconnectButton)
    ultrasoundLayout.addRow(hbox)

    self.setupIcons()

    self.captureIDSelector = QComboBox()
    self.captureIDSelector.setToolTip("Pick capture device ID")
    self.captureIDSelector.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.volumeReconstructorIDSelector = QComboBox()
    self.volumeReconstructorIDSelector.setToolTip( "Pick volume reconstructor device ID" )
    self.volumeReconstructorIDSelector.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.startStopRecordingButton = QPushButton("  Start Recording")
    self.startStopRecordingButton.setCheckable(True)
    self.startStopRecordingButton.setIcon(self.recordIcon)
    self.startStopRecordingButton.setEnabled(False)
    self.startStopRecordingButton.setToolTip("If clicked, start recording")
    self.startStopRecordingButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    recordParametersControlsLayout = QGridLayout()

    self.filenameLabel = self.createLabel("Filename:", visible=False)
    recordParametersControlsLayout.addWidget(self.filenameLabel, 1, 0)

     # Offline Reconstruction
    self.offlineReconstructButton = QPushButton("  Offline Reconstruction")
    self.offlineReconstructButton.setCheckable(True)
    self.offlineReconstructButton.setIcon(self.recordIcon)
    self.offlineReconstructButton.setEnabled(False)
    self.offlineReconstructButton.setToolTip("If clicked, reconstruct recorded volume")
    self.offlineReconstructButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.offlineVolumeToReconstructSelector = QComboBox()
    self.offlineVolumeToReconstructSelector.setEditable(True)
    self.offlineVolumeToReconstructSelector.setToolTip( "Pick/set volume to reconstruct" )
    self.offlineVolumeToReconstructSelector.visible = False

    hbox = QHBoxLayout()
    hbox.addWidget(self.startStopRecordingButton)
    hbox.addWidget(self.offlineReconstructButton)
    ultrasoundLayout.addRow(hbox)

    # Scout scan (record and low resolution reconstruction) and live reconstruction
    # Scout scan part

    self.startStopScoutScanButton = QPushButton("  Scout scan\n  Start recording")
    self.startStopScoutScanButton.setCheckable(True)
    self.startStopScoutScanButton.setIcon(self.recordIcon)
    self.startStopScoutScanButton.setToolTip("If clicked, start recording")
    self.startStopScoutScanButton.setEnabled(False)
    self.startStopScoutScanButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.startStopLiveReconstructionButton = QPushButton("  Start live reconstruction")
    self.startStopLiveReconstructionButton.setCheckable(True)
    self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
    self.startStopLiveReconstructionButton.setToolTip("If clicked, start live reconstruction")
    self.startStopLiveReconstructionButton.setEnabled(False)
    self.startStopLiveReconstructionButton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    self.displayRoiButton = QToolButton()
    self.displayRoiButton.setCheckable(True)
    self.displayRoiButton.setIcon(self.visibleOffIcon)
    self.displayRoiButton.setToolTip("If clicked, display ROI")

    hbox = QHBoxLayout()
    hbox.addWidget(self.startStopScoutScanButton)
    hbox.addWidget(self.startStopLiveReconstructionButton)
    # hbox.addWidget(self.displayRoiButton)
    ultrasoundLayout.addRow(hbox)

    self.snapshotTimer = QTimer()
    self.snapshotTimer.setSingleShot(True)

    self.onParameterSetSelected()

    return collapsibleButton

  def setupResliceDriver(self):
    layoutManager = slicer.app.layoutManager()
    # Show ultrasound in red view.
    redSlice = layoutManager.sliceWidget('Red')
    redSliceLogic = redSlice.sliceLogic()
    redSliceLogic.GetSliceCompositeNode().SetBackgroundVolumeID(self.liveUltrasoundNode_Reference.GetID())

    resliceLogic = slicer.modules.volumereslicedriver.logic()
    if resliceLogic:
      redNode = slicer.util.getNode('vtkMRMLSliceNodeRed')
      redNode.SetSliceResolutionMode(slicer.vtkMRMLSliceNode.SliceResolutionMatchVolumes)
      resliceLogic.SetDriverForSlice(self.liveUltrasoundNode_Reference.GetID(), redNode)
      resliceLogic.SetModeForSlice(6, redNode) # Transverse mode, default for PLUS ultrasound.
    else:
      logging.warning('Logic not found for Volume Reslice Driver')

  def createCollapsibleButton(self, text, collapsed=False):
    collapsibleButton = ctkCollapsibleButton()
    collapsibleButton.text = text
    collapsibleButton.collapsed = collapsed
    return collapsibleButton

  def createLabel(self, text, visible=True):
    label = QLabel()
    label.setText(text)
    label.visible = visible
    return label

  def setupConnections(self):
    self.startStopRecordingButton.connect('clicked(bool)', self.onStartStopRecordingButtonClicked)
    self.offlineReconstructButton.connect('clicked(bool)', self.onReconstVolume)
    self.startStopScoutScanButton.connect('clicked(bool)', self.onStartStopScoutScanButtonClicked)
    self.startStopLiveReconstructionButton.connect('clicked(bool)', self.onStartStopLiveReconstructionButtonClicked)
    self.displayRoiButton.connect('clicked(bool)', self.onDisplayRoiButtonClicked)
    self.captureIDSelector.connect('currentIndexChanged(QString)', self.updateParameterNodeFromGui)
    self.volumeReconstructorIDSelector.connect('currentIndexChanged(QString)', self.updateParameterNodeFromGui)
    self.offlineVolumeToReconstructSelector.connect('currentIndexChanged(int)', self.updateParameterNodeFromGui)
    self.displayRoiButton.connect('clicked(bool)', self.updateParameterNodeFromGui)
    self.snapshotTimer.timeout.connect(self.onRequestVolumeReconstructionSnapshot)
    self.connectDisconnectButton.connect('clicked(bool)', self.onConnectDisconnectButtonClicked)

  def disconnect(self):
    self.startStopRecordingButton.disconnect('clicked(bool)', self.onStartStopRecordingButtonClicked)
    self.offlineReconstructButton.disconnect('clicked(bool)', self.onReconstVolume)
    self.startStopScoutScanButton.disconnect('clicked(bool)', self.onStartStopScoutScanButtonClicked)
    self.startStopLiveReconstructionButton.disconnect('clicked(bool)', self.onStartStopLiveReconstructionButtonClicked)
    self.displayRoiButton.disconnect('clicked(bool)', self.onDisplayRoiButtonClicked)
    self.captureIDSelector.disconnect('currentIndexChanged(QString)', self.updateParameterNodeFromGui)
    self.volumeReconstructorIDSelector.disconnect('currentIndexChanged(QString)', self.updateParameterNodeFromGui)
    self.offlineVolumeToReconstructSelector.disconnect('currentIndexChanged(int)', self.updateParameterNodeFromGui)
    self.displayRoiButton.disconnect('clicked(bool)', self.updateParameterNodeFromGui)
    self.snapshotTimer.timeout.disconnect(self.onRequestVolumeReconstructionSnapshot)
    self.connectDisconnectButton.disconnect('clicked(bool)', self.onConnectDisconnectButtonClicked)

  def setupIcons(self):
    self.plusRemoteModuleDirectoryPath = slicer.modules.plusremote.path.replace("PlusRemote.py", "")
    self.recordIcon = QIcon(self.plusRemoteModuleDirectoryPath + '/Resources/Icons/icon_Record.png')
    self.stopIcon = QIcon(self.plusRemoteModuleDirectoryPath + '/Resources/Icons/icon_Stop.png')
    self.waitIcon = QIcon(self.plusRemoteModuleDirectoryPath + '/Resources/Icons/icon_Wait.png')
    self.visibleOffIcon = QIcon(":Icons\VisibleOff.png")
    self.visibleOnIcon = QIcon(":Icons\VisibleOn.png")

  def onParameterSetSelected(self):
    # Set up default values for new nodes
    if self.parameterNode:
      self.plusRemoteLogic.setDefaultParameters(self.parameterNode)
    self.updateGuiFromParameterNode()

  def updateGuiFromParameterNode(self):

    self.parameterVolumeList = {'OfflineVolumeToReconstruct': self.offlineVolumeToReconstructSelector}
    for parameter in self.parameterVolumeList:
      if self.parameterNode.GetParameter(parameter):
        self.parameterVolumeList[parameter].blockSignals(True)
      self.parameterVolumeList[parameter].blockSignals(False)

    if self.parameterNode.GetParameter('CaptureID'):
      self.captureIDSelector.blockSignals(True)
      for i in range(0, self.captureIDSelector.count):
        if self.parameterNode.GetParameter('CaptureID') == self.captureIDSelector.itemText(i):
          self.captureIDSelector.setCurrentIndex(int(self.parameterNode.GetParameter('CaptureIdIndex')))
      self.captureIDSelector.blockSignals(False)

    if self.parameterNode.GetParameter('VolumeReconstructor'):
      self.volumeReconstructorIDSelector.blockSignals(True)
      for i in range(0, self.volumeReconstructorIDSelector.count):
        if self.parameterNode.GetParameter('VolumeReconstructor') == self.volumeReconstructorIDSelector.itemText(i):
          self.volumeReconstructorIDSelector.setCurrentIndex(int(self.parameterNode.GetParameter('VolumeReconstructorIndex')))
      self.volumeReconstructorIDSelector.blockSignals(False)

      self.roiNode = self.parameterNode.GetNthNodeReference('ROI', 0)

  def updateParameterNodeFromGui(self):
    #Update parameter node value to save when user change value in the interface
    if not self.parameterNode:
      return
    self.parametersList = {'CaptureID': self.captureIDSelector.currentText,
                           'CaptureIdIndex': self.captureIDSelector.currentIndex,
                           'VolumeReconstructor': self.volumeReconstructorIDSelector.currentText,
                           'VolumeReconstructorIndex': self.volumeReconstructorIDSelector.currentIndex,
                           'OfflineVolumeToReconstruct': self.offlineVolumeToReconstructSelector.currentIndex}
    for parameter in self.parametersList:
      self.parameterNode.SetParameter(parameter, str(self.parametersList[parameter]))
    if self.roiNode:
      roiNodeID = self.roiNode.GetID()
      self.parameterNode.SetNthNodeReferenceID('ROI', 0, roiNodeID)

#
# Connector observation and actions
#

  def onConnectorNodeConnected(self):
    logging.debug("ProstateTrusUltrasound:onConnectorNodeConnected")
    self.connectorNodeConnected = True
    self.captureIDSelector.setDisabled(False)
    self.volumeReconstructorIDSelector.setDisabled(False)
    self.plusRemoteLogic.getCaptureDeviceIds(self.connectorNode.GetID(),
                                   self.onGetCaptureDeviceCommandResponseReceived)
    self.plusRemoteLogic.getVolumeReconstructorDeviceIds(self.connectorNode.GetID(),
                                               self.onGetVolumeReconstructorDeviceCommandResponseReceived)
    self.connectDisconnectButton.setText("Disconnect")

  def onConnectorNodeDisconnected(self):
    logging.debug("ProstateTrusUltrasound:onConnectorNodeDisconnected")
    self.connectorNodeConnected = False
    self.startStopRecordingButton.setEnabled(False)
    self.startStopScoutScanButton.setEnabled(False)
    self.startStopLiveReconstructionButton.setEnabled(False)
    self.offlineReconstructButton.setEnabled(False)
    self.captureIDSelector.setDisabled(True)
    self.volumeReconstructorIDSelector.setDisabled(True)
    self.connectDisconnectButton.setText("Connect")

  def getLiveVolumeRecNode(self):
    liveVolumeRecNode = slicer.util.getNode(self.LIVE_VOLUME_NODE_NAME)
    return liveVolumeRecNode

  def getOfflineVolumeRecNode(self):
    offlineVolumeRecNode = slicer.util.getNode(self.OFFLINE_VOLUME_NODE_NAME)
    return offlineVolumeRecNode

  def getScoutVolumeNode(self):
    scoutScanVolumeNode = slicer.util.getNode(self.SCOUT_VOLUME_NODE_NAME)
    return scoutScanVolumeNode

  def onConnectDisconnectButtonClicked(self):
    if self.connectorNode.GetState() == slicer.vtkMRMLIGTLConnectorNode.STATE_CONNECTED:
      self.connectorNode.Stop()
    else:
      self.connectorNode.Start()

  def onStartStopRecordingButtonClicked(self):
    if self.startStopRecordingButton.isChecked():
      self.startStopRecordingButton.setText("  Stop Recording")
      self.startStopRecordingButton.setIcon(self.stopIcon)
      self.startStopRecordingButton.setToolTip( "If clicked, stop recording" )
      self.onStartRecording(self.generateRecordingOutputFilename())
    else:
      self.startStopRecordingButton.setText("  Start Recording")
      self.startStopRecordingButton.setIcon(self.recordIcon)
      self.startStopRecordingButton.setToolTip( "If clicked, start recording" )
      self.onStopRecording(self.onVolumeRecorded)

  def onStartStopScoutScanButtonClicked(self):
    if self.startStopScoutScanButton.isChecked():
      self.startStopScoutScanButton.setText("  Scout Scan\n  Stop Recording and Reconstruct Recorded Volume")
      self.startStopScoutScanButton.setIcon(self.stopIcon)
      self.startStopScoutScanButton.setToolTip( "If clicked, stop recording and reconstruct recorded volume" )
      self.onStartRecording(self.generateScoutRecordingOutputFilename())
    else:
      self.onStopRecording(self.onScoutVolumeRecorded)

  def onStartStopLiveReconstructionButtonClicked(self):
    if self.startStopLiveReconstructionButton.isChecked():
      if self.roiNode:
        self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(self.LIVE_OUTPUT_VOLUME_SPACING,
                                                                                       self.roiNode)
      self.startStopLiveReconstructionButton.setText("  Stop Live Reconstruction")
      self.startStopLiveReconstructionButton.setIcon(self.stopIcon)
      self.startStopLiveReconstructionButton.setToolTip( "If clicked, stop live reconstruction" )
      self.onStartRecording(self.getLiveRecordingOutputFilename())
      self.onStartReconstruction()
    else:
      self.startStopLiveReconstructionButton.setText("  Start Live Reconstruction")
      self.startStopLiveReconstructionButton.setIcon(self.recordIcon)
      self.startStopLiveReconstructionButton.setToolTip( "If clicked, start live reconstruction" )
      self.onStopRecording(self.printCommandResponse)
      self.onStopReconstruction()

  def onDisplayRoiButtonClicked(self):
    if self.displayRoiButton.isChecked():
      self.displayRoiButton.setIcon(self.visibleOnIcon)
      self.displayRoiButton.setToolTip("If clicked, hide ROI")
      if self.roiNode:
        self.roiNode.SetDisplayVisibility(1)
    else:
      self.displayRoiButton.setIcon(self.visibleOffIcon)
      self.displayRoiButton.setToolTip("If clicked, display ROI")
      if self.roiNode:
        self.roiNode.SetDisplayVisibility(0)

  def generateRecordingOutputFilename(self):
    return self.plusRemoteLogic.addTimestampToFilename(self.RECORDING_FILENAME)

  def generateScoutRecordingOutputFilename(self):
    return self.plusRemoteLogic.addTimestampToFilename(self.SCOUT_RECORDING_FILENAME)

  def getLiveRecordingOutputFilename(self):
    return self.plusRemoteLogic.addTimestampToFilename(self.LIVE_RECORDING_FILENAME)

  def getLiveReconstructionOutputFilename(self):
    return self.plusRemoteLogic.addTimestampToFilename(self.LIVE_VOLUME_FILENAME)

  def onStartRecording(self, filename):
    self.plusRemoteLogic.startRecording(self.connectorNode.GetID(), self.captureIDSelector.currentText,
                                        filename, self.printCommandResponse)

  def onStopRecording(self, callback):
    self.plusRemoteLogic.stopRecording(self.connectorNode.GetID(), self.captureIDSelector.currentText, callback)

  def onStartReconstruction(self):
    if self.roiNode:
      self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(self.LIVE_OUTPUT_VOLUME_SPACING,
                                                                                     self.roiNode)
    self.plusRemoteLogic.startVolumeReconstuction(self.connectorNode.GetID(),
                                                   self.volumeReconstructorIDSelector.currentText,
                                                   self.liveOutputSpacingValue, self.roiOrigin,
                                                   self.roiExtent, self.printCommandResponse,
                                                   self.getLiveReconstructionOutputFilename(), self.LIVE_VOLUME_NODE_NAME)
    # Set up timer for requesting snapshot
    self.snapshotTimer.start(self.SNAPSHOT_INTERVAL*1000)

  def onStopReconstruction(self):
    self.snapshotTimer.stop()
    self.plusRemoteLogic.stopVolumeReconstruction(self.connectorNode.GetID(),
                                                  self.volumeReconstructorIDSelector.currentText,
                                                  self.onVolumeLiveReconstructed,
                                                  self.getLiveReconstructionOutputFilename(),
                                                  self.LIVE_VOLUME_NODE_NAME)

  def onReconstVolume(self):
    self.offlineReconstructButton.setIcon(self.waitIcon)
    self.offlineReconstructButton.setText("  Offline Reconstruction in progress ...")
    self.offlineReconstructButton.setEnabled(False)
    self.plusRemoteLogic.reconstructRecorded(self.connectorNode.GetID(), self.volumeReconstructorIDSelector.currentText,
                                             self.offlineVolumeToReconstructSelector.currentText, self.outputSpacing,
                                             self.onVolumeReconstructed, self.OFFLINE_VOLUME_FILENAME,
                                             self.OFFLINE_VOLUME_NODE_NAME)

  def onScoutScanReconstVolume(self):
    self.startStopScoutScanButton.setIcon(self.waitIcon)
    self.startStopScoutScanButton.setText("  Scout Scan\n  Reconstruction in progress ...")
    self.startStopScoutScanButton.setEnabled(False)
    self.plusRemoteLogic.reconstructRecorded(self.connectorNode.GetID(), self.volumeReconstructorIDSelector.currentText,
                                             self.lastScoutRecordingOutputFilename, self.outputSpacing,
                                             self.onScoutVolumeReconstructed, self.SCOUT_VOLUME_FILENAME,
                                             self.SCOUT_VOLUME_NODE_NAME)

  def onRequestVolumeReconstructionSnapshot(self, stopFlag = ""):
    self.plusRemoteLogic.getVolumeReconstructionSnapshot(self.connectorNode.GetID(),
                                                         self.volumeReconstructorIDSelector.currentText,
                                                         self.LIVE_VOLUME_FILENAME,
                                                         self.LIVE_VOLUME_NODE_NAME,
                                                         self.APPLY_HOLE_FILLING_FOR_SNAPSHOT, self.onSnapshotAcquired)

  def executeCommandDelayed(self, method, delay=100):
    # Order of OpenIGTLink message receiving and processing is not guaranteed to be the same
    # therefore we wait a bit to make sure the image message is processed as well
    QTimer.singleShot(delay, method)

  def printCommandResponse(self, command, q):
    statusText = "Command {0} [{1}]: {2}\n".format(command.GetCommandName(), command.GetID(),
                                                   command.StatusToString(command.GetStatus()))
    if command.GetResponseMessage():
      statusText = statusText + command.GetResponseMessage()
    elif command.GetResponseText():
      statusText = statusText + command.GetResponseText()
    logging.debug(statusText)

  def onGetCaptureDeviceCommandResponseReceived(self, command, q):
    self.printCommandResponse(command, q)
    if command.GetStatus() != command.CommandSuccess:
      return

    captureDeviceIdsListString = command.GetResponseMessage()
    if captureDeviceIdsListString:
      captureDevicesIdsList = captureDeviceIdsListString.split(",")
    else:
      captureDevicesIdsList = []

    for i in range(0,len(captureDevicesIdsList)):
      if self.captureIDSelector.findText(captureDevicesIdsList[i]) == -1:
        self.captureIDSelector.addItem(captureDevicesIdsList[i])

  def onGetVolumeReconstructorDeviceCommandResponseReceived(self, command, q):
    self.printCommandResponse(command, q)
    if command.GetStatus() != command.CommandSuccess:
      return

    volumeReconstructorDeviceIdsListString = command.GetResponseMessage()
    if volumeReconstructorDeviceIdsListString:
      volumeReconstructorDeviceIdsList = volumeReconstructorDeviceIdsListString.split(",")
    else:
      volumeReconstructorDeviceIdsList = []

    self.volumeReconstructorIDSelector.clear()
    self.volumeReconstructorIDSelector.addItems(volumeReconstructorDeviceIdsList)
    self.startStopRecordingButton.setEnabled(True)
    self.offlineReconstructButton.setEnabled(True)
    self.startStopScoutScanButton.setEnabled(True)
    if self.roiNode:
      self.startStopLiveReconstructionButton.setEnabled(True)

  def onVolumeRecorded(self, command, q):
    self.printCommandResponse(command, q)
    self.offlineReconstructButton.setEnabled(True)

    volumeToReconstructFileName = os.path.basename(command.GetResponseMessage())
    self.offlineVolumeToReconstructSelector.insertItem(0,volumeToReconstructFileName)
    self.offlineVolumeToReconstructSelector.setCurrentIndex(0)

  def onScoutVolumeRecorded(self, command, q):
    self.printCommandResponse(command,q)
    self.offlineReconstructButton.setEnabled(True)

    if command.GetStatus() == command.CommandExpired:
      logging.fatal("Scout Volume Recording: Timeout while waiting for volume reconstruction result")
      return

    if command.GetStatus() == command.CommandSuccess:
      self.lastScoutRecordingOutputFilename = os.path.basename(command.GetResponseMessage())
      self.onScoutScanReconstVolume()

  def onVolumeReconstructed(self, command, q):
    self.printCommandResponse(command,q)

    self.offlineReconstructButton.setIcon(self.recordIcon)
    self.offlineReconstructButton.setText("Offline Reconstruction")
    self.offlineReconstructButton.setEnabled(True)
    self.offlineReconstructButton.setChecked(False)

    if command.GetStatus() == command.CommandExpired:
      # volume reconstruction command timed out
      logging.fatal("Volume Reconstruction: Timeout while waiting for volume reconstruction result")
      return

    if command.GetStatus() != command.CommandSuccess:
      logging.debug("Volume Reconstruction: " + command.GetResponseMessage())
      return

    self.executeCommandDelayed(self.onVolumeReconstructedFinalize)

  def onVolumeReconstructedFinalize(self):
    applicationLogic = slicer.app.applicationLogic()
    applicationLogic.FitSliceToAll()
    self.guideletParent.showVolumeRendering(self.getOfflineVolumeRecNode())

  def onScoutVolumeReconstructed(self, command, q):
    self.printCommandResponse(command,q)

    if command.GetStatus() == command.CommandExpired:
      logging.fatal("Scout Volume Reconstruction: Timeout while waiting for scout volume reconstruction result")
      return

    self.startStopScoutScanButton.setIcon(self.recordIcon)
    self.startStopScoutScanButton.setText("  Scout Scan\n  Start Recording")
    self.startStopScoutScanButton.setEnabled(True)

    if command.GetStatus() != command.CommandSuccess:
      logging.debug("Scout Volume Reconstruction: " + command.GetResponseMessage())
      return

    self.executeCommandDelayed(self.onScoutVolumeReconstructedFinalize)

  def onScoutVolumeReconstructedFinalize(self):
    # Create and initialize ROI after scout scan because low resolution scout scan is used to set
    # a smaller ROI for the live high resolution reconstruction
    self.roiNode = self.logic.onRoiInitialization(self.SCOUT_VOLUME_NODE_NAME, self.roiNode)
    self.roiOrigin, self.roiExtent = self.logic.updateVolumeOriginAndExtentFromROI(self.LIVE_OUTPUT_VOLUME_SPACING,
                                                                                   self.roiNode)
    scoutScanVolumeNode = self.getScoutVolumeNode()

    applicationLogic = slicer.app.applicationLogic()
    applicationLogic.FitSliceToAll()

    self.guideletParent.showVolumeRendering(scoutScanVolumeNode)

  def onSnapshotAcquired(self, command, q):
    self.printCommandResponse(command,q)

    if not self.startStopLiveReconstructionButton.isChecked():
      # live volume reconstruction is not active
      return

    self.executeCommandDelayed(self.onSnapshotAcquiredFinalize)

  def onSnapshotAcquiredFinalize(self):
    self.guideletParent.showVolumeRendering(self.getLiveVolumeRecNode())
    self.snapshotTimer.start(self.SNAPSHOT_INTERVAL*1000)

  def onVolumeLiveReconstructed(self, command, q):
    self.printCommandResponse(command,q)

    if command.GetStatus() == command.CommandExpired:
      logging.fatal("LIVE Volume Reconstruction: Failed to stop volume reconstruction")
      return

    if command.GetStatus() != command.CommandSuccess:
      logging.debug("LIVE Volume Reconstruction " + command.GetResponseMessage())
      return

    self.executeCommandDelayed(self.getLiveVolumeRecNode)

  def onVolumeLiveReconstructedFinalize(self):
    self.guideletParent.showVolumeRendering(self.getLiveVolumeRecNode())