Exemple #1
0
def import_plugins(userpath=None):
    """Find and import available plugins."""

    # Get the base plugin path
    basepath = util.GetBasePluginsPath("")
    # Get the user plugin path if it has not been set
    if userpath == None:
        datapath = guiutil.get_data_dir()
        userpath = os.path.join(datapath, "plugins")
    # Get the list of possible plugins from both paths
    possibleplugins = []
    for i in os.listdir(userpath):
        possibleplugins.append({"plugin": i, "location": "user"})
    for i in os.listdir(basepath):
        possibleplugins.append({"plugin": i, "location": "base"})

    modules = []
    plugins = []
    for p in possibleplugins:
        module = p["plugin"].split(".")[0]
        if module not in modules:
            if not ((module == "__init__") or (module == "")):
                # only try to import the module once
                modules.append(module)
                try:
                    f, filename, description = imp.find_module(
                        module, [userpath, basepath]
                    )
                except ImportError:
                    # Not able to find module so pass
                    pass
                else:
                    # Try to import the module if no exception occurred
                    try:
                        m = imp.load_module(module, f, filename, description)
                    except ImportError:
                        logger.exception("%s could not be loaded", module)
                    else:
                        plugins.append({"plugin": m, "location": p["location"]})
                        logger.debug("%s loaded", module)
                    # If the module is a single file, close it
                    if not (description[2] == imp.PKG_DIRECTORY):
                        f.close()
    return plugins
Exemple #2
0
def import_plugins(userpath=None):
    """Find and import available plugins."""

    # Get the base plugin path
    basepath = util.GetBasePluginsPath('')
    # Get the user plugin path if it has not been set
    if (userpath == None):
        datapath = guiutil.get_data_dir()
        userpath = os.path.join(datapath, 'plugins')
    # Get the list of possible plugins from both paths
    possibleplugins = []
    for i in os.listdir(userpath):
        possibleplugins.append({'plugin': i, 'location': 'user'})
    for i in os.listdir(basepath):
        possibleplugins.append({'plugin': i, 'location': 'base'})

    modules = []
    plugins = []
    for p in possibleplugins:
        module = p['plugin'].split('.')[0]
        if module not in modules:
            if not ((module == "__init__") or (module == "")):
                # only try to import the module once
                modules.append(module)
                try:
                    f, filename, description = \
                            imp.find_module(module, [userpath, basepath])
                except ImportError:
                    # Not able to find module so pass
                    pass
                else:
                    # Try to import the module if no exception occurred
                    try:
                        m = imp.load_module(module, f, filename, description)
                    except ImportError:
                        logger.exception("%s could not be loaded", module)
                    else:
                        plugins.append({'plugin': m,
                                        'location': p['location']})
                        logger.debug("%s loaded", module)
                    # If the module is a single file, close it
                    if not (description[2] == imp.PKG_DIRECTORY):
                        f.close()
    return plugins
Exemple #3
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()
Exemple #4
0
    def OnShowLogs(self, evt):
        """Open and display the logs folder."""

        util.open_path(os.path.join(guiutil.get_data_dir(), 'logs'))
Exemple #5
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')
Exemple #6
0
    def OnShowLogs(self, evt):
        """Open and display the logs folder."""

        util.open_path(os.path.join(guiutil.get_data_dir(), 'logs'))
Exemple #7
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')
Exemple #8
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", 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 and font size on Mac
        controls = [self.notebookTools, self.choiceStructure]

        if guiutil.IsMac():
            font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
            font.SetPointSize(10)
            for control in controls:
                control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
                control.SetFont(font)

        # 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.App_SetMacAboutMenuItemId(XRCID("menuAbout"))
            wx.App_SetMacPreferencesMenuItemId(XRCID("menuPreferences"))
            wx.App_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
        wx.EVT_MENU(self, XRCID("menuOpen"), self.OnOpenPatient)
        wx.EVT_MENU(self, XRCID("menuExit"), self.OnClose)
        wx.EVT_MENU(self, XRCID("menuPreferences"), self.OnPreferences)
        wx.EVT_MENU(self, XRCID("menuShowLogs"), self.OnShowLogs)
        wx.EVT_MENU(self, XRCID("menuPluginManager"), self.OnPluginManager)
        wx.EVT_MENU(self, XRCID("menuAbout"), self.OnAbout)
        wx.EVT_MENU(self, XRCID("menuHomepage"), self.OnHomepage)
        wx.EVT_MENU(self, XRCID("menuLicense"), self.OnLicense)

        # 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.AddLabelTool(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
        wx.EVT_CHOICE(self, XRCID("choiceStructure"), self.OnStructureSelect)
        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=None, appname="dicompyler")
        else:
            self.prefmgr = preferences.PreferencesManager(parent=None, 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": unicode(sp.GetDocumentsDir()),
                        "callback": "general.dicom.import_location",
                    },
                ]
            },
            {
                "Plugin Settings": [
                    {
                        "name": "User Plugins Location",
                        "type": "directory",
                        "default": unicode(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", 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")

        # Send a message to the logging system to turn on/off detailed logging
        pub.sendMessage("preferences.requested.value", "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 = []
        pub.sendMessage("preferences.requested.value", "general.plugins.user_plugins_location")
        pub.sendMessage("preferences.requested.value", "general.calculation.dvh_recalc")
Exemple #9
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")