def openProject(self, folderName=None):
        """
		If no project name is supplied, it will open a file dialog so
		that the user can select a project file
		or project folder.

		:param folderName: Name of a folder with a project
		:type folderName: basestring
		"""
        fileName = ""
        if folderName:
            fileName = folderName
        else:
            fileName = QFileDialog.getExistingDirectory(
                self, "Open project", "", QFileDialog.ShowDirsOnly)

        if len(fileName) > 0:
            fullName = fileName + ProjectController.Instance().ProjectFile
            if os.path.isfile(fullName):
                self.multiDataWidget.transformations.clear()
                loaded = ProjectController.Instance().loadProject(fileName)
                if loaded:
                    RegistrationShop.settings.setValue("project/lastProject",
                                                       fileName)
                else:
                    print "Couldn't load project:", folderName
            else:
                print "Warning: Project file does not exist"
                RegistrationShop.settings.remove("project/lastProject")
    def setRenderWidgets(self, fixed=None, moving=None, multi=None):
        self.fixedWidget = fixed
        self.movingWidget = moving
        self.multiWidget = multi

        self.fixedPicker.setWidget(self.fixedWidget)
        self.movingPicker.setWidget(self.movingWidget)

        self.fixedPicker.pickedLocation.connect(self.pickedFixedLocation)
        self.movingPicker.pickedLocation.connect(self.pickedMovingLocation)

        # Save the original complete transform
        self.originalTransform = self.multiWidget.transformations.completeTransform(
        )
        self.originalScalingTransform = self.multiWidget.transformations.scalingTransform(
        )

        # Add a new transform on top of the others
        currentProject = ProjectController.Instance().currentProject
        transform = Transformation(vtkTransform(), Transformation.TypeLandmark,
                                   currentProject.movingData)
        self.multiWidget.transformations.append(transform)

        statusWidget = StatusWidget.Instance()
        statusWidget.setText(
            "Place landmarks in both volumes to create a landmark transform. "
            "Available methods for placing landmarks are the surface type and the two-step type."
        )
    def testSavingAndLoadingProjectsToDisk(self):
        projectController = ProjectController.Instance()

        # Save the project in the current directory
        path = os.path.dirname(os.path.abspath(__file__))
        projectPath = path + "/project"
        if not os.path.exists(projectPath):
            os.makedirs(projectPath)
        projectController.currentProject.title = "Unique title"
        projectController.currentProject.folder = unicode(projectPath)
        projectController.saveProject()

        # Reset the project controller
        projectController.newProject()
        self.assertIsNone(projectController.currentProject.title)
        self.assertIsNone(projectController.currentProject.folder)

        # Test for existance of a project file in the project folder
        self.assertTrue(os.path.exists(projectPath + "/project.yaml"))
        self.assertTrue(projectController.loadProject(projectPath))

        # Load the project again from disk
        projectController.loadProject(projectPath)
        self.assertIsNotNone(projectController.currentProject.title)
        self.assertIn("Unique", projectController.currentProject.title)

        try:
            os.remove(projectPath + "/project.yaml")
        except Exception:
            self.assertTrue(False)
    def exportDataAs(self):
        """
		Opens a file dialog so that the user can provide a filename
		for saving the transformed dataset to.
		"""
        fileType = FileTypeDialog.getFileType(self,
                                              "Choose file type for export")
        if len(fileType) == 0:
            return

        extension = "(*." + fileType + ")"
        fileName, other = QFileDialog.getSaveFileName(
            self, "Save registration result to...", "", extension)
        if len(fileName) == 0:
            return

        self.showProgressBar("Exporting data...")

        transform = self.multiDataWidget.transformations.completeTransform()
        dataReader = DataReader()
        imageData = dataReader.GetImageData(
            ProjectController.Instance().currentProject.movingData)
        transformer = DataTransformer()
        outputData = transformer.TransformImageData(imageData, transform)
        writer = DataWriter()
        writer.WriteToFile(outputData, fileName, fileType)

        self.hideProgressBar()
    def loadMovingDataSetFile(self):
        """
		Open file dialog to search for data files. If valid data is given, it will
		pass the data file location on to the slicer and the project controller.
		"""
        dataReader = DataReader()
        extensions = dataReader.GetSupportedExtensionsAsString()
        fileName, other = QFileDialog.getOpenFileName(
            self,
            "Open moving data set",
            "",
            "Images (" + extensions + ")",
            options=QFileDialog.Directory)
        if len(fileName) > 0:
            # If there was another dataset first, ask if the user if the
            # visualizations should be reset
            projectController = ProjectController.Instance()
            if projectController.currentProject.movingData:
                dialog = ResetVisualizationDialog(self)
                dialog.setWindowModality(Qt.WindowModal)
                dialog.exec_()
                if dialog.result is not None:
                    projectController.loadMovingDataSet(fileName)
                    if dialog.result:
                        self.movingRenderController.resetVisualizations()
            else:
                # Inserting an identity transform
                self.multiDataWidget.transformations.append(
                    Transformation(vtkTransform(), "No transform", fileName))
                projectController.loadMovingDataSet(fileName)
    def newProject(self):
        """
		Create new project by calling the project controller
		"""
        self.multiDataWidget.transformations.clear()
        ProjectController.Instance().newProject()
        # Reset the last loaded project in the settings
        RegistrationShop.settings.setValue("project/lastProject", "")
    def setRenderWidgets(self, fixed=None, moving=None, multi=None):
        self.movingWidget = moving
        self.renderWidget = multi
        currentProject = ProjectController.Instance().currentProject
        self.transformBox.setWidget(self.renderWidget)
        self.transformBox.setImageData(self.renderWidget.movingImageData)
        self.renderWidget.transformations.append(
            Transformation(vtkTransform(), Transformation.TypeUser,
                           currentProject.movingData))

        statusWidget = StatusWidget.Instance()
        statusWidget.setText(
            "Use the box widget to transform the volume. "
            "For more specific control of the transformation, use the matrix values to specify the transform."
        )
    def saveProjectAs(self):
        """
		Opens a file dialog so that the user can select a folder
		in which to save the project.
		"""
        # Open file dialog
        fileName = QFileDialog.getExistingDirectory(self,
                                                    "Select project folder",
                                                    "",
                                                    QFileDialog.ShowDirsOnly)
        if len(fileName) > 0:
            # TODO: check for existing project!

            # Set filename of project
            ProjectController.Instance().currentProject.folder = fileName
            # Call save project
            self.saveProject()
    def __init__(self, args):
        """
		Sets app specific properties.
		Initializes the UI.
		"""
        super(RegistrationShop, self).__init__(args)

        self.setApplicationPath()
        # Instantiate the project controller
        ProjectController.Instance()

        # Initialize the user interface
        self.initUI()

        lastProject = RegistrationShop.settings.value("project/lastProject",
                                                      None)
        if lastProject:
            self.openProject(lastProject)
    def startComparison(self):
        projectController = ProjectController.Instance()
        project = projectController.currentProject
        if not project or not project.fixedData or not project.movingData:
            statusWidget = StatusWidget.Instance()
            statusWidget.setText(
                "Could not start comparison. Please make a project first"
                " and make sure to load two datasets.")
            return

        if hasattr(self, "compareWidget"):
            del self.compareWidget

        transform = self.multiDataWidget.transformations.completeTransform()

        self.controller = ComparisonController()
        self.controller.setInputData(project.fixedData, project.movingData,
                                     transform)
        self.compareWidget = CompareWidget(self.controller.widgets)
        self.compareWidget.show()
        self.controller.initialize()
        self.controller.slicerChanged(self.controller.fixedImageWidget)
    def saveProject(self):
        """
		Save the project to the specified name in the current project. If no name
		is specified, then 'save project as' is called.
		"""
        projCont = ProjectController.Instance()

        if projCont.currentProject.folder is not None:
            # Save that project
            saved = projCont.saveProject()
            statusWidget = StatusWidget.Instance()
            if saved:
                # Save it in the settings that this was the last opened project
                RegistrationShop.settings.setValue(
                    "project/lastProject", projCont.currentProject.folder)
                statusWidget.setText(
                    "The project was succesfully saved to disk.")
            else:
                statusWidget.setText(
                    "Something went wrong while saving the project to disk. "
                    "Please try to save the project again.")
        else:
            self.saveProjectAs()
    def connectElements(self):
        """
		All the elements have to be connected because they are dependent
		on each other.
		There is the project controller, two render controllers and a multi render
		controller.
		Also there are two render widgets and a multi render widget. Together with some
		parameter widgets that show settings and with which the user can interact.
		"""
        projectController = ProjectController.Instance()
        projectController.fixedFileChanged.connect(
            self.fixedRenderController.setFile)
        projectController.fixedFileChanged.connect(
            self.multiRenderController.setFixedFile)
        projectController.movingFileChanged.connect(
            self.movingRenderController.setFile)
        projectController.movingFileChanged.connect(
            self.multiRenderController.setMovingFile)
        projectController.fixedSettingsChanged.connect(
            self.fixedRenderController.setRenderSettings)
        projectController.movingSettingsChanged.connect(
            self.movingRenderController.setRenderSettings)
        projectController.multiSettingsChanged.connect(
            self.multiRenderController.setRenderSettings)

        self.fixedRenderController.visualizationChanged.connect(
            self.multiRenderController.setFixedVisualization)
        self.fixedRenderController.visualizationUpdated.connect(
            self.multiRenderController.setFixedVisualization)
        self.movingRenderController.visualizationChanged.connect(
            self.multiRenderController.setMovingVisualization)
        self.movingRenderController.visualizationUpdated.connect(
            self.multiRenderController.setMovingVisualization)

        self.multiDataWidget.transformations.transformationChanged.connect(
            self.movingDataWidget.transformationsUpdated)
    def applyTransform(self):
        """
		* Show progress bar dialog
		* Define folder for output (projectFolder/data/result-<id>/.)
		* Write parameter file to output folder
		* Call elastix to process the data
		* Load the new data into the moving widget / project
		"""
        statusWidget = StatusWidget.Instance()
        statusWidget.setText(
            "Please grab a cup of coffee while Elastix " +
            "performs the registration: this might take a while...")

        self.startedElastix.emit("Transforming data...")

        projectController = ProjectController.Instance()
        currentProject = projectController.currentProject
        path = currentProject.folder

        if not path:
            statusWidget.setText(
                "Please create and save a project first so "
                "that the results of the registration can be saved to disk.")
            return

        # Determine filename + folder for new dataset (projectFolder/data/result-<id>/.)
        dataFolder = os.path.join(path, "data")
        filenames = os.listdir(dataFolder) if os.path.isdir(dataFolder) else []
        resultId = 0
        for filename in filenames:
            if os.path.isdir(os.path.join(dataFolder,
                                          filename)) and "result" in filename:
                resultId += 1
        outputFolder = os.path.join(dataFolder, "result-" + str(resultId))

        parameterFilePath = os.path.join(outputFolder, "Parameters.txt")
        initialTransformPath = os.path.join(outputFolder,
                                            "InitialTransformation.txt")

        # Iterate over the parameters to ensure that some parameters are adjusted
        # according to the data from the project
        for i in range(len(self.transformation)):
            param = self.transformation[i]
            if param.key() == "DefaultPixelValue":
                # Set the default pixel value to minimum scalar value
                scalarRange = self.movingWidget.imageData.GetScalarRange()
                param.setValue(scalarRange[0])
            if param.key() == "ResultImagePixelType":
                # Set the resulting image pixel type to the type of the input data
                pixelType = self.movingWidget.imageData.GetScalarTypeAsString()
                param.setValue(pixelType)

        self.transformation.saveToFile(parameterFilePath)
        transform = self.multiWidget.transformations.completeTransform()
        dataset = ProjectController.Instance().currentProject.movingData
        initialTransform = TransformixTransformation(
            dataset, transform).transformation()
        if initialTransform:
            initialTransform.saveToFile(initialTransformPath)
        else:
            initialTransformPath = None

        command = ElastixCommand(fixedData=currentProject.fixedData,
                                 movingData=currentProject.movingData,
                                 outputFolder=outputFolder,
                                 transformation=parameterFilePath,
                                 initialTransformation=initialTransformPath)

        self.operator = Operator()
        self.operator.addCommand(command)
        self.operator.queue.join()

        self.endedElastix.emit()

        # Assume that there is only one resulting dataset: result.0.mhd
        outputData = os.path.join(outputFolder, "result.0.mhd")
        if os.path.exists(outputData):
            statusWidget.setText(
                "Thanks for your patience. The " +
                "transformed data will now be loaded. It can be found in the project folder."
            )

            transformation = Transformation(vtkTransform(),
                                            Transformation.TypeDeformable,
                                            outputData)
            self.multiWidget.transformations.append(transformation)
            projectController.loadMovingDataSet(outputData)
        else:
            statusWidget.setText(
                "Something went wrong. Please see the project folder for the "
                + "elastix log to see what went wrong.")
            from subprocess import call
            call(["open", outputFolder])
    def testProjectController(self):
        projectController = ProjectController.Instance()
        self.assertIsNotNone(projectController.currentProject)

        projectController.newProject()
        self.assertIsNone(projectController.currentProject.title)
    def createElements(self):
        """
		Creates the widgets and docks of which the
		main window is composed.
		"""
        self.mainWindow = QMainWindow()
        projectController = ProjectController.Instance()
        self.transformTool = None

        # Render widgets
        self.fixedDataWidget = RenderWidget()
        self.movingDataWidget = RenderWidget()
        self.multiDataWidget = MultiRenderWidget()

        self.fixedRenderController = RenderController(self.fixedDataWidget,
                                                      "fixed")
        self.movingRenderController = RenderController(self.movingDataWidget,
                                                       "moving")
        self.multiRenderController = MultiRenderController(
            self.multiDataWidget)

        # Give references of the render controllers to the project controller
        projectController.fixedRenderController = self.fixedRenderController
        projectController.movingRenderController = self.movingRenderController
        projectController.multiRenderController = self.multiRenderController

        # Render properties widgets
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)

        self.fixedPropWidget = RenderPropWidget(self.fixedRenderController,
                                                parent=self)
        self.fixedPropWidget.setSizePolicy(sizePolicy)
        self.fixedPropWidget.setFileChangedSignal(
            projectController.fixedFileChanged)
        self.fixedPropWidget.setLoadDataSlot(self.loadFixedDataSetFile)

        self.movingPropWidget = RenderPropWidget(self.movingRenderController,
                                                 parent=self)
        self.movingPropWidget.setSizePolicy(sizePolicy)
        self.movingPropWidget.setFileChangedSignal(
            projectController.movingFileChanged)
        self.movingPropWidget.setLoadDataSlot(self.loadMovingDataSetFile)

        self.multiPropWidget = MultiRenderPropWidget(
            self.multiRenderController, parent=self)
        self.multiPropWidget.setSizePolicy(sizePolicy)

        self.verticalSplitter = QSplitter()
        self.verticalSplitter.setOrientation(Qt.Vertical)

        # Create the layouts

        fixedDataTitleWidget = TitleWidget("Fixed volume")
        multiDataTitleWidget = TitleWidget("Fixed + Moving")
        movingDataTitleWidget = TitleWidget("Moving volume")

        fixedLayout = QGridLayout()
        fixedLayout.setSpacing(0)
        fixedLayout.setContentsMargins(0, 0, 0, 0)
        fixedLayout.addWidget(fixedDataTitleWidget)
        fixedLayout.addWidget(self.fixedDataWidget)
        fixedWidget = QWidget()
        fixedWidget.setLayout(fixedLayout)

        multiLayout = QGridLayout()
        multiLayout.setSpacing(0)
        multiLayout.setContentsMargins(0, 0, 0, 0)
        multiLayout.addWidget(multiDataTitleWidget)
        multiLayout.addWidget(self.multiDataWidget)
        multiWidget = QWidget()
        multiWidget.setLayout(multiLayout)

        movingLayout = QGridLayout()
        movingLayout.setSpacing(0)
        movingLayout.setContentsMargins(0, 0, 0, 0)
        movingLayout.addWidget(movingDataTitleWidget)
        movingLayout.addWidget(self.movingDataWidget)
        movingWidget = QWidget()
        movingWidget.setLayout(movingLayout)

        horizontalSplitter = QSplitter()
        horizontalSplitter.setOrientation(Qt.Horizontal)
        horizontalSplitter.addWidget(fixedWidget)
        horizontalSplitter.addWidget(multiWidget)
        horizontalSplitter.addWidget(movingWidget)

        propsLayout = QHBoxLayout()
        propsLayout.setSpacing(1)
        propsLayout.setContentsMargins(0, 0, 0, 0)
        propsLayout.addWidget(self.fixedPropWidget)
        propsLayout.addWidget(self.multiPropWidget)
        propsLayout.addWidget(self.movingPropWidget)

        propsWidget = QWidget()
        propsWidget.setMinimumHeight(245)
        propsWidget.setMaximumHeight(350)
        propsWidget.setLayout(propsLayout)

        self.verticalSplitter.addWidget(horizontalSplitter)
        self.verticalSplitter.addWidget(propsWidget)
        self.verticalSplitter.setStretchFactor(0, 2)
        self.verticalSplitter.setStretchFactor(1, 1)
        self.setCentralWidget(self.verticalSplitter)