From 7f32b33505a8d0586818c0d22a30f8e915bdccbe Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Tue, 12 May 2009 22:24:09 +0000 Subject: [PATCH] Issue #436: Implement a new table editor dialog. Nukes both create + alter table dialogs. --- components/heidisql/include/const.inc | 2 + packages/delphi11/heidisql.dpr | 5 +- packages/delphi11/heidisql.dproj | 7 +- res/icons/gridcheckbox_checked.png | Bin 0 -> 189 bytes res/icons/gridcheckbox_unchecked.png | Bin 0 -> 163 bytes res/icons/key_fulltext.png | Bin 0 -> 414 bytes res/icons/key_index.png | Bin 0 -> 413 bytes res/icons/key_spatial.png | Bin 0 -> 406 bytes res/icons/key_unique.png | Bin 0 -> 406 bytes source/createtable.dfm | 415 ------- source/createtable.pas | 744 ------------- source/exportsql.pas | 2 +- source/grideditlinks.pas | 236 ++++ source/helpers.pas | 12 +- source/main.dfm | 109 +- source/main.pas | 38 +- source/mysql_structures.pas | 15 + source/table_editor.dfm | 704 ++++++++++++ source/table_editor.pas | 1441 +++++++++++++++++++++++++ source/tbl_properties.dfm | 185 ---- source/tbl_properties.pas | 319 ------ 21 files changed, 2519 insertions(+), 1715 deletions(-) create mode 100644 res/icons/gridcheckbox_checked.png create mode 100644 res/icons/gridcheckbox_unchecked.png create mode 100644 res/icons/key_fulltext.png create mode 100644 res/icons/key_index.png create mode 100644 res/icons/key_spatial.png create mode 100644 res/icons/key_unique.png delete mode 100644 source/createtable.dfm delete mode 100644 source/createtable.pas create mode 100644 source/table_editor.dfm create mode 100644 source/table_editor.pas delete mode 100644 source/tbl_properties.dfm delete mode 100644 source/tbl_properties.pas diff --git a/components/heidisql/include/const.inc b/components/heidisql/include/const.inc index e56d3d73..63362a0d 100644 --- a/components/heidisql/include/const.inc +++ b/components/heidisql/include/const.inc @@ -112,6 +112,7 @@ const REGNAME_PROCEDITOR_HEIGHT = 'ProcedureEditorHeight'; REGNAME_TABLEEDITOR_WIDTH = 'TableEditorWidth'; REGNAME_TABLEEDITOR_HEIGHT = 'TableEditorHeight'; + REGNAME_TABLEEDITOR_TABSHEIGHT = 'TableEditorTabsHeight'; REGNAME_HOST = 'Host'; DEFAULT_HOST = '127.0.0.1'; REGNAME_USER = 'User'; @@ -225,6 +226,7 @@ const ICONINDEX_INDEXKEY = 23; ICONINDEX_UNIQUEKEY = 24; ICONINDEX_FULLTEXTKEY = 22; + ICONINDEX_SPATIALKEY = 126; ICONINDEX_SERVER = 1; ICONINDEX_DB = 5; ICONINDEX_DB_HIGHLIGHT = 70; diff --git a/packages/delphi11/heidisql.dpr b/packages/delphi11/heidisql.dpr index c82759d2..969a78c4 100644 --- a/packages/delphi11/heidisql.dpr +++ b/packages/delphi11/heidisql.dpr @@ -7,10 +7,8 @@ uses main in '..\..\source\main.pas' {MainForm}, about in '..\..\source\about.pas' {AboutBox}, connections in '..\..\source\connections.pas' {connform}, - createtable in '..\..\source\createtable.pas' {CreateTableForm}, fieldeditor in '..\..\source\fieldeditor.pas' {FieldEditForm}, exportsql in '..\..\source\exportsql.pas' {ExportSQLForm}, - tbl_properties in '..\..\source\tbl_properties.pas' {tbl_properties_form}, loaddata in '..\..\source\loaddata.pas' {loaddataform}, usermanager in '..\..\source\usermanager.pas' {UserManagerForm}, options in '..\..\source\options.pas' {optionsform}, @@ -42,7 +40,8 @@ uses grideditlinks in '..\..\source\grideditlinks.pas', uVistaFuncs in '..\..\source\uVistaFuncs.pas', dataviewsave in '..\..\source\dataviewsave.pas' {FrmDataViewSave}, - routine_editor in '..\..\source\routine_editor.pas' {frmRoutineEditor}; + routine_editor in '..\..\source\routine_editor.pas' {frmRoutineEditor}, + table_editor in '..\..\source\table_editor.pas' {frmTableEditor}; {$R ..\..\res\icon.RES} {$R ..\..\res\version.RES} diff --git a/packages/delphi11/heidisql.dproj b/packages/delphi11/heidisql.dproj index 4997cd64..512471fc 100644 --- a/packages/delphi11/heidisql.dproj +++ b/packages/delphi11/heidisql.dproj @@ -129,9 +129,6 @@
CreateDatabaseForm
- -
CreateTableForm
-
FrmDataViewSave
@@ -190,8 +187,8 @@
frmSQLhelp
- -
tbl_properties_form
+ +
frmTableEditor
frmTextEditor
diff --git a/res/icons/gridcheckbox_checked.png b/res/icons/gridcheckbox_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc5d24fbd69bee6f98b321c1e7ea106b242191d GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDU1=9b4fZ_jv0|y#_fB^^_ zAngAjIiM_9377>`c%(|>6i|SFMGaQgJKw>_tHa1rDZw45rwH zf7{PAeNx_cuX520KB*g$tZ7f1+&FwVI5OB51Tb&E@wK`9XZ`c%(|>6i|S z7~ViL;~0}p*0D~|2$zBL!(~*Z%K3@Z`UL<)ybuDZ4$0Hbgt~SXxN+ zmA_NwKlxua;r9RHY1jUH)t&q*pRg>FC_~KhPOhJ|^wIy~mPh~l=05sgGV%8Rvd;Ve zt;>&nAj$y!>|0fv*!N)@Vxu~{W9+VH>uwJ8Lt7rfHQF{IeW^Z`24-l zyxafX6Yu{I%7JLsD%$;BHfa)WF91V4#;oAvx!!sA|NEre|L+iW|G!c8?k@)AdtVq< z?0+GbI6WAz?LeE)Pg?Tmze&*T{|>SD|C?p+{;Ck!lO$2PoL9PRJugAOI~AWlS=IUI zzk4!R^Jj(dzF2~qkQL~qZ*8?NJowTyZ^r}0=&4~OX&$4%P) z7~UZFm?l&HF`drxvyP{8j;SY;?Ax3pDg|BF(*7TOvh#oKCI7dXyOlhMHYD$uc3S?~*NXo)pY-~gvP?dbC_{=)nyp{{Xx9JsN5%gaJnH*D<#x&c-uq?$ ztB+ZKAj*J(WBP5=?$!OTzMu5J@qXt2qWj_h^X~ioZ`f_}8Lt7rfHSE)>v*c-yvMzw z+oAtc@4NpmxE}=8T)tcDd+H=v++F~NcueU@vvUjY_x{hk@AE(5zQh0g-9}%k_ZqyY z*>CtFWx8B2UfY2-pI`oH(*KCtCjXPcn$5n(^e7}%FPGr0UN6l{(C-!Jolf>Xs`{S+ zbT&})=cqn~Sc0066=ZMKYb`x!|FUR@>4W&GieV&a9=eJF-m8}U5o;$x00000NkvXX Hu0mjf`n%9- literal 0 HcmV?d00001 diff --git a/res/icons/key_spatial.png b/res/icons/key_spatial.png new file mode 100644 index 0000000000000000000000000000000000000000..7078dadf79b277f869dec69390c6197b18800456 GIT binary patch literal 406 zcmV;H0crk;P) z80KKdHztNH-#R&0{5;LD<6AQ6zTNY!z-HZ_|LZUR`7gWj&s&B)Z#;-MWXHEO)n$MF zRsanM*zo6n@ZmrIW%hjg%CPxzByonU{s z2jUFa@~tg$?VtZz9e@6t_y74X-SFo>UoFsplW#ubH(_=3V?XU(=Ut%-@ITv`tb$BhQq;l zZRcC}^L*7Vpr%S7F8%YLdFj)y3^UdzG2Fky%kcO)FG0U^ul#v3U>4BXK-+vxO`@%@mJY-b^07WgK8x*K3RR91007*qoM6N<$f^&<( AjQ{`u literal 0 HcmV?d00001 diff --git a/res/icons/key_unique.png b/res/icons/key_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..34a7cde98aa7a8a89be23c79d8dbb1596b7dc599 GIT binary patch literal 406 zcmV;H0crk;P) z7~bFqpAgdzKEBT1>Jq1c>|~OC`-4xc;9r8r|9>a8{{QEo{q{YdtOwDC0BubB=WF!$ z--^cn|H`8N|I3K||3gdb>vcZWNTLk+A;!1<-|DXa|C$2-|C?R@|6gI`|9{P4|G$Y! zejv^OKEAepZ7Ki%<(vQiSML1(U#jN+f045P-;3&f#%lo3=_bFGB~JY|SG@Nx7N{vi z;QzlwWr$`zmG6i7^l^Iu7~(NMg!s<=n^p zA4^aZvVy04e68=5WL~}yk$7;JPa%vX%|ll)04Q#Y?xrIQqyPW_07*qoM6N<$f+_0A AtpET3 literal 0 HcmV?d00001 diff --git a/source/createtable.dfm b/source/createtable.dfm deleted file mode 100644 index c4d692df..00000000 --- a/source/createtable.dfm +++ /dev/null @@ -1,415 +0,0 @@ -object CreateTableForm: TCreateTableForm - Left = 584 - Top = 95 - Caption = 'Create Table...' - ClientHeight = 330 - ClientWidth = 493 - Color = clBtnFace - Constraints.MinHeight = 360 - Constraints.MinWidth = 500 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poMainFormCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - DesignSize = ( - 493 - 330) - PixelsPerInch = 96 - TextHeight = 13 - object Label1: TLabel - Left = 8 - Top = 10 - Width = 69 - Height = 13 - Caption = 'Table name:' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [fsBold] - ParentFont = False - end - object Label2: TLabel - Left = 8 - Top = 101 - Width = 44 - Height = 13 - Caption = 'Columns:' - end - object Label3: TLabel - Left = 8 - Top = 60 - Width = 49 - Height = 13 - Caption = 'Comment:' - end - object Label4: TLabel - Left = 8 - Top = 35 - Width = 62 - Height = 13 - Caption = 'In database:' - end - object Label5: TLabel - Left = 255 - Top = 10 - Width = 55 - Height = 13 - Anchors = [akTop, akRight] - Caption = 'Table type:' - OnClick = Button1Click - end - object lblCharset: TLabel - Left = 255 - Top = 35 - Width = 70 - Height = 13 - Anchors = [akTop, akRight] - Caption = 'Character set:' - end - object lblCollation: TLabel - Left = 255 - Top = 60 - Width = 45 - Height = 13 - Anchors = [akTop, akRight] - Caption = 'Collation:' - end - object ButtonMoveUp: TPngSpeedButton - Left = 182 - Top = 235 - Width = 25 - Height = 25 - Anchors = [akTop, akRight] - Flat = True - OnClick = ButtonMoveUpClick - end - object ButtonMoveDown: TPngSpeedButton - Left = 182 - Top = 260 - Width = 25 - Height = 25 - Anchors = [akTop, akRight] - Flat = True - OnClick = ButtonMoveDownClick - end - object GroupBox1: TGroupBox - Left = 255 - Top = 101 - Width = 228 - Height = 187 - Anchors = [akTop, akRight, akBottom] - Caption = 'Column properties:' - TabOrder = 11 - object lblFieldType: TLabel - Left = 16 - Top = 24 - Width = 28 - Height = 13 - Caption = 'Type:' - Enabled = False - end - object lblLengthSet: TLabel - Left = 16 - Top = 48 - Width = 57 - Height = 13 - Caption = 'Length/Set:' - Enabled = False - end - object lblDefault: TLabel - Left = 16 - Top = 72 - Width = 68 - Height = 13 - Caption = 'Default Value:' - Enabled = False - end - object ComboBoxType: TComboBox - Left = 96 - Top = 24 - Width = 105 - Height = 21 - Style = csDropDownList - Enabled = False - ItemHeight = 13 - TabOrder = 0 - OnChange = ComboBoxTypeChange - Items.Strings = ( - 'TINYINT' - 'SMALLINT' - 'MEDIUMINT' - 'INT' - 'BIGINT' - 'FLOAT' - 'DOUBLE' - 'DECIMAL' - 'DATE' - 'DATETIME' - 'TIMESTAMP' - 'TIME' - 'YEAR' - 'CHAR' - 'VARCHAR' - 'TINYBLOB' - 'TINYTEXT' - 'TEXT' - 'BLOB' - 'MEDIUMBLOB' - 'MEDIUMTEXT' - 'LONGBLOB' - 'LONGTEXT' - 'ENUM' - 'SET') - end - object EditLengthSet: TEdit - Left = 96 - Top = 48 - Width = 105 - Height = 21 - Enabled = False - TabOrder = 1 - OnChange = EditLengthSetChange - end - object EditDefault: TEdit - Left = 96 - Top = 72 - Width = 105 - Height = 21 - Enabled = False - TabOrder = 2 - OnChange = EditDefaultChange - end - object CheckBoxPrimary: TCheckBox - Left = 16 - Top = 104 - Width = 57 - Height = 17 - Caption = 'Primary' - Enabled = False - TabOrder = 3 - OnClick = CheckBoxPrimaryClick - end - object CheckBoxBinary: TCheckBox - Left = 16 - Top = 128 - Width = 49 - Height = 17 - Caption = 'Binary' - Enabled = False - TabOrder = 6 - OnClick = CheckBoxBinaryClick - end - object CheckBoxIndex: TCheckBox - Left = 88 - Top = 104 - Width = 49 - Height = 17 - Caption = 'Index' - Enabled = False - TabOrder = 4 - OnClick = CheckBoxIndexClick - end - object CheckBoxUnique: TCheckBox - Left = 144 - Top = 104 - Width = 57 - Height = 17 - Caption = 'Unique' - Enabled = False - TabOrder = 5 - OnClick = CheckBoxUniqueClick - end - object CheckBoxUnsigned: TCheckBox - Left = 16 - Top = 144 - Width = 73 - Height = 17 - Caption = 'Unsigned' - Enabled = False - TabOrder = 7 - OnClick = CheckBoxUnsignedClick - end - object CheckBoxZerofill: TCheckBox - Left = 16 - Top = 160 - Width = 57 - Height = 17 - Caption = 'Zerofill' - Enabled = False - TabOrder = 8 - OnClick = CheckBoxZerofillClick - end - object CheckBoxNotNull: TCheckBox - Left = 88 - Top = 128 - Width = 65 - Height = 17 - Caption = 'Not Null' - Enabled = False - TabOrder = 9 - OnClick = CheckBoxNotNullClick - end - object CheckBoxAutoincrement: TCheckBox - Left = 88 - Top = 144 - Width = 89 - Height = 17 - Caption = 'AutoIncrement' - Enabled = False - TabOrder = 10 - OnClick = CheckBoxAutoincrementClick - end - end - object EditTablename: TTntEdit - Left = 88 - Top = 8 - Width = 154 - Height = 21 - Anchors = [akLeft, akTop, akRight] - MaxLength = 64 - TabOrder = 0 - OnChange = EditTablenameChange - end - object EditDescription: TTntEdit - Left = 88 - Top = 58 - Width = 154 - Height = 21 - Hint = 'A 60 characters comment for this table' - Anchors = [akLeft, akTop, akRight] - MaxLength = 60 - ParentShowHint = False - ShowHint = True - TabOrder = 2 - end - object ListboxColumns: TListBox - Left = 8 - Top = 146 - Width = 169 - Height = 142 - Anchors = [akLeft, akTop, akRight, akBottom] - ExtendedSelect = False - ItemHeight = 13 - TabOrder = 7 - OnClick = ListboxColumnsClick - end - object ButtonAdd: TButton - Left = 182 - Top = 122 - Width = 60 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Add' - TabOrder = 8 - OnClick = Button1Click - end - object ButtonDelete: TButton - Left = 182 - Top = 186 - Width = 60 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Remove' - Enabled = False - TabOrder = 10 - OnClick = ButtonDeleteClick - end - object ButtonChange: TButton - Left = 182 - Top = 154 - Width = 60 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Change' - Enabled = False - TabOrder = 9 - OnClick = ButtonChangeClick - end - object EditFieldname: TEdit - Left = 8 - Top = 122 - Width = 169 - Height = 21 - Anchors = [akLeft, akTop, akRight] - MaxLength = 64 - TabOrder = 6 - Text = 'FieldName' - OnChange = EditFieldnameChange - OnEnter = EditFieldnameEnter - OnExit = EditFieldnameExit - end - object DBComboBox: TTntComboBox - Left = 88 - Top = 33 - Width = 154 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 1 - end - object ComboBoxTableType: TComboBox - Left = 329 - Top = 8 - Width = 153 - Height = 21 - Style = csDropDownList - Anchors = [akTop, akRight] - ItemHeight = 13 - TabOrder = 3 - end - object comboCharset: TComboBox - Left = 329 - Top = 33 - Width = 153 - Height = 21 - Style = csDropDownList - Anchors = [akTop, akRight] - ItemHeight = 13 - Sorted = True - TabOrder = 4 - OnChange = comboCharsetChange - end - object comboCollation: TComboBox - Left = 329 - Top = 58 - Width = 153 - Height = 21 - Style = csDropDownList - Anchors = [akTop, akRight] - ItemHeight = 13 - Sorted = True - TabOrder = 5 - end - object ButtonCreate: TButton - Left = 314 - Top = 297 - Width = 83 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Create!' - Default = True - Enabled = False - ModalResult = 1 - TabOrder = 12 - OnClick = ButtonCreateClick - end - object ButtonCancel: TButton - Left = 402 - Top = 297 - Width = 83 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 13 - end -end diff --git a/source/createtable.pas b/source/createtable.pas deleted file mode 100644 index f3245a73..00000000 --- a/source/createtable.pas +++ /dev/null @@ -1,744 +0,0 @@ -unit createtable; - - -// ------------------------------------- -// Create table -// ------------------------------------- - - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ExtCtrls, Buttons, ComCtrls, ImgList, ToolWin, - Menus, db, PngSpeedButton, TntStdCtrls; - -type - TCreateTableForm = class(TForm) - ButtonCancel: TButton; - ButtonCreate: TButton; - GroupBox1: TGroupBox; - ComboBoxType: TComboBox; - EditLengthSet: TEdit; - EditDefault: TEdit; - CheckBoxPrimary: TCheckBox; - CheckBoxBinary: TCheckBox; - CheckBoxIndex: TCheckBox; - CheckBoxUnique: TCheckBox; - CheckBoxUnsigned: TCheckBox; - CheckBoxZerofill: TCheckBox; - CheckBoxNotNull: TCheckBox; - CheckBoxAutoincrement: TCheckBox; - lblFieldType: TLabel; - lblLengthSet: TLabel; - lblDefault: TLabel; - EditTablename: TTNTEdit; - Label1: TLabel; - Label2: TLabel; - EditDescription: TTNTEdit; - Label3: TLabel; - ButtonMoveUp: TPngSpeedButton; - ButtonMoveDown: TPngSpeedButton; - ButtonAdd: TButton; - ButtonDelete: TButton; - ButtonChange: TButton; - EditFieldname: TEdit; - Label4: TLabel; - DBComboBox: TTNTComboBox; - ComboBoxTableType: TComboBox; - Label5: TLabel; - ListboxColumns: TListBox; - lblCharset: TLabel; - lblCollation: TLabel; - comboCharset: TComboBox; - comboCollation: TComboBox; - procedure FormCreate(Sender: TObject); - procedure EditTablenameChange(Sender: TObject); - procedure ButtonCreateClick(Sender: TObject); - procedure ButtonDeleteClick(Sender: TObject); - procedure CheckBoxPrimaryClick(Sender: TObject); - procedure CheckBoxIndexClick(Sender: TObject); - procedure CheckBoxUniqueClick(Sender: TObject); - procedure CheckBoxBinaryClick(Sender: TObject); - procedure CheckBoxUnsignedClick(Sender: TObject); - procedure CheckBoxZerofillClick(Sender: TObject); - procedure CheckBoxNotNullClick(Sender: TObject); - procedure CheckBoxAutoincrementClick(Sender: TObject); - procedure Button1Click(Sender: TObject); - procedure EditFieldnameChange(Sender: TObject); - procedure ListboxColumnsClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure refreshColumnList(Sender: TObject); - procedure ButtonChangeClick(Sender: TObject); - procedure ComboBoxTypeChange(Sender: TObject); - procedure EditLengthSetChange(Sender: TObject); - procedure EditDefaultChange(Sender: TObject); - procedure disableControls(Sender: TObject); - procedure enableControls(Sender: TObject); - procedure fillControls(Sender: TObject); - procedure checktypes(Sender: TObject); - procedure ButtonMoveUpClick(Sender: TObject); - procedure ButtonMoveDownClick(Sender: TObject); - procedure comboCharsetChange(Sender: TObject); - procedure EditFieldnameEnter(Sender: TObject); - procedure EditFieldnameExit(Sender: TObject); - procedure FormDestroy(Sender: TObject); - private - index : Integer; - dsCollations : TDataSet; - defaultCharset : String; - { Private declarations } - public - { Public declarations } - end; - -{$I const.inc} - -implementation - -uses - Main, helpers, mysql_structures; - -var - cols : array of TMysqlField; - -{$R *.DFM} - - -{** - Fetch list with character sets and collations from the server - @todo: share these lists with other forms, fx createdatabase -} -procedure TCreateTableForm.FormCreate(Sender: TObject); -var - charset : String; -begin - // Assign images from main imagelist to speedbuttons - ButtonMoveUp.PngImage := Mainform.PngImageListMain.PngImages[74].PngImage; - ButtonMoveDown.PngImage := Mainform.PngImageListMain.PngImages[75].PngImage; - - InheritFont(Font); - - Width := GetRegValue(REGNAME_CRTABLEWINWIDTH, Width); - Height := GetRegValue(REGNAME_CRTABLEWINHEIGHT, Height); - SetWindowSizeGrip(Handle, True); - - try - dsCollations := Mainform.GetResults('SHOW COLLATION'); - // Detect servers default charset - defaultCharset := Mainform.GetVar( 'SHOW VARIABLES LIKE '+esc('character_set_server'), 1 ); - except - // Ignore it when the above statements don't work on pre 4.1 servers. - // If the list(s) are nil, disable the combobox(es), so we create the db without charset. - end; - - // Create a list with charsets from collations dataset - comboCharset.Enabled := dsCollations <> nil; - lblCharset.Enabled := comboCharset.Enabled; - if comboCharset.Enabled then - begin - comboCharset.Items.BeginUpdate; - dsCollations.First; - while not dsCollations.Eof do - begin - charset := dsCollations.FieldByName('Charset').AsString; - if comboCharset.Items.IndexOf(charset) = -1 then - comboCharset.Items.Add(charset); - dsCollations.Next; - end; - comboCharset.Items.EndUpdate; - end; - - comboCollation.Enabled := dsCollations <> nil; - lblCollation.Enabled := comboCollation.Enabled; - - // Display supported engines in pulldown - Mainform.TableEnginesCombo( ComboBoxTableType ); -end; - - -procedure TCreateTableForm.FormDestroy(Sender: TObject); -begin - // Save window layout - OpenRegistry; - MainReg.WriteInteger( REGNAME_CRTABLEWINWIDTH, Width ); - MainReg.WriteInteger( REGNAME_CRTABLEWINHEIGHT, Height ); -end; - - -procedure TCreateTableForm.ButtonCreateClick(Sender: TObject); -var - createQuery, primaryKey, uniqueKey, indexKey : WideString; - i : Integer; - LengthSet : String; - FieldType : TMysqlDataTypeRecord; -begin - // Prepare Query: - createQuery := 'CREATE TABLE ' + mainform.mask(DBComboBox.Text) + '.' + mainform.mask(EditTablename.Text) + ' ('; - - // Columns - for i := 0 to length(cols) - 1 do - begin - FieldType := MySqlDataTypeArray[cols[i].FieldType]; - createQuery := createQuery + mainform.mask(cols[i].Name) + ' ' + - comboboxtype.items[cols[i].FieldType]; // Typ - LengthSet := cols[i].LengthSet; - // Unset length if not allowed for fieldtype - if not FieldType.HasLength then - LengthSet := ''; - // Length required - if FieldType.RequiresLength and (LengthSet = '') then - begin - if FieldType.DefLengthSet <> '' then - LengthSet := FieldType.DefLengthSet - else - LengthSet := '50'; - end; - if LengthSet <> '' then - createQuery := createQuery + ' (' + LengthSet + ')'; // Length/Set - if FieldType.HasBinary and cols[i].Binary then - createQuery := createQuery + ' BINARY'; // Binary - if FieldType.HasUnsigned and cols[i].Unsigned then - createQuery := createQuery + ' UNSIGNED'; // Unsigned - if FieldType.HasZerofill and cols[i].Zerofill then - createQuery := createQuery + ' ZEROFILL'; // Zerofill - if cols[i].Default <> '' then begin - createQuery := createQuery + ' DEFAULT '; - if cols[i].FieldType = tpBIT then - createQuery := createQuery + ' b'; - createQuery := createQuery + '''' + cols[i].Default + ''''; // Default - end; - if cols[i].NotNull then - createQuery := createQuery + ' NOT NULL'; // Not null - if cols[i].AutoIncrement then - createQuery := createQuery + ' AUTO_INCREMENT'; // AutoIncrement - - if i < length(cols)-1 then - createQuery := createQuery + ', ' - end; - - // Indexes: - primaryKey := ''; - uniqueKey := ''; - indexKey := ''; - for i := 0 to length(cols) - 1 do - begin - if cols[i].Primary then - begin - if primaryKey <> '' then primaryKey := primaryKey + ','; - primaryKey := primaryKey + mainform.mask(cols[i].Name); - end; - if cols[i].Unique then - begin - if uniqueKey <> '' then uniqueKey := uniqueKey + ','; - uniqueKey := uniqueKey + mainform.mask(cols[i].Name); - end; - if cols[i].Index then - begin - if indexKey <> '' then indexKey := indexKey + ','; - indexKey := indexKey + mainform.mask(cols[i].Name); - end; - end; - if primaryKey <> '' then - createQuery := createQuery + ', PRIMARY KEY(' + primaryKey + ')'; - if uniqueKey <> '' then - createQuery := createQuery + ', UNIQUE(' + uniqueKey + ')'; - if indexKey <> '' then - createQuery := createQuery + ', INDEX(' + indexKey + ')'; - - // End of columns + indexes: - createQuery := createQuery + ') '; - - // Comment: - if EditDescription.Text <> '' then - createQuery := createQuery + ' COMMENT = "' + EditDescription.Text + '"'; - - if ComboBoxTableType.Text <> '' then - createQuery := createQuery + ' TYPE = ' + ComboBoxTableType.Text; - - if comboCharset.Enabled and (comboCharset.Text <> '') then - begin - createQuery := createQuery + ' /*!40100 DEFAULT CHARSET ' + comboCharset.Text; - if comboCollation.Enabled and (comboCollation.Text <> '') then - createQuery := createQuery + ' COLLATE ' + comboCollation.Text; - createQuery := createQuery + ' */'; - end; - - // Execute CREATE statement and reload tablesList - try - Mainform.ActiveDatabase := DBComboBox.Text; - Mainform.ExecUpdateQuery( createQuery, False, True ); - Mainform.actRefresh.Execute; - Mainform.SelectedTable := EditTablename.Text; - except on E: THandledSQLError do - // Keep the form open so the user can fix his faulty input - ModalResult := mrNone; - end; -end; - - - -procedure TCreateTableForm.refreshColumnList(Sender: TObject); -var i : word; -begin - // refresh list of columns - with ListboxColumns do - begin - Items.Clear; - if length(cols) > 0 then - for i := 0 to length(cols)-1 do - Items.Add(cols[i].Name); - ItemIndex := index; - end; - if index = -1 then - begin - buttonDelete.Enabled := false; - buttonChange.Enabled := false; - disableControls(self); - end else - begin - enableControls(self); - fillControls(self); - end; - if index = ListboxColumns.Items.Count - 1 then - ButtonMoveDown.Enabled := false - else - ButtonMoveDown.Enabled := true; - if index = 0 then - ButtonMoveUp.Enabled := false - else - ButtonMoveUp.Enabled := true; -end; - -procedure TCreateTableForm.ButtonDeleteClick(Sender: TObject); -var i : Word; -begin - // remove column - if length(cols) > 1 then - for i := index to length(cols)-2 do - begin - cols[i] := cols[i+1]; - end; - setlength(cols, length(cols)-1); - dec(index); - refreshColumnList(self); - EditFieldNameChange(self); - ListboxColumnsClick(self); - if length(cols) = 0 then - begin - ButtonMoveUp.Enabled := false; - ButtonMoveDown.Enabled := false; - ButtonCreate.Enabled := false; - end; -end; - - -procedure TCreateTableForm.checktypes(Sender: TObject); -var - FieldType : TMysqlDataTypeRecord; -begin - FieldType := MySqlDataTypeArray[ComboBoxType.ItemIndex]; - - // "binary" is only valid for text-types - CheckBoxBinary.Enabled := FieldType.HasBinary; - if not CheckBoxBinary.Enabled then - CheckBoxBinary.Checked := false; // Ensure checkbox is not ticked - - // "unsigned" is only valid for numerical columns - CheckBoxUnsigned.Enabled := FieldType.HasUnsigned; - if not CheckBoxUnsigned.Enabled then - CheckBoxUnsigned.Checked := false; // Ensure checkbox is not ticked - - // "zerofill" is only valid for numerical and float-columns - CheckBoxZerofill.Enabled := FieldType.HasZerofill; - if not CheckBoxZerofill.Enabled then - CheckBoxZerofill.Checked := false; // Ensure checkbox is not ticked - - // Length/Set - EditLengthSet.Enabled := FieldType.HasLength; - lblLengthSet.Enabled := EditLengthSet.Enabled; - if FieldType.RequiresLength then // Render required field as bold - lblLengthSet.Font.Style := lblLengthSet.Font.Style + [fsBold] - else - lblLengthSet.Font.Style := lblLengthSet.Font.Style - [fsBold]; - if not EditLengthSet.Enabled then - EditLengthSet.Text := ''; - // Fill length/set value with default value if empty - if FieldType.RequiresLength then - begin - if (EditLengthSet.Text = '') and (FieldType.DefLengthSet <> '') then - EditLengthSet.Text := FieldType.DefLengthSet; - end; - - // Default value - EditDefault.Enabled := FieldType.HasDefault; - lblDefault.Enabled := EditDefault.Enabled; - if not EditDefault.Enabled then - EditDefault.Text := ''; // Ensure empty default value - -end; - - -procedure TCreateTableForm.ComboBoxTypeChange(Sender: TObject); -begin - // Type - cols[index].FieldType := ComboBoxType.ItemIndex; - checktypes(self); -end; - -procedure TCreateTableForm.EditLengthSetChange(Sender: TObject); -begin - // LengthSet - cols[index].LengthSet := EditLengthSet.Text; -end; - - -{*** - Check if tablename is valid and warn the user in case he's - doing some crappy character here -} -procedure TCreateTableForm.EditTablenameChange(Sender: TObject); -begin - ButtonCreate.Enabled := false; - EditTablename.Font.Color := clWindowText; - EditTablename.Color := clWindow; - try - ensureValidIdentifier( EditTablename.Text ); - // Enable "OK"-Button if we have a valid name AND there - // is at least 1 column - ButtonCreate.Enabled := (ListBoxColumns.Items.Count > 0); - except - if EditTablename.Text <> '' then begin - EditTablename.Font.Color := clRed; - EditTablename.Color := clYellow; - end; - end; -end; - - -procedure TCreateTableForm.EditDefaultChange(Sender: TObject); -begin - // Default - cols[index].Default := EditDefault.Text; -end; - -procedure TCreateTableForm.CheckBoxPrimaryClick(Sender: TObject); -begin - // Primary - cols[index].Primary := CheckBoxPrimary.Checked; -end; - -procedure TCreateTableForm.CheckBoxIndexClick(Sender: TObject); -begin - // Index - cols[index].Index := CheckBoxIndex.Checked; -end; - -procedure TCreateTableForm.CheckBoxUniqueClick(Sender: TObject); -begin - // Unique - cols[index].Unique := CheckBoxUnique.Checked; -end; - -procedure TCreateTableForm.CheckBoxBinaryClick(Sender: TObject); -begin - // Binary - cols[index].Binary := CheckBoxBinary.Checked; -end; - -procedure TCreateTableForm.CheckBoxUnsignedClick(Sender: TObject); -begin - // Unsigned - cols[index].Unsigned := CheckBoxUnsigned.Checked; -end; - -procedure TCreateTableForm.CheckBoxZerofillClick(Sender: TObject); -begin - // Zerofill - cols[index].Zerofill := CheckBoxZerofill.Checked; -end; - -procedure TCreateTableForm.CheckBoxNotNullClick(Sender: TObject); -begin - // Not Null - cols[index].NotNull := CheckBoxNotNull.Checked; -end; - -procedure TCreateTableForm.CheckBoxAutoincrementClick(Sender: TObject); -begin - // AutoIncrement - cols[index].AutoIncrement := CheckBoxAutoIncrement.Checked; - // Fix bug #160 - auto increment is only valid for PK columns - if CheckBoxAutoIncrement.Checked then - CheckboxPrimary.Checked := True; -end; - -procedure TCreateTableForm.Button1Click(Sender: TObject); -begin - // Add new Field - index := length(cols); - setlength(cols, index+1); - with cols[index] do - begin - Name := EditFieldName.Text; - FieldType := 0; - LengthSet := ''; - default := ''; - Primary := false; - Index := false; - Unique := false; - Binary := false; - Unsigned := true; - Zerofill := false; - NotNull := false; - Autoincrement := false; - ListboxColumns.Items.Add(Name); - end; - refreshColumnList(self); - EditFieldnameChange(self); - ListboxColumns.ItemIndex := index; - // Call change-handler of Tablename-edit to check if - // the Create-Button should be enabled - EditTablenameChange(self); -end; - -procedure TCreateTableForm.EditFieldnameChange(Sender: TObject); -var - colExists, colSelected : Boolean; - i: Integer; -begin - // Field Name EditChange - colExists := False; - for i:=0 to ListboxColumns.Items.Count-1 do begin - if EditFieldName.Text = ListboxColumns.Items[i] then begin - colExists := True; - break; - end; - end; - colSelected := index > -1; - buttonAdd.Enabled := not colExists; - buttonChange.Enabled := (not colExists) and colSelected; - buttonDelete.Enabled := colSelected; - try - ensureValidIdentifier(EditFieldName.Text); - except - buttonAdd.Enabled := false; - buttonChange.Enabled := false; - end; -end; - -procedure TCreateTableForm.ListboxColumnsClick(Sender: TObject); -begin - // ListColumns Change - index := ListboxColumns.ItemIndex; - if index > -1 then - editfieldname.Text := cols[index].Name; - refreshColumnList(self); -end; - -procedure TCreateTableForm.FormShow(Sender: TObject); -var - i: Integer; -begin - // FormShow! - - // read dbs and Tables from treeview - DBComboBox.Items.Clear; - DBComboBox.Items.Assign(Mainform.Databases); - // Preselect relevant database in pulldown - DBComboBox.ItemIndex := DBComboBox.Items.IndexOf( Mainform.ActiveDatabase ); - if (DBComboBox.ItemIndex = -1) and (DBComboBox.Items.Count > 0) then - DBComboBox.ItemIndex := 0; - - if Mainform.mysql_version >= 32300 then - begin - EditDescription.Visible := true; - Label3.Visible := true; - end - else - begin - EditDescription.Visible := false; - Label3.Visible := false; - end; - - // Adds all datatypes for columns - ComboboxType.Items.Clear; - for i := Low(MySqlDataTypeArray) to High(MySqlDataTypeArray) do - begin - ComboboxType.Items.Add( MySqlDataTypeArray[i].Name ); - end; - - - index := -1; - setLength(cols, 0); - ListboxColumns.Items.Clear; - EditTableName.Text := 'Enter table name'; - EditFieldName.Text := 'Enter column name'; - Editdescription.Text := ''; - ButtonCreate.Enabled := false; - ButtonAdd.Enabled := true; - ButtonMoveUp.Enabled := False; - ButtonMoveDown.Enabled := False; - - // Preselect charset item in pulldown - if comboCharset.Items.Count > 0 then - begin - if comboCharset.Items.IndexOf(defaultCharset) > -1 then - comboCharset.ItemIndex := comboCharset.Items.IndexOf(defaultCharset) - else - comboCharset.ItemIndex := 0; - // Invoke selecting default collation - comboCharsetChange( Sender ); - end; - - disablecontrols(self); -end; - -procedure TCreateTableForm.ButtonChangeClick(Sender: TObject); -begin - // Change Fieldname - cols[index].Name := editfieldname.Text; - refreshColumnList(self); - editfieldnamechange(self); -end; - - -procedure TCreateTableForm.disableControls(Sender: TObject); -begin - // disable controls - ButtonDelete.Enabled := false; - lblFieldType.Enabled := false; // Type - lblLengthSet.Enabled := false; // Length - lblDefault.Enabled := false; // Default - ComboBoxType.Enabled := false; - EditLengthSet.Enabled := false; - EditDefault.Enabled := false; - CheckBoxPrimary.Enabled := false; - CheckBoxIndex.Enabled := false; - CheckBoxUnique.Enabled := false; - CheckBoxBinary.Enabled := false; - CheckBoxUnsigned.Enabled := false; - CheckBoxZerofill.Enabled := false; - CheckBoxNotNull.Enabled := false; - CheckBoxAutoIncrement.Enabled := false; -end; - - -procedure TCreateTableForm.enableControls(Sender: TObject); -begin - // enable controls - lblFieldType.Enabled := true; // Type - lblLengthSet.Enabled := true; // Length - lblDefault.Enabled := true; // Default - ComboBoxType.Enabled := true; - EditLengthSet.Enabled := true; - EditDefault.Enabled := true; - CheckBoxPrimary.Enabled := true; - CheckBoxIndex.Enabled := true; - CheckBoxUnique.Enabled := true; - CheckBoxBinary.Enabled := true; - CheckBoxUnsigned.Enabled := true; - CheckBoxZerofill.Enabled := true; - CheckBoxNotNull.Enabled := true; - CheckBoxAutoIncrement.Enabled := true; -end; - - -procedure TCreateTableForm.fillControls(Sender: TObject); -begin - // fill controls with values - with cols[index] do - begin - ComboBoxType.ItemIndex := FieldType; - EditLengthSet.Text := LengthSet; - EditDefault.Text := Default; - CheckBoxPrimary.Checked := Primary; - CheckBoxIndex.Checked := Index; - CheckBoxUnique.Checked := Unique; - CheckBoxBinary.Checked := Binary; - CheckBoxUnsigned.Checked := Unsigned; - CheckBoxZerofill.Checked := Zerofill; - CheckBoxNotNull.Checked := NotNull; - CheckBoxAutoIncrement.Checked := AutoIncrement; - end; - checktypes(self); -end; - - -procedure TCreateTableForm.ButtonMoveUpClick(Sender: TObject); -begin - // move up - setlength(cols, length(cols)+1); - cols[length(cols)-1] := cols[index-1]; - cols[index-1] := cols[index]; - cols[index] := cols[length(cols)-1]; - setlength(cols, length(cols)-1); - dec(index); - refreshColumnList(self); -end; - -procedure TCreateTableForm.ButtonMoveDownClick(Sender: TObject); -begin - // move down - setlength(cols, length(cols)+1); - cols[length(cols)-1] := cols[index+1]; - cols[index+1] := cols[index]; - cols[index] := cols[length(cols)-1]; - setlength(cols, length(cols)-1); - inc(index); - refreshColumnList(self); -end; - - -{** - Charset has been selected: Display fitting collations - and select default one. -} -procedure TCreateTableForm.comboCharsetChange(Sender: TObject); -var - defaultCollation : String; -begin - // Abort if collations were not fetched successfully - if dsCollations = nil then - Exit; - - // Fill pulldown with fitting collations - comboCollation.Items.BeginUpdate; - comboCollation.Items.Clear; - dsCollations.First; - while not dsCollations.Eof do - begin - if dsCollations.FieldByName('Charset').AsString = comboCharset.Text then - begin - comboCollation.Items.Add( dsCollations.FieldByName('Collation').AsString ); - if dsCollations.FieldByName('Default').AsString = 'Yes' then - defaultCollation := dsCollations.FieldByName('Collation').AsString; - end; - dsCollations.Next; - end; - - // Preselect default collation - if comboCollation.Items.IndexOf(defaultCollation) > -1 then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(defaultCollation) - else - comboCollation.ItemIndex := 0; - - comboCollation.Items.EndUpdate; -end; - - -procedure TCreateTableForm.EditFieldnameEnter(Sender: TObject); -begin - ButtonAdd.Default := True; - ButtonCreate.Default := False; -end; - - -procedure TCreateTableForm.EditFieldnameExit(Sender: TObject); -begin - ButtonAdd.Default := False; - ButtonCreate.Default := True; -end; - - -end. diff --git a/source/exportsql.pas b/source/exportsql.pas index c2d54ca0..5320cde0 100644 --- a/source/exportsql.pas +++ b/source/exportsql.pas @@ -1108,7 +1108,7 @@ begin ftInteger, ftSmallint, ftWord: value := Query.Fields[k].AsWideString; ftBoolean: - value := esc( Bool2Str( Query.Fields[k].AsBoolean ) ); + value := esc( BoolToStr( Query.Fields[k].AsBoolean ) ); ftBlob: if Query.Fields[k].AsString <> '' then value := '0x' + BinToWideHex(Query.Fields[k].AsString) diff --git a/source/grideditlinks.pas b/source/grideditlinks.pas index 24ec8ae3..7b15f646 100644 --- a/source/grideditlinks.pas +++ b/source/grideditlinks.pas @@ -152,6 +152,35 @@ type property OnButtonClick: TButtonClickEvent read FOnButtonClick write FOnButtonClick; end; + TColumnDefaultType = (cdtText, cdtNull, cdtCurTS, cdtAutoInc); + TColumnDefaultEditorLink = class(TInterfacedObject, IVTEditLink) + private + FTree: TCustomVirtualStringTree; + FNode: PVirtualNode; + FColumn: TColumnIndex; + FStopping: Boolean; + FPanel: TPanel; + FRadioText, FRadioNULL, FRadioCurTS, FRadioAutoInc: TRadioButton; + FMemoText: TTNTMemo; + FBtnOK, FBtnCancel: TButton; + procedure RadioClick(Sender: TObject); + procedure TextChange(Sender: TObject); + procedure BtnOKClick(Sender: TObject); + procedure BtnCancelClick(Sender: TObject); + public + DefaultType: TColumnDefaultType; + DefaultText: WideString; + constructor Create; + destructor Destroy; override; + function BeginEdit: Boolean; virtual; stdcall; + function CancelEdit: Boolean; virtual; stdcall; + function EndEdit: Boolean; virtual; stdcall; + function GetBounds: TRect; virtual; stdcall; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall; + procedure ProcessMessage(var Message: TMessage); virtual; stdcall; + procedure SetBounds(R: TRect); virtual; stdcall; + end; + implementation @@ -963,4 +992,211 @@ begin CalcEditorPosition; end; + + +{ Column default editor } + +constructor TColumnDefaultEditorLink.Create; +begin + inherited; +end; + + +destructor TColumnDefaultEditorLink.Destroy; +begin + inherited; + FPanel.Free; +end; + + +function TColumnDefaultEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +var + F: TFont; + TextBounds: TRect; + NodeText: WideString; + Default: TColumnDefaultType; +const + m = 5; +begin + Ftree := Tree as TCustomVirtualStringTree; + FNode := Node; + FColumn := Column; + + // Initial size, font and text of the node. + F := TFont.Create; + FTree.GetTextInfo(Node, Column, F, TextBounds, NodeText); + + FPanel := TPanel.Create(Tree); + FPanel.Parent := FTree; + FPanel.Left := TextBounds.Left; + FPanel.Top := TextBounds.Top; + FPanel.Width := 200; + FPanel.ParentBackground := False; + // usefull but looks ugly: + //SetWindowSizeGrip(FPanel.Handle, True); + + FRadioText := TRadioButton.Create(FPanel); + FRadioText.Parent := FPanel; + FRadioText.Top := m; + FRadioText.Left := m; + FRadioText.Width := FRadioText.Parent.Width - 2 * FRadioText.Left; + FRadioText.OnClick := RadioClick; + FRadioText.Caption := 'Text:'; + + FMemoText := TTNTMemo.Create(FPanel); + FMemoText.Parent := FPanel; + FMemoText.Top := FRadioText.Top + FRadioText.Height + m; + FMemoText.Left := 2*m; + FMemoText.Width := FMemoText.Parent.Width - FMemoText.Left - m; + FMemoText.Height := 40; + FMemoText.ScrollBars := ssVertical; + FMemoText.OnChange := TextChange; + + FRadioNull := TRadioButton.Create(FPanel); + FRadioNull.Parent := FPanel; + FRadioNull.Top := FMemoText.Top + FMemoText.Height + m; + FRadioNull.Left := m; + FRadioNull.Width := FRadioNull.Parent.Width - 2 * FRadioNull.Left; + FRadioNull.OnClick := RadioClick; + FRadioNull.Caption := 'NULL'; + + FRadioCurTS := TRadioButton.Create(FPanel); + FRadioCurTS.Parent := FPanel; + FRadioCurTS.Top := FRadioNull.Top + FRadioNull.Height + m; + FRadioCurTS.Left := m; + FRadioCurTS.Width := FRadioCurTS.Parent.Width - 2 * FRadioCurTS.Left; + FRadioCurTS.OnClick := RadioClick; + FRadioCurTS.Caption := 'CURRENT_TIMESTAMP'; + + FRadioAutoInc := TRadioButton.Create(FPanel); + FRadioAutoInc.Parent := FPanel; + FRadioAutoInc.Top := FRadioCurTS.Top + FRadioCurTS.Height + m; + FRadioAutoInc.Left := m; + FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left; + FRadioAutoInc.OnClick := RadioClick; + FRadioAutoInc.Caption := 'AUTO_INCREMENT'; + + FBtnOk := TButton.Create(FPanel); + FBtnOk.Parent := FPanel; + FBtnOk.Width := 60; + FBtnOk.Top := FRadioAutoInc.Top + FRadioAutoInc.Height + m; + FBtnOk.Left := FPanel.Width - 2*m - 2*FBtnOk.Width; + FBtnOk.OnClick := BtnOkClick; + FBtnOk.Caption := 'OK'; + + FBtnCancel := TButton.Create(FPanel); + FBtnCancel.Parent := FPanel; + FBtnCancel.Top := FBtnOk.Top; + FBtnCancel.Width := FBtnOk.Width; + FBtnCancel.Left := FBtnOk.Left + FBtnOk.Width + m; + FBtnCancel.OnClick := BtnCancelClick; + FBtnCancel.Caption := 'Cancel'; + + FPanel.Height := FBtnOk.Top + FBtnOk.Height + m; + FRadioText.Anchors := [akLeft, akTop, akRight]; + FMemoText.Anchors := [akLeft, akTop, akRight, akBottom]; + FRadioNull.Anchors := [akLeft, akBottom, akRight]; + FRadioCurTS.Anchors := [akLeft, akBottom, akRight]; + FRadioAutoInc.Anchors := [akLeft, akBottom, akRight]; + FBtnOk.Anchors := [akBottom, akRight]; + FBtnCancel.Anchors := FBtnOk.Anchors; + + case DefaultType of + cdtText: begin + FRadioText.Checked := True; + FMemoText.Text := DefaultText; + end; + cdtNull: FRadioNull.Checked := True; + cdtCurTS: FRadioCurTS.Checked := True; + cdtAutoInc: FRadioAutoInc.Checked := True; + end; + Result := True; +end; + + +procedure TColumnDefaultEditorLink.ProcessMessage(var Message: TMessage); stdcall; +begin +end; + + +function TColumnDefaultEditorLink.GetBounds: TRect; stdcall; +begin + Result := FPanel.BoundsRect; +end; + + +procedure TColumnDefaultEditorLink.SetBounds(R: TRect); stdcall; +begin + FPanel.Top := R.Top; + FPanel.Left := R.Left; +end; + + +function TColumnDefaultEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := not FStopping; + if Result then + FPanel.Show; +end; + + +function TColumnDefaultEditorLink.CancelEdit: Boolean; stdcall; +begin + Result := not FStopping; + if Result then begin + FStopping := True; + FTree.SetFocus; + end; +end; + + +function TColumnDefaultEditorLink.EndEdit: Boolean; stdcall; +var + newtext: WideString; +begin + Result := not FStopping; + if Result then begin + FStopping := True; + if FRadioText.Checked then + newText := IntToStr(Integer(cdtText)) + FMemoText.Text + else if FRadioNull.Checked then + newText := IntToStr(Integer(cdtNull)) + 'NULL' + else if FRadioCurTS.Checked then + newText := IntToStr(Integer(cdtCurTS)) + 'CURRENT_TIMESTAMP' + else + newText := IntToStr(Integer(cdtAutoInc)) + 'AUTO_INCREMENT'; + if newtext <> FTree.Text[FNode, FColumn] then + FTree.Text[FNode, FColumn] := newtext; + FTree.SetFocus; + end; +end; + + +procedure TColumnDefaultEditorLink.RadioClick(Sender: TObject); +begin + if not FRadioText.Checked then + FMemoText.Color := clBtnFace + else + FMemoText.Color := clWindow; +end; + + +procedure TColumnDefaultEditorLink.TextChange(Sender: TObject); +begin + FRadioText.Checked := True; +end; + + +procedure TColumnDefaultEditorLink.BtnOkClick(Sender: TObject); +begin + FTree.EndEditNode; +end; + + +procedure TColumnDefaultEditorLink.BtnCancelClick(Sender: TObject); +begin + FTree.CancelEditNode; +end; + + end. diff --git a/source/helpers.pas b/source/helpers.pas index 735719de..167184e9 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -138,7 +138,8 @@ type function RemoveNulChars(Text: WideString): WideString; procedure debug(txt: String); function fixNewlines(txt: string): string; - function bool2str( boolval : Boolean ) : String; + function BoolToStr(val: Boolean): String; + function StrToBool(val: String): Boolean; function GetShellFolder(CSIDL: integer): string; function getFilesFromDir( dir: String; pattern: String = '*.*'; hideExt: Boolean = false ): TStringList; function goodfilename( str: String ): String; @@ -1768,15 +1769,20 @@ end; @param boolean Value to convert @return string } -function bool2str( boolval : Boolean ) : String; +function BoolToStr(val: Boolean): String; begin - if boolval then + if val then result := 'Y' else result := 'N'; end; +function StrToBool(val: String): Boolean; +begin + Result := val = 'Y'; +end; + {*** Get the path of a Windows(r)-shellfolder, specified by an integer or a constant diff --git a/source/main.dfm b/source/main.dfm index 04e2e8c1..1d22d37c 100644 --- a/source/main.dfm +++ b/source/main.dfm @@ -3050,44 +3050,59 @@ object MainForm: TMainForm item PngImage.Data = { 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000001874455874536F667477617265005061696E742E4E45542076332E31 - 3072B22592000000D04944415478DA6364A01030D2D40069DB2A96A787DBFE90 - 650050332790EA03E2634043169364004CF367592D77F60F2F3FB37D7EDB83CB - 10465C9A3F299B787D96D39163FAFEF9A7F095FD37D9BEBCC36A082356CDEA56 - 5E9F150CE518FEFE6260F8F39381E9DBC79FC2D70E010D798F61082386662D07 - AFCFCAE672208D0C7F7E30C068A66F1F7E0ADF387E93EDEB071443900D28FA21 - A698F4D62E519BE1F77788C6DF3F20864069D64FAF3E8B5C3F7683E9DFBF44A0 - 2157A9EB028AC3802AB1409574409594886408F979815800000BCAB51102FAB3 - 960000000049454E44AE426082} + 610000001874455874536F667477617265005061696E742E4E45542076332E33 + 36A9E7E2250000016A4944415478DA6364A010300E6E0334D28F32313331B48B + 7270383DFBF263C6ADD9D67349324039F570819382707FB0151FC3B49DEFDE5D + 7EFD22FAFE5CB71D4419A09571344D53887FBA838A00D3A38FDF19FEB2FD66B8 + FEE2F3B7AB8FEEA43C5A18BD9CA001A6B927D7A7984B06DCBCCFC0202DC9C0F0 + ECCB4F06A61F2C0C47DF3DFB78ACCB5A80A0017A5947DBFCD5252B9F3C656460 + 67656078F78981E1FB2FA041C2B7BF9C6D73E3C5690030E04C247838A6B1FF67 + 12E1FDCDA3F8E9330B03373703C39F3F0C0C77B86EFFF8FCE17AD293F9F9D8BD + A09D7934868B8DA5285C4FCC70FF3106862FDF18183E09DEFEFA8F87E90B2323 + 13C3DB9737B21F2FC85A8B33101D8ACF9E0F34103558B4EE27030F370BC337BE + DBDF5EBDBB98FB43467A35332307C3B3EEA0CF78A3D1B1E8FC490B3161B3B3B7 + FE32BCE7B8FDE5D59BCB590F57152FC617D52806E8A66D6915E4E249F9F6F7FB + F7376FEF963D5896B38A810018E4798118000000CD8C116BFFE2750000000049 + 454E44AE426082} Name = 'PngImage23' Background = clWindow end item PngImage.Data = { 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000001874455874536F667477617265005061696E742E4E45542076332E31 - 3072B22592000000DC4944415478DA6364A01030D2D6803A3E5686A64FBFC933 - A08E8F0B484E01E2234043E691660054B3909880DBB72FDFBEFDF8F6AB039721 - 8CB8348BCA897A8A48084BFCFAF6EBF7D3BB4F1EFCF88EDD10466C9A2554C53D - C5644525FEFEFCC7F0EFE75F869F5F7FFE7E7AFFD9839F3F300D6144D72CA525 - E929A12221F1EFC75F863F400CA68186FCFAF2F3F7F327CF1FFCFCF91BC51064 - 03CAF9C47852355C3495FF7EFFCBF0F7C71F0608FD0F4803D94083BE7FFEFEED - D9F317F7FEFFFF1F0534E432955D407118502516A8920ED00C61202B25220CA1 - 202F100900A0BDC31179096B110000000049454E44AE426082} + 610000001874455874536F667477617265005061696E742E4E45542076332E33 + 36A9E7E225000001674944415478DA6364A010300E6E03728E6A30313130B773 + 70883A7DFDF16CC654EB5B73493220FBB072819CB053BF395F30C39E77D3DEBD + 7971397A86DBFD1D4419907B542B4D905F73BAB28003D387EF8F18387EFF6578 + F9F9FAB78777AEA6CC8D7EB49CA00185274DD79B4AA6043C60B8C920C920CDF0 + E5E733869F2C4C0CEF9E1DFDD8667D4C80A001F947F5DAD424FD2B9F323E6160 + 636067F8C8F08EE10FC37706A1DBCFBE34BA9DE5C5690030E04C783824A6FD67 + 6217F9C5C3ABF899E513033710FE036AE7BC7DE7C7BBEB9F93E6E43FC1EE85BC + A3DA316C2C5C453A62E1862718F603EDFBC2C07FFBD3571EA67F5F189918195E + DC789B3D37EBF15A9C815871D6E1BC9E68A0C1C69F8B18B8597818786E7FFBF6 + F6E2AB5C79E91FAB19389819DA829E7DC61B8DE5E71D4F8A0A5B98DDFE7B9681 + FDF6FB2FAF2FBFCA5A5EFC7031BEA84631206B8B6E2B178F60CADFEFDFBEBFBD + FBA66C51CE83550C04C020CF0BC40000F61A8C1171CBB5050000000049454E44 + AE426082} Name = 'PngImage24' Background = clWindow end item PngImage.Data = { 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000001874455874536F667477617265005061696E742E4E45542076332E31 - 3072B22592000000B64944415478DA6364A01030D2D4803A0606962606863F64 - 1900D4CC09A4FA80F818D090C5241900D3ACC5C0E0FE9281E1F35B06861E5C86 - 30E2D26CC2C0E0A5C3C020F79981E1E77E06869BEF7018C2884DB32550B32150 - F36F20E727107F0252078186BCC7620823BA667BA0665324CD3F910C390234E4 - 039A21C8061429303024C5313068FF00F27F2169FE01A55F03C30368C88D7F0C - 0C894043AE52D7051487015562812AE900DD10067252229221E4E70562010091 - D36011DDA2E8350000000049454E44AE426082} + 610000001874455874536F667477617265005061696E742E4E45542076332E33 + 36A9E7E225000001604944415478DA6364A010300E6E037EF009313130FC6967 + 96E074FAFBE2F70C8E4FEFE692688068015BA0513F43662E034379D9BB8FE73F + 450B7E7AB283280380B6A7B1D9C94F6788F6676238779381E11333C3AF4367BF + DD7FFA3B45F3D39DE5840D10E55BCF36B53A80E1FA710606493506866B8F1818 + 84FE32FC9874F823D79B170244B880AF8DAD3CB492E1E56506060E1E068677CF + 1818BE7C61F8B847F08BE09BCBBC380D003ADD845984751A8308A708B31A8722 + C3F7170C0CBC4240895F0C1FB7B1FFB8CCC09D64F7E912762F006D8D61606128 + 626BCE3264383C9F81E1E77786577B19BEB233897C6101CA5FFDC7956DF1E9CA + 5A9C81F85B5DE63C73459A01C3AA1E0606660686572759BE9DF92998ABC7A0B6 + 9A83E13783D8A73D9FF146E36F0DC993CC490E660C47B633BC3ACEF4E5E24F9E + 2CF74F8F16E38B6A14039EF2F1B57209F3A6FCFCF4E7FBADDF1C65769F1EAE62 + 200006795E2006000095827E1184AB478A0000000049454E44AE426082} Name = 'PngImage26' Background = clWindow end @@ -5941,6 +5956,48 @@ object MainForm: TMainForm D97825A78735DC6A478E7A004A4F0720512A80D90000000049454E44AE426082} Name = 'PngImage124' Background = clWindow + end + item + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001874455874536F667477617265005061696E742E4E45542076332E33 + 36A9E7E225000001594944415478DA6364A010300E7203B67F6362F8C3D0CEF9 + 85D9E9BBC0DF190C9E5C73493360F7B702EB4F6CFDC56A0C0C795719DE3D11FE + 10CDE02AB2833803B67F4B5379C7363D988381E906130303B33003C3C99FBFBE + 3DFD7E3785C14F77396103567D5BDFC8CB1670E4010383863803C303660686BF + AF1918F648FFF8F8CB934780B0019BBFB545FC64ABBC789B8181979D81E1C947 + 06862F7F19187EF87EF8F2CB5C8417B701DBBF9900036D1AD74F0611F647CC8A + CF81B60A733330FC024A7D72FFF083E1D5C5248660671C5ED8FC2D0618EA45F9 + 1C6C86B3F631307C07E9B278F9955192FD0B030B2BC3FFD717B31902EDD6E20C + 44BEB53FCF67F3301BB4EF0772FE0003CEE0E5B7BF9F4FE63278E8AD6660013A + 4356F233DE68E45EF1F3A4CB4766B34D77181898F45F7EF9FBE95C164396EF62 + 7C318DEA85A58F5A7999B9527E30FFFCFEFBF38D328624E7550C04C060CF0B44 + 000083BF7A11E54F777F0000000049454E44AE426082} + Name = 'PngImage126' + Background = clWindow + end + item + PngImage.Data = { + 89504E470D0A1A0A0000000D4948445200000010000000100403000000EDDDE2 + 5200000030504C5445000000FFFFFFFF00FFC0C0C0808080800080008080C0C0 + C0808080FF000000FF00FFFF000000FFFF00FF00FFFFFFFFFFC47A28CA000000 + 0374524E53FFFF00D7CA0D41000000234944415478DA63546280004604E31E88 + 62526054BA2F00647CA422036E32A6A55006009EE116315D7E201B0000000049 + 454E44AE426082} + Name = 'PngImage128' + Background = clWindow + end + item + PngImage.Data = { + 89504E470D0A1A0A0000000D4948445200000010000000100403000000EDDDE2 + 5200000030504C5445000000FFFFFFFF00FFC0C0C0808080800080008080C0C0 + C0808080FF000000FF00FFFF000000FFFF00FF00FFFFFFFFFFC47A28CA000000 + 0374524E53FFFF00D7CA0D41000000474944415478DA63546280004604E31E88 + 62526054BA2F00647C84323E304218FF3F82190C02EF19C18CFF021F04C16AFE + 33300A8019FC1F04A1BA3E08C0B583197093312D8532004C361C310712C3C500 + 00000049454E44AE426082} + Name = 'PngImage127' + Background = clWindow end> PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] Left = 104 diff --git a/source/main.pas b/source/main.pas index 2c578ff7..53d5b24c 100644 --- a/source/main.pas +++ b/source/main.pas @@ -21,7 +21,7 @@ uses SelectDBObject, Widestrings, ShlObj, SynEditMiscClasses, SynEditSearch, SynCompletionProposal, ZSqlMonitor, SynEditHighlighter, SynHighlighterSQL, TntStdCtrls, Tabs, SynUnicode, mysqlconn, EditVar, helpers, queryprogress, - mysqlquery, createdatabase, createtable, tbl_properties, SynRegExpr, + mysqlquery, createdatabase, table_editor, SynRegExpr, WideStrUtils, ZDbcLogging, ExtActns, CommCtrl, routine_editor, options; const @@ -772,7 +772,8 @@ type SqlMessages : TWideStringList; SqlMessagesLock : TRtlCriticalSection; dsShowEngines, - dsHaveEngines : TDataSet; + dsHaveEngines, + dsCollations : TDataset; FilterPanelManuallyOpened : Boolean; winName : String; FLastSelectedTableColumns, @@ -861,8 +862,7 @@ type prefNullColorDefault, prefNullBG : TColor; CreateDatabaseForm : TCreateDatabaseForm; - CreateTableForm : TCreateTableForm; - TablePropertiesForm : Ttbl_properties_form; + TableEditorForm : TfrmTableEditor; FDataGridResult, FQueryGridResult : TGridResult; FDataGridSelect : WideStrings.TWideStringList; @@ -934,6 +934,7 @@ type procedure DataViewClick(Sender: TObject); procedure LoadDataView(ViewName: String); function GetRegKeyTable: String; + function GetCollations: TDataset; end; @@ -1775,10 +1776,10 @@ begin FreeAndNil(InformationSchemaTables); FreeAndNil(dsShowEngines); FreeAndNil(dsHaveEngines); + FreeAndNil(dsCollations); // Free forms which use session based datasets, fx dsShowEngines - FreeAndNil(CreateTableForm); - FreeAndNil(TablePropertiesForm); + FreeAndNil(TableEditorForm); FreeAndNil(CreateDatabaseForm); // Closing connection @@ -2674,9 +2675,9 @@ end; procedure TMainForm.actCreateTableExecute(Sender: TObject); begin - if CreateTableForm = nil then - CreateTableForm := TCreateTableForm.Create(Self); - CreateTableForm.ShowModal; + if TableEditorForm = nil then + TableEditorForm := TfrmTableEditor.Create(Self); + TableEditorForm.ShowModal; end; @@ -2739,18 +2740,18 @@ var NodeData: PVTreeData; caller: TComponent; begin - if TablePropertiesForm = nil then - TablePropertiesForm := Ttbl_properties_form.Create(Self); + if TableEditorForm = nil then + TableEditorForm := TfrmTableEditor.Create(Self); caller := TAction(Sender).ActionComponent; if caller = menuTreeAlterTable then - TablePropertiesForm.TableName := SelectedTable + TableEditorForm.AlterTableName := SelectedTable else begin NodeData := ListTables.GetNodeData( ListTables.FocusedNode ); - TablePropertiesForm.TableName := NodeData.Captions[0]; + TableEditorForm.AlterTableName := NodeData.Captions[0]; end; - TablePropertiesForm.ShowModal; + TableEditorForm.ShowModal; end; @@ -9368,5 +9369,14 @@ begin end; +function TMainform.GetCollations: TDataset; +begin + // Return cached collation list, used in several places, e.g. table editor + if (dsCollations = nil) or (dsCollations.State = dsInactive) then + dsCollations := GetResults('SHOW COLLATION'); + dsCollations.First; + Result := dsCollations; +end; + end. diff --git a/source/mysql_structures.pas b/source/mysql_structures.pas index eeb278e2..9da38744 100644 --- a/source/mysql_structures.pas +++ b/source/mysql_structures.pas @@ -4167,6 +4167,7 @@ var ); function GetFunctionCategories: TStringList; + function GetDatatypeByName(Datatype: String): TMysqlDataTypeRecord; implementation @@ -4185,4 +4186,18 @@ begin Result.Sort; end; + +function GetDatatypeByName(Datatype: String): TMysqlDataTypeRecord; +var + i: Integer; +begin + for i:=Low(MySqlDataTypeArray) to High(MySqlDataTypeArray) do begin + if MySqlDataTypeArray[i].Name = Datatype then begin + Result := MySqlDataTypeArray[i]; + break; + end; + end; +end; + + end. diff --git a/source/table_editor.dfm b/source/table_editor.dfm new file mode 100644 index 00000000..5e5f74a6 --- /dev/null +++ b/source/table_editor.dfm @@ -0,0 +1,704 @@ +object frmTableEditor: TfrmTableEditor + Left = 0 + Top = 0 + Caption = 'Table editor' + ClientHeight = 412 + ClientWidth = 598 + 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 + OnDestroy = FormDestroy + OnShow = FormShow + DesignSize = ( + 598 + 412) + PixelsPerInch = 96 + TextHeight = 13 + object SplitterTopBottom: TSplitter + AlignWithMargins = True + Left = 8 + Top = 158 + Width = 582 + Height = 8 + Cursor = crSizeNS + Margins.Left = 8 + Margins.Top = 0 + Margins.Right = 8 + Margins.Bottom = 0 + Align = alTop + ResizeStyle = rsUpdate + end + object lblStatus: TLabel + Left = 104 + Top = 384 + Width = 41 + Height = 13 + Anchors = [akLeft, akBottom] + Caption = 'lblStatus' + end + object btnApply: TButton + Left = 515 + Top = 379 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Apply' + TabOrder = 6 + OnClick = btnApplyClick + end + object btnCancel: TButton + Left = 434 + Top = 379 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 5 + end + object btnOK: TButton + Left = 353 + Top = 379 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 4 + OnClick = btnApplyClick + end + object btnHelp: TButton + Left = 8 + Top = 379 + Width = 75 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = 'Help' + TabOrder = 3 + OnClick = btnHelpClick + end + object listColumns: TVirtualStringTree + AlignWithMargins = True + Left = 8 + Top = 196 + Width = 582 + Height = 176 + Margins.Left = 8 + Margins.Top = 8 + Margins.Right = 8 + Margins.Bottom = 40 + Align = alClient + CheckImageKind = ckSystem + Constraints.MinHeight = 50 + DragMode = dmAutomatic + Header.AutoSizeIndex = -1 + 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 = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible] + Images = MainForm.PngImageListMain + NodeDataSize = 0 + PopupMenu = popupColumns + TabOrder = 2 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag] + TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowDropmark, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] + WantTabs = True + OnAfterCellPaint = listColumnsAfterCellPaint + OnBeforePaint = listColumnsBeforePaint + OnClick = listColumnsClick + OnCreateEditor = listColumnsCreateEditor + OnDragOver = listColumnsDragOver + OnDragDrop = listColumnsDragDrop + OnEditing = listColumnsEditing + OnFocusChanged = listColumnsFocusChanged + OnGetText = listColumnsGetText + OnPaintText = listColumnsPaintText + OnNewText = listColumnsNewText + Columns = < + item + Alignment = taRightJustify + Color = clBtnFace + MinWidth = 20 + Options = [coDraggable, coEnabled, coParentBidiMode, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Width = 20 + WideText = '#' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Width = 100 + WideText = 'Name' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 2 + Width = 90 + WideText = 'Datatype' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 3 + Width = 90 + WideText = 'Length/Set' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 4 + Width = 60 + WideText = 'Unsigned' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 5 + Width = 70 + WideText = 'Allow NULL' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 6 + Width = 100 + WideText = 'Default' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 7 + Width = 130 + WideText = 'Comment' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 8 + Width = 100 + WideText = 'Collation' + end> + end + object PageControlMain: TPageControl + AlignWithMargins = True + Left = 8 + Top = 8 + Width = 582 + Height = 150 + Margins.Left = 8 + Margins.Top = 8 + Margins.Right = 8 + Margins.Bottom = 0 + ActivePage = tabBasic + Align = alTop + Constraints.MinHeight = 150 + Constraints.MinWidth = 500 + Images = MainForm.PngImageListMain + TabOrder = 0 + OnChange = PageControlMainChange + object tabBasic: TTabSheet + Caption = 'Basic' + ImageIndex = 14 + DesignSize = ( + 574 + 121) + object lblName: TLabel + Left = 4 + Top = 6 + Width = 31 + Height = 13 + Caption = 'Name:' + end + object lblComment: TLabel + Left = 4 + Top = 33 + Width = 49 + Height = 13 + Caption = 'Comment:' + end + object editName: TTntEdit + Left = 123 + Top = 3 + Width = 448 + Height = 21 + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + Text = 'editName' + OnChange = editNameChange + end + object memoComment: TTntMemo + Left = 123 + Top = 30 + Width = 448 + Height = 83 + Anchors = [akLeft, akTop, akRight, akBottom] + Lines.Strings = ( + 'memoComment') + MaxLength = 60 + TabOrder = 1 + OnChange = Modification + end + end + object tabOptions: TTabSheet + Caption = 'Options' + ImageIndex = 39 + DesignSize = ( + 574 + 121) + object lblAutoinc: TLabel + Left = 4 + Top = 6 + Width = 77 + Height = 13 + Caption = 'Auto increment:' + end + object lblAvgRowLen: TLabel + Left = 4 + Top = 29 + Width = 99 + Height = 13 + Caption = 'Average row length:' + end + object lblInsertMethod: TLabel + Left = 315 + Top = 98 + Width = 79 + Height = 13 + Caption = 'INSERT method:' + end + object lblUnion: TLabel + Left = 315 + Top = 52 + Width = 63 + Height = 13 + Caption = 'Union tables:' + end + object lblMaxRows: TLabel + Left = 4 + Top = 52 + Width = 99 + Height = 13 + Caption = 'Maximum row count:' + end + object lblRowFormat: TLabel + Left = 4 + Top = 98 + Width = 60 + Height = 13 + Caption = 'Row format:' + end + object lblCollation: TLabel + Left = 315 + Top = 6 + Width = 81 + Height = 13 + Caption = 'Default collation:' + end + object lblEngine: TLabel + Left = 315 + Top = 29 + Width = 36 + Height = 13 + Caption = 'Engine:' + end + object editAvgRowLen: TEdit + Left = 136 + Top = 26 + Width = 153 + Height = 21 + TabOrder = 1 + OnChange = editNumEditChange + end + object editMaxRows: TEdit + Left = 136 + Top = 49 + Width = 153 + Height = 21 + TabOrder = 2 + OnChange = editNumEditChange + end + object chkChecksum: TCheckBox + Left = 4 + Top = 75 + Width = 145 + Height = 17 + Alignment = taLeftJustify + Caption = 'Checksum for rows:' + TabOrder = 3 + OnClick = Modification + end + object comboRowFormat: TComboBox + Left = 136 + Top = 95 + Width = 153 + Height = 21 + Style = csDropDownList + ItemHeight = 0 + TabOrder = 4 + OnChange = Modification + end + object memoUnionTables: TTntMemo + Left = 411 + Top = 49 + Width = 160 + Height = 44 + Anchors = [akLeft, akTop, akRight] + Lines.Strings = ( + 'memoUnion') + TabOrder = 7 + OnChange = Modification + end + object comboInsertMethod: TComboBox + Left = 411 + Top = 95 + Width = 160 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 0 + TabOrder = 8 + OnClick = Modification + end + object editAutoInc: TEdit + Left = 136 + Top = 3 + Width = 152 + Height = 21 + TabOrder = 0 + OnChange = editNumEditChange + end + object comboCollation: TComboBox + Left = 411 + Top = 3 + Width = 160 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 0 + Sorted = True + TabOrder = 5 + OnChange = Modification + end + object comboEngine: TComboBox + Left = 411 + Top = 26 + Width = 160 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 0 + TabOrder = 6 + OnChange = Modification + OnSelect = comboEngineSelect + end + end + object tabIndexes: TTabSheet + Caption = 'Indexes' + ImageIndex = 13 + DesignSize = ( + 574 + 121) + object treeIndexes: TVirtualStringTree + Left = 75 + Top = 3 + Width = 251 + Height = 110 + Anchors = [akLeft, akTop, akRight, akBottom] + DragMode = dmAutomatic + EditDelay = 0 + 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, hoVisible] + Images = MainForm.PngImageListMain + PopupMenu = popupIndexes + TabOrder = 1 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] + OnBeforePaint = treeIndexesBeforePaint + OnCreateEditor = treeIndexesCreateEditor + OnDragOver = treeIndexesDragOver + OnDragDrop = treeIndexesDragDrop + OnEditing = treeIndexesEditing + OnFocusChanged = treeIndexesFocusChanged + OnGetText = treeIndexesGetText + OnGetImageIndex = treeIndexesGetImageIndex + OnInitChildren = treeIndexesInitChildren + OnInitNode = treeIndexesInitNode + OnNewText = treeIndexesNewText + Columns = < + item + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Width = 151 + WideText = 'Name' + end + item + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Width = 100 + WideText = 'Type' + end> + end + object tlbIndexes: TToolBar + Left = 3 + Top = 3 + Width = 66 + Height = 110 + Align = alNone + AutoSize = True + ButtonWidth = 66 + Caption = 'tlbIndexes' + Images = MainForm.PngImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddIndex: TToolButton + Left = 0 + Top = 0 + Hint = 'Add index' + Caption = 'Add' + ImageIndex = 45 + Wrap = True + OnClick = btnAddIndexClick + end + object btnRemoveIndex: TToolButton + Left = 0 + Top = 22 + Hint = 'Remove index' + Caption = 'Remove' + ImageIndex = 46 + Wrap = True + OnClick = btnRemoveIndexClick + end + object btnClearIndexes: TToolButton + Left = 0 + Top = 44 + Hint = 'Clear indexes' + Caption = 'Clear' + ImageIndex = 26 + Wrap = True + OnClick = btnClearIndexesClick + end + object btnMoveUpIndex: TToolButton + Left = 0 + Top = 66 + Hint = 'Move up' + Caption = 'Up' + ImageIndex = 74 + Wrap = True + OnClick = btnMoveUpIndexClick + end + object btnMoveDownIndex: TToolButton + Left = 0 + Top = 88 + Hint = 'Move down' + Caption = 'Down' + ImageIndex = 75 + OnClick = btnMoveDownIndexClick + end + end + object StaticText1: TStaticText + Left = 341 + Top = 25 + Width = 221 + Height = 39 + Anchors = [akTop, akRight] + AutoSize = False + Caption = + 'To add a column, drag it from the column list below into the ind' + + 'ex tree.' + TabOrder = 2 + end + end + object tabSQLCode: TTabSheet + Caption = 'SQL code' + ImageIndex = 119 + object SynMemoSQLcode: TSynMemo + Left = 0 + Top = 0 + Width = 574 + Height = 121 + SingleLineMode = False + Align = alClient + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Style = [] + TabOrder = 0 + Gutter.AutoSize = True + Gutter.DigitCount = 2 + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.LeftOffset = 2 + Gutter.ShowLineNumbers = True + Highlighter = MainForm.SynSQLSyn1 + Lines.UnicodeStrings = 'SynMemoSQLcode' + Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] + ReadOnly = True + end + end + end + object pnlColumnsTop: TPanel + AlignWithMargins = True + Left = 8 + Top = 166 + Width = 582 + Height = 22 + Margins.Left = 8 + Margins.Top = 0 + Margins.Right = 8 + Margins.Bottom = 0 + Align = alTop + Alignment = taLeftJustify + AutoSize = True + BevelOuter = bvNone + Caption = 'Columns:' + TabOrder = 1 + object tlbColumns: TToolBar + Left = 61 + Top = 0 + Width = 473 + Height = 22 + Align = alNone + ButtonWidth = 66 + Caption = 'Columns:' + Images = MainForm.PngImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddColumn: TToolButton + Left = 0 + Top = 0 + Hint = 'Add column' + Caption = 'Add' + ImageIndex = 45 + OnClick = btnAddColumnClick + end + object btnRemoveColumn: TToolButton + Left = 66 + Top = 0 + Hint = 'Remove column' + Caption = 'Remove' + ImageIndex = 46 + OnClick = btnRemoveColumnClick + end + object btnClearColumns: TToolButton + Left = 132 + Top = 0 + Hint = 'Remove all columns' + Caption = 'Clear' + ImageIndex = 26 + OnClick = btnClearColumnsClick + end + object btnMoveUpColumn: TToolButton + Left = 198 + Top = 0 + Hint = 'Move up' + Caption = 'Up' + ImageIndex = 74 + OnClick = btnMoveUpColumnClick + end + object btnMoveDownColumn: TToolButton + Left = 264 + Top = 0 + Hint = 'Move down' + Caption = 'Down' + ImageIndex = 75 + OnClick = btnMoveDownColumnClick + end + end + end + object popupIndexes: TPopupMenu + Images = MainForm.PngImageListMain + Left = 296 + Top = 376 + object menuAddIndex: TMenuItem + Caption = 'Add index' + ImageIndex = 45 + ShortCut = 45 + OnClick = btnAddIndexClick + end + object menuAddIndexColumn: TMenuItem + Caption = 'Add column' + ImageIndex = 91 + ShortCut = 16429 + OnClick = menuAddIndexColumnClick + end + object menuRemoveIndex: TMenuItem + Caption = 'Remove' + ImageIndex = 46 + ShortCut = 46 + OnClick = btnRemoveIndexClick + end + object menuClearIndexes: TMenuItem + Caption = 'Clear' + ImageIndex = 26 + ShortCut = 16430 + OnClick = btnClearIndexesClick + end + object menuMoveUpIndex: TMenuItem + Caption = 'Up' + ImageIndex = 74 + ShortCut = 16469 + OnClick = btnMoveUpIndexClick + end + object menuMoveDownIndex: TMenuItem + Caption = 'Down' + ImageIndex = 75 + ShortCut = 16452 + OnClick = btnMoveDownIndexClick + end + end + object popupColumns: TPopupMenu + Images = MainForm.PngImageListMain + Left = 264 + Top = 376 + object menuAddColumn: TMenuItem + Caption = 'Add column' + ImageIndex = 45 + ShortCut = 45 + OnClick = btnAddColumnClick + end + object menuRemoveColumn: TMenuItem + Caption = 'Remove column' + ImageIndex = 46 + ShortCut = 46 + OnClick = btnRemoveColumnClick + end + object menuClearColumns: TMenuItem + Caption = 'Clear all columns' + ImageIndex = 26 + ShortCut = 16430 + OnClick = btnClearColumnsClick + end + object menuMoveUpColumn: TMenuItem + Caption = 'Move up' + ImageIndex = 74 + ShortCut = 16469 + OnClick = btnMoveUpColumnClick + end + object menuMoveDownColumn: TMenuItem + Caption = 'Move down' + ImageIndex = 75 + ShortCut = 16452 + OnClick = btnMoveDownColumnClick + end + end +end diff --git a/source/table_editor.pas b/source/table_editor.pas new file mode 100644 index 00000000..c0449ce8 --- /dev/null +++ b/source/table_editor.pas @@ -0,0 +1,1441 @@ +unit table_editor; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, TntStdCtrls, ComCtrls, ToolWin, VirtualTrees, WideStrings, + SynRegExpr, ActiveX, DB, ExtCtrls, ImgList, SynEdit, SynMemo, Menus; + +type + TfrmTableEditor = class(TForm) + btnApply: TButton; + btnCancel: TButton; + btnOK: TButton; + btnHelp: TButton; + listColumns: TVirtualStringTree; + PageControlMain: TPageControl; + tabBasic: TTabSheet; + tabIndexes: TTabSheet; + tabOptions: TTabSheet; + lblName: TLabel; + editName: TTntEdit; + memoComment: TTntMemo; + lblComment: TLabel; + lblAutoinc: TLabel; + lblAvgRowLen: TLabel; + lblInsertMethod: TLabel; + lblUnion: TLabel; + lblMaxRows: TLabel; + lblRowFormat: TLabel; + editAutoInc: TEdit; + editAvgRowLen: TEdit; + editMaxRows: TEdit; + chkChecksum: TCheckBox; + comboRowFormat: TComboBox; + memoUnionTables: TTntMemo; + comboInsertMethod: TComboBox; + lblCollation: TLabel; + comboCollation: TComboBox; + lblEngine: TLabel; + comboEngine: TComboBox; + treeIndexes: TVirtualStringTree; + tlbIndexes: TToolBar; + btnAddIndex: TToolButton; + btnRemoveIndex: TToolButton; + btnClearIndexes: TToolButton; + btnMoveUpIndex: TToolButton; + btnMoveDownIndex: TToolButton; + StaticText1: TStaticText; + pnlColumnsTop: TPanel; + tlbColumns: TToolBar; + btnAddColumn: TToolButton; + btnRemoveColumn: TToolButton; + btnClearColumns: TToolButton; + btnMoveUpColumn: TToolButton; + btnMoveDownColumn: TToolButton; + SplitterTopBottom: TSplitter; + tabSQLCode: TTabSheet; + SynMemoSQLcode: TSynMemo; + popupIndexes: TPopupMenu; + menuAddIndex: TMenuItem; + menuAddIndexColumn: TMenuItem; + menuRemoveIndex: TMenuItem; + menuMoveUpIndex: TMenuItem; + menuMoveDownIndex: TMenuItem; + menuClearIndexes: TMenuItem; + lblStatus: TLabel; + popupColumns: TPopupMenu; + menuAddColumn: TMenuItem; + menuRemoveColumn: TMenuItem; + menuClearColumns: TMenuItem; + menuMoveUpColumn: TMenuItem; + menuMoveDownColumn: TMenuItem; + procedure FormCreate(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure editNameChange(Sender: TObject); + procedure Modification(Sender: TObject); + procedure btnAddColumnClick(Sender: TObject); + procedure btnRemoveColumnClick(Sender: TObject); + procedure btnClearColumnsClick(Sender: TObject); + procedure listColumnsBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure listColumnsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure btnHelpClick(Sender: TObject); + procedure listColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString); + procedure FormShow(Sender: TObject); + procedure listColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure listColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); + procedure btnMoveUpColumnClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure btnMoveDownColumnClick(Sender: TObject); + procedure listColumnsDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; + Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean); + procedure listColumnsDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); + procedure listColumnsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType); + procedure listColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure treeIndexesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure treeIndexesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: WideString); + procedure treeIndexesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure treeIndexesInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); + procedure treeIndexesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure btnClearIndexesClick(Sender: TObject); + procedure btnApplyClick(Sender: TObject); + procedure editNumEditChange(Sender: TObject); + procedure comboEngineSelect(Sender: TObject); + procedure listColumnsClick(Sender: TObject); + procedure listColumnsAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); + procedure btnAddIndexClick(Sender: TObject); + procedure treeIndexesDragOver(Sender: TBaseVirtualTree; Source: TObject; + Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; + var Effect: Integer; var Accept: Boolean); + procedure treeIndexesDragDrop(Sender: TBaseVirtualTree; Source: TObject; + DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; + Pt: TPoint; var Effect: Integer; Mode: TDropMode); + procedure treeIndexesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); + procedure treeIndexesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure treeIndexesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure treeIndexesCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure btnMoveUpIndexClick(Sender: TObject); + procedure btnMoveDownIndexClick(Sender: TObject); + procedure btnRemoveIndexClick(Sender: TObject); + procedure menuAddIndexColumnClick(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + private + { Private declarations } + FModified: Boolean; + FLoaded: Boolean; + SQLCodeValid: Boolean; + Columns, ColumnsChanges, + Indexes, OldIndexes: TWideStringList; + procedure ColumnsChange(Sender: TObject); + procedure IndexesChange(Sender: TObject); + procedure ValidateColumnControls; + procedure ValidateIndexControls; + procedure SelectNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode=nil); + procedure MoveFocusedColumn(NewIdx: Cardinal); + procedure MoveFocusedIndexPart(NewIdx: Cardinal); + procedure SetModified(Value: Boolean); + procedure ResetModificationFlags; + function ComposeCreateStatement: WideString; + function ComposeAlterStatement: WideString; + function GetIndexSQL(IndexList: TWideStringlist; idx: Integer): WideString; + property Modified: Boolean read FModified write SetModified; + procedure SetStatus(msg: WideString = ''); + procedure UpdateSQLcode; + public + { Public declarations } + AlterTableName: WideString; + end; + + +implementation + +uses main, helpers, grideditlinks, mysql_structures; + +const + PKEY = 'PRIMARY'; + KEY = 'KEY'; + UKEY = 'UNIQUE'; + FKEY = 'FULLTEXT'; + SKEY = 'SPATIAL'; + NotModifiedFlag : Byte = 0; + ModifiedFlag : Byte = 1; + + +{$R *.dfm} + + +procedure TfrmTableEditor.FormCreate(Sender: TObject); +begin + // Restore form dimensions + Width := GetRegValue(REGNAME_TABLEEDITOR_WIDTH, Width); + Height := GetRegValue(REGNAME_TABLEEDITOR_HEIGHT, Height); + PageControlMain.Height := GetRegValue(REGNAME_TABLEEDITOR_TABSHEIGHT, PageControlMain.Height); + SetWindowSizeGrip(Handle, True); + InheritFont(Font); + FixVT(listColumns); + FixVT(treeIndexes); + FLoaded := False; + comboRowFormat.Items.CommaText := 'DEFAULT,DYNAMIC,FIXED,COMPRESSED,REDUNDANT,COMPACT'; + comboInsertMethod.Items.CommaText := 'NO,FIRST,LAST'; + SynMemoSQLcode.TabWidth := Mainform.SynMemoQuery.TabWidth; + SynMemoSQLcode.Font.Name := Mainform.SynMemoQuery.Font.Name; + SynMemoSQLcode.Font.Size := Mainform.SynMemoQuery.Font.Size; + Columns := TWideStringList.Create; + Columns.OnChange := ColumnsChange; + ColumnsChanges := TWideStringList.Create; + Indexes := TWideStringList.Create; + Indexes.OnChange := IndexesChange; + OldIndexes := TWideStringList.Create; +end; + + +procedure TfrmTableEditor.FormDestroy(Sender: TObject); +begin + // Store form dimensions + OpenRegistry; + MainReg.WriteInteger(REGNAME_TABLEEDITOR_WIDTH, Width); + MainReg.WriteInteger(REGNAME_TABLEEDITOR_HEIGHT, Height); + MainReg.WriteInteger(REGNAME_TABLEEDITOR_TABSHEIGHT, PageControlMain.Height); +end; + + +procedure TfrmTableEditor.FormShow(Sender: TObject); +var + ds: TDataset; + Props: TWideStringlist; + IndexType: String; + LastKeyName, CreateTable: WideString; + rx: TRegExpr; +begin + SetStatus('Initializing ...'); + // Always start with "basic" tab activated + PageControlMain.ActivePage := tabBasic; + Mainform.TableEnginesCombo(comboEngine); + comboCollation.Items.Clear; + ds := Mainform.GetCollations; + while not ds.Eof do begin + comboCollation.Items.Add(ds.FieldByName('Collation').AsString); + ds.Next; + end; + + if AlterTableName = '' then begin + // Creating new table + editName.Clear; + memoComment.Text := ''; + editAutoInc.Text := ''; + editAvgRowLen.Text := ''; + editMaxRows.Text := ''; + chkChecksum.Checked := False; + comboRowFormat.ItemIndex := 0; + comboCollation.ItemIndex := comboCollation.Items.IndexOf(Mainform.GetVar('SHOW VARIABLES LIKE ''collation_database''', 1)); + memoUnionTables.Clear; + comboInsertMethod.ItemIndex := -1; + + PageControlMain.ActivePage := tabBasic; + editName.SetFocus; + + end else begin + // Editing existing table + editName.Text := AlterTableName; + ds := Mainform.GetResults('SHOW TABLE STATUS LIKE '+esc(AlterTableName)); + memoComment.Text := ds.FieldByName(DBO_COMMENT).AsWideString; + comboEngine.ItemIndex := comboEngine.Items.IndexOf(ds.FieldByName(DBO_ENGINE).AsString); + comboCollation.ItemIndex := comboCollation.Items.IndexOf(ds.FieldByName(DBO_COLLATION).AsString); + editAutoInc.Text := ds.FieldByName(DBO_AUTOINC).AsString; + editAvgRowLen.Text := ds.FieldByName(DBO_AVGROWLEN).AsString; + comboRowFormat.ItemIndex := comboRowFormat.Items.IndexOf(ds.FieldByName(DBO_ROWFORMAT).AsString); + FreeAndNil(ds); + CreateTable := Mainform.GetVar('SHOW CREATE TABLE '+Mainform.mask(AlterTableName), 1); + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '\bUNION=\((.+)\)'; + if rx.Exec(CreateTable) then + memoUnionTables.Text := rx.Match[1] + else + memoUnionTables.Clear; + FreeAndNil(rx); + + ds := Mainform.GetResults('SHOW FULL COLUMNS FROM '+Mainform.mask(AlterTableName)); + while not ds.Eof do begin + Props := TWideStringlist.Create; + Props.OnChange := ColumnsChange; + Props.Add(UpperCase(GetFirstWord(ds.FieldByName('Type').AsString))); + Props.Add(getEnumValues(ds.FieldByName('Type').AsWideString)); + Props.Add(BoolToStr(Pos('unsigned', ds.FieldByName('Type').AsWideString) > 0)); + Props.Add(BoolToStr(ds.FieldByName('Null').AsString = 'YES')); + if ds.FieldByName('Extra').AsWideString = 'auto_increment' then + Props.Add(IntToStr(Integer(cdtAutoInc))+'AUTO_INCREMENT') + else if ds.FieldByName('Default').IsNull then + Props.Add(IntToStr(Integer(cdtNull))+'NULL') + else if ds.FieldByName('Default').AsWideString = 'CURRENT_TIMESTAMP' then + Props.Add(IntToStr(Integer(cdtCurTS))+ds.FieldByName('Default').AsWideString) + else + Props.Add(IntToStr(Integer(cdtText))+ds.FieldByName('Default').AsWideString); + Props.Add(ds.FieldByName('Comment').AsWideString); + Props.Add(ds.FieldByName('Collation').AsString); + Columns.AddObject(ds.FieldByName('Field').AsWideString, Props); + ds.Next; + end; + FreeAndNil(ds); + + ds := Mainform.GetResults('SHOW KEYS FROM '+Mainform.mask(AlterTableName)); + LastKeyName := ''; + Props := nil; + while not ds.Eof do begin + if LastKeyName <> ds.FieldByName('Key_name').AsWideString then begin + Props := TWideStringlist.Create; + Props.OnChange := IndexesChange; + IndexType := ds.FieldByName('Key_name').AsString; + if (ds.FieldByName('Index_type').AsString = FKEY) or (ds.FieldByName('Index_type').AsString = SKEY) then + IndexType := ds.FieldByName('Index_type').AsString + else if (IndexType <> PKEY) and (ds.FieldByName('Non_unique').AsInteger = 0) then + IndexType := UKEY + else if ds.FieldByName('Non_unique').AsInteger = 1 then + IndexType := KEY; + Indexes.AddObject(ds.FieldByName('Key_name').AsWideString+REGDELIM+IndexType, Props); + end; + Props.Add(ds.FieldByName('Column_name').AsWideString); + if ds.FieldByName('Sub_part').AsString <> '' then + Props[Props.Count-1] := Props[Props.Count-1] + '('+ds.FieldByName('Sub_part').AsString+')'; + LastKeyName := ds.FieldByName('Key_name').AsWideString; + ds.Next; + end; + FreeAndNil(ds); + + end; + // Validate controls + ColumnsChange(Sender); + comboEngineSelect(comboEngine); + ValidateColumnControls; + ValidateIndexControls; + ResetModificationFlags; + // Indicate change mechanisms can call their events now. See Modification(). + FLoaded := True; + // Empty status label + SetStatus; +end; + + +procedure TfrmTableEditor.btnApplyClick(Sender: TObject); +var + sql: WideString; +begin + // Create or alter table + if AlterTableName = '' then + sql := ComposeCreateStatement + else + sql := ComposeAlterStatement; + try + Mainform.ExecUpdateQuery(sql, False, True); + ResetModificationFlags; + // Set table name for altering if Apply was clicked + AlterTableName := editName.Text; + except + ModalResult := mrNone; + end; +end; + + +procedure TfrmTableEditor.ResetModificationFlags; +var + i: Integer; + Parts: TWideStringlist; +begin + // Reset modification flags of TEdits and TMemos + for i:=0 to ComponentCount-1 do + Components[i].Tag := NotModifiedFlag; + // Reset name value pairs for column changes + ColumnsChanges.Clear; + for i:=0 to Columns.Count-1 do + ColumnsChanges.Add(Columns[i] + ColumnsChanges.NameValueSeparator + Columns[i]); + // Copy index list so we have one to work with and one which can later be used to detect changes + OldIndexes.Clear; + for i:=0 to Indexes.Count-1 do begin + Parts := TWideStringlist.Create; + Parts.Assign(TWideStringlist(Indexes.Objects[i])); + OldIndexes.AddObject(Indexes[i], Parts); + end; + Modified := False; +end; + + +procedure TfrmTableEditor.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Reset edited table name for the next call + AlterTableName := ''; + FLoaded := False; + btnClearColumnsClick(Sender); + btnClearIndexesClick(Sender); +end; + + +function TfrmTableEditor.ComposeAlterStatement: WideString; +var + Specs, Props, IndexesComposed, OldIndexesComposed: TWideStringlist; + ColSpec, IndexSQL: WideString; + i, j: Integer; + AddIt, DropIt: Boolean; + dt: TMySQLDataTypeRecord; + DefaultType: TColumnDefaultType; +begin + // Compose ALTER query, called by buttons and for SQL code tab + SetStatus('Composing ALTER statement ...'); + Specs := TWideStringlist.Create; + if editName.Text <> AlterTableName then + Specs.Add('RENAME TO ' + Mainform.mask(editName.Text)); + if memoComment.Tag = ModifiedFlag then + Specs.Add('COMMENT = ' + esc(memoComment.Text)); + if comboCollation.Tag = ModifiedFlag then + Specs.Add('COLLATE = ' + comboCollation.Text); + if comboEngine.Tag = ModifiedFlag then + Specs.Add('ENGINE = ' + comboEngine.Text); + if comboRowFormat.Tag = ModifiedFlag then + Specs.Add('ROW_FORMAT = ' + comboRowFormat.Text); + if chkChecksum.Tag = ModifiedFlag then + Specs.Add('CHECKSUM = ' + IntToStr(Integer(chkChecksum.Checked))); + if editAutoInc.Tag = ModifiedFlag then + Specs.Add('AUTO_INCREMENT = ' + IntToStr(MakeInt(editAutoInc.Text))); + if editAvgRowLen.Tag = ModifiedFlag then + Specs.Add('AVG_ROW_LENGTH = ' + IntToStr(MakeInt(editAvgRowLen.Text))); + if editMaxRows.Tag = ModifiedFlag then + Specs.Add('MAX_ROWS = ' + IntToStr(MakeInt(editMaxRows.Text))); + if memoUnionTables.Enabled and (memoUnionTables.Tag = ModifiedFlag) and (memoUnionTables.Text <> '') then + Specs.Add('UNION = ('+memoUnionTables.Text+')'); + if comboInsertMethod.Enabled and (comboInsertMethod.Tag = ModifiedFlag) and (comboInsertMethod.Text <> '') then + Specs.Add('INSERT_METHOD = '+comboInsertMethod.Text); + // Update columns + for i:=0 to Columns.Count - 1 do begin + AddIt := True; + ColSpec := ' ' + Mainform.mask(Columns[i]); + Props := TWideStringlist(Columns.Objects[i]); + ColSpec := ColSpec + ' ' +Props[0]; + if Props[1] <> '' then + ColSpec := ColSpec + '(' + Props[1] + ')'; + dt := GetDatatypeByName(Props[0]); + if dt.HasUnsigned and StrToBool(Props[2]) then + ColSpec := ColSpec + ' UNSIGNED'; + if not StrToBool(Props[3]) then + ColSpec := ColSpec + ' NOT'; + ColSpec := ColSpec + ' NULL'; + if Props[4] <> '' then begin + DefaultType := TColumnDefaultType(MakeInt(Copy(Props[4], 1, 1))); + case DefaultType of + cdtText: ColSpec := ColSpec + ' DEFAULT '+esc(Copy(Props[4], 2, Length(Props[4])-1)); + cdtNull: ColSpec := ColSpec + ' DEFAULT NULL'; + cdtCurTS: ColSpec := ColSpec + ' DEFAULT CURRENT_TIMESTAMP'; + cdtAutoInc: ColSpec := ColSpec + ' AUTO_INCREMENT'; + end; + end; + if Props[5] <> '' then + ColSpec := ColSpec + ' COMMENT '+esc(Props[5]); + if Props[6] <> '' then + ColSpec := ColSpec + ' COLLATE '+Props[6]; + if i = 0 then + ColSpec := ColSpec + ' FIRST' + else + ColSpec := ColSpec + ' AFTER '+Mainform.mask(Columns[i-1]); + for j:=0 to ColumnsChanges.Count - 1 do begin + if ColumnsChanges.ValueFromIndex[j] = Columns[i] then begin + Specs.Add('CHANGE COLUMN '+Mainform.mask(ColumnsChanges.Names[j]) + ColSpec); + AddIt := False; + break; + end; + end; + if AddIt then + Specs.Add('ADD COLUMN '+ColSpec); + end; + // Delete columns + for i:=0 to ColumnsChanges.Count-1 do begin + if ColumnsChanges.ValueFromIndex[i] = '' then + Specs.Add('DROP COLUMN '+Mainform.mask(ColumnsChanges.Names[i])); + end; + + // Prepare ADD INDEX ... clauses once so we don't call GetIndexSQL() too often + IndexesComposed := TWideStringlist.Create; + for i:=0 to Indexes.Count-1 do + IndexesComposed.Add(GetIndexSQL(Indexes, i)); + OldIndexesComposed := TWideStringlist.Create; + for i:=0 to OldIndexes.Count-1 do + OldIndexesComposed.Add(GetIndexSQL(OldIndexes, i)); + // Drop indexes + for i:=0 to OldIndexesComposed.Count-1 do begin + DropIt := IndexesComposed.IndexOf(OldIndexesComposed[i]) = -1; + if not DropIt then + Continue; + IndexSQL := Copy(OldIndexes[i], LastPos(REGDELIM, OldIndexes[i])+1, Length(OldIndexes[i])); + if IndexSQL = PKEY then + IndexSQL := 'PRIMARY KEY' + else + IndexSQL := 'INDEX ' + Mainform.Mask(Copy(OldIndexes[i], 1, LastPos(REGDELIM, OldIndexes[i])-1)); + Specs.Add('DROP '+IndexSQL); + end; + // Add changed or added indexes + for i:=0 to IndexesComposed.Count-1 do begin + if OldIndexesComposed.IndexOf(IndexesComposed[i]) = -1 then + Specs.Add(IndexesComposed[i]); + end; + + Result := 'ALTER TABLE '+Mainform.mask(AlterTableName) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); + FreeAndNil(Specs); + FreeAndNil(IndexesComposed); + FreeAndNil(OldIndexesComposed); + SetStatus; + Screen.Cursor := crDefault; +end; + + +function TfrmTableEditor.ComposeCreateStatement: WideString; +var + i: Integer; + ColProps: TWideStringlist; + dt: TMySQLDataTypeRecord; + DefaultType: TColumnDefaultType; +begin + // Compose CREATE query, called by buttons and for SQL code tab + Result := 'CREATE TABLE '+Mainform.mask(editName.Text)+' ('+CRLF; + for i:=0 to Columns.Count - 1 do begin + ColProps := TWideStringlist(Columns.Objects[i]); + Result := Result + #9 + Mainform.mask(Columns[i]) + ' ' +ColProps[0]; + if ColProps[1] <> '' then + Result := Result + '(' + ColProps[1] + ')'; + dt := GetDatatypeByName(ColProps[0]); + if dt.HasUnsigned and StrToBool(ColProps[2]) then + Result := Result + ' UNSIGNED'; + if not StrToBool(ColProps[3]) then + Result := Result + ' NOT'; + Result := Result + ' NULL'; + if ColProps[4] <> '' then + Result := Result + ' DEFAULT '+esc(ColProps[4]); + if ColProps[4] <> '' then begin + DefaultType := TColumnDefaultType(MakeInt(Copy(ColProps[4], 1, 1))); + case DefaultType of + cdtText: Result := Result + ' DEFAULT '+esc(Copy(ColProps[4], 2, Length(ColProps[4])-1)); + cdtNull: Result := Result + ' DEFAULT NULL'; + cdtCurTS: Result := Result + ' DEFAULT CURRENT_TIMESTAMP'; + cdtAutoInc: Result := Result + ' AUTO_INCREMENT'; + end; + end; + if ColProps[5] <> '' then + Result := Result + ' COMMENT '+esc(ColProps[5]); + if ColProps[6] <> '' then + Result := Result + ' COLLATE '+ColProps[6]; + Result := Result + ','+CRLF; + end; + + for i:=0 to Indexes.Count - 1 do begin + Result := Result + #9 + GetIndexSQL(Indexes, i) + ','+CRLF; + end; + if Columns.Count + Indexes.Count > 0 then + Delete(Result, Length(Result)-2, 3); + + Result := Result + CRLF + + ')' + CRLF + + 'COMMENT = '+esc(memoComment.Text) + CRLF + + 'COLLATE = '+comboCollation.Text + CRLF + + 'ENGINE = '+comboEngine.Text + CRLF + + 'ROW_FORMAT = '+comboRowFormat.Text + CRLF + + 'CHECKSUM = '+IntToStr(Integer(chkChecksum.Checked)) + CRLF; + if editAutoInc.Text <> '' then + Result := Result + 'AUTO_INCREMENT = '+editAutoInc.Text + CRLF; + if editAvgRowLen.Text <> '' then + Result := Result + 'AVG_ROW_LENGTH = '+editAvgRowLen.Text + CRLF; + if editMaxRows.Text <> '' then + Result := Result + 'MAX_ROWS = '+editMaxRows.Text + CRLF; + if memoUnionTables.Enabled and (memoUnionTables.Text <> '') then + Result := Result + 'UNION = ('+memoUnionTables.Text+')' + CRLF; + if comboInsertMethod.Enabled and (comboInsertMethod.Text <> '') then + Result := Result + 'INSERT_METHOD = '+comboInsertMethod.Text + CRLF; + +end; + + +function TfrmTableEditor.GetIndexSQL(IndexList: TWideStringlist; idx: Integer): WideString; +var + IndexName, IndexType, ColName: WideString; + Parts: TWideStringlist; + i, p: Integer; +begin + IndexName := Copy(IndexList[idx], 1, LastPos(REGDELIM, IndexList[idx])-1); + IndexType := Copy(IndexList[idx], LastPos(REGDELIM, IndexList[idx])+1, Length(IndexList[idx])); + Result := 'ADD '; + if IndexType = PKEY then + Result := Result + 'PRIMARY KEY ' + else begin + if IndexType <> KEY then + Result := Result + IndexType + ' '; + Result := Result + 'INDEX ' + Mainform.Mask(IndexName) + ' '; + end; + Result := Result + '('; + Parts := TWideStringlist(IndexList.Objects[idx]); + for i:=0 to Parts.Count - 1 do begin + ColName := Parts[i]; + p := LastPos('(', ColName); + if p > 1 then + Result := Result + Mainform.Mask(Copy(ColName, 1, p-1)) + Copy(ColName, p, Length(ColName)-p+1) + else + Result := Result + Mainform.Mask(ColName); + Result := Result + ', '; + end; + if Parts.Count > 0 then + Delete(Result, Length(Result)-1, 2); + + Result := Result + ')'; +end; + + +procedure TfrmTableEditor.editNameChange(Sender: TObject); +begin + // Name edited + editName.Font.Color := clWindowText; + editName.Color := clWindow; + try + ensureValidIdentifier( editName.Text ); + except + // Invalid name + if editName.Text <> '' then begin + editName.Font.Color := clRed; + editName.Color := clYellow; + end; + end; + Modification(Sender); +end; + + +procedure TfrmTableEditor.Modification(Sender: TObject); +begin + // Memorize modified status + if FLoaded then begin + if Sender is TComponent then + TComponent(Sender).Tag := ModifiedFlag; + Modified := True; + end; +end; + + +procedure TfrmTableEditor.btnAddColumnClick(Sender: TObject); +var + DefProperties, Properties: TWideStringList; + fn: PVirtualNode; + idx: Integer; +begin + // Add new column after selected one + fn := listColumns.FocusedNode; + Properties := TWideStringList.Create; + Properties.OnChange := ColumnsChange; + if Assigned(fn) then begin + idx := fn.Index+1; + // Copy properties from focused node + DefProperties := TWideStringlist(Columns.Objects[fn.Index]); + Properties.Assign(DefProperties); + end else begin + idx := Columns.Count; + Properties.CommaText := 'INT,10,'+BoolToStr(False)+','+BoolToStr(True)+',0,,'; + end; + Columns.InsertObject(idx, 'Column '+IntToStr(idx+1), Properties); + SelectNode(listColumns, idx); +end; + + +procedure TfrmTableEditor.btnRemoveColumnClick(Sender: TObject); +var + i: Integer; + n: PVirtualNode; +begin + // Remove selected column + n := listColumns.FocusedNode; + for i:=0 to ColumnsChanges.Count-1 do begin + if ColumnsChanges.ValueFromIndex[i] = Columns[n.Index] then begin + ColumnsChanges[i] := ColumnsChanges.Names[i] + ColumnsChanges.NameValueSeparator; + break; + end; + end; + Columns.Delete(n.Index); + if (not Assigned(n)) and (Columns.Count > 0) then + SelectNode(listColumns, Columns.Count-1); +end; + + +procedure TfrmTableEditor.btnClearColumnsClick(Sender: TObject); +var i: Integer; +begin + // Set empty values in changelist + for i:=0 to ColumnsChanges.Count - 1 do + ColumnsChanges[i] := ColumnsChanges.Names[i] + ColumnsChanges.NameValueSeparator; + // I suspect Columns.Clear to be silly enough and leave its objects in memory, + // so we'll free them explicitely + for i := 0 to Columns.Count - 1 do + Columns.Objects[i].Free; + Columns.Clear; +end; + + +procedure TfrmTableEditor.btnMoveUpColumnClick(Sender: TObject); +begin + // Move column up + MoveFocusedColumn(listColumns.FocusedNode.Index-1); +end; + + +procedure TfrmTableEditor.btnMoveDownColumnClick(Sender: TObject); +begin + // Move column down + MoveFocusedColumn(listColumns.FocusedNode.Index+1); +end; + + +procedure TfrmTableEditor.listColumnsDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; + Mode: TDropMode; var Effect: Integer; var Accept: Boolean); +begin + Accept := (Source = Sender) and (Mode <> dmNowhere); + // Not sure what this effect does, probably show a specific mouse cursor? + Effect := DROPEFFECT_MOVE; +end; + + +procedure TfrmTableEditor.listColumnsDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); +var + Node: PVirtualNode; +begin + Node := Sender.GetNodeAt(Pt.X, Pt.Y); + if Assigned(Node) then + MoveFocusedColumn(Node.Index); +end; + + +procedure TfrmTableEditor.listColumnsAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); +var + Props: TWideStringlist; + ImageIndex, X, Y: Integer; + VT: TVirtualStringTree; + dt: TMysqlDataTypeRecord; +begin + // Paint checkbox image in certain columns + if not (Column in [4, 5]) then + Exit; + Props := TWideStringlist(Columns.Objects[Node.Index]); + + // Restrict "Allow NULL" checkbox to numeric datatypes + if Column = 4 then begin + dt := GetDatatypeByName(Props[0]); + if not dt.HasUnsigned then + Exit; + end; + + if StrToBool(Props[Column-2]) then ImageIndex := 128 + else ImageIndex := 127; + VT := TVirtualStringTree(Sender); + X := CellRect.Left + (VT.Header.Columns[Column].Width div 2) - (VT.Images.Width div 2); + Y := CellRect.Top + Integer(VT.NodeHeight[Node] div 2) - (VT.Images.Height div 2); + VT.Images.Draw(TargetCanvas, X, Y, ImageIndex); +end; + + +procedure TfrmTableEditor.listColumnsBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); +var + VT: TVirtualStringTree; + OldNodeCount: Cardinal; +begin + // (Re)paint column list. Adjust number of nodes and autofit leftmost counter column. + VT := Sender as TVirtualStringTree; + OldNodeCount := VT.RootNodeCount; + VT.RootNodeCount := Columns.Count; + if OldNodeCount <> VT.RootNodeCount then + VT.Header.AutoFitColumns(False, smaUseColumnOption, 0, 0); +end; + + +procedure TfrmTableEditor.listColumnsFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + // Column focus changed + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.ValidateColumnControls; +var Node: PVirtualNode; +begin + Node := listColumns.FocusedNode; + btnRemoveColumn.Enabled := Assigned(Node); + btnClearColumns.Enabled := Columns.Count > 0; + btnMoveUpColumn.Enabled := Assigned(Node) and (Node <> listColumns.GetFirst); + btnMoveDownColumn.Enabled := Assigned(Node) and (Node <> listColumns.GetLast); + + menuRemoveColumn.Enabled := btnRemoveColumn.Enabled; + menuClearColumns.Enabled := btnClearColumns.Enabled; + menuMoveUpColumn.Enabled := btnMoveUpColumn.Enabled; + menuMoveDownColumn.Enabled := btnMoveDownColumn.Enabled; +end; + + +procedure TfrmTableEditor.listColumnsEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +begin + // No editor for very first column and checkbox columns + Allowed := not (Column in [0, 4, 5]); +end; + + +procedure TfrmTableEditor.listColumnsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: WideString); +var + Properties: TWideStringList; +begin + // Display column text + case Column of + 0: CellText := IntToStr(Node.Index+1); + 1: CellText := Columns[Node.Index]; + 4, 5: CellText := ''; // Checkbox + else begin + Properties := TWideStringList(Columns.Objects[Node.Index]); + CellText := Properties[Column-2]; + end; + end; + if Column = 6 then + CellText := Copy(CellText, 2, Length(CellText)-1); +end; + + +procedure TfrmTableEditor.listColumnsPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +var + Datatype: String; + TextColor: TColor; + dt: TMySQLDatatypeRecord; +begin + // Give datatype column specific color, as set in preferences + if vsSelected in Node.States then + Exit; + + case Column of + 2: begin + Datatype := TWideStringlist(Columns.Objects[Node.Index])[0]; + dt := GetDatatypeByName(Datatype); + + case dt.Category of + catInteger, catReal: TextColor := Mainform.prefFieldColorNumeric; + catTemporal: TextColor := Mainform.prefFieldColorDateTime; + catText: TextColor := Mainform.prefFieldColorText; + catBinary: TextColor := Mainform.prefFieldColorBinary; + catIntegerNamed: TextColor := Mainform.prefFieldColorEnum; + catSet, catSetNamed: TextColor := Mainform.prefFieldColorSet; + // TODO: catSpatial + else TextColor := TargetCanvas.Font.Color; + end; + end; + + 6: begin + // TODO: text black, special values blue? + TextColor := clBlue; + end; + else Exit; + end; + + TargetCanvas.Font.Color := TextColor; +end; + + +procedure TfrmTableEditor.listColumnsNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); +var + Properties: TWideStringList; + idx, i: Integer; +begin + // Column property edited + if Column = 1 then begin + idx := Columns.IndexOf(NewText); + if (idx > -1) and (idx <> Integer(Node.Index)) then begin + MessageDlg('Column "'+NewText+'" already exists.', mtError, [mbOk], 0); + Sender.EditNode(Node, Column); + Exit; + end; + + for i:=0 to ColumnsChanges.Count -1 do begin + if ColumnsChanges.ValueFromIndex[i] = Columns[Node.Index] then begin + ColumnsChanges.ValueFromIndex[i] := NewText; + break; + end; + end; + + Columns[Node.Index] := NewText; + end else if Column > 1 then begin + Properties := TWideStringList(Columns.Objects[Node.Index]); + Properties[Column-2] := NewText; + end; +end; + + +procedure TfrmTableEditor.listColumnsClick(Sender: TObject); +var + VT: TVirtualStringTree; + Props: TWideStringlist; + dt: TMySQLDataTypeRecord; + Node: PVirtualNode; +begin + // Handle click event + VT := Sender as TVirtualStringTree; + if not Assigned(VT.FocusedNode) then + Exit; + if VT.FocusedColumn in [4, 5] then begin + // For checkboxes, cell editors are disabled, instead toggle their state + Props := TWideStringList(Columns.Objects[VT.FocusedNode.Index]); + dt := GetDatatypeByName(Props[0]); + if dt.HasUnsigned or (VT.FocusedColumn = 5) then begin + Props[VT.FocusedColumn-2] := BoolToStr(not StrToBool(Props[VT.FocusedColumn-2])); + VT.InvalidateNode(VT.FocusedNode); + end; + end else begin + // All other cells go into edit mode please + // Explicitely done on OnClick, not in OnFocusChanged which seemed annoying for keyboard users + Node := VT.GetNodeAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y); + if Assigned(Node) then + VT.EditNode(Node, VT.FocusedColumn); + end; +end; + + +procedure TfrmTableEditor.listColumnsCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + EnumEditor: TEnumEditorLink; + DefaultEditor: TColumnDefaultEditorLink; + i: Integer; + ds: TDataset; + Props: TWideStringlist; +begin + // Start cell editor + case Column of + 2: begin // Datatype pulldown + EnumEditor := TEnumEditorLink.Create; + EnumEditor.ValueList := TWideStringList.Create; + for i:=Low(MySqlDataTypeArray) to High(MySqlDataTypeArray) do + EnumEditor.ValueList.Add(MySqlDataTypeArray[i].Name); + EditLink := EnumEditor; + end; + 8: begin // Collation pulldown + EnumEditor := TEnumEditorLink.Create; + EnumEditor.ValueList := TWideStringList.Create; + ds := Mainform.GetCollations; + while not ds.Eof do begin + EnumEditor.ValueList.Add(ds.FieldByName('Collation').AsString); + ds.Next; + end; + EditLink := EnumEditor; + end; + 6: begin + DefaultEditor := TColumnDefaultEditorLink.Create; + Props := TWideStringlist(Columns.Objects[Node.Index]); + DefaultEditor.DefaultType := TColumnDefaultType(MakeInt(Copy(Props[Column-2], 0, 1))); + DefaultEditor.DefaultText := Copy(Props[Column-2], 2, Length(Props[Column-2])-1); + EditLink := DefaultEditor; + end + else + EditLink := TStringEditLink.Create + end; +end; + + +procedure TfrmTableEditor.SetModified(Value: Boolean); +begin + // Some value has changed + FModified := Value; + btnOK.Enabled := FModified; + btnApply.Enabled := FModified; + SQLCodeValid := False; + UpdateSQLcode; +end; + + +procedure TfrmTableEditor.ColumnsChange(Sender: TObject); +begin + Modification(Sender); + listColumns.Repaint; +end; + + +procedure TfrmTableEditor.SelectNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode=nil); +var Node: PVirtualNode; +begin + // Helper to focus and highlight a node by its index + if Assigned(ParentNode) then + Node := VT.GetFirstChild(ParentNode) + else + Node := VT.GetFirst; + while Assigned(Node) do begin + if Node.Index = idx then begin + VT.FocusedNode := Node; + VT.Selected[Node] := True; + break; + end; + Node := VT.GetNextSibling(Node); + end; +end; + + +procedure TfrmTableEditor.MoveFocusedColumn(NewIdx: Cardinal); +begin + if listColumns.IsEditing then + listColumns.EndEditNode; + listColumns.FocusedColumn := listColumns.Header.MainColumn; + Columns.Move(listColumns.FocusedNode.Index, NewIdx); + SelectNode(listColumns, NewIdx); +end; + + +procedure TfrmTableEditor.editNumEditChange(Sender: TObject); +var + ed: TEdit; + ShouldBe: String; + CursorPos: Integer; +begin + // Only numbers allowed in this TEdit + Modification(Sender); + ed := Sender as TEdit; + ShouldBe := IntToStr(Makeint(ed.Text)); + if (ed.Text = ShouldBe) or (ed.Text = '') then Exit; + MessageBeep(MB_ICONEXCLAMATION); + CursorPos := ed.SelStart; + ed.OnChange := nil; + ed.Text := ShouldBe; + ed.SelStart := CursorPos; + ed.OnChange := editNumEditChange; +end; + + +procedure TfrmTableEditor.comboEngineSelect(Sender: TObject); +var + IsMerge: Boolean; +begin + // Enable/disable engine specific option controls + IsMerge := (Sender as TComboBox).Text = 'MRG_MYISAM'; + memoUnionTables.Enabled := IsMerge; + comboInsertMethod.Enabled := IsMerge; +end; + + +procedure TfrmTableEditor.IndexesChange(Sender: TObject); +begin + Modification(Sender); + treeIndexes.Invalidate; +end; + + +procedure TfrmTableEditor.btnAddIndexClick(Sender: TObject); +var + IndexParts: TWideStringlist; + Name: WideString; +begin + // Add new index + IndexParts := TWideStringlist.Create; + IndexParts.OnChange := IndexesChange; + Name := 'Index '+IntToStr(Indexes.Count+1); + Indexes.AddObject(Name+REGDELIM+KEY, IndexParts); + SelectNode(treeIndexes, Indexes.Count-1); +end; + + +procedure TfrmTableEditor.menuAddIndexColumnClick(Sender: TObject); +var + IndexParts: TWideStringlist; + Node: PVirtualNode; + i, j, p: Integer; + Col, NewCol: WideString; + ColExists: Boolean; +begin + // Add column to index + Node := treeIndexes.FocusedNode; + if not Assigned(Node) then + Exit; + if treeIndexes.GetNodeLevel(Node) = 1 then + Node := Node.Parent; + IndexParts := TWideStringlist(Indexes.Objects[Node.Index]); + ColExists := False; + NewCol := ''; + for i:=0 to Columns.Count - 1 do begin + for j:=0 to IndexParts.Count - 1 do begin + Col := IndexParts[j]; + p := LastPos('(', Col); + if p > 0 then + Col := Copy(Col, 0, p-1); + ColExists := Col = Columns[i]; + if ColExists then + break; + end; + if not ColExists then begin + NewCol := Columns[i]; + break; + end; + end; + treeIndexes.AddChild(Node); + IndexParts.Add(NewCol); + SelectNode(treeIndexes, IndexParts.Count-1, Node); +end; + + +procedure TfrmTableEditor.btnRemoveIndexClick(Sender: TObject); +var + IndexParts: TWideStringlist; + Name: WideString; + idx: Integer; + NewSelectNode: PVirtualNode; +begin + // Remove index or part + case treeIndexes.GetNodeLevel(treeIndexes.FocusedNode) of + 0: begin + idx := treeIndexes.FocusedNode.Index; + Indexes.Objects[idx].Free; + Indexes.Delete(idx); + end; + 1: begin + idx := treeIndexes.FocusedNode.Parent.Index; + IndexParts := TWideStringlist(Indexes.Objects[idx]); + IndexParts.Delete(treeIndexes.FocusedNode.Index); + Name := treeIndexes.Text[treeIndexes.FocusedNode.Parent, 0]; + end; + end; + NewSelectNode := treeIndexes.GetPreviousVisible(treeIndexes.FocusedNode); + treeIndexes.DeleteNode(treeIndexes.FocusedNode); + if Assigned(NewSelectNode) then + SelectNode(treeIndexes, NewSelectNode.Index, NewSelectNode.Parent); +end; + + +procedure TfrmTableEditor.btnClearIndexesClick(Sender: TObject); +var i: Integer; +begin + // Clear all indexes + for i := 0 to Indexes.Count - 1 do + Indexes.Objects[i].Free; + Indexes.Clear; + treeIndexes.Clear; +end; + + +procedure TfrmTableEditor.treeIndexesGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +var + IndexType: String; + VT: TVirtualStringTree; +begin + // Icon image showing type of index + VT := Sender as TVirtualStringTree; + if Column <> 0 then + Exit; + case VT.GetNodeLevel(Node) of + 0: begin + IndexType := VT.Text[Node, 1]; + if IndexType = PKEY then ImageIndex := ICONINDEX_PRIMARYKEY + else if IndexType = KEY then ImageIndex := ICONINDEX_INDEXKEY + else if IndexType = UKEY then ImageIndex := ICONINDEX_UNIQUEKEY + else if IndexType = FKEY then ImageIndex := ICONINDEX_FULLTEXTKEY + else if IndexType = SKEY then ImageIndex := ICONINDEX_SPATIALKEY; + end; + 1: ImageIndex := 42; + end; +end; + + +procedure TfrmTableEditor.treeIndexesGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: WideString); +var + IndexProps: TWideStringlist; + IndexType: WideString; +begin + // Index tree showing cell text + case Sender.GetNodeLevel(Node) of + 0: begin + IndexType := Copy(Indexes[Node.Index], LastPos(REGDELIM, Indexes[Node.Index])+1, Length(Indexes[Node.Index])); + case Column of + 0: if IndexType = PKEY then + CellText := IndexType + ' KEY' // Fixed name "PRIMARY KEY", cannot be changed + else + CellText := Copy(Indexes[Node.Index], 1, LastPos(REGDELIM, Indexes[Node.Index])-1); + 1: CellText := IndexType; + end; + end; + 1: case Column of + 0: begin + IndexProps := TWideStringlist(Indexes.Objects[Node.Parent.Index]); + CellText := IndexProps[Node.Index]; + end; + else CellText := ''; + end; + end; +end; + + +procedure TfrmTableEditor.treeIndexesInitChildren(Sender: TBaseVirtualTree; + Node: PVirtualNode; var ChildCount: Cardinal); +var + IndexParts: TWideStringlist; +begin + // Tell number of columns contained in index + IndexParts := TWideStringlist(Indexes.Objects[Node.Index]); + ChildCount := IndexParts.Count; +end; + + +procedure TfrmTableEditor.treeIndexesInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +begin + // Show plus sign on first level nodes + if Sender.GetNodeLevel(Node) = 0 then + Include( InitialStates, ivsHasChildren); +end; + + +procedure TfrmTableEditor.treeIndexesFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + ValidateIndexControls; +end; + + +procedure TfrmTableEditor.ValidateIndexControls; +var + Node: PVirtualNode; + HasNode: Boolean; + Level: Integer; +begin + // Enable/disable buttons + Node := treeIndexes.FocusedNode; + HasNode := Assigned(Node); + if HasNode then Level := treeIndexes.GetNodeLevel(Node) + else Level := -1; + + btnRemoveIndex.Enabled := HasNode; + btnClearIndexes.Enabled := Indexes.Count > 0; + btnMoveUpIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetFirstChild(Node.Parent)); + btnMoveDownIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetLastChild(Node.Parent)); + + menuAddIndexColumn.Enabled := HasNode; + menuRemoveIndex.Enabled := btnRemoveIndex.Enabled; + menuClearIndexes.Enabled := btnClearIndexes.Enabled; + menuMoveUpIndex.Enabled := btnMoveUpIndex.Enabled; + menuMoveDownIndex.Enabled := btnMoveDownIndex.Enabled; +end; + + +procedure TfrmTableEditor.treeIndexesEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +var + VT: TVirtualStringtree; +begin + // Disallow renaming primary key + VT := Sender as TVirtualStringtree; + if (VT.GetNodeLevel(Node) = 0) and (Column = VT.Header.MainColumn) and (VT.Text[Node, Column+1] = PKEY) then + Allowed := False + else if (VT.GetNodeLevel(Node) = 1) and (Column = 1) then + Allowed := False + else + Allowed := True; +end; + + +procedure TfrmTableEditor.treeIndexesCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + EnumEditor: TEnumEditorLink; + Level: Cardinal; +begin + // Start cell editor + Level := (Sender as TVirtualStringtree).GetNodeLevel(Node); + if (Level = 0) and (Column = 1) then begin + // Index type pulldown + EnumEditor := TEnumEditorLink.Create; + EnumEditor.ValueList := TWideStringList.Create; + EnumEditor.ValueList.CommaText := PKEY +','+ KEY +','+ UKEY +','+ FKEY +','+ SKEY; + EditLink := EnumEditor; + end else if (Level = 1) and (Column = 0) then begin + // Column names pulldown + EnumEditor := TEnumEditorLink.Create; + EnumEditor.ValueList := Columns; + EnumEditor.AllowCustomText := True; // Allows adding a subpart in index parts: "TextCol(20)" + EditLink := EnumEditor; + end else + EditLink := TStringEditLink.Create +end; + + +procedure TfrmTableEditor.treeIndexesNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); +var + VT: TVirtualStringtree; + IndexParts: TWideStringlist; +begin + // Rename index of column + VT := Sender as TVirtualStringtree; + case VT.GetNodeLevel(Node) of + 0: case Column of + 0: Indexes[Node.Index] := NewText + REGDELIM + VT.Text[Node, Column+1]; + 1: Indexes[Node.Index] := VT.Text[Node, Column-1] + REGDELIM + NewText; + end; + 1: begin + IndexParts := TWideStringlist(Indexes.Objects[Node.Parent.Index]); + IndexParts[Node.Index] := NewText; + end; + end; + VT.RepaintNode(Node); +end; + + +procedure TfrmTableEditor.treeIndexesBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); +begin + // (Re)paint index list + (Sender as TVirtualStringTree).RootNodeCount := Indexes.Count; +end; + + +procedure TfrmTableEditor.treeIndexesDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; + Mode: TDropMode; var Effect: Integer; var Accept: Boolean); +var + Node: PVirtualNode; +begin + // Accept nodes from the column list and allow column moving + if Source = listColumns then begin + Accept := True; + Exit; + end else if Source = Sender then begin + Node := Sender.GetNodeAt(Pt.X, Pt.Y); + Accept := Assigned(Node) and (Sender.GetNodeLevel(Node) = 1) and + (Node <> Sender.FocusedNode) and (Node.Parent = Sender.FocusedNode.Parent); + end; +end; + + +procedure TfrmTableEditor.treeIndexesDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); +var + Node: PVirtualNode; + IndexParts: TWideStringlist; + ColName: WideString; + ColPos: Integer; + VT: TVirtualStringtree; +begin + // Column node dropped here + VT := Sender as TVirtualStringtree; + Node := VT.GetNodeAt(Pt.X, Pt.Y); + if not Assigned(Node) then begin + MessageBeep(MB_ICONEXCLAMATION); + Exit; + end; + if VT.GetNodeLevel(Node) = 1 then begin + ColPos := Node.Index; + if Mode = dmBelow then Inc(ColPos); + Node := Node.Parent; + end else + ColPos := MaxInt; + + if Source = Sender then + MoveFocusedIndexPart(ColPos) + else begin + IndexParts := TWideStringlist(Indexes.Objects[Node.Index]); + ColName := Columns[(Source as TVirtualStringTree).FocusedNode.Index]; + if IndexParts.IndexOf(ColName) > -1 then begin + if MessageDlg('Index "'+VT.Text[Node, 0]+'" already contains the column "'+ColName+'". It is possible to add a column twice into a index, but total nonsense in practice.'+CRLF+CRLF+'Add anyway?', + mtConfirmation, [mbYes, mbNo], 0) = mrNo then + Exit; + end; + + if ColPos >= IndexParts.Count then + IndexParts.Add(ColName) + else + IndexParts.Insert(ColPos, ColName); + Node.States := Node.States + [vsHasChildren, vsExpanded]; + end; + // Finally tell parent node to update its children + VT.ReinitChildren(Node, False); +end; + + +procedure TfrmTableEditor.btnMoveUpIndexClick(Sender: TObject); +begin + // Move index part up + MoveFocusedIndexPart(treeIndexes.FocusedNode.Index-1); +end; + + +procedure TfrmTableEditor.btnMoveDownIndexClick(Sender: TObject); +begin + // Move index part down + MoveFocusedIndexPart(treeIndexes.FocusedNode.Index+1); +end; + + +procedure TfrmTableEditor.MoveFocusedIndexPart(NewIdx: Cardinal); +var + IndexParts: TWideStringlist; +begin + // Move focused index or index part + if treeIndexes.IsEditing then + treeIndexes.EndEditNode; + IndexParts := TWideStringlist(Indexes.Objects[treeIndexes.FocusedNode.Parent.Index]); + IndexParts.Move(treeIndexes.FocusedNode.Index, NewIdx); + SelectNode(treeIndexes, NewIdx, treeIndexes.FocusedNode.Parent); +end; + + +procedure TfrmTableEditor.SetStatus(msg: WideString); +begin + if msg <> '' then + Screen.Cursor := crHourglass + else + Screen.Cursor := crDefault; + lblStatus.Caption := msg; + lblStatus.Repaint; +end; + + +procedure TfrmTableEditor.PageControlMainChange(Sender: TObject); +begin + UpdateSQLcode; +end; + + +procedure TfrmTableEditor.UpdateSQLcode; +var + OldTopLine: Integer; +begin + if (PageControlMain.ActivePage = tabSQLCode) and (not SQLCodeValid) then begin + SynMemoSQLcode.BeginUpdate; + OldTopLine := SynMemoSQLcode.TopLine; + if AlterTableName <> '' then + SynMemoSQLcode.Text := ComposeAlterStatement + else + SynMemoSQLcode.Text := ComposeCreateStatement; + SynMemoSQLcode.TopLine := OldTopLine; + SynMemoSQLcode.EndUpdate; + SQLCodeValid := True; + end; +end; + + +procedure TfrmTableEditor.btnHelpClick(Sender: TObject); +begin + // Help button + Mainform.CallSQLHelpWithKeyword('CREATE TABLE'); +end; + + +end. diff --git a/source/tbl_properties.dfm b/source/tbl_properties.dfm deleted file mode 100644 index 3a42ec47..00000000 --- a/source/tbl_properties.dfm +++ /dev/null @@ -1,185 +0,0 @@ -object tbl_properties_form: Ttbl_properties_form - Left = 771 - Top = 113 - BorderIcons = [] - Caption = 'Table-Properties' - ClientHeight = 351 - ClientWidth = 312 - Color = clBtnFace - Constraints.MinHeight = 350 - Constraints.MinWidth = 180 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 13 - object lblName: TLabel - Left = 8 - Top = 20 - Width = 31 - Height = 13 - Caption = '&Name:' - FocusControl = editName - end - object lblCharset: TLabel - Left = 8 - Top = 95 - Width = 70 - Height = 13 - Caption = '&Character set:' - FocusControl = comboCharset - end - object lblCollation: TLabel - Left = 8 - Top = 120 - Width = 45 - Height = 13 - Caption = 'C&ollation:' - FocusControl = comboCollation - end - object lblComment: TLabel - Left = 8 - Top = 45 - Width = 49 - Height = 13 - Caption = 'Co&mment:' - FocusControl = editComment - end - object lblEngine: TLabel - Left = 8 - Top = 70 - Width = 36 - Height = 11 - Caption = '&Engine:' - FocusControl = comboEngine - end - object lblCreate: TLabel - Left = 8 - Top = 213 - Width = 156 - Height = 13 - Caption = 'SQL &preview for CREATE TABLE:' - FocusControl = SynMemoCreate - end - object lblAutoincrement: TLabel - Left = 8 - Top = 145 - Width = 77 - Height = 13 - Caption = '&Auto increment:' - FocusControl = editAutoincrement - end - object SynMemoCreate: TSynMemo - Left = 8 - Top = 232 - Width = 296 - Height = 111 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 8 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - end - object btnCancel: TButton - Left = 229 - Top = 178 - Width = 75 - Height = 25 - Anchors = [akTop, akRight] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 7 - end - object editName: TTntEdit - Left = 88 - Top = 17 - Width = 216 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - Text = 'editName' - OnChange = editNameChange - end - object editComment: TTntEdit - Left = 88 - Top = 42 - Width = 216 - Height = 21 - Anchors = [akLeft, akTop, akRight] - MaxLength = 60 - TabOrder = 1 - Text = 'editComment' - end - object comboCollation: TComboBox - Left = 88 - Top = 117 - Width = 216 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 4 - end - object comboCharset: TComboBox - Left = 88 - Top = 92 - Width = 216 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 3 - OnChange = comboCharsetChange - end - object comboEngine: TComboBox - Left = 88 - Top = 67 - Width = 216 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 2 - end - object btnOK: TButton - Left = 148 - Top = 178 - Width = 75 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 6 - end - object editAutoincrement: TEdit - Left = 88 - Top = 143 - Width = 216 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - Text = 'editAutoincrement' - end -end diff --git a/source/tbl_properties.pas b/source/tbl_properties.pas deleted file mode 100644 index 928f02c3..00000000 --- a/source/tbl_properties.pas +++ /dev/null @@ -1,319 +0,0 @@ -unit tbl_properties; - - -// ------------------------------------- -// Advanced table-properties -// ------------------------------------- - - -interface - -uses - Windows, Messages, SysUtils, Classes, Controls, Forms, Graphics, - Dialogs, StdCtrls, Db, Menus, SynMemo, SynEdit, WideStrings, TntStdCtrls; - -type - Ttbl_properties_form = class(TForm) - lblName: TLabel; - editName: TTntEdit; - lblComment: TLabel; - editComment: TTntEdit; - lblEngine: TLabel; - comboEngine: TComboBox; - lblCharset: TLabel; - comboCharset: TComboBox; - lblCollation: TLabel; - comboCollation: TComboBox; - lblAutoincrement: TLabel; - editAutoincrement: TEdit; - - btnOK: TButton; - btnCancel: TButton; - - lblCreate: TLabel; - SynMemoCreate: TSynMemo; - procedure FormDestroy(Sender: TObject); - - procedure comboCharsetChange(Sender: TObject); - procedure editNameChange(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure menuSelectAllClick(Sender: TObject); - private - dsCollations: TDataSet; - currentName, - currentComment, - currentEngine, - currentCharset, - currentCollation, - currentAutoincrement : WideString; - public - TableName : WideString; - end; - -implementation - -uses - Main, helpers; - -{$R *.DFM} - - -{** - Form gets created. Fetch list with charsets, collations and engines once. -} -procedure Ttbl_properties_form.FormCreate(Sender: TObject); -var - charset : String; -begin - InheritFont(Font); - - try - dsCollations := Mainform.GetResults('SHOW COLLATION'); - except - // Ignore it when the above statement doesn't work on pre 4.1 servers. - // If the list is nil, disable the combobox, so we create the db without charset. - end; - - // Create a list with charsets from collations dataset - comboCharset.Enabled := dsCollations <> nil; - lblCharset.Enabled := comboCharset.Enabled; - if comboCharset.Enabled then - begin - comboCharset.Items.BeginUpdate; - dsCollations.First; - while not dsCollations.Eof do - begin - charset := dsCollations.FieldByName('Charset').AsString; - if comboCharset.Items.IndexOf(charset) = -1 then - comboCharset.Items.Add(charset); - dsCollations.Next; - end; - comboCharset.Sorted := True; - comboCharset.Items.EndUpdate; - end; - - // Only enable collation selection if list was fetched successfully - comboCollation.Enabled := dsCollations <> nil; - lblCollation.Enabled := comboCollation.Enabled; - - // Display supported engines in pulldown - Mainform.TableEnginesCombo( comboEngine ); - - // Setup SynMemo - SynMemoCreate.Highlighter := Mainform.SynSQLSyn1; - SynMemoCreate.Font.Name := Mainform.SynMemoQuery.Font.Name; - SynMemoCreate.Font.Size := Mainform.SynMemoQuery.Font.Size; - - SetWindowSizeGrip( Self.Handle, True ); -end; - - -procedure Ttbl_properties_form.FormDestroy(Sender: TObject); -begin - if dsCollations <> nil then dsCollations.Close; - FreeAndNil(dsCollations); -end; - -{** - Form gets displayed. -} -procedure Ttbl_properties_form.FormShow(Sender: TObject); -var - ds: TDataSet; - sql : WideString; -begin - // Fetch table properties - sql := 'SHOW TABLE STATUS '; - sql := sql + 'LIKE '+esc(TableName); - ds := Mainform.GetResults(sql); - - // Table name - currentName := ds.FieldByName('Name').AsWideString; - editName.Text := currentName; - - // Comment - currentComment := ds.FieldByName('Comment').AsWideString; - editComment.Text := currentComment; - - // Engine - currentEngine := ds.Fields[1].AsString; - comboEngine.ItemIndex := comboEngine.Items.IndexOf(currentEngine); - - // Collation - if ds.FindField('Collation') <> nil then - currentCollation := ds.FieldByName('Collation').AsString; - - // Character set - currentCharset := ''; - if dsCollations <> nil then - begin - dsCollations.First; - while not dsCollations.Eof do - begin - if dsCollations.FieldByName('Collation').AsString = currentCollation then - begin - currentCharset := dsCollations.FieldByName('Charset').AsString; - comboCharset.ItemIndex := comboCharset.Items.IndexOf(currentCharset); - // Invoke selecting collation - comboCharsetChange( Sender ); - break; - end; - dsCollations.Next; - end; - end; - - // Auto increment. Disabled if empty string. - editAutoincrement.Text := ''; - editAutoincrement.Enabled := False; - if ds.FieldByName('Auto_increment').AsString <> '' then - begin - currentAutoincrement := IntToStr(MakeInt(ds.FieldByName('Auto_increment').AsString)); - editAutoincrement.Text := currentAutoincrement; - editAutoincrement.Enabled := True; - end; - lblAutoincrement.Enabled := editAutoincrement.Enabled; - ds.Close; - FreeAndNil(ds); - - // SQL preview - sql := 'SHOW CREATE TABLE '; - sql := sql + Mainform.mask(currentName); - SynMemoCreate.Lines.Text := Mainform.GetVar( sql, 1 ); - - editName.SetFocus; - editName.SelectAll; -end; - - -{** - Charset has been selected: Display fitting collations - and select default one. -} -procedure Ttbl_properties_form.comboCharsetChange(Sender: TObject); -var - defaultCollation : String; -begin - // Abort if collations were not fetched successfully - if dsCollations = nil then - Exit; - - // Fill pulldown with fitting collations - comboCollation.Items.BeginUpdate; - comboCollation.Items.Clear; - dsCollations.First; - while not dsCollations.Eof do - begin - if dsCollations.FieldByName('Charset').AsString = comboCharset.Text then - begin - comboCollation.Items.Add( dsCollations.FieldByName('Collation').AsString ); - if dsCollations.FieldByName('Default').AsString = 'Yes' then - defaultCollation := dsCollations.FieldByName('Collation').AsString; - end; - dsCollations.Next; - end; - comboCollation.Sorted := True; - - // Preselect default or current collation - if currentCollation <> '' then - defaultCollation := currentCollation; - if comboCollation.Items.IndexOf(defaultCollation) > -1 then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(defaultCollation) - else - comboCollation.ItemIndex := 0; - - comboCollation.Items.EndUpdate; -end; - - -{** - User writes something into editName -} -procedure Ttbl_properties_form.editNameChange(Sender: TObject); -begin - try - ensureValidIdentifier( editName.Text ); - editName.Font.Color := clWindowText; - editName.Color := clWindow; - // Enable "OK"-Button if we have a valid name - btnOK.Enabled := True; - except - editName.Font.Color := clRed; - editName.Color := clYellow; - btnOK.Enabled := False; - end; -end; - - -{** - Select all text in a synmemo -} -procedure Ttbl_properties_form.menuSelectAllClick(Sender: TObject); -begin - SynMemoCreate.SelectAll; -end; - - -{** - Form is closing. Check ModalResult for which button was clicked. -} -procedure Ttbl_properties_form.FormClose(Sender: TObject; var Action: - TCloseAction); -var - sql, tmp : WideString; - AlterSpecs : TWideStringList; -begin - if ModalResult = mrOK then - begin - AlterSpecs := TWideStringList.Create; - - // Rename table - if currentName <> editName.Text then - begin - tmp := 'RENAME '; - tmp := tmp + Mainform.mask(editName.Text); - AlterSpecs.Add( tmp ); - end; - - // Comment - if currentComment <> editComment.Text then - AlterSpecs.Add( 'COMMENT = ' + esc(editComment.Text) ); - - // Engine - if comboEngine.Enabled and (currentEngine <> comboEngine.Text) then - AlterSpecs.Add( 'ENGINE = ' + comboEngine.Text ); - - // Charset - if comboCharset.Enabled and (currentCharset <> comboCharset.Text) then - AlterSpecs.Add( 'CHARSET ' + comboCharset.Text ); - - // Collation - if comboCollation.Enabled and (currentCollation <> comboCollation.Text) then - AlterSpecs.Add( 'COLLATE ' + comboCollation.Text ); - - // Auto_increment - if editAutoincrement.Enabled and (currentAutoincrement <> editAutoincrement.Text) then - AlterSpecs.Add( 'AUTO_INCREMENT = ' + IntToStr( MakeInt(editAutoincrement.Text) ) ); - - if AlterSpecs.Count > 0 then - begin - sql := 'ALTER TABLE ' + Mainform.mask(currentName) + ' ' + ImplodeStr(', ', AlterSpecs); - try - Mainform.ExecUpdateQuery( sql ); - except - On E:Exception do - begin - MessageDlg('Altering table was not successful: '+CRLF+CRLF+E.Message, mtError, [mbOK], 0); - // Keep form open - ModalResult := mrNone; - end; - end; - Mainform.actRefresh.Execute; - end; - - end; -end; - - -end.