[WIP] Add extension point to the UI

- Allow to pass information to an external command after selecting a file

Change-Id: Ie434b12690ca79999b3b850efd646e0e4d7c439d
Signed-off-by: Jacques Bouthillier <jacques.bouthillier@ericsson.com>
diff --git a/org.eclipse.egerrit.ui/META-INF/MANIFEST.MF b/org.eclipse.egerrit.ui/META-INF/MANIFEST.MF
index bd28ae7..3e280cb 100644
--- a/org.eclipse.egerrit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egerrit.ui/META-INF/MANIFEST.MF
@@ -49,7 +49,8 @@
  org.eclipse.egerrit.internal.ui.table,
  org.eclipse.egerrit.internal.ui.table.model,
  org.eclipse.egerrit.internal.ui.tabs,
- org.eclipse.egerrit.internal.ui.utils
+ org.eclipse.egerrit.internal.ui.utils,
+ org.eclipse.egerrit.ui.extension
 Import-Package: org.apache.commons.codec.binary,
  org.apache.http;version="4.3.3",
  org.apache.http.client.utils;version="4.3.6",
diff --git a/org.eclipse.egerrit.ui/plugin.xml b/org.eclipse.egerrit.ui/plugin.xml
index c92381a..de66682 100644
--- a/org.eclipse.egerrit.ui/plugin.xml
+++ b/org.eclipse.egerrit.ui/plugin.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.4"?>
 <plugin>
+   <extension-point id="org.eclipse.egerrit.ui.extensionpoint.externalCmd" name="ExtCmd" schema="schema/org.eclipse.egerrit.ui.extensionpoint.externalCmd.exsd"/>
    <extension
          point="org.eclipse.ui.editors">
       <editor
