comparison dwtx/jface/internal/text/link/contentassist/ContentAssistant2.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children c4fb132a086c
comparison
equal deleted inserted replaced
128:8df1d4193877 129:eb30df5ca28b
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 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 Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.jface.internal.text.link.contentassist.ContentAssistant2;
14
15 import dwt.dwthelper.utils;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import dwt.DWT;
24 import dwt.DWTError;
25 import dwt.custom.StyledText;
26 import dwt.custom.VerifyKeyListener;
27 import dwt.events.ControlEvent;
28 import dwt.events.ControlListener;
29 import dwt.events.DisposeEvent;
30 import dwt.events.DisposeListener;
31 import dwt.events.FocusEvent;
32 import dwt.events.FocusListener;
33 import dwt.events.MouseEvent;
34 import dwt.events.MouseListener;
35 import dwt.events.VerifyEvent;
36 import dwt.graphics.Color;
37 import dwt.graphics.Point;
38 import dwt.graphics.Rectangle;
39 import dwt.widgets.Control;
40 import dwt.widgets.Display;
41 import dwt.widgets.Event;
42 import dwt.widgets.Listener;
43 import dwt.widgets.Shell;
44 import dwt.widgets.Widget;
45 import dwtx.core.runtime.Assert;
46 import dwtx.jface.text.BadLocationException;
47 import dwtx.jface.text.DefaultInformationControl;
48 import dwtx.jface.text.IEventConsumer;
49 import dwtx.jface.text.IInformationControl;
50 import dwtx.jface.text.IInformationControlCreator;
51 import dwtx.jface.text.ITextViewer;
52 import dwtx.jface.text.ITextViewerExtension;
53 import dwtx.jface.text.IViewportListener;
54 import dwtx.jface.text.IWidgetTokenKeeper;
55 import dwtx.jface.text.IWidgetTokenKeeperExtension;
56 import dwtx.jface.text.IWidgetTokenOwner;
57 import dwtx.jface.text.IWidgetTokenOwnerExtension;
58 import dwtx.jface.text.TextUtilities;
59 import dwtx.jface.text.contentassist.CompletionProposal;
60 import dwtx.jface.text.contentassist.ICompletionProposal;
61 import dwtx.jface.text.contentassist.ICompletionProposalExtension6;
62 import dwtx.jface.text.contentassist.IContentAssistProcessor;
63 import dwtx.jface.text.contentassist.IContentAssistant;
64 import dwtx.jface.text.contentassist.IContentAssistantExtension;
65 import dwtx.jface.text.contentassist.IContextInformation;
66 import dwtx.jface.text.contentassist.IContextInformationPresenter;
67 import dwtx.jface.text.contentassist.IContextInformationValidator;
68
69
70 /**
71 * A custom implementation of the <code>IContentAssistant</code> interface.
72 * This implementation is used by the linked mode UI. This is internal and subject
73 * to change without notice.
74 */
75 public class ContentAssistant2 : IContentAssistant, IContentAssistantExtension, IWidgetTokenKeeper, IWidgetTokenKeeperExtension {
76
77 /**
78 * A generic closer class used to monitor various
79 * interface events in order to determine whether
80 * content-assist should be terminated and all
81 * associated windows closed.
82 */
83 class Closer : ControlListener, MouseListener, FocusListener, DisposeListener, IViewportListener {
84
85 /** The shell on which we add listeners. */
86 private Shell fShell;
87 private long fViewportListenerStartTime;
88
89 /**
90 * Installs this closer on it's viewer's text widget.
91 */
92 protected void install() {
93 Control w= fViewer.getTextWidget();
94 if (Helper2.okToUse(w)) {
95
96 Shell shell= w.getShell();
97 fShell= shell;
98 shell.addControlListener(this);
99
100 w.addMouseListener(this);
101 w.addFocusListener(this);
102
103 /*
104 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of Internal Errors
105 */
106 w.addDisposeListener(this);
107 }
108
109 fViewer.addViewportListener(this);
110 fViewportListenerStartTime= System.currentTimeMillis() + 500;
111 }
112
113 /**
114 * Uninstalls this closer from the viewer's text widget.
115 */
116 protected void uninstall() {
117 Shell shell= fShell;
118 fShell= null;
119 if (Helper2.okToUse(shell))
120 shell.removeControlListener(this);
121
122 Control w= fViewer.getTextWidget();
123 if (Helper2.okToUse(w)) {
124
125 w.removeMouseListener(this);
126 w.removeFocusListener(this);
127
128 /*
129 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of Internal Errors
130 */
131 w.removeDisposeListener(this);
132 }
133
134 fViewer.removeViewportListener(this);
135 }
136
137 /*
138 * @see ControlListener#controlResized(ControlEvent)
139 */
140 public void controlResized(ControlEvent e) {
141 hide();
142 }
143
144 /*
145 * @see ControlListener#controlMoved(ControlEvent)
146 */
147 public void controlMoved(ControlEvent e) {
148 hide();
149 }
150
151 /*
152 * @see MouseListener#mouseDown(MouseEvent)
153 */
154 public void mouseDown(MouseEvent e) {
155 hide();
156 }
157
158 /*
159 * @see MouseListener#mouseUp(MouseEvent)
160 */
161 public void mouseUp(MouseEvent e) {
162 }
163
164 /*
165 * @see MouseListener#mouseDoubleClick(MouseEvent)
166 */
167 public void mouseDoubleClick(MouseEvent e) {
168 hide();
169 }
170
171 /*
172 * @see FocusListener#focusGained(FocusEvent)
173 */
174 public void focusGained(FocusEvent e) {
175 }
176
177 /*
178 * @see FocusListener#focusLost(FocusEvent)
179 */
180 public void focusLost(FocusEvent e) {
181 if (fViewer !is null) {
182 Control control= fViewer.getTextWidget();
183 if (control !is null) {
184 Display d= control.getDisplay();
185 if (d !is null) {
186 d.asyncExec(new Runnable() {
187 public void run() {
188 if (!hasFocus())
189 hide();
190 }
191 });
192 }
193 }
194 }
195 }
196
197 /*
198 * @seeDisposeListener#widgetDisposed(DisposeEvent)
199 */
200 public void widgetDisposed(DisposeEvent e) {
201 /*
202 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of Internal Errors
203 */
204 hide();
205 }
206
207 /*
208 * @see IViewportListener#viewportChanged(int)
209 */
210 public void viewportChanged(int topIndex) {
211 if (System.currentTimeMillis() > fViewportListenerStartTime)
212 hide();
213 }
214 }
215
216 /**
217 * An implementation of <code>IContentAssistListener</code>, this class is
218 * used to monitor key events in support of automatic activation
219 * of the content assistant. If enabled, the implementation utilizes a
220 * thread to watch for input characters matching the activation
221 * characters specified by the content assist processor, and if
222 * detected, will wait the indicated delay interval before
223 * activating the content assistant.
224 */
225 class AutoAssistListener : VerifyKeyListener, Runnable {
226
227 private Thread fThread;
228 private bool fIsReset= false;
229 private Object fMutex= new Object();
230 private int fShowStyle;
231
232 private final static int SHOW_PROPOSALS= 1;
233 private final static int SHOW_CONTEXT_INFO= 2;
234
235 protected AutoAssistListener() {
236 }
237
238 protected void start(int showStyle) {
239 fShowStyle= showStyle;
240 fThread= new Thread(this, ContentAssistMessages.getString("ContentAssistant.assist_delay_timer_name")); //$NON-NLS-1$
241 fThread.start();
242 }
243
244 public void run() {
245 try {
246 while (true) {
247 synchronized (fMutex) {
248 if (fAutoActivationDelay !is 0)
249 fMutex.wait(fAutoActivationDelay);
250 if (fIsReset) {
251 fIsReset= false;
252 continue;
253 }
254 }
255 showAssist(fShowStyle);
256 break;
257 }
258 } catch (InterruptedException e) {
259 }
260 fThread= null;
261 }
262
263 protected void reset(int showStyle) {
264 synchronized (fMutex) {
265 fShowStyle= showStyle;
266 fIsReset= true;
267 fMutex.notifyAll();
268 }
269 }
270
271 protected void stop() {
272 Thread threadToStop= fThread;
273 if (threadToStop !is null)
274 threadToStop.interrupt();
275 }
276
277 private bool contains(char[] characters, char character) {
278 if (characters !is null) {
279 for (int i= 0; i < characters.length; i++) {
280 if (character is characters[i])
281 return true;
282 }
283 }
284 return false;
285 }
286
287 public void verifyKey(VerifyEvent e) {
288 // Only act on typed characters and ignore modifier-only events
289 if (e.character is 0 && (e.keyCode & DWT.KEYCODE_BIT) is 0)
290 return;
291
292 if (e.character !is 0 && (e.stateMask is DWT.ALT))
293 return;
294
295 int showStyle;
296 int pos= fViewer.getSelectedRange().x;
297 char[] activation= getCompletionProposalAutoActivationCharacters(fViewer, pos);
298
299 if (contains(activation, e.character) && !fProposalPopup.isActive())
300 showStyle= SHOW_PROPOSALS;
301 else {
302 activation= getContextInformationAutoActivationCharacters(fViewer, pos);
303 if (contains(activation, e.character) && !fContextInfoPopup.isActive())
304 showStyle= SHOW_CONTEXT_INFO;
305 else {
306 if (fThread !is null && fThread.isAlive())
307 stop();
308 return;
309 }
310 }
311
312 if (fThread !is null && fThread.isAlive())
313 reset(showStyle);
314 else
315 start(showStyle);
316 }
317
318 protected void showAssist(final int showStyle) {
319 Control control= fViewer.getTextWidget();
320 Display d= control.getDisplay();
321 if (d !is null) {
322 try {
323 d.syncExec(new Runnable() {
324 public void run() {
325 if (showStyle is SHOW_PROPOSALS)
326 fProposalPopup.showProposals(true);
327 else if (showStyle is SHOW_CONTEXT_INFO)
328 fContextInfoPopup.showContextProposals(true);
329 }
330 });
331 } catch (DWTError e) {
332 }
333 }
334 }
335 }
336
337 /**
338 * The layout manager layouts the various
339 * windows associated with the content assistant based on the
340 * settings of the content assistant.
341 */
342 class LayoutManager : Listener {
343
344 // Presentation types.
345 /** proposal selector */
346 public final static int LAYOUT_PROPOSAL_SELECTOR= 0;
347 /** context selector */
348 public final static int LAYOUT_CONTEXT_SELECTOR= 1;
349 /** context info */
350 public final static int LAYOUT_CONTEXT_INFO_POPUP= 2;
351
352 int fContextType= LAYOUT_CONTEXT_SELECTOR;
353 Shell[] fShells= new Shell[3];
354 Object[] fPopups= new Object[3];
355
356 protected void add(Object popup, Shell shell, int type, int offset) {
357 Assert.isNotNull(popup);
358 Assert.isTrue(shell !is null && !shell.isDisposed());
359 checkType(type);
360
361 if (fShells[type] !is shell) {
362 if (fShells[type] !is null)
363 fShells[type].removeListener(DWT.Dispose, this);
364 shell.addListener(DWT.Dispose, this);
365 fShells[type]= shell;
366 }
367
368 fPopups[type]= popup;
369 if (type is LAYOUT_CONTEXT_SELECTOR || type is LAYOUT_CONTEXT_INFO_POPUP)
370 fContextType= type;
371
372 layout(type, offset);
373 adjustListeners(type);
374 }
375
376 protected void checkType(int type) {
377 Assert.isTrue(type is LAYOUT_PROPOSAL_SELECTOR ||
378 type is LAYOUT_CONTEXT_SELECTOR || type is LAYOUT_CONTEXT_INFO_POPUP);
379 }
380
381 public void handleEvent(Event event) {
382 Widget source= event.widget;
383 source.removeListener(DWT.Dispose, this);
384
385 int type= getShellType(source);
386 checkType(type);
387 fShells[type]= null;
388
389 switch (type) {
390 case LAYOUT_PROPOSAL_SELECTOR:
391 if (fContextType is LAYOUT_CONTEXT_SELECTOR &&
392 Helper2.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR])) {
393 // Restore event notification to the tip popup.
394 addContentAssistListener((IContentAssistListener2) fPopups[LAYOUT_CONTEXT_SELECTOR], CONTEXT_SELECTOR);
395 }
396 break;
397
398 case LAYOUT_CONTEXT_SELECTOR:
399 if (Helper2.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
400 if (fProposalPopupOrientation is PROPOSAL_STACKED)
401 layout(LAYOUT_PROPOSAL_SELECTOR, getSelectionOffset());
402 // Restore event notification to the proposal popup.
403 addContentAssistListener((IContentAssistListener2) fPopups[LAYOUT_PROPOSAL_SELECTOR], PROPOSAL_SELECTOR);
404 }
405 fContextType= LAYOUT_CONTEXT_INFO_POPUP;
406 break;
407
408 case LAYOUT_CONTEXT_INFO_POPUP:
409 if (Helper2.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
410 if (fContextInfoPopupOrientation is CONTEXT_INFO_BELOW)
411 layout(LAYOUT_PROPOSAL_SELECTOR, getSelectionOffset());
412 }
413 fContextType= LAYOUT_CONTEXT_SELECTOR;
414 break;
415 }
416 }
417
418 protected int getShellType(Widget shell) {
419 for (int i=0; i<fShells.length; i++) {
420 if (fShells[i] is shell)
421 return i;
422 }
423 return -1;
424 }
425
426 protected void layout(int type, int offset) {
427 switch (type) {
428 case LAYOUT_PROPOSAL_SELECTOR:
429 layoutProposalSelector(offset);
430 break;
431 case LAYOUT_CONTEXT_SELECTOR:
432 layoutContextSelector(offset);
433 break;
434 case LAYOUT_CONTEXT_INFO_POPUP:
435 layoutContextInfoPopup(offset);
436 break;
437 }
438 }
439
440 protected void layoutProposalSelector(int offset) {
441 if (fContextType is LAYOUT_CONTEXT_INFO_POPUP &&
442 fContextInfoPopupOrientation is CONTEXT_INFO_BELOW &&
443 Helper2.okToUse(fShells[LAYOUT_CONTEXT_INFO_POPUP])) {
444 // Stack proposal selector beneath the tip box.
445 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
446 Shell parent= fShells[LAYOUT_CONTEXT_INFO_POPUP];
447 shell.setLocation(getStackedLocation(shell, parent));
448 } else if (fContextType !is LAYOUT_CONTEXT_SELECTOR ||
449 !Helper2.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR])) {
450 // There are no other presentations to be concerned with,
451 // so place the proposal selector beneath the cursor line.
452 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
453 shell.setLocation(getBelowLocation(shell, offset));
454 } else {
455 switch (fProposalPopupOrientation) {
456 case PROPOSAL_REMOVE: {
457 // Remove the tip selector and place the
458 // proposal selector beneath the cursor line.
459 fShells[LAYOUT_CONTEXT_SELECTOR].dispose();
460 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
461 shell.setLocation(getBelowLocation(shell, offset));
462 break;
463 }
464 case PROPOSAL_OVERLAY: {
465 // Overlay the tip selector with the proposal selector.
466 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
467 shell.setLocation(getBelowLocation(shell, offset));
468 break;
469 }
470 case PROPOSAL_STACKED: {
471 // Stack the proposal selector beneath the tip selector.
472 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
473 Shell parent= fShells[LAYOUT_CONTEXT_SELECTOR];
474 shell.setLocation(getStackedLocation(shell, parent));
475 break;
476 }
477 }
478 }
479 }
480
481 protected void layoutContextSelector(int offset) {
482 // Always place the context selector beneath the cursor line.
483 Shell shell= fShells[LAYOUT_CONTEXT_SELECTOR];
484 shell.setLocation(getBelowLocation(shell, offset));
485
486 if (Helper2.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
487 switch (fProposalPopupOrientation) {
488 case PROPOSAL_REMOVE:
489 // Remove the proposal selector.
490 fShells[LAYOUT_PROPOSAL_SELECTOR].dispose();
491 break;
492
493 case PROPOSAL_OVERLAY:
494 // The proposal selector has been overlaid by the tip selector.
495 break;
496
497 case PROPOSAL_STACKED: {
498 // Stack the proposal selector beneath the tip selector.
499 shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
500 Shell parent= fShells[LAYOUT_CONTEXT_SELECTOR];
501 shell.setLocation(getStackedLocation(shell, parent));
502 break;
503 }
504 }
505 }
506 }
507
508 protected void layoutContextInfoPopup(int offset) {
509 switch (fContextInfoPopupOrientation) {
510 case CONTEXT_INFO_ABOVE: {
511 // Place the popup above the cursor line.
512 Shell shell= fShells[LAYOUT_CONTEXT_INFO_POPUP];
513 shell.setLocation(getAboveLocation(shell, offset));
514 break;
515 }
516 case CONTEXT_INFO_BELOW: {
517 // Place the popup beneath the cursor line.
518 Shell parent= fShells[LAYOUT_CONTEXT_INFO_POPUP];
519 parent.setLocation(getBelowLocation(parent, offset));
520 if (Helper2.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
521 // Stack the proposal selector beneath the context info popup.
522 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
523 shell.setLocation(getStackedLocation(shell, parent));
524 }
525 break;
526 }
527 }
528 }
529
530 protected void shiftHorizontalLocation(Point location, Rectangle shellBounds, Rectangle displayBounds) {
531 if (location.x + shellBounds.width > displayBounds.width)
532 location.x= displayBounds.width - shellBounds.width;
533
534 if (location.x < displayBounds.x)
535 location.x= displayBounds.x;
536 }
537
538 protected void shiftVerticalLocation(Point location, Rectangle shellBounds, Rectangle displayBounds) {
539 if (location.y + shellBounds.height > displayBounds.height)
540 location.y= displayBounds.height - shellBounds.height;
541
542 if (location.y < displayBounds.y)
543 location.y= displayBounds.y;
544 }
545
546 protected Point getAboveLocation(Shell shell, int offset) {
547 StyledText text= fViewer.getTextWidget();
548 Point location= text.getLocationAtOffset(offset);
549 location= text.toDisplay(location);
550
551 Rectangle shellBounds= shell.getBounds();
552 Rectangle displayBounds= shell.getDisplay().getClientArea();
553
554 location.y=location.y - shellBounds.height;
555
556 shiftHorizontalLocation(location, shellBounds, displayBounds);
557 shiftVerticalLocation(location, shellBounds, displayBounds);
558
559 return location;
560 }
561
562 protected Point getBelowLocation(Shell shell, int offset) {
563 StyledText text= fViewer.getTextWidget();
564 Point location= text.getLocationAtOffset(offset);
565 if (location.x < 0) location.x= 0;
566 if (location.y < 0) location.y= 0;
567 location= text.toDisplay(location);
568
569 Rectangle shellBounds= shell.getBounds();
570 Rectangle displayBounds= shell.getDisplay().getClientArea();
571
572 location.y= location.y + text.getLineHeight(offset);
573 shiftHorizontalLocation(location, shellBounds, displayBounds);
574 shiftVerticalLocation(location, shellBounds, displayBounds);
575
576 return location;
577 }
578
579 protected Point getStackedLocation(Shell shell, Shell parent) {
580 Point p= parent.getLocation();
581 Point size= parent.getSize();
582 p.x += size.x / 4;
583 p.y += size.y;
584
585 p= parent.toDisplay(p);
586
587 Rectangle shellBounds= shell.getBounds();
588 Rectangle displayBounds= shell.getDisplay().getClientArea();
589 shiftHorizontalLocation(p, shellBounds, displayBounds);
590 shiftVerticalLocation(p, shellBounds, displayBounds);
591
592 return p;
593 }
594
595 protected void adjustListeners(int type) {
596 switch (type) {
597 case LAYOUT_PROPOSAL_SELECTOR:
598 if (fContextType is LAYOUT_CONTEXT_SELECTOR &&
599 Helper2.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR]))
600 // Disable event notification to the tip selector.
601 removeContentAssistListener((IContentAssistListener2) fPopups[LAYOUT_CONTEXT_SELECTOR], CONTEXT_SELECTOR);
602 break;
603 case LAYOUT_CONTEXT_SELECTOR:
604 if (Helper2.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR]))
605 // Disable event notification to the proposal selector.
606 removeContentAssistListener((IContentAssistListener2) fPopups[LAYOUT_PROPOSAL_SELECTOR], PROPOSAL_SELECTOR);
607 break;
608 case LAYOUT_CONTEXT_INFO_POPUP:
609 break;
610 }
611 }
612 }
613
614 /**
615 * Internal key listener and event consumer.
616 */
617 class InternalListener : VerifyKeyListener, IEventConsumer {
618
619 /**
620 * Verifies key events by notifying the registered listeners.
621 * Each listener is allowed to indicate that the event has been
622 * handled and should not be further processed.
623 *
624 * @param e the verify event
625 * @see VerifyKeyListener#verifyKey(dwt.events.VerifyEvent)
626 */
627 public void verifyKey(VerifyEvent e) {
628 IContentAssistListener2[] listeners= (IContentAssistListener2[]) fListeners.clone();
629 for (int i= 0; i < listeners.length; i++) {
630 if (listeners[i] !is null) {
631 if (!listeners[i].verifyKey(e) || !e.doit)
632 return;
633 }
634 }
635 }
636
637 /*
638 * @see IEventConsumer#processEvent
639 */
640 public void processEvent(VerifyEvent event) {
641
642 installKeyListener();
643
644 IContentAssistListener2[] listeners= (IContentAssistListener2[])fListeners.clone();
645 for (int i= 0; i < listeners.length; i++) {
646 if (listeners[i] !is null) {
647 listeners[i].processEvent(event);
648 if (!event.doit)
649 return;
650 }
651 }
652 }
653 }
654
655
656 // Content-Assist Listener types
657 final static int CONTEXT_SELECTOR= 0;
658 final static int PROPOSAL_SELECTOR= 1;
659 final static int CONTEXT_INFO_POPUP= 2;
660
661 /**
662 * The popup priority: &gt; info pop-ups, &lt; standard content assist.
663 * Default value: <code>10</code>.
664 *
665 * @since 3.0
666 */
667 public static final int WIDGET_PRIORITY= 10;
668
669
670 private static final int DEFAULT_AUTO_ACTIVATION_DELAY= 500;
671
672 private IInformationControlCreator fInformationControlCreator;
673 private int fAutoActivationDelay= DEFAULT_AUTO_ACTIVATION_DELAY;
674 private bool fIsAutoActivated= false;
675 private bool fIsAutoInserting= false;
676 private int fProposalPopupOrientation= PROPOSAL_OVERLAY;
677 private int fContextInfoPopupOrientation= CONTEXT_INFO_ABOVE;
678 private Map fProcessors;
679 private String fPartitioning;
680
681 private Color fContextInfoPopupBackground;
682 private Color fContextInfoPopupForeground;
683 private Color fContextSelectorBackground;
684 private Color fContextSelectorForeground;
685
686 private ITextViewer fViewer;
687 private String fLastErrorMessage;
688
689 private Closer fCloser;
690 private LayoutManager fLayoutManager;
691 private AutoAssistListener fAutoAssistListener;
692 private InternalListener fInternalListener;
693 private CompletionProposalPopup2 fProposalPopup;
694 private ContextInformationPopup2 fContextInfoPopup;
695
696 private bool fKeyListenerHooked= false;
697 private IContentAssistListener2[] fListeners= new IContentAssistListener2[4];
698 private int fCompletionPosition;
699 private String[] fProposalStrings;
700 private ICompletionProposal[] fProposals;
701 private final List fProposalListeners= new ArrayList();
702
703 /**
704 * Tells whether colored label support is enabled.
705 * @since 3.4
706 */
707 private bool fIsColoredLabelsSupportEnabled= false;
708
709
710 /**
711 * Creates a new content assistant. The content assistant is not automatically activated,
712 * overlays the completion proposals with context information list if necessary, and
713 * shows the context information above the location at which it was activated. If auto
714 * activation will be enabled, without further configuration steps, this content assistant
715 * is activated after a 500 ms delay. It uses the default partitioning.
716 */
717 public ContentAssistant2() {
718 setContextInformationPopupOrientation(CONTEXT_INFO_ABOVE);
719 setInformationControlCreator(getInformationControlCreator());
720
721 // JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools();
722 // IColorManager manager= textTools.getColorManager();
723 //
724 // IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
725 //
726 // Color c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_FOREGROUND, manager);
727 // setProposalSelectorForeground(c);
728 //
729 // c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_BACKGROUND, manager);
730 // setProposalSelectorBackground(c);
731 }
732
733 /**
734 * Creates an <code>IInformationControlCreator</code> to be used to display context information.
735 *
736 * @return an <code>IInformationControlCreator</code> to be used to display context information
737 */
738 private IInformationControlCreator getInformationControlCreator() {
739 return new IInformationControlCreator() {
740 public IInformationControl createInformationControl(Shell parent) {
741 return new DefaultInformationControl(parent, false);
742 }
743 };
744 }
745
746 /**
747 * Sets the document partitioning this content assistant is using.
748 *
749 * @param partitioning the document partitioning for this content assistant
750 */
751 public void setDocumentPartitioning(String partitioning) {
752 Assert.isNotNull(partitioning);
753 fPartitioning= partitioning;
754 }
755
756 /*
757 * @see dwtx.jface.text.contentassist.IContentAssistantExtension#getDocumentPartitioning()
758 * @since 3.0
759 */
760 public String getDocumentPartitioning() {
761 return fPartitioning;
762 }
763
764 /**
765 * Registers a given content assist processor for a particular content type.
766 * If there is already a processor registered for this type, the new processor
767 * is registered instead of the old one.
768 *
769 * @param processor the content assist processor to register, or <code>null</code> to remove an existing one
770 * @param contentType the content type under which to register
771 */
772 public void setContentAssistProcessor(IContentAssistProcessor processor, String contentType) {
773
774 Assert.isNotNull(contentType);
775
776 if (fProcessors is null)
777 fProcessors= new HashMap();
778
779 if (processor is null)
780 fProcessors.remove(contentType);
781 else
782 fProcessors.put(contentType, processor);
783 }
784
785 /*
786 * @see IContentAssistant#getContentAssistProcessor
787 */
788 public IContentAssistProcessor getContentAssistProcessor(String contentType) {
789 if (fProcessors is null)
790 return null;
791
792 return (IContentAssistProcessor) fProcessors.get(contentType);
793 }
794
795 /**
796 * Enables the content assistant's auto activation mode.
797 *
798 * @param enabled indicates whether auto activation is enabled or not
799 */
800 public void enableAutoActivation(bool enabled) {
801 fIsAutoActivated= enabled;
802 manageAutoActivation(fIsAutoActivated);
803 }
804
805 /**
806 * Enables the content assistant's auto insertion mode. If enabled,
807 * the content assistant inserts a proposal automatically if it is
808 * the only proposal. In the case of ambiguities, the user must
809 * make the choice.
810 *
811 * @param enabled indicates whether auto insertion is enabled or not
812 * @since 2.0
813 */
814 public void enableAutoInsert(bool enabled) {
815 fIsAutoInserting= enabled;
816 }
817
818 /**
819 * Returns whether this content assistant is in the auto insertion
820 * mode or not.
821 *
822 * @return <code>true</code> if in auto insertion mode
823 * @since 2.0
824 */
825 bool isAutoInserting() {
826 return fIsAutoInserting;
827 }
828
829 /**
830 * Installs and uninstall the listeners needed for auto-activation.
831 * @param start <code>true</code> if listeners must be installed,
832 * <code>false</code> if they must be removed
833 * @since 2.0
834 */
835 private void manageAutoActivation(bool start) {
836 if (start) {
837
838 if (fViewer !is null && fAutoAssistListener is null) {
839 fAutoAssistListener= new AutoAssistListener();
840 if (fViewer instanceof ITextViewerExtension) {
841 ITextViewerExtension extension= (ITextViewerExtension) fViewer;
842 extension.appendVerifyKeyListener(fAutoAssistListener);
843 } else {
844 StyledText textWidget= fViewer.getTextWidget();
845 if (Helper2.okToUse(textWidget))
846 textWidget.addVerifyKeyListener(fAutoAssistListener);
847 }
848 }
849
850 } else if (fAutoAssistListener !is null) {
851
852 if (fViewer instanceof ITextViewerExtension) {
853 ITextViewerExtension extension= (ITextViewerExtension) fViewer;
854 extension.removeVerifyKeyListener(fAutoAssistListener);
855 } else {
856 StyledText textWidget= fViewer.getTextWidget();
857 if (Helper2.okToUse(textWidget))
858 textWidget.removeVerifyKeyListener(fAutoAssistListener);
859 }
860
861 fAutoAssistListener= null;
862 }
863 }
864
865 /**
866 * Sets the delay after which the content assistant is automatically invoked
867 * if the cursor is behind an auto activation character.
868 *
869 * @param delay the auto activation delay
870 */
871 public void setAutoActivationDelay(int delay) {
872 fAutoActivationDelay= delay;
873 }
874
875 /**
876 * Sets the proposal pop-ups' orientation.
877 * The following values may be used:
878 * <ul>
879 * <li>PROPOSAL_OVERLAY<p>
880 * proposal popup windows should overlay each other
881 * </li>
882 * <li>PROPOSAL_REMOVE<p>
883 * any currently shown proposal popup should be closed
884 * </li>
885 * <li>PROPOSAL_STACKED<p>
886 * proposal popup windows should be vertical stacked, with no overlap,
887 * beneath the line containing the current cursor location
888 * </li>
889 * </ul>
890 *
891 * @param orientation the popup's orientation
892 */
893 public void setProposalPopupOrientation(int orientation) {
894 fProposalPopupOrientation= orientation;
895 }
896
897 /**
898 * Sets the context information popup's orientation.
899 * The following values may be used:
900 * <ul>
901 * <li>CONTEXT_ABOVE<p>
902 * context information popup should always appear above the line containing
903 * the current cursor location
904 * </li>
905 * <li>CONTEXT_BELOW<p>
906 * context information popup should always appear below the line containing
907 * the current cursor location
908 * </li>
909 * </ul>
910 *
911 * @param orientation the popup's orientation
912 */
913 public void setContextInformationPopupOrientation(int orientation) {
914 fContextInfoPopupOrientation= orientation;
915 }
916
917 /**
918 * Sets the context information popup's background color.
919 *
920 * @param background the background color
921 */
922 public void setContextInformationPopupBackground(Color background) {
923 fContextInfoPopupBackground= background;
924 }
925
926 /**
927 * Returns the background of the context information popup.
928 *
929 * @return the background of the context information popup
930 * @since 2.0
931 */
932 Color getContextInformationPopupBackground() {
933 return fContextInfoPopupBackground;
934 }
935
936 /**
937 * Sets the context information popup's foreground color.
938 *
939 * @param foreground the foreground color
940 * @since 2.0
941 */
942 public void setContextInformationPopupForeground(Color foreground) {
943 fContextInfoPopupForeground= foreground;
944 }
945
946 /**
947 * Returns the foreground of the context information popup.
948 *
949 * @return the foreground of the context information popup
950 * @since 2.0
951 */
952 Color getContextInformationPopupForeground() {
953 return fContextInfoPopupForeground;
954 }
955
956 /**
957 * Sets the context selector's background color.
958 *
959 * @param background the background color
960 * @since 2.0
961 */
962 public void setContextSelectorBackground(Color background) {
963 fContextSelectorBackground= background;
964 }
965
966 /**
967 * Returns the background of the context selector.
968 *
969 * @return the background of the context selector
970 * @since 2.0
971 */
972 Color getContextSelectorBackground() {
973 return fContextSelectorBackground;
974 }
975
976 /**
977 * Sets the context selector's foreground color.
978 *
979 * @param foreground the foreground color
980 * @since 2.0
981 */
982 public void setContextSelectorForeground(Color foreground) {
983 fContextSelectorForeground= foreground;
984 }
985
986 /**
987 * Returns the foreground of the context selector.
988 *
989 * @return the foreground of the context selector
990 * @since 2.0
991 */
992 Color getContextSelectorForeground() {
993 return fContextSelectorForeground;
994 }
995
996 /**
997 * Sets the information control creator for the additional information control.
998 *
999 * @param creator the information control creator for the additional information control
1000 * @since 2.0
1001 */
1002 public void setInformationControlCreator(IInformationControlCreator creator) {
1003 fInformationControlCreator= creator;
1004 }
1005
1006 /*
1007 * @see IContentAssist#install
1008 */
1009 public void install(ITextViewer textViewer) {
1010 Assert.isNotNull(textViewer);
1011
1012 fViewer= textViewer;
1013
1014 fLayoutManager= new LayoutManager();
1015 fInternalListener= new InternalListener();
1016
1017 AdditionalInfoController2 controller= null;
1018 if (fInformationControlCreator !is null) {
1019 int delay= fAutoActivationDelay;
1020 if (delay is 0)
1021 delay= DEFAULT_AUTO_ACTIVATION_DELAY;
1022 delay= Math.round(delay * 1.5f);
1023 controller= new AdditionalInfoController2(fInformationControlCreator, delay);
1024 }
1025 fContextInfoPopup= new ContextInformationPopup2(this, fViewer);
1026 fProposalPopup= new CompletionProposalPopup2(this, fViewer, controller);
1027
1028 manageAutoActivation(fIsAutoActivated);
1029 }
1030
1031 /*
1032 * @see IContentAssist#uninstall
1033 */
1034 public void uninstall() {
1035
1036 if (fProposalPopup !is null)
1037 fProposalPopup.hide();
1038
1039 if (fContextInfoPopup !is null)
1040 fContextInfoPopup.hide();
1041
1042 manageAutoActivation(false);
1043
1044 if (fCloser !is null) {
1045 fCloser.uninstall();
1046 fCloser= null;
1047 }
1048
1049 fViewer= null;
1050 }
1051
1052 /**
1053 * Adds the given shell of the specified type to the layout.
1054 * Valid types are defined by <code>LayoutManager</code>.
1055 *
1056 * @param popup a content assist popup
1057 * @param shell the shell of the content-assist popup
1058 * @param type the type of popup
1059 * @param visibleOffset the offset at which to layout the popup relative to the offset of the viewer's visible region
1060 * @since 2.0
1061 */
1062 void addToLayout(Object popup, Shell shell, int type, int visibleOffset) {
1063 fLayoutManager.add(popup, shell, type, visibleOffset);
1064 }
1065
1066 /**
1067 * Layouts the registered popup of the given type relative to the
1068 * given offset. The offset is relative to the offset of the viewer's visible region.
1069 * Valid types are defined by <code>LayoutManager</code>.
1070 *
1071 * @param type the type of popup to layout
1072 * @param visibleOffset the offset at which to layout relative to the offset of the viewer's visible region
1073 * @since 2.0
1074 */
1075 void layout(int type, int visibleOffset) {
1076 fLayoutManager.layout(type, visibleOffset);
1077 }
1078
1079 /**
1080 * Notifies the controller that a popup has lost focus.
1081 *
1082 * @param e the focus event
1083 */
1084 void popupFocusLost(FocusEvent e) {
1085 fCloser.focusLost(e);
1086 }
1087
1088 /**
1089 * Returns the offset of the selection relative to the offset of the visible region.
1090 *
1091 * @return the offset of the selection relative to the offset of the visible region
1092 * @since 2.0
1093 */
1094 int getSelectionOffset() {
1095 StyledText text= fViewer.getTextWidget();
1096 return text.getSelectionRange().x;
1097 }
1098
1099 /**
1100 * Returns whether the widget token could be acquired.
1101 * The following are valid listener types:
1102 * <ul>
1103 * <li>AUTO_ASSIST
1104 * <li>CONTEXT_SELECTOR
1105 * <li>PROPOSAL_SELECTOR
1106 * <li>CONTEXT_INFO_POPUP
1107 * <ul>
1108 * @param type the listener type for which to acquire
1109 * @return <code>true</code> if the widget token could be acquired
1110 * @since 2.0
1111 */
1112 private bool acquireWidgetToken(int type) {
1113 switch (type) {
1114 case CONTEXT_SELECTOR:
1115 case PROPOSAL_SELECTOR:
1116 if (fViewer instanceof IWidgetTokenOwner) {
1117 IWidgetTokenOwner owner= (IWidgetTokenOwner) fViewer;
1118 return owner.requestWidgetToken(this);
1119 } else if (fViewer instanceof IWidgetTokenOwnerExtension) {
1120 IWidgetTokenOwnerExtension extension= (IWidgetTokenOwnerExtension) fViewer;
1121 return extension.requestWidgetToken(this, WIDGET_PRIORITY);
1122 }
1123 }
1124 return true;
1125 }
1126
1127 /**
1128 * Registers a content assist listener.
1129 * The following are valid listener types:
1130 * <ul>
1131 * <li>AUTO_ASSIST
1132 * <li>CONTEXT_SELECTOR
1133 * <li>PROPOSAL_SELECTOR
1134 * <li>CONTEXT_INFO_POPUP
1135 * <ul>
1136 * Returns whether the listener could be added successfully. A listener
1137 * can not be added if the widget token could not be acquired.
1138 *
1139 * @param listener the listener to register
1140 * @param type the type of listener
1141 * @return <code>true</code> if the listener could be added
1142 */
1143 bool addContentAssistListener(IContentAssistListener2 listener, int type) {
1144
1145 if (acquireWidgetToken(type)) {
1146
1147 fListeners[type]= listener;
1148
1149 if (getNumberOfListeners() is 1) {
1150 fCloser= new Closer();
1151 fCloser.install();
1152 fViewer.setEventConsumer(fInternalListener);
1153 installKeyListener();
1154 }
1155 return true;
1156 }
1157
1158 return false;
1159 }
1160
1161 /**
1162 * Installs a key listener on the text viewer's widget.
1163 */
1164 private void installKeyListener() {
1165 if (!fKeyListenerHooked) {
1166 StyledText text= fViewer.getTextWidget();
1167 if (Helper2.okToUse(text)) {
1168
1169 if (fViewer instanceof ITextViewerExtension) {
1170 ITextViewerExtension e= (ITextViewerExtension) fViewer;
1171 e.prependVerifyKeyListener(fInternalListener);
1172 } else {
1173 text.addVerifyKeyListener(fInternalListener);
1174 }
1175
1176 fKeyListenerHooked= true;
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Releases the previously acquired widget token if the token
1183 * is no longer necessary.
1184 * The following are valid listener types:
1185 * <ul>
1186 * <li>AUTO_ASSIST
1187 * <li>CONTEXT_SELECTOR
1188 * <li>PROPOSAL_SELECTOR
1189 * <li>CONTEXT_INFO_POPUP
1190 * <ul>
1191 *
1192 * @param type the listener type
1193 * @since 2.0
1194 */
1195 private void releaseWidgetToken(int type) {
1196 if (fListeners[CONTEXT_SELECTOR] is null && fListeners[PROPOSAL_SELECTOR] is null) {
1197 if (fViewer instanceof IWidgetTokenOwner) {
1198 IWidgetTokenOwner owner= (IWidgetTokenOwner) fViewer;
1199 owner.releaseWidgetToken(this);
1200 }
1201 }
1202 }
1203
1204 /**
1205 * Unregisters a content assist listener.
1206 *
1207 * @param listener the listener to unregister
1208 * @param type the type of listener
1209 *
1210 * @see #addContentAssistListener
1211 */
1212 void removeContentAssistListener(IContentAssistListener2 listener, int type) {
1213 fListeners[type]= null;
1214
1215 if (getNumberOfListeners() is 0) {
1216
1217 if (fCloser !is null) {
1218 fCloser.uninstall();
1219 fCloser= null;
1220 }
1221
1222 uninstallKeyListener();
1223 fViewer.setEventConsumer(null);
1224 }
1225
1226 releaseWidgetToken(type);
1227 }
1228
1229 /**
1230 * Uninstall the key listener from the text viewer's widget.
1231 */
1232 private void uninstallKeyListener() {
1233 if (fKeyListenerHooked) {
1234 StyledText text= fViewer.getTextWidget();
1235 if (Helper2.okToUse(text)) {
1236
1237 if (fViewer instanceof ITextViewerExtension) {
1238 ITextViewerExtension e= (ITextViewerExtension) fViewer;
1239 e.removeVerifyKeyListener(fInternalListener);
1240 } else {
1241 text.removeVerifyKeyListener(fInternalListener);
1242 }
1243
1244 fKeyListenerHooked= false;
1245 }
1246 }
1247 }
1248
1249 /**
1250 * Returns the number of listeners.
1251 *
1252 * @return the number of listeners
1253 * @since 2.0
1254 */
1255 private int getNumberOfListeners() {
1256 int count= 0;
1257 for (int i= 0; i <= CONTEXT_INFO_POPUP; i++) {
1258 if (fListeners[i] !is null)
1259 ++ count;
1260 }
1261 return count;
1262 }
1263
1264 /*
1265 * @see IContentAssist#showPossibleCompletions
1266 */
1267 public String showPossibleCompletions() {
1268 return fProposalPopup.showProposals(false);
1269 }
1270
1271 /**
1272 * Hides the proposal popup.
1273 */
1274 public void hidePossibleCompletions() {
1275 if (fProposalPopup !is null)
1276 fProposalPopup.hide();
1277 }
1278
1279 /**
1280 * Hides any open pop-ups.
1281 */
1282 protected void hide() {
1283 if (fProposalPopup !is null)
1284 fProposalPopup.hide();
1285 if (fContextInfoPopup !is null)
1286 fContextInfoPopup.hide();
1287 }
1288
1289 /**
1290 * Callback to signal this content assistant that the presentation of the possible completions has been stopped.
1291 * @since 2.1
1292 */
1293 protected void possibleCompletionsClosed() {
1294 }
1295
1296 /*
1297 * @see IContentAssist#showContextInformation
1298 */
1299 public String showContextInformation() {
1300 return fContextInfoPopup.showContextProposals(false);
1301 }
1302
1303
1304 /**
1305 * Callback to signal this content assistant that the presentation of the context information has been stopped.
1306 * @since 2.1
1307 */
1308 protected void contextInformationClosed() {
1309 }
1310
1311 /**
1312 * Requests that the specified context information to be shown.
1313 *
1314 * @param contextInformation the context information to be shown
1315 * @param position the position to which the context information refers to
1316 * @since 2.0
1317 */
1318 void showContextInformation(IContextInformation contextInformation, int position) {
1319 fContextInfoPopup.showContextInformation(contextInformation, position);
1320 }
1321
1322 /**
1323 * Returns the current content assist error message.
1324 *
1325 * @return an error message or <code>null</code> if no error has occurred
1326 */
1327 String getErrorMessage() {
1328 return fLastErrorMessage;
1329 }
1330
1331 /**
1332 * Returns the content assist processor for the content
1333 * type of the specified document position.
1334 *
1335 * @param viewer the text viewer
1336 * @param offset a offset within the document
1337 * @return a content-assist processor or <code>null</code> if none exists
1338 */
1339 private IContentAssistProcessor getProcessor(ITextViewer viewer, int offset) {
1340 try {
1341 String type= TextUtilities.getContentType(viewer.getDocument(), getDocumentPartitioning(), offset, true);
1342 return getContentAssistProcessor(type);
1343 } catch (BadLocationException x) {
1344 }
1345 return null;
1346 }
1347
1348 /**
1349 * Returns an array of completion proposals computed based on
1350 * the specified document position. The position is used to
1351 * determine the appropriate content assist processor to invoke.
1352 *
1353 * @param viewer the viewer for which to compute the proposals
1354 * @param position a document position
1355 * @return an array of completion proposals
1356 *
1357 * @see IContentAssistProcessor#computeCompletionProposals
1358 */
1359 ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int position) {
1360 if (fProposals !is null) {
1361 return fProposals;
1362 } else if (fProposalStrings !is null) {
1363 ICompletionProposal[] result= new ICompletionProposal[fProposalStrings.length];
1364 for (int i= 0; i < fProposalStrings.length; i++) {
1365 result[i]= new CompletionProposal(fProposalStrings[i], position, fProposalStrings[i].length(), fProposalStrings[i].length());
1366 }
1367 return result;
1368 } else return null;
1369 }
1370
1371 /**
1372 * Returns an array of context information objects computed based
1373 * on the specified document position. The position is used to determine
1374 * the appropriate content assist processor to invoke.
1375 *
1376 * @param viewer the viewer for which to compute the context information
1377 * @param position a document position
1378 * @return an array of context information objects
1379 *
1380 * @see IContentAssistProcessor#computeContextInformation
1381 */
1382 IContextInformation[] computeContextInformation(ITextViewer viewer, int position) {
1383 fLastErrorMessage= null;
1384
1385 IContextInformation[] result= null;
1386
1387 IContentAssistProcessor p= getProcessor(viewer, position);
1388 if (p !is null) {
1389 result= p.computeContextInformation(viewer, position);
1390 fLastErrorMessage= p.getErrorMessage();
1391 }
1392
1393 return result;
1394 }
1395
1396 /**
1397 * Returns the context information validator that should be used to
1398 * determine when the currently displayed context information should
1399 * be dismissed. The position is used to determine the appropriate
1400 * content assist processor to invoke.
1401 *
1402 * @param textViewer the text viewer
1403 * @param offset a document offset
1404 * @return an validator
1405 *
1406 * @see IContentAssistProcessor#getContextInformationValidator
1407 */
1408 IContextInformationValidator getContextInformationValidator(ITextViewer textViewer, int offset) {
1409 IContentAssistProcessor p= getProcessor(textViewer, offset);
1410 return p !is null ? p.getContextInformationValidator() : null;
1411 }
1412
1413 /**
1414 * Returns the context information presenter that should be used to
1415 * display context information. The position is used to determine the appropriate
1416 * content assist processor to invoke.
1417 *
1418 * @param textViewer the text viewer
1419 * @param offset a document offset
1420 * @return a presenter
1421 * @since 2.0
1422 */
1423 IContextInformationPresenter getContextInformationPresenter(ITextViewer textViewer, int offset) {
1424 IContextInformationValidator validator= getContextInformationValidator(textViewer, offset);
1425 if (validator instanceof IContextInformationPresenter)
1426 return (IContextInformationPresenter) validator;
1427 return null;
1428 }
1429
1430 /**
1431 * Returns the characters which when typed by the user should automatically
1432 * initiate proposing completions. The position is used to determine the
1433 * appropriate content assist processor to invoke.
1434 *
1435 * @param textViewer the text viewer
1436 * @param offset a document offset
1437 * @return the auto activation characters
1438 *
1439 * @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters
1440 */
1441 private char[] getCompletionProposalAutoActivationCharacters(ITextViewer textViewer, int offset) {
1442 IContentAssistProcessor p= getProcessor(textViewer, offset);
1443 return p !is null ? p.getCompletionProposalAutoActivationCharacters() : null;
1444 }
1445
1446 /**
1447 * Returns the characters which when typed by the user should automatically
1448 * initiate the presentation of context information. The position is used
1449 * to determine the appropriate content assist processor to invoke.
1450 *
1451 * @param textViewer the text viewer
1452 * @param offset a document offset
1453 * @return the auto activation characters
1454 *
1455 * @see IContentAssistProcessor#getContextInformationAutoActivationCharacters
1456 */
1457 private char[] getContextInformationAutoActivationCharacters(ITextViewer textViewer, int offset) {
1458 IContentAssistProcessor p= getProcessor(textViewer, offset);
1459 return p !is null ? p.getContextInformationAutoActivationCharacters() : null;
1460 }
1461
1462 /*
1463 * @see dwtx.jface.text.IWidgetTokenKeeper#requestWidgetToken(IWidgetTokenOwner)
1464 * @since 2.0
1465 */
1466 public bool requestWidgetToken(IWidgetTokenOwner owner) {
1467 hidePossibleCompletions();
1468 return true;
1469 }
1470
1471 /**
1472 * @param completionPosition
1473 */
1474 public void setCompletionPosition(int completionPosition) {
1475 fCompletionPosition= completionPosition;
1476 }
1477
1478 /**
1479 * @return the completion position
1480 */
1481 public int getCompletionPosition() {
1482 return fCompletionPosition;
1483 }
1484
1485 /**
1486 * @param proposals
1487 */
1488 public void setCompletions(String[] proposals) {
1489 fProposalStrings= proposals;
1490 }
1491
1492 /**
1493 * @param proposals
1494 */
1495 public void setCompletions(ICompletionProposal[] proposals) {
1496 fProposals= proposals;
1497 }
1498
1499 /*
1500 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(dwtx.jface.text.IWidgetTokenOwner, int)
1501 * @since 3.0
1502 */
1503 public bool requestWidgetToken(IWidgetTokenOwner owner, int priority) {
1504 if (priority > WIDGET_PRIORITY) {
1505 hidePossibleCompletions();
1506 return true;
1507 }
1508 return false;
1509 }
1510
1511 /*
1512 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#setFocus(dwtx.jface.text.IWidgetTokenOwner)
1513 * @since 3.0
1514 */
1515 public bool setFocus(IWidgetTokenOwner owner) {
1516 if (fProposalPopup !is null) {
1517 fProposalPopup.setFocus();
1518 return fProposalPopup.hasFocus();
1519 }
1520 return false;
1521 }
1522
1523 /**
1524 * Returns whether any popups controlled by the receiver have the input focus.
1525 *
1526 * @return <code>true</code> if any of the managed popups have the focus, <code>false</code> otherwise
1527 */
1528 public bool hasFocus() {
1529 return (fProposalPopup !is null && fProposalPopup.hasFocus())
1530 || (fContextInfoPopup !is null && fContextInfoPopup.hasFocus());
1531 }
1532
1533 /*
1534 * @see dwtx.jface.text.contentassist.IContentAssistantExtension#completePrefix()
1535 */
1536 public String completePrefix() {
1537 return null;
1538 }
1539
1540 /**
1541 * @param proposal
1542 */
1543 public void fireProposalChosen(ICompletionProposal proposal) {
1544 List list= new ArrayList(fProposalListeners);
1545 for (Iterator it= list.iterator(); it.hasNext();) {
1546 IProposalListener listener= (IProposalListener) it.next();
1547 listener.proposalChosen(proposal);
1548 }
1549
1550 }
1551
1552 /**
1553 * @param listener
1554 */
1555 public void removeProposalListener(IProposalListener listener) {
1556 fProposalListeners.remove(listener);
1557 }
1558
1559 /**
1560 * @param listener
1561 */
1562 public void addProposalListener(IProposalListener listener) {
1563 fProposalListeners.add(listener);
1564 }
1565
1566 /**
1567 * Tells whether the support for colored labels is enabled.
1568 *
1569 * @return <code>true</code> if the support for colored labels is enabled, <code>false</code> otherwise
1570 * @since 3.4
1571 */
1572 bool isColoredLabelsSupportEnabled() {
1573 return fIsColoredLabelsSupportEnabled;
1574 }
1575
1576 /**
1577 * Enables the support for colored labels in the proposal popup.
1578 * <p>Completion proposals can implement {@link ICompletionProposalExtension6}
1579 * to provide colored proposal labels.</p>
1580 *
1581 * @param isEnabled if <code>true</code> the support for colored labels is enabled in the proposal popup
1582 * @since 3.4
1583 */
1584 public void enableColoredLabels(bool isEnabled) {
1585 fIsColoredLabelsSupportEnabled= isEnabled;
1586 }
1587 }
1588