diff options
4 files changed, 417 insertions, 307 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ActionUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ActionUtils.java index f4616f5ab4..2add80da57 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ActionUtils.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ActionUtils.java @@ -17,7 +17,10 @@ import java.util.function.BooleanSupplier; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; import org.eclipse.jface.commands.ActionHandler; +import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Control; @@ -109,6 +112,95 @@ public final class ActionUtils { } /** + * Creates a new text action using a given {@link ActionFactory} to use as a + * template to set the label, image, and action definition id. + * + * @param target + * for the action + * @param factory + * to configure the action + * @param operationCode + * for the action + * @return the configured {@link UpdateableAction} + */ + public static UpdateableAction createTextAction( + ITextOperationTarget target, ActionFactory factory, + int operationCode) { + if (operationCode == ITextOperationTarget.REDO) { + // XXX: workaround for + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206111 + return createGlobalAction(factory, + () -> target.doOperation(operationCode), () -> true); + } + return createGlobalAction(factory, + () -> target.doOperation(operationCode), + () -> target.canDoOperation(operationCode)); + } + + private static UpdateableAction[] createStandardTextActions( + ITextOperationTarget target, boolean editable) { + UpdateableAction[] actions = new UpdateableAction[ITextOperationTarget.SELECT_ALL + + 1]; + if (editable) { + actions[ITextOperationTarget.UNDO] = createTextAction(target, + ActionFactory.UNDO, ITextOperationTarget.UNDO); + actions[ITextOperationTarget.REDO] = createTextAction(target, + ActionFactory.REDO, ITextOperationTarget.REDO); + actions[ITextOperationTarget.CUT] = createTextAction(target, + ActionFactory.CUT, ITextOperationTarget.CUT); + actions[ITextOperationTarget.PASTE] = createTextAction( + target, ActionFactory.PASTE, ITextOperationTarget.PASTE); + actions[ITextOperationTarget.DELETE] = createTextAction( + target, ActionFactory.DELETE, ITextOperationTarget.DELETE); + } + actions[ITextOperationTarget.COPY] = createTextAction(target, + ActionFactory.COPY, ITextOperationTarget.COPY); + actions[ITextOperationTarget.SELECT_ALL] = createTextAction( + target, ActionFactory.SELECT_ALL, + ITextOperationTarget.SELECT_ALL); + return actions; + } + + /** + * Create the standard text actions, fill them into a {@MenuManager} and + * return them as an array indexed by the {@link ITextOperationTarget} + * operation codes. For an editable target, creates undo, redo | cut, copy, + * paste | delete, select all; otherwise just copy, select all. + * + * @param target + * for the actions to operate on + * @param editable + * whether the target is editable + * @param manager + * to fill in; may be {@code null} if the actions shall not be + * added to a {@link MenuManager} + * @return the actions; may contain {@code null} values (index 0 will always + * be {@code null}) + */ + public static UpdateableAction[] fillStandardTextActions( + ITextOperationTarget target, boolean editable, + MenuManager manager) { + UpdateableAction[] actions = createStandardTextActions(target, + editable); + if (manager != null) { + if (editable) { + manager.add(actions[ITextOperationTarget.UNDO]); + manager.add(actions[ITextOperationTarget.REDO]); + manager.add(new Separator()); + manager.add(actions[ITextOperationTarget.CUT]); + } + manager.add(actions[ITextOperationTarget.COPY]); + if (editable) { + manager.add(actions[ITextOperationTarget.PASTE]); + manager.add(new Separator()); + manager.add(actions[ITextOperationTarget.DELETE]); + } + manager.add(actions[ITextOperationTarget.SELECT_ALL]); + } + return actions; + } + + /** * Hooks up the {@link Control} such that the given {@link IAction}s are * registered with the given {@link IHandlerService} while the control has * the focus. Ensures that actions are properly de-registered when the @@ -117,7 +209,8 @@ public final class ActionUtils { * @param control * to hook up * @param actions - * to be registered while the control has the focus + * to be registered while the control has the focus; {@code null} + * items are skipped. * @param service * to register the actions with */ @@ -148,12 +241,14 @@ public final class ActionUtils { // Looks like sometimes we get two focusGained events. return; } - for (final IAction action : actions) { - handlerActivations.add(service.activateHandler( - action.getActionDefinitionId(), - new ActionHandler(action), expression, false)); - if (action instanceof IUpdate) { - ((IUpdate) action).update(); + for (IAction action : actions) { + if (action != null) { + handlerActivations.add(service.activateHandler( + action.getActionDefinitionId(), + new ActionHandler(action), expression, false)); + if (action instanceof IUpdate) { + ((IUpdate) action).update(); + } } } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/ShowWhitespaceAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/ShowWhitespaceAction.java new file mode 100644 index 0000000000..dbdd042af9 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/ShowWhitespaceAction.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2012, 2019 Tomasz Zarna (IBM), Robin Stocker, and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Thomas Wolf <thomas.wolf@paranor.ch> - Factored out of SpellcheckableMessageArea. + *******************************************************************************/ +package org.eclipse.egit.ui.internal.dialogs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.IPainter; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension2; +import org.eclipse.jface.text.WhitespaceCharacterPainter; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.texteditor.AbstractTextEditor; + +/** + * An action to toggle showing whitespace in a an {@link ITextViewer}. + */ +public class ShowWhitespaceAction extends TextEditorPropertyAction { + + /** + * Creates a new {@link ShowWhitespaceAction}. + * + * @param viewer + * to operate on + * @param initiallyOff + * whether to show whitespace initially + */ + public ShowWhitespaceAction(ITextViewer viewer, boolean initiallyOff) { + super(UIText.SpellcheckableMessageArea_showWhitespace, viewer, + AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS, + initiallyOff); + } + + private IPainter whitespaceCharPainter; + + @Override + public void propertyChange(PropertyChangeEvent event) { + String property = event.getProperty(); + if (property == null) { + return; + } + switch (property) { + case AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS: + case AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES: + case AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS: + case AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS: + case AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS: + case AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN: + case AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED: + case AbstractTextEditor.PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE: + synchronizeWithPreference(); + break; + default: + break; + } + } + + @Override + protected final String getPreferenceKey() { + return AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS; + } + + @Override + protected void toggleState(boolean checked) { + if (checked) { + installPainter(); + } else { + uninstallPainter(); + } + } + + /** + * Installs the painter on the viewer. + */ + private void installPainter() { + Assert.isTrue(whitespaceCharPainter == null); + ITextViewer v = getTextViewer(); + if (v instanceof ITextViewerExtension2) { + IPreferenceStore store = getStore(); + whitespaceCharPainter = new WhitespaceCharacterPainter(v, + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN), + store.getBoolean( + AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED), + store.getInt( + AbstractTextEditor.PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE)); + ((ITextViewerExtension2) v).addPainter(whitespaceCharPainter); + } + } + + /** + * Remove the painter from the viewer. + */ + private void uninstallPainter() { + if (whitespaceCharPainter == null) { + return; + } + ITextViewer v = getTextViewer(); + if (v instanceof ITextViewerExtension2) { + ((ITextViewerExtension2) v).removePainter(whitespaceCharPainter); + } + whitespaceCharPainter.deactivate(true); + whitespaceCharPainter = null; + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java index 35719cd54e..d490c4cbcb 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java @@ -24,15 +24,14 @@ import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.egit.core.internal.Utils; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIPreferences; import org.eclipse.egit.ui.UIUtils; import org.eclipse.egit.ui.internal.ActionUtils; +import org.eclipse.egit.ui.internal.ActionUtils.UpdateableAction; import org.eclipse.egit.ui.internal.CommonUtils; -import org.eclipse.egit.ui.internal.UIText; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; @@ -40,20 +39,13 @@ import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.action.SubMenuManager; -import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IPainter; -import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.ITextOperationTarget; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.MarginPainter; import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.TextEvent; -import org.eclipse.jface.text.WhitespaceCharacterPainter; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.presentation.IPresentationReconciler; @@ -71,8 +63,6 @@ import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jgit.util.IntList; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BidiSegmentEvent; @@ -90,16 +80,12 @@ import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Layout; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; import org.eclipse.ui.handlers.IHandlerService; -import org.eclipse.ui.texteditor.AbstractTextEditor; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; -import org.eclipse.ui.texteditor.IUpdate; import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.themes.IThemeManager; @@ -116,119 +102,6 @@ public class SpellcheckableMessageArea extends Composite { private static final Pattern TRAILING_NEWLINES = Pattern.compile("\\v+$"); //$NON-NLS-1$ - private static class TextViewerAction extends Action implements IUpdate { - - private int fOperationCode= -1; - private ITextOperationTarget fOperationTarget; - - /** - * Creates a new action. - * - * @param target - * to operate on - * @param operationCode - * the opcode - */ - public TextViewerAction(ITextOperationTarget target, - int operationCode) { - fOperationCode= operationCode; - fOperationTarget = target; - update(); - } - - /** - * Updates the enabled state of the action. - */ - @Override - public void update() { - // XXX: workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=206111 - if (fOperationCode == ITextOperationTarget.REDO) { - return; - } - setEnabled(fOperationTarget != null - && fOperationTarget.canDoOperation(fOperationCode)); - } - - /** - * @see Action#run() - */ - @Override - public void run() { - if (fOperationCode != -1 && fOperationTarget != null) - fOperationTarget.doOperation(fOperationCode); - } - } - - private static abstract class TextEditorPropertyAction extends Action implements IPropertyChangeListener { - - private SourceViewer viewer; - private String preferenceKey; - private IPreferenceStore store; - - public TextEditorPropertyAction(String label, SourceViewer viewer, String preferenceKey) { - super(label, IAction.AS_CHECK_BOX); - this.viewer = viewer; - this.preferenceKey = preferenceKey; - this.store = EditorsUI.getPreferenceStore(); - if (store != null) - store.addPropertyChangeListener(this); - synchronizeWithPreference(); - } - - @Override - public void propertyChange(PropertyChangeEvent event) { - if (event.getProperty().equals(getPreferenceKey())) - synchronizeWithPreference(); - } - - protected void synchronizeWithPreference() { - // start read-only components without visible whitespace - if (!viewer.getTextWidget().getEditable()) { - return; - } - boolean checked = false; - if (store != null) - checked = store.getBoolean(getPreferenceKey()); - if (checked != isChecked()) { - setChecked(checked); - toggleState(checked); - } else if (checked) { - toggleState(false); - toggleState(true); - } - } - - protected String getPreferenceKey() { - return preferenceKey; - } - - @Override - public void run() { - toggleState(isChecked()); - if (store != null) - store.setValue(getPreferenceKey(), isChecked()); - } - - public void dispose() { - if (store != null) - store.removePropertyChangeListener(this); - } - - /** - * @param checked - * new state - */ - abstract protected void toggleState(boolean checked); - - protected ITextViewer getTextViewer() { - return viewer; - } - - protected IPreferenceStore getStore() { - return store; - } - } - private final HyperlinkSourceViewer sourceViewer; private TextSourceViewerConfiguration configuration; @@ -497,153 +370,18 @@ public class SpellcheckableMessageArea extends Composite { } } - private TextViewerAction createFromActionFactory(ActionFactory factory, - int operationCode) { - IWorkbenchAction template = factory - .create(PlatformUI.getWorkbench().getActiveWorkbenchWindow()); - TextViewerAction action = new TextViewerAction(sourceViewer, - operationCode); - action.setText(template.getText()); - action.setImageDescriptor(template.getImageDescriptor()); - action.setDisabledImageDescriptor( - template.getDisabledImageDescriptor()); - action.setActionDefinitionId(template.getActionDefinitionId()); - template.dispose(); - return action; - } - private void configureContextMenu() { final boolean editable = isEditable(sourceViewer); - TextViewerAction cutAction; - TextViewerAction undoAction; - TextViewerAction redoAction; - TextViewerAction pasteAction; - IAction quickFixAction; + IAction quickFixAction = null; if (editable) { - cutAction = createFromActionFactory(ActionFactory.CUT, - ITextOperationTarget.CUT); - undoAction = createFromActionFactory(ActionFactory.UNDO, - ITextOperationTarget.UNDO); - redoAction = createFromActionFactory(ActionFactory.REDO, - ITextOperationTarget.REDO); - pasteAction = createFromActionFactory(ActionFactory.PASTE, - ITextOperationTarget.PASTE); quickFixAction = new QuickfixAction(sourceViewer); - } else { - cutAction = null; - undoAction = null; - redoAction = null; - pasteAction = null; - quickFixAction = null; } - TextViewerAction copyAction = createFromActionFactory( - ActionFactory.COPY, ITextOperationTarget.COPY); - TextViewerAction selectAllAction = createFromActionFactory( - ActionFactory.SELECT_ALL, ITextOperationTarget.SELECT_ALL); - - final TextEditorPropertyAction showWhitespaceAction = new TextEditorPropertyAction( - UIText.SpellcheckableMessageArea_showWhitespace, - sourceViewer, - AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS) { - - private IPainter whitespaceCharPainter; - - @Override - public void propertyChange(PropertyChangeEvent event) { - String property = event.getProperty(); - if (property.equals(getPreferenceKey()) - || AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN - .equals(property) - || AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED - .equals(property) - || AbstractTextEditor.PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE - .equals(property)) { - synchronizeWithPreference(); - } - } - - @Override - protected void toggleState(boolean checked) { - if (checked) - installPainter(); - else - uninstallPainter(); - } - - /** - * Installs the painter on the viewer. - */ - private void installPainter() { - Assert.isTrue(whitespaceCharPainter == null); - ITextViewer v = getTextViewer(); - if (v instanceof ITextViewerExtension2) { - IPreferenceStore store = getStore(); - whitespaceCharPainter = new WhitespaceCharacterPainter( - v, - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN), - store.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED), - store.getInt(AbstractTextEditor.PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE)); - ((ITextViewerExtension2) v).addPainter(whitespaceCharPainter); - } - } - - /** - * Remove the painter from the viewer. - */ - private void uninstallPainter() { - if (whitespaceCharPainter == null) - return; - ITextViewer v = getTextViewer(); - if (v instanceof ITextViewerExtension2) - ((ITextViewerExtension2) v) - .removePainter(whitespaceCharPainter); - whitespaceCharPainter.deactivate(true); - whitespaceCharPainter = null; - } - }; + final ShowWhitespaceAction showWhitespaceAction = new ShowWhitespaceAction( + sourceViewer, !editable); MenuManager contextMenu = new MenuManager(); - if (cutAction != null) { - contextMenu.add(cutAction); - } - contextMenu.add(copyAction); - if (pasteAction != null) { - contextMenu.add(pasteAction); - } - contextMenu.add(selectAllAction); - if (undoAction != null) { - contextMenu.add(undoAction); - } - if (redoAction != null) { - contextMenu.add(redoAction); - } + UpdateableAction[] standardActions = ActionUtils + .fillStandardTextActions(sourceViewer, editable, contextMenu); contextMenu.add(new Separator()); contextMenu.add(showWhitespaceAction); contextMenu.add(new Separator()); @@ -662,15 +400,10 @@ public class SpellcheckableMessageArea extends Composite { final StyledText textWidget = getTextWidget(); List<IAction> globalActions = new ArrayList<>(); - if (editable) { - globalActions.add(cutAction); - globalActions.add(pasteAction); - globalActions.add(undoAction); - globalActions.add(redoAction); + globalActions.addAll(Arrays.asList(standardActions)); + if (quickFixAction != null) { globalActions.add(quickFixAction); } - globalActions.add(copyAction); - globalActions.add(selectAllAction); if (contentAssistAction != null) { globalActions.add(contentAssistAction); } @@ -679,35 +412,25 @@ public class SpellcheckableMessageArea extends Composite { textWidget.setMenu(contextMenu.createContextMenu(textWidget)); - sourceViewer.addSelectionChangedListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent event) { - if (cutAction != null) - cutAction.update(); - copyAction.update(); - } - - }); + sourceViewer.addSelectionChangedListener(event -> { + if (standardActions[ITextOperationTarget.CUT] != null) { + standardActions[ITextOperationTarget.CUT].update(); + } + standardActions[ITextOperationTarget.COPY].update(); + }); if (editable) { - sourceViewer.addTextListener(new ITextListener() { - @Override - public void textChanged(TextEvent event) { - if (undoAction != null) - undoAction.update(); - if (redoAction != null) - redoAction.update(); + sourceViewer.addTextListener(event -> { + if (standardActions[ITextOperationTarget.UNDO] != null) { + standardActions[ITextOperationTarget.UNDO].update(); + } + if (standardActions[ITextOperationTarget.REDO] != null) { + standardActions[ITextOperationTarget.REDO].update(); } }); } - textWidget.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent disposeEvent) { - showWhitespaceAction.dispose(); - } - }); + textWidget.addDisposeListener(e -> showWhitespaceAction.dispose()); } private void addProposals(final SubMenuManager quickFixMenu) { @@ -848,8 +571,14 @@ public class SpellcheckableMessageArea extends Composite { private IAction createContentAssistAction( final SourceViewer viewer) { - Action proposalAction = new TextViewerAction(viewer, - ISourceViewer.CONTENTASSIST_PROPOSALS); + Action proposalAction = new Action() { + + @Override + public void run() { + viewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); + } + + }; proposalAction .setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); return proposalAction; diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/TextEditorPropertyAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/TextEditorPropertyAction.java new file mode 100644 index 0000000000..9df5386a1b --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/TextEditorPropertyAction.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2012, 2019 Tomasz Zarna (IBM) and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Thomas Wolf <thomas.wolf@paranor.ch> - Factored out of SpellcheckableMessageArea. + *******************************************************************************/ +package org.eclipse.egit.ui.internal.dialogs; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.editors.text.EditorsUI; + +/** + * An {@link Action} that operates on an {@link ITextViewer} that represents a + * boolean preference in the text editor preferences. When toggled, it toggles + * the persisted state and invokes {@link #toggleState(boolean)}, which is to be + * implemented by sub-classes to update the text viewer in response to the + * preference change. + */ +public abstract class TextEditorPropertyAction extends Action + implements IPropertyChangeListener, IWorkbenchAction { + + // Possibly originally copied from + // org.eclipse.compare.internal.TextEditorPropertyAction and adapted? + + private ITextViewer viewer; + + private String preferenceKey; + + private IPreferenceStore store; + + /** + * Creates a new {@link TextEditorPropertyAction}. + * + * @param label + * for the action + * @param viewer + * to operate on + * @param preferenceKey + * in the {@link EditorsUI#getPreferenceStore()} for this action + * @param initiallyOff + * if {@code true}, the action initially is not checked and does + * not reflect the preference state + */ + public TextEditorPropertyAction(String label, ITextViewer viewer, + String preferenceKey, boolean initiallyOff) { + super(label, IAction.AS_CHECK_BOX); + this.viewer = viewer; + this.preferenceKey = preferenceKey; + this.store = EditorsUI.getPreferenceStore(); + if (store != null) { + store.addPropertyChangeListener(this); + } + if (!initiallyOff) { + synchronizeWithPreference(); + } + } + + @Override + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(getPreferenceKey())) { + synchronizeWithPreference(); + } + } + + /** + * Reads the preference and calls {@link #toggleState(boolean)} as + * appropriate. + */ + protected void synchronizeWithPreference() { + boolean checked = false; + if (store != null) { + checked = store.getBoolean(getPreferenceKey()); + } + if (checked != isChecked()) { + setChecked(checked); + toggleState(checked); + } else if (checked) { + toggleState(false); + toggleState(true); + } + } + + /** + * Retrieves the preference key of this action. + * + * @return the preference key. + */ + protected String getPreferenceKey() { + return preferenceKey; + } + + @Override + public void run() { + toggleState(isChecked()); + if (store != null) { + store.setValue(getPreferenceKey(), isChecked()); + } + } + + @Override + public void dispose() { + if (store != null) { + store.removePropertyChangeListener(this); + } + } + + /** + * Updates the {@link ITextViewer} of this action as appropriate. + * + * @param checked + * new state + */ + abstract protected void toggleState(boolean checked); + + /** + * Retrieves the {@link ITextViewer} this action operates on. + * + * @return the {@link ITextViewer} + */ + protected ITextViewer getTextViewer() { + return viewer; + } + + /** + * Retrieves the {@link IPreferenceStore} this action operates on. + * + * @return the {@link IPreferenceStore}, or {@code null} if there is no + * preference store for text editors + */ + protected IPreferenceStore getStore() { + return store; + } +} + |