Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2017-07-13 08:30:53 +0000
committerMatthias Sohn2017-07-13 21:00:42 +0000
commit56991ad4ed5b8977a641307802743601fc215e5f (patch)
treec6c8a1757dd622cd29d4cf50e5c1a6022f97337b
parent500d12d02986d3deb206d21975ccc6e87e7e7d73 (diff)
downloadegit-56991ad4ed5b8977a641307802743601fc215e5f.tar.gz
egit-56991ad4ed5b8977a641307802743601fc215e5f.tar.xz
egit-56991ad4ed5b8977a641307802743601fc215e5f.zip
Toolbar button to switch repositories in git views
Enable the user to quickly switch the staging view, the reflog view, the rebase interactive view, or the history view from one repository to another via a toolbar button with a drop-down menu listing all currently configured git repositories. Switching in one view makes all other EGit views that are linked to the current selection also switch. The current repository of a view, if any, is marked by a check mark in the menu. Use the "repository" image for the new button. Change the icon for "no filter" in history view to avoid a clash: instead of the repository icon, use a struck-out filter icon. Make sure all Git views provide selections that do adapt to Repository. This was already the case for the repositories view, the history view, and partly the staging view. For the reflog view, add an adaptable DTO wrapper around ReflogEntry for the tree. In staging view, add a MultiViewerSelectionProvider modeled after the JDT's SelectionProviderMediator that can provide the selection from whichever viewer has the focus. In the rebase interactive view, make PlanElement adapt to Repository, and fix some other minor bugs: don't clear when the linked selection is empty, don't show "No Repository Selected" briefly when a bare repo is selected, react on the initial selection in createControl() instead of remembering the selection when the view was created. (If the view is hidden, the selection may have changed by the time it is activated and its control is created.) Make the repositories view react on selection changes not only for IResource or File but also for Repository. Add special-purpose selection providers (RepositorySelectionProvider) to the staging view, the reflog view, the history view, and the rebase interactive view that provide a selection that identifies the current repository in those views if it is otherwise empty. Use a RepositoryNode for this to avoid multiple entries in the history view's navigation history. Since all views' selection listener mechanisms do handle a selection that adapts to Repository, this makes all EGit views nicely switch in sync when the "current" repository is changed in one of them. Includes initial UI tests. However, for some unknown reason I cannot get the test for the new button and the selection handling to work, so it is ignored. Somehow the selection in the other views does not get updated when run as a SWTBot test. Testing this is tricky anyway because most of our views load asynchronously one way or another. To be able to detect that for the staging view, I have made it use a WorkbenchJob instead of a plain Display.asyncExec(). Alas, that didn't help for that test. Bug: 518607 Change-Id: I976df6e3bf0363c27b877d995344487bb622f037 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
-rw-r--r--icons/org.eclipse.egit.ui/icons/elcl16/filter_none.svg253
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/RepositoryUtil.java2
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/internal/rebase/RebaseInteractivePlan.java15
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/selection/SelectionForViewsTest.java233
-rw-r--r--org.eclipse.egit.ui/icons/elcl16/filter_none.pngbin0 -> 723 bytes
-rw-r--r--org.eclipse.egit.ui/icons/elcl16/filter_none@2x.pngbin0 -> 1314 bytes
-rw-r--r--org.eclipse.egit.ui/plugin.xml14
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/JobFamilies.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java9
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositoryMenuUtil.java313
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java17
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java49
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java80
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogItem.java94
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogView.java55
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogViewContentProvider.java25
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java8
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/AbstractSelectionProvider.java88
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/MultiViewerSelectionProvider.java110
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositorySelectionProvider.java77
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java236
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties5
23 files changed, 1510 insertions, 183 deletions
diff --git a/icons/org.eclipse.egit.ui/icons/elcl16/filter_none.svg b/icons/org.eclipse.egit.ui/icons/elcl16/filter_none.svg
new file mode 100644
index 0000000000..6deb5835d8
--- /dev/null
+++ b/icons/org.eclipse.egit.ui/icons/elcl16/filter_none.svg
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="filter_none.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5103">
+ <stop
+ style="stop-color:#fefdef;stop-opacity:1"
+ offset="0"
+ id="stop5105" />
+ <stop
+ style="stop-color:#fce69e;stop-opacity:1"
+ offset="1"
+ id="stop5107" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4922">
+ <stop
+ style="stop-color:#77849a;stop-opacity:1"
+ offset="0"
+ id="stop4924" />
+ <stop
+ style="stop-color:#38445d;stop-opacity:1"
+ offset="1"
+ id="stop4926" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4878">
+ <stop
+ style="stop-color:#4e8fbd;stop-opacity:1"
+ offset="0"
+ id="stop4880" />
+ <stop
+ style="stop-color:#4d5a5d;stop-opacity:1"
+ offset="1"
+ id="stop4882" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4878"
+ id="linearGradient4884"
+ x1="0"
+ y1="13.5"
+ x2="7.9998932"
+ y2="13.5"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4878-7">
+ <stop
+ style="stop-color:#4e8fbd;stop-opacity:1"
+ offset="0"
+ id="stop4880-4" />
+ <stop
+ style="stop-color:#4d5a5d;stop-opacity:1"
+ offset="1"
+ id="stop4882-0" />
+ </linearGradient>
+ <linearGradient
+ gradientTransform="translate(0,1026.3622)"
+ y2="13.5"
+ x2="7.9998932"
+ y1="13.5"
+ x1="0"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4901"
+ xlink:href="#linearGradient4878-7"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4922"
+ id="linearGradient4929"
+ x1="10"
+ y1="1"
+ x2="10"
+ y2="6"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,1036.3622)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4922-8">
+ <stop
+ style="stop-color:#77849a;stop-opacity:1"
+ offset="0"
+ id="stop4924-8" />
+ <stop
+ style="stop-color:#38445d;stop-opacity:1"
+ offset="1"
+ id="stop4926-2" />
+ </linearGradient>
+ <linearGradient
+ y2="6"
+ x2="10"
+ y1="1"
+ x1="10"
+ gradientTransform="translate(0,-1053.3622)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4946"
+ xlink:href="#linearGradient4922-8"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5103"
+ id="linearGradient5109"
+ x1="11.906143"
+ y1="1042.3622"
+ x2="11.906143"
+ y2="1047.2684"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter4764">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.125"
+ id="feGaussianBlur4766" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="32"
+ inkscape:cx="8.622948"
+ inkscape:cy="8.030652"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1241"
+ inkscape:window-height="814"
+ inkscape:window-x="275"
+ inkscape:window-y="275"
+ inkscape:window-maximized="0"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:snap-global="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3999"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="display:inline"
+ transform="translate(0,-1036.3622)">
+ <path
+ style="fill:url(#linearGradient4884);stroke:none;fill-opacity:1;opacity:0.5"
+ d="m 0,13 0,1 5,0 0,2 L 7.9998932,13.5 5,11 5,13 z"
+ id="path4108"
+ inkscape:connector-curvature="0"
+ transform="translate(0,1036.3622)"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:url(#linearGradient4901);fill-opacity:1;stroke:none;display:inline;opacity:0.3"
+ d="m 0,1039.3622 0,1 5,0 0,2 2.9998932,-2.5 -2.9998932,-2.5 0,2 z"
+ id="path4108-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <rect
+ style="fill:url(#linearGradient4929);fill-opacity:1;stroke:none;opacity:0.5"
+ id="rect4920"
+ width="1"
+ height="5"
+ x="9"
+ y="1037.3622" />
+ <rect
+ style="fill:url(#linearGradient4946);fill-opacity:1;stroke:none;display:inline;opacity:0.5"
+ id="rect4920-4"
+ width="1"
+ height="5"
+ x="9"
+ y="-1052.3622"
+ transform="scale(1,-1)" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path4744"
+ style="font-size:7.60321283px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial"
+ d="m 22.25,1045.6747 0,-6 4,0 0,1 -3,0 0,1 2,0 0,1 -2,0 0,3 z" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path4744-9"
+ style="font-size:7.60321283px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:0.5;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;filter:url(#filter4764);font-family:Arial;-inkscape-font-specification:Arial"
+ d="m 22.382582,1045.8073 0,-6 4,0 0,1 -3,0 0,1 2,0 0,1 -2,0 0,3 z" />
+ <g
+ id="g3039"
+ transform="matrix(1.0000319,0,0,1,-15.438502,1.6875)">
+ <path
+ style="font-size:7.60321283px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000f6f;fill-opacity:1;stroke:#6f99c7;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Arial;-inkscape-font-specification:Arial"
+ d="m 16.9375,1035.6747 14,14"
+ id="path4792-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:7.60321283px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000f6f;fill-opacity:1;stroke:#000f6f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;-inkscape-font-specification:Arial"
+ d="m 16.25,1035.6747 14,14"
+ id="path4792"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5109);fill-opacity:1;stroke:none;display:inline"
+ d="m 5,1044.3622 0,1 7,0 0,2 2.999893,-2.5 -2.999893,-2.5 0,2 z"
+ id="path4108-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:#b57a13;fill-opacity:1;stroke:none;display:inline;opacity:1"
+ d="m 11,1041.3622 0,2 -5,0 -1,0 c -0.9918497,0.9918 -0.9863244,2.0137 0,3 l 1,0 5,0 0,2 c 0,0.6519 0.740915,0.6375 1.5,0 l 3.9375,-3.5 -3.9375,-3.5 c -0.760225,-0.7602 -1.5,-0.5203 -1.5,0 z m 1,1 3,2.5 -3,2.5 0,-2 -6.4375,0 c -0.2762136,-0.2099 -0.2774437,-0.7282 0,-1 l 6.4375,0 z"
+ id="path4108-1-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ </g>
+</svg>
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/RepositoryUtil.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/RepositoryUtil.java
index 21e7c3a4ea..b187aee1ce 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/RepositoryUtil.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/RepositoryUtil.java
@@ -525,10 +525,10 @@ public class RepositoryUtil {
sbAbsolute.append(File.pathSeparatorChar);
}
- prefs.put(PREFS_DIRECTORIES_REL, sbRelative.toString());
// redundantly store absolute paths to ensure compatibility with older
// EGit versions
prefs.put(PREFS_DIRECTORIES, sbAbsolute.toString());
+ prefs.put(PREFS_DIRECTORIES_REL, sbRelative.toString());
try {
prefs.flush();
} catch (BackingStoreException e) {
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/rebase/RebaseInteractivePlan.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/rebase/RebaseInteractivePlan.java
index 71be792485..d094a76572 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/rebase/RebaseInteractivePlan.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/rebase/RebaseInteractivePlan.java
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.internal.CoreText;
import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry;
@@ -456,7 +457,7 @@ public class RebaseInteractivePlan implements IndexDiffChangedListener,
* This class wraps a {@link RebaseTodoLine} and holds additional
* information about the underlying commit, if available.
*/
- public class PlanElement {
+ public class PlanElement implements IAdaptable {
private final RebaseTodoLine line;
/** author info, may be null */
@@ -673,6 +674,18 @@ public class RebaseInteractivePlan implements IndexDiffChangedListener,
public String toString() {
return line.toString();
}
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getAdapter(Class adapter) {
+ // TODO generify once EGit baseline is Eclipse 4.5
+ if (adapter.isInstance(this)) {
+ return this;
+ } else if (Repository.class.equals(adapter)) {
+ return repositoryRef.get();
+ }
+ return null;
+ }
}
/**
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/selection/SelectionForViewsTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/selection/SelectionForViewsTest.java
new file mode 100644
index 0000000000..f15537fbdd
--- /dev/null
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/selection/SelectionForViewsTest.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.selection;
+
+import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.withMnemonic;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.egit.core.AdapterUtils;
+import org.eclipse.egit.core.RepositoryUtil;
+import org.eclipse.egit.core.op.CloneOperation;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.JobFamilies;
+import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.rebase.RebaseInteractiveView;
+import org.eclipse.egit.ui.internal.reflog.ReflogView;
+import org.eclipse.egit.ui.internal.repository.RepositoriesView;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.egit.ui.internal.staging.StagingView;
+import org.eclipse.egit.ui.test.TestUtil;
+import org.eclipse.egit.ui.view.repositories.GitRepositoriesViewTestBase;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
+import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
+import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotToolbarDropDownButton;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
+import org.eclipse.team.internal.ui.history.GenericHistoryView;
+import org.eclipse.team.ui.history.IHistoryView;
+import org.eclipse.ui.PlatformUI;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for EGit views reacting on repository changes.
+ */
+@SuppressWarnings("restriction")
+@RunWith(SWTBotJunit4ClassRunner.class)
+public class SelectionForViewsTest extends GitRepositoriesViewTestBase {
+
+ private File localRepositoryDir; // Normal repo
+
+ private File remoteRepositoryDir; // Bare repo
+
+ private File clonedRepositoryDir; // 2nd normal repo
+
+ private SWTBotView stagingView;
+
+ private SWTBotView reflogView;
+
+ private SWTBotView rebaseInteractiveView;
+
+ private SWTBotView historyView;
+
+ private SWTBotView repoView;
+
+ @Before
+ public void before() throws Exception {
+ localRepositoryDir = createProjectAndCommitToRepository();
+ remoteRepositoryDir = createRemoteRepository(localRepositoryDir);
+ URIish uri = new URIish("file:///" + remoteRepositoryDir.getPath());
+ File workdir = new File(getTestDirectory(), "ClonedRepo");
+ CloneOperation op = new CloneOperation(uri, true, null, workdir,
+ "refs/heads/master", "origin", 0);
+ op.run(null);
+ clonedRepositoryDir = new File(workdir, Constants.DOT_GIT);
+ RepositoryUtil repoUtil = Activator.getDefault().getRepositoryUtil();
+ repoUtil.addConfiguredRepository(localRepositoryDir);
+ repoUtil.addConfiguredRepository(clonedRepositoryDir);
+ repoUtil.addConfiguredRepository(remoteRepositoryDir); // it's bare
+ stagingView = TestUtil.showView(StagingView.VIEW_ID);
+ reflogView = TestUtil.showView(ReflogView.VIEW_ID);
+ rebaseInteractiveView = TestUtil
+ .showView(RebaseInteractiveView.VIEW_ID);
+ repoView = TestUtil.showView(RepositoriesView.VIEW_ID);
+ RepositoriesView repos = (RepositoriesView) repoView.getViewReference()
+ .getView(false);
+ repos.setReactOnSelection(true);
+ historyView = TestUtil.showHistoryView();
+ IHistoryView history = (IHistoryView) historyView.getViewReference()
+ .getView(false);
+ ((GenericHistoryView) history).setLinkingEnabled(true);
+ // Ensure that the git history page is active
+ Exception[] exception = { null };
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ try {
+ history.showHistoryFor(new RepositoryNode(null,
+ lookupRepository(localRepositoryDir)), true);
+ } catch (Exception e) {
+ exception[0] = e;
+ }
+ });
+ if (exception[0] != null) {
+ throw exception[0];
+ }
+ waitForRefreshes();
+ }
+
+ @After
+ public void after() {
+ RepositoriesView repos = (RepositoriesView) repoView.getViewReference()
+ .getView(false);
+ repos.setReactOnSelection(false);
+ IHistoryView history = (IHistoryView) historyView.getViewReference()
+ .getView(false);
+ ((GenericHistoryView) history).setLinkingEnabled(false);
+ stagingView = null;
+ reflogView = null;
+ rebaseInteractiveView = null;
+ historyView = null;
+ repoView = null;
+ }
+
+ private void assertRepoSelection(SWTBotView view, File repoDir)
+ throws Exception {
+ view.show();
+ waitForRefreshes();
+ String viewId = view.getViewReference().getId();
+ ISelectionProvider selectionProvider = view.getViewReference()
+ .getView(false).getViewSite().getSelectionProvider();
+ assertNotNull("No selection provider " + viewId, selectionProvider);
+ ISelection selection = UIThreadRunnable
+ .syncExec(() -> selectionProvider.getSelection());
+ assertTrue("Expected an IStructuredSelection " + viewId,
+ selection instanceof IStructuredSelection);
+ assertFalse("Expected a non-empty selection " + viewId,
+ selection.isEmpty());
+ Object firstElement = ((IStructuredSelection) selection)
+ .getFirstElement();
+ assertNotNull("Null in selection " + viewId, firstElement);
+ Repository repo = AdapterUtils.adapt(firstElement, Repository.class);
+ assertNotNull("Expected a repository " + viewId + ", but "
+ + firstElement.getClass().getName()
+ + " doesn't adapt to Repository", repo);
+ assertEquals("Wrong directory " + viewId, repoDir, repo.getDirectory());
+ }
+
+ private void assertAllViews(File repoDir) throws Exception {
+ assertRepoSelection(repoView, repoDir);
+ assertRepoSelection(reflogView, repoDir);
+ assertRepoSelection(rebaseInteractiveView, repoDir);
+ assertRepoSelection(stagingView, repoDir);
+ assertRepoSelection(historyView, repoDir);
+ }
+
+ private void waitForRefreshes() throws Exception {
+ TestUtil.joinJobs(JobFamilies.GENERATE_HISTORY);
+ TestUtil.joinJobs(JobFamilies.STAGING_VIEW_RELOAD);
+ // Join UI update triggered by GenerateHistoryJob
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ // Nothing
+ });
+ refreshAndWait();
+ }
+
+ private String repositoryName(File repoDir) throws Exception {
+ return org.eclipse.egit.core.Activator.getDefault().getRepositoryUtil()
+ .getRepositoryName(lookupRepository(repoDir));
+ }
+
+ @Test
+ public void testViewsReactOnRepoViewSelection() throws Exception {
+ repoView.show();
+ repoView.setFocus();
+ SWTBotTree tree = repoView.bot().tree();
+ SWTBotTreeItem repoNode = myRepoViewUtil.getRootItem(tree,
+ clonedRepositoryDir);
+ repoNode.select();
+ assertAllViews(clonedRepositoryDir);
+ }
+
+ @Test
+ public void testViewsReactOnBareRepoViewSelection() throws Exception {
+ repoView.show();
+ repoView.setFocus();
+ SWTBotTree tree = repoView.bot().tree();
+ SWTBotTreeItem repoNode = myRepoViewUtil.getRootItem(tree,
+ remoteRepositoryDir);
+ repoNode.select();
+ assertAllViews(remoteRepositoryDir);
+ }
+
+ @Ignore("Doesn't work for an unknown reason. Other views do not update in test, while this works in production.")
+ @Test
+ public void testViewsReactOnRepoSwitchInStaging() throws Exception {
+ stagingView.show();
+ stagingView.setFocus();
+ waitForRefreshes();
+ SWTBotToolbarDropDownButton button = stagingView
+ .toolbarDropDownButton(UIText.RepositoryToolbarAction_tooltip);
+ button.menuItem(allOf(instanceOf(MenuItem.class),
+ withMnemonic(repositoryName(clonedRepositoryDir)))).click();
+ TestUtil.joinJobs(JobFamilies.STAGING_VIEW_RELOAD);
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ // Nothing
+ });
+ assertAllViews(clonedRepositoryDir);
+ stagingView.show();
+ stagingView.setFocus();
+ waitForRefreshes();
+ button = stagingView
+ .toolbarDropDownButton(UIText.RepositoryToolbarAction_tooltip);
+ button.menuItem(allOf(instanceOf(MenuItem.class),
+ withMnemonic(repositoryName(clonedRepositoryDir)))).click();
+ TestUtil.joinJobs(JobFamilies.STAGING_VIEW_RELOAD);
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ // Nothing
+ });
+ assertAllViews(localRepositoryDir);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.egit.ui/icons/elcl16/filter_none.png b/org.eclipse.egit.ui/icons/elcl16/filter_none.png
new file mode 100644
index 0000000000..36beea9d76
--- /dev/null
+++ b/org.eclipse.egit.ui/icons/elcl16/filter_none.png
Binary files differ
diff --git a/org.eclipse.egit.ui/icons/elcl16/filter_none@2x.png b/org.eclipse.egit.ui/icons/elcl16/filter_none@2x.png
new file mode 100644
index 0000000000..795309f533
--- /dev/null
+++ b/org.eclipse.egit.ui/icons/elcl16/filter_none@2x.png
Binary files differ
diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml
index 37b3f6735f..eb2464f264 100644
--- a/org.eclipse.egit.ui/plugin.xml
+++ b/org.eclipse.egit.ui/plugin.xml
@@ -120,6 +120,20 @@
</adapter>
</factory>
<factory
+ adaptableType="org.eclipse.egit.ui.internal.reflog.ReflogItem"
+ class="org.eclipse.egit.ui.internal.factories.GitAdapterFactory">
+ <adapter
+ type="org.eclipse.team.ui.history.IHistoryPageSource">
+ </adapter>
+ </factory>
+ <factory
+ adaptableType="org.eclipse.egit.core.internal.rebase.RebaseInteractivePlan$PlanElement"
+ class="org.eclipse.egit.ui.internal.factories.GitAdapterFactory">
+ <adapter
+ type="org.eclipse.team.ui.history.IHistoryPageSource">
+ </adapter>
+ </factory>
+ <factory
adaptableType="org.eclipse.egit.ui.internal.synchronize.model.GitModelRoot"
class="org.eclipse.egit.ui.internal.factories.GitAdapterFactory">
<adapter
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/JobFamilies.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/JobFamilies.java
index 06af3f6c62..dd1a37ca44 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/JobFamilies.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/JobFamilies.java
@@ -216,4 +216,10 @@ public class JobFamilies {
* Stash git job
*/
public static final Object STASH = new JobFamily(UIIcons.STASH);
+
+ /**
+ * Staging view reload
+ */
+ public static final Object STAGING_VIEW_RELOAD = new JobFamily();
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
index 08db44c505..c4c6b6c9e6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
@@ -141,6 +141,9 @@ public class UIIcons {
/** Synchronize Wizard banner */
public final static ImageDescriptor WIZBAN_SYNCHRONIZE;
+ /** History view, show full repo history */
+ public final static ImageDescriptor FILTERNONE;
+
/** History view, select all version in same project */
public final static ImageDescriptor FILTERPROJECT;
@@ -380,6 +383,7 @@ public class UIIcons {
CHECKBOX_ENABLED_UNCHECKED = map("checkboxes/enabled_unchecked.png"); //$NON-NLS-1$
CHECKBOX_DISABLED_CHECKED = map("checkboxes/disabled_checked.png"); //$NON-NLS-1$
CHECKBOX_DISABLED_UNCHECKED = map("checkboxes/disabled_unchecked.png"); //$NON-NLS-1$
+ FILTERNONE = map("elcl16/filter_none.png"); //$NON-NLS-1$
FILTERRESOURCE = map("elcl16/filterresource.png"); //$NON-NLS-1$
FILTERPROJECT = map("elcl16/filterproject.png"); //$NON-NLS-1$
FILTERFOLDER = map("elcl16/filterfolder.png"); //$NON-NLS-1$
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 311295ef17..48453bcf7a 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
@@ -1322,6 +1322,12 @@ public class UIText extends NLS {
public static String RepositoryAction_multiRepoSelectionTitle;
/** */
+ public static String RepositoryToolbarAction_label;
+
+ /** */
+ public static String RepositoryToolbarAction_tooltip;
+
+ /** */
public static String RepositoryCommit_AuthorDate;
/** */
@@ -5347,6 +5353,9 @@ public class UIText extends NLS {
public static String StagingView_MessageErrors;
/** */
+ public static String StagingView_LoadJob;
+
+ /** */
public static String StashApplyCommand_applyFailed;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositoryMenuUtil.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositoryMenuUtil.java
new file mode 100644
index 0000000000..0ef1982142
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositoryMenuUtil.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.components;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.egit.core.RepositoryCache;
+import org.eclipse.egit.core.RepositoryUtil;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.CommonUtils;
+import org.eclipse.egit.ui.internal.UIIcons;
+import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+
+/**
+ * Provides a way to populate a menu with a list of repositories.
+ */
+public final class RepositoryMenuUtil {
+
+ private RepositoryMenuUtil() {
+ // Utility class shall not be instantiated
+ }
+
+ /**
+ * Populates the given {@link IMenuManager} with a list of repositories.
+ * Each currently known configured repository is shown with its repository
+ * name and the path to the .git directory as tooltip; when a menu item is
+ * selected, the given {@code action} is invoked. Bare repositories can be
+ * excluded from the list. Menu items are sorted by repository name and .git
+ * directory paths.
+ *
+ * @param menuManager
+ * to populate with the list of repositories
+ * @param includeBare
+ * {@code true} if bare repositories should be included in the
+ * list, {@code false} otherwise
+ * @param currentRepoDir
+ * git directory of a repository that is to be marked as
+ * "current"; may be {@code null}.
+ * @param action
+ * to perform on the chosen repository
+ */
+ public static void fillRepositories(@NonNull IMenuManager menuManager,
+ boolean includeBare, @Nullable File currentRepoDir,
+ @NonNull Consumer<Repository> action) {
+ for (IAction item : getRepositoryActions(includeBare, currentRepoDir,
+ action)) {
+ menuManager.add(item);
+ }
+ }
+
+ /**
+ * Creates for each configured repository an {@link IAction} that will
+ * perform the given {@code action} when invoked.
+ *
+ * @param includeBare
+ * {@code true} if bare repositories should be included in the
+ * list, {@code false} otherwise
+ * @param currentRepoDir
+ * git directory of a repository that is to be marked as
+ * "current"; may be {@code null}.
+ * @param action
+ * to perform on the chosen repository
+ * @return the (possibly empty) list of actions
+ */
+ public static Collection<IAction> getRepositoryActions(boolean includeBare,
+ @Nullable File currentRepoDir,
+ @NonNull Consumer<Repository> action) {
+ RepositoryUtil util = org.eclipse.egit.core.Activator.getDefault()
+ .getRepositoryUtil();
+ RepositoryCache cache = org.eclipse.egit.core.Activator.getDefault()
+ .getRepositoryCache();
+ Set<String> repositories = util.getRepositories();
+ Map<String, Set<File>> repos = new HashMap<>();
+ for (String repo : repositories) {
+ File gitDir = new File(repo);
+ String name = null;
+ try {
+ Repository r = cache.lookupRepository(gitDir);
+ if (!includeBare && r.isBare()) {
+ continue;
+ }
+ name = util.getRepositoryName(r);
+ } catch (IOException e) {
+ continue;
+ }
+ Set<File> files = repos.get(name);
+ if (files == null) {
+ files = new HashSet<>();
+ files.add(gitDir);
+ repos.put(name, files);
+ } else {
+ files.add(gitDir);
+ }
+ }
+ String[] repoNames = repos.keySet().toArray(new String[repos.size()]);
+ Arrays.sort(repoNames, CommonUtils.STRING_ASCENDING_COMPARATOR);
+ List<IAction> result = new ArrayList<>();
+ for (String repoName : repoNames) {
+ Set<File> files = repos.get(repoName);
+ File[] gitDirs = files.toArray(new File[files.size()]);
+ Arrays.sort(gitDirs);
+ for (File f : gitDirs) {
+ IAction menuItem = new Action(repoName,
+ IAction.AS_RADIO_BUTTON) {
+ @Override
+ public void run() {
+ try {
+ Repository r = cache.lookupRepository(f);
+ action.accept(r);
+ } catch (IOException e) {
+ Activator.showError(e.getLocalizedMessage(), e);
+ }
+ }
+ };
+ menuItem.setToolTipText(f.getPath());
+ if (f.equals(currentRepoDir)) {
+ menuItem.setChecked(true);
+ }
+ result.add(menuItem);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Utility class facilitating creating toolbar actions that show a drop-down
+ * menu of all registered repositories, performing a given action on a
+ * selected repository.
+ */
+ public static class RepositoryToolbarAction extends Action
+ implements IWorkbenchAction, IMenuCreator {
+
+ private final RepositoryUtil util = org.eclipse.egit.core.Activator
+ .getDefault().getRepositoryUtil();
+
+ private final IEclipsePreferences preferences = util.getPreferences();
+
+ private final IPreferenceChangeListener listener;
+
+ private final @NonNull Consumer<Repository> action;
+
+ private final @NonNull Supplier<Repository> currentRepo;
+
+ private final boolean includeBare;
+
+ private Menu menu;
+
+ private boolean showMenu;
+
+ /**
+ * Creates a new {@link RepositoryToolbarAction} with the given
+ * {@code action} and default text, image, and tooltip.
+ *
+ * @param includeBare
+ * {@code true} if bare repositories shall be included,
+ * {@code false} otherwise
+ * @param currentRepo
+ * supplying the "current" repository, if any, or
+ * {@code null} otherwise
+ * @param action
+ * to run when a repository is selected from the drop-down
+ * menu
+ */
+ public RepositoryToolbarAction(boolean includeBare,
+ @NonNull Supplier<Repository> currentRepo,
+ @NonNull Consumer<Repository> action) {
+ this(UIText.RepositoryToolbarAction_label, UIIcons.REPOSITORY,
+ UIText.RepositoryToolbarAction_tooltip, includeBare,
+ currentRepo, action);
+ }
+
+ /**
+ * Creates a new {@link RepositoryToolbarAction} with the given text and
+ * the given {@code action}.
+ *
+ * @param text
+ * for the action
+ * @param image
+ * for the action
+ * @param tooltip
+ * for the action
+ * @param includeBare
+ * {@code true} if bare repositories shall be included,
+ * {@code false} otherwise
+ * @param currentRepo
+ * supplying the "current" repository, if any, or
+ * {@code null} otherwise
+ * @param action
+ * to run when a repository is selected from the drop-down
+ * menu
+ */
+ public RepositoryToolbarAction(String text,
+ @Nullable ImageDescriptor image, @Nullable String tooltip,
+ boolean includeBare, @NonNull Supplier<Repository> currentRepo,
+ @NonNull Consumer<Repository> action) {
+ super(text, IAction.AS_DROP_DOWN_MENU);
+ setImageDescriptor(image);
+ setToolTipText(tooltip == null ? text : tooltip);
+ this.includeBare = includeBare;
+ this.currentRepo = currentRepo;
+ this.action = action;
+ this.listener = event -> {
+ if (RepositoryUtil.PREFS_DIRECTORIES_REL
+ .equals(event.getKey())) {
+ setEnabled(!util.getRepositories().isEmpty());
+ }
+ };
+ setEnabled(!util.getRepositories().isEmpty());
+ preferences.addPreferenceChangeListener(listener);
+ }
+
+ @Override
+ public void run() {
+ showMenu = true;
+ }
+
+ @Override
+ public void runWithEvent(Event event) {
+ if (!isEnabled()) {
+ return;
+ }
+ // Show the menu also when the button is clicked, unless run() is
+ // overridden (and not called via super).
+ showMenu = false;
+ run();
+ Widget widget = event.widget;
+ if (showMenu && (widget instanceof ToolItem)) {
+ ToolItem item = (ToolItem) widget;
+ Rectangle bounds = item.getBounds();
+ event.detail = SWT.ARROW;
+ event.x = bounds.x;
+ event.y = bounds.y + bounds.height;
+ item.notifyListeners(SWT.Selection, event);
+ }
+ }
+
+ @Override
+ public IMenuCreator getMenuCreator() {
+ return this;
+ }
+
+ @Override
+ public Menu getMenu(Control parent) {
+ if (menu != null) {
+ menu.dispose();
+ menu = null;
+ }
+ if (isEnabled()) {
+ Repository current = currentRepo.get();
+ File gitDir = current == null ? null : current.getDirectory();
+ Collection<IAction> actions = RepositoryMenuUtil
+ .getRepositoryActions(includeBare, gitDir, action);
+ menu = new Menu(parent);
+ for (IAction a : actions) {
+ ActionContributionItem item = new ActionContributionItem(a);
+ item.fill(menu, -1);
+ }
+ }
+ return menu;
+ }
+
+ @Override
+ public Menu getMenu(Menu parent) {
+ // Not used
+ return null;
+ }
+
+ @Override
+ public void dispose() {
+ if (menu != null) {
+ menu.dispose();
+ menu = null;
+ }
+ preferences.removePreferenceChangeListener(listener);
+ }
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
index 0f4a9d4b49..8e741782dd 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
@@ -377,12 +377,14 @@ class CommitGraphTable {
void setInput(final RevFlag hFlag, final SWTCommitList list,
final SWTCommit[] asArray, HistoryPageInput input, boolean keepPosition) {
int topIndex = -1;
- if (keepPosition)
+ if (keepPosition) {
topIndex = table.getTable().getTopIndex();
+ }
setHistoryPageInput(input);
final SWTCommitList oldList = allCommits;
- if (oldList != null && oldList != list)
+ if (oldList != null && oldList != list) {
oldList.dispose();
+ }
highlight = hFlag;
allCommits = list;
int newAllCommitsLength = allCommits.size();
@@ -390,13 +392,18 @@ class CommitGraphTable {
if (asArray != null && asArray.length > 0) {
if (oldList != list || allCommitsLength < newAllCommitsLength)
initCommitsMap();
- } else
+ } else {
table.getTable().deselectAll();
+ // Fire an event
+ table.setSelection(table.getSelection());
+ }
allCommitsLength = newAllCommitsLength;
- if (commitToShow != null)
+ if (commitToShow != null) {
selectCommit(commitToShow);
- if (keepPosition)
+ }
+ if (keepPosition) {
table.getTable().setTopIndex(topIndex);
+ }
}
void setHistoryPageInput(HistoryPageInput input) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
index bdbef9fc86..bcf75950d2 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
@@ -8,7 +8,7 @@
* Copyright (C) 2012-2013 Robin Stocker <robin@nibor.org>
* Copyright (C) 2012, Fran├žois Rey <eclipse.org_@_francois_._rey_._name>
* Copyright (C) 2015, IBM Corporation (Dani Megert <daniel_megert@ch.ibm.com>)
- * Copyright (C) 2015-2016 Thomas Wolf <thomas.wolf@paranor.ch>
+ * Copyright (C) 2015-2017 Thomas Wolf <thomas.wolf@paranor.ch>
* Copyright (C) 2015-2017, Stefan Dirix <sdirix@eclipsesource.com>
*
* All rights reserved. This program and the accompanying materials
@@ -50,6 +50,7 @@ import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.DiffDocument;
import org.eclipse.egit.ui.internal.commit.DiffRegionFormatter;
import org.eclipse.egit.ui.internal.commit.DiffViewer;
+import org.eclipse.egit.ui.internal.components.RepositoryMenuUtil.RepositoryToolbarAction;
import org.eclipse.egit.ui.internal.dialogs.HyperlinkSourceViewer;
import org.eclipse.egit.ui.internal.dialogs.HyperlinkTokenScanner;
import org.eclipse.egit.ui.internal.fetch.FetchHeadChangedEvent;
@@ -58,8 +59,10 @@ import org.eclipse.egit.ui.internal.repository.tree.AdditionalRefNode;
import org.eclipse.egit.ui.internal.repository.tree.FileNode;
import org.eclipse.egit.ui.internal.repository.tree.FolderNode;
import org.eclipse.egit.ui.internal.repository.tree.RefNode;
+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.TagNode;
+import org.eclipse.egit.ui.internal.selection.RepositorySelectionProvider;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jface.action.Action;
@@ -102,6 +105,7 @@ import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.diff.DiffConfig;
import org.eclipse.jgit.diff.DiffEntry;
@@ -321,6 +325,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
ShowFilterAction showAllResourceVersionsAction;
+ RepositoryToolbarAction switchRepositoryAction;
+
private GitHistoryPage historyPage;
GitHistoryPageActions(GitHistoryPage historyPage) {
@@ -335,6 +341,7 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
}
private void createActions() {
+ createRepositorySwitchAction();
createFindToolbarAction();
createRefreshAction();
createFilterActions();
@@ -357,6 +364,31 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
fillCommentAction.setEnabled(showCommentAction.isChecked());
}
+ private void createRepositorySwitchAction() {
+ switchRepositoryAction = new RepositoryToolbarAction(true,
+ () -> historyPage.currentRepo,
+ repo -> {
+ Repository current = historyPage.currentRepo;
+ if (current != null && repo.getDirectory()
+ .equals(current.getDirectory())) {
+ HistoryPageInput currentInput = historyPage
+ .getInputInternal();
+ if (currentInput != null
+ && currentInput.getItems() == null
+ && currentInput.getFileList() == null) {
+ // Already showing this repo unfiltered
+ return;
+ }
+ }
+ if (historyPage.selectionTracker != null) {
+ historyPage.selectionTracker.clearSelection();
+ }
+ historyPage.getHistoryView()
+ .showHistoryFor(new RepositoryNode(null, repo));
+ });
+ actionsToDispose.add(switchRepositoryAction);
+ }
+
private void createFindToolbarAction() {
findAction = new Action(UIText.GitHistoryPage_FindMenuLabel,
UIIcons.ELCL16_FIND) {
@@ -416,7 +448,7 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
private void createFilterActions() {
showAllRepoVersionsAction = new ShowFilterAction(
- ShowFilter.SHOWALLREPO, UIIcons.REPOSITORY,
+ ShowFilter.SHOWALLREPO, UIIcons.FILTERNONE,
UIText.GitHistoryPage_AllInRepoMenuLabel,
UIText.GitHistoryPage_AllInRepoTooltip);
@@ -1285,7 +1317,11 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
attachCommitSelectionChanged();
initActions();
- getSite().setSelectionProvider(graph.getTableView());
+ getSite().setSelectionProvider(
+ new RepositorySelectionProvider(graph.getTableView(), () -> {
+ HistoryPageInput myInput = getInputInternal();
+ return myInput != null ? myInput.getRepository() : null;
+ }));
getSite().registerContextMenu(POPUP_ID, popupMgr, graph.getTableView());
// due to the issues described in bug 322751, it makes no
// sense to set a selection provider for the site here
@@ -1451,6 +1487,7 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
private void setupToolBar() {
IToolBarManager mgr = getSite().getActionBars().getToolBarManager();
mgr.add(actions.findAction);
+ mgr.add(actions.switchRepositoryAction);
mgr.add(new Separator());
mgr.add(actions.showAllRepoVersionsAction);
mgr.add(actions.showAllProjectVersionsAction);
@@ -2164,9 +2201,13 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
AnyObjectId headId = resolveHead(db, true);
if (headId == null) {
- graph.getTableView().setInput(new SWTCommit[0]);
+ TableViewer viewer = graph.getTableView();
+ viewer.setInput(new SWTCommit[0]);
currentHeadId = null;
currentFetchHeadId = null;
+ currentRepo = db;
+ // Force a selection changed event
+ viewer.setSelection(viewer.getSelection());
return;
}
AnyObjectId fetchHeadId = resolveFetchHead(db);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
index a693716abb..cb14c20966 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2016 SAP AG and others.
+ * Copyright (c) 2013, 2017 SAP AG and others.
* 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
@@ -8,7 +8,7 @@
* Contributors:
* Tobias Pfeifer (SAP AG) - initial implementation
* Tobias Baumann (tobbaumann@gmail.com) - Bug 473950
- * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 477248, 460595
+ * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 477248, 460595, 518607
*******************************************************************************/
package org.eclipse.egit.ui.internal.rebase;
@@ -44,8 +44,10 @@ import org.eclipse.egit.ui.internal.commands.shared.ProcessStepsRebaseCommand;
import org.eclipse.egit.ui.internal.commands.shared.SkipRebaseCommand;
import org.eclipse.egit.ui.internal.commit.CommitEditor;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
+import org.eclipse.egit.ui.internal.components.RepositoryMenuUtil.RepositoryToolbarAction;
import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.selection.RepositorySelectionProvider;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
@@ -114,6 +116,7 @@ import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
@@ -175,22 +178,12 @@ public class RebaseInteractiveView extends ViewPart implements
private IPropertyChangeListener uiPrefsListener;
- private InitialSelection initialSelection;
+ private IWorkbenchAction switchRepositoriesAction;
@Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
setPartName(UIText.InteractiveRebaseView_this_partName);
- initInitialSelection(site);
- }
-
- private void initInitialSelection(IViewSite site) {
- this.initialSelection = new InitialSelection(
- site.getWorkbenchWindow().getSelectionService().getSelection());
- if (!isViewInputDerivableFromSelection(initialSelection.selection)) {
- this.initialSelection.activeEditor = site.getPage()
- .getActiveEditor();
- }
}
private static boolean isViewInputDerivableFromSelection(Object o) {
@@ -205,6 +198,10 @@ public class RebaseInteractiveView extends ViewPart implements
* @param o
*/
public void setInput(Object o) {
+ newInput(o, true);
+ }
+
+ private void newInput(Object o, boolean force) {
if (o == null)
return;
@@ -230,7 +227,9 @@ public class RebaseInteractiveView extends ViewPart implements
if (repo == null) {
repo = AdapterUtils.adapt(o, Repository.class);
}
-
+ if (repo == null && !force) {
+ return;
+ }
currentRepository = repo;
showRepository(repo);
}
@@ -246,6 +245,10 @@ public class RebaseInteractiveView extends ViewPart implements
public void dispose() {
removeListeners();
resources.dispose();
+ if (switchRepositoriesAction != null) {
+ switchRepositoriesAction.dispose();
+ switchRepositoriesAction = null;
+ }
super.dispose();
}
@@ -393,7 +396,17 @@ public class RebaseInteractiveView extends ViewPart implements
linkSelectionAction.setImageDescriptor(UIIcons.ELCL16_SYNCED);
toolbar.add(linkSelectionAction);
- reactOnInitalSelection();
+ switchRepositoriesAction = new RepositoryToolbarAction(false,
+ () -> currentRepository,
+ repo -> setInput(new StructuredSelection(repo)));
+ toolbar.add(switchRepositoriesAction);
+
+ UIUtils.notifySelectionChangedWithCurrentSelection(
+ selectionChangedListener, getSite());
+
+ getSite().setSelectionProvider(new RepositorySelectionProvider(
+ planTreeViewer, () -> currentRepository));
+
}
private void createCommandToolBar(Form theForm, FormToolkit toolkit) {
@@ -508,17 +521,21 @@ public class RebaseInteractiveView extends ViewPart implements
public void selectionChanged(IWorkbenchPart part,
ISelection selection) {
if (!listenOnRepositoryViewSelection
- || part == getSite().getPart())
+ || part == getSite().getPart()) {
return;
-
+ }
// this may happen if we switch between editors
if (part instanceof IEditorPart) {
IEditorInput input = ((IEditorPart) part).getEditorInput();
- if (input instanceof IFileEditorInput)
- setInput(new StructuredSelection(
- ((IFileEditorInput) input).getFile()));
- } else
- setInput(selection);
+ if (input instanceof IFileEditorInput) {
+ newInput(
+ new StructuredSelection(
+ ((IFileEditorInput) input).getFile()),
+ false);
+ }
+ } else {
+ newInput(selection, false);
+ }
}
};
@@ -526,22 +543,6 @@ public class RebaseInteractiveView extends ViewPart implements
srv.addPostSelectionListener(selectionChangedListener);
}
- private void reactOnInitalSelection() {
- selectionChangedListener.selectionChanged(initialSelection.activeEditor,
- initialSelection.selection);
- this.initialSelection = null;
- }
-
- private static final class InitialSelection {
- ISelection selection;
-
- IEditorPart activeEditor;
-
- InitialSelection(ISelection selection) {
- this.selection = selection;
- }
- }
-
private class RebaseCommandItemSelectionListener extends SelectionAdapter {
private final AbstractRebaseCommandHandler command;
@@ -911,7 +912,6 @@ public class RebaseInteractiveView extends ViewPart implements
} else {
currentPlan = null;
planIndexer = null;
- form.setText(UIText.RebaseInteractiveView_NoSelection);
}
refresh();
}
@@ -934,6 +934,8 @@ public class RebaseInteractiveView extends ViewPart implements
try {
planTreeViewer.setInput(currentPlan);
refreshUI();
+ // Force a selection changed event
+ planTreeViewer.setSelection(planTreeViewer.getSelection());
} finally {
t.setRedraw(true);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogItem.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogItem.java
new file mode 100644
index 0000000000..d168aa63f1
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogItem.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.reflog;
+
+import java.util.Objects;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.egit.ui.internal.reflog.ReflogViewContentProvider.ReflogInput;
+import org.eclipse.jgit.lib.CheckoutEntry;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * A DTO for {@link ReflogEntry} to use as tree elements in the reflog view.
+ * Also adapts to the repository the item was loaded from.
+ */
+public class ReflogItem implements ReflogEntry, IAdaptable {
+
+ private final ReflogEntry entry;
+
+ private final ReflogInput input;
+
+ ReflogItem(ReflogInput input, ReflogEntry entry) {
+ this.entry = entry;
+ this.input = input;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getAdapter(Class adapter) {
+ // TODO generify once EGit base version is Eclipse 4.5
+ if (adapter.isInstance(this)) {
+ return this;
+ } else if (Repository.class.equals(adapter)) {
+ return input.getRepository();
+ }
+ return null;
+ }
+
+ @Override
+ public ObjectId getOldId() {
+ return entry.getOldId();
+ }
+
+ @Override
+ public ObjectId getNewId() {
+ return entry.getNewId();
+ }
+
+ @Override
+ public PersonIdent getWho() {
+ return entry.getWho();
+ }
+
+ @Override
+ public String getComment() {
+ return entry.getComment();
+ }
+
+ @Override
+ public CheckoutEntry parseCheckout() {
+ return entry.parseCheckout();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ReflogItem)) {
+ return false;
+ }
+ ReflogItem other = (ReflogItem) obj;
+ return input == other.input
+ && Objects.equals(getNewId(), other.getNewId())
+ && Objects.equals(getOldId(), other.getOldId())
+ && Objects.equals(getWho(), other.getWho())
+ && Objects.equals(getComment(), other.getComment());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(input, getNewId(), getOldId(), getWho(),
+ getComment());
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogView.java
index 4c7ad0791d..1c341a27b0 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogView.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2015 Chris Aniszczyk <caniszczyk@gmail.com> and others.
+ * Copyright (c) 2011, 2017 Chris Aniszczyk <caniszczyk@gmail.com> and others.
* 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
@@ -10,7 +10,7 @@
* EclipseSource - Filtered Viewer
* Robin Stocker <robin@nibor.org> - Show In support
* Tobias Baumann <tobbaumann@gmail.com> - Bug 475836
- * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 477248
+ * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 477248, 518607
*******************************************************************************/
package org.eclipse.egit.ui.internal.reflog;
@@ -29,8 +29,10 @@ import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.actions.ResetMenu;
import org.eclipse.egit.ui.internal.commit.CommitEditor;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
+import org.eclipse.egit.ui.internal.components.RepositoryMenuUtil.RepositoryToolbarAction;
import org.eclipse.egit.ui.internal.reflog.ReflogViewContentProvider.ReflogInput;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.selection.RepositorySelectionProvider;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
@@ -48,7 +50,6 @@ import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
@@ -85,6 +86,7 @@ import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.OpenAndLinkWithEditorHelper;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
@@ -129,6 +131,8 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
private PreferenceBasedDateFormatter dateFormatter;
+ private IWorkbenchAction switchRepositoriesAction;
+
@Override
public void createPartControl(Composite parent) {
dateFormatter = PreferenceBasedDateFormatter.create();
@@ -146,8 +150,8 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
Image repoImage = UIIcons.REPOSITORY.createImage();
UIUtils.hookDisposal(form, repoImage);
- final Image branchImage = UIIcons.CHANGESET.createImage();
- UIUtils.hookDisposal(form, branchImage);
+ Image commitImage = UIIcons.CHANGESET.createImage();
+ UIUtils.hookDisposal(form, commitImage);
form.setImage(repoImage);
form.setText(UIText.StagingView_NoSelectionTitle);
GridDataFactory.fillDefaults().grab(true, true).applyTo(form);
@@ -204,7 +208,7 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
@Override
public Image getImage(Object element) {
if (element instanceof ReflogEntry) {
- return branchImage;
+ return commitImage;
}
return null;
}
@@ -381,11 +385,22 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
UIUtils.notifySelectionChangedWithCurrentSelection(
selectionChangedListener, site);
- site.setSelectionProvider(refLogTableTreeViewer);
+ site.setSelectionProvider(new RepositorySelectionProvider(
+ refLogTableTreeViewer, () -> getRepository()));
+
+ // site.setSelectionProvider(refLogTableTreeViewer);
addRefsChangedListener = Repository.getGlobalListenerList()
.addRefsChangedListener(this);
+ // Toolbar
+ IToolBarManager toolbar = getViewSite().getActionBars()
+ .getToolBarManager();
+ switchRepositoriesAction = new RepositoryToolbarAction(false,
+ () -> getRepository(),
+ repo -> reactOnSelection(new StructuredSelection(repo)));
+ toolbar.add(switchRepositoriesAction);
+ getViewSite().getActionBars().updateActionBars();
// register context menu
MenuManager menuManager = new MenuManager();
menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
@@ -421,6 +436,10 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
}
Activator.getDefault().getPreferenceStore()
.removePropertyChangeListener(uiPrefsListener);
+ if (switchRepositoriesAction != null) {
+ switchRepositoriesAction.dispose();
+ switchRepositoriesAction = null;
+ }
}
private void reactOnSelection(ISelection selection) {
@@ -569,23 +588,13 @@ public class ReflogView extends ViewPart implements RefsChangedListener, IShowIn
@Override
public void onRefsChanged(RefsChangedEvent event) {
- PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
- @Override
- public void run() {
- Object currentInput = refLogTableTreeViewer.getInput();
- if (currentInput instanceof ReflogInput) {
- ReflogInput oldInput = (ReflogInput) currentInput;
- refLogTableTreeViewer.setInput(new ReflogInput(
- oldInput.getRepository(), oldInput.getRef()));
- }
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ Object currentInput = refLogTableTreeViewer.getInput();
+ if (currentInput instanceof ReflogInput) {
+ ReflogInput oldInput = (ReflogInput) currentInput;
+ refLogTableTreeViewer.setInput(new ReflogInput(
+ oldInput.getRepository(), oldInput.getRef()));
}
});
}
-
- /**
- * @return selection provider
- */
- public ISelectionProvider getSelectionProvider() {
- return refLogTableTreeViewer;
- }
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogViewContentProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogViewContentProvider.java
index 01ede86c39..fa972e92ff 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogViewContentProvider.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/reflog/ReflogViewContentProvider.java
@@ -13,19 +13,19 @@
package org.eclipse.egit.ui.internal.reflog;
import java.io.File;
-import java.util.Collection;
import java.util.Objects;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.model.WorkbenchAdapter;
@@ -77,6 +77,7 @@ public class ReflogViewContentProvider implements ITreeContentProvider {
}
};
+
/**
* Input class for this content provider.
*/
@@ -89,7 +90,7 @@ public class ReflogViewContentProvider implements ITreeContentProvider {
private final ISchedulingRule rule;
- private Collection<ReflogEntry> refLog;
+ private ReflogItem[] refLog;
/**
* Create input with non-null repository and non-null ref
@@ -126,7 +127,7 @@ public class ReflogViewContentProvider implements ITreeContentProvider {
@Override
public Object[] getChildren(Object o) {
if (refLog != null) {
- return refLog.toArray();
+ return refLog;
}
return null;
}
@@ -138,8 +139,10 @@ public class ReflogViewContentProvider implements ITreeContentProvider {
return; // Already loaded.
}
try (Git git = new Git(repository)) {
- refLog = git.reflog().setRef(ref).call();
- collector.add(refLog.toArray(), monitor);
+ refLog = git.reflog().setRef(ref).call().stream()
+ .map(entry -> new ReflogItem(ReflogInput.this, entry))
+ .toArray(ReflogItem[]::new);
+ collector.add(refLog, monitor);
} catch (Exception e) {
Activator.logError("Error running reflog command", e); //$NON-NLS-1$
collector.add(ERROR_ELEMENT, monitor);
@@ -170,6 +173,16 @@ public class ReflogViewContentProvider implements ITreeContentProvider {
currentInput = newInput;
if (viewer instanceof AbstractTreeViewer && newInput != null) {
loader = new DeferredBatchLoader((AbstractTreeViewer) viewer);
+ loader.addUpdateCompleteListener(new JobChangeAdapter() {
+
+ @Override
+ public void done(IJobChangeEvent event) {
+ if (event.getResult().isOK()) {
+ // Force a selection event
+ viewer.setSelection(viewer.getSelection());
+ }
+ }
+ });
}
}
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 7d1d2df205..ab88dd3356 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2016 SAP AG and others.
+ * Copyright (c) 2010, 2017 SAP AG and others.
* 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
@@ -958,6 +958,12 @@ public class RepositoriesView extends CommonNavigator implements IShowInSource,
showPaths(Arrays.asList(path));
return;
}
+ Repository repository = AdapterUtils.adapt(ssel.getFirstElement(),
+ Repository.class);
+ if (repository != null) {
+ showRepository(repository);
+ return;
+ }
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/AbstractSelectionProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/AbstractSelectionProvider.java
new file mode 100644
index 0000000000..19de9c6a8b
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/AbstractSelectionProvider.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.selection;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+
+/**
+ * Base class for custom selection providers.
+ */
+public abstract class AbstractSelectionProvider
+ implements IPostSelectionProvider {
+
+ private final CopyOnWriteArrayList<ISelectionChangedListener> selectionListeners = new CopyOnWriteArrayList<>();
+
+ private final CopyOnWriteArrayList<ISelectionChangedListener> postSelectionListeners = new CopyOnWriteArrayList<>();
+
+ @Override
+ public void addSelectionChangedListener(
+ ISelectionChangedListener listener) {
+ selectionListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removeSelectionChangedListener(
+ ISelectionChangedListener listener) {
+ selectionListeners.remove(listener);
+ }
+
+ @Override
+ public void addPostSelectionChangedListener(
+ ISelectionChangedListener listener) {
+ postSelectionListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removePostSelectionChangedListener(
+ ISelectionChangedListener listener) {
+ postSelectionListeners.remove(listener);
+ }
+
+ /**
+ * @return the list
+ */
+ protected CopyOnWriteArrayList<ISelectionChangedListener> getSelectionListeners() {
+ return selectionListeners;
+ }
+
+ /**
+ * @return the list
+ */
+ protected CopyOnWriteArrayList<ISelectionChangedListener> getPostSelectionListeners() {
+ return postSelectionListeners;
+ }
+
+ /**
+ * @param listeners
+ */
+ protected void fireSelectionChanged(
+ CopyOnWriteArrayList<ISelectionChangedListener> listeners) {
+ if (listeners.isEmpty()) {
+ return;
+ }
+ SelectionChangedEvent event = new SelectionChangedEvent(this,
+ getSelection());
+ for (ISelectionChangedListener listener : listeners) {
+ SafeRunner.run(new SafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.selectionChanged(event);
+ }
+ });
+ }
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/MultiViewerSelectionProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/MultiViewerSelectionProvider.java
new file mode 100644
index 0000000000..e4efe789ab
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/MultiViewerSelectionProvider.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.selection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * A {@link IPostSelectionProvider} for views with several viewers, tracking
+ * focus changes among the viewers to supply the correct selection.
+ */
+public class MultiViewerSelectionProvider extends AbstractSelectionProvider {
+
+ private final List<Viewer> viewers = new ArrayList<>();
+
+ private final Listener focusHook = event -> {
+ if (event.type == SWT.FocusIn && event.widget instanceof Control) {
+ focusChanged((Control) event.widget);
+ }
+ };
+
+ private final ISelectionChangedListener selectionHook = event -> selectionChanged(
+ event);
+
+ private final ISelectionChangedListener postSelectionHook = event -> postSelectionChanged(
+ event);
+
+ private Viewer currentViewer;
+
+ /**
+ * Creates a new {@link MultiViewerSelectionProvider} for the given viewers.
+ * The first viewer given is assumed to be the one that's focused initially.
+ *
+ * @param providers
+ * that contribute to this selection provider
+ */
+ public MultiViewerSelectionProvider(Viewer... providers) {
+ Assert.isLegal(providers != null && providers.length > 0);
+ for (Viewer viewer : providers) {
+ Assert.isLegal(viewer != null);
+ viewers.add(viewer);
+ viewer.getControl().addListener(SWT.FocusIn, focusHook);
+ viewer.addSelectionChangedListener(selectionHook);
+ if (viewer instanceof IPostSelectionProvider) {
+ ((IPostSelectionProvider) viewer)
+ .addPostSelectionChangedListener(postSelectionHook);
+ }
+ if (currentViewer == null) {
+ currentViewer = viewer;
+ }
+ }
+ }
+
+ private void focusChanged(Control control) {
+ for (Viewer viewer : viewers) {
+ if (control == viewer.getControl()) {
+ if (viewer != currentViewer) {
+ currentViewer = viewer;
+ fireSelectionChanged(getSelectionListeners());
+ fireSelectionChanged(getPostSelectionListeners());
+ }
+ return;
+ }
+ }
+ }
+
+ private void selectionChanged(SelectionChangedEvent event) {
+ if (event.getSelectionProvider() == currentViewer) {
+ fireSelectionChanged(getSelectionListeners());
+ }
+ }
+
+ private void postSelectionChanged(SelectionChangedEvent event) {
+ if (event.getSelectionProvider() == currentViewer) {
+ fireSelectionChanged(getPostSelectionListeners());
+ }
+ }
+
+ @Override
+ public ISelection getSelection() {
+ if (currentViewer != null) {
+ return currentViewer.getSelection();
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ if (currentViewer != null) {
+ currentViewer.setSelection(selection);
+ }
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositorySelectionProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositorySelectionProvider.java
new file mode 100644
index 0000000000..a61a772b05
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositorySelectionProvider.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (C) 2017, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.selection;
+
+import java.util.function.Supplier;
+
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * An {@link IPostSelectionProvider} that provides a selection containing the
+ * current repository as determined by a {@link Supplier} if the base selection
+ * provider does not have a selection.
+ */
+public class RepositorySelectionProvider extends AbstractSelectionProvider {
+
+ private final ISelectionProvider baseProvider;
+
+ private final Supplier<? extends Repository> repositoryProvider;
+
+ private final ISelectionChangedListener selectionHook = event -> fireSelectionChanged(
+ getSelectionListeners());
+
+ private final ISelectionChangedListener postSelectionHook = event -> fireSelectionChanged(
+ getPostSelectionListeners());
+
+ /**
+ * Creates a new {@link RepositorySelectionProvider}. If the base provider
+ * yields an empty selection, it supplies the current repository as
+ * determined by the given {@link Supplier}.
+ *
+ * @param baseProvider
+ * to use normally for selections
+ * @param repositoryProvider
+ * to use to get the repository
+ */
+ public RepositorySelectionProvider(ISelectionProvider baseProvider,
+ Supplier<? extends Repository> repositoryProvider) {
+ this.repositoryProvider = repositoryProvider;
+ this.baseProvider = baseProvider;
+ baseProvider.addSelectionChangedListener(selectionHook);
+ if (baseProvider instanceof IPostSelectionProvider) {
+ ((IPostSelectionProvider) baseProvider)
+ .addPostSelectionChangedListener(postSelectionHook);
+ }
+ }
+
+ @Override
+ public ISelection getSelection() {
+ ISelection selection = baseProvider.getSelection();
+ if (selection.isEmpty() && selection instanceof IStructuredSelection) {
+ Repository repository = repositoryProvider.get();
+ if (repository != null) {
+ return new StructuredSelection(
+ new RepositoryNode(null, repository));
+ }
+ }
+ return selection;
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ baseProvider.setSelection(selection);
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
index c4abbe9cae..6663e14334 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2011, 2016 Bernard Leach <leachbj@bouncycastle.org> and others.
+ * Copyright (C) 2011, 2017 Bernard Leach <leachbj@bouncycastle.org> and others.
* Copyright (C) 2015 SAP SE (Christian Georgi <christian.georgi@sap.com>)
* Copyright (C) 2015 Denis Zygann <d.zygann@web.de>
* Copyright (C) 2016 IBM (Daniel Megert <daniel_megert@ch.ibm.com>)
@@ -85,6 +85,7 @@ import org.eclipse.egit.ui.internal.commit.CommitJob;
import org.eclipse.egit.ui.internal.commit.CommitMessageHistory;
import org.eclipse.egit.ui.internal.commit.CommitProposalProcessor;
import org.eclipse.egit.ui.internal.commit.DiffViewer;
+import org.eclipse.egit.ui.internal.components.RepositoryMenuUtil.RepositoryToolbarAction;
import org.eclipse.egit.ui.internal.components.ToggleableWarningLabel;
import org.eclipse.egit.ui.internal.decorators.IProblemDecoratable;
import org.eclipse.egit.ui.internal.decorators.ProblemLabelDecorator;
@@ -98,6 +99,8 @@ import org.eclipse.egit.ui.internal.operations.DeletePathsOperationUI;
import org.eclipse.egit.ui.internal.operations.IgnoreOperationUI;
import org.eclipse.egit.ui.internal.push.PushMode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.selection.MultiViewerSelectionProvider;
+import org.eclipse.egit.ui.internal.selection.RepositorySelectionProvider;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IAction;
@@ -151,8 +154,6 @@ import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.events.ListenerHandle;
-import org.eclipse.jgit.events.RefsChangedEvent;
-import org.eclipse.jgit.events.RefsChangedListener;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
@@ -211,6 +212,7 @@ import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.Form;
@@ -223,6 +225,7 @@ import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.progress.WorkbenchJob;
/**
* A GitX style staging view with embedded commit dialog.
@@ -319,6 +322,12 @@ public class StagingView extends ViewPart
private IAction compareModeAction;
+ private IWorkbenchAction switchRepositoriesAction;
+
+ /** The currently set repository, even if it is bare. */
+ private Repository realRepository;
+
+ /** The currently set repository, if it's not a bare repository. */
@Nullable
private Repository currentRepository;
@@ -650,14 +659,11 @@ public class StagingView extends ViewPart
if (!RepositoryUtil.PREFS_DIRECTORIES_REL.equals(event.getKey())) {
return;
}
-
final Repository repo = currentRepository;
- if (repo == null)
+ if (repo == null || Activator.getDefault().getRepositoryUtil()
+ .contains(repo)) {
return;
-
- if (Activator.getDefault().getRepositoryUtil().contains(repo))
- return;
-
+ }
reload(null);
}
@@ -1255,7 +1261,9 @@ public class StagingView extends ViewPart
UIUtils.notifySelectionChangedWithCurrentSelection(
selectionChangedListener, site);
- site.setSelectionProvider(unstagedViewer);
+ site.setSelectionProvider(new RepositorySelectionProvider(
+ new MultiViewerSelectionProvider(unstagedViewer, stagedViewer),
+ () -> realRepository));
ViewerFilter filter = new ViewerFilter() {
@Override
@@ -1800,6 +1808,15 @@ public class StagingView extends ViewPart
toolbar.add(new Separator());
+ switchRepositoriesAction = new RepositoryToolbarAction(false,
+ () -> realRepository,
+ repo -> {
+ if (realRepository != repo) {
+ reload(repo);
+ }
+ });
+ toolbar.add(switchRepositoriesAction);
+
compareModeAction = new Action(UIText.StagingView_CompareMode,
IAction.AS_CHECK_BOX) {
@Override
@@ -3413,6 +3430,7 @@ public class StagingView extends ViewPart
*/
private void clearRepository(@Nullable Repository repository) {
saveCommitMessageComponentState();
+ realRepository = repository;
currentRepository = null;
StagingViewUpdate update = new StagingViewUpdate(null, null, null);
setStagingViewerInput(unstagedViewer, update, null, null);
@@ -3426,6 +3444,9 @@ public class StagingView extends ViewPart
form.setText(UIText.StagingView_NoSelectionTitle);
}
updateIgnoreErrorsButtonVisibility();
+ updateRebaseButtonVisibility(false);
+ // Force a selection changed event
+ unstagedViewer.setSelection(unstagedViewer.getSelection());
}
/**
@@ -3483,117 +3504,101 @@ public class StagingView extends ViewPart
return;
}
if (repository == null) {
- asyncExec(new Runnable() {
- @Override
- public void run() {
- clearRepository(null);
- }
- });
+ asyncUpdate(() -> clearRepository(null));
return;
}
if (!isValidRepo(repository)) {
- asyncExec(new Runnable() {
- @Override
- public void run() {
- clearRepository(repository);
- }
- });
+ asyncUpdate(() -> clearRepository(repository));
return;
}
final boolean repositoryChanged = currentRepository != repository;
+ realRepository = repository;
currentRepository = repository;
- asyncExec(new Runnable() {
-
- @Override
- public void run() {
- if (isDisposed()) {
- return;
- }
+ asyncUpdate(() -> {
+ if (isDisposed()) {
+ return;
+ }
- final IndexDiffData indexDiff = doReload(repository);
- boolean indexDiffAvailable = indexDiffAvailable(indexDiff);
- boolean noConflicts = noConflicts(indexDiff);
-
- if (repositoryChanged) {
- // Reset paths, they're from the old repository
- resetPathsToExpand();
- if (refsChangedListener != null)
- refsChangedListener.remove();
- refsChangedListener = repository.getListenerList()
- .addRefsChangedListener(new RefsChangedListener() {
-
- @Override
- public void onRefsChanged(RefsChangedEvent event) {
- updateRebaseButtonVisibility(repository
- .getRepositoryState().isRebasing());
- }
-
- });
- }
- final StagingViewUpdate update = new StagingViewUpdate(repository, indexDiff, null);
- Object[] unstagedExpanded = unstagedViewer.getVisibleExpandedElements();
- Object[] stagedExpanded = stagedViewer.getVisibleExpandedElements();
+ final IndexDiffData indexDiff = doReload(repository);
+ boolean indexDiffAvailable = indexDiffAvailable(indexDiff);
+ boolean noConflicts = noConflicts(indexDiff);
- int unstagedElementsCount = updateAutoExpand(unstagedViewer,
- getUnstaged(indexDiff));
- int stagedElementsCount = updateAutoExpand(stagedViewer,
- getStaged(indexDiff));
- int elementsCount = unstagedElementsCount + stagedElementsCount;
-
- if (elementsCount > getMaxLimitForListMode()) {
- listPresentationAction.setEnabled(false);
- if (presentation == Presentation.LIST) {
- compactTreePresentationAction.setChecked(true);
- switchToCompactModeInternal(true);
- } else {
- setExpandCollapseActionsVisible(false,
- unstagedElementsCount <= getMaxLimitForListMode(),
- true);
- setExpandCollapseActionsVisible(true,
- stagedElementsCount <= getMaxLimitForListMode(),
- true);
- }
+ if (repositoryChanged) {
+ // Reset paths, they're from the old repository
+ resetPathsToExpand();
+ if (refsChangedListener != null)
+ refsChangedListener.remove();
+ refsChangedListener = repository.getListenerList()
+ .addRefsChangedListener(
+ event -> updateRebaseButtonVisibility(repository
+ .getRepositoryState().isRebasing()));
+ }
+ final StagingViewUpdate update = new StagingViewUpdate(repository,
+ indexDiff, null);
+ Object[] unstagedExpanded = unstagedViewer
+ .getVisibleExpandedElements();
+ Object[] stagedExpanded = stagedViewer.getVisibleExpandedElements();
+
+ int unstagedElementsCount = updateAutoExpand(unstagedViewer,
+ getUnstaged(indexDiff));
+ int stagedElementsCount = updateAutoExpand(stagedViewer,
+ getStaged(indexDiff));
+ int elementsCount = unstagedElementsCount + stagedElementsCount;
+
+ if (elementsCount > getMaxLimitForListMode()) {
+ listPresentationAction.setEnabled(false);
+ if (presentation == Presentation.LIST) {
+ compactTreePresentationAction.setChecked(true);
+ switchToCompactModeInternal(true);
} else {
- listPresentationAction.setEnabled(true);
- boolean changed = getPreferenceStore().getBoolean(
- UIPreferences.STAGING_VIEW_PRESENTATION_CHANGED);
- if (changed) {
- listPresentationAction.setChecked(true);
- switchToListMode();
- } else if (presentation != Presentation.LIST) {
- setExpandCollapseActionsVisible(false, true, true);
- setExpandCollapseActionsVisible(true, true, true);
- }
+ setExpandCollapseActionsVisible(false,
+ unstagedElementsCount <= getMaxLimitForListMode(),
+ true);
+ setExpandCollapseActionsVisible(true,
+ stagedElementsCount <= getMaxLimitForListMode(),
+ true);
}
+ } else {
+ listPresentationAction.setEnabled(true);
+ boolean changed = getPreferenceStore().getBoolean(
+ UIPreferences.STAGING_VIEW_PRESENTATION_CHANGED);
+ if (changed) {
+ listPresentationAction.setChecked(true);
+ switchToListMode();
+ } else if (presentation != Presentation.LIST) {
+ setExpandCollapseActionsVisible(false, true, true);
+ setExpandCollapseActionsVisible(true, true, true);
+ }
+ }
- setStagingViewerInput(unstagedViewer, update, unstagedExpanded,
- pathsToExpandInUnstaged);
- setStagingViewerInput(stagedViewer, update, stagedExpanded,
- pathsToExpandInStaged);
- resetPathsToExpand();
- refreshAction.setEnabled(true);
-
- updateRebaseButtonVisibility(repository.getRepositoryState()
- .isRebasing());
+ setStagingViewerInput(unstagedViewer, update, unstagedExpanded,
+ pathsToExpandInUnstaged);
+ setStagingViewerInput(stagedViewer, update, stagedExpanded,
+ pathsToExpandInStaged);
+ resetPathsToExpand();
+ // Force a selection changed event
+ unstagedViewer.setSelection(unstagedViewer.getSelection());
+ refreshAction.setEnabled(true);
- updateIgnoreErrorsButtonVisibility();
+ updateRebaseButtonVisibility(
+ repository.getRepositoryState().isRebasing());
- boolean rebaseContinueEnabled = indexDiffAvailable
- && repository.getRepositoryState().isRebasing()
- && noConflicts;
- rebaseContinueButton.setEnabled(rebaseContinueEnabled);
+ updateIgnoreErrorsButtonVisibility();
- form.setText(GitLabels.getStyledLabelSafe(repository).toString());
- updateCommitMessageComponent(repositoryChanged, indexDiffAvailable);
- enableCommitWidgets(indexDiffAvailable && noConflicts);
+ boolean rebaseContinueEnabled = indexDiffAvailable
+ && repository.getRepositoryState().isRebasing()
+ && noConflicts;
+ rebaseContinueButton.setEnabled(rebaseContinueEnabled);
- updateCommitButtons();
- updateSectionText();
- }
+ form.setText(GitLabels.getStyledLabelSafe(repository).toString());
+ updateCommitMessageComponent(repositoryChanged, indexDiffAvailable);
+ enableCommitWidgets(indexDiffAvailable && noConflicts);
+ updateCommitButtons();
+ updateSectionText();
});
}
@@ -4072,6 +4077,11 @@ public class StagingView extends ViewPart
refsChangedListener.remove();
}
+ if (switchRepositoriesAction != null) {
+ switchRepositoriesAction.dispose();
+ switchRepositoriesAction = null;
+ }
+
getPreferenceStore().removePropertyChangeListener(uiPrefsListener);
getDialogSettings().put(STORE_SORT_STATE, sortAction.isChecked());
@@ -4093,6 +4103,30 @@ public class StagingView extends ViewPart
PlatformUI.getWorkbench().getDisplay().asyncExec(runnable);
}
+ private void asyncUpdate(Runnable runnable) {
+ Job update = new WorkbenchJob(UIText.StagingView_LoadJob) {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ try {
+ runnable.run();
+ return Status.OK_STATUS;
+ } catch (Exception e) {
+ return Activator.createErrorStatus(e.getLocalizedMessage(),
+ e);
+ }
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return family == JobFamilies.STAGING_VIEW_RELOAD
+ || super.belongsTo(family);
+ }
+ };
+ update.setSystem(true);
+ update.schedule();
+ }
+
/**
* This comparator sorts the {@link StagingEntry}s alphabetically or groups
* them by state. If grouped by state the entries in the same group are also
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 0bca35bc55..482cce18d8 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
@@ -419,6 +419,8 @@ RepositoryAction_errorFindingRepo=Could not find a repository associated with th
RepositoryAction_errorFindingRepoTitle=Cannot Find Repository
RepositoryAction_multiRepoSelection=Cannot perform action on multiple repositories simultaneously.\n\nPlease select items from only one repository.
RepositoryAction_multiRepoSelectionTitle=Multiple Repositories Selection
+RepositoryToolbarAction_label=Repository
+RepositoryToolbarAction_tooltip=Switch repository
RepositoryCommit_AuthorDate=\ ({0} on {1})
RepositoryCommit_AuthorDateCommitter=\ ({0} on {1}, committed by {2})
RepositoryLocationPage_info=Select a location of Git Repositories
@@ -1807,7 +1809,6 @@ Examples:\
OpenWorkingFileAction_text=&Open
OpenWorkingFileAction_tooltip=Open working file
OpenWorkingFileAction_openWorkingFileShellTitle=Problems Opening Working File
-
StagingView_UnstagedChanges=Unstaged Changes ({0})
StagingView_UnstagedChangesTooltip=Changes not in the git index; not in the commit
StagingView_ShowFileNamesFirst=Show File Names First
@@ -1865,7 +1866,7 @@ StagingView_AddJob=Adding files to index...
StagingView_RemoveJob=Removing files from index...
StagingView_ResetJob=Unstaging files...
StagingView_MessageErrors=Fix warnings/errors before you commit changes or explicitly ignore them
-
+StagingView_LoadJob=Staging View Loader
StagingView_IgnoreErrors=Ignore warnings and errors
StashApplyCommand_applyFailed=Applying stashed commit ''{0}'' failed due to ''{1}''
StashApplyCommand_jobTitle=Apply changes from stashed commit ''{0}''

Back to the top