Merge "Issue #2421 optimize color map loading. Change-Id: I871ddf0f3eabee0e27d858e2cfa897563875c304" into development
Former-commit-id:ccb9b15f8c
[formerlyf94bcf4776
] [formerlyeeee5c7948
] [formerlyc01eb85e53
[formerlyeeee5c7948
[formerly 7139b6fe32b6de8c87c96e3b55d6ad83f11b149a]]] Former-commit-id:c01eb85e53
Former-commit-id: 44f2874ed6741bb80dbe72b605f855a78f686c71 [formerly72a6650958
] Former-commit-id:18bbfeb4cb
This commit is contained in:
commit
54975835b5
4 changed files with 555 additions and 204 deletions
|
@ -47,14 +47,16 @@ import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* SOFTWARE HISTORY
|
* SOFTWARE HISTORY
|
||||||
* Date Ticket# Engineer Description
|
* Date Ticket# Engineer Description
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------- -------- ----------- --------------------------
|
||||||
* Feb 13, 2007 chammack Initial Creation.
|
* Feb 13, 2007 chammack Initial Creation.
|
||||||
* Aug 20, 2007 njensen Added listColorMaps().
|
* Aug 20, 2007 njensen Added listColorMaps().
|
||||||
* Aug 20, 2008 dglazesk JiBX to JaXB
|
* Aug 20, 2008 dglazesk JiBX to JaXB
|
||||||
* Aug 20, 2008 dglazesk Updated for new ColorMap interface
|
* Aug 20, 2008 dglazesk Updated for new ColorMap interface
|
||||||
* Jun 10, 2013 2075 njensen Added listColorMapFiles(subdirectory)
|
* Jun 10, 2013 2075 njensen Added listColorMapFiles(subdirectory)
|
||||||
* Aug 06, 2013 2210 njensen Moved colormaps to common_static
|
* Aug 06, 2013 2210 njensen Moved colormaps to common_static
|
||||||
|
* Sep 18, 2013 2421 bsteffen Moved some listing capabilities into
|
||||||
|
* ColorMapTree.
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -64,9 +66,9 @@ import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
|
||||||
public class ColorMapLoader {
|
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 = "";
|
private static final String sharedMutex = "";
|
||||||
|
|
||||||
|
@ -227,15 +229,6 @@ public class ColorMapLoader {
|
||||||
+ subDirectory);
|
+ subDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all the colormaps found in the system
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static LocalizationFile[] listColorMapFiles() {
|
|
||||||
return internalListColorMapFiles(DIR_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String shortenName(LocalizationFile file) {
|
public static String shortenName(LocalizationFile file) {
|
||||||
String name = file.getName()
|
String name = file.getName()
|
||||||
.replace(DIR_NAME + IPathManager.SEPARATOR, "")
|
.replace(DIR_NAME + IPathManager.SEPARATOR, "")
|
||||||
|
@ -258,7 +251,7 @@ public class ColorMapLoader {
|
||||||
*/
|
*/
|
||||||
public static String[] listColorMaps(
|
public static String[] listColorMaps(
|
||||||
LocalizationContext.LocalizationLevel aType) {
|
LocalizationContext.LocalizationLevel aType) {
|
||||||
LocalizationFile[] files = listColorMapFiles();
|
LocalizationFile[] files = internalListColorMapFiles(DIR_NAME);
|
||||||
String[] cmaps = new String[files.length];
|
String[] cmaps = new String[files.length];
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
cmaps[i] = shortenName(files[i]);
|
cmaps[i] = shortenName(files[i]);
|
||||||
|
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- ----------- --------------------------
|
||||||
|
* Sep 18, 2013 2421 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @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<ColorMapTree> 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<ColorMapTree> getSubTrees() {
|
||||||
|
synchronized (subTreesLock) {
|
||||||
|
if (subTrees == null) {
|
||||||
|
subTrees = new ArrayList<ColorMapTree>();
|
||||||
|
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<ColorMapTree>(subTrees);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return all color map files within this level of the tree.
|
||||||
|
*/
|
||||||
|
public List<LocalizationFile> getColorMapFiles() {
|
||||||
|
if (context == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
List<LocalizationFile> result = new ArrayList<LocalizationFile>();
|
||||||
|
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<ColorMapTree> treeRef;
|
||||||
|
|
||||||
|
private FileChangeListener(ColorMapTree tree) {
|
||||||
|
treeRef = new WeakReference<ColorMapTree>(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileUpdated(FileUpdatedMessage message) {
|
||||||
|
ColorMapTree tree = treeRef.get();
|
||||||
|
if (tree == null) {
|
||||||
|
LocalizationNotificationObserver.getInstance()
|
||||||
|
.removeGlobalFileChangeObserver(this);
|
||||||
|
} else {
|
||||||
|
tree.handleUpdate(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- ----------- --------------------------
|
||||||
|
* Sep 18, 2013 2421 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ColorMapTreeFactory {
|
||||||
|
|
||||||
|
private static ColorMapTree baseTree;
|
||||||
|
|
||||||
|
private static Object baseTreeLock = new Object();
|
||||||
|
|
||||||
|
private static final Map<LocalizationLevel, ColorMapTree> treesByLevel = new HashMap<LocalizationLevel, ColorMapTree>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,17 +19,20 @@
|
||||||
**/
|
**/
|
||||||
package com.raytheon.viz.ui.dialogs;
|
package com.raytheon.viz.ui.dialogs;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
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.SWT;
|
||||||
|
import org.eclipse.swt.events.MenuEvent;
|
||||||
|
import org.eclipse.swt.events.MenuListener;
|
||||||
import org.eclipse.swt.events.SelectionAdapter;
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
import org.eclipse.swt.graphics.Point;
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
@ -41,8 +44,17 @@ import org.eclipse.swt.widgets.MenuItem;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
|
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.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.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.exception.VizException;
|
||||||
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
|
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
|
||||||
|
|
||||||
|
@ -52,9 +64,10 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
|
||||||
* <pre>
|
* <pre>
|
||||||
*
|
*
|
||||||
* SOFTWARE HISTORY
|
* SOFTWARE HISTORY
|
||||||
* Date Ticket# Engineer Description
|
* Date Ticket# Engineer Description
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------- -------- ----------- --------------------------
|
||||||
* Jul 26, 2010 mschenke Initial creation
|
* Jul 26, 2010 mschenke Initial creation
|
||||||
|
* Sep 18, 2013 2421 bsteffen Use ColorMapTree for asyncronous loading.
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -64,88 +77,15 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
|
||||||
|
|
||||||
public class ColormapComp {
|
public class ColormapComp {
|
||||||
|
|
||||||
|
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||||
|
.getHandler(ColormapComp.class);
|
||||||
|
|
||||||
public static interface IColormapCompChangeListener {
|
public static interface IColormapCompChangeListener {
|
||||||
public void colormapChanged(String colorMap);
|
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<ColorMapMenuItem> children = childMap.get(parent);
|
|
||||||
if (children == null) {
|
|
||||||
children = new ArrayList<ColorMapMenuItem>();
|
|
||||||
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<IColormapCompChangeListener> listeners = new HashSet<IColormapCompChangeListener>();
|
private Set<IColormapCompChangeListener> listeners = new HashSet<IColormapCompChangeListener>();
|
||||||
|
|
||||||
private Map<Menu, List<ColorMapMenuItem>> childMap = new HashMap<Menu, List<ColorMapMenuItem>>();
|
|
||||||
|
|
||||||
private Button cmapButton;
|
private Button cmapButton;
|
||||||
|
|
||||||
private Shell shell;
|
private Shell shell;
|
||||||
|
@ -211,54 +151,8 @@ public class ColormapComp {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmapPopupMenu.setVisible(false);
|
cmapPopupMenu.setVisible(false);
|
||||||
|
cmapPopupMenu.addMenuListener(new MenuPopulator(cmapPopupMenu,
|
||||||
LocalizationFile[] files = ColorMapLoader.listColorMapFiles();
|
ColorMapTreeFactory.getBaseTree()));
|
||||||
for (LocalizationFile file : files) {
|
|
||||||
|
|
||||||
List<String> actualItems = new ArrayList<String>();
|
|
||||||
|
|
||||||
String[] split = ColorMapLoader.shortenName(file).split("[/\\\\]"); // Win32
|
|
||||||
|
|
||||||
Menu lastParent = cmapPopupMenu;
|
|
||||||
|
|
||||||
// Just to be sure, get rid of empty items
|
|
||||||
for (String text : split) {
|
|
||||||
if (text.trim().equals("") == false) {
|
|
||||||
actualItems.add(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < actualItems.size(); ++i) {
|
|
||||||
if (i == actualItems.size() - 1) {
|
|
||||||
// leaf node
|
|
||||||
new ColorMapMenuItem(lastParent, null, file,
|
|
||||||
actualItems.get(i));
|
|
||||||
} else {
|
|
||||||
String text = actualItems.get(i);
|
|
||||||
boolean found = false;
|
|
||||||
// traverse lastParent's children to see if we already exist
|
|
||||||
List<ColorMapMenuItem> children = childMap.get(lastParent);
|
|
||||||
if (children == null) {
|
|
||||||
children = new ArrayList<ColorMapMenuItem>();
|
|
||||||
childMap.put(lastParent, children);
|
|
||||||
}
|
|
||||||
for (ColorMapMenuItem item : children) {
|
|
||||||
if (item.subMenu != null && item.text.equals(text)) {
|
|
||||||
found = true;
|
|
||||||
lastParent = item.subMenu;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
Menu cmapParent = lastParent;
|
|
||||||
lastParent = new Menu(shell, SWT.DROP_DOWN);
|
|
||||||
new ColorMapMenuItem(cmapParent, lastParent, null, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortMenus(cmapPopupMenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -284,60 +178,6 @@ public class ColormapComp {
|
||||||
refreshItems();
|
refreshItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param parent
|
|
||||||
*/
|
|
||||||
private void sortMenus(Menu parent) {
|
|
||||||
List<ColorMapMenuItem> children = childMap.get(parent);
|
|
||||||
if (children == null || children.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(children, new Comparator<ColorMapMenuItem>() {
|
|
||||||
@Override
|
|
||||||
public int compare(ColorMapMenuItem o1, ColorMapMenuItem o2) {
|
|
||||||
// catch user menu item
|
|
||||||
if (o1.text.toUpperCase().equals("USER")) {
|
|
||||||
// user is always last
|
|
||||||
return 1;
|
|
||||||
} else if (o2.text.toUpperCase().equals("USER")) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// catch site menu item
|
|
||||||
if (o1.text.toUpperCase().equals("SITE")) {
|
|
||||||
// site is after all but user ( user gets caught first )
|
|
||||||
return 1;
|
|
||||||
} else if (o2.text.toUpperCase().equals("SITE")) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all other menu items
|
|
||||||
if (o1.subMenu != null && o2.subMenu == null) {
|
|
||||||
// Show those with submenus first
|
|
||||||
return -1;
|
|
||||||
} else if (o1.subMenu == null && o2.subMenu != null) {
|
|
||||||
// Show those with submenus first
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
// else look at text
|
|
||||||
return o1.text.toLowerCase().compareTo(
|
|
||||||
o2.text.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (ColorMapMenuItem child : children) {
|
|
||||||
child.initializeComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ColorMapMenuItem child : children) {
|
|
||||||
if (child.subMenu != null) {
|
|
||||||
sortMenus(child.subMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Menu getMenu() {
|
public Menu getMenu() {
|
||||||
return cmapPopupMenu;
|
return cmapPopupMenu;
|
||||||
}
|
}
|
||||||
|
@ -348,4 +188,160 @@ public class ColormapComp {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void changeColormap(String name) {
|
||||||
|
if (cmapButton != null) {
|
||||||
|
cmapButton.setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
params.setColorMap(ColorMapLoader.loadColorMap(name));
|
||||||
|
cap.notifyResources();
|
||||||
|
for (IColormapCompChangeListener listener : listeners) {
|
||||||
|
listener.colormapChanged(name);
|
||||||
|
}
|
||||||
|
} catch (VizException e) {
|
||||||
|
statusHandler.handle(Priority.ERROR, "Unable to change colormap.",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to recursively populate a menu based off the contents of a
|
||||||
|
* {@link ColorMapTree}. The menu is not populated until it is shown. This
|
||||||
|
* is also an eclipse Job that will automatically try to prefetch some
|
||||||
|
* information from the tree for faster population.
|
||||||
|
*/
|
||||||
|
private class MenuPopulator extends Job implements MenuListener {
|
||||||
|
|
||||||
|
private final Menu menu;
|
||||||
|
|
||||||
|
private final ColorMapTree tree;
|
||||||
|
|
||||||
|
public MenuPopulator(Menu menu, ColorMapTree tree) {
|
||||||
|
super("Loading Color Maps");
|
||||||
|
this.menu = menu;
|
||||||
|
this.tree = tree;
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void menuHidden(MenuEvent e) {
|
||||||
|
/* Do Nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the subTrees that will be displayed and call
|
||||||
|
* optimizeIsEmpty(). isEmpty() is usually the slowest operation in
|
||||||
|
* menuShown because it can go recursive. optimizeIsEmpty ensures that
|
||||||
|
* future calls(from menuShown) are as fast as possible.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected IStatus run(IProgressMonitor monitor) {
|
||||||
|
for (ColorMapTree subTree : tree.getSubTrees()) {
|
||||||
|
subTree.optimizeIsEmpty();
|
||||||
|
}
|
||||||
|
for (ColorMapTree subTree : getLevelTrees()) {
|
||||||
|
subTree.optimizeIsEmpty();
|
||||||
|
}
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the menu with items from the tree. Always create menus at the
|
||||||
|
* top even if there are other items
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void menuShown(MenuEvent e) {
|
||||||
|
int index = 0;
|
||||||
|
List<ColorMapTree> subTrees = tree.getSubTrees();
|
||||||
|
Collections.sort(subTrees, new Comparator<ColorMapTree>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ColorMapTree tree1, ColorMapTree tree2) {
|
||||||
|
return tree1.getName().compareToIgnoreCase(tree2.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
for (ColorMapTree subTree : subTrees) {
|
||||||
|
if (!subTree.isEmpty()) {
|
||||||
|
addSubTree(subTree, index++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<LocalizationFile> files = tree.getColorMapFiles();
|
||||||
|
Collections.sort(files, new Comparator<LocalizationFile>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(LocalizationFile file1,
|
||||||
|
LocalizationFile file2) {
|
||||||
|
return file1.getName().compareToIgnoreCase(file2.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
for (LocalizationFile file : files) {
|
||||||
|
addFile(file, index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ColorMapTree subTree : getLevelTrees()) {
|
||||||
|
if (!subTree.isEmpty()) {
|
||||||
|
addSubTree(subTree, index++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.removeMenuListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root menu should show not only the base tree, but also an
|
||||||
|
* additional menu item for each localization level(SITE, USER ...),
|
||||||
|
* this method gets those trees when they are needed so menu items can
|
||||||
|
* be added.
|
||||||
|
*/
|
||||||
|
private List<ColorMapTree> getLevelTrees() {
|
||||||
|
if (menu == cmapPopupMenu) {
|
||||||
|
List<ColorMapTree> trees = new ArrayList<ColorMapTree>();
|
||||||
|
IPathManager pm = PathManagerFactory.getPathManager();
|
||||||
|
LocalizationLevel[] levels = pm.getAvailableLevels();
|
||||||
|
for (LocalizationLevel level : levels) {
|
||||||
|
if (level != LocalizationLevel.BASE) {
|
||||||
|
ColorMapTree tree = ColorMapTreeFactory
|
||||||
|
.getTreeForLevel(level);
|
||||||
|
trees.add(tree);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trees;
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSubTree(ColorMapTree tree, int index) {
|
||||||
|
MenuItem item = new MenuItem(menu, SWT.CASCADE, index);
|
||||||
|
item.setText(tree.getName());
|
||||||
|
Menu subMenu = new Menu(shell, SWT.DROP_DOWN);
|
||||||
|
item.setMenu(subMenu);
|
||||||
|
subMenu.addMenuListener(new MenuPopulator(subMenu, tree));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFile(LocalizationFile file, int index) {
|
||||||
|
MenuItem item = new MenuItem(menu, SWT.None, index);
|
||||||
|
final String name = ColorMapLoader.shortenName(file);
|
||||||
|
int start = name.lastIndexOf(PathManager.SEPARATOR);
|
||||||
|
if (start >= 0) {
|
||||||
|
item.setText(name.substring(start + 1));
|
||||||
|
} else {
|
||||||
|
item.setText(name);
|
||||||
|
}
|
||||||
|
item.addSelectionListener(new SelectionAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
changeColormap(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue