コード例 #1
0
    def __init__(self, parent=None):
        """Constructor of ExportModule View
        """
        QWidget.__init__(self, parent)
        self.parent = parent

        #-----------------------------------------------------------------------
        #----------------------- Logger ----------------------------------------
        self.logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)
        #-----------------------------------------------------------------------
        #---------------------- App config --------------------------------------
        self.appConfig = AppConfigurationService()
        #-----------------------------------------------------------------------
        #--------------------- Create Module UI --------------------------------
        self.setupUi(self)
        #-----------------------------------------------------------------------
        #----------------------- Services --------------------------------------
        # There are two http services, one for communicating with my own
        # site server/database
        section = "RadPlanBioServer"
        hostname = self.appConfig.get(section)["host"]
        port = self.appConfig.get(section)["port"]
        self.svcHttp = HttpConnectionService(hostname, port, UserDetails())

        #TODO: SiteName according to user account
        self.mySite = self.svcHttp.getPartnerSiteByName("DKTK-DRESDEN")
        baseUrl = self.mySite.edc.soapbaseurl

        # Create connection artefact to OC
        self.ocConnectInfo = OCConnectInfo(baseUrl, OCUserDetails().username)
        self.ocConnectInfo.setPassword(OCUserDetails().password)
        self.ocWebServices = OCWebServices(self.ocConnectInfo)

        # Create REST mainzellieste
        userName = self.mySite.pidg.adminusername
        password = self.mySite.pidg.adminpassword
        baseUrl = self.mySite.pidg.generatorbaseurl
        apiKey = self.mySite.pidg.apikey

        connectInfo = MainzellisteConnectInfo(baseUrl, userName, password,
                                              apiKey)
        self.svcPseudonymisation = PseudonymisationService(connectInfo)
        #-----------------------------------------------------------------------
        #----------------------- On Create -------------------------------------
        self.reloadSites()
        #-----------------------------------------------------------------------
        #---------- Load modules buttons - events definitions ------------------
        self.btnNew.clicked.connect(self.btnNewClicked)
        self.btnReload.clicked.connect(self.btnReloadClicked)
        self.tvStudies.selectionModel().currentChanged.connect(
            self.tvStudyChanged)
コード例 #2
0
    def prepareServices(self):
        """Prepare services for this module
        """
        # HTTP connection to RadPlanBio server (Database)
        self._svcHttp = HttpConnectionService(ConfigDetails().rpbHost,
                                              ConfigDetails().rpbHostPort,
                                              UserDetails())
        self._svcHttp.application = ConfigDetails().rpbApplication

        if ConfigDetails().proxyEnabled:
            self._svcHttp.setupProxy(ConfigDetails().proxyHost,
                                     ConfigDetails().proxyPort,
                                     ConfigDetails().noProxy)
        if ConfigDetails().proxyAuthEnabled:
            self._svcHttp.setupProxyAuth(ConfigDetails().proxyAuthLogin,
                                         ConfigDetails().proxyAuthPassword)

        # Read partner site of logged user
        self._mySite = self._svcHttp.getMyDefaultAccount().partnersite

        # Create connection artefact to users main OpenClinica SOAP
        baseUrl = self._mySite.edc.soapbaseurl
        self.ocConnectInfo = OCConnectInfo(baseUrl, OCUserDetails().username)
        self.ocConnectInfo.setPasswordHash(OCUserDetails().passwordHash)

        if ConfigDetails().proxyEnabled:
            self.ocWebServices = OCWebServices(
                self.ocConnectInfo,
                ConfigDetails().proxyHost,
                ConfigDetails().proxyPort,
                ConfigDetails().noProxy,
                ConfigDetails().proxyAuthLogin,
                ConfigDetails().proxyAuthPassword)
        else:
            self.ocWebServices = OCWebServices(self.ocConnectInfo)

        # ODM XML metadata processing
        self.fileMetaDataService = OdmFileDataService()
        # DICOM PROCESSING SERVICE
        self._svcDicom = DicomService()
