Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2019-11-04 03:45:53 -0500
committerThomas Wolf2019-11-24 05:32:34 -0500
commit7c7b2e528b16412f9325515121c9019b0a202cf5 (patch)
tree1c7df91389425cd24665906e8b8e5650f76a9ab6
parent1009fc591d26f3eb824d7c42edaefa9d9799cf72 (diff)
downloadegit-7c7b2e528b16412f9325515121c9019b0a202cf5.tar.gz
egit-7c7b2e528b16412f9325515121c9019b0a202cf5.tar.xz
egit-7c7b2e528b16412f9325515121c9019b0a202cf5.zip
[repo groups] inline renaming of repository groups
Set up editing support in the repositories view, triggered programmatically via the RenameRepositoryGroup handler. Also use inline renaming for creating groups: create the group with a unique name, then immediately start the rename process. If the user then cancels the name edit, there will be a new group with the unique default name. This behavior is consistent with the way folders are created in many graphical UIs, for instance on Windows or also on Mac. Remove the ellipsis from the menu items since the commands now don't open dialogs anymore. Pasting proved to be a problem since the view already has a paste command, which "stole" the paste and always handled it. Thus pasting into an open cell editor was not possible. JFace does have some support for overriding edit _actions_ when a cell editor is active, but I haven't found anything similar for commands. In the end I settled for making the PasteCommand simply call the view first to give it a chance to forward the paste to the cell editor. Change-Id: If1cda3768bb284d1a6801ec63dfaa80cb684e940 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
-rw-r--r--org.eclipse.egit.ui/plugin.properties4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryGroupsMenu.java7
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/MessagePopupTextCellEditor.java196
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/groups/RepositoryGroups.java24
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/DropAdapterAssistant.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java129
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateRepositoryGroupCommand.java67
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java8
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RenameRepositoryGroupCommand.java33
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties3
11 files changed, 399 insertions, 77 deletions
diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties
index f75f53333..5fd30f877 100644
--- a/org.eclipse.egit.ui/plugin.properties
+++ b/org.eclipse.egit.ui/plugin.properties
@@ -295,10 +295,10 @@ ChangeSetModel.name = Git Commits
RepoViewDeleteRepository.label = &Delete Repository...
DeleteRepositoryCommand.name = Delete Repository
CreateRepositoryGroupCommand.name = Create a Repository Group
-CreateRepositoryGroupCommand.label = Create a Repository &Group...
+CreateRepositoryGroupCommand.label = Create a Repository &Group
CreateRepositoryGroupCommand.description = Create a repository group for structuring repositories in the Git Repositories view
DeleteRepositoryGroupCommand.label = &Delete Repository Group...
-RenameRepositoryGroupCommand.label = &Rename Repository Group...
+RenameRepositoryGroupCommand.label = &Rename Repository Group
RepositoryGroupMenu.label = Repository &Groups
RepoViewAddRepository.tooltip = Add an existing local Git Repository to this view
RepoViewCloneRepository.tooltip = Clone a Git Repository and add the clone to this view
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
index fea64c5b3..3f1283fd9 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
@@ -3821,6 +3821,9 @@ public class UIText extends NLS {
public static String RepositoriesView_messageEmpty;
/** */
+ public static String RepositoriesView_NewGroupFormat;
+
+ /** */
public static String RepositoriesView_NothingToPasteMessage;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryGroupsMenu.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryGroupsMenu.java
index 67448958f..d3ef614bb 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryGroupsMenu.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryGroupsMenu.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2019, Alexander Nittka <alex@nittka.de>
+ * Copyright (C) 2019, Alexander Nittka <alex@nittka.de> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -15,7 +15,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.UUID;
import java.util.stream.Collectors;
import org.eclipse.egit.ui.internal.CommonUtils;
@@ -131,13 +130,13 @@ public class RepositoryGroupsMenu extends CompoundContributionItem
private IContributionItem getAssignGroupItem(RepositoryGroups groupsUtil,
RepositoryGroup group, List<File> selectedRepoDirectories) {
- final UUID id = group.getGroupId();
String actionTitle = NLS.bind(UIText.RepositoriesView_RepoGroup_Assign,
group.getName());
return new ActionContributionItem(new Action(actionTitle) {
@Override
public void runWithEvent(Event event) {
- groupsUtil.addRepositoriesToGroup(id, selectedRepoDirectories);
+ groupsUtil.addRepositoriesToGroup(group,
+ selectedRepoDirectories);
refreshRepositoriesView();
}
});
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/MessagePopupTextCellEditor.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/MessagePopupTextCellEditor.java
new file mode 100644
index 000000000..f384bb8fc
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/MessagePopupTextCellEditor.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Thomas Wolf <thomas.wolf@paranor.ch>
+ *
+ * All rights reserved. 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
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.components;
+
+import org.eclipse.egit.core.internal.Utils;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.jface.viewers.ICellEditorListener;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.window.DefaultToolTip;
+import org.eclipse.jface.window.ToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * A {@link TextCellEditor} that automatically shows any message from an
+ * {@link org.eclipse.jface.viewers.ICellEditorValidator ICellEditorValidator}
+ * in a {@link DefaultToolTip} pop-up. The tooltip by default has a delay of
+ * 200ms and a light red background. The tooltip can be obtained via
+ * {@link #getToolTip()} and then customized, if needed.
+ * <p>
+ * Additionally, this editor supports canceling the edit when the focus is lost.
+ * </p>
+ */
+public class MessagePopupTextCellEditor extends TextCellEditor {
+
+ /** Default pop-up delay in milliseconds. */
+ private static final int DEFAULT_DELAY_MILLIS = 200;
+
+ /**
+ * Default background color. See css/egit.css for the use of this pinkish
+ * color.
+ */
+ private static final RGB DEFAULT_BACKGROUND = new RGB(0xFF, 0x96, 0x96);
+
+ private final boolean cancelOnFocusLost;
+
+ private DefaultToolTip errorPopup;
+
+ /**
+ * Creates a new {@link MessagePopupTextCellEditor} parented under the given
+ * control. The editor will have the standard behavior of applying the value
+ * when it loses the focus.
+ *
+ * @param parent
+ * the parent control
+ * @see TextCellEditor#TextCellEditor(Composite)
+ */
+ public MessagePopupTextCellEditor(Composite parent) {
+ this(parent, false);
+ }
+
+ /**
+ * Creates a new {@link MessagePopupTextCellEditor} parented under the given
+ * control.
+ *
+ * @param parent
+ * the parent control
+ * @param cancelOnFocusLost
+ * whether to cancel the edit when the focus is lost
+ * @see TextCellEditor#TextCellEditor(Composite)
+ */
+ public MessagePopupTextCellEditor(Composite parent,
+ boolean cancelOnFocusLost) {
+ super(parent);
+ this.cancelOnFocusLost = cancelOnFocusLost;
+ }
+
+ /**
+ * Creates a new {@link MessagePopupTextCellEditor} parented under the given
+ * control using the given style. The editor will have the standard behavior
+ * of applying the value when it loses the focus.
+ *
+ * @param parent
+ * the parent control
+ * @param style
+ * the style bits
+ * @see TextCellEditor#TextCellEditor(Composite, int)
+ */
+ public MessagePopupTextCellEditor(Composite parent, int style) {
+ this(parent, false, style);
+ }
+
+ /**
+ * Creates a new {@link MessagePopupTextCellEditor} parented under the given
+ * control using the given style.
+ *
+ * @param parent
+ * the parent control
+ * @param cancelOnFocusLost
+ * whether to cancel the edit when the focus is lost
+ * @param style
+ * the style bits
+ * @see TextCellEditor#TextCellEditor(Composite, int)
+ */
+ public MessagePopupTextCellEditor(Composite parent,
+ boolean cancelOnFocusLost, int style) {
+ super(parent, style);
+ this.cancelOnFocusLost = cancelOnFocusLost;
+ }
+
+ /**
+ * This cell editor uses the built-in focus listener provided by the super
+ * class.
+ */
+ @Override
+ protected boolean dependsOnExternalFocusListener() {
+ return false;
+ }
+
+ /**
+ * Invoked when the cell editor has lost the focus; cancels the editor
+ * without applying the value.
+ */
+ @Override
+ protected void focusLost() {
+ // The super implementation applies the value, but that may be a bit
+ // risky. In some contexts edits should be done only if the user
+ // explicitly hit <return>.
+ if (cancelOnFocusLost) {
+ if (isActivated()) {
+ fireCancelEditor();
+ }
+ } else {
+ super.focusLost();
+ }
+ }
+
+ @Override
+ protected Control createControl(Composite parent) {
+ Control control = super.createControl(parent);
+ errorPopup = new DefaultToolTip(control, ToolTip.NO_RECREATE, true);
+ // A delay enables us to cancel showing the tooltip if the user keeps
+ // typing and the value is valid again.
+ errorPopup.setPopupDelay(DEFAULT_DELAY_MILLIS);
+ errorPopup.setBackgroundColor(Activator.getDefault()
+ .getResourceManager().createColor(DEFAULT_BACKGROUND));
+ control.addDisposeListener(event -> errorPopup.hide());
+ addListener(new ICellEditorListener() {
+
+ @Override
+ public void editorValueChanged(boolean oldValidState,
+ boolean newValidState) {
+ if (newValidState) {
+ errorPopup.hide();
+ return;
+ }
+ Control editor = getControl();
+ Point pos = editor.getSize();
+ errorPopup.setText(getErrorMessage());
+ pos.x = 0;
+ errorPopup.show(pos);
+ }
+
+ @Override
+ public void cancelEditor() {
+ errorPopup.hide();
+ }
+
+ @Override
+ public void applyEditorValue() {
+ errorPopup.hide();
+ }
+ });
+ // Since "text" in the super class is protected, we may rely on (a)
+ // super.createControl() having created and returned a Text, and (b) it
+ // having actually set "text", and (c) control == text.
+ if ((text.getStyle() & SWT.SINGLE) != 0) {
+ // Prevent pasting multi-line text into a single-line control. See
+ // bug 273470.
+ text.addVerifyListener(
+ event -> event.text = Utils.firstLine(event.text));
+ }
+ return control;
+ }
+
+ /**
+ * Retrieves the {@link DefaultToolTip} used for the validation message
+ * pop-up.
+ *
+ * @return the tooltip
+ */
+ public DefaultToolTip getToolTip() {
+ return errorPopup;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/groups/RepositoryGroups.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/groups/RepositoryGroups.java
index 50e7e64ce..53d40caec 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/groups/RepositoryGroups.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/groups/RepositoryGroups.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2019, Alexander Nittka <alex@nittka.de>
+ * Copyright (C) 2019, Alexander Nittka <alex@nittka.de> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -108,18 +108,24 @@ public final class RepositoryGroups {
}
/**
+ * Creates a new group with the given name.
+ *
* @param groupName
* valid name of the new group
- * @return id of the new group
+ * @return the new group
+ * @throws IllegalArgumentException
+ * if the name is invalid
+ * @throws IllegalStateException
+ * if a group with the given name already exists
*/
- public UUID createGroup(String groupName) {
+ public RepositoryGroup createGroup(String groupName) {
checkGroupName(groupName);
if (!groupExists(groupName)) {
UUID groupId = UUID.randomUUID();
RepositoryGroup group = new RepositoryGroup(groupId, groupName);
groupMap.put(groupId, group);
savePreferences();
- return groupId;
+ return group;
} else {
throw new IllegalStateException(
MessageFormat.format(
@@ -170,15 +176,15 @@ public final class RepositoryGroups {
* adds repositories to the given group and removes them from all other
* groups
*
- * @param groupId
- * id of group to which the repositories are added
+ * @param group
+ * to which the repositories are added
* @param repoDirs
* repository directories to be added to the group
*
*/
- public void addRepositoriesToGroup(UUID groupId,
+ public void addRepositoriesToGroup(RepositoryGroup group,
Collection<File> repoDirs) {
- if (!groupMap.containsKey(groupId)) {
+ if (!groupMap.containsKey(group.getGroupId())) {
throw new IllegalArgumentException();
}
Collection<RepositoryGroup> currentGroups = groupMap.values();
@@ -186,7 +192,7 @@ public final class RepositoryGroups {
groups.removeRepositoryDirectories(repoDirs);
}
- groupMap.get(groupId).addRepositoryDirectories(repoDirs);
+ group.addRepositoryDirectories(repoDirs);
savePreferences();
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/DropAdapterAssistant.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/DropAdapterAssistant.java
index 52363434c..d792f04a6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/DropAdapterAssistant.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/DropAdapterAssistant.java
@@ -126,7 +126,7 @@ public class DropAdapterAssistant extends CommonDropAdapterAssistant {
reposToAdd.add(repo.getRepository().getDirectory());
}
RepositoryGroups.getInstance().addRepositoriesToGroup(
- group.getObject().getGroupId(), reposToAdd);
+ group.getObject(), reposToAdd);
refreshRepositoriesView();
return Status.OK_STATUS;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
index 3a29668fc..868bbcbce 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
@@ -58,6 +58,9 @@ import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.actions.ActionCommands;
import org.eclipse.egit.ui.internal.branch.BranchOperationUI;
+import org.eclipse.egit.ui.internal.components.MessagePopupTextCellEditor;
+import org.eclipse.egit.ui.internal.groups.RepositoryGroup;
+import org.eclipse.egit.ui.internal.groups.RepositoryGroups;
import org.eclipse.egit.ui.internal.history.HistoryPageInput;
import org.eclipse.egit.ui.internal.reflog.ReflogView;
import org.eclipse.egit.ui.internal.repository.tree.FetchNode;
@@ -89,9 +92,15 @@ import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceColors;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewerEditor;
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.FocusCellHighlighter;
import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
@@ -100,7 +109,10 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewerEditor;
+import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
import org.eclipse.jface.window.Window;
import org.eclipse.jgit.events.ConfigChangedEvent;
import org.eclipse.jgit.events.ConfigChangedListener;
@@ -120,6 +132,7 @@ import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.team.ui.history.IHistoryView;
@@ -276,6 +289,8 @@ public class RepositoriesView extends CommonNavigator implements IShowInSource,
private IContextService ctxSrv;
+ private TextCellEditor textCellEditor;
+
/**
* The default constructor
*/
@@ -524,6 +539,7 @@ public class RepositoriesView extends CommonNavigator implements IShowInSource,
handleSingleRepositoryContext(viewer.getSelection(), viewer);
}
});
+ setupInlineEditing(viewer);
// react on selection changes
ISelectionService srv = CommonUtils.getService(getSite(), ISelectionService.class);
srv.addPostSelectionListener(selectionChangedListener);
@@ -580,6 +596,115 @@ public class RepositoriesView extends CommonNavigator implements IShowInSource,
}
}
+ private void setupInlineEditing(CommonViewer viewer) {
+ TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(
+ viewer, new FocusCellHighlighter(viewer) {
+ // Empty; SWT highlights already.
+ });
+
+ ColumnViewerEditorActivationStrategy editorActivation = new ColumnViewerEditorActivationStrategy(
+ viewer) {
+
+ @Override
+ protected boolean isEditorActivationEvent(
+ ColumnViewerEditorActivationEvent event) {
+ // Editing is started only through the
+ // RenameRepositoryGroupCommand
+ return event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
+ }
+ };
+
+ // TABBING_HORIZONTAL with only one column effectively switches off
+ // tabbing. It may jump otherwise into an open editor (closing the cell
+ // editor), and when the user is typing he may then inadvertently modify
+ // that file.
+ TreeViewerEditor.create(viewer, focusCellManager, editorActivation,
+ ColumnViewerEditor.TABBING_HORIZONTAL);
+
+ // Record the initial value so that the validator can avoid producing an
+ // error if the text is the same again during editing.
+ String initialValue[] = { null };
+
+ textCellEditor = new MessagePopupTextCellEditor(viewer.getTree(), true);
+ textCellEditor.setValidator(value -> {
+ String currentText = value.toString().trim();
+ if (currentText.isEmpty()) {
+ return UIText.RepositoriesView_RepoGroup_EmptyNameError;
+ }
+ if (!currentText.equals(initialValue[0]) && RepositoryGroups
+ .getInstance().groupExists(currentText)) {
+ return MessageFormat.format(
+ UIText.RepositoryGroups_DuplicateGroupNameError,
+ currentText);
+ }
+ return null;
+ });
+
+ // We don't have a ViewerColumn at hand... use the legacy mechanism:
+
+ viewer.setColumnProperties(new String[] { "Name" }); //$NON-NLS-1$
+ viewer.setCellEditors(new CellEditor[] { textCellEditor });
+ viewer.setCellModifier(new ICellModifier() {
+
+ @Override
+ public boolean canModify(Object element, String property) {
+ return element instanceof RepositoryGroupNode;
+ }
+
+ private String doGetValue(Object element) {
+ if (element instanceof RepositoryGroupNode) {
+ return ((RepositoryGroupNode) element).getObject()
+ .getName();
+ }
+ return null;
+ }
+
+ @Override
+ public Object getValue(Object element, String property) {
+ String result = doGetValue(element);
+ initialValue[0] = result;
+ return result;
+ }
+
+ @Override
+ public void modify(Object element, String property, Object value) {
+ if (element instanceof Item) {
+ element = ((Item) element).getData();
+ }
+ if (element instanceof RepositoryGroupNode
+ && value instanceof CharSequence) {
+ RepositoryGroup group = ((RepositoryGroupNode) element)
+ .getObject();
+ String newName = value.toString().trim();
+ if (!newName.equals(group.getName())) {
+ RepositoryGroups.getInstance().renameGroup(group,
+ newName);
+ // Refresh all to get re-sorting
+ viewer.refresh();
+ // Re-set the selection to get a status bar update
+ viewer.setSelection(new StructuredSelection(element),
+ true);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * If a text editor is open and has the focus, paste into it.
+ *
+ * @return {@code true} if there was a text editor that did paste,
+ * {@code false} otherwise
+ */
+ public boolean pasteInEditor() {
+ if (textCellEditor != null && textCellEditor.isActivated()) {
+ // We're editing
+ textCellEditor.performPaste();
+ return true;
+ }
+ return false;
+ }
+
private void executeOpenCommandWithConfirmation(RepositoryTreeNode element,
String refName) {
if (!BranchOperationUI.checkoutWillShowQuestionDialog(refName)) {
@@ -672,6 +797,10 @@ public class RepositoriesView extends CommonNavigator implements IShowInSource,
@Override
public void dispose() {
+ if (textCellEditor != null) {
+ textCellEditor.dispose();
+ textCellEditor = null;
+ }
if (reactOnSelection != null) {
reactOnSelection.removeListener(reactOnSelectionListener);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateRepositoryGroupCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateRepositoryGroupCommand.java
index 8935d3090..e208b60fd 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateRepositoryGroupCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateRepositoryGroupCommand.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2019, Alexander Nittka <alex@nittka.de>
+ * Copyright (C) 2019, Alexander Nittka <alex@nittka.de> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -19,14 +19,16 @@ import java.util.stream.Collectors;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.groups.RepositoryGroup;
import org.eclipse.egit.ui.internal.groups.RepositoryGroups;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryGroupNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNodeType;
-import org.eclipse.jface.dialogs.InputDialog;
-import org.eclipse.jface.window.Window;
-import org.eclipse.jgit.util.StringUtils;
-import org.eclipse.swt.widgets.Shell;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.ui.navigator.CommonViewer;
/**
* Creates a repository group, if repositories are selected, they are added to
@@ -44,16 +46,22 @@ public class CreateRepositoryGroupCommand
public Object execute(ExecutionEvent event) throws ExecutionException {
RepositoryGroups groupsUtil = RepositoryGroups.getInstance();
- String groupName = getNewGroupName(getActiveShell(event),
- UIText.RepositoriesView_RepoGroup_Create_Title, groupsUtil, ""); //$NON-NLS-1$
- if (groupName != null) {
- UUID groupId = groupsUtil.createGroup(groupName);
- List<File> repoDirs = getSelectedRepositories(event);
- if (!repoDirs.isEmpty()) {
- groupsUtil.addRepositoriesToGroup(groupId, repoDirs);
- }
- getView(event).refresh();
+ RepositoryGroup group;
+ try {
+ group = groupsUtil.createGroup(newGroupName(groupsUtil));
+ } catch (IllegalStateException e) {
+ throw new ExecutionException(e.getLocalizedMessage(), e);
+ }
+ List<File> repoDirs = getSelectedRepositories(event);
+ if (!repoDirs.isEmpty()) {
+ groupsUtil.addRepositoriesToGroup(group, repoDirs);
}
+ CommonViewer viewer = getView(event).getCommonViewer();
+ viewer.refresh();
+ viewer.setSelection(
+ new StructuredSelection(new RepositoryGroupNode(group)), true);
+ IStructuredSelection sel = viewer.getStructuredSelection();
+ viewer.editElement(sel.getFirstElement(), 0);
return null;
}
@@ -67,27 +75,16 @@ public class CreateRepositoryGroupCommand
.collect(Collectors.toList());
}
- static String getNewGroupName(Shell shell, String title,
- RepositoryGroups groupsUtil, String initialName) {
- InputDialog inputDialog = new InputDialog(shell, title,
- UIText.RepositoriesView_RepoGroup_EnterName, initialName,
- name -> {
- if (name == null
- || StringUtils.isEmptyOrNull(name.trim())) {
- return UIText.RepositoriesView_RepoGroup_EmptyNameError;
- }
- if (groupsUtil.groupExists(name.trim())) {
- return MessageFormat.format(
- UIText.RepositoryGroups_DuplicateGroupNameError,
- name.trim());
- }
- return null;
- });
-
- if (inputDialog.open() == Window.OK) {
- return inputDialog.getValue().trim();
- } else {
- return null;
+ private static @NonNull String newGroupName(RepositoryGroups groups) {
+ for (int i = 1; i < 100; i++) {
+ String name = MessageFormat.format(
+ UIText.RepositoriesView_NewGroupFormat, Integer.valueOf(i));
+ if (name != null && !groups.groupExists(name)) {
+ return name;
+ }
}
+ // Come on!
+ return MessageFormat.format(UIText.RepositoriesView_NewGroupFormat,
+ Integer.valueOf(1)) + ' ' + UUID.randomUUID().toString();
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java
index ef6bf97cc..2a4e17fa1 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java
@@ -1,5 +1,6 @@
/*******************************************************************************
- * Copyright (c) 2010-2011 SAP AG.
+ * Copyright (c) 2010, 2019 SAP AG and others.
+ *
* All rights reserved. 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
@@ -21,6 +22,7 @@ import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.components.RepositorySelectionPage.Protocol;
+import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.lib.Constants;
@@ -51,6 +53,10 @@ public class PasteCommand extends
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoriesView view = getView(event);
+ if (view.pasteInEditor()) {
+ return null;
+ }
// we check if the pasted content is a directory
// repository location and try to add this
String errorMessage = null;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RenameRepositoryGroupCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RenameRepositoryGroupCommand.java
index 939a87a1d..c5cbcf88e 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RenameRepositoryGroupCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RenameRepositoryGroupCommand.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2019, Alexander Nittka <alex@nittka.de>
+ * Copyright (C) 2019, Alexander Nittka <alex@nittka.de> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -14,9 +14,9 @@ import java.util.List;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
-import org.eclipse.egit.ui.internal.groups.RepositoryGroup;
-import org.eclipse.egit.ui.internal.groups.RepositoryGroups;
+import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryGroupNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
@@ -28,31 +28,16 @@ public class RenameRepositoryGroupCommand
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
- RepositoryGroups groupsUtil = RepositoryGroups.getInstance();
-
- RepositoryGroup group = getSelectedGroup(event);
- String groupName =
- CreateRepositoryGroupCommand.getNewGroupName(getActiveShell(event),
- UIText.RepositoriesView_RepoGroup_Rename_Title,
- groupsUtil,
- group.getName());
- if (groupName != null) {
- groupsUtil.renameGroup(group, groupName);
- getView(event).refresh();
- }
- return null;
- }
-
- private RepositoryGroup getSelectedGroup(ExecutionEvent event)
- throws ExecutionException {
List<RepositoryTreeNode> elements = getSelectedNodes(event);
if (elements.size() == 1
&& elements.get(0) instanceof RepositoryGroupNode) {
- return ((RepositoryGroupNode) elements.get(0)).getObject();
+ RepositoriesView view = getView(event);
+ view.getCommonViewer().editElement(elements.get(0), 0);
} else {
- throw new ExecutionException(
- UIText.RepositoriesView_RepoGroup_Rename_IllegalSelection);
+ Activator.logError(
+ UIText.RepositoriesView_RepoGroup_Rename_IllegalSelection,
+ null);
}
+ return null;
}
-
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
index c3ba5316f..16e974356 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
@@ -1351,12 +1351,13 @@ RepositoriesView_linkAdd=Add an existing local Git repository
RepositoriesView_linkClone=Clone a Git repository
RepositoriesView_linkCreate=Create a new local Git repository
RepositoriesView_messageEmpty=Select one of the following to add a repository to this view:
+RepositoriesView_NewGroupFormat=New Group{0,choice,1#|1< {0}}
RepositoriesView_NothingToPasteMessage=Clipboard contains no data to paste.
RepositoriesView_PasteRepoAlreadyThere=Repository at location {0} is already in the list.
RepositoriesView_RemotesNodeText=Remotes
RepositoriesView_TagDeletionFailureMessage=Deletion of tags failed
RepositoriesView_WorkingDir_treenode=Working Tree
-RepositoriesView_RepoGroup_Create_MenuItemLabel=Create Repository Group...
+RepositoriesView_RepoGroup_Create_MenuItemLabel=Create Repository Group
RepositoriesView_RepoGroup_Create_Title=Create Repository Group
RepositoriesView_RepoGroup_Assign=Move to ''{0}''
RepositoriesView_RepoGroup_Remove_Title=Remove from Repository Group

Back to the top