UI: make VCS add/edit dialog pluggable
diff --git a/core/plugins/org.eclipse.hawk.core/src/org/eclipse/hawk/core/IVcsManager.java b/core/plugins/org.eclipse.hawk.core/src/org/eclipse/hawk/core/IVcsManager.java
index ab7e8db..400a991 100644
--- a/core/plugins/org.eclipse.hawk.core/src/org/eclipse/hawk/core/IVcsManager.java
+++ b/core/plugins/org.eclipse.hawk.core/src/org/eclipse/hawk/core/IVcsManager.java
@@ -160,4 +160,11 @@
 		return Category.VCS_MANAGER;
 	}
 
+	/**
+	 * Returns a sample URL, to use as the initial value in the VCS configuration dialog.
+	 */
+	default String getDefaultLocation() {
+		return "";
+	}
+
 }
diff --git a/core/plugins/org.eclipse.hawk.http/src/org/eclipse/hawk/http/HTTPManager.java b/core/plugins/org.eclipse.hawk.http/src/org/eclipse/hawk/http/HTTPManager.java
index 49e47c7..f605410 100644
--- a/core/plugins/org.eclipse.hawk.http/src/org/eclipse/hawk/http/HTTPManager.java
+++ b/core/plugins/org.eclipse.hawk.http/src/org/eclipse/hawk/http/HTTPManager.java
@@ -335,4 +335,9 @@
 	public void setFrozen(boolean f) {
 		isFrozen = f;
 	}
+
+	@Override
+	public String getDefaultLocation() {
+		return "http://host:port/path";
+	}
 }
diff --git a/core/plugins/org.eclipse.hawk.jgit/src/org/eclipse/hawk/git/JGitRepository.java b/core/plugins/org.eclipse.hawk.jgit/src/org/eclipse/hawk/git/JGitRepository.java
index aad09eb..db979c3 100644
--- a/core/plugins/org.eclipse.hawk.jgit/src/org/eclipse/hawk/git/JGitRepository.java
+++ b/core/plugins/org.eclipse.hawk.jgit/src/org/eclipse/hawk/git/JGitRepository.java
@@ -87,7 +87,7 @@
 		}

 

 	}

-	

+

 	/**

 	 * Thrown if a delta is requested for revisions that do not belong to the same ancestry.

 	 */

@@ -514,5 +514,10 @@
 

 		return commit;

 	}

+

+	@Override

+	public String getDefaultLocation() {

+		return "file://path/to/gitrepo?branch=BRANCH";

+	}

 	

 }

diff --git a/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFile.java b/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFile.java
index 558df11..43b94f3 100644
--- a/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFile.java
+++ b/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFile.java
@@ -127,4 +127,9 @@
 

 		return delta;

 	}

+

+	@Override

+	public String getDefaultLocation() {

+		return "file://path/to/file";

+	}

 }

diff --git a/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFolder.java b/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFolder.java
index 13b4ada..1458b00 100644
--- a/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFolder.java
+++ b/core/plugins/org.eclipse.hawk.localfolder/src/org/eclipse/hawk/localfolder/LocalFolder.java
@@ -302,4 +302,9 @@
 	private boolean isFileInteresting(File f) {

 		return fileFilter == null || fileFilter.apply(f);

 	}

+

+	@Override

+	public String getDefaultLocation() {

+		return "file://path/to/folder";

+	}

 }

diff --git a/core/plugins/org.eclipse.hawk.svn/src/org/eclipse/hawk/svn/SvnManager.java b/core/plugins/org.eclipse.hawk.svn/src/org/eclipse/hawk/svn/SvnManager.java
index 8b915a6..e91a32a 100644
--- a/core/plugins/org.eclipse.hawk.svn/src/org/eclipse/hawk/svn/SvnManager.java
+++ b/core/plugins/org.eclipse.hawk.svn/src/org/eclipse/hawk/svn/SvnManager.java
@@ -328,4 +328,9 @@
 	public void setFrozen(boolean f) {
 		isFrozen = f;
 	}
+
+	@Override
+	public String getDefaultLocation() {
+		return "svn://";
+	}
 }
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/.classpath b/core/plugins/org.eclipse.hawk.ui.localfolder/.classpath
new file mode 100644
index 0000000..c4b0fff
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+		<attributes>
+			<attribute name="module" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/.project b/core/plugins/org.eclipse.hawk.ui.localfolder/.project
new file mode 100644
index 0000000..3d9f8b3
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.hawk.ui.localfolder</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/.settings/org.eclipse.jdt.core.prefs b/core/plugins/org.eclipse.hawk.ui.localfolder/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..a58ebdc
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/META-INF/MANIFEST.MF b/core/plugins/org.eclipse.hawk.ui.localfolder/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..c118a85
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Hawk Local Folder UI components
+Bundle-SymbolicName: org.eclipse.hawk.ui.localfolder;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Vendor: Eclipse.org
+Automatic-Module-Name: org.eclipse.hawk.ui.localfolder
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.hawk.core;bundle-version="2.0.0",
+ org.eclipse.hawk.osgiserver;bundle-version="2.0.0",
+ org.eclipse.hawk.localfolder;bundle-version="2.0.0",
+ org.eclipse.hawk.ui2;bundle-version="2.0.0",
+ org.eclipse.core.resources;bundle-version="3.0.0",
+ org.eclipse.core.runtime;bundle-version="3.0.0",
+ org.eclipse.jface;bundle-version="3.14.0",
+ org.eclipse.swt
+Require-Bundle: org.eclipse.hawk.core;bundle-version="2.0.0",
+ org.eclipse.hawk.osgiserver;bundle-version="2.0.0",
+ org.eclipse.hawk.localfolder;bundle-version="2.0.0",
+ org.eclipse.hawk.ui2;bundle-version="2.0.0",
+ org.eclipse.core.resources;bundle-version="3.13.0",
+ org.eclipse.core.runtime;bundle-version="3.14.0",
+ org.eclipse.swt;bundle-version="3.107.0",
+ org.eclipse.jface;bundle-version="3.14.0"
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/build.properties b/core/plugins/org.eclipse.hawk.ui.localfolder/build.properties
new file mode 100644
index 0000000..e9863e2
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/plugin.xml b/core/plugins/org.eclipse.hawk.ui.localfolder/plugin.xml
new file mode 100644
index 0000000..3333b1b
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.hawk.ui.vcsConfigBlock">
+      <configBlock
+            class="org.eclipse.hawk.ui.localfolder.LocalFileConfigurationBlock">
+      </configBlock>
+   </extension>
+
+</plugin>
diff --git a/core/plugins/org.eclipse.hawk.ui.localfolder/src/org/eclipse/hawk/ui/localfolder/LocalFileConfigurationBlock.java b/core/plugins/org.eclipse.hawk.ui.localfolder/src/org/eclipse/hawk/ui/localfolder/LocalFileConfigurationBlock.java
new file mode 100644
index 0000000..3cbfaec
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.localfolder/src/org/eclipse/hawk/ui/localfolder/LocalFileConfigurationBlock.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Aston University.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
+ *
+ * Contributors:
+ *    Antonio Garcia-Dominguez - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.hawk.ui.localfolder;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.hawk.core.IVcsManager;
+import org.eclipse.hawk.localfolder.LocalFile;
+import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.dialog.HVCSDialog;
+import org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+public class LocalFileConfigurationBlock implements IVcsConfigurationBlock {
+
+	private HVCSDialog dialog;
+	private Text txtVCSLocation;
+	private Button btnVCSBrowse;
+
+	@Override
+	public boolean isApplicableTo(IVcsManager manager) {
+		return manager instanceof LocalFile;
+	}
+
+	@Override
+	public void createBlock(Composite container, HVCSDialog dialog) {
+		this.dialog = dialog;
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+
+		final GridLayout containerLayout = new GridLayout();
+		containerLayout.numColumns = 3;
+		container.setLayout(containerLayout);
+
+		// Location + browse
+		final Label lblLocation = new Label(container, SWT.NONE);
+		lblLocation.setText("Location:");
+		txtVCSLocation = new Text(container, SWT.BORDER);
+		final GridData txtVCSLocationLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		txtVCSLocationLayoutData.widthHint = 300;
+		txtVCSLocation.setLayoutData(txtVCSLocationLayoutData);
+		if (managerToEdit != null) {
+			txtVCSLocation.setText(managerToEdit.getLocation());
+			txtVCSLocation.setEnabled(false);
+		} else {
+			txtVCSLocation.setText(dialog.getSelectedVCSManager().getDefaultLocation());
+		}
+		txtVCSLocation.addModifyListener(e -> updateDialog());
+
+		btnVCSBrowse = new Button(container, SWT.PUSH);
+		GridData gridDataB = new GridData();
+		btnVCSBrowse.setLayoutData(gridDataB);
+		btnVCSBrowse.setText("Browse...");
+		btnVCSBrowse.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				FileDialog fd = new FileDialog(container.getShell(), SWT.OPEN);
+				fd.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile().toString());
+				fd.setText("Select a file");
+				String result = fd.open();
+				if (result != null) {
+					txtVCSLocation.setText(new File(result).toURI().toString());
+				}
+			}
+		});
+		btnVCSBrowse.setEnabled(false);
+
+		updateDialog();
+	}
+
+	@Override
+	public void okPressed(HModel hawkModel, boolean isFrozen) {
+		final String vcsType = dialog.getSelectedVCSManager().getClass().getName();
+		final String location = txtVCSLocation.getText();
+
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+		if (managerToEdit == null) {
+			hawkModel.addVCS(location, vcsType, "", "", isFrozen);
+		} else {
+			managerToEdit.setFrozen(isFrozen);
+		}
+	}
+
+	private void updateDialog() {
+		if (dialog.getManagerToEdit() == null) {
+			final IVcsManager vcsManager = dialog.getSelectedVCSManager();
+			btnVCSBrowse.setEnabled(vcsManager != null && vcsManager.isPathLocationAccepted());
+		}
+
+		if (!isLocationValid()) {
+			dialog.setErrorMessage("The location is not valid");
+		} else if (dialog.getSelectedVCSManager() == null) {
+			dialog.setErrorMessage("No VCS manager type has been selected");
+		} else {
+			dialog.setErrorMessage(null);
+		}
+	}
+
+	private boolean isLocationValidPath() {
+		File file = new File(txtVCSLocation.getText());
+		if (file.exists() && file.isFile() && file.canRead())
+			return true;
+		return false;
+	}
+
+	private boolean isLocationValid() {
+		IVcsManager vcsManager = dialog.getSelectedVCSManager();
+		return vcsManager.isPathLocationAccepted() && isLocationValidPath()
+				|| vcsManager.isURLLocationAccepted() && isLocationValidURI();
+	}
+
+	private boolean isLocationValidURI() {
+		try {
+			URI uri = new URI(txtVCSLocation.getText());
+			return uri.getScheme() != null && uri.getPath() != null;
+		} catch (URISyntaxException e) {
+			return false;
+		}
+	}
+
+}
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/.classpath b/core/plugins/org.eclipse.hawk.ui.uml/.classpath
new file mode 100644
index 0000000..e801ebf
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/.project b/core/plugins/org.eclipse.hawk.ui.uml/.project
new file mode 100644
index 0000000..049ad7d
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.hawk.ui.uml</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/.settings/org.eclipse.jdt.core.prefs b/core/plugins/org.eclipse.hawk.ui.uml/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..c9545f0
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/META-INF/MANIFEST.MF b/core/plugins/org.eclipse.hawk.ui.uml/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..2084ebf
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Hawk UML UI Components
+Bundle-SymbolicName: org.eclipse.hawk.ui.uml;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Vendor: Eclipse.org
+Automatic-Module-Name: org.eclipse.hawk.ui.uml
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.hawk.core;bundle-version="2.0.0",
+ org.eclipse.hawk.ui2;bundle-version="2.0.0",
+ org.eclipse.hawk.uml;bundle-version="2.0.0",
+ org.eclipse.hawk.osgiserver;bundle-version="2.0.0",
+ org.eclipse.swt
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/build.properties b/core/plugins/org.eclipse.hawk.ui.uml/build.properties
new file mode 100644
index 0000000..e9863e2
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/plugin.xml b/core/plugins/org.eclipse.hawk.ui.uml/plugin.xml
new file mode 100644
index 0000000..f778a21
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.hawk.ui.vcsConfigBlock">
+      <configBlock
+            class="org.eclipse.hawk.ui.uml.UMLConfigurationBlock">
+      </configBlock>
+   </extension>
+
+</plugin>
diff --git a/core/plugins/org.eclipse.hawk.ui.uml/src/org/eclipse/hawk/ui/uml/UMLConfigurationBlock.java b/core/plugins/org.eclipse.hawk.ui.uml/src/org/eclipse/hawk/ui/uml/UMLConfigurationBlock.java
new file mode 100644
index 0000000..e748e6f
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.uml/src/org/eclipse/hawk/ui/uml/UMLConfigurationBlock.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Aston University.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
+ *
+ * Contributors:
+ *    Antonio Garcia-Dominguez - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.hawk.ui.uml;
+
+import org.eclipse.hawk.core.IVcsManager;
+import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.dialog.HVCSDialog;
+import org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock;
+import org.eclipse.hawk.uml.vcs.PredefinedUMLLibraries;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class UMLConfigurationBlock implements IVcsConfigurationBlock {
+
+	private HVCSDialog dialog;
+
+	@Override
+	public boolean isApplicableTo(IVcsManager manager) {
+		return manager instanceof PredefinedUMLLibraries;
+	}
+
+	@Override
+	public void createBlock(Composite container, HVCSDialog dialog) {
+		this.dialog = dialog;
+
+		container.setLayout(new FillLayout());
+		Label label = new Label(container, SWT.NONE);
+		label.setText("No options to configure.");
+	}
+
+	@Override
+	public void okPressed(HModel hawkModel, boolean isFrozen) {
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+		if (managerToEdit == null) {
+			final String vcsType = dialog.getSelectedVCSManager().getClass().getName();
+			hawkModel.addVCS("unused", vcsType, "", "", isFrozen);
+		} else {
+			managerToEdit.setFrozen(isFrozen);
+		}
+	}
+
+}
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/.classpath b/core/plugins/org.eclipse.hawk.ui.workspace/.classpath
new file mode 100644
index 0000000..e801ebf
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/.project b/core/plugins/org.eclipse.hawk.ui.workspace/.project
new file mode 100644
index 0000000..169803d
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.hawk.ui.workspace</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/.settings/org.eclipse.jdt.core.prefs b/core/plugins/org.eclipse.hawk.ui.workspace/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..c9545f0
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/META-INF/MANIFEST.MF b/core/plugins/org.eclipse.hawk.ui.workspace/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b528ab8
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Hawk Workspace UI components
+Bundle-SymbolicName: org.eclipse.hawk.ui.workspace;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Vendor: Eclipse.org
+Automatic-Module-Name: org.eclipse.hawk.ui.workspace
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.hawk.core;bundle-version="2.0.0",
+ org.eclipse.hawk.ui2;bundle-version="2.0.0",
+ org.eclipse.hawk.workspace;bundle-version="2.0.0",
+ org.eclipse.hawk.osgiserver;bundle-version="2.0.0",
+ org.eclipse.swt
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/build.properties b/core/plugins/org.eclipse.hawk.ui.workspace/build.properties
new file mode 100644
index 0000000..e9863e2
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/plugin.xml b/core/plugins/org.eclipse.hawk.ui.workspace/plugin.xml
new file mode 100644
index 0000000..2a11b98
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.hawk.ui.vcsConfigBlock">
+      <configBlock
+            class="org.eclipse.hawk.ui.workspace.WorkspaceConfigurationBlock">
+      </configBlock>
+   </extension>
+
+</plugin>
diff --git a/core/plugins/org.eclipse.hawk.ui.workspace/src/org/eclipse/hawk/ui/workspace/WorkspaceConfigurationBlock.java b/core/plugins/org.eclipse.hawk.ui.workspace/src/org/eclipse/hawk/ui/workspace/WorkspaceConfigurationBlock.java
new file mode 100644
index 0000000..4e44886
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui.workspace/src/org/eclipse/hawk/ui/workspace/WorkspaceConfigurationBlock.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Aston University.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
+ *
+ * Contributors:
+ *    Antonio Garcia-Dominguez - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.hawk.ui.workspace;
+
+import org.eclipse.hawk.core.IVcsManager;
+import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.dialog.HVCSDialog;
+import org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock;
+import org.eclipse.hawk.workspace.Workspace;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class WorkspaceConfigurationBlock implements IVcsConfigurationBlock {
+
+	private HVCSDialog dialog;
+
+	@Override
+	public boolean isApplicableTo(IVcsManager manager) {
+		return manager instanceof Workspace;
+	}
+
+	@Override
+	public void createBlock(Composite container, HVCSDialog dialog) {
+		this.dialog = dialog;
+
+		container.setLayout(new FillLayout());
+		Label label = new Label(container, SWT.NONE);
+		label.setText("No options to configure.");
+	}
+
+	@Override
+	public void okPressed(HModel hawkModel, boolean isFrozen) {
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+		if (managerToEdit == null) {
+			final String vcsType = dialog.getSelectedVCSManager().getClass().getName();
+			hawkModel.addVCS(Workspace.REPOSITORY_URL, vcsType, "", "", isFrozen);
+		} else {
+			managerToEdit.setFrozen(isFrozen);
+		}
+	}
+
+}
diff --git a/core/plugins/org.eclipse.hawk.ui2/META-INF/MANIFEST.MF b/core/plugins/org.eclipse.hawk.ui2/META-INF/MANIFEST.MF
index 0e10d4a..413e7d0 100644
--- a/core/plugins/org.eclipse.hawk.ui2/META-INF/MANIFEST.MF
+++ b/core/plugins/org.eclipse.hawk.ui2/META-INF/MANIFEST.MF
@@ -20,6 +20,7 @@
  org.eclipse.hawk.ui2.mmselectors,
  org.eclipse.hawk.ui2.preferences,
  org.eclipse.hawk.ui2.util,
+ org.eclipse.hawk.ui2.vcs,
  org.eclipse.hawk.ui2.view,
  org.eclipse.hawk.ui2.wizard
 Bundle-Vendor: Eclipse.org
diff --git a/core/plugins/org.eclipse.hawk.ui2/plugin.xml b/core/plugins/org.eclipse.hawk.ui2/plugin.xml
index d560dbd..84f884d 100644
--- a/core/plugins/org.eclipse.hawk.ui2/plugin.xml
+++ b/core/plugins/org.eclipse.hawk.ui2/plugin.xml
@@ -2,6 +2,7 @@
 <?eclipse version="3.4"?>
 <plugin>
    <extension-point id="org.eclipse.hawk.ui.metamodelSelector" name="Metamodel Selector" schema="schema/org.eclipse.hawk.ui.metamodelSelector.exsd"/>
+   <extension-point id="org.eclipse.hawk.ui.vcsConfigBlock" name="VCS Configuration Block" schema="schema/org.eclipse.hawk.ui.vcsConfigBlock.exsd"/>
 
    <extension
          point="org.eclipse.ui.newWizards">
diff --git a/core/plugins/org.eclipse.hawk.ui2/schema/org.eclipse.hawk.ui.vcsConfigBlock.exsd b/core/plugins/org.eclipse.hawk.ui2/schema/org.eclipse.hawk.ui.vcsConfigBlock.exsd
new file mode 100644
index 0000000..d9b0dfd
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui2/schema/org.eclipse.hawk.ui.vcsConfigBlock.exsd
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.hawk.ui2" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.hawk.ui2" id="org.eclipse.hawk.ui.vcsConfigBlock" name="VCS Configuration Block"/>
+      </appinfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="configBlock"/>
+         </sequence>
+         <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="configBlock">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         2.0.0
+      </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/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/Activator.java b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/Activator.java
index ddd552a..654c248 100644
--- a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/Activator.java
+++ b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/Activator.java
@@ -17,9 +17,16 @@
  ******************************************************************************/
 package org.eclipse.hawk.ui2;
 
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.mmselectors.IHawkMetaModelResourceSelector;
 import org.eclipse.hawk.ui2.util.EclipseLogConsole;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
