/******************************************************************************* * Copyright (c) 2012 Spring IDE Developers * 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: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.data.jdt.core; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.IRewriteTarget; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.link.LinkedModeModel; import org.eclipse.jface.text.link.LinkedModeUI; import org.eclipse.jface.text.link.LinkedPosition; import org.eclipse.jface.text.link.LinkedPositionGroup; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.springframework.ide.eclipse.core.StringUtils; import org.springframework.ide.eclipse.data.internal.DataCorePlugin; import org.springsource.ide.eclipse.commons.core.StatusHandler; /** * @author Terry Denney * @since 3.2 */ @SuppressWarnings("restriction") public class FindByMethodCompletionProposal implements IJavaCompletionProposal, ICompletionProposalExtension2 { private final String propertyName; private final Class<?> propertyClass; private final Class<?> domainClass; private final int startOffset; private IRegion selectedRegion; private final ICompilationUnit cu; public FindByMethodCompletionProposal(String propertyName, Class<?> propertyClass, Class<?> domainClass, int startOffset, int endOffset, JavaContentAssistInvocationContext javaContext) { this.propertyName = propertyName; this.propertyClass = propertyClass; this.domainClass = domainClass; this.startOffset = startOffset; this.selectedRegion = new Region(startOffset, endOffset); cu = javaContext.getCompilationUnit(); } public static String getMethodName(String propertyName) { return "findBy" + StringUtils.capitalize(propertyName); } private String getMethodString() { StringBuilder str = new StringBuilder(); str.append(getMethodName(propertyName)); str.append("("); str.append(propertyClass.getSimpleName()); str.append(" "); str.append(propertyName.toLowerCase()); str.append(") : "); str.append("List<"); str.append(domainClass.getSimpleName()); str.append(">"); return str.toString(); } public Point getSelection(IDocument document) { return new Point(selectedRegion.getOffset(), selectedRegion.getLength()); } public String getAdditionalProposalInfo() { return null; } public String getDisplayString() { return getMethodString(); } public Image getImage() { return JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC); } public IContextInformation getContextInformation() { return null; } public int getRelevance() { return 0; } private void beginCompoundChange(ITextViewer viewer) { if (viewer instanceof ITextViewerExtension) { ITextViewerExtension extension = (ITextViewerExtension) viewer; IRewriteTarget rewriteTarget = extension.getRewriteTarget(); rewriteTarget.beginCompoundChange(); } } private void endCompoundChange(ITextViewer viewer) { if (viewer instanceof ITextViewerExtension) { ITextViewerExtension extension = (ITextViewerExtension) viewer; IRewriteTarget rewriteTarget = extension.getRewriteTarget(); rewriteTarget.beginCompoundChange(); } } public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { IDocument document = viewer.getDocument(); try { beginCompoundChange(viewer); int oldImportPos = getLastImportEndPosition(); if (cu.getImport(propertyClass.getCanonicalName()) != null) { cu.createImport(propertyClass.getCanonicalName(), null, null); } if (cu.getImport(domainClass.getCanonicalName()) != null) { cu.createImport(domainClass.getCanonicalName(), null, null); } if (cu.getImport("java.util.List") != null) { cu.createImport("java.util.List", null, null); } int importOffset = getLastImportEndPosition() - oldImportPos; LinkedModeModel model = new LinkedModeModel(); StringBuilder methodStr = new StringBuilder(); int startPos, length; List<LinkedPositionGroup> groups = new ArrayList<LinkedPositionGroup>(); LinkedPositionGroup group; group = new LinkedPositionGroup(); startPos = startOffset + importOffset + methodStr.length(); methodStr.append("List<"); methodStr.append(domainClass.getSimpleName()); methodStr.append(">"); length = methodStr.length(); group.addPosition(new LinkedPosition(document, startPos, length)); groups.add(group); methodStr.append(" "); group = new LinkedPositionGroup(); startPos = startOffset + importOffset + methodStr.length(); String methodName = getMethodName(propertyName); methodStr.append(methodName); length = methodName.length(); group.addPosition(new LinkedPosition(document, startPos, length)); groups.add(group); methodStr.append("("); group = new LinkedPositionGroup(); startPos = startOffset + importOffset + methodStr.length(); String paramTypeName = propertyClass.getSimpleName(); length = paramTypeName.length(); methodStr.append(paramTypeName); group.addPosition(new LinkedPosition(document, startPos, length)); groups.add(group); methodStr.append(" "); group = new LinkedPositionGroup(); startPos = startOffset + importOffset + methodStr.length(); String paramName = propertyName.toLowerCase(); length = paramName.length(); methodStr.append(paramName); group.addPosition(new LinkedPosition(document, startPos, length)); groups.add(group); methodStr.append(");"); document.replace(startOffset + importOffset, offset - startOffset, methodStr.toString()); for (LinkedPositionGroup currGroup : groups) { model.addGroup(currGroup); } model.forceInstall(); LinkedModeUI ui = new LinkedModeUI(model, viewer); ui.setExitPosition(viewer, startOffset + importOffset + methodStr.length(), 0, Integer.MAX_VALUE); ui.enter(); selectedRegion = ui.getSelectedRegion(); } catch (BadLocationException e) { StatusHandler.log(new Status(Status.ERROR, DataCorePlugin.PLUGIN_ID, e.getMessage(), e)); } catch (JavaModelException e) { StatusHandler.log(new Status(Status.ERROR, DataCorePlugin.PLUGIN_ID, e.getMessage(), e)); } finally { endCompoundChange(viewer); } } private int getLastImportEndPosition() { try { IImportDeclaration[] imports = cu.getImports(); int lastPos = -1; for (IImportDeclaration currImport : imports) { ISourceRange sourceRange = currImport.getSourceRange(); if (sourceRange != null) { int currPos = sourceRange.getOffset() + sourceRange.getLength(); if (currPos > lastPos) { lastPos = currPos; } } } return lastPos; } catch (JavaModelException e) { return -1; } } public void selected(ITextViewer viewer, boolean smartToggle) { } public void unselected(ITextViewer viewer) { } public boolean validate(IDocument document, int offset, DocumentEvent event) { return true; } /** * {@inheritDoc} * * @deprecated This method is no longer called by the framework and clients * should overwrite {@link #apply(ITextViewer, char, int, int)} instead */ @Deprecated public void apply(IDocument document) { // not called anymore } }