001: /*******************************************************************************
002: * Copyright (c) 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.editor.contentassist;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Collection;
015: import java.util.Comparator;
016: import java.util.ListIterator;
017:
018: import org.eclipse.core.resources.IProject;
019: import org.eclipse.jface.fieldassist.IContentProposal;
020: import org.eclipse.jface.fieldassist.IContentProposalProvider;
021: import org.eclipse.swt.graphics.Image;
022:
023: /**
024: * TypeContentProposalProvider
025: *
026: */
027: public class TypeContentProposalProvider extends
028: TypePackageCompletionProcessor implements
029: IContentProposalProvider {
030:
031: public static final char F_DOT = '.';
032:
033: private IProject fProject;
034:
035: private int fTypeScope;
036:
037: private ArrayList fInitialContentProposals;
038:
039: private String fInitialContent;
040:
041: private Comparator fComparator;
042:
043: /**
044: *
045: */
046: public TypeContentProposalProvider(IProject project, int scope) {
047: fProject = project;
048: fTypeScope = scope;
049: fComparator = new TypeComparator();
050:
051: reset();
052: }
053:
054: /**
055: * TypeComparator
056: *
057: */
058: private static class TypeComparator implements Comparator {
059:
060: /**
061: *
062: */
063: public TypeComparator() {
064: // NO-OP
065: }
066:
067: /* (non-Javadoc)
068: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
069: */
070: public int compare(Object arg0, Object arg1) {
071: String proposalSortKey1 = ((IContentProposal) arg0)
072: .getLabel();
073: String proposalSortKey2 = ((IContentProposal) arg1)
074: .getLabel();
075: return proposalSortKey1
076: .compareToIgnoreCase(proposalSortKey2);
077: }
078: }
079:
080: /* (non-Javadoc)
081: * @see org.eclipse.jface.fieldassist.IContentProposalProvider#getProposals(java.lang.String, int)
082: */
083: public IContentProposal[] getProposals(String contents, int position) {
084: // Generate a list of proposals based on the current contents
085: ArrayList currentContentProposals = null;
086: // Determine method to obtain proposals based on current field contents
087: if (position == 0) {
088: // If the document offset is at the 0 position (i.e. no input entered),
089: // do not perform content assist. The operation is too expensive
090: // because all classes and interfaces (depending on the specified scope)
091: // will need to be resolved as proposals
092: currentContentProposals = null;
093: } else if ((fInitialContentProposals == null)
094: || (contents.length() < fInitialContent.length())
095: || (endsWithDot(contents))) {
096: // Generate new proposals if the content assist session was just
097: // started
098: // Or generate new proposals if the current contents of the field
099: // is less than the initial contents of the field used to
100: // generate the original proposals; thus, widening the search
101: // scope. This can occur when the user types backspace
102: // Or generate new proposals if the current contents ends with a
103: // dot
104: currentContentProposals = generateContentProposals(contents);
105: } else {
106: // Filter existing proposals from a prevous search; thus, narrowing
107: // the search scope. This can occur when the user types additional
108: // characters in the field causing new characters to be appended to
109: // the initial field contents
110: currentContentProposals = filterContentProposals(contents);
111: }
112:
113: return convertResultsToSortedProposals(currentContentProposals);
114: }
115:
116: /**
117: *
118: */
119: public void reset() {
120: fInitialContentProposals = null;
121: }
122:
123: /* (non-Javadoc)
124: * @see org.eclipse.pde.internal.ui.editor.contentassist.TypePackageCompletionProcessor#addProposalToCollection(java.util.Collection, int, int, java.lang.String, java.lang.String, org.eclipse.swt.graphics.Image)
125: */
126: protected void addProposalToCollection(Collection collection,
127: int startOffset, int length, String label, String content,
128: Image image) {
129: // Create content proposals for field assist
130: // start offset and length not required
131: IContentProposal proposal = new TypeContentProposal(label,
132: content, null, image);
133: // Add the proposal to the list of proposals
134: collection.add(proposal);
135: }
136:
137: /**
138: * @param string
139: * @return
140: */
141: private boolean endsWithDot(String string) {
142: int index = string.lastIndexOf(F_DOT);
143: if ((index + 1) == string.length()) {
144: return true;
145: }
146: return false;
147: }
148:
149: /**
150: * @param currentContent
151: * @return
152: */
153: private ArrayList generateContentProposals(String currentContent) {
154: fInitialContentProposals = new ArrayList();
155: // Store the initial field contents to determine if we need to
156: // widen the scope later
157: fInitialContent = currentContent;
158: generateTypePackageProposals(currentContent, fProject,
159: fInitialContentProposals, 0, fTypeScope, true);
160: return fInitialContentProposals;
161: }
162:
163: /**
164: * @param list
165: * @return
166: */
167: private IContentProposal[] convertResultsToSortedProposals(
168: ArrayList list) {
169: IContentProposal[] proposals = null;
170: if ((list != null) && (list.size() != 0)) {
171: // Convert the results array list into an array of completion
172: // proposals
173: proposals = (IContentProposal[]) list
174: .toArray(new IContentProposal[list.size()]);
175: // Sort the proposals alphabetically
176: Arrays.sort(proposals, fComparator);
177: } else {
178: proposals = new IContentProposal[0];
179: }
180: return proposals;
181: }
182:
183: /**
184: * @param currentContent
185: * @return
186: */
187: private ArrayList filterContentProposals(String currentContent) {
188: String lowerCaseCurrentContent = currentContent.toLowerCase();
189: ListIterator iterator = fInitialContentProposals.listIterator();
190: // Maintain a list of filtered search results
191: ArrayList filteredContentProposals = new ArrayList();
192: // Iterate over the initial search results
193: while (iterator.hasNext()) {
194: Object object = iterator.next();
195: IContentProposal proposal = (IContentProposal) object;
196: String compareString = null;
197: if (lowerCaseCurrentContent.indexOf(F_DOT) == -1) {
198: // Use only the type name
199: compareString = proposal.getLabel().toLowerCase();
200: } else {
201: // Use the fully qualified type name
202: compareString = proposal.getContent().toLowerCase();
203: }
204: // Filter out any proposal not matching the current contents
205: // except for the edge case where the proposal is identical to the
206: // current contents
207: if (compareString.startsWith(lowerCaseCurrentContent, 0)) {
208: filteredContentProposals.add(proposal);
209: }
210: }
211: return filteredContentProposals;
212: }
213:
214: }
|