[repo view] Let "link with selection" be always enabled

It's actually a normal state toggling command for which a default
handler is fine. It didn't have a default handler because it was badly
implemented and assumed that the currently active part was the
repositories view.

Change the handling of all three toggle commands in the repositories
view. Let them only toggle their state, don't make them refresh the
view. Make the view listen to state changes and refresh if needed.
The content provider doesn't need to listen to changes; it has no way
to inform the viewer to refresh.

Also remove duplicating the state into local boolean variables; use
the state's current value instead.

Bug: 537958
Change-Id: I2027a64bd6f4e88439e7975b9d3c3eb3d381efef
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
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
index 28e605d..83351a9 100644
--- 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
@@ -20,16 +20,19 @@
 
 import java.io.File;
 
+import org.eclipse.core.commands.State;
 import org.eclipse.core.runtime.Adapters;
 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.CommonUtils;
 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.repository.tree.command.ToggleLinkWithSelectionCommand;
 import org.eclipse.egit.ui.internal.staging.StagingView;
 import org.eclipse.egit.ui.test.TestUtil;
 import org.eclipse.egit.ui.view.repositories.GitRepositoriesViewTestBase;
@@ -49,6 +52,8 @@
 import org.eclipse.team.internal.ui.history.GenericHistoryView;
 import org.eclipse.team.ui.history.IHistoryView;
 import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -78,6 +83,10 @@
 
 	private SWTBotView repoView;
 
+	private State linkWithSelectionState;
+
+	private Boolean initialLinkingWithSelection;
+
 	@Before
 	public void before() throws Exception {
 		localRepositoryDir = createProjectAndCommitToRepository();
@@ -92,14 +101,19 @@
 		repoUtil.addConfiguredRepository(localRepositoryDir);
 		repoUtil.addConfiguredRepository(clonedRepositoryDir);
 		repoUtil.addConfiguredRepository(remoteRepositoryDir); // it's bare
+		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(),
+				ICommandService.class);
+		linkWithSelectionState = srv
+				.getCommand(ToggleLinkWithSelectionCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
+		initialLinkingWithSelection = (Boolean) linkWithSelectionState
+				.getValue();
+		linkWithSelectionState.setValue(Boolean.TRUE);
 		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);
@@ -122,9 +136,7 @@
 
 	@After
 	public void after() {
-		RepositoriesView repos = (RepositoriesView) repoView.getViewReference()
-				.getView(false);
-		repos.setReactOnSelection(false);
+		linkWithSelectionState.setValue(initialLinkingWithSelection);
 		IHistoryView history = (IHistoryView) historyView.getViewReference()
 				.getView(false);
 		((GenericHistoryView) history).setLinkingEnabled(false);
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/submodules/SubmoduleFolderTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/submodules/SubmoduleFolderTest.java
index 14b4c33..bf7e051 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/submodules/SubmoduleFolderTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/submodules/SubmoduleFolderTest.java
@@ -24,6 +24,7 @@
 import java.io.File;
 import java.util.Collections;
 
+import org.eclipse.core.commands.State;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
@@ -40,10 +41,12 @@
 import org.eclipse.egit.core.project.RepositoryMapping;
 import org.eclipse.egit.core.test.TestRepository;
 import org.eclipse.egit.ui.common.LocalRepositoryTestCase;
+import org.eclipse.egit.ui.internal.CommonUtils;
 import org.eclipse.egit.ui.internal.UIText;
 import org.eclipse.egit.ui.internal.clone.ProjectRecord;
 import org.eclipse.egit.ui.internal.clone.ProjectUtils;
 import org.eclipse.egit.ui.internal.repository.RepositoriesView;
+import org.eclipse.egit.ui.internal.repository.tree.command.ToggleLinkWithSelectionCommand;
 import org.eclipse.egit.ui.internal.resources.IResourceState;
 import org.eclipse.egit.ui.internal.resources.ResourceStateFactory;
 import org.eclipse.egit.ui.test.ContextMenuHelper;
@@ -62,6 +65,9 @@
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
 import org.eclipse.ui.IEditorReference;
 import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.junit.After;
@@ -78,8 +84,6 @@
 
 	private static final String CHILDPROJECT = "ChildProject";
 
-	private static final TestUtil UTIL = new TestUtil();
-
 	private Repository parentRepository;
 
 	private Repository childRepository;
@@ -260,11 +264,14 @@
 
 	@Test
 	public void testRepoViewFollowSelection() throws Exception {
+		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(),
+				ICommandService.class);
+		State commandState = srv.getCommand(ToggleLinkWithSelectionCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
+		Boolean followsSelection = (Boolean) commandState.getValue();
+		commandState.setValue(Boolean.TRUE);
 		SWTBotView view = TestUtil.showView(RepositoriesView.VIEW_ID);
 		TestUtil.joinJobs(REPO_VIEW_REFRESH);
-		view.toolbarButton(
-				UTIL.getPluginLocalizedValue("LinkWithSelectionCommand"))
-				.click();
 		try {
 			SWTBotTree projectExplorerTree = TestUtil.getExplorerTree();
 			SWTBotTreeItem node = TestUtil.navigateTo(projectExplorerTree,
@@ -299,9 +306,7 @@
 					parentFound[0]);
 		} finally {
 			// Reset "follow selection"
-			view.toolbarButton(
-					UTIL.getPluginLocalizedValue("LinkWithSelectionCommand"))
-					.click();
+			commandState.setValue(followsSelection);
 		}
 	}
 
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewBranchHandlingTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewBranchHandlingTest.java
index 7fb8331..27c32d7 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewBranchHandlingTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewBranchHandlingTest.java
@@ -62,6 +62,7 @@
 import org.eclipse.ui.IPageLayout;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -378,7 +379,7 @@
 		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(),
 				ICommandService.class);
 		State commandState = srv.getCommand(ToggleBranchHierarchyCommand.ID)
