diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapLoader.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapLoader.java
index 187727372f..02e8949e22 100644
--- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapLoader.java
+++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapLoader.java
@@ -47,14 +47,16 @@ import com.raytheon.uf.viz.core.exception.VizException;
*
*
* SOFTWARE HISTORY
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * Feb 13, 2007 chammack Initial Creation.
- * Aug 20, 2007 njensen Added listColorMaps().
- * Aug 20, 2008 dglazesk JiBX to JaXB
- * Aug 20, 2008 dglazesk Updated for new ColorMap interface
- * Jun 10, 2013 2075 njensen Added listColorMapFiles(subdirectory)
- * Aug 06, 2013 2210 njensen Moved colormaps to common_static
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Feb 13, 2007 chammack Initial Creation.
+ * Aug 20, 2007 njensen Added listColorMaps().
+ * Aug 20, 2008 dglazesk JiBX to JaXB
+ * Aug 20, 2008 dglazesk Updated for new ColorMap interface
+ * Jun 10, 2013 2075 njensen Added listColorMapFiles(subdirectory)
+ * Aug 06, 2013 2210 njensen Moved colormaps to common_static
+ * Sep 18, 2013 2421 bsteffen Moved some listing capabilities into
+ * ColorMapTree.
*
*
*
@@ -64,9 +66,9 @@ import com.raytheon.uf.viz.core.exception.VizException;
public class ColorMapLoader {
- private static final String EXTENSION = ".cmap";
+ public static final String EXTENSION = ".cmap";
- private static final String DIR_NAME = "colormaps";
+ public static final String DIR_NAME = "colormaps";
private static final String sharedMutex = "";
@@ -227,15 +229,6 @@ public class ColorMapLoader {
+ subDirectory);
}
- /**
- * Lists all the colormaps found in the system
- *
- * @return
- */
- public static LocalizationFile[] listColorMapFiles() {
- return internalListColorMapFiles(DIR_NAME);
- }
-
public static String shortenName(LocalizationFile file) {
String name = file.getName()
.replace(DIR_NAME + IPathManager.SEPARATOR, "")
@@ -258,7 +251,7 @@ public class ColorMapLoader {
*/
public static String[] listColorMaps(
LocalizationContext.LocalizationLevel aType) {
- LocalizationFile[] files = listColorMapFiles();
+ LocalizationFile[] files = internalListColorMapFiles(DIR_NAME);
String[] cmaps = new String[files.length];
for (int i = 0; i < files.length; i++) {
cmaps[i] = shortenName(files[i]);
diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTree.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTree.java
new file mode 100644
index 0000000000..bfb2895859
--- /dev/null
+++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTree.java
@@ -0,0 +1,267 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.viz.core.drawables;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.raytheon.uf.common.localization.FileUpdatedMessage;
+import com.raytheon.uf.common.localization.ILocalizationFileObserver;
+import com.raytheon.uf.common.localization.IPathManager;
+import com.raytheon.uf.common.localization.LocalizationContext;
+import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
+import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
+import com.raytheon.uf.common.localization.LocalizationFile;
+import com.raytheon.uf.common.localization.LocalizationNotificationObserver;
+
+/**
+ * ColorMapTree represents the directory structure of colormaps directory. The
+ * levels of a Tree can represent a {@link LocalizationLevel}, a
+ * {@link LocalizationContext} or a localization directory.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Sep 18, 2013 2421 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+public class ColorMapTree {
+
+ private final String path;
+
+ private final IPathManager pathManager;
+
+ private final LocalizationLevel level;
+
+ private final LocalizationContext context;
+
+ private final Object filesLock = new Object();
+
+ private LocalizationFile[] files;
+
+ private final Object subTreesLock = new Object();
+
+ private List subTrees;
+
+ /**
+ * Create a tree for the given path and context. The tree will represent the
+ * colormap files that exist at the path within the context.
+ */
+ public ColorMapTree(IPathManager pathManager, LocalizationContext context,
+ String path) {
+ this.path = path;
+ this.pathManager = pathManager;
+ this.level = null;
+ this.context = context;
+ }
+
+ /**
+ * Create a tree for the given path and level. The tree will have the same
+ * name as the level and will have a subtree for each context that exists at
+ * that level. Each context tree will represent the colormap files that
+ * exist at the path.
+ */
+ public ColorMapTree(IPathManager pathManager, LocalizationLevel level,
+ String path) {
+ this.path = path;
+ this.pathManager = pathManager;
+ this.level = level;
+ this.context = null;
+ LocalizationNotificationObserver.getInstance()
+ .addGlobalFileChangeObserver(new FileChangeListener(this));
+ }
+
+ /**
+ * For a tree based only on a {@link LocalizationLevel} this returns the
+ * name of the level, for a tree at the root directory of a context this
+ * will be the name of the {@link LocalizationContext} and for a tree
+ * representing a subdirectory this will be the directory name.
+ */
+ public String getName() {
+ if (context == null) {
+ return level.name();
+ } else {
+ int start = path.lastIndexOf(IPathManager.SEPARATOR);
+ if (start <= 0) {
+ return context.getContextName();
+ }
+ return path.substring(start + 1);
+ }
+ }
+
+ /**
+ * For a tree based on a {@link LocalizationLevel} this returns a tree for
+ * each context at the level. Otherwise it returns a tree for each
+ * subdirectory of this tree.
+ */
+ public List getSubTrees() {
+ synchronized (subTreesLock) {
+ if (subTrees == null) {
+ subTrees = new ArrayList();
+ if (context == null) {
+ for (String context : pathManager.getContextList(level)) {
+ LocalizationContext ctx = pathManager.getContext(
+ LocalizationType.COMMON_STATIC, level);
+ ctx.setContextName(context);
+ subTrees.add(new ColorMapTree(pathManager, ctx, path));
+ }
+ } else {
+ for (LocalizationFile file : requestFiles()) {
+ if (file.isDirectory() && !path.equals(file.getName())) {
+ subTrees.add(new ColorMapTree(pathManager, context,
+ file.getName()));
+ }
+ }
+ }
+ }
+ return new ArrayList(subTrees);
+ }
+ }
+
+ /**
+ *
+ * @return all color map files within this level of the tree.
+ */
+ public List getColorMapFiles() {
+ if (context == null) {
+ return Collections.emptyList();
+ } else {
+ List result = new ArrayList();
+ for (LocalizationFile file : requestFiles()) {
+ if (!file.isDirectory()) {
+ result.add(file);
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ *
+ * @return true if this tree does not contain any color map files or any
+ * subtrees which contain color map files(recursively).
+ */
+ public boolean isEmpty() {
+ if (getColorMapFiles().isEmpty()) {
+ for (ColorMapTree tree : getSubTrees()) {
+ if (!tree.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Optimize the internal structure so future {@link #isEmpty()} calls are
+ * fast. isEmpty() is a slow operations on trees with many empty subtrees,
+ * so this can be called in the background to enable faster calls to isEmpty
+ * when it is needed. In cases where isEmpty does not need extra data or is
+ * already optimized this call should complete very quickly.
+ */
+ public void optimizeIsEmpty() {
+ /* isEmpty caches data in the subtrees so nothing else is needed. */
+ isEmpty();
+ }
+
+ /**
+ * This method will receive a message for every localization file in all
+ * contexts. It must filter by path and by level and/or context.
+ */
+ protected void handleUpdate(FileUpdatedMessage message) {
+ if (message.getFileName().startsWith(path)) {
+ LocalizationContext context = message.getContext();
+ if (context.getLocalizationLevel().equals(level)) {
+ synchronized (subTreesLock) {
+ if (subTrees != null) {
+ for (ColorMapTree subTree : subTrees) {
+ if (subTree.getName().equals(
+ context.getContextName())) {
+ subTree.handleUpdate(message);
+ return;
+ }
+ }
+ subTrees.add(new ColorMapTree(pathManager, context,
+ path));
+ }
+ }
+ } else if (context.equals(context)) {
+ synchronized (filesLock) {
+ files = null;
+ }
+ synchronized (subTreesLock) {
+ subTrees = null;
+ }
+ }
+ }
+ }
+
+ private LocalizationFile[] requestFiles() {
+ synchronized (filesLock) {
+ if (files == null) {
+ files = pathManager
+ .listFiles(context, path,
+ new String[] { ColorMapLoader.EXTENSION },
+ false, false);
+ }
+ return files;
+ }
+ }
+
+ /**
+ * {@link WeakReference} based listener which automatically removes itself
+ * when a notification arrives and the {@link ColorMapTree} has been garbage
+ * collected.
+ */
+ private static class FileChangeListener implements
+ ILocalizationFileObserver {
+
+ private final Reference treeRef;
+
+ private FileChangeListener(ColorMapTree tree) {
+ treeRef = new WeakReference(tree);
+ }
+
+ @Override
+ public void fileUpdated(FileUpdatedMessage message) {
+ ColorMapTree tree = treeRef.get();
+ if (tree == null) {
+ LocalizationNotificationObserver.getInstance()
+ .removeGlobalFileChangeObserver(this);
+ } else {
+ tree.handleUpdate(message);
+ }
+
+ }
+
+ }
+
+}
diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTreeFactory.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTreeFactory.java
new file mode 100644
index 0000000000..bfca3db606
--- /dev/null
+++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/ColorMapTreeFactory.java
@@ -0,0 +1,95 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.viz.core.drawables;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.raytheon.uf.common.localization.IPathManager;
+import com.raytheon.uf.common.localization.LocalizationContext;
+import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
+import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
+import com.raytheon.uf.common.localization.PathManagerFactory;
+
+/**
+ * Factory which can provide cached versions of {@link ColorMapTree} objects.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Sep 18, 2013 2421 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+
+public class ColorMapTreeFactory {
+
+ private static ColorMapTree baseTree;
+
+ private static Object baseTreeLock = new Object();
+
+ private static final Map treesByLevel = new HashMap();
+
+ private static Object treesByLevelLock = new Object();
+
+ /**
+ * Get a tree for the BASE localization context. This tree will be different
+ * from the tree returned by getTreeForLevel(LocalizationLevel.BASE) because
+ * it will not be for the BASE level but instead is for the BASE context.
+ *
+ */
+ public static ColorMapTree getBaseTree() {
+ synchronized (baseTreeLock) {
+ if(baseTree == null){
+ IPathManager pm = PathManagerFactory.getPathManager();
+ LocalizationContext baseContext = pm.getContext(
+ LocalizationType.COMMON_STATIC, LocalizationLevel.BASE);
+ baseTree = new ColorMapTree(pm, baseContext,
+ ColorMapLoader.DIR_NAME);
+ }
+ return baseTree;
+ }
+
+ }
+
+ /**
+ * Return a {@link ColorMapTree}Tree for the provided level. The tree will
+ * have the same name as the level and will have a subtree for each context
+ * that exists at that level.
+ */
+ public static ColorMapTree getTreeForLevel(LocalizationLevel level) {
+ synchronized (treesByLevelLock) {
+ ColorMapTree tree = treesByLevel.get(level);
+ if (tree == null) {
+ IPathManager pm = PathManagerFactory.getPathManager();
+ tree = new ColorMapTree(pm, level, ColorMapLoader.DIR_NAME);
+ treesByLevel.put(level, tree);
+ }
+ return tree;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/ColormapComp.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/ColormapComp.java
index 0d27ab86db..134c4514fc 100644
--- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/ColormapComp.java
+++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/ColormapComp.java
@@ -19,17 +19,20 @@
**/
package com.raytheon.viz.ui.dialogs;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
@@ -41,8 +44,17 @@ import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
+import com.raytheon.uf.common.localization.IPathManager;
+import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
import com.raytheon.uf.common.localization.LocalizationFile;
+import com.raytheon.uf.common.localization.PathManager;
+import com.raytheon.uf.common.localization.PathManagerFactory;
+import com.raytheon.uf.common.status.IUFStatusHandler;
+import com.raytheon.uf.common.status.UFStatus;
+import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.drawables.ColorMapLoader;
+import com.raytheon.uf.viz.core.drawables.ColorMapTree;
+import com.raytheon.uf.viz.core.drawables.ColorMapTreeFactory;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
@@ -52,9 +64,10 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
*
*
* SOFTWARE HISTORY
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * Jul 26, 2010 mschenke Initial creation
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Jul 26, 2010 mschenke Initial creation
+ * Sep 18, 2013 2421 bsteffen Use ColorMapTree for asyncronous loading.
*
*
*
@@ -64,88 +77,15 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
public class ColormapComp {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(ColormapComp.class);
+
public static interface IColormapCompChangeListener {
public void colormapChanged(String colorMap);
}
- private class ColorMapMenuItem {
-
- /** null if not leaf node */
- private LocalizationFile cmapFile;
-
- private Menu subMenu;
-
- private MenuItem actualItem;
-
- private Menu parent;
-
- private String text;
-
- /**
- * @param parent
- * @param style
- */
- public ColorMapMenuItem(Menu parent, Menu subMenu,
- LocalizationFile cmapFile, String text) {
- this.parent = parent;
- this.subMenu = subMenu;
- this.cmapFile = cmapFile;
- this.text = text;
-
- List children = childMap.get(parent);
- if (children == null) {
- children = new ArrayList();
- childMap.put(parent, children);
- }
- children.add(this);
- }
-
- public void initializeComponents() {
- actualItem = new MenuItem(parent, subMenu == null ? SWT.NONE
- : SWT.CASCADE);
- actualItem.setText(text);
- if (subMenu != null) {
- actualItem.setMenu(subMenu);
- }
-
- actualItem.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (cmapFile != null) {
- if (cmapButton != null) {
- cmapButton.setText(cmapFile.getName()
- .replace("colormaps" + File.separator, "")
- .replace(".cmap", ""));
- }
-
- try {
- String shortName = ColorMapLoader
- .shortenName(cmapFile);
- params.setColorMap(ColorMapLoader
- .loadColorMap(shortName));
- cap.notifyResources();
-
- for (IColormapCompChangeListener listener : listeners) {
- listener.colormapChanged(shortName);
- }
- } catch (VizException e1) {
- e1.printStackTrace();
- }
- }
- }
- });
- }
-
- public Menu getSubMenu() {
- return subMenu;
- }
-
- }
-
private Set listeners = new HashSet();
- private Map