コード例 #3
0
class CreateSubjectModule(QWidget, CreateSubjectModuleUI):
    """PullDataRequest Module view class
    """

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

    def __init__(self, parent=None):
        """Constructor of ExportModule View
        """
        QWidget.__init__(self, parent)
        self.parent = parent

        #-----------------------------------------------------------------------
        #----------------------- Logger ----------------------------------------
        self.logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)
        #-----------------------------------------------------------------------
        #---------------------- App config --------------------------------------
        self.appConfig = AppConfigurationService()
        #-----------------------------------------------------------------------
        #--------------------- Create Module UI --------------------------------
        self.setupUi(self)
        #-----------------------------------------------------------------------
        #----------------------- Services --------------------------------------
        # There are two http services, one for communicating with my own
        # site server/database
        section = "RadPlanBioServer"
        hostname = self.appConfig.get(section)["host"]
        port = self.appConfig.get(section)["port"]
        self.svcHttp = HttpConnectionService(hostname, port, UserDetails())

        #TODO: SiteName according to user account
        self.mySite = self.svcHttp.getPartnerSiteByName("DKTK-DRESDEN")
        baseUrl = self.mySite.edc.soapbaseurl

        # Create connection artefact to OC
        self.ocConnectInfo = OCConnectInfo(baseUrl, OCUserDetails().username)
        self.ocConnectInfo.setPassword(OCUserDetails().password)
        self.ocWebServices = OCWebServices(self.ocConnectInfo)

        # Create REST mainzellieste
        userName = self.mySite.pidg.adminusername
        password = self.mySite.pidg.adminpassword
        baseUrl = self.mySite.pidg.generatorbaseurl
        apiKey = self.mySite.pidg.apikey

        connectInfo = MainzellisteConnectInfo(baseUrl, userName, password,
                                              apiKey)
        self.svcPseudonymisation = PseudonymisationService(connectInfo)
        #-----------------------------------------------------------------------
        #----------------------- On Create -------------------------------------
        self.reloadSites()
        #-----------------------------------------------------------------------
        #---------- Load modules buttons - events definitions ------------------
        self.btnNew.clicked.connect(self.btnNewClicked)
        self.btnReload.clicked.connect(self.btnReloadClicked)
        self.tvStudies.selectionModel().currentChanged.connect(
            self.tvStudyChanged)

    #----------------------------------------------------------------------
    #------------------- Module buttons Handlers --------------------------

    def btnNewClicked(self):
        """
        """
        index = self.tabCreateSubjectModule.currentIndex()

        if index == 1:
            # Initialize dialog and bind data to UI
            dialog = NewSubjectDialog(self)
            dialog.svcPseudonymisation = self.svcPseudonymisation
            dialog.setData(self.selectedStudy, self.selectedStudySite)

            # Show dialog
            dialogResult = dialog.exec_()

            # When ok commit session transaction
            if dialogResult == QtGui.QDialog.Accepted:
                try:
                    newStudySubject = dialog.newStudySubject
                    self.ocWebServices.createStudySubject(
                        newStudySubject, self.selectedStudy,
                        self.selectedStudySite)
                except:
                    QtGui.QMessageBox.warning(self, 'Error',
                                              'OC study subject not created.')

            # Reload
            index = self.tabCreateSubjectModule.currentIndex()
            self.loadModuleData(index)
        elif index == 2:
            studyEvents = self.ocWebServices.listAllStydyEventDefinitionsByStudy(
                self.selectedStudy)

            dialog = NewEventDialog(self)
            dialog.setData(self.selectedStudy, self.selectedStudySite,
                           self.selectedSubject, studyEvents)

            # Show dialog
            dialogResult = dialog.exec_()

            # When ok commit session transaction
            if dialogResult == QtGui.QDialog.Accepted:
                #try:
                unsheduledEvent = dialog.selectedEvent
                self.ocWebServices.scheduleStudyEvent(self.selectedStudy,
                                                      self.selectedStudySite,
                                                      self.selectedSubject,
                                                      unsheduledEvent)
                #except:
                #    QtGui.QMessageBox.warning(self, 'Error', 'OC study event was not sheduled.')

            # Reload
            index = self.tabCreateSubjectModule.currentIndex()
            self.loadModuleData(index)

    def btnReloadClicked(self):
        """
        """
        index = self.tabCreateSubjectModule.currentIndex()
        self.loadModuleData(index)

    #----------------------------------------------------------------------
    #------------------- TableView Handlers -------------------------------

    def tvStudyChanged(self, current, previous):
        self.tvSubjects.setModel(None)

        index = current.row()

        self.selectedStudy = None
        self.selectedStudySite = None

        counter = 0
        found = False
        for study in self.studies:
            for site in study.sites:
                if counter == index:
                    self.selectedStudy = study
                    self.selectedStudySite = site
                    found = True
                    break
                else:
                    counter = counter + 1

            if found:
                break

        if found:
            self.reloadSubjects()

    def tvSubjectChanged(self, current, previous):
        index = current.row()

        self.selectedSubject = self.subjects[index]

        self.reloadEvents()

    def tvEventsChanged(self, current, previous):
        index = current.row()

        self.selectedEvent = self.events[index]

    #----------------------------------------------------------------------
    #------------------------ Module commands -----------------------------

    def loadModuleData(self, selectedIndex):
        if selectedIndex == 0:
            self.reloadSites()
            self.tvStudies.selectionModel().currentChanged.connect(
                self.tvStudyChanged)
        elif selectedIndex == 1:
            self.reloadSubjects()
            self.tvSubjects.selectionModel().currentChanged.connect(
                self.tvSubjectChanged)
        elif selectedIndex == 2:
            self.reloadSubjects()
            self.tvSubjects.selectionModel().currentChanged.connect(
                self.tvSubjectChanged)

            self.selectedSubject = first.first(
                subject for subject in self.subjects
                if subject.subject.uniqueIdentifier ==
                self.selectedSubject.subject.uniqueIdentifier)

            self.reloadEvents()
            self.tvEvents.selectionModel().currentChanged.connect(
                self.tvEventsChanged)

    def reloadSites(self):
        successfull, self.studies = self.ocWebServices.listAllStudies()

        # Quick way of crating simple viewModel
        self.studySitesModel = QtGui.QStandardItemModel()
        self.studySitesModel.setHorizontalHeaderLabels(
            ["OID", "Partner Site", "Study"])

        row = 0
        for study in self.studies:
            if len(study.sites) > 0:
                for site in study.sites:
                    siteOidValue = QtGui.QStandardItem(site.oid)
                    siteNameValue = QtGui.QStandardItem(site.name)
                    studyNameValue = QtGui.QStandardItem(study.name())

                    self.studySitesModel.setItem(row, 0, siteOidValue)
                    self.studySitesModel.setItem(row, 1, siteNameValue)
                    self.studySitesModel.setItem(row, 2, studyNameValue)

                    row = row + 1

        self.tvStudies.setModel(self.studySitesModel)
        self.tvStudies.resizeColumnsToContents()

    def reloadSubjects(self):
        self.subjects = self.ocWebServices.listAllStudySubjectsByStudySite(
            self.selectedStudy, self.selectedStudySite)

        # Quick way of crating simple viewModel
        self.subjectsModel = QtGui.QStandardItemModel()
        self.subjectsModel.setHorizontalHeaderLabels(
            ["PID", "Gender", "Enrollment date"])

        row = 0
        for studySubject in self.subjects:
            pidItem = QtGui.QStandardItem(
                studySubject.subject.uniqueIdentifier)
            genderItem = QtGui.QStandardItem(studySubject.subject.gender)
            enrollmentDateItem = QtGui.QStandardItem(
                studySubject.enrollmentDate)

            self.subjectsModel.setItem(row, 0, pidItem)
            self.subjectsModel.setItem(row, 1, genderItem)
            self.subjectsModel.setItem(row, 2, enrollmentDateItem)

            row = row + 1

        self.tvSubjects.setModel(self.subjectsModel)
        self.tvSubjects.resizeColumnsToContents()

    def reloadEvents(self):
        self.events = self.selectedSubject.events

        # Quick way of crating simple viewModel
        self.eventsModel = QtGui.QStandardItemModel()
        self.eventsModel.setHorizontalHeaderLabels(["Event OID", "Start date"])

        row = 0
        for event in self.events:
            oidItem = QtGui.QStandardItem(event.eventDefinitionOID)
            startDateItem = QtGui.QStandardItem(event.startDate.isoformat())

            self.eventsModel.setItem(row, 0, oidItem)
            self.eventsModel.setItem(row, 1, startDateItem)

            row = row + 1

        self.tvEvents.setModel(self.eventsModel)
        self.tvEvents.resizeColumnsToContents()
コード例 #4
0
class DicomDownloadModule(QWidget, DicomDownloadModuleUI):
    """Bulk download of DICOM data withing specific clinical trial
    """
    def __init__(self, parent=None):
        """Constructor of DicomUploadModule
        """
        # Setup GUI
        QWidget.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        # Setup logger - use config file
        self.logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)

        # List of worker threads
        self._threadPool = []

        # Initialise main data members
        self._mySite = None
        # Prepares services and main data for this ViewModel
        self.prepareServices()

        # Initialize data structures for UI
        self._downloadDir = None
        self._studies = []
        self._studySubjects = []

        # Initial data load
        self.reloadData()

        # Finish UI setup
        self.lblOcConnection.setText("[" + OCUserDetails().username + "] " +
                                     self._mySite.edc.soapbaseurl)

        # Register handlers
        self.btnDownload.clicked.connect(self.btnDownloadClicked)
        self.cmbStudy.currentIndexChanged['QString'].connect(
            self.cmbStudyChanged)
        self.destroyed.connect(self.handleDestroyed)

    def __del__(self):
        """Default Destructor
        """
        self.handleDestroyed()