@@ -96,4 +103,5 @@
 		final String bundleName = FrameworkUtil.getBundle(Activator.class).getSymbolicName();
 		getDefault().getLog().log(new Status(IStatus.ERROR, bundleName, msg, t));
 	}
+
 }
diff --git a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HConfigDialog.java b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HConfigDialog.java
index 559f0c6..c376d4c 100644
--- a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HConfigDialog.java
+++ b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HConfigDialog.java
@@ -18,7 +18,6 @@
  ******************************************************************************/

 package org.eclipse.hawk.ui2.dialog;

 

-import java.awt.FlowLayout;

 import java.util.ArrayList;

 import java.util.Collections;

 import java.util.Map;

diff --git a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HVCSDialog.java b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HVCSDialog.java
index 582dee1..52139b6 100644
--- a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HVCSDialog.java
+++ b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/dialog/HVCSDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015 The University of York.
+ * Copyright (c) 2015-2020 The University of York, Aston University.
  * 
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License 2.0 which is available at
@@ -16,23 +16,25 @@
  ******************************************************************************/
 package org.eclipse.hawk.ui2.dialog;
 
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
-import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.hawk.core.IVcsManager;
 import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.Activator;
 import org.eclipse.hawk.ui2.dialog.HConfigDialog.VCSLabelProvider;
+import org.eclipse.hawk.ui2.vcs.DefaultVcsConfigurationBlock;
+import org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.TitleAreaDialog;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.ComboViewer;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.GridData;
@@ -40,34 +42,33 @@
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.DirectoryDialog;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
 
