diff options
author | Mathias Kinzler | 2010-06-16 06:56:15 +0000 |
---|---|---|
committer | Matthias Sohn | 2010-06-17 09:08:20 +0000 |
commit | e1a9051b8d15f188458a3b1f05411826e2048aa5 (patch) | |
tree | d7cc86c2d0253226e94495c066dabc361931e521 /org.eclipse.egit.ui | |
parent | 5c1ce943b67820bc360d36e727ba0a83ea9d48db (diff) | |
download | egit-e1a9051b8d15f188458a3b1f05411826e2048aa5.tar.gz egit-e1a9051b8d15f188458a3b1f05411826e2048aa5.tar.xz egit-e1a9051b8d15f188458a3b1f05411826e2048aa5.zip |
Git Repositories View in Common Navigator Framework.
The Git Repositories View is re-implemented in the Common Navigator Framework.
The menu contributions are now declared in the plugin.xml for extension point
org.eclipse.ui.command and default handlers are implemented for this.
Change-Id: Ie12786896b0f45844cecbb6f2ed1c48ebf37b642
Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.egit.ui')
43 files changed, 2995 insertions, 1853 deletions
diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF index d2f8deed6f..0a0a8402b0 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 476fbdd7c0..d4b0d74bb9 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 4de8339283..010dd85dce 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 8d3326dba5..7d97c7f596 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 b3ec1123bc..a222eed1b8 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 253fd9065e..7c4ecf4f30 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 5f435d7437..87a165db43 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 a30fb2a119..b6003fa197 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 b128ec7de2..9cbb9c5f46 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 0f4ef41d55..b25077eb76 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 9f9955e83c..0faa38c56e 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 6138c61138..164961fb98 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 419ddaf1ff..05c9e9eb7c 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 0000000000..dd025acde3 --- /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 0000000000..a6a80be00c --- /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 0000000000..c32d64ffd2 --- /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 0000000000..6702ec7a8a --- /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 7d532bc2c2..f09abaa25f 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 0000000000..768a1b3970 --- /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 0000000000..5a80af33f6 --- /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 0000000000..63bb3eb77e --- /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 0000000000..b5ad394332 --- /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 0000000000..e31a932a53 --- /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 0000000000..78440b4c0d --- /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 0000000000..8d51b80a69 --- /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 0000000000..fcec66bfce --- /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 0000000000..6291368291 --- /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 0000000000..55786f71b6 --- /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 0000000000..1b436a4bb9 --- /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 0000000000..a3ec5fab49 --- /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 0000000000..f33e67fe94 --- /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 0000000000..d60608dca7 --- /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 0000000000..14228d631a --- /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 0000000000..adb668bb6c --- /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 0000000000..99c8f5dacb --- /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 0000000000..ffb7e44902 --- /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 0000000000..3e3ff3883f --- /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 0000000000..840d5e5a96 --- /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 0000000000..2fad28138c --- /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 0000000000..e4977c6b7b --- /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 0000000000..8ff2492792 --- /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 0000000000..15c5ddfba2 --- /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 0000000000..7e0015ca29 --- /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(); + } +} |