blob: 29816fab7be05d1521ba5ac2f8bac0b73c74bf4c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2008 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.core.internal.utility.jdt;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter;
import org.eclipse.jpt.core.utility.jdt.Member;
import org.eclipse.jpt.core.utility.jdt.ModifiedDeclaration;
import org.eclipse.jpt.core.utility.jdt.Type;
import org.eclipse.jpt.utility.Command;
import org.eclipse.jpt.utility.CommandExecutor;
import org.eclipse.jpt.utility.CommandExecutorProvider;
import org.eclipse.jpt.utility.internal.StringTools;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
/**
* Adapt and extend a JDT member with simplified annotation handling.
*/
public abstract class JDTMember
implements Member
{
private final IMember jdtMember;
/** this will be null for a top-level type */
private final Type declaringType;
private final CommandExecutorProvider modifySharedDocumentCommandExecutorProvider;
private final AnnotationEditFormatter annotationEditFormatter;
// ********** constructor **********
JDTMember(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) {
this(jdtMember, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance());
}
JDTMember(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) {
super();
this.jdtMember = jdtMember;
IType jdtDeclaringType = jdtMember.getDeclaringType();
this.declaringType = (jdtDeclaringType == null) ? null : new JDTType(jdtDeclaringType, modifySharedDocumentCommandExecutorProvider);
this.modifySharedDocumentCommandExecutorProvider = modifySharedDocumentCommandExecutorProvider;
this.annotationEditFormatter = annotationEditFormatter;
}
// ********** accessors **********
protected IMember getJdtMember() {
return this.jdtMember;
}
public boolean wraps(IMember member) {
return this.jdtMember.exists()
&& this.jdtMember.equals(member);
}
/**
* this will return null for a top-level type
*/
protected Type declaringType() {
return this.declaringType;
}
// ********** miscellaneous **********
protected ICompilationUnit getCompilationUnit() {
return this.jdtMember.getCompilationUnit();
}
public String getName() {
return this.jdtMember.getElementName();
}
/**
* note: this creates a *new* AST
*/
public CompilationUnit getAstRoot() {
return JDTTools.buildASTRoot(this.jdtMember);
}
public ModifiedDeclaration getModifiedDeclaration() {
return this.getModifiedDeclaration(this.getAstRoot());
}
public ModifiedDeclaration getModifiedDeclaration(CompilationUnit astRoot) {
return new JDTModifiedDeclaration(this.getBodyDeclaration(astRoot));
}
@Override
public String toString() {
return StringTools.buildToStringFor(this, this.getName());
}
// ********** editing **********
/**
* Edit the member with the specified editor.
* The editor will be invoked once the member's compilation unit
* is in an editable state.
*/
public void edit(Editor editor) {
try {
this.edit_(editor);
} catch (JavaModelException ex) {
throw new RuntimeException(ex);
} catch (BadLocationException ex) {
throw new RuntimeException(ex);
}
}
/**
* NB: Be careful changing this method.
* Things to look out for:
* - when editing via the JavaEditor there is no need to create a working copy
* - when editing headlessly, a "working copy" must be created
* (at least as far as I can tell ~kfm)
* - when editing via a plain text editor, make a working copy or else things are screwed
* up the second time you edit through the XmlPersistence XmlProperties View
*/
private void edit_(Editor editor) throws JavaModelException, BadLocationException {
ICompilationUnit compilationUnit = this.getCompilationUnit();
if ( ! compilationUnit.isWorkingCopy()) {
compilationUnit.becomeWorkingCopy(null);
}
ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(compilationUnit.getResource().getFullPath(), LocationKind.NORMALIZE);
boolean sharedDocument = (buffer != null); // documents are typically shared when they are already open in an editor
IDocument doc = sharedDocument ?
buffer.getDocument()
:
new Document(compilationUnit.getBuffer().getContents());
CompilationUnit astRoot = this.getAstRoot();
astRoot.recordModifications();
editor.edit(this.getModifiedDeclaration(astRoot));
TextEdit edits = astRoot.rewrite(doc, compilationUnit.getJavaProject().getOptions(true));
if (sharedDocument) {
this.getModifySharedDocumentCommandExecutor().execute(new ModifySharedDocumentCommand(edits, doc));
} else {
this.applyEdits(edits, doc);
}
if ( ! sharedDocument) {
compilationUnit.getBuffer().setContents(doc.get());
compilationUnit.commitWorkingCopy(true, null); // true="force"
compilationUnit.discardWorkingCopy();
}
}
/**
* apply the specified edits to the specified document,
* reformatting the document if necessary
*/
void applyEdits(TextEdit edits, IDocument doc) throws MalformedTreeException, BadLocationException {
edits.apply(doc, TextEdit.UPDATE_REGIONS);
this.getAnnotationEditFormatter().format(doc, edits);
}
private AnnotationEditFormatter getAnnotationEditFormatter() {
return this.annotationEditFormatter;
}
private CommandExecutor getModifySharedDocumentCommandExecutor() {
return this.modifySharedDocumentCommandExecutorProvider.getCommandExecutor();
}
// ********** modify shared document command class **********
/**
* simple command that calls back to the member to apply the edits
* in the same way as if the document were not shared
*/
class ModifySharedDocumentCommand implements Command {
private final TextEdit edits;
private final IDocument doc;
ModifySharedDocumentCommand(TextEdit edits, IDocument doc) {
super();
this.edits = edits;
this.doc = doc;
}
public void execute() {
try {
JDTMember.this.applyEdits(this.edits, this.doc);
} catch (MalformedTreeException ex) {
throw new RuntimeException(ex);
} catch (BadLocationException ex) {
throw new RuntimeException(ex);
}
}
}
}