summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorDariusz Luksza2010-04-11 16:25:44 (EDT)
committer Matthias Sohn2010-05-12 18:20:44 (EDT)
commit708aa2d18f58c7a9655045b6fe5d0483fde89e6e (patch)
treeeb8da6a2fbb5c94ac17fa508209fdf8c3922afbb
parent3f61491eeb40bc79cf987d859d3b035ef854bc46 (diff)
downloadegit-708aa2d18f58c7a9655045b6fe5d0483fde89e6e.zip
egit-708aa2d18f58c7a9655045b6fe5d0483fde89e6e.tar.gz
egit-708aa2d18f58c7a9655045b6fe5d0483fde89e6e.tar.bz2
Add tagging UI supportrefs/changes/44/544/11
Implements UI for unsigned and annotated tags. This implementation allows the user to select which commit object should be associated with created tag. List of all commits is available in the 'Advanced' section of the dialog. There is a special combo widget that can suggest commits based on match of typed-in text with commit SHA-1 or part of first line of existing commit messages. User can also edit/overwrite tag message or associated commit of an existing tag by selecting it from the list of existing tags and marking the 'Force replace existing tag' check box. By default tag is created for current HEAD, this can be changed in the 'Advanced' section. The tag dialog is available in project's context menu ('Team->Tag...'). [ms]: rebased to master and resolved conflict CQ: 4073 Bug: 311262 Change-Id: Icb30655845d1e1198e59992a10148421ab9f9bd5 Signed-off-by: Dariusz Luksza <dariusz@luksza.org> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java9
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties6
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/op/TagOperation.java108
-rw-r--r--org.eclipse.egit.ui/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.egit.ui/plugin.properties3
-rw-r--r--org.eclipse.egit.ui/plugin.xml6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java72
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java25
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/SWTUtils.java7
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ValidationUtils.java57
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagAction.java183
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java15
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java27
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitCombo.java223
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java553
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties28
16 files changed, 1285 insertions, 40 deletions
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
index 3fda278..9c27f08 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
@@ -235,6 +235,15 @@ public class CoreText extends NLS {
/** */
public static String BranchOperation_performingBranch;
+ /** */
+ public static String TagOperation_performingTagging;
+
+ /** */
+ public static String TagOperation_taggingFailure;
+
+ /** */
+ public static String TagOperation_objectIdNotFound;
+
static {
initializeMessages("org.eclipse.egit.core.coretext", //$NON-NLS-1$
CoreText.class);
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
index 9d9221f..ded3690 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
@@ -96,4 +96,8 @@ AddToIndexOperation_failed=Failed to add resource to index
TrackOperation_writingIndex=Writing index for {0}
-BranchOperation_performingBranch=Performing branch to {0} \ No newline at end of file
+BranchOperation_performingBranch=Performing branch to {0}
+
+TagOperation_performingTagging=Making tag {0}
+TagOperation_taggingFailure=Tag {0} creation failed (cause: {1})
+TagOperation_objectIdNotFound=Could not find object Id associated with tag {0} (cause: {1}) \ No newline at end of file
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/TagOperation.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/TagOperation.java
new file mode 100644
index 0000000..abcfe6e
--- /dev/null
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/TagOperation.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.core.op;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.egit.core.CoreText;
+import org.eclipse.egit.core.internal.util.ProjectUtil;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Tag;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.team.core.TeamException;
+
+/**
+ * Tags repository with given {@link Tag} object.
+ */
+public class TagOperation implements IEGitOperation {
+
+ private final Tag tag;
+ private final Repository repo;
+ private final boolean shouldMoveTag;
+
+ /**
+ * Construct TagOperation
+ *
+ * @param repo
+ * @param tag
+ * @param shouldMoveTag if <code>true</code> it will replace tag with same name
+ */
+ public TagOperation(Repository repo, Tag tag, boolean shouldMoveTag) {
+ this.tag = tag;
+ this.repo = repo;
+ this.shouldMoveTag = shouldMoveTag;
+ }
+
+
+ public void execute(IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor.beginTask(NLS.bind(CoreText.TagOperation_performingTagging,
+ tag.getTag()), 3);
+
+ updateTagObject();
+ monitor.worked(1);
+
+ updateRepo();
+ monitor.worked(1);
+
+ ProjectUtil.refreshProjects(repo, SubMonitor.convert(monitor, 1));
+ } finally {
+ monitor.done();
+ }
+ }
+
+ private void updateRepo() throws TeamException {
+ String refName = Constants.R_TAGS + tag.getTag();
+
+ try {
+ RefUpdate tagRef = repo.updateRef(refName);
+ tagRef.setNewObjectId(tag.getTagId());
+
+ tagRef.setForceUpdate(shouldMoveTag);
+ Result updateResult = tagRef.update();
+
+ if (updateResult != Result.NEW && updateResult != Result.FORCED)
+ throw new TeamException(NLS.bind(CoreText.TagOperation_taggingFailure,
+ tag.getTag(), updateResult));
+ } catch (IOException e) {
+ throw new TeamException(NLS.bind(CoreText.TagOperation_taggingFailure,
+ tag.getTag(), e.getMessage()), e);
+ }
+ }
+
+ private void updateTagObject() throws TeamException {
+ ObjectId startPointRef = tag.getObjId();
+
+ try {
+ ObjectLoader object = repo.openObject(startPointRef);
+ tag.setType(Constants.typeString(object.getType()));
+ ObjectWriter objWriter = new ObjectWriter(repo);
+ tag.setTagId(objWriter.writeTag(tag));
+ } catch (IOException e) {
+ throw new TeamException(NLS.bind(CoreText.TagOperation_objectIdNotFound,
+ tag.getTag(), e.getMessage()), e);
+ }
+ }
+
+
+ public ISchedulingRule getSchedulingRule() {
+ return null;
+ }
+
+}
diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
index 2003a7a..b9e73e2 100644
--- a/org.eclipse.egit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
@@ -21,7 +21,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)",
org.eclipse.jsch.ui;bundle-version="[1.1.100,2.0.0)",
org.eclipse.jsch.core;bundle-version="[1.1.100,2.0.0)",
org.eclipse.ui.editors;bundle-version="[3.4.0,4.0.0)",
- com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
+ com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)",
+ org.eclipse.ui.forms;bundle-version="[3.3.100,4.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: org.eclipse.egit.core;version="[0.8.0,0.9.0)",
diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties
index 6f07596..7e8248c 100644
--- a/org.eclipse.egit.ui/plugin.properties
+++ b/org.eclipse.egit.ui/plugin.properties
@@ -66,6 +66,9 @@ ResetAction_tooltip=Reset the current branch to the same or another commit
BranchAction_label=&Branch...
BranchAction_tooltip=Switch to another branch
+TagAction_label=&Tag...
+TagAction_tooltip=Create or edit tag
+
FetchAction_label=&Fetch From...
FetchAction_tooltip=Fetch from another repository
diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml
index 9d72148..202611a 100644
--- a/org.eclipse.egit.ui/plugin.xml
+++ b/org.eclipse.egit.ui/plugin.xml
@@ -59,6 +59,12 @@
tooltip="%ResetAction_tooltip">
</action>
<action
+ class="org.eclipse.egit.ui.internal.actions.TagAction"
+ id="org.eclipse.egit.ui.internal.actions.TagAction"
+ label="%TagAction_label"
+ menubarPath="team.main/projectGroup"
+ tooltip="%TagAction_tooltip"/>
+ <action
class="org.eclipse.egit.ui.internal.actions.BranchAction"
id="org.eclipse.egit.ui.internal.actions.BranchAction"
label="%BranchAction_label"
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 e10cebd..575d8fc 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
@@ -1962,6 +1962,78 @@ public class UIText extends NLS {
/** */
public static String Update_update;
+ /** */
+ public static String TagAction_cannotCheckout;
+
+ /** */
+ public static String TagAction_cannotGetBranchName;
+
+ /** */
+ public static String TagAction_repositoryState;
+
+ /** */
+ public static String TagAction_errorCreatingTag;
+
+ /** */
+ public static String TagAction_unableToCreateTag;
+
+ /** */
+ public static String TagAction_errorDuringTagging;
+
+ /** */
+ public static String TagAction_errorWhileGettingRevCommits;
+
+ /** */
+ public static String TagAction_unableToResolveHeadObjectId;
+
+ /** */
+ public static String TagAction_errorWhileMappingRevTag;
+
+ /** */
+ public static String TagAction_creating;
+
+ /** */
+ public static String TagAction_taggingFailed;
+
+ /** */
+ public static String CreateTagDialog_tagName;
+
+ /** */
+ public static String CreateTagDialog_tagMessage;
+
+ /** */
+ public static String CreateTagDialog_questionNewTagTitle;
+
+ /** */
+ public static String CreateTagDialog_overwriteTag;
+
+ /** */
+ public static String CreateTagDialog_overwriteTagToolTip;
+
+ /** */
+ public static String CreateTagDialog_existingTags;
+
+ /** */
+ public static String CreateTagDialog_advanced;
+
+ /** */
+ public static String CreateTagDialog_advancedToolTip;
+
+ /** */
+ public static String CreateTagDialog_advancedMessage;
+
+ /** */
+ public static String CreateTagDialog_tagNameToolTip;
+
+ /** */
+ public static String CreateTagDialog_clearButton;
+
+ /** */
+ public static String CreateTagDialog_clearButtonTooltip;
+
+ /** */
+ public static String CommitCombo_showSuggestedCommits;
+
static {
initializeMessages("org.eclipse.egit.ui.uitext", UIText.class); //$NON-NLS-1$
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
index 58e3672..f811992 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
@@ -10,8 +10,12 @@
*******************************************************************************/
package org.eclipse.egit.ui;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.PlatformUI;
/**
@@ -37,4 +41,25 @@ public class UIUtils {
.getFontRegistry().getBold(id);
}
+ /**
+ * Adds little bulb decoration to given control. Bulb will appear in top left
+ * corner of control after giving focus for this control.
+ *
+ * After clicking on bulb image text from <code>tooltip</code> will appear.
+ *
+ * @param control instance of {@link Control} object with should be decorated
+ * @param tooltip text value which should appear after clicking on bulb image.
+ */
+ public static void addBulbDecorator(final Control control, final String tooltip) {
+ ControlDecoration dec = new ControlDecoration(control, SWT.TOP | SWT.LEFT);
+
+ dec.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(
+ FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage());
+
+ dec.setShowOnlyOnFocus(true);
+ dec.setShowHover(true);
+
+ dec.setDescriptionText(tooltip);
+ }
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/SWTUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/SWTUtils.java
index 976bc06..7b29120 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/SWTUtils.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/SWTUtils.java
@@ -19,7 +19,12 @@ import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.PreferenceLinkArea;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ValidationUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ValidationUtils.java
new file mode 100644
index 0000000..5f17754
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ValidationUtils.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.egit.ui.internal;
+
+import java.io.IOException;
+
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * A collection of validators
+ */
+public class ValidationUtils {
+
+ /**
+ * Creates and returns input validator for refNames
+ *
+ * @param repo
+ * @param refPrefix
+ * @return input validator for refNames
+ */
+ public static IInputValidator getRefNameInputValidator(final Repository repo, final String refPrefix) {
+ return new IInputValidator() {
+ public String isValid(String newText) {
+ if (newText.length() == 0) {
+ // nothing entered, just don't let the user proceed,
+ // no need to prompt them with an error message
+ return ""; //$NON-NLS-1$
+ }
+
+ String testFor = refPrefix + newText;
+ try {
+ if (repo.resolve(testFor) != null)
+ return UIText.BranchSelectionDialog_ErrorAlreadyExists;
+ } catch (IOException e1) {
+ Activator.logError(NLS.bind(
+ UIText.BranchSelectionDialog_ErrorCouldNotResolve, testFor), e1);
+ return e1.getMessage();
+ }
+ if (!Repository.isValidRefName(testFor))
+ return UIText.BranchSelectionDialog_ErrorInvalidRefName;
+ return null;
+ }
+ };
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagAction.java
new file mode 100644
index 0000000..ef6d198
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagAction.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.actions;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.egit.core.op.TagOperation;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.ValidationUtils;
+import org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator;
+import org.eclipse.egit.ui.internal.dialogs.CreateTagDialog;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Tag;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * An action for creating tag.
+ *
+ * @see TagOperation
+ */
+public class TagAction extends RepositoryAction {
+
+ private Repository repo;
+
+ @Override
+ public boolean isEnabled() {
+ return getRepository(false) != null;
+ }
+
+ @Override
+ protected void execute(IAction action) throws InvocationTargetException,
+ InterruptedException {
+ repo = getRepository(true);
+ if (repo == null)
+ return;
+
+ if (!repo.getRepositoryState().canCheckout()) {
+ MessageDialog.openError(getShell(),
+ UIText.TagAction_cannotCheckout, NLS.bind(
+ UIText.TagAction_repositoryState, repo
+ .getRepositoryState().getDescription()));
+ return;
+ }
+
+ String currentBranchName;
+ try {
+ currentBranchName = repo.getBranch();
+ } catch (IOException e) {
+ throw new InvocationTargetException(e,
+ UIText.TagAction_cannotGetBranchName);
+ }
+
+ CreateTagDialog dialog = new CreateTagDialog(getShell(),
+ ValidationUtils
+ .getRefNameInputValidator(repo, Constants.R_TAGS),
+ currentBranchName);
+
+ // get and set commits
+ RevWalk revCommits = getRevCommits();
+ dialog.setRevCommitList(revCommits);
+
+ // get and set existing tags
+ List<Tag> tags = getRevTags();
+ dialog.setExistingTags(tags);
+
+ if (dialog.open() != IDialogConstants.OK_ID)
+ return;
+
+ final Tag tag = new Tag(repo);
+ PersonIdent personIdent = new PersonIdent(repo);
+ String tagName = dialog.getTagName();
+
+ tag.setTag(tagName);
+ tag.setTagger(personIdent);
+ tag.setMessage(dialog.getTagMessage());
+
+ ObjectId tagCommit = getTagCommit(dialog.getTagCommit());
+ tag.setObjId(tagCommit);
+
+ String tagJobName = NLS.bind(UIText.TagAction_creating, tagName);
+ final boolean shouldMoveTag = dialog.shouldOverWriteTag();
+
+ Job tagJob = new Job(tagJobName) {
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ new TagOperation(repo, tag, shouldMoveTag).execute(monitor);
+ } catch (CoreException e) {
+ return Activator.createErrorStatus(
+ UIText.TagAction_taggingFailed, e);
+ } finally {
+ GitLightweightDecorator.refresh();
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ };
+
+ tagJob.setUser(true);
+ tagJob.schedule();
+ }
+
+ private List<Tag> getRevTags() {
+ Collection<Ref> revTags = repo.getTags().values();
+ List<Tag> tags = new ArrayList<Tag>();
+ for (Ref ref : revTags) {
+ try {
+ Tag tag = repo.mapTag(ref.getName());
+ tags.add(tag);
+ } catch (IOException e) {
+ ErrorDialog.openError(getShell(),
+ UIText.TagAction_errorDuringTagging, NLS.bind(
+ UIText.TagAction_errorWhileMappingRevTag, ref
+ .getName()), new Status(IStatus.ERROR,
+ Activator.getPluginId(), e.getMessage(), e));
+ }
+ }
+ return tags;
+ }
+
+ private RevWalk getRevCommits() {
+ RevWalk revWalk = new RevWalk(repo);
+ revWalk.sort(RevSort.COMMIT_TIME_DESC, true);
+ revWalk.sort(RevSort.BOUNDARY, true);
+
+ try {
+ AnyObjectId headId = repo.resolve(Constants.HEAD);
+ if (headId != null)
+ revWalk.markStart(revWalk.parseCommit(headId));
+ } catch (IOException e) {
+ ErrorDialog.openError(getShell(),
+ UIText.TagAction_errorDuringTagging,
+ UIText.TagAction_errorWhileGettingRevCommits, new Status(
+ IStatus.ERROR, Activator.getPluginId(), e
+ .getMessage(), e));
+ }
+
+ return revWalk;
+ }
+
+ private ObjectId getTagCommit(ObjectId objectId)
+ throws InvocationTargetException {
+ ObjectId result = null;
+ if (objectId == null) {
+ try {
+ result = repo.resolve(Constants.HEAD);
+ } catch (IOException e) {
+ throw new InvocationTargetException(e,
+ UIText.TagAction_unableToResolveHeadObjectId);
+ }
+ } else {
+ result = objectId;
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java
index d45e0fc..694e55e 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java
@@ -24,9 +24,8 @@ import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.UIUtils;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
-import org.eclipse.jface.fieldassist.ControlDecoration;
-import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
@@ -847,17 +846,7 @@ public class RepositorySelectionPage extends BaseWizardPage {
private void addContentProposalToUriText(Text uriTextField) {
- ControlDecoration dec = new ControlDecoration(uriTextField, SWT.TOP
- | SWT.LEFT);
-
- dec.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(
- FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage());
-
- dec.setShowOnlyOnFocus(true);
- dec.setShowHover(true);
-
- dec
- .setDescriptionText(UIText.RepositorySelectionPage_ShowPreviousURIs_HoverText);
+ UIUtils.addBulbDecorator(uriTextField, UIText.RepositorySelectionPage_ShowPreviousURIs_HoverText);
IContentProposalProvider cp = new IContentProposalProvider() {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
index 0772358..171d2c6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com.dewire.com>
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
@@ -22,9 +22,9 @@ import org.eclipse.egit.ui.internal.repository.RepositoriesViewContentProvider;
import org.eclipse.egit.ui.internal.repository.RepositoriesViewLabelProvider;
import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType;
+import org.eclipse.egit.ui.internal.ValidationUtils;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
@@ -308,28 +308,7 @@ public class BranchSelectionDialog extends Dialog {
getShell(),
UIText.BranchSelectionDialog_QuestionNewBranchTitle,
prompt,
- null, new IInputValidator() {
- public String isValid(String newText) {
- if (newText.length() == 0) {
- // nothing entered, just don't let the user proceed,
- // no need to prompt them with an error message
- return ""; //$NON-NLS-1$
- }
-
- String testFor = refPrefix + newText;
- try {
- if (repo.resolve(testFor) != null)
- return UIText.BranchSelectionDialog_ErrorAlreadyExists;
- } catch (IOException e1) {
- Activator.logError(NLS.bind(
- UIText.BranchSelectionDialog_ErrorCouldNotResolve, testFor), e1);
- return e1.getMessage();
- }
- if (!Repository.isValidRefName(testFor))
- return UIText.BranchSelectionDialog_ErrorInvalidRefName;
- return null;
- }
- });
+ null, ValidationUtils.getRefNameInputValidator(repo, refPrefix));
labelDialog.setBlockOnOpen(true);
return labelDialog;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitCombo.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitCombo.java
new file mode 100644
index 0000000..bfd7a74
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitCombo.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.UIUtils;
+import org.eclipse.jface.fieldassist.ComboContentAdapter;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.IContentProposal;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This is an extended version of {@link Combo} widget with is specialized in
+ * displaying commits and simplifying selection process.
+ *
+ * It is integrated with {@link ContentProposalAdapter} that helps select
+ * preferred tag by user. To get activate proposal provider simply just start
+ * writing commit SHA-1 or part of commit's message first line
+ */
+public class CommitCombo extends Composite {
+
+ private final List<ComboCommitEnt> commits;
+
+ private final Combo combo;
+
+ private class ComboCommitEnt {
+
+ private final String message;
+
+ private final ObjectId objectId;
+
+ public ComboCommitEnt(ObjectId objecId, String message) {
+ this.objectId = objecId;
+ this.message = message;
+ }
+
+ }
+
+ private class CommitContentProposalProvider implements
+ IContentProposalProvider {
+
+ public IContentProposal[] getProposals(String contents, int position) {
+ List<IContentProposal> list = new ArrayList<IContentProposal>();
+ Pattern pattern = Pattern.compile(contents,
+ Pattern.CASE_INSENSITIVE);
+ for (int i = 0; i < commits.size(); i++) {
+ String message = commits.get(i).message;
+ if (message.length() >= contents.length()
+ && pattern.matcher(message).find()) {
+ list.add(makeContentProposal(message));
+ }
+ }
+ return list.toArray(new IContentProposal[] {});
+ }
+
+ /*
+ * Make an IContentProposal for showing the specified String.
+ */
+ private IContentProposal makeContentProposal(final String proposal) {
+ return new IContentProposal() {
+ public String getContent() {
+ return proposal;
+ }
+
+ public String getDescription() {
+ return null;
+ }
+
+ public String getLabel() {
+ return null;
+ }
+
+ public int getCursorPosition() {
+ return proposal.length();
+ }
+ };
+ }
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ *
+ * @param parent
+ * a widget which will be the parent of the new instance (cannot
+ * be null)
+ * @param style
+ * the SWT style bits
+ */
+ public CommitCombo(Composite parent, int style) {
+ super(parent, style);
+
+ combo = new Combo(this, SWT.DROP_DOWN);
+ commits = new ArrayList<ComboCommitEnt>();
+
+ setLayout(GridLayoutFactory.swtDefaults().create());
+ setLayoutData(GridDataFactory.fillDefaults().create());
+
+ GridData totalLabelData = new GridData();
+ totalLabelData.horizontalAlignment = SWT.FILL;
+ totalLabelData.grabExcessHorizontalSpace = true;
+ combo.setLayoutData(totalLabelData);
+ combo.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (null == getValue())
+ combo.setText(""); //$NON-NLS-1$
+ }
+ });
+
+ UIUtils
+ .addBulbDecorator(combo,
+ UIText.CommitCombo_showSuggestedCommits);
+
+ ContentProposalAdapter adapter = new ContentProposalAdapter(combo,
+ new ComboContentAdapter(), new CommitContentProposalProvider(),
+ null, null);
+ adapter.setPropagateKeys(true);
+ adapter
+ .setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+ }
+
+ /**
+ * Add a {@link RevCommit} to widget.
+ *
+ * @param revCommit
+ */
+ public void add(RevCommit revCommit) {
+ Assert.isNotNull(revCommit);
+ checkWidget();
+
+ String shortSha1 = revCommit.getName().substring(0, 8);
+ String message = shortSha1 + ": " + revCommit.getShortMessage(); //$NON-NLS-1$
+ combo.add(message);
+ commits.add(new ComboCommitEnt(revCommit.getId(), message));
+ }
+
+ /**
+ * Returns value of SHA-1 for selected commit.
+ *
+ * @param index
+ * index of item in check box
+ * @return SHA-1 of selected commit
+ */
+ public ObjectId getItem(int index) {
+ checkWidget();
+
+ if (!(0 <= index && index < commits.size())) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ return commits.get(index).objectId;
+ }
+
+ /**
+ * @return index of selected element
+ */
+ public int getSelectedIndex() {
+ return combo.getSelectionIndex();
+ }
+
+ /**
+ * @return SHA-1 of selected commit
+ */
+ public ObjectId getValue() {
+ int selectionIndex = combo.getSelectionIndex();
+ return -1 != selectionIndex ? getItem(selectionIndex) : null;
+ }
+
+ /**
+ * Selects the item with is associated with given <code>objectId</code>
+ *
+ * @param objectId
+ */
+ public void setSelectedElement(ObjectId objectId) {
+ if (objectId == null) {
+ return;
+ }
+
+ for (int i = 0; i < commits.size(); i++)
+ if (objectId.equals(commits.get(i).objectId)) {
+ combo.select(i);
+ break;
+ }
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ combo.setEnabled(enabled);
+ super.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the selection in the receiver's text field to an empty selection
+ * starting just before the first character. If the text field is editable,
+ * this has the effect of placing the i-beam at the start of the text.
+ */
+ public void clearSelection() {
+ combo.clearSelection();
+ combo.setText(""); //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java
new file mode 100644
index 0000000..6bc6031
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java
@@ -0,0 +1,553 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.dialogs;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.UIUtils;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Tag;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+/**
+ * Dialog for creating and editing tags.
+ *
+ */
+public class CreateTagDialog extends Dialog {
+
+ /**
+ * Button id for a "Clear" button (value 22).
+ */
+ public static final int CLEAR_ID = 22;
+
+ private String tagName;
+
+ private String tagMessage;
+
+ private ObjectId tagCommit;
+
+ private boolean overwriteTag;
+
+ private RevWalk revCommits;
+
+ private List<Tag> existingTags;
+
+ private Tag tag;
+
+ private Text tagNameText;
+
+ private Text tagMessageText;
+
+ private Text tagNameErrorText;
+
+ private Button overwriteButton;
+
+ private TableViewer tagViewer;
+
+ private CommitCombo commitCombo;
+
+ private Pattern tagNamePattern;
+
+ private final String branchName;
+
+ private final IInputValidator tagNameValidator;
+
+ class TagInputList extends LabelProvider implements IWorkbenchAdapter {
+
+ private final List<Tag> tagList;
+
+ public TagInputList(List<Tag> tagList) {
+ this.tagList = tagList;
+ }
+
+ public Object[] getChildren(Object o) {
+ return tagList.toArray(new Object[] {});
+ }
+
+ public ImageDescriptor getImageDescriptor(Object object) {
+ return null;
+ }
+
+ public String getLabel(Object o) {
+ if (o instanceof Tag)
+ return ((Tag) o).getTag();
+
+ return null;
+ }
+
+ public Object getParent(Object o) {
+ return null;
+ }
+
+ public Object getAdapter(Class adapter) {
+ if (adapter == IWorkbenchAdapter.class)
+ return this;
+
+ return null;
+ }
+ }
+
+ class TagLabelProvider extends WorkbenchLabelProvider implements
+ ITableLabelProvider {
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ return ((Tag) element).getTag();
+ }
+
+ }
+
+ /**
+ * Construct dialog to creating or editing tag.
+ *
+ * @param parent
+ * @param tagNameValidator
+ * @param branchName
+ */
+ public CreateTagDialog(Shell parent, IInputValidator tagNameValidator,
+ String branchName) {
+ super(parent);
+ this.tagNameValidator = tagNameValidator;
+ this.branchName = branchName;
+ }
+
+ /**
+ * @return {@link ObjectId} of commit with new or edited tag should be
+ * associated with
+ */
+ public ObjectId getTagCommit() {
+ return tagCommit;
+ }
+
+ /**
+ * @return message for created or edited tag.
+ */
+ public String getTagMessage() {
+ return tagMessage;
+ }
+
+ /**
+ * @return name of new tag
+ */
+ public String getTagName() {
+ return tagName;
+ }
+
+ /**
+ * Indicates does tag should be forced to update (overwritten) or created.
+ *
+ * @return <code>true</code> if tag should be forced to update,
+ * <code>false</code> if tag should be created
+ */
+ public boolean shouldOverWriteTag() {
+ return overwriteTag;
+ }
+
+ /**
+ * Sets list of already existing tags. This list will be loaded in
+ * <code>Details</code> section of this dialog.
+ *
+ * @param existingTags
+ */
+ public void setExistingTags(List<Tag> existingTags) {
+ this.existingTags = existingTags;
+ }
+
+ /**
+ * Sets list of existing commits. This list will be loaded in
+ * {@link CommitCombo} widget in <code>Advanced</code> section of this
+ * dialog.
+ *
+ * @param revCommits
+ */
+ public void setRevCommitList(RevWalk revCommits) {
+ this.revCommits = revCommits;
+ }
+
+ /**
+ * Data from <code>tag</code> argument will be set in this dialog box.
+ *
+ * @param tag
+ */
+ public void setTag(Tag tag) {
+ this.tag = tag;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ if (branchName != null) {
+ newShell.setText(NLS.bind(
+ UIText.CreateTagDialog_questionNewTagTitle, branchName));
+ }
+
+ newShell.setMinimumSize(703, 345);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ parent.setLayout(GridLayoutFactory.swtDefaults().create());
+ parent.setLayoutData(GridDataFactory.fillDefaults().grab(true, false)
+ .create());
+
+ Button clearButton = createButton(parent, CLEAR_ID,
+ UIText.CreateTagDialog_clearButton, false);
+ clearButton.setToolTipText(UIText.CreateTagDialog_clearButtonTooltip);
+ setButtonLayoutData(clearButton);
+
+ Composite margin = new Composite(parent, SWT.NONE);
+ margin.setLayoutData(GridDataFactory.fillDefaults().grab(true, false)
+ .create());
+
+ super.createButtonsForButtonBar(parent);
+
+ validateInput();
+ }
+
+ @Override
+ protected Control createDialogArea(final Composite parent) {
+ initializeDialogUnits(parent);
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ final SashForm mainForm = new SashForm(composite, SWT.HORIZONTAL | SWT.FILL);
+ mainForm.setLayoutData(GridDataFactory.fillDefaults().grab(true, true)
+ .create());
+
+ createLeftSection(mainForm);
+ createExistingTagsSection(mainForm);
+
+ mainForm.setWeights(new int[] { 70, 30 });
+ if (tag != null) {
+ setTagImpl();
+ }
+
+ applyDialogFont(parent);
+ return composite;
+ }
+
+ @Override
+ protected void buttonPressed(int buttonId) {
+ switch (buttonId) {
+ case CLEAR_ID:
+ tagNameText.setText(""); //$NON-NLS-1$
+ tagMessageText.setText(""); //$NON-NLS-1$
+ commitCombo.clearSelection();
+
+ commitCombo.setEnabled(true);
+ tagNameText.setEnabled(true);
+ tagMessageText.setEnabled(true);
+ overwriteButton.setEnabled(false);
+ overwriteButton.setSelection(false);
+ break;
+ case IDialogConstants.OK_ID:
+ // read and store data from widgets
+ tagName = tagNameText.getText();
+ tagCommit = commitCombo.getValue();
+ tagMessage = tagMessageText.getText();
+ overwriteTag = overwriteButton.getSelection();
+ //$FALL-THROUGH$ continue propagating OK button action
+ default:
+ super.buttonPressed(buttonId);
+ }
+ }
+
+ @Override
+ protected boolean isResizable() {
+ return true;
+ }
+
+ private void createLeftSection(SashForm mainForm) {
+ Composite left = new Composite(mainForm, SWT.RESIZE);
+ left.setLayout(GridLayoutFactory.swtDefaults().margins(10, 5).create());
+ left.setLayoutData(GridDataFactory.fillDefaults().grab(true, true)
+ .create());
+
+ Label label = new Label(left, SWT.WRAP);
+ label.setText(UIText.CreateTagDialog_tagName);
+ GridData data = new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.HORIZONTAL_ALIGN_FILL
+ | GridData.VERTICAL_ALIGN_CENTER);
+ data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+ label.setLayoutData(data);
+ label.setFont(left.getFont());
+
+ tagNameText = new Text(left, SWT.SINGLE | SWT.BORDER);
+ tagNameText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.HORIZONTAL_ALIGN_FILL));
+ tagNameText.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ String textValue = Pattern.quote(tagNameText.getText());
+ tagNamePattern = Pattern.compile(textValue,
+ Pattern.CASE_INSENSITIVE);
+ tagViewer.refresh();
+ validateInput();
+ }
+ });
+
+ UIUtils.addBulbDecorator(tagNameText,
+ UIText.CreateTagDialog_tagNameToolTip);
+
+ tagNameErrorText = new Text(left, SWT.READ_ONLY | SWT.WRAP);
+ tagNameErrorText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.HORIZONTAL_ALIGN_FILL));
+ tagNameErrorText.setBackground(tagNameErrorText.getDisplay()
+ .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+
+ new Label(left, SWT.WRAP).setText(UIText.CreateTagDialog_tagMessage);
+
+ tagMessageText = new Text(left, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
+ tagMessageText.setLayoutData(GridDataFactory.fillDefaults().minSize(50,
+ 50).grab(true, true).create());
+
+ // key listener taken from CommitDialog.createDialogArea() allow to
+ // commit with ctrl-enter
+ tagMessageText.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent arg0) {
+ if (arg0.keyCode == SWT.CR
+ && (arg0.stateMask & SWT.CONTROL) > 0) {
+ Control button = getButton(IDialogConstants.OK_ID);
+ // fire OK action only when button is enabled
+ if (button != null && button.isEnabled())
+ buttonPressed(IDialogConstants.OK_ID);
+ } else if (arg0.keyCode == SWT.TAB
+ && (arg0.stateMask & SWT.SHIFT) == 0) {
+ arg0.doit = false;
+ tagMessageText.traverse(SWT.TRAVERSE_TAB_NEXT);
+ }
+ validateInput();
+ }
+ });
+
+ overwriteButton = new Button(left, SWT.CHECK);
+ overwriteButton.setEnabled(false);
+ overwriteButton.setText(UIText.CreateTagDialog_overwriteTag);
+ overwriteButton
+ .setToolTipText(UIText.CreateTagDialog_overwriteTagToolTip);
+ overwriteButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean state = overwriteButton.getSelection();
+ tagNameText.setEnabled(state);
+ commitCombo.setEnabled(state);
+ tagMessageText.setEnabled(state);
+ validateInput();
+ }
+ });
+
+ createAdvancedSection(left);
+ }
+
+ private void createAdvancedSection(final Composite composite) {
+ ExpandableComposite advanced = new ExpandableComposite(composite,
+ ExpandableComposite.TREE_NODE
+ | ExpandableComposite.CLIENT_INDENT);
+
+ advanced.setText(UIText.CreateTagDialog_advanced);
+ advanced.setToolTipText(UIText.CreateTagDialog_advancedToolTip);
+ advanced.setLayoutData(GridDataFactory.fillDefaults().grab(true, false)
+ .create());
+
+ Composite advancedComposite = new Composite(advanced, SWT.WRAP);
+ advancedComposite.setLayout(GridLayoutFactory.swtDefaults().create());
+ advancedComposite.setLayoutData(GridDataFactory.fillDefaults().grab(
+ true, true).create());
+
+ Label advancedLabel = new Label(advancedComposite, SWT.WRAP);
+ advancedLabel.setText(UIText.CreateTagDialog_advancedMessage);
+ advancedLabel.setLayoutData(GridDataFactory.fillDefaults().grab(true,
+ false).create());
+
+ commitCombo = new CommitCombo(advancedComposite, SWT.NORMAL);
+ commitCombo.setLayoutData(GridDataFactory.fillDefaults().grab(true,
+ false).create());
+
+ for (RevCommit revCommit : revCommits)
+ commitCombo.add(revCommit);
+
+ advanced.setClient(advancedComposite);
+ advanced.addExpansionListener(new ExpansionAdapter() {
+ public void expansionStateChanged(ExpansionEvent e) {
+ composite.layout();
+ }
+ });
+ }
+
+ private void createExistingTagsSection(Composite parent) {
+ Composite right = new Composite(parent, SWT.NORMAL);
+ right.setLayout(GridLayoutFactory.swtDefaults().create());
+ right.setLayoutData(GridLayoutFactory.fillDefaults().create());
+
+ new Label(right, SWT.WRAP).setText(UIText.CreateTagDialog_existingTags);
+
+ Table table = new Table(right, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER
+ | SWT.SINGLE);
+ table.setLayoutData(GridDataFactory.fillDefaults().grab(true, true)
+ .hint(80, 100).create());
+
+ TableLayout layout = new TableLayout();
+ layout.addColumnData(new ColumnWeightData(100, 20));
+ table.setLayout(layout);
+
+ tagViewer = new TableViewer(table);
+ tagViewer.setLabelProvider(new TagLabelProvider());
+ tagViewer.setContentProvider(new WorkbenchContentProvider());
+ tagViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ fillTagDialog();
+ }
+ });
+
+ tagViewer.setInput(new TagInputList(existingTags));
+ tagViewer.addFilter(new ViewerFilter() {
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement,
+ Object element) {
+ Tag tag = (Tag) element;
+
+ if (tagNamePattern != null)
+ return tagNamePattern.matcher(tag.getTag()).find();
+ else
+ return true;
+ }
+ });
+
+ applyDialogFont(parent);
+ }
+
+ private void validateInput() {
+ // don't validate if dialog is disposed
+ if (getShell() == null) {
+ return;
+ }
+
+ // validate tag name
+ String tagNameMessage = tagNameValidator.isValid(tagNameText.getText());
+ setTagNameError(tagNameMessage);
+
+ String tagMessageVal = tagMessageText.getText().trim();
+
+ Control button = getButton(IDialogConstants.OK_ID);
+ if (button != null) {
+ boolean containsTagNameAndMessage = (tagNameMessage == null || tagMessageVal
+ .length() == 0)
+ && tagMessageVal.length() != 0;
+ boolean shouldOverwriteTag = (overwriteButton.getSelection() && Repository
+ .isValidRefName(Constants.R_TAGS + tagNameText.getText()));
+
+ button.setEnabled(containsTagNameAndMessage || shouldOverwriteTag);
+ }
+ }
+
+ private void fillTagDialog() {
+ IStructuredSelection selection = (IStructuredSelection) tagViewer
+ .getSelection();
+ Object firstSelected = selection.getFirstElement();
+
+ if (firstSelected instanceof Tag) {
+ tag = (Tag) firstSelected;
+
+ if (!overwriteButton.isEnabled()) {
+ String tagMessageValue = tag.getMessage();
+ // don't enable OK button if we are dealing with un-annotated
+ // tag because JGit doesn't support them
+ if (tagMessageValue != null
+ && tagMessageValue.trim().length() != 0)
+ overwriteButton.setEnabled(true);
+
+ tagNameText.setEnabled(false);
+ commitCombo.setEnabled(false);
+ tagMessageText.setEnabled(false);
+ }
+
+ setTagImpl();
+ }
+ }
+
+ private void setTagImpl() {
+ tagNameText.setText(tag.getTag());
+ commitCombo.setSelectedElement(tag.getObjId());
+
+ // handle un-annotated tags
+ String message = tag.getMessage();
+ tagMessageText.setText(null != message ? message : ""); //$NON-NLS-1$
+ }
+
+ private void setTagNameError(String tagNameMessage) {
+ // copied form
+ // org.eclipse.jface.dialogs.InputDialog.setErrorMessage(String)
+ if (tagNameErrorText != null && !tagNameErrorText.isDisposed()) {
+ tagNameErrorText
+ .setText(tagNameMessage == null ? " \n " : tagNameMessage); //$NON-NLS-1$
+ // Disable the error message text control if there is no error, or
+ // no error text (empty or whitespace only). Hide it also to avoid
+ // color change.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=130281
+ boolean hasError = tagNameMessage != null
+ && (StringConverter.removeWhiteSpaces(tagNameMessage))
+ .length() > 0;
+ tagNameErrorText.setEnabled(hasError);
+ tagNameErrorText.setVisible(hasError);
+ tagNameErrorText.getParent().update();
+ }
+ }
+
+}
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 3d26a4c..232a283 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
@@ -514,6 +514,7 @@ BranchSelectionDialog_NewBranch=&New branch
BranchSelectionDialog_OkCheckout=&Checkout
BranchSelectionDialog_OkReset=&Reset
BranchSelectionDialog_QuestionNewBranchMessage=Enter name of the new branch. It will branch from the selected branch {0}. {1} will be prepended to the name you type
+BranchSelectionDialog_QuestionNewBranchNameMessage=Enter new name of the {0} branch. refs/heads/ will be prepended to the name you type
BranchSelectionDialog_QuestionNewBranchNameMessage=Enter new name of the {0} branch. {1} will be prepended to the name you type
BranchSelectionDialog_QuestionNewBranchTitle=New branch
BranchSelectionDialog_QuestionNewBranchNameTitle=Rename branch
@@ -699,3 +700,30 @@ UIIcons_errorDeterminingIconBase=Can't determine icon base.
UIIcons_errorLoadingPluginImage=Can't load plugin image.
Untrack_untrack=Untrack
Update_update=Update
+
+TagAction_cannotCheckout=Cannot checkout now
+TagAction_cannotGetBranchName=Cannot get actual branch name
+TagAction_repositoryState=Cannot checkout repository because it is in state: {0}
+TagAction_errorCreatingTag=Error while creating tag {0}
+TagAction_unableToCreateTag=Unable to create tag {0}
+TagAction_errorDuringTagging=Error during tagging
+TagAction_errorWhileMappingRevTag=Unable to get information about {0} tag.
+TagAction_errorWhileGettingRevCommits=An error occurred while getting list of commits.
+TagAction_unableToResolveHeadObjectId=Unable to resolve object id associated with current HEAD.
+TagAction_creating=Creating {0} tag.
+TagAction_taggingFailed=Tagging failed
+
+CreateTagDialog_tagName=Tag &name*:
+CreateTagDialog_tagMessage=Tag &message*:
+CreateTagDialog_questionNewTagTitle=Create new tag on branch "{0}"
+CreateTagDialog_overwriteTag=Force &replace existing tag
+CreateTagDialog_overwriteTagToolTip=Select this option if you want to change message or commit associated with already existing tag.
+CreateTagDialog_existingTags=Existing tags:
+CreateTagDialog_advanced=&Advanced
+CreateTagDialog_advancedToolTip=In the advanced section you may choose the commit to be tagged.
+CreateTagDialog_advancedMessage=Choose commit that should be associated with this tag.
+CreateTagDialog_tagNameToolTip=Start typing tag name to filter list of existing tags.
+CreateTagDialog_clearButton=C&lear
+CreateTagDialog_clearButtonTooltip=Clear all dialog fields.
+
+CommitCombo_showSuggestedCommits=Start typing SHA-1 of existing commit or part of first line in commit message to see suggested commits.