-final class HVCSDialog extends TitleAreaDialog {
-	private final class UpdateDialogModifyListener implements ModifyListener {
-		@Override
-		public void modifyText(ModifyEvent e) {
-			updateDialog();
-		}
-	}
+public class HVCSDialog extends TitleAreaDialog {
 
 	private final IVcsManager managerToEdit;
 	private final HModel hawkModel;
+
 	private Button freeze;
 	private ComboViewer cmbVCSType;
-	private Text txtVCSLocation;
-	private Button btnVCSBrowse;
-	private Text txtUser;
-	private Text txtPass;
 	private List<IVcsManager> availableVCS;
 
+	private Composite cmpConfiguration;
+	private IVcsConfigurationBlock configBlock;
+
 	public HVCSDialog(Shell parentShell, HModel hawkModel, IVcsManager managerToEdit) {
 		super(parentShell);
 		this.hawkModel = hawkModel;
 		this.managerToEdit = managerToEdit;
+
 		this.availableVCS = hawkModel.getVCSInstances();
+		Collections.sort(availableVCS, new Comparator<IVcsManager>() {
+			@Override
+			public int compare(IVcsManager o1, IVcsManager o2) {
+				return o1.getHumanReadableName().compareTo(o2.getHumanReadableName());
+			}
+		});
 	}
 
 	@Override
@@ -75,8 +76,7 @@
 		super.create();
 		if (managerToEdit == null) {
 			setTitle("Add repository");
-			setMessage(
-					"Select the repository type, enter the location and optionally enter the authentication credentials.");
+			setMessage("Select the repository type and configure its options.");
 		} else {
 			setTitle("Edit repository");
 			setMessage("Change the authentication credentials.");
@@ -84,13 +84,6 @@
 	}
 
 	@Override
-	protected Control createContents(Composite parent) {
-		final Control contents = super.createContents(parent);
-		updateDialog();
-		return contents;
-	}
-
-	@Override
 	protected Control createDialogArea(Composite parent) {
 		final Composite area = (Composite) super.createDialogArea(parent);
 		final Composite container = new Composite(area, SWT.NONE);
@@ -107,12 +100,34 @@
 		cmbVCSType.setContentProvider(new ArrayContentProvider());
 		
 		cmbVCSType.setInput(availableVCS.toArray());
+
 		final GridData cmbVCSTypeLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
 		cmbVCSTypeLayoutData.horizontalSpan = 2;
 		cmbVCSType.getCombo().setLayoutData(cmbVCSTypeLayoutData);
+		cmbVCSType.getCombo().addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				updateConfigurationBlock();
+			}
+		});
+
+		final Label lblFreeze = new Label(container, SWT.NONE);
+		lblFreeze.setText("Freeze repo:");
+		freeze = new Button(container, SWT.CHECK);
+		boolean isFrozen = managerToEdit == null ? false : managerToEdit.isFrozen();
+		freeze.setSelection(isFrozen);
+		if (managerToEdit == null) {
+			freeze.setEnabled(false);
+		}
+
+		// Placeholder container for the VCS configuration block
+		cmpConfiguration = new Composite(container, SWT.FILL | SWT.BORDER);
+		final GridData cmpConfigurationLD = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		cmpConfigurationLD.horizontalSpan = 3;
+		cmpConfiguration.setLayoutData(cmpConfigurationLD);
+
 		if (managerToEdit != null) {
 			final String managerType = managerToEdit.getType();
-
 			int i = 0;
 			for (IVcsManager kind : availableVCS) {
 				final String availableType = kind.getType();
@@ -126,128 +141,24 @@
 		} else {
 			cmbVCSType.getCombo().select(0);
 		}
-		cmbVCSType.getCombo().addSelectionListener(new SelectionAdapter() {
-			public void widgetSelected(SelectionEvent e) {
-				txtVCSLocation.setText("");
-				updateDialog();
-			}
-		});
-
-		// Location + browse
-		final Label lblLocation = new Label(container, SWT.NONE);
-		lblLocation.setText("Location:");
-		txtVCSLocation = new Text(container, SWT.BORDER);
-		final GridData txtVCSLocationLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
-		txtVCSLocationLayoutData.widthHint = 300;
-		txtVCSLocation.setLayoutData(txtVCSLocationLayoutData);
-		if (managerToEdit != null) {
-			txtVCSLocation.setText(managerToEdit.getLocation());
-			txtVCSLocation.setEnabled(false);
-		}
-		txtVCSLocation.addModifyListener(new ModifyListener() {
-			public void modifyText(ModifyEvent e) {
-				updateDialog();
-			}
-		});
-
-		btnVCSBrowse = new Button(container, SWT.PUSH);
-		GridData gridDataB = new GridData();
-		btnVCSBrowse.setLayoutData(gridDataB);
-		btnVCSBrowse.setText("Browse...");
-		btnVCSBrowse.addSelectionListener(new SelectionAdapter() {
-			@Override
-			public void widgetSelected(SelectionEvent e) {
-				DirectoryDialog dd = new DirectoryDialog(getShell(), SWT.OPEN);
-
-				dd.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile().toString());
-				dd.setMessage("Select a folder to add to the indexer");
-				dd.setText("Select a directory");
-				String result = dd.open();
-
-				if (result != null) {
-					txtVCSLocation.setText(new File(result).toURI().toString());
-				}
-			}
-		});
-		btnVCSBrowse.setEnabled(false);
-
-		String usernameToEdit = null;
-		String passwordToEdit = null;
-		if (managerToEdit != null) {
-			usernameToEdit = managerToEdit.getUsername();
-			passwordToEdit = managerToEdit.getPassword();
-		}
-
-		final Label lblUser = new Label(container, SWT.NONE);
-		lblUser.setText("User (optional):");
-		txtUser = new Text(container, SWT.BORDER | SWT.SINGLE);
-		final GridData txtUserLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
-		txtUserLayoutData.horizontalSpan = 2;
-		txtUser.setLayoutData(txtUserLayoutData);
-		if (usernameToEdit != null) {
-			txtUser.setText(usernameToEdit);
-		}
-		txtUser.addModifyListener(new UpdateDialogModifyListener());
-
-		final Label lblPass = new Label(container, SWT.NONE);
-		lblPass.setText("Pass (optional):");
-		txtPass = new Text(container, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD);
-		final GridData txtPassLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
-		txtPassLayoutData.horizontalSpan = 2;
-		txtPass.setLayoutData(txtPassLayoutData);
-		if (passwordToEdit != null) {
-			txtPass.setText(passwordToEdit);
-		}
-		txtPass.addModifyListener(new UpdateDialogModifyListener());
-
-		final Label lblFreeze = new Label(container, SWT.NONE);
-		lblFreeze.setText("Freeze repo:");
-
-		freeze = new Button(container, SWT.CHECK);
-		boolean isFrozen = managerToEdit == null ? false : managerToEdit.isFrozen();
-		freeze.setSelection(isFrozen);
-
-		if (managerToEdit == null)
-			freeze.setEnabled(false);
+		updateConfigurationBlock();
 
 		return container;
 	}
 
