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