diff --git a/packages/delphiXE/heidisql.dpr b/packages/delphiXE/heidisql.dpr
index 6a376b75..9d6cd3ba 100644
--- a/packages/delphiXE/heidisql.dpr
+++ b/packages/delphiXE/heidisql.dpr
@@ -38,7 +38,8 @@ uses
event_editor in '..\..\source\event_editor.pas' {frmEventEditor: TFrame},
loginform in '..\..\source\loginform.pas' {frmLogin},
Cromis.DirectoryWatch in '..\..\source\Cromis.DirectoryWatch.pas',
- exportgrid in '..\..\source\exportgrid.pas' {frmExportGrid};
+ exportgrid in '..\..\source\exportgrid.pas' {frmExportGrid},
+ syncdb in '..\..\source\syncdb.pas' {frmSyncDB};
{$R ..\..\res\icon.RES}
{$R ..\..\res\version.RES}
diff --git a/packages/delphiXE/heidisql.dproj b/packages/delphiXE/heidisql.dproj
index cc007643..316d8706 100644
--- a/packages/delphiXE/heidisql.dproj
+++ b/packages/delphiXE/heidisql.dproj
@@ -212,6 +212,9 @@
+
+
+
diff --git a/source/main.dfm b/source/main.dfm
index 7b5dbf43..b523be99 100644
--- a/source/main.dfm
+++ b/source/main.dfm
@@ -1850,6 +1850,9 @@ object MainForm: TMainForm
object Exportdata1: TMenuItem
Action = actExportData
end
+ object Synchronizedatabase1: TMenuItem
+ Action = actSynchronizeDatabase
+ end
end
object Help1: TMenuItem
Tag = 22
@@ -2583,6 +2586,12 @@ object MainForm: TMainForm
ImageIndex = 165
OnExecute = actToggleCommentExecute
end
+ object actSynchronizeDatabase: TAction
+ Category = 'Export/Import'
+ Caption = 'Synchronize database'
+ ImageIndex = 27
+ OnExecute = actSynchronizeDatabaseExecute
+ end
end
object SaveDialog2: TSaveDialog
DefaultExt = 'reg'
diff --git a/source/main.pas b/source/main.pas
index 9f0716c5..68687b10 100644
--- a/source/main.pas
+++ b/source/main.pas
@@ -18,7 +18,7 @@ uses
CommCtrl, Contnrs, Generics.Collections, SynEditExport, SynExportHTML, Math, ExtDlgs, Registry, AppEvnts,
routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor,
TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection,
- insertfiles, searchreplace, loaddata, copytable, VTHeaderPopup, Cromis.DirectoryWatch;
+ insertfiles, searchreplace, loaddata, copytable, VTHeaderPopup, Cromis.DirectoryWatch, SyncDB;
type
@@ -503,6 +503,8 @@ type
actCancelOperation: TAction;
actToggleComment: TAction;
Uncomment1: TMenuItem;
+ actSynchronizeDatabase: TAction;
+ Synchronizedatabase1: TMenuItem;
Disconnect1: TMenuItem;
procedure actCreateDBObjectExecute(Sender: TObject);
procedure menuConnectionsPopup(Sender: TObject);
@@ -812,6 +814,7 @@ type
procedure actCancelOperationExecute(Sender: TObject);
procedure AnyGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure actToggleCommentExecute(Sender: TObject);
+ procedure actSynchronizeDatabaseExecute(Sender: TObject);
procedure DBtreeBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect;
var ContentRect: TRect);
@@ -3299,6 +3302,15 @@ begin
end;
+procedure TMainForm.actSynchronizeDatabaseExecute(Sender: TObject);
+var
+ SyncForm: TfrmSyncDB;
+begin
+ SyncForm := TfrmSyncDB.Create(Self);
+ SyncForm.ShowModal;
+end;
+
+
{***
Show SQL Help window directly using a keyword
@param String SQL-keyword
@@ -9406,7 +9418,7 @@ var
begin
// Resize "Size" column in dbtree to hold widest possible byte numbers without cutting text
VT := Sender as TVirtualStringTree;
- if coVisible in VT.Header.Columns[1].Options then
+ if (VT.Header.Columns.Count >= 2) and (coVisible in VT.Header.Columns[1].Options) then
VT.Header.Columns[1].Width := TextWidth(VT.Canvas, FormatByteNumber(SIZE_MB-1))+VT.TextMargin*2;
end;
diff --git a/source/syncdb.dfm b/source/syncdb.dfm
new file mode 100644
index 00000000..8bd57142
--- /dev/null
+++ b/source/syncdb.dfm
@@ -0,0 +1,210 @@
+object frmSyncDB: TfrmSyncDB
+ Left = 0
+ Top = 0
+ Caption = 'frmSyncDB'
+ ClientHeight = 373
+ ClientWidth = 539
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poMainFormCenter
+ OnClose = FormClose
+ OnCreate = FormCreate
+ DesignSize = (
+ 539
+ 373)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object lblSource: TLabel
+ Left = 8
+ Top = 8
+ Width = 169
+ Height = 13
+ Caption = 'Select source database or table(s):'
+ end
+ object lblDifferences: TLabel
+ Left = 207
+ Top = 191
+ Width = 59
+ Height = 13
+ Caption = 'Differences:'
+ end
+ object treeSource: TVirtualStringTree
+ Left = 8
+ Top = 24
+ Width = 193
+ Height = 310
+ AccessibleName = 'tree'
+ Anchors = [akLeft, akTop, akBottom]
+ Header.AutoSizeIndex = 0
+ Header.DefaultHeight = 17
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'Tahoma'
+ Header.Font.Style = []
+ Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs]
+ Images = MainForm.ImageListMain
+ TabOrder = 0
+ TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick]
+ TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed]
+ OnChange = treeSourceChange
+ OnGetText = treeSourceGetText
+ OnPaintText = treeSourcePaintText
+ OnGetImageIndex = treeSourceGetImageIndex
+ OnGetNodeDataSize = treeSourceGetNodeDataSize
+ OnInitChildren = treeSourceInitChildren
+ OnInitNode = treeSourceInitNode
+ Columns = <
+ item
+ Position = 0
+ Width = 193
+ WideText = 'Name'
+ end>
+ end
+ object grpTarget: TGroupBox
+ Left = 207
+ Top = 8
+ Width = 324
+ Height = 105
+ Anchors = [akLeft, akTop, akRight]
+ Caption = 'Target database or table'
+ TabOrder = 1
+ DesignSize = (
+ 324
+ 105)
+ object lblTargetServer: TLabel
+ Left = 9
+ Top = 21
+ Width = 36
+ Height = 13
+ Caption = 'Server:'
+ end
+ object lblTargetDatabase: TLabel
+ Left = 9
+ Top = 48
+ Width = 50
+ Height = 13
+ Caption = 'Database:'
+ end
+ object lblTargetTable: TLabel
+ Left = 9
+ Top = 75
+ Width = 30
+ Height = 13
+ Caption = 'Table:'
+ end
+ object comboTargetServer: TComboBox
+ Left = 88
+ Top = 18
+ Width = 228
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ OnChange = comboTargetServerChange
+ end
+ object comboTargetDatabase: TComboBox
+ Left = 88
+ Top = 45
+ Width = 228
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 1
+ OnChange = comboTargetDatabaseChange
+ end
+ object comboTargetTable: TComboBox
+ Left = 88
+ Top = 72
+ Width = 228
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 2
+ end
+ end
+ object btnClose: TButton
+ Left = 456
+ Top = 340
+ Width = 75
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Cancel = True
+ Caption = 'Close'
+ ImageIndex = 26
+ Images = MainForm.ImageListMain
+ ModalResult = 2
+ TabOrder = 2
+ end
+ object btnApply: TButton
+ Left = 375
+ Top = 340
+ Width = 75
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = 'Apply'
+ Enabled = False
+ ImageIndex = 120
+ Images = MainForm.ImageListMain
+ TabOrder = 3
+ end
+ object btnAnalyze: TButton
+ Left = 294
+ Top = 340
+ Width = 75
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = 'Analyze'
+ ImageIndex = 146
+ Images = MainForm.ImageListMain
+ TabOrder = 4
+ end
+ object grpOptions: TGroupBox
+ Left = 207
+ Top = 119
+ Width = 324
+ Height = 66
+ Anchors = [akLeft, akTop, akRight]
+ Caption = 'Options'
+ TabOrder = 5
+ object radioOptionsStructure: TCheckBox
+ Left = 88
+ Top = 16
+ Width = 97
+ Height = 17
+ Caption = 'Structure'
+ TabOrder = 0
+ end
+ object radioOptionsData: TCheckBox
+ Left = 88
+ Top = 39
+ Width = 97
+ Height = 17
+ Caption = 'Data'
+ TabOrder = 1
+ end
+ end
+ object treeDifferences: TVirtualStringTree
+ Left = 207
+ Top = 208
+ Width = 324
+ Height = 126
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Header.AutoSizeIndex = 0
+ Header.DefaultHeight = 17
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'Tahoma'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Images = MainForm.ImageListMain
+ TabOrder = 6
+ Columns = <>
+ end
+end
diff --git a/source/syncdb.pas b/source/syncdb.pas
new file mode 100644
index 00000000..189a77a2
--- /dev/null
+++ b/source/syncdb.pas
@@ -0,0 +1,179 @@
+unit syncdb;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, VirtualTrees;
+
+type
+ TfrmSyncDB = class(TForm)
+ treeSource: TVirtualStringTree;
+ lblSource: TLabel;
+ grpTarget: TGroupBox;
+ comboTargetServer: TComboBox;
+ lblTargetServer: TLabel;
+ lblTargetDatabase: TLabel;
+ comboTargetDatabase: TComboBox;
+ comboTargetTable: TComboBox;
+ lblTargetTable: TLabel;
+ btnClose: TButton;
+ btnApply: TButton;
+ btnAnalyze: TButton;
+ grpOptions: TGroupBox;
+ radioOptionsStructure: TCheckBox;
+ radioOptionsData: TCheckBox;
+ treeDifferences: TVirtualStringTree;
+ lblDifferences: TLabel;
+ procedure treeSourceChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure treeSourceGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
+ procedure treeSourceGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+ procedure treeSourceGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: string);
+ procedure treeSourceInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ var ChildCount: Cardinal);
+ procedure treeSourceInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure treeSourcePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
+ procedure FormCreate(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure comboTargetServerChange(Sender: TObject);
+ procedure comboTargetDatabaseChange(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+
+implementation
+
+uses main, helpers, dbconnection;
+
+{$R *.dfm}
+
+
+
+procedure TfrmSyncDB.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Action := caFree;
+end;
+
+
+procedure TfrmSyncDB.FormCreate(Sender: TObject);
+begin
+ InheritFont(Font);
+ SetWindowSizeGrip(Self.Handle, True);
+ FixVT(treeSource);
+ FixVT(treeDifferences);
+ treeSource.RootNodeCount := Mainform.DBtree.RootNodeCount;
+ MainReg.OpenKey(RegPath + REGKEY_SESSIONS, True);
+ MainReg.GetKeyNames(comboTargetServer.Items);
+ comboTargetServer.Items.Insert(0, 'Select server session ...');
+ comboTargetServer.ItemIndex := 0;
+end;
+
+
+procedure TfrmSyncDB.comboTargetServerChange(Sender: TObject);
+var
+ Parameters: TConnectionParameters;
+ Connection: TDBConnection;
+begin
+ comboTargetDatabase.Clear;
+ if comboTargetServer.ItemIndex > 0 then begin
+ Parameters := LoadConnectionParams(comboTargetServer.Text);
+ Connection := Parameters.CreateConnection(Self);
+ Connection.OnLog := MainForm.LogSQL;
+ Connection.LogPrefix := comboTargetServer.Text;
+ Connection.Active := True;
+ comboTargetDatabase.Items.Assign(Connection.AllDatabases);
+ Connection.Active := False;
+ Connection.Free;
+ end;
+ comboTargetDatabase.Items.Insert(0, '[Same as source]');
+ comboTargetDatabase.ItemIndex := 0;
+end;
+
+
+procedure TfrmSyncDB.comboTargetDatabaseChange(Sender: TObject);
+var
+ Parameters: TConnectionParameters;
+ Connection: TDBConnection;
+ Objects: TDBObjectList;
+ Obj: TDBObject;
+begin
+ comboTargetTable.Clear;
+ if comboTargetDatabase.ItemIndex > 0 then begin
+ Parameters := LoadConnectionParams(comboTargetServer.Text);
+ Connection := Parameters.CreateConnection(Self);
+ Connection.OnLog := MainForm.LogSQL;
+ Connection.LogPrefix := comboTargetServer.Text;
+ Connection.Active := True;
+ Objects := Connection.GetDBObjects(comboTargetDatabase.Text);
+ for Obj in Objects do begin
+ if Obj.NodeType = lntTable then
+ comboTargetTable.Items.Add(Obj.Name);
+ end;
+ Connection.Active := False;
+ Connection.Free;
+ end;
+ comboTargetTable.Items.Insert(0, '[Same as source]');
+ comboTargetTable.ItemIndex := 0;
+end;
+
+
+procedure TfrmSyncDB.treeSourceChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+begin
+ MainForm.DBtree.OnChange(Sender, Node);
+end;
+
+
+procedure TfrmSyncDB.treeSourceGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
+begin
+ MainForm.DBtree.OnGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex);
+end;
+
+
+procedure TfrmSyncDB.treeSourceGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+begin
+ MainForm.DBtree.OnGetNodeDataSize(Sender, NodeDataSize);
+end;
+
+
+procedure TfrmSyncDB.treeSourceGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: string);
+begin
+ MainForm.DBtree.OnGetText(Sender, Node, Column, TextType, CellText);
+end;
+
+
+procedure TfrmSyncDB.treeSourceInitChildren(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var ChildCount: Cardinal);
+begin
+ MainForm.DBtree.OnInitChildren(Sender, Node, ChildCount);
+end;
+
+
+procedure TfrmSyncDB.treeSourceInitNode(Sender: TBaseVirtualTree; ParentNode,
+ Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
+begin
+ MainForm.DBtree.OnInitNode(Sender, ParentNode, Node, InitialStates);
+ if Sender.GetNodeLevel(Node) in [1, 2] then begin
+ Node.CheckType := ctTriStateCheckBox;
+ Node.CheckState := csUncheckedNormal;
+ end;
+end;
+
+
+procedure TfrmSyncDB.treeSourcePaintText(Sender: TBaseVirtualTree;
+ const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType);
+begin
+ MainForm.DBtree.OnPaintText(Sender, TargetCanvas, Node, Column, TextType);
+end;
+
+end.