def __init__(self, parent=None):
        """Default Constructor
        """
        QtGui.QDialog.__init__(self, parent)
        self.setWindowTitle("About")

        size = 100
        lblIcon = QtGui.QLabel()
        appIconPath = ":/images/rpb-icon.jpg"
        myPixmap = QtGui.QPixmap(appIconPath)
        myScaledPixmap = myPixmap.scaled(size, size, Qt.KeepAspectRatio)
        lblIcon.setPixmap(myScaledPixmap)

        copyright = u"\u00A9"

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

        # About Text
        lblAppName = QtGui.QLabel(ConfigDetails().name)
        lblAppVersion = QtGui.QLabel("version: " + ConfigDetails().version)
        lblPlatform = QtGui.QLabel("system: " + platform.system())
        lblLogFile = QtGui.QLabel("log: " + ConfigDetails().logFilePath)
        lblEmptyLine = QtGui.QLabel("")
        lblAppCopyright = QtGui.QLabel(copyright + ConfigDetails().copyright)

        # Layouting
        rootLayout.addWidget(lblIcon)
        rootLayout.addWidget(lblAppName)
        rootLayout.addWidget(lblAppVersion)
        rootLayout.addWidget(lblPlatform)
        rootLayout.addWidget(lblLogFile)
        rootLayout.addWidget(lblEmptyLine)
        rootLayout.addWidget(lblAppCopyright)
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()

    # Log the version of client (useful for remote debuging)
    logger.info(ConfigDetails().name + " version: " + ConfigDetails().version)

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

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

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

        # Main application window
        ui = MainWindow()
        ui.show()
                
        currentExitCode = app.exec_()
        return currentExitCode
Exemplo n.º 3
0
    def __init__(self, parent=None):
        """Default Constructor
        """
        QtGui.QDialog.__init__(self, parent)
        self.setWindowTitle("About")

        size = 100
        lblIcon = QtGui.QLabel()
        appIconPath = ":/images/rpb-icon.jpg"
        myPixmap = QtGui.QPixmap(appIconPath)
        myScaledPixmap = myPixmap.scaled(size, size, Qt.KeepAspectRatio)
        lblIcon.setPixmap(myScaledPixmap)

        copyright = u"\u00A9"

        self.svcCrypto = CryptoService()

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

        # About Text
        lblAppName = QtGui.QLabel(ConfigDetails().name)
        lblAppVersion = QtGui.QLabel("version: " + ConfigDetails().version)
        lblPlatform = QtGui.QLabel("system: " + platform.system())
        lblLogFile = QtGui.QLabel("log: " + ConfigDetails().logFilePath)
        lblEmptyLine = QtGui.QLabel("")
        lblAppCopyright = QtGui.QLabel(copyright + ConfigDetails().copyright)

        # Show encrytpion key
        # 32 bytes long key for AES-256
        self.btnKey = QtGui.QPushButton("Encrytpion Key")
        if self.svcCrypto.keyExists():
            self.btnKey.setToolTip(
                "Show base64 encoded 32 bytes long key used for AES-256 encryption"
            )
            self.btnKey.setDisabled(False)
        else:
            self.btnKey.setToolTip("Encryption key does not exist")
            self.btnKey.setDisabled(True)
        self.btnKey.clicked.connect(self.btnKeyClicked)

        # Show Licence
        self.btnLicense = QtGui.QPushButton("License")
        self.btnLicense.setToolTip("Show software license")
        self.btnLicense.clicked.connect(self.btnLicenseClicked)

        # Layouting
        rootLayout.addWidget(lblIcon)
        rootLayout.addWidget(lblAppName)
        rootLayout.addWidget(lblAppVersion)
        rootLayout.addWidget(lblPlatform)
        rootLayout.addWidget(lblLogFile)
        rootLayout.addWidget(self.btnKey)
        rootLayout.addWidget(self.btnLicense)
        rootLayout.addWidget(lblEmptyLine)
        rootLayout.addWidget(lblAppCopyright)
Exemplo n.º 4
0
    def getPatient(self):
        # Augment with Patient PID
        self.dicomData.patient.newId = self.PatientID

        if ConfigDetails().replacePatientNameWith == "pid":
            self.dicomData.patient.newName = self.PatientID
        elif ConfigDetails().replacePatientNameWith == "const":
            self.dicomData.patient.newName = ConfigDetails().constPatientName

        return self.dicomData.patient
Exemplo n.º 5
0
    def reloadEvents(self):
        """Reload OpenClinica events scheduled for selected study subject
        """
        # Setup loading UI
        self.window().statusBar.showMessage("Loading subject scheduled events...")
        self.window().enableIndefiniteProgess()
        self.tabWidget.setEnabled(False)

        # Define a job
        # Need to get EventRepeatKeys
        self._threadPool.append(
                WorkerThread(
                        self.svcHttp.getStudyCasebookEvents, 
                        [ConfigDetails().ocHost, self.getStudyOid(), self._selectedStudySubject.oid]
                    )
            )

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

        # Start thread
        self._threadPool[len(self._threadPool) - 1].start()
Exemplo n.º 6
0
    def reloadSubjects(self):
        """Reload OpenClinica study subects enrolled into selected study/site in working thread
        """
        # Clear study subjects
        del self._studySubjects[:]
        self._studySubjects = []
        self._selectedStudySubject = None
        self._studySubjects = None
        self._subjectsREST = None

        # Setup loading UI
        self.window().statusBar.showMessage("Loading list of study subjects...")
        self.window().enableIndefiniteProgess()
        self.tabWidget.setEnabled(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, [ConfigDetails().ocHost, 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 retranslateUi(self, MainWindow):
     """
     """
     MainWindow.setWindowTitle(
         QtGui.QApplication.translate("MainWindow",
                                      ConfigDetails().name, None,
                                      QtGui.QApplication.UnicodeUTF8))
     self.btnLoadOcModule.setText(
         QtGui.QApplication.translate("MainWindow",
                                      "Load OpenClinica module", None,
                                      QtGui.QApplication.UnicodeUTF8))
    def setupUi(self, MainWindow):
        """ Prepare complete GUI for application main window
        """
        # Main window size
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(ConfigDetails().width, ConfigDetails().height)

        appIconPath = ":/images/rpb-icon.jpg"
        appIcon = QtGui.QIcon()
        appIcon.addPixmap(QtGui.QPixmap(appIconPath))
        MainWindow.setWindowIcon(appIcon)

        # Central widget is main window in this case
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))

        # Prepare menu bar UI
        self._setupMenuBar(MainWindow)

        # Root layout manager for main window is stack panel
        rootLayout = QtGui.QVBoxLayout(self.centralwidget)

        # Prepare tool bar UI
        rootLayout.addLayout(self._setupToolBar())

        # Prepare main tab for modules UI
        rootLayout.addWidget(self._setupModulesTab())

        self._setupWelcomeModule()
        self._setupStatusBar(MainWindow)

        # Put defined central widget into ManWindow central widget
        self.retranslateUi(MainWindow)
        MainWindow.setCentralWidget(self.centralwidget)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        # Event handlers
        QtCore.QObject.connect(self, QtCore.SIGNAL("RESTARTREQUIRED"),
                               self.restart)
