blob: af59cbc2d3dc29eafdbd2a22683fe835f5041246 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012-2014 SAP SE.
* 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:
* SAP SE - initial API and implementation and/or initial documentation
*
*******************************************************************************/
package org.eclipse.ogee.designer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.graphiti.ui.editor.DiagramEditorInput;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.ogee.designer.messages.Messages;
import org.eclipse.ogee.designer.pages.EDMXReferencePage;
import org.eclipse.ogee.designer.utils.ArtifactUtil;
import org.eclipse.ogee.designer.utils.IODataEditorConstants;
import org.eclipse.ogee.model.api.IModelContext;
import org.eclipse.ogee.model.api.ModelAPIException;
import org.eclipse.ogee.model.odata.EDMXSet;
import org.eclipse.ogee.utils.logger.Logger;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Listener;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ogee.help.IHelpConstants;
/**
* The following class implements a MultiPageEditor with an OData Model Editor &
* EDMX Reference page.
*
*/
public class ODataMultiPageEditor extends MultiPageEditorPart {
private CTabFolder tabFolder;
private int defaultTabHeight;
private ODataEditor designEditor = null;
private IFile modelFile;
private boolean isSourceDeleted = false;
private IFile resource;
private Image odataTitleImage;
private ODataDiagramListener odataListener;
private EDMXReferencePage edmxReferencePage;
private boolean isReadOnly = false;
/**
* Creates a multi-page editor.
*/
public ODataMultiPageEditor() {
super();
}
/**
* The resource listener updates the receiver when a change has occurred.
*/
private IResourceChangeListener resourceListener = new IResourceChangeListener() {
/*
* @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
*/
@Override
public void resourceChanged(IResourceChangeEvent event) {
final IResourceDelta mainDelta = event.getDelta();
if (mainDelta == null) {
return;
}
final IResourceDelta affectedElement = mainDelta
.findMember(getResource().getFullPath());
if (affectedElement != null) {
this.processDelta(affectedElement);
}
if (isMarkerChangedForResource(event)) {
// Changes in markers on this resource, so re-decorate title
// image
decorateTitleImage();
}
}
/*
* Checks if there is any change in marker for the resource.
*/
private boolean isMarkerChangedForResource(
final IResourceChangeEvent event) {
boolean isMarkerChangeForThisResource = false;
if (ResourceUtil.getResource(getEditorInput()) != null) {
final IPath path = ResourceUtil.getResource(getEditorInput())
.getFullPath();
final IResourceDelta delta = event.getDelta().findMember(path);
isMarkerChangeForThisResource = (delta != null)
&& ((delta.getFlags() & IResourceDelta.MARKERS) != 0);
}
return isMarkerChangeForThisResource;
}
/*
* Process the delta for the receiver
*/
private boolean processDelta(final IResourceDelta delta) {
Runnable changeRunnable = null;
switch (delta.getKind()) {
case IResourceDelta.REMOVED:
if ((IResourceDelta.MOVED_TO & delta.getFlags()) != 0) {
changeRunnable = new Runnable() {
@Override
public void run() {
final IPath path = delta.getMovedToPath();
final IFile newFile = delta.getResource()
.getWorkspace().getRoot().getFile(path);
if (newFile != null) {
sourceChanged(newFile);
}
}
};
} else {
changeRunnable = new Runnable() {
@Override
public void run() {
setSourceDeleted(true);
getSite().getPage().closeEditor(
ODataMultiPageEditor.this, true);
setDesignEditor(null);
}
};
}
break;
case IResourceDelta.CHANGED:
if ((IResourceDelta.MARKERS & delta.getFlags()) != 0) {
changeRunnable = new Runnable() {
@Override
public void run() {
if (getDesignEditor() != null) {
getDesignEditor().getDiagramBehavior();
}
}
};
}
break;
default:
break;
}
if (changeRunnable != null) {
update(changeRunnable);
}
return true;
}
};
/**
* decorates the title image with error decorators.
*/
public void decorateTitleImage() {
final Shell shell = this.getEditorSite().getShell();
if (shell != null && !shell.isDisposed()) {
shell.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
final Image decoratedImage = decorateImage(getTitleImage(),
getSeverity());
if (decoratedImage != null) {
updateTitleImage(decoratedImage);
}
}
});
}
}
/**
* @param image
* - updated title image with error decorator if any.
*/
public void updateTitleImage(final Image image) {
setTitleImage(image);
}
protected Image decorateImage(Image titleImage, int severity) {
ImageDescriptor descriptor = null;
Image decoratedTitleImage = null;
if (severity == IMarker.PRIORITY_HIGH) {
descriptor = ImageDescriptor.createFromURL(FileLocator.find(
Activator.getDefault().getBundle(), new Path(
"/icons/error_co.gif"), null)); //$NON-NLS-1$
}
if (severity == IMarker.PRIORITY_NORMAL) {
descriptor = ImageDescriptor.createFromURL(FileLocator.find(
Activator.getDefault().getBundle(), new Path(
"/icons/warning_co.gif"), null)); //$NON-NLS-1$
}
if (decoratedTitleImage == null
&& (severity == IMarker.PRIORITY_HIGH || severity == IMarker.PRIORITY_NORMAL)) {
decoratedTitleImage = new DecorationOverlayIcon(titleImage,
descriptor, IDecoration.BOTTOM_LEFT).createImage();
} else {
descriptor = ImageDescriptor.createFromURL(FileLocator.find(
Activator.getDefault().getBundle(), new Path(
"/icons/odata.png"), null)); //$NON-NLS-1$
if (descriptor != null) {
decoratedTitleImage = descriptor.createImage();
}
}
if (decoratedTitleImage == null) {
decoratedTitleImage = titleImage;
}
return decoratedTitleImage;
}
protected int getSeverity() {
int severity = 0;
try {
if (ResourceUtil.getResource(getEditorInput()) != null) {
severity = ResourceUtil.getResource(getEditorInput())
.findMaxProblemSeverity(IMarker.PROBLEM, true,
IResource.DEPTH_INFINITE);
}
} catch (CoreException e) {
// Might be a project that is not open
}
return severity;
}
/**
* The source has changed to the newFile. Update editors and set any
* required flags
*
* @param newFile
* The file to get the new contents from.
*/
protected void sourceChanged(IFile newFile) {
this.modelFile = newFile;
final FileEditorInput newInput = new FileEditorInput(newFile);
setInputWithNotify(newInput);
setPartName(newInput.getName());
setTitleToolTip(newFile.getFullPath().makeRelative().toString());
if (getDesignEditor() != null) {
getDesignEditor().setModelFile(newFile);
getDesignEditor().getDiagramBehavior().refresh();
}
}
/**
* Posts the update code "behind" the running operation.
*
* @param runnable
* the update code
*/
protected void update(Runnable runnable) {
final IWorkbench workbench = PlatformUI.getWorkbench();
final IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
if (windows != null && windows.length > 0) {
final Display display = windows[0].getShell().getDisplay();
display.asyncExec(runnable);
} else {
runnable.run();
}
}
/**
* Initializes the editor when created from scratch.
*
* This method is called soon after part construction and marks the start of
* the extension lifecycle. At the end of the extension lifecycle
* <code>shutdown will be invoked
* to terminate the lifecycle.
*
* @param site
* @param input
* - The initial input element for the editor. In most cases it
* is an <code>IFile but other types are acceptable.
*/
@Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
try {
if (input instanceof IFileEditorInput) {
this.modelFile = ((IFileEditorInput) input).getFile();
// OData file is read only
this.isReadOnly = ((IFileEditorInput) input).getFile()
.isReadOnly();
} else if (input instanceof DiagramEditorInput) {
URI uri = ((DiagramEditorInput) input).getUri();
String uriString = uri.trimFragment().toPlatformString(true);
this.modelFile = this.getModelFile(new Path(uriString));
// OData file is read only
this.isReadOnly = getModelFile(new Path(uriString))
.isReadOnly();
}
setSite(site);
setInput(input);
setInputWithNotify(input);
// Update titles.
setTitleToolTip(input.getToolTipText());
final ImageDescriptor imageDesc = input.getImageDescriptor();
if (imageDesc != null) {
this.odataTitleImage = imageDesc.createImage();
setTitleImage(this.odataTitleImage);
}
decorateTitleImage();
super.init(site, input);
} catch (PartInitException e) {
Logger.getLogger(Activator.PLUGIN_ID).logError(e);
throw new PartInitException(new Status(IStatus.ERROR,
Activator.PLUGIN_ID, e.getMessage(), e));
} catch (Exception t) {
Logger.getLogger(Activator.PLUGIN_ID).logError(t);
throw new PartInitException(new Status(IStatus.ERROR,
Activator.PLUGIN_ID, t.getMessage(), t));
}
}
@Override
protected void setInputWithNotify(IEditorInput input) {
if (input instanceof IFileEditorInput
|| input instanceof DiagramEditorInput
|| input instanceof ODataEditorInput) {
if (this.getResource() == null) {
ResourcesPlugin.getWorkspace().addResourceChangeListener(
this.resourceListener);
}
this.setResource(this.modelFile);
}
super.setInputWithNotify(input);
}
@Override
public void doSave(IProgressMonitor monitor) {
if (this.designEditor != null) {
this.designEditor.doSave(monitor);
}
try {
if (this.resource != null) {
this.resource.refreshLocal(IResource.DEPTH_ZERO, monitor);
}
} catch (CoreException ex) {
// Do nothing on a failed refresh
}
}
@Override
public void doSaveAs() {
final IEditorPart activeEditor = getActiveEditor();
if (activeEditor != null) {
activeEditor.doSaveAs();
}
}
@Override
public boolean isSaveAsAllowed() {
boolean isSaveAsAllowed = false;
/*
* Depending upon the active page in multi-page editor, call the
* saveAsAllowed. It helps to see whether a particular editor allows
* 'save as' feature
*/
final IEditorPart activeEditor = getActiveEditor();
if (activeEditor != null) {
isSaveAsAllowed = activeEditor.isSaveAsAllowed();
}
return isSaveAsAllowed;
}
/*
* See IEditorPart.isSaveOnCloseNeeded()
*/
@Override
public boolean isSaveOnCloseNeeded() {
return !this.isSourceDeleted() && super.isSaveOnCloseNeeded();
}
@Override
public void dispose() {
super.dispose();
if (this.getResource() != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(
this.resourceListener);
this.resourceListener = null;
this.setResource(null);
}
// can dispose the title image because it was created in init
if (this.odataTitleImage != null) {
this.odataTitleImage.dispose();
this.odataTitleImage = null;
}
if (this.odataListener != null) {
this.odataListener.removeListeners();
this.odataListener = null;
}
this.modelFile = null;
this.designEditor = null;
this.tabFolder = null;
if (this.edmxReferencePage != null) {
this.edmxReferencePage.dispose();
this.edmxReferencePage = null;
}
}
@Override
public String getTitle() {
if (this.designEditor != null) {
return this.designEditor.getTitle();
}
return super.getTitle();
}
@Override
public String getPartName() {
if (this.modelFile != null) {
// if odata file is read-only
if (this.modelFile.isReadOnly()) {
String title = this.modelFile.getName()
+ Messages.ODataMultiPageEditor_0;
return title;
} else {
if (IODataEditorConstants.TEMPFILE_EXTENSION
.equals(this.modelFile.getFileExtension())) {
return this.modelFile.getFullPath().removeFileExtension()
.lastSegment();
}
return this.modelFile.getName();
}
}
return super.getPartName();
}
@Override
public String getTitleToolTip() {
if (this.modelFile != null) {
if (IODataEditorConstants.TEMPFILE_EXTENSION.equals(this.modelFile
.getFileExtension())) {
if (this.getEditorInput() instanceof ODataEditorInput) {
final ODataEditorInput input = (ODataEditorInput) this
.getEditorInput();
final String titleToolTip = input.getGWConnectionName()
+ "/" + this.modelFile.getFullPath().removeFileExtension().lastSegment(); //$NON-NLS-1$
return titleToolTip;
}
return this.modelFile.getFullPath().removeFileExtension()
.lastSegment();
}
return this.modelFile.getFullPath().makeRelative().toString();
}
return super.getTitleToolTip();
}
@Override
public void removePage(int pageIndex) {
Object page = this.tabFolder.getItem(pageIndex).getData();
if (page instanceof EditorPart) {
// make sure the editor gets disposed - neither CTabFolder nor super
// does this for us!
((EditorPart) page).dispose();
}
super.removePage(pageIndex);
updateTabs();
}
/**
* remove Source Viewer
*/
public void removeSourceViewer() {
}
@Override
protected void createPages() {
this.tabFolder = (CTabFolder) getContainer();
this.tabFolder.addCTabFolder2Listener(new CTabFolder2Listener() {
@Override
public void close(CTabFolderEvent event) {
}
@Override
public void minimize(CTabFolderEvent event) {
}
@Override
public void maximize(CTabFolderEvent event) {
}
@Override
public void restore(CTabFolderEvent event) {
}
@Override
public void showList(CTabFolderEvent event) {
}
});
try {
createDesignEditor();
// TODO Start - Enable with OData V4 support
// createEDMXReferencePage();
// End - Enable with OData V4 support
} catch (CoreException e) {
Logger.getLogger(Activator.PLUGIN_ID).logError(e);
}
}
/**
* @return ODataEditor
*/
public ODataEditor getDesignEditor() {
return this.designEditor;
}
/**
* @param designEditor
*/
public void setDesignEditor(final ODataEditor designEditor) {
this.designEditor = designEditor;
}
private void updateTabs() {
if (this.tabFolder.getItemCount() == 1) {
this.tabFolder.setTabHeight(0);
} else {
this.tabFolder.setTabHeight(this.defaultTabHeight);
}
this.tabFolder.layout();
}
private IFile getModelFile(IPath fullPath) {
return ResourcesPlugin.getWorkspace().getRoot()
.getFile(fullPath.makeAbsolute());
}
private void createDesignEditor() throws CoreException {
if (this.designEditor == null) {
this.designEditor = new DesignEditor();
try {
int pageIndex = this.tabFolder.getItemCount();
addPage(pageIndex, this.designEditor,
ODataMultiPageEditor.this.getEditorInput());
this.defaultTabHeight = this.tabFolder.getTabHeight();
setPageText(pageIndex,
Messages.ODATA_MULTIPAGE_EDITOR_MODEL_TAB);
this.defaultTabHeight = this.tabFolder.getTabHeight();
updateTabs();
this.odataListener = new ODataDiagramListener(this.designEditor);
this.odataListener.registerListeners();
} catch (Exception e) {
Logger.getLogger(Activator.PLUGIN_ID).logError(e);
throw new CoreException(new Status(IStatus.ERROR,
Activator.PLUGIN_ID, e.getMessage(), e));
}
}
}
/*
* EDMX References Page.
*/
private void createEDMXReferencePage() {
EDMXSet edmxSet = null;
// boolean isReadOnly = false;
final IEditorInput editorInput = getEditorInput();
// Editor is invoked from IODataDiagramCreator#createDiagram() API.
if (editorInput instanceof ODataEditorInput) {
final ODataEditorInput odataEditorInput = (ODataEditorInput) getEditorInput();
edmxSet = odataEditorInput.getDiagramInput().getEDMXSet();
isReadOnly = odataEditorInput.getDiagramInput().isReadOnlyMode();
}
// Editor is invoked from Project Explorer or when eclipse IDE is
// launched.
else if (editorInput instanceof FileEditorInput
|| editorInput instanceof DiagramEditorInput) {
try {
final TransactionalEditingDomain editingDomain = IModelContext.INSTANCE
.getTransaction(this.modelFile);
final String path = this.modelFile.getFullPath().toString();
final URI uri = URI.createPlatformResourceURI(path, true);
ResourceSet resourceSet = null;
if (editingDomain != null) {
resourceSet = editingDomain.getResourceSet();
} else {
resourceSet = new ResourceSetImpl();
}
final Resource model = resourceSet.getResource(uri, true);
if (model instanceof XMIResource) {
edmxSet = ArtifactUtil.getEDMXSetFromModel(model);
}
// OData file is read only
if (editorInput instanceof FileEditorInput) {
final FileEditorInput fileEditorInput = (FileEditorInput) getEditorInput();
this.isReadOnly = fileEditorInput.getFile().isReadOnly();
}
if (editorInput instanceof DiagramEditorInput) {
final DiagramEditorInput diagramEditorInput = (DiagramEditorInput) getEditorInput();
final URI uriDiagram = diagramEditorInput.getUri();
final String uriString = uriDiagram.trimFragment()
.toPlatformString(true);
this.isReadOnly = getModelFile(new Path(uriString))
.isReadOnly();
}
} catch (ModelAPIException e) {
Logger.getLogger(Activator.PLUGIN_ID).logError(e);
}
}
final int pageIndex = this.tabFolder.getItemCount();
this.edmxReferencePage = new EDMXReferencePage(this.getContainer(),
edmxSet, isReadOnly, getEditorSite(), getDesignEditor());
addPage(this.edmxReferencePage);
this.tabFolder.getItem(pageIndex).setShowClose(false);
setPageText(pageIndex, Messages.ODATA_MULTIPAGE_EDITOR_REF_TAB);
updateTabs();
}
/**
* @return an instance of IFile
*/
public IFile getResource() {
return this.resource;
}
/**
* @param resource
* - IFile
*/
public void setResource(final IFile resource) {
this.resource = resource;
}
/**
* The isSourceDeleted flag makes sure that the receiver is not dirty when
* shutting down.
*
* @return boolean is Source Deleted
*/
public boolean isSourceDeleted() {
return this.isSourceDeleted;
}
/**
* The isSourceDeleted flag makes sure that the receiver is not dirty when
* shutting down.
*
* @param isSourceDeleted
* - boolean
*/
public void setSourceDeleted(boolean isSourceDeleted) {
this.isSourceDeleted = isSourceDeleted;
}
/**
* @author I057523
*
*/
public class DesignEditor extends ODataEditor {
@Override
protected void createActions() {
super.createActions();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.MultiPageEditorPart#setFocus()
*/
@Override
public void setFocus() {
super.setFocus();
int activePage = getActivePage();
switch (activePage) {
case 0:
if (this.designEditor != null) {
final GraphicalViewer graphicalViewer = this.designEditor
.getGraphicalViewer();
if (graphicalViewer != null) {
final Control control = graphicalViewer.getControl();
/*PlatformUI
.getWorkbench()
.getHelpSystem()
.setHelp(control,
IODataEditorConstants.HELP_CONTEXT_ID);*/
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(control, IHelpConstants.HELP_CONTEXT_ID);
}
}
break;
case 1:
/*PlatformUI
.getWorkbench()
.getHelpSystem()
.setHelp(
this.edmxReferencePage,
IODataEditorConstants.HELP_CONTEXT_ID_EDMXREFERENCES);*/
PlatformUI
.getWorkbench()
.getHelpSystem()
.setHelp(this.edmxReferencePage,
IHelpConstants.HELP_CONTEXT_ID_EDMXREFERENCES);
break;
default:
break;
}
}
/**
* @return instance of EDMXReferencePage.
*/
public EDMXReferencePage getEdmxReferencePage() {
return this.edmxReferencePage;
}
}