Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

summaryrefslogtreecommitdiffstats
blob: d8b4de75a6743b9095df2d4a0e80bd377ef998fd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/*******************************************************************************
 * Copyright (c) 2004 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jst.jsp.ui.internal.contentassist;



import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jst.jsp.core.internal.provisional.JSP11Namespace;
import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace;
import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts;
import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
import org.eclipse.wst.sse.core.utils.StringUtils;
import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal;
import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceCompletionProposal;
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;

/**
 * An implementation of ICompletionProposal whose values can be
 * read after creation.
 * 
 * @plannedfor 1.0
 */
public class JavaTypeCompletionProposal extends CustomCompletionProposal implements IRelevanceCompletionProposal {

	private int fCursorPosition = 0;
	private String fLocalDisplayString;
	private String fShortName;
	private String fQualifiedName;
	private String fContainerName;

	public JavaTypeCompletionProposal(String replacementString, int replacementOffset, int replacementLength, String qualifiedName, Image image, String typeName, String containerName,  int relevence,  boolean updateReplacementLengthOnValidate) {
		super(replacementString, replacementOffset, replacementLength, qualifiedName.length() + 2, image, 
                (containerName != null && containerName.length() > 0) ? typeName + " - " + containerName : typeName, null, null, relevence, true); //$NON-NLS-1$
		// CMVC 243817, superclass was comparing incorrect display string in validate method...
		//super(replacementString, replacementOffset, replacementLength, image, (containerName != null && containerName.length() > 0)? typeName + " - " + containerName:typeName/*qualifiedName*/, relevence);
		fShortName = typeName;
		fQualifiedName = qualifiedName;
		fContainerName = containerName;
		fCursorPosition = fQualifiedName.length() + 2;
		//fProposalInfo = proposalInfo;
		if (containerName != null && containerName.length() > 0)
			fLocalDisplayString = typeName + " - " + containerName; //$NON-NLS-1$
		else
			fLocalDisplayString = typeName;
	}

	public String getDisplayString() {
		return fLocalDisplayString;
	}

	public int getCursorPosition() {
		return fCursorPosition;
	}

	public void setCursorPosition(int cursorPosition) {
		super.setCursorPosition(cursorPosition);
		fCursorPosition = cursorPosition;
	}

	public String getQualifiedName() {
		return fQualifiedName;
	}

	public String getAdditionalProposalInfo() {
		//		String info = super.getAdditionalProposalInfo();
		//		if (info == null || info.length() == 0 && fProposalInfo != null)
		//			return fProposalInfo.getInfo();
		//		return info;
		return null; // unexplained NPE
	}

	public String getShortName() {
		return fShortName;
	}

