def InitTree(self): """Initialize the tree control for use.""" iSize = (16, 16) iList = wx.ImageList(iSize[0], iSize[1]) iList.Add(wx.Bitmap(util.GetResourcePath("group.png"), wx.BITMAP_TYPE_PNG)) iList.Add(wx.Bitmap(util.GetResourcePath("user.png"), wx.BITMAP_TYPE_PNG)) iList.Add(wx.Bitmap(util.GetResourcePath("book.png"), wx.BITMAP_TYPE_PNG)) iList.Add( wx.Bitmap(util.GetResourcePath("table_multiple.png"), wx.BITMAP_TYPE_PNG) ) iList.Add(wx.Bitmap(util.GetResourcePath("pencil.png"), wx.BITMAP_TYPE_PNG)) iList.Add(wx.Bitmap(util.GetResourcePath("chart_bar.png"), wx.BITMAP_TYPE_PNG)) iList.Add( wx.Bitmap(util.GetResourcePath("chart_curve.png"), wx.BITMAP_TYPE_PNG) ) iList.Add( wx.Bitmap(util.GetResourcePath("pencil_error.png"), wx.BITMAP_TYPE_PNG) ) iList.Add( wx.Bitmap(util.GetResourcePath("chart_bar_error.png"), wx.BITMAP_TYPE_PNG) ) iList.Add( wx.Bitmap(util.GetResourcePath("chart_curve_error.png"), wx.BITMAP_TYPE_PNG) ) self.tcPatients.AssignImageList(iList) root = self.tcPatients.AddRoot("Patients", image=0) return root
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 get_icon(): """Returns the icon for the application.""" icon = None if IsMSWindows(): if util.main_is_frozen(): import sys exeName = sys.executable icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO) else: icon = wx.Icon(util.GetResourcePath('dicompyler.ico'), wx.BITMAP_TYPE_ICO) elif IsGtk(): icon = wx.Icon(util.GetResourcePath('dicompyler_icon11_16.png'), wx.BITMAP_TYPE_PNG) return icon
def pluginMenu(self, evt): res = XmlResource(util.GetResourcePath('dicomgui.xrc')) dlg = res.LoadDialog(self.parent, "DicomImporterDialog") dlg.Init(res) if dlg.ShowModal() == wx.ID_OK: try: self.patient_data = self.GetPatientDataFromDialog(dlg) self.import_path = dlg.path # Since we have decided to use this location to import from, # update the location in the preferences for the next session # if the 'import_location_setting' is "Remember Last Used" if (self.import_location_setting == "Remember Last Used"): pub.sendMessage( 'preferences.updated.value', msg={'general.dicom.import_location': dlg.path}) pub.sendMessage('preferences.requested.values', msg='general.dicom') # Otherwise show an error dialog except (AttributeError, EOFError, IOError, KeyError) as ex: wx.MessageDialog(dlg, message="Something went wrong!", caption="Error selecting patient", style=wx.OK | wx.ICON_ERROR).ShowModal() raise dlg.Destroy() # Open a dialog to select the output directory dirDlg = wx.DirDialog( self.parent, defaultPath=self.import_path, message="Choose a folder to save the anonymized DICOM data...") if dirDlg.ShowModal() == wx.ID_OK: base_path = dirDlg.GetPath() dirDlg.Destroy() dlgProgress = guiutil.get_progress_dialog(wx.GetApp().GetTopWindow(), "Anonymizing DICOM data...") folder_counter = itertools.count() i = 0 length = len(self.patient_data) for pat, pat_data in self.patient_data.items(): i += 1 wx.CallAfter(dlg.OnUpdateProgress, i, length, "Anonymising...") for study, study_data in pat_data.items(): for series, series_data in study_data.items(): path = os.path.join(base_path, pat, study, series) if not os.path.exists(path): os.makedirs(path) name = str(uuid.uuid1()) patientid = str(uuid.uuid1()) self.AnonymizeDataThread(series_data, path, name, patientid, True) return
def InitPluginList(self): """Initialize the plugin list control.""" iSize = (16, 16) iList = wx.ImageList(iSize[0], iSize[1]) iList.Add(wx.Bitmap(util.GetResourcePath("bricks.png"), wx.BITMAP_TYPE_PNG)) iList.Add(wx.Bitmap(util.GetResourcePath("plugin.png"), wx.BITMAP_TYPE_PNG)) iList.Add( wx.Bitmap(util.GetResourcePath("plugin_disabled.png"), wx.BITMAP_TYPE_PNG) ) self.tcPlugins.AssignImageList(iList) self.root = self.tcPlugins.AddRoot("Plugins") self.baseroot = self.tcPlugins.AppendItem(self.root, "Built-In Plugins", 0) self.userroot = self.tcPlugins.AppendItem(self.root, "User Plugins", 0) font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) font.SetWeight(wx.FONTWEIGHT_BOLD) self.tcPlugins.SetItemFont(self.baseroot, font) self.tcPlugins.SetItemFont(self.userroot, font)
def get_progress_dialog(parent, title="Loading..."): """Function to load the progress dialog.""" # Load the XRC file for our gui resources res = XmlResource(util.GetResourcePath('guiutil.xrc')) dialogProgress = res.LoadDialog(parent, 'ProgressDialog') dialogProgress.Init(res, title) return dialogProgress
def OnInit(self): wx.GetApp().SetAppName("dicompyler") # Load the XRC file for our gui resources self.res = XmlResource(util.GetResourcePath('main.xrc')) dicompylerFrame = MainFrame(None, -1, "dicompyler", self.res) self.SetTopWindow(dicompylerFrame) dicompylerFrame.Show() return 1
def PluginManager(parent, plugins, pluginsDisabled): """Prepare to show the plugin manager dialog.""" # Load the XRC file for our gui resources res = XmlResource(util.GetResourcePath("plugin.xrc")) dlgPluginManager = res.LoadDialog(parent, "PluginManagerDialog") dlgPluginManager.Init(plugins, pluginsDisabled) # Show the dialog dlgPluginManager.ShowModal()
def Init(self): """Method called after the dialog has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.txtDICOMFolder = XRCCTRL(self, 'txtDICOMFolder') self.checkPatientName = XRCCTRL(self, 'checkPatientName') self.txtFirstName = XRCCTRL(self, 'txtFirstName') self.txtLastName = XRCCTRL(self, 'txtLastName') self.checkPatientID = XRCCTRL(self, 'checkPatientID') self.txtPatientID = XRCCTRL(self, 'txtPatientID') self.checkPrivateTags = XRCCTRL(self, 'checkPrivateTags') self.bmpError = XRCCTRL(self, 'bmpError') self.lblDescription = XRCCTRL(self, 'lblDescription') # Bind interface events to the proper methods wx.EVT_BUTTON(self, XRCID('btnFolderBrowse'), self.OnFolderBrowse) wx.EVT_CHECKBOX(self, XRCID('checkPatientName'), self.OnCheckPatientName) wx.EVT_CHECKBOX(self, XRCID('checkPatientID'), self.OnCheckPatientID) wx.EVT_BUTTON(self, wx.ID_OK, self.OnOK) # Set and bold the font of the description label if guiutil.IsMac(): font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) font.SetWeight(wx.FONTWEIGHT_BOLD) self.lblDescription.SetFont(font) # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom.import_location') pub.sendMessage('preferences.requested.value', 'general.dicom.import_location') # Pre-select the text on the text controls due to a Mac OS X bug self.txtFirstName.SetSelection(-1, -1) self.txtLastName.SetSelection(-1, -1) self.txtPatientID.SetSelection(-1, -1) # Load the error bitmap self.bmpError.SetBitmap(wx.Bitmap(util.GetResourcePath('error.png'))) # Initialize variables self.name = self.txtLastName.GetValue( ) + '^' + self.txtFirstName.GetValue() self.patientid = self.txtPatientID.GetValue() self.privatetags = True
def OnMouseMotion(self, evt): """Process mouse motion events and pass to the appropriate handler.""" if evt.LeftIsDown(): self.OnLeftIsDown(evt) self.SetCursor(wx.Cursor(wx.CURSOR_SIZING)) elif evt.RightIsDown(): self.OnRightIsDown(evt) # Custom cursors with > 2 colors only works on Windows currently if guiutil.IsMSWindows(): image = wx.Image(util.GetResourcePath('contrast_high.png')) self.SetCursor(wx.CursorFromImage(image)) # Update the positon and values of the mouse cursor self.mousepos = evt.GetPosition() self.OnUpdatePositionValues(evt)
def __init__(self, parent): self.parent = parent # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom') pub.sendMessage('preferences.requested.values', msg='general.dicom') # Setup toolbar controls openbmp = wx.Bitmap(util.GetResourcePath('pipeline.png')) self.tools = [{ 'label': "pyRadiomics", 'bmp': openbmp, 'shortHelp': "Begin pyRadiomics analysis...", 'eventhandler': self.pluginMenu }]
def OnInit(self): # no-op in wxPython2.8 and later: wx.InitAllImageHandlers() wx.GetApp().SetAppName("dicompyler") # Load the XRC file for our gui resources self.res = XmlResource(util.GetResourcePath('main.xrc')) # Use the native listctrl on Mac OS X if guiutil.IsMac(): wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 0) dicompylerFrame = MainFrame(None, -1, "dicompyler", self.res) self.SetTopWindow(dicompylerFrame) dicompylerFrame.Show() return 1
def __init__(self, parent): # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, "general.dicom") pub.sendMessage("preferences.requested.values", msg="general.dicom") self.parent = parent # Setup toolbar controls openbmp = wx.Bitmap(util.GetResourcePath("folder_image.png")) self.tools = [{ "label": "Open Quickly", "bmp": openbmp, "shortHelp": "Open DICOM File Quickly...", "eventhandler": self.pluginMenu, }]
def __init__(self, parent): # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom') pub.sendMessage('preferences.requested.values', msg='general.dicom') self.parent = parent # Setup toolbar controls openbmp = wx.Bitmap(util.GetResourcePath('AnonButton2.png')) self.tools = [{ 'label': "ANON", 'bmp': openbmp, 'shortHelp': "Anonymize the Patient Identifiers", 'eventhandler': self.pluginMenu }]
def __init__(self, parent): # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom') pub.sendMessage('preferences.requested.values', 'general.dicom') self.parent = parent # Setup toolbar controls openbmp = wx.Bitmap(util.GetResourcePath('folder_image.png')) self.tools = [{ 'label': "Open Quickly", 'bmp': openbmp, 'shortHelp': "Open DICOM File Quickly...", 'eventhandler': self.pluginMenu }]
def ImportDicom(parent): """Prepare to show the dialog that will Import DICOM and DICOM RT files.""" # Load the XRC file for our gui resources res = XmlResource(util.GetResourcePath('dicomgui.xrc')) dlgDicomImporter = res.LoadDialog(parent, "DicomImporterDialog") dlgDicomImporter.Init(res) # Show the dialog and return the result if (dlgDicomImporter.ShowModal() == wx.ID_OK): value = dlgDicomImporter.GetPatient() pub.sendMessage('patient.updated.raw_data', value) else: value = {} # Block until the thread is done before destroying the dialog if dlgDicomImporter: dlgDicomImporter.t.join() dlgDicomImporter.Destroy() return value
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, res): """Method called after the panel has been initialized.""" # Bind ui events to the proper methods self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) # Initialize variables self.images = [] self.structures = {} self.window = 0 self.level = 0 self.zoom = 1 self.pan = [0, 0] self.bwidth = 0 self.bheight = 0 self.xpos = 0 self.ypos = 0 self.mousepos = wx.Point(-10000, -10000) self.mouse_in_window = False self.isodose_line_style = 'Solid' self.isodose_fill_opacity = 25 self.structure_line_style = 'Solid' self.structure_fill_opacity = 50 self.plugins = {} # Setup toolbar controls if guiutil.IsGtk(): drawingstyles = ['Solid', 'Transparent', 'Dot'] else: drawingstyles = ['Solid', 'Transparent', 'Dot', 'Dash', 'Dot Dash'] zoominbmp = wx.Bitmap(util.GetResourcePath('magnifier_zoom_in.png')) zoomoutbmp = wx.Bitmap(util.GetResourcePath('magnifier_zoom_out.png')) toolsbmp = wx.Bitmap(util.GetResourcePath('cog.png')) self.tools = [] self.tools.append({ 'label': "Zoom In", 'bmp': zoominbmp, 'shortHelp': "Zoom In", 'eventhandler': self.OnZoomIn }) self.tools.append({ 'label': "Zoom Out", 'bmp': zoomoutbmp, 'shortHelp': "Zoom Out", 'eventhandler': self.OnZoomOut }) self.tools.append({ 'label': "Tools", 'bmp': toolsbmp, 'shortHelp': "Tools", 'eventhandler': self.OnToolsMenu }) # Set up preferences self.preferences = [{ 'Drawing Settings': [{ 'name': 'Isodose Line Style', 'type': 'choice', 'values': drawingstyles, 'default': 'Solid', 'callback': '2dview.drawingprefs.isodose_line_style' }, { 'name': 'Isodose Fill Opacity', 'type': 'range', 'values': [0, 100], 'default': 25, 'units': '%', 'callback': '2dview.drawingprefs.isodose_fill_opacity' }, { 'name': 'Structure Line Style', 'type': 'choice', 'values': drawingstyles, 'default': 'Solid', 'callback': '2dview.drawingprefs.structure_line_style' }, { 'name': 'Structure Fill Opacity', 'type': 'range', 'values': [0, 100], 'default': 50, 'units': '%', 'callback': '2dview.drawingprefs.structure_fill_opacity' }] }] # Set up pubsub pub.subscribe(self.OnUpdatePatient, 'patient.updated.parsed_data') pub.subscribe(self.OnStructureCheck, 'structures.checked') pub.subscribe(self.OnIsodoseCheck, 'isodoses.checked') pub.subscribe(self.OnRefresh, '2dview.refresh') pub.subscribe(self.OnDrawingPrefsChange, '2dview.drawingprefs') pub.subscribe(self.OnPluginLoaded, 'plugin.loaded.2dview') pub.sendMessage('preferences.requested.values', msg='2dview.drawingprefs')
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")