{"thread":{"id":"6441","subject":"[PATCH] [EGit] Indroduce GitAction class","startedAt":"2007-01-19T21:32:37Z","lastAt":"2007-01-20T03:18:08Z","messageCount":2,"participants":["Guilhem Bonnefille","Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"32087","messageId":"8b65902a0701191332n5055a28bi59600e35140582de@mail.gmail.com","threadId":"6441","inReplyTo":null,"subject":"[PATCH] [EGit] Indroduce GitAction class","fromName":"Guilhem Bonnefille","fromEmail":"guilhem.bonnefille@gmail.com","sentAt":"2007-01-19T21:32:37Z","receivedAt":"2007-01-19T21:32:37Z","isPatch":true,"sender":{"key":"guilhem.bonnefille@gmail.com","avatar":"https://gravatar.com/avatar/375364bfee1f61197c540e37465abe3619fc24eb3a36b0edcea7f15b124036b0?d=mp&s=160"},"body":"Hi,\n\nI introduce GitAction as base class for all actions. It allows to\ndisable the action menu item if the selection does not live in a Git\ncontrolled repository.\n\nThe current code is quite \"gruik\". It is mainly based on copy/paste\nfrom other plugins.\n\nA better solution could be to avoid inserting EGit actions in menus if\nthe selection does not live in a Git repo. (some plugin.xml hack)\n\n-- \nGuilhem BONNEFILLE\n-=- #UIN: 15146515 JID: guyou@im.apinc.org MSN: guilhem_bonnefille@hotmail.com\n-=- mailto:guilhem.bonnefille@gmail.com\n-=- http://nathguil.free.fr/\n\n\ndiff --git a/org.spearce.egit.core/META-INF/MANIFEST.MF b/org.spearce.egit.core/META-INF/MANIFEST.MF\nindex b7301a6..b7dd10d 100644\n--- a/org.spearce.egit.core/META-INF/MANIFEST.MF\n+++ b/org.spearce.egit.core/META-INF/MANIFEST.MF\n@@ -17,6 +17,8 @@ Require-Bundle: org.eclipse.core.runtime,\n  org.eclipse.ui.ide,\n  org.eclipse.ui.workbench,\n  org.eclipse.ui.workbench.texteditor\n-Export-Package: org.spearce.egit.core.op,\n+Export-Package: org.spearce.egit.core,\n+ org.spearce.egit.core.internal.mapping;x-internal:=true,\n+ org.spearce.egit.core.op,\n  org.spearce.egit.core.project\n Eclipse-LazyStart: true\ndiff --git a/org.spearce.egit.ui/META-INF/MANIFEST.MF b/org.spearce.egit.ui/META-INF/MANIFEST.MF\nindex f188478..bf90784 100644\n--- a/org.spearce.egit.ui/META-INF/MANIFEST.MF\n+++ b/org.spearce.egit.ui/META-INF/MANIFEST.MF\n@@ -14,5 +14,6 @@ Require-Bundle: org.eclipse.core.runtime,\n  org.spearce.jgit,\n  org.spearce.egit.core,\n  org.eclipse.compare,\n- org.eclipse.core.filesystem\n+ org.eclipse.core.filesystem,\n+ org.eclipse.jface.text\n Eclipse-LazyStart: true\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java\nindex d1a8d7c..c68e158 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java\n@@ -20,8 +20,12 @@ import org.eclipse.core.runtime.CoreException;\n import org.eclipse.core.runtime.IStatus;\n import org.eclipse.core.runtime.Platform;\n import org.eclipse.core.runtime.Status;\n+import org.eclipse.team.core.TeamException;\n+import org.eclipse.ui.IWorkbenchPage;\n+import org.eclipse.ui.IWorkbenchWindow;\n import org.eclipse.ui.plugin.AbstractUIPlugin;\n import org.osgi.framework.BundleContext;\n+import org.spearce.egit.core.GitProvider;\n \n public class Activator extends AbstractUIPlugin {\n     private static Activator plugin;\n@@ -34,6 +38,28 @@ public class Activator extends AbstractUIPlugin {\n \treturn getDefault().getBundle().getSymbolicName();\n     }\n \n+    /**\n+     * This is the provider ID of the plugin as defined in the plugin.xml\n+     * FIXME Inspired/Copied from FileSystem example. Specialize to EGit\n+     */\n+    public static String getPluginProviderId() {\n+\treturn GitProvider.class.getName();\n+    }\n+\n+    /**\n+     * Convenience method to get the currently active workbench page. Note that\n+     * the active page may not be the one that the usr perceives as active in\n+     * some situations so this method of obtaining the activae page should only\n+     * be used if no other method is available.\n+     * \n+     * @return the active workbench page\n+     */\n+    public static IWorkbenchPage getActivePage() {\n+    \tIWorkbenchWindow window = getDefault().getWorkbench().getActiveWorkbenchWindow();\n+    \tif (window == null) return null;\n+    \treturn window.getActivePage();\n+    }\n+\n     public static CoreException error(final String message, final Throwable thr) {\n \treturn new CoreException(new Status(IStatus.ERROR, getPluginId(), 0,\n \t\tmessage, thr));\n@@ -43,6 +69,10 @@ public class Activator extends AbstractUIPlugin {\n \tgetDefault().getLog().log(\n \t\tnew Status(IStatus.ERROR, getPluginId(), 0, message, thr));\n     }\n+    \n+\tpublic static void log(TeamException e) {\n+\t\tgetDefault().getLog().log(new Status(e.getStatus().getSeverity(), getPluginId(), 0, \"simpleInternal\", e)); //$NON-NLS-1$\n+\t}\n \n     private static boolean isOptionSet(final String optionId) {\n \tfinal String option = getPluginId() + optionId;\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/AbstractOperationAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/AbstractOperationAction.java\nindex 759189e..d2af9de 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/AbstractOperationAction.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/AbstractOperationAction.java\n@@ -17,7 +17,6 @@\n package org.spearce.egit.ui.internal.actions;\n \n import java.lang.reflect.InvocationTargetException;\n-import java.util.Collections;\n import java.util.List;\n \n import org.eclipse.core.resources.IWorkspaceRunnable;\n@@ -28,29 +27,15 @@ import org.eclipse.core.runtime.Status;\n import org.eclipse.jface.action.IAction;\n import org.eclipse.jface.dialogs.ErrorDialog;\n import org.eclipse.jface.operation.IRunnableWithProgress;\n-import org.eclipse.jface.viewers.ISelection;\n-import org.eclipse.jface.viewers.IStructuredSelection;\n-import org.eclipse.ui.IObjectActionDelegate;\n import org.eclipse.ui.IWorkbenchPart;\n import org.spearce.egit.ui.Activator;\n import org.spearce.egit.ui.UIText;\n \n-public abstract class AbstractOperationAction implements IObjectActionDelegate {\n+public abstract class AbstractOperationAction extends GitAction {\n     private IWorkbenchPart wp;\n \n     private IWorkspaceRunnable op;\n \n-    public void selectionChanged(final IAction act, final ISelection sel) {\n-\tfinal List selection;\n-\tif (sel instanceof IStructuredSelection && !sel.isEmpty()) {\n-\t    selection = ((IStructuredSelection) sel).toList();\n-\t} else {\n-\t    selection = Collections.EMPTY_LIST;\n-\t}\n-\top = createOperation(act, selection);\n-\tact.setEnabled(op != null && wp != null);\n-    }\n-\n     public void setActivePart(final IAction act, final IWorkbenchPart part) {\n \twp = part;\n     }\n@@ -62,6 +47,7 @@ public abstract class AbstractOperationAction implements IObjectActionDelegate {\n     }\n \n     public void run(final IAction act) {\n+\top = createOperation(act, getSelection().toList());\n \tif (op != null) {\n \t    try {\n \t\ttry {\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CompareWithRevisionAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CompareWithRevisionAction.java\nindex bb7fbc7..205536c 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CompareWithRevisionAction.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CompareWithRevisionAction.java\n@@ -22,12 +22,10 @@ import java.util.Hashtable;\n import org.eclipse.core.resources.IResource;\n import org.eclipse.jface.action.IAction;\n import org.eclipse.swt.widgets.Shell;\n-import org.eclipse.team.core.TeamException;\n-import org.eclipse.team.internal.ui.actions.TeamAction;\n import org.eclipse.team.ui.TeamUI;\n import org.eclipse.team.ui.history.HistoryPageSaveablePart;\n \n-public class CompareWithRevisionAction extends TeamAction {\n+public class CompareWithRevisionAction extends GitAction {\n \n     public void run(IAction action) {\n \tsuper.run(action);\n@@ -45,9 +43,4 @@ public class CompareWithRevisionAction extends TeamAction {\n     protected void showCompareInDialog(Shell shell, Object object) {\n \tHistoryPageSaveablePart.showHistoryInDialog(shell, object);\n     }\n-\n-    protected boolean isEnabled() throws TeamException {\n-\treturn !getSelection().isEmpty();\n-    }\n-\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/GitAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/GitAction.java\nnew file mode 100644\nindex 0000000..0769e38\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/GitAction.java\n@@ -0,0 +1,35 @@\n+/*******************************************************************************\n+ * Copyright (C) 2006  Guilhem Bonnefille\n+ * All rights reserved. This program and the accompanying materials\n+ * are made available under the terms of the Eclipse Public License v1.0\n+ * which accompanies this distribution, and is available at\n+ * http://www.eclipse.org/legal/epl-v10.html\n+ *******************************************************************************/\n+package org.spearce.egit.ui.internal.actions;\n+\n+import org.eclipse.core.resources.mapping.ResourceMapping;\n+import org.spearce.egit.ui.Activator;\n+\n+/**\n+ * An abstract class that acts as a super class for FileSystemProvider actions.\n+ * It provides some general methods applicable to multiple actions.\n+ */\n+public abstract class GitAction extends TeamAction {\n+\n+\t/**\n+\t * @see TeamAction#isEnabled()\n+\t */\n+\tprotected boolean isEnabled() {\n+\t\treturn getSelectedMappings().length > 0;\n+\t}\n+\t\n+\t/**\n+\t * Return the selected resource mappings that are associated with the\n+\t * file system provider.\n+\t * @return the selected resource mappings that are associated with the\n+\t * file system provider.\n+\t */\n+\tprotected ResourceMapping[] getSelectedMappings() {\n+\t\treturn getSelectedResourceMappings(Activator.getPluginProviderId());\n+\t}\n+}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ShowResourceInHistoryAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ShowResourceInHistoryAction.java\nindex 3e6b870..f48c5e5 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ShowResourceInHistoryAction.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ShowResourceInHistoryAction.java\n@@ -18,12 +18,10 @@ package org.spearce.egit.ui.internal.actions;\n \n import org.eclipse.jface.action.IAction;\n import org.eclipse.swt.widgets.Shell;\n-import org.eclipse.team.core.TeamException;\n-import org.eclipse.team.internal.ui.actions.TeamAction;\n import org.eclipse.team.ui.TeamUI;\n import org.eclipse.team.ui.history.HistoryPageSaveablePart;\n \n-public class ShowResourceInHistoryAction extends TeamAction {\n+public class ShowResourceInHistoryAction extends GitAction {\n \n     public void run(IAction action) {\n \tTeamUI.getHistoryView().showHistoryFor(getSelectedResources()[0]);\n@@ -32,8 +30,9 @@ public class ShowResourceInHistoryAction extends TeamAction {\n     protected void showCompareInDialog(Shell shell, Object object) {\n \tHistoryPageSaveablePart.showHistoryInDialog(shell, object);\n     }\n-\n+/*\n     protected boolean isEnabled() throws TeamException {\n \treturn !getSelection().isEmpty();\n     }\n+    */\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/TeamAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/TeamAction.java\nnew file mode 100644\nindex 0000000..fbcfcb7\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/TeamAction.java\n@@ -0,0 +1,418 @@\n+/*******************************************************************************\n+ * copied from: org.eclipse.team.internal.ui.actions.TeamAction\n+ * \n+ * Copyright (c) 2000, 2003 IBM Corporation and others.\n+ * All rights reserved. This program and the accompanying materials \n+ * are made available under the terms of the Common Public License v1.0\n+ * which accompanies this distribution, and is available at\n+ * http://www.eclipse.org/legal/cpl-v10.html\n+ * \n+ * Contributors:\n+ *     IBM Corporation - initial API and implementation\n+ *******************************************************************************/\n+package org.spearce.egit.ui.internal.actions;\n+\n+\n+import java.lang.reflect.Array;\n+import java.lang.reflect.InvocationTargetException;\n+import java.util.ArrayList;\n+import java.util.Hashtable;\n+import java.util.Iterator;\n+import java.util.List;\n+\n+import org.eclipse.core.resources.IProject;\n+import org.eclipse.core.resources.IResource;\n+import org.eclipse.core.resources.IResourceStatus;\n+import org.eclipse.core.resources.mapping.ResourceMapping;\n+import org.eclipse.core.runtime.IAdaptable;\n+import org.eclipse.core.runtime.NullProgressMonitor;\n+import org.eclipse.jface.action.IAction;\n+import org.eclipse.jface.dialogs.ProgressMonitorDialog;\n+import org.eclipse.jface.operation.IRunnableWithProgress;\n+import org.eclipse.jface.text.ITextSelection;\n+import org.eclipse.jface.viewers.ISelection;\n+import org.eclipse.jface.viewers.IStructuredSelection;\n+import org.eclipse.jface.viewers.StructuredSelection;\n+import org.eclipse.swt.custom.BusyIndicator;\n+import org.eclipse.swt.widgets.Display;\n+import org.eclipse.swt.widgets.Shell;\n+import org.eclipse.team.core.RepositoryProvider;\n+import org.eclipse.team.core.TeamException;\n+import org.eclipse.ui.IEditorInput;\n+import org.eclipse.ui.IEditorPart;\n+import org.eclipse.ui.IObjectActionDelegate;\n+import org.eclipse.ui.IViewActionDelegate;\n+import org.eclipse.ui.IViewPart;\n+import org.eclipse.ui.IWorkbench;\n+import org.eclipse.ui.IWorkbenchPage;\n+import org.eclipse.ui.IWorkbenchPart;\n+import org.eclipse.ui.IWorkbenchWindow;\n+import org.eclipse.ui.PartInitException;\n+import org.eclipse.ui.actions.ActionDelegate;\n+import org.eclipse.ui.internal.LegacyResourceSupport;\n+import org.spearce.egit.ui.Activator;\n+\n+/**\n+ * The abstract superclass of all Team actions. This class contains some convenience\n+ * methods for getting selected objects and mapping selected objects to their\n+ * providers.\n+ * \n+ * Team providers may subclass this class when creating their actions.\n+ * Team providers may also instantiate or subclass any of the  \n+ * subclasses of TeamAction provided in this package.\n+ */\n+public abstract class TeamAction extends ActionDelegate implements IObjectActionDelegate, IViewActionDelegate {\n+\t// The current selection\n+\tprotected IStructuredSelection selection;\n+\t\n+\t// The shell, required for the progress dialog\n+\tprotected Shell shell;\n+\n+\t// Constants for determining the type of progress. Subclasses may\n+\t// pass one of these values to the run method.\n+\tpublic final static int PROGRESS_DIALOG = 1;\n+\tpublic final static int PROGRESS_BUSYCURSOR = 2;\n+\n+\tprivate IWorkbenchPart targetPart;\n+\n+\t/**\n+\t * Creates an array of the given class type containing all the\n+\t * objects in the selection that adapt to the given class.\n+\t * \n+\t * @param selection\n+\t * @param c\n+\t * @return\n+\t */\n+\tpublic static Object[] getSelectedAdaptables(ISelection selection, Class c) {\n+\t\tArrayList result = null;\n+\t\tif (!selection.isEmpty()) {\n+\t\t\tresult = new ArrayList();\n+\t\t\tIterator elements = ((IStructuredSelection) selection).iterator();\n+\t\t\twhile (elements.hasNext()) {\n+\t\t\t\tObject adapter = getAdapter(elements.next(), c);\n+\t\t\t\tif (c.isInstance(adapter)) {\n+\t\t\t\t\tresult.add(adapter);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (result != null && !result.isEmpty()) {\n+\t\t\treturn result.toArray((Object[])Array.newInstance(c, result.size()));\n+\t\t}\n+\t\treturn (Object[])Array.newInstance(c, 0);\n+\t}\n+\t\n+\t/**\n+\t * Find the object associated with the given object when it is adapted to\n+\t * the provided class. Null is returned if the given object does not adapt\n+\t * to the given class\n+\t * \n+\t * @param selection\n+\t * @param c\n+\t * @return Object\n+\t */\n+\tpublic static Object getAdapter(Object adaptable, Class c) {\n+\t\tif (c.isInstance(adaptable)) {\n+\t\t\treturn adaptable;\n+\t\t}\n+\t\tif (adaptable instanceof IAdaptable) {\n+\t\t\tIAdaptable a = (IAdaptable) adaptable;\n+\t\t\tObject adapter = a.getAdapter(c);\n+\t\t\tif (c.isInstance(adapter)) {\n+\t\t\t\treturn adapter;\n+\t\t\t}\n+\t\t}\n+\t\treturn null;\n+\t}\n+\t\n+\t/**\n+\t * Returns the selected projects.\n+\t * \n+\t * @return the selected projects\n+\t */\n+\tprotected IProject[] getSelectedProjects() {\n+\t\tIResource[] selectedResources = getSelectedResources();\n+\t\tif (selectedResources.length == 0) return new IProject[0];\n+\t\tArrayList projects = new ArrayList();\n+\t\tfor (int i = 0; i < selectedResources.length; i++) {\n+\t\t\tIResource resource = selectedResources[i];\n+\t\t\tif (resource.getType() == IResource.PROJECT) {\n+\t\t\t\tprojects.add(resource);\n+\t\t\t}\n+\t\t}\n+\t\treturn (IProject[]) projects.toArray(new IProject[projects.size()]);\n+\t}\n+\t\n+\t/**\n+\t * Returns an array of the given class type c that contains all\n+\t * instances of c that are either contained in the selection or\n+\t * are adapted from objects contained in the selection.\n+\t * \n+\t * @param c\n+\t * @return\n+\t */\n+\tprotected Object[] getSelectedResources(Class c) {\n+\t\treturn getSelectedAdaptables(selection, c);\n+\t}\n+\t\n+\t/**\n+\t * Returns the selected resources.\n+\t * \n+\t * @return the selected resources\n+\t */\n+\tprotected IResource[] getSelectedResources() {\n+\t\treturn (IResource[])getSelectedResources(IResource.class);\n+\t}\n+\t\n+\t/**\n+\t * Convenience method for getting the current shell.\n+\t * \n+\t * @return the shell\n+\t */\n+\tpublic Shell getShell() {\n+\t\tif (shell != null) {\n+\t\t\treturn shell;\n+\t\t} else {\n+\t\t\tIWorkbench workbench = Activator.getDefault().getWorkbench();\n+\t\t\tif (workbench == null) return null;\n+\t\t\tIWorkbenchWindow window = workbench.getActiveWorkbenchWindow();\n+\t\t\tif (window == null) return null;\n+\t\t\treturn window.getShell();\n+\t\t}\n+\t}\n+\t/**\n+\t * Convenience method for running an operation with progress and\n+\t * error feedback.\n+\t * \n+\t * @param runnable  the runnable which executes the operation\n+\t * @param problemMessage  the message to display in the case of errors\n+\t * @param progressKind  one of PROGRESS_BUSYCURSOR or PROGRESS_DIALOG\n+\t */\n+\tfinal protected void run(final IRunnableWithProgress runnable, final String problemMessage, int progressKind) {\n+\t\tfinal Exception[] exceptions = new Exception[] {null};\n+\t\tswitch (progressKind) {\n+\t\t\tcase PROGRESS_BUSYCURSOR :\n+\t\t\t\tBusyIndicator.showWhile(Display.getCurrent(), new Runnable() {\n+\t\t\t\t\tpublic void run() {\n+\t\t\t\t\t\ttry {\n+\t\t\t\t\t\t\trunnable.run(new NullProgressMonitor());\n+\t\t\t\t\t\t} catch (InvocationTargetException e) {\n+\t\t\t\t\t\t\texceptions[0] = e;\n+\t\t\t\t\t\t} catch (InterruptedException e) {\n+\t\t\t\t\t\t\texceptions[0] = null;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t});\n+\t\t\t\tbreak;\n+\t\t\tdefault :\n+\t\t\tcase PROGRESS_DIALOG :\n+\t\t\t\ttry {\n+\t\t\t\t\tnew ProgressMonitorDialog(getShell()).run(true, true, runnable);\n+\t\t\t\t} catch (InvocationTargetException e) {\n+\t\t\t\t\texceptions[0] = e;\n+\t\t\t\t} catch (InterruptedException e) {\n+\t\t\t\t\texceptions[0] = null;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tif (exceptions[0] != null) {\n+\t\t\thandle(exceptions[0], null, problemMessage);\n+\t\t}\n+\t}\n+\t\n+\t/*\n+\t * Method declared on IActionDelegate.\n+\t */\n+\tpublic void selectionChanged(IAction action, ISelection sel) {\n+\t\tif (sel instanceof IStructuredSelection) {\n+\t\t\tthis.selection = (IStructuredSelection) sel;\n+\t\t\tif (action != null) {\n+\t\t\t\tsetActionEnablement(action);\n+\t\t\t}\n+\t\t}\n+\t\tif (sel instanceof ITextSelection){\n+\t\t\t\tIEditorPart part = getTargetPage().getActiveEditor();\n+\t\t\t\tif (part != null) {\n+\t\t\t\t\tIEditorInput input = part.getEditorInput();\n+\t\t\t\t\tIResource r = (IResource) input.getAdapter(IResource.class);\n+\t\t\t\t\tif (r != null) {\n+\t\t\t\t\t\tswitch(r.getType()){\n+\t\t\t\t\t\t\tcase IResource.FILE:\n+\t\t\t\t\t\t\t\tthis.selection = new StructuredSelection(r);\n+\t\t\t\t\t\t\t\tif (action != null) {\n+\t\t\t\t\t\t\t\t\tsetActionEnablement(action);\n+\t\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\t//\tset selection to current editor file;\n+\t\t\t\t}\n+\t\t}\n+\t}\n+\t\n+\t/**\n+\t * Method invoked from <code>selectionChanged(IAction, ISelection)</code> \n+\t * to set the enablement status of the action. The instance variable \n+\t * <code>selection</code> will contain the latest selection so the methods\n+\t * <code>getSelectedResources()</code> and <code>getSelectedProjects()</code>\n+\t * will provide the proper objects.\n+\t * \n+\t * This method can be overridden by subclasses but should not be invoked by them.\n+\t */\n+\tprotected void setActionEnablement(IAction action) {\n+\t\ttry {\n+\t\t\taction.setEnabled(isEnabled());\n+\t\t} catch (TeamException e) {\n+\t\t\tif (e.getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {\n+\t\t\t\t// Enable the action to allow the user to discover the problem\n+\t\t\t\taction.setEnabled(true);\n+\t\t\t} else {\n+\t\t\t\taction.setEnabled(false);\n+\t\t\t\t// We should not open a dialog when determining menu enablements so log it instead\n+\t\t\t\tActivator.log(e);\n+\t\t\t}\n+\t\t}\n+\t}\n+\t\n+\t/*\n+\t * Method declared on IObjectActionDelegate.\n+\t */\n+\tpublic void setActivePart(IAction action, IWorkbenchPart targetPart) {\n+\t\tif(targetPart != null) {\n+\t\t\tthis.shell = targetPart.getSite().getShell();\n+\t\t\tthis.targetPart = targetPart;\n+\t\t}\n+\t}\n+\t/**\n+\t * Shows the given errors to the user.\n+\t * \n+\t * @param status  the status containing the error\n+\t * @param title  the title of the error dialog\n+\t * @param message  the message for the error dialog\n+\t * @param shell  the shell to open the error dialog in\n+\t */\n+\tprotected void handle(Exception exception, String title, String message) {\n+\t\t// FIXME Utils.handleError(getShell(), exception, title, message);\n+\t}\n+\t\n+\t/**\n+\t * Concrete action enablement code.\n+\t * Subclasses must implement.\n+\t * \n+\t * @return whether the action is enabled\n+\t * @throws TeamException if an error occurs during enablement detection\n+\t */\n+\tabstract protected boolean isEnabled() throws TeamException;\n+\t\n+\t/**\n+\t * Convenience method that maps the selected resources to their providers.\n+\t * The returned Hashtable has keys which are ITeamProviders, and values\n+\t * which are Lists of IResources that are shared with that provider.\n+\t * \n+\t * @return a hashtable mapping providers to their selected resources\n+\t */\n+\tprotected Hashtable getProviderMapping() {\n+\t\treturn getProviderMapping(getSelectedResources());\n+\t}\n+\t/**\n+\t * Convenience method that maps the given resources to their providers.\n+\t * The returned Hashtable has keys which are ITeamProviders, and values\n+\t * which are Lists of IResources that are shared with that provider.\n+\t * \n+\t * @return a hashtable mapping providers to their resources\n+\t */\n+\tprotected Hashtable getProviderMapping(IResource[] resources) {\n+\t\tHashtable result = new Hashtable();\n+\t\tfor (int i = 0; i < resources.length; i++) {\n+\t\t\tRepositoryProvider provider = RepositoryProvider.getProvider(resources[i].getProject());\n+\t\t\tList list = (List)result.get(provider);\n+\t\t\tif (list == null) {\n+\t\t\t\tlist = new ArrayList();\n+\t\t\t\tresult.put(provider, list);\n+\t\t\t}\n+\t\t\tlist.add(resources[i]);\n+\t\t}\n+\t\treturn result;\n+\t}\n+\t\n+\tprotected IStructuredSelection getSelection() {\n+\t\tif (selection == null)\n+\t\t\tselection = StructuredSelection.EMPTY;\n+\t\treturn selection;\n+\t}\n+\t\n+/**\n+     * Return the selected resource mappins that contain resources in \n+     * projects that are associated with a repository of the given id.\n+     * @param providerId the repository provider id\n+     * @return the resource mappings that contain resources associated with the given provider\n+     */\n+    protected ResourceMapping[] getSelectedResourceMappings(String providerId) {\n+        Object[] elements = getSelection().toArray();\n+        ArrayList providerMappings = new ArrayList();\n+        for (int i = 0; i < elements.length; i++) {\n+            Object object = elements[i];\n+            Object adapted = getResourceMapping(object);\n+            if (adapted instanceof ResourceMapping) {\n+                ResourceMapping mapping = (ResourceMapping) adapted;\n+                if (providerId == null || isMappedToProvider(mapping, providerId)) {\n+                    providerMappings.add(mapping);\n+                }\n+            }\n+        }\n+        return (ResourceMapping[]) providerMappings.toArray(new ResourceMapping[providerMappings.size()]);\n+    }\n+    \n+    private Object getResourceMapping(Object object) {\n+        if (object instanceof ResourceMapping)\n+            return (ResourceMapping)object;\n+        return LegacyResourceSupport.getAdaptedContributorResourceMapping(object);\n+    }\n+    \n+    private boolean isMappedToProvider(ResourceMapping element, String providerId) {\n+        IProject[] projects = element.getProjects();\n+        for (int k = 0; k < projects.length; k++) {\n+            IProject project = projects[k];\n+            RepositoryProvider provider = RepositoryProvider.getProvider(project);\n+            if (provider != null && provider.getID().equals(providerId)) {\n+                return true;\n+            }\n+        }\n+        return false;\n+    }\n+\t    /**\n+\t * @return IWorkbenchPart\n+\t */\n+\tprotected IWorkbenchPart getTargetPart() {\n+\t\treturn targetPart;\n+\t}\n+\n+\t/**\n+\t * Return the path that was active when the menu item was selected.\n+\t * @return IWorkbenchPage\n+\t */\n+\tprotected IWorkbenchPage getTargetPage() {\n+\t\tif (getTargetPart() == null) return Activator.getActivePage();\n+\t\treturn getTargetPart().getSite().getPage();\n+\t}\n+\t\n+\t/**\n+\t * Show the view with the given ID in the perspective from which the action\n+\t * was executed. Returns null if the view is not registered.\n+\t * \n+\t * @param viewId\n+\t * @return IViewPart\n+\t */\n+\tprotected IViewPart showView(String viewId) {\n+\t\ttry {\n+\t\t\treturn getTargetPage().showView(viewId);\n+\t\t} catch (PartInitException pe) {\n+\t\t\treturn null;\n+\t\t}\n+\t}\n+\t\n+\t/* (non-Javadoc)\n+\t * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)\n+\t */\n+\tpublic void init(IViewPart view) {\n+\t\ttargetPart = view;\n+\t}\n+}\n"},{"id":"32136","messageId":"20070120031808.GA11200@spearce.org","threadId":"6441","inReplyTo":"8b65902a0701191332n5055a28bi59600e35140582de@mail.gmail.com","subject":"Re: [PATCH] [EGit] Indroduce GitAction class","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-01-20T03:18:08Z","receivedAt":"2007-01-20T03:18:08Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Guilhem Bonnefille <guilhem.bonnefille@gmail.com> wrote:\n> I introduce GitAction as base class for all actions. It allows to\n> disable the action menu item if the selection does not live in a Git\n> controlled repository.\n> \n> The current code is quite \"gruik\". It is mainly based on copy/paste\n> from other plugins.\n> \n> A better solution could be to avoid inserting EGit actions in menus if\n> the selection does not live in a Git repo. (some plugin.xml hack)\n\nThanks for the patch!  I've applied it, and done some cleanup\nbehind.  I really appreciate that someone else is trying to help\negit move along.\n\nA few thoughts:\n\n * Please format your code using the Eclipse formatter prior to\n a patch.  The project settings are configured to be the builtin\n Java Conventions that ship with Eclipse.  I rely *very* heavily on\n the Eclipse formatter being able to format my source code for me,\n so that I don't need to worry about whitespace, brace placement,\n line breaks, etc.  It saves me tons of time.\n\n * I noticed the copyright you sent in on one of your files was dated\n 2006.  I applied it as is.  Are you sure you did not mean 2007?  ;-)\n\n * You did not send the patch inline or as an mbox.  This makes\n it much more difficult for me to apply the patch with `git am`.\n In the future can you please either submit the patch inline, or\n format using `git format-patch` and attach the *entire* output so\n that I have a proper Date/From/Subject/commit-message immediately\n available?\n\nBy the way, I have just added a SUBMITTING_PATCHES file at the top\nlevel directory of the egit.git repository which covers some of\nthese topics.  I apologize for not shipping one earlier with the\nproject, as doing so may have eliminated some confusion.\n\n-- \nShawn.\n"}]}