-	private boolean isAuthSupported() {
-		final IVcsManager vcsManager = getSelectedVCSManager();
-		return vcsManager != null && vcsManager.isAuthSupported();
+	public IVcsManager getManagerToEdit() {
+		return managerToEdit;
 	}
 
-	private IVcsManager getSelectedVCSManager() {
-		final IStructuredSelection selection = (IStructuredSelection) cmbVCSType.getSelection();
-		return (IVcsManager) selection.getFirstElement();
-	}
-
-	private boolean isLocationValid() {
-		IVcsManager vcsManager = getSelectedVCSManager();
-		return vcsManager.isPathLocationAccepted() && isLocationValidPath()
-				|| vcsManager.isURLLocationAccepted() && isLocationValidURI();
-	}
-
-	private void updateDialog() {
-		final boolean authEnabled = isAuthSupported() && isLocationValid();
-		txtUser.setEnabled(authEnabled);
-		txtPass.setEnabled(authEnabled);
-
-		if (managerToEdit == null) {
-			final IVcsManager vcsManager = getSelectedVCSManager();
-			btnVCSBrowse.setEnabled(vcsManager != null && vcsManager.isPathLocationAccepted());
+	private void updateConfigurationBlock() {
+		for (Control child : cmpConfiguration.getChildren()) {
+			child.dispose();
 		}
+		setErrorMessage(null);
 
-		if (!isLocationValid()) {
-			setErrorMessage("The location is not valid");
-		} else if (getSelectedVCSManager() == null) {
-			setErrorMessage("No VCS manager type has been selected");
-		} else if ("".equals(txtUser.getText()) != "".equals(txtPass.getText())) {
-			setErrorMessage("The username and password must be empty or not empty at the same time");
-		} else {
-			setErrorMessage(null);
-		}
+		configBlock = getConfigurationBlockFor(getSelectedVCSManager());
+		configBlock.createBlock(cmpConfiguration, HVCSDialog.this);
+		cmpConfiguration.requestLayout();
 	}
 
 	@Override
@@ -258,37 +169,30 @@
 		super.setErrorMessage(newErrorMessage);
 	}
 
-	private boolean isLocationValidPath() {
-		File dir = new File(txtVCSLocation.getText());
-		if (!isAuthSupported() && dir.exists() && dir.isDirectory() && dir.canRead())
-			return true;
-		return false;
-	}
-
-	private boolean isLocationValidURI() {
-		try {
-			URI uri = new URI(txtVCSLocation.getText());
-			return uri.getScheme() != null && uri.getPath() != null;
-		} catch (URISyntaxException e) {
-			return false;
-		}
+	public IVcsManager getSelectedVCSManager() {
+		final IStructuredSelection selection = (IStructuredSelection) cmbVCSType.getSelection();
+		return (IVcsManager) selection.getFirstElement();
 	}
 
 	@Override
 	protected void okPressed() {
-
-		final String vcsType = getSelectedVCSManager().getClass().getName();
-		final String location = txtVCSLocation.getText();
-		final String user = txtUser.getText();
-		final String pass = txtPass.getText();
-
-		if (managerToEdit == null) {
-			hawkModel.addVCS(location, vcsType, user, pass, freeze.getSelection());
-		} else {
-			managerToEdit.setCredentials(user, pass, hawkModel.getManager().getCredentialsStore());
-			managerToEdit.setFrozen(freeze.getSelection());
-		}
+		configBlock.okPressed(hawkModel, freeze.getSelection());
 		super.okPressed();
 	}
 
+	private IVcsConfigurationBlock getConfigurationBlockFor(IVcsManager manager) {
+		for (IConfigurationElement e : Platform.getExtensionRegistry().getConfigurationElementsFor(IVcsConfigurationBlock.EXT_ID)) {
+			try {
+				IVcsConfigurationBlock selector = (IVcsConfigurationBlock) e.createExecutableExtension(IVcsConfigurationBlock.EXT_ATTR_CLASS);
+				if (selector.isApplicableTo(manager)) {
+					return selector;
+				}
+			} catch (CoreException ex) {
+				Activator.logError("Could not create the config block for " + manager.getHumanReadableName(), ex);
+			}
+		}
+
+		return new DefaultVcsConfigurationBlock();
+	}
+
 }
\ No newline at end of file
diff --git a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/DefaultVcsConfigurationBlock.java b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/DefaultVcsConfigurationBlock.java
new file mode 100644
index 0000000..196a03d
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/DefaultVcsConfigurationBlock.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2020 University of York, Aston University.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
+ *
+ * Contributors:
+ *    Antonio Garcia-Dominguez - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.hawk.ui2.vcs;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.hawk.core.IVcsManager;
+import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.dialog.HVCSDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Fallback implementation of {@link IVcsConfigurationBlock} in case there is no
+ * dedicated implementation for a certain type of {@link IVcsManager}.
+ */
+public class DefaultVcsConfigurationBlock implements IVcsConfigurationBlock {
+
+	private HVCSDialog dialog;
+	private Text txtVCSLocation;
+	private Button btnVCSBrowse;
+	private Text txtUser;
+	private Text txtPass;
+
+	@Override
+	public boolean isApplicableTo(IVcsManager manager) {
+		return true;
+	}
+
+	@Override
+	public void createBlock(Composite container, HVCSDialog dialog) {
+		this.dialog = dialog;
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+
+		final GridLayout containerLayout = new GridLayout();
+		containerLayout.numColumns = 3;
+		container.setLayout(containerLayout);
+
+		// Location + browse
+		final Label lblLocation = new Label(container, SWT.NONE);
+		lblLocation.setText("Location:");
+		txtVCSLocation = new Text(container, SWT.BORDER);
+		final GridData txtVCSLocationLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		txtVCSLocationLayoutData.widthHint = 300;
+		txtVCSLocation.setLayoutData(txtVCSLocationLayoutData);
+		if (managerToEdit != null) {
+			txtVCSLocation.setText(managerToEdit.getLocation());
+			txtVCSLocation.setEnabled(false);
+		} else {
+			txtVCSLocation.setText(dialog.getSelectedVCSManager().getDefaultLocation());
+		}
+		txtVCSLocation.addModifyListener(e -> updateDialog());
+
+		btnVCSBrowse = new Button(container, SWT.PUSH);
+		GridData gridDataB = new GridData();
+		btnVCSBrowse.setLayoutData(gridDataB);
+		btnVCSBrowse.setText("Browse...");
+		btnVCSBrowse.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				DirectoryDialog dd = new DirectoryDialog(container.getShell(), SWT.OPEN);
+
+				dd.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile().toString());
+				dd.setMessage("Select a folder to add to the indexer");
+				dd.setText("Select a directory");
+				String result = dd.open();
+
+				if (result != null) {
+					txtVCSLocation.setText(new File(result).toURI().toString());
+				}
+			}
+		});
+		btnVCSBrowse.setEnabled(false);
+
+		String usernameToEdit = null;
+		String passwordToEdit = null;
+		if (managerToEdit != null) {
+			usernameToEdit = managerToEdit.getUsername();
+			passwordToEdit = managerToEdit.getPassword();
+		}
+
+		if (isAuthSupported()) {
+			final Label lblUser = new Label(container, SWT.NONE);
+			lblUser.setText("User (optional):");
+			txtUser = new Text(container, SWT.BORDER | SWT.SINGLE);
+			final GridData txtUserLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+			txtUserLayoutData.horizontalSpan = 2;
+			txtUser.setLayoutData(txtUserLayoutData);
+			if (usernameToEdit != null) {
+				txtUser.setText(usernameToEdit);
+			}
+			txtUser.addModifyListener(e -> updateDialog());
+
+			final Label lblPass = new Label(container, SWT.NONE);
+			lblPass.setText("Pass (optional):");
+			txtPass = new Text(container, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD);
+			final GridData txtPassLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+			txtPassLayoutData.horizontalSpan = 2;
+			txtPass.setLayoutData(txtPassLayoutData);
+			if (passwordToEdit != null) {
+				txtPass.setText(passwordToEdit);
+			}
+			txtPass.addModifyListener(e -> updateDialog());
+		}
+
+		updateDialog();
+	}
+
+	@Override
+	public void okPressed(HModel hawkModel, boolean isFrozen) {
+		final String vcsType = dialog.getSelectedVCSManager().getClass().getName();
+		final String location = txtVCSLocation.getText();
+		final String user = txtUser == null ? "" : txtUser.getText();
+		final String pass = txtPass == null ? "" : txtPass.getText();
+
+		final IVcsManager managerToEdit = dialog.getManagerToEdit();
+		if (managerToEdit == null) {
+			hawkModel.addVCS(location, vcsType, user, pass, isFrozen);
+		} else {
+			managerToEdit.setCredentials(user, pass, hawkModel.getManager().getCredentialsStore());
+			managerToEdit.setFrozen(isFrozen);
+		}
+	}
+
+	private void updateDialog() {
+		if (isAuthSupported()) {
+			final boolean authEnabled = isLocationValid();
+			txtUser.setEnabled(authEnabled);
+			txtPass.setEnabled(authEnabled);
+
+			if ("".equals(txtUser.getText()) != "".equals(txtPass.getText())) {
+				dialog.setErrorMessage("The username and password must be empty or not empty at the same time");
+			}
+		}
+
+		if (dialog.getManagerToEdit() == null) {
+			final IVcsManager vcsManager = dialog.getSelectedVCSManager();
+			btnVCSBrowse.setEnabled(vcsManager != null && vcsManager.isPathLocationAccepted());
+		}
+
+		if (!isLocationValid()) {
+			dialog.setErrorMessage("The location is not valid");
+		} else if (dialog.getSelectedVCSManager() == null) {
+			dialog.setErrorMessage("No VCS manager type has been selected");
+		} else {
+			dialog.setErrorMessage(null);
+		}
+	}
+
+	private boolean isLocationValidPath() {
+		File dir = new File(txtVCSLocation.getText());
+		if (!isAuthSupported() && dir.exists() && dir.isDirectory() && dir.canRead())
+			return true;
+		return false;
+	}
+
+	private boolean isAuthSupported() {
+		final IVcsManager vcsManager = dialog.getSelectedVCSManager();
+		return vcsManager != null && vcsManager.isAuthSupported();
+	}
+
+	private boolean isLocationValid() {
+		IVcsManager vcsManager = dialog.getSelectedVCSManager();
+		return vcsManager.isPathLocationAccepted() && isLocationValidPath()
+				|| vcsManager.isURLLocationAccepted() && isLocationValidURI();
+	}
+
+	private boolean isLocationValidURI() {
+		try {
+			URI uri = new URI(txtVCSLocation.getText());
+			return uri.getScheme() != null && uri.getPath() != null;
+		} catch (URISyntaxException e) {
+			return false;
+		}
+	}
+
+}
diff --git a/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/IVcsConfigurationBlock.java b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/IVcsConfigurationBlock.java
new file mode 100644
index 0000000..1971bdf
--- /dev/null
+++ b/core/plugins/org.eclipse.hawk.ui2/src/org/eclipse/hawk/ui2/vcs/IVcsConfigurationBlock.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2020 University of York, Aston University.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
+ *
+ * Contributors:
+ *    Antonio Garcia-Dominguez - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.hawk.ui2.vcs;
+
+import org.eclipse.hawk.core.IVcsManager;
+import org.eclipse.hawk.osgiserver.HModel;
+import org.eclipse.hawk.ui2.dialog.HVCSDialog;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Generic interface for a block that configures a new {@link IVcsManager} for use.
+ */
+public interface IVcsConfigurationBlock {
+
+	/**
+	 * Eclipse extension point ID for all VCS configuration blocks.
+	 */
+	String EXT_ID = "org.eclipse.hawk.ui.vcsConfigBlock";
+
+	/**
+	 * Name of the class that refers to the configuration block class.
+	 */
+	String EXT_ATTR_CLASS = "class";
+
+	/**
+	 * Returns {@code true} iff this component can set up the provided {@link IVcsManager}.
+	 */
+	boolean isApplicableTo(IVcsManager manager);
+
+	/**
+	 * Creates and populates the container with all the controls needed to set up
+	 * the {@link IVcsManager}. The component should retain references to the
+	 * various widgets inside, for the later call to
+	 * {@link #configure(IVcsManager)}.
+	 */
+	void createBlock(Composite container, HVCSDialog dialog);
+
+	/**
+	 * Configures the provided manager based on the current state of the widgets inside
+	 * the container returned by {@link #createBlock()}. 
+	 */
+	public void okPressed(HModel hawkModel, boolean isFrozen);
+
+}
diff --git a/core/pom.xml b/core/pom.xml
index 24560b9..7405775 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -25,10 +25,9 @@
     <module>releng/org.eclipse.hawk.uml.feature</module>
     <module>releng/org.eclipse.hawk.workspace.feature</module>
 
