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