001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.text.template.contentassist;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014: import java.util.Map;
015:
016: import org.eclipse.text.edits.MalformedTreeException;
017:
018: import org.eclipse.core.runtime.CoreException;
019:
020: import org.eclipse.swt.graphics.Image;
021: import org.eclipse.swt.graphics.Point;
022: import org.eclipse.swt.widgets.Shell;
023:
024: import org.eclipse.jface.dialogs.MessageDialog;
025:
026: import org.eclipse.jface.text.BadLocationException;
027: import org.eclipse.jface.text.Document;
028: import org.eclipse.jface.text.DocumentEvent;
029: import org.eclipse.jface.text.IDocument;
030: import org.eclipse.jface.text.IRegion;
031: import org.eclipse.jface.text.IRewriteTarget;
032: import org.eclipse.jface.text.ITextViewer;
033: import org.eclipse.jface.text.ITextViewerExtension;
034: import org.eclipse.jface.text.Region;
035: import org.eclipse.jface.text.templates.GlobalTemplateVariables;
036: import org.eclipse.jface.text.templates.Template;
037: import org.eclipse.jface.text.templates.TemplateBuffer;
038: import org.eclipse.jface.text.templates.TemplateException;
039:
040: import org.eclipse.jdt.core.ICompilationUnit;
041: import org.eclipse.jdt.core.IJavaProject;
042: import org.eclipse.jdt.core.dom.AST;
043: import org.eclipse.jdt.core.dom.ASTNode;
044: import org.eclipse.jdt.core.dom.ASTParser;
045: import org.eclipse.jdt.core.dom.Block;
046: import org.eclipse.jdt.core.dom.MethodDeclaration;
047: import org.eclipse.jdt.core.dom.Statement;
048:
049: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
050: import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
051: import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContext;
052: import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType;
053: import org.eclipse.jdt.internal.corext.template.java.JavaContextType;
054:
055: import org.eclipse.jdt.ui.text.java.IInvocationContext;
056:
057: import org.eclipse.jdt.internal.ui.JavaPlugin;
058: import org.eclipse.jdt.internal.ui.text.correction.AssistContext;
059: import org.eclipse.jdt.internal.ui.text.correction.SurroundWith;
060:
061: public class SurroundWithTemplateProposal extends TemplateProposal {
062:
063: private static class SurroundWithTemplate extends SurroundWith {
064:
065: private static final String $_LINE_SELECTION = "${" + GlobalTemplateVariables.LineSelection.NAME + "}"; //$NON-NLS-1$ //$NON-NLS-2$
066:
067: private final Template fTemplate;
068: private final IJavaProject fCurrentProject;
069: private ASTNode fTemplateNode;
070:
071: public SurroundWithTemplate(IInvocationContext context,
072: Statement[] selectedNodes, Template template) {
073: super (context.getASTRoot(), selectedNodes);
074: fTemplate = template;
075: fCurrentProject = context.getCompilationUnit()
076: .getJavaProject();
077: }
078:
079: protected List getVariableDeclarationReadsInside(
080: Statement[] selectedNodes, int maxVariableId) {
081: if (isNewContext())
082: return super .getVariableDeclarationReadsInside(
083: selectedNodes, maxVariableId);
084: return new ArrayList();
085: }
086:
087: protected boolean isNewContext() {
088:
089: final String templateVariableRegEx = "\\$\\{[^\\}]*\\}"; //$NON-NLS-1$
090:
091: String template = fTemplate.getPattern();
092: int currentPosition = template.indexOf($_LINE_SELECTION);
093: int insertionPosition = -1;
094: while (currentPosition != -1) {
095: insertionPosition = currentPosition;
096: template = template.replaceFirst(templateVariableRegEx,
097: ""); //$NON-NLS-1$
098: currentPosition = template.indexOf($_LINE_SELECTION);
099: }
100: template = template.replaceAll(templateVariableRegEx, ""); //$NON-NLS-1$
101:
102: AST ast = getAst();
103: ASTParser parser = ASTParser.newParser(ast.apiLevel());
104: parser.setSource(template.toCharArray());
105: parser.setProject(fCurrentProject);
106: parser.setKind(ASTParser.K_STATEMENTS);
107: ASTNode root = parser.createAST(null);
108: if (((Block) root).statements().isEmpty()) {
109: parser = ASTParser.newParser(ast.apiLevel());
110: parser.setSource(template.toCharArray());
111: parser.setProject(fCurrentProject);
112: parser.setKind(ASTParser.K_EXPRESSION);
113: root = parser.createAST(null);
114: }
115:
116: final int lineSelectionPosition = insertionPosition;
117: root.accept(new GenericVisitor() {
118: public void endVisit(Block node) {
119: super .endVisit(node);
120: if (fTemplateNode == null
121: && node.getStartPosition() <= lineSelectionPosition
122: && node.getLength()
123: + node.getStartPosition() >= lineSelectionPosition) {
124: fTemplateNode = node;
125: }
126: }
127: });
128:
129: if (fTemplateNode != null
130: && ASTNodes.getParent(fTemplateNode,
131: MethodDeclaration.class) != null) {
132: return true;
133: }
134:
135: return false;
136: }
137:
138: }
139:
140: private final IRegion fRegion;
141: private final ICompilationUnit fCompilationUnit;
142: private final CompilationUnitContext fContext;
143: private final Template fTemplate;
144: private final Statement[] fSelectedStatements;
145: private TemplateProposal fProposal;
146: private IRegion fSelectedRegion;
147:
148: public SurroundWithTemplateProposal(
149: ICompilationUnit compilationUnit, Template template,
150: CompilationUnitContext context, IRegion region,
151: Image image, Statement[] selectedStatements) {
152: super (template, context, region, image);
153: fCompilationUnit = compilationUnit;
154: fTemplate = template;
155: fContext = context;
156: fRegion = region;
157: fSelectedStatements = selectedStatements;
158: }
159:
160: /* (non-Javadoc)
161: * @see org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateProposal#getAdditionalProposalInfo()
162: */
163: public String getPreviewContent() {
164: try {
165: IDocument document = new Document(fCompilationUnit
166: .getBuffer().getContents());
167: CompilationUnitContext context = createNewContext(document);
168:
169: int offset = context.getCompletionOffset();
170: int start = context.getStart();
171: int end = context.getEnd();
172: IRegion region = new Region(start, end - start);
173:
174: context.setReadOnly(false);
175: TemplateBuffer templateBuffer;
176: try {
177: templateBuffer = context.evaluate(fTemplate);
178: } catch (TemplateException e1) {
179: JavaPlugin.log(e1);
180: return null;
181: }
182:
183: start = region.getOffset();
184: end = region.getOffset() + region.getLength();
185: end = Math.max(end, offset);
186:
187: String templateString = templateBuffer.getString();
188: document.replace(start, end - start, templateString);
189:
190: return document.get();
191:
192: } catch (MalformedTreeException e) {
193: JavaPlugin.log(e);
194: } catch (IllegalArgumentException e) {
195: JavaPlugin.log(e);
196: } catch (BadLocationException e) {
197: JavaPlugin.log(e);
198: } catch (CoreException e) {
199: JavaPlugin.log(e);
200: }
201: return null;
202: }
203:
204: /* (non-Javadoc)
205: * @see org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateProposal#apply(org.eclipse.jface.text.ITextViewer, char, int, int)
206: */
207: public void apply(ITextViewer viewer, char trigger, int stateMask,
208: int offset) {
209: try {
210: setRedraw(viewer, false);
211: IDocument document = viewer.getDocument();
212: CompilationUnitContext context = createNewContext(document);
213:
214: int start = context.getStart();
215: int end = context.getEnd();
216: IRegion region = new Region(start, end - start);
217:
218: //Evaluate the template within the new context
219: fProposal = new TemplateProposal(fTemplate, context,
220: region, null);
221: fProposal.apply(viewer, trigger, stateMask, context
222: .getCompletionOffset());
223: } catch (MalformedTreeException e) {
224: handleException(viewer, e, fRegion);
225: } catch (IllegalArgumentException e) {
226: handleException(viewer, e, fRegion);
227: } catch (BadLocationException e) {
228: handleException(viewer, e, fRegion);
229: } catch (CoreException e) {
230: handleException(viewer, e, fRegion);
231: } finally {
232: setRedraw(viewer, true);
233: }
234: }
235:
236: private void setRedraw(ITextViewer viewer, boolean redraw) {
237: if (viewer instanceof ITextViewerExtension) {
238: ITextViewerExtension extension = (ITextViewerExtension) viewer;
239: IRewriteTarget target = extension.getRewriteTarget();
240: target.setRedraw(redraw);
241: }
242: }
243:
244: public Point getSelection(IDocument document) {
245: if (fSelectedRegion != null) {
246: return new Point(fSelectedRegion.getOffset(),
247: fSelectedRegion.getLength());
248: } else if (fProposal != null) {
249: return fProposal.getSelection(document);
250: } else {
251: return null;
252: }
253: }
254:
255: private CompilationUnitContext createNewContext(IDocument document)
256: throws CoreException, BadLocationException {
257: AssistContext invocationContext = new AssistContext(
258: fCompilationUnit, fContext.getStart(), fContext
259: .getEnd()
260: - fContext.getStart());
261:
262: SurroundWithTemplate surroundWith = new SurroundWithTemplate(
263: invocationContext, fSelectedStatements, fTemplate);
264: Map options = fCompilationUnit.getJavaProject()
265: .getOptions(true);
266:
267: surroundWith.getRewrite().rewriteAST(document, options).apply(
268: document);
269:
270: int offset = surroundWith.getBodyStart();
271: int length = surroundWith.getBodyLength();
272: String newSelection = document.get(offset, length);
273:
274: //Create the new context
275: CompilationUnitContextType contextType = (CompilationUnitContextType) JavaPlugin
276: .getDefault().getTemplateContextRegistry()
277: .getContextType(JavaContextType.ID);
278: CompilationUnitContext context = contextType.createContext(
279: document, offset, newSelection.length(),
280: fCompilationUnit);
281: context.setVariable("selection", newSelection); //$NON-NLS-1$
282: context.setForceEvaluation(true);
283: return context;
284: }
285:
286: private void handleException(ITextViewer viewer, Exception e,
287: IRegion region) {
288: JavaPlugin.log(e);
289: openErrorDialog(viewer.getTextWidget().getShell(), e);
290: fSelectedRegion = region;
291: }
292:
293: private void openErrorDialog(Shell shell, Exception e) {
294: MessageDialog
295: .openError(
296: shell,
297: TemplateContentAssistMessages.TemplateEvaluator_error_title,
298: e.getMessage());
299: }
300:
301: /**
302: * {@inheritDoc}
303: */
304: public boolean validate(IDocument document, int offset,
305: DocumentEvent event) {
306: return false;
307: }
308: }
|