-				.getState(ToggleBranchHierarchyCommand.TOGGLE_STATE);
+				.getState(RegistryToggleState.STATE_ID);
 		Boolean isHierarchical = (Boolean) commandState.getValue();
 		commandState.setValue(Boolean.TRUE);
 		try {
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java
index 15dcbe6..1a62755 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java
@@ -65,6 +65,7 @@
 import org.eclipse.ui.internal.wizards.AbstractExtensionWizardRegistry;
 import org.eclipse.ui.wizards.IWizardCategory;
 import org.eclipse.ui.wizards.IWizardDescriptor;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -90,14 +91,22 @@
 
 	private File repositoryFile;
 
+	private boolean initialLinkingState;
+
 	@Before
-	public void beforeClass() throws Exception {
+	public void prepare() throws Exception {
 		setVerboseBranchMode(false);
+		initialLinkingState = setLinkWithSelection(false);
 		repositoryFile = createProjectAndCommitToRepository();
 		Activator.getDefault().getRepositoryUtil()
 				.addConfiguredRepository(repositoryFile);
 	}
 
+	@After
+	public void resetLinkingState() {
+		setLinkWithSelection(initialLinkingState);
+	}
+
 	/**
 	 * First level should have 5 children
 	 *
@@ -527,9 +536,6 @@
 
 		// the selection should be project
 		assertTrue(tree.selection().get(0, 0).equals(PROJ1));
-
-		// deactivate the link with selection
-		toggleLinkWithSelection();
 	}
 
 	/**
@@ -869,7 +875,8 @@
 
 	private void toggleLinkWithSelection() throws Exception {
 		getOrOpenView().toolbarButton(
-				myUtil.getPluginLocalizedValue("LinkWithSelectionCommand"))
+				myUtil.getPluginLocalizedValue(
+						"RepoViewLinkWithSelection.tooltip"))
 				.click();
 	}
 
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTestBase.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTestBase.java
index 0305508..4865f8b 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTestBase.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTestBase.java
@@ -35,6 +35,7 @@
 import org.eclipse.egit.ui.internal.UIText;
 import org.eclipse.egit.ui.internal.repository.RepositoriesView;
 import org.eclipse.egit.ui.internal.repository.tree.command.ToggleBranchCommitCommand;
+import org.eclipse.egit.ui.internal.repository.tree.command.ToggleLinkWithSelectionCommand;
 import org.eclipse.egit.ui.test.TestUtil;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
@@ -45,6 +46,7 @@
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 import org.junit.After;
 import org.junit.Before;
 
@@ -106,12 +108,23 @@
 	protected static void setVerboseBranchMode(boolean state) {
 		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(),
 				ICommandService.class);
-		State verboseBranchModeState = srv.getCommand(
-				ToggleBranchCommitCommand.ID).getState(
-				ToggleBranchCommitCommand.TOGGLE_STATE);
+		State verboseBranchModeState = srv
+				.getCommand(ToggleBranchCommitCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
 		verboseBranchModeState.setValue(Boolean.valueOf(state));
 	}
 
+	protected static boolean setLinkWithSelection(boolean state) {
+		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(),
+				ICommandService.class);
+		State linkingState = srv.getCommand(ToggleLinkWithSelectionCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
+		boolean previousState = ((Boolean) linkingState.getValue())
+				.booleanValue();
+		linkingState.setValue(Boolean.valueOf(state));
+		return previousState;
+	}
+
 	protected SWTBotView getOrOpenView() throws Exception {
 		SWTBotView view = TestUtil.showView(RepositoriesView.VIEW_ID);
 		TestUtil.joinJobs(JobFamilies.REPO_VIEW_REFRESH);
diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties
index 3130ebb..4b9a9e3 100644
--- a/org.eclipse.egit.ui/plugin.properties
+++ b/org.eclipse.egit.ui/plugin.properties
@@ -180,7 +180,7 @@
 OpenInEditorCommand = Open in Editor
 DeleteFileCommand = Delete
 OpenCommand = Open
-LinkWithSelectionCommand = Link with Selection
+LinkWithSelectionCommand = Toggle "Link with Selection" (Git Repositories View)
 SynchronizeCommand = Synchronize...
 UntrackCommand.name = Untrack
 
@@ -293,6 +293,7 @@
 RepoCloneRepositoryViewMenu.label = &Clone a Repository
 RepoCreateRepositoryViewMenu.label = &Create a Repository
 RepoViewLinkWithSelectionMenu.label = Link with &Selection
+RepoViewLinkWithSelection.tooltip = Link with Selection
 RepoViewCreateRepositoryCommand.name = Create a Repository
 CreateRepositoryWizard.name = Git Repository
 CreateRepositoryWizard.description = Create a Git repository
diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml
index bb88653..fde94ea 100644
--- a/org.eclipse.egit.ui/plugin.xml
+++ b/org.eclipse.egit.ui/plugin.xml
@@ -2441,17 +2441,6 @@
          </activeWhen>
       </handler>
       <handler
-            commandId="org.eclipse.egit.ui.RepositoriesLinkWithSelection">
-         <class
-               class="org.eclipse.egit.ui.internal.repository.tree.command.LinkWithSelectionCommand">
-         </class>
-         <activeWhen>
-            <with variable="activePart">
-               <instanceof value="org.eclipse.egit.ui.internal.repository.RepositoriesView" />
-            </with>
-         </activeWhen>
-      </handler>
-      <handler
             commandId="org.eclipse.egit.ui.RepositoriesViewRemove">
          <class
                class="org.eclipse.egit.ui.internal.repository.tree.command.RemoveCommand">
@@ -4915,6 +4904,7 @@
          </command>
          <command
                commandId="org.eclipse.egit.ui.RepositoriesLinkWithSelection"
+               tooltip="%RepoViewLinkWithSelection.tooltip"
                style="toggle">
          </command>
          <separator
@@ -5905,6 +5895,7 @@
       <command
             categoryId="org.eclipse.egit.ui.commandCategory"
             id="org.eclipse.egit.ui.RepositoriesLinkWithSelection"
+            defaultHandler="org.eclipse.egit.ui.internal.repository.tree.command.ToggleLinkWithSelectionCommand"
             name="%LinkWithSelectionCommand">
           <state
                 class="org.eclipse.ui.handlers.RegistryToggleState:false"
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 025d72b..d4619b4 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
@@ -30,7 +30,8 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IStateListener;
+import org.eclipse.core.commands.State;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.Adapters;
@@ -69,6 +70,8 @@
 import org.eclipse.egit.ui.internal.repository.tree.StashedCommitNode;
 import org.eclipse.egit.ui.internal.repository.tree.TagNode;
 import org.eclipse.egit.ui.internal.repository.tree.WorkingDirNode;
+import org.eclipse.egit.ui.internal.repository.tree.command.ToggleBranchHierarchyCommand;
+import org.eclipse.egit.ui.internal.repository.tree.command.ToggleLinkWithSelectionCommand;
 import org.eclipse.egit.ui.internal.selection.SelectionUtils;
 import org.eclipse.egit.ui.internal.staging.StagingView;
 import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
@@ -195,12 +198,64 @@
 
 	private volatile long lastInputUpdate = -1L;
 
-	private boolean reactOnSelection;
+	private State reactOnSelection;
+
+	private final ISelectionListener selectionChangedListener = (part,
+			selection) -> {
+		if (!((Boolean) reactOnSelection.getValue()).booleanValue()
+				|| part == RepositoriesView.this) {
+			return;
+		}
+
+		// this may happen if we switch between editors
+		if (part instanceof IEditorPart) {
+			IEditorInput input = ((IEditorPart) part).getEditorInput();
+			if (input instanceof IFileEditorInput) {
+				reactOnSelection(new StructuredSelection(
+						((IFileEditorInput) input).getFile()));
+			} else if (input instanceof IURIEditorInput) {
+				reactOnSelection(new StructuredSelection(input));
+			}
+
+		} else {
+			reactOnSelection(selection);
+		}
+	};
+
+	private final IStateListener reactOnSelectionListener = (state,
+			oldValue) -> {
+		if (((Boolean) state.getValue()).booleanValue()) {
+			PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+				ISelectionService service = CommonUtils
+						.getService(getViewSite(), ISelectionService.class);
+				if (service == null) {
+					return;
+				}
+				ISelection currentSelection = service.getSelection();
+				if (currentSelection == null || currentSelection.isEmpty()) {
+					return;
+				}
+				IWorkbenchWindow window = PlatformUI.getWorkbench()
+						.getActiveWorkbenchWindow();
+				if (window == null) {
+					return;
+				}
+				IWorkbenchPart part = window.getPartService().getActivePart();
+				if (part != null) {
+					selectionChangedListener.selectionChanged(part,
+							currentSelection);
+				}
+			});
+		}
+	};
+
+	private State branchHierarchy;
+
+	private final IStateListener stateChangeListener = (state,
+			oldValue) -> refresh();
 
 	private final IPreferenceChangeListener configurationListener;
 
-	private ISelectionListener selectionChangedListener;
-
 	/**
 	 * The default constructor
 	 */
@@ -242,30 +297,6 @@
 				scheduleRefresh(DEFAULT_REFRESH_DELAY, null);
 			}
 		};