diff --git a/org.eclipse.egerrit.ui/schema/org.eclipse.egerrit.ui.extensionpoint.externalCmd.exsd b/org.eclipse.egerrit.ui/schema/org.eclipse.egerrit.ui.extensionpoint.externalCmd.exsd
new file mode 100644
index 0000000..2df5835
--- /dev/null
+++ b/org.eclipse.egerrit.ui/schema/org.eclipse.egerrit.ui.extensionpoint.externalCmd.exsd
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.egerrit.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.egerrit.ui" id="org.eclipse.egerrit.ui.extensionpoint.externalCmd" name="ExtCmd"/>
+      </appinfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <choice minOccurs="1" maxOccurs="unbounded">
+            <element ref="client"/>
+         </choice>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="client">
+      <complexType>
+         <attribute name="class" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.egerrit.ui.extension.IExternalCmd"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/EvaluateContributionsHandler.java b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/EvaluateContributionsHandler.java
new file mode 100644
index 0000000..f0e8465
--- /dev/null
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/EvaluateContributionsHandler.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Ericsson AB.
+ * 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:
+ *     Jacques Bouthillier - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egerrit.extensionpoint.definition;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.egerrit.ui.extension.IExternalCmd;
+
+/**
+ * Evaluate the external contribution to EGerrit
+ */
+public class EvaluateContributionsHandler extends AbstractHandler {
+
+	private static final String IEXTERNALCOMMAND_ID = "org.eclipse.egerrit.ui.extensionpoint.externalCmd"; //$NON-NLS-1$
+
+//  AbstractHandler new method
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IExtensionRegistry reg = Platform.getExtensionRegistry();
+		execute(reg);
+		return null;
+	}
+
+	public void execute(IExtensionRegistry registry) {
+
+		IConfigurationElement[] config = registry.getConfigurationElementsFor(IEXTERNALCOMMAND_ID);
+		try {
+			for (IConfigurationElement e : config) {
+				final Object o = e.createExecutableExtension("class"); //$NON-NLS-1$
+				if (o instanceof IExternalCmd) {
+					executeExtension(o);
+				}
+			}
+		} catch (CoreException ex) {
+			System.out.println(ex.getMessage());
+		}
+	}
+
+	private void executeExtension(final Object o) {
+		ISafeRunnable runnable = new ISafeRunnable() {
+			@Override
+			public void handleException(Throwable e) {
+				System.out.println("Exception in client \n" + e.getMessage()); //$NON-NLS-1$
+			}
+
+			@Override
+			public void run() throws Exception {
+				System.out.println("run() in EvaluateContribution for: " + ((IExternalCmd) o).toString()); //$NON-NLS-1$
+				((IExternalCmd) o).cmd1();
+			}
+		};
+		SafeRunner.run(runnable);
+	}
+
+}
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/HandleExternalFileSelection.java b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/HandleExternalFileSelection.java
new file mode 100644
index 0000000..f2d7f0d
--- /dev/null
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/extensionpoint/definition/HandleExternalFileSelection.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Ericsson AB.
+ * 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:
+ *     Jacques Bouthillier - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.egerrit.extensionpoint.definition;
+
+import java.util.Iterator;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.egerrit.internal.core.GerritClient;
+import org.eclipse.egerrit.internal.model.FileInfo;
+import org.eclipse.egerrit.internal.model.impl.StringToFileInfoImpl;
+import org.eclipse.egerrit.internal.ui.compare.GerritDiffNode;
+import org.eclipse.egerrit.ui.extension.IExternalCmd.ExternalInfo;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+
+/**
+ * This class implements the selection of the file in the Files table and open the workspace file.
+ *
+ * @since 1.0
+ */
+public class HandleExternalFileSelection {
+
+	private GerritClient fGerritClient;
+
+	private ColumnViewer fViewer;
+
+	public HandleExternalFileSelection(GerritClient gerritClient, ColumnViewer viewer) {
+		this.fGerritClient = gerritClient;
+		this.fViewer = viewer;
+	}
+
+	/**
+	 * Open the selected file in the Files table and open the workspace file
+	 *
+	 * @return boolean
+	 * @throws Throwable
+	 */
+	public boolean showFileSelection() {
+		boolean ok = true;
+		ISelection selection = fViewer.getSelection();
+		if (selection instanceof IStructuredSelection) {
+
+			IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+			Iterator<?> itr = structuredSelection.iterator();
+			while (itr.hasNext()) {
+				getReviewInfo(itr);
+				notifyContributionHandler();
+			}
+		}
+
+		return ok;
+
+	}
+
+	private void notifyContributionHandler() {
+		EvaluateContributionsHandler eval = new EvaluateContributionsHandler();
+		try {
+			eval.execute(new ExecutionEvent());
+		} catch (ExecutionException e) {
+			System.out.println("------- exception on execute() ----------------"); //$NON-NLS-1$
+			e.printStackTrace();
+		}
+
+	}
+
+	/**
+	 * @param itr
+	 */
+	private void getReviewInfo(Iterator<?> itr) {
+		Object element = itr.next();
+		if (element == null) {
+			return;
+		}
+		FileInfo fileInfo;
+		if (fViewer instanceof TableViewer) {
+			fileInfo = ((StringToFileInfoImpl) element).getValue();
+		} else {
+			fileInfo = ((GerritDiffNode) element).getFileInfo();
+		}
+
+		// Fill the Data structure to show
+		IResource workspaceFile = ResourcesPlugin.getWorkspace().getRoot();
+		ExternalInfo.workspacePath = workspaceFile.getLocationURI().getRawPath();
+		ExternalInfo.filePath = fileInfo.getPath();
+		ExternalInfo.project = fileInfo.getRevision().getChangeInfo().getProject();
+		ExternalInfo.serverName = this.fGerritClient.getRepository().getHostname();
+		ExternalInfo.reviewCommit = fileInfo.getRevision().getId();
+		ExternalInfo.patchSet = fileInfo.getRevision().getRef();
+		ExternalInfo.serverPath = this.fGerritClient.getRepository().getServerInfo().getServerURI();
+
+	}
+}
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/table/provider/DynamicMenuBuilder.java b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/table/provider/DynamicMenuBuilder.java
index 8a5580d..2f367a6 100644
--- a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/table/provider/DynamicMenuBuilder.java
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/table/provider/DynamicMenuBuilder.java
@@ -17,6 +17,11 @@
 
 import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
 import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.egerrit.extensionpoint.definition.HandleExternalFileSelection;
 import org.eclipse.egerrit.internal.core.GerritClient;
 import org.eclipse.egerrit.internal.model.FileInfo;
 import org.eclipse.egerrit.internal.model.impl.StringToFileInfoImpl;
@@ -24,6 +29,7 @@
 import org.eclipse.egerrit.internal.ui.editors.ClearReviewedFlag;
 import org.eclipse.egerrit.internal.ui.table.model.ITableModel;
 import org.eclipse.egerrit.internal.ui.utils.Messages;
+import org.eclipse.egerrit.ui.extension.IExternalCmd;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.viewers.ColumnViewer;
 import org.eclipse.jface.viewers.TableViewer;
@@ -89,6 +95,14 @@
 				//Menu item: Show File name first
 				showFileNameFirstMenuItem(menu, viewer);
 			}
