Merge "Issue #26 add tear off code to git baseline" into 10-Tech_Blocked

Former-commit-id: f37c6c8286 [formerly 4a1bf4fc3e [formerly 23d17e07b1b09e841eb84903c9448dcc4d96a7e3]]
Former-commit-id: 4a1bf4fc3e
Former-commit-id: 54e5792bf0
This commit is contained in:
Lee Venable 2012-01-25 13:46:01 -06:00 committed by Gerrit Code Review
commit 6600fe68a3
30 changed files with 2875 additions and 169 deletions

View file

@ -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

View file

@ -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<String, String> parms = new HashMap<String, String>();
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));
}
}

View file

@ -23,6 +23,7 @@
<httpServerAddress>http://localhost:9581/services</httpServerAddress>
<dataDirectory>/awips2/edex/data/share</dataDirectory>
<textureCardPreference>512</textureCardPreference>
<tearoffmenus>true</tearoffmenus>
<framesPerSecondPreference>25</framesPerSecondPreference>
<tileBoundaries>false</tileBoundaries>
<fontMagnification>1.0</fontMagnification>

View file

@ -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

View file

@ -12,4 +12,11 @@
extensionFilter=".xml">
</path>
</extension>
<extension
point="org.eclipse.ui.preferencePages">
<page
class="com.raytheon.uf.viz.ui.menus.widgets.tearoff.TearOffPreferencePage"
id="com.raytheon.uf.viz.ui.menus.tearoffpreferencepage"
name="Tear-Off Menus"/>
</extension>
</plugin>

View file

@ -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);
}

View file

@ -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 {
}
}
}
}

View file

@ -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<String> removals;
/**
*
* @param includeSubstitutions
* @param name
* @param ci
* @param removals
* @param mListener
*/
public SubmenuContributionItem(VariableSubstitution[] includeSubstitutions,
String name, CommonAbstractMenuContribution[] ci,
Set<String> removals) {
super();
Set<String> 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<String, String> 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);
}
}
}
}
}

View file

@ -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

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 15, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 5, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 14, 2011 mnash Initial creation
*
* </pre>
*
* @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();
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 14, 2011 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class TearOffMenuListener implements IMenuListener2 {
private List<IMenuManager> openDialogs = new ArrayList<IMenuManager>();
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;
}
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 23, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 15, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 5, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 14, 2011 mnash Initial creation
*
* </pre>
*
* @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();
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 14, 2011 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class TearOffMenuListener implements IMenuListener2 {
private List<IMenuManager> openDialogs = new ArrayList<IMenuManager>();
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;
}
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 23, 2011 mnash Initial creation
*
* </pre>
*
* @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);
}
}

View file

@ -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);
}

View file

@ -60,6 +60,8 @@ import com.raytheon.uf.viz.ui.menus.widgets.SubmenuContributionItem;
public class IncludeMenuContribution extends
AbstractMenuContributionItem<CommonIncludeMenuContribution> {
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()]);
}
}

View file

@ -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<String> 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);
}
}
}

View file

@ -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<CommonSubmenuContribution> {
AbstractMenuContributionItem<CommonSubmenuContribution> 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<String>());
return new IContributionItem[] { smci };
submenuCont = new SubmenuContributionItem(subs, item.menuText,
item.contributions, new HashSet<String>(), 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);
}
}

View file

@ -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,

View file

@ -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<String> 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<String, String> parms = new HashMap<String, String>();
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, "<Empty>", 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<String> 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<String, String> parms = new HashMap<String, String>();
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, "<Empty>", null,
null, CommandContributionItem.STYLE_PUSH,
null, true)));
}
}
}
return menuMgr.getItems();
}
}

View file

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
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
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.
-->
@ -937,10 +937,12 @@
name="State"
optional="false">
</commandParameter>
<!--
<state
class="org.eclipse.ui.handlers.RadioState:Contrast"
id="org.eclipse.ui.commands.radioState">
</state>
-->
</command>
<command
id="com.raytheon.viz.mpe.ui.actions.saveBestEstimate"

View file

@ -312,7 +312,7 @@ public class MPEDisplayManager {
public static MPEDisplayManager getCurrent() {
MPEDisplayManager instance = null;
IEditorPart editor = EditorUtil.getActiveEditor();
if (editor != null && editor instanceof IDisplayPaneContainer) {
if ((editor != null) && (editor instanceof IDisplayPaneContainer)) {
IDisplayPane pane = null;
if (editor instanceof IMultiPaneEditor) {
IMultiPaneEditor multiPane = (IMultiPaneEditor) editor;
@ -420,8 +420,7 @@ public class MPEDisplayManager {
displayMode = EnumSet.noneOf(DisplayMode.class);
gageDisplay = EnumSet.noneOf(GageDisplay.class);
gageMissing = GageMissingOptions.MissingNone;
gageColor = GageColor.valueOf(String.valueOf(colorCommand.getState(
RadioState.STATE_ID).getValue()));
gageColor = GageColor.Solid;
VizApp.runAsync(new Runnable() {
@Override
@ -891,6 +890,12 @@ public class MPEDisplayManager {
*/
public void setGageColor(GageColor gc) {
gageColor = gc;
final ICommandService service = (ICommandService) PlatformUI
.getWorkbench().getService(ICommandService.class);
service.refreshElements(
"com.raytheon.viz.mpe.ui.actions.toggleGageColor", null);
}
/**

View file

@ -19,10 +19,14 @@
**/
package com.raytheon.viz.mpe.ui.actions;
import java.util.Map;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.RadioState;
import org.eclipse.ui.menus.UIElement;
import com.raytheon.viz.mpe.ui.MPEDisplayManager;
import com.raytheon.viz.mpe.ui.MPEDisplayManager.GageColor;
@ -43,7 +47,8 @@ import com.raytheon.viz.mpe.ui.MPEDisplayManager.GageColor;
* @version 1.0
*/
public class ToggleGageColor extends AbstractHandler {
public class ToggleGageColor extends AbstractHandler implements
IElementUpdater {
/*
* (non-Javadoc)
*
@ -59,4 +64,17 @@ public class ToggleGageColor extends AbstractHandler {
return null;
}
@SuppressWarnings("unchecked")
@Override
public void updateElement(UIElement element, Map parameters) {
MPEDisplayManager dm = MPEDisplayManager.getCurrent();
if (dm == null) {
return;
}
GageColor color = dm.getGageColor();
String g = (String) parameters.get(RadioState.PARAMETER_ID);
GageColor val = GageColor.valueOf(g);
element.setChecked(color.equals(val));
}
}

View file

@ -33,6 +33,7 @@ import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import com.raytheon.uf.viz.ui.menus.DiscoverMenuContributions;
import com.raytheon.uf.viz.ui.menus.widgets.tearoff.TearOffMenuListener;
import com.raytheon.viz.ui.dialogs.ModeListener;
import com.raytheon.viz.ui.perspectives.AbstractVizPerspectiveManager;
import com.raytheon.viz.ui.perspectives.VizPerspectiveListener;
@ -135,6 +136,12 @@ public class VizWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
if (perspective != null) {
listener.perspectiveActivated(page, perspective);
}
if (com.raytheon.uf.viz.core.Activator.getDefault()
.getPreferenceStore().getBoolean("tearoffmenus")) {
new TearOffMenuListener(VizActionBarAdvisor.getInstance(window)
.getMenuManager());
}
}
/*