-    <module>plugins/org.eclipse.hawk.ui.emf</module>
     <module>plugins/org.eclipse.hawk.bpmn</module>
-    <module>plugins/org.eclipse.hawk.core</module>
     <module>plugins/org.eclipse.hawk.core.dependencies</module>
+    <module>plugins/org.eclipse.hawk.core</module>
     <module>plugins/org.eclipse.hawk.emf</module>
     <module>plugins/org.eclipse.hawk.emfresource</module>
     <module>plugins/org.eclipse.hawk.epsilon</module>
@@ -42,11 +41,14 @@
     <module>plugins/org.eclipse.hawk.svn</module>
     <module>plugins/org.eclipse.hawk.timeaware</module>
     <module>plugins/org.eclipse.hawk.ui.emc.dt2</module>
+    <module>plugins/org.eclipse.hawk.ui.emf</module>
     <module>plugins/org.eclipse.hawk.ui.emfresource</module>
+    <module>plugins/org.eclipse.hawk.ui.localfolder</module>
+    <module>plugins/org.eclipse.hawk.ui.uml</module>
+    <module>plugins/org.eclipse.hawk.ui.workspace</module>
     <module>plugins/org.eclipse.hawk.ui2</module>
     <module>plugins/org.eclipse.hawk.uml</module>
     <module>plugins/org.eclipse.hawk.workspace</module>