-
-		selectionChangedListener = new ISelectionListener() {
-			@Override
-			public void selectionChanged(IWorkbenchPart part,
-					ISelection selection) {
-				if (!reactOnSelection || part == RepositoriesView.this) {
-					return;
-				}
-
-				// this may happen if we switch between editors
-				if (part instanceof IEditorPart) {
-					IEditorInput input = ((IEditorPart) part).getEditorInput();
-					if (input instanceof IFileEditorInput) {
-						reactOnSelection(new StructuredSelection(
-								((IFileEditorInput) input).getFile()));
-					} else if (input instanceof IURIEditorInput) {
-						reactOnSelection(new StructuredSelection(input));
-					}
-
-				} else {
-					reactOnSelection(selection);
-				}
-			}
-		};
 	}
 
 	/**
@@ -370,7 +401,6 @@
 				.grab(true, false).applyTo(createLink);
 	}
 
-	@SuppressWarnings("boxing")
 	@Override
 	public void createPartControl(Composite aParent) {
 		Composite displayArea = new Composite(aParent, SWT.NONE);
@@ -383,11 +413,12 @@
 		IWorkbenchWindow w = PlatformUI.getWorkbench()
 				.getActiveWorkbenchWindow();
 		ICommandService csrv = CommonUtils.getService(w, ICommandService.class);
-		Command command = csrv
-				.getCommand("org.eclipse.egit.ui.RepositoriesLinkWithSelection"); //$NON-NLS-1$
-		reactOnSelection = (Boolean) command.getState(
-				RegistryToggleState.STATE_ID).getValue();
-
+		reactOnSelection = csrv.getCommand(ToggleLinkWithSelectionCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
+		reactOnSelection.addListener(reactOnSelectionListener);
+		branchHierarchy = csrv.getCommand(ToggleBranchHierarchyCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
+		branchHierarchy.addListener(stateChangeListener);
 		IWorkbenchSiteProgressService service = CommonUtils.getService(getSite(), IWorkbenchSiteProgressService.class);
 		if (service != null) {
 			service.showBusyForFamily(JobFamilies.REPO_VIEW_REFRESH);
@@ -413,15 +444,6 @@
 		return super.getAdapter(adapter);
 	}
 
-	/**
-	 * Used by the "link with selection" action
-	 *
-	 * @param reactOnSelection
-	 */
-	public void setReactOnSelection(boolean reactOnSelection) {
-		this.reactOnSelection = reactOnSelection;
-	}
-
 	@Override
 	protected CommonViewer createCommonViewer(Composite aParent) {
 		CommonViewer viewer = super.createCommonViewer(aParent);
@@ -580,6 +602,12 @@
 
 	@Override
 	public void dispose() {
+		if (reactOnSelection != null) {
+			reactOnSelection.removeListener(reactOnSelectionListener);
+		}
+		if (branchHierarchy != null) {
+			branchHierarchy.removeListener(stateChangeListener);
+		}
 		// make sure to cancel the refresh job
 		if (this.scheduledJob != null) {
 			this.scheduledJob.cancel();
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java
index f50a9b7..90761f1 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java
@@ -1,5 +1,6 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 SAP AG and others.
+ * 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
@@ -36,7 +37,6 @@
 import java.util.Set;
 import java.util.WeakHashMap;
 
-import org.eclipse.core.commands.IStateListener;
 import org.eclipse.core.commands.State;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.WorkspaceJob;
@@ -94,21 +94,19 @@
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 
 /**
  * Content Provider for the Git Repositories View
  */
-public class RepositoriesViewContentProvider implements ITreeContentProvider,
-		IStateListener {
+public class RepositoriesViewContentProvider implements ITreeContentProvider {
 
 	private static final Object[] NO_CHILDREN = new Object[0];
 
 	private final RepositoryCache repositoryCache = org.eclipse.egit.core.Activator
 			.getDefault().getRepositoryCache();
 
-	private final State commandState;
-
-	private boolean branchHierarchyMode = false;
+	private final State branchHierarchy;
 
 	private boolean showUnbornHead = false;
 
@@ -134,16 +132,8 @@
 		super();
 		this.showUnbornHead = showUnbornHead;
 		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(), ICommandService.class);
-		commandState = srv.getCommand(
-				ToggleBranchHierarchyCommand.ID)
-				.getState(ToggleBranchHierarchyCommand.TOGGLE_STATE);
-		commandState.addListener(this);
-		try {
-			this.branchHierarchyMode = ((Boolean) commandState.getValue())
-					.booleanValue();
-		} catch (Exception e) {
-			Activator.handleError(e.getMessage(), e, false);
-		}
+		branchHierarchy = srv.getCommand(ToggleBranchHierarchyCommand.ID)
+				.getState(RegistryToggleState.STATE_ID);
 	}
 
 	@Override
@@ -187,9 +177,7 @@
 
 	@Override
 	public void dispose() {
-		commandState.removeListener(this);
-		for (ListenerHandle handle : refsChangedListeners.values())
-			handle.remove();
+		refsChangedListeners.values().forEach(ListenerHandle::remove);
 		refsChangedListeners.clear();
 	}
 
@@ -391,7 +379,7 @@
 
 	private Object[] getBranchChildren(RepositoryTreeNode node, Repository repo,
 			String prefix) {
-		if (branchHierarchyMode) {
+		if (isHierarchical()) {
 			return getBranchHierarchyChildren(node, repo, prefix);
 		} else {
 			try {
@@ -592,16 +580,6 @@
 		}
 	}
 
-	@Override
-	public void handleStateChange(State state, Object oldValue) {
-		try {
-			this.branchHierarchyMode = ((Boolean) state.getValue())
-					.booleanValue();
-		} catch (Exception e) {
-			Activator.handleError(e.getMessage(), e, false);
-		}
-	}
-
 	private synchronized Map<String, Ref> getRefs(final Repository repo, final String prefix) throws IOException {
 		Map<String, Ref> allRefs = branchRefs.get(repo);
 		if (allRefs == null) {
@@ -674,6 +652,6 @@
 	 *         layout; {@code false} otherwise
 	 */
 	public boolean isHierarchical() {
-		return branchHierarchyMode;
+		return ((Boolean) branchHierarchy.getValue()).booleanValue();
 	}
 }
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
index 046038b..d462fe0 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
@@ -42,6 +42,7 @@
 import org.eclipse.jgit.submodule.SubmoduleWalk;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.RegistryToggleState;
 
 /**
  * Lightweight decorator for {@link RepositoryTreeNode}s. Note that this
@@ -63,7 +64,7 @@
 	public RepositoryTreeNodeDecorator() {
 		ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(), ICommandService.class);
 		verboseBranchModeState = srv.getCommand(ToggleBranchCommitCommand.ID)
-				.getState(ToggleBranchCommitCommand.TOGGLE_STATE);
+				.getState(RegistryToggleState.STATE_ID);
 		verboseBranchModeState.addListener(this);
 		try {
 			this.verboseBranchMode = ((Boolean) verboseBranchModeState
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AbstractToggleCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AbstractToggleCommand.java
index 69cbda4..7f1a692 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AbstractToggleCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AbstractToggleCommand.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 Thomas Wolf <thomas.wolf@paranor.ch>
+ * Copyright (c) 2017, 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
@@ -12,12 +12,7 @@
 
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.egit.ui.internal.repository.RepositoriesView;
 import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
-import org.eclipse.ui.IViewPart;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.handlers.HandlerUtil;
 
 /**
@@ -29,17 +24,6 @@
 	@Override
 	public Object execute(ExecutionEvent event) throws ExecutionException {
 		HandlerUtil.toggleCommandState(event.getCommand());
-		IWorkbenchWindow window = PlatformUI.getWorkbench()
-				.getActiveWorkbenchWindow();
-		if (window != null) {
-			IWorkbenchPage page = window.getActivePage();
-			if (page != null) {
-				IViewPart part = page.findView(RepositoriesView.VIEW_ID);
-				if (part instanceof RepositoriesView) {
-					(((RepositoriesView) part).getCommonViewer()).refresh();
-				}
-			}
-		}
 		return null;
 	}
 
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/LinkWithSelectionCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/LinkWithSelectionCommand.java
deleted file mode 100644
index 2a8b41e..0000000
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/LinkWithSelectionCommand.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 SAP AG.
- * 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
- *
- * Contributors:
- *    Mathias Kinzler (SAP AG) - initial implementation
- *******************************************************************************/
-package org.eclipse.egit.ui.internal.repository.tree.command;
-
-import org.eclipse.core.commands.Command;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
-import org.eclipse.ui.handlers.HandlerUtil;
-import org.eclipse.ui.handlers.RegistryToggleState;
-
-/**
- * Implements "Link With Selection" toggle
- */
-public class LinkWithSelectionCommand extends
-		RepositoriesViewCommandHandler<RepositoryTreeNode> {
-	@Override
-	public Object execute(final ExecutionEvent event) throws ExecutionException {
-		Command command = event.getCommand();
-		HandlerUtil.toggleCommandState(command);
-		@SuppressWarnings("boxing")
-		boolean test = (Boolean) command.getState(RegistryToggleState.STATE_ID).getValue();
-		getView(event).setReactOnSelection(test);
-		return null;
-	}
-}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchCommitCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchCommitCommand.java
index d942c26..0adebd4 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchCommitCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchCommitCommand.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2011, 2017 GitHub Inc. and others.
+ *  Copyright (c) 2011, 2019 GitHub Inc. 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
@@ -23,9 +23,4 @@
 	 */
 	public static final String ID = "org.eclipse.egit.ui.RepositoriesToggleBranchCommit"; //$NON-NLS-1$
 
-	/**
-	 * The toggle state of this command
-	 */
-	public static final String TOGGLE_STATE = "org.eclipse.ui.commands.toggleState"; //$NON-NLS-1$
-
 }
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchHierarchyCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchHierarchyCommand.java
index 680c477..91346fc 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchHierarchyCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleBranchHierarchyCommand.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2017 SAP AG and others.
+ * 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
@@ -23,9 +23,4 @@
 	 */
 	public static final String ID = "org.eclipse.egit.ui.RepositoriesToggleBranchHierarchy"; //$NON-NLS-1$
 
-	/**
-	 * The toggle state of this command
-	 */
-	public static final String TOGGLE_STATE = "org.eclipse.ui.commands.toggleState"; //$NON-NLS-1$
-
 }
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleLinkWithSelectionCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleLinkWithSelectionCommand.java
new file mode 100644
index 0000000..8441214
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ToggleLinkWithSelectionCommand.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *    Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+/**
+ * Implements "Link With Selection" toggle
+ */
+public class ToggleLinkWithSelectionCommand extends AbstractToggleCommand {
+
+	/**
+	 * The command id for toggling "link with selection"
+	 */
+	public static final String ID = "org.eclipse.egit.ui.RepositoriesLinkWithSelection"; //$NON-NLS-1$
+
+}