Exemplo n.º 9
0
    def patient(self):
        """DICOM Patient Getter
        """
        if self._patient is None:
            patientIdList = self.unique("PatientID")
            if len(patientIdList) == 1:
                self._patient = DicomPatient()
                self._patient.id = patientIdList[0]
                if len(self.unique("PatientName")) == 1:
                    self._patient.name = self.unique("PatientName")[0]
                if len(self.unique("PatientSex")) == 1:
                    self._patient.gender = self.unique("PatientSex")[0]
                if len(self.unique("PatientBirthDate")) == 1:
                    self._patient.dob = self.unique("PatientBirthDate")[0]

                self._patient.newName = self._deidentConfig.ReplacePatientNameWith
                if ConfigDetails().retainPatientCharacteristicsOption:
                    self._patient.newGender = self._patient.gender
                else:
                    self._patient.newGender = self._deidentConfig.ReplaceDefaultWith
                self._patient.newDob = self._deidentConfig.ReplaceDateWith
            elif len(patientIdList) > 1:
                # More patients use the first which is detected
                self._patient = DicomPatient()
                self._patient.id = patientIdList[0]
                self._patient.name = self.unique("PatientName")[0]
                self._patient.gender = self.unique("PatientSex")[0]
                self._patient.dob = self.unique("PatientBirthDate")[0]

                self._patient.newName = self._deidentConfig.ReplacePatientNameWith
                if ConfigDetails().retainPatientCharacteristicsOption:
                    self._patient.newGender = self._patient.gender
                else:
                    self._patient.newGender = self._deidentConfig.ReplaceDefaultWith
                self._patient.newDob = self._deidentConfig.ReplaceDateWith

        return self._patient
    def handleLogin(self):
        """Send authenticate user message to site server
        """
        username = str(self.txtUsername.text())
        password = str(self.txtPassword.text())
        passwordHash = hashlib.sha1(password).hexdigest()

        # Create connection artefact to users main OpenClinica SOAP
        ocConnectInfo = OCConnectInfo(ConfigDetails().ocWsHost, username)
        ocConnectInfo.setPasswordHash(passwordHash)

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

        successfull = False
        try:
            successfull, studies = ocWebServices.listAllStudies()
        except:
            QtGui.QMessageBox.warning(
                self, "Error",
                "Cannot communicate with the server, no network connection or the server is not running."
            )

        if (successfull):
            OCUserDetails().username = username
            OCUserDetails().passwordHash = passwordHash
            OCUserDetails().connected = True

            UserDetails().username = username
            UserDetails().clearpass = password
            UserDetails().password = passwordHash

            self.accept()
        else:
            QtGui.QMessageBox.warning(self, 'Error',
                                      'Wrong username or password.')
Exemplo n.º 11
0
    def __init__(self, parent = None):
        """Default Constructor
        """
        # Setup GUI
        QWidget.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        # Hide summary of XML for importing data to OC (for user not necessary)
        self.lblSummary.hide()

        # 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 = []

        # Prepares services and main data for this ViewModel
        self.prepareServices()

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

        self.reloadData()

        # Finish UI setup
        self.lblOcConnection.setText("[" + OCUserDetails().username + "] " + ConfigDetails().ocHost)

        # Register handlers
        self.btnReloadStudySubjects.clicked.connect(self.btnReloadStudySubjectsClicked)
        self.btnNewStudySubject.clicked.connect(self.btnNewStudySubjectClicked)
        self.btnNewEvent.clicked.connect(self.btnNewEventClicked)
        self.btnUpload.clicked.connect(self.btnImportClicked)
        self.cmbStudy.currentIndexChanged["QString"].connect(self.cmbStudyChanged)
        self.destroyed.connect(self.handleDestroyed)
Exemplo n.º 12
0
def configure():
    """Read configuration settings from config file
    """
    appConfig = AppConfigurationService(ConfigDetails().configFileName)
    
    section = "OpenClinica"
    if appConfig.hasSection(section):
        option = "host"
        if appConfig.hasOption(section, option):
            ConfigDetails().ocHost = appConfig.get(section)[option]
        option = "port"
        if appConfig.hasOption(section, option):
            ConfigDetails().ocPort = appConfig.get(section)[option]

    section = "OpenClinica-ws"
    if appConfig.hasSection(section):
        option = "host"
        if appConfig.hasOption(section, option):
            ConfigDetails().ocWsHost = appConfig.get(section)[option]
        option = "port"
        if appConfig.hasOption(section, option):
            ConfigDetails().ocWsPort = appConfig.get(section)[option]

    section = "Proxy"
    if appConfig.hasSection(section):
        option = "enabled"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyEnabled = appConfig.getboolean(section, option)
        option = "host"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyHost = appConfig.get(section)[option]
        option = "port"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyPort = appConfig.get(section)[option]
        option = "noproxy"
        if appConfig.hasOption(section, option):
            ConfigDetails().noProxy = appConfig.get(section)[option]

    section = "Proxy-auth"
    if appConfig.hasSection(section):
        option = "enabled"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyAuthEnabled = appConfig.getboolean(section, option)
        option = "login"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyAuthLogin = appConfig.get(section)[option]
        option = "password"
        if appConfig.hasOption(section, option):
            ConfigDetails().proxyAuthPassword = appConfig.get(section)[option]

    section = "GUI"
    if appConfig.hasSection(section):
        option = "main.width"
        if appConfig.hasOption(section, option):
            ConfigDetails().width = int(appConfig.get(section)[option])
        option = "main.height"
        if appConfig.hasOption(section, option):
            ConfigDetails().height = int(appConfig.get(section)[option])
