blob: cb57662f58bbb3c6bd1e877669af5d7f16fd808c [file] [log] [blame]
/**
*
*/
package org.eclipse.epf.diagramming.base.providers;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.filebuffers.manipulation.ContainerCreator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.workspace.AbstractEMFOperation;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.epf.diagram.core.part.DiagramFileEditorInputProxy;
import org.eclipse.epf.diagram.core.part.IDiagramFileEditorInputProxy;
import org.eclipse.epf.diagramming.base.DiagrammingResources;
import org.eclipse.epf.diagramming.base.persistence.DiagramPersister;
import org.eclipse.epf.diagramming.base.persistence.DiagramService;
import org.eclipse.epf.diagramming.base.persistence.ISaveEventDispatcher;
import org.eclipse.epf.diagramming.base.persistence.ISaveInfo;
import org.eclipse.epf.diagramming.base.persistence.SaveEventDispatcher;
import org.eclipse.epf.diagramming.base.persistence.SaveInfo;
import org.eclipse.epf.diagramming.base.util.UmaUmlUtil;
import org.eclipse.epf.diagramming.part.EPFDiagramEditorPlugin;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.DiagramModificationListener;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider;
import org.eclipse.gmf.runtime.emf.core.resources.GMFResource;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.NamedElement;
/**
* Specialized document provider for handle changes and manipulate document associated
* and synchronize the other opened editor's document and do merge any conflict synchronize.
* Also handles the timestamp synchronization if the multiple editors are sharing same resource.
* @author Shashidhar Kannoori
*/
public class DiagramEditorDocumentProvider extends FileDiagramDocumentProvider {
/**
*
*/
public DiagramEditorDocumentProvider() {
// TODO Auto-generated constructor stub
}
/**
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider#setDocumentContent(org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument, org.eclipse.ui.IEditorInput)
*
* @modified
*/
protected boolean setDocumentContent(IDocument document,
IEditorInput editorInput) throws CoreException {
if (editorInput instanceof DiagramFileEditorInputProxy) {
DiagramFileEditorInputProxy diagramElement = (DiagramFileEditorInputProxy) editorInput;
((IDiagramDocument) document).setEditingDomain(diagramElement
.getEditingDomain());
if (editorInput instanceof IStorageEditorInput) {
IStorage storage = ((IStorageEditorInput) editorInput)
.getStorage();
setDocumentContentFromStorage(document, storage, editorInput);
return true;
}
}
return false;
}
protected void setupDocument(Object element, IDocument document) {
super.setupDocument(element, document);
}
/**
* (non-Javadoc)
* @custom
*/
protected void setDocumentContentFromStorage(IDocument document,
IStorage storage, IEditorInput editorInput) throws CoreException {
Diagram diagram = (Diagram) document.getContent();
if (diagram != null) {
Resource resource = diagram.eResource();
IFile resourceFile = WorkspaceSynchronizer.getFile(resource);
// unload if the resourceFile and storage is same.
// if not same throw exception.
if (resourceFile != null) {
if (resourceFile.equals(storage)) {
document.setContent(null);
} else {
throw new CoreException(
new Status(
IStatus.ERROR,
EPFDiagramEditorPlugin.getPluginId(),
1,
DiagrammingResources.FileDocumentProvider_handleElementContentChanged,
null));
}
}
}
IDiagramDocument diagramDocument = (IDiagramDocument) document;
TransactionalEditingDomain domain = diagramDocument.getEditingDomain();
diagram = DiagramPersister.load(domain, storage, true,
getProgressMonitor(), editorInput);
document.setContent(diagram);
//super.setDocumentContentFromStorage(document, storage);
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider#handleElementContentChanged(org.eclipse.ui.IFileEditorInput)
* @custom
*/
protected void handleElementContentChanged(IFileEditorInput fileEditorInput) {
FileInfo info= (FileInfo) getElementInfo(fileEditorInput);
if (info == null)
return;
IDocument document= createEmptyDocument();
IStatus status= null;
try {
try {
refreshFile(fileEditorInput.getFile());
} catch (CoreException x) {
handleCoreException(x, "File Changed outside");
}
setDocumentContent(document, fileEditorInput);
} catch (CoreException x) {
status= x.getStatus();
}
Object newContent= document.getContent();
if ( !newContent.equals(info.fDocument.getContent())) {
// set the new content and fire content related events
fireElementContentAboutToBeReplaced(fileEditorInput);
removeUnchangedElementListeners(fileEditorInput, info);
info.fDocument.removeDocumentListener(info);
info.fDocument.setContent(newContent);
info.fCanBeSaved= false;
info.fModificationStamp= computeModificationStamp(fileEditorInput.getFile());
info.fStatus= status;
addUnchangedElementListeners(fileEditorInput, info);
fireElementContentReplaced(fileEditorInput);
}
}
protected void handleElementMoved(IFileEditorInput fileEditorInput, IPath path) {
super.handleElementMoved(fileEditorInput, path);
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider#createInputWithEditingDomain(org.eclipse.ui.IEditorInput, org.eclipse.emf.transaction.TransactionalEditingDomain)
* @custom
*/
public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, TransactionalEditingDomain domain) {
if(editorInput instanceof IDiagramFileEditorInputProxy){
((IDiagramFileEditorInputProxy)editorInput).setTransactionalEditingDomain(domain);
return editorInput;
}else{
return super.createInputWithEditingDomain(editorInput, domain);
}
}
/**
* @author Shashidhar Kannoori
* @custom
*/
public class DiagramFileInfoSync extends DiagramFileInfo{
ISaveEventDispatcher dispatcher;
IFileEditorInput input;
public boolean refreshedByShared = false;
public DiagramFileInfoSync(IDocument document, FileSynchronizer fileSynchronizer, DiagramModificationListener listener,
IFileEditorInput input) {
super(document, fileSynchronizer, listener);
final IDocument inUseDocument = document;
final DiagramFileEditorInputProxy inputProxy =(DiagramFileEditorInputProxy)input;
if(dispatcher == null){
dispatcher = new SaveEventDispatcher(){
public void updateTimeStamp(ISaveInfo info) {
fModificationStamp = info.getTimeStamp();
// Object object = info.getSource();
//
// if(object instanceof ElementInfo){
//
// if(inUseDocument.equals(((ElementInfo)object).fDocument)){
// return;
// }
// }
// MergeOperation operation = new MergeOperation(inputProxy.getEditingDomain(),
// "Document Merge Operation", (ElementInfo)object, inUseDocument);
// try{
// operation.execute(new NullProgressMonitor(), null );
// }catch(ExecutionException exception){
// exception.printStackTrace();
// }
}
};
if(dispatcher != null){
DiagramService.eInstance().addDispatchers(dispatcher);
}
}
this.input = input;
}
public void updateTimeStamp(){
long timestamp = getModificationStamp(input);
SaveInfo info = DiagramService.eInstance().getSaveInfo(this, timestamp);
refreshedByShared = true;
DiagramService.eInstance().dispatch(info);
refreshedByShared = false;
}
public void updateTimeStamp(IFile file){
long timestamp = computeModificationStamp(file);
SaveInfo info = DiagramService.eInstance().getSaveInfo(this, timestamp);
DiagramService.eInstance().dispatch(info);
}
public void disposeDispatcher(){
if(dispatcher !=null)
DiagramService.eInstance().removeDispatchers(dispatcher);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider#doSaveDocument(org.eclipse.core.runtime.IProgressMonitor, java.lang.Object, org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument, boolean)
* @custom
*/
protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException {
if (element instanceof IFileEditorInput) {
IFileEditorInput input= (IFileEditorInput) element;
FileInfo info= (FileInfo) getElementInfo(element);
IFile file= input.getFile();
if (file.exists()) {
if (info != null && !overwrite)
checkSynchronizationState(info.fModificationStamp, file);
// inform about the upcoming content change
fireElementStateChanging(element);
try {
System.out.println("Time timestamp before saving: " + computeModificationStamp(file));
saveDocumentToFile(document, file, overwrite, monitor);
// Dispatch the save event.
if(info instanceof DiagramFileInfoSync){
((DiagramFileInfoSync)info).updateTimeStamp();
}
System.out.println("Time timestamp after saving: " + computeModificationStamp(file));
} catch (CoreException x) {
// inform about failure
fireElementStateChangeFailed(element);
throw x;
} catch (RuntimeException x) {
// inform about failure
fireElementStateChangeFailed(element);
throw x;
}
// If here, the editor state will be flipped to "not dirty".
// Thus, the state changing flag will be reset.
if (info != null) {
info.fModificationStamp= computeModificationStamp(file);
}
} else {
try {
monitor.beginTask(DiagrammingResources.FileDocumentProvider_task_saving, 3000);
ContainerCreator creator = new ContainerCreator(file.getWorkspace(), file.getParent().getFullPath());
creator.createContainer(new SubProgressMonitor(monitor, 1000));
file.create(new ByteArrayInputStream("".getBytes()), false, new SubProgressMonitor(monitor, 1000)); //$NON-NLS-1$
saveDocumentToFile(document, file, overwrite, new SubProgressMonitor(monitor, 1000));
}
finally {
monitor.done();
}
}
} else {
super.doSaveDocument(monitor, element, document, overwrite);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileDiagramDocumentProvider#disposeElementInfo(java.lang.Object, org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.AbstractDocumentProvider.ElementInfo)
* @custom
*/
protected void disposeElementInfo(Object element, ElementInfo info) {
if(info instanceof DiagramFileInfoSync){
((DiagramFileInfoSync)info).disposeDispatcher();
}
super.disposeElementInfo(element, info);
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editor.AbstractDocumentProvider#createElementInfo(java.lang.Object)
*/
protected ElementInfo createElementInfo(Object element) throws CoreException {
if (element instanceof IFileEditorInput) {
IFileEditorInput input= (IFileEditorInput) element;
try {
refreshFile(input.getFile());
} catch (CoreException x) {
handleCoreException(x, DiagrammingResources.FileDocumentProvider_createElementInfo);
}
IDocument d= null;
IStatus s= null;
try {
d= createDocument(element);
} catch (CoreException x) {
handleCoreException(x, DiagrammingResources.FileDocumentProvider_createElementInfo);
s= x.getStatus();
d= createEmptyDocument();
}
DiagramFileSynchronizer f= new DiagramFileSynchronizer(input);
f.install();
FileInfo info= createFileInfo(d, f, input);
info.fModificationStamp= computeModificationStamp(input.getFile());
info.fStatus= s;
return info;
}
return super.createElementInfo(element);
}
/**
* Does merge operation of the resource if resource contents are saved by shared
* IDocument.
* @author Shashidhar Kannoori
*/
public class MergeOperation extends AbstractEMFOperation{
private ElementInfo elementInfo;
private IDocument toMergeDocument;
public MergeOperation(TransactionalEditingDomain domain, String label,
ElementInfo elementInfo, IDocument toMergeDocument) {
super(domain, label);
this.elementInfo = elementInfo;
this.toMergeDocument = toMergeDocument;
}
protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
try{
if(elementInfo instanceof ElementInfo){
IDocument savedDocument = ((ElementInfo)elementInfo).fDocument;
Diagram saveddiagram = (Diagram)savedDocument.getContent();
if(saveddiagram != null){
Diagram inUseDiagram = (Diagram)toMergeDocument.getContent();
GMFResource gmfResource = (GMFResource)inUseDiagram.eResource();
EList list = gmfResource.getContents();
String guid = UmaUmlUtil.getUmaGuidFromUmlElement((NamedElement)saveddiagram.getElement());
Diagram replacingDiagram = null;
List newList = new ArrayList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
EObject element = (EObject) iter.next();
if(element instanceof Activity){
String currentguid = UmaUmlUtil.getUmaGuidFromUmlElement((NamedElement)element);
if(currentguid.equals(guid)){
newList.add(saveddiagram.getElement());
}else{
newList.add(element);
}
}
if(element instanceof Diagram){
Diagram diagram = (Diagram)element;
EObject object = ((Diagram)element).getElement();
String rGuid = UmaUmlUtil.getUmaGuidFromUmlElement((NamedElement)object);
if(guid.equals(rGuid)){
replacingDiagram = diagram;
newList.add(saveddiagram);
}else{
newList.add(element);
}
}
}
if(replacingDiagram == null){
newList.add(saveddiagram.getElement());
newList.add(saveddiagram);
}
//Transaction tx = create
// TODO handle better way to merge the elements.
if(!newList.isEmpty()){
boolean notification = gmfResource.eDeliver();
gmfResource.eSetDeliver(false);
gmfResource.getContents().clear();
gmfResource.getContents().addAll(newList);
gmfResource.eSetDeliver(notification);
//list.addAll(newList);
}
}
}
}catch(Exception e){
System.out.println("Warning: Document merge failed due to "+ e.getMessage());
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
}
/**
* Handles the saving of the diagram to a file
*
* @param domain
* the TransactionalEditingDomain we are saving in
* @param file
* the IFile to save to
* @param diagram
* Diagram that will be saved
* @param options
* save options or null
* @param monitor
* IProgressMonitor
* @throws CoreException
*/
protected void doSave(TransactionalEditingDomain domain, IFile file,
Diagram diagram, Map options, IProgressMonitor monitor)
throws CoreException {
if (options == null) {
DiagramPersister.save(domain, file, diagram, DiagramPersister
.hasUnrecognizedData(diagram.eResource()), monitor);
} else {
DiagramPersister.save(domain, file, diagram, monitor, options);
}
}
/**
* Synchronizes the document with external resource changes.
*/
protected class DiagramFileSynchronizer extends FileSynchronizer {
/**
* Creates a new file synchronizer. Is not yet installed on a resource.
*
* @param fileEditorInput the editor input to be synchronized
*/
public DiagramFileSynchronizer(IFileEditorInput fileEditorInput) {
super(fileEditorInput);
}
/*
* @see IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
*/
public boolean visit(IResourceDelta delta) throws CoreException {
if (delta == null)
return false;
delta= delta.findMember(getFile().getFullPath());
if (delta == null)
return false;
Runnable runnable= null;
switch (delta.getKind()) {
case IResourceDelta.CHANGED:
DiagramFileInfoSync info= (DiagramFileInfoSync) getElementInfo(fFileEditorInput);
if (info == null || info.fCanBeSaved)
break;
boolean isSynchronized= computeModificationStamp(getFile()) == info.fModificationStamp;
if (((IResourceDelta.ENCODING & delta.getFlags()) != 0 && isSynchronized) || ((IResourceDelta.CONTENT & delta.getFlags()) != 0 && !isSynchronized)
|| info.refreshedByShared) {
runnable = new SafeChange(fFileEditorInput) {
protected void execute(IFileEditorInput input) throws Exception {
//handleElementContentChanged(input);
}
};
}
break;
case IResourceDelta.REMOVED:
if ((IResourceDelta.MOVED_TO & delta.getFlags()) != 0) {
final IPath path= delta.getMovedToPath();
runnable= new SafeChange(fFileEditorInput) {
protected void execute(IFileEditorInput input) throws Exception {
handleElementMoved(input, path);
}
};
} else {
info= (DiagramFileInfoSync) getElementInfo(fFileEditorInput);
if (info != null && !info.fCanBeSaved) {
runnable= new SafeChange(fFileEditorInput) {
protected void execute(IFileEditorInput input) throws Exception {
handleElementDeleted(input);
}
};
}
}
break;
}
if (runnable != null)
update(runnable);
return false;
}
}
public void unsetCanSaveDocument(Object element) {
if (element != null) {
ElementInfo info = (ElementInfo) getElementInfo(element);
if (info != null) {
removeUnchangedElementListeners(element, info);
info.fCanBeSaved = false;
addUnchangedElementListeners(element, info);
fireElementDirtyStateChanged(element, info.fCanBeSaved);
}
}
}
}