##     ##    ###    ##    ## ########  ##       ######## ########   ######
##     ##   ## ##   ###   ## ##     ## ##       ##       ##     ## ##    ##
##     ##  ##   ##  ####  ## ##     ## ##       ##       ##     ## ##
######### ##     ## ## ## ## ##     ## ##       ######   ########   ######
##     ## ######### ##  #### ##     ## ##       ##       ##   ##         ##
##     ## ##     ## ##   ### ##     ## ##       ##       ##    ##  ##    ##
##     ## ##     ## ##    ## ########  ######## ######## ##     ##  ######

    def cmbStudyChanged(self, text):
        """Executed when the concrete study is selected from studies combobox
        """
        # Reset table views
        self.tvStudies.setModel(None)
        self.textBrowserProgress.clear()

        # Set selected study and reload sites
        self._selectedStudy = first.first(
            study for study in self._studies
            if study.name().encode("utf-8") == text.toUtf8())

        # Disable download button
        self._selectedStudySite = None
        self.btnDownload.setDisabled(True)

        # Reload study sites
        self.reloadStudySites()

    def tblStudyItemChanged(self, current, previous):
        """Event handler which is triggered when selectedStudy change

        When the study is selected I have to clean all the other data elements
        Which depends on study. It means: StudySubjects, StudyEventDefinitions, StudyEventCRFs
        """
        self.textBrowserProgress.clear()

        # Take the first column of selected row from table view
        index = self.studyProxyModel.index(current.row(), 0)

        # Multicentric
        if len(self._selectedStudy.sites) > 0:
            self._selectedStudySite = first.first(
                studySite for studySite in self._selectedStudy.sites
                if studySite.identifier.encode(
                    "utf-8") == index.data().toPyObject().toUtf8())
            # Enabled download button
            if (self._selectedStudySite is not None):
                self.btnDownload.setDisabled(False)
        else:
            if (self._selectedStudy is not None):
                self.btnDownload.setDisabled(False)

        # Get the study metadata
        self.reloadStudyMetadata()

        # Show the selected upload target
        msg = "Selected study for download: "
        msg += self._selectedStudy.name() + "/"
        if len(self._selectedStudy.sites) > 0:
            msg += self._selectedStudySite.name + "/"

        self.textBrowserProgress.append(msg)

    def tblStudySubjectItemChanged(self, current, previous):
        """Event handler which is triggered when selectedStudySubject change
        """
        self.tvStudyEvents.setModel(None)
        self.tvDicomStudies.setModel(None)
        self.textBrowserProgress.clear()

        # Take the first column of selected row from table view
        index = self.studySubjectProxyModel.index(current.row(), 1)
        if index.data().toPyObject():
            self._selectedStudySubject = (first.first(
                subject for subject in self._studySubjects
                if subject.label().encode(
                    "utf-8") == index.data().toPyObject().toUtf8()))

            # TODO: enable this when you migrate to a new version of OC
            # I need to load a SubjectKey
            # ssREST = self._svcHttp.getStudyCasebookSubject(
            #         self._mySite.edc.edcbaseurl,
            #         self.getStudyOid(),
            #         self._selectedStudySubject.label()
            #     )
            # if ssREST != None:
            #     self._selectedStudySubject.oid = ssREST.oid
            #     self.logger.debug("Loaded subject key: " + self._selectedStudySubject.oid)

            # TODO: I dont like it, get rid of it ()
            # Propagate PatientID into service
            self._svcDicom.PatientID = self._selectedStudySubject.subject.uniqueIdentifier

    def btnDownloadClicked(self):
        """Upload button pressed (DICOM upload workflow started)
        """
        QtGui.qApp.processEvents(QtCore.QEventLoop.AllEvents, 1000)

        #self.progressBar.setRange(0, 100)
        #self.progressBar.setValue(0)

        self._downloadDir = self.selectFolderDialog()

        if self._downloadDir is not None:

            # Disable upload button for now but better is to disable whole UI
            self.btnDownload.setEnabled(False)

            # Start download DICOM data
            # Create thread
            self._threadPool.append(
                WorkerThread(self._svcDicom.downloadDicomData, [
                    self._downloadDir,
                    self.getStudyIdentifier(), self._svcHttp
                ]))
            # Connect finish event
            self._threadPool[len(self._threadPool) - 1].finished.connect(
                self.DicomDownloadFinishedMessage)
            # Connect message eventscd
            self.connect(self._threadPool[len(self._threadPool) - 1],
                         QtCore.SIGNAL("message(QString)"), self.Message)
            self.connect(self._threadPool[len(self._threadPool) - 1],
                         QtCore.SIGNAL("log(QString)"), self.LogMessage)
            # Progress
            self.connect(self._threadPool[len(self._threadPool) - 1],
                         QtCore.SIGNAL("taskUpdated"), self.handleTaskUpdated)
            # Start thread
            self._threadPool[len(self._threadPool) - 1].start()

    def handleTaskUpdated(self, data):
        """Move progress bar precento by precento
        """
        if type(data) is list:
            if data[0]:
                processed = data[0]
            if data[1]:
                size = data[1]

            progress = processed * 100 / size
            self.window().statusBar.showMessage("Processed files: [" +
                                                str(processed) + "/" +
                                                str(size) + "]")
            self.progressBar.setValue(progress)

    def handleDestroyed(self):
        """Kill running threads
        """
        self.logger.debug("Destroying DICOM download module")
        for thread in self._threadPool:
            thread.terminate()
            thread.wait()
            self.logger.debug("Thread killed.")

    def getStudyOid(self):
        """Return study or site OID depending on mono/multi centre configuration
        """
        # Multicentre
        if len(self._selectedStudy.sites) > 0:
            return self._selectedStudySite.oid
        # Monocentre
        else:
            return self._selectedStudy.oid()

    def getStudyIdentifier(self):
        """Return study or site OID depending on mono/multi centre configuration
        """
        # Multicentre
        if len(self._selectedStudy.sites) > 0:
            return self._selectedStudySite.identifier
        # Monocentre
        else:
            return self._selectedStudy.identifier()

