def __applyCommandLineArgs(self): """Called when this action is executed. Prompts the user to enter some command line arguments, and then passes them to the :func:`applyCommandLineArgs` function. """ # prompt user for some arguments dlg = fsldlg.TextEditDialog(self.__panel, strings.titles[self, 'title'], strings.messages[self, 'apply'], style=fsldlg.TED_MULTILINE | fsldlg.TED_OK_CANCEL) dlg.CentreOnParent() if dlg.ShowModal() != wx.ID_OK: return # Pass GetText through str, because it # returns a unicode string, and python's # argparse does not seem to like unicode. argv = str(dlg.GetText()).split() errTitle = strings.titles[self, 'error'] errMsg = strings.messages[self, 'error'] # apply said arguments with status.reportIfError(errTitle, errMsg): applyCommandLineArgs(self.__overlayList, self.__displayCtx, argv, self.__panel)
def __loadVertexData(self): """Called when this action is executed. Prompts the user to load some vertex data for the currently selected :class:`.TriangleMesh` overlay, then sets the :attr:`.MeshOpts.vertexData` property accordingly. If the file was successfully loaded, also adds the loaded file as an option on the :attr:`.MeshOpts.vertexData` property. """ import wx app = wx.GetApp() overlay = self.__displayCtx.getSelectedOverlay() fromDir = op.dirname(overlay.dataSource) msg = strings.messages[self, 'loadVertexData'].format(overlay.name) dlg = wx.FileDialog(app.GetTopWindow(), message=msg, defaultDir=fromDir, wildcard='*.*', style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return path = dlg.GetPath() errtitle = strings.titles[ self, 'error'] errmsg = strings.messages[self, 'error'].format(overlay.name) with status.reportIfError(errtitle, errmsg): loadVertexData(overlay, self.__displayCtx, path)
def __onSaveButton(self, ev): """Called when the user pushe the *Save labels* button. Asks the user where they'd like the label saved, then saves said labels. """ overlay = self.displayCtx.getSelectedOverlay() volLabels = self.overlayList.getData(overlay, 'VolumeLabels') if isinstance(overlay, fslmelimage.MelodicImage): defaultDir = overlay.getMelodicDir() elif overlay.dataSource is not None: defaultDir = op.dirname(overlay.dataSource) else: defaultDir = None dlg = wx.FileDialog( self, message=strings.titles[self, 'saveDialog'], defaultDir=defaultDir, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() != wx.ID_OK: return filename = dlg.GetPath() emsg = strings.messages[self, 'saveError'].format(filename) etitle = strings.titles[ self, 'saveError'] with status.reportIfError(msg=emsg, title=etitle, raiseError=False): volLabels.save(filename, dirname=defaultDir)
def loadAtlas(parent=None): """Prompts the user to select an atlas specification file, and then loads the atlas. """ import wx app = wx.GetApp() if parent is None: parent = app.GetTopWindow() msg = strings.titles[LoadAtlasAction, 'fileDialog'] dlg = wx.FileDialog(parent, message=msg, wildcard='XML atlas specification|*.xml', style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return path = dlg.GetPath() errtitle = strings.titles[ LoadAtlasAction, 'error'] errmsg = strings.messages[LoadAtlasAction, 'error'].format(path) with status.reportIfError(errtitle, errmsg): atlases.addAtlas(path)
def __loadit(self, key, func): """Shared by the :meth:`__loadVertices` and :meth:`__loadVertexData` methods. """ import wx app = wx.GetApp() overlay = self.__displayCtx.getSelectedOverlay() fromDir = op.dirname(overlay.dataSource) msg = strings.messages[self, key].format(overlay.name) dlg = wx.FileDialog(app.GetTopWindow(), message=msg, defaultDir=fromDir, wildcard='*.*', style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return path = dlg.GetPath() errtitle = strings.titles[self, 'error'] errmsg = strings.messages[self, 'error'].format(overlay.name) with status.reportIfError(errtitle, errmsg, raiseError=False): func(overlay, self.__displayCtx, path)
def __saveFlirtXfm(self): """Called when this action is executed. Prompts the user to save a FLIRT transform for the currently selected image. """ displayCtx = self.displayCtx overlayList = self.overlayList overlay = displayCtx.getSelectedOverlay() affType, matFile, refFile = applyflirtxfm.promptForFlirtFiles( self.__frame, overlay, overlayList, displayCtx, save=True) if all((affType is None, matFile is None, refFile is None)): return if affType == 'flirt': xform = calculateTransform(overlay, overlayList, displayCtx, refFile) else: xform = overlay.voxToWorldMat errtitle = strings.titles[self, 'error'] errmsg = strings.messages[self, 'error'] with status.reportIfError(errtitle, errmsg): np.savetxt(matFile, xform, fmt='%0.10f')
def __checkForUpdates(self, showUpToDateMessage=True, showErrorMessage=True, ignorePoint=False): """Run this action. Downloads a text file from a URL which contains the latest available version of FSLeyes. Compares that version with the running version. Displays a message to the user. :arg showUpToDateMessage: Defaults to ``True``. If ``False``, and the current version of FSLeyes is up to date, the user is not informed. :arg showErrorMessage: Defaults to ``True``. If ``False``, and some error occurs while checking for updates, the user is not informed. :arg ignorePoint: Defaults to ``False``. If ``True``, the point release number is ignored in the comparison. """ errMsg = strings.messages[self, 'newVersionError'] errTitle = strings.titles[self, 'newVersionError'] with status.reportIfError(errTitle, errMsg, report=showErrorMessage): log.debug('Checking for FSLeyes updates ({})'.format( _FSLEYES_VERSION_URL)) f = request.urlopen(_FSLEYES_VERSION_URL) latest = f.read().decode('utf-8').strip() current = version.__version__ upToDate = fslversion.compareVersions(latest, current, ignorePoint) <= 0 log.debug('This version of FSLeyes ({}) is ' '{} date (latest: {})'.format( current, 'up to' if upToDate else 'out of', latest)) if upToDate and not showUpToDateMessage: return urlMsg = strings.messages[self, 'updateUrl'] if upToDate: title = strings.titles[self, 'upToDate'] msg = strings.messages[self, 'upToDate'] msg = msg.format(current) else: title = strings.titles[self, 'newVersionAvailable'] msg = strings.messages[self, 'newVersionAvailable'] msg = msg.format(current, latest, _FSLEYES_URL) parent = wx.GetTopLevelWindows()[0] dlg = UrlDialog(parent, title, msg, urlMsg, _FSLEYES_URL) dlg.CentreOnParent() dlg.ShowModal()
def __onSaveLut(self, ev): """Called when the user presses the *Save LUT* button. Makes sure that the current :class:`LookupTable` is saved (see the :func:`.colourmaps.installLookupTable` function). """ etitle = strings.titles[self, 'installerror'] emsg = strings.messages[self, 'installerror'] with status.reportIfError(title=etitle, msg=emsg, raiseError=False): fslcmaps.installLookupTable(self.__selectedLut.key)
def test_reportIfError_error_noraise(): title = 'title' msg = 'msg' exc = Exception() # report=True with mock.patch('fsleyes_widgets.utils.status.reportError') as reperr: with status.reportIfError(title, msg, raiseError=False): raise exc reperr.assert_called_once_with(title, msg, exc) # report=False with mock.patch('fsleyes_widgets.utils.status.reportError') as reperr, \ mock.patch('fsleyes_widgets.utils.status.log.error') as log: with status.reportIfError(title, msg, raiseError=False, report=False): raise exc reperr.assert_not_called() log.assert_called_once()
def __onLoadLut(self, ev): """Called when the user presses the *Load LUT* button. Does the following: - Prompts the user to select a LUT file with a ``wx.FileDialog`` - Prompts the user to enter a name for the LUT via the :func:`promptForLutName` function. - Creates and registers a new :class:`.LookupTable` instance, initialising it with the selected file. - Updates this ``LookupTablePanel`` via the :meth:`__updateLutChoices` and :meth:`__setLut` methods. """ parent = wx.GetApp().GetTopWindow() loadDir = fslsettings.read('fsleyes.loadlutdir', os.getcwd()) # Prompt the user to select a lut file fileDlg = wx.FileDialog(parent, defaultDir=loadDir, message=strings.titles[self, 'loadLut'], style=wx.FD_OPEN) if fileDlg.ShowModal() != wx.ID_OK: return lutFile = fileDlg.GetPath() lutDir = op.dirname(lutFile) lutName = op.splitext(op.basename(lutFile))[0] # Prompt the user to enter a name lutKey, lutName = promptForLutName(lutName) if lutKey is None: return # Register the lut errTitle = strings.titles[self, 'loadError'] errMsg = strings.messages[self, 'loadError'].format(lutFile) with status.reportIfError(errTitle, errMsg): lut = fslcmaps.registerLookupTable(lutFile, self.overlayList, self.displayCtx, key=lutKey, name=lutName) # Save the directory for next time fslsettings.write('fsleyes.loadlutdir', lutDir) # Select the lut in the panel self.__updateLutChoices() self.__setLut(lut)
def doSave(overlay, path=None): """Called by :func:`saveOverlay`. Tries to save the given ``overlay`` to the given ``path``, and shows an error message if something goes wrong. Returns ``True`` if the save was successful, ``False`` otherwise. """ emsg = strings.messages['SaveOverlayAction.saveError'].format(path) etitle = strings.titles['SaveOverlayAction.saveError'] with status.reportIfError(msg=emsg, title=etitle, raiseError=False): overlay.save(path) return True return False
def __loadPlugin(self, *args, **kwargs): """Prompts the user to select a plugin file, asks them whether they would like to install it permanently, and then passes it to either :func:`.loadPlugin` or :func:`.installPlugin`. """ lastDir = fslsettings.read('loadPluginLastDir') if lastDir is None: lastDir = os.getcwd() msg = strings.messages[self, 'loadPlugin'] dlg = wx.FileDialog(self.__frame, message=msg, defaultDir=lastDir, wildcard='*.py', style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return fname = dlg.GetPath() fslsettings.write('loadPluginLastDir', op.dirname(fname)) dlg = wx.MessageDialog(self.__frame, caption=strings.titles[self, 'installPlugin'], message=strings.messages[self, 'installPlugin'], style=wx.YES_NO | wx.CANCEL) result = dlg.ShowModal() if result == wx.ID_YES: etitle = strings.titles[self, 'installError'] emsg = strings.messages[self, 'installError'] func = plugins.installPlugin elif result == wx.ID_NO: etitle = strings.titles[self, 'loadError'] emsg = strings.messages[self, 'loadError'] func = plugins.loadPlugin else: return with status.reportIfError(title=etitle, msg=emsg, raiseError=False): func(fname) self.__frame.refreshViewMenu() self.__frame.refreshToolsMenu() self.__frame.refreshSettingsMenu()
def __openNotebooks(self, nbfile=None): """Called when this ``NotebookAction`` is invoked. Starts the server and kernel if necessary. If the server/kernel have not yet been started and ``nbfile`` is provided, the server will be started with ``nbfile`` opened. """ # If the kernel and server are both # ok, open the notebook homepage if self.__kernel is not None and \ self.__server is not None and \ self.__kernel.is_alive() and \ self.__server.is_alive(): webbrowser.open(self.__server.url) return # have the kernel or server threads crashed? if self.__kernel is not None and not self.__kernel.is_alive(): self.__kernel = None if self.__server is not None and not self.__server.is_alive(): self.__server = None # show a progress dialog if we need # to initialise the kernel or server if self.__kernel is None or self.__server is None: title = strings.titles[self, 'init'] progdlg = progress.Bounce(title) else: progdlg = None try: # start the kernel/server, and show # an error if something goes wrong errt = strings.titles[self, 'init.error'] errm = strings.messages[self, 'init.error'] with status.reportIfError(errt, errm): if self.__kernel is None: self.__kernel = self.__startKernel(progdlg) if self.__server is None: self.__server = self.__startServer(progdlg, nbfile) finally: if progdlg is not None: progdlg.Destroy() progdlg = None
def __onSave(self, ev): """Called when the Save button is pushed. Saves the current crop parameters to a text file. """ overlay = self.__overlay cropBox = self.__profile.cropBox fileName = '{}_crop.txt'.format(overlay.name) if overlay.dataSource is not None: dirName = op.dirname(overlay.dataSource) else: dirName = os.getcwd() dlg = wx.FileDialog( self, defaultDir=dirName, defaultFile=fileName, message=strings.messages[self, 'saveCrop'], style=wx.FD_SAVE) if dlg.ShowModal() != wx.ID_OK: return filePath = dlg.GetPath() # The crop parameters are saved # in a fslroi-compatible manner. params = [cropBox.xlo, cropBox.xhi - cropBox.xlo, cropBox.ylo, cropBox.yhi - cropBox.ylo, cropBox.zlo, cropBox.zhi - cropBox.zlo] if overlay.ndim >= 4: tlo = self.__volumeWidget.GetLow() thi = self.__volumeWidget.GetHigh() params.extend((tlo, thi - tlo)) errTitle = strings.titles[ self, 'saveError'] errMsg = strings.messages[self, 'saveError'] with status.reportIfError(errTitle, errMsg, raiseError=False): np.savetxt(filePath, [params], fmt='%i')
def MacOpenURL(self, url): """On OSX, support opening files via a ``fsleyes://`` url. """ if self.__overlayList is None: return import fsleyes_widgets.utils.status as status import fsleyes.strings as strings import fsleyes.parseargs as parseargs import fsleyes.actions.applycommandline as applycommandline errTitle = strings.titles[self, 'openURLError'] errMsg = strings.messages[self, 'openURLError'] with status.reportIfError(errTitle, errMsg): applycommandline.applyCommandLineArgs( self.__overlayList, self.__displayCtx, parseargs.fsleyesUrlToArgs(url))
def __onSave(self, ev): """Called when the *save* button is pushed. Prompts the user to select a file name, then saves the current history to that file. """ history = self.getHistory() msg = strings.messages[self, 'save'] defDir = fslsettings.read('loadSaveOverlayDir') dlg = wx.FileDialog(self, message=msg, defaultDir=defDir, wildcard='*.txt', style=wx.FD_SAVE) if dlg.ShowModal() != wx.ID_OK: return errTitle = strings.titles[ self, 'saveError'] errMsg = strings.messages[self, 'saveError'].format(dlg.GetPath()) with status.reportIfError(errTitle, errMsg, raiseError=False): saveLocationHistory(history, dlg.GetPath())
def __onLoad(self, ev): """Called when the Save button is pushed. Prompts the user to select a file to load crop parameters from. """ overlay = self.__overlay cropBox = self.__profile.cropBox fileName = '{}_crop.txt'.format(overlay.name) if overlay.dataSource is not None: dirName = op.dirname(overlay.dataSource) else: dirName = os.getcwd() if not op.exists(op.join(dirName, fileName)): fileName = '' dlg = wx.FileDialog( self, defaultDir=dirName, defaultFile=fileName, message=strings.messages[self, 'saveCrop'], style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if dlg.ShowModal() != wx.ID_OK: return filePath = dlg.GetPath() errTitle = strings.titles[ self, 'loadError'] errMsg = strings.messages[self, 'loadError'] with status.reportIfError(errTitle, errMsg, raiseError=False): params = loadCropParameters(filePath, overlay) cropBox[:] = params[:6] if overlay.ndim >= 4: tlo, thi = params[6:] self.__volumeWidget.SetLow(tlo) self.__volumeWidget.SetHigh(thi)
def __openNotebooks(self): """Called when this ``NotebookAction`` is invoked. Starts the server and kernel if necessary, then opens a new notebook in a web browser. """ # have the kernel or server threads crashed? if self.__kernel is not None and not self.__kernel.is_alive(): self.__kernel = None if self.__server is not None and not self.__server.is_alive(): self.__server = None # show a progress dialog if we need # to initialise the kernel or server if self.__kernel is None or self.__server is None: title = strings.titles[self, 'init'] progdlg = progress.Bounce(title) else: progdlg = None try: # start the kernel/server, and show # an error if something goes wrong errt = strings.titles[ self, 'init.error'] errm = strings.messages[self, 'init.error'] with status.reportIfError(errt, errm): if self.__kernel is None: self.__kernel = self.__startKernel(progdlg) if self.__server is None: self.__server = self.__startServer(progdlg) finally: if progdlg is not None: progdlg.Destroy() progdlg = None # if all is well, open the # notebook server homepage webbrowser.open(self.__server.url)
def init(splash): # See FSLeyesSplash.Show # for horribleness. splash.Show() # Parse command line arguments if necessary. # If arguments are invalid, the parseargs # module will raise SystemExit. try: if namespace[0] is None: errmsg = strings.messages['main.parseArgs.error'] errtitle = strings.titles['main.parseArgs.error'] with status.reportIfError(errtitle, errmsg, raiseError=True): namespace[0] = parseArgs(args) # But the wx.App.MainLoop eats SystemExit # exceptions for unknown reasons, and # causes the application to exit # immediately. This makes testing FSLeyes # (e.g. code coverage) impossible. So I'm # catching SystemExit here, and then # telling the wx.App to exit gracefully. except (SystemExit, Exception) as e: app.ExitMainLoop() exitCode[0] = getattr(e, 'code', 1) return # Configure logging (this has to be done # after cli arguments have been parsed, # but before initialise is called). fsleyes.configLogging(namespace[0].verbose, namespace[0].noisy) # Initialise sub-modules/packages. The # buildGui function is passed through # as a callback, which gets called when # initialisation is complete. initialise(splash, namespace[0], buildGui)
def __onLoad(self, ev): """Called when the *load* button is pushed. Prompts the user to select a file, then loads a history from that file. """ msg = strings.messages[self, 'load'] fromDir = fslsettings.read('loadSaveOverlayDir') dlg = wx.FileDialog(self, message=msg, defaultDir=fromDir, wildcard='*.txt', style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return errTitle = strings.titles[ self, 'loadError'] errMsg = strings.messages[self, 'loadError'].format(dlg.GetPath()) with status.reportIfError(errTitle, errMsg, raiseError=False): history = loadLocationHistory(dlg.GetPath()) self.__list.Clear() for loc, comment in history: self.__addLocation(loc, comment)
def __onLoadButton(self, ev): """Called when the *Load labels* button is pushed. Prompts the user to select a label file to load, then does the following: 1. If the selected label file refers to the currently selected melodic_IC overlay, the labels are applied to the overlay. 2. If the selected label file refers to a different melodic_IC overlay, the user is asked whether they want to load the different melodic_IC file (the default), or whether they want the labels applied to the existing overlay. 3. If the selected label file does not refer to any overlay (it only contains the bad component list), the user is asked whether they want the labels applied to the current melodic_IC overlay. If the number of labels in the file is less than the number of melodic_IC components, the remaining components are labelled as unknown. If the number of labels in the file is greater than the number of melodic_IC components, an error is shown, and nothing is done. """ # The aim of the code beneath the # applyLabels function is to load # a set of component labels, and # to figure out which overlay # they should be added to. # When it has done this, it calls # applyLabels, which applies the # loaded labels to the overlay. def applyLabels(labelFile, overlay, allLabels, newOverlay): # labelFile: Path to the loaded label file # overlay: Overlay to apply them to # allLabels: Loaded labels (list of (component, [label]) tuples) # newOverlay: True if the selected overlay has changed, False # otherwise lut = self.__lut volLabels = self.overlayList.getData(overlay, 'VolumeLabels') ncomps = volLabels.numComponents() nlabels = len(allLabels) # Error: number of labels in the # file is greater than the number # of components in the overlay. if ncomps < nlabels: msg = strings.messages[self, 'wrongNComps'].format( labelFile, overlay.dataSource) title = strings.titles[ self, 'loadError'] wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK) return # Number of labels in the file is # less than number of components # in the overlay - we pad the # labels with 'Unknown' elif ncomps > nlabels: for i in range(nlabels, ncomps): allLabels.append(['Unknown']) # Disable notification while applying # labels so the component/label grids # don't confuse themselves. with volLabels.skip(self.__componentGrid.name), \ volLabels.skip(self.__labelGrid .name): volLabels.clear() for comp, lbls in enumerate(allLabels): for lbl in lbls: volLabels.addLabel(comp, lbl) # Make sure a colour in the melodic # lookup table exists for all labels for label in volLabels.getAllLabels(): label = volLabels.getDisplayLabel(label) lutLabel = lut.getByName(label) if lutLabel is None: log.debug('New melodic classification ' 'label: {}'.format(label)) lut.new(label, colour=fslcm.randomBrightColour()) # New overlay was loaded if newOverlay: # Make sure the new image is selected. with props.skip(self.displayCtx, 'selectedOverlay', self.name): self.displayCtx.selectOverlay(overlay) self.__componentGrid.setOverlay(overlay) self.__labelGrid .setOverlay(overlay) # Labels were applied to # already selected overlay. else: self.__componentGrid.refreshTags() self.__labelGrid .refreshTags() # If the current overlay is a compatible # Image, the open file dialog starting # point will be its directory. overlay = self.__overlay if overlay is not None and overlay.dataSource is not None: loadDir = op.dirname(overlay.dataSource) # Otherwise it will be the most # recent overlay load directory. else: loadDir = fslsettings.read('loadSaveOverlayDir', os.getcwd()) # Ask the user to select a label file dlg = wx.FileDialog( self, message=strings.titles[self, 'loadDialog'], defaultDir=loadDir, style=wx.FD_OPEN) # User cancelled the dialog if dlg.ShowModal() != wx.ID_OK: return # Load the specified label file filename = dlg.GetPath() emsg = strings.messages[self, 'loadError'].format(filename) etitle = strings.titles[ self, 'loadError'] try: with status.reportIfError(msg=emsg, title=etitle): melDir, allLabels = fixlabels.loadLabelFile(filename) except Exception: return # Ok we've got the labels, now # we need to figure out which # overlay to add them to. # If the label file does not refer # to a Melodic directory, and the # current overlay is a compatible # image, apply the labels to the # image. if overlay is not None and melDir is None: applyLabels(filename, overlay, allLabels, False) return # If the label file refers to a # Melodic directory, and the # current overlay is a compatible # image. if overlay is not None and melDir is not None: if isinstance(overlay, fslmelimage.MelodicImage): overlayDir = overlay.getMelodicDir() elif overlay.dataSource is not None: overlayDir = op.dirname(overlay.dataSource) else: overlayDir = 'none' # And both the current overlay and # the label file refer to the same # directory, then we apply the # labels to the curent overlay. if op.abspath(melDir) == op.abspath(overlayDir): applyLabels(filename, overlay, allLabels, False) return # Otherwise, if the overlay and the # label file refer to different # directories... # Ask the user whether they want to load # the image specified in the label file, # or apply the labels to the currently # selected image. dlg = wx.MessageDialog( self, strings.messages[self, 'diffMelDir'].format( melDir, overlayDir), style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL) dlg.SetYesNoLabels( strings.messages[self, 'diffMelDir.labels'], strings.messages[self, 'diffMelDir.overlay']) response = dlg.ShowModal() # User cancelled the dialog if response == wx.ID_CANCEL: return # User chose to load the melodic # image specified in the label # file. We'll carry on with this # processing below. elif response == wx.ID_YES: pass # Apply the labels to the current # overlay, even though they are # from different analyses. else: applyLabels(filename, overlay, allLabels, False) return # If we've reached this far, we are # going to attempt to identify the # image associated with the label # file, load that image, and then # apply the labels. # The label file does not # specify a melodic directory if melDir is None: msg = strings.messages[self, 'noMelDir'].format(filename) title = strings.titles[ self, 'loadError'] wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK) return # Try loading the melodic_IC image # specified in the label file. try: overlay = fslmelimage.MelodicImage(melDir) log.debug('Adding {} to overlay list'.format(overlay)) with props.skip(self.overlayList, 'overlays', self.name),\ props.skip(self.displayCtx, 'selectedOverlay', self.name): self.overlayList.append(overlay) if self.displayCtx.autoDisplay: autodisplay.autoDisplay(overlay, self.overlayList, self.displayCtx) fslsettings.write('loadSaveOverlayDir', op.abspath(melDir)) except Exception as e: e = str(e) msg = strings.messages[self, 'loadError'].format(filename, e) title = strings.titles[ self, 'loadError'] log.debug('Error loading classification file ' '({}), ({})'.format(filename, e), exc_info=True) wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK) # Apply the loaded labels # to the loaded overlay. applyLabels(filename, overlay, allLabels, True)
def DownloadFile(self, fobj, dest, showProgress=True): """Download the given ``xnat`` file object to the path specified by ``dest``. :arg fobj: An XNAT file object, as returned by :meth:`GetSelectedFiles`. :arg dest: Directory to download the file to. :arg showProgress: If ``True``, a ``wx.ProgressDialog`` is shown, displaying the download progress. :returns: Path to the downloaded file, or ``None`` if the download was cancelled.. Note that the path may be different to ``dest``, as the user may be prompted to select a different locaion. """ fname = fobj.id fsize = fobj.size # if destination already exists, ask # the user if they want to skip, # overwrite, or choose a new name if op.exists(dest): # We potentially show two dialogs - # the first one asking the user what # they want to do, and the second # one prompting for a new file. If # the user cancels the second dialog, # he/she is re-shown the first. while True: dlg = wx.MessageDialog( self, message=LABELS['download.exists.message'].format(fname), caption=LABELS['download.exists.title'], style=(wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION)) dlg.SetYesNoCancelLabels( LABELS['download.exists.overwrite'], LABELS['download.exists.newdest'], LABELS['download.exists.skip']) choice = dlg.ShowModal() # overwrite if choice == wx.ID_YES: break # skip elif choice == wx.ID_CANCEL: return None # choose a new destination elif choice == wx.ID_NO: dlg = wx.FileDialog( self, message=LABELS['download.exists.choose'], defaultDir=op.dirname(dest), defaultFile=fname, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) # If user cancelled this dialog, # show them the first dialog again. if dlg.ShowModal() == wx.ID_OK: dest = dlg.GetPath() fname = op.basename(dest) break if showProgress: dlg = wx.ProgressDialog( LABELS['download.title'], LABELS['download.startMessage'].format(fname), maximum=int(fsize), parent=self) msg = LABELS['download.updateMessage'] def update(nbytes, total, finished): nmb = nbytes / 1048576. tmb = total / 1048576. dlg.Update(nbytes, msg.format(fname, nmb, tmb)) dlg.Fit() if finished: dlg.Close() dlg.Show() else: update = None errTitle = LABELS['download.error.title'] errMsg = LABELS['download.error.message'].format(fname) with status.reportIfError(errTitle, errMsg, raiseError=False): with open(dest, 'wb') as f: fobj.download_stream(f, update_func=update) if showProgress: dlg.Close() return dest
def test_reportIfError_noError(): with mock.patch('fsleyes_widgets.utils.status.reportError') as func: with status.reportIfError('title', 'message'): pass func.assert_not_called()
def __loadColourMap(self): """This method does the following: 1. Prompts the user to select a colour map file 2. Prompts the user to name the new colour map. 3. Registers the colour map with the :mod:`.colourmaps` module. 4. Asks the user if they want the colour map installed, and installs it if they do. """ import wx app = wx.GetApp() # Get the most recent colour map # directory if there is one loadDir = fslsettings.read('fsleyes.loadcolourmapdir', os.getcwd()) # prompt the user to choose a colour map file dlg = wx.FileDialog(app.GetTopWindow(), defaultDir=loadDir, message=strings.messages[self, 'loadcmap'], style=wx.FD_OPEN) if dlg.ShowModal() != wx.ID_OK: return # prompt the user to choose a name for the colour # map (using the filename prefix as the default) cmapFile = dlg.GetPath() cmapDir = op.dirname(cmapFile) cmapName = op.splitext(op.basename(cmapFile))[0] cmapNameMsg = strings.messages[self, 'namecmap'] cmapNameTitle = strings.titles[self, 'namecmap'] while True: dlg = wx.TextEntryDialog(app.GetTopWindow(), cmapNameMsg, cmapNameTitle, cmapName) if dlg.ShowModal() != wx.ID_OK: return cmapName = dlg.GetValue() cmapKey = fslcmap.makeValidMapKey(cmapName) # a colour map with the specified name already exists if fslcmap.isColourMapRegistered(cmapKey): cmapNameMsg = strings.messages[self, 'alreadyinstalled'] continue break # register the selected colour map file fslcmap.registerColourMap(cmapFile, self.overlayList, self.displayCtx, key=cmapKey, name=cmapName) # Save the directory for next time fslsettings.write('fsleyes.loadcolourmapdir', cmapDir) # ask the user if they want to install # the colour map for future use dlg = wx.MessageDialog(app.GetTopWindow(), caption=strings.titles[self, 'installcmap'], message=strings.messages[self, 'installcmap'], style=wx.YES_NO) if dlg.ShowModal() != wx.ID_YES: return # install the colour map etitle = strings.titles[self, 'installerror'] emsg = strings.messages[self, 'installerror'] with status.reportIfError(title=etitle, msg=emsg, raiseError=False): fslcmap.installColourMap(cmapKey)