-
     <module>releng/org.eclipse.hawk.targetplatform</module>
     <module>releng/org.eclipse.hawk.updatesite</module>
 
diff --git a/core/releng/org.eclipse.hawk.ui.feature/feature.xml b/core/releng/org.eclipse.hawk.ui.feature/feature.xml
index d8bb71d..ee563a2 100644
--- a/core/releng/org.eclipse.hawk.ui.feature/feature.xml
+++ b/core/releng/org.eclipse.hawk.ui.feature/feature.xml
@@ -204,4 +204,25 @@
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="org.eclipse.hawk.ui.workspace"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.hawk.ui.uml"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.hawk.ui.localfolder"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
diff --git a/server/plugins/org.eclipse.hawk.service.remote.thrift/src/org/eclipse/hawk/service/remote/thrift/ThriftRemoteModelIndexer.java b/server/plugins/org.eclipse.hawk.service.remote.thrift/src/org/eclipse/hawk/service/remote/thrift/ThriftRemoteModelIndexer.java
index 9bb2be2..235f09f 100644
--- a/server/plugins/org.eclipse.hawk.service.remote.thrift/src/org/eclipse/hawk/service/remote/thrift/ThriftRemoteModelIndexer.java
+++ b/server/plugins/org.eclipse.hawk.service.remote.thrift/src/org/eclipse/hawk/service/remote/thrift/ThriftRemoteModelIndexer.java
@@ -436,6 +436,11 @@
 					name, location), e);
 			}
 		}
+
+		@Override
+		public String getDefaultLocation() {
+			return "";
+		}
 	}
 
 	private final String name, location;