From 593e70e58ea7551e57e817ddb08d70c34673bb04 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Tue, 23 Jun 2015 17:27:41 +0100
Subject: [PATCH] Load lut feature is working. Simplified colour map/lut
 installation code - I'm still not entirely happy with any of this code.

---
 fsl/data/strings.py                      |  1 +
 fsl/fslview/colourmaps.py                | 88 ++++++++++--------------
 fsl/fslview/controls/lookuptablepanel.py | 43 ++++++++----
 3 files changed, 65 insertions(+), 67 deletions(-)

diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index c933d5210..b1f07c015 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -116,6 +116,7 @@ titles = TypeDict({
     'LutLabelDialog'        : 'New LUT label',
     'NewLutDialog'          : 'New LUT',
 
+    'LookupTablePanel.loadLut'     : 'Select a lookup table file',
     'LookupTablePanel.labelExists' : 'Label already exists',
 })
 
diff --git a/fsl/fslview/colourmaps.py b/fsl/fslview/colourmaps.py
index 6bc98900e..fcf3a7c37 100644
--- a/fsl/fslview/colourmaps.py
+++ b/fsl/fslview/colourmaps.py
@@ -133,7 +133,6 @@ and generating/manipulating colours.:
 
 import logging
 import glob
-import shutil
 import bisect
 import os.path as op
 
@@ -250,8 +249,6 @@ class LutLabel(object):
 class LookupTable(props.HasProperties):
     """Class which encapsulates a list of labels and associated colours and
     names, defining a lookup table to be used for colouring label images.
-
-    :attr:`lutFile`
     """
 
     
@@ -274,12 +271,10 @@ class LookupTable(props.HasProperties):
     
     def __init__(self, name, lutFile=None):
         
-        self.name    = name
-        self.lutFile = lutFile
+        self.name = name
 
         if lutFile is not None:
             self._load(lutFile)
-            self.saved = True
         
 
     def __len__(self):
@@ -385,20 +380,10 @@ class LookupTable(props.HasProperties):
                 self.set(label, name=lName, colour=(r, g, b), enabled=True)
 
 
-    def save(self, lutFile=None):
+    def _save(self, lutFile):
         """Saves this ``LookupTable`` instance to the specified ``lutFile``.
-
-        If ``lutFile`` is not provided, saves the lut information to the
-        ``lutFile`` specified in :meth:`__init__`, or on a previous call to
-        this method.
         """
 
-        if lutFile is None:
-            lutFile = self.lutFile
-
-        if lutFile is None:
-            raise ValueError('No lookup table file specified')
-
         with open(lutFile, 'wt') as f:
             for label in self.labels:
                 value  = label.value()
@@ -410,9 +395,6 @@ class LookupTable(props.HasProperties):
 
                 f.write('{}\n'.format(line))
 
-        self.lutFile = lutFile
-        self.saved   = True
-
 
 def init():
     """This function must be called before any of the other functions in this
@@ -522,7 +504,7 @@ def registerColourMap(cmapFile, overlayList=None, displayCtx=None, name=None):
 
     mplcm.register_cmap(name, cmap)
 
-    _cmaps[name] = _Map(name, cmap, cmapFile, False)
+    _cmaps[name] = _Map(name, cmap, None, False)
 
     # TODO Any new Opts types which have a colour
     #      map will need to be patched here
@@ -586,8 +568,14 @@ def registerLookupTable(lut, overlayList=None, displayCtx=None, name=None):
     else:
         if name is None:
             name = lut.name
+        else:
+            lut.name = name
+
+    # Even though the lut may have been loaded from
+    # a file, it has not necessarily been installed
+    lut.saved = False
             
-    _luts[name] = _Map(name, lut, lutFile, False)
+    _luts[name] = _Map(name, lut, None, False)
 
     log.debug('Patching LabelOpts classes to support '
               'new LookupTable {}'.format(name))
@@ -607,6 +595,8 @@ def registerLookupTable(lut, overlayList=None, displayCtx=None, name=None):
 
     # and for any future label overlays
     fsldisplay.LabelOpts.lut.addChoice(lut, lut.name)
+    
+    return lut
 
 
 def getLookupTables():
@@ -651,36 +641,24 @@ def isLookupTableInstalled(lutName):
 def installColourMap(cmapName):
     """Attempts to install a previously registered colourmap into the
     ``fsl/fslview/colourmaps`` directory.