Exemplo n.º 13
0
def configure():
    """Read configuration settings from config file
    """
    appConfig = AppConfigurationService(ConfigDetails().configFileName)

    section = "RadPlanBioServer"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "host"):
            ConfigDetails().rpbHost = appConfig.get(section)["host"]
        if appConfig.hasOption(section, "port"):
            ConfigDetails().rpbHostPort = appConfig.get(section)["port"]
        if appConfig.hasOption(section, "application"):
            ConfigDetails().rpbApplication = appConfig.get(
                section)["application"]

    section = "Proxy"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "enabled"):
            ConfigDetails().proxyEnabled = appConfig.getboolean(
                section, "enabled")
        if appConfig.hasOption(section, "host"):
            ConfigDetails().proxyHost = appConfig.get(section)["host"]
        if appConfig.hasOption(section, "port"):
            ConfigDetails().proxyPort = appConfig.get(section)["port"]
        if appConfig.hasOption(section, "noproxy"):
            ConfigDetails().noProxy = appConfig.get(section)["noproxy"]

    section = "Proxy-auth"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "enabled"):
            ConfigDetails().proxyAuthEnabled = appConfig.getboolean(
                section, "enabled")
        if appConfig.hasOption(section, "login"):
            ConfigDetails().proxyAuthLogin = appConfig.get(section)["login"]
        if appConfig.hasOption(section, "password"):
            ConfigDetails().proxyAuthPassword = appConfig.get(
                section)["password"]

    section = "GUI"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "main.width"):
            ConfigDetails().width = int(appConfig.get(section)["main.width"])
        if appConfig.hasOption(section, "main.height"):
            ConfigDetails().height = int(appConfig.get(section)["main.height"])

    section = "DICOM"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "replacepatientnamewith"):
            ConfigDetails().replacePatientNameWith = appConfig.get(
                section)["replacepatientnamewith"]
        if appConfig.hasOption(section, "constpatientname"):
            ConfigDetails().constPatientName = appConfig.get(
                section)["constpatientname"]
        if appConfig.hasOption(section, "allowmultiplepatientids"):
            ConfigDetails().allowMultiplePatientIDs = appConfig.getboolean(
                section, "allowmultiplepatientids")
        if appConfig.hasOption(section, "retainpatientcharacteristicsoption"):
            ConfigDetails(
            ).retainPatientCharacteristicsOption = appConfig.getboolean(
                section, "retainpatientcharacteristicsoption")
        if appConfig.hasOption(section, "retainstudydate"):
            ConfigDetails().retainStudyDate = appConfig.getboolean(
                section, "retainstudydate")
        if appConfig.hasOption(section, "retainstudytime"):
            ConfigDetails().retainStudyTime = appConfig.getboolean(
                section, "retainstudytime")
        if appConfig.hasOption(section, "retainseriesdate"):
            ConfigDetails().retainSeriesDate = appConfig.getboolean(
                section, "retainseriesdate")
        if appConfig.hasOption(section, "retainseriestime"):
            ConfigDetails().retainSeriesTime = appConfig.getboolean(
                section, "retainseriestime")
        if appConfig.hasOption(section, "retainstudyseriesdescriptions"):
            ConfigDetails(
            ).retainStudySeriesDescriptions = appConfig.getboolean(
                section, "retainstudyseriesdescriptions")
        if appConfig.hasOption(section, "autortstructmatch"):
            ConfigDetails().autoRTStructMatch = appConfig.getboolean(
                section, "autortstructmatch")
        if appConfig.hasOption(section, "autortstructref"):
            ConfigDetails().autoRTStructRef = appConfig.getboolean(
                section, "autortstructref")
        if appConfig.hasOption(section, "downloaddicompatientfoldername"):
            ConfigDetails().downloadDicomPatientFolderName = appConfig.get(
                section)["downloaddicompatientfoldername"]
        if appConfig.hasOption(section, "downloaddicomstudyfoldername"):
            ConfigDetails().downloadDicomStudyFolderName = appConfig.get(
                section)["downloaddicomstudyfoldername"]

    section = "AE"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "name"):
            ConfigDetails().rpbAE = appConfig.get(section)["name"]
        if appConfig.hasOption(section, "port"):
            ConfigDetails().rpbAEport = int(appConfig.get(section)["port"])
        if appConfig.hasOption(section, "aetsuffix"):
            ConfigDetails().rpbAETsuffix = appConfig.get(section)["aetsuffix"]

        if not ApplicationEntityService().isReady:
            if ConfigDetails(
            ).rpbAE is not None and ConfigDetails().rpbAE != "":

                # Consider AET suffix option when creating AE for client
                AET = ConfigDetails().rpbAE

                if ConfigDetails().rpbAETsuffix == "host":
                    AET += str(QtNetwork.QHostInfo.localHostName())
                elif ConfigDetails().rpbAETsuffix == "fqdn":
                    AET += str(
                        QtNetwork.QHostInfo.localHostName()) + "." + str(
                            QtNetwork.QHostInfo.localDomainName())

                ApplicationEntityService().init(AET, ConfigDetails().rpbAEport)

    aeCount = 0
    section = "RemoteAEs"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "count"):
            aeCount = int(appConfig.get(section)["count"])

    for i in range(0, aeCount):
        section = "RemoteAE" + str(i)
        if appConfig.hasSection(section):
            address = ""
            if appConfig.hasOption(section, "address"):
                address = appConfig.get(section)["address"]
            port = -1
            if appConfig.hasOption(section, "port"):
                port = int(appConfig.get(section)["port"])
            aet = ""
            if appConfig.hasOption(section, "aet"):
                aet = appConfig.get(section)["aet"]

            ConfigDetails().remoteAEs.append(
                dict(Address=address, Port=port, AET=aet))

    section = "SanityTests"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "patientgendermatch"):
            ConfigDetails().patientGenderMatch = appConfig.getboolean(
                section, "patientGenderMatch")
        if appConfig.hasOption(section, "patientdobmatch"):
            ConfigDetails().patientDobMatch = appConfig.getboolean(
                section, "patientDobMatch")

    section = "General"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "startupupdatecheck"):
            ConfigDetails().startupUpdateCheck = appConfig.getboolean(
                section, "startupupdatecheck")

    section = "Temp"
    if appConfig.hasSection(section):
        if appConfig.hasOption(section, "isupgrading"):
            ConfigDetails().isUpgrading = appConfig.get(section)["isupgrading"]
        if appConfig.hasOption(section, "upgradefinished"):
            ConfigDetails().upgradeFinished = appConfig.get(
                section)["upgradefinished"]
Exemplo n.º 14
0
    def setModel(self, patient, dicomDataRoot):
        """Prepare view models for this dialog
        """
        self._patient = patient

        if dicomDataRoot is not None:

            # Take the main selected study from dataRoot
            for study in dicomDataRoot.children:
                if study.isChecked:
                    self._study = study
                    break

            # Consider all selected series from dataRoot
            for study in dicomDataRoot.children:
                for serie in study.children:
                    if serie.isChecked:
                        self._studySeries.append(serie)

        # View model for DICOM patient
        self.txtPatientId.setText(self._patient.id)
        self.txtNewPatientId.setText(self._patient.newId)
        self.txtPatientName.setText(self._patient.name)
        self.txtNewPatientName.setText(self._patient.newName)
        self.txtPatientGender.setText(self._patient.gender)
        self.txtNewPatientGender.setText(self._patient.newGender)
        self.txtPatientDOB.setText(self._patient.dob)
        self.txtNewPatientDOB.setText(self._patient.newDob)

        # View model for DICOM study
        self.cmbStudyType.addItems(self._studyTypeList)
        index = self.cmbStudyType.findText(self._study.studyType)
        if index != -1:
            self.cmbStudyType.setCurrentIndex(index)

        self.txtStudyDescription.setText(self._study.description)
        if self._study.description == "":
            self.txtNewStudyDescription.setReadOnly(True)

        # View model for DICOM study series
        self.seriesModel = DicomStudySeriesTableModel(self._studySeries)

        self.seriesProxyModel = QtGui.QSortFilterProxyModel()
        self.seriesProxyModel.setSourceModel(self.seriesModel)
        self.seriesProxyModel.setDynamicSortFilter(True)
        self.seriesProxyModel.setFilterCaseSensitivity(
            QtCore.Qt.CaseInsensitive)

        # Filtering
        QtCore.QObject.connect(self.txtSeriesFilter,
                               QtCore.SIGNAL("textChanged(QString)"),
                               self.seriesProxyModel.setFilterRegExp)

        # Assign to TableView
        self.tvSeries.setModel(self.seriesProxyModel)
        self.tvSeries.resizeColumnsToContents()

        # Selection changed
        self.cmbStudyType.currentIndexChanged['QString'].connect(
            self.cmbStudyTypeChanged)
        self.tvSeries.selectionModel().currentChanged.connect(
            self.tblSeriesItemChanged)

        # Automatically copy descriptions: save user some clicks
        if ConfigDetails().retainStudySeriesDescriptions:
            self.copyStudyDescButtonClicked()
            self.btnCopySeriesDescClicked()
