From 01ac4b40e3491a97e2246eb8f348294ae2c7346e Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Mon, 22 Aug 2011 05:57:57 +0000 Subject: [PATCH] Introduce new dialog "Synchronize database", see issue #1289. Complex code behind "Analyze" and "Apply" buttons is missing yet. --- packages/delphiXE/heidisql.dpr | 3 +- packages/delphiXE/heidisql.dproj | 3 + source/main.dfm | 9 ++ source/main.pas | 16 ++- source/syncdb.dfm | 210 +++++++++++++++++++++++++++++++ source/syncdb.pas | 179 ++++++++++++++++++++++++++ 6 files changed, 417 insertions(+), 3 deletions(-) create mode 100644 source/syncdb.dfm create mode 100644 source/syncdb.pas 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 @@
frmExportGrid
+ +
frmSyncDB
+
updater.res
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.