/*******************************************************************************
* Copyright (c) 2014, 2016 itemis AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.mvc.fx.ui.parts;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.gef.common.adapt.AdapterKey;
import org.eclipse.gef.fx.swt.canvas.IFXCanvasFactory;
import org.eclipse.gef.mvc.fx.domain.HistoricizingDomain;
import org.eclipse.gef.mvc.fx.domain.IDomain;
import org.eclipse.gef.mvc.fx.ui.actions.DeleteAction;
import org.eclipse.gef.mvc.fx.ui.actions.SelectAllAction;
import org.eclipse.gef.mvc.fx.ui.properties.IPropertySheetPageFactory;
import org.eclipse.gef.mvc.fx.viewer.IViewer;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.operations.UndoRedoActionGroup;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.services.IDisposable;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import com.google.inject.Inject;
import com.google.inject.Injector;
import javafx.embed.swt.FXCanvas;
import javafx.scene.Scene;
/**
* Abstract base class for views.
*
* @author Alexander Nyßen (anyssen)
*
*/
public abstract class AbstractFXView extends ViewPart {
@Inject
private IDomain domain;
@Inject
private IFXCanvasFactory canvasFactory;
private FXCanvas canvas = null;
@Inject(optional = true)
private ISelectionProviderFactory selectionProviderFactory;
private ISelectionProvider selectionProvider;
@Inject(optional = true)
private IPropertySheetPageFactory propertySheetPageFactory;
private IPropertySheetPage propertySheetPage;
private UndoRedoActionGroup undoRedoActionGroup;
private DeleteAction deleteAction;
private SelectAllAction selectAllAction;
/**
* Constructs a new {@link AbstractFXView} that uses the given
* {@link Injector} to inject its members.
*
* @param injector
* The {@link Injector} that is used to inject the members of
* this {@link AbstractFXView}.
*/
// TOOD: use executable extension factory to inject this class
public AbstractFXView(final Injector injector) {
injector.injectMembers(this);
}
/**
* Activates this {@link AbstractFXView} by activating the {@link IDomain}
* that was previously injected.
*/
protected void activate() {
domain.activate();
}
/**
* Create actions for this view and registers at the action bars of the
* view's site.
*/
protected void createActions() {
IViewSite site = getViewSite();
undoRedoActionGroup = new UndoRedoActionGroup(getSite(),
(IUndoContext) getAdapter(IUndoContext.class), true);
undoRedoActionGroup.fillActionBars(site.getActionBars());
deleteAction = new DeleteAction();
deleteAction.init(getContentViewer());
site.getActionBars().setGlobalActionHandler(
ActionFactory.DELETE.getId(), deleteAction);
selectAllAction = new SelectAllAction();
selectAllAction.init(getContentViewer());
site.getActionBars().setGlobalActionHandler(
ActionFactory.SELECT_ALL.getId(), selectAllAction);
}
private FXCanvas createCanvas(final Composite parent) {
return canvasFactory.createCanvas(parent, SWT.NONE);
}
@Override
public void createPartControl(final Composite parent) {
// create viewer and canvas only after toolkit has been initialized
canvas = createCanvas(parent);
// hook viewer controls and selection forwarder
hookViewers();
// register selection provider (if we want to a provide selection)
if (selectionProviderFactory != null) {
selectionProvider = selectionProviderFactory.create(this);
getSite().setSelectionProvider(selectionProvider);
}
// activate domain
activate();
}
private IPropertySheetPage createPropertySheetPage() {
if (propertySheetPageFactory != null) {
return propertySheetPageFactory.create(this);
}
return null;
}
/**
* Deactivates this {@link AbstractFXView} by deactivating its
* {@link IDomain} that was previously injected.
*/
protected void deactivate() {
domain.deactivate();
}
@Override
public void dispose() {
// deactivate domain
deactivate();
// unhook selection forwarder
unhookViewers();
// unregister selection provider
selectionProviderFactory = null;
if (selectionProvider != null) {
getSite().setSelectionProvider(null);
if (selectionProvider instanceof IDisposable) {
((IDisposable) selectionProvider).dispose();
}
selectionProvider = null;
}
// XXX: The propertySheetPage does not need to be disposed, as this is
// already done by the PropertySheet (view) when this view is closed.
propertySheetPage = null;
propertySheetPageFactory = null;
disposeActions();
domain.dispose();
domain = null;
canvasFactory = null;
if (!canvas.isDisposed()) {
canvas.dispose();
}
canvas = null;
super.dispose();
}
/**
* Dispose the actions created by this view.
*/
protected void disposeActions() {
if (undoRedoActionGroup != null) {
undoRedoActionGroup.dispose();
undoRedoActionGroup = null;
}
if (deleteAction != null) {
deleteAction.dispose();
deleteAction = null;
}
if (selectAllAction != null) {
selectAllAction.dispose();
selectAllAction = null;
}
}
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(final Class key) {
// Provide a default selection provider (subclasses may overwrite by
// handling the key and returning a different implementation
// replace with binding
if (ISelectionProvider.class.equals(key)) {
if (selectionProvider != null) {
return selectionProvider;
}
}
// contribute to Properties view (only created if required)
if (IPropertySheetPage.class.equals(key)) {
if (propertySheetPage == null) {
propertySheetPage = createPropertySheetPage();
}
if (propertySheetPage != null) {
return propertySheetPage;
}
}
if (IUndoContext.class.equals(key)) {
if (domain instanceof HistoricizingDomain) {
return ((HistoricizingDomain) domain).getUndoContext();
}
}
if (IOperationHistory.class.equals(key)) {
if (domain instanceof HistoricizingDomain) {
return ((HistoricizingDomain) domain).getOperationHistory();
}
}
return super.getAdapter(key);
}
/**
* Returns the {@link FXCanvas} that was previously created by the injected
* {@link IFXCanvasFactory}.
*
* @return The {@link FXCanvas} that was previously created by the injected
* {@link IFXCanvasFactory}.
*/
protected FXCanvas getCanvas() {
return canvas;
}
/**
* Returns the {@link IViewer} of the {@link IDomain} that was previously
* injected.
*
* @return The {@link IViewer} of the {@link IDomain} that was previously
* injected.
*/
public IViewer getContentViewer() {
return domain.getAdapter(
AdapterKey.get(IViewer.class, IDomain.CONTENT_VIEWER_ROLE));
}
/**
* Returns the {@link IDomain} that was previously injected.
*
* @return The {@link IDomain} that was previously injected.
*/
public IDomain getDomain() {
return domain;
}
/**
* Hooks all viewers that are part of this {@link AbstractFXView} into the
* {@link FXCanvas} that was previously created by the injected
* {@link IFXCanvasFactory}.
*/
protected void hookViewers() {
// by default we only have a single (content) viewer, so hook its
// visuals as root visuals into the scene
canvas.setScene(new Scene(getContentViewer().getCanvas()));
}
@Override
public void init(final IViewSite site) throws PartInitException {
super.init(site);
createActions();
}
@Override
public void setFocus() {
canvas.setFocus();
}
/**
* Unhooks all viewers that are part of this {@link AbstractFXView}.
*/
protected void unhookViewers() {
// TODO: What about taking the visuals out of the canvas?
}
}