Example #1
0
    def InitTree(self):
        """Initialize the tree control for use."""

        iSize = (16, 16)
        iList = wx.ImageList(iSize[0], iSize[1])
        iList.Add(wx.Bitmap(util.GetResourcePath("group.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(wx.Bitmap(util.GetResourcePath("user.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(wx.Bitmap(util.GetResourcePath("book.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(
            wx.Bitmap(util.GetResourcePath("table_multiple.png"), wx.BITMAP_TYPE_PNG)
        )
        iList.Add(wx.Bitmap(util.GetResourcePath("pencil.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(wx.Bitmap(util.GetResourcePath("chart_bar.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(
            wx.Bitmap(util.GetResourcePath("chart_curve.png"), wx.BITMAP_TYPE_PNG)
        )
        iList.Add(
            wx.Bitmap(util.GetResourcePath("pencil_error.png"), wx.BITMAP_TYPE_PNG)
        )
        iList.Add(
            wx.Bitmap(util.GetResourcePath("chart_bar_error.png"), wx.BITMAP_TYPE_PNG)
        )
        iList.Add(
            wx.Bitmap(util.GetResourcePath("chart_curve_error.png"), wx.BITMAP_TYPE_PNG)
        )

        self.tcPatients.AssignImageList(iList)

        root = self.tcPatients.AddRoot("Patients", image=0)

        return root
Example #2
0
    def __init__(self,
                 parent,
                 name=None,
                 appname="the application",
                 filename='preferences.txt'):

        # Load the XRC file for our gui resources
        res = XmlResource(util.GetResourcePath('preferences.xrc'))
        self.dlgPreferences = res.LoadDialog(None, "PreferencesDialog")
        self.dlgPreferences.Init(name, appname)

        # Setup internal pubsub methods
        pub.subscribe(self.SetPreferenceTemplate,
                      'preferences.updated.template')
        pub.subscribe(self.SavePreferenceValues, 'preferences.updated.values')

        # Setup user pubsub methods
        pub.subscribe(self.GetPreferenceValue, 'preferences.requested.value')
        pub.subscribe(self.GetPreferenceValues, 'preferences.requested.values')
        pub.subscribe(self.SetPreferenceValue, 'preferences.updated.value')

        # Initialize variables
        self.preftemplate = []
        self.values = {}
        self.filename = os.path.join(guiutil.get_data_dir(), filename)
        self.LoadPreferenceValues()
Example #3
0
def get_icon():
    """Returns the icon for the application."""

    icon = None
    if IsMSWindows():
        if util.main_is_frozen():
            import sys
            exeName = sys.executable
            icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
        else:
            icon = wx.Icon(util.GetResourcePath('dicompyler.ico'),
                           wx.BITMAP_TYPE_ICO)
    elif IsGtk():
        icon = wx.Icon(util.GetResourcePath('dicompyler_icon11_16.png'),
                       wx.BITMAP_TYPE_PNG)

    return icon
    def pluginMenu(self, evt):
        res = XmlResource(util.GetResourcePath('dicomgui.xrc'))

        dlg = res.LoadDialog(self.parent, "DicomImporterDialog")
        dlg.Init(res)

        if dlg.ShowModal() == wx.ID_OK:
            try:
                self.patient_data = self.GetPatientDataFromDialog(dlg)
                self.import_path = dlg.path
                # Since we have decided to use this location to import from,
                # update the location in the preferences for the next session
                # if the 'import_location_setting' is "Remember Last Used"
                if (self.import_location_setting == "Remember Last Used"):
                    pub.sendMessage(
                        'preferences.updated.value',
                        msg={'general.dicom.import_location': dlg.path})
                    pub.sendMessage('preferences.requested.values',
                                    msg='general.dicom')
            # Otherwise show an error dialog
            except (AttributeError, EOFError, IOError, KeyError) as ex:
                wx.MessageDialog(dlg,
                                 message="Something went wrong!",
                                 caption="Error selecting patient",
                                 style=wx.OK | wx.ICON_ERROR).ShowModal()
                raise

        dlg.Destroy()

        # Open a dialog to select the output directory
        dirDlg = wx.DirDialog(
            self.parent,
            defaultPath=self.import_path,
            message="Choose a folder to save the anonymized DICOM data...")
        if dirDlg.ShowModal() == wx.ID_OK:
            base_path = dirDlg.GetPath()

        dirDlg.Destroy()

        dlgProgress = guiutil.get_progress_dialog(wx.GetApp().GetTopWindow(),
                                                  "Anonymizing DICOM data...")

        folder_counter = itertools.count()
        i = 0
        length = len(self.patient_data)
        for pat, pat_data in self.patient_data.items():
            i += 1
            wx.CallAfter(dlg.OnUpdateProgress, i, length, "Anonymising...")
            for study, study_data in pat_data.items():
                for series, series_data in study_data.items():
                    path = os.path.join(base_path, pat, study, series)
                    if not os.path.exists(path):
                        os.makedirs(path)
                    name = str(uuid.uuid1())
                    patientid = str(uuid.uuid1())
                    self.AnonymizeDataThread(series_data, path, name,
                                             patientid, True)
        return
Example #5
0
    def InitPluginList(self):
        """Initialize the plugin list control."""

        iSize = (16, 16)
        iList = wx.ImageList(iSize[0], iSize[1])
        iList.Add(wx.Bitmap(util.GetResourcePath("bricks.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(wx.Bitmap(util.GetResourcePath("plugin.png"), wx.BITMAP_TYPE_PNG))
        iList.Add(
            wx.Bitmap(util.GetResourcePath("plugin_disabled.png"), wx.BITMAP_TYPE_PNG)
        )
        self.tcPlugins.AssignImageList(iList)
        self.root = self.tcPlugins.AddRoot("Plugins")
        self.baseroot = self.tcPlugins.AppendItem(self.root, "Built-In Plugins", 0)
        self.userroot = self.tcPlugins.AppendItem(self.root, "User Plugins", 0)

        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        font.SetWeight(wx.FONTWEIGHT_BOLD)
        self.tcPlugins.SetItemFont(self.baseroot, font)
        self.tcPlugins.SetItemFont(self.userroot, font)
Example #6
0
def get_progress_dialog(parent, title="Loading..."):
    """Function to load the progress dialog."""

    # Load the XRC file for our gui resources
    res = XmlResource(util.GetResourcePath('guiutil.xrc'))

    dialogProgress = res.LoadDialog(parent, 'ProgressDialog')
    dialogProgress.Init(res, title)

    return dialogProgress
Example #7
0
    def OnInit(self):
        wx.GetApp().SetAppName("dicompyler")

        # Load the XRC file for our gui resources
        self.res = XmlResource(util.GetResourcePath('main.xrc'))

        dicompylerFrame = MainFrame(None, -1, "dicompyler", self.res)
        self.SetTopWindow(dicompylerFrame)
        dicompylerFrame.Show()
        return 1
Example #8
0
def PluginManager(parent, plugins, pluginsDisabled):
    """Prepare to show the plugin manager dialog."""

    # Load the XRC file for our gui resources
    res = XmlResource(util.GetResourcePath("plugin.xrc"))

    dlgPluginManager = res.LoadDialog(parent, "PluginManagerDialog")
    dlgPluginManager.Init(plugins, pluginsDisabled)

    # Show the dialog
    dlgPluginManager.ShowModal()
Example #9
0
    def Init(self):
        """Method called after the dialog has been initialized."""

        # Set window icon
        if not guiutil.IsMac():
            self.SetIcon(guiutil.get_icon())

        # Initialize controls
        self.txtDICOMFolder = XRCCTRL(self, 'txtDICOMFolder')
        self.checkPatientName = XRCCTRL(self, 'checkPatientName')
        self.txtFirstName = XRCCTRL(self, 'txtFirstName')
        self.txtLastName = XRCCTRL(self, 'txtLastName')
        self.checkPatientID = XRCCTRL(self, 'checkPatientID')
        self.txtPatientID = XRCCTRL(self, 'txtPatientID')
        self.checkPrivateTags = XRCCTRL(self, 'checkPrivateTags')
        self.bmpError = XRCCTRL(self, 'bmpError')
        self.lblDescription = XRCCTRL(self, 'lblDescription')

        # Bind interface events to the proper methods
        wx.EVT_BUTTON(self, XRCID('btnFolderBrowse'), self.OnFolderBrowse)
        wx.EVT_CHECKBOX(self, XRCID('checkPatientName'),
                        self.OnCheckPatientName)
        wx.EVT_CHECKBOX(self, XRCID('checkPatientID'), self.OnCheckPatientID)
        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOK)

        # Set and bold the font of the description label
        if guiutil.IsMac():
            font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
            font.SetWeight(wx.FONTWEIGHT_BOLD)
            self.lblDescription.SetFont(font)

        # Initialize the import location via pubsub
        pub.subscribe(self.OnImportPrefsChange,
                      'general.dicom.import_location')
        pub.sendMessage('preferences.requested.value',
                        'general.dicom.import_location')

        # Pre-select the text on the text controls due to a Mac OS X bug
        self.txtFirstName.SetSelection(-1, -1)
        self.txtLastName.SetSelection(-1, -1)
        self.txtPatientID.SetSelection(-1, -1)

        # Load the error bitmap
        self.bmpError.SetBitmap(wx.Bitmap(util.GetResourcePath('error.png')))

        # Initialize variables
        self.name = self.txtLastName.GetValue(
        ) + '^' + self.txtFirstName.GetValue()
        self.patientid = self.txtPatientID.GetValue()
        self.privatetags = True
Example #10
0
    def OnMouseMotion(self, evt):
        """Process mouse motion events and pass to the appropriate handler."""

        if evt.LeftIsDown():
            self.OnLeftIsDown(evt)
            self.SetCursor(wx.Cursor(wx.CURSOR_SIZING))
        elif evt.RightIsDown():
            self.OnRightIsDown(evt)
            # Custom cursors with > 2 colors only works on Windows currently
            if guiutil.IsMSWindows():
                image = wx.Image(util.GetResourcePath('contrast_high.png'))
                self.SetCursor(wx.CursorFromImage(image))
        # Update the positon and values of the mouse cursor
        self.mousepos = evt.GetPosition()
        self.OnUpdatePositionValues(evt)
Example #11
0
    def __init__(self, parent):
        self.parent = parent

        # Initialize the import location via pubsub
        pub.subscribe(self.OnImportPrefsChange, 'general.dicom')
        pub.sendMessage('preferences.requested.values', msg='general.dicom')

        # Setup toolbar controls
        openbmp = wx.Bitmap(util.GetResourcePath('pipeline.png'))
        self.tools = [{
            'label': "pyRadiomics",
            'bmp': openbmp,
            'shortHelp': "Begin pyRadiomics analysis...",
            'eventhandler': self.pluginMenu
        }]
Example #12
0
    def OnInit(self):
        # no-op in wxPython2.8 and later: wx.InitAllImageHandlers()
        wx.GetApp().SetAppName("dicompyler")

        # Load the XRC file for our gui resources
        self.res = XmlResource(util.GetResourcePath('main.xrc'))

        # Use the native listctrl on Mac OS X
        if guiutil.IsMac():
            wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 0)

        dicompylerFrame = MainFrame(None, -1, "dicompyler", self.res)
        self.SetTopWindow(dicompylerFrame)
        dicompylerFrame.Show()
        return 1
Example #13
0
    def __init__(self, parent):

        # Initialize the import location via pubsub
        pub.subscribe(self.OnImportPrefsChange, "general.dicom")
        pub.sendMessage("preferences.requested.values", msg="general.dicom")

        self.parent = parent

        # Setup toolbar controls
        openbmp = wx.Bitmap(util.GetResourcePath("folder_image.png"))
        self.tools = [{
            "label": "Open Quickly",
            "bmp": openbmp,
            "shortHelp": "Open DICOM File Quickly...",
            "eventhandler": self.pluginMenu,
        }]
Example #14
0
    def __init__(self, parent):

        # Initialize the import location via pubsub
        pub.subscribe(self.OnImportPrefsChange, 'general.dicom')
        pub.sendMessage('preferences.requested.values', msg='general.dicom')

        self.parent = parent

        # Setup toolbar controls
        openbmp = wx.Bitmap(util.GetResourcePath('AnonButton2.png'))
        self.tools = [{
            'label': "ANON",
            'bmp': openbmp,
            'shortHelp': "Anonymize the Patient Identifiers",
            'eventhandler': self.pluginMenu
        }]
Example #15
0
    def __init__(self, parent):

        # Initialize the import location via pubsub
        pub.subscribe(self.OnImportPrefsChange, 'general.dicom')
        pub.sendMessage('preferences.requested.values', 'general.dicom')

        self.parent = parent

        # Setup toolbar controls
        openbmp = wx.Bitmap(util.GetResourcePath('folder_image.png'))
        self.tools = [{
            'label': "Open Quickly",
            'bmp': openbmp,
            'shortHelp': "Open DICOM File Quickly...",
            'eventhandler': self.pluginMenu
        }]
Example #16
0
def ImportDicom(parent):
    """Prepare to show the dialog that will Import DICOM and DICOM RT files."""

    # Load the XRC file for our gui resources
    res = XmlResource(util.GetResourcePath('dicomgui.xrc'))

    dlgDicomImporter = res.LoadDialog(parent, "DicomImporterDialog")
    dlgDicomImporter.Init(res)

    # Show the dialog and return the result
    if (dlgDicomImporter.ShowModal() == wx.ID_OK):
        value = dlgDicomImporter.GetPatient()
        pub.sendMessage('patient.updated.raw_data', value)
    else:
        value = {}
    # Block until the thread is done before destroying the dialog
    if dlgDicomImporter:
        dlgDicomImporter.t.join()
        dlgDicomImporter.Destroy()

    return value
Example #17
0
    def __init__(self, parent, id, title, res):

        # Initialize logging
        logger = logging.getLogger('dicompyler')

        # Configure the exception hook to process threads as well
        self.InstallThreadExcepthook()

        # Remap the exception hook so that we can log and display exceptions
        def LogExcepthook(*exc_info):
            # Log the exception
            text = "".join(traceback.format_exception(*exc_info))
            logger.error("Unhandled exception: %s", text)
            pub.sendMessage('logging.exception', msg=text)

        sys.excepthook = LogExcepthook

        # Modify the logging system from pydicom to capture important messages
        pydicom_logger = logging.getLogger('pydicom')
        for l in pydicom_logger.handlers:
            pydicom_logger.removeHandler(l)

        # Add file logger
        logpath = os.path.join(guiutil.get_data_dir(), 'logs')
        if not os.path.exists(logpath):
            os.makedirs(logpath)
        self.fh = logging.handlers.RotatingFileHandler(os.path.join(
            logpath, 'dicompyler.log'),
                                                       maxBytes=524288,
                                                       backupCount=7)
        self.fh.setFormatter(
            logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
        self.fh.setLevel(logging.WARNING)
        logger.addHandler(self.fh)
        pydicom_logger.addHandler(self.fh)

        # Add console logger if not frozen
        if not util.main_is_frozen():
            self.ch = logging.StreamHandler()
            self.ch.setFormatter(
                logging.Formatter('%(levelname)s: %(message)s'))
            self.ch.setLevel(logging.WARNING)
            logger.addHandler(self.ch)
            pydicom_logger.addHandler(self.ch)
        # Otherwise if frozen, send stdout/stderror to /dev/null since
        # logging the messages seems to cause instability due to recursion
        else:
            devnull = open(os.devnull, 'w')
            sys.stdout = devnull
            sys.stderr = devnull

        # Set the window size
        if guiutil.IsMac():
            size = (900, 700)
        else:
            size = (850, 625)

        wx.Frame.__init__(self,
                          parent,
                          id,
                          title,
                          pos=wx.DefaultPosition,
                          size=size,
                          style=wx.DEFAULT_FRAME_STYLE)

        # Set up the status bar
        self.sb = self.CreateStatusBar(3)

        # set up resource file and config file
        self.res = res

        # Set window icon
        if not guiutil.IsMac():
            self.SetIcon(guiutil.get_icon())

        # Load the main panel for the program
        self.panelGeneral = self.res.LoadPanel(self, 'panelGeneral')

        # Initialize the General panel controls
        self.notebook = XRCCTRL(self, 'notebook')
        self.notebookTools = XRCCTRL(self, 'notebookTools')
        self.lblPlanName = XRCCTRL(self, 'lblPlanName')
        self.lblRxDose = XRCCTRL(self, 'lblRxDose')
        self.lblPatientName = XRCCTRL(self, 'lblPatientName')
        self.lblPatientID = XRCCTRL(self, 'lblPatientID')
        self.lblPatientGender = XRCCTRL(self, 'lblPatientGender')
        self.lblPatientDOB = XRCCTRL(self, 'lblPatientDOB')
        self.choiceStructure = XRCCTRL(self, 'choiceStructure')
        self.lblStructureVolume = XRCCTRL(self, 'lblStructureVolume')
        self.lblStructureMinDose = XRCCTRL(self, 'lblStructureMinDose')
        self.lblStructureMaxDose = XRCCTRL(self, 'lblStructureMaxDose')
        self.lblStructureMeanDose = XRCCTRL(self, 'lblStructureMeanDose')
        self.cclbStructures = guiutil.ColorCheckListBox(
            self.notebookTools, 'structure')
        self.cclbIsodoses = guiutil.ColorCheckListBox(self.notebookTools,
                                                      'isodose')

        # Modify the control size on Mac
        controls = [self.notebookTools, self.choiceStructure]

        if guiutil.IsMac():
            for control in controls:
                control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)

        # Setup the layout for the frame
        mainGrid = wx.BoxSizer(wx.VERTICAL)
        hGrid = wx.BoxSizer(wx.HORIZONTAL)
        if guiutil.IsMac():
            hGrid.Add(self.panelGeneral,
                      1,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE,
                      border=4)
        else:
            hGrid.Add(self.panelGeneral,
                      1,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE)

        mainGrid.Add(hGrid, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE)

        # Load the menu for the frame
        menuMain = self.res.LoadMenuBar('menuMain')

        # If we are running on Mac OS X, alter the menu location
        if guiutil.IsMac():
            wx.PyApp.SetMacAboutMenuItemId(XRCID('menuAbout'))
            wx.PyApp.SetMacPreferencesMenuItemId(XRCID('menuPreferences'))
            wx.PyApp.SetMacExitMenuItemId(XRCID('menuExit'))

        # Set the menu as the default menu for this frame
        self.SetMenuBar(menuMain)

        # Setup Tools menu
        self.menuShowLogs = menuMain.FindItemById(
            XRCID('menuShowLogs')).GetMenu()
        self.menuPlugins = menuMain.FindItemById(
            XRCID('menuPluginManager')).GetMenu()

        # Setup Import menu
        self.menuImport = menuMain.FindItemById(
            XRCID('menuImportPlaceholder')).GetMenu()
        self.menuImport.Delete(
            menuMain.FindItemById(XRCID('menuImportPlaceholder')).GetId())
        self.menuImportItem = menuMain.FindItemById(XRCID('menuImport'))
        self.menuImportItem.Enable(False)

        # Setup Export menu
        self.menuExport = menuMain.FindItemById(
            XRCID('menuExportPlaceholder')).GetMenu()
        self.menuExport.Delete(
            menuMain.FindItemById(XRCID('menuExportPlaceholder')).GetId())
        self.menuExportItem = menuMain.FindItemById(XRCID('menuExport'))
        self.menuExportItem.Enable(False)

        # Bind menu events to the proper methods
        self.Bind(wx.EVT_MENU, self.OnOpenPatient, id=XRCID('menuOpen'))
        self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnPreferences, id=wx.ID_PREFERENCES)
        self.Bind(wx.EVT_MENU, self.OnShowLogs, id=XRCID('menuShowLogs'))
        self.Bind(wx.EVT_MENU,
                  self.OnPluginManager,
                  id=XRCID('menuPluginManager'))
        self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT)
        self.Bind(wx.EVT_MENU, self.OnHomepage, id=XRCID('menuHomepage'))
        self.Bind(wx.EVT_MENU, self.OnLicense, id=XRCID('menuLicense'))

        # Load the toolbar for the frame
        toolbarMain = self.res.LoadToolBar(self, 'toolbarMain')
        self.SetToolBar(toolbarMain)
        self.toolbar = self.GetToolBar()

        # Setup main toolbar controls
        folderbmp = wx.Bitmap(util.GetResourcePath('folder_user.png'))
        self.maintools = [{
            'label': "Open Patient",
            'bmp': folderbmp,
            'shortHelp': "Open Patient...",
            'eventhandler': self.OnOpenPatient
        }]
        for m, tool in enumerate(self.maintools):
            self.toolbar.AddTool(m + 1,
                                 tool['label'],
                                 tool['bmp'],
                                 shortHelp=tool['shortHelp'])
            self.Bind(wx.EVT_TOOL, tool['eventhandler'], id=m + 1)
        self.toolbar.Realize()

        # Bind interface events to the proper methods
        self.Bind(wx.EVT_CHOICE,
                  self.OnStructureSelect,
                  id=XRCID('choiceStructure'))
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        # Events to work around a focus bug in Windows
        self.notebook.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.notebook.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
        self.notebookTools.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.notebookTools.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)

        self.SetSizer(mainGrid)
        self.Layout()

        #Set the Minumum size
        self.SetMinSize(size)
        self.Centre(wx.BOTH)

        # Initialize the welcome notebook tab
        panelWelcome = self.res.LoadPanel(self.notebook, 'panelWelcome')
        self.notebook.AddPage(panelWelcome, 'Welcome')
        # Set the version on the welcome notebook tab
        XRCCTRL(self, 'lblVersion').SetLabel('Version ' + __version__)

        # Initialize the tools notebook
        self.notebookTools.AddPage(self.cclbStructures, 'Structures')
        self.notebookTools.AddPage(self.cclbIsodoses, 'Isodoses')

        # Create the data folder
        datapath = guiutil.get_data_dir()
        if not os.path.exists(datapath):
            os.mkdir(datapath)

        # Initialize the preferences
        if guiutil.IsMac():
            self.prefmgr = preferences.PreferencesManager(parent=self,
                                                          appname='dicompyler')
        else:
            self.prefmgr = preferences.PreferencesManager(parent=self,
                                                          appname='dicompyler',
                                                          name='Options')
        sp = wx.StandardPaths.Get()
        self.generalpreftemplate = [{
            'DICOM Import Settings': [{
                'name':
                'Import Location',
                'type':
                'choice',
                'values': ['Remember Last Used', 'Always Use Default'],
                'default':
                'Remember Last Used',
                'callback':
                'general.dicom.import_location_setting'
            }, {
                'name':
                'Default Location',
                'type':
                'directory',
                'default':
                sp.GetDocumentsDir(),
                'callback':
                'general.dicom.import_location'
            }]
        }, {
            'Plugin Settings': [{
                'name': 'User Plugins Location',
                'type': 'directory',
                'default': os.path.join(datapath, 'plugins'),
                'callback': 'general.plugins.user_plugins_location',
                'restart': True
            }]
        }, {
            'Calculation Settings': [{
                'name':
                'DVH Calculation',
                'type':
                'choice',
                'values':
                ['Use RT Dose DVH if Present', 'Always Recalculate DVH'],
                'default':
                'Use RT Dose DVH if Present',
                'callback':
                'general.calculation.dvh_recalc'
            }]
        }, {
            'Advanced Settings': [{
                'name':
                'Enable Detailed Logging',
                'type':
                'checkbox',
                'default':
                False,
                'callback':
                'general.advanced.detailed_logging'
            }]
        }]
        self.preftemplate = [{'General': self.generalpreftemplate}]
        pub.sendMessage('preferences.updated.template', msg=self.preftemplate)

        # Initialize variables
        self.ptdata = {}

        # Set up pubsub
        pub.subscribe(self.OnLoadPatientData, 'patient.updated.raw_data')
        pub.subscribe(self.OnStructureCheck, 'colorcheckbox.checked.structure')
        pub.subscribe(self.OnStructureUncheck,
                      'colorcheckbox.unchecked.structure')
        pub.subscribe(self.OnIsodoseCheck, 'colorcheckbox.checked.isodose')
        pub.subscribe(self.OnIsodoseUncheck, 'colorcheckbox.unchecked.isodose')
        pub.subscribe(self.OnUpdatePlugins,
                      'general.plugins.user_plugins_location')
        pub.subscribe(self.OnUpdatePreferences, 'general')
        pub.subscribe(self.OnUpdateStatusBar, 'main.update_statusbar')
        pub.subscribe(self.OnOpenPatient, 'dicomgui.show')

        # Send a message to the logging system to turn on/off detailed logging
        pub.sendMessage('preferences.requested.value',
                        msg='general.advanced.detailed_logging')

        # Create the default user plugin path
        self.userpluginpath = os.path.join(datapath, 'plugins')
        if not os.path.exists(self.userpluginpath):
            os.mkdir(self.userpluginpath)

        # Load and initialize plugins
        self.plugins = []
        self.pluginsDisabled = []
        pub.sendMessage('preferences.requested.value',
                        msg='general.plugins.user_plugins_location')
        pub.sendMessage('preferences.requested.value',
                        msg='general.calculation.dvh_recalc')
        pub.sendMessage('preferences.requested.value',
                        msg='general.plugins.disabled_list')
        pub.sendMessage('preferences.requested.values', msg='general.window')
Example #18
0
    def Init(self, res):
        """Method called after the panel has been initialized."""

        # Bind ui events to the proper methods
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)

        # Initialize variables
        self.images = []
        self.structures = {}
        self.window = 0
        self.level = 0
        self.zoom = 1
        self.pan = [0, 0]
        self.bwidth = 0
        self.bheight = 0
        self.xpos = 0
        self.ypos = 0
        self.mousepos = wx.Point(-10000, -10000)
        self.mouse_in_window = False
        self.isodose_line_style = 'Solid'
        self.isodose_fill_opacity = 25
        self.structure_line_style = 'Solid'
        self.structure_fill_opacity = 50
        self.plugins = {}

        # Setup toolbar controls
        if guiutil.IsGtk():
            drawingstyles = ['Solid', 'Transparent', 'Dot']
        else:
            drawingstyles = ['Solid', 'Transparent', 'Dot', 'Dash', 'Dot Dash']
        zoominbmp = wx.Bitmap(util.GetResourcePath('magnifier_zoom_in.png'))
        zoomoutbmp = wx.Bitmap(util.GetResourcePath('magnifier_zoom_out.png'))
        toolsbmp = wx.Bitmap(util.GetResourcePath('cog.png'))
        self.tools = []
        self.tools.append({
            'label': "Zoom In",
            'bmp': zoominbmp,
            'shortHelp': "Zoom In",
            'eventhandler': self.OnZoomIn
        })
        self.tools.append({
            'label': "Zoom Out",
            'bmp': zoomoutbmp,
            'shortHelp': "Zoom Out",
            'eventhandler': self.OnZoomOut
        })
        self.tools.append({
            'label': "Tools",
            'bmp': toolsbmp,
            'shortHelp': "Tools",
            'eventhandler': self.OnToolsMenu
        })

        # Set up preferences
        self.preferences = [{
            'Drawing Settings': [{
                'name':
                'Isodose Line Style',
                'type':
                'choice',
                'values':
                drawingstyles,
                'default':
                'Solid',
                'callback':
                '2dview.drawingprefs.isodose_line_style'
            }, {
                'name':
                'Isodose Fill Opacity',
                'type':
                'range',
                'values': [0, 100],
                'default':
                25,
                'units':
                '%',
                'callback':
                '2dview.drawingprefs.isodose_fill_opacity'
            }, {
                'name':
                'Structure Line Style',
                'type':
                'choice',
                'values':
                drawingstyles,
                'default':
                'Solid',
                'callback':
                '2dview.drawingprefs.structure_line_style'
            }, {
                'name':
                'Structure Fill Opacity',
                'type':
                'range',
                'values': [0, 100],
                'default':
                50,
                'units':
                '%',
                'callback':
                '2dview.drawingprefs.structure_fill_opacity'
            }]
        }]

        # Set up pubsub
        pub.subscribe(self.OnUpdatePatient, 'patient.updated.parsed_data')
        pub.subscribe(self.OnStructureCheck, 'structures.checked')
        pub.subscribe(self.OnIsodoseCheck, 'isodoses.checked')
        pub.subscribe(self.OnRefresh, '2dview.refresh')
        pub.subscribe(self.OnDrawingPrefsChange, '2dview.drawingprefs')
        pub.subscribe(self.OnPluginLoaded, 'plugin.loaded.2dview')
        pub.sendMessage('preferences.requested.values',
                        msg='2dview.drawingprefs')
Example #19
0
    def __init__(self, parent, id, title, res):

        # Initialize logging
        logger = logging.getLogger("dicompyler")

        # Configure the exception hook to process threads as well
        self.InstallThreadExcepthook()

        # Remap the exception hook so that we can log and display exceptions
        def LogExcepthook(*exc_info):
            # Log the exception
            text = "".join(traceback.format_exception(*exc_info))
            logger.error("Unhandled exception: %s", text)
            pub.sendMessage("logging.exception", msg=text)

        sys.excepthook = LogExcepthook

        # Modify the logging system from pydicom to capture important messages
        pydicom_logger = logging.getLogger("pydicom")
        for l in pydicom_logger.handlers:
            pydicom_logger.removeHandler(l)

        # Add file logger
        logpath = os.path.join(guiutil.get_data_dir(), "logs")
        if not os.path.exists(logpath):
            os.makedirs(logpath)
        self.fh = logging.handlers.RotatingFileHandler(os.path.join(
            logpath, "dicompyler.log"),
                                                       maxBytes=524288,
                                                       backupCount=7)
        self.fh.setFormatter(
            logging.Formatter(
                "%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
        self.fh.setLevel(logging.WARNING)
        logger.addHandler(self.fh)
        pydicom_logger.addHandler(self.fh)

        # Add console logger if not frozen
        if not util.main_is_frozen():
            self.ch = logging.StreamHandler()
            self.ch.setFormatter(
                logging.Formatter("%(levelname)s: %(message)s"))
            self.ch.setLevel(logging.WARNING)
            logger.addHandler(self.ch)
            pydicom_logger.addHandler(self.ch)
        # Otherwise if frozen, send stdout/stderror to /dev/null since
        # logging the messages seems to cause instability due to recursion
        else:
            devnull = open(os.devnull, "w")
            sys.stdout = devnull
            sys.stderr = devnull

        # Set the window size
        if guiutil.IsMac():
            size = (1200, 700)
        else:
            size = (1200, 700)

        wx.Frame.__init__(
            self,
            parent,
            id,
            title,
            pos=wx.DefaultPosition,
            size=size,
            style=wx.DEFAULT_FRAME_STYLE,
        )

        # Set up the status bar
        self.sb = self.CreateStatusBar(3)

        # set up resource file and config file
        self.res = res

        # Set window icon
        if not guiutil.IsMac():
            self.SetIcon(guiutil.get_icon())

        # Load the main panel for the program
        self.panelGeneral = self.res.LoadPanel(self, "panelGeneral")

        # Initialize the General panel controls
        self.notebook = XRCCTRL(self, "notebook")
        self.notebookTools = XRCCTRL(self, "notebookTools")
        self.lblPlanName = XRCCTRL(self, "lblPlanName")
        self.lblRxDose = XRCCTRL(self, "lblRxDose")
        self.lblPatientName = XRCCTRL(self, "lblPatientName")
        self.lblPatientID = XRCCTRL(self, "lblPatientID")
        self.lblPatientGender = XRCCTRL(self, "lblPatientGender")
        self.lblPatientDOB = XRCCTRL(self, "lblPatientDOB")
        self.choiceStructure = XRCCTRL(self, "choiceStructure")
        self.lblStructureVolume = XRCCTRL(self, "lblStructureVolume")
        self.lblStructureMinDose = XRCCTRL(self, "lblStructureMinDose")
        self.lblStructureMaxDose = XRCCTRL(self, "lblStructureMaxDose")
        self.lblStructureMeanDose = XRCCTRL(self, "lblStructureMeanDose")
        self.cclbStructures = guiutil.ColorCheckListBox(
            self.notebookTools, "structure")
        self.cclbIsodoses = guiutil.ColorCheckListBox(self.notebookTools,
                                                      "isodose")
        """test code"""
        self.sidePanel = XRCCTRL(self, "sidePanel")

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.sidePanel.SetSizer(sizer)

        self.histPanel = HistPanel(self.sidePanel)
        self.histPanel.plot_histogram_img(util.GetResourcePath("book.png"))
        sizer.Add(self.histPanel, 0, wx.ALL | wx.EXPAND)
        """test code"""

        # Modify the control size on Mac
        controls = [self.notebookTools, self.choiceStructure]

        if guiutil.IsMac():
            for control in controls:
                control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)

        # Setup the layout for the frame
        mainGrid = wx.BoxSizer(wx.VERTICAL)
        hGrid = wx.BoxSizer(wx.HORIZONTAL)
        if guiutil.IsMac():
            hGrid.Add(
                self.panelGeneral,
                1,
                flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE,
                border=4,
            )
        else:
            hGrid.Add(self.panelGeneral,
                      1,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE)

        mainGrid.Add(hGrid, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE)

        # Load the menu for the frame
        menuMain = self.res.LoadMenuBar("menuMain")

        # If we are running on Mac OS X, alter the menu location
        if guiutil.IsMac():
            wx.PyApp.SetMacAboutMenuItemId(XRCID("menuAbout"))
            wx.PyApp.SetMacPreferencesMenuItemId(XRCID("menuPreferences"))
            wx.PyApp.SetMacExitMenuItemId(XRCID("menuExit"))

        # Set the menu as the default menu for this frame
        self.SetMenuBar(menuMain)

        # Setup Tools menu
        self.menuShowLogs = menuMain.FindItemById(
            XRCID("menuShowLogs")).GetMenu()
        self.menuPlugins = menuMain.FindItemById(
            XRCID("menuPluginManager")).GetMenu()

        # Setup Import menu
        self.menuImport = menuMain.FindItemById(
            XRCID("menuImportPlaceholder")).GetMenu()
        self.menuImport.Delete(
            menuMain.FindItemById(XRCID("menuImportPlaceholder")).GetId())
        self.menuImportItem = menuMain.FindItemById(XRCID("menuImport"))
        self.menuImportItem.Enable(False)

        # Setup Export menu
        self.menuExport = menuMain.FindItemById(
            XRCID("menuExportPlaceholder")).GetMenu()
        self.menuExport.Delete(
            menuMain.FindItemById(XRCID("menuExportPlaceholder")).GetId())
        self.menuExportItem = menuMain.FindItemById(XRCID("menuExport"))
        self.menuExportItem.Enable(False)

        # Bind menu events to the proper methods
        self.Bind(wx.EVT_MENU, self.OnOpenPatient, id=XRCID("menuOpen"))
        self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnPreferences, id=wx.ID_PREFERENCES)
        self.Bind(wx.EVT_MENU, self.OnShowLogs, id=XRCID("menuShowLogs"))
        self.Bind(wx.EVT_MENU,
                  self.OnPluginManager,
                  id=XRCID("menuPluginManager"))
        self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT)
        self.Bind(wx.EVT_MENU, self.OnHomepage, id=XRCID("menuHomepage"))
        self.Bind(wx.EVT_MENU, self.OnLicense, id=XRCID("menuLicense"))

        # Load the toolbar for the frame
        toolbarMain = self.res.LoadToolBar(self, "toolbarMain")
        self.SetToolBar(toolbarMain)
        self.toolbar = self.GetToolBar()

        # Setup main toolbar controls
        folderbmp = wx.Bitmap(util.GetResourcePath("folder_user.png"))
        self.maintools = [{
            "label": "Open Patient",
            "bmp": folderbmp,
            "shortHelp": "Open Patient...",
            "eventhandler": self.OnOpenPatient,
        }]
        for m, tool in enumerate(self.maintools):
            self.toolbar.AddTool(m + 1,
                                 tool["label"],
                                 tool["bmp"],
                                 shortHelp=tool["shortHelp"])
            self.Bind(wx.EVT_TOOL, tool["eventhandler"], id=m + 1)
        self.toolbar.Realize()

        # Bind interface events to the proper methods
        self.Bind(wx.EVT_CHOICE,
                  self.OnStructureSelect,
                  id=XRCID("choiceStructure"))
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        # Events to work around a focus bug in Windows
        self.notebook.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.notebook.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
        self.notebookTools.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.notebookTools.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)

        self.SetSizer(mainGrid)
        self.Layout()

        # Set the Minumum size
        self.SetMinSize(size)
        self.Centre(wx.BOTH)

        # Initialize the welcome notebook tab
        panelWelcome = self.res.LoadPanel(self.notebook, "panelWelcome")
        self.notebook.AddPage(panelWelcome, "Welcome")
        # Set the version on the welcome notebook tab
        XRCCTRL(self, "lblVersion").SetLabel("Version " + __version__)

        # Initialize the tools notebook
        self.notebookTools.AddPage(self.cclbStructures, "Structures")
        self.notebookTools.AddPage(self.cclbIsodoses, "Isodoses")

        # Create the data folder
        datapath = guiutil.get_data_dir()
        if not os.path.exists(datapath):
            os.mkdir(datapath)

        # Initialize the preferences
        if guiutil.IsMac():
            self.prefmgr = preferences.PreferencesManager(parent=self,
                                                          appname="dicompyler")
        else:
            self.prefmgr = preferences.PreferencesManager(parent=self,
                                                          appname="dicompyler",
                                                          name="Options")
        sp = wx.StandardPaths.Get()
        self.generalpreftemplate = [
            {
                "DICOM Import Settings": [
                    {
                        "name": "Import Location",
                        "type": "choice",
                        "values": ["Remember Last Used", "Always Use Default"],
                        "default": "Remember Last Used",
                        "callback": "general.dicom.import_location_setting",
                    },
                    {
                        "name": "Default Location",
                        "type": "directory",
                        "default": sp.GetDocumentsDir(),
                        "callback": "general.dicom.import_location",
                    },
                ]
            },
            {
                "Plugin Settings": [{
                    "name":
                    "User Plugins Location",
                    "type":
                    "directory",
                    "default":
                    os.path.join(datapath, "plugins"),
                    "callback":
                    "general.plugins.user_plugins_location",
                    "restart":
                    True,
                }]
            },
            {
                "Calculation Settings": [{
                    "name":
                    "DVH Calculation",
                    "type":
                    "choice",
                    "values": [
                        "Use RT Dose DVH if Present",
                        "Always Recalculate DVH",
                    ],
                    "default":
                    "Use RT Dose DVH if Present",
                    "callback":
                    "general.calculation.dvh_recalc",
                }]
            },
            {
                "Advanced Settings": [{
                    "name":
                    "Enable Detailed Logging",
                    "type":
                    "checkbox",
                    "default":
                    False,
                    "callback":
                    "general.advanced.detailed_logging",
                }]
            },
        ]
        self.preftemplate = [{"General": self.generalpreftemplate}]
        pub.sendMessage("preferences.updated.template", msg=self.preftemplate)

        # Initialize variables
        self.ptdata = {}

        # Set up pubsub
        pub.subscribe(self.OnLoadPatientData, "patient.updated.raw_data")
        pub.subscribe(self.OnStructureCheck, "colorcheckbox.checked.structure")
        pub.subscribe(self.OnStructureUncheck,
                      "colorcheckbox.unchecked.structure")
        pub.subscribe(self.OnIsodoseCheck, "colorcheckbox.checked.isodose")
        pub.subscribe(self.OnIsodoseUncheck, "colorcheckbox.unchecked.isodose")
        pub.subscribe(self.OnUpdatePlugins,
                      "general.plugins.user_plugins_location")
        pub.subscribe(self.OnUpdatePreferences, "general")
        pub.subscribe(self.OnUpdateStatusBar, "main.update_statusbar")
        pub.subscribe(self.OnOpenPatient, "dicomgui.show")

        # Send a message to the logging system to turn on/off detailed logging
        pub.sendMessage("preferences.requested.value",
                        msg="general.advanced.detailed_logging")

        # Create the default user plugin path
        self.userpluginpath = os.path.join(datapath, "plugins")
        if not os.path.exists(self.userpluginpath):
            os.mkdir(self.userpluginpath)

        # Load and initialize plugins
        self.plugins = []
        self.pluginsDisabled = []
        pub.sendMessage("preferences.requested.value",
                        msg="general.plugins.user_plugins_location")
        pub.sendMessage("preferences.requested.value",
                        msg="general.calculation.dvh_recalc")
        pub.sendMessage("preferences.requested.value",
                        msg="general.plugins.disabled_list")
        pub.sendMessage("preferences.requested.values", msg="general.window")