1 11 package org.eclipse.jdt.internal.ui.text.java; 12 13 import java.util.ArrayList ; 14 import java.util.Collections ; 15 import java.util.Comparator ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 19 import org.eclipse.core.runtime.Assert; 20 import org.eclipse.core.runtime.IProgressMonitor; 21 import org.eclipse.core.runtime.NullProgressMonitor; 22 import org.eclipse.core.runtime.Platform; 23 import org.eclipse.core.runtime.SubProgressMonitor; 24 25 import org.eclipse.swt.SWT; 26 import org.eclipse.swt.events.SelectionAdapter; 27 import org.eclipse.swt.events.SelectionEvent; 28 import org.eclipse.swt.layout.GridData; 29 import org.eclipse.swt.layout.GridLayout; 30 import org.eclipse.swt.widgets.Button; 31 import org.eclipse.swt.widgets.Composite; 32 import org.eclipse.swt.widgets.Control; 33 import org.eclipse.swt.widgets.Link; 34 import org.eclipse.swt.widgets.Shell; 35 36 import org.eclipse.jface.action.LegacyActionTools; 37 import org.eclipse.jface.bindings.TriggerSequence; 38 import org.eclipse.jface.bindings.keys.KeySequence; 39 import org.eclipse.jface.dialogs.IDialogConstants; 40 import org.eclipse.jface.dialogs.MessageDialog; 41 import org.eclipse.jface.preference.IPreferenceStore; 42 import org.eclipse.jface.resource.JFaceResources; 43 44 import org.eclipse.jface.text.IDocument; 45 import org.eclipse.jface.text.ITextViewer; 46 import org.eclipse.jface.text.contentassist.ContentAssistEvent; 47 import org.eclipse.jface.text.contentassist.ContentAssistant; 48 import org.eclipse.jface.text.contentassist.ICompletionListener; 49 import org.eclipse.jface.text.contentassist.ICompletionProposal; 50 import org.eclipse.jface.text.contentassist.IContentAssistProcessor; 51 import org.eclipse.jface.text.contentassist.IContentAssistantExtension2; 52 import org.eclipse.jface.text.contentassist.IContentAssistantExtension3; 53 import org.eclipse.jface.text.contentassist.IContextInformation; 54 import org.eclipse.jface.text.contentassist.IContextInformationValidator; 55 56 import org.eclipse.ui.PlatformUI; 57 import org.eclipse.ui.dialogs.PreferencesUtil; 58 import org.eclipse.ui.keys.IBindingService; 59 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; 60 61 import org.eclipse.jdt.internal.corext.util.Messages; 62 63 import org.eclipse.jdt.ui.PreferenceConstants; 64 import org.eclipse.jdt.ui.text.IJavaPartitions; 65 import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; 66 67 import org.eclipse.jdt.internal.ui.JavaPlugin; 68 import org.eclipse.jdt.internal.ui.JavaUIMessages; 69 import org.eclipse.jdt.internal.ui.dialogs.OptionalMessageDialog; 70 71 89 public class ContentAssistProcessor implements IContentAssistProcessor { 90 private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jdt.ui/debug/ResultCollector")); 92 98 private static final String PREF_WARN_ABOUT_EMPTY_ASSIST_CATEGORY= "EmptyDefaultAssistCategory"; 100 private static final Comparator ORDER_COMPARATOR= new Comparator () { 101 102 public int compare(Object o1, Object o2) { 103 CompletionProposalCategory d1= (CompletionProposalCategory) o1; 104 CompletionProposalCategory d2= (CompletionProposalCategory) o2; 105 106 return d1.getSortOrder() - d2.getSortOrder(); 107 } 108 109 }; 110 111 private final List fCategories; 112 private final String fPartition; 113 private final ContentAssistant fAssistant; 114 115 private char[] fCompletionAutoActivationCharacters; 116 117 118 private int fRepetition= -1; 119 private List fCategoryIteration= null; 120 private String fIterationGesture= null; 121 private int fNumberOfComputedResults= 0; 122 private String fErrorMessage; 123 124 public ContentAssistProcessor(ContentAssistant assistant, String partition) { 125 Assert.isNotNull(partition); 126 Assert.isNotNull(assistant); 127 fPartition= partition; 128 fCategories= CompletionProposalComputerRegistry.getDefault().getProposalCategories(); 129 fAssistant= assistant; 130 fAssistant.addCompletionListener(new ICompletionListener() { 131 132 135 public void assistSessionStarted(ContentAssistEvent event) { 136 if (event.processor != ContentAssistProcessor.this) 137 return; 138 139 fIterationGesture= getIterationGesture(); 140 KeySequence binding= getIterationBinding(); 141 142 fCategoryIteration= getCategoryIteration(); 144 for (Iterator it= fCategories.iterator(); it.hasNext();) { 145 CompletionProposalCategory cat= (CompletionProposalCategory) it.next(); 146 cat.sessionStarted(); 147 } 148 149 fRepetition= 0; 150 if (event.assistant instanceof IContentAssistantExtension2) { 151 IContentAssistantExtension2 extension= (IContentAssistantExtension2) event.assistant; 152 153 if (fCategoryIteration.size() == 1) { 154 extension.setRepeatedInvocationMode(false); 155 extension.setShowEmptyList(false); 156 } else { 157 extension.setRepeatedInvocationMode(true); 158 extension.setStatusLineVisible(true); 159 extension.setStatusMessage(createIterationMessage()); 160 extension.setShowEmptyList(true); 161 if (extension instanceof IContentAssistantExtension3) { 162 IContentAssistantExtension3 ext3= (IContentAssistantExtension3) extension; 163 ((ContentAssistant) ext3).setRepeatedInvocationTrigger(binding); 164 } 165 } 166 167 } 168 } 169 170 173 public void assistSessionEnded(ContentAssistEvent event) { 174 if (event.processor != ContentAssistProcessor.this) 175 return; 176 177 for (Iterator it= fCategories.iterator(); it.hasNext();) { 178 CompletionProposalCategory cat= (CompletionProposalCategory) it.next(); 179 cat.sessionEnded(); 180 } 181 182 fCategoryIteration= null; 183 fRepetition= -1; 184 fIterationGesture= null; 185 if (event.assistant instanceof IContentAssistantExtension2) { 186 IContentAssistantExtension2 extension= (IContentAssistantExtension2) event.assistant; 187 extension.setShowEmptyList(false); 188 extension.setRepeatedInvocationMode(false); 189 extension.setStatusLineVisible(false); 190 if (extension instanceof IContentAssistantExtension3) { 191 IContentAssistantExtension3 ext3= (IContentAssistantExtension3) extension; 192 ((ContentAssistant) ext3).setRepeatedInvocationTrigger(null); 193 } 194 } 195 } 196 197 200 public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {} 201 202 }); 203 } 204 205 208 public final ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { 209 long start= DEBUG ? System.currentTimeMillis() : 0; 210 211 clearState(); 212 213 IProgressMonitor monitor= createProgressMonitor(); 214 monitor.beginTask(JavaTextMessages.ContentAssistProcessor_computing_proposals, fCategories.size() + 1); 215 216 ContentAssistInvocationContext context= createContext(viewer, offset); 217 long setup= DEBUG ? System.currentTimeMillis() : 0; 218 219 monitor.subTask(JavaTextMessages.ContentAssistProcessor_collecting_proposals); 220 List proposals= collectProposals(viewer, offset, monitor, context); 221 long collect= DEBUG ? System.currentTimeMillis() : 0; 222 223 monitor.subTask(JavaTextMessages.ContentAssistProcessor_sorting_proposals); 224 List filtered= filterAndSortProposals(proposals, monitor, context); 225 fNumberOfComputedResults= filtered.size(); 226 long filter= DEBUG ? System.currentTimeMillis() : 0; 227 228 ICompletionProposal[] result= (ICompletionProposal[]) filtered.toArray(new ICompletionProposal[filtered.size()]); 229 monitor.done(); 230 231 if (DEBUG) { 232 System.err.println("Code Assist Stats (" + result.length + " proposals)"); System.err.println("Code Assist (setup):\t" + (setup - start) ); System.err.println("Code Assist (collect):\t" + (collect - setup) ); System.err.println("Code Assist (sort):\t" + (filter - collect) ); } 237 238 return result; 239 } 240 241 private void clearState() { 242 fErrorMessage=null; 243 fNumberOfComputedResults= 0; 244 } 245 246 private List collectProposals(ITextViewer viewer, int offset, IProgressMonitor monitor, ContentAssistInvocationContext context) { 247 List proposals= new ArrayList (); 248 List providers= getCategories(); 249 for (Iterator it= providers.iterator(); it.hasNext();) { 250 CompletionProposalCategory cat= (CompletionProposalCategory) it.next(); 251 List computed= cat.computeCompletionProposals(context, fPartition, new SubProgressMonitor(monitor, 1)); 252 proposals.addAll(computed); 253 if (fErrorMessage == null) 254 fErrorMessage= cat.getErrorMessage(); 255 } 256 257 return proposals; 258 } 259 260 271 protected List filterAndSortProposals(List proposals, IProgressMonitor monitor, ContentAssistInvocationContext context) { 272 return proposals; 273 } 274 275 278 public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { 279 clearState(); 280 281 IProgressMonitor monitor= createProgressMonitor(); 282 monitor.beginTask(JavaTextMessages.ContentAssistProcessor_computing_contexts, fCategories.size() + 1); 283 284 monitor.subTask(JavaTextMessages.ContentAssistProcessor_collecting_contexts); 285 List proposals= collectContextInformation(viewer, offset, monitor); 286 287 monitor.subTask(JavaTextMessages.ContentAssistProcessor_sorting_contexts); 288 List filtered= filterAndSortContextInformation(proposals, monitor); 289 fNumberOfComputedResults= filtered.size(); 290 291 IContextInformation[] result= (IContextInformation[]) filtered.toArray(new IContextInformation[filtered.size()]); 292 monitor.done(); 293 return result; 294 } 295 296 private List collectContextInformation(ITextViewer viewer, int offset, IProgressMonitor monitor) { 297 List proposals= new ArrayList (); 298 ContentAssistInvocationContext context= createContext(viewer, offset); 299 300 List providers= getCategories(); 301 for (Iterator it= providers.iterator(); it.hasNext();) { 302 CompletionProposalCategory cat= (CompletionProposalCategory) it.next(); 303 List computed= cat.computeContextInformation(context, fPartition, new SubProgressMonitor(monitor, 1)); 304 proposals.addAll(computed); 305 if (fErrorMessage == null) 306 fErrorMessage= cat.getErrorMessage(); 307 } 308 309 return proposals; 310 } 311 312 323 protected List filterAndSortContextInformation(List contexts, IProgressMonitor monitor) { 324 return contexts; 325 } 326 327 333 public final void setCompletionProposalAutoActivationCharacters(char[] activationSet) { 334 fCompletionAutoActivationCharacters= activationSet; 335 } 336 337 338 341 public final char[] getCompletionProposalAutoActivationCharacters() { 342 return fCompletionAutoActivationCharacters; 343 } 344 345 348 public char[] getContextInformationAutoActivationCharacters() { 349 return null; 350 } 351 352 355 public String getErrorMessage() { 356 if (fNumberOfComputedResults > 0) 357 return null; 358 if (fErrorMessage != null) 359 return fErrorMessage; 360 return JavaUIMessages.JavaEditor_codeassist_noCompletions; 361 } 362 363 366 public IContextInformationValidator getContextInformationValidator() { 367 return null; 368 } 369 370 379 protected IProgressMonitor createProgressMonitor() { 380 return new NullProgressMonitor(); 381 } 382 383 391 protected ContentAssistInvocationContext createContext(ITextViewer viewer, int offset) { 392 return new ContentAssistInvocationContext(viewer, offset); 393 } 394 395 private List getCategories() { 396 if (fCategoryIteration == null) 397 return fCategories; 398 399 int iteration= fRepetition % fCategoryIteration.size(); 400 fAssistant.setStatusMessage(createIterationMessage()); 401 fAssistant.setEmptyMessage(createEmptyMessage()); 402 fRepetition++; 403 404 return (List ) fCategoryIteration.get(iteration); 407 } 408 409 private List getCategoryIteration() { 410 List sequence= new ArrayList (); 411 sequence.add(getDefaultCategories()); 412 for (Iterator it= getSeparateCategories().iterator(); it.hasNext();) { 413 CompletionProposalCategory cat= (CompletionProposalCategory) it.next(); 414 sequence.add(Collections.singletonList(cat)); 415 } 416 return sequence; 417 } 418 419 private List getDefaultCategories() { 420 List included= getDefaultCategoriesUnchecked(); 422 423 if ((IJavaPartitions.JAVA_DOC.equals(fPartition) || IDocument.DEFAULT_CONTENT_TYPE.equals(fPartition)) && included.isEmpty() && !fCategories.isEmpty()) 424 if (informUserAboutEmptyDefaultCategory()) 425 included= getDefaultCategoriesUnchecked(); 427 428 return included; 429 } 430 431 private List getDefaultCategoriesUnchecked() { 432 List included= new ArrayList (); 433 for (Iterator it= fCategories.iterator(); it.hasNext();) { 434 CompletionProposalCategory category= (CompletionProposalCategory) it.next(); 435 if (category.isIncluded() && category.hasComputers(fPartition)) 436 included.add(category); 437 } 438 return included; 439 } 440 441 447 private boolean informUserAboutEmptyDefaultCategory() { 448 if (OptionalMessageDialog.isDialogEnabled(PREF_WARN_ABOUT_EMPTY_ASSIST_CATEGORY)) { 449 final Shell shell= JavaPlugin.getActiveWorkbenchShell(); 450 String title= JavaTextMessages.ContentAssistProcessor_all_disabled_title; 451 String message= JavaTextMessages.ContentAssistProcessor_all_disabled_message; 452 final String restoreButtonLabel= JFaceResources.getString("defaults"); final String linkMessage= Messages.format(JavaTextMessages.ContentAssistProcessor_all_disabled_preference_link, LegacyActionTools.removeMnemonics(restoreButtonLabel)); 455 final int restoreId= IDialogConstants.CLIENT_ID + 10; 456 final int settingsId= IDialogConstants.CLIENT_ID + 11; 457 final OptionalMessageDialog dialog= new OptionalMessageDialog(PREF_WARN_ABOUT_EMPTY_ASSIST_CATEGORY, shell, title, null , message, MessageDialog.WARNING, new String [] { restoreButtonLabel, IDialogConstants.CLOSE_LABEL }, 1) { 458 461 protected Control createCustomArea(Composite composite) { 462 Composite parent= new Composite(composite, SWT.NONE); 464 GridLayout layout= new GridLayout(); 465 layout.marginHeight= 0; 466 layout.marginWidth= 0; 467 layout.verticalSpacing= 0; 468 parent.setLayout(layout); 469 470 Composite linkComposite= new Composite(parent, SWT.NONE); 471 layout= new GridLayout(); 472 layout.marginHeight= convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); 473 layout.marginWidth= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); 474 layout.horizontalSpacing= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); 475 linkComposite.setLayout(layout); 476 477 Link link= new Link(linkComposite, SWT.NONE); 478 link.setText(linkMessage); 479 link.addSelectionListener(new SelectionAdapter() { 480 public void widgetSelected(SelectionEvent e) { 481 setReturnCode(settingsId); 482 close(); 483 } 484 }); 485 GridData gridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false); 486 gridData.widthHint= this.getMinimumMessageWidth(); 487 link.setLayoutData(gridData); 488 489 super.createCustomArea(parent); 491 492 return parent; 493 } 494 495 498 protected void createButtonsForButtonBar(Composite parent) { 499 Button[] buttons= new Button[2]; 500 buttons[0]= createButton(parent, restoreId, restoreButtonLabel, false); 501 buttons[1]= createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, true); 502 setButtons(buttons); 503 } 504 }; 505 int returnValue= dialog.open(); 506 if (restoreId == returnValue || settingsId == returnValue) { 507 if (restoreId == returnValue) { 508 IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); 509 store.setToDefault(PreferenceConstants.CODEASSIST_CATEGORY_ORDER); 510 store.setToDefault(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES); 511 } 512 if (settingsId == returnValue) 513 PreferencesUtil.createPreferenceDialogOn(shell, "org.eclipse.jdt.ui.preferences.CodeAssistPreferenceAdvanced", null, null).open(); CompletionProposalComputerRegistry registry= CompletionProposalComputerRegistry.getDefault(); 515 registry.reload(); 516 return true; 517 } 518 } 519 return false; 520 } 521 522 private List getSeparateCategories() { 523 ArrayList sorted= new ArrayList (); 524 for (Iterator it= fCategories.iterator(); it.hasNext();) { 525 CompletionProposalCategory category= (CompletionProposalCategory) it.next(); 526 if (category.isSeparateCommand() && category.hasComputers(fPartition)) 527 sorted.add(category); 528 } 529 Collections.sort(sorted, ORDER_COMPARATOR); 530 return sorted; 531 } 532 533 private String createEmptyMessage() { 534 return Messages.format(JavaTextMessages.ContentAssistProcessor_empty_message, new String []{getCategoryLabel(fRepetition)}); 535 } 536 537 private String createIterationMessage() { 538 return Messages.format(JavaTextMessages.ContentAssistProcessor_toggle_affordance_update_message, new String []{ getCategoryLabel(fRepetition), fIterationGesture, getCategoryLabel(fRepetition + 1) }); 539 } 540 541 private String getCategoryLabel(int repetition) { 542 int iteration= repetition % fCategoryIteration.size(); 543 if (iteration == 0) 544 return JavaTextMessages.ContentAssistProcessor_defaultProposalCategory; 545 return toString((CompletionProposalCategory) ((List ) fCategoryIteration.get(iteration)).get(0)); 546 } 547 548 private String toString(CompletionProposalCategory category) { 549 return category.getDisplayName(); 550 } 551 552 private String getIterationGesture() { 553 TriggerSequence binding= getIterationBinding(); 554 return binding != null ? 555 Messages.format(JavaTextMessages.ContentAssistProcessor_toggle_affordance_press_gesture, new Object [] { binding.format() }) 556 : JavaTextMessages.ContentAssistProcessor_toggle_affordance_click_gesture; 557 } 558 559 private KeySequence getIterationBinding() { 560 final IBindingService bindingSvc= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); 561 TriggerSequence binding= bindingSvc.getBestActiveBindingFor(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); 562 if (binding instanceof KeySequence) 563 return (KeySequence) binding; 564 return null; 565 } 566 } 567 | Popular Tags |