+
+			// Adding menu option for External point when available
+			boolean hasExtensionPoint = testEgerritExtensionpoint();
+			if (available && hasExtensionPoint) {
+
+				//Menu item: Open External file
+				openExternalFileMenuItem(menu, viewer, client);
+			}
 		}
 	}
 
@@ -190,4 +204,52 @@
 			}
 		});
 	}
+
+	/**
+	 * @param menu
+	 * @param viewer
+	 * @param client
+	 */
+	private void openExternalFileMenuItem(Menu menu, ColumnViewer viewer, GerritClient client) {
+		final MenuItem openFile = new MenuItem(menu, SWT.PUSH);
+		openFile.setText(Messages.UIFilesTable_4);
+		if (viewer instanceof TableViewer) {
+			tableLabelProvider = (FileTableLabelProvider) viewer.getLabelProvider();
+			openFile.setSelection(tableLabelProvider.getFileOrder());
+		}
+
+		openFile.addSelectionListener(new SelectionListener() {
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				HandleExternalFileSelection handleSelection = new HandleExternalFileSelection(client, viewer);//Open the workspace file from the context menu
+				handleSelection.showFileSelection();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+			}
+		});
+	}
+
+	private boolean testEgerritExtensionpoint() {
+		Boolean hasExtensionPoint = false;
+		String IEXTERNALCOMMAND_ID = "org.eclipse.egerrit.ui.extensionpoint.externalCmd"; //$NON-NLS-1$
+
+		IExtensionRegistry registry = Platform.getExtensionRegistry();
+
+		IConfigurationElement[] config = registry.getConfigurationElementsFor(IEXTERNALCOMMAND_ID);
+		try {
+			for (IConfigurationElement e : config) {
+				final Object o = e.createExecutableExtension("class"); //$NON-NLS-1$
+				if (o instanceof IExternalCmd) {
+					hasExtensionPoint = true;
+				}
+			}
+		} catch (CoreException ex) {
+			System.out.println(ex.getMessage());
+		}
+		return hasExtensionPoint;
+	}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/Messages.java b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/Messages.java
index d95747e..eea20b0 100644
--- a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/Messages.java
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/Messages.java
@@ -336,6 +336,8 @@
 
 	public static String UIFilesTable_3;
 
+	public static String UIFilesTable_4;
+
 	public static String UIFilesTable_clearReviewedFlag;
 
 	public static String UIUtils_EGerriTipShowAgain;
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/messages.properties b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/messages.properties
index f3c3aa2..ae13b89 100644
--- a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/messages.properties
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/internal/ui/utils/messages.properties
@@ -172,6 +172,7 @@
 UIFilesTable_1=Show File Names first
 UIFilesTable_2=The following file(s) could not be found in the workspace:
 UIFilesTable_3=File(s) not found
+UIFilesTable_4=External Option
 UIFilesTable_clearReviewedFlag=Clear all reviewed flags
 UIUtils_EGerriTipShowAgain=Don't show this message again
 UIUtils_EGerriTipRenameShowAgain=Don't prompt again\n\
diff --git a/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/ui/extension/IExternalCmd.java b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/ui/extension/IExternalCmd.java
new file mode 100644
index 0000000..41b3217
--- /dev/null
+++ b/org.eclipse.egerrit.ui/src/org/eclipse/egerrit/ui/extension/IExternalCmd.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Ericsson AB.
+ * 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:
+ *     Jacques Bouthillier - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.egerrit.ui.extension;
+
+/**
+ * Interface returning some of the current review information to be used in an external plug-in
+ */
+public interface IExternalCmd {
+
+	class ExternalInfo {
+		public static String workspacePath;
+
+		public static String filePath;
+
+		public static String project;
+
+		public static String serverPath;
+
+		public static String serverName;
+
+		public static String patchSet;
+
+		public static String reviewCommit;
+
+	};
+
+	// Method to be implemented from the Extension point plugin
+	public void cmd1();
+
+	// Implementing default methods
+	public default String getWorkspacePath() {
+		return ExternalInfo.workspacePath;
+	};
+
+	public default String getFilePath() {
+		return ExternalInfo.filePath;
+	};
+
+	public default String getProject() {
+		return ExternalInfo.project;
+	};
+
+	public default String getServerPath() {
+		return ExternalInfo.serverPath;
+	};
+
+	public default String getserverName() {
+		return ExternalInfo.serverName;
+	};
+
+	public default String getPatchSet() {
+		return ExternalInfo.patchSet;
+	};
+
+	public default String getReviewCommit() {
+		return ExternalInfo.reviewCommit;
+	};
+
+}