/*******************************************************************************
* Copyright (c) 2012 Arapiki Solutions Inc.
* 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:
* psmith - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package com.buildml.eclipse.packages;
import org.eclipse.emf.common.util.URI;
import org.eclipse.graphiti.ui.editor.DiagramBehavior;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.graphiti.ui.editor.DiagramEditorInput;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.PartInitException;
import com.buildml.eclipse.ISubEditor;
import com.buildml.eclipse.MainEditor;
import com.buildml.eclipse.packages.layout.LayoutAlgorithm;
import com.buildml.eclipse.utils.EclipsePartUtils;
import com.buildml.model.IActionMgr;
import com.buildml.model.IActionMgrListener;
import com.buildml.model.IBuildStore;
import com.buildml.model.IFileGroupMgr;
import com.buildml.model.IFileGroupMgrListener;
import com.buildml.model.IPackageMemberMgr;
import com.buildml.model.IPackageMemberMgr.PackageDesc;
import com.buildml.model.IPackageMemberMgrListener;
import com.buildml.model.IPackageMgr;
import com.buildml.model.IPackageMgrListener;
import com.buildml.model.ISubPackageMgr;
import com.buildml.model.ISubPackageMgrListener;
import com.buildml.model.types.PackageSet;
import com.buildml.utils.types.IntegerTreeSet;
/**
* A Graphiti DiagramEditor for displaying a BuildML package. This editor would typically
* appears within one of the tabs in the BuildML main editor.
*
* @author Peter Smith <psmith@arapiki.com>
*/
public class PackageDiagramEditor extends DiagramEditor
implements ISubEditor, IPackageMgrListener,
IActionMgrListener, IPackageMemberMgrListener,
IFileGroupMgrListener, ISubPackageMgrListener {
/*=====================================================================================*
* FIELDS/TYPES
*=====================================================================================*/
/** The BuildStore we're editing */
private IBuildStore buildStore = null;
/** The PackageMgr we're using for package information */
private IPackageMgr pkgMgr = null;
/** The PackageMgr we're using for package membership */
private IPackageMemberMgr pkgMemberMgr = null;
/** The FileGroupMgr we're using for file group content */
private IFileGroupMgr fileGroupMgr = null;
/** The ActionMgr we're using for action information */
private IActionMgr actionMgr = null;
/** The SubPackageMgr we're using for sub-package information */
private ISubPackageMgr subPkgMgr = null;
/** The ID of the package we're displaying */
private int packageId;
/** The layout algorithm for determining the location of members on the package */
private LayoutAlgorithm layoutAlgorithm;
/** The object (associated with this editor) that manages our behaviour */
private PackageDiagramBehaviour behaviour = null;
/** The delegate object that Graphiti queries to see if our underlying model has changed */
private PackageEditorUpdateBehavior updateBehavior;
/*=====================================================================================*
* CONSTRUCTORS
*=====================================================================================*/
/**
* Create a new PackageDiagramEditor object.
*
* @param buildStore The BuildStore that we're editing.
* @param packageId ID of the package we're displaying
*/
public PackageDiagramEditor(IBuildStore buildStore, int packageId) {
super();
/* Save away our BuildStore information, for later use */
this.buildStore = buildStore;
this.pkgMgr = buildStore.getPackageMgr();
this.pkgMemberMgr = buildStore.getPackageMemberMgr();
this.fileGroupMgr = buildStore.getFileGroupMgr();
this.actionMgr = buildStore.getActionMgr();
this.subPkgMgr = buildStore.getSubPackageMgr();
this.packageId = packageId;
/* we use a layout algorithm to help determine the location of things */
layoutAlgorithm = new LayoutAlgorithm(buildStore);
/* listen for changes to the packages and actions */
pkgMgr.addListener(this);
pkgMemberMgr.addListener(this);
actionMgr.addListener(this);
fileGroupMgr.addListener(this);
subPkgMgr.addListener(this);
}
/*=====================================================================================*
* PUBLIC METHODS
*=====================================================================================*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#getEditorImage()
*/
@Override
public Image getEditorImage() {
return EclipsePartUtils.getImage("images/package_icon.gif");
}
/*-------------------------------------------------------------------------------------*/
/**
* @return This package diagram editor's layout algorithm.
*/
public LayoutAlgorithm getLayoutAlgorithm() {
return layoutAlgorithm;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setOption(int, boolean)
*/
@Override
public void setOption(int optionBits, boolean enable) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setOptions(int)
*/
@Override
public void setOptions(int optionBits) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#getOptions()
*/
@Override
public int getOptions() {
// TODO Auto-generated method stub
return 0;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#isOptionSet(int)
*/
@Override
public boolean isOptionSet(int optionBit) {
// TODO Auto-generated method stub
return false;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#updateOptionsFromPreferenceStore()
*/
@Override
public void updateOptionsFromPreferenceStore() {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#getFilterPackageSet()
*/
@Override
public PackageSet getFilterPackageSet() {
// TODO Auto-generated method stub
return null;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setFilterPackageSet(com.buildml.model.types.PackageSet)
*/
@Override
public void setFilterPackageSet(PackageSet newSet) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setRemovable(boolean)
*/
@Override
public void setRemovable(boolean removable) {
/* nothing to do - package diagrams are always removable */
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#isRemovable()
*/
@Override
public boolean isRemovable() {
/* package diagrams are always removeable */
return true;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#isDisposed()
*/
@Override
public boolean isDisposed() {
// TODO Auto-generated method stub
return false;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#expandSubtree(java.lang.Object)
*/
@Override
public void expandSubtree(Object node) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#refreshView(boolean)
*/
@Override
public void refreshView(boolean force) {
updateBehavior.markChanged();
refreshDiagramLater();
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setVisibilityFilterSet(com.buildml.utils.types.IntegerTreeSet)
*/
@Override
public void setVisibilityFilterSet(IntegerTreeSet visibleActions) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#getVisibilityFilterSet()
*/
@Override
public IntegerTreeSet getVisibilityFilterSet() {
// TODO Auto-generated method stub
return null;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#setItemVisibilityState(java.lang.Object, boolean)
*/
@Override
public void setItemVisibilityState(Object item, boolean state) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#pageChange()
*/
@Override
public void pageChange() {
/*
* This call is necessary when somebody double-clicks on a package name in the
* Outline view. If we don't call setFocus(), then the diagram won't be updated
* from the model correctly. However, this call isn't necessary in the case
* where we switch editor tabs (setFocus() gets called some other way).
*/
setFocus();
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#hasFeature(java.lang.String)
*/
@Override
public boolean hasFeature(String feature) {
if ("removable".equals(feature)) {
return (packageId != pkgMgr.getMainPackage());
}
return false;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#doCopyCommand(org.eclipse.swt.dnd.Clipboard, org.eclipse.jface.viewers.ISelection)
*/
@Override
public void doCopyCommand(Clipboard clipboard, ISelection selection) {
// TODO Auto-generated method stub
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.eclipse.ISubEditor#getEditorImagePath()
*/
@Override
public String getEditorImagePath() {
/* not relevant for this editor */
return null;
}
/*-------------------------------------------------------------------------------------*/
/**
* @return The BuildStore associated with this sub-editor.
*/
public IBuildStore getBuildStore() {
return buildStore;
}
/*-------------------------------------------------------------------------------------*/
/**
* @return The ID of the package that this editor represents.
*/
public int getPackageId() {
return packageId;
}
/*-------------------------------------------------------------------------------------*/
/**
* Receive notifications if the BuildStore's packages change in some way.
*/
@Override
public void packageChangeNotification(int pkgId, int how) {
if (pkgId == this.packageId){
/* was the package that we're displaying removed? */
if (how == IPackageMgrListener.REMOVED_PACKAGE) {
MainEditor mainEditor = EclipsePartUtils.getActiveMainEditor();
if (mainEditor != null) {
mainEditor.setActiveEditor(this);
int activeTab = mainEditor.getActivePage();
if (activeTab != -1) {
mainEditor.removePage(activeTab);
}
}
}
}
/*
* If the name or slots from *ANY* package was changed, update this diagram so that
* sub-packages will now have the correct name drawn on their pictogram. We don't
* actually know if this package has any sub-packages of this type, but changing
* package names is rare, so refreshing is not a problem.
*/
if ((how == IPackageMgrListener.CHANGED_NAME) ||
(how == IPackageMgrListener.CHANGED_SLOT)) {
updateBehavior.markChanged();
refreshDiagramLater();
}
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.model.IPackageMemberMgrListener#packageMemberChangeNotification(int, int)
*/
@Override
public void packageMemberChangeNotification(int pkgId, int how, int memberType, int memberId) {
if (pkgId == this.packageId){
/* has the content of the package changed? Action/files added or removed? */
if ((how == IPackageMemberMgrListener.CHANGED_MEMBERSHIP) ||
(how == IPackageMemberMgrListener.CHANGED_LOCATION)) {
updateBehavior.markChanged();
refreshDiagramLater();
}
}
}
/*-------------------------------------------------------------------------------------*/
/**
* Receive notifications if an action (possibly on this package) changes in some way.
*/
@Override
public void actionChangeNotification(int actionId, int how, int changeId) {
PackageDesc pkg = pkgMemberMgr.getPackageOfMember(IPackageMemberMgr.TYPE_ACTION, actionId);
if ((pkg == null) || (pkg.pkgId != this.packageId)) {
return;
}
updateBehavior.markChanged();
refreshDiagramLater();
}
/*-------------------------------------------------------------------------------------*/
/**
* Receive notifications if a file group (possibly on this package) changes in some way.
*/
@Override
public void fileGroupChangeNotification(int fileGroupId, int how) {
PackageDesc pkg = pkgMemberMgr.getPackageOfMember(IPackageMemberMgr.TYPE_FILE_GROUP, fileGroupId);
if ((pkg == null) || (pkg.pkgId != this.packageId)) {
return;
}
updateBehavior.markChanged();
refreshDiagramLater();
}
/*-------------------------------------------------------------------------------------*/
/**
* Receive notifications if a sub-package (possibly on this package) changes in some way.
*/
@Override
public void subPackageChangeNotification(int subPkgId, int how, int changeId) {
PackageDesc pkg = pkgMemberMgr.getPackageOfMember(IPackageMemberMgr.TYPE_SUB_PACKAGE, subPkgId);
if ((pkg == null) || (pkg.pkgId != this.packageId)) {
return;
}
updateBehavior.markChanged();
refreshDiagramLater();
}
/*-------------------------------------------------------------------------------------*/
/**
* This editor is being closed/disposed.
*/
@Override
public void dispose() {
super.dispose();
pkgMgr.removeListener(this);
pkgMemberMgr.removeListener(this);
actionMgr.removeListener(this);
fileGroupMgr.removeListener(this);
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see org.eclipse.graphiti.ui.editor.DiagramEditor#getDiagramBehavior()
*/
@Override
public DiagramBehavior getDiagramBehavior() {
return behaviour;
}
/*=====================================================================================*
* PROTECTED METHODS
*=====================================================================================*/
/* (non-Javadoc)
* @see org.eclipse.graphiti.ui.editor.DiagramEditor#createDiagramBehavior()
*/
@Override
protected DiagramBehavior createDiagramBehavior() {
/* figure out our editor behaviours */
if (behaviour == null) {
behaviour = new PackageDiagramBehaviour(this);
updateBehavior = (PackageEditorUpdateBehavior) behaviour.createUpdateBehavior();
}
return behaviour;
}
/*-------------------------------------------------------------------------------------*/
/**
* No matter what IEditorInput this editor is opened with, we replace this with
* a DiagramEditorInput object which is suitable for passing to a DiagramEditor object.
*/
@Override
protected DiagramEditorInput convertToDiagramEditorInput(IEditorInput input)
throws PartInitException {
URI pkgURI = URI.createURI("buildml:" + packageId);
return new DiagramEditorInput(pkgURI, "com.buildml.eclipse.diagram.package.provider");
}
/*=====================================================================================*
* PRIVATE METHODS
*=====================================================================================*/
/**
* Schedule the diagram to be refreshed at a later time (when the UI is not busy). This
* is important because we might be in the middle of some other UI operation that we
* can't interrupt at the moment.
*/
private void refreshDiagramLater() {
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
setFocus();
}
});
}
/*-------------------------------------------------------------------------------------*/
}