fix #774 infinite loop in net.sourceforge.phpeclipse.builder.IdentifierIndexManager...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / template / contentassist / TemplateEngine.java
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          */
48         public TemplateEngine(TemplateContextType contextType) {
49                 Assert.isNotNull(contextType);
50                 fContextType = contextType;
51         }
52
53         /**
54          * Empties the collector.
55          */
56         public void reset() {
57                 fProposals.clear();
58         }
59
60         /**
61          * Returns the array of matching templates.
62          */
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          */
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          */
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 }