######   #######  ##     ## ##     ##    ###    ##    ## ########   ######
##    ## ##     ## ###   ### ###   ###   ## ##   ###   ## ##     ## ##    ##
##       ##     ## #### #### #### ####  ##   ##  ####  ## ##     ## ##
##       ##     ## ## ### ## ## ### ## ##     ## ## ## ## ##     ##  ######
##       ##     ## ##     ## ##     ## ######### ##  #### ##     ##       ##
##    ## ##     ## ##     ## ##     ## ##     ## ##   ### ##     ## ##    ##
######   #######  ##     ## ##     ## ##     ## ##    ## ########   ######

    def prepareServices(self):
        """Prepare services for this module
        """
        # HTTP connection to RadPlanBio server (Database)
        self._svcHttp = HttpConnectionService(ConfigDetails().rpbHost,
                                              ConfigDetails().rpbHostPort,
                                              UserDetails())
        self._svcHttp.application = ConfigDetails().rpbApplication

        if ConfigDetails().proxyEnabled:
            self._svcHttp.setupProxy(ConfigDetails().proxyHost,
                                     ConfigDetails().proxyPort,
                                     ConfigDetails().noProxy)
        if ConfigDetails().proxyAuthEnabled:
            self._svcHttp.setupProxyAuth(ConfigDetails().proxyAuthLogin,
                                         ConfigDetails().proxyAuthPassword)

        # Read partner site of logged user
        self._mySite = self._svcHttp.getMyDefaultAccount().partnersite

        # Create connection artefact to users main OpenClinica SOAP
        baseUrl = self._mySite.edc.soapbaseurl
        self.ocConnectInfo = OCConnectInfo(baseUrl, OCUserDetails().username)
        self.ocConnectInfo.setPasswordHash(OCUserDetails().passwordHash)

        if ConfigDetails().proxyEnabled:
            self.ocWebServices = OCWebServices(
                self.ocConnectInfo,
                ConfigDetails().proxyHost,
                ConfigDetails().proxyPort,
                ConfigDetails().noProxy,
                ConfigDetails().proxyAuthLogin,
                ConfigDetails().proxyAuthPassword)
        else:
            self.ocWebServices = OCWebServices(self.ocConnectInfo)

        # ODM XML metadata processing
        self.fileMetaDataService = OdmFileDataService()
        # DICOM PROCESSING SERVICE
        self._svcDicom = DicomService()

    def reloadData(self):
        """Initialization of data for UI
        """
        # OpenClinica study
        del self._studies[:]
        self._studies = []
        self._selectedStudy = None
        self._studyMetadata = None

        # OpenClinica study site
        self._selectedStudySite = None

        # OpenClinica study subjects
        del self._studySubjects[:]
        self._studySubjects = []
        self._selectedStudySubject = None

        # Load studies
        self.reloadStudies()

    def reloadStudies(self):
        """Reload OpenClinica studies (in working thread)
        """
        # Setup loading UI
        self.window().statusBar.showMessage(
            "Loading list of clinical studies...")
        self.window().enableIndefiniteProgess()
        self.tabWidget.setEnabled(False)

        # Create data loading thread
        self._threadPool.append(WorkerThread(
            self.ocWebServices.listAllStudies))

        # Connect slots
        self.connect(self._threadPool[len(self._threadPool) - 1],
                     QtCore.SIGNAL("finished(QVariant)"),
                     self.loadStudiesFinished)

        # Start thread
        self._threadPool[len(self._threadPool) - 1].start()

    def reloadStudyMetadata(self):
        """Reload study metadata for selected study
        """
        # Setup loading UI
        self.window().statusBar.showMessage("Loading study metadata...")
        self.window().enableIndefiniteProgess()
        self.tabWidget.setEnabled(False)

        # Create data loading thread
        self._threadPool.append(
            WorkerThread(self.ocWebServices.getStudyMetadata,
                         self._selectedStudy))

        # Connect slots
        self.connect(self._threadPool[len(self._threadPool) - 1],
                     QtCore.SIGNAL("finished(QVariant)"),
                     self.loadStudyMetadataFinished)

        # Start thread
        self._threadPool[len(self._threadPool) - 1].start()

    def reloadStudySites(self):
        """Reload sites for selected OpenClinica sutdy (in memory processing)
        (If it is monocentric study show one default site)
        """
        # Quick way of crating simple viewModel
        self.studySitesModel = QtGui.QStandardItemModel()
        self.studySitesModel.setHorizontalHeaderLabels(
            ["Identifier", "Partner Site", "Study"])

        row = 0
        if len(self._selectedStudy.sites) > 0:
            for site in self._selectedStudy.sites:
                siteIdentifierValue = QtGui.QStandardItem(site.identifier)
                siteNameValue = QtGui.QStandardItem(site.name)
                studyNameValue = QtGui.QStandardItem(
                    self._selectedStudy.name())

                self.studySitesModel.setItem(row, 0, siteIdentifierValue)
                self.studySitesModel.setItem(row, 1, siteNameValue)
                self.studySitesModel.setItem(row, 2, studyNameValue)

                row = row + 1
        else:
            studyIdentifierValue = QtGui.QStandardItem(
                self._selectedStudy.identifier())
            studyNameValue = QtGui.QStandardItem(self._selectedStudy.name())

            self.studySitesModel.setItem(row, 0, studyIdentifierValue)
            self.studySitesModel.setItem(row, 2, studyNameValue)

            row = row + 1

        # Create a proxy model to enable Sorting and filtering
        self.studyProxyModel = QtGui.QSortFilterProxyModel()
        self.studyProxyModel.setSourceModel(self.studySitesModel)
        self.studyProxyModel.setDynamicSortFilter(True)
        self.studyProxyModel.setFilterCaseSensitivity(
            QtCore.Qt.CaseInsensitive)

        # Connect to filtering UI element
        QtCore.QObject.connect(self.txtStudyFilter,
                               QtCore.SIGNAL("textChanged(QString)"),
                               self.studyProxyModel.setFilterRegExp)

        self.tvStudies.setModel(self.studyProxyModel)
        self.tvStudies.resizeColumnsToContents()

        # After the view has model, set currentChanged behaviour
        self.tvStudies.selectionModel().currentChanged.connect(
            self.tblStudyItemChanged)

    def reloadSubjects(self):
        """Reload OpenClinica study subects enrolled into selected study/site in working thread
        """
        # Setup loading UI
        self.window().statusBar.showMessage(
            "Loading list of study subjects...")
        self.window().enableIndefiniteProgess()
        self.tabWidget.setEnabled(False)
        self._subjectsLoaded = False

        # Load subject for whole study or only site if it is multicentre study
        if self._selectedStudy and self._selectedStudy.isMulticentre:
            self._threadPool.append(
                WorkerThread(
                    self.ocWebServices.listAllStudySubjectsByStudySite, [
                        self._selectedStudy, self._selectedStudySite,
                        self._studyMetadata
                    ]))
        else:
            self._threadPool.append(
                WorkerThread(self.ocWebServices.listAllStudySubjectsByStudy,
                             [self._selectedStudy, self._studyMetadata]))

        # Connect slots
        self.connect(self._threadPool[len(self._threadPool) - 1],
                     QtCore.SIGNAL("finished(QVariant)"),
                     self.loadSubjectsFinished)

        # Start thread
        self._threadPool[len(self._threadPool) - 1].start()

        # TODO: it would be much faster if I request REST subject only for the selected one
        # TODO: however we have to migrate to a new version of OC first
        # Need to get OIDs of subjects
        self._threadPool.append(
            WorkerThread(self._svcHttp.getStudyCasebookSubjects,
                         [self._mySite.edc.edcbaseurl,
                          self.getStudyOid()]))

        # Connect slots
        self.connect(self._threadPool[len(self._threadPool) - 1],
                     QtCore.SIGNAL("finished(QVariant)"),
                     self.loadSubjectsRESTFinished)

        # Start thread
        self._threadPool[len(self._threadPool) - 1].start()

    def selectFolderDialog(self):
        """User selects a directory for DICOM study files
        """
        try:
            dirPath = QtGui.QFileDialog.getExistingDirectory(
                None, "Please select the DICOM download destination folder")
            if dirPath == "":
                return None

            isReadable = os.access(str(dirPath), os.R_OK)
            QtGui.qApp.processEvents(QtCore.QEventLoop.AllEvents, 1000)

            if isReadable == False:
                self.Error(
                    "The client is not allowed to read data from the selected folder!"
                )
                self.logger.error("No read access to selected folder.")
                return None
        except UnicodeEncodeError:
            self.Error(
                "The path to the selected folder contains unsupported characters (unicode), please use only ascii characters in names of folders!"
            )
            self.logger.error("Unsupported unicode folder path selected.")
            return None

        return str(dirPath)

    def loadStudiesFinished(self, studies):
        """Finished loading studies from server
        """
        self._studies = studies.toPyObject()
        self._studies.sort(cmp=lambda x, y: cmp(x.name(), y.name()))

        # And prepare ViewModel for the GUI
        studiesModel = QtGui.QStandardItemModel()
        for study in self._studies:
            text = QtGui.QStandardItem(study.name())
            studiesModel.appendRow([text])
        self.cmbStudy.setModel(studiesModel)

        # Select the first study
        self._selectedStudy = self._studies[0]

        # Update status bar
        self.tabWidget.setEnabled(True)
        self.window().statusBar.showMessage("Ready")
        self.window().disableIndefiniteProgess()

    def loadStudyMetadataFinished(self, metadata):
        """Finished loading metadata from server
        """
        self._studyMetadata = metadata.toPyObject()

        # Update status bar
        self.tabWidget.setEnabled(False)
        self.window().statusBar.showMessage("Ready")
        self.window().disableIndefiniteProgess()

        # Set the OC active study according to the selection (in order to make sure that RESTfull calls are executed)
        if self._selectedStudy and self._selectedStudy.isMulticentre:
            ocStudy = self._svcHttp.getOCStudyByIdentifier(
                self._selectedStudySite.identifier)
        else:
            ocStudy = self._svcHttp.getOCStudyByIdentifier(
                self._selectedStudy.identifier())

        updateResult = self._svcHttp.changeUserActiveStudy(
            UserDetails().username, ocStudy.id)

        self.tabWidget.setEnabled(True)
        self.window().statusBar.showMessage("Ready")
        self.window().disableIndefiniteProgess()

    def loadSubjectsFinished(self, subjects):
        """Finished loading of subject data
        """
        self._studySubjects = subjects.toPyObject()
        self._subjectsLoaded = True

    def loadSubjectsRESTFinished(self, subjects):
        """
        """
        # In case the REST worker finished sooner than the SOAP worker
        while self._subjectsLoaded != True:
            time.sleep(1)

        subjectsREST = subjects.toPyObject()

        # Create the ViewModels for Views
        # Quick way of crating simple viewModel
        self.subjectsModel = QtGui.QStandardItemModel()
        self.subjectsModel.setHorizontalHeaderLabels([
            "PersonID", "StudySubjectID", "SecondaryID", "Gender",
            "Enrollment date", "OID"
        ])

        row = 0
        for studySubject in self._studySubjects:
            # Always mandatory
            labelItem = QtGui.QStandardItem(studySubject.label())
            enrollmentDateItem = QtGui.QStandardItem(
                studySubject.enrollmentDate)

            # Optional
            secondaryLabelItem = QtGui.QStandardItem("")
            if studySubject.secondaryLabel() != None:
                secondaryLabelItem = QtGui.QStandardItem(
                    studySubject.secondaryLabel())

            # Not everything has to be collected (depend on study setup)
            pidItem = QtGui.QStandardItem("")
            genderItem = QtGui.QStandardItem("")
            if studySubject.subject != None:
                if studySubject.subject.uniqueIdentifier != None:
                    pidItem = QtGui.QStandardItem(
                        studySubject.subject.uniqueIdentifier)
                if studySubject.subject.gender != None:
                    genderItem = QtGui.QStandardItem(
                        studySubject.subject.gender)

            oidItem = QtGui.QStandardItem("")
            for sREST in subjectsREST:
                if sREST.studySubjectId == studySubject.label():
                    oidItem = QtGui.QStandardItem(sREST.oid)
                    studySubject.oid = sREST.oid

            self.subjectsModel.setItem(row, 0, pidItem)
            self.subjectsModel.setItem(row, 1, labelItem)
            self.subjectsModel.setItem(row, 2, secondaryLabelItem)
            self.subjectsModel.setItem(row, 3, genderItem)
            self.subjectsModel.setItem(row, 4, enrollmentDateItem)
            self.subjectsModel.setItem(row, 5, oidItem)

            row = row + 1

        # Create a proxy model to enable Sorting and filtering
        self.studySubjectProxyModel = QtGui.QSortFilterProxyModel()
        self.studySubjectProxyModel.setSourceModel(self.subjectsModel)
        self.studySubjectProxyModel.setDynamicSortFilter(True)
        self.studySubjectProxyModel.setFilterCaseSensitivity(
            QtCore.Qt.CaseInsensitive)

        # Connect to filtering UI element
        QtCore.QObject.connect(self.txtStudySubjectFilter,
                               QtCore.SIGNAL("textChanged(QString)"),
                               self.studySubjectProxyModel.setFilterRegExp)

        # Set the models Views
        self.tvStudySubjects.setModel(self.studySubjectProxyModel)

        # Resize the width of columns to fit the content
        self.tvStudySubjects.resizeColumnsToContents()

        # After the view has model, set currentChanged behaviour
        self.tvStudySubjects.selectionModel().currentChanged.connect(
            self.tblStudySubjectItemChanged)

        self.tabWidget.setEnabled(True)
        self.window().statusBar.showMessage("Ready")
        self.window().disableIndefiniteProgess()