Exemplo n.º 15
0
    def passSanityCheck(self, rpbStudySubject):
        """Check whether the main subject characteristics of DICOM data is matching chosen RPB subject
        """
        genderPass = False
        dobPass = False

        if rpbStudySubject.subject != None and self._patient != None:

            # Gender match is enabled and RPB subject has gender and DICOM patient has gender
            if ConfigDetails().patientGenderMatch and \
               rpbStudySubject.subject.gender is not None and rpbStudySubject.subject.gender != "" and \
               self._patient.gender is not None and self._patient.gender != "" and self._patient.gender != "O":

                # Gender is the same
                if rpbStudySubject.subject.gender.lower(
                ) == self._patient.gender.lower():
                    genderPass = True
                    self._logger.info("Gender sanity check passed.")
                else:
                    self._logger.error("RPB subject gender: " +
                                       rpbStudySubject.subject.gender.lower())
                    self._logger.error("DICOM patient gender: " +
                                       self._patient.gender.lower())

            # Gender is not provided so pass the test
            else:
                genderPass = True
                self._logger.info("Gender sanity check was skipped.")

            # DOB match is enabled and full date of birth collected and RPB subject has DOB and DICOM patient has DOB
            if ConfigDetails().patientDobMatch and\
               rpbStudySubject.subject.dateOfBirth is not None and rpbStudySubject.subject.dateOfBirth != "" and\
               self._patient.dob != None and self._patient.dob != "":

                # Convert from strings dates
                format = "%Y%m%d"
                dicomdob = datetime.strptime(self._patient.dob, format)
                deidentdob = datetime.strptime(
                    self._deidentConfig.ReplaceDateWith, format)
                format = "%Y-%m-%d"
                edcdob = datetime.strptime(rpbStudySubject.subject.dateOfBirth,
                                           format)

                # DOB is the same
                if edcdob == dicomdob:
                    dobPass = True
                    self._logger.info("Full DOB sanity check passed.")
                # DICOM DOB was deidentified before
                elif dicomdob == deidentdob:
                    dobPass = True
                    self._logger.info(
                        "DOB sanity chack was skipped, because provided DICOM DOB is already de-identifed."
                    )
                else:
                    self._logger.error("RPB subject date of birth: " +
                                       str(edcdob))
                    self._logger.error("DICOM patient date of birth: " +
                                       str(dicomdob))

            # DOB match is enabled and only year of birth collected and RPB subject has year of birth and DICOM patient has DOB
            elif ConfigDetails().patientDobMatch and\
                 rpbStudySubject.subject.yearOfBirth is not None and rpbStudySubject.subject.yearOfBirth != "" and\
                 self._patient.dob != None and self._patient.dob != "":

                # Year of birth is the same
                if rpbStudySubject.subject.yearOfBirth == self._patient[:4]:
                    dobPass = True
                    self._logger.info("Year of birth sanity check passed.")
                else:
                    self._logger.error("RPB subject year of birth: " +
                                       rpbStudySubject.subject.yearOfBirth)
                    self._logger.error("DICOM patient year of birth: " +
                                       self._patient[:4])

            # DOB is not provided so pass the test
            else:
                dobPass = True
                self._logger.info("DOB sanity check was skipped.")

        return genderPass and dobPass
Exemplo n.º 16
0
    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!")