-
-    A ``KeyError`` is raised if the colourmap is not registered, a
-    ``RuntimeError`` if the colourmap cannot be installed, or an
-    ``IOError`` if the colourmap file cannot be copied.
     """
 
     # keyerror if not registered
     cmap = _cmaps[cmapName]
 
-    # built-in, or already installed
-    if cmap.installed:
-        return
-
-    # cmap has been incorrectly registered
-    if cmap.mapFile is None:
-        raise RuntimeError('Colour map {} appears to have been '
-                           'incorrectly registered'.format(cmapName))
-
-    destfile = op.join(op.dirname(__file__),
-                       'colourmaps',
-                       '{}.cmap'.format(cmapName))
+    if cmap.mapFile is not None:
+        destFile = cmap.mapFile
+    else:
+        destFile = op.join(op.dirname(__file__),
+                           'colourmaps',
+                           '{}.cmap'.format(cmapName))
 
-    # destination file already exists
-    if op.exists(destfile):
-        raise RuntimeError('Destination file for colour map {} already '
-                           'exists: {}'.format(cmapName, destfile))
+    log.debug('Installing colour map {} to {}'.format(cmapName, destFile))
 
-    log.debug('Installing colour map {} to {}'.format(cmapName, destfile))
-        
-    shutil.copyfile(cmap.mapFile, destfile)
+    # I think the colors attribute is only
+    # available on ListedColormap instances ...
+    data = cmap.mapObj.colors
+    np.savetxt(destFile, data, '%0.6f')
     
     cmap.installed = True
 
@@ -688,21 +666,25 @@ def installColourMap(cmapName):
 def installLookupTable(lutName):
     """Attempts to install/save a previously registered lookup table into
     the ``fsl/fslview/luts`` directory.
-
-    A ``KeyError`` is raised if the lookup table is not registered, or an
-    ``IOError`` if the lookup table cannot be saved. 
     """
     
     # keyerror if not registered
     lut = _luts[lutName]
 
-    if lut.mapFile is not None: destFile = lut.mapFile
-    else:                       op.join(_lutDir, '{}.lut'.format(lutName))
+    if lut.mapFile is not None:
+        destFile = lut.mapFile
+    else:
+        destFile = op.join(
+            _lutDir,
+            '{}.lut'.format(lutName.lower().replace(' ', '_')))
+
+    log.debug('Installing lookup table {} to {}'.format(lutName, destFile))
 
-    lut.mapObj.save(destFile)
+    lut.mapObj._save(destFile)
 
-    lut.mapFile   = destFile
-    lut.installed = True
+    lut.mapFile      = destFile
+    lut.installed    = True
+    lut.mapObj.saved = True
     
 
 ###############
diff --git a/fsl/fslview/controls/lookuptablepanel.py b/fsl/fslview/controls/lookuptablepanel.py
index 2ee5456d1..72f20ecc3 100644
--- a/fsl/fslview/controls/lookuptablepanel.py
+++ b/fsl/fslview/controls/lookuptablepanel.py
@@ -5,6 +5,7 @@
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
 
+import os
 import logging
 
 import wx
@@ -88,18 +89,7 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
 
         fslpanel.FSLViewPanel.__init__(self, parent, overlayList, displayCtx)
 
-        # If non-lut image is shown, just show a message
-
-        # Overlay name
-        # Change lookup table
-        # Add label
-        # New lut
-        # Copy lut
-        # Save lut
-        # Load lut
-
-        self.__controlRow = wx.Panel(self)
-
+        self.__controlRow    = wx.Panel(self)
         self.__disabledLabel = wx.StaticText(self,
                                              style=wx.ALIGN_CENTER_VERTICAL |
                                                    wx.ALIGN_CENTER_HORIZONTAL)
@@ -178,6 +168,8 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
         
     def destroy(self):
 
+        fslpanel.FSLViewPanel.destroy(self)
+
         self._overlayList.removeListener('overlays',        self._name)
         self._displayCtx .removeListener('selectedOverlay', self._name)
 
@@ -373,11 +365,34 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
 
     
     def __onLoadLut(self, ev):
-        pass
 
+        nameDlg = NewLutDialog(self.GetTopLevelParent())
+        
+        if nameDlg.ShowModal() != wx.ID_OK:
+            return
+        
+        fileDlg = wx.FileDialog(wx.GetApp().GetTopWindow(),
+                                message=strings.titles[self, 'loadLut'],
+                                defaultDir=os.getcwd(),
+                                style=wx.FD_OPEN)
+
+        if fileDlg.ShowModal() != wx.ID_OK:
+            return
+
+        name = nameDlg.name
+        path = fileDlg.GetPath()
+
+        lut = fslcmaps.registerLookupTable(path,
+                                           self._overlayList,
+                                           self._displayCtx,
+                                           name)
+
+        if self.__selectedOpts is not None:
+            self.__selectedOpts.lut = lut
+        
     
     def __onSaveLut(self, ev):
-        pass 
+        fslcmaps.installLookupTable(self.__selectedLut.name)
 
     
     def __onLabelAdd(self, ev):
-- 
GitLab