##     ## ########  ######   ######     ###     ######   ########  ######
###   ### ##       ##    ## ##    ##   ## ##   ##    ##  ##       ##    ##
#### #### ##       ##       ##        ##   ##  ##        ##       ##
## ### ## ######    ######   ######  ##     ## ##   #### ######    ######
##     ## ##             ##       ## ######### ##    ##  ##             ##
##     ## ##       ##    ## ##    ## ##     ## ##    ##  ##       ##    ##
##     ## ########  ######   ######  ##     ##  ######   ########  ######

    def Question(self, string):
        """Question message box
        """
        reply = QtGui.QMessageBox.question(self, "Question", string,
                                           QtGui.QMessageBox.Yes,
                                           QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            self.btnDownload.setEnabled(False)
        else:
            self.btnDownload.setEnabled(True)

    def Error(self, string):
        """Error message box
        """
        QtGui.QMessageBox.critical(self, "Error", string)
        self.btnDownload.setEnabled(True)

    def Warning(self, string):
        """Warning message box
        """
        QtGui.QMessageBox.warning(self, "Warning", string)
        self.btnDownload.setEnabled(True)

    def Message(self, string):
        """Called from message event, opens a small window with the message
        """
        QtGui.QMessageBox.about(self, "Info", string)
        self.btnDownload.setEnabled(True)

    def LogMessage(self, string):
        """Called from log event in thread and adds log into textbrowser UI
        """
        self.textBrowserProgress.append(string)

    def DicomDownloadFinishedMessage(self):
        """ Called after uploadDataThread finished, after the data were uploaded to
        the RadPlanBio server
        """
        # Enable upload button
        self.btnDownload.setEnabled(True)
        self.window().statusBar.showMessage("Ready")
コード例 #5
0
    def __init__(self, parent=None):
        """Constructor of ExportModule View
        """
        QWidget.__init__(self, parent)
        self.parent = parent

        #-----------------------------------------------------------------------
        #----------------------- Logger ----------------------------------------
        self.logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)
        #-----------------------------------------------------------------------
        #---------------------- App config --------------------------------------
        self.appConfig = AppConfigurationService()
        #-----------------------------------------------------------------------
        #--------------------- Create Module UI --------------------------------
        self.setupUi(self)
        #-----------------------------------------------------------------------
        #---------- Load modules buttons - events definitions ------------------
        self.btnReload.clicked.connect(self.btnReloadClicked)

        self.btnMapExportField.clicked.connect(self.btnMapExportFieldClicked)

        self.btnLocateDataFilename.clicked.connect(
            self.btnLocateDataFilenameClicked)
        self.btnLocateMetaDataFilename.clicked.connect(
            self.btnLocateMetaDataFilenameClicked)
        self.btnValidateMapping.clicked.connect(
            self.btnValidateDataTransformationClicked)
        self.btnLoadMapping.clicked.connect(self.btnLoadMappingClicked)

        self.cmbStudyEvent.currentIndexChanged['QString'].connect(
            self.cmbStudyEventChanged)
        self.cmbEventForm.currentIndexChanged['QString'].connect(
            self.cmbEventFormChanged)
        #-----------------------------------------------------------------------
        # Domain model
        self.__study = None
        self.__studyEvents = []
        self.__selectedStudyEvent = None
        self.__studyEventCrfs = []
        self.__selectedEventCrf = None

        #-----------------------------------------------------------------------
        #----------------------- Services --------------------------------------
        # There are two http services, one for communicating with my own
        # site server/database
        section = "MySiteServer"
        hostname = self.appConfig.get(section)["host"]
        port = self.appConfig.get(section)["port"]
        self.svcHttp = HttpConnectionService(hostname, port, UserDetails())

        self.reload()

        #-----------------------------------------------------------------------
        # TODO: make it a Stragety desing pattern later
        self.fileDataService = CsvFileDataService()
        self.fileMetaDataService = OdmFileDataService()
        self.exportMapping = []

        # Just for testing to have guick access to files
        self.dataFilename = "/mnt/edv/skripcakt/ulice/branches/radplanbio/data/radiochemotherapy.csv"
        self.metaDataFilename = "/mnt/edv/skripcakt/ulice/branches/radplanbio/data/HNSCCStudyMetadata.xml"

        #-----------------------------------------------------------------------
        # Create REST mainzellieste
        userName = "******"
        password = "******"
        baseUrl = "http://g89rtpsrv.med.tu-dresden.de:8080/mainzelliste-1.1-SNAPSHOT/"
        apiKey = "mdatdd"

        connectInfo = MainzellisteConnectInfo(baseUrl, userName, password,
                                              apiKey)
        self.svcPseudonymisation = PseudonymisationService(connectInfo)
