/********************************************************
* ADO.NET 2.0 Data Provider for SQLite Version 3.X
* Written by Robert Simpson (robert@blackcastlesoft.com)
*
* Released to the public domain, use at your own risk!
********************************************************/
namespace SQLite.Designer
{
using System;
using Microsoft.VisualStudio.Data;
using System.Windows.Forms.Design;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using System.Data.Common;
using System.Globalization;
using SQLite.Designer.Editors;
enum cmdid
{
CreateTable = 0x3520,
CreateView = 0x3521,
Alter = 0x3003,
Refresh = 0x3004,
Delete = 17,
Vacuum = 262,
Rekey = 263,
Triggers = 264,
}
internal sealed class SQLiteCommandHandler : DataViewCommandHandler
{
internal static readonly Guid guidDataCmdSet = new Guid("501822E1-B5AF-11d0-B4DC-00A0C91506EF");
internal static readonly Guid guidSQLiteCmdSet = new Guid("814658EE-A28E-4b97-BC33-4B1BC81EBECB");
internal static readonly Guid guidIFCmdId = new Guid("{74d21311-2aee-11d1-8bfb-00a0c90f26f7}");
internal static readonly Guid guidDavinci = new Guid("{732abe75-cd80-11d0-a2db-00aa00a3efff}");
internal static readonly Guid guidDavinciGrp = new Guid("{732abe74-cd80-11d0-a2db-00aa00a3efff}");
internal static readonly Guid guidQueryGroup = new Guid("5efc7975-14bc-11cf-9b2b-00aa00573819");
internal static Guid guidTableDesignContext = new Guid("4194fee5-6777-419f-a5fc-47a536df1bdb");
internal static Guid guidViewDesignContext = new Guid("b968e165-98e0-41f0-8fbe-a8ed1d246a90");
public SQLiteCommandHandler()
{
}
public override OleCommandStatus GetCommandStatus(int[] itemIds, OleCommand command, OleCommandTextType textType, OleCommandStatus status)
{
if (command.GroupGuid == guidSQLiteCmdSet)
{
switch ((cmdid)command.CommandId)
{
case cmdid.CreateTable:
case cmdid.Vacuum:
case cmdid.Rekey:
status.Supported = true;
status.Visible = true;
status.Enabled = true;
return status;
}
}
else if (command.GroupGuid == VSConstants.GUID_VSStandardCommandSet97)
{
switch ((VSConstants.VSStd97CmdID)command.CommandId)
{
case VSConstants.VSStd97CmdID.Delete:
status.Supported = true;
status.Visible = true;
status.Enabled = (SystemTableSelected == false && SystemIndexSelected == false);
return status;
}
}
else if (command.GroupGuid == guidDataCmdSet)
{
switch ((cmdid)command.CommandId)
{
case cmdid.Alter:
status.Supported = true;
status.Visible = true;
status.Enabled = (SystemTableSelected == false && SystemIndexSelected == false);
return status;
case cmdid.CreateTable:
case cmdid.CreateView:
status.Supported = true;
status.Visible = true;
status.Enabled = true;
return status;
}
}
base.GetCommandStatus(itemIds, command, textType, status);
return status;
}
private bool SystemTableSelected
{
get
{
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
int n;
object[] parts;
for (n = 0; n < items.Length; n++)
{
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
if (parts == null) return true;
if (parts[2].ToString().StartsWith("sqlite_", StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
}
private bool SystemIndexSelected
{
get
{
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
int n;
object[] parts;
for (n = 0; n < items.Length; n++)
{
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
if (parts == null) return true;
if (parts[2].ToString().StartsWith("sqlite_", StringComparison.OrdinalIgnoreCase))
return true;
if (parts.Length > 3)
{
if (parts[3].ToString().StartsWith("sqlite_autoindex_", StringComparison.OrdinalIgnoreCase)
|| parts[3].ToString().StartsWith("sqlite_master_PK_", StringComparison.OrdinalIgnoreCase))
return true;
}
}
return false;
}
}
public override object[] ExecuteCommand(int[] itemIds, OleCommand command, OleCommandExecutionOption executionOption, object arguments)
{
return base.ExecuteCommand(itemIds, command, executionOption, arguments);
}
/// <summary>
/// This method executes a specified command, potentially based
/// on parameters passed in from the data view support XML.
/// </summary>
public override object ExecuteCommand(int itemId, OleCommand command, OleCommandExecutionOption executionOption, object arguments)
{
object returnValue = null;
object[] args = arguments as object[];
if (command.GroupGuid == guidSQLiteCmdSet)
{
switch ((cmdid)command.CommandId)
{
case cmdid.Vacuum:
Vacuum();
break;
case cmdid.Rekey:
ChangePassword(itemId);
break;
default:
returnValue = base.ExecuteCommand(itemId, command, executionOption, arguments);
break;
}
}
else if (command.GroupGuid == VSConstants.GUID_VSStandardCommandSet97)
{
switch ((VSConstants.VSStd97CmdID)command.CommandId)
{
case VSConstants.VSStd97CmdID.Delete:
switch ((string)args[0])
{
case "Table":
DropSelectedTables();
break;
case "Index":
DropSelectedIndexes();
break;
case "View":
DropSelectedViews();
break;
}
break;
}
}
else if (command.GroupGuid == guidDataCmdSet)
{
switch ((cmdid)command.CommandId)
{
case cmdid.CreateTable:
DesignTable(itemId, null);
break;
case cmdid.CreateView:
DesignView(itemId, null);
break;
case cmdid.Alter:
switch ((string)args[0])
{
case "Table":
{
object[] parts;
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[0]);
DesignTable(itemId, parts[2].ToString());
}
break;
case "Index":
break;
case "View":
{
object[] parts;
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[0]);
DesignView(itemId, parts[2].ToString());
}
break;
}
break;
}
}
else
{
returnValue = base.ExecuteCommand(itemId, command, executionOption, arguments);
}
return returnValue;
}
private void DesignTable(int itemId, string tableName)
{
Microsoft.VisualStudio.OLE.Interop.IServiceProvider provider = DataViewHierarchyAccessor.ServiceProvider as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
IVsUIShell shell = DataViewHierarchyAccessor.ServiceProvider.GetService(typeof(IVsUIShell)) as IVsUIShell;
IVsUIHierarchy hier = DataViewHierarchyAccessor.Hierarchy;
IVsWindowFrame frame;
if (shell != null)
{
TableDesignerDoc form = new TableDesignerDoc(itemId, DataViewHierarchyAccessor, tableName);
IntPtr formptr = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(form);
Guid empty = Guid.Empty;
FakeHierarchy fake = new FakeHierarchy(form, hier);
int code = shell.CreateDocumentWindow(
0, // (uint)(__VSCREATEDOCWIN.CDW_fCreateNewWindow | __VSCREATEDOCWIN.CDW_RDTFLAGS_MASK) | (uint)(_VSRDTFLAGS.RDT_CanBuildFromMemory | _VSRDTFLAGS.RDT_NonCreatable | _VSRDTFLAGS.RDT_VirtualDocument | _VSRDTFLAGS.RDT_DontAddToMRU),
form.Name, fake, (uint)itemId, formptr, formptr, ref empty, null, ref guidTableDesignContext, provider, "", form.Caption, null, out frame);
if (frame != null)
{
object ret;
int prop = (int)__VSFPROPID.VSFPROPID_Caption;
code = frame.GetProperty(prop, out ret);
code = frame.Show();
}
}
}
private void DesignView(int itemId, string viewName)
{
Microsoft.VisualStudio.OLE.Interop.IServiceProvider provider = DataViewHierarchyAccessor.ServiceProvider as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
IVsUIShell shell = DataViewHierarchyAccessor.ServiceProvider.GetService(typeof(IVsUIShell)) as IVsUIShell;
IVsUIHierarchy hier = DataViewHierarchyAccessor.Hierarchy;
IVsWindowFrame frame;
if (shell != null)
{
ViewDesignerDoc form = new ViewDesignerDoc(itemId, DataViewHierarchyAccessor, viewName);
IntPtr formptr = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(form);
Guid empty = Guid.Empty;
FakeHierarchy fake = new FakeHierarchy(form, hier);
int code = shell.CreateDocumentWindow(
0, // (uint)(__VSCREATEDOCWIN.CDW_fCreateNewWindow | __VSCREATEDOCWIN.CDW_RDTFLAGS_MASK) | (uint)(_VSRDTFLAGS.RDT_CanBuildFromMemory | _VSRDTFLAGS.RDT_NonCreatable | _VSRDTFLAGS.RDT_VirtualDocument | _VSRDTFLAGS.RDT_DontAddToMRU),
form.Name, fake, (uint)itemId, formptr, formptr, ref empty, null, ref guidViewDesignContext, provider, "", form.Caption, null, out frame);
if (frame != null)
{
object ret;
int prop = (int)__VSFPROPID.VSFPROPID_Caption;
code = frame.GetProperty(prop, out ret);
code = frame.Show();
}
}
}
private void DropSelectedTables()
{
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
int n;
object[] parts;
for (n = 0; n < items.Length; n++)
{
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
if (parts == null) continue;
if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop table {0} ({1}), are you sure?", parts[2], parts[0]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
{
string sql = String.Format(CultureInfo.InvariantCulture, "DROP TABLE [{0}].[{1}]", parts[0], parts[2]);
DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
DataViewHierarchyAccessor.DropObjectNode(items[n]);
}
else throw new OperationCanceledException();
}
}
private void DropSelectedViews()
{
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
int n;
object[] parts;
for (n = 0; n < items.Length; n++)
{
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
if (parts == null) continue;
if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop view {0} ({1}), are you sure?", parts[2], parts[0]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
{
string sql = String.Format(CultureInfo.InvariantCulture, "DROP VIEW [{0}].[{1}]", parts[0], parts[2]);
DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
DataViewHierarchyAccessor.DropObjectNode(items[n]);
}
else throw new OperationCanceledException();
}
}
private void DropSelectedIndexes()
{
int[] items = DataViewHierarchyAccessor.GetSelectedItems();
int n;
object[] parts;
for (n = 0; n < items.Length; n++)
{
parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
if (parts == null) continue;
if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop index {0} ({1}), are you sure?", parts[3], parts[0]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
{
string sql = String.Format(CultureInfo.InvariantCulture, "DROP INDEX [{0}].[{1}]", parts[0], parts[3]);
DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
DataViewHierarchyAccessor.DropObjectNode(items[n]);
}
else throw new OperationCanceledException();
}
}
private void Vacuum()
{
DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults("VACUUM", (int)System.Data.CommandType.Text, null, 0);
}
private void ChangePassword(int itemId)
{
DataConnection dataConn = DataViewHierarchyAccessor.Connection;
DbConnection cnn = DataViewHierarchyAccessor.Connection.ConnectionSupport.ProviderObject as DbConnection;
if (cnn == null) return;
SQLiteConnectionProperties props = new SQLiteConnectionProperties(cnn.ConnectionString);
using (ChangePasswordDialog dlg = new ChangePasswordDialog(props))
{
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
if (String.IsNullOrEmpty(dlg.Password))
props.Remove("Password");
else
props["Password"] = dlg.Password;
System.Reflection.MethodInfo method = cnn.GetType().GetMethod("ChangePassword", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, new Type[] { typeof(string) }, null);
if (method != null)
{
method.Invoke(cnn, new object[] { dlg.Password });
dataConn.Close();
dataConn.DisplayConnectionString = props.ToDisplayString();
dataConn.Open();
Refresh(itemId);
}
}
}
}
public void Refresh(int itemId)
{
Refresh(DataViewHierarchyAccessor, itemId);
}
public static void Refresh(DataViewHierarchyAccessor accessor, int itemId)
{
IVsUIHierarchy hier = accessor.Hierarchy as IVsUIHierarchy;
Guid g = VSConstants.GUID_VSStandardCommandSet97;
hier.ExecCommand((uint)itemId, ref g, (uint)0xbd, (uint)OleCommandExecutionOption.DoDefault, IntPtr.Zero, IntPtr.Zero);
}
}
}