129
|
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 * Guy Gurfinkel, guy.g@zend.com - [content assist][api] provide better access to ContentAssistant - https://bugs.eclipse.org/bugs/show_bug.cgi?id=169954
|
|
11 * Anton Leherbauer (Wind River Systems) - [content assist][api] ContentAssistEvent should contain information about auto activation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=193728
|
|
12 * Port to the D programming language:
|
|
13 * Frank Benoit <benoit@tionex.de>
|
|
14 *******************************************************************************/
|
|
15 module dwtx.jface.text.contentassist.ContentAssistant;
|
|
16
|
|
17 import dwt.dwthelper.utils;
|
|
18
|
|
19 import java.util.HashMap;
|
|
20 import java.util.Iterator;
|
|
21 import java.util.Map;
|
|
22 import java.util.Map.Entry;
|
|
23
|
|
24 import dwt.DWT;
|
|
25 import dwt.DWTError;
|
|
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.KeyAdapter;
|
|
34 import dwt.events.KeyEvent;
|
|
35 import dwt.events.KeyListener;
|
|
36 import dwt.events.MouseEvent;
|
|
37 import dwt.events.MouseListener;
|
|
38 import dwt.events.TraverseEvent;
|
|
39 import dwt.events.TraverseListener;
|
|
40 import dwt.events.VerifyEvent;
|
|
41 import dwt.graphics.Color;
|
|
42 import dwt.graphics.Point;
|
|
43 import dwt.graphics.Rectangle;
|
|
44 import dwt.widgets.Control;
|
|
45 import dwt.widgets.Display;
|
|
46 import dwt.widgets.Event;
|
|
47 import dwt.widgets.Listener;
|
|
48 import dwt.widgets.Monitor;
|
|
49 import dwt.widgets.Shell;
|
|
50 import dwt.widgets.Widget;
|
|
51 import dwtx.core.commands.IHandler;
|
|
52 import dwtx.core.runtime.Assert;
|
|
53 import dwtx.core.runtime.ListenerList;
|
|
54 import dwtx.jface.bindings.keys.KeySequence;
|
|
55 import dwtx.jface.contentassist.IContentAssistSubjectControl;
|
|
56 import dwtx.jface.contentassist.ISubjectControlContentAssistProcessor;
|
|
57 import dwtx.jface.dialogs.IDialogSettings;
|
|
58 import dwtx.jface.preference.JFacePreferences;
|
|
59 import dwtx.jface.text.BadLocationException;
|
|
60 import dwtx.jface.text.IDocument;
|
|
61 import dwtx.jface.text.IDocumentExtension3;
|
|
62 import dwtx.jface.text.IEventConsumer;
|
|
63 import dwtx.jface.text.IInformationControlCreator;
|
|
64 import dwtx.jface.text.ITextViewer;
|
|
65 import dwtx.jface.text.IViewportListener;
|
|
66 import dwtx.jface.text.IWidgetTokenKeeper;
|
|
67 import dwtx.jface.text.IWidgetTokenKeeperExtension;
|
|
68 import dwtx.jface.text.IWidgetTokenOwner;
|
|
69 import dwtx.jface.text.IWidgetTokenOwnerExtension;
|
|
70 import dwtx.jface.text.TextUtilities;
|
|
71 import dwtx.jface.util.Geometry;
|
|
72
|
|
73
|
|
74 /**
|
|
75 * The standard implementation of the <code>IContentAssistant</code> interface. Usually, clients
|
|
76 * instantiate this class and configure it before using it.
|
|
77 */
|
|
78 public class ContentAssistant : IContentAssistant, IContentAssistantExtension, IContentAssistantExtension2, IContentAssistantExtension3, IContentAssistantExtension4, IWidgetTokenKeeper, IWidgetTokenKeeperExtension {
|
|
79
|
|
80
|
|
81
|
|
82 /**
|
|
83 * Content assist command identifier for 'select next proposal'.
|
|
84 *
|
|
85 * @since 3.4
|
|
86 */
|
|
87 public static final String SELECT_NEXT_PROPOSAL_COMMAND_ID= "dwtx.ui.edit.text.contentAssist.selectNextProposal"; //$NON-NLS-1$
|
|
88 /**
|
|
89 * Content assist command identifier for 'select previous proposal'.
|
|
90 *
|
|
91 * @since 3.4
|
|
92 */
|
|
93 public static final String SELECT_PREVIOUS_PROPOSAL_COMMAND_ID= "dwtx.ui.edit.text.contentAssist.selectPreviousProposal"; //$NON-NLS-1$
|
|
94
|
|
95
|
|
96 /**
|
|
97 * A generic closer class used to monitor various interface events in order to determine whether
|
|
98 * content-assist should be terminated and all associated windows closed.
|
|
99 */
|
|
100 class Closer : ControlListener, MouseListener, FocusListener, DisposeListener, IViewportListener {
|
|
101
|
|
102 /** The shell that a <code>ControlListener</code> is registered with. */
|
|
103 private Shell fShell;
|
|
104 /**
|
|
105 * The control that a <code>MouseListener</code>, a<code>FocusListener</code> and a
|
|
106 * <code>DisposeListener</code> are registered with.
|
|
107 */
|
|
108 private Control fControl;
|
|
109
|
|
110 /**
|
|
111 * Installs this closer on it's viewer's text widget.
|
|
112 */
|
|
113 protected void install() {
|
|
114 Control control= fContentAssistSubjectControlAdapter.getControl();
|
|
115 fControl= control;
|
|
116 if (Helper.okToUse(control)) {
|
|
117
|
|
118 Shell shell= control.getShell();
|
|
119 fShell= shell;
|
|
120 shell.addControlListener(this);
|
|
121
|
|
122 control.addMouseListener(this);
|
|
123 control.addFocusListener(this);
|
|
124
|
|
125 /*
|
|
126 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of
|
|
127 * Internal Errors
|
|
128 */
|
|
129 control.addDisposeListener(this);
|
|
130 }
|
|
131 if (fViewer !is null)
|
|
132 fViewer.addViewportListener(this);
|
|
133 }
|
|
134
|
|
135 /**
|
|
136 * Uninstalls this closer from the viewer's text widget.
|
|
137 */
|
|
138 protected void uninstall() {
|
|
139 Control shell= fShell;
|
|
140 fShell= null;
|
|
141 if (Helper.okToUse(shell))
|
|
142 shell.removeControlListener(this);
|
|
143
|
|
144 Control control= fControl;
|
|
145 fControl= null;
|
|
146 if (Helper.okToUse(control)) {
|
|
147
|
|
148 control.removeMouseListener(this);
|
|
149 control.removeFocusListener(this);
|
|
150
|
|
151 /*
|
|
152 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of
|
|
153 * Internal Errors
|
|
154 */
|
|
155 control.removeDisposeListener(this);
|
|
156 }
|
|
157
|
|
158 if (fViewer !is null)
|
|
159 fViewer.removeViewportListener(this);
|
|
160 }
|
|
161
|
|
162 /*
|
|
163 * @see ControlListener#controlResized(ControlEvent)
|
|
164 */
|
|
165 public void controlResized(ControlEvent e) {
|
|
166 hide();
|
|
167 }
|
|
168
|
|
169 /*
|
|
170 * @see ControlListener#controlMoved(ControlEvent)
|
|
171 */
|
|
172 public void controlMoved(ControlEvent e) {
|
|
173 hide();
|
|
174 }
|
|
175
|
|
176 /*
|
|
177 * @see MouseListener#mouseDown(MouseEvent)
|
|
178 */
|
|
179 public void mouseDown(MouseEvent e) {
|
|
180 hide();
|
|
181 }
|
|
182
|
|
183 /*
|
|
184 * @see MouseListener#mouseUp(MouseEvent)
|
|
185 */
|
|
186 public void mouseUp(MouseEvent e) {
|
|
187 }
|
|
188
|
|
189 /*
|
|
190 * @see MouseListener#mouseDoubleClick(MouseEvent)
|
|
191 */
|
|
192 public void mouseDoubleClick(MouseEvent e) {
|
|
193 hide();
|
|
194 }
|
|
195
|
|
196 /*
|
|
197 * @see FocusListener#focusGained(FocusEvent)
|
|
198 */
|
|
199 public void focusGained(FocusEvent e) {
|
|
200 }
|
|
201
|
|
202 /*
|
|
203 * @see FocusListener#focusLost(FocusEvent)
|
|
204 */
|
|
205 public void focusLost(FocusEvent e) {
|
|
206 Control control= fControl;
|
|
207 if (Helper.okToUse(control)) {
|
|
208 Display d= control.getDisplay();
|
|
209 if (d !is null) {
|
|
210 d.asyncExec(new Runnable() {
|
|
211 public void run() {
|
|
212 if (!fProposalPopup.hasFocus() && (fContextInfoPopup is null || !fContextInfoPopup.hasFocus()))
|
|
213 hide();
|
|
214 }
|
|
215 });
|
|
216 }
|
|
217 }
|
|
218 }
|
|
219
|
|
220 /*
|
|
221 * @seeDisposeListener#widgetDisposed(DisposeEvent)
|
|
222 */
|
|
223 public void widgetDisposed(DisposeEvent e) {
|
|
224 /*
|
|
225 * 1GGYYWK: ITPJUI:ALL - Dismissing editor with code assist up causes lots of Internal
|
|
226 * Errors
|
|
227 */
|
|
228 hide();
|
|
229 }
|
|
230
|
|
231 /*
|
|
232 * @see IViewportListener#viewportChanged(int)
|
|
233 */
|
|
234 public void viewportChanged(int topIndex) {
|
|
235 hide();
|
|
236 }
|
|
237 }
|
|
238
|
|
239 /**
|
|
240 * An implementation of <code>IContentAssistListener</code>, this class is used to monitor
|
|
241 * key events in support of automatic activation of the content assistant. If enabled, the
|
|
242 * implementation utilizes a thread to watch for input characters matching the activation
|
|
243 * characters specified by the content assist processor, and if detected, will wait the
|
|
244 * indicated delay interval before activating the content assistant.
|
|
245 *
|
|
246 * @since 3.4 protected, was added in 2.1 as private class
|
|
247 */
|
|
248 protected class AutoAssistListener : KeyAdapter , KeyListener, Runnable, VerifyKeyListener {
|
|
249
|
|
250 private Thread fThread;
|
|
251 private bool fIsReset= false;
|
|
252 private Object fMutex= new Object();
|
|
253 private int fShowStyle;
|
|
254
|
|
255 private final static int SHOW_PROPOSALS= 1;
|
|
256 private final static int SHOW_CONTEXT_INFO= 2;
|
|
257
|
|
258 protected AutoAssistListener() {
|
|
259 }
|
|
260
|
|
261 protected void start(int showStyle) {
|
|
262 fShowStyle= showStyle;
|
|
263 fThread= new Thread(this, JFaceTextMessages.getString("ContentAssistant.assist_delay_timer_name")); //$NON-NLS-1$
|
|
264 fThread.start();
|
|
265 }
|
|
266
|
|
267 public void run() {
|
|
268 try {
|
|
269 while (true) {
|
|
270 synchronized (fMutex) {
|
|
271 if (fAutoActivationDelay !is 0)
|
|
272 fMutex.wait(fAutoActivationDelay);
|
|
273 if (fIsReset) {
|
|
274 fIsReset= false;
|
|
275 continue;
|
|
276 }
|
|
277 }
|
|
278 showAssist(fShowStyle);
|
|
279 break;
|
|
280 }
|
|
281 } catch (InterruptedException e) {
|
|
282 }
|
|
283 fThread= null;
|
|
284 }
|
|
285
|
|
286 protected void reset(int showStyle) {
|
|
287 synchronized (fMutex) {
|
|
288 fShowStyle= showStyle;
|
|
289 fIsReset= true;
|
|
290 fMutex.notifyAll();
|
|
291 }
|
|
292 }
|
|
293
|
|
294 protected void stop() {
|
|
295 Thread threadToStop= fThread;
|
|
296 if (threadToStop !is null && threadToStop.isAlive())
|
|
297 threadToStop.interrupt();
|
|
298 }
|
|
299
|
|
300 private bool contains(char[] characters, char character) {
|
|
301 if (characters !is null) {
|
|
302 for (int i= 0; i < characters.length; i++) {
|
|
303 if (character is characters[i])
|
|
304 return true;
|
|
305 }
|
|
306 }
|
|
307 return false;
|
|
308 }
|
|
309
|
|
310 public void keyPressed(KeyEvent e) {
|
|
311 // Only act on typed characters and ignore modifier-only events
|
|
312 if (e.character is 0 && (e.keyCode & DWT.KEYCODE_BIT) is 0)
|
|
313 return;
|
|
314
|
|
315 if (e.character !is 0 && (e.stateMask is DWT.ALT))
|
|
316 return;
|
|
317
|
|
318 // Only act on characters that are trigger candidates. This
|
|
319 // avoids computing the model selection on every keystroke
|
|
320 if (computeAllAutoActivationTriggers().indexOf(e.character) < 0) {
|
|
321 stop();
|
|
322 return;
|
|
323 }
|
|
324
|
|
325 int showStyle;
|
|
326 int pos= fContentAssistSubjectControlAdapter.getSelectedRange().x;
|
|
327 char[] activation;
|
|
328
|
|
329 activation= fContentAssistSubjectControlAdapter.getCompletionProposalAutoActivationCharacters(ContentAssistant.this, pos);
|
|
330
|
|
331 if (contains(activation, e.character) && !isProposalPopupActive())
|
|
332 showStyle= SHOW_PROPOSALS;
|
|
333 else {
|
|
334 activation= fContentAssistSubjectControlAdapter.getContextInformationAutoActivationCharacters(ContentAssistant.this, pos);
|
|
335 if (contains(activation, e.character) && !isContextInfoPopupActive())
|
|
336 showStyle= SHOW_CONTEXT_INFO;
|
|
337 else {
|
|
338 stop();
|
|
339 return;
|
|
340 }
|
|
341 }
|
|
342
|
|
343 if (fThread !is null && fThread.isAlive())
|
|
344 reset(showStyle);
|
|
345 else
|
|
346 start(showStyle);
|
|
347 }
|
|
348
|
|
349 /*
|
|
350 * @see dwt.custom.VerifyKeyListener#verifyKey(dwt.events.VerifyEvent)
|
|
351 */
|
|
352 public void verifyKey(VerifyEvent event) {
|
|
353 keyPressed(event);
|
|
354 }
|
|
355
|
|
356 protected void showAssist(final int showStyle) {
|
|
357 final Control control= fContentAssistSubjectControlAdapter.getControl();
|
|
358 if (control is null)
|
|
359 return;
|
|
360
|
|
361 final Display d= control.getDisplay();
|
|
362 if (d is null)
|
|
363 return;
|
|
364
|
|
365 try {
|
|
366 d.syncExec(new Runnable() {
|
|
367 public void run() {
|
|
368 if (isProposalPopupActive())
|
|
369 return;
|
|
370
|
|
371 if (control.isDisposed() || !control.isFocusControl())
|
|
372 return;
|
|
373
|
|
374 if (showStyle is SHOW_PROPOSALS) {
|
|
375 if (!prepareToShowCompletions(true))
|
|
376 return;
|
|
377 fProposalPopup.showProposals(true);
|
|
378 fLastAutoActivation= System.currentTimeMillis();
|
|
379 } else if (showStyle is SHOW_CONTEXT_INFO && fContextInfoPopup !is null) {
|
|
380 promoteKeyListener();
|
|
381 fContextInfoPopup.showContextProposals(true);
|
|
382 }
|
|
383 }
|
|
384 });
|
|
385 } catch (DWTError e) {
|
|
386 }
|
|
387 }
|
|
388 }
|
|
389
|
|
390 /**
|
|
391 * The layout manager layouts the various windows associated with the content assistant based on
|
|
392 * the settings of the content assistant.
|
|
393 */
|
|
394 class LayoutManager : Listener {
|
|
395
|
|
396 // Presentation types.
|
|
397 /** The presentation type for the proposal selection popup. */
|
|
398 public final static int LAYOUT_PROPOSAL_SELECTOR= 0;
|
|
399 /** The presentation type for the context selection popup. */
|
|
400 public final static int LAYOUT_CONTEXT_SELECTOR= 1;
|
|
401 /** The presentation type for the context information hover . */
|
|
402 public final static int LAYOUT_CONTEXT_INFO_POPUP= 2;
|
|
403
|
|
404 int fContextType= LAYOUT_CONTEXT_SELECTOR;
|
|
405 Shell[] fShells= new Shell[3];
|
|
406 Object[] fPopups= new Object[3];
|
|
407
|
|
408 protected void add(Object popup, Shell shell, int type, int offset) {
|
|
409 Assert.isNotNull(popup);
|
|
410 Assert.isTrue(shell !is null && !shell.isDisposed());
|
|
411 checkType(type);
|
|
412
|
|
413 if (fShells[type] !is shell) {
|
|
414 if (fShells[type] !is null)
|
|
415 fShells[type].removeListener(DWT.Dispose, this);
|
|
416 shell.addListener(DWT.Dispose, this);
|
|
417 fShells[type]= shell;
|
|
418 }
|
|
419
|
|
420 fPopups[type]= popup;
|
|
421 if (type is LAYOUT_CONTEXT_SELECTOR || type is LAYOUT_CONTEXT_INFO_POPUP)
|
|
422 fContextType= type;
|
|
423
|
|
424 layout(type, offset);
|
|
425 adjustListeners(type);
|
|
426 }
|
|
427
|
|
428 protected void checkType(int type) {
|
|
429 Assert.isTrue(type is LAYOUT_PROPOSAL_SELECTOR ||
|
|
430 type is LAYOUT_CONTEXT_SELECTOR || type is LAYOUT_CONTEXT_INFO_POPUP);
|
|
431 }
|
|
432
|
|
433 public void handleEvent(Event event) {
|
|
434 Widget source= event.widget;
|
|
435 source.removeListener(DWT.Dispose, this);
|
|
436
|
|
437 int type= getShellType(source);
|
|
438 checkType(type);
|
|
439 fShells[type]= null;
|
|
440
|
|
441 switch (type) {
|
|
442 case LAYOUT_PROPOSAL_SELECTOR:
|
|
443 if (fContextType is LAYOUT_CONTEXT_SELECTOR &&
|
|
444 Helper.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR])) {
|
|
445 // Restore event notification to the tip popup.
|
|
446 addContentAssistListener((IContentAssistListener) fPopups[LAYOUT_CONTEXT_SELECTOR], CONTEXT_SELECTOR);
|
|
447 }
|
|
448 break;
|
|
449
|
|
450 case LAYOUT_CONTEXT_SELECTOR:
|
|
451 if (Helper.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
|
|
452 if (fProposalPopupOrientation is PROPOSAL_STACKED)
|
|
453 layout(LAYOUT_PROPOSAL_SELECTOR, getSelectionOffset());
|
|
454 // Restore event notification to the proposal popup.
|
|
455 addContentAssistListener((IContentAssistListener) fPopups[LAYOUT_PROPOSAL_SELECTOR], PROPOSAL_SELECTOR);
|
|
456 }
|
|
457 fContextType= LAYOUT_CONTEXT_INFO_POPUP;
|
|
458 break;
|
|
459
|
|
460 case LAYOUT_CONTEXT_INFO_POPUP:
|
|
461 if (Helper.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
|
|
462 if (fContextInfoPopupOrientation is CONTEXT_INFO_BELOW)
|
|
463 layout(LAYOUT_PROPOSAL_SELECTOR, getSelectionOffset());
|
|
464 }
|
|
465 fContextType= LAYOUT_CONTEXT_SELECTOR;
|
|
466 break;
|
|
467 }
|
|
468 }
|
|
469
|
|
470 protected int getShellType(Widget shell) {
|
|
471 for (int i= 0; i < fShells.length; i++) {
|
|
472 if (fShells[i] is shell)
|
|
473 return i;
|
|
474 }
|
|
475 return -1;
|
|
476 }
|
|
477
|
|
478 /**
|
|
479 * Layouts the popup defined by <code>type</code> at the given widget offset.
|
|
480 *
|
|
481 * @param type the kind of popup to layout
|
|
482 * @param offset the widget offset
|
|
483 */
|
|
484 protected void layout(int type, int offset) {
|
|
485 switch (type) {
|
|
486 case LAYOUT_PROPOSAL_SELECTOR:
|
|
487 layoutProposalSelector(offset);
|
|
488 break;
|
|
489 case LAYOUT_CONTEXT_SELECTOR:
|
|
490 layoutContextSelector(offset);
|
|
491 break;
|
|
492 case LAYOUT_CONTEXT_INFO_POPUP:
|
|
493 layoutContextInfoPopup(offset);
|
|
494 break;
|
|
495 }
|
|
496 }
|
|
497
|
|
498 protected void layoutProposalSelector(int offset) {
|
|
499 if (fContextType is LAYOUT_CONTEXT_INFO_POPUP &&
|
|
500 fContextInfoPopupOrientation is CONTEXT_INFO_BELOW &&
|
|
501 Helper.okToUse(fShells[LAYOUT_CONTEXT_INFO_POPUP])) {
|
|
502 // Stack proposal selector beneath the tip box.
|
|
503 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
504 Shell parent= fShells[LAYOUT_CONTEXT_INFO_POPUP];
|
|
505 shell.setLocation(getStackedLocation(shell, parent));
|
|
506 } else if (fContextType !is LAYOUT_CONTEXT_SELECTOR ||
|
|
507 !Helper.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR])) {
|
|
508 // There are no other presentations to be concerned with,
|
|
509 // so place the proposal selector beneath the cursor line.
|
|
510 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
511 CompletionProposalPopup popup= (CompletionProposalPopup) fPopups[LAYOUT_PROPOSAL_SELECTOR];
|
|
512 shell.setBounds(computeBoundsBelowAbove(shell, shell.getSize(), offset, popup));
|
|
513 } else {
|
|
514 CompletionProposalPopup popup= ((CompletionProposalPopup) fPopups[LAYOUT_PROPOSAL_SELECTOR]);
|
|
515 switch (fProposalPopupOrientation) {
|
|
516 case PROPOSAL_REMOVE: {
|
|
517 // Remove the tip selector and place the
|
|
518 // proposal selector beneath the cursor line.
|
|
519 fShells[LAYOUT_CONTEXT_SELECTOR].dispose();
|
|
520 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
521 shell.setBounds(computeBoundsBelowAbove(shell, shell.getSize(), offset, popup));
|
|
522 break;
|
|
523 }
|
|
524 case PROPOSAL_OVERLAY: {
|
|
525 // Overlay the tip selector with the proposal selector.
|
|
526 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
527 shell.setBounds(computeBoundsBelowAbove(shell, shell.getSize(), offset, popup));
|
|
528 break;
|
|
529 }
|
|
530 case PROPOSAL_STACKED: {
|
|
531 // Stack the proposal selector beneath the tip selector.
|
|
532 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
533 Shell parent= fShells[LAYOUT_CONTEXT_SELECTOR];
|
|
534 shell.setLocation(getStackedLocation(shell, parent));
|
|
535 break;
|
|
536 }
|
|
537 }
|
|
538 }
|
|
539 }
|
|
540
|
|
541 protected void layoutContextSelector(int offset) {
|
|
542 // Always place the context selector beneath the cursor line.
|
|
543 Shell shell= fShells[LAYOUT_CONTEXT_SELECTOR];
|
|
544 shell.setBounds(computeBoundsBelowAbove(shell, shell.getSize(), offset, null));
|
|
545
|
|
546 if (Helper.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
|
|
547 switch (fProposalPopupOrientation) {
|
|
548 case PROPOSAL_REMOVE:
|
|
549 // Remove the proposal selector.
|
|
550 fShells[LAYOUT_PROPOSAL_SELECTOR].dispose();
|
|
551 break;
|
|
552
|
|
553 case PROPOSAL_OVERLAY:
|
|
554 // The proposal selector has been overlaid by the tip selector.
|
|
555 break;
|
|
556
|
|
557 case PROPOSAL_STACKED: {
|
|
558 // Stack the proposal selector beneath the tip selector.
|
|
559 shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
560 Shell parent= fShells[LAYOUT_CONTEXT_SELECTOR];
|
|
561 shell.setLocation(getStackedLocation(shell, parent));
|
|
562 break;
|
|
563 }
|
|
564 }
|
|
565 }
|
|
566 }
|
|
567
|
|
568 protected void layoutContextInfoPopup(int offset) {
|
|
569 switch (fContextInfoPopupOrientation) {
|
|
570 case CONTEXT_INFO_ABOVE: {
|
|
571 // Place the popup above the cursor line.
|
|
572 Shell shell= fShells[LAYOUT_CONTEXT_INFO_POPUP];
|
|
573 shell.setBounds(computeBoundsAboveBelow(shell, shell.getSize(), offset));
|
|
574 break;
|
|
575 }
|
|
576 case CONTEXT_INFO_BELOW: {
|
|
577 // Place the popup beneath the cursor line.
|
|
578 Shell parent= fShells[LAYOUT_CONTEXT_INFO_POPUP];
|
|
579 parent.setBounds(computeBoundsBelowAbove(parent, parent.getSize(), offset, null));
|
|
580 if (Helper.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR])) {
|
|
581 // Stack the proposal selector beneath the context info popup.
|
|
582 Shell shell= fShells[LAYOUT_PROPOSAL_SELECTOR];
|
|
583 shell.setLocation(getStackedLocation(shell, parent));
|
|
584 }
|
|
585 break;
|
|
586 }
|
|
587 }
|
|
588 }
|
|
589
|
|
590 /**
|
|
591 * Moves <code>point</code> such that <code>rectangle</code> does not bleed outside of
|
|
592 * <code>bounds</code>. All coordinates must have the same reference.
|
|
593 *
|
|
594 * @param point the point to move if needed
|
|
595 * @param shellSize the size of the shell that may be moved
|
|
596 * @param bounds the bounds
|
|
597 * @since 3.3
|
|
598 */
|
|
599 protected void constrainLocation(Point point, Point shellSize, Rectangle bounds) {
|
|
600 if (point.x + shellSize.x > bounds.x + bounds.width)
|
|
601 point.x= bounds.x + bounds.width - shellSize.x;
|
|
602
|
|
603 if (point.x < bounds.x)
|
|
604 point.x= bounds.x;
|
|
605
|
|
606 if (point.y + shellSize.y > bounds.y + bounds.height)
|
|
607 point.y= bounds.y + bounds.height - shellSize.y;
|
|
608
|
|
609 if (point.y < bounds.y)
|
|
610 point.y= bounds.y;
|
|
611 }
|
|
612
|
|
613 protected Rectangle constrainHorizontally(Rectangle rect, Rectangle bounds) {
|
|
614 // clip width
|
|
615 if (rect.width > bounds.width)
|
|
616 rect.width= bounds.width;
|
|
617
|
|
618 if (rect.x + rect.width > bounds.x + bounds.width)
|
|
619 rect.x= bounds.x + bounds.width - rect.width;
|
|
620 if (rect.x < bounds.x)
|
|
621 rect.x= bounds.x;
|
|
622
|
|
623 return rect;
|
|
624 }
|
|
625
|
|
626 /**
|
|
627 * Returns the display bounds for <code>shell</code> such that it appears right above
|
|
628 * <code>offset</code>, or below it if above is not suitable. The returned bounds lie
|
|
629 * within the monitor at the caret location and never overlap with the caret line.
|
|
630 *
|
|
631 * @param shell the shell to compute the placement for
|
|
632 * @param preferred the preferred size for <code>shell</code>
|
|
633 * @param offset the caret offset in the subject control
|
|
634 * @return the point right above <code>offset</code> in display coordinates
|
|
635 * @since 3.3
|
|
636 */
|
|
637 protected Rectangle computeBoundsAboveBelow(Shell shell, Point preferred, int offset) {
|
|
638 Control subjectControl= fContentAssistSubjectControlAdapter.getControl();
|
|
639 Display display= subjectControl.getDisplay();
|
|
640 Rectangle caret= getCaretRectangle(offset);
|
|
641 Monitor monitor= getClosestMonitor(display, caret);
|
|
642 Rectangle bounds= monitor.getClientArea();
|
|
643 Geometry.moveInside(caret, bounds);
|
|
644
|
|
645 int spaceAbove= caret.y - bounds.y;
|
|
646 int caretLowerY= caret.y + caret.height;
|
|
647 int spaceBelow= bounds.y + bounds.height - caretLowerY;
|
|
648 Rectangle rect;
|
|
649 if (spaceAbove >= preferred.y)
|
|
650 rect= new Rectangle(caret.x, caret.y - preferred.y, preferred.x, preferred.y);
|
|
651 else if (spaceBelow >= preferred.y)
|
|
652 rect= new Rectangle(caret.x, caretLowerY, preferred.x, preferred.y);
|
|
653 // we can't fit in the preferred size - squeeze into larger area
|
|
654 else if (spaceBelow <= spaceAbove)
|
|
655 rect= new Rectangle(caret.x, bounds.y, preferred.x, spaceAbove);
|
|
656 else
|
|
657 rect= new Rectangle(caret.x, caretLowerY, preferred.x, spaceBelow);
|
|
658
|
|
659 return constrainHorizontally(rect, bounds);
|
|
660 }
|
|
661
|
|
662 /**
|
|
663 * Returns the display bounds for <code>shell</code> such that it appears right below
|
|
664 * <code>offset</code>, or above it if below is not suitable. The returned bounds lie
|
|
665 * within the monitor at the caret location and never overlap with the caret line.
|
|
666 *
|
|
667 * @param shell the shell to compute the placement for
|
|
668 * @param preferred the preferred size for <code>shell</code>
|
|
669 * @param offset the caret offset in the subject control
|
|
670 * @param popup a popup to inform if the location was switched to above, <code>null</code> to do nothing
|
|
671 * @return the point right below <code>offset</code> in display coordinates
|
|
672 * @since 3.3
|
|
673 */
|
|
674 protected Rectangle computeBoundsBelowAbove(Shell shell, Point preferred, int offset, CompletionProposalPopup popup) {
|
|
675 Control subjectControl= fContentAssistSubjectControlAdapter.getControl();
|
|
676 Display display= subjectControl.getDisplay();
|
|
677 Rectangle caret= getCaretRectangle(offset);
|
|
678 Monitor monitor= getClosestMonitor(display, caret);
|
|
679 Rectangle bounds= monitor.getClientArea();
|
|
680 Geometry.moveInside(caret, bounds);
|
|
681
|
|
682 int threshold= popup is null ? Integer.MAX_VALUE : popup.getMinimalHeight();
|
|
683 int spaceAbove= caret.y - bounds.y;
|
|
684 int spaceBelow= bounds.y + bounds.height - (caret.y + caret.height);
|
|
685 Rectangle rect;
|
|
686 bool switched= false;
|
|
687 if (spaceBelow >= preferred.y)
|
|
688 rect= new Rectangle(caret.x, caret.y + caret.height, preferred.x, preferred.y);
|
|
689 // squeeze in below if we have at least threshold space
|
|
690 else if (spaceBelow >= threshold)
|
|
691 rect= new Rectangle(caret.x, caret.y + caret.height, preferred.x, spaceBelow);
|
|
692 else if (spaceAbove >= preferred.y) {
|
|
693 rect= new Rectangle(caret.x, caret.y - preferred.y, preferred.x, preferred.y);
|
|
694 switched= true;
|
|
695 } else if (spaceBelow >= spaceAbove) {
|
|
696 // we can't fit in the preferred size - squeeze into larger area
|
|
697 rect= new Rectangle(caret.x, caret.y + caret.height, preferred.x, spaceBelow);
|
|
698 } else {
|
|
699 rect= new Rectangle(caret.x, bounds.y, preferred.x, spaceAbove);
|
|
700 switched= true;
|
|
701 }
|
|
702
|
|
703 if (popup !is null)
|
|
704 popup.switchedPositionToAbove(switched);
|
|
705
|
|
706 return constrainHorizontally(rect, bounds);
|
|
707 }
|
|
708
|
|
709 private Rectangle getCaretRectangle(int offset) {
|
|
710 Point location= fContentAssistSubjectControlAdapter.getLocationAtOffset(offset);
|
|
711 Control subjectControl= fContentAssistSubjectControlAdapter.getControl();
|
|
712 Point controlSize= subjectControl.getSize();
|
|
713 constrainLocation(location, new Point(0, 0), new Rectangle(0, 0, controlSize.x, controlSize.y));
|
|
714 location= subjectControl.toDisplay(location);
|
|
715 Rectangle subjectRectangle= new Rectangle(location.x, location.y, 1, fContentAssistSubjectControlAdapter.getLineHeight());
|
|
716 return subjectRectangle;
|
|
717 }
|
|
718
|
|
719 protected Point getStackedLocation(Shell shell, Shell parent) {
|
|
720 Point p= parent.getLocation();
|
|
721 Point size= parent.getSize();
|
|
722 p.x += size.x / 4;
|
|
723 p.y += size.y;
|
|
724
|
|
725 p= parent.toDisplay(p);
|
|
726
|
|
727 Point shellSize= shell.getSize();
|
|
728 Monitor monitor= getClosestMonitor(parent.getDisplay(), new Rectangle(p.x, p.y, 0, 0));
|
|
729 Rectangle displayBounds= monitor.getClientArea();
|
|
730 constrainLocation(p, shellSize, displayBounds);
|
|
731
|
|
732 return p;
|
|
733 }
|
|
734
|
|
735 protected void adjustListeners(int type) {
|
|
736 switch (type) {
|
|
737 case LAYOUT_PROPOSAL_SELECTOR:
|
|
738 if (fContextType is LAYOUT_CONTEXT_SELECTOR &&
|
|
739 Helper.okToUse(fShells[LAYOUT_CONTEXT_SELECTOR]))
|
|
740 // Disable event notification to the tip selector.
|
|
741 removeContentAssistListener((IContentAssistListener) fPopups[LAYOUT_CONTEXT_SELECTOR], CONTEXT_SELECTOR);
|
|
742 break;
|
|
743 case LAYOUT_CONTEXT_SELECTOR:
|
|
744 if (Helper.okToUse(fShells[LAYOUT_PROPOSAL_SELECTOR]))
|
|
745 // Disable event notification to the proposal selector.
|
|
746 removeContentAssistListener((IContentAssistListener) fPopups[LAYOUT_PROPOSAL_SELECTOR], PROPOSAL_SELECTOR);
|
|
747 break;
|
|
748 case LAYOUT_CONTEXT_INFO_POPUP:
|
|
749 break;
|
|
750 }
|
|
751 }
|
|
752
|
|
753 /**
|
|
754 * Copied from dwtx.jface.window.Window.
|
|
755 * Returns the monitor whose client area contains the given point. If no
|
|
756 * monitor contains the point, returns the monitor that is closest to the
|
|
757 * point. If this is ever made public, it should be moved into a separate
|
|
758 * utility class.
|
|
759 *
|
|
760 * @param toSearch
|
|
761 * point to find (display coordinates)
|
|
762 * @param rectangle
|
|
763 * rectangle to find (display coordinates)
|
|
764 * @return the monitor closest to the given point
|
|
765 * @since 3.3
|
|
766 */
|
|
767 private Monitor getClosestMonitor(Display toSearch, Rectangle rectangle) {
|
|
768 int closest = Integer.MAX_VALUE;
|
|
769
|
|
770 Point toFind= Geometry.centerPoint(rectangle);
|
|
771 Monitor[] monitors = toSearch.getMonitors();
|
|
772 Monitor result = monitors[0];
|
|
773
|
|
774 for (int idx = 0; idx < monitors.length; idx++) {
|
|
775 Monitor current = monitors[idx];
|
|
776
|
|
777 Rectangle clientArea = current.getClientArea();
|
|
778
|
|
779 if (clientArea.contains(toFind)) {
|
|
780 return current;
|
|
781 }
|
|
782
|
|
783 int distance = Geometry.distanceSquared(Geometry.centerPoint(clientArea), toFind);
|
|
784 if (distance < closest) {
|
|
785 closest = distance;
|
|
786 result = current;
|
|
787 }
|
|
788 }
|
|
789
|
|
790 return result;
|
|
791 }
|
|
792 }
|
|
793
|
|
794 /**
|
|
795 * Internal key listener and event consumer.
|
|
796 */
|
|
797 class InternalListener : VerifyKeyListener, IEventConsumer {
|
|
798
|
|
799 /**
|
|
800 * Verifies key events by notifying the registered listeners. Each listener is allowed to
|
|
801 * indicate that the event has been handled and should not be further processed.
|
|
802 *
|
|
803 * @param e the verify event
|
|
804 * @see VerifyKeyListener#verifyKey(dwt.events.VerifyEvent)
|
|
805 */
|
|
806 public void verifyKey(VerifyEvent e) {
|
|
807 IContentAssistListener[] listeners= (IContentAssistListener[]) fListeners.clone();
|
|
808 for (int i= 0; i < listeners.length; i++) {
|
|
809 if (listeners[i] !is null) {
|
|
810 if (!listeners[i].verifyKey(e) || !e.doit)
|
|
811 break;
|
|
812 }
|
|
813 }
|
|
814 if (fAutoAssistListener !is null)
|
|
815 fAutoAssistListener.keyPressed(e);
|
|
816 }
|
|
817
|
|
818 /*
|
|
819 * @see IEventConsumer#processEvent
|
|
820 */
|
|
821 public void processEvent(VerifyEvent event) {
|
|
822
|
|
823 installKeyListener();
|
|
824
|
|
825 IContentAssistListener[] listeners= (IContentAssistListener[]) fListeners.clone();
|
|
826 for (int i= 0; i < listeners.length; i++) {
|
|
827 if (listeners[i] !is null) {
|
|
828 listeners[i].processEvent(event);
|
|
829 if (!event.doit)
|
|
830 return;
|
|
831 }
|
|
832 }
|
|
833 }
|
|
834 }
|
|
835
|
|
836 /**
|
|
837 * Dialog store constants.
|
|
838 *
|
|
839 * @since 3.0
|
|
840 */
|
|
841 public static final String STORE_SIZE_X= "size.x"; //$NON-NLS-1$
|
|
842 public static final String STORE_SIZE_Y= "size.y"; //$NON-NLS-1$
|
|
843
|
|
844 // Content-Assist Listener types
|
|
845 final static int CONTEXT_SELECTOR= 0;
|
|
846 final static int PROPOSAL_SELECTOR= 1;
|
|
847 final static int CONTEXT_INFO_POPUP= 2;
|
|
848
|
|
849 /**
|
|
850 * The popup priority: > linked position proposals and hover pop-ups. Default value:
|
|
851 * <code>20</code>;
|
|
852 *
|
|
853 * @since 3.0
|
|
854 */
|
|
855 public static final int WIDGET_PRIORITY= 20;
|
|
856
|
|
857 private static final int DEFAULT_AUTO_ACTIVATION_DELAY= 500;
|
|
858
|
|
859 private IInformationControlCreator fInformationControlCreator;
|
|
860 private int fAutoActivationDelay= DEFAULT_AUTO_ACTIVATION_DELAY;
|
|
861 private bool fIsAutoActivated= false;
|
|
862 private bool fIsAutoInserting= false;
|
|
863 private int fProposalPopupOrientation= PROPOSAL_OVERLAY;
|
|
864 private int fContextInfoPopupOrientation= CONTEXT_INFO_ABOVE;
|
|
865 private Map fProcessors;
|
|
866
|
|
867 /**
|
|
868 * The partitioning.
|
|
869 *
|
|
870 * @since 3.0
|
|
871 */
|
|
872 private String fPartitioning;
|
|
873
|
|
874 private Color fContextInfoPopupBackground;
|
|
875 private Color fContextInfoPopupForeground;
|
|
876 private Color fContextSelectorBackground;
|
|
877 private Color fContextSelectorForeground;
|
|
878 private Color fProposalSelectorBackground;
|
|
879 private Color fProposalSelectorForeground;
|
|
880
|
|
881 private ITextViewer fViewer;
|
|
882 private String fLastErrorMessage;
|
|
883
|
|
884 private Closer fCloser;
|
|
885 LayoutManager fLayoutManager;
|
|
886 private AutoAssistListener fAutoAssistListener;
|
|
887 private InternalListener fInternalListener;
|
|
888 private CompletionProposalPopup fProposalPopup;
|
|
889 private ContextInformationPopup fContextInfoPopup;
|
|
890
|
|
891 /**
|
|
892 * Flag which tells whether a verify key listener is hooked.
|
|
893 *
|
|
894 * @since 3.0
|
|
895 */
|
|
896 private bool fVerifyKeyListenerHooked= false;
|
|
897 private IContentAssistListener[] fListeners= new IContentAssistListener[4];
|
|
898 /**
|
|
899 * The content assist subject control.
|
|
900 *
|
|
901 * @since 3.0
|
|
902 */
|
|
903 private IContentAssistSubjectControl fContentAssistSubjectControl;
|
|
904 /**
|
|
905 * The content assist subject control's shell.
|
|
906 *
|
|
907 * @since 3.2
|
|
908 */
|
|
909 private Shell fContentAssistSubjectControlShell;
|
|
910 /**
|
|
911 * The content assist subject control's shell traverse listener.
|
|
912 *
|
|
913 * @since 3.2
|
|
914 */
|
|
915 private TraverseListener fCASCSTraverseListener;
|
|
916 /**
|
|
917 * The content assist subject control adapter.
|
|
918 *
|
|
919 * @since 3.0
|
|
920 */
|
|
921 private ContentAssistSubjectControlAdapter fContentAssistSubjectControlAdapter;
|
|
922 /**
|
|
923 * The dialog settings for the control's bounds.
|
|
924 *
|
|
925 * @since 3.0
|
|
926 */
|
|
927 private IDialogSettings fDialogSettings;
|
|
928 /**
|
|
929 * Prefix completion setting.
|
|
930 *
|
|
931 * @since 3.0
|
|
932 */
|
|
933 private bool fIsPrefixCompletionEnabled= false;
|
|
934 /**
|
|
935 * The list of completion listeners.
|
|
936 *
|
|
937 * @since 3.2
|
|
938 */
|
|
939 private ListenerList fCompletionListeners= new ListenerList(ListenerList.IDENTITY);
|
|
940 /**
|
|
941 * The message to display at the bottom of the proposal popup.
|
|
942 *
|
|
943 * @since 3.2
|
|
944 */
|
|
945 private String fMessage= ""; //$NON-NLS-1$
|
|
946 /**
|
|
947 * The cycling mode property.
|
|
948 *
|
|
949 * @since 3.2
|
|
950 */
|
|
951 private bool fIsRepetitionMode= false;
|
|
952 /**
|
|
953 * The show empty property.
|
|
954 *
|
|
955 * @since 3.2
|
|
956 */
|
|
957 private bool fShowEmptyList= false;
|
|
958 /**
|
|
959 * The message line property.
|
|
960 *
|
|
961 * @since 3.2
|
|
962 */
|
|
963 private bool fIsStatusLineVisible;
|
|
964 /**
|
|
965 * The last system time when auto activation performed.
|
|
966 *
|
|
967 * @since 3.2
|
|
968 */
|
|
969 private long fLastAutoActivation= Long.MIN_VALUE;
|
|
970 /**
|
|
971 * The iteration key sequence to listen for, or <code>null</code>.
|
|
972 *
|
|
973 * @since 3.2
|
|
974 */
|
|
975 private KeySequence fRepeatedInvocationKeySequence;
|
|
976
|
|
977 /**
|
|
978 * Maps handler to command identifiers.
|
|
979 *
|
|
980 * @since 3.4
|
|
981 */
|
|
982 private Map fHandlers;
|
|
983
|
|
984 /**
|
|
985 * Tells whether colored labels support is enabled.
|
|
986 *
|
|
987 * @since 3.4
|
|
988 */
|
|
989 private bool fIsColoredLabelsSupportEnabled= false;
|
|
990
|
|
991
|
|
992 /**
|
|
993 * Creates a new content assistant. The content assistant is not automatically activated,
|
|
994 * overlays the completion proposals with context information list if necessary, and shows the
|
|
995 * context information above the location at which it was activated. If auto activation will be
|
|
996 * enabled, without further configuration steps, this content assistant is activated after a 500
|
|
997 * milliseconds delay. It uses the default partitioning.
|
|
998 */
|
|
999 public ContentAssistant() {
|
|
1000 fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING;
|
|
1001 }
|
|
1002
|
|
1003 /**
|
|
1004 * Sets the document partitioning this content assistant is using.
|
|
1005 *
|
|
1006 * @param partitioning the document partitioning for this content assistant
|
|
1007 * @since 3.0
|
|
1008 */
|
|
1009 public void setDocumentPartitioning(String partitioning) {
|
|
1010 Assert.isNotNull(partitioning);
|
|
1011 fPartitioning= partitioning;
|
|
1012 }
|
|
1013
|
|
1014 /*
|
|
1015 * @see dwtx.jface.text.contentassist.IContentAssistantExtension#getDocumentPartitioning()
|
|
1016 * @since 3.0
|
|
1017 */
|
|
1018 public String getDocumentPartitioning() {
|
|
1019 return fPartitioning;
|
|
1020 }
|
|
1021
|
|
1022 /**
|
|
1023 * Registers a given content assist processor for a particular content type. If there is already
|
|
1024 * a processor registered for this type, the new processor is registered instead of the old one.
|
|
1025 *
|
|
1026 * @param processor the content assist processor to register, or <code>null</code> to remove
|
|
1027 * an existing one
|
|
1028 * @param contentType the content type under which to register
|
|
1029 */
|
|
1030 public void setContentAssistProcessor(IContentAssistProcessor processor, String contentType) {
|
|
1031
|
|
1032 Assert.isNotNull(contentType);
|
|
1033
|
|
1034 if (fProcessors is null)
|
|
1035 fProcessors= new HashMap();
|
|
1036
|
|
1037 if (processor is null)
|
|
1038 fProcessors.remove(contentType);
|
|
1039 else
|
|
1040 fProcessors.put(contentType, processor);
|
|
1041 }
|
|
1042
|
|
1043 /*
|
|
1044 * @see IContentAssistant#getContentAssistProcessor
|
|
1045 */
|
|
1046 public IContentAssistProcessor getContentAssistProcessor(String contentType) {
|
|
1047 if (fProcessors is null)
|
|
1048 return null;
|
|
1049
|
|
1050 return (IContentAssistProcessor) fProcessors.get(contentType);
|
|
1051 }
|
|
1052
|
|
1053 /**
|
|
1054 * Computes the sorted set of all auto activation trigger characters.
|
|
1055 *
|
|
1056 * @return the sorted set of all auto activation trigger characters
|
|
1057 * @since 3.1
|
|
1058 */
|
|
1059 private String computeAllAutoActivationTriggers() {
|
|
1060 if (fProcessors is null)
|
|
1061 return ""; //$NON-NLS-1$
|
|
1062
|
|
1063 StringBuffer buf= new StringBuffer(5);
|
|
1064 Iterator iter= fProcessors.entrySet().iterator();
|
|
1065 while (iter.hasNext()) {
|
|
1066 Entry entry= (Entry) iter.next();
|
|
1067 IContentAssistProcessor processor= (IContentAssistProcessor) entry.getValue();
|
|
1068 char[] triggers= processor.getCompletionProposalAutoActivationCharacters();
|
|
1069 if (triggers !is null)
|
|
1070 buf.append(triggers);
|
|
1071 triggers= processor.getContextInformationAutoActivationCharacters();
|
|
1072 if (triggers !is null)
|
|
1073 buf.append(triggers);
|
|
1074 }
|
|
1075 return buf.toString();
|
|
1076 }
|
|
1077
|
|
1078 /**
|
|
1079 * Enables the content assistant's auto activation mode.
|
|
1080 *
|
|
1081 * @param enabled indicates whether auto activation is enabled or not
|
|
1082 */
|
|
1083 public void enableAutoActivation(bool enabled) {
|
|
1084 fIsAutoActivated= enabled;
|
|
1085 manageAutoActivation(fIsAutoActivated);
|
|
1086 }
|
|
1087
|
|
1088 /**
|
|
1089 * Enables the content assistant's auto insertion mode. If enabled, the content assistant
|
|
1090 * inserts a proposal automatically if it is the only proposal. In the case of ambiguities, the
|
|
1091 * user must make the choice.
|
|
1092 *
|
|
1093 * @param enabled indicates whether auto insertion is enabled or not
|
|
1094 * @since 2.0
|
|
1095 */
|
|
1096 public void enableAutoInsert(bool enabled) {
|
|
1097 fIsAutoInserting= enabled;
|
|
1098 }
|
|
1099
|
|
1100 /**
|
|
1101 * Returns whether this content assistant is in the auto insertion mode or not.
|
|
1102 *
|
|
1103 * @return <code>true</code> if in auto insertion mode
|
|
1104 * @since 2.0
|
|
1105 */
|
|
1106 bool isAutoInserting() {
|
|
1107 return fIsAutoInserting;
|
|
1108 }
|
|
1109
|
|
1110 /**
|
|
1111 * Installs and uninstall the listeners needed for auto activation.
|
|
1112 *
|
|
1113 * @param start <code>true</code> if listeners must be installed, <code>false</code> if they
|
|
1114 * must be removed
|
|
1115 * @since 2.0
|
|
1116 */
|
|
1117 private void manageAutoActivation(bool start) {
|
|
1118 if (start) {
|
|
1119
|
|
1120 if ((fContentAssistSubjectControlAdapter !is null) && fAutoAssistListener is null) {
|
|
1121 fAutoAssistListener= createAutoAssistListener();
|
|
1122 // For details see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49212
|
|
1123 if (fContentAssistSubjectControlAdapter.supportsVerifyKeyListener())
|
|
1124 fContentAssistSubjectControlAdapter.appendVerifyKeyListener(fAutoAssistListener);
|
|
1125 else
|
|
1126 fContentAssistSubjectControlAdapter.addKeyListener(fAutoAssistListener);
|
|
1127 }
|
|
1128
|
|
1129 } else if (fAutoAssistListener !is null) {
|
|
1130 // For details see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=49212
|
|
1131 if (fContentAssistSubjectControlAdapter.supportsVerifyKeyListener())
|
|
1132 fContentAssistSubjectControlAdapter.removeVerifyKeyListener(fAutoAssistListener);
|
|
1133 else
|
|
1134 fContentAssistSubjectControlAdapter.removeKeyListener(fAutoAssistListener);
|
|
1135 fAutoAssistListener= null;
|
|
1136 }
|
|
1137 }
|
|
1138
|
|
1139 /**
|
|
1140 * This method allows subclasses to provide their own {@link AutoAssistListener}.
|
|
1141 *
|
|
1142 * @return a new auto assist listener
|
|
1143 * @since 3.4
|
|
1144 */
|
|
1145 protected AutoAssistListener createAutoAssistListener() {
|
|
1146 return new AutoAssistListener();
|
|
1147 }
|
|
1148
|
|
1149 /**
|
|
1150 * Sets the delay after which the content assistant is automatically invoked if the cursor is
|
|
1151 * behind an auto activation character.
|
|
1152 *
|
|
1153 * @param delay the auto activation delay
|
|
1154 */
|
|
1155 public void setAutoActivationDelay(int delay) {
|
|
1156 fAutoActivationDelay= delay;
|
|
1157 }
|
|
1158
|
|
1159 /**
|
|
1160 * Gets the delay after which the content assistant is automatically invoked if the cursor is
|
|
1161 * behind an auto activation character.
|
|
1162 *
|
|
1163 * @return the auto activation delay
|
|
1164 * @since 3.4
|
|
1165 */
|
|
1166 public int getAutoActivationDelay() {
|
|
1167 return fAutoActivationDelay;
|
|
1168 }
|
|
1169
|
|
1170 /**
|
|
1171 * Sets the proposal pop-ups' orientation. The following values may be used:
|
|
1172 * <ul>
|
|
1173 * <li>PROPOSAL_OVERLAY<p>
|
|
1174 * proposal popup windows should overlay each other
|
|
1175 * </li>
|
|
1176 * <li>PROPOSAL_REMOVE<p>
|
|
1177 * any currently shown proposal popup should be closed
|
|
1178 * </li>
|
|
1179 * <li>PROPOSAL_STACKED<p>
|
|
1180 * proposal popup windows should be vertical stacked, with no overlap,
|
|
1181 * beneath the line containing the current cursor location
|
|
1182 * </li>
|
|
1183 * </ul>
|
|
1184 *
|
|
1185 * @param orientation the popup's orientation
|
|
1186 */
|
|
1187 public void setProposalPopupOrientation(int orientation) {
|
|
1188 fProposalPopupOrientation= orientation;
|
|
1189 }
|
|
1190
|
|
1191 /**
|
|
1192 * Sets the context information popup's orientation.
|
|
1193 * The following values may be used:
|
|
1194 * <ul>
|
|
1195 * <li>CONTEXT_ABOVE<p>
|
|
1196 * context information popup should always appear above the line containing
|
|
1197 * the current cursor location
|
|
1198 * </li>
|
|
1199 * <li>CONTEXT_BELOW<p>
|
|
1200 * context information popup should always appear below the line containing
|
|
1201 * the current cursor location
|
|
1202 * </li>
|
|
1203 * </ul>
|
|
1204 *
|
|
1205 * @param orientation the popup's orientation
|
|
1206 */
|
|
1207 public void setContextInformationPopupOrientation(int orientation) {
|
|
1208 fContextInfoPopupOrientation= orientation;
|
|
1209 }
|
|
1210
|
|
1211 /**
|
|
1212 * Sets the context information popup's background color.
|
|
1213 *
|
|
1214 * @param background the background color
|
|
1215 */
|
|
1216 public void setContextInformationPopupBackground(Color background) {
|
|
1217 fContextInfoPopupBackground= background;
|
|
1218 }
|
|
1219
|
|
1220 /**
|
|
1221 * Returns the background of the context information popup.
|
|
1222 *
|
|
1223 * @return the background of the context information popup
|
|
1224 * @since 2.0
|
|
1225 */
|
|
1226 Color getContextInformationPopupBackground() {
|
|
1227 return fContextInfoPopupBackground;
|
|
1228 }
|
|
1229
|
|
1230 /**
|
|
1231 * Sets the context information popup's foreground color.
|
|
1232 *
|
|
1233 * @param foreground the foreground color
|
|
1234 * @since 2.0
|
|
1235 */
|
|
1236 public void setContextInformationPopupForeground(Color foreground) {
|
|
1237 fContextInfoPopupForeground= foreground;
|
|
1238 }
|
|
1239
|
|
1240 /**
|
|
1241 * Returns the foreground of the context information popup.
|
|
1242 *
|
|
1243 *
|
|
1244 * @return the foreground of the context information popup
|
|
1245 * @since 2.0
|
|
1246 */
|
|
1247 Color getContextInformationPopupForeground() {
|
|
1248 return fContextInfoPopupForeground;
|
|
1249 }
|
|
1250
|
|
1251 /**
|
|
1252 * Sets the proposal selector's background color.
|
|
1253 * <p>
|
|
1254 * <strong>Note:</strong> As of 3.4, you should only call this
|
|
1255 * method if you want to override the {@link JFacePreferences#CONTENT_ASSIST_BACKGROUND_COLOR}.
|
|
1256 * </p>
|
|
1257 *
|
|
1258 * @param background the background color
|
|
1259 * @since 2.0
|
|
1260 */
|
|
1261 public void setProposalSelectorBackground(Color background) {
|
|
1262 fProposalSelectorBackground= background;
|
|
1263 }
|
|
1264
|
|
1265 /**
|
|
1266 * Returns the custom background color of the proposal selector.
|
|
1267 *
|
|
1268 * @return the background of the proposal selector or <code>null</code> if not set
|
|
1269 * @since 2.0
|
|
1270 */
|
|
1271 Color getProposalSelectorBackground() {
|
|
1272 return fProposalSelectorBackground;
|
|
1273 }
|
|
1274
|
|
1275 /**
|
|
1276 * Sets the proposal's foreground color.
|
|
1277 * <p>
|
|
1278 * <strong>Note:</strong> As of 3.4, you should only call this
|
|
1279 * method if you want to override the {@link JFacePreferences#CONTENT_ASSIST_FOREGROUND_COLOR}.
|
|
1280 * </p>
|
|
1281 *
|
|
1282 * @param foreground the foreground color
|
|
1283 * @since 2.0
|
|
1284 */
|
|
1285 public void setProposalSelectorForeground(Color foreground) {
|
|
1286 fProposalSelectorForeground= foreground;
|
|
1287 }
|
|
1288
|
|
1289 /**
|
|
1290 * Returns the custom foreground color of the proposal selector.
|
|
1291 *
|
|
1292 * @return the foreground of the proposal selector or <code>null</code> if not set
|
|
1293 * @since 2.0
|
|
1294 */
|
|
1295 Color getProposalSelectorForeground() {
|
|
1296 return fProposalSelectorForeground;
|
|
1297 }
|
|
1298
|
|
1299 /**
|
|
1300 * Sets the context selector's background color.
|
|
1301 *
|
|
1302 * @param background the background color
|
|
1303 * @since 2.0
|
|
1304 */
|
|
1305 public void setContextSelectorBackground(Color background) {
|
|
1306 fContextSelectorBackground= background;
|
|
1307 }
|
|
1308
|
|
1309 /**
|
|
1310 * Returns the background of the context selector.
|
|
1311 *
|
|
1312 * @return the background of the context selector
|
|
1313 * @since 2.0
|
|
1314 */
|
|
1315 Color getContextSelectorBackground() {
|
|
1316 return fContextSelectorBackground;
|
|
1317 }
|
|
1318
|
|
1319 /**
|
|
1320 * Sets the context selector's foreground color.
|
|
1321 *
|
|
1322 * @param foreground the foreground color
|
|
1323 * @since 2.0
|
|
1324 */
|
|
1325 public void setContextSelectorForeground(Color foreground) {
|
|
1326 fContextSelectorForeground= foreground;
|
|
1327 }
|
|
1328
|
|
1329 /**
|
|
1330 * Returns the foreground of the context selector.
|
|
1331 *
|
|
1332 * @return the foreground of the context selector
|
|
1333 * @since 2.0
|
|
1334 */
|
|
1335 Color getContextSelectorForeground() {
|
|
1336 return fContextSelectorForeground;
|
|
1337 }
|
|
1338
|
|
1339 /**
|
|
1340 * Sets the information control creator for the additional information control.
|
|
1341 *
|
|
1342 * @param creator the information control creator for the additional information control
|
|
1343 * @since 2.0
|
|
1344 */
|
|
1345 public void setInformationControlCreator(IInformationControlCreator creator) {
|
|
1346 fInformationControlCreator= creator;
|
|
1347 }
|
|
1348
|
|
1349 /*
|
|
1350 * @see IControlContentAssistant#install(IContentAssistSubjectControl)
|
|
1351 * @since 3.0
|
|
1352 */
|
|
1353 protected void install(IContentAssistSubjectControl contentAssistSubjectControl) {
|
|
1354 fContentAssistSubjectControl= contentAssistSubjectControl;
|
|
1355 fContentAssistSubjectControlAdapter= new ContentAssistSubjectControlAdapter(fContentAssistSubjectControl);
|
|
1356 install();
|
|
1357 }
|
|
1358
|
|
1359 /*
|
|
1360 * @see IContentAssist#install
|
|
1361 * @since 3.0
|
|
1362 */
|
|
1363 public void install(ITextViewer textViewer) {
|
|
1364 fViewer= textViewer;
|
|
1365 fContentAssistSubjectControlAdapter= new ContentAssistSubjectControlAdapter(fViewer);
|
|
1366 install();
|
|
1367 }
|
|
1368
|
|
1369 protected void install() {
|
|
1370
|
|
1371 fLayoutManager= new LayoutManager();
|
|
1372 fInternalListener= new InternalListener();
|
|
1373
|
|
1374 AdditionalInfoController controller= null;
|
|
1375 if (fInformationControlCreator !is null) {
|
|
1376 int delay= fAutoActivationDelay;
|
|
1377 if (delay is 0)
|
|
1378 delay= DEFAULT_AUTO_ACTIVATION_DELAY;
|
|
1379 delay= Math.round(delay * 1.5f);
|
|
1380 controller= new AdditionalInfoController(fInformationControlCreator, delay);
|
|
1381 }
|
|
1382
|
|
1383 fContextInfoPopup= fContentAssistSubjectControlAdapter.createContextInfoPopup(this);
|
|
1384 fProposalPopup= fContentAssistSubjectControlAdapter.createCompletionProposalPopup(this, controller);
|
|
1385
|
|
1386 registerHandler(SELECT_NEXT_PROPOSAL_COMMAND_ID, fProposalPopup.createProposalSelectionHandler(CompletionProposalPopup.ProposalSelectionHandler.SELECT_NEXT));
|
|
1387 registerHandler(SELECT_PREVIOUS_PROPOSAL_COMMAND_ID, fProposalPopup.createProposalSelectionHandler(CompletionProposalPopup.ProposalSelectionHandler.SELECT_PREVIOUS));
|
|
1388
|
|
1389 if (Helper.okToUse(fContentAssistSubjectControlAdapter.getControl())) {
|
|
1390 fContentAssistSubjectControlShell= fContentAssistSubjectControlAdapter.getControl().getShell();
|
|
1391 fCASCSTraverseListener= new TraverseListener() {
|
|
1392 public void keyTraversed(TraverseEvent e) {
|
|
1393 if (e.detail is DWT.TRAVERSE_ESCAPE && isProposalPopupActive())
|
|
1394 e.doit= false;
|
|
1395 }
|
|
1396 };
|
|
1397 fContentAssistSubjectControlShell.addTraverseListener(fCASCSTraverseListener);
|
|
1398 }
|
|
1399
|
|
1400 manageAutoActivation(fIsAutoActivated);
|
|
1401 }
|
|
1402
|
|
1403 /*
|
|
1404 * @see IContentAssist#uninstall
|
|
1405 */
|
|
1406 public void uninstall() {
|
|
1407 hide();
|
|
1408 manageAutoActivation(false);
|
|
1409
|
|
1410 if (fHandlers !is null) {
|
|
1411 fHandlers.clear();
|
|
1412 fHandlers= null;
|
|
1413 }
|
|
1414
|
|
1415 if (fCloser !is null) {
|
|
1416 fCloser.uninstall();
|
|
1417 fCloser= null;
|
|
1418 }
|
|
1419
|
|
1420 if (Helper.okToUse(fContentAssistSubjectControlShell))
|
|
1421 fContentAssistSubjectControlShell.removeTraverseListener(fCASCSTraverseListener);
|
|
1422 fCASCSTraverseListener= null;
|
|
1423 fContentAssistSubjectControlShell= null;
|
|
1424
|
|
1425 fViewer= null;
|
|
1426 fContentAssistSubjectControl= null;
|
|
1427 fContentAssistSubjectControlAdapter= null;
|
|
1428 }
|
|
1429
|
|
1430 /**
|
|
1431 * Adds the given shell of the specified type to the layout. Valid types are defined by
|
|
1432 * <code>LayoutManager</code>.
|
|
1433 *
|
|
1434 * @param popup a content assist popup
|
|
1435 * @param shell the shell of the content-assist popup
|
|
1436 * @param type the type of popup
|
|
1437 * @param visibleOffset the offset at which to layout the popup relative to the offset of the
|
|
1438 * viewer's visible region
|
|
1439 * @since 2.0
|
|
1440 */
|
|
1441 void addToLayout(Object popup, Shell shell, int type, int visibleOffset) {
|
|
1442 fLayoutManager.add(popup, shell, type, visibleOffset);
|
|
1443 }
|
|
1444
|
|
1445 /**
|
|
1446 * Layouts the registered popup of the given type relative to the given offset. The offset is
|
|
1447 * relative to the offset of the viewer's visible region. Valid types are defined by
|
|
1448 * <code>LayoutManager</code>.
|
|
1449 *
|
|
1450 * @param type the type of popup to layout
|
|
1451 * @param visibleOffset the offset at which to layout relative to the offset of the viewer's
|
|
1452 * visible region
|
|
1453 * @since 2.0
|
|
1454 */
|
|
1455 void layout(int type, int visibleOffset) {
|
|
1456 fLayoutManager.layout(type, visibleOffset);
|
|
1457 }
|
|
1458
|
|
1459 /**
|
|
1460 * Returns the layout manager.
|
|
1461 *
|
|
1462 * @return the layout manager
|
|
1463 * @since 3.3
|
|
1464 */
|
|
1465 LayoutManager getLayoutManager() {
|
|
1466 return fLayoutManager;
|
|
1467 }
|
|
1468
|
|
1469 /**
|
|
1470 * Notifies the controller that a popup has lost focus.
|
|
1471 *
|
|
1472 * @param e the focus event
|
|
1473 */
|
|
1474 void popupFocusLost(FocusEvent e) {
|
|
1475 fCloser.focusLost(e);
|
|
1476 }
|
|
1477
|
|
1478 /**
|
|
1479 * Returns the offset of the selection relative to the offset of the visible region.
|
|
1480 *
|
|
1481 * @return the offset of the selection relative to the offset of the visible region
|
|
1482 * @since 2.0
|
|
1483 */
|
|
1484 int getSelectionOffset() {
|
|
1485 return fContentAssistSubjectControlAdapter.getWidgetSelectionRange().x;
|
|
1486 }
|
|
1487
|
|
1488 /**
|
|
1489 * Returns whether the widget token could be acquired. The following are valid listener types:
|
|
1490 * <ul>
|
|
1491 * <li>AUTO_ASSIST</li>
|
|
1492 * <li>CONTEXT_SELECTOR</li>
|
|
1493 * <li>PROPOSAL_SELECTOR</li>
|
|
1494 * <li>CONTEXT_INFO_POPUP</li>
|
|
1495 * </ul>
|
|
1496 *
|
|
1497 * @param type the listener type for which to acquire
|
|
1498 * @return <code>true</code> if the widget token could be acquired
|
|
1499 * @since 2.0
|
|
1500 */
|
|
1501 private bool acquireWidgetToken(int type) {
|
|
1502 switch (type) {
|
|
1503 case CONTEXT_SELECTOR:
|
|
1504 case PROPOSAL_SELECTOR:
|
|
1505 if (fContentAssistSubjectControl instanceof IWidgetTokenOwnerExtension) {
|
|
1506 IWidgetTokenOwnerExtension extension= (IWidgetTokenOwnerExtension) fContentAssistSubjectControl;
|
|
1507 return extension.requestWidgetToken(this, WIDGET_PRIORITY);
|
|
1508 } else if (fContentAssistSubjectControl instanceof IWidgetTokenOwner) {
|
|
1509 IWidgetTokenOwner owner= (IWidgetTokenOwner) fContentAssistSubjectControl;
|
|
1510 return owner.requestWidgetToken(this);
|
|
1511 } else if (fViewer instanceof IWidgetTokenOwnerExtension) {
|
|
1512 IWidgetTokenOwnerExtension extension= (IWidgetTokenOwnerExtension) fViewer;
|
|
1513 return extension.requestWidgetToken(this, WIDGET_PRIORITY);
|
|
1514 } else if (fViewer instanceof IWidgetTokenOwner) {
|
|
1515 IWidgetTokenOwner owner= (IWidgetTokenOwner) fViewer;
|
|
1516 return owner.requestWidgetToken(this);
|
|
1517 }
|
|
1518 }
|
|
1519 return true;
|
|
1520 }
|
|
1521
|
|
1522 /**
|
|
1523 * Registers a content assist listener. The following are valid listener types:
|
|
1524 * <ul>
|
|
1525 * <li>AUTO_ASSIST</li>
|
|
1526 * <li>CONTEXT_SELECTOR</li>
|
|
1527 * <li>PROPOSAL_SELECTOR</li>
|
|
1528 * <li>CONTEXT_INFO_POPUP</li>
|
|
1529 * </ul>
|
|
1530 * Returns whether the listener could be added successfully. A listener can not be added if the
|
|
1531 * widget token could not be acquired.
|
|
1532 *
|
|
1533 * @param listener the listener to register
|
|
1534 * @param type the type of listener
|
|
1535 * @return <code>true</code> if the listener could be added
|
|
1536 */
|
|
1537 bool addContentAssistListener(IContentAssistListener listener, int type) {
|
|
1538
|
|
1539 if (acquireWidgetToken(type)) {
|
|
1540
|
|
1541 fListeners[type]= listener;
|
|
1542
|
|
1543 if (fCloser is null && getNumberOfListeners() is 1) {
|
|
1544 fCloser= new Closer();
|
|
1545 fCloser.install();
|
|
1546 fContentAssistSubjectControlAdapter.setEventConsumer(fInternalListener);
|
|
1547 installKeyListener();
|
|
1548 } else
|
|
1549 promoteKeyListener();
|
|
1550 return true;
|
|
1551 }
|
|
1552
|
|
1553 return false;
|
|
1554 }
|
|
1555
|
|
1556 /**
|
|
1557 * Re-promotes the key listener to the first position, using prependVerifyKeyListener. This
|
|
1558 * ensures no other instance is filtering away the keystrokes underneath, if we've been up for a
|
|
1559 * while (e.g. when the context info is showing.
|
|
1560 *
|
|
1561 * @since 3.0
|
|
1562 */
|
|
1563 private void promoteKeyListener() {
|
|
1564 uninstallVerifyKeyListener();
|
|
1565 installKeyListener();
|
|
1566 }
|
|
1567
|
|
1568 /**
|
|
1569 * Installs a key listener on the text viewer's widget.
|
|
1570 */
|
|
1571 private void installKeyListener() {
|
|
1572 if (!fVerifyKeyListenerHooked) {
|
|
1573 if (Helper.okToUse(fContentAssistSubjectControlAdapter.getControl())) {
|
|
1574 fVerifyKeyListenerHooked= fContentAssistSubjectControlAdapter.prependVerifyKeyListener(fInternalListener);
|
|
1575 }
|
|
1576 }
|
|
1577 }
|
|
1578
|
|
1579 /**
|
|
1580 * Releases the previously acquired widget token if the token is no longer necessary. The
|
|
1581 * following are valid listener types:
|
|
1582 * <ul>
|
|
1583 * <li>AUTO_ASSIST</li>
|
|
1584 * <li>CONTEXT_SELECTOR</li>
|
|
1585 * <li>PROPOSAL_SELECTOR</li>
|
|
1586 * <li>CONTEXT_INFO_POPUP</li>
|
|
1587 * </ul>
|
|
1588 *
|
|
1589 * @param type the listener type
|
|
1590 * @since 2.0
|
|
1591 */
|
|
1592 private void releaseWidgetToken(int type) {
|
|
1593 if (fListeners[CONTEXT_SELECTOR] is null && fListeners[PROPOSAL_SELECTOR] is null) {
|
|
1594 IWidgetTokenOwner owner= null;
|
|
1595 if (fContentAssistSubjectControl instanceof IWidgetTokenOwner)
|
|
1596 owner= (IWidgetTokenOwner) fContentAssistSubjectControl;
|
|
1597 else if (fViewer instanceof IWidgetTokenOwner)
|
|
1598 owner= (IWidgetTokenOwner) fViewer;
|
|
1599 if (owner !is null)
|
|
1600 owner.releaseWidgetToken(this);
|
|
1601 }
|
|
1602 }
|
|
1603
|
|
1604 /**
|
|
1605 * Unregisters a content assist listener.
|
|
1606 *
|
|
1607 * @param listener the listener to unregister
|
|
1608 * @param type the type of listener
|
|
1609 * @see #addContentAssistListener(IContentAssistListener, int)
|
|
1610 */
|
|
1611 void removeContentAssistListener(IContentAssistListener listener, int type) {
|
|
1612 fListeners[type]= null;
|
|
1613
|
|
1614 if (getNumberOfListeners() is 0) {
|
|
1615
|
|
1616 if (fCloser !is null) {
|
|
1617 fCloser.uninstall();
|
|
1618 fCloser= null;
|
|
1619 }
|
|
1620
|
|
1621 uninstallVerifyKeyListener();
|
|
1622 fContentAssistSubjectControlAdapter.setEventConsumer(null);
|
|
1623 }
|
|
1624
|
|
1625 releaseWidgetToken(type);
|
|
1626 }
|
|
1627
|
|
1628 /**
|
|
1629 * Uninstall the key listener from the text viewer's widget.
|
|
1630 *
|
|
1631 * @since 3.0
|
|
1632 */
|
|
1633 private void uninstallVerifyKeyListener() {
|
|
1634 if (fVerifyKeyListenerHooked) {
|
|
1635 if (Helper.okToUse(fContentAssistSubjectControlAdapter.getControl()))
|
|
1636 fContentAssistSubjectControlAdapter.removeVerifyKeyListener(fInternalListener);
|
|
1637 fVerifyKeyListenerHooked= false;
|
|
1638 }
|
|
1639 }
|
|
1640
|
|
1641 /**
|
|
1642 * Returns the number of listeners.
|
|
1643 *
|
|
1644 * @return the number of listeners
|
|
1645 * @since 2.0
|
|
1646 */
|
|
1647 private int getNumberOfListeners() {
|
|
1648 int count= 0;
|
|
1649 for (int i= 0; i <= CONTEXT_INFO_POPUP; i++) {
|
|
1650 if (fListeners[i] !is null)
|
|
1651 ++count;
|
|
1652 }
|
|
1653 return count;
|
|
1654 }
|
|
1655
|
|
1656 /*
|
|
1657 * @see IContentAssist#showPossibleCompletions
|
|
1658 */
|
|
1659 public String showPossibleCompletions() {
|
|
1660 if (!prepareToShowCompletions(false))
|
|
1661 return null;
|
|
1662 if (fIsPrefixCompletionEnabled)
|
|
1663 return fProposalPopup.incrementalComplete();
|
|
1664 return fProposalPopup.showProposals(false);
|
|
1665 }
|
|
1666
|
|
1667 /*
|
|
1668 * @see dwtx.jface.text.contentassist.IContentAssistantExtension#completePrefix()
|
|
1669 * @since 3.0
|
|
1670 */
|
|
1671 public String completePrefix() {
|
|
1672 if (!prepareToShowCompletions(false))
|
|
1673 return null;
|
|
1674 return fProposalPopup.incrementalComplete();
|
|
1675 }
|
|
1676
|
|
1677 /**
|
|
1678 * Prepares to show content assist proposals. It returns false if auto activation has kicked in
|
|
1679 * recently.
|
|
1680 *
|
|
1681 * @param isAutoActivated whether completion was triggered by auto activation
|
|
1682 * @return <code>true</code> if the caller should continue and show the proposals,
|
|
1683 * <code>false</code> otherwise.
|
|
1684 * @since 3.2
|
|
1685 */
|
|
1686 private bool prepareToShowCompletions(bool isAutoActivated) {
|
|
1687 long current= System.currentTimeMillis();
|
|
1688 int gracePeriod= Math.max(fAutoActivationDelay, 200);
|
|
1689 if (current < fLastAutoActivation + gracePeriod)
|
|
1690 return false;
|
|
1691
|
|
1692 promoteKeyListener();
|
|
1693 fireSessionBeginEvent(isAutoActivated);
|
|
1694 return true;
|
|
1695 }
|
|
1696
|
|
1697 /**
|
|
1698 * Callback to signal this content assistant that the presentation of the possible completions
|
|
1699 * has been stopped.
|
|
1700 *
|
|
1701 * @since 2.1
|
|
1702 */
|
|
1703 protected void possibleCompletionsClosed() {
|
|
1704 fLastAutoActivation= Long.MIN_VALUE;
|
|
1705 storeCompletionProposalPopupSize();
|
|
1706 }
|
|
1707
|
|
1708 /*
|
|
1709 * @see IContentAssist#showContextInformation
|
|
1710 */
|
|
1711 public String showContextInformation() {
|
|
1712 promoteKeyListener();
|
|
1713 if (fContextInfoPopup !is null)
|
|
1714 return fContextInfoPopup.showContextProposals(false);
|
|
1715 return null;
|
|
1716 }
|
|
1717
|
|
1718 /**
|
|
1719 * Callback to signal this content assistant that the presentation of the context information
|
|
1720 * has been stopped.
|
|
1721 *
|
|
1722 * @since 2.1
|
|
1723 */
|
|
1724 protected void contextInformationClosed() {
|
|
1725 }
|
|
1726
|
|
1727 /**
|
|
1728 * Requests that the specified context information to be shown.
|
|
1729 *
|
|
1730 * @param contextInformation the context information to be shown
|
|
1731 * @param offset the offset to which the context information refers to
|
|
1732 * @since 2.0
|
|
1733 */
|
|
1734 void showContextInformation(IContextInformation contextInformation, int offset) {
|
|
1735 if (fContextInfoPopup !is null)
|
|
1736 fContextInfoPopup.showContextInformation(contextInformation, offset);
|
|
1737 }
|
|
1738
|
|
1739 /**
|
|
1740 * Returns the current content assist error message.
|
|
1741 *
|
|
1742 * @return an error message or <code>null</code> if no error has occurred
|
|
1743 */
|
|
1744 String getErrorMessage() {
|
|
1745 return fLastErrorMessage;
|
|
1746 }
|
|
1747
|
|
1748 /**
|
|
1749 * Returns the content assist processor for the content type of the specified document position.
|
|
1750 *
|
|
1751 * @param viewer the text viewer
|
|
1752 * @param offset a offset within the document
|
|
1753 * @return a content-assist processor or <code>null</code> if none exists
|
|
1754 * @since 3.0
|
|
1755 */
|
|
1756 private IContentAssistProcessor getProcessor(ITextViewer viewer, int offset) {
|
|
1757 try {
|
|
1758
|
|
1759 IDocument document= viewer.getDocument();
|
|
1760 String type= TextUtilities.getContentType(document, getDocumentPartitioning(), offset, true);
|
|
1761
|
|
1762 return getContentAssistProcessor(type);
|
|
1763
|
|
1764 } catch (BadLocationException x) {
|
|
1765 }
|
|
1766
|
|
1767 return null;
|
|
1768 }
|
|
1769
|
|
1770 /**
|
|
1771 * Returns the content assist processor for the content type of the specified document position.
|
|
1772 *
|
|
1773 * @param contentAssistSubjectControl the content assist subject control
|
|
1774 * @param offset a offset within the document
|
|
1775 * @return a content-assist processor or <code>null</code> if none exists
|
|
1776 * @since 3.0
|
|
1777 */
|
|
1778 private IContentAssistProcessor getProcessor(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1779 try {
|
|
1780
|
|
1781 IDocument document= contentAssistSubjectControl.getDocument();
|
|
1782 String type;
|
|
1783 if (document !is null)
|
|
1784 type= TextUtilities.getContentType(document, getDocumentPartitioning(), offset, true);
|
|
1785 else
|
|
1786 type= IDocument.DEFAULT_CONTENT_TYPE;
|
|
1787
|
|
1788 return getContentAssistProcessor(type);
|
|
1789
|
|
1790 } catch (BadLocationException x) {
|
|
1791 }
|
|
1792
|
|
1793 return null;
|
|
1794 }
|
|
1795
|
|
1796 /**
|
|
1797 * Returns an array of completion proposals computed based on the specified document position.
|
|
1798 * The position is used to determine the appropriate content assist processor to invoke.
|
|
1799 *
|
|
1800 * @param contentAssistSubjectControl the content assist subject control
|
|
1801 * @param offset a document offset
|
|
1802 * @return an array of completion proposals
|
|
1803 * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
|
|
1804 * @since 3.0
|
|
1805 */
|
|
1806 ICompletionProposal[] computeCompletionProposals(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1807 fLastErrorMessage= null;
|
|
1808
|
|
1809 ICompletionProposal[] result= null;
|
|
1810
|
|
1811 IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset);
|
|
1812 if (p instanceof ISubjectControlContentAssistProcessor) {
|
|
1813 result= ((ISubjectControlContentAssistProcessor) p).computeCompletionProposals(contentAssistSubjectControl, offset);
|
|
1814 fLastErrorMessage= p.getErrorMessage();
|
|
1815 }
|
|
1816
|
|
1817 return result;
|
|
1818 }
|
|
1819
|
|
1820 /**
|
|
1821 * Returns an array of completion proposals computed based on the specified document position.
|
|
1822 * The position is used to determine the appropriate content assist processor to invoke.
|
|
1823 *
|
|
1824 * @param viewer the viewer for which to compute the proposals
|
|
1825 * @param offset a document offset
|
|
1826 * @return an array of completion proposals or <code>null</code> if no proposals are possible
|
|
1827 * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
|
|
1828 */
|
|
1829 ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
|
|
1830 fLastErrorMessage= null;
|
|
1831
|
|
1832 ICompletionProposal[] result= null;
|
|
1833
|
|
1834 IContentAssistProcessor p= getProcessor(viewer, offset);
|
|
1835 if (p !is null) {
|
|
1836 result= p.computeCompletionProposals(viewer, offset);
|
|
1837 fLastErrorMessage= p.getErrorMessage();
|
|
1838 }
|
|
1839
|
|
1840 return result;
|
|
1841 }
|
|
1842
|
|
1843 /**
|
|
1844 * Returns an array of context information objects computed based on the specified document
|
|
1845 * position. The position is used to determine the appropriate content assist processor to
|
|
1846 * invoke.
|
|
1847 *
|
|
1848 * @param viewer the viewer for which to compute the context information
|
|
1849 * @param offset a document offset
|
|
1850 * @return an array of context information objects
|
|
1851 * @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
|
|
1852 */
|
|
1853 IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
|
|
1854 fLastErrorMessage= null;
|
|
1855
|
|
1856 IContextInformation[] result= null;
|
|
1857
|
|
1858 IContentAssistProcessor p= getProcessor(viewer, offset);
|
|
1859 if (p !is null) {
|
|
1860 result= p.computeContextInformation(viewer, offset);
|
|
1861 fLastErrorMessage= p.getErrorMessage();
|
|
1862 }
|
|
1863
|
|
1864 return result;
|
|
1865 }
|
|
1866
|
|
1867 /**
|
|
1868 * Returns an array of context information objects computed based on the specified document
|
|
1869 * position. The position is used to determine the appropriate content assist processor to
|
|
1870 * invoke.
|
|
1871 *
|
|
1872 * @param contentAssistSubjectControl the content assist subject control
|
|
1873 * @param offset a document offset
|
|
1874 * @return an array of context information objects
|
|
1875 * @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
|
|
1876 * @since 3.0
|
|
1877 */
|
|
1878 IContextInformation[] computeContextInformation(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1879 fLastErrorMessage= null;
|
|
1880
|
|
1881 IContextInformation[] result= null;
|
|
1882
|
|
1883 IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset);
|
|
1884 if (p instanceof ISubjectControlContentAssistProcessor) {
|
|
1885 result= ((ISubjectControlContentAssistProcessor) p).computeContextInformation(contentAssistSubjectControl, offset);
|
|
1886 fLastErrorMessage= p.getErrorMessage();
|
|
1887 }
|
|
1888
|
|
1889 return result;
|
|
1890 }
|
|
1891
|
|
1892 /**
|
|
1893 * Returns the context information validator that should be used to determine when the currently
|
|
1894 * displayed context information should be dismissed. The position is used to determine the
|
|
1895 * appropriate content assist processor to invoke.
|
|
1896 *
|
|
1897 * @param viewer the text viewer
|
|
1898 * @param offset a document offset
|
|
1899 * @return an validator
|
|
1900 * @see IContentAssistProcessor#getContextInformationValidator()
|
|
1901 * @since 3.0
|
|
1902 */
|
|
1903 IContextInformationValidator getContextInformationValidator(ITextViewer viewer, int offset) {
|
|
1904 IContentAssistProcessor p= getProcessor(viewer, offset);
|
|
1905 return p !is null ? p.getContextInformationValidator() : null;
|
|
1906 }
|
|
1907
|
|
1908 /**
|
|
1909 * Returns the context information validator that should be used to determine when the currently
|
|
1910 * displayed context information should be dismissed. The position is used to determine the
|
|
1911 * appropriate content assist processor to invoke.
|
|
1912 *
|
|
1913 * @param contentAssistSubjectControl the content assist subject control
|
|
1914 * @param offset a document offset
|
|
1915 * @return an validator
|
|
1916 * @see IContentAssistProcessor#getContextInformationValidator()
|
|
1917 * @since 3.0
|
|
1918 */
|
|
1919 IContextInformationValidator getContextInformationValidator(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1920 IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset);
|
|
1921 return p !is null ? p.getContextInformationValidator() : null;
|
|
1922 }
|
|
1923
|
|
1924 /**
|
|
1925 * Returns the context information presenter that should be used to display context information.
|
|
1926 * The position is used to determine the appropriate content assist processor to invoke.
|
|
1927 *
|
|
1928 * @param viewer the text viewer
|
|
1929 * @param offset a document offset
|
|
1930 * @return a presenter
|
|
1931 * @since 2.0
|
|
1932 */
|
|
1933 IContextInformationPresenter getContextInformationPresenter(ITextViewer viewer, int offset) {
|
|
1934 IContextInformationValidator validator= getContextInformationValidator(viewer, offset);
|
|
1935 if (validator instanceof IContextInformationPresenter)
|
|
1936 return (IContextInformationPresenter) validator;
|
|
1937 return null;
|
|
1938 }
|
|
1939
|
|
1940 /**
|
|
1941 * Returns the context information presenter that should be used to display context information.
|
|
1942 * The position is used to determine the appropriate content assist processor to invoke.
|
|
1943 *
|
|
1944 * @param contentAssistSubjectControl the content assist subject control
|
|
1945 * @param offset a document offset
|
|
1946 * @return a presenter
|
|
1947 * @since 3.0
|
|
1948 */
|
|
1949 IContextInformationPresenter getContextInformationPresenter(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1950 IContextInformationValidator validator= getContextInformationValidator(contentAssistSubjectControl, offset);
|
|
1951 if (validator instanceof IContextInformationPresenter)
|
|
1952 return (IContextInformationPresenter) validator;
|
|
1953 return null;
|
|
1954 }
|
|
1955
|
|
1956 /**
|
|
1957 * Returns the characters which when typed by the user should automatically initiate proposing
|
|
1958 * completions. The position is used to determine the appropriate content assist processor to
|
|
1959 * invoke.
|
|
1960 *
|
|
1961 * @param contentAssistSubjectControl the content assist subject control
|
|
1962 * @param offset a document offset
|
|
1963 * @return the auto activation characters
|
|
1964 * @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
|
|
1965 * @since 3.0
|
|
1966 */
|
|
1967 char[] getCompletionProposalAutoActivationCharacters(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
1968 IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset);
|
|
1969 return p !is null ? p.getCompletionProposalAutoActivationCharacters() : null;
|
|
1970 }
|
|
1971
|
|
1972 /**
|
|
1973 * Returns the characters which when typed by the user should automatically initiate proposing
|
|
1974 * completions. The position is used to determine the appropriate content assist processor to
|
|
1975 * invoke.
|
|
1976 *
|
|
1977 * @param viewer the text viewer
|
|
1978 * @param offset a document offset
|
|
1979 * @return the auto activation characters
|
|
1980 * @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
|
|
1981 */
|
|
1982 char[] getCompletionProposalAutoActivationCharacters(ITextViewer viewer, int offset) {
|
|
1983 IContentAssistProcessor p= getProcessor(viewer, offset);
|
|
1984 return p !is null ? p.getCompletionProposalAutoActivationCharacters() : null;
|
|
1985 }
|
|
1986
|
|
1987 /**
|
|
1988 * Returns the characters which when typed by the user should automatically initiate the
|
|
1989 * presentation of context information. The position is used to determine the appropriate
|
|
1990 * content assist processor to invoke.
|
|
1991 *
|
|
1992 * @param viewer the text viewer
|
|
1993 * @param offset a document offset
|
|
1994 * @return the auto activation characters
|
|
1995 * @see IContentAssistProcessor#getContextInformationAutoActivationCharacters()
|
|
1996 * @since 3.0
|
|
1997 */
|
|
1998 char[] getContextInformationAutoActivationCharacters(ITextViewer viewer, int offset) {
|
|
1999 IContentAssistProcessor p= getProcessor(viewer, offset);
|
|
2000 return p !is null ? p.getContextInformationAutoActivationCharacters() : null;
|
|
2001 }
|
|
2002
|
|
2003 /**
|
|
2004 * Returns the characters which when typed by the user should automatically initiate the
|
|
2005 * presentation of context information. The position is used to determine the appropriate
|
|
2006 * content assist processor to invoke.
|
|
2007 *
|
|
2008 * @param contentAssistSubjectControl the content assist subject control
|
|
2009 * @param offset a document offset
|
|
2010 * @return the auto activation characters
|
|
2011 * @see IContentAssistProcessor#getContextInformationAutoActivationCharacters()
|
|
2012 * @since 3.0
|
|
2013 */
|
|
2014 char[] getContextInformationAutoActivationCharacters(IContentAssistSubjectControl contentAssistSubjectControl, int offset) {
|
|
2015 IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset);
|
|
2016 return p !is null ? p.getContextInformationAutoActivationCharacters() : null;
|
|
2017 }
|
|
2018
|
|
2019 /*
|
|
2020 * @see dwtx.jface.text.IWidgetTokenKeeper#requestWidgetToken(IWidgetTokenOwner)
|
|
2021 * @since 2.0
|
|
2022 */
|
|
2023 public bool requestWidgetToken(IWidgetTokenOwner owner) {
|
|
2024 return false;
|
|
2025 }
|
|
2026
|
|
2027 /*
|
|
2028 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(dwtx.jface.text.IWidgetTokenOwner,
|
|
2029 * int)
|
|
2030 * @since 3.0
|
|
2031 */
|
|
2032 public bool requestWidgetToken(IWidgetTokenOwner owner, int priority) {
|
|
2033 if (priority > WIDGET_PRIORITY) {
|
|
2034 hide();
|
|
2035 return true;
|
|
2036 }
|
|
2037 return false;
|
|
2038 }
|
|
2039
|
|
2040 /*
|
|
2041 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#setFocus(dwtx.jface.text.IWidgetTokenOwner)
|
|
2042 * @since 3.0
|
|
2043 */
|
|
2044 public bool setFocus(IWidgetTokenOwner owner) {
|
|
2045 if (fProposalPopup !is null) {
|
|
2046 fProposalPopup.setFocus();
|
|
2047 return fProposalPopup.hasFocus();
|
|
2048 }
|
|
2049 return false;
|
|
2050 }
|
|
2051
|
|
2052 /**
|
|
2053 * Hides any open pop-ups.
|
|
2054 *
|
|
2055 * @since 3.0
|
|
2056 */
|
|
2057 protected void hide() {
|
|
2058 if (fProposalPopup !is null)
|
|
2059 fProposalPopup.hide();
|
|
2060
|
|
2061 if (fContextInfoPopup !is null)
|
|
2062 fContextInfoPopup.hide();
|
|
2063 }
|
|
2064
|
|
2065 // ------ control's size handling dialog settings ------
|
|
2066
|
|
2067 /**
|
|
2068 * Tells this information control manager to open the information control with the values
|
|
2069 * contained in the given dialog settings and to store the control's last valid size in the
|
|
2070 * given dialog settings.
|
|
2071 * <p>
|
|
2072 * Note: This API is only valid if the information control implements
|
|
2073 * {@link dwtx.jface.text.IInformationControlExtension3}. Not following this restriction
|
|
2074 * will later result in an {@link UnsupportedOperationException}.
|
|
2075 * </p>
|
|
2076 * <p>
|
|
2077 * The constants used to store the values are:
|
|
2078 * <ul>
|
|
2079 * <li>{@link ContentAssistant#STORE_SIZE_X}</li>
|
|
2080 * <li>{@link ContentAssistant#STORE_SIZE_Y}</li>
|
|
2081 * </ul>
|
|
2082 * </p>
|
|
2083 *
|
|
2084 * @param dialogSettings
|
|
2085 * @since 3.0
|
|
2086 */
|
|
2087 public void setRestoreCompletionProposalSize(IDialogSettings dialogSettings) {
|
|
2088 Assert.isTrue(dialogSettings !is null);
|
|
2089 fDialogSettings= dialogSettings;
|
|
2090 }
|
|
2091
|
|
2092 /**
|
|
2093 * Stores the content assist pop-up's size.
|
|
2094 */
|
|
2095 protected void storeCompletionProposalPopupSize() {
|
|
2096 if (fDialogSettings is null || fProposalPopup is null)
|
|
2097 return;
|
|
2098
|
|
2099 Point size= fProposalPopup.getSize();
|
|
2100 if (size is null)
|
|
2101 return;
|
|
2102
|
|
2103 fDialogSettings.put(STORE_SIZE_X, size.x);
|
|
2104 fDialogSettings.put(STORE_SIZE_Y, size.y);
|
|
2105 }
|
|
2106
|
|
2107 /**
|
|
2108 * Restores the content assist pop-up's size.
|
|
2109 *
|
|
2110 * @return the stored size
|
|
2111 * @since 3.0
|
|
2112 */
|
|
2113 protected Point restoreCompletionProposalPopupSize() {
|
|
2114 if (fDialogSettings is null)
|
|
2115 return null;
|
|
2116
|
|
2117 Point size= new Point(-1, -1);
|
|
2118
|
|
2119 try {
|
|
2120 size.x= fDialogSettings.getInt(STORE_SIZE_X);
|
|
2121 size.y= fDialogSettings.getInt(STORE_SIZE_Y);
|
|
2122 } catch (NumberFormatException ex) {
|
|
2123 size.x= -1;
|
|
2124 size.y= -1;
|
|
2125 }
|
|
2126
|
|
2127 // sanity check
|
|
2128 if (size.x is -1 && size.y is -1)
|
|
2129 return null;
|
|
2130
|
|
2131 Rectangle maxBounds= null;
|
|
2132 if (fContentAssistSubjectControl !is null && Helper.okToUse(fContentAssistSubjectControl.getControl()))
|
|
2133 maxBounds= fContentAssistSubjectControl.getControl().getDisplay().getBounds();
|
|
2134 else {
|
|
2135 // fallback
|
|
2136 Display display= Display.getCurrent();
|
|
2137 if (display is null)
|
|
2138 display= Display.getDefault();
|
|
2139 if (display !is null && !display.isDisposed())
|
|
2140 maxBounds= display.getBounds();
|
|
2141 }
|
|
2142
|
|
2143 if (size.x > -1 && size.y > -1) {
|
|
2144 if (maxBounds !is null) {
|
|
2145 size.x= Math.min(size.x, maxBounds.width);
|
|
2146 size.y= Math.min(size.y, maxBounds.height);
|
|
2147 }
|
|
2148
|
|
2149 // Enforce an absolute minimal size
|
|
2150 size.x= Math.max(size.x, 30);
|
|
2151 size.y= Math.max(size.y, 30);
|
|
2152 }
|
|
2153
|
|
2154 return size;
|
|
2155 }
|
|
2156
|
|
2157 /**
|
|
2158 * Sets the prefix completion property. If enabled, content assist delegates completion to
|
|
2159 * prefix completion.
|
|
2160 *
|
|
2161 * @param enabled <code>true</code> to enable prefix completion, <code>false</code> to
|
|
2162 * disable
|
|
2163 */
|
|
2164 public void enablePrefixCompletion(bool enabled) {
|
|
2165 fIsPrefixCompletionEnabled= enabled;
|
|
2166 }
|
|
2167
|
|
2168 /**
|
|
2169 * Returns the prefix completion state.
|
|
2170 *
|
|
2171 * @return <code>true</code> if prefix completion is enabled, <code>false</code> otherwise
|
|
2172 * @since 3.2
|
|
2173 */
|
|
2174 bool isPrefixCompletionEnabled() {
|
|
2175 return fIsPrefixCompletionEnabled;
|
|
2176 }
|
|
2177
|
|
2178 /**
|
|
2179 * Returns whether the content assistant proposal popup has the focus.
|
|
2180 *
|
|
2181 * @return <code>true</code> if the proposal popup has the focus
|
|
2182 * @since 3.0
|
|
2183 */
|
|
2184 public bool hasProposalPopupFocus() {
|
|
2185 return fProposalPopup.hasFocus();
|
|
2186 }
|
|
2187
|
|
2188 /*
|
|
2189 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#addCompletionListener(dwtx.jface.text.contentassist.ICompletionListener)
|
|
2190 * @since 3.2
|
|
2191 */
|
|
2192 public void addCompletionListener(ICompletionListener listener) {
|
|
2193 Assert.isLegal(listener !is null);
|
|
2194 fCompletionListeners.add(listener);
|
|
2195 }
|
|
2196
|
|
2197 /*
|
|
2198 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#removeCompletionListener(dwtx.jface.text.contentassist.ICompletionListener)
|
|
2199 * @since 3.2
|
|
2200 */
|
|
2201 public void removeCompletionListener(ICompletionListener listener) {
|
|
2202 fCompletionListeners.remove(listener);
|
|
2203 }
|
|
2204
|
|
2205 /**
|
|
2206 * Fires a session begin event to all registered {@link ICompletionListener}s.
|
|
2207 *
|
|
2208 * @param isAutoActivated <code>true</code> if this session was triggered by auto activation
|
|
2209 * @since 3.2
|
|
2210 */
|
|
2211 void fireSessionBeginEvent(bool isAutoActivated) {
|
|
2212 if (fContentAssistSubjectControlAdapter !is null && !isProposalPopupActive()) {
|
|
2213 IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x);
|
|
2214 ContentAssistEvent event= new ContentAssistEvent(this, processor, isAutoActivated);
|
|
2215 Object[] listeners= fCompletionListeners.getListeners();
|
|
2216 for (int i= 0; i < listeners.length; i++) {
|
|
2217 ICompletionListener listener= (ICompletionListener)listeners[i];
|
|
2218 listener.assistSessionStarted(event);
|
|
2219 }
|
|
2220 }
|
|
2221 }
|
|
2222
|
|
2223 /**
|
|
2224 * Fires a session restart event to all registered {@link ICompletionListener}s.
|
|
2225 *
|
|
2226 * @since 3.4
|
|
2227 */
|
|
2228 void fireSessionRestartEvent() {
|
|
2229 if (fContentAssistSubjectControlAdapter !is null) {
|
|
2230 IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x);
|
|
2231 ContentAssistEvent event= new ContentAssistEvent(this, processor);
|
|
2232 Object[] listeners= fCompletionListeners.getListeners();
|
|
2233 for (int i= 0; i < listeners.length; i++) {
|
|
2234 ICompletionListener listener= (ICompletionListener)listeners[i];
|
|
2235 if (listener instanceof ICompletionListenerExtension)
|
|
2236 ((ICompletionListenerExtension)listener).assistSessionRestarted(event);
|
|
2237 }
|
|
2238 }
|
|
2239 }
|
|
2240
|
|
2241 /**
|
|
2242 * Fires a session end event to all registered {@link ICompletionListener}s.
|
|
2243 *
|
|
2244 * @since 3.2
|
|
2245 */
|
|
2246 void fireSessionEndEvent() {
|
|
2247 if (fContentAssistSubjectControlAdapter !is null) {
|
|
2248 IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x);
|
|
2249 ContentAssistEvent event= new ContentAssistEvent(this, processor);
|
|
2250 Object[] listeners= fCompletionListeners.getListeners();
|
|
2251 for (int i= 0; i < listeners.length; i++) {
|
|
2252 ICompletionListener listener= (ICompletionListener)listeners[i];
|
|
2253 listener.assistSessionEnded(event);
|
|
2254 }
|
|
2255 }
|
|
2256 }
|
|
2257
|
|
2258 /*
|
|
2259 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#setRepeatedInvocationMode(bool)
|
|
2260 * @since 3.2
|
|
2261 */
|
|
2262 public void setRepeatedInvocationMode(bool cycling) {
|
|
2263 fIsRepetitionMode= cycling;
|
|
2264 }
|
|
2265
|
|
2266 /**
|
|
2267 * Returns <code>true</code> if repeated invocation mode is enabled, <code>false</code>
|
|
2268 * otherwise.
|
|
2269 *
|
|
2270 * @return <code>true</code> if repeated invocation mode is enabled, <code>false</code>
|
|
2271 * otherwise
|
|
2272 * @since 3.2
|
|
2273 */
|
|
2274 bool isRepeatedInvocationMode() {
|
|
2275 return fIsRepetitionMode;
|
|
2276 }
|
|
2277
|
|
2278 /*
|
|
2279 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#setShowEmptyList(bool)
|
|
2280 * @since 3.2
|
|
2281 */
|
|
2282 public void setShowEmptyList(bool showEmpty) {
|
|
2283 fShowEmptyList= showEmpty;
|
|
2284 }
|
|
2285
|
|
2286 /**
|
|
2287 * Returns <code>true</code> if empty lists should be displayed, <code>false</code>
|
|
2288 * otherwise.
|
|
2289 *
|
|
2290 * @return <code>true</code> if empty lists should be displayed, <code>false</code>
|
|
2291 * otherwise
|
|
2292 * @since 3.2
|
|
2293 */
|
|
2294 bool isShowEmptyList() {
|
|
2295 return fShowEmptyList;
|
|
2296 }
|
|
2297
|
|
2298 /*
|
|
2299 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#setStatusLineVisible(bool)
|
|
2300 * @since 3.2
|
|
2301 */
|
|
2302 public void setStatusLineVisible(bool show) {
|
|
2303 fIsStatusLineVisible= show;
|
|
2304 if (fProposalPopup !is null)
|
|
2305 fProposalPopup.setStatusLineVisible(show);
|
|
2306 }
|
|
2307
|
|
2308 /**
|
|
2309 * Returns <code>true</code> if a message line should be displayed, <code>false</code>
|
|
2310 * otherwise.
|
|
2311 *
|
|
2312 * @return <code>true</code> if a message line should be displayed, <code>false</code>
|
|
2313 * otherwise
|
|
2314 * @since 3.2
|
|
2315 */
|
|
2316 bool isStatusLineVisible() {
|
|
2317 return fIsStatusLineVisible;
|
|
2318 }
|
|
2319
|
|
2320 /*
|
|
2321 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#setStatusMessage(java.lang.String)
|
|
2322 * @since 3.2
|
|
2323 */
|
|
2324 public void setStatusMessage(String message) {
|
|
2325 Assert.isLegal(message !is null);
|
|
2326 fMessage= message;
|
|
2327 if (fProposalPopup !is null)
|
|
2328 fProposalPopup.setMessage(message);
|
|
2329 }
|
|
2330
|
|
2331 /**
|
|
2332 * Returns the affordance caption for the cycling affordance at the bottom of the pop-up.
|
|
2333 *
|
|
2334 * @return the affordance caption for the cycling affordance at the bottom of the pop-up
|
|
2335 * @since 3.2
|
|
2336 */
|
|
2337 String getStatusMessage() {
|
|
2338 return fMessage;
|
|
2339 }
|
|
2340
|
|
2341 /*
|
|
2342 * @see dwtx.jface.text.contentassist.IContentAssistantExtension2#setEmptyMessage(java.lang.String)
|
|
2343 * @since 3.2
|
|
2344 */
|
|
2345 public void setEmptyMessage(String message) {
|
|
2346 Assert.isLegal(message !is null);
|
|
2347 if (fProposalPopup !is null)
|
|
2348 fProposalPopup.setEmptyMessage(message);
|
|
2349 }
|
|
2350
|
|
2351 /**
|
|
2352 * Fires a selection event, see {@link ICompletionListener}.
|
|
2353 *
|
|
2354 * @param proposal the selected proposal, possibly <code>null</code>
|
|
2355 * @param smartToggle true if the smart toggle is on
|
|
2356 * @since 3.2
|
|
2357 */
|
|
2358 void fireSelectionEvent(ICompletionProposal proposal, bool smartToggle) {
|
|
2359 Object[] listeners= fCompletionListeners.getListeners();
|
|
2360 for (int i= 0; i < listeners.length; i++) {
|
|
2361 ICompletionListener listener= (ICompletionListener)listeners[i];
|
|
2362 listener.selectionChanged(proposal, smartToggle);
|
|
2363 }
|
|
2364 }
|
|
2365
|
|
2366 /*
|
|
2367 * @see dwtx.jface.text.contentassist.IContentAssistantExtension3#setInvocationTrigger(dwtx.jface.bindings.keys.KeySequence)
|
|
2368 * @since 3.2
|
|
2369 */
|
|
2370 public void setRepeatedInvocationTrigger(KeySequence sequence) {
|
|
2371 fRepeatedInvocationKeySequence= sequence;
|
|
2372 }
|
|
2373
|
|
2374 /**
|
|
2375 * Returns the repeated invocation key sequence.
|
|
2376 *
|
|
2377 * @return the repeated invocation key sequence or <code>null</code>, if none
|
|
2378 * @since 3.2
|
|
2379 */
|
|
2380 KeySequence getRepeatedInvocationKeySequence() {
|
|
2381 return fRepeatedInvocationKeySequence;
|
|
2382 }
|
|
2383
|
|
2384 /**
|
|
2385 * Returns whether proposal popup is active.
|
|
2386 *
|
|
2387 * @return <code>true</code> if the proposal popup is active, <code>false</code> otherwise
|
|
2388 * @since 3.4
|
|
2389 */
|
|
2390 protected bool isProposalPopupActive(){
|
|
2391 return fProposalPopup !is null && fProposalPopup.isActive();
|
|
2392 }
|
|
2393
|
|
2394 /**
|
|
2395 * Returns whether the context information popup is active.
|
|
2396 *
|
|
2397 * @return <code>true</code> if the context information popup is active, <code>false</code> otherwise
|
|
2398 * @since 3.4
|
|
2399 */
|
|
2400 protected bool isContextInfoPopupActive(){
|
|
2401 return fContextInfoPopup !is null && fContextInfoPopup.isActive();
|
|
2402 }
|
|
2403
|
|
2404 /**
|
|
2405 * {@inheritDoc}
|
|
2406 *
|
|
2407 * @since 3.4
|
|
2408 */
|
|
2409 public final IHandler getHandler(String commandId) {
|
|
2410 if (fHandlers is null)
|
|
2411 throw new IllegalStateException();
|
|
2412
|
|
2413 IHandler handler= (IHandler)fHandlers.get(commandId);
|
|
2414 if (handler !is null)
|
|
2415 return handler;
|
|
2416
|
|
2417 Assert.isLegal(false);
|
|
2418 return null;
|
|
2419 }
|
|
2420
|
|
2421 /**
|
|
2422 * Registers the given handler under the given command identifier.
|
|
2423 *
|
|
2424 * @param commandId the command identifier
|
|
2425 * @param handler the handler
|
|
2426 * @since 3.4
|
|
2427 */
|
|
2428 protected final void registerHandler(String commandId, IHandler handler) {
|
|
2429 if (fHandlers is null)
|
|
2430 fHandlers= new HashMap(2);
|
|
2431 fHandlers.put(commandId, handler);
|
|
2432 }
|
|
2433
|
|
2434 /**
|
|
2435 * Tells whether the support for colored labels is enabled.
|
|
2436 *
|
|
2437 * @return <code>true</code> if the support for colored labels is enabled, <code>false</code> otherwise
|
|
2438 * @since 3.4
|
|
2439 */
|
|
2440 bool isColoredLabelsSupportEnabled() {
|
|
2441 return fIsColoredLabelsSupportEnabled;
|
|
2442 }
|
|
2443
|
|
2444 /**
|
|
2445 * Enables the support for colored labels in the proposal popup.
|
|
2446 * <p>Completion proposals can implement {@link ICompletionProposalExtension6}
|
|
2447 * to provide colored proposal labels.</p>
|
|
2448 *
|
|
2449 * @param isEnabled if <code>true</code> the support for colored labels is enabled in the proposal popup
|
|
2450 * @since 3.4
|
|
2451 */
|
|
2452 public void enableColoredLabels(bool isEnabled) {
|
|
2453 fIsColoredLabelsSupportEnabled= isEnabled;
|
|
2454 }
|
|
2455
|
|
2456 }
|