summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorBenjamin Muskalla2010-08-02 21:21:24 (EDT)
committer Chris Aniszczyk2010-08-03 12:49:34 (EDT)
commit71a9fd0e76343f4e13fd987600b2d703f8f12607 (patch)
tree039803cfa273b9b7a9f5d7117d8cb441998f47f7
parent0fd896dd5cc4fdab36aeb99fea0245607baa18c1 (diff)
downloadegit-71a9fd0e76343f4e13fd987600b2d703f8f12607.zip
egit-71a9fd0e76343f4e13fd987600b2d703f8f12607.tar.gz
egit-71a9fd0e76343f4e13fd987600b2d703f8f12607.tar.bz2
Support spellchecking in commit dialogrefs/changes/13/1213/2
In order to improve user expierence during commit, this introduces spellchecking and quick fixes for the commit message. In addition, a margin was added to help wrapping the commit messages. In the future, it may be feasible to have preferences for the margin width and visibility. Bug: 318530 Change-Id: Ic88c1ae82318311bf74eea9b979895dc39711856 Signed-off-by: Benjamin Muskalla <bmuskalla@eclipsesource.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java12
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java25
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageArea.java375
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties4
4 files changed, 402 insertions, 14 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index fb2ca3a..a127be6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -1201,6 +1201,18 @@ public class UIText extends NLS {
public static String ConfigureUriPage_Remove_button;
/** */
+ public static String CommitMessageArea_copy;
+
+ /** */
+ public static String CommitMessageArea_cut;
+
+ /** */
+ public static String CommitMessageArea_paste;
+
+ /** */
+ public static String CommitMessageArea_selectAll;
+
+ /** */
public static String CommitMessageViewer_author;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
index ddcdff1..a7816d3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
@@ -162,7 +162,7 @@ public class CommitDialog extends Dialog {
IDialogConstants.CANCEL_LABEL, false);
}
- Text commitText;
+ CommitMessageArea commitText;
Text authorText;
Text committerText;
Button amendingButton;
@@ -191,19 +191,19 @@ public class CommitDialog extends Dialog {
label.setText(UIText.CommitDialog_CommitMessage);
label.setLayoutData(GridDataFactory.fillDefaults().span(2, 1).grab(true, false).create());
- commitText = new Text(container, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
+ commitText = new CommitMessageArea(container, commitMessage);
commitText.setLayoutData(GridDataFactory.fillDefaults().span(2, 1).grab(true, true)
.hint(600, 200).create());
// allow to commit with ctrl-enter
- commitText.addKeyListener(new KeyAdapter() {
- public void keyPressed(KeyEvent arg0) {
- if (arg0.keyCode == SWT.CR
- && (arg0.stateMask & SWT.CONTROL) > 0) {
+ commitText.getTextWidget().addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent event) {
+ if (event.keyCode == SWT.CR
+ && (event.stateMask & SWT.CONTROL) > 0) {
okPressed();
- } else if (arg0.keyCode == SWT.TAB
- && (arg0.stateMask & SWT.SHIFT) == 0) {
- arg0.doit = false;
+ } else if (event.keyCode == SWT.TAB
+ && (event.stateMask & SWT.SHIFT) == 0) {
+ event.doit = false;
commitText.traverse(SWT.TRAVERSE_TAB_NEXT);
}
}
@@ -346,19 +346,16 @@ public class CommitDialog extends Dialog {
showUntrackedButton.setSelection(showUntracked);
- showUntrackedButton.addSelectionListener(new SelectionListener() {
+ showUntrackedButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
showUntracked = showUntrackedButton.getSelection();
filesViewer.refresh(true);
}
- public void widgetDefaultSelected(SelectionEvent e) {
- // Empty
- }
});
- commitText.addModifyListener(new ModifyListener() {
+ commitText.getTextWidget().addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateSignedOffButton();
updateChangeIdButton();
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageArea.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageArea.java
new file mode 100644
index 0000000..aebcfcd
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageArea.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Benjamin Muskalla <bmuskalla@eclipsesource.com>
+ *
+ * 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:
+ * Benjamin Muskalla (EclipseSource) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.dialogs;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+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.commands.ActionHandler;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.MarginPainter;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
+import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.text.source.IAnnotationAccess;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.ISharedTextColors;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+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.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+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;
+
+/**
+ * Text field with support for spellchecking.
+ */
+public class CommitMessageArea extends Composite {
+
+ private static class TextViewerAction extends Action implements IUpdate {
+
+ private int fOperationCode= -1;
+ private ITextOperationTarget fOperationTarget;
+
+ /**
+ * Creates a new action.
+ *
+ * @param viewer the viewer
+ * @param operationCode the opcode
+ */
+ public TextViewerAction(ITextViewer viewer, int operationCode) {
+ fOperationCode= operationCode;
+ fOperationTarget= viewer.getTextOperationTarget();
+ update();
+ }
+
+ /**
+ * Updates the enabled state of the action.
+ * Fires a property change if the enabled state changes.
+ *
+ * @see Action#firePropertyChange(String, Object, Object)
+ */
+ public void update() {
+ // XXX: workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=206111
+ if (fOperationCode == ITextOperationTarget.REDO)
+ return;
+
+ boolean wasEnabled= isEnabled();
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ setEnabled(isEnabled);
+
+ if (wasEnabled != isEnabled) {
+ firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE);
+ }
+ }
+
+ /**
+ * @see Action#run()
+ */
+ public void run() {
+ if (fOperationCode != -1 && fOperationTarget != null) {
+ fOperationTarget.doOperation(fOperationCode);
+ }
+ }
+ }
+
+ private final SourceViewer sourceViewer;
+
+ /**
+ * @param parent
+ * @param initialText
+ */
+ public CommitMessageArea(Composite parent, String initialText) {
+ super(parent, SWT.BORDER);
+ setLayout(new FillLayout());
+
+ AnnotationModel annotationModel = new AnnotationModel();
+ sourceViewer = new SourceViewer(this, null, null, true, SWT.MULTI
+ | SWT.V_SCROLL | SWT.WRAP);
+ getTextWidget().setIndent(2);
+
+ createMarginPainter();
+
+ final SourceViewerDecorationSupport support = configureAnnotationPreferences();
+ final IHandlerActivation handlerActivation = installQuickFixActionHandler();
+
+ configureContextMenu();
+
+ Document document = new Document(initialText);
+
+ sourceViewer.configure(new TextSourceViewerConfiguration(EditorsUI
+ .getPreferenceStore()));
+ sourceViewer.setDocument(document, annotationModel);
+
+ getTextWidget().addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent disposeEvent) {
+ support.uninstall();
+ getHandlerService().deactivateHandler(handlerActivation);
+ }
+ });
+ }
+
+ private void configureContextMenu() {
+ final TextViewerAction cutAction = new TextViewerAction(sourceViewer, ITextOperationTarget.CUT);
+ cutAction.setText(UIText.CommitMessageArea_cut);
+ cutAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_CUT);
+
+ final TextViewerAction copyAction = new TextViewerAction(sourceViewer, ITextOperationTarget.COPY);
+ copyAction.setText(UIText.CommitMessageArea_copy);
+ copyAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY);
+
+ final TextViewerAction pasteAction = new TextViewerAction(sourceViewer, ITextOperationTarget.PASTE);
+ pasteAction.setText(UIText.CommitMessageArea_paste);
+ pasteAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_PASTE);
+
+ final TextViewerAction selectAllAction = new TextViewerAction(sourceViewer, ITextOperationTarget.SELECT_ALL);
+ selectAllAction.setText(UIText.CommitMessageArea_selectAll);
+ selectAllAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_SELECT_ALL);
+
+ MenuManager contextMenu = new MenuManager();
+ contextMenu.add(cutAction);
+ contextMenu.add(copyAction);
+ contextMenu.add(pasteAction);
+ contextMenu.add(selectAllAction);
+ contextMenu.add(new Separator());
+
+ final SubMenuManager quickFixMenu = new SubMenuManager(contextMenu);
+ quickFixMenu.setVisible(true);
+ quickFixMenu.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ quickFixMenu.removeAll();
+ addProposals(quickFixMenu);
+ }
+ });
+ StyledText textWidget = getTextWidget();
+ getTextWidget().setMenu(contextMenu.createContextMenu(textWidget));
+
+ getTextWidget().addFocusListener(new FocusListener() {
+
+ private IHandlerActivation cutHandlerActivation;
+ private IHandlerActivation copyHandlerActivation;
+ private IHandlerActivation pasteHandlerActivation;
+ private IHandlerActivation selectAllHandlerActivation;
+
+ public void focusGained(FocusEvent e) {
+ cutAction.update();
+ copyAction.update();
+ IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
+ this.cutHandlerActivation = service.activateHandler(IWorkbenchCommandConstants.EDIT_CUT, new ActionHandler(cutAction), new ActiveShellExpression(getParent().getShell()));
+ this.copyHandlerActivation = service.activateHandler(IWorkbenchCommandConstants.EDIT_COPY, new ActionHandler(copyAction), new ActiveShellExpression(getParent().getShell()));
+ this.pasteHandlerActivation = service.activateHandler(IWorkbenchCommandConstants.EDIT_PASTE, new ActionHandler(pasteAction), new ActiveShellExpression(getParent().getShell()));
+ this.selectAllHandlerActivation = service.activateHandler(IWorkbenchCommandConstants.EDIT_SELECT_ALL, new ActionHandler(selectAllAction), new ActiveShellExpression(getParent().getShell()));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.FocusAdapter#focusLost(org.eclipse.swt.events.FocusEvent)
+ */
+ public void focusLost(FocusEvent e) {
+ IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
+
+ if (cutHandlerActivation != null) {
+ service.deactivateHandler(cutHandlerActivation);
+ }
+
+ if (copyHandlerActivation != null) {
+ service.deactivateHandler(copyHandlerActivation);
+ }
+
+ if (pasteHandlerActivation != null) {
+ service.deactivateHandler(pasteHandlerActivation);
+ }
+
+ if (selectAllHandlerActivation != null) {
+ service.deactivateHandler(selectAllHandlerActivation);
+ }
+ }
+
+ });
+
+ sourceViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ cutAction.update();
+ copyAction.update();
+ }
+
+ });
+ }
+
+ private void addProposals(final SubMenuManager quickFixMenu) {
+ IAnnotationModel sourceModel = sourceViewer.getAnnotationModel();
+ Iterator annotationIterator = sourceModel.getAnnotationIterator();
+ while (annotationIterator.hasNext()) {
+ Annotation annotation = (Annotation) annotationIterator.next();
+ boolean isDeleted = annotation.isMarkedDeleted();
+ boolean isIncluded = includes(sourceModel.getPosition(annotation),
+ getTextWidget().getCaretOffset());
+ boolean isFixable = sourceViewer.getQuickAssistAssistant().canFix(
+ annotation);
+ if (!isDeleted && isIncluded && isFixable) {
+ IQuickAssistProcessor processor = sourceViewer
+ .getQuickAssistAssistant()
+ .getQuickAssistProcessor();
+ IQuickAssistInvocationContext context = sourceViewer
+ .getQuickAssistInvocationContext();
+ ICompletionProposal[] proposals = processor
+ .computeQuickAssistProposals(context);
+
+ for (ICompletionProposal proposal : proposals)
+ quickFixMenu.add(createQuickFixAction(proposal));
+ }
+ }
+ }
+
+ private boolean includes(Position position, int caretOffset) {
+ return position.includes(caretOffset)
+ || (position.offset + position.length) == caretOffset;
+ }
+
+ private IAction createQuickFixAction(final ICompletionProposal proposal) {
+ return new Action(proposal.getDisplayString()) {
+
+ public void run() {
+ proposal.apply(sourceViewer.getDocument());
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ Image image = proposal.getImage();
+ if (image != null) {
+ return ImageDescriptor.createFromImage(image);
+ }
+ return null;
+ }
+ };
+ }
+
+ private IHandlerService getHandlerService() {
+ final IHandlerService handlerService = (IHandlerService) PlatformUI
+ .getWorkbench().getService(IHandlerService.class);
+ return handlerService;
+ }
+
+ private SourceViewerDecorationSupport configureAnnotationPreferences() {
+ ISharedTextColors textColors = EditorsUI.getSharedTextColors();
+ IAnnotationAccess annotationAccess = new DefaultMarkerAnnotationAccess();
+ final SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(
+ sourceViewer, null, annotationAccess, textColors);
+
+ List annotationPreferences = new MarkerAnnotationPreferences()
+ .getAnnotationPreferences();
+ Iterator e = annotationPreferences.iterator();
+ while (e.hasNext())
+ support.setAnnotationPreference((AnnotationPreference) e.next());
+
+ support.install(EditorsUI.getPreferenceStore());
+ return support;
+ }
+
+ private void createMarginPainter() {
+ MarginPainter marginPainter = new MarginPainter(sourceViewer);
+ marginPainter.setMarginRulerColumn(65);
+ marginPainter.setMarginRulerColor(Display.getDefault().getSystemColor(
+ SWT.COLOR_GRAY));
+ sourceViewer.addPainter(marginPainter);
+ }
+
+ /**
+ * @return widget
+ */
+ public StyledText getTextWidget() {
+ return sourceViewer.getTextWidget();
+ }
+
+ private IHandlerActivation installQuickFixActionHandler() {
+ IHandlerService handlerService = getHandlerService();
+ ActionHandler handler = createQuickFixActionHandler(sourceViewer);
+ ActiveShellExpression expression = new ActiveShellExpression(
+ sourceViewer.getTextWidget().getShell());
+ return handlerService.activateHandler(
+ ITextEditorActionDefinitionIds.QUICK_ASSIST, handler,
+ expression);
+ }
+
+ private ActionHandler createQuickFixActionHandler(
+ final ITextOperationTarget textOperationTarget) {
+ Action quickFixAction = new Action() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ public void run() {
+ textOperationTarget.doOperation(ISourceViewer.QUICK_ASSIST);
+ }
+ };
+ quickFixAction
+ .setActionDefinitionId(ITextEditorActionDefinitionIds.QUICK_ASSIST);
+ return new ActionHandler(quickFixAction);
+ }
+
+ /**
+ * @return text
+ */
+ public String getText() {
+ return getTextWidget().getText();
+ }
+
+ /**
+ * @param text
+ */
+ public void setText(String text) {
+ getTextWidget().setText(text);
+ }
+
+ /**
+ *
+ */
+ public boolean setFocus() {
+ return getTextWidget().setFocus();
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index ec1d13e..7f0aabc 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -427,6 +427,10 @@ ConfigureUriPage_MissingUris_message=No URIs specified
ConfigureUriPage_ParsingProblem_message=Can not parse this
ConfigureUriPage_Remove_button=Remove
+CommitMessageArea_copy=&Copy
+CommitMessageArea_cut=C&ut
+CommitMessageArea_paste=&Paste
+CommitMessageArea_selectAll=Select &All
CommitMessageViewer_author=Author
CommitMessageViewer_child=Child
CommitMessageViewer_commit=commit