Merge "Issue #808 create API for managing floating views and made CaveDetachedWindow more robust." into development

Former-commit-id: c0dad4432c [formerly 80746bd2c441de92304fb1dabdcfbd66ce3f49a6]
Former-commit-id: 1b3d6560e4
This commit is contained in:
Nate Jensen 2012-07-12 17:17:57 -05:00 committed by Gerrit Code Review
commit 565100d787
3 changed files with 476 additions and 145 deletions

View file

@ -37,13 +37,13 @@ import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.DetachedWindow;
import org.eclipse.ui.internal.EditorManager;
import org.eclipse.ui.internal.ILayoutContainer;
import org.eclipse.ui.internal.IWorkbenchConstants;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.LayoutPart;
@ -56,6 +56,7 @@ import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.internal.dnd.IDragOverListener;
import org.eclipse.ui.internal.dnd.IDropTarget;
import org.eclipse.ui.internal.presentations.PresentationFactoryUtil;
import org.eclipse.ui.presentations.IPresentablePart;
import org.eclipse.ui.presentations.StackDropResult;
/**
@ -84,6 +85,13 @@ public class CaveDetachedWindow extends DetachedWindow implements
// wasn't canceled
e.doit = handleClose();
}
@Override
public void shellActivated(ShellEvent e) {
page.getPartService().setActivePart(
folder.getSelection().getPartReference());
}
};
private Listener resizeListener = new Listener() {
@ -119,7 +127,111 @@ public class CaveDetachedWindow extends DetachedWindow implements
this.page = workbenchPage;
folder = new ViewStack(page, false, PresentationFactoryUtil.ROLE_VIEW,
null);
null) {
/**
* Override close because super.close expects to find the view in
* the page.
*/
@Override
protected void close(IPresentablePart part) {
if (!presentationSite.isCloseable(part)) {
return;
}
LayoutPart layoutPart = getPaneFor(part);
if (layoutPart != null && layoutPart instanceof PartPane) {
PartPane viewPane = (PartPane) layoutPart;
IViewReference ref = (IViewReference) viewPane
.getPartReference();
CaveWorkbenchPageManager.getInstance(page).hideView(ref);
}
}
/**
* Override paneDragStart so we can check if the stack is empty and
* close the window
*/
@Override
public void paneDragStart(LayoutPart pane, Point initialLocation,
boolean keyboard) {
super.paneDragStart(pane, initialLocation, keyboard);
if (pane == null) {
// This means the whole stack is getting dragged:
for (LayoutPart lpart : getChildren()) {
checkChild(lpart);
}
} else {
checkChild(pane);
}
}
/**
* Use this after dragging to check if I still only my children,
* normally the page removes them but that doesn't work for
* CaveDetachedWindows so this removes it from the stack when
* someone else gets it.
*
* @param pane
*/
private void checkChild(LayoutPart pane) {
if (pane.getContainer() != this) {
// the part does nto get properly dereferenced since it is
// not part of the page
ILayoutContainer newContainer = pane.getContainer();
newContainer.remove(pane);
remove(pane);
newContainer.add(pane);
if (this.getItemCount() == 0 && windowShell != null) {
windowShell.dispose();
}
}
}
/**
* Override add so we can change floating status
*/
@Override
public void add(LayoutPart child, Object cookie) {
super.add(child, cookie);
setFloating(child, true);
}
/**
* Override remove so we can change floating status
*/
@Override
public void remove(LayoutPart child) {
super.remove(child);
setFloating(child, false);
}
private void setFloating(LayoutPart child, boolean floating) {
if (child instanceof ViewPane) {
ViewPane pane = (ViewPane) child;
IViewPart view = pane.getViewReference().getView(false);
if (view instanceof CaveFloatingView) {
((CaveFloatingView) view).setFloating(floating);
}
}
}
/**
* Override set selection so we can fire appropriate activation
* listeners.
*/
@Override
public void setSelection(LayoutPart part) {
super.setSelection(part);
if (part instanceof PartPane) {
page.getPartService().setActivePart(
((PartPane) part).getPartReference());
}
}
};
folder.addListener(propertyListener);
}
@ -180,6 +292,7 @@ public class CaveDetachedWindow extends DetachedWindow implements
public void create() {
windowShell = new Shell(Display.getCurrent(), SWT.SHELL_TRIM);
windowShell.addShellListener(shellListener);
windowShell.setData(this);
windowShell.setText("Detached Window");
DragUtil.addDragTarget(windowShell, this);
@ -214,33 +327,6 @@ public class CaveDetachedWindow extends DetachedWindow implements
folder.setBounds(windowShell.getClientArea());
}
/**
* Adds a visual part to this window. Supports reparenting.
*/
public void add(ViewPane part) {
Shell shell = getShell();
if (shell != null) {
part.reparent(shell);
}
folder.add(part);
updateMinimumSize();
}
public boolean belongsToWorkbenchPage(IWorkbenchPage workbenchPage) {
return (this.page == workbenchPage);
}
public boolean close() {
hideViewsOnClose = false;
Shell shell = getShell();
if (shell != null && !shell.isDisposed()) {
shell.removeShellListener(shellListener);
shell.close();
}
return true;
}
/**
* Closes this window and disposes its shell.
*/
@ -262,7 +348,8 @@ public class CaveDetachedWindow extends DetachedWindow implements
// Only close if closable...
if (child.isCloseable()) {
page.hideView(child.getViewReference());
CaveWorkbenchPageManager.getInstance(page).hideView(
child.getViewReference());
// Was the close cancelled?
if (child.getContainer() != null)
@ -352,34 +439,36 @@ public class CaveDetachedWindow extends DetachedWindow implements
public IDropTarget drag(Control currentControl, Object draggedObject,
Point position, Rectangle dragRectangle) {
if (!(draggedObject instanceof PartPane)) {
if (!(draggedObject instanceof ViewPane)) {
return null;
}
final PartPane sourcePart = (PartPane) draggedObject;
ViewPane sourcePart = (ViewPane) draggedObject;
if (sourcePart.getWorkbenchWindow() != page.getWorkbenchWindow()) {
return null;
}
// Only handle the event if the source part is acceptable to the
// particular PartStack
IDropTarget target = null;
if (sourcePart instanceof ViewPane) {
target = folder.getDropTarget(draggedObject, position);
if (target == null) {
Rectangle displayBounds = DragUtil.getDisplayBounds(folder
.getControl());
if (displayBounds.contains(position)) {
target = folder.createDropTarget(sourcePart,
new StackDropResult(displayBounds, null));
} else {
return null;
}
}
// If you put views in a CaveDetachedWindow then you can't find them
// using the workbenchPage, this is expected for FLoatingViews but
// puttiing other views in the detached window would cause API problems
// by unexpectedly losing views.
if (!(sourcePart.getViewReference().getPart(false) instanceof CaveFloatingView)) {
return null;
}
IDropTarget target = folder.getDropTarget(draggedObject, position);
if (target == null) {
Rectangle displayBounds = DragUtil.getDisplayBounds(folder
.getControl());
if (displayBounds.contains(position)) {
target = folder.createDropTarget(sourcePart,
new StackDropResult(displayBounds, null));
} else {
return null;
}
}
return target;
}
@ -441,35 +530,6 @@ public class CaveDetachedWindow extends DetachedWindow implements
return this.page;
}
/**
* @see IPersistablePart
*/
public void restoreState(IMemento memento) {
// Read the bounds.
Integer bigInt;
bigInt = memento.getInteger(IWorkbenchConstants.TAG_X);
int x = bigInt.intValue();
bigInt = memento.getInteger(IWorkbenchConstants.TAG_Y);
int y = bigInt.intValue();
bigInt = memento.getInteger(IWorkbenchConstants.TAG_WIDTH);
int width = bigInt.intValue();
bigInt = memento.getInteger(IWorkbenchConstants.TAG_HEIGHT);
int height = bigInt.intValue();
bigInt = memento.getInteger(IWorkbenchConstants.TAG_FLOAT);
// Set the bounds.
bounds = new Rectangle(x, y, width, height);
if (getShell() != null) {
getShell().setBounds(bounds);
}
// Create the folder.
IMemento childMem = memento.getChild(IWorkbenchConstants.TAG_FOLDER);
if (childMem != null) {
folder.restoreState(childMem);
}
}
/**
* @see IPersistablePart
*/
@ -517,4 +577,8 @@ public class CaveDetachedWindow extends DetachedWindow implements
return Window.OK;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}

View file

@ -24,19 +24,7 @@ import java.io.File;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ILayoutContainer;
import org.eclipse.ui.internal.PartPane;
import org.eclipse.ui.internal.ViewPane;
import org.eclipse.ui.internal.ViewSite;
import org.eclipse.ui.internal.WorkbenchPage;
import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.part.ViewPart;
import com.raytheon.viz.ui.UiPlugin;
@ -61,13 +49,7 @@ import com.raytheon.viz.ui.UiPlugin;
public abstract class CaveFloatingView extends ViewPart {
private boolean detached;
private CaveDetachedWindow window;
private ILayoutContainer container;
private Rectangle bounds;
protected FloatAction floatAction;
/**
* Constructs the view
@ -81,8 +63,13 @@ public abstract class CaveFloatingView extends ViewPart {
createToolbarButton();
}
public IViewPart getPart() {
return this;
public void setFloating(boolean floating) {
floatAction.setChecked(floating);
if (floating) {
floatAction.setToolTipText("Dock");
} else {
floatAction.setToolTipText("Float");
}
}
/**
@ -90,57 +77,31 @@ public abstract class CaveFloatingView extends ViewPart {
*/
protected void createToolbarButton() {
IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager();
final Action floatAction = new Action("Float", SWT.TOGGLE) {
@Override
public void run() {
// should only run when the user is currently attached to cave
// (or detached, but not a floating dialog)
this.setToolTipText("Dock");
setChecked(true);
detached = true;
WorkbenchPage page = (WorkbenchPage) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage();
bounds = ((ViewSite) ((ViewPart) getPart()).getViewSite())
.getPane().getBounds();
floatAction = new FloatAction();
mgr.add(floatAction);
container = ((ViewSite) ((ViewPart) getPart()).getViewSite())
.getPane().getStack();
window = new CaveDetachedWindow(page);
window.create();
window.open();
}
bounds.x += PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell().getMonitor()
.getBounds().x;
ViewPane pane = (ViewPane) ((ViewSite) getPart().getViewSite())
.getPane();
container = pane.getContainer();
window.drop(pane);
window.getShell().setBounds(bounds);
};
private class FloatAction extends Action {
@Override
public void runWithEvent(Event event) {
if (!detached) {
run();
return;
}
setToolTipText("Float");
setChecked(false);
detached = false;
WorkbenchPage page = (WorkbenchPage) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage();
PartPane layoutPart = ((ViewSite) getPart().getViewSite())
.getPane();
Point point = new Point(bounds.x + bounds.width / 2, bounds.y
+ bounds.height / 2);
window.getShell().setVisible(false);
window = null;
DragUtil.dragTo(Display.getCurrent(), layoutPart, point, bounds);
public FloatAction() {
super("Float", SWT.TOGGLE);
setImageDescriptor(UiPlugin.getImageDescriptor("icons"
+ File.separator + "float.gif"));
}
@Override
public void run() {
if (isChecked()) {
CaveWorkbenchPageManager manager = CaveWorkbenchPageManager
.getInstance(getSite().getPage());
manager.floatView(CaveFloatingView.this);
} else {
CaveWorkbenchPageManager manager = CaveWorkbenchPageManager
.getInstance(getSite().getPage());
manager.dockView(CaveFloatingView.this);
}
};
floatAction.setImageDescriptor(UiPlugin.getImageDescriptor("icons"
+ File.separator + "float.gif"));
mgr.add(floatAction);
}
}

View file

@ -0,0 +1,306 @@
/**
* 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.viz.ui.views;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IPageListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ILayoutContainer;
import org.eclipse.ui.internal.LayoutPart;
import org.eclipse.ui.internal.PartPane;
import org.eclipse.ui.internal.PartStack;
import org.eclipse.ui.internal.ViewPane;
import org.eclipse.ui.internal.ViewSite;
import org.eclipse.ui.internal.WorkbenchPage;
/**
* The Eclipse WorkbenchPage has lots of nifty functions for dealing with views,
* but unfortunately it fails to take into account CaveFloatingViews that are in
* CaveDetachedWindows, the goal of this class is to provide an API of equal
* niftosity that works for CaveFloatingViews.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class CaveWorkbenchPageManager {
private static Map<IWorkbenchPage, CaveWorkbenchPageManager> instanceMap = new HashMap<IWorkbenchPage, CaveWorkbenchPageManager>();
public static CaveWorkbenchPageManager getInstance(IWorkbenchPage page) {
synchronized (instanceMap) {
CaveWorkbenchPageManager instance = instanceMap.get(page);
if (instance == null) {
instance = new CaveWorkbenchPageManager(page);
instanceMap.put(page, instance);
}
return instance;
}
}
public static CaveWorkbenchPageManager getActiveInstance() {
synchronized (instanceMap) {
return getInstance(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage());
}
}
private final IWorkbenchPage workbenchPage;
private List<CaveDetachedWindow> detachedWindows = new ArrayList<CaveDetachedWindow>();
private CaveWorkbenchPageManager(IWorkbenchPage workbenchPage) {
this.workbenchPage = workbenchPage;
workbenchPage.getWorkbenchWindow().addPageListener(
new PageListener(this));
}
public IWorkbenchPage getWorkbenchPage() {
return workbenchPage;
}
public IViewReference[] getViewReferences() {
if (detachedWindows.isEmpty()) {
return workbenchPage.getViewReferences();
}
List<IViewReference> result = Arrays.asList(workbenchPage
.getViewReferences());
result = new ArrayList<IViewReference>(result);
for (CaveDetachedWindow window : detachedWindows) {
for (LayoutPart part : window.getChildren()) {
if (part instanceof ViewPane) {
result.add(((ViewPane) part).getViewReference());
}
}
}
return result.toArray(new IViewReference[0]);
}
public IViewPart showView(String viewID) throws PartInitException {
return showView(viewID, null, IWorkbenchPage.VIEW_ACTIVATE);
}
public IViewPart showView(String viewId, String secondaryId, int mode)
throws PartInitException {
IViewReference ref = findDetachedViewReference(viewId, secondaryId);
if (ref != null) {
IViewPart view = ref.getView(true);
if (mode == IWorkbenchPage.VIEW_ACTIVATE) {
activate(view);
} else if (mode == IWorkbenchPage.VIEW_VISIBLE) {
workbenchPage.bringToTop(view);
}
return view;
}
return workbenchPage.showView(viewId, secondaryId, mode);
}
public void activate(IViewPart view) {
for (CaveDetachedWindow window : detachedWindows) {
for (LayoutPart part : window.getChildren()) {
if (((ViewPane) part).getPartReference().getPart(false) == view) {
window.getShell().forceActive();
ILayoutContainer container = part.getContainer();
if (container != null && container instanceof PartStack) {
PartStack folder = (PartStack) container;
if (folder.getSelection() != part) {
folder.setSelection(part);
}
}
return;
}
}
}
workbenchPage.activate(view);
}
public void bringToTop(IViewPart view) {
for (CaveDetachedWindow window : detachedWindows) {
for (LayoutPart part : window.getChildren()) {
if (((ViewPane) part).getPartReference().getPart(false) == view) {
window.getShell().moveAbove(null);
ILayoutContainer container = part.getContainer();
if (container != null && container instanceof PartStack) {
PartStack folder = (PartStack) container;
if (folder.getSelection() != part) {
folder.setSelection(part);
}
}
return;
}
}
}
workbenchPage.bringToTop(view);
}
public IViewReference findViewReference(String viewId) {
return findViewReference(viewId, null);
}
public IViewReference findViewReference(String viewId, String secondaryId) {
IViewReference ref = findDetachedViewReference(viewId, secondaryId);
if (ref == null) {
ref = workbenchPage.findViewReference(viewId, secondaryId);
}
return ref;
}
private IViewReference findDetachedViewReference(String viewId,
String secondaryId) {
for (CaveDetachedWindow window : detachedWindows) {
for (LayoutPart part : window.getChildren()) {
if (part instanceof ViewPane) {
IViewReference ref = ((ViewPane) part).getViewReference();
if (ref.getId().equals(viewId)
&& ((secondaryId == null && ref.getSecondaryId() == null) || secondaryId
.equals(ref.getSecondaryId()))) {
return ref;
}
}
}
}
return null;
}
public void hideView(IViewReference view) {
for (CaveDetachedWindow window : detachedWindows) {
for (LayoutPart part : window.getChildren()) {
if (part instanceof ViewPane) {
if (((ViewPane) part).getPartReference() == view) {
WorkbenchPage page = (WorkbenchPage) workbenchPage;
if (page.getActivePartReference() == view) {
// You cannot hide the active part, normally the
// page changes the active part but since we bypass
// the page we need to choose a new active part
for (IWorkbenchPartReference wbRef : page
.getSortedParts()) {
if (wbRef != view) {
page.activate(wbRef.getPart(false));
break;
}
}
}
page.getActivePerspective().hideView(view);
return;
}
}
}
}
workbenchPage.hideView(view);
}
public void floatView(IViewPart part) {
ViewSite site = ((ViewSite) part.getViewSite());
WorkbenchPage page = (WorkbenchPage) site.getPage();
PartPane pane = site.getPane();
Control control = pane.getStack().getControl();
Rectangle bounds = control.getBounds();
Point corner = control.getParent().toDisplay(bounds.x, bounds.y);
bounds.x = corner.x;
bounds.y = corner.y;
CaveDetachedWindow window = new CaveDetachedWindow(page);
window.setBounds(bounds);
window.create();
window.drop(pane);
window.getShell().setBounds(bounds);
window.getShell().addShellListener(new ShellListener(this, window));
window.open();
window.getShell().forceActive();
detachedWindows.add(window);
}
public void dockView(IViewPart part) {
WorkbenchPage page = (WorkbenchPage) part.getSite().getPage();
IViewReference ref = (IViewReference) page.getReference(part);
page.attachView(ref);
}
private static class ShellListener extends ShellAdapter {
private final CaveWorkbenchPageManager manager;
private final CaveDetachedWindow window;
public ShellListener(CaveWorkbenchPageManager manager,
CaveDetachedWindow window) {
this.manager = manager;
this.window = window;
}
@Override
public void shellClosed(ShellEvent e) {
manager.detachedWindows.remove(window);
}
}
private static class PageListener implements IPageListener {
private final CaveWorkbenchPageManager manager;
public PageListener(CaveWorkbenchPageManager manager) {
this.manager = manager;
}
@Override
public void pageActivated(IWorkbenchPage page) {
}
@Override
public void pageClosed(IWorkbenchPage page) {
if (page == manager.getWorkbenchPage()) {
page.getWorkbenchWindow().removePageListener(this);
}
}
@Override
public void pageOpened(IWorkbenchPage page) {
}
}
}