/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.ui.editor;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.CoreUtil.array;
import static melnorme.utilbox.core.CoreUtil.assertInstance;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import melnorme.lang.ide.core.LangCore;
import melnorme.lang.ide.core.operations.ToolchainPreferences;
import melnorme.lang.ide.core.utils.EclipseUtils;
import melnorme.lang.ide.ui.EditorSettings_Actual;
import melnorme.lang.ide.ui.EditorSettings_Actual.EditorPrefConstants;
import melnorme.lang.ide.ui.LangImages;
import melnorme.lang.ide.ui.LangUIPlugin;
import melnorme.lang.ide.ui.LangUIPlugin_Actual;
import melnorme.lang.ide.ui.editor.actions.AbstractEditorToolOperation;
import melnorme.lang.ide.ui.editor.actions.GotoMatchingBracketManager;
import melnorme.lang.ide.ui.editor.text.LangPairMatcher;
import melnorme.lang.ide.ui.text.AbstractLangSourceViewerConfiguration;
import melnorme.lang.ide.ui.utils.PluginImagesHelper.ImageHandle;
import melnorme.lang.ide.ui.utils.prefs.EclipsePreferencesAdapter;
import melnorme.lang.utils.EnablementCounter;
import melnorme.utilbox.concurrency.ICancelMonitor;
import melnorme.utilbox.misc.ArrayUtil;
import melnorme.utilbox.ownership.Disposable;
public abstract class AbstractLangEditor extends TextEditorExt {
public AbstractLangEditor() {
super();
// Force start debug plugin to ensure action contributions are propagated.
// XXX: Definitely there should be a better way to achieve the above, but it's tricky.
LangUIPlugin.startDebugPlugin();
}
@Override
protected void initializeEditor() {
super.initializeEditor();
initialize_setContextMenuIds();
}
/* ----------------- actions init ----------------- */
@Override
protected void initializeKeyBindingScopes() {
setKeyBindingScopes(array(EditorSettings_Actual.EDITOR_CONTEXT_ID));
}
protected void initialize_setContextMenuIds() {
setEditorContextMenuId(LangUIPlugin_Actual.EDITOR_CONTEXT);
setRulerContextMenuId(LangUIPlugin_Actual.RULER_CONTEXT);
}
/* ----------------- input ----------------- */
@Override
protected void doSetInput(IEditorInput input) throws CoreException {
super.doSetInput(input);
if(input == null) {
// Do nothing, editor will be closed.
LangCore.logError("doSetInput = null");
return;
}
SourceViewer sourceViewer = getSourceViewer_();
if(sourceViewer == null) {
changePreferenceStore(createCombinedPreferenceStore(input));
} else {
getSourceViewerDecorationSupport(sourceViewer).uninstall();
sourceViewer.unconfigure();
changePreferenceStore(createCombinedPreferenceStore(input));
sourceViewer.configure(getSourceViewerConfiguration());
getSourceViewerDecorationSupport(sourceViewer).install(getPreferenceStore());
}
IDocument doc = getDocumentProvider().getDocument(input);
// Setup up partitioning if not set. It can happen if opening non-language files in the language editor.
LangUIPlugin_Actual.createDocumentSetupHelper().setupPartitioningIfNotSet(doc);
internalDoSetInput(input);
}
protected void changePreferenceStore(IPreferenceStore store) {
super.setPreferenceStore(store);
setSourceViewerConfiguration(createSourceViewerConfiguration());
}
protected abstract AbstractLangSourceViewerConfiguration createSourceViewerConfiguration();
public AbstractLangSourceViewerConfiguration getSourceViewerConfiguration_asLang() {
SourceViewerConfiguration svc = getSourceViewerConfiguration();
if(svc instanceof AbstractLangSourceViewerConfiguration) {
return (AbstractLangSourceViewerConfiguration) svc;
}
return null;
}
protected IPreferenceStore createCombinedPreferenceStore(IEditorInput input) {
List<IPreferenceStore> stores = new ArrayList<IPreferenceStore>(4);
IProject project = EditorUtils.getAssociatedProject(input);
if (project != null) {
stores.add(new EclipsePreferencesAdapter(new ProjectScope(project), LangUIPlugin.PLUGIN_ID));
}
stores.add(LangUIPlugin.getInstance().getPreferenceStore());
stores.add(LangUIPlugin.getInstance().getCorePreferenceStore());
alterCombinedPreferenceStores_beforeEditorsUI(stores);
stores.add(EditorsUI.getPreferenceStore());
return new ChainedPreferenceStore(ArrayUtil.createFrom(stores, IPreferenceStore.class));
}
@SuppressWarnings("unused")
protected void alterCombinedPreferenceStores_beforeEditorsUI(List<IPreferenceStore> stores) {
}
@Override
protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
AbstractLangSourceViewerConfiguration langSVC = getSourceViewerConfiguration_asLang();
if(langSVC != null) {
LangSourceViewer sourceViewer = getSourceViewer_();
langSVC.handlePropertyChange(event, getPreferenceStore(), sourceViewer);
}
super.handlePreferenceStoreChanged(event);
}
@Override
protected boolean affectsTextPresentation(PropertyChangeEvent event) {
return super.affectsTextPresentation(event);
}
protected void internalDoSetInput(IEditorInput input) {
assertNotNull(input);
editorTitleImageUpdater.updateEditorImage(EditorUtils.getAssociatedFile(input));
}
/* ----------------- create controls ----------------- */
@Override
public int getOrientation() {
return SWT.LEFT_TO_RIGHT; // Always left to right,
// also, this fixes bug super.getOrientation(), which can return SWT.NONE (but shouldn't)
}
@Override
protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
LangSourceViewer viewer = doCreateSourceViewer(parent, ruler, styles);
assertInstance(viewer, SourceViewer.class);
assertInstance(viewer, ISourceViewerExt.class);
return viewer;
}
public LangSourceViewer getSourceViewer_() {
return (LangSourceViewer) getSourceViewer();
}
public ISourceViewerExt getSourceViewer_asExt() {
return (ISourceViewerExt) getSourceViewer();
}
protected LangSourceViewer doCreateSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
LangSourceViewer viewer =
new LangSourceViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
// ensure decoration support has been created and configured.
getSourceViewerDecorationSupport(viewer);
return viewer;
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
editorSelChangedListener.install(getSelectionProvider());
}
/* ----------------- other ----------------- */
protected final EditorTitleImageUpdater editorTitleImageUpdater = addOwned(new EditorTitleImageUpdater(this));
public ImageHandle getBaseEditorImage() {
return LangImages.SOURCE_EDITOR_ICON;
}
@Override
protected boolean isTabsToSpacesConversionEnabled() {
return false;
}
protected final AbstractSelectionChangedListener editorSelChangedListener = new AbstractSelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
handleEditorSelectionChanged(event);
}
};
@SuppressWarnings("unused")
protected void handleEditorSelectionChanged(SelectionChangedEvent event) {
}
/* ----------------- Bracket matcher ----------------- */
protected final LangPairMatcher fBracketMatcher = addOwned(init_createBracketMatcher());
protected final GotoMatchingBracketManager gotoMatchingBracketManager = init_createGoToMatchingBracketManager();
protected abstract LangPairMatcher init_createBracketMatcher();
protected GotoMatchingBracketManager init_createGoToMatchingBracketManager() {
return new GotoMatchingBracketManager(this);
}
public final LangPairMatcher getBracketMatcher() {
return fBracketMatcher;
}
public final GotoMatchingBracketManager getGotoMatchingBracketManager() {
return gotoMatchingBracketManager;
}
@Override
protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
configureBracketMatcher(support);
super.configureSourceViewerDecorationSupport(support);
}
protected void configureBracketMatcher(SourceViewerDecorationSupport support) {
support.setCharacterPairMatcher(fBracketMatcher);
support.setMatchingCharacterPainterPreferenceKeys(
EditorPrefConstants.MATCHING_BRACKETS_.key,
EditorPrefConstants.MATCHING_BRACKETS_COLOR2.getActiveKey(),
EditorPrefConstants.HIGHLIGHT_BRACKET_AT_CARET_LOCATION,
EditorPrefConstants.ENCLOSING_BRACKETS);
}
/* ----------------- save ----------------- */
/** Whether save actions are enabled or not. */
protected final EnablementCounter saveActionsEnablement = new EnablementCounter();
public EnablementCounter saveActionsEnablement() {
return saveActionsEnablement;
}
public void saveWithoutSaveActions2(ICancelMonitor cm) {
saveWithoutSaveActions(EclipseUtils.pm(cm));
}
public void saveWithoutSaveActions(IProgressMonitor pm) {
try(Disposable disposable = saveActionsEnablement().enterDisable()) {
doSave(pm);
}
}
@Override
protected void performSave(boolean overwrite, IProgressMonitor pm) {
if(saveActionsEnablement.isEnabled()) {
IProject associatedProject = EditorUtils.getAssociatedProject(getEditorInput());
if(ToolchainPreferences.FORMAT_ON_SAVE.getEffectiveValue(associatedProject)) {
AbstractEditorToolOperation<?> formatOperation = LangUIPlugin_Actual.getFormatOperation(this);
formatOperation.handleSoftFailureWithDialog = false;
formatOperation.executeAndHandle();
}
}
super.performSave(overwrite, pm);
}
}