Skip to content
Snippets Groups Projects
Commit 3a934425 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

New module 'state' which saves/restores the state of a FSLEyesFrame -

restore not implemented yet. Most logic moved from diagnosticreport into
state.
parent 9f98eee9
No related branches found
No related tags found
No related merge requests found
...@@ -187,8 +187,11 @@ Some other miscellaneous modules are contained in the ``fsleyes`` package: ...@@ -187,8 +187,11 @@ Some other miscellaneous modules are contained in the ``fsleyes`` package:
~fsl.fsleyes.toolbar ~fsl.fsleyes.toolbar
~fsl.fsleyes.tooltips ~fsl.fsleyes.tooltips
~fsl.fsleyes.perspectives ~fsl.fsleyes.perspectives
~fsl.fsleyes.autodisplay
~fsl.fsleyes.state
~fsl.fsleyes.icons ~fsl.fsleyes.icons
~fsl.fsleyes.colourmaps ~fsl.fsleyes.colourmaps
~fsl.fsleyes.plotting ~fsl.fsleyes.plotting
~fsl.fsleyes.splash ~fsl.fsleyes.splash
~fsl.fsleyes.about
""" """
...@@ -16,9 +16,11 @@ import logging ...@@ -16,9 +16,11 @@ import logging
import platform import platform
from collections import OrderedDict from collections import OrderedDict
import action import fsl.data.strings as strings
import fsl.data.strings as strings import fsl.utils.status as status
import fsl.utils.status as status import fsl.fsleyes.state as fslstate
from . import action
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -92,8 +94,7 @@ class DiagnosticReportAction(action.Action): ...@@ -92,8 +94,7 @@ class DiagnosticReportAction(action.Action):
state. state.
""" """
import fsl.version as version import fsl.version as version
import fsl.fsleyes.perspectives as perspectives
report = OrderedDict() report = OrderedDict()
overlays = [] overlays = []
...@@ -111,25 +112,11 @@ class DiagnosticReportAction(action.Action): ...@@ -111,25 +112,11 @@ class DiagnosticReportAction(action.Action):
report['VCS Version'] = version.__vcs_version__ report['VCS Version'] = version.__vcs_version__
report['OpenGL'] = self.__openGLReport() report['OpenGL'] = self.__openGLReport()
report['Settings'] = self.__settingsReport() report['Settings'] = self.__settingsReport()
report['Layout'] = perspectives.serialisePerspective(self.__frame)
report['Overlays'] = overlays
report['Master display context'] = self.__displayContextReport(
self.__overlayList,
self.__displayCtx)
for viewPanel in self.__frame.getViewPanels(): state = fslstate.save(self.__frame)
# Accessing the undocumented for k, v in state.items():
# AuiPaneInfo.name attribute report[k] = v
vpName = self.__frame.getViewPanelInfo(viewPanel).name
vpDisplayCtx = viewPanel.getDisplayContext()
report[vpName] = OrderedDict([
('View', self.__viewPanelReport(viewPanel)),
('Display context', self.__displayContextReport(
self.__overlayList,
vpDisplayCtx))])
return report return report
...@@ -182,100 +169,6 @@ class DiagnosticReportAction(action.Action): ...@@ -182,100 +169,6 @@ class DiagnosticReportAction(action.Action):
return report return report
def __displayContextReport(self, overlayList, displayCtx):
"""Creates and returns a hierarchical dictionary containing
information about the given :class:`.DisplayContext` and the
:class:`.Display`/:class:`.DisplayOpts` instances which it
is managing.
"""
report = OrderedDict()
overlays = []
props = displayCtx.getAllProperties()[0]
for overlay in overlayList:
display = displayCtx.getDisplay(overlay)
opts = displayCtx.getOpts( overlay)
overlays.append(OrderedDict([
('Display', self.__displayReport( display)),
('DisplayOpts', self.__displayOptsReport(opts))]))
for prop in props:
report[prop] = str(getattr(displayCtx, prop))
report['overlays'] = overlays
return report
def __displayReport(self, display):
"""Creates and returns a dictionary containing informtion about
the given :class:`.Display` instance.
"""
report = OrderedDict()
props = display.getAllProperties()[0]
for prop in props:
report[prop] = str(getattr(display, prop))
return report
def __displayOptsReport(self, opts):
"""Creates and returns a dictionary containing informtion about
the given :class:`.DisplayOpts` instance.
"""
report = OrderedDict()
report['type'] = type(opts).__name__
props = opts.getAllProperties()[0]
for prop in props:
value = getattr(opts, prop)
if prop in ('cmap', 'negativeCmap'):
value = value.name
report[prop] = str(value)
return report
def __viewPanelReport(self, viewPanel):
"""Creates and returns a dictionary containing informtion about
the given :class:`.ViewPanel`.
"""
import fsl.fsleyes.views as views
report = OrderedDict()
props = viewPanel.getAllProperties()[0]
report['type'] = type(viewPanel).__name__
for prop in props:
report[prop] = str(getattr(viewPanel, prop))
if isinstance(viewPanel, views.CanvasPanel):
sceneOptsReport = OrderedDict()
sceneOpts = viewPanel.getSceneOptions()
props = sceneOpts.getAllProperties()[0]
sceneOptsReport['type'] = type(sceneOpts).__name__
for prop in props:
sceneOptsReport[prop] = str(getattr(sceneOpts, prop))
report['SceneOpts'] = sceneOptsReport
return report
def __formatReport(self, reportDict): def __formatReport(self, reportDict):
"""Converts the given hierarchical dictionary to a JSON-formatted """Converts the given hierarchical dictionary to a JSON-formatted
......
...@@ -73,6 +73,8 @@ class FSLEyesFrame(wx.Frame): ...@@ -73,6 +73,8 @@ class FSLEyesFrame(wx.Frame):
.. autosummary:: .. autosummary::
:nosignatures: :nosignatures:
getOverlayList
getDisplayContext
getViewPanels getViewPanels
getViewPanelInfo getViewPanelInfo
addViewPanel addViewPanel
...@@ -209,6 +211,20 @@ class FSLEyesFrame(wx.Frame): ...@@ -209,6 +211,20 @@ class FSLEyesFrame(wx.Frame):
self.Layout() self.Layout()
def getOverlayList(self):
"""Returns the :class:`.OverlayList` which contains the overlays
being displayed by this ``FSLEyesFrame``.
"""
return self.__overlayList
def getDisplayContext(self):
"""Returns the top-level :class:`.DisplayContext` associated with this
``FSLEyesFrame``.
"""
return self.__displayCtx
def getViewPanels(self): def getViewPanels(self):
"""Returns a list of all :class:`.ViewPanel` instances that are """Returns a list of all :class:`.ViewPanel` instances that are
currenlty displayed in this ``FSLEyesFrame``. currenlty displayed in this ``FSLEyesFrame``.
...@@ -266,7 +282,7 @@ class FSLEyesFrame(wx.Frame): ...@@ -266,7 +282,7 @@ class FSLEyesFrame(wx.Frame):
self.__onViewPanelClose(panel=vp, displaySync=False) self.__onViewPanelClose(panel=vp, displaySync=False)
self.__auiManager.ClosePane(paneInfo) self.__auiManager.ClosePane(paneInfo)
self.__auiManager.Update() self.__auiManager.Update()
def addViewPanel(self, panelCls): def addViewPanel(self, panelCls):
......
...@@ -565,7 +565,11 @@ def _addControlPanel(viewPanel, panelType): ...@@ -565,7 +565,11 @@ def _addControlPanel(viewPanel, panelType):
def _getPanelProps(panel): def _getPanelProps(panel):
""" """Creates and returns two dictionaries, containing properties of the given
:class:`.ViewPanel` (and its associated :class:`.SceneOpts` instance, if
it is a :class:`.CanvasPanel`), which are to be saved as part of a
seriaised *FSLeyes* perspective. The properties to be saved are listed in
the :data:`VIEWPANEL_PROPS` dictionary.
""" """
import fsl.fsleyes.views as views import fsl.fsleyes.views as views
......
#!/usr/bin/env python
#
# state.py - Functions for saving/restoring the state of *FSLeyes*.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides two functions, :func:`save` and :func:`restore`.
These functions may be used to save/restore the state of *FSLeyes*.
.. note:: :func:`restore` is currently not implemented.
"""
import importlib
from collections import OrderedDict
import props
from . import perspectives
def save(frame):
"""Creates and returns a dictionary containing the current state of the
given :class:`.FSLeyesFrame`, the :class:`.OverlayList` and
:class:`.DisplayContext` associated with it, and the :class:`.ViewPanel`
instances being displayed.
"""
overlayList = frame.getOverlayList()
displayCtx = frame.getDisplayContext()
viewPanels = frame.getViewPanels()
layout = perspectives.serialisePerspective(frame)
overlays = [(type(o).__name__, o.dataSource) for o in overlayList]
overlays = []
for i, ovl in enumerate(overlayList):
overlays.append(OrderedDict([
('type', '{}.{}'.format(ovl.__module__, type(ovl).__name__)),
('name', ovl.name),
('source', ovl.dataSource)]))
state = OrderedDict()
state['Layout'] = layout
state['Overlays'] = overlays
state['DisplayContext'] = _displayContextState(overlayList, displayCtx)
vpStates = {}
for vp in viewPanels:
# Accessing the undocumented
# AuiPaneInfo.name attribute
vpName = frame.getViewPanelInfo(vp).name
vpDisplayCtx = vp.getDisplayContext()
vpStates[vpName] = OrderedDict([
('View', _viewPanelState(vp)),
('DisplayContext', _displayContextState(overlayList,
vpDisplayCtx))])
state['ViewPanels'] = vpStates
return state
def _displayContextState(overlayList, displayCtx):
"""Creates and returns a hierarchical dictionary containing
the state of the given :class:`.DisplayContext` and the
:class:`.Display`/:class:`.DisplayOpts` instances which it
is managing.
"""
state = OrderedDict()
overlays = []
propNames = displayCtx.getAllProperties()[0]
for overlay in overlayList:
display = displayCtx.getDisplay(overlay)
opts = displayCtx.getOpts( overlay)
overlays.append(OrderedDict([
('Display', _displayState( display)),
('DisplayOpts', _displayOptsState(opts))]))
for propName in propNames:
state[propName] = props.serialise(displayCtx, propName)
print 'displayCtx.{} = {}'.format(propName, state[propName])
state['Overlays'] = overlays
return state
def _displayState(display):
"""Creates and returns a dictionary containing the state of the given
:class:`.Display` instance.
"""
state = OrderedDict()
propNames = display.getAllProperties()[0]
for propName in propNames:
state[propName] = props.serialise(display, propName)
return state
def _displayOptsState(opts):
"""Creates and returns a dictionary containing the state of the given
:class:`.DisplayOpts` instance.
"""
state = OrderedDict()
propNames = opts.getAllProperties()[0]
state['type'] = type(opts).__name__
for propName in propNames:
state[propName] = props.serialise(opts, propName)
return state
def _viewPanelState(viewPanel):
"""Creates and returns a dictionary containing the state of the given
:class:`.ViewPanel`.
"""
import fsl.fsleyes.views as views
state = OrderedDict()
propNames = viewPanel.getAllProperties()[0]
state['type'] = type(viewPanel).__name__
for propName in propNames:
state[propName] = props.serialise(viewPanel, propName)
if isinstance(viewPanel, views.CanvasPanel):
sceneOptsState = OrderedDict()
sceneOpts = viewPanel.getSceneOptions()
propNames = sceneOpts.getAllProperties()[0]
sceneOptsState['type'] = type(sceneOpts).__name__
for propName in propNames:
sceneOptsState[propName] = props.serialise(sceneOpts, propName)
state['SceneOpts'] = sceneOptsState
return state
def restore(frame, state):
"""Applies a state, previously saved via :func:`save`, to the given
:class:`.FSLeyesFrame`.
.. note:: Not implemented.
"""
return
overlayList = frame.getOverlayList()
displayCtx = frame.getDisplayContext()
layout = state['Layout']
overlays = state['Overlays']
displayCtxState = state['DisplayContext']
vpStates = state['ViewPanels']
# First, remove all view panels and then
# clear the overlay list. We do it in this
# order to avoid any unncessary processing
# by existing view panel DisplayContexts.
frame.removeAllViewPanels()
overlayList[:] = []
# Populate the overlay list and configure
# the master display context
overlayObjs = []
for ovl in overlays:
klass = ovl['type']
name = ovl['name']
dataSource = ovl['source']
# We can't restore in-memory overlays
if dataSource is None or dataSource.lower() == 'none':
continue
# Split the (fully-qualified)
# class name into the containing
# module and the class name.
klass = klass.split('.')
module = '.'.join(klass[:-1])
klass = klass[-1]
# Import the module, and
# look up the class object
module = importlib.import_module(module)
klass = getattr(module, klass)
# Create the overlay object
ovl = klass(dataSource)
ovl.name = name
overlayObjs.append(ovl)
# Restore the master display contxt
_restoreDisplayContext(displayCtx, overlayList, displayCtxState)
# Apply the frame perspective
perspectives.applyPerspective(frame, None, layout)
# Restore view panel settings
viewPanels = frame.getViewPanels()
for vp, vpState in zip(viewPanels, vpStates):
_restoreViewPanel(vp, overlayList, vpState)
def _restoreViewPanel(viewPanel, overlayList, state):
displayCtx = viewPanel.getDisplayContext()
sceneOpts = viewPanel.getSceneOptions()
vpState = state['View']
dcState = state['DisplayContext']
vpType = vpState.pop('type')
sceneOptsState = vpState.pop('SceneOpts')
_restoreDisplayContext(displayCtx, overlayList, dcState)
_applyProps(viewPanel, vpState)
_applyProps(sceneOpts, sceneOptsState)
def _restoreDisplayContext(displayCtx, overlayList, state):
# Configure selected properties
# of the master display context
dcProps = ['selectedOverlay',
'location',
# 'overlayOrder',
'syncOverlayDisplay',
'displaySpace',
'autoDisplay']
_applyProps(displayCtx, state, dcProps)
for overlay, ovlState in zip(overlayList, state['Overlays']):
displayState = ovlState['Display']
optsState = ovlState['DisplayOpts']
display = displayCtx.getDisplay(overlay)
_applyProps(display, displayState)
# TODO: This will almost certainly fail
# for non-trivial properties (e.g.
# VolumeOpts.clipImage)
opts = displayCtx.getOpts(overlay)
_applyProps(opts, optsState)
def _applyProps(target, values, propNames=None):
if propNames is None:
propNames = values.keys()
for propName in propNames:
val = values[propName]
val = props.deserialise(target, propName, val)
setattr(target, propName, val)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment