def test_convert_works_with_fulldate_normal_ordering(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        dateConverter.setIsIsoOrdered(False)

        dateConverter.setDateSeparator(".")

        rawDates = [
            "1.3.2004", "12. 4. 1987", " 26. 4. 2006 ", "04.6.1969",
            "6.07.2010"
        ]
        expectedDates = [
            "2004-03-01", "1987-04-12", "2006-04-26", "1969-06-04",
            "2010-07-06"
        ]

        works = True
        i = 0
        for date in rawDates:
            result = dateConverter.convert(date)
            if expectedDates[i] != result:
                works = False
                break
            i = i + 1

        self.assertTrue(works)
    def test_convert_works_with_fulldate_normal_ordering(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        dateConverter.setIsIsoOrdered(False)

        dateConverter.setDateSeparator(".")

        rawDates = ["1.3.2004", "12. 4. 1987", " 26. 4. 2006 ", "04.6.1969", "6.07.2010"]
        expectedDates = ["2004-03-01", "1987-04-12", "2006-04-26", "1969-06-04", "2010-07-06"]

        works = True
        i = 0
        for date in rawDates:
            result = dateConverter.convert(date)
            if expectedDates[i] != result:
                works = False
                break
            i = i + 1

        self.assertTrue(works)
    def test_ispartialdate_is_false_when_fulldate_provided(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        isPartialDate = dateConverter.isPartialDate()

        self.assertTrue(not isPartialDate)
    def test_isfulldate_is_true_when_fulldate_provided(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        isFullDate = dateConverter.isFullDate()

        self.assertTrue(isFullDate)
    def test_ispartialdate_is_false_when_fulldate_provided(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        isPartialDate = dateConverter.isPartialDate()

        self.assertTrue(not isPartialDate)
    def test_isfulldate_is_true_when_fulldate_provided(self):
        """
        """
        dateConverter = DateConverter()
        dateConverter.setHasDayComponet(True)
        dateConverter.setHasMonthComponet(True)
        dateConverter.setHasYearComponet(True)

        isFullDate = dateConverter.isFullDate()

        self.assertTrue(isFullDate)
Beispiel #7
0
class ExportFieldMappingDialog(QtGui.QDialog):
    """Export Field Mapping dialog
    """

    #----------------------------------------------------------------------
    #--------------------------- Constructors -----------------------------

    def __init__(self, parent=None):
        """
        """
        QtGui.QDialog.__init__(self, parent)

        #------------------------------------------------------
        #-------------------- GUI -----------------------------
        self.width = 700
        self.height = 600
        self.setFixedSize(self.width, self.height)
        self.setWindowTitle("Map data field to metadata field for export")

        # Dialog layout root
        rootLayout = QtGui.QVBoxLayout(self)

        # Metadata field for mapping UI
        rootLayout.addWidget(self.__setupMetadataFieldUI())
        # Date Tranformation UI
        rootLayout.addWidget(self.__setupDateTransformationGroupUI())
        # Float Transformation UI
        rootLayout.addWidget(self.__setupFloatTransformationGroupUI())
        # Code List Transformation UI
        rootLayout.addWidget(self.__setupCodeListTransformationGroupUI())
        # Data mapping preview UI
        rootLayout.addWidget(self.__setupDataMappingPreviewUI())

        # Dialog buttons
        btnLayout = QtGui.QGridLayout()
        btnLayout.setSpacing(10)
        rootLayout.addLayout(btnLayout)

        self.btnOk = QtGui.QPushButton("Ok")
        self.btnCancel = QtGui.QPushButton("Cancel")

        btnLayout.addWidget(self.btnOk, 1, 0)
        btnLayout.addWidget(self.btnCancel, 1, 1)

        #----------------------------------------------------------
        #----------------- Event handlers -------------------------

        self.btnOk.clicked.connect(self.handleOk)
        self.btnCancel.clicked.connect(self.handleCancel)

        #-----------------------------------------------------------
        #------------------ View Models ----------------------------
        self.dataHeaders = []
        self.dataMapping = None
        self.dataService = None

    #----------------------------------------------------------------------
    #--------------------------- Setup UI  --------------------------------

    def __setupMetadataFieldUI(self):
        """
        """
        # Dialog grid
        layout = QtGui.QGridLayout()
        self.metadataFieldGroup = QtGui.QGroupBox('Metadata field:')
        self.metadataFieldGroup.setLayout(layout)

        lblMetadataFieldText = QtGui.QLabel("Study metadata field: ")
        self.lblMetadataField = QtGui.QLabel()

        lblMetadataDataFormat = QtGui.QLabel("Study metadata format:")
        self.lblMetadataFieldFormat = QtGui.QLabel()

        lblDataFieldText = QtGui.QLabel("Assign to data field: ")
        self.cmbDataFields = QtGui.QComboBox()

        # Add to layout
        layout.addWidget(lblMetadataFieldText, 0, 0)
        layout.addWidget(self.lblMetadataField, 0, 1)

        layout.addWidget(lblMetadataDataFormat, 1, 0)
        layout.addWidget(self.lblMetadataFieldFormat, 1, 1)

        layout.addWidget(lblDataFieldText, 2, 0)
        layout.addWidget(self.cmbDataFields, 2, 1)

        self.cmbDataFields.currentIndexChanged['QString'].connect(
            self.cmbDataFieldsChanged)

        return self.metadataFieldGroup

    def __setupDateTransformationGroupUI(self):
        """
        """
        # Date transformation UI
        dateTransformationLayout = QtGui.QGridLayout()
        self.dateTransformationGroup = QtGui.QGroupBox(
            "Date format transformation:")
        self.dateTransformationGroup.setLayout(dateTransformationLayout)

        self.chbYear = QtGui.QCheckBox("year")
        self.chbMonth = QtGui.QCheckBox("month")
        self.chbDay = QtGui.QCheckBox("day")
        dateStructureGroup = QtGui.QGroupBox("Raw data date consists of: ")
        dateStructureBox = QtGui.QVBoxLayout()
        dateStructureGroup.setLayout(dateStructureBox)
        dateStructureBox.addWidget(self.chbYear)
        dateStructureBox.addWidget(self.chbMonth)
        dateStructureBox.addWidget(self.chbDay)
        dateStructureBox.addStretch(1)

        self.rbtnDash = QtGui.QRadioButton("-")
        self.rbtnDot = QtGui.QRadioButton(".")
        self.rbtnSlash = QtGui.QRadioButton("/")
        dateSeparatorGroup = QtGui.QGroupBox("Date separator is: ")
        dateSeparatorBox = QtGui.QVBoxLayout()
        dateSeparatorGroup.setLayout(dateSeparatorBox)
        dateSeparatorBox.addWidget(self.rbtnDash)
        dateSeparatorBox.addWidget(self.rbtnDot)
        dateSeparatorBox.addWidget(self.rbtnSlash)
        dateSeparatorBox.addStretch(1)

        self.rbtnDayYear = QtGui.QRadioButton("day-month-year")
        self.rbtnYearDay = QtGui.QRadioButton("year-month-day")
        dateOrderGroup = QtGui.QGroupBox("Date order is: ")
        dateOrderBox = QtGui.QVBoxLayout()
        dateOrderGroup.setLayout(dateOrderBox)
        dateOrderBox.addWidget(self.rbtnDayYear)
        dateOrderBox.addWidget(self.rbtnYearDay)
        dateOrderBox.addStretch(1)

        dateTransformationLayout.addWidget(dateStructureGroup, 0, 0)
        dateTransformationLayout.addWidget(dateSeparatorGroup, 0, 1)
        dateTransformationLayout.addWidget(dateOrderGroup, 0, 2)

        self.chbYear.stateChanged.connect(self.chbYearStateChanged)
        self.chbMonth.stateChanged.connect(self.chbMonthStateChanged)
        self.chbDay.stateChanged.connect(self.chbDayStateChanged)

        self.rbtnDash.toggled.connect(self.rbtnDashToggled)
        self.rbtnDot.toggled.connect(self.rbtnDotToggled)
        self.rbtnSlash.toggled.connect(self.rbtnSlashToggled)

        self.rbtnDayYear.toggled.connect(self.rbtnDayYearToggled)
        self.rbtnYearDay.toggled.connect(self.rbtnYearDayToggled)

        return self.dateTransformationGroup

    def __setupFloatTransformationGroupUI(self):
        """
        """
        # Float transformation UI
        floatTransformationLayout = QtGui.QGridLayout()
        self.floatTransformationGroup = QtGui.QGroupBox(
            "Float format transformation: ")
        self.floatTransformationGroup.setLayout(floatTransformationLayout)

        self.rbtnFloatComma = QtGui.QRadioButton(",")
        self.rbtnFloatDot = QtGui.QRadioButton(".")
        floatSeparatorGroup = QtGui.QGroupBox("Floating number delimiter is: ")
        # TODO: GroupBox seems to add a margin which does not look nice in GUI
        floatSeparatorBox = QtGui.QHBoxLayout()
        floatSeparatorGroup.setLayout(floatSeparatorBox)
        floatSeparatorBox.addWidget(self.rbtnFloatComma)
        floatSeparatorBox.addWidget(self.rbtnFloatDot)
        floatSeparatorBox.addStretch(1)

        floatTransformationLayout.addWidget(floatSeparatorGroup, 0, 0)

        self.rbtnFloatComma.toggled.connect(self.rbtnFloatCommaToggled)
        self.rbtnFloatDot.toggled.connect(self.rbtnFloatDotToggled)

        return self.floatTransformationGroup

    def __setupCodeListTransformationGroupUI(self):
        """
        """
        # Code transformation UI
        codeListTransformationLayout = QtGui.QGridLayout()

        self.codeListTransformationGroup = QtGui.QGroupBox(
            'Code list format transformation:')
        self.codeListTransformationGroup.setLayout(
            codeListTransformationLayout)

        lblUseCodeListText = QtGui.QLabel(
            "Use metadata defined code list to encode data:\n (Raw data is not coded according to list)"
        )
        chbUseCodeList = QtGui.QCheckBox()

        lblCodeListText = QtGui.QLabel(
            "Defined code list for this data item: ")
        self.tvCodeList = QtGui.QTableView()

        codeListTransformationLayout.addWidget(lblUseCodeListText, 0, 0)
        codeListTransformationLayout.addWidget(chbUseCodeList, 0, 1)

        codeListTransformationLayout.addWidget(lblCodeListText, 1, 0)
        codeListTransformationLayout.addWidget(self.tvCodeList, 1, 1)

        chbUseCodeList.stateChanged.connect(self.chbUseCodeListChanged)

        return self.codeListTransformationGroup

    def __setupDataMappingPreviewUI(self):
        """
        """
        # Data mapping preview UI
        previewLayout = QtGui.QGridLayout()
        self.previewGroup = QtGui.QGroupBox('Data mapping preview:')
        self.previewGroup.setLayout(previewLayout)

        btnValidateMapping = QtGui.QPushButton("Validate mapping")

        self.tvDataMappingPreview = QtGui.QTableView()

        previewLayout.addWidget(btnValidateMapping, 1, 0)
        previewLayout.addWidget(self.tvDataMappingPreview, 2, 0, 2, 1)

        btnValidateMapping.clicked.connect(self.btnValidateMappingClicked)

        return self.previewGroup

    #----------------------------------------------------------------------
    #--------------------------- Set View Model ---------------------------

    def setData(self, dataMapping, dataHeaders):
        """
        """
        # Data bidned to dialog UI
        self.dataHeaders = dataHeaders
        self.dataMapping = dataMapping

        self.lblMetadataField.setText(dataMapping.metadata)
        self.lblMetadataFieldFormat.setText(dataMapping.dataType)

        self.cmbDataFields.addItems(self.dataHeaders)

        # Visibility of UI depended on type dataFormat of metadata element
        # Date format
        if dataMapping.dataType == "partialDate" or dataMapping.dataType == "date":
            self.dateConverter = DateConverter()

            self.dataMapping.setConverter(self.dateConverter)

            self.dateTransformationGroup.setVisible(True)
            self.floatTransformationGroup.setVisible(False)
            self.codeListTransformationGroup.setVisible(False)
        # Float format
        elif dataMapping.dataType == "float":
            self.floatConverter = FloatConverter()

            self.dataMapping.setConverter(self.floatConverter)

            self.floatTransformationGroup.setVisible(True)
            self.dateTransformationGroup.setVisible(False)
            self.codeListTransformationGroup.setVisible(False)
        # Integer format - needed for coded list
        elif dataMapping.dataType == "integer" and dataMapping.codeList is not None:
            self.codeListTransformationGroup.setVisible(True)
            self.dateTransformationGroup.setVisible(False)
            self.floatTransformationGroup.setVisible(False)

            codeListModel = QtGui.QStandardItemModel()
            codeListModel.setHorizontalHeaderLabels(
                ["Metadata values", "Meaning"])

            if self.dataMapping.codeList is not None:
                row = 0
                for itm in self.dataMapping.codeList.listItems:
                    iCodedValue = QtGui.QStandardItem(itm.codedValue)
                    iDecodedValue = QtGui.QStandardItem(itm.decodedValue)
                    codeListModel.setItem(row, 0, iCodedValue)
                    codeListModel.setItem(row, 1, iDecodedValue)
                    row = row + 1

            self.tvCodeList.setModel(codeListModel)
            self.tvCodeList.resizeColumnsToContents()

        #If neccessary also for text, URI
        else:
            self.dateTransformationGroup.setVisible(False)
            self.floatTransformationGroup.setVisible(False)
            self.codeListTransformationGroup.setVisible(False)

    #----------------------------------------------------------------------
    #------------------- Code List Form Event Handlers -------------------------

    def chbUseCodeListChanged(self, state):
        """
        """
        if state == QtCore.Qt.Checked:
            self.dataMapping.setUseCodeListToEncodeData(True)
        else:
            self.dataMapping.setUseCodeListToEncodeData(False)

    #----------------------------------------------------------------------
    #------------------- Date Form Event Handlers -------------------------

    def chbYearStateChanged(self, state):
        """
        """
        if state == QtCore.Qt.Checked:
            self.dateConverter.setHasYearComponet(True)
        else:
            self.dateConverter.setHasYearComponet(False)

    def chbMonthStateChanged(self, state):
        """
        """
        if state == QtCore.Qt.Checked:
            self.dateConverter.setHasMonthComponet(True)
        else:
            self.dateConverter.setHasMonthComponet(False)

    def chbDayStateChanged(self, state):
        """
        """
        if state == QtCore.Qt.Checked:
            self.dateConverter.setHasDayComponet(True)
        else:
            self.dateConverter.setHasDayComponet(False)

    def rbtnDashToggled(self, enabled):
        if enabled:
            self.dateConverter.setDateSeparator("-")

    def rbtnDotToggled(self, enabled):
        if enabled:
            self.dateConverter.setDateSeparator(".")

    def rbtnSlashToggled(self, enabled):
        if enabled:
            self.dateConverter.setDateSeparator("/")

    def rbtnDayYearToggled(self, enabled):
        if enabled:
            self.dateConverter.setIsIsoOrdered(False)

    def rbtnYearDayToggled(self, enabled):
        if enabled:
            self.dateConverter.setIsIsoOrdered(False)

    #----------------------------------------------------------------------
    #------------------- Float Form Event Handlers ------------------------

    def rbtnFloatCommaToggled(self, enabled):
        if enabled:
            self.floatConverter.setFloatingNumberDelimiter(",")

    def rbtnFloatDotToggled(self, enabled):
        if enabled:
            self.floatConverter.setFloatingNumberDelimiter(".")

    #----------------------------------------------------------------------
    #------------------- Preview Form Event Handlers ------------------------

    def btnValidateMappingClicked(self):
        """
        """
        errors = []

        row = 0
        for data in self.dataValues:
            try:
                transformedData = self.dataMapping.map(data)
                itemTransformedData = QtGui.QStandardItem(transformedData)

                #TODO: if it has code list check if itemTransformedData has a value from coded list

                self.model.setItem(row, 1, itemTransformedData)
                row = row + 1
            except ValueError as detail:
                errors.append("Conversion error on line " + str(row + 1) +
                              " details: " + detail)
                row = row + 1

        self.tvDataMappingPreview.setModel(self.model)
        self.tvDataMappingPreview.resizeColumnsToContents()

        if errors is not []:
            pass
            # TODO: show dialog vith list of errors occured during mapping

    def cmbDataFieldsChanged(self, text):
        """
        """
        # Selected data to map to metadata
        self.dataMapping.data = first.first(dataHeader
                                            for dataHeader in self.dataHeaders
                                            if dataHeader == text)

        # Now extract data values from data file according to selection
        self.dataValues = []

        # Load data values from data file according to selection
        for i in range(1, self.dataService.size()):
            dataRow = self.dataService.getRow(i)
            dataIndex = self.dataService.headers.index(self.dataMapping.data)
            dataValue = dataRow[dataIndex]

            self.dataValues.append(dataValue)

        # Create view model for preview table view
        self.model = QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(
            ["Raw Data", "Mapping transformed data"])

        row = 0
        for data in self.dataValues:
            itemDataField = QtGui.QStandardItem(data)
            itemTransformedData = QtGui.QStandardItem("")
            self.model.setItem(row, 0, itemDataField)
            self.model.setItem(row, 1, itemTransformedData)
            row = row + 1

        self.tvDataMappingPreview.setModel(self.model)
        self.tvDataMappingPreview.resizeColumnsToContents()

    #----------------------------------------------------------------------
    #------------------- Dialog Buttons Handlers --------------------------

    def handleOk(self):
        """OK Button Click
        """
        if (self.dataMapping.isComplete()):
            self.accept()
        else:
            QtGui.QMessageBox.warning(
                self, 'Error',
                'Specified data mapping for this metadata field is not complete.'
            )

    def handleCancel(self):
        """Cancel Button Click
        """
        self.reject()