Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java4
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/TestUtil.java101
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java243
-rw-r--r--org.eclipse.egit.ui/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.egit.ui/plugin.properties27
-rw-r--r--org.eclipse.egit.ui/plugin.xml751
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/RepositoryUtil.java151
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java9
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectRepositoryPage.java75
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectWizardPage.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java8
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/NewRemoteWizard.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java2028
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java41
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java94
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/LinkHelper.java137
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/PropertyTester.java94
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewActionProvider.java111
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewSorter.java46
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AddCommand.java34
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CheckoutCommand.java80
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CloneCommand.java30
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureFetchCommand.java44
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigurePushCommand.java44
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureRemoteCommand.java34
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CopyPathCommand.java64
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateBranchCommand.java90
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteBranchCommand.java81
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteFetchCommand.java41
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeletePushCommand.java40
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchCommand.java38
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java33
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ImportProjectsCommand.java49
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/LinkWithSelectionCommand.java32
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenCommand.java38
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenInTextEditorCommand.java48
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenPropertiesCommand.java36
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java84
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java38
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java33
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RefreshCommand.java26
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveCommand.java136
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveRemoteCommand.java51
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java40
46 files changed, 3342 insertions, 1854 deletions
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java
index 073af3eea..7b0133113 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java
@@ -8,6 +8,7 @@
*******************************************************************************/
package org.eclipse.egit.ui.test;
+import org.eclipse.egit.ui.view.repositories.GitRepositoriesViewTest;
import org.eclipse.egit.ui.wizards.clone.GitCloneWizardTest;
import org.eclipse.egit.ui.wizards.share.SharingWizardTest;
import org.junit.runner.RunWith;
@@ -15,7 +16,8 @@ import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
-@SuiteClasses({ GitCloneWizardTest.class, SharingWizardTest.class })
+@SuiteClasses( { GitCloneWizardTest.class, SharingWizardTest.class,
+ GitRepositoriesViewTest.class })
public class AllTests {
// empty class, don't need anything here
}
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/TestUtil.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/TestUtil.java
new file mode 100644
index 000000000..1c0b6d6d8
--- /dev/null
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/TestUtil.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.test;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.osgi.service.localization.BundleLocalization;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Utilities to be used by SWTBot tests
+ */
+public class TestUtil {
+
+ private static final char AMPERSAND = '&';
+
+ private static final TestUtil INSTANCE = new TestUtil();
+
+ public static TestUtil getInstance() {
+ return INSTANCE;
+ }
+
+ private ResourceBundle myBundle;
+
+ /**
+ * Allows access to the localized values of the EGit UI Plug-in
+ * <p>
+ * This will effectively read the plugin.properties. Ampersands (often used
+ * in menu items and field labels for keyboard shortcuts) will be filtered
+ * out (see also {@link #getPluginLocalizedValue(String, boolean)} in order
+ * to be able to reference these fields using SWTBot).
+ *
+ * @param key
+ * the key, must not be null
+ * @return the localized value in the current default {@link Locale}, or
+ * null
+ * @throws MissingResourceException
+ * if no value is found for the given key
+ */
+ public synchronized String getPluginLocalizedValue(String key)
+ throws MissingResourceException {
+ return getPluginLocalizedValue(key, false);
+ }
+
+ /**
+ * Allows access to the localized values of the EGit UI Plug-in
+ * <p>
+ *
+ * @param key
+ * see {@link #getPluginLocalizedValue(String)}
+ * @param keepAmpersands
+ * if <code>true</code>, ampersands will be kept
+ * @return see {@link #getPluginLocalizedValue(String)}
+ * @throws MissingResourceException
+ * see {@link #getPluginLocalizedValue(String)}
+ */
+ public synchronized String getPluginLocalizedValue(String key,
+ boolean keepAmpersands) throws MissingResourceException {
+ if (myBundle == null) {
+ ServiceTracker localizationTracker;
+
+ BundleContext context = Activator.getDefault().getBundle()
+ .getBundleContext();
+
+ localizationTracker = new ServiceTracker(context,
+ BundleLocalization.class.getName(), null);
+ localizationTracker.open();
+
+ BundleLocalization location = (BundleLocalization) localizationTracker
+ .getService();
+ if (location != null)
+ myBundle = location.getLocalization(Activator.getDefault()
+ .getBundle(), Locale.getDefault().toString());
+ }
+
+ String raw = myBundle.getString(key);
+
+ if (keepAmpersands || raw.indexOf(AMPERSAND) < 0)
+ return raw;
+
+ StringBuilder sb = new StringBuilder(raw.length());
+ for (int i = 0; i < raw.length(); i++) {
+ char c = raw.charAt(i);
+ if (c != AMPERSAND)
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+}
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
new file mode 100644
index 000000000..552336980
--- /dev/null
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.view.repositories;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.egit.core.op.ConnectProviderOperation;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.test.ContextMenuHelper;
+import org.eclipse.egit.ui.test.TestUtil;
+import org.eclipse.egit.ui.wizards.clone.GitCloneWizardTest;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
+import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
+import org.eclipse.swtbot.swt.finder.utils.TableCollection;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * SWTBot Tests for the Git Repositories View
+ */
+@RunWith(SWTBotJunit4ClassRunner.class)
+public class GitRepositoriesViewTest {
+
+ private static final String PRJ_NAME = "ImportProjectsTest";
+
+ private static final SWTWorkbenchBot bot = new SWTWorkbenchBot();
+
+ private SWTBotView viewbot;
+
+ private static IProject myProject;
+
+ private final static TestUtil myUtil = TestUtil.getInstance();
+
+ private static String viewName;
+
+ private static String gitCategory;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ // the show in context menu does not appear in the project explorer for
+ // general projects
+ bot.perspectiveById("org.eclipse.pde.ui.PDEPerspective").activate();
+ GitCloneWizardTest.closeWelcomePage();
+ myProject = ResourcesPlugin.getWorkspace().getRoot().getProject(
+ PRJ_NAME);
+ if (myProject.exists())
+ myProject.delete(true, null);
+ myProject.create(null);
+ myProject.open(null);
+
+ IFolder folder = myProject.getFolder("folder");
+ folder.create(false, true, null);
+ folder.getFile("test.txt").create(
+ new ByteArrayInputStream("Hello, world".getBytes("UTF-8")),
+ false, null);
+
+ File dirFile = myProject.getLocation().append(".git").toFile();
+ Repository repo = new Repository(dirFile);
+ repo.create();
+
+ new ConnectProviderOperation(myProject, dirFile).execute(null);
+ Activator.getDefault().getRepositoryUtil().addConfiguredRepository(
+ dirFile);
+
+ viewName = myUtil.getPluginLocalizedValue("GitRepositoriesView_name");
+ gitCategory = myUtil.getPluginLocalizedValue("GitCategory_name");
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ myProject.delete(true, null);
+ }
+
+ @Test
+ public void testOpenView() throws Exception {
+ getOrOpenView();
+ }
+
+ @Test
+ @Ignore
+ // TODO currently, this does not work if a refresh is currently running ->
+ // fix RepositoriesView
+ public void testShowIn() throws Exception {
+ SWTBotTree tree = bot.viewById("org.eclipse.jdt.ui.PackageExplorer")
+ .bot().tree();
+ tree.getAllItems()[0].select();
+ ContextMenuHelper.clickContextMenu(tree, "Show In", viewName);
+
+ SWTBotTree viewerTree = getOrOpenView().bot().tree();
+
+ TableCollection selection = viewerTree.selection();
+ assertTrue("Selection should contain one eelement", selection
+ .rowCount() == 1);
+ String nodeText = selection.get(0).get(0);
+ assertTrue("Node text should contain project name", nodeText
+ .contains(myProject.getName()));
+
+ tree.select(tree.getAllItems()[0].expand().getNode("folder").expand()
+ .getNode("test.txt"));
+
+ ContextMenuHelper.clickContextMenu(tree, "Show In", viewName);
+
+ selection = viewerTree.selection();
+ assertTrue("Selection should contain one eelement", selection
+ .rowCount() == 1);
+ nodeText = selection.get(0).get(0);
+ assertTrue("Node text should contain file name", nodeText
+ .contains("test.txt"));
+ }
+
+ @Test
+ @Ignore
+ // TODO this consistently fails with a "Widget disposed" SWT Exception
+ // if run in the AllTests test suite, but consistently works
+ // if this test class is run alone -> investigate
+ public void testOpenFirstLevel() throws Exception {
+ final SWTBotView view = getOrOpenView();
+ final SWTBotTreeItem[] items = view.bot().tree().getAllItems();
+ items[0].expand();
+ SWTBotTreeItem[] children;
+
+ children = items[0].getItems();
+ assertEquals("Wrong number of children", 5, children.length);
+ }
+
+ @Test
+ public void testHasRepo() throws Exception {
+ final SWTBotView view = getOrOpenView();
+ final SWTBotTreeItem[] items = view.bot().tree().getAllItems();
+ boolean found = false;
+ for (SWTBotTreeItem item : items) {
+ if (item.getText().startsWith(PRJ_NAME)) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Tree should have item with correct text", found);
+ }
+
+ @Test
+ public void testCopyPathToClipboard() throws Exception {
+ final SWTBotView view = getOrOpenView();
+ final SWTBotTreeItem[] items = view.bot().tree().getAllItems();
+ items[0].select();
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ Clipboard clp = new Clipboard(Display.getCurrent());
+ clp.clearContents();
+ clp.setContents(new Object[] { "x" },
+ new TextTransfer[] { TextTransfer.getInstance() });
+ String value = (String) clp.getContents(TextTransfer
+ .getInstance());
+ assertEquals("Clipboard content should be x", "x", value);
+
+ ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil
+ .getPluginLocalizedValue("CopyPathCommand"));
+
+ value = (String) clp.getContents(TextTransfer.getInstance());
+ assertTrue("Clipboard content should be a repository path",
+ FileKey.isGitRepository(new File(value), FS.DETECTED));
+
+ clp.dispose();
+ }
+ });
+
+ }
+
+ @Test
+ public void testAddRepoButton() throws Exception {
+ getOrOpenView().toolbarButton(
+ myUtil.getPluginLocalizedValue("AddRepositoryCommand")).click();
+ SWTBotShell shell = bot.shell(
+ UIText.RepositorySearchDialog_AddGitRepositories).activate();
+ shell.close();
+ }
+
+ @Test
+ public void testCloneRepoButton() throws Exception {
+ getOrOpenView().toolbarButton(
+ myUtil.getPluginLocalizedValue("CloneRepositoryCommand"))
+ .click();
+ SWTBotShell shell = bot.shell(UIText.GitCloneWizard_title).activate();
+ shell.close();
+ }
+
+ private SWTBotView getOrOpenView() throws Exception {
+ if (viewbot == null) {
+ bot.menu("Window").menu("Show View").menu("Other...").click();
+ SWTBotShell shell = bot.shell("Show View").activate();
+ shell.bot().tree().expandNode(gitCategory).getNode(viewName)
+ .select();
+ shell.bot().button(0).click();
+
+ viewbot = bot.viewByTitle(viewName);
+
+ assertNotNull("Repositories View should not be null", viewbot);
+ }
+ return viewbot;
+ }
+
+ @Test
+ @Ignore
+ public void testLinkWithSelection() throws Exception {
+ // TODO implement
+ }
+
+ @Test
+ @Ignore
+ public void testCollapseAll() throws Exception {
+ // TODO implement
+ }
+}
diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
index d2f8deed6..0a0a8402b 100644
--- a/org.eclipse.egit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
@@ -22,7 +22,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)",
org.eclipse.jsch.core;bundle-version="[1.1.100,2.0.0)",
org.eclipse.ui.editors;bundle-version="[3.4.0,4.0.0)",
com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)",
- org.eclipse.ui.forms;bundle-version="[3.3.100,4.0.0)"
+ org.eclipse.ui.navigator;bundle-version="[3.3.0,4.0.0)",
+ org.eclipse.ui.forms;bundle-version="[3.3.0,4.0.0)",
+ org.eclipse.core.expressions;bundle-version="[3.4.0,4.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: org.eclipse.egit.core;version="[0.9.0,0.10.0)",
diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties
index 476fbdd7c..d4b0d74bb 100644
--- a/org.eclipse.egit.ui/plugin.properties
+++ b/org.eclipse.egit.ui/plugin.properties
@@ -128,4 +128,29 @@ GitRepositoriesView_name = Git Repositories
GitCategory_name = Git
GitRepositoryPerspective_name = Git Repository Exploring
-ApplyPatchAction_label=Appl&y Patch... \ No newline at end of file
+ApplyPatchAction_label=Appl&y Patch...
+GitRepositoriesContentName = Git Repositories
+AddRepositoryCommand = Add a Git Repository
+CloneRepositoryCommand = Clone a Git Repository
+CheckoutCommand = Checkout
+CopyPathCommand = Copy Path to Clipboard
+DeleteBranchCommand = Delete Branch...
+FetchCommand = Fetch...
+PastePathCommand = Paste Repository Path
+OpenPropertiesCommand = Open Properties View
+PushCommand = Push...
+RefreshCommand = Refresh
+RemoveRepositoryCommand = Remove Repository
+ImportProjectsCommand = Import Projects...
+CreateBranchCommand = Create Branch...
+NewRemoteCommand = New Remote...
+ConfigureFetchCommand = Configure Fetch...
+ConfigurePushCommand = Configure Push...
+RemoveRemoteCommand = Remove Remote
+SimplePushCommand = Push
+SimpleFetchCommand = Fetch
+RemovePushCommand = Delete Push
+RemoveFetchCommand = Delete Fetch
+OpenInEditorCommand = Open in Text Editor
+OpenCommand = Open
+LinkWithSelectionCommand = Link with Selection \ No newline at end of file
diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml
index 4de833928..010dd85dc 100644
--- a/org.eclipse.egit.ui/plugin.xml
+++ b/org.eclipse.egit.ui/plugin.xml
@@ -556,4 +556,755 @@
</showInPart>
</perspectiveExtension>
</extension>
+ <extension
+ point="org.eclipse.ui.navigator.navigatorContent">
+ <navigatorContent
+ contentProvider="org.eclipse.egit.ui.internal.repository.RepositoriesViewContentProvider"
+ icon="icons/obj16/repository_rep.gif"
+ id="org.eclipse.egit.ui.RepositoriesViewContent"
+ labelProvider="org.eclipse.egit.ui.internal.repository.RepositoriesViewLabelProvider"
+ name="%GitRepositoriesContentName">
+ <triggerPoints>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.core.internal.resources.WorkspaceRoot">
+ </instanceof>
+ </or>
+ </triggerPoints>
+ <commonSorter
+ class="org.eclipse.egit.ui.internal.repository.tree.RepositoriesViewSorter">
+ </commonSorter>
+ </navigatorContent>
+ <actionProvider
+ class="org.eclipse.egit.ui.internal.repository.tree.RepositoriesViewActionProvider"
+ id="RepositoriesViewActionProvider">
+ <enablement>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode">
+ </instanceof>
+ </enablement>
+ </actionProvider>
+ </extension>
+ <extension
+ point="org.eclipse.ui.navigator.viewer">
+ <viewer
+ viewerId="org.eclipse.egit.ui.RepositoriesView">
+ </viewer>
+ <viewerContentBinding
+ viewerId="org.eclipse.egit.ui.RepositoriesView">
+ <includes>
+ <contentExtension
+ pattern="org.eclipse.egit.ui.RepositoriesViewContent">
+ </contentExtension>
+ <contentExtension
+ pattern="org.eclipse.egit.ui.RepositoriesViewLinkHelper">
+ </contentExtension>
+ </includes>
+ </viewerContentBinding>
+ <viewerActionBinding
+ viewerId="org.eclipse.egit.ui.RepositoriesView">
+ <includes>
+ <actionExtension
+ pattern="RepositoriesViewActionProvider">
+ </actionExtension>
+ </includes>
+ </viewerActionBinding>
+ </extension>
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ locationURI="popup:org.eclipse.egit.ui.RepositoriesView">
+ <separator
+ name="FirstGroup">
+ </separator>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewFetch"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewPush"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewImportProjects"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.WorkingDirNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FolderNode">
+ </instanceof>
+ </or>
+ </iterate>
+ <iterate>
+ <not>
+ <test
+ property="GitRepository.isBare">
+ </test>
+ </not>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewCheckout"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <and>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.TagNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RefNode">
+ </instanceof>
+ </or>
+ <not>
+ <test
+ property="GitRepository.isRefCheckedOut">
+ </test>
+ </not>
+ <not>
+ <test
+ property="GitRepository.isBare">
+ </test>
+ </not>
+ </and>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewFetchConfigured"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FetchNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewPushConfigured"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.PushNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <separator
+ name="FirstSeparator"
+ visible="true">
+ </separator>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewRemove"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="+">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewCreateBranch"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.LocalBranchesNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RefNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.BranchesNode">
+ </instanceof>
+ </or>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewNewRemote"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RemotesNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewConfigureFetch"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <and>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RemoteNode">
+ </instanceof>
+ <not>
+ <test
+ property="GitRepository.fetchExists">
+ </test>
+ </not>
+ </and>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FetchNode">
+ </instanceof>
+ </or>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewConfigurePush"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.PushNode">
+ </instanceof>
+ <and>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RemoteNode">
+ </instanceof>
+ <not>
+ <test
+ property="GitRepository.pushExists">
+ </test>
+ </not>
+ </and>
+ </or>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <separator
+ name="SecondGroup">
+ </separator>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewOpenInTextEditor"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FileNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <separator
+ name="SecondSeparator"
+ visible="true">
+ </separator>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewDeleteBranch"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <and>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RefNode">
+ </instanceof>
+ <test
+ property="GitRepository.isLocalBranch">
+ </test>
+ </or>
+ <not>
+ <test
+ property="GitRepository.isRefCheckedOut">
+ </test>
+ </not>
+ </and>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewRemoveRemote"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RemoteNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewDeleteFetch"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FetchNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewDeletePush"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate
+ ifEmpty="false"
+ operator="and">
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.PushNode">
+ </instanceof>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewOpenProperties"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RemoteNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FetchNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.PushNode">
+ </instanceof>
+ </or>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewCopyPath"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FileNode">
+ </instanceof>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FolderNode">
+ </instanceof>
+ <and>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.WorkingDirNode">
+ </instanceof>
+ <not>
+ <test
+ property="GitRepository.isBare">
+ </test>
+ </not>
+ </and>
+ </or>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewPaste"
+ style="push">
+ </command>
+ </menuContribution>
+ <menuContribution
+ locationURI="toolbar:org.eclipse.egit.ui.RepositoriesView">
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewAddRepository"
+ style="push">
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewClone"
+ style="push">
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesViewRefresh"
+ style="push">
+ </command>
+ <command
+ commandId="org.eclipse.egit.ui.RepositoriesLinkWithSelection"
+ style="toggle">
+ </command>
+ </menuContribution>
+ </extension>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewAddRepository"
+ name="%AddRepositoryCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.AddCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewClone"
+ name="%CloneRepositoryCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.CloneCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewCheckout"
+ name="%CheckoutCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.CheckoutCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewCopyPath"
+ name="%CopyPathCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.CopyPathCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewDeleteBranch"
+ name="%DeleteBranchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.DeleteBranchCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewFetch"
+ name="%FetchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.FetchCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewPaste"
+ name="%PastePathCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.PasteCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewOpenProperties"
+ name="%OpenPropertiesCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.OpenPropertiesCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewPush"
+ name="%PushCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.PushCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewRefresh"
+ name="%RefreshCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.RefreshCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewRemove"
+ name="%RemoveRepositoryCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.RemoveCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewImportProjects"
+ name="%ImportProjectsCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.ImportProjectsCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewCreateBranch"
+ name="%CreateBranchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.CreateBranchCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewNewRemote"
+ name="%NewRemoteCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.ConfigureRemoteCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewConfigureFetch"
+ name="%ConfigureFetchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.ConfigureFetchCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewConfigurePush"
+ name="%ConfigurePushCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.ConfigurePushCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewRemoveRemote"
+ name="%RemoveRemoteCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.RemoveRemoteCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewPushConfigured"
+ name="%SimplePushCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.PushConfiguredRemoteCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewFetchConfigured"
+ name="%SimpleFetchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.FetchConfiguredRemoteCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewDeletePush"
+ name="%RemovePushCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.DeletePushCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewDeleteFetch"
+ name="%RemoveFetchCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.DeleteFetchCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewOpenInTextEditor"
+ name="%OpenInEditorCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.OpenInTextEditorCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesViewOpen"
+ name="%OpenCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.OpenCommand">
+ </defaultHandler>
+ </command>
+ <command
+ id="org.eclipse.egit.ui.RepositoriesLinkWithSelection"
+ name="%LinkWithSelectionCommand">
+ <defaultHandler
+ class="org.eclipse.egit.ui.internal.repository.tree.command.LinkWithSelectionCommand">
+ </defaultHandler>
+ </command>
+ </extension>
+ <extension
+ point="org.eclipse.ui.commandImages">
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesViewAddRepository"
+ icon="icons/etool16/newlocation_wiz.gif">
+ </image>
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesViewFetch"
+ icon="icons/obj16/pull.gif">
+ </image>
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesViewClone"
+ icon="icons/obj16/cloneGit.gif">
+ </image>
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesViewRefresh"
+ icon="icons/obj16/refresh.gif">
+ </image>
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesViewPush"
+ icon="icons/obj16/commit.gif">
+ </image>
+ <image
+ commandId="org.eclipse.egit.ui.RepositoriesLinkWithSelection"
+ icon="icons/elcl16/synced.gif">
+ </image>
+ </extension>
+ <extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.eclipse.egit.ui.internal.repository.tree.PropertyTester"
+ id="org.eclipse.egit.ui.RepositoryTester"
+ namespace="GitRepository"
+ properties="isBare,isRefCheckedOut,isLocalBranch,fetchExists,pushExists"
+ type="org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode">
+ </propertyTester>
+ </extension>
+ <extension
+ point="org.eclipse.ui.navigator.linkHelper">
+ <linkHelper
+ class="org.eclipse.egit.ui.internal.repository.tree.LinkHelper"
+ id="org.eclipse.egit.ui.RepositoriesViewLinkHelper">
+ <editorInputEnablement>
+ <instanceof
+ value="org.eclipse.ui.IURIEditorInput">
+ </instanceof></editorInputEnablement>
+ <selectionEnablement>
+ <instanceof
+ value="org.eclipse.egit.ui.internal.repository.tree.FileNode">
+ </instanceof>
+ </selectionEnablement>
+ </linkHelper>
+ </extension>
</plugin>
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/RepositoryUtil.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/RepositoryUtil.java
index 8d3326dba..7d97c7f59 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/RepositoryUtil.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/RepositoryUtil.java
@@ -12,27 +12,44 @@ package org.eclipse.egit.ui;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.StringTokenizer;
import java.util.TreeSet;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Tag;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.util.FS;
+import org.osgi.service.prefs.BackingStoreException;
/**
* Utility class for handling Repositories in the UI.
*/
public class RepositoryUtil {
+ private static final String PREFS_DIRECTORIES = "GitRepositoriesView.GitDirectories"; //$NON-NLS-1$
+
private final Map<String, Map<String, String>> commitMappingCache = new HashMap<String, Map<String, String>>();
private final Map<String, String> repositoryNameCache = new HashMap<String, String>();
+ private final IEclipsePreferences prefs = new InstanceScope()
+ .getNode(Activator.getPluginId());
+
/**
* Clients should obtain an instance from {@link Activator}
*/
@@ -77,7 +94,6 @@ public class RepositoryUtil {
*/
public String mapCommitToRef(Repository repository, String commitId,
boolean refresh) {
-
synchronized (commitMappingCache) {
if (!ObjectId.isId(commitId)) {
@@ -205,9 +221,8 @@ public class RepositoryUtil {
if (gitDir != null) {
String name = repositoryNameCache.get(gitDir.getPath()
.toString());
- if (name != null) {
+ if (name != null)
return name;
- }
name = gitDir.getParentFile().getName();
repositoryNameCache.put(gitDir.getPath().toString(), name);
return name;
@@ -216,4 +231,134 @@ public class RepositoryUtil {
return ""; //$NON-NLS-1$
}
+ /**
+ * @return the underlying preferences
+ */
+ public IEclipsePreferences getPreferences() {
+ return prefs;
+ }
+
+ /**
+ * Checks if the directories are still valid; in case of invalid directories
+ * the underlying {@link IEclipsePreferences} will be changed (by removing
+ * these directories) and the registered listeners will be notified.
+ */
+ public void checkDirectories() {
+ getConfiguredRepositories(true);
+ }
+
+ /**
+ *
+ * @return the list of configured Repository paths; will be sorted
+ */
+ public List<String> getConfiguredRepositories() {
+ return this.getConfiguredRepositories(false);
+ }
+
+ private List<String> getConfiguredRepositories(boolean checkPaths) {
+ synchronized (prefs) {
+ Set<String> configuredStrings = new HashSet<String>();
+ Set<String> resultStrings = new HashSet<String>();
+
+ String dirs = prefs.get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
+ if (dirs != null && dirs.length() > 0) {
+ StringTokenizer tok = new StringTokenizer(dirs,
+ File.pathSeparator);
+ while (tok.hasMoreTokens()) {
+ String dirName = tok.nextToken();
+ configuredStrings.add(dirName);
+ if (checkPaths) {
+ File testFile = new File(dirName);
+ if (!FileKey.isGitRepository(testFile, FS.DETECTED))
+ resultStrings.add(dirName);
+ }
+ resultStrings.add(dirName);
+ }
+ }
+
+ if (checkPaths && resultStrings.size() < configuredStrings.size())
+ saveDirs(resultStrings);
+ List<String> result = new ArrayList<String>();
+ result.addAll(resultStrings);
+ Collections.sort(result);
+ return result;
+ }
+ }
+
+ /**
+ *
+ * @param repositoryDir
+ * the Repository path
+ * @return <code>true</code> if the repository path was not yet configured
+ * @throws IllegalArgumentException
+ * if the path does not "look" like a Repository
+ */
+ public boolean addConfiguredRepository(File repositoryDir)
+ throws IllegalArgumentException {
+ synchronized (prefs) {
+
+ if (!FileKey.isGitRepository(repositoryDir, FS.DETECTED))
+ throw new IllegalArgumentException();
+
+ String dirString;
+ try {
+ dirString = repositoryDir.getCanonicalPath();
+ } catch (IOException e) {
+ dirString = repositoryDir.getAbsolutePath();
+ }
+
+ List<String> dirStrings = getConfiguredRepositories(false);
+ if (dirStrings.contains(dirString)) {
+ return false;
+ } else {
+ Set<String> dirs = new HashSet<String>();
+ dirs.addAll(dirStrings);
+ dirs.add(dirString);
+ saveDirs(dirs);
+ return true;
+ }
+ }
+ }
+
+ /**
+ * @param file
+ * @return <code>true</code> if the configuration was changed by the remove
+ */
+ public boolean removeDir(File file) {
+ synchronized (prefs) {
+
+ String dir;
+ try {
+ dir = file.getCanonicalPath();
+ } catch (IOException e1) {
+ dir = file.getAbsolutePath();
+ }
+
+ Set<String> dirStrings = new HashSet<String>();
+ dirStrings.addAll(getConfiguredRepositories(false));
+ if (dirStrings.remove(dir)) {
+ saveDirs(dirStrings);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private void saveDirs(Set<String> gitDirStrings) {
+ StringBuilder sb = new StringBuilder();
+ for (String gitDirString : gitDirStrings) {
+ sb.append(gitDirString);
+ sb.append(File.pathSeparatorChar);
+ }
+
+ prefs.put(PREFS_DIRECTORIES, sb.toString());
+ try {
+ prefs.flush();
+ } catch (BackingStoreException e) {
+ IStatus error = new Status(IStatus.ERROR, Activator.getPluginId(),
+ e.getMessage(), e);
+ Activator.getDefault().getLog().log(error);
+ }
+ }
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java
index b3ec1123b..a222eed1b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java
@@ -23,10 +23,10 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egit.core.op.CloneOperation;
import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.RepositoryUtil;
import org.eclipse.egit.ui.UIIcons;
import org.eclipse.egit.ui.UIText;
import org.eclipse.egit.ui.internal.components.RepositorySelectionPage;
-import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
@@ -144,6 +144,9 @@ public class GitCloneWizard extends Wizard {
alreadyClonedInto = workdir.getPath();
+ final RepositoryUtil config = Activator.getDefault()
+ .getRepositoryUtil();
+
if (background) {
final Job job = new Job(NLS.bind(UIText.GitCloneWizard_jobName, uri
.toString())) {
@@ -152,7 +155,7 @@ public class GitCloneWizard extends Wizard {
try {
op.run(monitor);
RepositorySelectionPage.saveUriInPrefs(uri.toString());
- RepositoriesView.addDir(op.getGitDir());
+ config.addConfiguredRepository(op.getGitDir());
return Status.OK_STATUS;
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
@@ -182,7 +185,7 @@ public class GitCloneWizard extends Wizard {
});
RepositorySelectionPage.saveUriInPrefs(uri.toString());
- RepositoriesView.addDir(op.getGitDir());
+ config.addConfiguredRepository(op.getGitDir());
return true;
} catch (InterruptedException e) {
MessageDialog.openInformation(getShell(),
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectRepositoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectRepositoryPage.java
index 253fd9065..7c4ecf4f3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectRepositoryPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectRepositoryPage.java
@@ -16,8 +16,8 @@ import java.util.List;
import java.util.Set;
import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.RepositoryUtil;
import org.eclipse.egit.ui.UIText;
-import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.egit.ui.internal.repository.RepositoriesViewContentProvider;
import org.eclipse.egit.ui.internal.repository.RepositoriesViewLabelProvider;
import org.eclipse.egit.ui.internal.repository.RepositorySearchDialog;
@@ -46,6 +46,8 @@ import org.eclipse.swt.widgets.Composite;
*/
public class GitSelectRepositoryPage extends WizardPage {
+ private final RepositoryUtil util;
+
private TableViewer tv;
private Button addRepo;
@@ -59,6 +61,7 @@ public class GitSelectRepositoryPage extends WizardPage {
super(GitSelectRepositoryPage.class.getName());
setTitle(UIText.GitSelectRepositoryPage_PageTitle);
setMessage(UIText.GitSelectRepositoryPage_PageMessage);
+ util = Activator.getDefault().getRepositoryUtil();
}
/**
@@ -84,7 +87,7 @@ public class GitSelectRepositoryPage extends WizardPage {
| SWT.BORDER);
tv.setContentProvider(new RepositoriesViewContentProvider());
GridDataFactory.fillDefaults().grab(true, true).applyTo(tv.getTable());
- new RepositoriesViewLabelProvider(tv);
+ tv.setLabelProvider(new RepositoriesViewLabelProvider());
Composite tb = new Composite(main, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(1).applyTo(tb);
@@ -98,42 +101,33 @@ public class GitSelectRepositoryPage extends WizardPage {
SWT.BEGINNING).applyTo(cloneRepo);
cloneRepo.addSelectionListener(new SelectionAdapter() {
-
@Override
public void widgetSelected(SelectionEvent e) {
- List<String> dirsBefore = RepositoriesView.getDirs();
+ List<String> dirsBefore = util.getConfiguredRepositories();
WizardDialog dlg = new WizardDialog(getShell(),
new GitCloneWizard());
if (dlg.open() == Window.OK) {
- try {
- tv.setInput(RepositoriesView
- .getRepositoriesFromDirs(null));
- List<String> dirsAfter = RepositoriesView.getDirs();
- if (!dirsBefore.containsAll(dirsAfter)) {
- for (String dir : dirsAfter) {
- if (!dirsBefore.contains(dir)) {
- try {
- RepositoryNode node = new RepositoryNode(
- null, new Repository(new File(
- dir)));
- tv
- .setSelection(new StructuredSelection(
- node));
- } catch (IOException e1) {
- Activator.handleError(e1.getMessage(),
- e1, false);
- }
+ List<String> dirsAfter = util.getConfiguredRepositories();
+ if (!dirsBefore.containsAll(dirsAfter)) {
+ tv.setInput(dirsAfter);
+ for (String dir : dirsAfter) {
+ if (!dirsBefore.contains(dir)) {
+ try {
+ RepositoryNode node = new RepositoryNode(
+ null, new Repository(new File(dir)));
+ tv.setSelection(new StructuredSelection(
+ node));
+ } catch (IOException e1) {
+ Activator.handleError(e1.getMessage(), e1,
+ false);
}
}
}
- checkPage();
- } catch (InterruptedException e1) {
- // ignore
}
+ checkPage();
}
}
-
});
addRepo = new Button(tb, SWT.PUSH);
@@ -145,20 +139,19 @@ public class GitSelectRepositoryPage extends WizardPage {
@Override
public void widgetSelected(SelectionEvent e) {
+
+ List<String> configuredDirs = util.getConfiguredRepositories();
RepositorySearchDialog dlg = new RepositorySearchDialog(
- getShell(), RepositoriesView.getDirs());
+ getShell(), configuredDirs);
if (dlg.open() == Window.OK && dlg.getDirectories().size() > 0) {
- try {
- Set<String> dirs = dlg.getDirectories();
- for (String dir : dirs)
- RepositoriesView.addDir(new File(dir));
-
- tv.setInput(RepositoriesView
- .getRepositoriesFromDirs(null));
- checkPage();
- } catch (InterruptedException e1) {
- // ignore
- }
+
+ Set<String> dirs = dlg.getDirectories();
+ for (String dir : dirs)
+ util.addConfiguredRepository(new File(dir));
+
+ tv.setInput(util.getConfiguredRepositories());
+ checkPage();
+
}
}
@@ -171,11 +164,7 @@ public class GitSelectRepositoryPage extends WizardPage {
}
});
- try {
- tv.setInput(RepositoriesView.getRepositoriesFromDirs(null));
- } catch (InterruptedException e) {
- // ignore
- }
+ tv.setInput(util.getConfiguredRepositories());
// we need to select at least a repository to become complete
setPageComplete(false);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectWizardPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectWizardPage.java
index 5f435d743..87a165db4 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectWizardPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitSelectWizardPage.java
@@ -239,7 +239,7 @@ public class GitSelectWizardPage extends WizardPage {
tv.setContentProvider(cp);
GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 200)
.applyTo(tv.getTree());
- new RepositoriesViewLabelProvider(tv);
+ tv.setLabelProvider(new RepositoriesViewLabelProvider());
tv.addSelectionChangedListener(new ISelectionChangedListener() {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
index a30fb2a11..b6003fa19 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/BranchSelectionDialog.java
@@ -106,7 +106,7 @@ public class BranchSelectionDialog extends TitleAreaDialog {
// TODO deprecated constructor for now
FilteredTree tree = new FilteredTree(parent, SWT.SINGLE | SWT.BORDER, new PatternFilter());
branchTree = tree.getViewer();
- new RepositoriesViewLabelProvider(branchTree);
+ branchTree.setLabelProvider(new RepositoriesViewLabelProvider());
branchTree.setContentProvider(new RepositoriesViewContentProvider());
GridDataFactory.fillDefaults().grab(true, true).hint(500, 300).applyTo(
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java
index b128ec7de..9cbb9c5f4 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java
@@ -26,9 +26,13 @@ import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
/**
- *
+ * Allows to configure a "Remote".
+ * <p>
+ * Asks for a name and whether to configure fetch, push, or both. Depending on
+ * the user's decision about what to configure, the fetch, push, or both
+ * configurations are performed.
*/
-class ConfigureRemoteWizard extends Wizard {
+public class ConfigureRemoteWizard extends Wizard {
final RepositoryConfig myConfiguration;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/NewRemoteWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/NewRemoteWizard.java
index 0f4ef41d5..b25077eb7 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/NewRemoteWizard.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/NewRemoteWizard.java
@@ -28,7 +28,7 @@ import org.eclipse.jgit.transport.URIish;
* Used for "remote" configuration of a Repository
*
*/
-class NewRemoteWizard extends Wizard {
+public class NewRemoteWizard extends Wizard {
final RepositoryConfig myConfiguration;
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 9f9955e83..0faa38c56 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
@@ -12,97 +12,47 @@ package org.eclipse.egit.ui.internal.repository;
import java.io.File;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import org.eclipse.core.filesystem.EFS;
-import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.InstanceScope;
-import org.eclipse.egit.core.op.BranchOperation;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.egit.core.RepositoryCache;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.UIIcons;
-import org.eclipse.egit.ui.UIText;
-import org.eclipse.egit.ui.internal.clone.GitCloneWizard;
-import org.eclipse.egit.ui.internal.clone.GitCreateProjectViaWizardWizard;
-import org.eclipse.egit.ui.internal.fetch.FetchConfiguredRemoteAction;
-import org.eclipse.egit.ui.internal.fetch.FetchWizard;
-import org.eclipse.egit.ui.internal.push.PushConfiguredRemoteAction;
-import org.eclipse.egit.ui.internal.push.PushWizard;
-import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.egit.ui.RepositoryUtil;
+import org.eclipse.egit.ui.internal.repository.tree.FileNode;
+import org.eclipse.egit.ui.internal.repository.tree.RefNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNodeType;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.action.IToolBarManager;
-import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.dialogs.ProgressMonitorDialog;
-import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.egit.ui.internal.repository.tree.TagNode;
import org.eclipse.jface.viewers.IOpenListener;
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.ITreeContentProvider;
import org.eclipse.jface.viewers.OpenEvent;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.jface.wizard.WizardDialog;
-import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jgit.lib.IndexChangedEvent;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefsChangedEvent;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.RepositoryCache;
-import org.eclipse.jgit.lib.RepositoryConfig;
import org.eclipse.jgit.lib.RepositoryListener;
-import org.eclipse.jgit.transport.RemoteConfig;
-import org.eclipse.jgit.util.FS;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.dnd.Clipboard;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.events.MenuDetectEvent;
-import org.eclipse.swt.events.MenuDetectListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
@@ -111,261 +61,79 @@ import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.actions.ActionFactory;
-import org.eclipse.ui.editors.text.EditorsUI;
-import org.eclipse.ui.ide.FileStoreEditorInput;
-import org.eclipse.ui.ide.IDE;
-import org.eclipse.ui.part.IShowInTarget;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.navigator.CommonNavigator;
+import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.part.ShowInContext;
-import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.PropertySheetPage;
-import org.osgi.service.prefs.BackingStoreException;
/**
- *
- * The Git Repositories view.
- * <p>
- * This keeps track of a bunch of local directory names each of which represent
- * a Git Repository. This list is stored in some Preferences object and used to
- * build the tree in the view.
- * <p>
- * Implements {@link ISelectionProvider} in order to integrate with the
- * Properties view.
- * <p>
- * This periodically refreshes itself in order to react on Repository changes.
+ * The "Git Repositories View"
*/
-public class RepositoriesView extends ViewPart implements ISelectionProvider,
- IShowInTarget {
-
- /** The view ID */
- public static final String VIEW_ID = "org.eclipse.egit.ui.RepositoriesView"; //$NON-NLS-1$
+public class RepositoriesView extends CommonNavigator {
- // TODO central constants? RemoteConfig ones are private
- static final String REMOTE = "remote"; //$NON-NLS-1$
+ /** "remote" */
+ public static final String REMOTE = "remote"; //$NON-NLS-1$
- static final String URL = "url"; //$NON-NLS-1$
+ /** "url" */
+ public static final String URL = "url"; //$NON-NLS-1$
- static final String PUSHURL = "pushurl"; //$NON-NLS-1$
+ /** "pushurl" */
+ public static final String PUSHURL = "pushurl"; //$NON-NLS-1$
- static final String FETCH = "fetch"; //$NON-NLS-1$
+ /** "push" */
+ public static final String PUSH = "push"; //$NON-NLS-1$
- static final String PUSH = "push"; //$NON-NLS-1$
+ /** "fetch" */
+ public static final String FETCH = "fetch"; //$NON-NLS-1$
- private static final String PREFS_DIRECTORIES = "GitRepositoriesView.GitDirectories"; //$NON-NLS-1$
-
- private static final String PREFS_SYNCED = "GitRepositoriesView.SyncWithSelection"; //$NON-NLS-1$
+ /** view id */
+ public static final String VIEW_ID = "org.eclipse.egit.ui.RepositoriesView"; //$NON-NLS-1$
private final Set<Repository> repositories = new HashSet<Repository>();
- private final List<ISelectionChangedListener> selectionListeners = new ArrayList<ISelectionChangedListener>();
-
private RepositoryListener repositoryListener;
- private ISelection currentSelection = new StructuredSelection();
-
private Job scheduledJob;
- private TreeViewer tv;
+ private final RepositoryUtil repositoryUtil;
- private IAction importAction;
+ private final RepositoryCache repositoryCache;
- private IAction addAction;
+ private long lastInputChange = 0l;
- private IAction refreshAction;
+ private long lastInputUpdate = -1l;
- private IAction linkWithSelectionAction;
+ private boolean reactOnSelection = false;
- private IAction copyAction;
+ private final IPreferenceChangeListener configurationListener;
- private IAction pasteAction;
+ private ISelectionListener selectionChangedListener;
/**
- * TODO move to utility class
- *
- * @return the directories as configured for this view
+ * The default constructor
*/
- public static List<String> getDirs() {
- List<String> resultStrings = new ArrayList<String>();
- String dirs = getPrefs().get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
- if (dirs != null && dirs.length() > 0) {
- StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
- while (tok.hasMoreTokens()) {
- String dirName = tok.nextToken();
- File testFile = new File(dirName);
- if (testFile.exists() && !resultStrings.contains(dirName)) {
- resultStrings.add(dirName);
- }
- }
- }
- Collections.sort(resultStrings);
- return resultStrings;
- }
-
- private static void removeDir(File file) {
-
- String dir;
- try {
- dir = file.getCanonicalPath();
- } catch (IOException e1) {
- dir = file.getAbsolutePath();
- }
-
- IEclipsePreferences prefs = getPrefs();
-
- TreeSet<String> resultStrings = new TreeSet<String>();
- String dirs = prefs.get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
- if (dirs != null && dirs.length() > 0) {
- StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
- while (tok.hasMoreTokens()) {
- String dirName = tok.nextToken();
- File testFile = new File(dirName);
- if (testFile.exists()) {
- try {
- resultStrings.add(testFile.getCanonicalPath());
- } catch (IOException e) {
- resultStrings.add(testFile.getAbsolutePath());
- }
- }
- }
- }
-
- if (resultStrings.remove(dir)) {
- StringBuilder sb = new StringBuilder();
- for (String gitDirString : resultStrings) {
- sb.append(gitDirString);
- sb.append(File.pathSeparatorChar);
- }
-
- prefs.put(PREFS_DIRECTORIES, sb.toString());
- try {
- prefs.flush();
- } catch (BackingStoreException e) {
- IStatus error = new Status(IStatus.ERROR, Activator
- .getPluginId(), e.getMessage(), e);
- Activator.getDefault().getLog().log(error);
- }
- }
-
- }
-
- @Override
- public Object getAdapter(Class adapter) {
- // integrate with Properties view
- if (adapter == IPropertySheetPage.class) {
- PropertySheetPage page = new PropertySheetPage();
- page
- .setPropertySourceProvider(new RepositoryPropertySourceProvider(
- page));
- return page;
- }
-
- return super.getAdapter(adapter);
- }
-
- @Override
- public void createPartControl(Composite parent) {
- tv = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
- tv.setContentProvider(new RepositoriesViewContentProvider());
- // the label provider registers itself
- new RepositoriesViewLabelProvider(tv);
-
- getSite().setSelectionProvider(this);
-
- tv.addSelectionChangedListener(new ISelectionChangedListener() {
-
- public void selectionChanged(SelectionChangedEvent event) {
-
- copyAction.setEnabled(false);
-
- IStructuredSelection ssel = (IStructuredSelection) event
- .getSelection();
- if (ssel.size() == 1) {
- RepositoryTreeNode node = (RepositoryTreeNode) ssel
- .getFirstElement();
- // allow copy on repository, file, or folder (copying the
- // directory)
- if (node.getType() == RepositoryTreeNodeType.REPO
- || node.getType() == RepositoryTreeNodeType.WORKINGDIR
- || node.getType() == RepositoryTreeNodeType.FOLDER
- || node.getType() == RepositoryTreeNodeType.FILE) {
- copyAction.setEnabled(true);
- }
- setSelection(new StructuredSelection(ssel.getFirstElement()));
- } else {
- setSelection(new StructuredSelection());
- }
-
- }
- });
- tv.addOpenListener(new IOpenListener() {
- public void open(OpenEvent event) {
- IStructuredSelection selection = (IStructuredSelection) event
- .getSelection();
- if (selection.isEmpty()) {
- // nothing selected, ignore
- return;
- }
-
- Object element = selection.getFirstElement();
- ITreeContentProvider contentProvider = (ITreeContentProvider) tv
- .getContentProvider();
- if (contentProvider.hasChildren(element)) {
- // this element has children, expand/collapse it
- tv.setExpandedState(element, !tv.getExpandedState(element));
- } else {
- Object[] selectionArray = selection.toArray();
- for (Object selectedElement : selectionArray) {
- RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
- // if any of the selected elements are not files, ignore
- // the open request
- if (node.getType() != RepositoryTreeNodeType.FILE
- && node.getType() != RepositoryTreeNodeType.REF
- && node.getType() != RepositoryTreeNodeType.TAG) {
- return;
- }
- }
-
- // open the files the user has selected
- for (Object selectedElement : selectionArray) {
- RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
- if (node.getType() == RepositoryTreeNodeType.FILE)
- openFile((File) node.getObject());
- else if (node.getType() == RepositoryTreeNodeType.REF
- || node.getType() == RepositoryTreeNodeType.TAG) {
- Ref ref = (Ref) node.getObject();
- if (!isBare(node.getRepository())
- && ref.getName().startsWith(
- Constants.R_REFS))
- checkoutBranch(node, ref.getName());
- }
- }
- }
+ public RepositoriesView() {
+ repositoryUtil = Activator.getDefault().getRepositoryUtil();
+ repositoryCache = org.eclipse.egit.core.Activator.getDefault()
+ .getRepositoryCache();
+
+ configurationListener = new IPreferenceChangeListener() {
+ public void preferenceChange(PreferenceChangeEvent event) {
+ lastInputChange = System.currentTimeMillis();
+ scheduleRefresh();
}
- });
-
- createRepositoryChangedListener();
-
- addContextMenu();
-
- addActionsToToolbar();
-
- scheduleRefresh();
-
- ISelectionService srv = (ISelectionService) getSite().getService(
- ISelectionService.class);
- srv.addPostSelectionListener(new ISelectionListener() {
+ };
+ selectionChangedListener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart part,
ISelection selection) {
-
- // if the "link with selection" toggle is off, we're done
- if (linkWithSelectionAction == null
- || !linkWithSelectionAction.isChecked())
+ if (!reactOnSelection)
return;
// this may happen if we switch between editors
@@ -379,1232 +147,231 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
reactOnSelection(selection);
}
}
-
- });
+ };
+ createRepositoryChangedListener();
}
- private void reactOnSelection(ISelection selection) {
- if (selection instanceof StructuredSelection) {
- StructuredSelection ssel = (StructuredSelection) selection;
- if (ssel.size() != 1)
- return;
- if (ssel.getFirstElement() instanceof IResource) {
- showResource((IResource) ssel.getFirstElement());
- }
- if (ssel.getFirstElement() instanceof IAdaptable) {
- IResource adapted = (IResource) ((IAdaptable) ssel
- .getFirstElement()).getAdapter(IResource.class);
- if (adapted != null)
- showResource(adapted);
- }
+ @Override
+ public Object getAdapter(Class adapter) {
+ // integrate with Properties view
+ if (adapter == IPropertySheetPage.class) {
+ PropertySheetPage page = new PropertySheetPage();
+ page.setPropertySourceProvider(new RepositoryPropertySourceProvider(
+ page));
+ return page;
}
+ return super.getAdapter(adapter);
}
- private void addContextMenu() {
- tv.getTree().addMenuDetectListener(new MenuDetectListener() {
-
- public void menuDetected(MenuDetectEvent e) {
- Menu men = tv.getTree().getMenu();
- if (men != null) {
- men.dispose();
- }
- men = new Menu(tv.getTree());
-
- TreeItem testItem = tv.getTree().getItem(
- tv.getTree().toControl(new Point(e.x, e.y)));
- if (testItem == null) {
- addMenuItemsForPanel(men);
- } else {
- addMenuItemsForTreeSelection(men);
- }
-
- tv.getTree().setMenu(men);
- }
- });
- }
-
- private void addMenuItemsForPanel(Menu men) {
-
- MenuItem importItem = new MenuItem(men, SWT.PUSH);
- importItem.setText(UIText.RepositoriesView_ImportRepository_MenuItem);
- importItem.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- importAction.run();
- }
-
- });
-
- MenuItem addItem = new MenuItem(men, SWT.PUSH);
- addItem.setText(UIText.RepositoriesView_AddRepository_MenuItem);
- addItem.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- addAction.run();
- }
-
- });
-
- MenuItem pasteItem = new MenuItem(men, SWT.PUSH);
- pasteItem.setText(UIText.RepositoriesView_PasteMenu);
- pasteItem.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- pasteAction.run();
- }
-
- });
-
- MenuItem refreshItem = new MenuItem(men, SWT.PUSH);
- refreshItem.setText(refreshAction.getText());
- refreshItem.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- refreshAction.run();
- }
-
- });
-
+ /**
+ * Used by the "link with selection" action
+ *
+ * @param reactOnSelection
+ */
+ public void setReactOnSelection(boolean reactOnSelection) {
+ // TODO persist the state of the button somewhere
+ this.reactOnSelection = reactOnSelection;
}
- private void addMenuItemsForTreeSelection(Menu men) {
-
- final IStructuredSelection sel = (IStructuredSelection) tv
- .getSelection();
-
- boolean repoOnly = true;
- for (Object selected : sel.toArray()) {
-
- if (((RepositoryTreeNode) selected).getType() != RepositoryTreeNodeType.REPO) {
- repoOnly = false;
- break;
- }
- }
-
- if (sel.size() > 1 && repoOnly) {
- List nodes = sel.toList();
- final Repository[] repos = new Repository[nodes.size()];
- for (int i = 0; i < sel.size(); i++)
- repos[i] = ((RepositoryTreeNode) nodes.get(i)).getRepository();
-
- MenuItem remove = new MenuItem(men, SWT.PUSH);
- remove.setText(UIText.RepositoriesView_Remove_MenuItem);
- remove.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- // TODO progress monitoring/cancellation
- removeRepository(new NullProgressMonitor(), repos);
- }
- });
-
- }
-
- // from here on, we only deal with single selection
- if (sel.size() > 1)
- return;
-
- final RepositoryTreeNode node = (RepositoryTreeNode) sel
- .getFirstElement();
-
- final boolean isBare = isBare(node.getRepository());
-
- if (node.getType() == RepositoryTreeNodeType.REF) {
-
- final Ref ref = (Ref) node.getObject();
-
- // we don't check out symbolic references
- if (!ref.isSymbolic()) {
-
- if (!isBare) {
- MenuItem checkout = new MenuItem(men, SWT.PUSH);
- checkout.setText(UIText.RepositoriesView_CheckOut_MenuItem);
-
- checkout.setEnabled(!isRefCheckedOut(node.getRepository(),
- ref.getName()));
-
- checkout.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- checkoutBranch(node, ref.getLeaf().getName());
- }
- });
-
- new MenuItem(men, SWT.SEPARATOR);
- }
-
- createCreateBranchItem(men, node);
- createDeleteBranchItem(men, node);
-
- }
- }
-
- if (node.getType() == RepositoryTreeNodeType.TAG) {
-
- final Ref ref = (Ref) node.getObject();
-
- MenuItem checkout = new MenuItem(men, SWT.PUSH);
- checkout.setText(UIText.RepositoriesView_CheckOut_MenuItem);
-
- checkout.setEnabled(!isRefCheckedOut(node.getRepository(), ref
- .getName()));
-
- checkout.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- checkoutBranch(node, ref.getLeaf().getName());
- }
- });
- }
-
- if (node.getType() == RepositoryTreeNodeType.BRANCHES
- || node.getType() == RepositoryTreeNodeType.LOCALBRANCHES)
- // offering this on the "Remote Branches" node would probably be
- // confusing
- createCreateBranchItem(men, node);
-
- // for Repository: import existing projects, remove, (delete), open
- // properties
- if (node.getType() == RepositoryTreeNodeType.REPO) {
-
- final Repository repo = (Repository) node.getObject();
-
- // TODO "import existing plug-in" menu item
-
- MenuItem remove = new MenuItem(men, SWT.PUSH);
- remove.setText(UIText.RepositoriesView_Remove_MenuItem);
- remove.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- // TODO progress monitoring/cancellation
- removeRepository(new NullProgressMonitor(), repo);
- }
- });
-
- new MenuItem(men, SWT.SEPARATOR);
-
- MenuItem fetchItem = new MenuItem(men, SWT.PUSH);
- fetchItem.setText(UIText.RepositoriesView_FetchMenu);
- fetchItem.setImage(UIIcons.FETCH.createImage());
- fetchItem.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- try {
- new WizardDialog(getSite().getShell(), new FetchWizard(
- repo)).open();
- } catch (URISyntaxException e1) {
- Activator.handleError(e1.getMessage(), e1, true);
- }
- }
-
- });
+ @Override
+ protected CommonViewer createCommonViewer(Composite aParent) {
+ CommonViewer viewer = super.createCommonViewer(aParent);
+ // handle the double-click event
+ viewer.addOpenListener(new IOpenListener() {
- MenuItem pushItem = new MenuItem(men, SWT.PUSH);
- pushItem.setText(UIText.RepositoriesView_PushMenu);
- pushItem.setImage(UIIcons.PUSH.createImage());
- pushItem.addSelectionListener(new SelectionAdapter() {
+ public void open(OpenEvent event) {
+ TreeSelection sel = (TreeSelection) event.getSelection();
+ RepositoryTreeNode element = (RepositoryTreeNode) sel
+ .getFirstElement();
+
+ if (element instanceof RefNode || element instanceof FileNode
+ || element instanceof TagNode) {
+ IHandlerService srv = (IHandlerService) getViewSite()
+ .getService(IHandlerService.class);
+ ICommandService csrv = (ICommandService) getViewSite()
+ .getService(ICommandService.class);
+ Command openCommand = csrv
+ .getCommand("org.eclipse.egit.ui.RepositoriesViewOpen"); //$NON-NLS-1$
+ ExecutionEvent evt = srv.createExecutionEvent(openCommand,
+ null);
- @Override
- public void widgetSelected(SelectionEvent e) {
try {
- new WizardDialog(getSite().getShell(), new PushWizard(
- repo)).open();
- } catch (URISyntaxException e1) {
- Activator.handleError(e1.getMessage(), e1, true);
+ openCommand.executeWithChecks(evt);
+ } catch (Exception e) {
+ Activator.handleError(e.getMessage(), e, false);
}
}
-
- });
-
- // TODO delete does not work because of file locks on .pack-files
- // Shawn Pearce has added the following thoughts:
-
- // Hmm. We probably can't active detect file locks on pack files on
- // Windows, can we?
- // It would be nice if we could support a delete, but only if the
- // repository is
- // reasonably believed to be not-in-use right now.
- //
- // Within EGit you might be able to check GitProjectData and its
- // repositoryCache to
- // see if the repository is open by this workspace. If it is, then
- // we know we shouldn't
- // try to delete it.
- //
- // Some coding might look like this:
- //
- // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
- // deleteRepo.setText("Delete");
- // deleteRepo.addSelectionListener(new SelectionAdapter() {
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- //
- // boolean confirmed = MessageDialog.openConfirm(getSite()
- // .getShell(), "Confirm",
- // "This will delete the repository, continue?");
- //
- // if (!confirmed)
- // return;
- //
- // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
- //
- // public void run(IProgressMonitor monitor)
- // throws CoreException {
- // File workDir = repos.get(0).getRepository()
- // .getWorkDir();
- //
- // File gitDir = repos.get(0).getRepository()
- // .getDirectory();
- //
- // IPath wdPath = new Path(workDir.getAbsolutePath());
- // for (IProject prj : ResourcesPlugin.getWorkspace()
- // .getRoot().getProjects()) {
- // if (wdPath.isPrefixOf(prj.getLocation())) {
- // prj.delete(false, false, monitor);
- // }
- // }
- //
- // repos.get(0).getRepository().close();
- //
- // boolean deleted = deleteRecursively(gitDir, monitor);
- // if (!deleted) {
- // MessageDialog.openError(getSite().getShell(),
- // "Error",
- // "Could not delete Git Repository");
- // }
- //
- // deleted = deleteRecursively(workDir, monitor);
- // if (!deleted) {
- // MessageDialog
- // .openError(getSite().getShell(),
- // "Error",
- // "Could not delete Git Working Directory");
- // }
- //
- // scheduleRefresh();
- // }
- //
- // private boolean deleteRecursively(File fileToDelete,
- // IProgressMonitor monitor) {
- // if (fileToDelete.isDirectory()) {
- // for (File file : fileToDelete.listFiles()) {
- // if (!deleteRecursively(file, monitor)) {
- // return false;
- // }
- // }
- // }
- // monitor.setTaskName(fileToDelete.getAbsolutePath());
- // boolean deleted = fileToDelete.delete();
- // if (!deleted) {
- // System.err.println("Could not delete "
- // + fileToDelete.getAbsolutePath());
- // }
- // return deleted;
- // }
- // };
- //
- // try {
- // ResourcesPlugin.getWorkspace().run(wsr,
- // ResourcesPlugin.getWorkspace().getRoot(),
- // IWorkspace.AVOID_UPDATE,
- // new NullProgressMonitor());
- // } catch (CoreException e1) {
- // // TODO Exception handling
- // e1.printStackTrace();
- // }
- //
- // }
- //
- // });
-
- new MenuItem(men, SWT.SEPARATOR);
-
- if (!isBare) {
- createImportProjectItem(men, repo, repo.getWorkDir().getPath());
-
- new MenuItem(men, SWT.SEPARATOR);
}
+ });
+ // react on selection changes
+ ISelectionService srv = (ISelectionService) getSite().getService(
+ ISelectionService.class);
+ srv.addPostSelectionListener(selectionChangedListener);
+ // react on changes in the configured repositories
+ repositoryUtil.getPreferences().addPreferenceChangeListener(
+ configurationListener);
- MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
- openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
- openPropsView.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- try {
- PlatformUI.getWorkbench().getActiveWorkbenchWindow()
- .getActivePage().showView(
- IPageLayout.ID_PROP_SHEET);
- } catch (PartInitException e1) {
- // just ignore
- }
- }
-
- });
-
- new MenuItem(men, SWT.SEPARATOR);
-
- createCopyPathItem(men, repo.getDirectory().getPath());
- }
-
- if (node.getType() == RepositoryTreeNodeType.REMOTES) {
-
- MenuItem remoteConfig = new MenuItem(men, SWT.PUSH);
- remoteConfig.setText(UIText.RepositoriesView_NewRemoteMenu);
- remoteConfig.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- WizardDialog dlg = new WizardDialog(getSite().getShell(),
- new NewRemoteWizard(node.getRepository()));
- if (dlg.open() == Window.OK)
- tv.refresh();
-
- }
-
- });
- }
-
- if (node.getType() == RepositoryTreeNodeType.REMOTE) {
-
- final String configName = (String) node.getObject();
-
- RemoteConfig rconfig;
+ // listen for repository changes
+ for (String dir : repositoryUtil.getConfiguredRepositories()) {
try {
- rconfig = new RemoteConfig(node.getRepository().getConfig(),
- configName);
- } catch (URISyntaxException e2) {
- // TODO Exception handling
- rconfig = null;
- }
-
- boolean fetchExists = rconfig != null
- && !rconfig.getURIs().isEmpty();
- boolean pushExists = rconfig != null
- && !rconfig.getPushURIs().isEmpty();
-
- if (!fetchExists) {
- MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
- configureUrlFetch
- .setText(UIText.RepositoriesView_CreateFetch_menu);
-
- configureUrlFetch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- WizardDialog dlg = new WizardDialog(getSite()
- .getShell(), new ConfigureRemoteWizard(node
- .getRepository(), configName, false));
- if (dlg.open() == Window.OK)
- tv.refresh();
-
- }
-
- });
- }
-
- if (!pushExists) {
- MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
-
- configureUrlPush
- .setText(UIText.RepositoriesView_CreatePush_menu);
-
- configureUrlPush.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- WizardDialog dlg = new WizardDialog(getSite()
- .getShell(), new ConfigureRemoteWizard(node
- .getRepository(), configName, true));
- if (dlg.open() == Window.OK)
- tv.refresh();
-
- }
-
- });
+ Repository repo = repositoryCache
+ .lookupRepository(new File(dir));
+ repo.addRepositoryChangedListener(repositoryListener);
+ repositories.add(repo);
+ } catch (IOException e) {
+ Activator.handleError(e.getMessage(), e, false);
}
-
- if (!fetchExists || !pushExists)
- // add a separator dynamically
- new MenuItem(men, SWT.SEPARATOR);
-
- MenuItem removeRemote = new MenuItem(men, SWT.PUSH);
- removeRemote.setText(UIText.RepositoriesView_RemoveRemoteMenu);
- removeRemote.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- boolean ok = MessageDialog
- .openConfirm(
- getSite().getShell(),
- UIText.RepositoriesView_ConfirmDeleteRemoteHeader,
- NLS
- .bind(
- UIText.RepositoriesView_ConfirmDeleteRemoteMessage,
- configName));
- if (ok) {
- RepositoryConfig config = node.getRepository()
- .getConfig();
- config.unsetSection(REMOTE, configName);
- try {
- config.save();
- tv.refresh();
- } catch (IOException e1) {
- Activator.handleError(
- UIText.RepositoriesView_ErrorHeader, e1,
- true);
- }
- }
-
- }
-
- });
-
- new MenuItem(men, SWT.SEPARATOR);
-
- MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
- openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
- openPropsView.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- try {
- PlatformUI.getWorkbench().getActiveWorkbenchWindow()
- .getActivePage().showView(
- IPageLayout.ID_PROP_SHEET);
- } catch (PartInitException e1) {
- // just ignore
- }
- }
-
- });
- }
-
- if (node.getType() == RepositoryTreeNodeType.FETCH) {
-
- final String configName = (String) node.getParent().getObject();
-
- MenuItem doFetch = new MenuItem(men, SWT.PUSH);
- doFetch.setText(UIText.RepositoriesView_DoFetchMenu);
- doFetch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent evt) {
- new FetchConfiguredRemoteAction(node.getRepository(),
- configName).run(getSite().getShell());
- }
-
- });
-
- MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
- configureUrlFetch
- .setText(UIText.RepositoriesView_ConfigureFetchMenu);
-
- configureUrlFetch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- WizardDialog dlg = new WizardDialog(getSite().getShell(),
- new ConfigureRemoteWizard(node.getRepository(),
- configName, false));
- if (dlg.open() == Window.OK)
- tv.refresh();
-
- }
-
- });
-
- MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
- deleteFetch.setText(UIText.RepositoriesView_RemoveFetch_menu);
- deleteFetch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- RepositoryConfig config = node.getRepository().getConfig();
- config.unset("remote", configName, "url"); //$NON-NLS-1$ //$NON-NLS-2$
- config.unset("remote", configName, "fetch"); //$NON-NLS-1$//$NON-NLS-2$
- try {
- config.save();
- tv.refresh();
- } catch (IOException e1) {
- MessageDialog.openError(getSite().getShell(),
- UIText.RepositoriesView_ErrorHeader, e1
- .getMessage());
- }
- }
-
- });
-
- }
-
- if (node.getType() == RepositoryTreeNodeType.PUSH) {
-
- final String configName = (String) node.getParent().getObject();
-
- MenuItem doPush = new MenuItem(men, SWT.PUSH);
- doPush.setText(UIText.RepositoriesView_DoPushMenuItem);
- doPush.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent evt) {
- new PushConfiguredRemoteAction(node.getRepository(),
- configName).run(getSite().getShell(), false);
- }
- });
-
- MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
- configureUrlPush.setText(UIText.RepositoriesView_ConfigurePushMenu);
-
- configureUrlPush.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- WizardDialog dlg = new WizardDialog(getSite().getShell(),
- new ConfigureRemoteWizard(node.getRepository(),
- configName, true));
- if (dlg.open() == Window.OK)
- tv.refresh();
- }
-
- });
-
- MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
- deleteFetch.setText(UIText.RepositoriesView_RemovePush_menu);
- deleteFetch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- RepositoryConfig config = node.getRepository().getConfig();
- config.unset("remote", configName, "pushurl"); //$NON-NLS-1$ //$NON-NLS-2$
- config.unset("remote", configName, "push"); //$NON-NLS-1$ //$NON-NLS-2$
- try {
- config.save();
- tv.refresh();
- } catch (IOException e1) {
- MessageDialog.openError(getSite().getShell(),
- UIText.RepositoriesView_ErrorHeader, e1
- .getMessage());
- }
- }
-
- });
- }
-
- if (node.getType() == RepositoryTreeNodeType.FILE) {
-
- final File file = (File) node.getObject();
-
- MenuItem openInTextEditor = new MenuItem(men, SWT.PUSH);
- openInTextEditor
- .setText(UIText.RepositoriesView_OpenInTextEditor_menu);
- openInTextEditor.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- openFile(file);
- }
-
- });
-
- new MenuItem(men, SWT.SEPARATOR);
- createCopyPathItem(men, file.getPath());
- }
-
- if (!isBare && node.getType() == RepositoryTreeNodeType.WORKINGDIR) {
- String path = node.getRepository().getWorkDir().getAbsolutePath();
- createImportProjectItem(men, node.getRepository(), path);
- new MenuItem(men, SWT.SEPARATOR);
- createCopyPathItem(men, path);
- }
-
- if (node.getType() == RepositoryTreeNodeType.FOLDER) {
- String path = ((File) node.getObject()).getPath();
- createImportProjectItem(men, node.getRepository(), path);
- new MenuItem(men, SWT.SEPARATOR);
- createCopyPathItem(men, path);
}
-
+ return viewer;
}
- private boolean isBare(Repository repository) {
- return repository.getConfig().getBoolean("core", "bare", false); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- private boolean isRefCheckedOut(Repository repository, String refName) {
- String branchName;
- String compareString;
-
- try {
- branchName = repository.getFullBranch();
- if (branchName == null)
- return false;
- if (refName.startsWith(Constants.R_HEADS)) {
- // local branch: HEAD would be on the branch
- compareString = refName;
- } else if (refName.startsWith(Constants.R_TAGS)) {
- // tag: HEAD would be on the commit id to which the tag is
- // pointing
- compareString = repository.mapTag(refName).getObjId().getName();
- } else if (refName.startsWith(Constants.R_REMOTES)) {
- // remote branch: HEAD would be on the commit id to which
- // the branch is pointing
- compareString = repository.mapCommit(refName).getCommitId()
- .getName();
- } else {
- // some other symbolic reference
- return false;
- }
- } catch (IOException e1) {
- return false;
+ @Override
+ public void dispose() {
+ // make sure to cancel the refresh job
+ if (this.scheduledJob != null) {
+ this.scheduledJob.cancel();
+ this.scheduledJob = null;
}
- return compareString.equals(branchName);
- }
-
- private void createCopyPathItem(Menu men, final String path) {
+ repositoryUtil.getPreferences().removePreferenceChangeListener(
+ configurationListener);
- MenuItem copyPath;
- copyPath = new MenuItem(men, SWT.PUSH);
- copyPath.setText(UIText.RepositoriesView_CopyPathToClipboardMenu);
- copyPath.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- Clipboard clipboard = new Clipboard(null);
- TextTransfer textTransfer = TextTransfer.getInstance();
- Transfer[] transfers = new Transfer[] { textTransfer };
- Object[] data = new Object[] { path };
- clipboard.setContents(data, transfers);
- clipboard.dispose();
- }
+ ISelectionService srv = (ISelectionService) getSite().getService(
+ ISelectionService.class);
+ srv.removePostSelectionListener(selectionChangedListener);
- });
+ // remove RepositoryChangedListener
+ unregisterRepositoryListener();
+ repositories.clear();
+ super.dispose();
}
- private void createCreateBranchItem(Menu men, final RepositoryTreeNode node) {
- final Ref ref;
- if (node.getType() == RepositoryTreeNodeType.REF)
- ref = (Ref) node.getObject();
- else
- ref = null;
-
- MenuItem createLocal = new MenuItem(men, SWT.PUSH);
- createLocal.setText(UIText.RepositoriesView_NewBranchMenu);
-
- createLocal.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- Wizard wiz = new Wizard() {
-
- @Override
- public void addPages() {
- addPage(new CreateBranchPage(node.getRepository(), ref));
- setWindowTitle(UIText.RepositoriesView_NewBranchTitle);
- }
-
- @Override
- public boolean performFinish() {
+ /**
+ * Opens the tree and marks the working directory file or folder that points
+ * to a resource if possible
+ *
+ * @param resource
+ * the resource to show
+ */
+ @SuppressWarnings("unchecked")
+ private void showResource(final IResource resource) {
+ try {
+ IProject project = resource.getProject();
+ RepositoryMapping mapping = RepositoryMapping.getMapping(project);
+ if (mapping == null)
+ return;
- try {
- getContainer().run(false, true,
- new IRunnableWithProgress() {
-
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
- CreateBranchPage cp = (CreateBranchPage) getPages()[0];
- try {
- cp.createBranch(monitor);
- } catch (CoreException ce) {
- throw new InvocationTargetException(
- ce);
- } catch (IOException ioe) {
- throw new InvocationTargetException(
- ioe);
- }
-
- }
- });
- } catch (InvocationTargetException ite) {
- Activator
- .handleError(
- UIText.RepositoriesView_BranchCreationFailureMessage,
- ite.getCause(), true);
- return false;
- } catch (InterruptedException ie) {
- // ignore here
- }
- return true;
- }
- };
- if (new WizardDialog(getSite().getShell(), wiz).open() == Window.OK)
- tv.refresh();
+ boolean added = repositoryUtil.addConfiguredRepository(mapping
+ .getRepository().getDirectory());
+ if (added) {
+ scheduleRefresh();
}
- });
- }
-
- private void createDeleteBranchItem(Menu men, final RepositoryTreeNode node) {
+ boolean doSetSelection = false;
- final Ref ref = (Ref) node.getObject();
-
- MenuItem deleteBranch = new MenuItem(men, SWT.PUSH);
- deleteBranch.setText(UIText.RepositoriesView_DeleteBranchMenu);
-
- deleteBranch.setEnabled(!isRefCheckedOut(node.getRepository(), ref
- .getName()));
-
- deleteBranch.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
-
- if (!MessageDialog
- .openConfirm(
- getSite().getShell(),
- UIText.RepositoriesView_ConfirmDeleteTitle,
- NLS
- .bind(
- UIText.RepositoriesView_ConfirmBranchDeletionMessage,
- ref.getName())))
- return;
-
- try {
- new ProgressMonitorDialog(getSite().getShell()).run(false,
- false, new IRunnableWithProgress() {
-
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
-
- try {
- RefUpdate op = node.getRepository()
- .updateRef(ref.getName());
- op.setRefLogMessage("branch deleted", //$NON-NLS-1$
- false);
- // we set the force update in order
- // to avoid having this rejected
- // due to minor issues
- op.setForceUpdate(true);
- op.delete();
- tv.refresh();
- } catch (IOException ioe) {
- throw new InvocationTargetException(ioe);
- }
+ if (this.scheduledJob != null) {
+ int state = this.scheduledJob.getState();
+ if (state == Job.WAITING || state == Job.RUNNING) {
+ this.scheduledJob
+ .addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(IJobChangeEvent event) {
+ showResource(resource);
}
});
- } catch (InvocationTargetException e1) {
- Activator
- .handleError(
- UIText.RepositoriesView_BranchDeletionFailureMessage,
- e1.getCause(), true);
- e1.printStackTrace();
- } catch (InterruptedException e1) {
- // ignore
+ } else {
+ doSetSelection = true;
}
}
- });
-
- }
-
- private void openFile(File file) {
- IFileStore store = EFS.getLocalFileSystem().getStore(
- new Path(file.getAbsolutePath()));
- try {
- // TODO do we need a read-only editor here?
- IDE.openEditor(getSite().getPage(),
- new FileStoreEditorInput(store),
- EditorsUI.DEFAULT_TEXT_EDITOR_ID);
- } catch (PartInitException e) {
- Activator.handleError(UIText.RepositoriesView_Error_WindowTitle, e,
- true);
- }
- }
-
- private void checkoutBranch(final RepositoryTreeNode node,
- final String refName) {
- // for the sake of UI responsiveness, let's start a job
- Job job = new Job(NLS.bind(UIText.RepositoriesView_CheckingOutMessage,
- refName)) {
-
- @Override
- protected IStatus run(IProgressMonitor monitor) {
-
- Repository repo = node.getRepository();
-
- final BranchOperation op = new BranchOperation(repo, refName);
- IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
-
- public void run(IProgressMonitor myMonitor)
- throws CoreException {
- op.execute(myMonitor);
- }
- };
-
- try {
- ResourcesPlugin.getWorkspace().run(wsr,
- ResourcesPlugin.getWorkspace().getRoot(),
- IWorkspace.AVOID_UPDATE, monitor);
- Display.getDefault().syncExec(new Runnable() {
-
- public void run() {
- tv.refresh();
+ if (doSetSelection) {
+ RepositoryTreeNode currentNode = null;
+ ITreeContentProvider cp = (ITreeContentProvider) getCommonViewer()
+ .getContentProvider();
+ for (Object repo : cp.getElements(getCommonViewer().getInput())) {
+ RepositoryTreeNode node = (RepositoryTreeNode) repo;
+ // TODO equals implementation of Repository?
+ if (mapping.getRepository().getDirectory().equals(
+ ((Repository) node.getObject()).getDirectory())) {
+ for (Object child : cp.getChildren(node)) {
+ RepositoryTreeNode childNode = (RepositoryTreeNode) child;
+ if (childNode.getType() == RepositoryTreeNodeType.WORKINGDIR) {
+ currentNode = childNode;
+ break;
+ }
}
- });
-
- } catch (CoreException e1) {
- return new Status(IStatus.ERROR, Activator.getPluginId(),
- e1.getMessage(), e1);
- }
-
- return Status.OK_STATUS;
- }
- };
-
- job.setUser(true);
- job.schedule();
- }
-
- private void createImportProjectItem(Menu men, final Repository repo,
- final String path) {
-
- MenuItem startWizard;
- startWizard = new MenuItem(men, SWT.PUSH);
- startWizard.setText(UIText.RepositoriesView_ImportProjectsMenu);
- startWizard.addSelectionListener(new SelectionAdapter() {
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- WizardDialog dlg = new WizardDialog(getSite().getShell(),
- new GitCreateProjectViaWizardWizard(repo, path));
- dlg.open();
- }
-
- });
-
- // we could start the ImportWizard here,
- // unfortunately, this fails within a wizard
- // startWizard = new MenuItem(men, SWT.PUSH);
- // startWizard.setText("Start the Import wizard...");
- // startWizard.addSelectionListener(new SelectionAdapter() {
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- //
- // IHandlerService handlerService = (IHandlerService) getSite()
- // .getWorkbenchWindow().getWorkbench().getService(
- // IHandlerService.class);
- //
- // try {
- // handlerService.executeCommand("org.eclipse.ui.file.import", //$NON-NLS-1$
- // null);
- // } catch (ExecutionException e1) {
- // Activator.handleError(e1.getMessage(), e1, true);
- // } catch (NotDefinedException e1) {
- // Activator.handleError(e1.getMessage(), e1, true);
- // } catch (NotEnabledException e1) {
- // Activator.handleError(e1.getMessage(), e1, true);
- // } catch (NotHandledException e1) {
- // Activator.handleError(e1.getMessage(), e1, true);
- // }
- // }
- //
- // });
- }
-
- private void addActionsToToolbar() {
-
- IToolBarManager manager = getViewSite().getActionBars()
- .getToolBarManager();
-
- refreshAction = new Action(UIText.RepositoriesView_Refresh_Button) {
-
- @Override
- public void run() {
- scheduleRefresh();
- }
- };
- refreshAction.setImageDescriptor(UIIcons.ELCL16_REFRESH);
- manager.add(refreshAction);
-
- linkWithSelectionAction = new Action(
- UIText.RepositoriesView_LinkWithSelection_action,
- IAction.AS_CHECK_BOX) {
-
- @Override
- public void run() {
- IEclipsePreferences prefs = getPrefs();
- prefs.putBoolean(PREFS_SYNCED, isChecked());
- try {
- prefs.flush();
- } catch (BackingStoreException e) {
- // ignore here
- }
- if (isChecked()) {
- ISelectionService srv = (ISelectionService) getSite()
- .getService(ISelectionService.class);
- reactOnSelection(srv.getSelection());
- }
-
- }
-
- };
-
- linkWithSelectionAction
- .setToolTipText(UIText.RepositoriesView_LinkWithSelection_action);
- linkWithSelectionAction.setImageDescriptor(UIIcons.ELCL16_SYNCED);
- linkWithSelectionAction.setChecked(getPrefs().getBoolean(PREFS_SYNCED,
- false));
-
- manager.add(linkWithSelectionAction);
-
- manager.add(new Separator());
-
- IAction collapseAllAction = new Action(
- UIText.RepositoriesView_CollapseAllMenu) {
-
- @Override
- public void run() {
- tv.collapseAll();
- }
- };
- collapseAllAction.setImageDescriptor(UIIcons.COLLAPSEALL);
- manager.add(collapseAllAction);
-
- manager.add(new Separator());
-
- importAction = new Action(UIText.RepositoriesView_Import_Button) {
-
- @Override
- public void run() {
- WizardDialog dlg = new WizardDialog(getSite().getShell(),
- new GitCloneWizard());
- if (dlg.open() == Window.OK)
- scheduleRefresh();
- }
- };
- importAction.setToolTipText(UIText.RepositoriesView_Clone_Tooltip);
- importAction.setImageDescriptor(UIIcons.CLONEGIT);
-
- manager.add(importAction);
-
- addAction = new Action(UIText.RepositoriesView_Add_Button) {
-
- @Override
- public void run() {
- RepositorySearchDialog sd = new RepositorySearchDialog(
- getSite().getShell(), getDirs());
- if (sd.open() == Window.OK) {
- Set<String> dirs = new HashSet<String>();
- dirs.addAll(getDirs());
- if (dirs.addAll(sd.getDirectories()))
- saveDirs(dirs);
- scheduleRefresh();
+ break;
+ }
}
- }
- };
- addAction.setToolTipText(UIText.RepositoriesView_AddRepository_Tooltip);
- addAction.setImageDescriptor(UIIcons.NEW_REPOSITORY);
-
- manager.add(addAction);
-
- // copy and paste are global actions; we just implement them
- // and register them with the global action handler
- // we enable/disable them upon tree selection changes
+ IPath relPath = new Path(mapping.getRepoRelativePath(resource));
- copyAction = new Action("") { //$NON-NLS-1$
-
- @Override
- public void run() {
- // for REPO, WORKINGDIR, FILE, FOLDER: copy directory
- IStructuredSelection sel = (IStructuredSelection) tv
- .getSelection();
- if (sel.size() == 1) {
- RepositoryTreeNode node = (RepositoryTreeNode) sel
- .getFirstElement();
- String dir = null;
- if (node.getType() == RepositoryTreeNodeType.REPO) {
- dir = node.getRepository().getDirectory().getPath();
- } else if (node.getType() == RepositoryTreeNodeType.FILE
- || node.getType() == RepositoryTreeNodeType.FOLDER) {
- dir = ((File) node.getObject()).getPath();
- } else if (node.getType() == RepositoryTreeNodeType.WORKINGDIR) {
- if (!isBare(node.getRepository()))
- dir = node.getRepository().getWorkDir().getPath();
- }
- if (dir != null) {
- Clipboard clip = null;
- try {
- clip = new Clipboard(getSite().getShell()
- .getDisplay());
- clip
- .setContents(new Object[] { dir },
- new Transfer[] { TextTransfer
- .getInstance() });
- } finally {
- if (clip != null)
- // we must dispose ourselves
- clip.dispose();
+ for (String segment : relPath.segments()) {
+ for (Object child : cp.getChildren(currentNode)) {
+ RepositoryTreeNode<File> childNode = (RepositoryTreeNode<File>) child;
+ if (childNode.getObject().getName().equals(segment)) {
+ currentNode = childNode;
+ break;
}
}
}
- }
-
- };
- copyAction.setEnabled(false);
- getViewSite().getActionBars().setGlobalActionHandler(
- ActionFactory.COPY.getId(), copyAction);
+ final RepositoryTreeNode selNode = currentNode;
- pasteAction = new Action("") { //$NON-NLS-1$
-
- @Override
- public void run() {
- // we check if the pasted content is a directory
- // repository location and try to add this
- String errorMessage = null;
-
- Clipboard clip = null;
- try {
- clip = new Clipboard(getSite().getShell().getDisplay());
- String content = (String) clip.getContents(TextTransfer
- .getInstance());
- if (content == null) {
- errorMessage = UIText.RepositoriesView_NothingToPasteMessage;
- return;
- }
-
- File file = new File(content);
- if (!file.exists() || !file.isDirectory()) {
- errorMessage = UIText.RepositoriesView_ClipboardContentNotDirectoryMessage;
- return;
- }
+ Display.getDefault().asyncExec(new Runnable() {
- if (!RepositoryCache.FileKey.isGitRepository(file, FS.DETECTED)) {
- errorMessage = NLS
- .bind(
- UIText.RepositoriesView_ClipboardContentNoGitRepoMessage,
- content);
- return;
+ public void run() {
+ selectReveal(new StructuredSelection(selNode));
}
+ });
- if (addDir(file))
- scheduleRefresh();
- else
- errorMessage = NLS.bind(
- UIText.RepositoriesView_PasteRepoAlreadyThere,
- content);
- } finally {
- if (clip != null)
- // we must dispose ourselves
- clip.dispose();
- if (errorMessage != null)
- MessageDialog.openWarning(getSite().getShell(),
- UIText.RepositoriesView_PasteFailureTitle,
- errorMessage);
- }
}
-
- };
-
- getViewSite().getActionBars().setGlobalActionHandler(
- ActionFactory.PASTE.getId(), pasteAction);
-
+ } catch (RuntimeException rte) {
+ Activator.handleError(rte.getMessage(), rte, false);
+ }
}
/**
- * @return the preferences
+ * Executes an immediate refresh
*/
- protected static IEclipsePreferences getPrefs() {
- return new InstanceScope().getNode(Activator.getPluginId());
- }
-
- @Override
- public void dispose() {
- // make sure to cancel the refresh job
- if (this.scheduledJob != null) {
- this.scheduledJob.cancel();
- this.scheduledJob = null;
- }
- // remove RepositoryChangedListener
- unregisterRepositoryListener();
- repositories.clear();
- super.dispose();
+ public void refresh() {
+ lastInputUpdate = -1l;
+ scheduleRefresh();
}
- /**
- * Schedules a refresh
- */
private void scheduleRefresh() {
-
- if (scheduledJob != null && scheduledJob.getState() == Job.RUNNING)
+ if (scheduledJob != null && scheduledJob.getState() == Job.RUNNING) {
+ // TODO add some "delay" here in order to avoid repeated updates
return;
+ }
+
+ final CommonViewer tv = getCommonViewer();
+ final boolean needsNewInput = lastInputChange > lastInputUpdate;
Job job = new Job("Refreshing Git Repositories view") { //$NON-NLS-1$
- @SuppressWarnings("unchecked")
@Override
protected IStatus run(IProgressMonitor monitor) {
- // first, let's check if the list of Directories has changed
- final List<String> directories = getDirs();
-
- boolean needsNewInput = tv.getInput() == null;
- List<RepositoryTreeNode<Repository>> oldInput = (List) tv
- .getInput();
- if (!needsNewInput)
- needsNewInput = oldInput.size() != directories.size();
-
- if (!needsNewInput) {
- List<String> oldDirectories = new ArrayList<String>();
- for (RepositoryTreeNode<Repository> node : oldInput) {
- oldDirectories.add(node.getRepository().getDirectory()
- .getPath());
- }
- needsNewInput = !directories.containsAll(oldDirectories);
- }
- final boolean updateInput = needsNewInput;
- final List<RepositoryTreeNode<Repository>> newInput;
- if (updateInput) {
+ if (needsNewInput) {
unregisterRepositoryListener();
- try {
- newInput = getRepositoriesFromDirs(monitor);
- } catch (InterruptedException e) {
- return new Status(IStatus.ERROR, Activator
- .getPluginId(), e.getMessage(), e);
- }
repositories.clear();
- for (RepositoryTreeNode<Repository> node: newInput) {
- Repository repo = node.getRepository();
- repositories.add(repo);
- // add listener if not already added
- repo.removeRepositoryChangedListener(repositoryListener);
- repo.addRepositoryChangedListener(repositoryListener);
+ for (String dir : repositoryUtil
+ .getConfiguredRepositories()) {
+ try {
+ Repository repo = repositoryCache
+ .lookupRepository(new File(dir));
+ repo
+ .addRepositoryChangedListener(repositoryListener);
+ repositories.add(repo);
+ } catch (IOException e) {
+ Activator.handleError(e.getMessage(), e, false);
+ }
}
- } else {
- newInput = null;
}
+
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// keep expansion state and selection so that we can
@@ -1614,9 +381,11 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
IStructuredSelection sel = (IStructuredSelection) tv
.getSelection();
- if (updateInput)
- tv.setInput(newInput);
- else
+ if (needsNewInput) {
+ lastInputUpdate = System.currentTimeMillis();
+ tv.setInput(ResourcesPlugin.getWorkspace()
+ .getRoot());
+ } else
tv.refresh();
tv.setExpandedElements(expanded);
@@ -1635,7 +404,8 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
}
}
});
- return new Status(IStatus.OK, Activator.getPluginId(), ""); //$NON-NLS-1$
+
+ return Status.OK_STATUS;
}
};
@@ -1647,7 +417,6 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
service.schedule(job);
scheduledJob = job;
-
}
private void createRepositoryChangedListener() {
@@ -1663,217 +432,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
}
private void unregisterRepositoryListener() {
- for (Repository repo:repositories)
+ for (Repository repo : repositories)
repo.removeRepositoryChangedListener(repositoryListener);
}
-
- /**
- * Adds a directory to the list if it is not already there
- *
- * @param file
- * @return see {@link Collection#add(Object)}
- */
- public static boolean addDir(File file) {
-
- String dirString;
- try {
- dirString = file.getCanonicalPath();
- } catch (IOException e) {
- dirString = file.getAbsolutePath();
- }
-
- List<String> dirStrings = getDirs();
- if (dirStrings.contains(dirString)) {
- return false;
- } else {
- Set<String> dirs = new HashSet<String>();
- dirs.addAll(dirStrings);
- dirs.add(dirString);
- saveDirs(dirs);
- return true;
- }
- }
-
- /**
- * Converts the directories as configured for this view into a list of
- * {@link Repository} objects suitable for the tree content provider
- * <p>
- * TODO move to some utility class
- *
- * @param monitor
- * @return a list of nodes
- * @throws InterruptedException
- */
- public static List<RepositoryTreeNode<Repository>> getRepositoriesFromDirs(
- IProgressMonitor monitor) throws InterruptedException {
-
- List<String> gitDirStrings = getDirs();
- List<RepositoryTreeNode<Repository>> input = new ArrayList<RepositoryTreeNode<Repository>>();
-
- for (String dirString : gitDirStrings) {
- if (monitor != null && monitor.isCanceled()) {
- throw new InterruptedException(
- UIText.RepositoriesView_ActionCanceled_Message);
- }
- try {
- File dir = new File(dirString);
- if (dir.exists() && dir.isDirectory()) {
- Repository repo = org.eclipse.egit.core.Activator
- .getDefault().getRepositoryCache()
- .lookupRepository(dir);
- RepositoryNode node = new RepositoryNode(null, repo);
- input.add(node);
- }
- } catch (IOException e) {
- IStatus error = new Status(IStatus.ERROR, Activator
- .getPluginId(), e.getMessage(), e);
- Activator.getDefault().getLog().log(error);
- }
- }
- Collections.sort(input);
- return input;
- }
-
- private static void saveDirs(Set<String> gitDirStrings) {
- StringBuilder sb = new StringBuilder();
- for (String gitDirString : gitDirStrings) {
- sb.append(gitDirString);
- sb.append(File.pathSeparatorChar);
- }
-
- IEclipsePreferences prefs = getPrefs();
- prefs.put(PREFS_DIRECTORIES, sb.toString());
- try {
- prefs.flush();
- } catch (BackingStoreException e) {
- IStatus error = new Status(IStatus.ERROR, Activator.getPluginId(),
- e.getMessage(), e);
- Activator.getDefault().getLog().log(error);
- }
- }
-
- @Override
- public void setFocus() {
- tv.getTree().setFocus();
- }
-
- @SuppressWarnings("boxing")
- private boolean confirmProjectDeletion(List<IProject> projectsToDelete) {
- boolean confirmed;
- confirmed = MessageDialog
- .openConfirm(
- getSite().getShell(),
- UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle,
- NLS
- .bind(
- UIText.RepositoriesView_ConfirmProjectDeletion_Question,
- projectsToDelete.size()));
- return confirmed;
- }
-
- public void addSelectionChangedListener(ISelectionChangedListener listener) {
- selectionListeners.add(listener);
- }
-
- public ISelection getSelection() {
- return currentSelection;
- }
-
- public void removeSelectionChangedListener(
- ISelectionChangedListener listener) {
- selectionListeners.remove(listener);
-
- }
-
- public void setSelection(ISelection selection) {
- currentSelection = selection;
- for (ISelectionChangedListener listener : selectionListeners) {
- listener.selectionChanged(new SelectionChangedEvent(
- RepositoriesView.this, selection));
- }
- }
-
- /**
- * Opens the tree and marks the folder to which a project is pointing
- *
- * @param resource
- * TODO exceptions?
- */
- @SuppressWarnings("unchecked")
- public void showResource(final IResource resource) {
- IProject project = resource.getProject();
- RepositoryMapping mapping = RepositoryMapping.getMapping(project);
- if (mapping == null)
- return;
-
- if (addDir(mapping.getRepository().getDirectory())) {
- scheduleRefresh();
- }
-
- boolean doSetSelection = false;
-
- if (this.scheduledJob != null) {
- int state = this.scheduledJob.getState();
- if (state == Job.WAITING || state == Job.RUNNING) {
- this.scheduledJob.addJobChangeListener(new JobChangeAdapter() {
-
- @Override
- public void done(IJobChangeEvent event) {
- showResource(resource);
- }
- });
- } else {
- doSetSelection = true;
- }
- }
-
- if (doSetSelection) {
- RepositoriesViewContentProvider cp = (RepositoriesViewContentProvider) tv
- .getContentProvider();
- RepositoryTreeNode currentNode = null;
- Object[] repos = cp.getElements(tv.getInput());
- for (Object repo : repos) {
- RepositoryTreeNode node = (RepositoryTreeNode) repo;
- // TODO equals implementation of Repository?
- if (mapping.getRepository().getDirectory().equals(
- ((Repository) node.getObject()).getDirectory())) {
- for (Object child : cp.getChildren(node)) {
- RepositoryTreeNode childNode = (RepositoryTreeNode) child;
- if (childNode.getType() == RepositoryTreeNodeType.WORKINGDIR) {
- currentNode = childNode;
- break;
- }
- }
- break;
- }
- }
-
- IPath relPath = new Path(mapping.getRepoRelativePath(resource));
-
- for (String segment : relPath.segments()) {
- for (Object child : cp.getChildren(currentNode)) {
- RepositoryTreeNode<File> childNode = (RepositoryTreeNode<File>) child;
- if (childNode.getObject().getName().equals(segment)) {
- currentNode = childNode;
- break;
- }
- }
- }
-
- final RepositoryTreeNode selNode = currentNode;
-
- Display.getDefault().asyncExec(new Runnable() {
-
- public void run() {
- tv.setSelection(new StructuredSelection(selNode), true);
- }
- });
-
- }
-
- }
-
public boolean show(ShowInContext context) {
ISelection selection = context.getSelection();
if (selection instanceof IStructuredSelection) {
@@ -1893,57 +455,121 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider,
return false;
}
- private void removeRepository(final IProgressMonitor monitor,
- final Repository... repository) {
- final List<IProject> projectsToDelete = new ArrayList<IProject>();
-
- monitor
- .setTaskName(UIText.RepositoriesView_DeleteRepoDeterminProjectsMessage);
-
- for (Repository repo : repository) {
- File workDir = repo.getWorkDir();
- final IPath wdPath = new Path(workDir.getAbsolutePath());
- for (IProject prj : ResourcesPlugin.getWorkspace().getRoot()
- .getProjects()) {
- if (monitor.isCanceled())
- return;
- if (wdPath.isPrefixOf(prj.getLocation())) {
- projectsToDelete.add(prj);
- }
- }
- repo.removeRepositoryChangedListener(repositoryListener);
- }
-
- if (!projectsToDelete.isEmpty()) {
- boolean confirmed;
- confirmed = confirmProjectDeletion(projectsToDelete);
- if (!confirmed) {
+ private void reactOnSelection(ISelection selection) {
+ if (selection instanceof StructuredSelection) {
+ StructuredSelection ssel = (StructuredSelection) selection;
+ if (ssel.size() != 1)
return;
+ if (ssel.getFirstElement() instanceof IResource)
+ showResource((IResource) ssel.getFirstElement());
+ if (ssel.getFirstElement() instanceof IAdaptable) {
+ IResource adapted = (IResource) ((IAdaptable) ssel
+ .getFirstElement()).getAdapter(IResource.class);
+ if (adapted != null)
+ showResource(adapted);
}
}
-
- if (monitor.isCanceled())
- return;
-
- IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
-
- public void run(IProgressMonitor actMonitor) throws CoreException {
-
- for (IProject prj : projectsToDelete) {
- prj.delete(false, false, actMonitor);
- }
- for (Repository repo : repository)
- removeDir(repo.getDirectory());
- scheduleRefresh();
- }
- };
-
- try {
- ResourcesPlugin.getWorkspace().run(wsr,
- ResourcesPlugin.getWorkspace().getRoot(),
- IWorkspace.AVOID_UPDATE, monitor);
- } catch (CoreException e1) {
- Activator.logError(e1.getMessage(), e1);
- }
}
+
+ // TODO delete does not work because of file locks on .pack-files
+ // Shawn Pearce has added the following thoughts:
+
+ // Hmm. We probably can't active detect file locks on pack files on
+ // Windows, can we?
+ // It would be nice if we could support a delete, but only if the
+ // repository is
+ // reasonably believed to be not-in-use right now.
+ //
+ // Within EGit you might be able to check GitProjectData and its
+ // repositoryCache to
+ // see if the repository is open by this workspace. If it is, then
+ // we know we shouldn't
+ // try to delete it.
+ //
+ // Some coding might look like this:
+ //
+ // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
+ // deleteRepo.setText("Delete");
+ // deleteRepo.addSelectionListener(new SelectionAdapter() {
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent e) {
+ //
+ // boolean confirmed = MessageDialog.openConfirm(getSite()
+ // .getShell(), "Confirm",
+ // "This will delete the repository, continue?");
+ //
+ // if (!confirmed)
+ // return;
+ //
+ // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
+ //
+ // public void run(IProgressMonitor monitor)
+ // throws CoreException {
+ // File workDir = repos.get(0).getRepository()
+ // .getWorkDir();
+ //
+ // File gitDir = repos.get(0).getRepository()
+ // .getDirectory();
+ //
+ // IPath wdPath = new Path(workDir.getAbsolutePath());
+ // for (IProject prj : ResourcesPlugin.getWorkspace()
+ // .getRoot().getProjects()) {
+ // if (wdPath.isPrefixOf(prj.getLocation())) {
+ // prj.delete(false, false, monitor);
+ // }
+ // }
+ //
+ // repos.get(0).getRepository().close();
+ //
+ // boolean deleted = deleteRecursively(gitDir, monitor);
+ // if (!deleted) {
+ // MessageDialog.openError(getSite().getShell(),
+ // "Error",
+ // "Could not delete Git Repository");
+ // }
+ //
+ // deleted = deleteRecursively(workDir, monitor);
+ // if (!deleted) {
+ // MessageDialog
+ // .openError(getSite().getShell(),
+ // "Error",
+ // "Could not delete Git Working Directory");
+ // }
+ //
+ // scheduleRefresh();
+ // }
+ //
+ // private boolean deleteRecursively(File fileToDelete,
+ // IProgressMonitor monitor) {
+ // if (fileToDelete.isDirectory()) {
+ // for (File file : fileToDelete.listFiles()) {
+ // if (!deleteRecursively(file, monitor)) {
+ // return false;
+ // }
+ // }
+ // }
+ // monitor.setTaskName(fileToDelete.getAbsolutePath());
+ // boolean deleted = fileToDelete.delete();
+ // if (!deleted) {
+ // System.err.println("Could not delete "
+ // + fileToDelete.getAbsolutePath());
+ // }
+ // return deleted;
+ // }
+ // };
+ //
+ // try {
+ // ResourcesPlugin.getWorkspace().run(wsr,
+ // ResourcesPlugin.getWorkspace().getRoot(),
+ // IWorkspace.AVOID_UPDATE,
+ // new NullProgressMonitor());
+ // } catch (CoreException e1) {
+ // handle this
+ // e1.printStackTrace();
+ // }
+ //
+ // }
+ //
+ // });
}
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 6138c6113..164961fb9 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
@@ -15,12 +15,16 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.egit.core.RepositoryCache;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIText;
import org.eclipse.egit.ui.internal.repository.tree.BranchesNode;
@@ -34,6 +38,7 @@ import org.eclipse.egit.ui.internal.repository.tree.RefNode;
import org.eclipse.egit.ui.internal.repository.tree.RemoteBranchesNode;
import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
import org.eclipse.egit.ui.internal.repository.tree.RemotesNode;
+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.SymbolicRefNode;
import org.eclipse.egit.ui.internal.repository.tree.SymbolicRefsNode;
@@ -53,10 +58,39 @@ import org.eclipse.jgit.transport.RemoteConfig;
*/
public class RepositoriesViewContentProvider implements ITreeContentProvider {
+ private final RepositoryCache repositoryCache = org.eclipse.egit.core.Activator
+ .getDefault().getRepositoryCache();
+
@SuppressWarnings("unchecked")
public Object[] getElements(Object inputElement) {
- List<RepositoryTreeNode> nodes = (List<RepositoryTreeNode>) inputElement;
+ List<RepositoryTreeNode> nodes = new ArrayList<RepositoryTreeNode>();
+ List<String> directories = new ArrayList<String>();
+
+ if (inputElement instanceof Collection) {
+ for (Iterator it = ((Collection) inputElement).iterator(); it
+ .hasNext();) {
+ Object next = it.next();
+ if (next instanceof RepositoryTreeNode)
+ nodes.add((RepositoryTreeNode) next);
+ else if (next instanceof String)
+ directories.add((String) next);
+ }
+ } else if (inputElement instanceof IWorkspaceRoot) {
+ directories.addAll(Activator.getDefault().getRepositoryUtil()
+ .getConfiguredRepositories());
+ }
+
+ for (String directory : directories) {
+ try {
+ RepositoryNode rNode = new RepositoryNode(null, repositoryCache
+ .lookupRepository(new File(directory)));
+ nodes.add(rNode);
+ } catch (IOException e) {
+ // ignore for now
+ }
+ }
+
Collections.sort(nodes);
return nodes.toArray();
}
@@ -302,8 +336,9 @@ public class RepositoriesViewContentProvider implements ITreeContentProvider {
}
public Object getParent(Object element) {
-
- return ((RepositoryTreeNode) element).getParent();
+ if (element instanceof RepositoryTreeNode)
+ return ((RepositoryTreeNode) element).getParent();
+ return null;
}
public boolean hasChildren(Object element) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java
index 419ddaf1f..05c9e9eb7 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java
@@ -19,7 +19,6 @@ import org.eclipse.egit.ui.UIIcons;
import org.eclipse.egit.ui.UIText;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.jface.resource.CompositeImageDescriptor;
-import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
@@ -38,97 +37,6 @@ public class RepositoriesViewLabelProvider extends LabelProvider {
*/
private Map<Image, Image> decoratedImages = new HashMap<Image, Image>();
- // private DefaultInformationControl infoControl;
-
- /**
- *
- * @param viewer
- */
- public RepositoriesViewLabelProvider(final ColumnViewer viewer) {
-
- viewer.setLabelProvider(this);
- // we could implement some hover here to display additional information
- // viewer.getTree().addMouseTrackListener(new MouseTrackAdapter() {
- //
- // @Override
- // public void mouseHover(MouseEvent e) {
-
- // Point eventPoint = new Point(e.x, e.y);
- //
- // TreeItem item = viewer.getTree().getItem(eventPoint);
- // if (item != null) {
- //
- // RepositoryTreeNode node = (RepositoryTreeNode) item
- // .getData();
- // String text = node.getRepository().getDirectory()
- // .getCanonicalPath();
- //
- // final ViewerCell cell = viewer.getCell(eventPoint);
- //
- // if (infoControl != null && infoControl.isVisible()) {
- // infoControl.setVisible(false);
- // }
- //
- // GC testGc = new GC(cell.getControl());
- // final Point textExtent = testGc.textExtent(text);
- // testGc.dispose();
- //
- // if (infoControl == null || !infoControl.isVisible()) {
- //
- // IInformationPresenter ips = new IInformationPresenter() {
- //
- // public String updatePresentation(
- // Display display, String hoverInfo,
- // TextPresentation presentation,
- // int maxWidth, int maxHeight) {
- // return hoverInfo;
- // }
- //
- // };
- //
- // infoControl = new DefaultInformationControl(Display
- // .getCurrent().getActiveShell().getShell(),
- // ips) {
- //
- // @Override
- // public void setInformation(String content) {
- // super.setInformation(content);
- // super.setSize(textExtent.x, textExtent.y);
- // }
- //
- // };
- // }
- //
- // Point dispPoint = viewer.getControl().toDisplay(
- // eventPoint);
- //
- // infoControl.setLocation(dispPoint);
- //
- // // the default info provider works better with \r ...
- // infoControl.setInformation(text);
- //
- // final MouseMoveListener moveListener = new
- // MouseMoveListener() {
- //
- // public void mouseMove(MouseEvent evt) {
- // infoControl.setVisible(false);
- // cell.getControl().removeMouseMoveListener(this);
- //
- // }
- // };
- //
- // cell.getControl().addMouseMoveListener(moveListener);
- //
- // infoControl.setVisible(true);
- //
- // }
- //
- // }
- //
- // });
-
- }
-
@Override
public Image getImage(Object element) {
return decorateImage(
@@ -137,6 +45,8 @@ public class RepositoriesViewLabelProvider extends LabelProvider {
@Override
public String getText(Object element) {
+ if (!(element instanceof RepositoryTreeNode))
+ return null;
RepositoryTreeNode node = (RepositoryTreeNode) element;
switch (node.getType()) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/LinkHelper.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/LinkHelper.java
new file mode 100644
index 000000000..dd025acde
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/LinkHelper.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.RepositoryUtil;
+import org.eclipse.egit.ui.internal.repository.RepositoriesViewContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.navigator.ILinkHelper;
+
+/**
+ * Link Helper for Git Repositories View
+ */
+public class LinkHelper implements ILinkHelper {
+ public void activateEditor(IWorkbenchPage aPage,
+ IStructuredSelection aSelection) {
+
+ try {
+ FileNode node = (FileNode) aSelection.getFirstElement();
+
+ File file = node.getObject();
+
+ for (IEditorReference ref : aPage.getEditorReferences()) {
+ IEditorPart part = ref.getEditor(false);
+ if (part != null) {
+ IEditorInput input = part.getEditorInput();
+ if (input instanceof IFileEditorInput) {
+ if (((IFileEditorInput) input).getFile().equals(file)) {
+ aPage.activate(part);
+ return;
+ }
+ }
+ if (input instanceof IURIEditorInput) {
+ if (((IURIEditorInput) input).getURI().equals(
+ file.toURI())) {
+ aPage.activate(part);
+ return;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // simply ignore here
+ }
+ }
+
+ /**
+ * TODO javadoc missing
+ */
+ @SuppressWarnings("unchecked")
+ public IStructuredSelection findSelection(IEditorInput anInput) {
+ if (!(anInput instanceof IURIEditorInput)) {
+ return null;
+ }
+
+ URI uri = ((IURIEditorInput) anInput).getURI();
+
+ if (!uri.getScheme().equals("file")) //$NON-NLS-1$
+ return null;
+
+ File file = new File(uri.getPath());
+
+ if (!file.exists())
+ return null;
+
+ RepositoryUtil config = Activator.getDefault().getRepositoryUtil();
+
+ List<String> repos = config.getConfiguredRepositories();
+ for (String repo : repos) {
+ Repository repository;
+ try {
+ repository = new Repository(new File(repo));
+ } catch (IOException e) {
+ continue;
+ }
+ if (file.getPath().startsWith(repository.getWorkDir().getPath())) {
+ RepositoriesViewContentProvider cp = new RepositoriesViewContentProvider();
+
+ RepositoryNode repoNode = new RepositoryNode(null, repository);
+ RepositoryTreeNode result = null;
+
+ for (Object child : cp.getChildren(repoNode)) {
+ if (child instanceof WorkingDirNode) {
+ result = (WorkingDirNode) child;
+ break;
+ }
+ }
+
+ if (result == null)
+ return null;
+
+ IPath remainingPath = new Path(file.getPath().substring(
+ repository.getWorkDir().getPath().length()));
+ for (String segment : remainingPath.segments()) {
+ for (Object child : cp.getChildren(result)) {
+ RepositoryTreeNode<File> fileNode;
+ try {
+ fileNode = (RepositoryTreeNode<File>) child;
+ } catch (ClassCastException e) {
+ return null;
+ }
+ if (fileNode.getObject().getName().equals(segment)) {
+ result = fileNode;
+ break;
+ }
+ }
+ }
+
+ return new StructuredSelection(result);
+ }
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/PropertyTester.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/PropertyTester.java
new file mode 100644
index 000000000..a6a80be00
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/PropertyTester.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RemoteConfig;
+
+/**
+ * Property Tester used for enabling/disabling of context menus in the Git
+ * Repositories View.
+ */
+public class PropertyTester extends org.eclipse.core.expressions.PropertyTester {
+ /**
+ * TODO javadoc missing
+ */
+ public boolean test(Object receiver, String property, Object[] args,
+ Object expectedValue) {
+
+ if (!(receiver instanceof RepositoryTreeNode))
+ return false;
+ RepositoryTreeNode node = (RepositoryTreeNode) receiver;
+
+ if (property.equals("isBare")) { //$NON-NLS-1$
+ Repository rep = node.getRepository();
+ return rep.getConfig().getBoolean("core", "bare", false); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ if (property.equals("isRefCheckedOut")) { //$NON-NLS-1$
+ if (!(node.getObject() instanceof Ref))
+ return false;
+ Ref ref = (Ref) node.getObject();
+ try {
+ return ref.getName().equals(
+ node.getRepository().getFullBranch());
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ if (property.equals("isLocalBranch")) { //$NON-NLS-1$
+ if (!(node.getObject() instanceof Ref))
+ return false;
+ Ref ref = (Ref) node.getObject();
+ return ref.getName().startsWith(Constants.R_HEADS);
+ }
+ if (property.equals("fetchExists")) { //$NON-NLS-1$
+ if (node instanceof RemoteNode) {
+ String configName = ((RemoteNode) node).getObject();
+
+ RemoteConfig rconfig;
+ try {
+ rconfig = new RemoteConfig(
+ node.getRepository().getConfig(), configName);
+ } catch (URISyntaxException e2) {
+ // TODO Exception handling
+ rconfig = null;
+ }
+
+ boolean fetchExists = rconfig != null
+ && !rconfig.getURIs().isEmpty();
+ return fetchExists;
+ }
+ }
+ if (property.equals("pushExists")) { //$NON-NLS-1$
+ if (node instanceof RemoteNode) {
+ String configName = ((RemoteNode) node).getObject();
+
+ RemoteConfig rconfig;
+ try {
+ rconfig = new RemoteConfig(
+ node.getRepository().getConfig(), configName);
+ } catch (URISyntaxException e2) {
+ // TODO Exception handling
+ rconfig = null;
+ }
+ boolean pushExists = rconfig != null
+ && !rconfig.getPushURIs().isEmpty();
+ return pushExists;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewActionProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewActionProvider.java
new file mode 100644
index 000000000..c32d64ffd
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewActionProvider.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.navigator.CommonActionProvider;
+
+/**
+ * Contributes the global actions (copy/paste)
+ *
+ */
+public class RepositoriesViewActionProvider extends CommonActionProvider {
+
+ private IAction copyAction;
+
+ private IAction pasteAction;
+
+ @Override
+ public void fillActionBars(IActionBars actionBars) {
+ if (pasteAction == null) {
+ pasteAction = new Action("") { //$NON-NLS-1$
+
+ @Override
+ public void run() {
+ IHandlerService srv = (IHandlerService) PlatformUI
+ .getWorkbench().getService(IHandlerService.class);
+ ICommandService csrv = (ICommandService) PlatformUI
+ .getWorkbench().getService(ICommandService.class);
+ Command openCommand = csrv
+ .getCommand("org.eclipse.egit.ui.RepositoriesViewPaste"); //$NON-NLS-1$
+ ExecutionEvent evt = srv.createExecutionEvent(openCommand,
+ null);
+
+ try {
+ openCommand.executeWithChecks(evt);
+ } catch (Exception e) {
+ Activator.handleError(e.getMessage(), e, true);
+ }
+ }
+
+ };
+ }
+
+ actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(),
+ pasteAction);
+
+ if (copyAction == null) {
+ copyAction = new Action("") { //$NON-NLS-1$
+
+ @Override
+ public void run() {
+ IHandlerService srv = (IHandlerService) PlatformUI
+ .getWorkbench().getService(IHandlerService.class);
+ ICommandService csrv = (ICommandService) PlatformUI
+ .getWorkbench().getService(ICommandService.class);
+ Command openCommand = csrv
+ .getCommand("org.eclipse.egit.ui.RepositoriesViewCopyPath"); //$NON-NLS-1$
+ ExecutionEvent evt = srv.createExecutionEvent(openCommand,
+ null);
+
+ try {
+ openCommand.executeWithChecks(evt);
+ } catch (Exception e) {
+ Activator.handleError(e.getMessage(), e, true);
+ }
+ }
+
+ };
+ }
+
+ IStructuredSelection sel = (IStructuredSelection) getActionSite()
+ .getViewSite().getSelectionProvider().getSelection();
+
+ if (sel.size() == 1) {
+ RepositoryTreeNode node = (RepositoryTreeNode) sel
+ .getFirstElement();
+ if (node.getType() == RepositoryTreeNodeType.REPO
+ || node.getType() == RepositoryTreeNodeType.FILE
+ || node.getType() == RepositoryTreeNodeType.FOLDER) {
+ copyAction.setEnabled(true);
+ } else if (node.getType() == RepositoryTreeNodeType.WORKINGDIR) {
+ boolean isBare = node.getRepository().getConfig().getBoolean(
+ "core", "bare", false); //$NON-NLS-1$//$NON-NLS-2$
+ copyAction.setEnabled(!isBare);
+ } else {
+ copyAction.setEnabled(false);
+ }
+ }
+
+ actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(),
+ copyAction);
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewSorter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewSorter.java
new file mode 100644
index 000000000..6702ec7a8
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewSorter.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree;
+
+import java.text.Collator;
+
+/**
+ * Sorter for the Git Repositories View.
+ */
+public class RepositoriesViewSorter extends
+ org.eclipse.jface.viewers.ViewerSorter {
+
+ /**
+ * Default constructor
+ */
+ public RepositoriesViewSorter() {
+ // default
+ }
+
+ /**
+ * Construct sorter from collator
+ * @param collator to be used for locale-sensitive sorting
+ */
+ public RepositoriesViewSorter(Collator collator) {
+ super(collator);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public int category(Object element) {
+ if (element instanceof RepositoryTreeNode) {
+ RepositoryTreeNode<? extends Object> node = (RepositoryTreeNode<? extends Object>) element;
+ return node.getType().ordinal();
+ }
+ return super.category(element);
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
index 7d532bc2c..f09abaa25 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
@@ -304,7 +304,7 @@ public abstract class RepositoryTreeNode<T> implements Comparable<RepositoryTree
case SYMBOLICREFS:
// fall through
case ERROR:
- // fall through
+ // fall through TODO fix this: Repository may be null
case WORKINGDIR:
return ((Repository) myObject).getDirectory().equals(
((Repository) otherObject).getDirectory());
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AddCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AddCommand.java
new file mode 100644
index 000000000..768a1b397
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/AddCommand.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.File;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.RepositorySearchDialog;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.window.Window;
+
+/**
+ * "Adds" repositories
+ */
+public class AddCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositorySearchDialog sd = new RepositorySearchDialog(getView(event)
+ .getSite().getShell(), util.getConfiguredRepositories());
+ if (sd.open() == Window.OK)
+ for (String dir : sd.getDirectories())
+ util.addConfiguredRepository(new File(dir));
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CheckoutCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CheckoutCommand.java
new file mode 100644
index 000000000..5a80af33f
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CheckoutCommand.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.egit.core.op.BranchOperation;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Implements "Checkout"
+ */
+public class CheckoutCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ final RepositoryTreeNode node = getSelectedNodes(event).get(0);
+ if (!(node.getObject() instanceof Ref))
+ return null;
+
+ final Ref ref = (Ref) node.getObject();
+
+ // for the sake of UI responsiveness, let's start a job
+ Job job = new Job(NLS.bind(UIText.RepositoriesView_CheckingOutMessage,
+ ref.getName())) {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+
+ Repository repo = node.getRepository();
+
+ final BranchOperation op = new BranchOperation(repo, ref
+ .getName());
+ IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
+
+ public void run(IProgressMonitor myMonitor)
+ throws CoreException {
+ op.execute(myMonitor);
+ }
+ };
+
+ try {
+ ResourcesPlugin.getWorkspace().run(wsr,
+ ResourcesPlugin.getWorkspace().getRoot(),
+ IWorkspace.AVOID_UPDATE, monitor);
+ } catch (CoreException e1) {
+ return new Status(IStatus.ERROR, Activator.getPluginId(),
+ e1.getMessage(), e1);
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ job.setUser(true);
+ job.schedule();
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CloneCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CloneCommand.java
new file mode 100644
index 000000000..63bb3eb77
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CloneCommand.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.clone.GitCloneWizard;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Clones a Repository by calling the clone wizard.
+ */
+public class CloneCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ WizardDialog dlg = new WizardDialog(
+ getView(event).getSite().getShell(), new GitCloneWizard());
+ dlg.open();
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureFetchCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureFetchCommand.java
new file mode 100644
index 000000000..b5ad39433
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureFetchCommand.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.ConfigureRemoteWizard;
+import org.eclipse.egit.ui.internal.repository.tree.FetchNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Configures the Fetch
+ */
+public class ConfigureFetchCommand extends
+ RepositoriesViewCommandHandler<RemoteNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryTreeNode selectedNode = getSelectedNodes(event).get(0);
+ final String configName;
+
+ if (selectedNode instanceof RemoteNode)
+ configName = ((RemoteNode) selectedNode).getObject();
+ else if (selectedNode instanceof FetchNode)
+ configName = ((RemoteNode) selectedNode.getParent()).getObject();
+ else
+ return null;
+
+ WizardDialog dlg = new WizardDialog(
+ getView(event).getSite().getShell(), new ConfigureRemoteWizard(
+ selectedNode.getRepository(), configName, false));
+ dlg.open();
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigurePushCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigurePushCommand.java
new file mode 100644
index 000000000..e31a932a5
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigurePushCommand.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.ConfigureRemoteWizard;
+import org.eclipse.egit.ui.internal.repository.tree.PushNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Configures the Push
+ */
+public class ConfigurePushCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryTreeNode selectedNode = getSelectedNodes(event).get(0);
+ final String configName;
+
+ if (selectedNode instanceof RemoteNode)
+ configName = ((RemoteNode) selectedNode).getObject();
+ else if (selectedNode instanceof PushNode)
+ configName = ((RemoteNode) selectedNode.getParent()).getObject();
+ else
+ return null;
+
+ WizardDialog dlg = new WizardDialog(
+ getView(event).getSite().getShell(), new ConfigureRemoteWizard(
+ selectedNode.getRepository(), configName, true));
+ dlg.open();
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureRemoteCommand.java
new file mode 100644
index 000000000..78440b4c0
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ConfigureRemoteCommand.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.NewRemoteWizard;
+import org.eclipse.egit.ui.internal.repository.tree.RemotesNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Configures the Remote
+ */
+public class ConfigureRemoteCommand extends
+ RepositoriesViewCommandHandler<RemotesNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RemotesNode node = getSelectedNodes(event).get(0);
+
+ WizardDialog dlg = new WizardDialog(
+ getView(event).getSite().getShell(), new NewRemoteWizard(node
+ .getRepository()));
+ dlg.open();
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CopyPathCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CopyPathCommand.java
new file mode 100644
index 000000000..8d51b80a6
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CopyPathCommand.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+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.RepositoryTreeNode;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+
+/**
+ * Implements "Copy Path to Clipboard"
+ */
+public class CopyPathCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryTreeNode node = getSelectedNodes(event).get(0);
+ String path;
+
+ switch (node.getType()) {
+ case REPO:
+ path = node.getRepository().getDirectory().toString();
+ break;
+ case WORKINGDIR:
+ if (node.getRepository().getConfig().getBoolean(
+ "core", "bare", false)) { //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+ path = node.getRepository().getWorkDir().toString();
+ break;
+ case FILE:
+ path = ((FileNode) node).getObject().getPath().toString();
+ break;
+ case FOLDER:
+ path = ((FolderNode) node).getObject().getPath().toString();
+ break;
+ default:
+ return null;
+ }
+
+ Clipboard clipboard = new Clipboard(null);
+ try {
+ TextTransfer textTransfer = TextTransfer.getInstance();
+ Transfer[] transfers = new Transfer[] { textTransfer };
+ Object[] data = new Object[] { path };
+ clipboard.setContents(data, transfers);
+ } finally {
+ clipboard.dispose();
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateBranchCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateBranchCommand.java
new file mode 100644
index 000000000..fcec66bfc
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CreateBranchCommand.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.CreateBranchPage;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jgit.lib.Ref;
+
+/**
+ * Creates a branch using a simple dialog.
+ * <p>
+ * This is context-sensitive as it suggests the currently selected branch or (if
+ * not started from a branch) the currently checked-out branch as source branch.
+ * The user can override this suggestion.
+ */
+public class CreateBranchCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ final RepositoryTreeNode node = getSelectedNodes(event).get(0);
+ final Ref baseBranch;
+ if (node.getObject() instanceof Ref)
+ baseBranch = (Ref) node.getObject();
+ else
+ baseBranch = null;
+
+ Wizard wiz = new Wizard() {
+
+ @Override
+ public void addPages() {
+ addPage(new CreateBranchPage(node.getRepository(), baseBranch));
+ setWindowTitle(UIText.RepositoriesView_NewBranchTitle);
+ }
+
+ @Override
+ public boolean performFinish() {
+ try {
+ getContainer().run(false, true,
+ new IRunnableWithProgress() {
+
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException,
+ InterruptedException {
+ CreateBranchPage cp = (CreateBranchPage) getPages()[0];
+ try {
+ cp.createBranch(monitor);
+ } catch (CoreException ce) {
+ throw new InvocationTargetException(ce);
+ } catch (IOException ioe) {
+ throw new InvocationTargetException(ioe);
+ }
+
+ }
+ });
+ } catch (InvocationTargetException ite) {
+ Activator
+ .handleError(
+ UIText.RepositoriesView_BranchCreationFailureMessage,
+ ite.getCause(), true);
+ return false;
+ } catch (InterruptedException ie) {
+ // ignore here
+ }
+ return true;
+ }
+ };
+ new WizardDialog(getView(event).getSite().getShell(), wiz).open();
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteBranchCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteBranchCommand.java
new file mode 100644
index 000000000..629136829
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteBranchCommand.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.tree.RefNode;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Deletes a branch.
+ * <p>
+ * TODO This uses the force option always, so a warning pop-up is shown to the
+ * user; instead this should check if deletion can be performed without data
+ * loss and in this case the deletion should be done quietly; the warning pop-up
+ * should only be shown if the force option is really needed.
+ */
+public class DeleteBranchCommand extends
+ RepositoriesViewCommandHandler<RefNode> {
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ final RefNode node = getSelectedNodes(event).get(0);
+ final Ref ref = node.getObject();
+
+ if (!MessageDialog.openConfirm(getView(event).getSite().getShell(),
+ UIText.RepositoriesView_ConfirmDeleteTitle, NLS.bind(
+ UIText.RepositoriesView_ConfirmBranchDeletionMessage,
+ ref.getName())))
+ return null;
+
+ try {
+ new ProgressMonitorDialog(getView(event).getSite().getShell()).run(
+ false, false, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException,
+ InterruptedException {
+ try {
+ RefUpdate op = node.getRepository().updateRef(
+ ref.getName());
+ op.setRefLogMessage("branch deleted", //$NON-NLS-1$
+ false);
+ // we set the force update in order
+ // to avoid having this rejected
+ // due to minor issues
+ op.setForceUpdate(true);
+ op.delete();
+ } catch (IOException ioe) {
+ throw new InvocationTargetException(ioe);
+ }
+ }
+ });
+ } catch (InvocationTargetException e1) {
+ Activator.handleError(
+ UIText.RepositoriesView_BranchDeletionFailureMessage, e1
+ .getCause(), true);
+ e1.printStackTrace();
+ } catch (InterruptedException e1) {
+ // ignore
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteFetchCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteFetchCommand.java
new file mode 100644
index 000000000..55786f71b
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeleteFetchCommand.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.repository.tree.FetchNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+import org.eclipse.jgit.lib.RepositoryConfig;
+
+/**
+ * Deletes the Fetch
+ */
+public class DeleteFetchCommand extends
+ RepositoriesViewCommandHandler<FetchNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ FetchNode node = getSelectedNodes(event).get(0);
+ RemoteNode remote = (RemoteNode) node.getParent();
+ RepositoryConfig config = node.getRepository().getConfig();
+ config.unset("remote", remote.getObject(), "url"); //$NON-NLS-1$ //$NON-NLS-2$
+ config.unset("remote", remote.getObject(), "fetch"); //$NON-NLS-1$//$NON-NLS-2$
+ try {
+ config.save();
+ } catch (IOException e1) {
+ Activator.handleError(e1.getMessage(), e1, true);
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeletePushCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeletePushCommand.java
new file mode 100644
index 000000000..1b436a4bb
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/DeletePushCommand.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.repository.tree.PushNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+import org.eclipse.jgit.lib.RepositoryConfig;
+
+/**
+ * Deletes the Push
+ */
+public class DeletePushCommand extends RepositoriesViewCommandHandler<PushNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ PushNode node = getSelectedNodes(event).get(0);
+ RemoteNode remote = (RemoteNode) node.getParent();
+ RepositoryConfig config = node.getRepository().getConfig();
+ config.unset("remote", remote.getObject(), "pushurl"); //$NON-NLS-1$ //$NON-NLS-2$
+ config.unset("remote", remote.getObject(), "push"); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ config.save();
+ } catch (IOException e1) {
+ Activator.handleError(e1.getMessage(), e1, true);
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchCommand.java
new file mode 100644
index 000000000..a3ec5fab4
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.net.URISyntaxException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.fetch.FetchWizard;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Implements "Fetch" from a Repository
+ */
+public class FetchCommand extends
+ RepositoriesViewCommandHandler<RepositoryNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryNode node = getSelectedNodes(event).get(0);
+
+ try {
+ new WizardDialog(getView(event).getSite().getShell(),
+ new FetchWizard(node.getRepository())).open();
+ } catch (URISyntaxException e1) {
+ Activator.handleError(e1.getMessage(), e1, true);
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java
new file mode 100644
index 000000000..f33e67fe9
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.fetch.FetchConfiguredRemoteAction;
+import org.eclipse.egit.ui.internal.repository.tree.FetchNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+
+/**
+ * Fetches from the remote
+ */
+public class FetchConfiguredRemoteCommand extends
+ RepositoriesViewCommandHandler<FetchNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ FetchNode node = getSelectedNodes(event).get(0);
+ RemoteNode remote = (RemoteNode) node.getParent();
+
+ new FetchConfiguredRemoteAction(node.getRepository(), remote
+ .getObject()).run(getView(event).getSite().getShell());
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ImportProjectsCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ImportProjectsCommand.java
new file mode 100644
index 000000000..d60608dca
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/ImportProjectsCommand.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.clone.GitCreateProjectViaWizardWizard;
+import org.eclipse.egit.ui.internal.repository.tree.FolderNode;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Implements "Add Projects" for Repository, Working Directory, and Folder
+ */
+public class ImportProjectsCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryTreeNode node = getSelectedNodes(event).get(0);
+ String path;
+
+ switch (node.getType()) {
+ case REPO:
+ // fall through
+ case WORKINGDIR:
+ path = node.getRepository().getWorkDir().toString();
+ break;
+ case FOLDER:
+ path = ((FolderNode) node).getObject().getPath().toString();
+ break;
+ default:
+ return null;
+ }
+
+ WizardDialog dlg = new WizardDialog(
+ getView(event).getSite().getShell(),
+ new GitCreateProjectViaWizardWizard(node.getRepository(), path));
+ dlg.open();
+
+ 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
new file mode 100644
index 000000000..14228d631
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/LinkWithSelectionCommand.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.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.swt.widgets.Event;
+import org.eclipse.swt.widgets.ToolItem;
+
+/**
+ * Implements "Link With Selection" toggle
+ */
+public class LinkWithSelectionCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ // is there a better way?
+ Event evt = (Event) event.getTrigger();
+ ToolItem item = (ToolItem) evt.widget;
+ boolean selected = item.getSelection();
+ getView(event).setReactOnSelection(selected);
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenCommand.java
new file mode 100644
index 000000000..adb668bb6
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.tree.FileNode;
+import org.eclipse.egit.ui.internal.repository.tree.RefNode;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.repository.tree.TagNode;
+
+/**
+ * Implements "Open" (double-click).
+ * <p>
+ * On a file, this delegates "Open in Text Editor", while on a branch or tag, it
+ * is doing "Checkout".
+ */
+public class OpenCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ final RepositoryTreeNode node = getSelectedNodes(event).get(0);
+
+ if (node instanceof RefNode || node instanceof TagNode)
+ return new CheckoutCommand().execute(event);
+ if (node instanceof FileNode)
+ return new OpenInTextEditorCommand().execute(event);
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenInTextEditorCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenInTextEditorCommand.java
new file mode 100644
index 000000000..99c8f5dac
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenInTextEditorCommand.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.tree.FileNode;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+import org.eclipse.ui.ide.IDE;
+
+/**
+ * Implements "Open in Text Editor"
+ */
+public class OpenInTextEditorCommand extends
+ RepositoriesViewCommandHandler<FileNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ FileNode node = getSelectedNodes(event).get(0);
+
+ IFileStore store = EFS.getLocalFileSystem().getStore(
+ new Path(node.getObject().getAbsolutePath()));
+ try {
+ // TODO do we need a read-only editor here?
+ IDE.openEditor(getView(event).getSite().getPage(),
+ new FileStoreEditorInput(store),
+ EditorsUI.DEFAULT_TEXT_EDITOR_ID);
+ } catch (PartInitException e) {
+ Activator.handleError(UIText.RepositoriesView_Error_WindowTitle, e,
+ true);
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenPropertiesCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenPropertiesCommand.java
new file mode 100644
index 000000000..ffb7e4490
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/OpenPropertiesCommand.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.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.IPageLayout;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Implements "Open Properties"
+ */
+public class OpenPropertiesCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ try {
+ // TODO should we get this from the event?
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+ .getActivePage().showView(IPageLayout.ID_PROP_SHEET);
+ } catch (PartInitException e1) {
+ // just ignore
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java
new file mode 100644
index 000000000..3e3ff3883
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PasteCommand.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.File;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+
+/**
+ * "Adds" a Repository upon pasting the clip-board contents.
+ * <p>
+ * This checks if the clip-board contents corresponds to a Git repository folder
+ * and adds that repository to the view if it doesn't already exists.
+ * <p>
+ * TODO we should extend this and open the "Add Repositories" dialog if the
+ * clip-board contents corresponds to an existing directory in the local file
+ * system. The "Directory" field of the dialog should be pre-filled with the
+ * directory from the clip-board.
+ */
+public class PasteCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ // we check if the pasted content is a directory
+ // repository location and try to add this
+ String errorMessage = null;
+
+ Clipboard clip = null;
+ try {
+ clip = new Clipboard(getView(event).getSite().getShell()
+ .getDisplay());
+ String content = (String) clip.getContents(TextTransfer
+ .getInstance());
+ if (content == null) {
+ errorMessage = UIText.RepositoriesView_NothingToPasteMessage;
+ return null;
+ }
+
+ File file = new File(content);
+ if (!file.exists() || !file.isDirectory()) {
+ errorMessage = UIText.RepositoriesView_ClipboardContentNotDirectoryMessage;
+ return null;
+ }
+
+ if (!RepositoryCache.FileKey.isGitRepository(file, FS.DETECTED)) {
+ errorMessage = NLS
+ .bind(
+ UIText.RepositoriesView_ClipboardContentNoGitRepoMessage,
+ content);
+ return null;
+ }
+
+ if (util.addConfiguredRepository(file)) {
+ // let's do the auto-refresh the rest
+ } else
+ errorMessage = NLS.bind(
+ UIText.RepositoriesView_PasteRepoAlreadyThere, content);
+
+ return null;
+ } finally {
+ if (clip != null)
+ // we must dispose ourselves
+ clip.dispose();
+ if (errorMessage != null)
+ Activator.handleError(errorMessage, null, true);
+ }
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java
new file mode 100644
index 000000000..840d5e5a9
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.net.URISyntaxException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.push.PushWizard;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.jface.wizard.WizardDialog;
+
+/**
+ * Implements "Push" from a Repository
+ */
+public class PushCommand extends RepositoriesViewCommandHandler<RepositoryNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ RepositoryNode node = getSelectedNodes(event).get(0);
+
+ try {
+ new WizardDialog(getView(event).getSite().getShell(),
+ new PushWizard(node.getRepository())).open();
+ } catch (URISyntaxException e1) {
+ Activator.handleError(e1.getMessage(), e1, true);
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java
new file mode 100644
index 000000000..2fad28138
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.push.PushConfiguredRemoteAction;
+import org.eclipse.egit.ui.internal.repository.tree.PushNode;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+
+/**
+ * Pushes to the remote
+ */
+public class PushConfiguredRemoteCommand extends
+ RepositoriesViewCommandHandler<PushNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ PushNode node = getSelectedNodes(event).get(0);
+ RemoteNode remote = (RemoteNode) node.getParent();
+
+ new PushConfiguredRemoteAction(node.getRepository(), remote.getObject())
+ .run(getView(event).getSite().getShell(), false);
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RefreshCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RefreshCommand.java
new file mode 100644
index 000000000..e4977c6b7
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RefreshCommand.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+
+/**
+ * Does a (forced) refresh on the Git Repositories View.
+ */
+public class RefreshCommand extends
+ RepositoriesViewCommandHandler<RepositoryTreeNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ getView(event).refresh();
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveCommand.java
new file mode 100644
index 000000000..8ff249279
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveCommand.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+
+/**
+ * "Removes" one or several nodes
+ */
+public class RemoveCommand extends
+ RepositoriesViewCommandHandler<RepositoryNode> implements IHandler {
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getView(
+ event).getSite()
+ .getService(IWorkbenchSiteProgressService.class);
+
+ Job job = new Job("Remove Repositories Job") { //$NON-NLS-1$
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final List<IProject> projectsToDelete = new ArrayList<IProject>();
+
+ monitor
+ .setTaskName(UIText.RepositoriesView_DeleteRepoDeterminProjectsMessage);
+
+ for (RepositoryNode node : getSelectedNodes(event)) {
+ File workDir = node.getRepository().getWorkDir();
+ final IPath wdPath = new Path(workDir.getAbsolutePath());
+ for (IProject prj : ResourcesPlugin.getWorkspace()
+ .getRoot().getProjects()) {
+ if (monitor.isCanceled())
+ return Status.OK_STATUS;
+ if (wdPath.isPrefixOf(prj.getLocation())) {
+ projectsToDelete.add(prj);
+ }
+ }
+ }
+
+ if (!projectsToDelete.isEmpty()) {
+ final boolean[] confirmed = new boolean[] { false };
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ confirmed[0] = confirmProjectDeletion(
+ projectsToDelete, event);
+ }
+ });
+ if (!confirmed[0]) {
+ return Status.OK_STATUS;
+ }
+ }
+
+ IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
+
+ public void run(IProgressMonitor actMonitor)
+ throws CoreException {
+
+ for (IProject prj : projectsToDelete) {
+ prj.delete(false, false, actMonitor);
+ }
+ }
+ };
+
+ try {
+ ResourcesPlugin.getWorkspace().run(wsr,
+ ResourcesPlugin.getWorkspace().getRoot(),
+ IWorkspace.AVOID_UPDATE, monitor);
+ } catch (CoreException e1) {
+ Activator.logError(e1.getMessage(), e1);
+ }
+
+ for (RepositoryNode node : getSelectedNodes(event)) {
+ util.removeDir(node.getRepository().getDirectory());
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ getView(event).getCommonViewer().refresh();
+ }
+ });
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ service.schedule(job);
+
+ return null;
+ }
+
+ @SuppressWarnings("boxing")
+ private boolean confirmProjectDeletion(List<IProject> projectsToDelete,
+ ExecutionEvent event) {
+ boolean confirmed;
+ confirmed = MessageDialog
+ .openConfirm(
+ getView(event).getSite().getShell(),
+ UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle,
+ NLS
+ .bind(
+ UIText.RepositoriesView_ConfirmProjectDeletion_Question,
+ projectsToDelete.size()));
+ return confirmed;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveRemoteCommand.java
new file mode 100644
index 000000000..15c5ddfba
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RemoveRemoteCommand.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.repository.RepositoriesView;
+import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jgit.lib.RepositoryConfig;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Removes a remote
+ */
+public class RemoveRemoteCommand extends
+ RepositoriesViewCommandHandler<RemoteNode> {
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ final RemoteNode node = getSelectedNodes(event).get(0);
+ final String configName = node.getObject();
+
+ boolean ok = MessageDialog.openConfirm(getView(event).getSite()
+ .getShell(), UIText.RepositoriesView_ConfirmDeleteRemoteHeader,
+ NLS.bind(UIText.RepositoriesView_ConfirmDeleteRemoteMessage,
+ configName));
+ if (ok) {
+ RepositoryConfig config = node.getRepository().getConfig();
+ config.unsetSection(RepositoriesView.REMOTE, configName);
+ try {
+ config.save();
+ } catch (IOException e1) {
+ Activator.handleError(UIText.RepositoriesView_ErrorHeader, e1,
+ true);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java
new file mode 100644
index 000000000..7e0015ca2
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Kinzler (SAP AG) - initial implementation
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.repository.tree.command;
+
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.RepositoryUtil;
+import org.eclipse.egit.ui.internal.repository.RepositoriesView;
+import org.eclipse.jface.viewers.TreeSelection;
+
+abstract class RepositoriesViewCommandHandler<T> extends AbstractHandler {
+
+ protected final RepositoryUtil util = Activator.getDefault()
+ .getRepositoryUtil();
+
+ public RepositoriesView getView(ExecutionEvent event) {
+ Object part = ((IEvaluationContext) event.getApplicationContext())
+ .getRoot().getVariable("activePart"); //$NON-NLS-1$ TODO constant for this?
+ return (RepositoriesView) part;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<T> getSelectedNodes(ExecutionEvent event) {
+ TreeSelection selection = (TreeSelection) ((IEvaluationContext) event
+ .getApplicationContext()).getRoot().getVariable("selection"); //$NON-NLS-1$ TODO constant for this?
+ return selection.toList();
+ }
+}

Back to the top