/******************************************************************************* * Copyright (c) 2008-2010 Sonatype, Inc. * 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: * Sonatype, Inc. - initial API and implementation *******************************************************************************/ package com.liferay.ide.portal.ui.templates; import com.liferay.ide.portal.ui.PortalImages; import com.liferay.ide.portal.ui.PortalUI; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.templates.ContextTypeRegistry; import org.eclipse.jface.text.templates.DocumentTemplateContext; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateContextType; import org.eclipse.jface.text.templates.TemplateException; import org.eclipse.jface.text.templates.TemplateProposal; import org.eclipse.jface.text.templates.persistence.TemplateStore; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.sse.core.utils.StringUtils; import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest; import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor; import org.w3c.dom.Node; import org.w3c.dom.Text; /** * @author Gregory Amerson */ @SuppressWarnings( { "deprecation", "restriction" } ) public class StructuresContentAssistProcessor extends XMLContentAssistProcessor { private ISourceViewer sourceViewer; public StructuresContentAssistProcessor( ISourceViewer sourceViewer ) { super(); this.sourceViewer = sourceViewer; } public static final String extractPrefix( ITextViewer viewer, int offset ) { int i = offset; IDocument document = viewer.getDocument(); if( i > document.getLength() ) { return ""; //$NON-NLS-1$ } try { while( i > 0 ) { char ch = document.getChar( i - 1 ); if( ch == '>' || ch == '<' || ch == ' ' || ch == '\n' || ch == '\t' ) { break; } i--; } return document.get( i, offset - i ); } catch( BadLocationException e ) { return ""; //$NON-NLS-1$ } } @Override protected void addTagInsertionProposals( ContentAssistRequest contentAssistRequest, int childPosition ) { String currentNodeName = getCurrentNode( contentAssistRequest ).getNodeName(); addProposals( contentAssistRequest, StructuresTemplateContext.fromNodeName( currentNodeName ) ); super.addTagInsertionProposals( contentAssistRequest, childPosition ); } private Node getCurrentNode( ContentAssistRequest contentAssistRequest ) { Node currentNode = contentAssistRequest.getNode(); if( currentNode instanceof Text ) { currentNode = currentNode.getParentNode(); } return currentNode; } private void addProposals( ContentAssistRequest request, StructuresTemplateContext context, Node currentNode, String prefix ) { if( request != null ) { IProject eclipseprj = XmlUtils.extractProject( sourceViewer ); ICompletionProposal[] templateProposals = getTemplateProposals( eclipseprj, sourceViewer, request.getReplacementBeginPosition(), context.getContextTypeId(), currentNode, prefix ); for( ICompletionProposal proposal : templateProposals ) { if( request.shouldSeparate() ) { request.addMacro( proposal ); } else { request.addProposal( proposal ); } } } } protected TemplateContext createContext( ITextViewer viewer, IRegion region, String contextTypeId ) { TemplateContextType contextType = getContextType( viewer, region, contextTypeId ); if( contextType != null ) { IDocument document = viewer.getDocument(); return new DocumentTemplateContext( contextType, document, region.getOffset(), region.getLength() ); } return null; } protected TemplateContextType getContextType( ITextViewer viewer, IRegion region, String contextTypeId ) { ContextTypeRegistry registry = PortalUI.getDefault().getTemplateContextRegistry(); if( registry != null ) { return registry.getContextType( contextTypeId ); } return null; } protected int getRelevance( Template template, String prefix ) { if( template.getName().startsWith( prefix ) ) { return 90; } return 0; } private TemplateProposal createProposalForTemplate( String prefix, Region region, TemplateContext context, Image image, final Template template, boolean isUserTemplate ) { try { context.getContextType().validate( template.getPattern() ); if( template.matches( prefix, context.getContextType().getId() ) ) { if( isUserTemplate ) { // for templates defined by users, preserve the default behaviour.. return new TemplateProposal( template, context, region, image, getRelevance( template, prefix ) ) { public String getAdditionalProposalInfo() { return StringUtils.convertToHTMLContent( super.getAdditionalProposalInfo() ); } }; } else { return new TemplateProposal( template, context, region, image, getRelevance( template, prefix ) ) { public String getAdditionalProposalInfo() { return getTemplate().getDescription(); } public String getDisplayString() { return template.getName(); } }; } } } catch( TemplateException e ) { // ignore } return null; } private ICompletionProposal[] getTemplateProposals( IProject eclipseprj, ITextViewer viewer, int offset, String contextTypeId, Node currentNode, String prefix ) { ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection(); // adjust offset to end of normalized selection if( selection.getOffset() == offset ) { offset = selection.getOffset() + selection.getLength(); } // String prefix = extractPrefix(viewer, offset); Region region = new Region( offset - prefix.length(), prefix.length() ); TemplateContext context = createContext( viewer, region, contextTypeId ); if( context == null ) { return new ICompletionProposal[0]; } // name of the selection variables {line, word}_selection context.setVariable( "selection", selection.getText() ); //$NON-NLS-1$ StructuresTemplateContext templateContext = StructuresTemplateContext.fromId( contextTypeId ); // add the user defined templates - separate them from the rest of the templates // so that we know what they are and can assign proper icon to them. Image image = PortalImages.IMG_USER_TEMPLATE; List<TemplateProposal> matches = new ArrayList<TemplateProposal>(); TemplateStore store = PortalUI.getDefault().getTemplateStore(); if( store != null ) { Template[] templates = store.getTemplates( contextTypeId ); for( Template template : templates ) { TemplateProposal proposal = createProposalForTemplate( prefix, region, context, image, template, true ); if( proposal != null ) { matches.add( proposal ); } } } image = null; Template[] templates = templateContext.getTemplates( eclipseprj, currentNode, prefix ); for( Template template : templates ) { TemplateProposal proposal = createProposalForTemplate( prefix, region, context, image, template, false ); if( proposal != null ) { matches.add( proposal ); } } return (ICompletionProposal[]) matches.toArray( new ICompletionProposal[matches.size()] ); } private void addProposals( ContentAssistRequest request, StructuresTemplateContext context ) { ITextSelection selection = (ITextSelection) sourceViewer.getSelectionProvider().getSelection(); int offset = request.getReplacementBeginPosition(); // adjust offset to end of normalized selection if( selection.getOffset() == offset ) { offset = selection.getOffset() + selection.getLength(); } String prefix = extractPrefix( sourceViewer, offset ); addProposals( request, context, getCurrentNode( request ), prefix ); } }