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