1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.text.template.contentassist;
12 
13 import java.util.ArrayList;
14 
15 import net.sourceforge.phpdt.core.ICompilationUnit;
16 import net.sourceforge.phpdt.internal.corext.Assert;
17 import net.sourceforge.phpdt.internal.corext.template.php.CompilationUnitContext;
18 import net.sourceforge.phpdt.internal.corext.template.php.CompilationUnitContextType;
19 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
20 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
21 
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.IRegion;
25 import org.eclipse.jface.text.ITextViewer;
26 import org.eclipse.jface.text.Region;
27 import org.eclipse.jface.text.templates.GlobalTemplateVariables;
28 import org.eclipse.jface.text.templates.Template;
29 import org.eclipse.jface.text.templates.TemplateContextType;
30 import org.eclipse.swt.graphics.Point;
31 
32 public class TemplateEngine {
33 
34 	private static final String $_LINE_SELECTION = "${" + GlobalTemplateVariables.LineSelection.NAME + "}"; //$NON-NLS-1$ //$NON-NLS-2$
35 
36 	private static final String $_WORD_SELECTION = "${" + GlobalTemplateVariables.WordSelection.NAME + "}"; //$NON-NLS-1$ //$NON-NLS-2$
37 
38 	/** The context type. */
39 	private TemplateContextType fContextType;
40 
41 	/** The result proposals. */
42 	private ArrayList fProposals = new ArrayList();
43 
44 	/**
45 	 * Creates the template engine for a particular context type. See
46 	 * <code>TemplateContext</code> for supported context types.
47 	 */
TemplateEngine(TemplateContextType contextType)48 	public TemplateEngine(TemplateContextType contextType) {
49 		Assert.isNotNull(contextType);
50 		fContextType = contextType;
51 	}
52 
53 	/**
54 	 * Empties the collector.
55 	 */
reset()56 	public void reset() {
57 		fProposals.clear();
58 	}
59 
60 	/**
61 	 * Returns the array of matching templates.
62 	 */
getResults()63 	public TemplateProposal[] getResults() {
64 		return (TemplateProposal[]) fProposals
65 				.toArray(new TemplateProposal[fProposals.size()]);
66 	}
67 
68 	/**
69 	 * Inspects the context of the compilation unit around
70 	 * <code>completionPosition</code> and feeds the collector with proposals.
71 	 *
72 	 * @param viewer
73 	 *            the text viewer
74 	 * @param completionPosition
75 	 *            the context position in the document of the text viewer
76 	 * @param compilationUnit
77 	 *            the compilation unit (may be <code>null</code>)
78 	 */
complete(ITextViewer viewer, int completionPosition, ICompilationUnit compilationUnit)79 	public void complete(ITextViewer viewer, int completionPosition,
80 			ICompilationUnit compilationUnit) {
81 		IDocument document = viewer.getDocument();
82 
83 		if (!(fContextType instanceof CompilationUnitContextType))
84 			return;
85 
86 		Point selection = viewer.getSelectedRange();
87 
88 		// remember selected text
89 		String selectedText = null;
90 		if (selection.y != 0) {
91 			try {
92 				selectedText = document.get(selection.x, selection.y);
93 			} catch (BadLocationException e) {
94 			}
95 		}
96 
97 		CompilationUnitContext context = ((CompilationUnitContextType) fContextType)
98 				.createContext(document, completionPosition, selection.y,
99 						compilationUnit);
100 		context.setVariable("selection", selectedText); //$NON-NLS-1$
101 		int start = context.getStart();
102 		int end = context.getEnd();
103 		IRegion region = new Region(start, end - start);
104 
105 		Template[] templates = PHPeclipsePlugin.getDefault().getTemplateStore()
106 				.getTemplates();
107 
108 		if (selection.y == 0) {
109 			for (int i = 0; i != templates.length; i++)
110 				if (context.canEvaluate(templates[i]))
111 					fProposals.add(new TemplateProposal(templates[i], context,
112 							region, PHPUiImages
113 									.get(PHPUiImages.IMG_OBJS_TEMPLATE)));
114 
115 		} else {
116 
117 			if (context.getKey().length() == 0)
118 				context.setForceEvaluation(true);
119 
120 			boolean multipleLinesSelected = areMultipleLinesSelected(viewer);
121 
122 			for (int i = 0; i != templates.length; i++) {
123 				Template template = templates[i];
124 				if (context.canEvaluate(template)
125 						&& template.getContextTypeId().equals(
126 								context.getContextType().getId())
127 						&& (!multipleLinesSelected
128 								&& template.getPattern().indexOf(
129 										$_WORD_SELECTION) != -1 || (multipleLinesSelected && template
130 								.getPattern().indexOf($_LINE_SELECTION) != -1))) {
131 					fProposals.add(new TemplateProposal(templates[i], context,
132 							region, PHPUiImages
133 									.get(PHPUiImages.IMG_OBJS_TEMPLATE)));
134 				}
135 			}
136 		}
137 	}
138 
139 	/**
140 	 * Returns <code>true</code> if one line is completely selected or if
141 	 * multiple lines are selected. Being completely selected means that all
142 	 * characters except the new line characters are selected.
143 	 *
144 	 * @return <code>true</code> if one or multiple lines are selected
145 	 * @since 2.1
146 	 */
areMultipleLinesSelected(ITextViewer viewer)147 	private boolean areMultipleLinesSelected(ITextViewer viewer) {
148 		if (viewer == null)
149 			return false;
150 
151 		Point s = viewer.getSelectedRange();
152 		if (s.y == 0)
153 			return false;
154 
155 		try {
156 
157 			IDocument document = viewer.getDocument();
158 			int startLine = document.getLineOfOffset(s.x);
159 			int endLine = document.getLineOfOffset(s.x + s.y);
160 			IRegion line = document.getLineInformation(startLine);
161 			return startLine != endLine
162 					|| (s.x == line.getOffset() && s.y == line.getLength());
163 
164 		} catch (BadLocationException x) {
165 			return false;
166 		}
167 	}
168 }
169