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> childMap = new HashMap>(); - private Button cmapButton; private Shell shell; @@ -211,54 +151,8 @@ public class ColormapComp { } cmapPopupMenu.setVisible(false); - - LocalizationFile[] files = ColorMapLoader.listColorMapFiles(); - for (LocalizationFile file : files) { - - List actualItems = new ArrayList(); - - 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 children = childMap.get(lastParent); - if (children == null) { - children = new ArrayList(); - 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); + cmapPopupMenu.addMenuListener(new MenuPopulator(cmapPopupMenu, + ColorMapTreeFactory.getBaseTree())); } /** @@ -284,60 +178,6 @@ public class ColormapComp { refreshItems(); } - /** - * @param parent - */ - private void sortMenus(Menu parent) { - List children = childMap.get(parent); - if (children == null || children.size() == 0) { - return; - } - - Collections.sort(children, new Comparator() { - @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() { return cmapPopupMenu; } @@ -348,4 +188,160 @@ public class ColormapComp { } 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 subTrees = tree.getSubTrees(); + Collections.sort(subTrees, new Comparator() { + + @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 files = tree.getColorMapFiles(); + Collections.sort(files, new Comparator() { + + @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 getLevelTrees() { + if (menu == cmapPopupMenu) { + List trees = new ArrayList(); + 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); + } + + }); + } + + } + }