diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.Designer.cs b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.Designer.cs
new file mode 100644
index 0000000000..757a491845
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.Designer.cs
@@ -0,0 +1,239 @@
+/*
+ * Responsibilities:<br>
+ * <br>
+ * Collaboration:<br>
+ * <br>
+ * User: ${USER}
+ * Date: ${DATE}
+ * Time: ${TIME}
+ * 
+ */
+namespace SharpDbTools.Forms
+{
+	partial class ConnectionStringDefinitionDialog : System.Windows.Forms.Form
+	{
+		/// <summary>
+		/// Designer variable used to keep track of non-visual components.
+		/// </summary>
+		private System.ComponentModel.IContainer components = null;
+		
+		/// <summary>
+		/// Disposes resources used by the form.
+		/// </summary>
+		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing) {
+				if (components != null) {
+					components.Dispose();
+				}
+			}
+			base.Dispose(disposing);
+		}
+		
+		/// <summary>
+		/// This method is required for Windows Forms designer support.
+		/// Do not change the method contents inside the source code editor. The Forms designer might
+		/// not be able to load this method if it was changed manually.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.components = new System.ComponentModel.Container();
+			this.connStringPropertyGrid = new System.Windows.Forms.PropertyGrid();
+			this.buttonsFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel();
+			this.testButton = new System.Windows.Forms.Button();
+			this.submitButton = new System.Windows.Forms.Button();
+			this.cancelButton = new System.Windows.Forms.Button();
+			this.providerTypeComboBox = new System.Windows.Forms.ComboBox();
+			this.dataSourceTypeLabel = new System.Windows.Forms.Label();
+			this.connStringResult = new System.Windows.Forms.TextBox();
+			this.connectionStringLabel = new System.Windows.Forms.Label();
+			this.progressTimer = new System.Windows.Forms.Timer(this.components);
+			this.statusStrip = new System.Windows.Forms.StatusStrip();
+			this.outputMessageTabControl = new System.Windows.Forms.TabControl();
+			this.connectionStringTab = new System.Windows.Forms.TabPage();
+			this.testResultTab = new System.Windows.Forms.TabPage();
+			this.testResultTextBox = new System.Windows.Forms.TextBox();
+			this.buttonsFlowLayoutPanel.SuspendLayout();
+			this.outputMessageTabControl.SuspendLayout();
+			this.connectionStringTab.SuspendLayout();
+			this.testResultTab.SuspendLayout();
+			this.SuspendLayout();
+			// 
+			// connStringPropertyGrid
+			// 
+			this.connStringPropertyGrid.Location = new System.Drawing.Point(0, 39);
+			this.connStringPropertyGrid.Name = "connStringPropertyGrid";
+			this.connStringPropertyGrid.Size = new System.Drawing.Size(547, 300);
+			this.connStringPropertyGrid.TabIndex = 0;
+			// 
+			// buttonsFlowLayoutPanel
+			// 
+			this.buttonsFlowLayoutPanel.Controls.Add(this.testButton);
+			this.buttonsFlowLayoutPanel.Controls.Add(this.submitButton);
+			this.buttonsFlowLayoutPanel.Controls.Add(this.cancelButton);
+			this.buttonsFlowLayoutPanel.Location = new System.Drawing.Point(3, 447);
+			this.buttonsFlowLayoutPanel.Name = "buttonsFlowLayoutPanel";
+			this.buttonsFlowLayoutPanel.Size = new System.Drawing.Size(312, 34);
+			this.buttonsFlowLayoutPanel.TabIndex = 1;
+			// 
+			// testButton
+			// 
+			this.testButton.Location = new System.Drawing.Point(3, 3);
+			this.testButton.Name = "testButton";
+			this.testButton.Size = new System.Drawing.Size(75, 23);
+			this.testButton.TabIndex = 0;
+			this.testButton.Text = "Test";
+			this.testButton.UseVisualStyleBackColor = true;
+			this.testButton.Click += new System.EventHandler(this.TestButtonClick);
+			// 
+			// submitButton
+			// 
+			this.submitButton.Location = new System.Drawing.Point(84, 3);
+			this.submitButton.Name = "submitButton";
+			this.submitButton.Size = new System.Drawing.Size(75, 23);
+			this.submitButton.TabIndex = 1;
+			this.submitButton.Text = "Submit";
+			this.submitButton.UseVisualStyleBackColor = true;
+			this.submitButton.Click += new System.EventHandler(this.SubmitButtonClick);
+			// 
+			// cancelButton
+			// 
+			this.cancelButton.Location = new System.Drawing.Point(165, 3);
+			this.cancelButton.Name = "cancelButton";
+			this.cancelButton.Size = new System.Drawing.Size(75, 23);
+			this.cancelButton.TabIndex = 2;
+			this.cancelButton.Text = "Cancel";
+			this.cancelButton.UseVisualStyleBackColor = true;
+			this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick);
+			// 
+			// providerTypeComboBox
+			// 
+			this.providerTypeComboBox.FormattingEnabled = true;
+			this.providerTypeComboBox.Location = new System.Drawing.Point(117, 12);
+			this.providerTypeComboBox.Name = "providerTypeComboBox";
+			this.providerTypeComboBox.Size = new System.Drawing.Size(195, 21);
+			this.providerTypeComboBox.TabIndex = 2;
+			this.providerTypeComboBox.SelectedIndexChanged += new System.EventHandler(this.ProviderTypeSelectedIndexChanged);
+			// 
+			// dataSourceTypeLabel
+			// 
+			this.dataSourceTypeLabel.Location = new System.Drawing.Point(3, 9);
+			this.dataSourceTypeLabel.Name = "dataSourceTypeLabel";
+			this.dataSourceTypeLabel.Size = new System.Drawing.Size(108, 23);
+			this.dataSourceTypeLabel.TabIndex = 3;
+			this.dataSourceTypeLabel.Text = "Data Source Type:";
+			this.dataSourceTypeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+			// 
+			// connStringResult
+			// 
+			this.connStringResult.Enabled = false;
+			this.connStringResult.Location = new System.Drawing.Point(0, 0);
+			this.connStringResult.Multiline = true;
+			this.connStringResult.Name = "connStringResult";
+			this.connStringResult.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+			this.connStringResult.Size = new System.Drawing.Size(413, 74);
+			this.connStringResult.TabIndex = 4;
+			// 
+			// connectionStringLabel
+			// 
+			this.connectionStringLabel.Location = new System.Drawing.Point(12, 348);
+			this.connectionStringLabel.Name = "connectionStringLabel";
+			this.connectionStringLabel.Size = new System.Drawing.Size(100, 23);
+			this.connectionStringLabel.TabIndex = 5;
+			this.connectionStringLabel.Text = "Connection String:";
+			// 
+			// progressTimer
+			// 
+			this.progressTimer.Interval = 1000;
+			this.progressTimer.Tick += new System.EventHandler(this.ProgressTimerTick);
+			// 
+			// statusStrip
+			// 
+			this.statusStrip.Location = new System.Drawing.Point(0, 478);
+			this.statusStrip.Name = "statusStrip";
+			this.statusStrip.Size = new System.Drawing.Size(547, 22);
+			this.statusStrip.TabIndex = 6;
+			this.statusStrip.Text = "statusStrip1";
+			// 
+			// testResultTab
+			// 
+			this.outputMessageTabControl.Controls.Add(this.connectionStringTab);
+			this.outputMessageTabControl.Controls.Add(this.testResultTab);
+			this.outputMessageTabControl.Location = new System.Drawing.Point(118, 345);
+			this.outputMessageTabControl.Name = "testResultTab";
+			this.outputMessageTabControl.SelectedIndex = 0;
+			this.outputMessageTabControl.Size = new System.Drawing.Size(417, 100);
+			this.outputMessageTabControl.TabIndex = 7;
+			// 
+			// tabPage1
+			// 
+			this.connectionStringTab.Controls.Add(this.connStringResult);
+			this.connectionStringTab.Location = new System.Drawing.Point(4, 22);
+			this.connectionStringTab.Name = "tabPage1";
+			this.connectionStringTab.Padding = new System.Windows.Forms.Padding(3);
+			this.connectionStringTab.Size = new System.Drawing.Size(409, 74);
+			this.connectionStringTab.TabIndex = 0;
+			this.connectionStringTab.Text = "Connection String";
+			this.connectionStringTab.UseVisualStyleBackColor = true;
+			// 
+			// tabPage2
+			// 
+			this.testResultTab.Controls.Add(this.testResultTextBox);
+			this.testResultTab.Location = new System.Drawing.Point(4, 22);
+			this.testResultTab.Name = "tabPage2";
+			this.testResultTab.Padding = new System.Windows.Forms.Padding(3);
+			this.testResultTab.Size = new System.Drawing.Size(409, 74);
+			this.testResultTab.TabIndex = 1;
+			this.testResultTab.Text = "Test Result Message";
+			this.testResultTab.UseVisualStyleBackColor = true;
+			// 
+			// testResultTextBox
+			// 
+			this.testResultTextBox.Location = new System.Drawing.Point(-5, 0);
+			this.testResultTextBox.Multiline = true;
+			this.testResultTextBox.Name = "testResultTextBox";
+			this.testResultTextBox.Size = new System.Drawing.Size(418, 77);
+			this.testResultTextBox.TabIndex = 0;
+			// 
+			// ConnectionStringDefinitionDialog
+			// 
+			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.ClientSize = new System.Drawing.Size(547, 500);
+			this.Controls.Add(this.outputMessageTabControl);
+			this.Controls.Add(this.statusStrip);
+			this.Controls.Add(this.connectionStringLabel);
+			this.Controls.Add(this.dataSourceTypeLabel);
+			this.Controls.Add(this.providerTypeComboBox);
+			this.Controls.Add(this.buttonsFlowLayoutPanel);
+			this.Controls.Add(this.connStringPropertyGrid);
+			this.Name = "ConnectionStringDefinitionDialog";
+			this.Text = "Set up Connection String";
+			this.buttonsFlowLayoutPanel.ResumeLayout(false);
+			this.outputMessageTabControl.ResumeLayout(false);
+			this.connectionStringTab.ResumeLayout(false);
+			this.connectionStringTab.PerformLayout();
+			this.testResultTab.ResumeLayout(false);
+			this.testResultTab.PerformLayout();
+			this.ResumeLayout(false);
+			this.PerformLayout();
+		}
+		private System.Windows.Forms.TabControl outputMessageTabControl;
+		private System.Windows.Forms.TextBox testResultTextBox;
+		private System.Windows.Forms.TabPage testResultTab;
+		private System.Windows.Forms.TabPage connectionStringTab;
+		
+		private System.Windows.Forms.Timer progressTimer;
+		private System.Windows.Forms.StatusStrip statusStrip;
+		private System.Windows.Forms.TextBox connStringResult;
+		private System.Windows.Forms.Label connectionStringLabel;
+		private System.Windows.Forms.Label dataSourceTypeLabel;
+		private System.Windows.Forms.ComboBox providerTypeComboBox;
+		private System.Windows.Forms.Button cancelButton;
+		private System.Windows.Forms.Button submitButton;
+		private System.Windows.Forms.Button testButton;
+		private System.Windows.Forms.FlowLayoutPanel buttonsFlowLayoutPanel;
+		private System.Windows.Forms.PropertyGrid connStringPropertyGrid;		
+	}
+}
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.cs b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.cs
new file mode 100644
index 0000000000..560c9527e6
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.cs
@@ -0,0 +1,257 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Dickon Field" email=""/>
+//     <version>$Revision: 1684 $</version>
+// </file>
+
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.ComponentModel;
+
+using SharpDbTools.Data;
+
+namespace SharpDbTools.Forms
+{
+	/// <summary>
+	/// This class creates a dialog that can be used to create and test connection strings
+	/// that can be used with .net 2.0 DbProviders.
+	/// It utilises .net 2.0 configuration to discover any DbProviderFactories that are
+	/// installed and configured in machine.config, app.config or user.config using
+	/// standard .net 2.0 apis.
+	/// It then enables a user to browse the properties of each type of db connection,
+	/// set values for them and test the resulting connection string.
+	/// When the submit button is clicked the dialog is dismissed and the connection
+	/// string constructed is accessible through the ConnectionString property of the dialog.
+	/// </summary>
+	public partial class ConnectionStringDefinitionDialog
+	{
+		ToolStripProgressBar connectionTestProgressBar = new ToolStripProgressBar();
+		ConnectionTestBackgroundWorker testConnectionBackgroundWorker;
+		string resultMessage;
+		string invariantName;
+		ConnectionTestState connectionTestState = ConnectionTestState.UnTested;
+		
+		public ConnectionStringDefinitionDialog()
+		{
+			//
+			// The InitializeComponent() call is required for Windows Forms designer support.
+			//
+			InitializeComponent();
+			this.connStringPropertyGrid.PropertyValueChanged += 
+				new PropertyValueChangedEventHandler(this.ConnStringAttributesViewPropertyValueChanged);
+			// add a ProgressBar to the statusString
+			this.statusStrip.Items.Add(connectionTestProgressBar);
+			this.connectionTestProgressBar.Step = 10;
+			this.connectionTestProgressBar.Minimum = 0;
+			this.connectionTestProgressBar.Maximum = 150;
+		}
+		
+		public string InvariantName {
+			get {
+				return this.invariantName;
+			}
+			set {
+				this.invariantName = value;
+			}
+		}
+		
+		public ConnectionTestState ConnectionTestState {
+			get {
+				return this.connectionTestState;
+			}
+		}
+		
+		public string ResultMessage
+		{
+			get
+			{
+				return resultMessage;
+			}
+			set
+			{
+				resultMessage = value;
+			}
+		}
+		
+		public DbConnectionStringBuilder ConnectionStringBuilder
+		{
+			get
+			{
+					return (DbConnectionStringBuilder)this.connStringPropertyGrid.SelectedObject;
+			}
+		}
+		
+		public string ConnectionString
+		{
+			get
+			{
+				return ((DbConnectionStringBuilder)this.connStringPropertyGrid.SelectedObject).ConnectionString;
+			}
+		}
+		
+		protected override void OnLoad(EventArgs e)
+		{
+			//
+			// set the PropertyGrid to browse the available DbProviders
+			//
+
+			base.OnLoad(e);
+			
+			DbProvidersService service = DbProvidersService.GetDbProvidersService();
+			List<string> names = service.Names;
+			this.providerTypeComboBox.DataSource = names;
+			this.connStringResult.Text = this.ConnectionString;
+		}
+		
+		void CancelButtonClick(object sender, System.EventArgs e)
+		{
+			this.DialogResult = DialogResult.Cancel;
+			this.Close();
+		}
+		
+		void ProviderTypeSelectedIndexChanged(object sender, System.EventArgs e)
+		{
+			string selection = (string)this.providerTypeComboBox.SelectedItem;
+			DbProvidersService service = DbProvidersService.GetDbProvidersService();
+			DbProviderFactory factory = service[selection];
+			DbConnectionStringBuilder builder = factory.CreateConnectionStringBuilder();
+			connStringPropertyGrid.SelectedObject = builder;
+		}
+		
+		void ConnStringAttributesViewPropertyValueChanged(Object s, PropertyValueChangedEventArgs args)
+		{
+			// looking for changes to the ConnectionString property in the PropertyGrid
+			this.connStringResult.Text = this.ConnectionString;
+			this.outputMessageTabControl.SelectTab(this.connectionStringTab);
+			ResetTestResultTextBox();
+		}
+		
+		void TestButtonClick(object sender, System.EventArgs e)
+		{
+			string dbTypeName = (string)this.providerTypeComboBox.SelectedItem;
+			testConnectionBackgroundWorker = new ConnectionTestBackgroundWorker(dbTypeName);
+			testConnectionBackgroundWorker.WorkerSupportsCancellation = false;
+			progressTimer.Enabled = true;
+			testConnectionBackgroundWorker.DoWork += 
+				new DoWorkEventHandler(this.TestConnectionBackgroundWorkerDoWork);
+			testConnectionBackgroundWorker.RunWorkerCompleted += 
+				new RunWorkerCompletedEventHandler(TestConnectionRunWorkerComplete);
+			testConnectionBackgroundWorker.RunWorkerAsync();
+		}
+		
+		void ProgressTimerTick(object sender, System.EventArgs e)
+		{
+			this.BeginInvoke(new EventHandler(UpdateProgressBar));
+		}
+		
+		void UpdateProgressBar(object sender, EventArgs e)
+		{
+			ToolStripProgressBar p = connectionTestProgressBar;
+			if (p.Value == p.Maximum) p.Value = 0;
+			p.PerformStep();
+		}
+		
+		void SetTestResultTextBox()
+		{
+			this.testResultTextBox.Text = ResultMessage;
+			this.outputMessageTabControl.SelectTab(this.testResultTab);
+		}
+		
+		void ResetTestResultTextBox()
+		{
+			this.testResultTextBox.Text = "";
+			this.connectionTestState = ConnectionTestState.UnTested;
+		}
+		
+		void TestConnectionBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
+		{
+			DbConnection connection = null;
+			try
+			{
+				// get the current name
+								
+				ConnectionTestBackgroundWorker bw = sender as ConnectionTestBackgroundWorker;
+				string currentDbTypeName = bw.DatabaseType; 
+				
+				// get the DbProviderFactory for this name
+				
+				DbProvidersService service = DbProvidersService.GetDbProvidersService();
+				DbProviderFactory factory = service[currentDbTypeName];
+				
+				// get a connection object or this factory
+				
+				connection = factory.CreateConnection();
+				connection.ConnectionString = this.ConnectionString;
+
+				connection.Open();				
+				e.Result = "Connection Succeeded";
+				connectionTestState = ConnectionTestState.TestSucceeded;
+			}
+			catch(Exception ex)
+			{
+				e.Result = "Connection Failed: " + ex.Message;
+				connectionTestState = ConnectionTestState.TestFailed;
+			}
+			finally
+			{
+				if (connection != null)
+				{
+					connection.Close();
+				}
+			}			
+		}
+		
+		void TestConnectionRunWorkerComplete(object sender, RunWorkerCompletedEventArgs args)
+		{
+			ResultMessage = args.Result as string;
+			this.Invoke(new EventHandler(TestConnectionCompleted));
+		}
+		
+		void TestConnectionCompleted(object sender, EventArgs args)
+		{
+			progressTimer.Enabled = false;
+			connectionTestProgressBar.Value = 0;
+			SetTestResultTextBox();
+			testConnectionBackgroundWorker.Dispose();
+		}
+		
+		void SubmitButtonClick(object sender, System.EventArgs e)
+		{
+			string name = (string)this.providerTypeComboBox.SelectedItem;
+			DbProvidersService service = DbProvidersService.GetDbProvidersService();
+			this.InvariantName = service.GetInvariantName(name);
+			
+			this.DialogResult = DialogResult.OK;
+			this.Close();			
+		}
+	}
+	
+	public enum ConnectionTestState
+	{
+		UnTested,
+		TestFailed,
+		TestSucceeded
+	}
+	
+	class ConnectionTestBackgroundWorker: BackgroundWorker
+	{
+		private string dbTypeName;
+		
+		public ConnectionTestBackgroundWorker(string dbTypeName): base()
+		{
+			this.dbTypeName = dbTypeName;	
+		}
+		
+		public string DatabaseType
+		{
+			get
+			{
+				return dbTypeName;
+			}
+		}
+	}
+}
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.resx b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.resx
new file mode 100644
index 0000000000..157d9061d2
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ConnectionStringDefinitionDialog.resx
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="progressTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>247, 17</value>
+  </metadata>
+  <metadata name="statusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>371, 17</value>
+  </metadata>
+</root>
\ No newline at end of file
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.Designer.cs b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.Designer.cs
new file mode 100644
index 0000000000..bf888294c5
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.Designer.cs
@@ -0,0 +1,100 @@
+/*
+ * User: dickon
+ * Date: 04/08/2006
+ * Time: 22:21
+ */
+namespace SharpDbTools.Forms
+{
+	partial class GetConnectionLogicalNameDialog : System.Windows.Forms.Form
+	{
+		/// <summary>
+		/// Designer variable used to keep track of non-visual components.
+		/// </summary>
+		private System.ComponentModel.IContainer components = null;
+		
+		/// <summary>
+		/// Disposes resources used by the form.
+		/// </summary>
+		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing) {
+				if (components != null) {
+					components.Dispose();
+				}
+			}
+			base.Dispose(disposing);
+		}
+		
+		/// <summary>
+		/// This method is required for Windows Forms designer support.
+		/// Do not change the method contents inside the source code editor. The Forms designer might
+		/// not be able to load this method if it was changed manually.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.connectionName = new System.Windows.Forms.TextBox();
+			this.connectionNameOKButton = new System.Windows.Forms.Button();
+			this.connectionNameCancelButton = new System.Windows.Forms.Button();
+			this.label1 = new System.Windows.Forms.Label();
+			this.SuspendLayout();
+			// 
+			// connectionName
+			// 
+			this.connectionName.Location = new System.Drawing.Point(12, 33);
+			this.connectionName.MaxLength = 30;
+			this.connectionName.Name = "connectionName";
+			this.connectionName.Size = new System.Drawing.Size(292, 21);
+			this.connectionName.TabIndex = 0;
+			// 
+			// connectionNameOKButton
+			// 
+			this.connectionNameOKButton.Location = new System.Drawing.Point(66, 70);
+			this.connectionNameOKButton.Name = "connectionNameOKButton";
+			this.connectionNameOKButton.Size = new System.Drawing.Size(75, 23);
+			this.connectionNameOKButton.TabIndex = 1;
+			this.connectionNameOKButton.Text = "OK";
+			this.connectionNameOKButton.UseVisualStyleBackColor = true;
+			this.connectionNameOKButton.Click += new System.EventHandler(this.ConnectionNameOKButtonClick);
+			// 
+			// connectionNameCancelButton
+			// 
+			this.connectionNameCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+			this.connectionNameCancelButton.Location = new System.Drawing.Point(171, 70);
+			this.connectionNameCancelButton.Name = "connectionNameCancelButton";
+			this.connectionNameCancelButton.Size = new System.Drawing.Size(75, 23);
+			this.connectionNameCancelButton.TabIndex = 2;
+			this.connectionNameCancelButton.Text = "Cancel";
+			this.connectionNameCancelButton.UseVisualStyleBackColor = true;
+			this.connectionNameCancelButton.Click += new System.EventHandler(this.ConnectionNameCancelButtonClick);
+			// 
+			// label1
+			// 
+			this.label1.Location = new System.Drawing.Point(12, 9);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(259, 23);
+			this.label1.TabIndex = 3;
+			this.label1.Text = "Please provide the name for your db connection:";
+			// 
+			// GetConnectionLogicalNameDialog
+			// 
+			this.AcceptButton = this.connectionNameOKButton;
+			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.CancelButton = this.connectionNameCancelButton;
+			this.ClientSize = new System.Drawing.Size(316, 114);
+			this.Controls.Add(this.label1);
+			this.Controls.Add(this.connectionNameCancelButton);
+			this.Controls.Add(this.connectionNameOKButton);
+			this.Controls.Add(this.connectionName);
+			this.Name = "GetConnectionLogicalNameDialog";
+			this.Text = "Connection Name";
+			this.ResumeLayout(false);
+			this.PerformLayout();
+		}
+		private System.Windows.Forms.TextBox connectionName;
+		private System.Windows.Forms.Label label1;
+		private System.Windows.Forms.Button connectionNameCancelButton;
+		private System.Windows.Forms.Button connectionNameOKButton;
+	}
+}
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.cs b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.cs
new file mode 100644
index 0000000000..b485d5180b
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.cs
@@ -0,0 +1,46 @@
+/*
+ * User: dickon
+ * Date: 04/08/2006
+ * Time: 22:21
+ */
+
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace SharpDbTools.Forms
+{
+	/// <summary>
+	/// Description of GetConnectionLogicalNameDialog.
+	/// </summary>
+	public partial class GetConnectionLogicalNameDialog
+	{
+		public GetConnectionLogicalNameDialog()
+		{
+			//
+			// The InitializeComponent() call is required for Windows Forms designer support.
+			//
+			InitializeComponent();
+			
+			//
+			// TODO: Add constructor code after the InitializeComponent() call.
+			//
+		}
+		
+		public string LogicalConnectionName {
+			get {
+				return this.connectionName.Text;
+			}				
+		}
+		
+		void ConnectionNameOKButtonClick(object sender, System.EventArgs e)
+		{
+			this.Close();
+		}
+		
+		void ConnectionNameCancelButtonClick(object sender, System.EventArgs e)
+		{
+			this.Close();
+		}
+	}
+}
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.resx b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.resx
new file mode 100644
index 0000000000..7080a7d118
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/GetConnectionLogicalNameDialog.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ServerBrowserTool.cs b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ServerBrowserTool.cs
new file mode 100644
index 0000000000..2e4b76c179
--- /dev/null
+++ b/src/AddIns/Misc/SharpDbTools/Project/Src/Forms/ServerBrowserTool.cs
@@ -0,0 +1,454 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Dickon Field" email=""/>
+//     <version>$Revision: 1766 $</version>
+// </file>
+
+/*
+ * User: Dickon Field
+ * Date: 12/06/2006
+ * Time: 06:25
+ */
+
+using System;
+using System.Windows.Forms;
+using System.Data;
+using System.Data.Common;
+using System.Collections.Generic;
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using SharpDbTools.Data;
+
+namespace SharpDbTools.Forms
+{
+	/// <summary>
+	/// Enables a user to browse metadata associated with a db server and to open resources
+	/// referenced therein. The intention is to extend this to other server processes over
+	/// time.
+	/// </summary>
+	public class ServerBrowserTool : AbstractPadContent
+	{
+		Panel ctl;
+		
+		/// <summary>
+		/// ServerBrowserTool hosts one or more TreeViews providing views of types
+		/// of server. Currently it shows only relational database servers.
+		/// </summary>
+		public ServerBrowserTool()
+		{
+			LoggingService.Debug("Loading ServerBrowserTool");
+			ServerToolTreeView dbTree = new ServerToolTreeView();
+			dbTree.Dock = DockStyle.Fill;
+			ctl = new Panel();
+			ctl.Controls.Add(dbTree);			
+		}
+		
+		/// <summary>
+		/// The <see cref="System.Windows.Forms.Control"/> representing the pad
+		/// </summary>
+		public override Control Control {
+			get {
+				return ctl;
+			}
+		}
+		
+		/// <summary>
+		/// Rebuildes the pad
+		/// </summary>
+		public override void RedrawContent()
+		{
+			// TODO: Rebuild the whole pad control here, renew all resource strings whatever
+			//       Note that you do not need to recreate the control.
+		}
+		
+		/// <summary>
+		/// Cleans up all used resources
+		/// </summary>
+		public override void Dispose()
+		{
+			ctl.Dispose();
+		}
+	}
+	
+	class ServerToolTreeView : TreeView
+	{		
+		public ServerToolTreeView(): base()
+		{				
+			// this is the wrong place for this, but lets give it a go...
+			DbModelInfoService.LoadNamesFromFiles();
+			Rebuild();
+
+		}
+		
+		/// <summary>
+		/// Rebuilds the database connection tree.
+		/// Should only be called from a delegate via Invoke or BeginInvoke.
+		/// </summary>
+		public void Rebuild()
+		{
+			this.BeginUpdate();
+			// TODO: put the Rebuild... behaviour into a view builder;
+			TreeNode dbNode = null;
+			TreeNode[] dbNodes = this.Nodes.Find("DatabaseExplorer", true);
+			
+			// lets assume there is only one with this above name
+			if (dbNodes.Length == 0) {
+				LoggingService.Debug("could not find DatabaseExplorer Node, so creating it now");
+				dbNode = new TreeNode();
+				dbNode.Text = "Database Explorer";
+				dbNode.Name = "DatabaseExplorer";
+				this.Nodes.Add(dbNode);
+			} else {
+				dbNode = dbNodes[0];
+			}
+			
+			// create the context menu for the database server node
+			ContextMenuStrip cMenu = new ContextMenuStrip();
+			ToolStripMenuItem addConnectionMenuItem = 
+				new ToolStripMenuItem("Add Connection");
+			addConnectionMenuItem.Click += new EventHandler(AddDbConnectionClickHandler);
+			
+			ToolStripMenuItem deleteConnectionMenuItem = 
+				new ToolStripMenuItem("Delete Connection");
+			deleteConnectionMenuItem.Click += new EventHandler(DeleteDbConnectionClickHandler);
+			
+			ToolStripMenuItem saveMetadataMenuItem =
+				new ToolStripMenuItem("Save All");
+			saveMetadataMenuItem.Click += new EventHandler(SaveDbModelInfoClickHandler);
+			
+			
+			cMenu.Items.AddRange(new ToolStripMenuItem[] 
+			                     {	
+			                     	addConnectionMenuItem,
+			                     	deleteConnectionMenuItem,
+			                     	saveMetadataMenuItem
+			                     } 
+			                    );
+			dbNode.ContextMenuStrip = cMenu;
+
+			// Rebuild each of the root nodes in the ServerToolTreeView
+			dbNode.Nodes.Clear();
+			foreach (string name in DbModelInfoService.Names) {
+				TreeNode dbModelInfoNode = CreateDbModelInfoNode(name);
+				TreeNode connectionNode = CreateConnectionPropertiesNode(name);
+				TreeNode metadataNode = CreateMetaDataNode(name);
+				dbModelInfoNode.Nodes.Add(connectionNode);
+				dbModelInfoNode.Nodes.Add(metadataNode);
+				dbNode.Nodes.Add(dbModelInfoNode);
+			}
+			this.EndUpdate();
+		}
+		
+		public TreeNode CreateDbModelInfoNode(string name)
+		{
+			TreeNode treeNode = new TreeNode(name);
+			treeNode.Tag = "ConnectionRoot";
+			// create and add the menustrip for this node
+			
+			NodeAwareContextMenuStrip cMenu = new NodeAwareContextMenuStrip(treeNode);
+			
+			// create menu items
+			ToolStripMenuItem setConnectionStringMenuItem = 
+				new ToolStripMenuItem("Set Connection String");
+			setConnectionStringMenuItem.Click += new EventHandler(SetConnectionStringOnDbModelInfoClickHandler);
+			
+			ToolStripMenuItem loadMetadataFromConnectionMenuItem =
+				new ToolStripMenuItem("Load Metadata from Connection");
+			loadMetadataFromConnectionMenuItem.Click += new EventHandler(LoadMetadataFromConnectionClickHandler);
+			
+			ToolStripMenuItem loadMetadataFromFileMenuItem =
+				new ToolStripMenuItem("Load Metadata from File");
+			loadMetadataFromFileMenuItem.Click += new EventHandler(LoadMetadataFromFileClickHandler);
+			
+			
+			cMenu.Items.AddRange(new ToolStripMenuItem[] 
+			                     {
+			                     	setConnectionStringMenuItem,
+			                     	loadMetadataFromConnectionMenuItem,
+			                     	loadMetadataFromFileMenuItem
+			                     });
+	
+			treeNode.ContextMenuStrip = cMenu;
+			return treeNode;
+		}
+		
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="name"></param>
+		/// <returns>a TreeNode representation of the connection properties
+		/// of the connection</returns>
+		public TreeNode CreateConnectionPropertiesNode(string name)
+		{
+			// create sub TreeNodes for the connection string and invariant name if they exist
+			DbModelInfo modelInfo = DbModelInfoService.GetDbModelInfo(name);
+			if (name == null) throw new KeyNotFoundException();
+			string connectionString = modelInfo.ConnectionString;
+			string invariantName = modelInfo.InvariantName;
+			
+			TreeNode attributesNode = new TreeNode("Connection Properties");
+				
+			if (connectionString != null) {
+				TreeNode cstringNode = new TreeNode("Connection String: " + connectionString);
+				attributesNode.Nodes.Add(cstringNode);
+			}
+			
+			if (invariantName != null) {
+				TreeNode invNameNode = new TreeNode("Invariant Name: " + invariantName);
+				attributesNode.Nodes.Add(invNameNode);
+			}
+			
+			return attributesNode;
+		}
+		
+		public TreeNode CreateMetaDataNode(string name)
+		{
+			TreeNode metaNode = new TreeNode("Db Objects");
+			metaNode.Name = name + ":MetaData";
+			DbModelInfo info = DbModelInfoService.GetDbModelInfo(name);
+			DataTable metadataCollectionsTable = info.Tables[TableNames.MetaDataCollections];
+			if (metadataCollectionsTable != null) {
+				for (int i = 0; i < TableNames.PrimaryObjects.Length; i++) {
+					string metadataCollectionName = TableNames.PrimaryObjects[i];
+					LoggingService.Debug("looking for metadata: " + metadataCollectionName);
+					DataTable metaCollectionTable = info.Tables[metadataCollectionName];
+					LoggingService.Debug("found metadata collection: " + metadataCollectionName);
+					TreeNode collectionNode = new TreeNode(metadataCollectionName);
+					collectionNode.Name = name + ":Collection:" + metadataCollectionName;
+					metaNode.Nodes.Add(collectionNode);
+					foreach (DataRow dbObjectRow in metaCollectionTable.Rows) {
+						// TODO: >>>>>>>NEXT: at this point it is not enough to make this assumption - it doesn't hold
+						// for SQLServer for example, only for Oracle. The following text illustrates the difference between
+						// SQLServer and Oracle for the Users metadatacollection.
+						
+						/*
+						 * C:\workspace\ExampleDBFactories\DbExperiments\bin\Debug>DbExperiments.exe Users
+
+uid user_name createdate updatedate
+0 public 08/04/2003 09:10:19 14/10/2005 01:36:15
+1 dbo 08/04/2003 09:10:19 08/04/2003 09:10:19
+2 guest 08/04/2003 09:10:19 08/04/2003 09:10:19
+3 INFORMATION_SCHEMA 14/10/2005 01:36:06 14/10/2005 01:36:06
+4 sys 14/10/2005 01:36:06 14/10/2005 01:36:06
+5 ##MS_AgentSigningCertificate## 26/08/2006 23:04:16 26/08/2006 23:04:16
+16384 db_owner 08/04/2003 09:10:19 14/10/2005 01:36:15
+16385 db_accessadmin 08/04/2003 09:10:19 14/10/2005 01:36:15
+16386 db_securityadmin 08/04/2003 09:10:19 14/10/2005 01:36:15
+16387 db_ddladmin 08/04/2003 09:10:19 14/10/2005 01:36:15
+16389 db_backupoperator 08/04/2003 09:10:19 14/10/2005 01:36:15
+16390 db_datareader 08/04/2003 09:10:19 14/10/2005 01:36:15
+16391 db_datawriter 08/04/2003 09:10:19 14/10/2005 01:36:15
+16392 db_denydatareader 08/04/2003 09:10:19 14/10/2005 01:36:15
+16393 db_denydatawriter 08/04/2003 09:10:19 14/10/2005 01:36:15
+
+C:\workspace\ExampleDBFactories\DbExperiments\bin\Debug>DbExperiments.exe Users
+
+NAME ID CREATEDATE
+ANONYMOUS 28 07/02/2006 22:40:15
+CTXSYS 25 07/02/2006 22:38:38
+DBSNMP 23 07/02/2006 22:35:21
+DEV 36 26/07/2006 00:09:58
+DIP 18 07/02/2006 22:17:03
+FLOWS_020100 35 07/02/2006 22:52:43
+FLOWS_FILES 34 07/02/2006 22:52:43
+HR 33 07/02/2006 22:51:21
+MDSYS 32 07/02/2006 22:44:47
+OUTLN 11 07/02/2006 22:10:24
+SYS 0 07/02/2006 22:10:13
+SYSTEM 5 07/02/2006 22:10:13
+TSMSYS 20 07/02/2006 22:27:15
+XDB 27 07/02/2006 22:40:14
+
+C:\workspace\ExampleDBFactories\DbExperiments\bin\Debug>
+						 * 
+						 * 
+						 */
+						TreeNode objectNode = null;
+						if (dbObjectRow.ItemArray.Length > 1) {
+							objectNode = new TreeNode((string)dbObjectRow[1]);
+							objectNode.Name = name + ":Object:" + (string)dbObjectRow[1];
+						} else {
+							objectNode = new TreeNode((string)dbObjectRow[0]);
+							objectNode.Name = name + ":Object:" + (string)dbObjectRow[0];
+						}
+						// HACK All this building stuff needs to be externalise I think						
+						if (metadataCollectionName.Equals("Tables")) {
+							// add the handler to invoke describer
+							NodeAwareContextMenuStrip cMenu = new NodeAwareContextMenuStrip(objectNode);
+							ToolStripMenuItem invokeDescriberMenuItem = new ToolStripMenuItem("Describe");
+							invokeDescriberMenuItem.Click += new EventHandler(DescribeTableClickHandler);
+							cMenu.Items.Add(invokeDescriberMenuItem);
+							objectNode.ContextMenuStrip = cMenu;
+						}
+						    	
+						    
+						
+//						TreeNode ownerNode = new TreeNode("Owner: " + (string)dbObjectRow["OWNER"]);
+//						TreeNode typeNode = new TreeNode("Type: " + (string)dbObjectRow["TYPE"]);
+//						// TODO: add fields to each Table
+//						TreeNode fieldsNode = new TreeNode("Fields [TODO]");
+//						objectNode.Nodes.AddRange(new TreeNode[] {ownerNode, typeNode, fieldsNode });
+						collectionNode.Nodes.Add(objectNode);
+					}
+				}	
+			}
+			return metaNode;
+		}
+		
+		/// <summary>
+		/// Uses a dialog to get the logical name of a new Connection then
+		/// adds a new DbModelInfo for it to the cache and updates the DatabaseServer 
+		/// Tree.
+		/// </summary>
+		/// <param name="sender"></param>
+		/// <param name="e"></param>
+		public void AddDbConnectionClickHandler(object sender, EventArgs e)
+		{
+			LoggingService.Debug("add connection clicked");
+			
+			// get the logical name of the new connection
+			string logicalName =  null;			
+			using (GetConnectionLogicalNameDialog dialog = new GetConnectionLogicalNameDialog()) {
+				dialog.ShowDialog();
+				logicalName = dialog.LogicalConnectionName;
+			}
+			if (logicalName.Equals("") || logicalName == null) return;
+			
+			LoggingService.Debug("name received is: " + logicalName);
+			
+			// add a new DbModelInfo to the cache			
+			DbModelInfoService.Add(logicalName, null, null);
+			
+			// rebuild the database server node
+			this.BeginInvoke(new MethodInvoker(this.Rebuild));
+		}
+		
+		public void DeleteDbConnectionClickHandler(object sender, EventArgs e)
+		{
+			LoggingService.Debug("delete connection clicked");
+		}
+		
+		public void SaveDbModelInfoClickHandler(object sender, EventArgs e)
+		{
+			// save each DbModelInfo separately, confirming overwrite where necessary
+			LoggingService.Debug("save all metadata clicked - will iterate through each and attempt to save");
+			IList<string> names = DbModelInfoService.Names;
+			foreach (string name in names) {
+				bool saved = DbModelInfoService.SaveToFile(name, false);
+				if (!saved) {
+					DialogResult result = MessageBox.Show("Overwrite existing file for connection: " + name + "?", 
+					                "File exists for connection", MessageBoxButtons.YesNo,
+					                MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
+					if (result.Equals(DialogResult.Yes)) {
+						DbModelInfoService.SaveToFile(name, true);
+					}
+				}
+			}
+		}
+		
+		public void LoadMetadataFromFileClickHandler(object sender, EventArgs e)
+		{
+			LoggingService.Debug("load metadata from file clicked");
+			string logicalConnectionName = getConnectionName(sender);
+			DbModelInfoService.LoadFromFile(logicalConnectionName);
+			this.BeginInvoke(new MethodInvoker(this.Rebuild));
+		}
+		
+		private static string getConnectionName(object sender)
+		{
+			ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
+			NodeAwareContextMenuStrip toolStrip = menuItem.Owner as NodeAwareContextMenuStrip;
+			TreeNode node = toolStrip.TreeNode;
+			while ((node.Tag == null) || (!node.Tag.Equals("ConnectionRoot"))) {
+				node = node.Parent;				       	
+			}
+			string connectionLogicalName = node.Text;
+			return connectionLogicalName;
+		}
+		
+		public void SetConnectionStringOnDbModelInfoClickHandler(object sender, EventArgs e)
+		{
+			string connectionLogicalName = getConnectionName(sender);
+			LoggingService.Debug("add connection string clicked for item with name: " + connectionLogicalName);
+			
+			// use the ConnectionStringDefinitionDialog to get a connection string and invariant name
+			ConnectionStringDefinitionDialog definitionDialog = new ConnectionStringDefinitionDialog();
+			DialogResult result = definitionDialog.ShowDialog();
+			
+			// if the dialog was cancelled then do nothing
+			if (result == DialogResult.Cancel) {
+				return;
+			}
+			
+			// if the dialog was submitted and connection string has changed then clear the DbModelInfo metadata
+			// note that is is not required for the Connection string to be valid - it may be work
+			// in progress and a user might want to save a partially formed connection string
+
+			DbModelInfo dbModelInfo = DbModelInfoService.GetDbModelInfo(connectionLogicalName);
+			string connectionString = dbModelInfo.ConnectionString;
+			string newConnectionString = definitionDialog.ConnectionString;
+			
+			if (newConnectionString == null) {
+				return;
+			}
+			
+			dbModelInfo.ConnectionString = newConnectionString;
+			dbModelInfo.InvariantName = definitionDialog.InvariantName;
+			
+			// rebuild the database explorer node
+			this.BeginInvoke(new MethodInvoker(this.Rebuild));
+		}
+		
+		public void LoadMetadataFromConnectionClickHandler(object sender, EventArgs args)
+		{
+			string connectionLogicalName = getConnectionName(sender);
+			LoggingService.Debug("load metadata from connection clicked for connection with name: "
+			                     + connectionLogicalName);
+			try {	
+				DbModelInfoService.LoadMetadataFromConnection(connectionLogicalName);
+			}
+			catch(DbException e) {
+				MessageService.ShowError(e, 
+				"An Exception was thrown while trying to connect to: " + connectionLogicalName);                       
+			}
+		}
+		
+		public void DescribeTableClickHandler(object sender, EventArgs args)
+		{
+			string logicalConnectionName = getConnectionName(sender);
+			ToolStripMenuItem item = sender as ToolStripMenuItem;
+			NodeAwareContextMenuStrip s = item.Owner as NodeAwareContextMenuStrip;
+			string tableName = s.TreeNode.Text;
+			LoggingService.Debug("describe table clicked for: " + logicalConnectionName + " and table name: " + tableName);
+			DataTable tableInfo = DbModelInfoService.GetTableInfo(logicalConnectionName, tableName);
+			//DataSet dbModelInfo = DbModelInfoService.GetDbModelInfo(logicalConnectionName);
+//			TableDescribeForm describeForm = new TableDescribeForm(tableInfo);
+//			describeForm.Show();
+			TableDescribeViewContent tableDescribeViewContent = new TableDescribeViewContent(tableInfo, tableName);
+			WorkbenchSingleton.Workbench.ShowView(tableDescribeViewContent);
+		}
+	}
+	
+	class NodeAwareContextMenuStrip : ContextMenuStrip
+	{
+		TreeNode treeNodeAttached;
+		
+		public NodeAwareContextMenuStrip(TreeNode treeNodeAttached) : base()
+		{
+			this.treeNodeAttached = treeNodeAttached;		
+		}
+		
+		public TreeNode TreeNode {
+			get {
+				return treeNodeAttached;
+			}
+		}
+	}
+}
+
+
+
+
+