コード例 #6
0
class ExportModule(QWidget, ExportModuleUI):
    """Export Module view class

    Export Module is class inerited from ExportModuleUI. There the GUI layout
    and elements are defined. In this class the handlers aka View application
    logic is defined. Handler are invoking functionality which is provided in
    bussiness layer of the application (services, domain).
    """

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

    def __init__(self, parent=None):
        """Constructor of ExportModule View
        """
        QWidget.__init__(self, parent)
        self.parent = parent

        #-----------------------------------------------------------------------
        #----------------------- Logger ----------------------------------------
        self.logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)
        #-----------------------------------------------------------------------
        #---------------------- App config --------------------------------------
        self.appConfig = AppConfigurationService()
        #-----------------------------------------------------------------------
        #--------------------- Create Module UI --------------------------------
        self.setupUi(self)
        #-----------------------------------------------------------------------
        #---------- Load modules buttons - events definitions ------------------
        self.btnReload.clicked.connect(self.btnReloadClicked)

        self.btnMapExportField.clicked.connect(self.btnMapExportFieldClicked)

        self.btnLocateDataFilename.clicked.connect(
            self.btnLocateDataFilenameClicked)
        self.btnLocateMetaDataFilename.clicked.connect(
            self.btnLocateMetaDataFilenameClicked)
        self.btnValidateMapping.clicked.connect(
            self.btnValidateDataTransformationClicked)
        self.btnLoadMapping.clicked.connect(self.btnLoadMappingClicked)

        self.cmbStudyEvent.currentIndexChanged['QString'].connect(
            self.cmbStudyEventChanged)
        self.cmbEventForm.currentIndexChanged['QString'].connect(
            self.cmbEventFormChanged)
        #-----------------------------------------------------------------------
        # Domain model
        self.__study = None
        self.__studyEvents = []
        self.__selectedStudyEvent = None
        self.__studyEventCrfs = []
        self.__selectedEventCrf = None

        #-----------------------------------------------------------------------
        #----------------------- Services --------------------------------------
        # There are two http services, one for communicating with my own
        # site server/database
        section = "MySiteServer"
        hostname = self.appConfig.get(section)["host"]
        port = self.appConfig.get(section)["port"]
        self.svcHttp = HttpConnectionService(hostname, port, UserDetails())

        self.reload()

        #-----------------------------------------------------------------------
        # TODO: make it a Stragety desing pattern later
        self.fileDataService = CsvFileDataService()
        self.fileMetaDataService = OdmFileDataService()
        self.exportMapping = []

        # Just for testing to have guick access to files
        self.dataFilename = "/mnt/edv/skripcakt/ulice/branches/radplanbio/data/radiochemotherapy.csv"
        self.metaDataFilename = "/mnt/edv/skripcakt/ulice/branches/radplanbio/data/HNSCCStudyMetadata.xml"

        #-----------------------------------------------------------------------
        # Create REST mainzellieste
        userName = "******"
        password = "******"
        baseUrl = "http://g89rtpsrv.med.tu-dresden.de:8080/mainzelliste-1.1-SNAPSHOT/"
        apiKey = "mdatdd"

        connectInfo = MainzellisteConnectInfo(baseUrl, userName, password,
                                              apiKey)
        self.svcPseudonymisation = PseudonymisationService(connectInfo)

        # # Retrive all pids
        # allPids = self.svcPseudonymisation.getAllPatients()

        # # Start reading session (I know the PID and I want to gat patient data)
        # sessionId, uri1 = self.svcPseudonymisation.newSession()
        # tokenId, url2 = self.svcPseudonymisation.readPatientToken(sessionId, allPids[0].idString)
        # self.svcPseudonymisation.getPatient(tokenId)

        #tokenId, uri2 = self.svcPseudonymisation.newPatientToken(sessionId)
        #self.svcPseudonymisation.createPatientJson(tokenId)
        #self.svcPseudonymisation.resolveTempIds(tokenId)

    def loadModuleData(self, selectedIndex):
        if selectedIndex == 0:
            pass

    def reload(self):
        requests = []

        # TODO: read from users data
        # It is not Heidelberg I have it here just for testing to simulate on one database
        mySite = "DKTK-HEIDELBERG"
        site = self.svcHttp.getPartnerSiteByName(mySite)
        if site is not None:
            requests = self.svcHttp.getAllPullDataRequestsToSite(site.sitename)

        pullDataRequestModel = QtGui.QStandardItemModel()
        pullDataRequestModel.setHorizontalHeaderLabels(
            ["Request sent from", "Subject", "Created"])

        row = 0
        for itm in requests:
            fromValue = QtGui.QStandardItem(itm.sentFromSite.sitename)
            subjectValue = QtGui.QStandardItem(itm.subject)
            createdValue = QtGui.QStandardItem(str(itm.created))

            pullDataRequestModel.setItem(row, 0, fromValue)
            pullDataRequestModel.setItem(row, 1, subjectValue)
            pullDataRequestModel.setItem(row, 2, createdValue)

            row = row + 1

        self.tvPullDataRequests.setModel(pullDataRequestModel)
        self.tvPullDataRequests.resizeColumnsToContents()

    #----------------------------------------------------------------------
    #------------------- Browse Buttons Handlers -------------------------

    def btnLocateDataFilenameClicked(self):
        """User selects a file to export
        """
        # Get a data file name
        fileName = QtGui.QFileDialog.getOpenFileName(self, "Locate data file",
                                                     QtCore.QDir.currentPath(),
                                                     "csv files(*.csv)")

        # Check read access to the file
        ok = os.access(fileName, os.R_OK)

        # If access is OK
        if ok:
            self.dataFilename = str(fileName)
            self.txtDataFilename.setText(self.dataFilename)

    def btnLocateMetaDataFilenameClicked(self):
        """Open a file open dialog where user selects a study metadata XML file

        """
        # Get a metadata file name
        fileName = QtGui.QFileDialog.getOpenFileName(self,
                                                     "Locate metadata file",
                                                     QtCore.QDir.currentPath(),
                                                     "xml files(*.xml)")

        # Check read access to the file
        ok = os.access(fileName, os.R_OK)

        # If access is OK
        if ok:
            # Get file path as string
            self.metaDataFilename = str(fileName)
            # Set the path to GUI
            self.txtMetaDataFilename.setText(self.metaDataFilename)
            # Prepare service for reading XML ODM files
            self.fileMetaDataService.setFilename(self.metaDataFilename)

            # Load the Study domain object
            self.__study = self.fileMetaDataService.loadStudy()
            # And inform the GUI
            self.lblStudy.setText(self.__study.name())

            # Load list of Study Event Definition domain objects
            self.__studyEvents = self.fileMetaDataService.loadStudyEvents()

            # And prepare ViewModel for the GUI
            seModel = QtGui.QStandardItemModel()

            for studyEventDef in self.__studyEvents:
                text = QtGui.QStandardItem(studyEventDef.name())
                seModel.appendRow([text])

            self.cmbStudyEvent.setModel(seModel)

    #----------------------------------------------------------------------
    #------------------- Command Buttons Handlers -------------------------

    def btnReloadClicked(self):
        self.reload()

    def btnLoadMappingClicked(self):
        """Load mapping into table view
        """
        if self.dataFilename == "":
            if self.txtDataFileName.text() == "":
                # error
                pass
            else:
                ok = os.access(self.txtDataFilename.text(), os.R_OK)
                if ok:
                    self.dataFilename = self.txtDataFilename.text()
                else:
                    #error
                    pass

        if self.metaDataFilename == "":
            if self.txtMetaDataFilename.text() == "":
                # error
                pass
            else:
                ok = os.access(self.txtMetaDataFilename.text(), os.R_OK)
                if ok:
                    self.metaDataFilename = self.txtMetaDataFilename.text()
                else:
                    #error
                    pass

        # Accumulate data headers
        self.fileDataService.setFilename(self.dataFilename)
        self.fileDataService.loadHeaders()

        # Accumulate metadata headers
        self.fileMetaDataService.setFilename(self.metaDataFilename)
        self.fileMetaDataService.loadHeaders()

        # Create a exportMaping list for table ViewModel
        self.exportMapping = self.fileMetaDataService.loadExportMapping(
            self.__selectedEventCrf)

        # Create a tableView model
        self.exportMappingModel = ExportMappingTableModel(self.exportMapping)
        self.tvExportDataMapping.setModel(self.exportMappingModel)

        # Make tableView editable
        self.tvExportDataMapping.setEditTriggers(
            QtGui.QAbstractItemView.CurrentChanged)

        # Create combo box delegate to display in teableView
        #dataComboBoxDelegate = ComboBoxDelegate(self, self.fileDataService.headers)
        #actionButtonDelegate = PushButtonDelegate(self)

        # Assign delegates to columns
        #self.tvExportDataMapping.setItemDelegateForColumn(2, dataComboBoxDelegate)
        #self.tvExportDataMapping.setItemDelegateForColumn(4, actionButtonDelegate)

        # Make cobobox always displayed
        #for i in range(0, len(self.fileMetaDataService.headers)):
        #self.tvExportDataMapping.openPersistentEditor(self.exportMappingModel.index(i, 2));
        #self.tvExportDataMapping.openPersistentEditor(self.exportMappingModel.index(i, 4));

        # Resize table columns to content
        self.tvExportDataMapping.resizeColumnsToContents()

        self.tvExportDataMapping.selectionModel().currentChanged.connect(
            self.tblExportDataMappingItemChanged)

    def btnMapExportFieldClicked(self):
        """Map metadata to datafiled from provided CSV data
        """
        # Initialize dialog
        dialog = ExportFieldMappingDialog(self)
        dialog.dataService = self.fileDataService
        dialog.setData(self.selectedDataMapping, self.fileDataService.headers)

        # Show dialog
        dialogResult = dialog.exec_()

        if dialogResult == QtGui.QDialog.Accepted:
            # Take data from dialog
            self.exportMappingModel.dataItems[
                self.selectedRow].data = dialog.dataMapping.data
            self.exportMappingModel.dataItems[
                self.selectedRow].setConverter = dialog.dataMapping.converter

            # Resize table columns to content
            self.tvExportDataMapping.resizeColumnsToContents()

    def btnMapExportFieldConstantClicked(self):
        pass

    def btnValidateMappingClicked(self):
        """
        """
        mappingErrors = []
        for i in range(0, len(self.fileMetaDataService.headers)):
            print self.exportMappingModel.dataItems[
                i].metadata + " -> " + self.exportMappingModel.dataItems[i].data

        # Error: All mandatory columns are mapped
        # Warning: one column is mapped to several metadata

    def btnValidateDataTransformationClicked(self):
        """
        """
        dataSize = self.fileDataService.size()

        validationErrors = []
        # Try to convert all data (from 1 ignore the header)
        for i in range(1, dataSize):
            # For every row of input data set
            dataRow = self.fileDataService.getRow(i)
            # Go through specified export mapping
            for j in range(0, len(self.fileMetaDataService.headers)):
                # And locate data in csv which corresponds to mapping
                metadataHeader = self.exportMappingModel.dataItems[j].metadata

                dataHeader = self.exportMappingModel.dataItems[j].data
                dataIndex = self.fileDataService.headers.index(dataHeader)
                dataValue = dataRow[dataIndex]

                print "metadata: " + metadataHeader + " -> " + dataHeader + " = " + dataValue

                # Check if the data conform
                #self.exportMappingModel.dataItems[j].checkDataType(dataValue)
                if (self.exportMappingModel.dataItems[j].validate(dataValue) ==
                        False):
                    errorMessage = "Input file row: " + i + ". " + dataHeader + " = " + dataValue + "does not conform metadata codelist for: " + metadataHeader
                    validationErrors.append(errorMessage)

        # Show errors if appiers

        # Show confirmation of valid in no errors

    #----------------------------------------------------------------------
    #------------------- ComboBox Handlers --------------------------------

    def cmbStudyEventChanged(self, text):
        """
        """
        # I need to find StudyEvent object according to name (text)
        self.__selectedStudyEvent = first.first(event
                                                for event in self.__studyEvents
                                                if event.name() == text)

        # When selected event found search CRFs for the event
        if self.__selectedStudyEvent is not None:
            # Load list of Study Event Form Definition domain objects
            self.__studyEventCrfs = self.fileMetaDataService.loadEventCrfs(
                self.__selectedStudyEvent)

            # And prepare ViewModel for the GUI
            sefModel = QtGui.QStandardItemModel()

            for studyEventCrf in self.__studyEventCrfs:
                text = QtGui.QStandardItem(studyEventCrf.name())
                sefModel.appendRow([text])

            self.cmbEventForm.setModel(sefModel)

    def cmbEventFormChanged(self, text):
        """
        """
        self.__selectedEventCrf = first.first(crf
                                              for crf in self.__studyEventCrfs
                                              if crf.name() == text)

    #----------------------------------------------------------------------
    #------------------- TableView Handlers -------------------------------

    def tblExportDataMappingItemChanged(self, current, previous):
        self.selectedDataMapping = self.exportMappingModel.dataItems[
            current.row()]
        self.selectedRow = current.row()