Exemplo n.º 17
0
    def setModel(self, originalRoiNameDict, formalizedRTStructs, leftRightContours, extraTextContours, oarContours, tvContours, tvMultipleContours):
        """Fills the entries of the table with the ROI names and checkboxes for the default names
        """
        self.__originalRoiNameDict = originalRoiNameDict
        self.__originalRoiNumberList = originalRoiNameDict.keys()
        self.__formalizedRTStructs = formalizedRTStructs

        self._extraTextContours = extraTextContours
        self._leftRightContours = leftRightContours
        self._oarContours = oarContours
        self._tvContours = tvContours
        self._tvMultipleContours = tvMultipleContours

        # Each ROI will be presented on separate row
        Nrows = len(self.__originalRoiNameDict.values())
        Ncols = 6

        # Set number of rows and columns and set widths and titles of rows
        self.tableWidget.setRowCount(Nrows)
        self.tableWidget.setColumnCount(Ncols)
        self.tableWidget.setColumnWidth(0, 200)
        self.tableWidget.setColumnWidth(1, 200)
        self.tableWidget.setColumnWidth(2, 200)
        self.tableWidget.setColumnWidth(3, 120)
        self.tableWidget.setColumnWidth(4, 120)
        self.tableWidget.setColumnWidth(5, 200)
        self.tableWidget.setHorizontalHeaderLabels(["Original Name", "Replace Name" ,"Assigned Name", "Additional Info", "Margin (mm)", "Prescription dose (cGy)"])

        # Full table: standardised combined string
        self.txtStandardisedList = []
        # Fill table: original ROI name on the left, default name comboboxes on the right
        self.comboBoxList = []
        # Fill the table: additional info txt box
        self.cmbExtraList = []
        # Fill the table: margin txt box
        self.cmbMarginList = []
        # Fill the table: dose txt box
        self.cmbDoseList = []

        # Create rows
        for i in xrange(Nrows):

            # Key for Original ROI Name dictionary - it is the number of original ROI in DCM
            key = self.__originalRoiNumberList[i]

            # Standard
            txtStandard = QtGui.QLabel()
            txtStandard.setStyleSheet(self.greenStyle)

            # Assigned name
            combobox = ExtendedCombo()
            combobox.setStyleSheet(self.orangeStyle)

            # Organ laterality and extra
            cmbExtra = QtGui.QComboBox()
            cmbExtra.setStyleSheet(self.orangeStyle)
            cmbExtra.setEnabled(False)
            cmbExtra.setEditable(False)

            # Margin
            cmbMargin = QtGui.QComboBox()
            cmbMargin.setStyleSheet(self.orangeStyle)
            cmbMargin.setEnabled(False)
            cmbMargin.setEditable(False)

            # Dose
            cmbDose = QtGui.QComboBox()
            cmbDose.setStyleSheet(self.orangeStyle)
            cmbDose.setEnabled(False)
            cmbDose.setEditable(False)

            # Use formalized RTStructs as data set for combobox
            rtsNames = []
            for item in self.__formalizedRTStructs:
                combobox.addItem(item.name, item.identifier)
                rtsNames.append(item.name)

            # Put original ROI name into first column
            self.tableWidget.setItem(
                i,
                0,
                QtGui.QTableWidgetItem(
                    self.__originalRoiNameDict[key][0])
                )
            # Original name is not editable
            self.tableWidget.item(i, 0).setFlags(QtCore.Qt.ItemIsSelectable |  QtCore.Qt.ItemIsEnabled)
            self.tableWidget.item(i, 0).setBackgroundColor(QtGui.QColor(gui.colours.RED))

            # Put combo boxes to extra columns
            self.tableWidget.setCellWidget(i, 1, txtStandard)
            self.tableWidget.setCellWidget(i, 2, combobox)
            self.tableWidget.setCellWidget(i, 3, cmbExtra)
            self.tableWidget.setCellWidget(i, 4, cmbMargin)
            self.tableWidget.setCellWidget(i, 5, cmbDose)

            # Automatic matching of RTStructs names is configurable
            j = 0 # Select first otherwise
            if ConfigDetails().autoRTStructMatch:
                # Find most promising agreement (first) to ROIName in default_values
                closest = get_close_matches(\
                    self.__originalRoiNameDict[key][0],\
                    rtsNames, 1, 0)[0]

                # Find position of closest name in
                j = rtsNames.index(closest)
            
            combobox.setCurrentIndex(j)

            self.logger.debug(self.__originalRoiNameDict[key][0] + \
                " initally mapped to: " + \
                self.formalizedRTStructs[j].identifier.encode("utf-8"))

            # Save presselected options to RoiNameDic
            self.__originalRoiNameDict[self.__originalRoiNumberList[i]].\
                append(self.formalizedRTStructs[j].identifier)

            # Show initial mapping in GUI
            txtStandard.setText(self.formalizedRTStructs[j].identifier.encode("utf-8"))

            # Enable additional info for L/R
            if self.__formalizedRTStructs[j].name in self._leftRightContours:
                cmbExtra.setEnabled(True)
                cmbExtra.setEditable(False)
                cmbExtra.clear()
                for lrItem in self._leftRightModel:
                    cmbExtra.addItem(lrItem[0], lrItem[1])
            # Enable additional info form multiple TV
            elif self.__formalizedRTStructs[j].name in self._tvMultipleContours:
                cmbExtra.setEnabled(True)
                cmbExtra.setEditable(False)
                cmbExtra.clear()
                for multiItem in self._tvMultipleModel:
                    cmbExtra.addItem(multiItem[0], multiItem[1])

            # Enable non standard additional info for contours of common type
            elif self.__formalizedRTStructs[j].name in self._extraTextContours:
                cmbExtra.setEnabled(True)
                cmbExtra.setEditable(True)
                cmbExtra.clear()
            else:
                cmbExtra.setEnabled(False)
                cmbExtra.setEditable(False)
                cmbExtra.clear()

            # Enable margin info for organ at risk OAR as well as TV
            if self.__formalizedRTStructs[j].name in self._oarContours:
                cmbMargin.setEnabled(True)
                cmbMargin.setEditable(True)
                cmbMargin.setValidator(QtGui.QIntValidator(0, 99, cmbMargin))
                cmbMargin.clear()
                for marginItem in self._oarMarginModel:
                    cmbMargin.addItem(marginItem[0], marginItem[1])
            elif self.__formalizedRTStructs[j].name in self._tvContours:
                cmbMargin.setEnabled(True)
                cmbMargin.setEditable(True)
                cmbMargin.setValidator(QtGui.QIntValidator(0, 99, cmbMargin))
                cmbMargin.clear()
            else:
                cmbMargin.setEnabled(False)
                cmbMargin.setEditable(False)
                cmbMargin.clear()

            # Enable dose info for target volume TV
            if self.__formalizedRTStructs[j].name in self._tvContours:
                cmbDose.setEnabled(True)
                cmbDose.setEditable(True)
                cmbDose.setValidator(QtGui.QIntValidator(0, 90000, cmbDose))
                cmbDose.clear()
            else:
                cmbDose.setEnabled(False)
                cmbDose.setEditable(False)
                cmbDose.clear()

            # Handler
            self.connect(combobox, QtCore.SIGNAL("currentIndexChanged(QString)"), self.updateMapping)
            self.connect(cmbExtra, QtCore.SIGNAL("editTextChanged(QString)"), self.updateDetailsMappingText)
            self.connect(cmbExtra, QtCore.SIGNAL("currentIndexChanged(int)"), self.updateDetailsMappingCombo)
            self.connect(cmbMargin, QtCore.SIGNAL("currentIndexChanged(int)"), self.updateMarginMappingCombo)
            self.connect(cmbMargin, QtCore.SIGNAL("editTextChanged(QString)"), self.updateMarginMappingText)
            self.connect(cmbDose, QtCore.SIGNAL("editTextChanged(QString)"), self.updateDoseMappingText)

            # Append combobox to list
            self.txtStandardisedList.append(txtStandard)
            self.comboBoxList.append(combobox)
            self.cmbExtraList.append(cmbExtra)
            self.cmbMarginList.append(cmbMargin)
            self.cmbDoseList.append(cmbDose)
Exemplo n.º 18
0
    def downloadDicomData(self, data, thread):
        """Get DICOM data from server
        """
        downloadDir = data[0]  # self._downloadDir
        studyIdentifier = data[1]  # self.getStudyIdentifier()
        svcHttp = data[2]

        # Create study/site folder
        thread.emit(QtCore.SIGNAL("log(QString)"),
                    "Creating download study folder...")

        studyPath = downloadDir + os.sep + studyIdentifier
        if not os.path.isdir(studyPath):
            os.mkdir(studyPath)

        # Give me and list of what DICOM studies are available and how to access them
        thread.emit(QtCore.SIGNAL("log(QString)"),
                    "Querying list of available DICOM data...")

        patientsDicomData = svcHttp.getAllSubjectsDicomData(studyIdentifier)

        thread.emit(QtCore.SIGNAL("log(QString)"),
                    str(len(patientsDicomData)) + " patients available...")

        # For each patient
        for p in patientsDicomData:

            # Create patient folder
            patientFolderName = ""

            if ConfigDetails().downloadDicomPatientFolderName == "pid":
                patientFolderName = p.uniqueIdentifier
            elif ConfigDetails().downloadDicomPatientFolderName == "ssid":
                patientFolderName = p.studySubjectId

            thread.emit(
                QtCore.SIGNAL("log(QString)"), "Processing patient: " +
                p.uniqueIdentifier + " (" + p.studySubjectId + ")")

            patientPath = studyPath + os.sep + patientFolderName
            if not os.path.isdir(patientPath):
                os.mkdir(patientPath)

            # For each dicom study
            for dicom in p.dicomData:

                studyFolderName = ""
                if ConfigDetails().downloadDicomStudyFolderName == "oid":
                    studyFolderName = dicom.oid
                elif ConfigDetails().downloadDicomStudyFolderName == "label":
                    studyFolderName = dicom.label

                thread.emit(
                    QtCore.SIGNAL("log(QString)"),
                    "Unzipping DICOM study data: " + studyFolderName +
                    " please wait...")

                # Unzip and list of files
                data = svcHttp.unzipDicomData(dicom.webApiUrl)

                # Download files
                count = len(data[0].dicomData[0].fileUrls)
                downloaded = 0
                thread.emit(
                    QtCore.SIGNAL("log(QString)"),
                    str(count) + " files in DICOM study: " + studyFolderName)

                # Create DICOM study folder - based on crfItem name
                thread.emit(
                    QtCore.SIGNAL("log(QString)"),
                    "Downloading DICOM study data: " + studyFolderName + "...")

                studyPath = patientPath + os.sep + studyFolderName
                if not os.path.isdir(studyPath):
                    os.mkdir(studyPath)

                for fileUrl in data[0].dicomData[0].fileUrls:
                    svcHttp.downloadDicomData(fileUrl, studyPath)
                    downloaded += 1

                    thread.emit(QtCore.SIGNAL("taskUpdated"),
                                [downloaded, count])

                # Cleanup unzipped files from server
                svcHttp.clearDicomData(dicom.webApiUrl)

        thread.emit(QtCore.SIGNAL('log(QString)'), 'Finished!')
        thread.emit(QtCore.SIGNAL('message(QString)'),
                    "Download job was successful.")

        return True
