diff --git a/cave/com.raytheon.uf.viz.core.maps/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.core.maps/META-INF/MANIFEST.MF index 034757a059..103c057c33 100644 --- a/cave/com.raytheon.uf.viz.core.maps/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.uf.viz.core.maps/META-INF/MANIFEST.MF @@ -16,7 +16,8 @@ Require-Bundle: org.eclipse.ui, org.apache.commons.lang;bundle-version="2.3.0", com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", com.raytheon.uf.viz.productbrowser;bundle-version="1.12.1152", - com.raytheon.uf.viz.core.rsc;bundle-version="1.0.0" + com.raytheon.uf.viz.core.rsc;bundle-version="1.0.0", + com.raytheon.uf.viz.ui.menus;bundle-version="1.12.1174" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Eclipse-RegisterBuddy: com.raytheon.uf.viz.core diff --git a/cave/com.raytheon.uf.viz.core.maps/src/com/raytheon/uf/viz/core/maps/menus/MapsMenu.java b/cave/com.raytheon.uf.viz.core.maps/src/com/raytheon/uf/viz/core/maps/menus/MapsMenu.java index 7c682c2b43..c8f9936d7f 100644 --- a/cave/com.raytheon.uf.viz.core.maps/src/com/raytheon/uf/viz/core/maps/menus/MapsMenu.java +++ b/cave/com.raytheon.uf.viz.core.maps/src/com/raytheon/uf/viz/core/maps/menus/MapsMenu.java @@ -31,6 +31,7 @@ import org.eclipse.ui.menus.CommandContributionItemParameter; import com.raytheon.uf.viz.core.maps.MapStore; import com.raytheon.uf.viz.core.maps.MapStore.MapNode; +import com.raytheon.uf.viz.ui.menus.widgets.tearoff.TearOffMenuListener; /** * TODO Add Description @@ -50,6 +51,8 @@ import com.raytheon.uf.viz.core.maps.MapStore.MapNode; public class MapsMenu extends CompoundContributionItem { + boolean addTear = false; + /* * (non-Javadoc) * @@ -65,6 +68,12 @@ public class MapsMenu extends CompoundContributionItem { private MenuManager createMenu(MapNode root) { MenuManager menuMgr = new MenuManager(root.getName()); for (MapNode node : root.getSubTree()) { + if (addTear + && com.raytheon.uf.viz.core.Activator.getDefault() + .getPreferenceStore().getBoolean("tearoffmenus")) { + menuMgr.addMenuListener(new TearOffMenuListener(menuMgr)); + addTear = false; + } if (node.getSubTree() == null) { Map parms = new HashMap(); parms.put("mapName", node.getName()); @@ -80,6 +89,7 @@ public class MapsMenu extends CompoundContributionItem { null, true)); menuMgr.add(item); } else { + addTear = true; menuMgr.add(createMenu(node)); } } diff --git a/cave/com.raytheon.uf.viz.core/config.xml b/cave/com.raytheon.uf.viz.core/config.xml index 8a89ecfe20..00e70d3f27 100644 --- a/cave/com.raytheon.uf.viz.core/config.xml +++ b/cave/com.raytheon.uf.viz.core/config.xml @@ -23,6 +23,7 @@ http://localhost:9581/services /awips2/edex/data/share 512 +true 25 false 1.0 diff --git a/cave/com.raytheon.uf.viz.ui.menus/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.ui.menus/META-INF/MANIFEST.MF index 9f69a33c5a..f91fa184d8 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.uf.viz.ui.menus/META-INF/MANIFEST.MF @@ -34,4 +34,5 @@ Import-Package: com.raytheon.edex.scriptfactory, com.raytheon.uf.viz.core.status Export-Package: com.raytheon.uf.viz.ui.menus, com.raytheon.uf.viz.ui.menus.widgets, + com.raytheon.uf.viz.ui.menus.widgets.tearoff, com.raytheon.uf.viz.ui.menus.xml diff --git a/cave/com.raytheon.uf.viz.ui.menus/plugin.xml b/cave/com.raytheon.uf.viz.ui.menus/plugin.xml index ebde0dab00..21f28a2f0d 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/plugin.xml +++ b/cave/com.raytheon.uf.viz.ui.menus/plugin.xml @@ -12,4 +12,11 @@ extensionFilter=".xml"> + + + diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java index 5dfef52e97..7238abe22e 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java @@ -215,6 +215,12 @@ public class BundleContributionItem extends ContributionItem { if (!performQuery) { widget.setText(menuText); + + // notify things of menu update times + Event event = new Event(); + event.data = widget; + event.widget = widget; + widget.notifyListeners(SWT.Modify, event); return; } @@ -243,6 +249,12 @@ public class BundleContributionItem extends ContributionItem { String labelStr = this.menuText + " \t" + dateStr; widget.setText(labelStr); + + // notify things of menu update times + Event event = new Event(); + event.data = widget; + event.widget = widget; + widget.notifyListeners(SWT.Modify, event); } protected void updateTime(DataTime time, BinOffset offset) { @@ -282,6 +294,7 @@ public class BundleContributionItem extends ContributionItem { private Listener getItemListener() { if (menuItemListener == null) { menuItemListener = new Listener() { + @Override public void handleEvent(Event event) { switch (event.type) { case SWT.Dispose: @@ -405,6 +418,7 @@ public class BundleContributionItem extends ContributionItem { this.offset = offset; } + @Override public void updateTime(DataTime time) { BundleContributionItem.this.updateTime(time, offset); } diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/IncludeContributionItem.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/IncludeContributionItem.java index 9cb0cf6bc0..ff197c4542 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/IncludeContributionItem.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/IncludeContributionItem.java @@ -88,12 +88,13 @@ public class IncludeContributionItem extends ContributionItem { return items; } + @Override public void fill(Menu menu, int index) { - getContributionItems(); + IContributionItem[] items = getContributionItems(); if (index == -1) { index = menu.getItemCount(); } - IContributionItem[] items = getContributionItems(); + getContributionItems(); for (int i = 0; i < items.length; i++) { IContributionItem item = items[i]; int oldItemCount = menu.getItemCount(); @@ -106,12 +107,13 @@ public class IncludeContributionItem extends ContributionItem { } } + @Override public void fill(ToolBar toolbar, int index) { - getContributionItems(); + IContributionItem[] items = getContributionItems(); if (index == -1) { index = toolbar.getItemCount(); } - IContributionItem[] items = getContributionItems(); + getContributionItems(); for (int i = 0; i < items.length; i++) { IContributionItem item = items[i]; int oldItemCount = toolbar.getItemCount(); @@ -138,5 +140,4 @@ public class IncludeContributionItem extends ContributionItem { } } } - } \ No newline at end of file diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/SubmenuContributionItem.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/SubmenuContributionItem.java index 119eeb4ca9..54e3f007b8 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/SubmenuContributionItem.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/SubmenuContributionItem.java @@ -22,13 +22,10 @@ package com.raytheon.uf.viz.ui.menus.widgets; import java.util.Map; import java.util.Set; -import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.action.IContributionItem; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MenuEvent; -import org.eclipse.swt.events.MenuListener; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.MenuManager; import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.MenuItem; import com.raytheon.uf.common.menus.xml.CommonAbstractMenuContribution; import com.raytheon.uf.common.menus.xml.VariableSubstitution; @@ -57,7 +54,7 @@ import com.raytheon.uf.viz.ui.menus.xml.MenuXMLMap; * @version 1.0 */ -public class SubmenuContributionItem extends ContributionItem { +public class SubmenuContributionItem extends MenuManager { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(SubmenuContributionItem.class); @@ -66,88 +63,51 @@ public class SubmenuContributionItem extends ContributionItem { private CommonAbstractMenuContribution[] contribs; - private String name; - - private MenuItem widget; - - protected Menu menu; - protected VariableSubstitution[] subs; protected IContributionItem[][] contributionItems; protected Set removals; + /** + * + * @param includeSubstitutions + * @param name + * @param ci + * @param removals + * @param mListener + */ public SubmenuContributionItem(VariableSubstitution[] includeSubstitutions, String name, CommonAbstractMenuContribution[] ci, - Set removals) { - super(); + Set removals, IMenuListener menuListener) { + super(processNameSubstitution(includeSubstitutions, name)); this.subs = includeSubstitutions; this.contribs = ci; this.removals = removals; + if (menuListener != null) { + this.addMenuListener(menuListener); + } + } + private static String processNameSubstitution( + VariableSubstitution[] includeSubstitutions, String name) { if (includeSubstitutions != null && includeSubstitutions.length > 0) { Map map = VariableSubstitution .toMap(includeSubstitutions); try { - this.name = VariableSubstitutionUtil - .processVariables(name, map); + name = VariableSubstitutionUtil.processVariables(name, map); } catch (VizException e) { - this.name = name; statusHandler.handle(Priority.PROBLEM, "Error during menu substitution", e); } - } else { - this.name = name; } - + return name; } @Override public void fill(Menu parent, int index) { - - if (widget != null && widget.isDisposed()) { - widget = null; - } - - if (widget != null || parent == null) { - return; - } - - MenuItem item = null; - if (index >= 0) { - item = new MenuItem(parent, SWT.CASCADE, index); - } else { - item = new MenuItem(parent, SWT.CASCADE); - } - - item.setData(this); - - item.setText(this.name); - - widget = item; - - createMenu(); - - update(null); - } - - private void createMenu() { - menu = new Menu(widget.getParent().getShell(), SWT.DROP_DOWN); - menu.addMenuListener(new MenuListener() { - @Override - public void menuHidden(MenuEvent e) { - // should Menu Items be disposed here? - } - - @Override - public void menuShown(MenuEvent e) { - fillMenu(); - } - }); - - widget.setMenu(menu); - + removeAll(); + super.fill(parent, index); getContributionItemsJob.schedule(new GetContributionItemsRunnable()); } @@ -172,30 +132,9 @@ public class SubmenuContributionItem extends ContributionItem { return this.contributionItems; } - private void fillMenu() { - getContributionItems(); - if (this.menu.getItemCount() == 0) { - for (int i = 0; i < this.contributionItems.length; i++) { - for (IContributionItem item : this.contributionItems[i]) { - if (item.isVisible()) { - item.fill(this.menu, -1); - } - } - } - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.jface.action.ContributionItem#dispose() - */ @Override - public void dispose() { - super.dispose(); - if (this.menu != null && !this.menu.isDisposed()) { - this.menu.dispose(); - } + public boolean isVisible() { + return true; } // call getContributionItems using the getContributionItems JobPool. @@ -204,7 +143,11 @@ public class SubmenuContributionItem extends ContributionItem { @Override public void run() { getContributionItems(); + for (int i = 0; i < contributionItems.length; i++) { + for (IContributionItem item : contributionItems[i]) { + add(item); + } + } } } - } diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/entries b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/entries new file mode 100644 index 0000000000..d39c23039e --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/entries @@ -0,0 +1,198 @@ +9 + +dir +21 +svn+ssh://lightning/var/svn/awips2/trunk/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff +svn+ssh://lightning/var/svn/awips2 + + + +2011-12-16T13:34:21.647792Z +20 +mnash + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +16d501fb-59f8-4822-b6dc-d000d8df5b99 + +MenuItemComposite.java +file +208 + + + +2012-01-16T19:54:41.000000Z +71e7fd3f76d9ee8390ce6f65fadf1722 +2012-01-16T20:48:28.773256Z +208 +mnash + + + + + + + + + + + + + + + + + + + + + +20861 + +PopupMenu.java +file +90 + + + +2012-01-06T18:10:56.000000Z +fb1f4e9c0869ac2084212b7e58b172b7 +2012-01-06T18:15:50.878244Z +90 +mnash + + + + + + + + + + + + + + + + + + + + + +8631 + +TearOffMenuDialog.java +file +200 + + + +2012-01-16T14:18:00.000000Z +25d4798b84a8b481129a4da10531331d +2012-01-16T14:18:38.246084Z +200 +mnash + + + + + + + + + + + + + + + + + + + + + +5705 + +TearOffMenuListener.java +file +90 + + + +2012-01-06T18:15:29.000000Z +57931261ed0a281cbdaeff8f2ec2b4d7 +2012-01-06T18:15:50.878244Z +90 +mnash + + + + + + + + + + + + + + + + + + + + + +6295 + +TearOffPreferencePage.java +file +208 + + + +2012-01-16T19:51:58.000000Z +fe5ad92983858f74326fe424004ec39b +2012-01-16T20:48:28.773256Z +208 +mnash + + + + + + + + + + + + + + + + + + + + + +2377 + diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/format b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/format new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/format @@ -0,0 +1 @@ +9 diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/MenuItemComposite.java.svn-base b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/MenuItemComposite.java.svn-base new file mode 100644 index 0000000000..51139c5d80 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/MenuItemComposite.java.svn-base @@ -0,0 +1,532 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackAdapter; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.ui.progress.UIJob; + +import com.raytheon.viz.ui.EditorUtil; +import com.raytheon.viz.ui.editor.AbstractEditor; + +/** + * Holds the information for all the menu items in the dialog + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 15, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class MenuItemComposite extends Composite { + + private Control firstItem; + + private Control secondItem; + + // backing data for executing listeners + private MenuItem item; + + private Image arrow = null; + + private Image highlightedArrow = null; + + private Listener updateListener = null; + + private Listener showListener = null; + + private Menu menu = null; + + private Composite parent = null; + + private Menu topLevelMenu = null; + + private UIJob job = null; + + /** + * @param parent + * @param style + */ + public MenuItemComposite(Composite parent, int style) { + super(parent, style); + this.parent = parent; + } + + // creates both labels and ties them together + public void addLabels(MenuItem it, int labelStyle) { + if (it.isDisposed()) { + return; + } + + // going to hold the menu around so that if the cave menu gets opened + // again (when the items get disposed), we will be able to go back in + // and get the items from the menu and rebuild in the background + menu = it.getParent(); + + topLevelMenu = menu; + while (topLevelMenu.getParentMenu() != null + && topLevelMenu.getParentMenu().getParentMenu() != null) { + topLevelMenu = topLevelMenu.getParentMenu(); + } + + item = it; + String[] labels = item.getText().split("\t"); + // handle for a separator menu item + if (item.getStyle() == SWT.SEPARATOR) { + firstItem = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + gd.horizontalSpan = 2; + firstItem.setLayoutData(gd); + } else { + // radio items + if (item.getStyle() == SWT.RADIO) { + firstItem = new Button(this, SWT.RADIO); + ((Button) firstItem).setSelection(item.getSelection()); + GridData gd = new GridData(18, 18); + firstItem.setLayoutData(gd); + + secondItem = new Label(this, labelStyle); + ((Label) secondItem).setText(labels[0]); + gd = new GridData(SWT.LEFT, SWT.CENTER, true, true); + secondItem.setLayoutData(gd); + } + // check boxes + else if (item.getStyle() == SWT.CHECK) { + // if (item.getStyle() == SWT.CHECK) { + firstItem = new Button(this, SWT.CHECK); + ((Button) firstItem).setSelection(item.getSelection()); + GridData gd = new GridData(18, 18); + firstItem.setLayoutData(gd); + + secondItem = new Label(this, labelStyle); + ((Label) secondItem).setText(labels[0]); + gd = new GridData(SWT.LEFT, SWT.CENTER, true, true); + secondItem.setLayoutData(gd); + } + // submenus (with arrows) + else if (item.getStyle() == SWT.CASCADE) { + firstItem = new Label(this, SWT.PUSH); + firstItem.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, + true, false)); + ((Label) firstItem).setText(labels[0]); + secondItem = new Label(this, labelStyle); + createArrow(); + ((Label) secondItem).setImage(arrow); + } + // regular selectable menu items + else { + firstItem = new Label(this, labelStyle); + firstItem.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, + true, false)); + ((Label) firstItem).setText(labels[0]); + + secondItem = new Label(this, labelStyle); + if (labels.length > 1) { + ((Label) secondItem).setText(labels[1]); + } + + createUpdateListener(this); + item.addListener(SWT.Modify, updateListener); + + showListener = new Listener() { + @Override + public void handleEvent(final Event event) { + job = new UIJob(Display.getCurrent(), + "Regenerate Tear Off Menus") { + + @Override + public IStatus runInUIThread( + IProgressMonitor monitor) { + if (menu == null || menu.isDisposed()) { + for (MenuItem item : topLevelMenu + .getItems()) { + if (item.getMenu() != null) { + for (Listener list : item.getMenu() + .getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = item; + event.type = SWT.Show; + list.handleEvent(event); + } + if (getShell().isDisposed()) { + break; + } else if (getShell().getText() + .equals(item.getText())) { + menu = item.getMenu(); + break; + } + } + } + } + + int start = 0; + if (menu.getItemCount() != parent.getChildren().length) { + start = 1; + } + for (int i = start; i < menu.getItemCount(); i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i - start]; + if (mic.item.isDisposed()) { + mic.item = menu.getItem(i); + createUpdateListener(mic); + mic.item.addListener(SWT.Modify, + updateListener); + + for (Listener list : mic.item + .getListeners(SWT.Modify)) { + Event e = new Event(); + e.type = SWT.Modify; + e.data = mic.item; + list.handleEvent(e); + } + } + } + return Status.OK_STATUS; + } + }; + job.schedule(); + } + }; + item.getParent().addListener(SWT.Show, showListener); + topLevelMenu.addListener(SWT.Show, showListener); + } + + if (item.isEnabled()) { + // add the listeners to both the first and the second + // control, so the same thing happens if you scroll over either, + // or the MenuItemComposite + MouseTrackAdapter mouseTrackAdapter = getMouseTrackAdapter(); + firstItem.addMouseTrackListener(mouseTrackAdapter); + secondItem.addMouseTrackListener(mouseTrackAdapter); + this.addMouseTrackListener(mouseTrackAdapter); + + MouseAdapter mouseAdapter = getMouseAdapter(); + firstItem.addMouseListener(mouseAdapter); + secondItem.addMouseListener(mouseAdapter); + this.addMouseListener(mouseAdapter); + } else { + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_DARK_GRAY)); + } + } + } + + protected void createUpdateListener(final MenuItemComposite mic) { + updateListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (mic.secondItem != null && !mic.secondItem.isDisposed()) { + if (mic.item == event.data) { + if (((MenuItem) event.data).getText().split("\t").length > 1) { + ((Label) mic.secondItem) + .setText(((MenuItem) event.data).getText() + .split("\t")[1]); + // don't want to make the times go off the + // screen + mic.layout(); + } + } + } + } + }; + } + + /** + * Sets the background on all the visible items + */ + @Override + public void setBackground(Color color) { + firstItem.setBackground(color); + secondItem.setBackground(color); + super.setBackground(color); + } + + /** + * Sets the foreground on all the visible items to the necessary color + */ + @Override + public void setForeground(Color color) { + firstItem.setForeground(color); + secondItem.setForeground(color); + super.setForeground(color); + } + + /** + * Creates the arrows for submenus + */ + private void createArrow() { + int imgWidth = 11; + int imgHeight = 11; + + arrow = new Image(Display.getCurrent(), imgWidth, imgHeight); + highlightedArrow = new Image(Display.getCurrent(), imgWidth, imgHeight); + + // the normal arrow + GC gc = new GC(arrow); + drawArrowImage(gc, imgWidth, imgHeight, SWT.COLOR_WIDGET_BACKGROUND, + SWT.COLOR_BLACK); + + // the highlighted arrow + gc = new GC(highlightedArrow); + drawArrowImage(gc, imgWidth, imgHeight, SWT.COLOR_LIST_SELECTION, + SWT.COLOR_WHITE); + + gc.dispose(); + } + + /** + * Create the arrow image. + * + * @param gc + * Graphic context. + * @param imgWidth + * Image width. + * @param imgHeight + * Image height. + */ + private void drawArrowImage(GC gc, int imgWidth, int imgHeight, + int highlightColor, int arrowColor) { + gc.setAntialias(SWT.ON); + + // "Erase" the canvas by filling it in with a white rectangle. + gc.setBackground(Display.getCurrent().getSystemColor(highlightColor)); + + gc.fillRectangle(0, 0, imgWidth, imgHeight); + + gc.setBackground(Display.getCurrent().getSystemColor(arrowColor)); + + int[] polyArray = new int[] { 2, 0, 8, 4, 2, 8 }; + + gc.fillPolygon(polyArray); + } + + private void addMenu(MenuItem item, int y) { + PopupMenu men = new PopupMenu(); + men.addSubmenus(item, this.getShell(), y); + } + + /** + * Highlight the areas of the composite so that we get the "look" of the + * whole thing being highlighted + * + * @return + */ + private MouseTrackAdapter getMouseTrackAdapter() { + MouseTrackAdapter trackAdapter = new MouseTrackAdapter() { + @Override + public void mouseEnter(MouseEvent e) { + // we want all the colors to be the same for background + // and foreground, so we set that here, this is to tell + // the whole thing to be highlighted + setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_LIST_SELECTION)); + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_LIST_SELECTION_TEXT)); + // changes the arrow image to the highlighted version + if (secondItem instanceof Label) { + if (((Label) secondItem).getImage() != null) { + ((Label) secondItem).setImage(highlightedArrow); + } + } + } + + @Override + public void mouseExit(MouseEvent e) { + // we want all the colors to be the same for background + // and foreground, so we set that here, this is to + // unhighlight the whole thing + setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_WIDGET_BACKGROUND)); + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_WIDGET_FOREGROUND)); + // changes the arrow image to the unhighlighted version + if (secondItem instanceof Label) { + if (((Label) secondItem).getImage() != null) { + ((Label) secondItem).setImage(arrow); + } + } + } + }; + return trackAdapter; + } + + /** + * Select on either item being selected, so that we get the same action for + * both being selected + * + * @return + */ + private MouseAdapter getMouseAdapter() { + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + // if the menu has been opened, then the items need to + // be regenerated if there is a submenu, then add the + // ability to show it + if (item == null || item.isDisposed()) { + ((MenuItemComposite) ((Label) e.getSource()).getParent()) + .getData(); + for (int i = 0; i < menu.getItemCount(); i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i]; + if (mic.item.isDisposed()) { + mic.item = menu.getItem(i); + createUpdateListener(mic); + mic.item.addListener(SWT.Modify, updateListener); + + for (Listener list : mic.item + .getListeners(SWT.Modify)) { + Event ev = new Event(); + ev.type = SWT.Modify; + ev.data = mic.item; + list.handleEvent(ev); + } + } + } + } + + if (item.getMenu() != null) { + // get the y offset based on the location of the + // click + int y = 0; + if (e.widget instanceof MenuItemComposite) { + y = ((Control) e.widget).getLocation().y; + } else { + y = ((Control) e.widget).getParent().getLocation().y; + } + addMenu(item, y); + return; + } + + // handle the selection event, so if it is able to load + // something, do it (by looping over ALL the selection + // listeners assigned to the item) + for (Listener list : item.getListeners(SWT.Selection)) { + Event event = new Event(); + event.type = SWT.Selection; + event.widget = item; + list.handleEvent(event); + } + + // for commands that do not refresh the editor, menus worked + // since the display was covered by the editor and when the menu + // went away a refresh was forced... this doesn't happen with + // tear-offs that are in the main dialog, since nothing about + // the display changes, so we must force a refresh on the editor + ((AbstractEditor) EditorUtil.getActiveEditor()).refresh(); + + // handles the check boxes, if clicking the check box + // need to not do this (because SWT does it already) + // otherwise do it + if (firstItem instanceof Button) { + if (e.widget != firstItem) { + ((Button) firstItem).setSelection(!((Button) firstItem) + .getSelection()); + } + } + + for (int i = 0; i < parent.getChildren().length; i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i]; + if (item.getStyle() == SWT.RADIO) { + try { + if (((Control) e.widget).getParent() + .getData("radioGroup") + .equals(mic.getData("radioGroup"))) { + if (!((Control) e.widget).getParent().equals( + mic)) { + ((Button) mic.firstItem) + .setSelection(false); + } else { + ((Button) mic.firstItem).setSelection(true); + } + } + } catch (NullPointerException e1) { + } + } + } + } + }; + return mouseAdapter; + } + + @Override + // TODO XXX make sure we don't leak anything here + public void dispose() { + if (arrow != null) { + arrow.dispose(); + } + if (highlightedArrow != null) { + highlightedArrow.dispose(); + } + + if (updateListener != null) { + item.removeListener(SWT.Modify, updateListener); + } + if (showListener != null) { + item.getParent().removeListener(SWT.Show, showListener); + topLevelMenu.removeListener(SWT.Show, showListener); + } + firstItem.dispose(); + if (secondItem != null) { + secondItem.dispose(); + } + if (job != null) { + job.cancel(); + } + updateListener = null; + showListener = null; + parent.dispose(); + item.dispose(); + super.dispose(); + } + + public void setSelection(boolean selection) { + if (firstItem instanceof Button) { + ((Button) firstItem).setSelection(selection); + } + } +} \ No newline at end of file diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/PopupMenu.java.svn-base b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/PopupMenu.java.svn-base new file mode 100644 index 0000000000..ac33ee1719 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/PopupMenu.java.svn-base @@ -0,0 +1,216 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MenuAdapter; +import org.eclipse.swt.events.MenuEvent; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; + +/** + * The popup menu for when items are populated out of the TearOffMenuDialog + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 5, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class PopupMenu { + + Listener selectionListener = null; + + Listener updateListener = null; + + Listener showListener = null; + + public PopupMenu() { + // default constructor + } + + protected void buildMenu(final MenuItem item, final Shell shell, + final Menu menu) { + String longest = ""; + for (final MenuItem menItem : item.getMenu().getItems()) { + // building a new menu item that does what we want it to do, but + // very similar to the original item in the menu + final MenuItem mItem = new MenuItem(menu, menItem.getStyle()); + mItem.setText(menItem.getText()); + + // check for length + if (mItem.getText().length() > longest.length()) { + longest = mItem.getText(); + } + + mItem.setEnabled(menItem.getEnabled()); + mItem.setSelection(menItem.getSelection()); + // still going to have the menItem TODO need to update if the + // MenuItems are disposed + mItem.setData(menItem); + + // adding all the selection listeners from the menu + for (Listener list : menItem.getListeners(SWT.Selection)) { + mItem.addListener(SWT.Selection, list); + } + + // a show listener, so when the menu is shown (in cave) it updates + // the time in the tear off submenu + // this tries to update all the times when the menu is opened + showListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (!mItem.isDisposed()) { + if (mItem.getData() == event.data) { + mItem.setText(((MenuItem) event.data).getText()); + } + } + } + }; + menItem.getParent().addListener(SWT.Show, showListener); + + // modify listener gets fired from BundleContributionItem if the + // times are updated, so we listen for that here so that item times + // can get updated, in the submenus + // this does the periodic updating of the menus through the + // SWT.Modify event which is fired from BundleContributionItem + updateListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (!mItem.isDisposed()) { + if (mItem.getData() == event.data) { + mItem.setText(((MenuItem) event.data).getText()); + } + } + } + }; + menItem.addListener(SWT.Modify, updateListener); + + // if it has a submenu, do the following + if (mItem.getStyle() == SWT.CASCADE) { + final Menu subMenu = new Menu(shell, SWT.DROP_DOWN); + mItem.setMenu(subMenu); + subMenu.addMenuListener(new MenuAdapter() { + @Override + public void menuShown(MenuEvent e) { + // if not empty + if (subMenu.getItemCount() == 0) { + // execute the show listeners on the menu of the + // stored off MenuItem, which will populate the Menu + // with the items and then we are able to get those + // items to populate our submenu + for (Listener list : ((MenuItem) mItem.getData()) + .getMenu().getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = (Menu) e.getSource(); + event.type = SWT.Show; + list.handleEvent(event); + } + // now that we have the items, we build the menu + buildMenu((MenuItem) mItem.getData(), shell, + subMenu); + subMenu.setVisible(true); + } + } + }); + } + + // add toggle button functionality + if (mItem.getStyle() == SWT.CHECK) { + selectionListener = new Listener() { + @Override + public void handleEvent(Event event) { + // set it to the actual menu item, so that next time it + // pops up it will hold the correct selection + menItem.setSelection(((MenuItem) event.widget) + .getSelection()); + } + }; + mItem.addListener(SWT.Selection, selectionListener); + } + + menu.addMenuListener(new MenuAdapter() { + @Override + public void menuHidden(MenuEvent e) { + if (selectionListener != null) { + mItem.removeListener(SWT.Selection, selectionListener); + } + menItem.removeListener(SWT.Modify, updateListener); + menItem.getParent().removeListener(SWT.Show, showListener); + + // execute the hide listener on the menu so that the + // TearOffMenuListener gets removed from the menu and you + // don't get duplicate tear off items + for (Listener list : menItem.getParent().getListeners( + SWT.Hide)) { + Event event = new Event(); + event.type = SWT.Hide; + event.widget = menItem.getParent(); + list.handleEvent(event); + } + } + }); + } + } + + /** + * Adds the popup menu that pops up off the main TearOffMenuDialog + * + * @param item + * @param shell + * @param y + * y - used for the y location + */ + private void addPopupMenu(MenuItem item, Shell shell, int y) { + Menu menu = new Menu(shell, SWT.POP_UP); + buildMenu(item, shell, menu); + // get the location for the popup menu + // TODO XXX need to figure out bounds and such so that we dont put the + // pop up over the menu item selected + int xOffset = shell.getLocation().x; + int yOffset = shell.getLocation().y; + menu.setLocation(xOffset + shell.getSize().x, yOffset + y); + menu.setVisible(true); + } + + protected void addSubmenus(MenuItem item, Shell shell, int y) { + // showing the menu in cave (won't actually show), but executes all the + // listeners to build the menus (since they are built on-demand) + for (Listener list : item.getMenu().getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = item; + event.type = SWT.Show; + list.handleEvent(event); + } + + addPopupMenu(item, shell, y); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuDialog.java.svn-base b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuDialog.java.svn-base new file mode 100644 index 0000000000..9af79157e1 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuDialog.java.svn-base @@ -0,0 +1,162 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Monitor; +import org.eclipse.swt.widgets.Shell; + +import com.raytheon.viz.ui.VizWorkbenchManager; +import com.raytheon.viz.ui.dialogs.CaveSWTDialog; + +/** + * "Tear-off" menus to emulate A1 behavior + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 14, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class TearOffMenuDialog extends CaveSWTDialog { + + private MenuItem[] items = null; + + private ScrolledComposite scrolledComp = null; + + private Composite fullComp = null; + + /** + * @param parentShell + */ + public TearOffMenuDialog(Menu menu) { + super(VizWorkbenchManager.getInstance().getCurrentWindow().getShell(), + SWT.DIALOG_TRIM | SWT.RESIZE, CAVE.INDEPENDENT_SHELL + | CAVE.DO_NOT_BLOCK); + String text = menu.getParentItem().getText(); + + // handle for the & that makes key bindings + if (text.contains("&")) { + text = text.replace("&", ""); + } + setText(text); + this.items = menu.getItems(); + } + + @Override + protected void initializeComponents(final Shell shell) { + // allow for scrolling if necessary + scrolledComp = new ScrolledComposite(shell, SWT.V_SCROLL); + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); + scrolledComp.setLayoutData(gd); + fullComp = new Composite(scrolledComp, SWT.NONE); + GridLayout fullLayout = new GridLayout(); + fullLayout.marginHeight = 0; + fullLayout.marginWidth = 0; + // don't want any space between the two controls + fullLayout.horizontalSpacing = 0; + fullComp.setLayout(fullLayout); + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + fullComp.setLayoutData(gd); + + // remove the first menu item which is the tear off item, so that it + // doesn't accidentally appear anywhere else + MenuItem[] preparedItems = new MenuItem[items.length - 1]; + for (int i = 1; i < items.length; i++) { + preparedItems[i - 1] = items[i]; + } + items = preparedItems; + + // TODO, handle radio items, probably in here to keep track of what + // radio items are selected so that they can be deselected + + // go through menu items and build MenuItemComposite for each item, + // which handles all the selection and color of the "MenuItem" in the + // dialog + int radioGroups = 0; + for (int i = 0; i < items.length; i++) { + int labelStyle = SWT.NONE; + if (items[i] == null) { + labelStyle = SWT.SEPARATOR | SWT.HORIZONTAL; + } + + final MenuItemComposite comp = new MenuItemComposite(fullComp, + SWT.NONE); + + if (items[i].getStyle() == SWT.RADIO) { + comp.setData("radioGroup", radioGroups); + } else { + radioGroups++; + } + + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + comp.setLayout(layout); + gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + comp.setLayoutData(gd); + + // add the labels to the dialog with each of the MenuItems + comp.addLabels(items[i], labelStyle); + } + scrolledComp.setContent(fullComp); + scrolledComp.setExpandHorizontal(true); + scrolledComp.setExpandVertical(true); + scrolledComp.setMinSize(fullComp.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + shell.setMinimumSize(150, fullComp.getSize().y); + shell.pack(); + // sets the location based on the current shell size (after it is + // packed) + Monitor primary = Display.getCurrent().getPrimaryMonitor(); + Rectangle monitorBounds = primary.getBounds(); + Rectangle shellBounds = shell.getBounds(); + int x = (monitorBounds.width / 2) - (shellBounds.width / 2); + int y = (monitorBounds.height / 2) - (shellBounds.height / 2); + shell.setLocation(x, y); + } + + @Override + protected void disposed() { + for (Control control : fullComp.getChildren()) { + control.dispose(); + } + scrolledComp.dispose(); + fullComp.dispose(); + super.disposed(); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuListener.java.svn-base b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuListener.java.svn-base new file mode 100644 index 0000000000..ef7ef9effc --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffMenuListener.java.svn-base @@ -0,0 +1,201 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuListener2; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +import com.raytheon.uf.viz.ui.menus.xml.IVizMenuManager; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 14, 2011            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class TearOffMenuListener implements IMenuListener2 { + + private List openDialogs = new ArrayList(); + + private static final String ID = "tearOffMenuItem"; + + public TearOffMenuListener(IMenuManager mgr) { + register(mgr.getItems(), this); + } + + /** + * When the menu is about to show, check if the list contains that menu + * manager and if it doesn't add a TearOffContributionItem + */ + @Override + public void menuAboutToShow(final IMenuManager manager) { + register(manager.getItems(), this); + if (openDialogs.contains(manager) == false) { + // No open dialog for this menu, add tear off button + MenuItem[] menuItems = ((MenuManager) manager).getMenu().getItems(); + manager.add(new TearOffContributionItem(manager, menuItems)); + } + } + + /** + * Remove the menu manager from the list, so that the menu item will show + * back up + */ + @Override + public void menuAboutToHide(IMenuManager manager) { + unregister(manager.getItems(), this); + manager.remove(ID); + } + + public static void register(IContributionItem[] items, + IMenuListener listener) { + for (IContributionItem item : items) { + if (item instanceof IMenuManager) { + ((IMenuManager) item).addMenuListener(listener); + } else if (item instanceof IVizMenuManager) { + ((IVizMenuManager) item).addMenuListener(listener); + } + } + } + + public static void unregister(IContributionItem[] items, + IMenuListener listener) { + for (IContributionItem item : items) { + if (item instanceof IMenuManager) { + // ((IMenuManager) item).removeMenuListener(listener); + } else if (item instanceof IVizMenuManager) { + ((IVizMenuManager) item).removeMenuListener(listener); + } + } + } + + private class TearOffContributionItem extends ContributionItem { + + private Menu menu; + + private IMenuManager manager; + + private MenuItem[] items; + + /** + * @param action + */ + public TearOffContributionItem(IMenuManager manager, MenuItem[] items) { + super(ID); + this.manager = manager; + this.items = items; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.action.ActionContributionItem#fill(org.eclipse. + * swt.widgets.Menu, int) + */ + @Override + public void fill(Menu parent, int index) { + this.menu = parent; + String longest = ""; + for (MenuItem item : menu.getItems()) { + String check = item.getText(); + if (check.length() > longest.length()) { + longest = check; + } + } + byte[] bytes = new byte[longest.length() * 2]; + Arrays.fill(bytes, (byte) '|'); + // String filled = new String(bytes); + String filled = "- - - - - - TEAR-OFF : " + + parent.getParentItem().getText() + " - - - - - -"; + // String filled = "-" * bytes.length + new ActionContributionItem(new TearOffAction(filled, manager, + items, menu)).fill(parent, 0); + } + } + + private class TearOffAction extends Action { + + private IMenuManager manager; + + private Menu menu; + + private TearOffAction(String text, final IMenuManager manager, + final MenuItem[] items, Menu menu) { + super(text); + this.manager = manager; + this.menu = menu; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + TearOffMenuDialog dialog = new TearOffMenuDialog(menu); + dialog.addListener(SWT.Dispose, new Listener() { + @Override + public void handleEvent(Event event) { + openDialogs.remove(manager); + } + }); + openDialogs.add(manager); + dialog.open(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#getId() + */ + @Override + public String getId() { + return ID; + } + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffPreferencePage.java.svn-base b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffPreferencePage.java.svn-base new file mode 100644 index 0000000000..c6a16319b2 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/.svn/text-base/TearOffPreferencePage.java.svn-base @@ -0,0 +1,78 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import com.raytheon.uf.viz.core.Activator; +import com.raytheon.uf.viz.core.localization.HierarchicalPreferenceStore; + +/** + * Preference page for tear off menus + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 23, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class TearOffPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + @Override + public void init(IWorkbench workbench) { + HierarchicalPreferenceStore store = Activator.getDefault() + .getPreferenceStore(); + setPreferenceStore(store); + setDescription("CAVE UI Preferences"); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors + * () + */ + @Override + protected void createFieldEditors() { + BooleanFieldEditor editor = new BooleanFieldEditor("tearoffmenus", + "Enable Tear-Off Menus (requires restart)", + getFieldEditorParent()); + addField(editor); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/MenuItemComposite.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/MenuItemComposite.java new file mode 100644 index 0000000000..73e2318e55 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/MenuItemComposite.java @@ -0,0 +1,552 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackAdapter; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.ui.progress.UIJob; + +import com.raytheon.viz.ui.EditorUtil; +import com.raytheon.viz.ui.editor.AbstractEditor; + +/** + * Holds the information for all the menu items in the dialog + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 15, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class MenuItemComposite extends Composite { + + private Control firstItem; + + private Control secondItem; + + // backing data for executing listeners + private MenuItem item; + + private Image arrow = null; + + private Image highlightedArrow = null; + + private Listener updateListener = null; + + private Listener showListener = null; + + private Menu menu = null; + + private Composite parent = null; + + private Menu topLevelMenu = null; + + private UIJob job = null; + + /** + * @param parent + * @param style + */ + public MenuItemComposite(Composite parent, int style) { + super(parent, style); + this.parent = parent; + } + + // creates both labels and ties them together + public void addLabels(MenuItem it, int labelStyle) { + if (it.isDisposed()) { + return; + } + + // going to hold the menu around so that if the cave menu gets opened + // again (when the items get disposed), we will be able to go back in + // and get the items from the menu and rebuild in the background + menu = it.getParent(); + + topLevelMenu = menu; + while (topLevelMenu.getParentMenu() != null + && topLevelMenu.getParentMenu().getParentMenu() != null) { + topLevelMenu = topLevelMenu.getParentMenu(); + } + + item = it; + String[] labels = item.getText().split("\t"); + // handle for a separator menu item + if (item.getStyle() == SWT.SEPARATOR) { + firstItem = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + gd.horizontalSpan = 2; + firstItem.setLayoutData(gd); + } else { + // radio items + if (item.getStyle() == SWT.RADIO) { + firstItem = new Button(this, SWT.RADIO); + ((Button) firstItem).setSelection(item.getSelection()); + GridData gd = new GridData(18, 18); + firstItem.setLayoutData(gd); + + secondItem = new Label(this, labelStyle); + ((Label) secondItem).setText(labels[0]); + gd = new GridData(SWT.LEFT, SWT.CENTER, true, true); + secondItem.setLayoutData(gd); + } + // check boxes + else if (item.getStyle() == SWT.CHECK) { + // if (item.getStyle() == SWT.CHECK) { + firstItem = new Button(this, SWT.CHECK); + ((Button) firstItem).setSelection(item.getSelection()); + GridData gd = new GridData(18, 18); + firstItem.setLayoutData(gd); + + secondItem = new Label(this, labelStyle); + ((Label) secondItem).setText(labels[0]); + gd = new GridData(SWT.LEFT, SWT.CENTER, true, true); + secondItem.setLayoutData(gd); + } + // submenus (with arrows) + else if (item.getStyle() == SWT.CASCADE) { + firstItem = new Label(this, SWT.PUSH); + firstItem.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, + true, false)); + ((Label) firstItem).setText(labels[0]); + secondItem = new Label(this, labelStyle); + createArrow(); + ((Label) secondItem).setImage(arrow); + } + // regular selectable menu items + else { + firstItem = new Label(this, labelStyle); + firstItem.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, + true, false)); + ((Label) firstItem).setText(labels[0]); + + secondItem = new Label(this, labelStyle); + if (labels.length > 1) { + ((Label) secondItem).setText(labels[1]); + } + + createUpdateListener(this); + item.addListener(SWT.Modify, updateListener); + + showListener = new Listener() { + @Override + public void handleEvent(final Event event) { + job = new UIJob(Display.getCurrent(), + "Regenerate Tear Off Menus") { + + @Override + public IStatus runInUIThread( + IProgressMonitor monitor) { + if (menu == null || menu.isDisposed()) { + for (MenuItem item : topLevelMenu + .getItems()) { + if (item.getMenu() != null) { + for (Listener list : item.getMenu() + .getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = item; + event.type = SWT.Show; + list.handleEvent(event); + } + if (getShell().getText().equals( + item.getText())) { + menu = item.getMenu(); + break; + } + } + } + } + + int start = 0; + if (menu.getItemCount() != parent.getChildren().length) { + start = 1; + } + if (parent.getChildren().length > 0) { + for (int i = start; i < menu.getItemCount(); i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i - start]; + if (mic.item.isDisposed()) { + mic.item = menu.getItem(i); + createUpdateListener(mic); + mic.item.addListener(SWT.Modify, + updateListener); + + for (Listener list : mic.item + .getListeners(SWT.Modify)) { + Event e = new Event(); + e.type = SWT.Modify; + e.data = mic.item; + list.handleEvent(e); + } + } + } + } + return Status.OK_STATUS; + } + }; + job.schedule(); + } + }; + item.getParent().addListener(SWT.Show, showListener); + topLevelMenu.addListener(SWT.Show, showListener); + } + + if (item.isEnabled()) { + // add the listeners to both the first and the second + // control, so the same thing happens if you scroll over either, + // or the MenuItemComposite + MouseTrackAdapter mouseTrackAdapter = getMouseTrackAdapter(); + firstItem.addMouseTrackListener(mouseTrackAdapter); + secondItem.addMouseTrackListener(mouseTrackAdapter); + this.addMouseTrackListener(mouseTrackAdapter); + + MouseAdapter mouseAdapter = getMouseAdapter(); + firstItem.addMouseListener(mouseAdapter); + secondItem.addMouseListener(mouseAdapter); + this.addMouseListener(mouseAdapter); + } else { + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_DARK_GRAY)); + } + } + } + + protected void createUpdateListener(final MenuItemComposite mic) { + updateListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (mic.secondItem != null && !mic.secondItem.isDisposed()) { + if (mic.item == event.data) { + if (((MenuItem) event.data).getText().split("\t").length > 1) { + ((Label) mic.secondItem) + .setText(((MenuItem) event.data).getText() + .split("\t")[1]); + // don't want to make the times go off the + // screen + mic.layout(); + } + } + } + } + }; + } + + /** + * Sets the background on all the visible items + */ + @Override + public void setBackground(Color color) { + firstItem.setBackground(color); + secondItem.setBackground(color); + super.setBackground(color); + } + + /** + * Sets the foreground on all the visible items to the necessary color + */ + @Override + public void setForeground(Color color) { + firstItem.setForeground(color); + secondItem.setForeground(color); + super.setForeground(color); + } + + /** + * Creates the arrows for submenus + */ + private void createArrow() { + int imgWidth = 11; + int imgHeight = 11; + + arrow = new Image(Display.getCurrent(), imgWidth, imgHeight); + highlightedArrow = new Image(Display.getCurrent(), imgWidth, imgHeight); + + // the normal arrow + GC gc = new GC(arrow); + drawArrowImage(gc, imgWidth, imgHeight, SWT.COLOR_WIDGET_BACKGROUND, + SWT.COLOR_BLACK); + + // the highlighted arrow + gc = new GC(highlightedArrow); + drawArrowImage(gc, imgWidth, imgHeight, SWT.COLOR_LIST_SELECTION, + SWT.COLOR_WHITE); + + gc.dispose(); + } + + /** + * Create the arrow image. + * + * @param gc + * Graphic context. + * @param imgWidth + * Image width. + * @param imgHeight + * Image height. + */ + private void drawArrowImage(GC gc, int imgWidth, int imgHeight, + int highlightColor, int arrowColor) { + gc.setAntialias(SWT.ON); + + // "Erase" the canvas by filling it in with a white rectangle. + gc.setBackground(Display.getCurrent().getSystemColor(highlightColor)); + + gc.fillRectangle(0, 0, imgWidth, imgHeight); + + gc.setBackground(Display.getCurrent().getSystemColor(arrowColor)); + + int[] polyArray = new int[] { 2, 0, 8, 4, 2, 8 }; + + gc.fillPolygon(polyArray); + } + + private void addMenu(MenuItem item, int y) { + PopupMenu men = new PopupMenu(); + men.addSubmenus(item, this.getShell(), y); + } + + /** + * Highlight the areas of the composite so that we get the "look" of the + * whole thing being highlighted + * + * @return + */ + private MouseTrackAdapter getMouseTrackAdapter() { + MouseTrackAdapter trackAdapter = new MouseTrackAdapter() { + @Override + public void mouseEnter(MouseEvent e) { + // we want all the colors to be the same for background + // and foreground, so we set that here, this is to tell + // the whole thing to be highlighted + setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_LIST_SELECTION)); + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_LIST_SELECTION_TEXT)); + // changes the arrow image to the highlighted version + if (secondItem instanceof Label) { + if (((Label) secondItem).getImage() != null) { + ((Label) secondItem).setImage(highlightedArrow); + } + } + } + + @Override + public void mouseExit(MouseEvent e) { + // we want all the colors to be the same for background + // and foreground, so we set that here, this is to + // unhighlight the whole thing + setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_WIDGET_BACKGROUND)); + setForeground(Display.getCurrent().getSystemColor( + SWT.COLOR_WIDGET_FOREGROUND)); + // changes the arrow image to the unhighlighted version + if (secondItem instanceof Label) { + if (((Label) secondItem).getImage() != null) { + ((Label) secondItem).setImage(arrow); + } + } + } + }; + return trackAdapter; + } + + /** + * Select on either item being selected, so that we get the same action for + * both being selected + * + * @return + */ + private MouseAdapter getMouseAdapter() { + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + if (menu == null || menu.isDisposed()) { + for (MenuItem item : topLevelMenu.getItems()) { + if (item.getMenu() != null) { + for (Listener list : item.getMenu().getListeners( + SWT.Show)) { + Event event = new Event(); + event.widget = item; + event.type = SWT.Show; + list.handleEvent(event); + } + if (getShell().getText().equals(item.getText())) { + menu = item.getMenu(); + break; + } + } + } + } + // if the menu has been opened, then the items need to + // be regenerated if there is a submenu, then add the + // ability to show it + if (item == null || item.isDisposed()) { + int start = 0; + if (menu.getItemCount() != parent.getChildren().length) { + start = 1; + } + for (int i = start; i < menu.getItemCount(); i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i - start]; + if (mic.item.isDisposed()) { + mic.item = menu.getItem(i); + createUpdateListener(mic); + mic.item.addListener(SWT.Modify, updateListener); + + for (Listener list : mic.item + .getListeners(SWT.Modify)) { + Event ev = new Event(); + ev.type = SWT.Modify; + ev.data = mic.item; + list.handleEvent(ev); + } + } + } + } + + if (item.getMenu() != null) { + // get the y offset based on the location of the + // click + int y = 0; + if (e.widget instanceof MenuItemComposite) { + y = ((Control) e.widget).getLocation().y; + } else { + y = ((Control) e.widget).getParent().getLocation().y; + } + addMenu(item, y); + return; + } + + // handle the selection event, so if it is able to load + // something, do it (by looping over ALL the selection + // listeners assigned to the item) + for (Listener list : item.getListeners(SWT.Selection)) { + Event event = new Event(); + event.type = SWT.Selection; + event.widget = item; + list.handleEvent(event); + } + + // for commands that do not refresh the editor, menus worked + // since the display was covered by the editor and when the menu + // went away a refresh was forced... this doesn't happen with + // tear-offs that are in the main dialog, since nothing about + // the display changes, so we must force a refresh on the editor + ((AbstractEditor) EditorUtil.getActiveEditor()).refresh(); + + // handles the check boxes, if clicking the check box + // need to not do this (because SWT does it already) + // otherwise do it + if (firstItem instanceof Button) { + if (e.widget != firstItem) { + ((Button) firstItem).setSelection(!((Button) firstItem) + .getSelection()); + } + } + + for (int i = 0; i < parent.getChildren().length; i++) { + MenuItemComposite mic = (MenuItemComposite) parent + .getChildren()[i]; + if (item.getStyle() == SWT.RADIO) { + try { + if (((Control) e.widget).getParent() + .getData("radioGroup") + .equals(mic.getData("radioGroup"))) { + if (!((Control) e.widget).getParent().equals( + mic)) { + ((Button) mic.firstItem) + .setSelection(false); + } else { + ((Button) mic.firstItem).setSelection(true); + } + } + } catch (NullPointerException e1) { + } + } + } + } + }; + return mouseAdapter; + } + + @Override + // TODO XXX make sure we don't leak anything here + public void dispose() { + if (arrow != null) { + arrow.dispose(); + } + if (highlightedArrow != null) { + highlightedArrow.dispose(); + } + + if (updateListener != null && !item.isDisposed()) { + item.removeListener(SWT.Modify, updateListener); + } + if (showListener != null && !item.isDisposed() + && !item.getParent().isDisposed()) { + item.getParent().removeListener(SWT.Show, showListener); + topLevelMenu.removeListener(SWT.Show, showListener); + } + firstItem.dispose(); + if (secondItem != null) { + secondItem.dispose(); + } + if (job != null) { + job.cancel(); + } + updateListener = null; + showListener = null; + parent.dispose(); + item.dispose(); + super.dispose(); + } + + public void setSelection(boolean selection) { + if (firstItem instanceof Button) { + ((Button) firstItem).setSelection(selection); + } + } +} \ No newline at end of file diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/PopupMenu.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/PopupMenu.java new file mode 100644 index 0000000000..ac33ee1719 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/PopupMenu.java @@ -0,0 +1,216 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MenuAdapter; +import org.eclipse.swt.events.MenuEvent; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; + +/** + * The popup menu for when items are populated out of the TearOffMenuDialog + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 5, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class PopupMenu { + + Listener selectionListener = null; + + Listener updateListener = null; + + Listener showListener = null; + + public PopupMenu() { + // default constructor + } + + protected void buildMenu(final MenuItem item, final Shell shell, + final Menu menu) { + String longest = ""; + for (final MenuItem menItem : item.getMenu().getItems()) { + // building a new menu item that does what we want it to do, but + // very similar to the original item in the menu + final MenuItem mItem = new MenuItem(menu, menItem.getStyle()); + mItem.setText(menItem.getText()); + + // check for length + if (mItem.getText().length() > longest.length()) { + longest = mItem.getText(); + } + + mItem.setEnabled(menItem.getEnabled()); + mItem.setSelection(menItem.getSelection()); + // still going to have the menItem TODO need to update if the + // MenuItems are disposed + mItem.setData(menItem); + + // adding all the selection listeners from the menu + for (Listener list : menItem.getListeners(SWT.Selection)) { + mItem.addListener(SWT.Selection, list); + } + + // a show listener, so when the menu is shown (in cave) it updates + // the time in the tear off submenu + // this tries to update all the times when the menu is opened + showListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (!mItem.isDisposed()) { + if (mItem.getData() == event.data) { + mItem.setText(((MenuItem) event.data).getText()); + } + } + } + }; + menItem.getParent().addListener(SWT.Show, showListener); + + // modify listener gets fired from BundleContributionItem if the + // times are updated, so we listen for that here so that item times + // can get updated, in the submenus + // this does the periodic updating of the menus through the + // SWT.Modify event which is fired from BundleContributionItem + updateListener = new Listener() { + @Override + public void handleEvent(Event event) { + if (!mItem.isDisposed()) { + if (mItem.getData() == event.data) { + mItem.setText(((MenuItem) event.data).getText()); + } + } + } + }; + menItem.addListener(SWT.Modify, updateListener); + + // if it has a submenu, do the following + if (mItem.getStyle() == SWT.CASCADE) { + final Menu subMenu = new Menu(shell, SWT.DROP_DOWN); + mItem.setMenu(subMenu); + subMenu.addMenuListener(new MenuAdapter() { + @Override + public void menuShown(MenuEvent e) { + // if not empty + if (subMenu.getItemCount() == 0) { + // execute the show listeners on the menu of the + // stored off MenuItem, which will populate the Menu + // with the items and then we are able to get those + // items to populate our submenu + for (Listener list : ((MenuItem) mItem.getData()) + .getMenu().getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = (Menu) e.getSource(); + event.type = SWT.Show; + list.handleEvent(event); + } + // now that we have the items, we build the menu + buildMenu((MenuItem) mItem.getData(), shell, + subMenu); + subMenu.setVisible(true); + } + } + }); + } + + // add toggle button functionality + if (mItem.getStyle() == SWT.CHECK) { + selectionListener = new Listener() { + @Override + public void handleEvent(Event event) { + // set it to the actual menu item, so that next time it + // pops up it will hold the correct selection + menItem.setSelection(((MenuItem) event.widget) + .getSelection()); + } + }; + mItem.addListener(SWT.Selection, selectionListener); + } + + menu.addMenuListener(new MenuAdapter() { + @Override + public void menuHidden(MenuEvent e) { + if (selectionListener != null) { + mItem.removeListener(SWT.Selection, selectionListener); + } + menItem.removeListener(SWT.Modify, updateListener); + menItem.getParent().removeListener(SWT.Show, showListener); + + // execute the hide listener on the menu so that the + // TearOffMenuListener gets removed from the menu and you + // don't get duplicate tear off items + for (Listener list : menItem.getParent().getListeners( + SWT.Hide)) { + Event event = new Event(); + event.type = SWT.Hide; + event.widget = menItem.getParent(); + list.handleEvent(event); + } + } + }); + } + } + + /** + * Adds the popup menu that pops up off the main TearOffMenuDialog + * + * @param item + * @param shell + * @param y + * y - used for the y location + */ + private void addPopupMenu(MenuItem item, Shell shell, int y) { + Menu menu = new Menu(shell, SWT.POP_UP); + buildMenu(item, shell, menu); + // get the location for the popup menu + // TODO XXX need to figure out bounds and such so that we dont put the + // pop up over the menu item selected + int xOffset = shell.getLocation().x; + int yOffset = shell.getLocation().y; + menu.setLocation(xOffset + shell.getSize().x, yOffset + y); + menu.setVisible(true); + } + + protected void addSubmenus(MenuItem item, Shell shell, int y) { + // showing the menu in cave (won't actually show), but executes all the + // listeners to build the menus (since they are built on-demand) + for (Listener list : item.getMenu().getListeners(SWT.Show)) { + Event event = new Event(); + event.widget = item; + event.type = SWT.Show; + list.handleEvent(event); + } + + addPopupMenu(item, shell, y); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuDialog.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuDialog.java new file mode 100644 index 0000000000..0eb19aa350 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuDialog.java @@ -0,0 +1,169 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Monitor; +import org.eclipse.swt.widgets.Shell; + +import com.raytheon.viz.ui.VizWorkbenchManager; +import com.raytheon.viz.ui.dialogs.CaveSWTDialog; + +/** + * "Tear-off" menus to emulate A1 behavior + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 14, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class TearOffMenuDialog extends CaveSWTDialog { + + private MenuItem[] items = null; + + private ScrolledComposite scrolledComp = null; + + private Composite fullComp = null; + + /** + * @param parentShell + */ + public TearOffMenuDialog(Menu menu) { + super(VizWorkbenchManager.getInstance().getCurrentWindow().getShell(), + SWT.DIALOG_TRIM | SWT.RESIZE, CAVE.DO_NOT_BLOCK); + String text = menu.getParentItem().getText(); + + // handle for the & that makes key bindings + if (text.contains("&")) { + text = text.replace("&", ""); + } + setText(text); + this.items = menu.getItems(); + } + + @Override + protected void initializeComponents(final Shell shell) { + // allow for scrolling if necessary + scrolledComp = new ScrolledComposite(shell, SWT.V_SCROLL); + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); + scrolledComp.setLayoutData(gd); + fullComp = new Composite(scrolledComp, SWT.NONE); + GridLayout fullLayout = new GridLayout(); + fullLayout.marginHeight = 0; + fullLayout.marginWidth = 0; + // don't want any space between the two controls + fullLayout.horizontalSpacing = 0; + fullComp.setLayout(fullLayout); + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + fullComp.setLayoutData(gd); + + // remove the first menu item which is the tear off item, so that it + // doesn't accidentally appear anywhere else + MenuItem[] preparedItems = new MenuItem[items.length - 1]; + for (int i = 1; i < items.length; i++) { + preparedItems[i - 1] = items[i]; + } + items = preparedItems; + + // TODO, handle radio items, probably in here to keep track of what + // radio items are selected so that they can be deselected + + // go through menu items and build MenuItemComposite for each item, + // which handles all the selection and color of the "MenuItem" in the + // dialog + int radioGroups = 0; + for (int i = 0; i < items.length; i++) { + int labelStyle = SWT.NONE; + if (items[i] == null) { + labelStyle = SWT.SEPARATOR | SWT.HORIZONTAL; + } + + final MenuItemComposite comp = new MenuItemComposite(fullComp, + SWT.NONE); + + if (items[i].getStyle() == SWT.RADIO) { + comp.setData("radioGroup", radioGroups); + } else { + radioGroups++; + } + + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + comp.setLayout(layout); + gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + comp.setLayoutData(gd); + + // add the labels to the dialog with each of the MenuItems + comp.addLabels(items[i], labelStyle); + } + scrolledComp.setContent(fullComp); + scrolledComp.setExpandHorizontal(true); + scrolledComp.setExpandVertical(true); + scrolledComp.setMinSize(fullComp.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + shell.setMinimumSize(150, fullComp.getSize().y); + shell.pack(); + // sets the location based on the current shell size (after it is + // packed) + Monitor primary = Display.getCurrent().getPrimaryMonitor(); + Rectangle monitorBounds = primary.getBounds(); + Rectangle shellBounds = shell.getBounds(); + int x = (monitorBounds.width / 2) - (shellBounds.width / 2); + int y = (monitorBounds.height / 2) - (shellBounds.height / 2); + shell.setLocation(x, y); + + // close the dialog on perspective change + shell.addListener(SWT.Hide, new Listener() { + @Override + public void handleEvent(Event event) { + close(); + } + }); + } + + @Override + protected void disposed() { + for (Control control : fullComp.getChildren()) { + control.dispose(); + } + super.disposed(); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuListener.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuListener.java new file mode 100644 index 0000000000..ef7ef9effc --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffMenuListener.java @@ -0,0 +1,201 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuListener2; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +import com.raytheon.uf.viz.ui.menus.xml.IVizMenuManager; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 14, 2011            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class TearOffMenuListener implements IMenuListener2 { + + private List openDialogs = new ArrayList(); + + private static final String ID = "tearOffMenuItem"; + + public TearOffMenuListener(IMenuManager mgr) { + register(mgr.getItems(), this); + } + + /** + * When the menu is about to show, check if the list contains that menu + * manager and if it doesn't add a TearOffContributionItem + */ + @Override + public void menuAboutToShow(final IMenuManager manager) { + register(manager.getItems(), this); + if (openDialogs.contains(manager) == false) { + // No open dialog for this menu, add tear off button + MenuItem[] menuItems = ((MenuManager) manager).getMenu().getItems(); + manager.add(new TearOffContributionItem(manager, menuItems)); + } + } + + /** + * Remove the menu manager from the list, so that the menu item will show + * back up + */ + @Override + public void menuAboutToHide(IMenuManager manager) { + unregister(manager.getItems(), this); + manager.remove(ID); + } + + public static void register(IContributionItem[] items, + IMenuListener listener) { + for (IContributionItem item : items) { + if (item instanceof IMenuManager) { + ((IMenuManager) item).addMenuListener(listener); + } else if (item instanceof IVizMenuManager) { + ((IVizMenuManager) item).addMenuListener(listener); + } + } + } + + public static void unregister(IContributionItem[] items, + IMenuListener listener) { + for (IContributionItem item : items) { + if (item instanceof IMenuManager) { + // ((IMenuManager) item).removeMenuListener(listener); + } else if (item instanceof IVizMenuManager) { + ((IVizMenuManager) item).removeMenuListener(listener); + } + } + } + + private class TearOffContributionItem extends ContributionItem { + + private Menu menu; + + private IMenuManager manager; + + private MenuItem[] items; + + /** + * @param action + */ + public TearOffContributionItem(IMenuManager manager, MenuItem[] items) { + super(ID); + this.manager = manager; + this.items = items; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.action.ActionContributionItem#fill(org.eclipse. + * swt.widgets.Menu, int) + */ + @Override + public void fill(Menu parent, int index) { + this.menu = parent; + String longest = ""; + for (MenuItem item : menu.getItems()) { + String check = item.getText(); + if (check.length() > longest.length()) { + longest = check; + } + } + byte[] bytes = new byte[longest.length() * 2]; + Arrays.fill(bytes, (byte) '|'); + // String filled = new String(bytes); + String filled = "- - - - - - TEAR-OFF : " + + parent.getParentItem().getText() + " - - - - - -"; + // String filled = "-" * bytes.length + new ActionContributionItem(new TearOffAction(filled, manager, + items, menu)).fill(parent, 0); + } + } + + private class TearOffAction extends Action { + + private IMenuManager manager; + + private Menu menu; + + private TearOffAction(String text, final IMenuManager manager, + final MenuItem[] items, Menu menu) { + super(text); + this.manager = manager; + this.menu = menu; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + TearOffMenuDialog dialog = new TearOffMenuDialog(menu); + dialog.addListener(SWT.Dispose, new Listener() { + @Override + public void handleEvent(Event event) { + openDialogs.remove(manager); + } + }); + openDialogs.add(manager); + dialog.open(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#getId() + */ + @Override + public String getId() { + return ID; + } + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffPreferencePage.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffPreferencePage.java new file mode 100644 index 0000000000..c6a16319b2 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/tearoff/TearOffPreferencePage.java @@ -0,0 +1,78 @@ +/** + * 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.ui.menus.widgets.tearoff; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import com.raytheon.uf.viz.core.Activator; +import com.raytheon.uf.viz.core.localization.HierarchicalPreferenceStore; + +/** + * Preference page for tear off menus + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 23, 2011            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class TearOffPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + @Override + public void init(IWorkbench workbench) { + HierarchicalPreferenceStore store = Activator.getDefault() + .getPreferenceStore(); + setPreferenceStore(store); + setDescription("CAVE UI Preferences"); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors + * () + */ + @Override + protected void createFieldEditors() { + BooleanFieldEditor editor = new BooleanFieldEditor("tearoffmenus", + "Enable Tear-Off Menus (requires restart)", + getFieldEditorParent()); + addField(editor); + } +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IVizMenuManager.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IVizMenuManager.java new file mode 100644 index 0000000000..4112a67e68 --- /dev/null +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IVizMenuManager.java @@ -0,0 +1,9 @@ +package com.raytheon.uf.viz.ui.menus.xml; + +import org.eclipse.jface.action.IMenuListener; + +public interface IVizMenuManager { + public void addMenuListener(IMenuListener listener); + + public void removeMenuListener(IMenuListener listener); +} diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuContribution.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuContribution.java index be25d58148..62464ab95e 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuContribution.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuContribution.java @@ -60,6 +60,8 @@ import com.raytheon.uf.viz.ui.menus.widgets.SubmenuContributionItem; public class IncludeMenuContribution extends AbstractMenuContributionItem { + private SubmenuContributionItem submenuCont = null; + @Override public IContributionItem[] getContributionItems( CommonAbstractMenuContribution items, VariableSubstitution[] subs, @@ -71,9 +73,10 @@ public class IncludeMenuContribution extends newItem.id = item.id; newItem.substitutions = item.substitutions; newItem.suppressErrors = item.suppressErrors; - return new IContributionItem[] { new SubmenuContributionItem(subs, - item.subMenuName, - new CommonAbstractMenuContribution[] { newItem }, removals) }; + submenuCont = new SubmenuContributionItem(subs, item.subMenuName, + new CommonAbstractMenuContribution[] { newItem }, removals, + null); + return new IContributionItem[] { submenuCont }; } return getContributionItemsInternal(items, subs, removals); } @@ -119,5 +122,4 @@ public class IncludeMenuContribution extends return contribList.toArray(new IContributionItem[contribList.size()]); } - } diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuItem.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuItem.java index 6a9e61875f..94fea49fe6 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuItem.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/IncludeMenuItem.java @@ -31,6 +31,7 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; import com.raytheon.uf.common.localization.PathManagerFactory; import com.raytheon.uf.common.menus.MenuSerialization; @@ -64,10 +65,14 @@ import com.raytheon.uf.viz.ui.menus.widgets.SubmenuContributionItem; */ public class IncludeMenuItem extends CommonIncludeMenuItem implements - IContribItemProvider, ISerializableObject { + IContribItemProvider, ISerializableObject, IVizMenuManager { static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(IncludeMenuItem.class); + private SubmenuContributionItem submenuCont = null; + + private IMenuListener mListener = null; + /* * (non-Javadoc) * @@ -81,8 +86,8 @@ public class IncludeMenuItem extends CommonIncludeMenuItem implements VariableSubstitution[] incomingSubs, Set removalsIn) throws VizException { if (subMenuName != null) { - return new IContributionItem[] { new SubmenuContributionItem( - incomingSubs, subMenuName, null, removalsIn) { + submenuCont = new SubmenuContributionItem(incomingSubs, + subMenuName, null, removalsIn, mListener) { @Override protected synchronized IContributionItem[][] getContributionItems() { @@ -97,7 +102,18 @@ public class IncludeMenuItem extends CommonIncludeMenuItem implements } return this.contributionItems; } - } }; + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.MenuManager#getId() + */ + @Override + public String getId() { + return subMenuName; + } + }; + return new IContributionItem[] { submenuCont }; } // return getAllContributionItems(items, incomingSubs, removalsIn); return new IContributionItem[] { new IncludeContributionItem(this, @@ -141,7 +157,8 @@ public class IncludeMenuItem extends CommonIncludeMenuItem implements continue; if (amc == null) { - System.out.println(c.getClass()); + System.out.println("There is no xml mapping for " + + c.getClass()); } IContributionItem[] contribItems = amc .getContributionItems(c, combinedSub, removalsSet); @@ -163,4 +180,19 @@ public class IncludeMenuItem extends CommonIncludeMenuItem implements } + @Override + public void addMenuListener(IMenuListener listener) { + mListener = listener; + // can't add it to the submenu if the submenu doesn't exist + if (submenuCont != null) { + submenuCont.addMenuListener(mListener); + } + } + + @Override + public void removeMenuListener(IMenuListener listener) { + if (submenuCont != null) { + submenuCont.removeMenuListener(listener); + } + } } diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/SubmenuContribution.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/SubmenuContribution.java index 667a1cf1ec..8ed85a8b2d 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/SubmenuContribution.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/xml/SubmenuContribution.java @@ -23,12 +23,14 @@ import java.util.HashSet; import java.util.Set; import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; import com.raytheon.uf.common.menus.xml.CommonAbstractMenuContribution; import com.raytheon.uf.common.menus.xml.CommonSubmenuContribution; import com.raytheon.uf.common.menus.xml.VariableSubstitution; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.ui.menus.widgets.SubmenuContributionItem; +import com.raytheon.uf.viz.ui.menus.widgets.tearoff.TearOffMenuListener; /** * Describes a submenu contribution @@ -46,7 +48,12 @@ import com.raytheon.uf.viz.ui.menus.widgets.SubmenuContributionItem; * @version 1.0 */ public class SubmenuContribution extends - AbstractMenuContributionItem { + AbstractMenuContributionItem implements + IVizMenuManager { + + private SubmenuContributionItem submenuCont = null; + + private IMenuListener mListener = null; /* * (non-Javadoc) @@ -64,9 +71,25 @@ public class SubmenuContribution extends if (removals.contains(item.id)) return new IContributionItem[0]; - final SubmenuContributionItem smci = new SubmenuContributionItem(subs, - item.menuText, item.contributions, new HashSet()); - return new IContributionItem[] { smci }; + submenuCont = new SubmenuContributionItem(subs, item.menuText, + item.contributions, new HashSet(), mListener); + // adding tear off listener, seems out of place, but must be done + if (mListener == null + && com.raytheon.uf.viz.core.Activator.getDefault() + .getPreferenceStore().getBoolean("tearoffmenus")) { + mListener = new TearOffMenuListener(submenuCont); + submenuCont.addMenuListener(mListener); + } + return new IContributionItem[] { submenuCont }; } + @Override + public void addMenuListener(IMenuListener listener) { + mListener = listener; + } + + @Override + public void removeMenuListener(IMenuListener listener) { + submenuCont.removeMenuListener(listener); + } } diff --git a/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF b/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF index eb121f6718..c06d3d53ca 100644 --- a/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF @@ -60,6 +60,7 @@ Import-Package: com.raytheon.edex.meteoLib, com.raytheon.uf.common.serialization.comm, com.raytheon.uf.viz.python.swt, com.raytheon.uf.viz.python.swt.widgets, + com.raytheon.uf.viz.ui.menus.widgets.tearoff, com.raytheon.viz.core.gl, com.raytheon.viz.pointdata, com.raytheon.viz.ui.tools.map, diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ui/GFEEditAreaMenu.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ui/GFEEditAreaMenu.java index 8b9a0db813..b0f7ab5504 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ui/GFEEditAreaMenu.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ui/GFEEditAreaMenu.java @@ -30,6 +30,7 @@ import org.eclipse.ui.actions.CompoundContributionItem; import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.CommandContributionItemParameter; +import com.raytheon.uf.viz.ui.menus.widgets.tearoff.TearOffMenuListener; import com.raytheon.viz.gfe.GFEPreference; import com.raytheon.viz.gfe.core.DataManager; import com.raytheon.viz.gfe.core.IReferenceSetManager; @@ -53,57 +54,81 @@ import com.raytheon.viz.gfe.core.IReferenceSetManager; */ public class GFEEditAreaMenu extends CompoundContributionItem { - private static final String COMMAND_ID = "com.raytheon.viz.gfe.actions.EditArea"; + private static final String COMMAND_ID = "com.raytheon.viz.gfe.actions.EditArea"; - private static final String NULL_COMMAND_ID = "com.raytheon.viz.ui.actions.nullAction"; + private static final String NULL_COMMAND_ID = "com.raytheon.viz.ui.actions.nullAction"; - /* - * (non-Javadoc) - * - * @see - * org.eclipse.ui.actions.CompoundContributionItem#getContributionItems() - */ - @Override - protected IContributionItem[] getContributionItems() { - MenuManager menuMgr = new MenuManager("Edit Areas"); - DataManager dm = DataManager.getCurrentInstance(); - if (dm != null) { - IReferenceSetManager refMgr = dm.getRefManager(); - List groupList = refMgr.getGroupInventory(); - groupList.add("Misc"); - int menuLength = GFEPreference - .getIntPreference("MaxMenuItemsBeforeCascade"); - menuLength = (menuLength > 1) ? menuLength : 30; - for (String group : groupList) { - MenuManager mm = new MenuManager(group); - menuMgr.add(mm); - int count = 0; - for (String ref : refMgr.getGroupData(group)) { - Map parms = new HashMap(); - parms.put("name", ref); - mm.add(new CommandContributionItem( - new CommandContributionItemParameter(PlatformUI - .getWorkbench(), null, COMMAND_ID, parms, - null, null, null, ref, null, null, - CommandContributionItem.STYLE_PUSH, null, - true))); - if (++count % menuLength == 0) { - MenuManager mm1 = new MenuManager("More"); - mm.add(mm1); - mm = mm1; - } - } + // private boolean addTear = true; - if (count == 0) { - mm.add(new CommandContributionItem( - new CommandContributionItemParameter(PlatformUI - .getWorkbench(), null, NULL_COMMAND_ID, - null, null, null, null, "", null, - null, CommandContributionItem.STYLE_PUSH, - null, true))); - } - } - } - return menuMgr.getItems(); - } + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.actions.CompoundContributionItem#getContributionItems() + */ + @Override + protected IContributionItem[] getContributionItems() { + // TODO, fix this code to not show extra items + // boolean needTear = com.raytheon.uf.viz.core.Activator.getDefault() + // .getPreferenceStore().getBoolean("tearoffmenus"); + + MenuManager menuMgr = new MenuManager("Edit Areas"); + DataManager dm = DataManager.getCurrentInstance(); + if (dm != null) { + IReferenceSetManager refMgr = dm.getRefManager(); + List groupList = refMgr.getGroupInventory(); + groupList.add("Misc"); + int menuLength = GFEPreference + .getIntPreference("MaxMenuItemsBeforeCascade"); + menuLength = (menuLength > 1) ? menuLength : 30; + // if (addTear && needTear) { + // menuMgr.addMenuListener(new TearOffMenuListener(menuMgr)); + // addTear = false; + // } + for (String group : groupList) { + MenuManager mm = new MenuManager(group); + menuMgr.add(mm); + + // if (needTear) { + // menuMgr.addMenuListener(new TearOffMenuListener(mm)); + // addTear = true; + // } + + int count = 0; + for (String ref : refMgr.getGroupData(group)) { + // if (needTear && addTear) { + // mm.addMenuListener(new TearOffMenuListener(mm)); + // addTear = false; + // } + Map parms = new HashMap(); + parms.put("name", ref); + mm.add(new CommandContributionItem( + new CommandContributionItemParameter(PlatformUI + .getWorkbench(), null, COMMAND_ID, parms, + null, null, null, ref, null, null, + CommandContributionItem.STYLE_PUSH, null, + true))); + if (++count % menuLength == 0) { + MenuManager mm1 = new MenuManager("More"); + mm.add(mm1); + mm = mm1; + // if (needTear && addTear) { + // mm.addMenuListener(new TearOffMenuListener(mm)); + // addTear = false; + // } + } + } + + if (count == 0) { + mm.add(new CommandContributionItem( + new CommandContributionItemParameter(PlatformUI + .getWorkbench(), null, NULL_COMMAND_ID, + null, null, null, null, "", null, + null, CommandContributionItem.STYLE_PUSH, + null, true))); + } + } + } + return menuMgr.getItems(); + } } diff --git a/cave/com.raytheon.viz.mpe.ui/plugin.xml b/cave/com.raytheon.viz.mpe.ui/plugin.xml index 7869350e32..e7d3064263 100644 --- a/cave/com.raytheon.viz.mpe.ui/plugin.xml +++ b/cave/com.raytheon.viz.mpe.ui/plugin.xml @@ -1,20 +1,20 @@ @@ -937,10 +937,12 @@ name="State" optional="false"> +