	protected String getImport(IStructuredDocumentRegion flatNode) {
		ITextRegionList regions = flatNode.getRegions();
		String importSpec = null;
		boolean isImport = false;
		for (int i = 0; i < regions.size(); i++) {
			ITextRegion region = regions.get(i);
			if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) {
				if (flatNode.getText(region).equals(JSP11Namespace.ATTR_NAME_IMPORT)) {
					isImport = true;
				}
				else {
					isImport = false;
				}
			}
			else if (isImport && region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
				importSpec = flatNode.getText(region);
			}
		}
		return importSpec;
	}

	/**
	 * Add an import page directive for the current type name
	 */
	protected int applyImport(IStructuredDocument model) {
		// if the type is in the default package or java.lang, skip it
		if (fContainerName == null || fContainerName.length() == 0 || fContainerName.equals("java.lang")) //$NON-NLS-1$
			return 0;
		// collect page directives and store their import values
		List imports = new ArrayList();
		IStructuredDocumentRegion node = model.getFirstStructuredDocumentRegion();

		// use the last position of a page directive as a hint as to where to add
		// a new one
		int hint = 0;
		// watch for jsp:root so that we use the right XML/JSP format for the directive
		boolean useXML = false;

		while (node != null) {
			// Can't just look for all StructuredDocumentRegions starting with JSP_DIRECTIVE_OPEN
			// since the XML form is required, too
			ITextRegionList regions = node.getRegions();
			if (regions.size() > 1) {
				ITextRegion name = regions.get(1);
				// verify that this is a JSP directive
				if (name.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) {
					// verify that this is a *page* directive
					if (node.getText(name).equals(JSP11Namespace.ATTR_NAME_PAGE) || node.getText(name).equals(JSP12Namespace.ElementName.DIRECTIVE_PAGE)) {
						if (node.getEndOffset() < getReplacementOffset())
							hint = node.getEndOffset();
						String importSpec = getImport(node);
						if (importSpec != null) {
							imports.add(importSpec);
						}
					}
				}
				else {
					// if this is a jsp:root tag, use the XML form
					useXML = useXML || name.getType() == DOMJSPRegionContexts.JSP_ROOT_TAG_NAME;
				}
			}
			node = node.getNext();
		}

		// evaluate requirements for a "new" import directive
		boolean needsImport = !importHandles(fQualifiedName, imports);
		int adjustmentLength = 0;
		// insert "new" import directive
		if (needsImport) {
			String directive = null;

			// vary the XML behavior
			if (useXML) {
				directive = "<jsp:directive.page import=\"" + fQualifiedName + "\"/>"; //$NON-NLS-1$ //$NON-NLS-2$
			}
			else {
				directive = "<%@ page import=\"" + fQualifiedName + "\" %>"; //$NON-NLS-1$ //$NON-NLS-2$
			}

			try {
				IRegion line = model.getLineInformationOfOffset(hint);
				boolean prependNewLine = line.getOffset() + line.getLength() == hint;
				boolean appendNewLine = hint == 0;
				if (prependNewLine)
					directive = model.getLineDelimiter() + directive;
				if (appendNewLine)
					directive = directive + model.getLineDelimiter();
				adjustmentLength = directive.length();
			}
			catch (BadLocationException e) {
				// ignore
			}

			try {
				model.replace(hint, 0, directive);

			}
			catch (BadLocationException e) {
				// Not that we should ever get a BLE, but if so, our
				// replacement offset from the Content Assist call should
				// work
				try {
					model.replace(getReplacementOffset(), 0, directive);
					adjustmentLength = directive.length();
				}
				catch (BadLocationException e2) {
					// now what?
				}
			}
		}
		return adjustmentLength;
	}

	/**
	 * See if the import specification is a wildcard import, and if so, that
	 * it applies to the given type.
	 */
	protected boolean isWildcardMatch(String importSpec, String type) {
		int specLength = importSpec.length();
		if (importSpec.endsWith("*") && specLength > 2 && type.length() >= specLength) { //$NON-NLS-1$
			// pull out the package name including the final '.'
			String container = importSpec.substring(0, specLength - 1);
			// verify that the type is in the container's hierarchy and that
			// there are no other package separators afterwards
			if (type.startsWith(container) && type.indexOf('.', specLength - 1) < 0) {
				// container matches
				return true;
			}
		}
		return false;
	}

	protected boolean importHandles(String type, List listOfImports) {
		Iterator imports = listOfImports.iterator();
		while (imports.hasNext()) {
			String importSpec = StringUtils.strip(imports.next().toString());
			if (importSpec.equals(type) || isWildcardMatch(importSpec, type))
				return true;
		}
		return false;
	}

	public void apply(IDocument document, char trigger, int offset) {
		// If we have a parsed IStructuredDocument, insert the short name instead of the
		// fully qualified name and a import page directive if
		// needed.  Do the import first so the cursor goes to the right location
		// and we don't surprise the user.

		boolean addShortForm = false; //document instanceof IStructuredDocument && fContainerName != null && fContainerName.length() > 0;
		if (addShortForm) {
			setReplacementString('"' + fShortName + '"');
			int importLength = applyImport((IStructuredDocument) document);
			setReplacementOffset(getReplacementOffset() + importLength);
		}

		setCursorPosition(getReplacementString().length());
		super.apply(document, trigger, offset);

	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension1#apply(org.eclipse.jface.text.ITextViewer, char, int, int)
	 */
	public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
		// CMVC 243815
		// (pa) this is overridden to get around replacement length modification
		// which is done in the super (since eclipse 2.1)
		apply(viewer.getDocument(), trigger, offset);
	}

	// code is borrowed from JavaCompletionProposal
	protected boolean startsWith(IDocument document, int offset, String word) {
		int wordLength = word == null ? 0 : word.length();
		if (offset > getReplacementOffset() + wordLength)
			return false;

		try {
			int length = offset - getReplacementOffset();
			// CMVC 243817
			// slightly modified to be a little more flexible for attribute value string matching..
			String start = StringUtils.stripQuotes(document.get(getReplacementOffset(), length));
			return word.toLowerCase().startsWith(start.toLowerCase()) || fQualifiedName.toLowerCase().startsWith(start.toLowerCase());
			//return word.substring(0, length).equalsIgnoreCase(start);
		}
		catch (BadLocationException x) {
			// ignore
		}

		return false;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#validate(org.eclipse.jface.text.IDocument, int, org.eclipse.jface.text.DocumentEvent)
	 //	 */
	//	public boolean validate(IDocument document, int offset, org.eclipse.jface.text.DocumentEvent event) {
	//		return super.validate(document, offset, event);
	//	}
	/* (non-Javadoc)
	 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#selected(org.eclipse.jface.text.ITextViewer, boolean)
	 */
	public void selected(ITextViewer viewer, boolean smartToggle) {
		// (pa) we currently don't use smart toggle...
		super.selected(viewer, false);
	}

}

Back to the top