Exemplo n.º 19
0
    def checkTreatmentPlanData(self, thread=None):
        """Checks the completeness of DICOM study data (treatment plan)

        Only applicable if study is treatment plan
        """
        modalities = self.dicomData.getModalities()

        if "CT" in modalities and \
           "RTSTRUCT" in modalities and \
           "RTPLAN" in modalities and \
           "RTDOSE" in modalities:

            ct_dicomData = self.dicomData.belongingTo("Modality", "CT")
            li_SOPInstanceUID_CT = []
            for elem in ct_dicomData:
                li_SOPInstanceUID_CT.append(elem["SOPInstanceUID"])

            # Check how many RTSTRUCT is in the folder
            rtstruct_dicomData = self.dicomData.belongingTo(
                "Modality", "RTSTRUCT")
            if len(rtstruct_dicomData) > 1:
                thread.emit(QtCore.SIGNAL("message(QString)"),
                            gui.messages.ERR_MULTIPLE_RTSTRUCT)
                return False

            rtstruct_dicomData = rtstruct_dicomData[0]

            if "FrameOfReferenceUID" not in rtstruct_dicomData:
                msg = "Structure set is not defined on top of CT data. "
                msg += "Upload of inconsistent treatment plan is not possible!"
                thread.emit(QtCore.SIGNAL("message(QString)"), msg)
                return False

            # Check whether all CT images to where RTSTRUCT refers are provided
            missingCT = False
            missingCT_UID = []
            for elem in rtstruct_dicomData["ContourImageSequence"]:
                if elem not in li_SOPInstanceUID_CT:
                    missingCT = True
                    missingCT_UID.append(elem)
            if missingCT:
                msg = "Structure set (RTSTRUCT) is referencing CT images which are not within the provided data set: "
                msg += str(missingCT_UID)
                thread.emit(QtCore.SIGNAL("message(QString)"), msg)
                return False

            rtplan_dicomData = self.dicomData.belongingTo("Modality", "RTPLAN")

            # SOP instance UID of RTSTRUCT
            rtstruct_SOPInstanceUID = rtstruct_dicomData["SOPInstanceUID"]

            # Collect SOP instance UID from RTPLAN (one or more)
            rtplan_SOPInstanceUID = []
            # Each plan sould refer max 1 RTSTRUCT
            planRefStructUID = []

            for elem in rtplan_dicomData:
                rtplan_SOPInstanceUID.append(elem["SOPInstanceUID"])
                planRefStructUID.append(
                    elem["ReferencedSOPInstanceUID_RTSTRUCT"])

            # Collect SOP instance UID from RTDOSE referencing to RTPLAN
            # Collect SOP instance UID from RTDOSE referencing to RTSTRUCT
            rtdose_dicomData = self.dicomData.belongingTo("Modality", "RTDOSE")
            self._doseCount = len(rtdose_dicomData)

            doseRefPlanUID = []
            doseRefStructUID = []
            for elem in rtdose_dicomData:
                doseRefPlanUID.append(elem["ReferencedSOPInstanceUID_RTPLAN"])
                # Is not mandatory so it does not have to be there
                if "ReferencedSOPInstanceUID_RTSTRUCT" in elem:
                    doseRefStructUID.append(
                        elem["ReferencedSOPInstanceUID_RTSTRUCT"])

            # Remove duplicate values
            doseRefStructUID = list(set(doseRefStructUID))
            doseRefPlanUID = list(set(doseRefPlanUID))

            # Check whether the all RTPLANs referenced from RTDOSEs exists
            for refRtPlanUID in doseRefPlanUID:
                if refRtPlanUID not in rtplan_SOPInstanceUID:
                    msg = "One of RTDOSE is referencing to unknown RTPLAN. "
                    msg += "Upload of inconsistent treatment plan is not possible!"
                    thread.emit(QtCore.SIGNAL("message(QString)"), msg)
                    return False

            # Check whether the RTSTRUCT referenced from RTDOSEs exists
            for refRtStructUID in doseRefStructUID:
                if refRtStructUID != rtstruct_SOPInstanceUID:
                    msg = "One of RTDOSE is referencing to unknown RTSTRUCT. "
                    msg += "Upload of inconsistent treatment plan is not possible!"
                    thread.emit(QtCore.SIGNAL("message(QString)"), msg)
                    return False

            # How many RTPLAN and RTDOSE SOP instances have been detected
            if rtplan_dicomData is not None:
                self._planCount = len(rtplan_dicomData)
            if rtdose_dicomData is not None:
                self._doseCount = len(rtdose_dicomData)

            # RTDOSE DoseSummationType should be uniform accross treatment planning data
            self._summNumberOfBeams = 0
            if len(self.dicomData.unique("DoseSummationType")) == 1:
                self._doseSumType = self.dicomData.unique(
                    "DoseSummationType")[0]

                if self._doseSumType == "BEAM":
                    for i in xrange(self._planCount):
                        # Summ number of beams from each plan
                        if "BeamNumbers" in rtplan_dicomData[i]:
                            self._summNumberOfBeams += rtplan_dicomData[i][
                                "BeamNumbers"]

            # Check whether the RTSTRUCT is referenced from all RTPLANs
            if not ConfigDetails().autoRTStructRef:
                for refRtStructUID in planRefStructUID:
                    if refRtStructUID != rtstruct_SOPInstanceUID:
                        msg = "One of RTPLAN is referencing to unknown RTSTRUCT. "
                        msg += "Upload of inconsistent treatment plan is not possible!"
                        thread.emit(QtCore.SIGNAL("message(QString)"), msg)
                        return False

            return True

        else:
            missingModality = ""
            li_ModalityFull = ["RTSTRUCT", "RTPLAN", "CT", "RTDOSE"]
            for elem in li_ModalityFull:
                if elem not in modalities:
                    missingModality = elem

            msg = "Treatment plan data is not complete. "
            msg += missingModality + " modality is missing. "
            msg += "Upload of not complete treatment plan is not possible. "
            msg += "Please correct your treatment plan and try it again."
            thread.emit(QtCore.SIGNAL("message(QString)"), msg)

            return False
    for study in studies:
        selectedStudy = study
        sucessfull, studyMetadata = ocWebServices.getStudyMetadata(selectedStudy)
        break

# Load subject for whole study or only site if it is multicentre study
if selectedStudy and selectedStudy.isMulticentre:
    studySubjects = ocWebServicees.listAllStudySubjectsByStudySite(
        [selectedStudy, selectedStudySite, studyMetadata]
    )
else:
    studySubjects = ocWebServices.listAllStudySubjectsByStudy(
        [selectedStudy, studyMetadata]
    )

ConfigDetails().ocHost = "http://skripcak.net:8080/OpenClinica"
ConfigDetails().ocPort = "80"

UserDetails().username = OCUserDetails().username
UserDetails().clearpass = password

svcHttp = HttpConnectionService(
    ConfigDetails().ocHost, 
    ConfigDetails().ocPort, 
    UserDetails()
)

