/******************************************************************************* * Copyright (c) 2015, 2017 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.properties.editor; import java.lang.reflect.Method; import java.util.Map; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; import org.eclipse.jdt.internal.ui.propertiesfileeditor.IPropertiesFilePartitions; import org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileSourceViewerConfiguration; import org.eclipse.jdt.ui.text.IColorManager; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; import org.eclipse.jface.text.quickassist.QuickAssistAssistant; import org.eclipse.jface.text.reconciler.IReconciler; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.editors.text.EditorsPlugin; import org.eclipse.ui.texteditor.ITextEditor; import org.springframework.ide.eclipse.boot.properties.editor.quickfix.SpringPropertyProblemQuickAssistProcessor; import org.springframework.ide.eclipse.boot.properties.editor.reconciling.SpringPropertiesReconcileEngine; import org.springframework.ide.eclipse.boot.properties.editor.util.HyperlinkDetectorUtil; import org.springframework.ide.eclipse.editor.support.ForceableReconciler; import org.springframework.ide.eclipse.editor.support.completions.CompletionFactory; import org.springframework.ide.eclipse.editor.support.completions.ProposalProcessor; import org.springframework.ide.eclipse.editor.support.hover.HoverInfoTextHover; import org.springframework.ide.eclipse.editor.support.hover.HoverInformationControlCreator; import org.springframework.ide.eclipse.editor.support.reconcile.DefaultQuickfixContext; import org.springframework.ide.eclipse.editor.support.reconcile.IReconcileEngine; import org.springframework.ide.eclipse.editor.support.reconcile.QuickfixContext; import org.springframework.ide.eclipse.editor.support.reconcile.ReconcileProblemAnnotationHover; import org.springframework.ide.eclipse.editor.support.util.DefaultUserInteractions; import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil; @SuppressWarnings("restriction") public class SpringPropertiesFileSourceViewerConfiguration extends PropertiesFileSourceViewerConfiguration implements IReconcileTrigger { private static final String DIALOG_SETTINGS_KEY = PropertiesFileSourceViewerConfiguration.class.getName(); private static final DocumentContextFinder documentContextFinder = DocumentContextFinders.PROPS_DEFAULT; private SpringPropertiesCompletionEngine engine; private ForceableReconciler fReconciler; private SpringPropertiesReconcilerFactory fReconcilerFactory = new SpringPropertiesReconcilerFactory() { @Override protected IReconcileEngine createEngine() throws Exception { SpringPropertiesCompletionEngine e = getEngine(); return new SpringPropertiesReconcileEngine(e.getIndexProvider(), e.getTypeUtil()); } }; private ITextEditor editor; public SpringPropertiesFileSourceViewerConfiguration( IColorManager colorManager, IPreferenceStore preferenceStore, ITextEditor editor, String partitioning) { super(colorManager, preferenceStore, editor, partitioning); this.editor = editor; } @Override public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { try { SpringPropertiesCompletionEngine engine = getEngine(); ContentAssistant a = new ContentAssistant(); a.setDocumentPartitioning(IPropertiesFilePartitions.PROPERTIES_FILE_PARTITIONING); a.setContentAssistProcessor(new ProposalProcessor(engine), IDocument.DEFAULT_CONTENT_TYPE); a.setContentAssistProcessor(new ProposalProcessor(engine), IPropertiesFilePartitions.PROPERTY_VALUE); a.enableColoredLabels(true); a.enableAutoActivation(true); a.setInformationControlCreator(new HoverInformationControlCreator(JavaPlugin.getAdditionalInfoAffordanceString())); setSorter(a); a.setRestoreCompletionProposalSize(getDialogSettings(sourceViewer, DIALOG_SETTINGS_KEY)); return a; } catch (Exception e) { SpringPropertiesEditorPlugin.log(e); } return null; } private SpringPropertiesCompletionEngine getEngine() throws Exception { if (engine==null) { ITextEditor editor = getEditor(); if (editor == null) { throw ExceptionUtil.coreException("Text editor is missing for the viewer to be configured"); } else { IEditorInput editorInput = getEditor().getEditorInput(); IJavaProject jp = EditorUtility.getJavaProject(editorInput); if (jp == null) { throw ExceptionUtil.coreException("Unable to find Java project owning editor input: " + editorInput.getName() + " (Editor input: " + editorInput.getClass().getName() + ")"); } else { engine = new SpringPropertiesCompletionEngine(jp); } } } return engine; } @Override public ITextHover getTextHover(ISourceViewer sourceViewer,String contentType) { return getTextHover(sourceViewer, contentType, 0); } @Override public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { ITextHover delegate = new ReconcileProblemAnnotationHover(sourceViewer, getQuickfixContext(sourceViewer)); try { if (contentType.equals(IDocument.DEFAULT_CONTENT_TYPE) || contentType.equals(IPropertiesFilePartitions.PROPERTY_VALUE)) { SpringPropertiesCompletionEngine engine = getEngine(); return new HoverInfoTextHover(sourceViewer, engine, delegate); } } catch (Exception e) { SpringPropertiesEditorPlugin.log(e); } return delegate; } protected QuickfixContext getQuickfixContext(ISourceViewer sourceViewer) { return new DefaultQuickfixContext(SpringPropertiesEditorPlugin.PLUGIN_ID, getPreferencesStore(), sourceViewer, new DefaultUserInteractions(getShell())); } protected Shell getShell() { return editor.getSite().getShell(); } private IDialogSettings getDialogSettings(ISourceViewer sourceViewer, String dialogSettingsKey) { IDialogSettings existing = SpringPropertiesEditorPlugin.getDefault().getDialogSettings().getSection(DIALOG_SETTINGS_KEY); if (existing!=null) { return existing; } IDialogSettings created = SpringPropertiesEditorPlugin.getDefault().getDialogSettings().addNewSection(DIALOG_SETTINGS_KEY); Rectangle windowBounds = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().getBounds(); int suggestW = (int)(windowBounds.width*0.35); int suggestH = (int)(suggestW*0.6); if (suggestW>300) { created.put(ContentAssistant.STORE_SIZE_X, suggestW); created.put(ContentAssistant.STORE_SIZE_Y, suggestH); } return created; } public static void setSorter(ContentAssistant a) { try { Class<?> sorterInterface = Class.forName("org.eclipse.jface.text.contentassist.ICompletionProposalSorter"); Method m = ContentAssistant.class.getMethod("setSorter", sorterInterface); m.invoke(a, CompletionFactory.SORTER); } catch (Throwable e) { //ignore, sorter not supported with Eclipse 3.7 API } } @Override public IReconciler getReconciler(ISourceViewer sourceViewer) { if (fReconciler==null) { fReconciler = fReconcilerFactory.createReconciler(sourceViewer, documentContextFinder, this); } return fReconciler; } @Override public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { SpringPropertiesHyperlinkDetector myDetector = null; try { myDetector = new SpringPropertiesHyperlinkDetector(getEngine()); } catch (Exception e) { SpringPropertiesEditorPlugin.log(e); } return HyperlinkDetectorUtil.merge( super.getHyperlinkDetectors(sourceViewer), myDetector ); } // @Override // public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) { // return super.getHyperlinkPresenter(sourceViewer); // } @Override public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) { QuickAssistAssistant assistant= new QuickAssistAssistant(); assistant.setQuickAssistProcessor(new SpringPropertyProblemQuickAssistProcessor(getPreferencesStore(), new DefaultUserInteractions(getShell()))); assistant.setRestoreCompletionProposalSize(EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$ assistant.setInformationControlCreator(getQuickAssistAssistantInformationControlCreator()); return assistant; } protected IPreferenceStore getPreferencesStore() { return SpringPropertiesEditorPlugin.getDefault().getPreferenceStore(); } private IInformationControlCreator getQuickAssistAssistantInformationControlCreator() { return new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { return new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString()); } }; } protected Map<String,IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer) { Map<String, IAdaptable> superTargets = super.getHyperlinkDetectorTargets(sourceViewer); superTargets.remove("org.eclipse.jdt.ui.PropertiesFileEditor"); //This just adds a 'search for' link which never seems to return anything useful return superTargets; }; public void forceReconcile() { if (fReconciler!=null) { fReconciler.forceReconcile(); } } }