From c7ae50a178722e60a15e3e9f66b297c46e957346 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Tue, 2 Feb 2016 21:54:18 +0000
Subject: [PATCH] Diagnostic report action finished.

---
 fsl/data/strings.py                     |   2 +-
 fsl/fsleyes/actions/diagnosticreport.py | 123 +++++++++++++++++++++++-
 fsl/fsleyes/displaycontext/group.py     |  10 ++
 3 files changed, 129 insertions(+), 6 deletions(-)

diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index d399f019d..17b6aa950 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -250,7 +250,7 @@ actions = TypeDict({
     'LoadColourMapAction'     : 'Load custom colour map',
     'SavePerspectiveAction'   : 'Save current perspective',
     'ClearPerspectiveAction'  : 'Clear all perspectives',
-    'DiagnosticReportAction'  : 'Generate diagnostic report',
+    'DiagnosticReportAction'  : 'Diagnostic report',
 
     'FSLEyesFrame.closeViewPanel' : 'Close',
 
diff --git a/fsl/fsleyes/actions/diagnosticreport.py b/fsl/fsleyes/actions/diagnosticreport.py
index 853f42645..e1e0493d7 100644
--- a/fsl/fsleyes/actions/diagnosticreport.py
+++ b/fsl/fsleyes/actions/diagnosticreport.py
@@ -27,10 +27,21 @@ log = logging.getLogger(__name__)
 
 
 class DiagnosticReportAction(action.Action):
-    """
+    """The ``DiagnosticReportAction`` generates a JSON-formatted report file
+    containing information about the current state of *FSLeyes*. When the this
+    :class:`.Action` is run, the user is prompted to select a location to save
+    the file Then the report is generated, and written out to the specified
+    location.
     """
 
+    
     def __init__(self, overlayList, displayCtx, frame):
+        """Create a ``DiagnosticReportAction``.
+
+        :arg overlayList: The :class:`.OverlayList`.
+        :arg displayCtx:  The master :class:`.DisplayContext`.
+        :arg frame:       The :class:`.FSLEyesFrame`.
+        """
 
         action.Action.__init__(self, self.__action)
 
@@ -40,6 +51,17 @@ class DiagnosticReportAction(action.Action):
 
 
     def __action(self):
+        """This method is the guts of the ``DiagnosticReportAction``. It does
+        the following:
+
+          1. Prompts the user to select a location to save the report file.
+
+          2. Generates the report.
+
+          3. Formats the report as JSON.
+
+          4. Saves the report to the specified location.
+        """
 
         dlg = wx.FileDialog( 
             self.__frame,
@@ -64,8 +86,11 @@ class DiagnosticReportAction(action.Action):
             f.write(report)
 
 
-
     def __generateReport(self):
+        """Generates and returns a *report*, a hierarchical dictionary
+        containing information about the current system and *FSLeyes*
+        state.
+        """
 
         import fsl.version              as version
         import fsl.fsleyes.perspectives as perspectives
@@ -107,13 +132,101 @@ class DiagnosticReportAction(action.Action):
 
 
     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.
+        """
         
-        pass
+        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):
-        pass
+        """Creates and returns a dictionary containing informtion about
+        the given :class:`.ViewPanel`.
+        """ 
 
+        import fsl.fsleyes.views as views
+        
+        report = OrderedDict()
+        props  = viewPanel.getAllProperties()[0]
 
-    def __formatReport(self, reportDict):
+        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):
+        """Converts the given hierarchical dictionary to a JSON-formatted
+        string.
+        """
         return json.dumps(reportDict, indent=2)
diff --git a/fsl/fsleyes/displaycontext/group.py b/fsl/fsleyes/displaycontext/group.py
index dd9edf2bb..cadabd8be 100644
--- a/fsl/fsleyes/displaycontext/group.py
+++ b/fsl/fsleyes/displaycontext/group.py
@@ -147,6 +147,16 @@ class OverlayGroup(props.HasProperties):
         """
         return OverlayGroup(self, self.__displayCtx, self.__overlayList)
 
+
+    def __str__(self):
+        """Returns a string representation of this ``OverlayGroup``."""
+        return str([str(o) for o in self.overlays])
+
+    
+    def __repr__(self):
+        """Returns a string representation of this ``OverlayGroup``."""
+        return '[{}]'.format(', '.join([str(o) for o in self.overlays]))
+
             
     def addOverlay(self, overlay):
         """Add an overlay to this ``OverlayGroup``.
-- 
GitLab