restSubjects = svcHttp.getStudyCasebookSubjects(
    [ConfigDetails().ocHost, selectedStudy.oid]
)
Exemplo n.º 21
0
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()
    def __init__(self):
        """Default constructor
        """
        # Setup GUI
        QtGui.QDialog.__init__(self)
        self.setWindowTitle("OpenClinica - Login")
        appIconPath = ':/images/rpb-icon.jpg'
        appIcon = QtGui.QIcon()
        appIcon.addPixmap(QtGui.QPixmap(appIconPath))
        self.setWindowIcon(appIcon)

        toolBarButtonSize = 15

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

        # Login grid
        loginLayout = QtGui.QGridLayout()
        loginLayout.setSpacing(10)
        rootLayout.addLayout(loginLayout)

        # Connection
        lblConnection = QtGui.QLabel("Connection:")
        self.txtConnection = QtGui.QLineEdit()
        self.txtConnection.setText(ConfigDetails().ocHost + "/")
        self.txtConnection.setMinimumWidth(300)
        self.txtConnection.setDisabled(True)

        # User label
        lblUsername = QtGui.QLabel("Username:"******"Password:"******"Login")
        self.btnLogin.setIcon(loginIcon)
        self.btnLogin.setToolTip("Login")
        self.btnLogin.setIconSize(
            QtCore.QSize(toolBarButtonSize, toolBarButtonSize))
        self.btnLogin.clicked.connect(self.handleLogin)

        # Add to connection layout
        loginLayout.addWidget(lblConnection, 0, 0)
        loginLayout.addWidget(self.txtConnection, 0, 2)
        loginLayout.addWidget(lblUsername, 1, 0)
        loginLayout.addWidget(self.txtUsername, 1, 1, 1, 2)

        loginLayout.addWidget(lblPassword, 2, 0)
        loginLayout.addWidget(self.txtPassword, 2, 1, 1, 2)

        loginLayout.addWidget(self.btnLogin, 3, 1, 1, 2)

        self.txtUsername.setFocus()

        #------------------------------------------------------------------
        #------------------ ViewModel -------------------------------------
        self.userName = ""
        self.password = ""
