| /******************************************************************************* |
| * Copyright (c) 2011, 2012 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 |
| * which accompanies this distribution. |
| * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html |
| * and the Eclipse Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * Contributors: |
| * Oracle - initial API and implementation |
| * |
| ******************************************************************************/ |
| package org.eclipse.jpt.jpa.ui.internal.jpql; |
| |
| import java.text.MessageFormat; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.ResourceBundle; |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.IHandler; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.expressions.EvaluationResult; |
| import org.eclipse.core.expressions.Expression; |
| import org.eclipse.core.expressions.ExpressionInfo; |
| import org.eclipse.core.expressions.IEvaluationContext; |
| import org.eclipse.jface.bindings.Binding; |
| import org.eclipse.jface.bindings.Trigger; |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.jface.bindings.keys.SWTKeySupport; |
| import org.eclipse.jface.fieldassist.ControlDecoration; |
| import org.eclipse.jface.fieldassist.FieldDecorationRegistry; |
| import org.eclipse.jface.internal.text.html.HTMLTextPresenter; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.DefaultInformationControl; |
| import org.eclipse.jface.text.DefaultTextHover; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.DocumentEvent; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.IInformationControl; |
| import org.eclipse.jface.text.IInformationControlCreator; |
| import org.eclipse.jface.text.ITextHover; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.contentassist.ContentAssistant; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.jface.text.contentassist.IContentAssistant; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jface.text.contentassist.IContextInformationValidator; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.AnnotationModel; |
| import org.eclipse.jface.text.source.DefaultAnnotationHover; |
| import org.eclipse.jface.text.source.IAnnotationHover; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.jface.text.source.SourceViewerConfiguration; |
| import org.eclipse.jpt.common.ui.internal.listeners.SWTPropertyChangeListenerWrapper; |
| import org.eclipse.jpt.common.utility.internal.StringTools; |
| import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent; |
| import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener; |
| import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; |
| import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; |
| import org.eclipse.jpt.jpa.core.JptJpaCorePlugin; |
| import org.eclipse.jpt.jpa.core.context.NamedQuery; |
| import org.eclipse.jpt.jpa.ui.internal.JptUiMessages; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.persistence.jpa.jpql.JPQLQueryProblem; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.ISources; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.editors.text.EditorsUI; |
| import org.eclipse.ui.handlers.IHandlerActivation; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.internal.editors.text.EditorsPlugin; |
| import org.eclipse.ui.keys.IBindingService; |
| import org.eclipse.ui.swt.IFocusService; |
| import org.eclipse.ui.texteditor.AnnotationPreference; |
| import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; |
| |
| /** |
| * This provider installs content assist support on a {@link StyledText} widget in order to give |
| * choices at any given position within a JPQL query. |
| * <p> |
| * TODO. Add syntax highlight for the JPQL identifiers. |
| * |
| * @version 3.2 |
| * @since 3.0 |
| * @author Pascal Filion |
| */ |
| @SuppressWarnings({"nls", "restriction"}) |
| public final class JpaJpqlContentProposalProvider extends JpqlCompletionProposalComputer<ICompletionProposal> { |
| |
| /** |
| * This model holds onto the {@link Annotation annotations} that have been created for each |
| * {@link JPQLQueryProblem} |
| */ |
| private AnnotationModel annotationModel; |
| |
| /** |
| * The decoration support required to paint the {@link Annotation annotations}, which are the |
| * JPQL problems. |
| */ |
| private SourceViewerDecorationSupport decorationSupport; |
| |
| /** |
| * This handler will trigger an event that will be used to notify the {@link SourceViewer} to |
| * invoke the content assist. |
| */ |
| private IHandlerActivation handlerActivation; |
| |
| /** |
| * The position within the JPQL query. |
| */ |
| private int position; |
| |
| /** |
| * The holder of the named query. |
| */ |
| private PropertyValueModel<? extends NamedQuery> queryHolder; |
| |
| /** |
| * The {@link ResourceBundle} that contains the JPQL problems. |
| */ |
| private ResourceBundle resourceBundle; |
| |
| /** |
| * This viewer is used to install various functionality over the {@link StyledText}. |
| */ |
| private SourceViewer sourceViewer; |
| |
| /** |
| * The configuration object used to configure the {@link SourceViewer}. |
| */ |
| private JpqlSourceViewerConfiguration sourceViewerConfiguration; |
| |
| /** |
| * The widget used to display the JPQL query. |
| */ |
| private StyledText styledText; |
| |
| /** |
| * This listener is used to dispose the {@link org.eclipse.persistence.jpa.jpql.JPQLQueryHelper |
| * JPQLQueryHelper} when the subject changes and to reset the undo manager in order to prevent |
| * the query from being entirely deleted with an undo. |
| */ |
| private PropertyChangeListener subjectChangeListener; |
| |
| /** |
| * The holder of the JPQL query. |
| */ |
| private ModifiablePropertyValueModel<String> textHolder; |
| |
| /** |
| * Listens to the JPQL query and keep the {@link Document} in sync. |
| */ |
| private PropertyChangeListener textListener; |
| |
| /** |
| * The unique identifier - appended by hashCode() - used to register the widget with the focus |
| * handler. |
| */ |
| private static final String CONTROL_ID = "jpql.focus.control"; |
| |
| /** |
| * The unique identifier used to mark an {@link Annotation} as a JPQL problem. |
| */ |
| private static final String ERROR_TYPE = "org.eclipse.jdt.ui.error"; |
| |
| /** |
| * Creates a new <code>JpaJpqlContentProposalProvider</code>. |
| * |
| * @param parent The parent {@link Composite} where to add the JPQL query editor |
| * @param queryHolder The holder of the named query |
| * @param textHolder The holder of the JPQL query |
| */ |
| public JpaJpqlContentProposalProvider(Composite parent, |
| PropertyValueModel<? extends NamedQuery> queryHolder, |
| ModifiablePropertyValueModel<String> textHolder) { |
| |
| super(); |
| initialize(parent, queryHolder, textHolder); |
| } |
| |
| private void activateHandler() { |
| |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| IFocusService focusService = (IFocusService) workbench.getService(IFocusService.class); |
| IHandlerService handlerService = (IHandlerService) workbench.getService(IHandlerService.class); |
| |
| if ((focusService != null) && (handlerService != null)) { |
| |
| focusService.addFocusTracker(styledText, CONTROL_ID + hashCode()); |
| |
| Expression expression = buildExpression(); |
| IHandler handler = buildHandler(); |
| |
| handlerActivation = handlerService.activateHandler( |
| ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, |
| handler, |
| expression |
| ); |
| |
| handlerActivation = handlerService.activateHandler( |
| ActionFactory.UNDO.getCommandId(), |
| handler, |
| expression |
| ); |
| |
| handlerActivation = handlerService.activateHandler( |
| ActionFactory.REDO.getCommandId(), |
| handler, |
| expression |
| ); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private List<AnnotationPreference> annotationPreferences() { |
| return EditorsPlugin.getDefault().getMarkerAnnotationPreferences().getAnnotationPreferences(); |
| } |
| |
| private DisposeListener buildDisposeListener() { |
| return new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| dispose(); |
| } |
| }; |
| } |
| |
| private IDocumentListener buildDocumentListener() { |
| return new IDocumentListener() { |
| public void documentAboutToBeChanged(DocumentEvent event) { |
| } |
| public void documentChanged(DocumentEvent event) { |
| try { |
| IDocument document = event.getDocument(); |
| String text = document.get(0, document.getLength()); |
| textHolder.setValue(text); |
| validate(); |
| } |
| catch (BadLocationException e) { |
| // Simply ignore, should never happen |
| } |
| } |
| }; |
| } |
| |
| private Expression buildExpression() { |
| return new Expression() { |
| @Override |
| public void collectExpressionInfo(ExpressionInfo info) { |
| info.addVariableNameAccess(ISources.ACTIVE_FOCUS_CONTROL_NAME); |
| } |
| @Override |
| public EvaluationResult evaluate(IEvaluationContext context) { |
| Object variable = context.getVariable(ISources.ACTIVE_FOCUS_CONTROL_NAME); |
| return (variable == styledText) ? EvaluationResult.TRUE : EvaluationResult.FALSE; |
| } |
| }; |
| } |
| |
| private IHandler buildHandler() { |
| return new AbstractHandler() { |
| public Object execute(ExecutionEvent event) throws ExecutionException { |
| String commandId = event.getCommand().getId(); |
| |
| // Content Assist |
| if (ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS.equals(commandId)) { |
| sourceViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); |
| } |
| // Undo |
| else if (ActionFactory.UNDO.getCommandId().equals(commandId)) { |
| if (sourceViewer.getUndoManager().undoable()) { |
| sourceViewer.getUndoManager().undo(); |
| validate(); |
| } |
| } |
| // Redo |
| else if (ActionFactory.REDO.getCommandId().equals(commandId)) { |
| if (sourceViewer.getUndoManager().redoable()) { |
| sourceViewer.getUndoManager().redo(); |
| validate(); |
| } |
| } |
| |
| return null; |
| } |
| }; |
| } |
| |
| private String buildMessage(JPQLQueryProblem problem) { |
| String message = resourceBundle().getString(problem.getMessageKey()); |
| message = MessageFormat.format(message, (Object[]) problem.getMessageArguments()); |
| return message; |
| } |
| |
| private ModifyListener buildModifyListener() { |
| return new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| validate(); |
| } |
| }; |
| } |
| |
| private Comparator<JPQLQueryProblem> buildProblemComparator() { |
| return new Comparator<JPQLQueryProblem>() { |
| public int compare(JPQLQueryProblem problem1, JPQLQueryProblem problem2) { |
| int result = problem1.getStartPosition() - problem2.getStartPosition(); |
| if (result == 0) { |
| result = problem1.getEndPosition() - problem2.getEndPosition(); |
| } |
| return result; |
| } |
| }; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| ICompletionProposal buildProposal(String proposal, |
| String displayString, |
| String additionalInfo, |
| Image image, |
| int cursorOffset) { |
| |
| return new JpqlCompletionProposal( |
| contentAssistProposals, |
| proposal, |
| displayString, |
| additionalInfo, |
| image, |
| namedQuery, |
| actualQuery, |
| jpqlQuery, |
| offset, |
| position, |
| cursorOffset, |
| false |
| ); |
| } |
| |
| private PropertyChangeListener buildSubjectChangeListener() { |
| return new PropertyChangeListener() { |
| public void propertyChanged(PropertyChangeEvent e) { |
| subjectChanged(e); |
| } |
| }; |
| } |
| |
| private PropertyChangeListener buildTextListener() { |
| return new SWTPropertyChangeListenerWrapper(new PropertyChangeListener() { |
| public void propertyChanged(PropertyChangeEvent event) { |
| String text = (String) event.getNewValue(); |
| if (text == null) { |
| text = StringTools.EMPTY_STRING; |
| } |
| if (!styledText.getText().equals(text)) { |
| sourceViewer.getDocument().set(text); |
| } |
| } |
| }); |
| } |
| |
| private Image contentAssistImage() { |
| FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault(); |
| return registry.getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage(); |
| } |
| |
| /** |
| * Makes sure the {@link Color} used to paint the underlying problem is disposed when the |
| * {@link StyledText} widget is disposed. |
| */ |
| private void dispose() { |
| |
| sessionEnded(); |
| |
| decorationSupport.dispose(); |
| textHolder.removePropertyChangeListener(PropertyValueModel.VALUE, textListener); |
| queryHolder.removePropertyChangeListener(PropertyValueModel.VALUE, subjectChangeListener); |
| |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| IHandlerService handlerService = (IHandlerService) workbench.getService(IHandlerService.class); |
| handlerService.deactivateHandler(handlerActivation); |
| } |
| |
| private KeyStroke findContentAssistTrigger() { |
| |
| IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getService(IBindingService.class); |
| |
| // Dig through the list of available bindings to find the one for content assist |
| for (Binding binding : bindingService.getBindings()) { |
| if (isContentAssistBinding(binding)) { |
| Trigger[] triggers = binding.getTriggerSequence().getTriggers(); |
| if ((triggers != null) && (triggers.length > 0)) { |
| return (KeyStroke) triggers[0]; |
| } |
| } |
| } |
| |
| // The default trigger was not found, use the default |
| return KeyStroke.getInstance(SWT.CTRL, ' '); |
| } |
| |
| /** |
| * Returns the widget used to display the JPQL query. |
| * |
| * @return The main widget |
| */ |
| public StyledText getStyledText() { |
| return styledText; |
| } |
| |
| private void initialize(Composite parent, |
| PropertyValueModel<? extends NamedQuery> queryHolder, |
| ModifiablePropertyValueModel<String> textHolder) { |
| |
| this.queryHolder = queryHolder; |
| this.annotationModel = new AnnotationModel(); |
| this.textHolder = textHolder; |
| |
| // Make sure the StyledText is kept in sync with the text holder |
| textListener = buildTextListener(); |
| textHolder.addPropertyChangeListener(PropertyValueModel.VALUE, textListener); |
| |
| // Make sure the user can't delete the entire query when doing undo |
| subjectChangeListener = buildSubjectChangeListener(); |
| queryHolder.addPropertyChangeListener(PropertyValueModel.VALUE, subjectChangeListener); |
| |
| // Create the SourceViewer, which is responsible for everything: content assist, tool tip |
| // hovering over the annotation (problems), etc |
| sourceViewer = new SourceViewer(parent, null, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FLAT); |
| sourceViewerConfiguration = new JpqlSourceViewerConfiguration(); |
| sourceViewer.configure(sourceViewerConfiguration); |
| sourceViewer.setDocument(new Document(), annotationModel); |
| sourceViewer.getDocument().addDocumentListener(buildDocumentListener()); |
| |
| styledText = sourceViewer.getTextWidget(); |
| styledText.addModifyListener(buildModifyListener()); |
| styledText.addDisposeListener(buildDisposeListener()); |
| |
| // Add the support for painting the annotations (JPQL problems) in the source viewer |
| installDecorationSupport(); |
| |
| // Bind the content assist key trigger with the handler service |
| activateHandler(); |
| |
| // Install a custom context menu to the widget |
| TextTransferHandler.installContextMenu(styledText, sourceViewer.getUndoManager()); |
| } |
| |
| /** |
| * Installs the content assist icon at the top left of the {@link StyledText}. |
| */ |
| public void installControlDecoration() { |
| |
| // Retrieve the content assist trigger |
| KeyStroke contentAssistTrigger = findContentAssistTrigger(); |
| String key = SWTKeySupport.getKeyFormatterForPlatform().format(contentAssistTrigger); |
| |
| // Add the context assist icon at the top left corner of the StyledText |
| ControlDecoration decoration = new ControlDecoration(styledText, SWT.LEFT | SWT.TOP); |
| decoration.setDescriptionText(NLS.bind(JptUiMessages.JpqlContentProposalProvider_Description, key)); |
| decoration.setImage(contentAssistImage()); |
| decoration.setShowOnlyOnFocus(true); |
| } |
| |
| private void installDecorationSupport() { |
| |
| decorationSupport = new SourceViewerDecorationSupport( |
| sourceViewer, |
| null, |
| new DefaultMarkerAnnotationAccess(), |
| EditorsPlugin.getDefault().getSharedTextColors() |
| ); |
| |
| for (AnnotationPreference preference : annotationPreferences()) { |
| decorationSupport.setAnnotationPreference(preference); |
| } |
| |
| decorationSupport.install(EditorsPlugin.getDefault().getPreferenceStore()); |
| } |
| |
| private boolean isContentAssistBinding(Binding binding) { |
| |
| ParameterizedCommand command = binding.getParameterizedCommand(); |
| |
| return command != null && |
| command.getCommand() != null && |
| command.getCommand().getId().equals(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); |
| } |
| |
| private NamedQuery query() { |
| return queryHolder.getValue(); |
| } |
| |
| private ResourceBundle resourceBundle() { |
| if (resourceBundle == null) { |
| resourceBundle = ResourceBundle.getBundle( |
| "jpa_jpql_validation", |
| Locale.getDefault(), |
| JptJpaCorePlugin.class.getClassLoader() |
| ); |
| } |
| return resourceBundle; |
| } |
| |
| private List<JPQLQueryProblem> sortProblems(List<JPQLQueryProblem> problems) { |
| Collections.sort(problems, buildProblemComparator()); |
| return problems; |
| } |
| |
| private void subjectChanged(PropertyChangeEvent e) { |
| |
| namedQuery = (NamedQuery) e.getNewValue(); |
| |
| if (namedQuery != null) { |
| |
| // Prevent undoing the actual query that was set |
| sourceViewer.getUndoManager().reset(); |
| |
| // Make sure the new query is validated |
| validate(); |
| } |
| else { |
| queryHelper = null; |
| annotationModel.removeAllAnnotations(); |
| } |
| } |
| |
| /** |
| * Validates the given JPQL query and add highlights where problems have been found. |
| */ |
| private void validate() { |
| |
| // First clear any existing problems |
| annotationModel.removeAllAnnotations(); |
| |
| // Nothing to validate |
| if ((query() == null) || |
| styledText.isDisposed() || |
| StringTools.stringIsEmpty(styledText.getText())) { |
| |
| return; |
| } |
| |
| try { |
| // The information was disposed but the content might be updated outside of the pane, |
| // like in the editor itself, make sure NamedQuery and the helper are initialized |
| if (queryHelper == null) { |
| namedQuery = query(); |
| queryHelper = namedQuery.getPersistenceUnit().createJpqlQueryHelper(); |
| } |
| |
| String jpqlQuery = styledText.getText(); |
| queryHelper.setQuery(query(), jpqlQuery); |
| String parsedJpqlQuery = queryHelper.getParsedJPQLQuery(); |
| |
| for (JPQLQueryProblem problem : sortProblems(queryHelper.validate())) { |
| |
| // Create the range |
| int[] positions = queryHelper.buildPositions(problem, parsedJpqlQuery, jpqlQuery); |
| |
| // Add the problem to the tool tip |
| Annotation annotation = new Annotation(ERROR_TYPE, true, buildMessage(problem)); |
| annotationModel.addAnnotation(annotation, new Position(positions[0], positions[1] - positions[0])); |
| } |
| } |
| finally { |
| queryHelper.dispose(); |
| } |
| } |
| |
| /** |
| * This processor is responsible to create the list of {@link ICompletionProposal proposals} |
| * based on the position of the cursor within the query. |
| */ |
| private class ContentAssistProcessor implements IContentAssistProcessor { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { |
| |
| JpaJpqlContentProposalProvider.this.position = offset; |
| |
| String jpqlQuery = viewer.getDocument().get(); |
| List<ICompletionProposal> proposals = buildProposals(query(), jpqlQuery, 0, position); |
| return proposals.toArray(new ICompletionProposal[proposals.size()]); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public char[] getCompletionProposalAutoActivationCharacters() { |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public char[] getContextInformationAutoActivationCharacters() { |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public IContextInformationValidator getContextInformationValidator() { |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getErrorMessage() { |
| return null; |
| } |
| } |
| |
| private class JpqlSourceViewerConfiguration extends SourceViewerConfiguration { |
| |
| /** |
| * Keeps track of the content assist since we need to know when the popup is opened or not. |
| */ |
| ContentAssistant contentAssistant; |
| |
| private IInformationControlCreator buildInformationControlCreator() { |
| return new IInformationControlCreator() { |
| public IInformationControl createInformationControl(Shell parent) { |
| return new DefaultInformationControl( |
| parent, |
| EditorsUI.getTooltipAffordanceString(), |
| new HTMLTextPresenter(true) |
| ); |
| } |
| }; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { |
| return new DefaultAnnotationHover(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { |
| contentAssistant = new ContentAssistant(); |
| contentAssistant.setContentAssistProcessor(new ContentAssistProcessor(), IDocument.DEFAULT_CONTENT_TYPE); |
| contentAssistant.setInformationControlCreator(buildInformationControlCreator()); |
| return contentAssistant; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { |
| return new DefaultTextHover(sourceViewer); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { |
| return new DefaultTextHover(sourceViewer); |
| } |
| } |
| } |