unit fieldeditor; // ------------------------------------- // Field-/Index-Editor // ------------------------------------- interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ImgList, ToolWin, ExtCtrls, Buttons; type TFieldEditorMode = (femFieldAdd,femFieldUpdate,femIndexEditor); TFieldEditForm = class(TForm) pc: TPageControl; tabField: TTabSheet; ButtonCancel: TButton; ButtonOK: TButton; lblName: TLabel; lblType: TLabel; lblLengthSet: TLabel; lblDefault: TLabel; EditDefault: TEdit; EditLength: TEdit; ComboBoxType: TComboBox; EditFieldname: TEdit; GroupBoxAttributes: TGroupBox; CheckBoxBinary: TCheckBox; CheckBoxUnsigned: TCheckBox; CheckBoxZerofill: TCheckBox; CheckBoxNotNull: TCheckBox; CheckBoxAutoIncrement: TCheckBox; tabIndexes: TTabSheet; ComboBoxKeys: TComboBox; lblIndexName: TLabel; CheckBoxUnique: TCheckBox; ButtonAdd: TButton; ButtonDelete: TButton; lblColumnsUsed: TLabel; listColumnsUsed: TListBox; listColumnsAvailable: TListBox; btnAddColumnToIndex: TBitBtn; btnDeleteColumnFromIndex: TBitBtn; lblColumnsAvailable: TLabel; ButtonAddPrimary: TButton; ComboBoxPosition: TComboBox; lblPosition: TLabel; CheckBoxFulltext: TCheckBox; btnAddAllColumnsToIndex: TBitBtn; btnDeleteAllColumnsFromIndex: TBitBtn; btnDatatypeHelp: TSpeedButton; procedure btnDatatypeHelpClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure ComboBoxTypeChange(Sender: TObject); procedure AddUpdateField(Sender: TObject); procedure ButtonCancelClick(Sender: TObject); procedure pcChange(Sender: TObject); procedure OKClick(Sender: TObject); procedure UpdateKeys(Sender: TObject); procedure ComboBoxKeysChange(Sender: TObject); procedure ButtonAddClick(Sender: TObject); procedure InitFieldEditor(Sender: TObject); procedure InitIndexEditor(Sender: TObject); procedure RemoveField(Sender: TObject); procedure ButtonDeleteClick(Sender: TObject); procedure ButtonAddPrimaryClick(Sender: TObject); procedure ShowKeys(index: Integer=0); procedure CheckBoxUniqueClick(Sender: TObject); procedure AddField(Sender: TObject); procedure CheckBoxFulltextClick(Sender: TObject); procedure btnAddAllColumnsToIndexClick(Sender: TObject); procedure btnDeleteAllColumnsFromIndexClick(Sender: TObject); procedure togglebuttons(Sender: TObject); procedure ComboBoxKeysDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); private { Private declarations } TempKeys : TStringList; FMode : TFieldEditorMode; FModeWhenCalled : TFieldEditorMode; FFieldName : String; procedure ValidateControls; public { Public declarations } end; function FieldEditorWindow (AOwner : TComponent; AMode : TFieldEditorMode; AFieldName : String = '') : Boolean; var FieldEditForm: TFieldEditForm; {$I const.inc} implementation uses helpers, childwin, Main, mysql, db; var klist : Array of TMysqlIndex; {$R *.DFM} {*** Create form } function FieldEditorWindow (AOwner : TComponent; AMode : TFieldEditorMode; AFieldName : String = '') : Boolean; var f : TFieldEditForm; begin f := TFieldEditForm.Create(AOwner); f.FMode := AMode; // Also remember original mode for restoring when switching pagecontrol tabs f.FModeWhenCalled := AMode; f.FFieldName := AFieldName; // Init both editors f.InitFieldEditor (nil); f.InitIndexEditor (nil); Result := (f.ShowModal = mrOK); FreeAndNil (f); end; {*** Init Field-Editor } procedure TFieldEditForm.InitFieldEditor(Sender: TObject); var strtype : String; i : Integer; ListColumns : TListView; begin // Initiate "Position"-combobox ComboBoxPosition.Items.Clear; ComboBoxPosition.Items.Add('At End of Table'); ComboBoxPosition.Items.Add('At Beginning of Table'); // Reference to childwin's column-ListView ListColumns := Mainform.ChildWin.ListColumns; // get fieldlist // add fieldnames for i:=0 to ListColumns.Items.Count-1 do begin ComboBoxPosition.Items.Add('AFTER ' + mainform.mask(ListColumns.Items[i].Caption)); end; // re-fill datatypes-combobox ComboBoxType.Items.Clear; for i := Low(MySqlDataTypeArray) to High(MySqlDataTypeArray) do begin ComboBoxType.Items.Add( MySqlDataTypeArray[i].Name ); end; CheckBoxAutoIncrement.Enabled := true; case FMode of // "Field" tab in Add-mode femFieldAdd, femIndexEditor: begin CheckBoxAutoIncrement.Enabled := false; EditFieldName.Text := 'FieldName'; ComboBoxType.ItemIndex := 0; EditLength.Text := ''; EditDefault.Text := ''; CheckBoxUnsigned.Checked := true; if ListColumns.Selected <> nil then ComboBoxPosition.ItemIndex := ListColumns.Selected.Index+2 else ComboBoxPosition.ItemIndex := 0; end; // "Field" tab in Update-mode femFieldUpdate: begin EditFieldname.Text := ListColumns.Selected.Caption; EditLength.Text := getEnumValues( ListColumns.Selected.Subitems[0] ); EditDefault.Text := ListColumns.Selected.Subitems[2]; // extract field type strtype := UpperCase( ListColumns.Selected.Subitems[0] ); if Pos ('(',strtype) > 0 then strtype := Trim(copy (strtype,0,Pos ('(',strtype)-1)); // field field type structure for i := Low(MySqlDataTypeArray) to High(MySqlDataTypeArray) do begin if (strtype=MySqlDataTypeArray[i].Name) then begin if MySqlDataTypeArray[i].HasLength then begin // enable / disable length field // get default length .. end; ComboBoxType.ItemIndex := MySqlDataTypeArray[i].Index; Break; end; end; // set attributes: strtype := LowerCase( ListColumns.Selected.Subitems[0] ); CheckBoxBinary.Checked := pos('binary', strtype) > 0; CheckBoxZerofill.Checked := pos('zerofill', strtype) > 0; CheckBoxUnsigned.Checked := pos('unsigned', strtype) > 0; CheckBoxNotNull.Checked := lowercase(ListColumns.Selected.Subitems[1]) <> 'yes'; CheckBoxAutoIncrement.Checked := lowercase(ListColumns.Selected.Subitems[3]) = 'auto_increment'; // TODO: Disable 'auto increment' checkbox if field is not part of index or primary key. end; end; end; {*** Init Index-Editor @todo cleanup code, get rid of WITH statement } procedure TFieldEditForm.InitIndexEditor(Sender: TObject); var i : Integer; cwin : TMDIChild; ds: TDataSet; begin listColumnsUsed.Items.Clear; listColumnsAvailable.Items.Clear; setlength(klist, 0); TempKeys := TStringList.Create; cwin := Mainform.ChildWin; ds := cwin.GetResults( 'SHOW KEYS FROM ' + mainform.mask(cwin.ActualTable) ); for i:=1 to ds.RecordCount do begin if TempKeys.IndexOf(ds.Fields[2].AsString) = -1 then begin TempKeys.Add(ds.Fields[2].AsString); setlength(klist, length(klist)+1); klist[length(klist)-1].Name := ds.Fields[2].AsString; klist[length(klist)-1].Columns := TStringList.Create; klist[length(klist)-1].Columns.Add(ds.Fields[4].AsString); klist[length(klist)-1].Modified := false; klist[length(klist)-1].Unique := (ds.Fields[1].AsString = '0'); if cwin.mysql_version < 40002 then klist[length(klist)-1].Fulltext := (ds.FieldByName('Comment').AsString = 'FULLTEXT') else klist[length(klist)-1].Fulltext := (ds.FieldByName('Index_type').AsString = 'FULLTEXT') end else klist[TempKeys.IndexOf(ds.Fields[2].AsString)].Columns.Add(ds.Fields[4].AsString); ds.Next; end; for i:=0 to cwin.ListColumns.Items.Count-1 do begin if cwin.ListColumns.Items[i] <> nil then self.listColumnsAvailable.Items.Add(cwin.ListColumns.Items[i].Caption); end; showkeys(); end; {*** FormShow } procedure TFieldEditForm.FormShow(Sender: TObject); begin if fMode in [femFieldUpdate, femFieldAdd] then begin pc.ActivePage := tabField; EditFieldName.SetFocus(); end; if fMode in [femIndexEditor] then begin pc.ActivePage := tabIndexes; if Length(klist) > 0 then ComboBoxKeys.SetFocus(); end; ComboBoxTypeChange(self); ValidateControls; end; {*** User selected a new datatype for the selected field. Take care of limitations of different datatypes, toggle clickability of certain checkboxes } procedure TFieldEditForm.ComboBoxTypeChange(Sender: TObject); var FieldType : TMysqlDataTypeRecord; begin // Attributes // Detect column-type FieldType := MySqlDataTypeArray[ComboBoxType.ItemIndex]; // BINARY CheckBoxBinary.Enabled := FieldType.HasBinary; if not CheckBoxBinary.Enabled then CheckBoxBinary.Checked := false; // Ensure checkbox is not ticked // UNSIGNED CheckBoxUnsigned.Enabled := FieldType.HasUnsigned; if not CheckBoxUnsigned.Enabled then CheckBoxUnsigned.Checked := false; // Ensure checkbox is not ticked // ZEROFILL CheckBoxZerofill.Enabled := FieldType.HasZerofill; if not CheckBoxZerofill.Enabled then CheckBoxZerofill.Checked := false; // Ensure checkbox is not ticked // Length/Set EditLength.Enabled := FieldType.HasLength; lblLengthSet.Enabled := EditLength.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 EditLength.Enabled then EditLength.Text := ''; // Fill length/set value with default value if empty if FieldType.RequiresLength then begin if (EditLength.Text = '') and (FieldType.DefLengthSet <> '') then EditLength.Text := FieldType.DefLengthSet; end; // DEFAULT EditDefault.Enabled := FieldType.HasDefault; lblDefault.Enabled := EditDefault.Enabled; if not EditDefault.Enabled then EditDefault.Text := ''; // Ensure text is empty end; {*** Add or update field @todo code cleanup } procedure TFieldEditForm.AddUpdateField(Sender: TObject); var strNotNull, strAttributes, strAutoIncrement, strLengthSet, strDefault, strPosition, fielddef : String; cwin : TMDIChild; begin // Apply Changes to field-definition // move field if position changed if (ComboBoxPosition.ItemIndex > -1) and (FMode in [femFieldUpdate]) then begin // Move field position if MessageDLG('You are about to move a field''s position in the table-structure. While there is no handy one-query-method in MySQL to do that, this will be done in 4 steps:'+CRLF+ ' 1. Adding a temporary field at the specified position'+CRLF+ ' 2. Filling the temporary field with the same data as source field'+CRLF+ ' 3. Dropping the source-field'+CRLF+ ' 4. Renaming the temporary field to it''s original name.'+CRLF+CRLF+ 'Be aware that this method can mess up existing indexes in your table or even can result in losing data! If you are not sure you should not use this function on indexed fields.'+CRLF+CRLF+ 'Continue?', mtConfirmation, [mbYes, mbCancel], 0 ) <> mrYes then Exit; end; Screen.Cursor := crSQLWait; try strAttributes := ''; // none of the 3 attributes binary, unsigned, zerofill strNotNull := ''; strDefault := ''; strAutoIncrement := ''; if CheckBoxBinary.Checked = true then strAttributes := strAttributes + ' BINARY'; if CheckBoxUnsigned.Checked = true then strAttributes := strAttributes + ' UNSIGNED'; if CheckBoxZerofill.Checked = true then strAttributes := strAttributes + ' ZEROFILL'; if (length(EditDefault.Text) > 0) and EditDefault.Enabled then strDefault := ' DEFAULT ' + esc(EditDefault.Text); if CheckBoxNotNull.Checked = True then strNotNull := ' NOT NULL'; if CheckBoxAutoIncrement.Checked = True then strAutoIncrement := ' AUTO_INCREMENT'; if (EditLength.text <> '') and EditLength.Enabled then strLengthSet := '(' + EditLength.text + ') ' else strLengthSet := ''; strPosition := ''; case ComboBoxPosition.ItemIndex of 0 : ; 1 : strPosition := ' FIRST'; else strPosition := ' ' + ComboBoxPosition.Text; end; fielddef := ComboBoxType.Text + // Type strLengthSet + // Length/Set strAttributes + // Attribute strDefault + // Default strNotNull + // Not Null strAutoIncrement; // Auto_increment cwin := Mainform.ChildWin; if (FMode = femFieldAdd) then begin cwin.ExecUpdateQuery( 'ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' ' + // table 'ADD ' + mainform.mask(EditFieldname.Text) + ' ' + // new name fielddef + strPosition // Position ); end else if (FMode = femFieldUpdate) then begin cwin.ExecUpdateQuery( 'ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' ' + // table 'CHANGE ' + mainform.mask(cwin.ListColumns.Selected.Caption) + ' ' + // old name mainform.mask(EditFieldName.Text) + ' ' + // new name fielddef ); //ShowMessageFmt ('ComboBox position: %d',[ComboBoxPosition.ItemIndex]); if ComboBoxPosition.ItemIndex > -1 then begin // Move field position cwin.ExecUpdateQuery( 'ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' ' + // table 'ADD ' + mainform.mask(TEMPFIELDNAME) + ' ' + // new name fielddef + strPosition // Position ); cwin.ExecUpdateQuery('UPDATE ' + mainform.mask(cwin.ActualTable) + ' SET '+mainform.mask(TEMPFIELDNAME)+'='+mainform.mask(EditFieldName.Text)); cwin.ExecUpdateQuery('ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' DROP '+mainform.mask(EditFieldName.Text)); cwin.ExecUpdateQuery( 'ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' ' + 'CHANGE ' + mainform.mask(TEMPFIELDNAME) + ' ' + mainform.mask(EditFieldName.Text) + ' ' + fielddef ); end; end; cwin.ShowTableProperties(self); ModalResult := mrOK; except on E: THandledSQLError do; end; Screen.Cursor := crDefault; end; {*** Cancel Form } procedure TFieldEditForm.ButtonCancelClick(Sender: TObject); begin ModalResult := mrCancel; end; {*** User selected another tab in the main-pagecontrol } procedure TFieldEditForm.pcChange(Sender: TObject); begin // Set FMode, according to selected tab if pc.ActivePage = tabField then begin if FModeWhenCalled = femFieldUpdate then begin // "Field" tab selected and original mode was "UpdateField" FMode := femFieldUpdate; end else begin // "Field" tab selected and original mode was "AddField" FMode := femFieldAdd; end; end else if pc.ActivePage = tabIndexes then begin // "Index" tab selected FMode := femIndexEditor; end; ValidateControls; end; {*** OK clicked - call correct save-procedure according to current mode } procedure TFieldEditForm.OKClick(Sender: TObject); begin // add/update what? if fMode in [femFieldUpdate, femFieldAdd] then begin AddUpdateField(self); end; if fMode in [femIndexEditor] then begin UpdateKeys(self); ModalResult := mrOK; end else ModalResult := mrCancel; end; {*** User selected another index in the combobox @todo code cleanup, get rid of WITH statement } procedure TFieldEditForm.ComboBoxKeysChange(Sender: TObject); var i : Integer; begin if ComboBoxKeys.ItemIndex > -1 then begin listColumnsAvailable.Items.Clear; for i:=0 to Mainform.ChildWin.ListColumns.Items.Count-1 do if (Mainform.ChildWin.ListColumns.Items[i] <> nil) and (klist[ComboBoxKeys.ItemIndex].columns.Indexof(Mainform.ChildWin.ListColumns.Items[i].Caption)=-1) then listColumnsAvailable.Items.Add(Mainform.ChildWin.ListColumns.Items[i].Caption); with klist[ComboBoxKeys.ItemIndex] do begin listColumnsUsed.Items := Columns; CheckBoxUnique.OnClick := nil; CheckBoxUnique.Checked := Unique; CheckBoxUnique.OnClick := CheckBoxUniqueClick; CheckBoxFulltext.OnClick := nil; CheckBoxFulltext.Checked := Fulltext; CheckBoxFulltext.OnClick := CheckBoxFulltextClick; CheckBoxUnique.Enabled := not (ComboBoxKeys.Text = 'PRIMARY'); CheckBoxFulltext.Enabled := not (ComboBoxKeys.Text = 'PRIMARY'); ButtonDelete.Enabled := true; listColumnsUsed.Enabled := true; listColumnsAvailable.Enabled := true; end; end; togglebuttons(self); end; {*** Add new index, init that with default values } procedure TFieldEditForm.ButtonAddClick(Sender: TObject); var kname : String; begin kname := 'NewIndex'; if not InputQuery('New Index...', 'Index-Name:', kname) then exit; if ComboBoxKeys.Items.IndexOf(kname) > -1 then begin MessageDlg('Index-Name '''+kname+''' already used!', mtError, [mbOk], 0); exit; end; setlength(klist, length(klist)+1); klist[length(klist)-1].Name := kname; klist[length(klist)-1].Columns := TStringList.Create; klist[length(klist)-1].Unique := false; klist[length(klist)-1].Fulltext := false; klist[length(klist)-1].Modified := true; showkeys(length(klist)-1); end; {*** Delete existing index } procedure TFieldEditForm.ButtonDeleteClick(Sender: TObject); var i,j : Integer; begin i := ComboBoxKeys.ItemIndex; if i > -1 then if MessageDlg('Delete Index ''' + ComboBoxKeys.Text + ''' ?', mtConfirmation, [mbYes,mbCancel], 0) = mrYes then begin inc(i); // jump to next entry after the one to delete! for j:=i to length(klist)-1 do klist[j-1] := klist[j]; setlength(klist, length(klist)-1); ShowKeys(i-2); end; end; {*** Add primary key } procedure TFieldEditForm.ButtonAddPrimaryClick(Sender: TObject); begin setlength(klist, length(klist)+1); klist[length(klist)-1].Name := 'PRIMARY'; klist[length(klist)-1].Columns := TStringList.Create; klist[length(klist)-1].Unique := false; klist[length(klist)-1].Fulltext := false; klist[length(klist)-1].Modified := true; ShowKeys(length(klist)-1); ButtonAddPrimary.Enabled := false; end; {*** Show indexes in combobox @param integer ItemIndex to select } procedure TFieldEditForm.ShowKeys(index: Integer=0); var i : Integer; begin ComboBoxKeys.Items.Clear; ButtonAddPrimary.Enabled := true; ButtonDelete.Enabled := false; listColumnsUsed.Enabled := false; listColumnsAvailable.Enabled := false; btnAddColumnToIndex.Enabled := false; btnDeleteColumnFromIndex.Enabled := false; for i:=0 to length(klist)-1 do ComboBoxKeys.Items.Add(klist[i].Name); if ComboBoxKeys.Items.IndexOf('PRIMARY') > -1 then ButtonAddPrimary.Enabled := false; if (index = -1) and (length(klist) > 0) then index := 0; if index < length(klist) then // careful: only if given index is < length(klist) ComboBoxKeys.ItemIndex := index; with ComboBoxKeys do if Items.Count = 0 then begin Enabled := false; Color := clBtnFace; end else begin Enabled := true; Color := clWindow; end; ComboBoxKeys.OnChange(self); end; {*** Make index unique! } procedure TFieldEditForm.CheckBoxUniqueClick(Sender: TObject); begin klist[ComboBoxKeys.ItemIndex].Unique := CheckBoxUnique.Checked; if CheckBoxUnique.Checked then begin klist[ComboBoxKeys.ItemIndex].Fulltext := false; CheckBoxFulltext.Checked := false; end; klist[ComboBoxKeys.ItemIndex].Modified := true; end; {*** Make index fulltext! } procedure TFieldEditForm.CheckBoxFulltextClick(Sender: TObject); begin klist[ComboBoxKeys.ItemIndex].Fulltext := CheckBoxFulltext.Checked; if CheckBoxFulltext.Checked then begin klist[ComboBoxKeys.ItemIndex].Unique := false; CheckBoxUnique.Checked := false; end; klist[ComboBoxKeys.ItemIndex].Modified := true; end; {*** update keys! for each TempKey (see OnFormShow) check if it was changed or even deleted in klist @todo code cleanup, get rid of WITH statement } procedure TFieldEditForm.UpdateKeys(Sender: TObject); var i,j,k, index : Integer; query1, query : String; columns_sql : String; begin query1 := 'ALTER TABLE ' + mainform.mask(Mainform.ChildWin.ActualTable); for i:=0 to TempKeys.Count-1 do begin index := -1; for j:=0 to length(klist)-1 do begin if TempKeys[i] = klist[j].Name then begin index := j; break; end; end; if (index > -1) and (klist[index].Modified) then begin // modify existing key // Prepare columns-list columns_sql := ''; for k := 0 to klist[index].Columns.Count - 1 do begin columns_sql := columns_sql + mainform.mask( klist[index].Columns[k] ); if k < klist[index].Columns.Count-1 then columns_sql := columns_sql + ', '; end; // PK: if klist[index].Name = 'PRIMARY' then query := query1 + ' DROP PRIMARY KEY' + ', ADD PRIMARY KEY (' + columns_sql + ')' // UNIQUE: else if klist[index].Unique then query := query1 + ' DROP INDEX ' + mainform.mask(klist[index].Name) + ', ADD UNIQUE ' + mainform.mask(klist[index].Name) + ' (' + columns_sql + ')' // FULLTEXT: else if klist[index].Fulltext then query := query1 + ' DROP INDEX ' + mainform.mask(klist[index].Name) + ', ADD FULLTEXT ' + mainform.mask(klist[index].Name) + ' (' + columns_sql + ')' // INDEX: else query := query1 + ' DROP INDEX '+ mainform.mask(klist[index].Name) + ', ADD INDEX ' + mainform.mask(klist[index].Name) + ' (' + columns_sql + ')'; Mainform.ChildWin.ExecUpdateQuery(query); klist[index].Modified := false; end else if index = -1 then begin // delete existing key if TempKeys[i] = 'PRIMARY' then query := query1 + ' DROP PRIMARY KEY' else query := query1 + ' DROP INDEX ' + mainform.mask(TempKeys[i]); Mainform.ChildWin.ExecUpdateQuery(query); end; if index > -1 then klist[index].Ready := true; end; for j:=0 to length(klist)-1 do begin if (not klist[j].Ready) then begin // Add a new key // Prepare columns-list columns_sql := ''; for k := 0 to klist[j].Columns.Count - 1 do begin columns_sql := columns_sql + mainform.mask( klist[j].Columns[k] ); if k < klist[j].Columns.Count-1 then columns_sql := columns_sql + ', '; end; // PK: if klist[j].Name = 'PRIMARY' then query := query1 + ' ADD PRIMARY KEY (' + columns_sql + ')' // UNIQUE: else if klist[j].Unique then query := query1 + ' ADD UNIQUE ' + mainform.mask(klist[j].Name) + ' (' + columns_sql + ')' // UNIQUE: else if klist[j].Fulltext then query := query1 + ' ADD FULLTEXT ' + mainform.mask(klist[j].Name) + ' (' + columns_sql + ')' // INDEX: else query := query1 + ' ADD INDEX '+ mainform.mask(klist[j].Name) + ' (' + columns_sql + ')'; Mainform.ChildWin.ExecUpdateQuery(query); end; end; Mainform.ChildWin.ShowTableProperties(self); close; end; {*** Add column to index } procedure TFieldEditForm.AddField(Sender: TObject); var idx : Integer; item: string; begin if listColumnsAvailable.ItemIndex > -1 then begin idx := listColumnsAvailable.ItemIndex; item := listColumnsAvailable.Items[idx]; listColumnsUsed.Items.Add(item); klist[ComboBoxKeys.ItemIndex].Columns.Add(item); listColumnsAvailable.Items.Delete(idx); klist[ComboBoxKeys.ItemIndex].Modified := true; // Highlight previous item to added one. listColumnsAvailable.ItemIndex := Min(Max(idx - 1, 0), listColumnsAvailable.Items.Count - 1); end; togglebuttons(self); end; {*** Add all columns to index } procedure TFieldEditForm.btnAddAllColumnsToIndexClick(Sender: TObject); begin listColumnsUsed.Items.AddStrings(listColumnsAvailable.Items); klist[ComboBoxKeys.ItemIndex].Columns.AddStrings(listColumnsAvailable.Items); listColumnsAvailable.Items.Clear; klist[ComboBoxKeys.ItemIndex].Modified := true; togglebuttons(self); end; {*** Delete column from index } procedure TFieldEditForm.RemoveField(Sender: TObject); var idx : Integer; item: string; begin if listColumnsUsed.ItemIndex > -1 then begin idx := listColumnsUsed.ItemIndex; item := listColumnsUsed.Items[idx]; klist[ComboBoxKeys.ItemIndex].Columns.Delete(idx); klist[ComboBoxKeys.ItemIndex].Modified := true; listColumnsAvailable.Items.Add(item); listColumnsUsed.Items.Delete(idx); // Highlight previous item to removed one. listColumnsUsed.ItemIndex := Min(Max(idx - 1, 0), listColumnsUsed.Items.Count - 1); end; togglebuttons(self); end; {*** Delete all columns from index } procedure TFieldEditForm.btnDeleteAllColumnsFromIndexClick(Sender: TObject); begin klist[ComboBoxKeys.ItemIndex].Columns.Clear; klist[ComboBoxKeys.ItemIndex].Modified := true; listColumnsAvailable.Items.AddStrings(listColumnsUsed.Items); listColumnsUsed.Items.Clear; togglebuttons(self); end; {*** Toggle enabled-status of Add- and Delete-Column-From-Index-buttons } procedure TFieldEditForm.togglebuttons(Sender: TObject); begin btnAddColumnToIndex.Enabled := (listColumnsAvailable.ItemIndex > -1); btnDeleteColumnFromIndex.Enabled := (listColumnsUsed.ItemIndex > -1); btnAddAllColumnsToIndex.Enabled := (listColumnsAvailable.Items.Count > 0); btnDeleteAllColumnsFromIndex.Enabled := (listColumnsUsed.Items.Count > 0); ValidateControls; end; {*** Add square-icon to index-names in combobox @todo: use Delphi's built-in TComboBox with icon-support } procedure TFieldEditForm.ComboBoxKeysDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var icon : Integer; c : tComboBox; begin c := (Control as TComboBox); with c.Canvas do begin Brush.Color := clWindow; FillRect(rect); if (klist[index].Unique) and (klist[index].Name <> 'PRIMARY') then icon := 64 else if klist[index].Fulltext then icon := 65 else if klist[index].Name = 'PRIMARY' then icon := 26 else icon := 63; Mainform.ImageList1.Draw(c.canvas, Rect.Left, Rect.Top, Icon); Font.Color := clWindowText; TextOut(Rect.Left + 18, Rect.Top, c.Items[Index]); end; end; {*** Call SQL help for selected datatype } procedure TFieldEditForm.btnDatatypeHelpClick(Sender: TObject); begin Mainform.ChildWin.CallSQLHelpWithKeyword(ComboBoxType.Text); end; {*** Ensure correct state of various controls } procedure TFieldEditForm.ValidateControls; begin ButtonOK.Enabled := true; case FMode of femFieldUpdate: begin ButtonOK.Caption := 'Update Field'; end; femFieldAdd: begin ButtonOK.Caption := 'Add Field'; end; femIndexEditor: begin ButtonOK.Caption := 'Update Indexes'; // Disable the button if a key was selected and no columns are listed on the left ButtonOK.Enabled := (ComboBoxKeys.ItemIndex = -1) or (listColumnsUsed.Items.Count > 0); end; end; Caption := Mainform.ChildWin.Description + ' - ' + ButtonOK.Caption; end; end.