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