Lines 22-38
Link Here
|
22 |
import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
22 |
import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
23 |
import org.eclipse.jface.text.contentassist.IContextInformation; |
23 |
import org.eclipse.jface.text.contentassist.IContextInformation; |
24 |
import org.eclipse.jface.text.contentassist.IContextInformationValidator; |
24 |
import org.eclipse.jface.text.contentassist.IContextInformationValidator; |
25 |
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
|
|
26 |
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
27 |
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
28 |
import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; |
29 |
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
30 |
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; |
31 |
import org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor; |
25 |
import org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor; |
32 |
import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor; |
26 |
import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor; |
33 |
import org.eclipse.wst.xsl.core.XSLCore; |
27 |
import org.eclipse.wst.xsl.core.XSLCore; |
34 |
import org.eclipse.wst.xsl.ui.internal.Messages; |
28 |
import org.eclipse.wst.xsl.ui.internal.Messages; |
35 |
import org.w3c.dom.Node; |
|
|
36 |
|
29 |
|
37 |
/** |
30 |
/** |
38 |
* The XSL Content Assist Processor provides content assistance for various |
31 |
* The XSL Content Assist Processor provides content assistance for various |
Lines 42-61
Link Here
|
42 |
* @author David Carver |
35 |
* @author David Carver |
43 |
* @since 1.0 |
36 |
* @since 1.0 |
44 |
*/ |
37 |
*/ |
45 |
public class XSLContentAssistProcessor implements IContentAssistProcessor { |
38 |
public class XSLContentAssistProcessor extends AbstractXSLContentAssistProcessor implements IContentAssistProcessor { |
46 |
|
39 |
|
47 |
private String errorMessage = ""; //$NON-NLS-1$ |
|
|
48 |
private ITextViewer textViewer = null; |
49 |
private ArrayList<ICompletionProposal> xslProposals; |
40 |
private ArrayList<ICompletionProposal> xslProposals; |
50 |
private ArrayList<ICompletionProposal> additionalProposals; |
41 |
private ArrayList<ICompletionProposal> additionalProposals; |
51 |
private IndexedRegion treeNode; |
42 |
private ArrayList<String> namespaces; |
52 |
private Node node; |
|
|
53 |
private IDOMNode xmlNode; |
54 |
private IStructuredDocumentRegion sdRegion; |
55 |
private ITextRegion completionRegion; |
56 |
private String matchString; |
57 |
private int cursorPosition; |
58 |
|
59 |
/** |
43 |
/** |
60 |
* Provides an XSL Content Assist Processor class that is XSL aware and XML |
44 |
* Provides an XSL Content Assist Processor class that is XSL aware and XML |
61 |
* aware. |
45 |
* aware. |
Lines 64-69
Link Here
|
64 |
super(); |
48 |
super(); |
65 |
xslProposals = new ArrayList<ICompletionProposal>(); |
49 |
xslProposals = new ArrayList<ICompletionProposal>(); |
66 |
additionalProposals = new ArrayList<ICompletionProposal>(); |
50 |
additionalProposals = new ArrayList<ICompletionProposal>(); |
|
|
51 |
namespaces = new ArrayList<String>(); |
52 |
namespaces.add(XSLCore.XSL_NAMESPACE_URI); |
67 |
} |
53 |
} |
68 |
|
54 |
|
69 |
/** |
55 |
/** |
Lines 83-96
Link Here
|
83 |
ITextViewer textViewer, int documentPosition) { |
69 |
ITextViewer textViewer, int documentPosition) { |
84 |
initializeProposalVariables(textViewer, documentPosition); |
70 |
initializeProposalVariables(textViewer, documentPosition); |
85 |
|
71 |
|
86 |
ICompletionProposal[] xmlProposals = getXMLProposals(); |
|
|
87 |
|
88 |
additionalProposals = getAdditionalXSLElementProposals(); |
72 |
additionalProposals = getAdditionalXSLElementProposals(); |
89 |
|
73 |
|
90 |
xslProposals = getXSLNamespaceProposals(); |
74 |
xslProposals = getXSLNamespaceProposals(); |
91 |
|
75 |
|
92 |
ArrayList<ICompletionProposal> proposalList = new ArrayList<ICompletionProposal>(); |
76 |
ArrayList<ICompletionProposal> proposalList = new ArrayList<ICompletionProposal>(); |
93 |
addProposals(xmlProposals, proposalList); |
|
|
94 |
proposalList.addAll(additionalProposals); |
77 |
proposalList.addAll(additionalProposals); |
95 |
proposalList.addAll(xslProposals); |
78 |
proposalList.addAll(xslProposals); |
96 |
|
79 |
|
Lines 103-124
Link Here
|
103 |
return combinedProposals; |
86 |
return combinedProposals; |
104 |
} |
87 |
} |
105 |
|
88 |
|
106 |
/** |
|
|
107 |
* @param textViewer |
108 |
* @param documentPosition |
109 |
*/ |
110 |
private void initializeProposalVariables(ITextViewer textViewer, |
111 |
int documentPosition) { |
112 |
this.textViewer = textViewer; |
113 |
cursorPosition = documentPosition; |
114 |
treeNode = ContentAssistUtils.getNodeAt(textViewer, cursorPosition); |
115 |
node = getActualDOMNode((Node) treeNode); |
116 |
xmlNode = (IDOMNode) node; |
117 |
sdRegion = getStructuredDocumentRegion(); |
118 |
completionRegion = getCompletionRegion(cursorPosition, node); |
119 |
matchString = getMatchString(sdRegion, completionRegion, cursorPosition); |
120 |
} |
121 |
|
122 |
private ArrayList<ICompletionProposal> getXSLNamespaceProposals() { |
89 |
private ArrayList<ICompletionProposal> getXSLNamespaceProposals() { |
123 |
if (XSLCore.isXSLNamespace(xmlNode)) { |
90 |
if (XSLCore.isXSLNamespace(xmlNode)) { |
124 |
XSLContentAssistRequestFactory requestFactory = new XSLContentAssistRequestFactory( |
91 |
XSLContentAssistRequestFactory requestFactory = new XSLContentAssistRequestFactory( |
Lines 141-163
Link Here
|
141 |
return additionalProposals; |
108 |
return additionalProposals; |
142 |
} |
109 |
} |
143 |
|
110 |
|
144 |
private ICompletionProposal[] getXMLProposals() { |
|
|
145 |
AbstractContentAssistProcessor processor = new XMLContentAssistProcessor(); |
146 |
|
147 |
ICompletionProposal proposals[] = processor.computeCompletionProposals( |
148 |
textViewer, cursorPosition); |
149 |
return proposals; |
150 |
} |
151 |
|
152 |
private void addProposals(ICompletionProposal[] proposals, |
153 |
ArrayList<ICompletionProposal> proposalList) { |
154 |
if (proposals != null) { |
155 |
for (int cnt = 0; cnt < proposals.length; cnt++) { |
156 |
proposalList.add(proposals[cnt]); |
157 |
} |
158 |
} |
159 |
} |
160 |
|
161 |
private ICompletionProposal[] combineProposals( |
111 |
private ICompletionProposal[] combineProposals( |
162 |
ArrayList<ICompletionProposal> proposalList) { |
112 |
ArrayList<ICompletionProposal> proposalList) { |
163 |
ICompletionProposal[] combinedProposals = new ICompletionProposal[proposalList |
113 |
ICompletionProposal[] combinedProposals = new ICompletionProposal[proposalList |
Lines 167-394
Link Here
|
167 |
} |
117 |
} |
168 |
|
118 |
|
169 |
/** |
119 |
/** |
170 |
* @param node |
|
|
171 |
* @return |
172 |
*/ |
173 |
private Node getActualDOMNode(Node node) { |
174 |
while ((node != null) && (node.getNodeType() == Node.TEXT_NODE) |
175 |
&& (node.getParentNode() != null)) { |
176 |
node = node.getParentNode(); |
177 |
} |
178 |
return node; |
179 |
} |
180 |
|
181 |
/** |
182 |
* StructuredTextViewer must be set before using this. |
183 |
* |
184 |
* @param pos |
185 |
* @return |
186 |
*/ |
187 |
private IStructuredDocumentRegion getStructuredDocumentRegion() { |
188 |
return ContentAssistUtils.getStructuredDocumentRegion(textViewer, |
189 |
cursorPosition); |
190 |
} |
191 |
|
192 |
/** |
193 |
* Return the region whose content's require completion. This is something |
194 |
* of a misnomer as sometimes the user wants to be prompted for contents of |
195 |
* a non-existent ITextRegion, such as for enumerated attribute values |
196 |
* following an '=' sign. |
197 |
* |
198 |
* Copied from AbstractContentAssist Processor. |
199 |
*/ |
200 |
protected ITextRegion getCompletionRegion(int documentPosition, Node domnode) { |
201 |
if (domnode == null) { |
202 |
return null; |
203 |
} |
204 |
|
205 |
ITextRegion region = null; |
206 |
int offset = documentPosition; |
207 |
IStructuredDocumentRegion flatNode = null; |
208 |
IDOMNode node = (IDOMNode) domnode; |
209 |
|
210 |
if (node.getNodeType() == Node.DOCUMENT_NODE) { |
211 |
if (node.getStructuredDocument().getLength() == 0) { |
212 |
return null; |
213 |
} |
214 |
ITextRegion result = node.getStructuredDocument() |
215 |
.getRegionAtCharacterOffset(offset) |
216 |
.getRegionAtCharacterOffset(offset); |
217 |
while (result == null) { |
218 |
offset--; |
219 |
result = node.getStructuredDocument() |
220 |
.getRegionAtCharacterOffset(offset) |
221 |
.getRegionAtCharacterOffset(offset); |
222 |
} |
223 |
return result; |
224 |
} |
225 |
|
226 |
IStructuredDocumentRegion startTag = node |
227 |
.getStartStructuredDocumentRegion(); |
228 |
IStructuredDocumentRegion endTag = node |
229 |
.getEndStructuredDocumentRegion(); |
230 |
|
231 |
if ((startTag != null) && (startTag.getStartOffset() <= offset) |
232 |
&& (offset < startTag.getStartOffset() + startTag.getLength())) { |
233 |
flatNode = startTag; |
234 |
} else if ((endTag != null) && (endTag.getStartOffset() <= offset) |
235 |
&& (offset < endTag.getStartOffset() + endTag.getLength())) { |
236 |
flatNode = endTag; |
237 |
} |
238 |
|
239 |
if (flatNode != null) { |
240 |
region = getCompletionRegion(offset, flatNode); |
241 |
} else { |
242 |
flatNode = node.getStructuredDocument().getRegionAtCharacterOffset( |
243 |
offset); |
244 |
if ((flatNode.getStartOffset() <= documentPosition) |
245 |
&& (flatNode.getEndOffset() >= documentPosition)) { |
246 |
if ((offset == flatNode.getStartOffset()) |
247 |
&& (flatNode.getPrevious() != null) |
248 |
&& (((flatNode |
249 |
.getRegionAtCharacterOffset(documentPosition) != null) && (flatNode |
250 |
.getRegionAtCharacterOffset(documentPosition) |
251 |
.getType() != DOMRegionContext.XML_CONTENT)) |
252 |
|| (flatNode.getPrevious().getLastRegion() |
253 |
.getType() == DOMRegionContext.XML_TAG_OPEN) || (flatNode |
254 |
.getPrevious().getLastRegion().getType() == DOMRegionContext.XML_END_TAG_OPEN))) { |
255 |
region = flatNode.getPrevious().getLastRegion(); |
256 |
} else if (flatNode.getEndOffset() == documentPosition) { |
257 |
region = flatNode.getLastRegion(); |
258 |
} else { |
259 |
region = flatNode.getFirstRegion(); |
260 |
} |
261 |
} else { |
262 |
region = flatNode.getLastRegion(); |
263 |
} |
264 |
} |
265 |
|
266 |
return region; |
267 |
} |
268 |
|
269 |
protected ITextRegion getCompletionRegion(int offset, |
270 |
IStructuredDocumentRegion sdRegion) { |
271 |
ITextRegion region = sdRegion.getRegionAtCharacterOffset(offset); |
272 |
if (region == null) { |
273 |
return null; |
274 |
} |
275 |
|
276 |
if (sdRegion.getStartOffset(region) == offset) { |
277 |
// The offset is at the beginning of the region |
278 |
if ((sdRegion.getStartOffset(region) == sdRegion.getStartOffset()) |
279 |
&& (sdRegion.getPrevious() != null) |
280 |
&& (!sdRegion.getPrevious().isEnded())) { |
281 |
region = sdRegion.getPrevious().getRegionAtCharacterOffset( |
282 |
offset - 1); |
283 |
} else { |
284 |
// Is there no separating whitespace from the previous region? |
285 |
// If not, |
286 |
// then that region is the important one |
287 |
ITextRegion previousRegion = sdRegion |
288 |
.getRegionAtCharacterOffset(offset - 1); |
289 |
if ((previousRegion != null) |
290 |
&& (previousRegion != region) |
291 |
&& (previousRegion.getTextLength() == previousRegion |
292 |
.getLength())) { |
293 |
region = previousRegion; |
294 |
} |
295 |
} |
296 |
} else { |
297 |
// The offset is NOT at the beginning of the region |
298 |
if (offset > sdRegion.getStartOffset(region) |
299 |
+ region.getTextLength()) { |
300 |
// Is the offset within the whitespace after the text in this |
301 |
// region? |
302 |
// If so, use the next region |
303 |
ITextRegion nextRegion = sdRegion |
304 |
.getRegionAtCharacterOffset(sdRegion |
305 |
.getStartOffset(region) |
306 |
+ region.getLength()); |
307 |
if (nextRegion != null) { |
308 |
region = nextRegion; |
309 |
} |
310 |
} else { |
311 |
// Is the offset within the important text for this region? |
312 |
// If so, then we've already got the right one. |
313 |
} |
314 |
} |
315 |
|
316 |
// valid WHITE_SPACE region handler (#179924) |
317 |
if ((region != null) |
318 |
&& (region.getType() == DOMRegionContext.WHITE_SPACE)) { |
319 |
ITextRegion previousRegion = sdRegion |
320 |
.getRegionAtCharacterOffset(sdRegion.getStartOffset(region) - 1); |
321 |
if (previousRegion != null) { |
322 |
region = previousRegion; |
323 |
} |
324 |
} |
325 |
|
326 |
return region; |
327 |
} |
328 |
|
329 |
private String getMatchString(IStructuredDocumentRegion parent, |
330 |
ITextRegion aRegion, int offset) { |
331 |
String matchString = ""; //$NON-NLS-1$ |
332 |
|
333 |
if (isNotMatchStringRegion(parent, aRegion, offset)) { |
334 |
return matchString; |
335 |
} |
336 |
|
337 |
if (hasMatchString(parent, aRegion, offset)) { |
338 |
matchString = extractMatchString(parent, aRegion, offset); |
339 |
} |
340 |
return matchString; |
341 |
} |
342 |
|
343 |
private boolean isNotMatchStringRegion(IStructuredDocumentRegion parent, ITextRegion aRegion, int offset) { |
344 |
if (aRegion == null || parent == null) |
345 |
return true; |
346 |
|
347 |
String regionType = aRegion.getType(); |
348 |
int totalRegionOffset = parent.getStartOffset(aRegion) |
349 |
+ aRegion.getTextLength(); |
350 |
return (isCloseRegion(aRegion) |
351 |
|| hasNoMatchString(offset, regionType, totalRegionOffset)); |
352 |
} |
353 |
|
354 |
private boolean isCloseRegion(ITextRegion region) { |
355 |
String type = region.getType(); |
356 |
return ((type == DOMRegionContext.XML_PI_CLOSE) |
357 |
|| (type == DOMRegionContext.XML_TAG_CLOSE) |
358 |
|| (type == DOMRegionContext.XML_EMPTY_TAG_CLOSE) |
359 |
|| (type == DOMRegionContext.XML_CDATA_CLOSE) |
360 |
|| (type == DOMRegionContext.XML_COMMENT_CLOSE) |
361 |
|| (type == DOMRegionContext.XML_ATTLIST_DECL_CLOSE) |
362 |
|| (type == DOMRegionContext.XML_ELEMENT_DECL_CLOSE) |
363 |
|| (type == DOMRegionContext.XML_DOCTYPE_DECLARATION_CLOSE) || (type == DOMRegionContext.XML_DECLARATION_CLOSE)); |
364 |
} |
365 |
|
366 |
private boolean hasMatchString(IStructuredDocumentRegion parent, |
367 |
ITextRegion aRegion, int offset) { |
368 |
return (parent.getText(aRegion).length() > 0) |
369 |
&& (parent.getStartOffset(aRegion) < offset); |
370 |
} |
371 |
|
372 |
private boolean hasNoMatchString(int offset, String regionType, |
373 |
int totalRegionOffset) { |
374 |
return regionType.equals(DOMRegionContext.XML_CONTENT) |
375 |
|| regionType.equals(DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS) |
376 |
|| regionType.equals(DOMRegionContext.XML_TAG_OPEN) |
377 |
|| offset > totalRegionOffset; |
378 |
} |
379 |
|
380 |
private String extractMatchString(IStructuredDocumentRegion parent, |
381 |
ITextRegion aRegion, int offset) { |
382 |
String matchString; |
383 |
matchString = parent.getText(aRegion).substring(0, |
384 |
offset - parent.getStartOffset(aRegion)); |
385 |
if (matchString.startsWith("\"")) { //$NON-NLS-1$ |
386 |
matchString = matchString.substring(1); |
387 |
} |
388 |
return matchString; |
389 |
} |
390 |
|
391 |
/** |
392 |
* (non-Javadoc) |
120 |
* (non-Javadoc) |
393 |
* |
121 |
* |
394 |
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, |
122 |
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, |
Lines 432-453
Link Here
|
432 |
return null; |
160 |
return null; |
433 |
} |
161 |
} |
434 |
|
162 |
|
435 |
/** |
163 |
public String getMaximumVersion() { |
436 |
* (non-Javadoc) |
164 |
return "2.0"; //$NON-NLS-1$ |
437 |
* |
|
|
438 |
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage() |
439 |
*/ |
440 |
public String getErrorMessage() { |
441 |
return errorMessage; |
442 |
} |
165 |
} |
443 |
|
166 |
|
444 |
/** |
167 |
public String getMinimumVersion() { |
445 |
* Sets the error message for why content assistance didn't complete. |
168 |
return "1.0"; //$NON-NLS-1$ |
446 |
* |
169 |
} |
447 |
* @param errorMessage |
170 |
|
448 |
*/ |
171 |
public ArrayList<String> getNamespaces() { |
449 |
public void setErrorMessage(String errorMessage) { |
172 |
return null; |
450 |
this.errorMessage = errorMessage; |
|
|
451 |
} |
173 |
} |
452 |
|
174 |
|
453 |
} |
175 |
} |