Exemplo n.º 23
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()
Exemplo n.º 24
0
    def prepareServices(self):
        """Prepare services for this module
        """
        # HTTP connection to RadPlanBio server (Database)
        self.svcHttp = HttpConnectionService(ConfigDetails().ocHost, ConfigDetails().ocPort, UserDetails())

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

        # Create connection artefact to users main OpenClinica SOAP
        self.ocConnectInfo = OCConnectInfo(ConfigDetails().ocWsHost, 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.svcOdm = OdmFileDataService()
if successfull:
    for study in studies:
        selectedStudy = study
        sucessfull, studyMetadata = ocWebServices.getStudyMetadata(
            selectedStudy)
        break

# Load subject for whole study or only site if it is multicentre study
if selectedStudy and selectedStudy.isMulticentre:
    studySubjects = ocWebServicees.listAllStudySubjectsByStudySite(
        [selectedStudy, selectedStudySite, studyMetadata])
else:
    studySubjects = ocWebServices.listAllStudySubjectsByStudy(
        [selectedStudy, studyMetadata])

ConfigDetails().ocHost = "http://skripcak.net:8080/OpenClinica"
ConfigDetails().ocPort = "80"

UserDetails().username = OCUserDetails().username
UserDetails().clearpass = password

svcHttp = HttpConnectionService(ConfigDetails().ocHost,
                                ConfigDetails().ocPort, UserDetails())

restSubjects = svcHttp.getStudyCasebookSubjects(
    [ConfigDetails().ocHost, selectedStudy.oid])

# Enhance with subject OID
for studySubject in studySubjects:
    for sREST in restSubjects:
        if sREST.studySubjectId == studySubject.label:
Exemplo n.º 26
0
    def __init__(self, destination, patient, dicomDataRoot, mappingRoiDic):
        """Default constructor
        """
        self._svcCrypto = CryptoService()

        # Configuration of deidentification
        self._deidentConfig = DeidentConfig()
        self._deidentConfig.ReplacePatientNameWith = patient.newName
        self._deidentConfig.RetainPatientCharacteristicsOption = ConfigDetails(
        ).retainPatientCharacteristicsOption

        # Load the deident model according to configuration
        self._modelLoader = DeidentModelLoader(self._deidentConfig)

        # Get profile and options from loaded model
        self._profile = self._modelLoader.GetProfile()
        self._options = self._modelLoader.GetOptions()

        self._destination = destination
        self._lastGeneratedUid = None

        self._errorMessage = ""
        self._sourceSize = 0

        # List of original DICOM UID for elements with name in li_NameUID
        self.li_UID = blist([])
        # List of anonymised DICOM UID for element with name in li_NameUID
        self.li_UID_anonym = blist([])

        self.__patient = patient

        if dicomDataRoot is not None:
            self._dicomDataRoot = dicomDataRoot
            self.__series = []

            # Take the main selected study from dataRoot
            for study in dicomDataRoot.children:
                if study.isChecked:
                    self.__study = study
                    break

            # Consider all selected series from dataRoot
            for study in dicomDataRoot.children:
                for serie in study.children:
                    if serie.isChecked:
                        self.__series.append(serie)

        self.__mappingRoiDic = mappingRoiDic

        # These list for now define the Basic Profile

        # Which fields are UIDs and should be replaced by randomly generated UID
        self.li_NameUID = [
            'Concatenation UID', 'Context Group Extension Creator UID',
            'Creator Version UID', 'Creator-Version UID', 'Device UID',
            'Dimension Organization UID', 'Dose Reference UID',
            'Failed SOP Instance UID List', 'Fiducial UID',
            'Frame of Reference UID', 'Instance Creator UID',
            'Irradiation Event UID', 'Large Palette Color Lookup Table UID',
            'Media Storage SOP Instance UID', 'Palette Color Lookup Table UID',
            'Referenced Frame of Reference UID',
            'Referenced General Purpose Scheduled Procedure Step Transaction UID',
            'Referenced SOP Instance UID',
            'Referenced SOP Instance UID in File',
            'Related Frame of Reference UID', 'Requested SOP Instance UID',
            'Series Instance UID', 'SOP Instance UID',
            'Storage Media File-set UID',
            'Synchronization Frame of Reference UID',
            'Template Extension Creator UID',
            'Template Extension Organization UID', 'Transaction UID', 'UID'
        ]

        # Which fields should be removed
        self.li_NameRemove = [
            'Acquisition Comments', 'Acquisition Context Sequence',
            'Acquisition Protocol Description',
            'Actual Human Performers Sequence', "Additional Patient's History",
            "Additional Patient History", 'Admission ID', 'Admitting Date',
            'Admitting Diagnoses Code Sequence',
            'Admitting Diagnoses Description', 'Admitting Time',
            'Affected SOP Instance UID', 'Allergies', 'Arbitrary',
            'Author Observer Sequence', 'Branch of Service', 'Cassette ID',
            'Comments on Performed Procedure Step',
            'Comments on the Performed Procedure Step',
            'Confidentiality Constraint on Patient Data Description',
            "Content Creator's Identification Code",
            "Content Creator's Identification Code Sequence",
            'Content Sequence', 'Contribution Description',
            'Country of Residence', 'Current Patient Location', 'Curve Data',
            'Curve Date', 'Curve Time', 'Custodial Organization Sequence',
            'Data Set Trailing Padding', 'Derivation Description',
            'Detector ID', 'Digital Signature UID',
            'Digital Signatures Sequence', 'Discharge Diagnosis Description',
            'Distribution Address', 'Distribution Address', 'Ethnic Group',
            'Frame Comments', 'Gantry ID', 'Generator ID',
            'Human Performers Name', "Human Performer's Name",
            'Human Performers Organization', "Human Performer's Organization",
            'Icon Image Sequence', 'Identifying Comments', 'Image Comments',
            'Image Presentation Comments', 'Image Service Request Comments',
            "Imaging Service Request Comments", 'Impressions',
            'Institution Address', 'Institutional Department Name',
            'Insurance Plan Identification',
            'Intended Recipients of Results Identification Sequence',
            'Interpretation Approver Sequence', 'Interpretation Author',
            'Interpretation Diagnosis Description', 'Interpretation ID Issuer',
            'Interpretation Recorder', 'Interpretation Text',
            'Interpretation Transcriber', 'Issuer of Admission ID',
            'Issuer of Patient ID', 'Issuer of Service Episode ID',
            'Last Menstrual Date', 'MAC', 'Medical Alerts',
            'Medical Record Locator', 'Military Rank',
            'Modified Attributes Sequence', 'Modified Image Description',
            'Modifying Device ID', 'Modifying Device Manufacturer',
            'Name of Physician(s) Reading Study',
            'Names of Intended Recipients of Results', 'Occupation',
            'Original Attributes Sequence', 'Order Callback Phone Number',
            'Order Entered By', 'Order Enterer Location',
            "Order Enterer's Location", 'Other Patient IDs',
            'Other Patient IDs Sequence', 'Other Patient Names',
            'Overlay Comments', 'Overlay Data', 'Overlay Date', 'Overlay Time',
            'Participant Sequence', 'Patient Address', "Patient's Address",
            "Patient's Age", 'Patient Comments', 'Patient State',
            'Patient Transport Arrangements', "Patient's Birth Name",
            "Patient's Birth Time", "Patient's Institution Residence",
            "Patient's Insurance Plan Code Sequence",
            "Patient's Mother's Birth Name",
            "Patient's Primary Language Code Sequence",
            "Patient's Primary Language Modifier Code Sequence",
            "Patient's Religious Preference", "Patient's Size",
            "Patient's Telephone Numbers", "Patient's Weight",
            'Performed Location', 'Performed Procedure Step Description',
            'Performed Procedure Step ID',
            'Performed Procedure Step Start Date',
            'Performed Procedure Step Start Time',
            'Performed Station AE Title',
            'Performed Station Geographic Location Code Sequence',
            'Performed Station Name', 'Performed Station Name Code Sequence',
            "Performing Physicians' Identification Sequence",
            "Performing Physician Identification Sequence",
            "Performing Physicians' Name", "Performing Physician's Name",
            'Person Address', "Person's Address", 'Person Telephone Numbers',
            "Person's Telephone Numbers", 'Physician Approving Interpretation',
            'Physician Reading Study Identification Sequence',
            "Physician(s) Reading Study Identification Sequence",
            'Physician(s) of Record',
            'Physician(s) of Record Identification Sequence', 'Plate ID',
            'Procedure Code Sequence', 'Pre-Medication', 'Pregnancy Status',
            'Reason for Imaging Service Request',
            'Reason for the Imaging Service Request', 'Reason for Study',
            'Referenced Digital Signature Sequence',
            'Referenced Patient Alias Sequence', 'Referenced Patient Sequence',
            'Referenced Performed Procedure Step Sequence',
            'Referenced SOP Instance MAC Sequence',
            'Referenced Study Sequence', "Referring Physician's Address",
            "Referring Physician's Identification Sequence",
            "Referring Physician Identification Sequence",
            "Referring Physician's Telephone Numbers", 'Region of Residence',
            'Request Attributes Sequence', 'Requested Contrast Agent',
            'Requested Procedure Comments', 'Requested Procedure ID',
            'Requested Procedure Code Sequence',
            'Requested Procedure Location', 'Requesting Physician',
            'Requesting Service', 'Responsible Person', 'Results Comments',
            'Results Distribution List Sequence', 'Results ID Issuer',
            'Scheduled Human Performers Sequence',
            'Scheduled Patient Institution Residence',
            'Scheduled Performing Physician Identification Sequence',
            'Scheduled Performing Physician Name',
            "Scheduled Performing Physician's Name",
            'Scheduled Procedure Step End Date',
            'Scheduled Procedure Step End Time',
            'Scheduled Procedure Step Description',
            'Scheduled Procedure Step Location',
            'Scheduled Procedure Step Start Date',
            'Scheduled Procedure Step Start Time',
            'Scheduled Station AE Title',
            'Scheduled Station Geographic Location Code Sequence',
            'Scheduled Station Name', 'Scheduled Station Name Code Sequence',
            'Scheduled Study Location', 'Scheduled Study Location AE Title',
            'Service Episode Description', 'Service Episode ID',
            'Smoking Status', 'Source Image Sequence', 'Special Needs',
            'Study Comments', 'Study ID', 'Study ID Issuer', 'Text Comments',
            'Text String', 'Timezone Offset From UTC', 'Topic Author',
            'Topic Key Words', "Topic Keywords", 'Topic Subject',
            'Topic Title', 'Verifying Organization', 'Visit Comments'
        ]

        # Which fields sshould be replaces by default value
        self.li_NameReplace = [
            'Accession Number', 'Acquisition Date', 'Acquisition Date Time',
            "Acquisition DateTime",
            'Acquisition Device Processing Description', 'Acquisition Time',
            "Content Creator's Name", 'Content Date', 'Content Time',
            'Contrast Bolus Agent', "Contrast/Bolus Agent",
            'Device Serial Number',
            'Filler Order Number of Imaging Service Request',
            "Filler Order Number / Imaging Service Request",
            'Graphic Annotation Sequence', 'Institution Code Sequence',
            'Institution Name', "Operators' Identification Sequence",
            "Operator Identification Sequence", "Operators' Name",
            "Patient's Sex", 'Patient Sex Neutered', "Patient's Sex Neutered",
            "Patient's Birth Date", 'Person Identification Code Sequence',
            'Placer Order Number of Imaging Service Request',
            "Placer Order Number / Imaging Service Request", 'Protocol Name',
            "Referring Physician's Name", 'Requested Procedure Description',
            'Reviewer Name', "Series Date", "Series Time", 'Station Name',
            "Study Date", 'Study ID', "Study Time",
            'Verifying Observer Identification Code Sequence',
            'Verifying Observer Name', 'Verifying Observer Sequence'
        ]

        # Study/Series Date and Time seems to be important for later analysis
        if ConfigDetails().retainStudyDate:
            self.li_NameReplace.remove("Study Date")
        if ConfigDetails().retainStudyTime:
            self.li_NameReplace.remove("Study Time")
        if ConfigDetails().retainSeriesDate:
            self.li_NameReplace.remove("Series Date")
        if ConfigDetails().retainSeriesTime:
            self.li_NameReplace.remove("Series Time")