upload tizen1.0 source
[sdk/ide/product.git] / org.eclipse.cdt.ui / src / org / eclipse / cdt / internal / ui / text / contentassist / CCompletionProposal.java
1 /*******************************************************************************
2  *  Copyright (c) 2004, 2011 IBM Corporation and others.
3  *  All rights reserved. This program and the accompanying materials
4  *  are made available under the terms of the Eclipse Public License v1.0
5  *  which accompanies this distribution, and is available at
6  *  http://www.eclipse.org/legal/epl-v10.html
7  * 
8  *  Contributors:
9  *     IBM Rational Software - Initial API and implementation
10  *     Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
11  *******************************************************************************/
12
13 package org.eclipse.cdt.internal.ui.text.contentassist;
14
15
16 import org.eclipse.core.runtime.Assert;
17 import org.eclipse.jface.preference.IPreferenceStore;
18 import org.eclipse.jface.preference.PreferenceConverter;
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.BadPositionCategoryException;
21 import org.eclipse.jface.text.DefaultPositionUpdater;
22 import org.eclipse.jface.text.DocumentEvent;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.IInformationControlCreator;
25 import org.eclipse.jface.text.IPositionUpdater;
26 import org.eclipse.jface.text.IRegion;
27 import org.eclipse.jface.text.ITextViewer;
28 import org.eclipse.jface.text.ITextViewerExtension2;
29 import org.eclipse.jface.text.ITextViewerExtension5;
30 import org.eclipse.jface.text.Position;
31 import org.eclipse.jface.text.Region;
32 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
33 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
34 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
35 import org.eclipse.jface.text.contentassist.IContextInformation;
36 import org.eclipse.jface.text.link.ILinkedModeListener;
37 import org.eclipse.jface.text.link.LinkedModeModel;
38 import org.eclipse.jface.text.link.LinkedModeUI;
39 import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags;
40 import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy;
41 import org.eclipse.jface.text.link.LinkedPosition;
42 import org.eclipse.jface.text.link.LinkedPositionGroup;
43 import org.eclipse.swt.SWT;
44 import org.eclipse.swt.custom.StyleRange;
45 import org.eclipse.swt.custom.StyledText;
46 import org.eclipse.swt.events.VerifyEvent;
47 import org.eclipse.swt.graphics.Color;
48 import org.eclipse.swt.graphics.Image;
49 import org.eclipse.swt.graphics.Point;
50 import org.eclipse.swt.graphics.RGB;
51 import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
52
53 import org.eclipse.cdt.ui.CUIPlugin;
54 import org.eclipse.cdt.ui.text.ICCompletionProposal;
55
56 import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
57
58 import org.eclipse.cdt.internal.ui.text.CTextTools;
59
60
61 public class CCompletionProposal implements ICCompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3 {
62         
63         private String fDisplayString;
64     private String fIdString;
65         private String fReplacementString;
66         private int fReplacementOffset;
67         private int fReplacementLength;
68         private int fCursorPosition;
69         private Image fImage;
70         private IContextInformation fContextInformation;
71         private int fContextInformationPosition;
72         private String fProposalInfo;
73         private char[] fTriggerCharacters;
74         protected boolean fToggleEating;
75         protected ITextViewer fTextViewer;      
76         
77         private int fRelevance;
78         private StyleRange fRememberedStyleRange;
79
80         /**
81          * Creates a new completion proposal. All fields are initialized based on the provided information.
82          *
83          * @param replacementString the actual string to be inserted into the document
84          * @param replacementOffset the offset of the text to be replaced
85          * @param replacementLength the length of the text to be replaced
86          * @param image the image to display for this proposal
87          * @param displayString the string to be displayed for the proposal
88          * If set to <code>null</code>, the replacement string will be taken as display string.
89          */
90         public CCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image, String displayString, int relevance) {
91         this(replacementString, replacementOffset, replacementLength, image, displayString, null, relevance, null);
92         }
93
94     /**
95      * Creates a new completion proposal. All fields are initialized based on the provided information.
96      *
97      * @param replacementString the actual string to be inserted into the document
98      * @param replacementOffset the offset of the text to be replaced
99      * @param replacementLength the length of the text to be replaced
100      * @param image the image to display for this proposal
101      * @param displayString the string to be displayed for the proposal
102      * @param viewer the text viewer for which this proposal is computed, may be <code>null</code>
103      * If set to <code>null</code>, the replacement string will be taken as display string.
104      */
105     public CCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image, String displayString, int relevance, ITextViewer viewer) {
106         this(replacementString, replacementOffset, replacementLength, image, displayString, null, relevance, viewer);
107     }
108
109     /**
110      * Creates a new completion proposal. All fields are initialized based on the provided information.
111      *
112      * @param replacementString the actual string to be inserted into the document
113      * @param replacementOffset the offset of the text to be replaced
114      * @param replacementLength the length of the text to be replaced
115      * @param image the image to display for this proposal
116      * @param displayString the string to be displayed for the proposal
117      * @param idString the string to be uniquely identify this proposal
118      * @param viewer the text viewer for which this proposal is computed, may be <code>null</code>
119      * If set to <code>null</code>, the replacement string will be taken as display string.
120      */
121     public CCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image, String displayString, String idString, int relevance, ITextViewer viewer) {
122         Assert.isNotNull(replacementString);
123                 Assert.isTrue(replacementOffset >= 0);
124                 Assert.isTrue(replacementLength >= 0);
125                                 
126                 fReplacementString = replacementString;
127                 fReplacementOffset = replacementOffset;
128                 fReplacementLength = replacementLength;
129                 fImage = image;
130         fRelevance = relevance;
131         fTextViewer = viewer;
132         
133                 fDisplayString = displayString != null ? displayString : replacementString;
134         fIdString = idString != null ? idString : displayString;
135
136                 fCursorPosition = replacementString.length();
137         
138                 fContextInformation = null;
139                 fContextInformationPosition = -1;
140                 fTriggerCharacters = null;
141                 fProposalInfo = null;
142         }
143         
144         /**
145          * Sets the context information.
146          * @param contextInformation The context information associated with this proposal
147          */
148         public void setContextInformation(IContextInformation contextInformation) {
149                 fContextInformation= contextInformation;
150                 fContextInformationPosition= (fContextInformation != null ? fCursorPosition : -1);
151         }
152         
153         /**
154          * Sets the trigger characters.
155          * @param triggerCharacters The set of characters which can trigger the application of this completion proposal
156          */
157         public void setTriggerCharacters(char[] triggerCharacters) {
158                 fTriggerCharacters= triggerCharacters;
159         }
160         
161         /**
162          * Sets the proposal info.
163          * @param proposalInfo The additional information associated with this proposal or <code>null</code>
164          */
165         public void setAdditionalProposalInfo(String proposalInfo) {
166                 fProposalInfo= proposalInfo;
167         }
168         
169         /**
170          * Sets the cursor position relative to the insertion offset. By default this is the length of the completion string
171          * (Cursor positioned after the completion)
172          * @param cursorPosition The cursorPosition to set
173          */
174         public void setCursorPosition(int cursorPosition) {
175                 Assert.isTrue(cursorPosition >= 0);
176                 fCursorPosition= cursorPosition;
177                 fContextInformationPosition= (fContextInformation != null ? fCursorPosition : -1);
178         }
179         
180         /*
181          * @see ICompletionProposalExtension#apply(IDocument, char, int)
182          */
183         public void apply(IDocument document, char trigger, int offset) {
184                 try {
185                         // patch replacement length
186                         int delta= offset - (fReplacementOffset + fReplacementLength);
187                         if (delta > 0)
188                                 fReplacementLength += delta;
189                         
190                         String string;
191                         if (trigger == (char) 0) {
192                                 string= fReplacementString;
193                         } else {
194                                 StringBuffer buffer= new StringBuffer(fReplacementString);
195
196                                 // fix for PR #5533. Assumes that no eating takes place.
197                                 if ((fCursorPosition > 0 && fCursorPosition <= buffer.length() && buffer.charAt(fCursorPosition - 1) != trigger)) {
198                                         buffer.insert(fCursorPosition, trigger);
199                                         ++fCursorPosition;
200                                 }
201                                 
202                                 string= buffer.toString();
203                         }
204
205                         // reference position just at the end of the document change.
206                         int referenceOffset= fReplacementOffset + fReplacementLength;
207                         final ReferenceTracker referenceTracker= new ReferenceTracker();
208                         referenceTracker.preReplace(document, referenceOffset);
209
210                         replace(document, fReplacementOffset, fReplacementLength, string);
211
212                         referenceOffset= referenceTracker.postReplace(document);                        
213                         fReplacementOffset= referenceOffset - (string == null ? 0 : string.length());
214
215                         if (fTextViewer != null && string != null) {
216                                 int index= string.indexOf("()"); //$NON-NLS-1$
217                                 if (index != -1 && index + 1 == fCursorPosition) {
218                                         int newOffset= fReplacementOffset + fCursorPosition;
219                                         
220                                         LinkedPositionGroup group= new LinkedPositionGroup();
221                                         group.addPosition(new LinkedPosition(document, newOffset, 0, LinkedPositionGroup.NO_STOP));
222                                         
223                                         LinkedModeModel model= new LinkedModeModel();
224                                         model.addGroup(group);
225                                         model.forceInstall();
226                                         
227                                         LinkedModeUI ui= new EditorLinkedModeUI(model, fTextViewer);
228                                         ui.setSimpleMode(true);
229                                         ui.setExitPolicy(new ExitPolicy(')'));
230                                         ui.setExitPosition(fTextViewer, newOffset + 1, 0, Integer.MAX_VALUE);
231                                         ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER);
232                                         ui.enter();
233                                 }
234                         }
235
236                 } catch (BadLocationException x) {
237                         // ignore
238                 }               
239         }
240
241         /**
242          * A class to simplify tracking a reference position in a document. 
243          */
244         private static final class ReferenceTracker {
245
246                 /** The reference position category name. */
247                 private static final String CATEGORY= "reference_position"; //$NON-NLS-1$
248                 /** The position updater of the reference position. */
249                 private final IPositionUpdater fPositionUpdater= new DefaultPositionUpdater(CATEGORY);
250                 /** The reference position. */
251                 private final Position fPosition= new Position(0);
252                 
253                 /**
254                  * Called before document changes occur. It must be followed by a call to postReplace().
255                  * 
256                  * @param document the document on which to track the reference position.
257                  *      
258                  */
259                 public void preReplace(IDocument document, int offset) throws BadLocationException {
260                         fPosition.setOffset(offset);
261                         try {
262                                 document.addPositionCategory(CATEGORY);
263                                 document.addPositionUpdater(fPositionUpdater);
264                                 document.addPosition(CATEGORY, fPosition);
265
266                         } catch (BadPositionCategoryException e) {
267                                 // should not happen
268                                 CUIPlugin.log(e);
269                         }
270                 }
271         
272                 /**
273                  * Called after the document changed occured. It must be preceded by a call to preReplace().
274                  * 
275                  * @param document the document on which to track the reference position.
276                  */
277                 public int postReplace(IDocument document) {
278                         try {
279                                 document.removePosition(CATEGORY, fPosition);
280                                 document.removePositionUpdater(fPositionUpdater);
281                                 document.removePositionCategory(CATEGORY);
282                                  
283                         } catch (BadPositionCategoryException e) {
284                                 // should not happen
285                                 CUIPlugin.log(e);
286                         }
287                         return fPosition.getOffset();
288                 }
289         }       
290         
291         protected static class ExitPolicy implements IExitPolicy {
292                 
293                 final char fExitCharacter;
294                 
295                 public ExitPolicy(char exitCharacter) {
296                         fExitCharacter= exitCharacter;
297                 }
298
299                 /*
300                  * @see org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int)
301                  */
302                 public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event, int offset, int length) {
303                         
304                         if (event.character == fExitCharacter) {
305                                 if (environment.anyPositionContains(offset))
306                                         return new ExitFlags(ILinkedModeListener.UPDATE_CARET, false);
307                                 
308                                 return new ExitFlags(ILinkedModeListener.UPDATE_CARET, true);
309                         }       
310                         
311                         switch (event.character) {                      
312                         case ';':
313                                 return new ExitFlags(ILinkedModeListener.NONE, true);
314                                                                 
315                         default:
316                                 return null;
317                         }                                               
318                 }
319
320         }       
321         
322         // #6410 - File unchanged but dirtied by code assist
323         private void replace(IDocument document, int offset, int length, String string) throws BadLocationException {
324                 if (!document.get(offset, length).equals(string))
325                         document.replace(offset, length, string);
326         }
327
328         /*
329          * @see ICompletionProposal#apply
330          */
331         public void apply(IDocument document) {
332                 apply(document, (char) 0, fReplacementOffset + fReplacementLength);
333         }
334         
335         /*
336          * @see ICompletionProposal#getSelection
337          */
338         public Point getSelection(IDocument document) {
339                 return new Point(fReplacementOffset + fCursorPosition, 0);
340         }
341
342         /*
343          * @see ICompletionProposal#getContextInformation()
344          */
345         public IContextInformation getContextInformation() {
346                 return fContextInformation;
347         }
348
349         /*
350          * @see ICompletionProposal#getImage()
351          */
352         public Image getImage() {
353                 return fImage;
354         }
355
356         /*
357          * @see ICompletionProposal#getDisplayString()
358          */
359         public String getDisplayString() {
360                 return fDisplayString;
361         }
362
363     /**
364      * This method is used by the comparator to compare proposals. It ignores the return type of a function.
365      * 
366      * @return the string representing the display name without the return type (if any).
367      */
368     public String getIdString() {
369         return fIdString;
370     }
371     
372         /*
373          * @see ICompletionProposal#getAdditionalProposalInfo()
374          */
375         public String getAdditionalProposalInfo() {
376                 if (fProposalInfo != null) {
377                         return fProposalInfo;
378                 }
379                 return null;
380         }
381         
382         /*
383          * @see ICompletionProposalExtension#getTriggerCharacters()
384          */
385         public char[] getTriggerCharacters() {
386                 return fTriggerCharacters;
387         }
388
389         /*
390          * @see ICompletionProposalExtension#getContextInformationPosition()
391          */
392         public int getContextInformationPosition() {
393                 return fReplacementOffset + fContextInformationPosition;
394         }
395         
396         /**
397          * Gets the replacement offset.
398          * @return Returns a int
399          */
400         public int getReplacementOffset() {
401                 return fReplacementOffset;
402         }
403         
404         /*
405          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getCompletionOffset()
406          */
407         public int getPrefixCompletionStart(IDocument document, int completionOffset) {
408                 return getReplacementOffset();
409         }
410
411         /**
412          * Sets the replacement offset.
413          * @param replacementOffset The replacement offset to set
414          */
415         public void setReplacementOffset(int replacementOffset) {
416                 Assert.isTrue(replacementOffset >= 0);
417                 fReplacementOffset= replacementOffset;
418         }       
419
420         /**
421          * Gets the replacement length.
422          * @return Returns a int
423          */
424         public int getReplacementLength() {
425                 return fReplacementLength;
426         }
427
428         /**
429          * Sets the replacement length.
430          * @param replacementLength The replacementLength to set
431          */
432         public void setReplacementLength(int replacementLength) {
433                 Assert.isTrue(replacementLength >= 0);
434                 fReplacementLength= replacementLength;
435         }
436
437         /**
438          * Gets the replacement string.
439          * @return Returns a String
440          */
441         public String getReplacementString() {
442                 return fReplacementString;
443         }
444         
445         /*
446          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getReplacementText()
447          */
448         public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
449                 String string= getReplacementString();
450                 int pos= string.indexOf('(');
451                 if (pos > 0)
452                         return string.subSequence(0, pos);
453                 return string;
454         }
455
456         /**
457          * Sets the replacement string.
458          * @param replacementString The replacement string to set
459          */
460         public void setReplacementString(String replacementString) {
461                 fReplacementString= replacementString;
462         }
463
464         /**
465          * Sets the image.
466          * @param image The image to set
467          */
468         public void setImage(Image image) {
469                 fImage= image;
470         }
471
472         /*
473          * @see ICompletionProposalExtension#isValidFor(IDocument, int)
474          */
475         public boolean isValidFor(IDocument document, int offset) {
476                 return validate(document, offset, null);
477         }
478
479         /*
480          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument, int, org.eclipse.jface.text.DocumentEvent)
481          */
482         public boolean validate(IDocument document, int offset, DocumentEvent event) {
483
484                 if (offset < fReplacementOffset)
485                         return false;
486                                 
487                 boolean validated= match(document, offset, fReplacementString); 
488
489                 if (validated && event != null) {
490                         // adapt replacement range to document change
491                         int delta= (event.fText == null ? 0 : event.fText.length()) - event.fLength;
492                         fReplacementLength += delta;    
493                 }
494
495                 return validated;
496         }
497         
498         /**
499          * Gets the proposal's relevance.
500          * @return Returns a int
501          */
502         public int getRelevance() {
503                 return fRelevance;
504         }
505
506         /**
507          * Sets the proposal's relevance.
508          * @param relevance The relevance to set
509          */
510         public void setRelevance(int relevance) {
511                 fRelevance= relevance;
512         }
513
514         /**
515          * Returns <code>true</code> if a words matches the code completion prefix in the document,
516          * <code>false</code> otherwise.
517          */     
518         protected boolean match(IDocument document, int offset, String word) {
519                 if (word == null) 
520                         return false;
521                 
522                 final int wordLength= word.length();
523                 if (offset >  fReplacementOffset + wordLength)
524                         return false;
525                 
526                 try {
527                         int length= offset - fReplacementOffset;
528                         String pattern= document.get(fReplacementOffset, length);
529                         return ContentAssistMatcherFactory.getInstance().match(pattern.toCharArray(), word.toCharArray());
530                 } catch (BadLocationException x) {
531                 }
532                 
533                 return false;   
534         }       
535
536         private static boolean insertCompletion() {
537                 IPreferenceStore preference= CUIPlugin.getDefault().getPreferenceStore();
538                 return preference.getBoolean(ContentAssistPreference.AUTOINSERT);
539         }
540
541         /*
542          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension1#apply(org.eclipse.jface.text.ITextViewer, char, int, int)
543          */
544         public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
545
546                 IDocument document= viewer.getDocument();
547
548                 // don't eat if not in preferences, XOR with modifier key 1 (Ctrl)
549                 // but: if there is a selection, replace it!
550                 Point selection= viewer.getSelectedRange();
551                 fToggleEating= (stateMask & SWT.MOD1) != 0;
552                 if (insertCompletion() ^ fToggleEating)
553                         fReplacementLength= selection.x + selection.y - fReplacementOffset;
554                 
555                 apply(document, trigger, offset);
556                 fToggleEating= false;
557         }
558
559         private static Color getForegroundColor(StyledText text) {
560
561                 IPreferenceStore preference= CUIPlugin.getDefault().getPreferenceStore();
562                 RGB rgb= PreferenceConverter.getColor(preference, ContentAssistPreference.PROPOSALS_FOREGROUND);
563                 CTextTools textTools= CUIPlugin.getDefault().getTextTools();
564                 return textTools.getColorManager().getColor(rgb);
565         }
566
567         private static Color getBackgroundColor(StyledText text) {
568
569                 IPreferenceStore preference= CUIPlugin.getDefault().getPreferenceStore();
570                 RGB rgb= PreferenceConverter.getColor(preference, ContentAssistPreference.PROPOSALS_BACKGROUND);
571                 CTextTools textTools= CUIPlugin.getDefault().getTextTools();
572                 return textTools.getColorManager().getColor(rgb);
573         }
574         
575         private void repairPresentation(ITextViewer viewer) {
576                 if (fRememberedStyleRange != null) {
577                          if (viewer instanceof ITextViewerExtension2) {
578                                 // attempts to reduce the redraw area
579                                 ITextViewerExtension2 viewer2= (ITextViewerExtension2) viewer;
580                                 
581                                 if (viewer instanceof ITextViewerExtension5) {
582                                         
583                                         ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
584                                         IRegion widgetRange= extension.modelRange2WidgetRange(new Region(fRememberedStyleRange.start, fRememberedStyleRange.length));
585                                         if (widgetRange != null)
586                                                 viewer2.invalidateTextPresentation(widgetRange.getOffset(), widgetRange.getLength());
587                                                 
588                                 } else {
589                                         viewer2.invalidateTextPresentation(fRememberedStyleRange.start + viewer.getVisibleRegion().getOffset(), fRememberedStyleRange.length);
590                                 }
591                                 
592                         } else
593                                 viewer.invalidateTextPresentation();
594                 }
595         }
596
597         private void updateStyle(ITextViewer viewer) {
598
599                 StyledText text= viewer.getTextWidget();
600                 if (text == null || text.isDisposed())
601                         return;
602
603                 int widgetCaret= text.getCaretOffset();
604                 
605                 int modelCaret= 0;
606                 if (viewer instanceof ITextViewerExtension5) {
607                         ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
608                         modelCaret= extension.widgetOffset2ModelOffset(widgetCaret);
609                 } else {
610                         IRegion visibleRegion= viewer.getVisibleRegion();
611                         modelCaret= widgetCaret + visibleRegion.getOffset();                    
612                 }
613                 
614                 if (modelCaret >= fReplacementOffset + fReplacementLength) {
615                         repairPresentation(viewer);
616                         return;
617                 }
618                                         
619                 int offset= widgetCaret;
620                 int length= fReplacementOffset + fReplacementLength - modelCaret;
621         
622                 Color foreground= getForegroundColor(text);
623                 Color background= getBackgroundColor(text);
624
625                 StyleRange range= text.getStyleRangeAtOffset(offset);
626                 int fontStyle= range != null ? range.fontStyle : SWT.NORMAL;
627
628                 repairPresentation(viewer);
629                 fRememberedStyleRange= new StyleRange(offset, length, foreground, background, fontStyle);
630                 
631                 // http://dev.eclipse.org/bugs/show_bug.cgi?id=34754
632                 try {
633                         text.setStyleRange(fRememberedStyleRange);
634                 } catch (IllegalArgumentException x) {
635                         // catching exception as offset + length might be outside of the text widget
636                         fRememberedStyleRange= null;
637                 }
638         }
639
640         /*
641          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(ITextViewer, boolean)
642          */
643         public void selected(ITextViewer viewer, boolean smartToggle) {
644                 if (!insertCompletion() ^ smartToggle)
645                         updateStyle(viewer);
646                 else {
647                         repairPresentation(viewer);
648                         fRememberedStyleRange= null;
649                 }
650         }
651
652         /*
653          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(ITextViewer)
654          */
655         public void unselected(ITextViewer viewer) {
656                 repairPresentation(viewer);
657                 fRememberedStyleRange= null;
658         }
659
660         /*
661          * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getInformationControlCreator()
662          */
663         public IInformationControlCreator getInformationControlCreator() {
664                 return null;
665         }
666
667         public void updateReplacementOffset(int newOffset) {
668                 setReplacementOffset(newOffset);
669         }
670
671         public void updateReplacementLength(int length) {
672                 setReplacementLength(length);
673         }
674
675         /*
676          * @see java.lang.Object#hashCode()
677          */
678         @Override
679         public int hashCode() {
680                 return fIdString.hashCode();
681         }
682
683         /*
684          * @see java.lang.Object#equals(java.lang.Object)
685          */
686         @Override
687         public boolean equals(Object other) {
688                 if(!(other instanceof ICCompletionProposal))
689                         return false;
690                 return fIdString.equalsIgnoreCase(((ICCompletionProposal)other).getIdString());
691         }
692
693 }