package com.redhat.ceylon.eclipse.code.viewer;
/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.CompositeRuler;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IPageListener;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.PartEventAction;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorExtension3;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.editor.CeylonSourceViewerConfiguration;
public class CeylonMergeViewer extends TextMergeViewer {
private Map<SourceViewer, CeylonSourceViewerConfiguration> sourceViewerConfigurations;
private Map<SourceViewer, CeylonEditorAdapter> editors;
private ArrayList <SourceViewer> sourceViewers;
private IWorkbenchPartSite site;
public CeylonMergeViewer(Composite parent, int styles, CompareConfiguration mp) {
super(parent, styles | SWT.LEFT_TO_RIGHT, mp);
}
@Override
protected void handleDispose(DisposeEvent event) {
sourceViewers= null;
if (editors != null) {
for (CeylonEditorAdapter cea: editors.values()) {
cea.dispose();
}
editors= null;
}
site= null;
super.handleDispose(event);
}
@Override
public String getTitle() {
return "Ceylon Source Comparison";
}
@Override
protected IDocumentPartitioner getDocumentPartitioner() {
return null;
}
@Override
protected String getDocumentPartitioning() {
return IDocument.DEFAULT_CONTENT_TYPE;
}
@Override
protected void configureTextViewer(TextViewer viewer) {
if (viewer instanceof SourceViewer) {
SourceViewer sourceViewer= (SourceViewer) viewer;
if (sourceViewers == null) {
sourceViewers= new ArrayList<SourceViewer>();
}
if (!sourceViewers.contains(sourceViewer))
sourceViewers.add(sourceViewer);
IEditorInput editorInput= getEditorInput(sourceViewer);
sourceViewer.unconfigure();
if (editorInput == null) {
sourceViewer.configure(getSourceViewerConfiguration(sourceViewer, null));
sourceViewer.invalidateTextPresentation();
}
else {
getSourceViewerConfiguration(sourceViewer, editorInput);
sourceViewer.invalidateTextPresentation();
}
}
}
@Override
protected void setEditable(ISourceViewer sourceViewer, boolean state) {
super.setEditable(sourceViewer, state);
if (editors != null) {
CeylonEditorAdapter cea = editors.get(sourceViewer);
if (cea!=null) {
cea.setEditable(state);
}
}
}
@Override
protected boolean isEditorBacked(ITextViewer textViewer) {
return getSite() != null;
}
@Override
protected IEditorInput getEditorInput(ISourceViewer sourceViewer) {
IEditorInput editorInput= super.getEditorInput(sourceViewer);
if (editorInput == null)
return null;
if (getSite() == null)
return null;
if (!(editorInput instanceof IStorageEditorInput))
return null;
return editorInput;
}
private IWorkbenchPartSite getSite() {
if (site == null) {
IWorkbenchPart workbenchPart = getCompareConfiguration()
.getContainer().getWorkbenchPart();
site= workbenchPart != null ? workbenchPart.getSite() : null;
}
return site;
}
private CeylonSourceViewerConfiguration getSourceViewerConfiguration(SourceViewer sourceViewer,
IEditorInput editorInput) {
if (sourceViewerConfigurations == null) {
sourceViewerConfigurations= new HashMap<SourceViewer, CeylonSourceViewerConfiguration>(3);
}
CeylonSourceViewerConfiguration configuration = new CeylonSourceViewerConfiguration(null);
if (editorInput != null) {
// when input available, use editor
CeylonEditorAdapter cea = editors.get(sourceViewer);
try {
cea.init((IEditorSite) cea.getSite(), editorInput);
cea.createActions();
}
catch (PartInitException e) {
e.printStackTrace();
}
}
sourceViewerConfigurations.put(sourceViewer, configuration);
return sourceViewerConfigurations.get(sourceViewer);
}
@Override
protected SourceViewer createSourceViewer(Composite parent, int textOrientation) {
SourceViewer viewer;
if (getSite() != null) {
CeylonEditorAdapter cea= new CeylonEditorAdapter(textOrientation);
cea.createPartControl(parent);
ISourceViewer sourceViewer = cea.getCeylonSourceViewer();
Assert.isTrue(sourceViewer instanceof SourceViewer);
viewer = (SourceViewer) sourceViewer;
if (editors == null) {
editors = new HashMap<SourceViewer, CeylonEditorAdapter>(3);
}
editors.put(viewer, cea);
}
else {
viewer = super.createSourceViewer(parent, textOrientation);
}
if (sourceViewers == null) {
sourceViewers = new ArrayList<SourceViewer>();
}
sourceViewers.add(viewer);
return viewer;
}
@Override
protected void setActionsActivated(SourceViewer sourceViewer, boolean state) {
if (editors != null) {
Object editor = editors.get(sourceViewer);
if (editor instanceof CeylonEditorAdapter) {
CeylonEditorAdapter cea = (CeylonEditorAdapter) editor;
//cuea.setActionsActivated(state);
IAction saveAction = cea.getAction(ITextEditorActionConstants.SAVE);
if (saveAction instanceof IPageListener) {
PartEventAction partEventAction = (PartEventAction) saveAction;
IWorkbenchPart compareEditorPart= getCompareConfiguration().getContainer().getWorkbenchPart();
if (state) {
partEventAction.partActivated(compareEditorPart);
}
else {
partEventAction.partDeactivated(compareEditorPart);
}
}
}
}
}
@Override
protected void createControls(Composite composite) {
super.createControls(composite);
IWorkbenchPart workbenchPart = getCompareConfiguration().getContainer().getWorkbenchPart();
if (workbenchPart != null) {
IContextService service = (IContextService) workbenchPart.getSite()
.getService(IContextService.class);
if (service != null) {
service.activateContext(PLUGIN_ID + ".context");
}
}
}
@Override
public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
if (adapter == ITextEditorExtension3.class) {
IEditorInput activeInput = (IEditorInput) super.getAdapter(IEditorInput.class);
if (activeInput!=null) {
for (CeylonEditorAdapter cea: editors.values()) {
if (activeInput.equals(cea.getEditorInput())) {
return cea;
}
}
}
return null;
}
return super.getAdapter(adapter);
}
private class CeylonEditorAdapter extends CeylonEditor {
private int fTextOrientation;
private boolean fEditable;
private CeylonEditorAdapter(int textOrientation) {
fTextOrientation = textOrientation;
}
private void setEditable(boolean editable) {
fEditable = editable;
}
@Override
public IWorkbenchPartSite getSite() {
return CeylonMergeViewer.this.getSite();
}
@Override
public void createActions() {}
@Override
public void createPartControl(Composite composite) {
SourceViewer sourceViewer = createSourceViewer(composite, new CompositeRuler(),
fTextOrientation | SWT.H_SCROLL | SWT.V_SCROLL);
setSourceViewer(this, sourceViewer);
createNavigationActions();
getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener());
}
// called by org.eclipse.ui.texteditor.TextEditorAction.canModifyEditor()
@Override
public boolean isEditable() {
return fEditable;
}
@Override
public boolean isEditorInputModifiable() {
return fEditable;
}
@Override
public boolean isEditorInputReadOnly() {
return !fEditable;
}
@Override
public void close(boolean save) {
getDocumentProvider().disconnect(getEditorInput());
}
}
// no setter to private field AbstractTextEditor.fSourceViewer
private void setSourceViewer(ITextEditor editor, SourceViewer viewer) {
Field field= null;
try {
field= AbstractTextEditor.class.getDeclaredField("fSourceViewer");
} catch (Exception ex) {
ex.printStackTrace();
}
field.setAccessible(true);
try {
field.set(editor, viewer);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// @Override
// protected int findInsertionPosition(char type, ICompareInput input) {
//
// int pos= super.findInsertionPosition(type, input);
// if (pos != 0)
// return pos;
//
// if (input instanceof IDiffElement) {
//
// // find the other (not deleted) element
// JavaNode otherJavaElement= null;
// ITypedElement otherElement= null;
// switch (type) {
// case 'L':
// otherElement= input.getRight();
// break;
// case 'R':
// otherElement= input.getLeft();
// break;
// }
// if (otherElement instanceof JavaNode)
// otherJavaElement= (JavaNode) otherElement;
//
// // find the parent of the deleted elements
// JavaNode javaContainer= null;
// IDiffElement diffElement= (IDiffElement) input;
// IDiffContainer container= diffElement.getParent();
// if (container instanceof ICompareInput) {
//
// ICompareInput parent= (ICompareInput) container;
// ITypedElement element= null;
//
// switch (type) {
// case 'L':
// element= parent.getLeft();
// break;
// case 'R':
// element= parent.getRight();
// break;
// }
//
// if (element instanceof JavaNode)
// javaContainer= (JavaNode) element;
// }
//
// if (otherJavaElement != null && javaContainer != null) {
//
// Object[] children;
// Position p;
//
// switch (otherJavaElement.getTypeCode()) {
//
// case JavaNode.PACKAGE:
// return 0;
//
// case JavaNode.IMPORT_CONTAINER:
// // we have to find the place after the package declaration
// children= javaContainer.getChildren();
// if (children.length > 0) {
// JavaNode packageDecl= null;
// for (int i= 0; i < children.length; i++) {
// JavaNode child= (JavaNode) children[i];
// switch (child.getTypeCode()) {
// case JavaNode.PACKAGE:
// packageDecl= child;
// break;
// case JavaNode.CLASS:
// return child.getRange().getOffset();
// }
// }
// if (packageDecl != null) {
// p= packageDecl.getRange();
// return p.getOffset() + p.getLength();
// }
// }
// return javaContainer.getRange().getOffset();
//
// case JavaNode.IMPORT:
// // append after last import
// p= javaContainer.getRange();
// return p.getOffset() + p.getLength();
//
// case JavaNode.CLASS:
// // append after last class
// children= javaContainer.getChildren();
// if (children.length > 0) {
// for (int i= children.length-1; i >= 0; i--) {
// JavaNode child= (JavaNode) children[i];
// switch (child.getTypeCode()) {
// case JavaNode.CLASS:
// case JavaNode.IMPORT_CONTAINER:
// case JavaNode.PACKAGE:
// case JavaNode.FIELD:
// p= child.getRange();
// return p.getOffset() + p.getLength();
// }
// }
// }
// return javaContainer.getAppendPosition().getOffset();
//
// case JavaNode.METHOD:
// // append in next line after last child
// children= javaContainer.getChildren();
// if (children.length > 0) {
// JavaNode child= (JavaNode) children[children.length-1];
// p= child.getRange();
// return findEndOfLine(javaContainer, p.getOffset() + p.getLength());
// }
// // otherwise use position from parser
// return javaContainer.getAppendPosition().getOffset();
//
// case JavaNode.FIELD:
// // append after last field
// children= javaContainer.getChildren();
// if (children.length > 0) {
// JavaNode method= null;
// for (int i= children.length-1; i >= 0; i--) {
// JavaNode child= (JavaNode) children[i];
// switch (child.getTypeCode()) {
// case JavaNode.METHOD:
// method= child;
// break;
// case JavaNode.FIELD:
// p= child.getRange();
// return p.getOffset() + p.getLength();
// }
// }
// if (method != null)
// return method.getRange().getOffset();
// }
// return javaContainer.getAppendPosition().getOffset();
// }
// }
//
// if (javaContainer != null) {
// // return end of container
// Position p= javaContainer.getRange();
// return p.getOffset() + p.getLength();
// }
// }
//
// // we give up
// return 0;
// }
//
// private int findEndOfLine(JavaNode container, int pos) {
// int line;
// IDocument doc= container.getDocument();
// try {
// line= doc.getLineOfOffset(pos);
// pos= doc.getLineOffset(line+1);
// } catch (BadLocationException ex) {
// // silently ignored
// }
//
// // ensure that position is within container range
// Position containerRange= container.getRange();
// int start= containerRange.getOffset();
// int end= containerRange.getOffset() + containerRange.getLength();
// if (pos < start)
// return start;
// if (pos >= end)
// return end-1;
//
// return pos;
// }
}