/*
* Copyright (c) 2011, M. Woelker, H. Westphal
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of jo-widgets.org nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.jowidgets.workbench.impl.rcp.internal.part;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.jowidgets.api.model.item.IMenuModel;
import org.jowidgets.api.toolkit.Toolkit;
import org.jowidgets.api.widgets.IPopupMenu;
import org.jowidgets.common.types.Position;
import org.jowidgets.tools.controller.ListModelAdapter;
import org.jowidgets.tools.types.VetoHolder;
import org.jowidgets.workbench.api.ClosePolicy;
import org.jowidgets.workbench.api.IView;
import org.jowidgets.workbench.api.IViewLayout;
import org.jowidgets.workbench.api.ViewScope;
import org.jowidgets.workbench.impl.rcp.internal.ComponentContext;
import org.jowidgets.workbench.impl.rcp.internal.ViewContext;
import org.jowidgets.workbench.impl.rcp.internal.WorkbenchApplicationContext;
import org.jowidgets.workbench.impl.rcp.internal.WorkbenchContext;
import org.jowidgets.workbench.impl.rcp.internal.util.ImageHelper;
public final class DynamicView extends ViewPart implements IPartListener2 {
public static final String ID = "org.jowidgets.workbench.impl.rcp.internal.part.dynamicView"; //$NON-NLS-1$
private static final IAction EMPTY_ACTION = new Action() {};
private String viewId;
private IView view;
private ViewContext viewContext;
private Composite parent;
private IPopupMenu popupMenu;
@Override
public void createPartControl(final Composite viewComposite) {
viewId = getViewSite().getSecondaryId();
final ViewLayoutContext viewLayoutContext = PartSupport.getInstance().getViewLayoutContext(viewId);
if (viewLayoutContext == null) {
// view layout is not registered -> close it immediately
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().hideView(DynamicView.this);
}
});
return;
}
final IViewLayout viewLayout = viewLayoutContext.getViewLayout();
final ComponentContext componentContext = viewLayoutContext.getComponentContext();
setPartName(viewLayout.getLabel());
setTitleImage(ImageHelper.getImage(viewLayout.getIcon(), null));
setTitleToolTip(viewLayout.getTooltip());
viewComposite.setLayout(new FillLayout());
final ViewContext closedViewContext = PartSupport.getInstance().getViewContext(viewId);
if (closedViewContext != null) {
// re-use closed view
parent = closedViewContext.getParent();
final Composite dummyParent = parent.getParent();
parent.setParent(viewComposite);
dummyParent.dispose();
view = PartSupport.getInstance().getView(viewId);
viewContext = closedViewContext;
if (PartSupport.getInstance().isViewHiding(viewId)) {
view.onHiddenStateChanged(false);
viewContext.unsetHidden();
PartSupport.getInstance().clearViewHiding(viewId);
}
getViewSite().getPage().addPartListener(DynamicView.this);
}
else {
parent = new Composite(viewComposite, SWT.NONE);
// add paint listener to correct layout after re-setting perspective
parent.addPaintListener(new PaintListener() {
@Override
public void paintControl(final PaintEvent e) {
parent.layout();
}
});
}
final IMenuModel menuModel = viewLayoutContext.getFolderContext().getPopupMenu();
popupMenu = Toolkit.getWidgetWrapperFactory().createComposite(parent).createPopupMenu();
popupMenu.setModel(menuModel);
final IMenuManager menuManager = getViewSite().getActionBars().getMenuManager();
menuManager.setRemoveAllWhenShown(true);
if (!menuModel.getChildren().isEmpty()) {
menuManager.add(EMPTY_ACTION);
}
menuManager.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(final IMenuManager manager) {
final Point position = parent.toControl(parent.getDisplay().getCursorLocation());
popupMenu.show(new Position(position.x - 10, -3));
parent.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
menuManager.add(EMPTY_ACTION);
menuManager.update(true);
}
});
}
});
menuModel.addListModelListener(new ListModelAdapter() {
@Override
public void afterChildAdded(final int index) {
if (menuModel.getChildren().size() == 1) {
menuManager.add(EMPTY_ACTION);
menuManager.update(true);
}
}
@Override
public void afterChildRemoved(final int index) {
if (menuModel.getChildren().size() == 0) {
menuManager.removeAll();
menuManager.update(true);
}
}
});
if (closedViewContext == null) {
// lazy initialization of view content
getViewSite().getPage().addPartListener(new IPartListener2() {
@Override
public void partVisible(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == DynamicView.this) {
init();
}
}
@Override
public void partOpened(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
// needed for lazy initializing detached views, since partVisible() is not fired for them apparently
if (part == DynamicView.this
&& part.getSite().getShell() != PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()) {
init();
}
}
private void init() {
final ViewScope scope = viewLayout.getScope();
viewContext = new ViewContext(getViewSite().getId(), scope, parent, componentContext);
if (scope == ViewScope.COMPONENT) {
view = componentContext.getComponent().createView(viewLayout.getId(), viewContext);
}
else if (scope == ViewScope.WORKBENCH_APPLICATION) {
view = ((WorkbenchApplicationContext) componentContext.getWorkbenchApplicationContext()).getApplication().createView(
viewLayout.getId(),
viewContext);
}
else if (scope == ViewScope.WORKBENCH) {
view = ((WorkbenchContext) componentContext.getWorkbenchContext()).getWorkbench().createView(
viewLayout.getId(),
viewContext);
}
else {
throw new IllegalStateException("unsupported view layout scope: " + viewLayout.getScope());
}
PartSupport.getInstance().setViewAndContext(viewId, view, viewContext);
final IWorkbenchPage page = getViewSite().getPage();
page.removePartListener(this);
view.onVisibleStateChanged(true);
page.addPartListener(DynamicView.this);
}
@Override
public void partInputChanged(final IWorkbenchPartReference partRef) {}
@Override
public void partHidden(final IWorkbenchPartReference partRef) {}
@Override
public void partDeactivated(final IWorkbenchPartReference partRef) {}
@Override
public void partClosed(final IWorkbenchPartReference partRef) {}
@Override
public void partBroughtToTop(final IWorkbenchPartReference partRef) {}
@Override
public void partActivated(final IWorkbenchPartReference partRef) {}
});
}
}
@Override
public void partActivated(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == this && view != null) {
view.onActiveStateChanged(true);
}
}
@Override
public void partDeactivated(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == this && view != null) {
view.onActiveStateChanged(false);
}
}
@Override
public void partVisible(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == this && view != null) {
view.onVisibleStateChanged(true);
}
}
@Override
public void partHidden(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == this && view != null) {
view.onVisibleStateChanged(false);
}
}
@Override
public void partClosed(final IWorkbenchPartReference partRef) {
final IWorkbenchPart part = partRef.getPart(false);
if (part == this && view != null) {
if (!PlatformUI.getWorkbench().isClosing()) {
if (!PartSupport.getInstance().isViewClosing(viewId)) {
if (PartSupport.getInstance().isViewHiding(viewId)) {
// re-parent composite to re-use it when opening view again
parent.setParent(new Shell());
view.onHiddenStateChanged(true);
return;
}
final VetoHolder vetoHolder = new VetoHolder();
view.onClose(vetoHolder);
if (vetoHolder.hasVeto()) {
// re-parent composite to re-use it when opening view again
parent.setParent(new Shell());
final IViewReference viewRef = (IViewReference) partRef;
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(
viewRef.getId(),
viewRef.getSecondaryId(),
IWorkbenchPage.VIEW_ACTIVATE);
}
catch (final PartInitException e) {
throw new RuntimeException(e);
}
return;
}
// TODO HW fix handling of hide policy
if (PartSupport.getInstance().getViewLayoutContext(viewId).getViewLayout().getClosePolicy() == ClosePolicy.HIDE) {
// re-parent composite to re-use it when opening view again
parent.setParent(new Shell());
view.onHiddenStateChanged(true);
return;
}
}
PartSupport.getInstance().removeViewAndContext(viewId);
}
view.onDispose();
}
}
@Override
public void partBroughtToTop(final IWorkbenchPartReference partRef) {}
@Override
public void partOpened(final IWorkbenchPartReference partRef) {}
@Override
public void partInputChanged(final IWorkbenchPartReference partRef) {}
@Override
public void setFocus() {
if (viewContext != null) {
((Composite) viewContext.getContainer().getUiReference()).setFocus();
}
}
@Override
public void dispose() {
((Menu) popupMenu.getUiReference()).dispose();
super.dispose();
}
}