/*******************************************************************************
* Copyright (c) 2000, 2009 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
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.corext.codemanipulation;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IField;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.ITypeHierarchy;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.Signature;
import org.eclipse.wst.jsdt.internal.corext.dom.TokenScanner;
import org.eclipse.wst.jsdt.internal.corext.util.MethodOverrideTester;
import org.eclipse.wst.jsdt.internal.corext.util.Strings;
import org.eclipse.wst.jsdt.internal.corext.util.SuperTypeHierarchyCache;
import org.eclipse.wst.jsdt.internal.ui.JavaUIStatus;
import org.eclipse.wst.jsdt.ui.CodeGeneration;
/**
*
* Provisional API: This class/interface is part of an interim API that is still under development and expected to
* change significantly before reaching stability. It is being made available at this early stage to solicit feedback
* from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
* (repeatedly) as the API evolves.
*/
public class AddJavaDocStubOperation implements IWorkspaceRunnable {
private IMember[] fMembers;
public AddJavaDocStubOperation(IMember[] members) {
super();
fMembers= members;
}
private String createTypeComment(IType type, String lineDelimiter) throws CoreException {
return CodeGeneration.getTypeComment(type.getJavaScriptUnit(), type.getTypeQualifiedName('.'), lineDelimiter);
}
private String createMethodComment(IFunction meth, String lineDelimiter) throws CoreException {
IType declaringType= meth.getDeclaringType();
IFunction overridden= null;
if (!meth.isConstructor() && declaringType!=null) {
ITypeHierarchy hierarchy= SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
MethodOverrideTester tester= new MethodOverrideTester(declaringType, hierarchy);
overridden= tester.findOverriddenMethod(meth, true);
}
return CodeGeneration.getMethodComment(meth, overridden, lineDelimiter);
}
private String createFieldComment(IField field, String lineDelimiter) throws JavaScriptModelException, CoreException {
String typeName= Signature.toString(field.getTypeSignature());
String fieldName= field.getElementName();
return CodeGeneration.getFieldComment(field.getJavaScriptUnit(), typeName, fieldName, lineDelimiter);
}
/**
* @return Returns the scheduling rule for this operation
*/
public ISchedulingRule getScheduleRule() {
return ResourcesPlugin.getWorkspace().getRoot();
}
/**
* Runs the operation.
* @throws OperationCanceledException Runtime error thrown when operation is cancelled.
*/
public void run(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
if (monitor == null) {
monitor= new NullProgressMonitor();
}
if (fMembers.length == 0) {
return;
}
try {
monitor.beginTask(CodeGenerationMessages.AddJavaDocStubOperation_description, fMembers.length + 2);
addJavadocComments(monitor);
} finally {
monitor.done();
}
}
/* moved this so we this can be re-used in web component */
protected IDocument getDocument(IJavaScriptUnit cu, IProgressMonitor monitor) throws CoreException {
ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
IPath path= cu.getPath();
try {
manager.connect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1));
return manager.getTextFileBuffer(path).getDocument();
}finally {
manager.disconnect(path, LocationKind.IFILE,new SubProgressMonitor(monitor, 1));
}
}
private void addJavadocComments(IProgressMonitor monitor) throws CoreException {
IJavaScriptUnit cu= fMembers[0].getJavaScriptUnit();
try {
IDocument document= getDocument(cu,monitor);
String lineDelim= TextUtilities.getDefaultLineDelimiter(document);
MultiTextEdit edit= new MultiTextEdit();
for (int i= 0; i < fMembers.length; i++) {
IMember curr= fMembers[i];
int memberStartOffset= getMemberStartOffset(curr, document);
String comment= null;
switch (curr.getElementType()) {
case IJavaScriptElement.TYPE:
comment= createTypeComment((IType) curr, lineDelim);
break;
case IJavaScriptElement.FIELD:
comment= createFieldComment((IField) curr, lineDelim);
break;
case IJavaScriptElement.METHOD:
comment= createMethodComment((IFunction) curr, lineDelim);
break;
}
if (comment == null) {
StringBuffer buf= new StringBuffer();
buf.append("/**").append(lineDelim); //$NON-NLS-1$
buf.append(" *").append(lineDelim); //$NON-NLS-1$
buf.append(" */").append(lineDelim); //$NON-NLS-1$
comment= buf.toString();
} else {
if (!comment.endsWith(lineDelim)) {
comment= comment + lineDelim;
}
}
final IJavaScriptProject project= cu.getJavaScriptProject();
IRegion region= document.getLineInformationOfOffset(memberStartOffset);
String line= document.get(region.getOffset(), region.getLength());
String indentString= Strings.getIndentString(line, project);
String indentedComment= Strings.changeIndent(comment, 0, project, indentString, lineDelim);
edit.addChild(new InsertEdit(memberStartOffset, indentedComment));
monitor.worked(1);
}
edit.apply(document); // apply all edits
} catch (BadLocationException e) {
throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e));
} finally {
}
}
private int getMemberStartOffset(IMember curr, IDocument document) throws JavaScriptModelException {
int offset= curr.getSourceRange().getOffset();
TokenScanner scanner= new TokenScanner(document, curr.getJavaScriptProject());
try {
return scanner.getNextStartOffset(offset, true); // read to the first real non comment token
} catch (CoreException e) {
// ignore
}
return offset;
}
}