コード例 #7
0
ファイル: mainClient.py プロジェクト: wahyuwh/rpb-client
    def __init__(self, parent=None):
        """Constructor of main application widnow
        """
        QMainWindow.__init__(self, parent)

        self._logger = logging.getLogger(__name__)
        logging.config.fileConfig("logging.ini",
                                  disable_existing_loggers=False)

        self.setupUi(self)
        self.statusBar.showMessage("Ready")

        self._logger.info("RadPlanBio host: " + ConfigDetails().rpbHost + ":" +
                          str(ConfigDetails().rpbHostPort))
        self._logger.info("Partner site proxy: " + ConfigDetails().proxyHost +
                          ":" + str(ConfigDetails().proxyPort) + " [" +
                          str(ConfigDetails().proxyEnabled) + "]")

        self.svcHttp = HttpConnectionService(ConfigDetails().rpbHost,
                                             ConfigDetails().rpbHostPort,
                                             UserDetails())
        self.svcHttp.application = ConfigDetails().rpbApplication
        if ConfigDetails().proxyEnabled:
            self.svcHttp.setupProxy(ConfigDetails().proxyHost,
                                    ConfigDetails().proxyPort,
                                    ConfigDetails().noProxy)
        if ConfigDetails().proxyAuthEnabled:
            self.svcHttp.setupProxyAuth(ConfigDetails().proxyAuthLogin,
                                        ConfigDetails().proxyAuthPassword)

        self.lblRPBConnection.setText("[" + UserDetails().username + "]@" +
                                      ConfigDetails().rpbHost + "/" +
                                      ConfigDetails().rpbApplication + ":" +
                                      str(ConfigDetails().rpbHostPort))

        try:
            defaultAccount = self.svcHttp.getMyDefaultAccount()
        except Exception:
            self._logger.info("HTTP communication failed.")

        if defaultAccount.ocusername and defaultAccount.ocusername != "":
            ocUsername = defaultAccount.ocusername
            ocPasswordHash = self.svcHttp.getOCAccountPasswordHash()
            ocSoapBaseUrl = defaultAccount.partnersite.edc.soapbaseurl

            successful = False
            try:
                # Create connection artifact to OC
                self.ocConnectInfo = OCConnectInfo(ocSoapBaseUrl, ocUsername)
                self.ocConnectInfo.setPasswordHash(ocPasswordHash)

                if ConfigDetails().proxyEnabled:
                    self.ocWebServices = OCWebServices(
                        self.ocConnectInfo,
                        ConfigDetails().proxyHost,
                        ConfigDetails().proxyPort,
                        ConfigDetails().noProxy,
                        ConfigDetails().proxyAuthLogin,
                        ConfigDetails().proxyAuthPassword)
                else:
                    self.ocWebServices = OCWebServices(self.ocConnectInfo)

                successful, studies = self.ocWebServices.listAllStudies()
            except:
                self._logger.info("HTTP OC communication failed.",
                                  exc_info=True)

            if successful:
                ocUserDetails = OCUserDetails()
                ocUserDetails.username = ocUsername
                ocUserDetails.passwordHash = ocPasswordHash
                ocUserDetails.connected = True
            else:
                QtGui.QMessageBox.warning(self, "Error",
                                          "Wrong username or password!")
コード例 #8
0
ファイル: mainClient.py プロジェクト: wahyuwh/rpb-client
class MainWindow(QMainWindow, MainWindowUI):
    """Main window view shell
    Main view shell where the other modules views are registered
    """
    def __init__(self, parent=None):
        """Constructor of main application widnow
        """
        QMainWindow.__init__(self, parent)

        self._logger = logging.getLogger(__name__)
        logging.config.fileConfig("logging.ini",
                                  disable_existing_loggers=False)

        self.setupUi(self)
        self.statusBar.showMessage("Ready")

        self._logger.info("RadPlanBio host: " + ConfigDetails().rpbHost + ":" +
                          str(ConfigDetails().rpbHostPort))
        self._logger.info("Partner site proxy: " + ConfigDetails().proxyHost +
                          ":" + str(ConfigDetails().proxyPort) + " [" +
                          str(ConfigDetails().proxyEnabled) + "]")

        self.svcHttp = HttpConnectionService(ConfigDetails().rpbHost,
                                             ConfigDetails().rpbHostPort,
                                             UserDetails())
        self.svcHttp.application = ConfigDetails().rpbApplication
        if ConfigDetails().proxyEnabled:
            self.svcHttp.setupProxy(ConfigDetails().proxyHost,
                                    ConfigDetails().proxyPort,
                                    ConfigDetails().noProxy)
        if ConfigDetails().proxyAuthEnabled:
            self.svcHttp.setupProxyAuth(ConfigDetails().proxyAuthLogin,
                                        ConfigDetails().proxyAuthPassword)

        self.lblRPBConnection.setText("[" + UserDetails().username + "]@" +
                                      ConfigDetails().rpbHost + "/" +
                                      ConfigDetails().rpbApplication + ":" +
                                      str(ConfigDetails().rpbHostPort))

        try:
            defaultAccount = self.svcHttp.getMyDefaultAccount()
        except Exception:
            self._logger.info("HTTP communication failed.")

        if defaultAccount.ocusername and defaultAccount.ocusername != "":
            ocUsername = defaultAccount.ocusername
            ocPasswordHash = self.svcHttp.getOCAccountPasswordHash()
            ocSoapBaseUrl = defaultAccount.partnersite.edc.soapbaseurl

            successful = False
            try:
                # Create connection artifact to OC
                self.ocConnectInfo = OCConnectInfo(ocSoapBaseUrl, ocUsername)
                self.ocConnectInfo.setPasswordHash(ocPasswordHash)

                if ConfigDetails().proxyEnabled:
                    self.ocWebServices = OCWebServices(
                        self.ocConnectInfo,
                        ConfigDetails().proxyHost,
                        ConfigDetails().proxyPort,
                        ConfigDetails().noProxy,
                        ConfigDetails().proxyAuthLogin,
                        ConfigDetails().proxyAuthPassword)
                else:
                    self.ocWebServices = OCWebServices(self.ocConnectInfo)

                successful, studies = self.ocWebServices.listAllStudies()
            except:
                self._logger.info("HTTP OC communication failed.",
                                  exc_info=True)

            if successful:
                ocUserDetails = OCUserDetails()
                ocUserDetails.username = ocUsername
                ocUserDetails.passwordHash = ocPasswordHash
                ocUserDetails.connected = True
            else:
                QtGui.QMessageBox.warning(self, "Error",
                                          "Wrong username or password!")

    def closeEvent(self, event):
        """Cleaning up
        """
        self._logger.debug("Destroying the application.")
        ApplicationEntityService().quit()

    def quit(self):
        """Quit (exit) event handler
        """
        reply = QtGui.QMessageBox.question(self, "Question",
                                           gui.messages.QUE_EXIT,
                                           QtGui.QMessageBox.Yes,
                                           QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            self._logger.debug("Destroying the application.")
            ApplicationEntityService().quit()
            QtGui.qApp.quit()

##     ## ######## ######## ##     ##  #######  ########   ######
###   ### ##          ##    ##     ## ##     ## ##     ## ##    ##
#### #### ##          ##    ##     ## ##     ## ##     ## ##
## ### ## ######      ##    ######### ##     ## ##     ##  ######
##     ## ##          ##    ##     ## ##     ## ##     ##       ##
##     ## ##          ##    ##     ## ##     ## ##     ## ##    ##
##     ## ########    ##    ##     ##  #######  ########   ######

    def connectToOpenClinica(self):
        """Connection to OpenClinica SOAP web services
        """
        if not OCUserDetails().connected:
            QtGui.QMessageBox.warning(
                self, "Error",
                "Cannot connect to RadPlanBio - OpenClinica SOAP services!")
        else:
            return True
コード例 #9
0
ファイル: mainClient.py プロジェクト: wahyuwh/rpb-client
def startup():
    """Start the client/upgrade
    """
    logger = logging.getLogger(__name__)
    logging.config.fileConfig("logging.ini", disable_existing_loggers=False)

    # Apply app configuration according the config file
    configure()
    # Internationalisation
    # translate()

    # Log the version of client (useful for remote debuging)
    logger.info("RPB desktop client version: " + ConfigDetails().version)
    logger.info("Qt version: " + QT_VERSION_STR)
    logger.info("PyQt version: " + PYQT_VERSION_STR)

    # Basic services
    svcDiagnostic = DiagnosticService()
    svcDiagnostic.ProxyDiagnostic()

    svcHttp = HttpConnectionService(ConfigDetails().rpbHost,
                                    ConfigDetails().rpbHostPort, UserDetails())
    svcHttp.application = ConfigDetails().rpbApplication

    if ConfigDetails().proxyEnabled:
        svcHttp.setupProxy(ConfigDetails().proxyHost,
                           ConfigDetails().proxyPort,
                           ConfigDetails().noProxy)
    if ConfigDetails().proxyAuthEnabled:
        svcHttp.setupProxyAuth(ConfigDetails().proxyAuthLogin,
                               ConfigDetails().proxyAuthPassword)

    # App log
    app = QtGui.QApplication(sys.argv)
    ConfigDetails().logFilePath = (str(
        QtCore.QDir.currentPath())) + os.sep + "client.log"

    # Startup
    if ConfigDetails().isUpgrading is None or ConfigDetails(
    ).isUpgrading == "False":
        # Check whether upgrade was done
        showNotify = False
        if ConfigDetails().upgradeFinished is not None and ConfigDetails(
        ).upgradeFinished == "True":
            # Start upgrade procedure
            svcUpgrade = UpgradeService()
            svcUpgrade.cleanup()
            msg = "RadPlanBio client has been successfully upgraded"
            showNotify = True

        # Continue with standard login dialog
        loginDialog = LoginDialog(svcHttp)
        if loginDialog.exec_() == QtGui.QDialog.Accepted:

            # Main application window
            ui = MainWindow()
            ui.show()

            # Upgrade completed notification
            if showNotify:
                reply = QtGui.QMessageBox.information(ui, "Upgrade completed",
                                                      msg,
                                                      QtGui.QMessageBox.Ok)
                if reply == QtGui.QMessageBox.Ok:
                    showNotify = False

            # Automatic update check at startup
            if (ConfigDetails().startupUpdateCheck):

                # Load version from server, user details updated in login dialog
                latestSoftware = svcHttp.getLatestSoftware(
                    ConfigDetails().identifier)

                if latestSoftware != None:
                    latestVersion = str(latestSoftware.version)
                else:
                    latestVersion = ConfigDetails().version

                cmp = lambda x, y: LooseVersion(x).__cmp__(y)
                canUpgrade = cmp(ConfigDetails().version, latestVersion)
                if canUpgrade < 0:
                    ui.upgradePopup()

            currentExitCode = app.exec_()
            return currentExitCode
        else:
            ApplicationEntityService().quit()
            QtGui.qApp.quit()
    else:
        # Start updater (RadPlanBio-update.exe)
        if platform.system() == "Windows":
            if os.path.isfile("./update/RadPlanBio-update.exe"):
                QtCore.QProcess.startDetached("./update/RadPlanBio-update.exe")
            else:
                QtCore.QProcess.startDetached("python ./update/mainUpdate.py")
        elif platform.system() == "Linux":
            if os.path.isfile("./update/RadPlanBio-update"):
                QtCore.QProcess.startDetached("./update/RadPlanBio-update")
            else:
                QtCore.QProcess.startDetached("python ./update/mainUpdate.py")
        else:
            QtCore.QProcess.startDetached("python ./update/mainUpdate.py")

        # Close this one
        ApplicationEntityService().quit()
        QtGui.qApp.quit()