From dd398bb1011849e373071df2f75972e827c4066a Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Mon, 14 Dec 2009 23:55:36 +0000 Subject: [PATCH] * Factor more code out of each database object editors into parent TDBObjectEditor. * Use this chance to add a confirmation dialog when leaving the editors, to ask the user if he wants to save modifications. Fixes issue #1524. * Also, enhance Mainform.RefreshTreeDB in a way that it does not trigger the OnFocusChange event. Important for the editors when saving changes. --- source/helpers.pas | 55 ++++++++++++++++++++++- source/main.pas | 60 ++++++++++++++++++------- source/routine_editor.dfm | 2 +- source/routine_editor.pas | 62 +++++++++++-------------- source/table_editor.pas | 95 +++++++++++++++++---------------------- source/trigger_editor.pas | 41 ++++++++--------- source/view.pas | 45 +++++++++++-------- 7 files changed, 213 insertions(+), 147 deletions(-) diff --git a/source/helpers.pas b/source/helpers.pas index 0ef88ec8..a04def97 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -147,9 +147,15 @@ type private FModified: Boolean; procedure SetModified(Value: Boolean); + protected + FEditObjectName: WideString; public - procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); Virtual; Abstract; + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); virtual; + procedure DeInit; property Modified: Boolean read FModified write SetModified; + procedure ApplyModifications; virtual; abstract; end; @@ -245,7 +251,7 @@ var implementation -uses main, uVistaFuncs; +uses main, uVistaFuncs, table_editor, view, routine_editor, trigger_editor; type CharacterSet = record @@ -3236,11 +3242,56 @@ end; { *** TDBObjectEditor } +constructor TDBObjectEditor.Create(AOwner: TComponent); +begin + inherited; + // Do not set alClient via DFM! In conjunction with ExplicitXXX properties that + // repeatedly breaks the GUI layout when you reload the project + Align := alClient; + InheritFont(Font); +end; + +destructor TDBObjectEditor.Destroy; +begin + DeInit; + inherited; +end; + procedure TDBObjectEditor.SetModified(Value: Boolean); begin FModified := Value; end; +procedure TDBObjectEditor.Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); +begin + DeInit; + Mainform.showstatus('Initializing editor ...'); + FEditObjectName := ObjectName; + Mainform.SetEditorTabCaption(Self, FEditObjectName); + Screen.Cursor := crHourglass; + MainForm.SetupSynEditors; +end; + +procedure TDBObjectEditor.DeInit; +var + Msg, ObjType: WideString; +begin + // Ask for saving modifications + if Modified then begin + if Self is TfrmTableEditor then ObjType := 'table' + else if Self is TfrmView then ObjType := 'view' + else if Self is TfrmRoutineEditor then ObjType := 'routine' + else if Self is TfrmTriggerEditor then ObjType := 'trigger' + else ObjType := ''; + if FEditObjectName <> '' then + Msg := 'Save modified '+ObjType+' "'+FEditObjectName+'"?' + else + Msg := 'Save new '+ObjType+'?'; + if MessageDlg(Msg, mtConfirmation, [mbYes, mbNo], 0) = mrYes then + ApplyModifications; + end; +end; + end. diff --git a/source/main.pas b/source/main.pas index 43991301..12600632 100644 --- a/source/main.pas +++ b/source/main.pas @@ -1056,6 +1056,20 @@ procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); var filename : String; begin + // Destroy editors and dialogs. Must be done before connection gets closed, as some destructors do SQL stuff. + FreeAndNil(RoutineEditor); + FreeAndNil(TableToolsDialog); + FreeAndNil(UserManagerForm); + FreeAndNil(ViewEditor); + FreeAndNil(SelectDBObjectForm); + FreeAndNil(SQLHelpForm); + FreeAndNil(OptionsForm); + FreeAndNil(SessionManager); + FreeAndNil(TableEditor); + FreeAndNil(TriggerEditor); + FreeAndNil(CreateDatabaseForm); + + // Close database connection DoDisconnect; OpenRegistry; @@ -1086,18 +1100,6 @@ begin SaveListSetup(ListCommandStats); SaveListSetup(ListTables); - FreeAndNil(RoutineEditor); - FreeAndNil(TableToolsDialog); - FreeAndNil(UserManagerForm); - FreeAndNil(ViewEditor); - FreeAndNil(SelectDBObjectForm); - FreeAndNil(SQLHelpForm); - FreeAndNil(OptionsForm); - FreeAndNil(SessionManager); - FreeAndNil(TableEditor); - FreeAndNil(TriggerEditor); - FreeAndNil(CreateDatabaseForm); - debug('mem: clearing query and browse data.'); SetLength(DataGridResult.Rows, 0); SetLength(DataGridResult.Columns, 0); @@ -6286,15 +6288,39 @@ end; procedure TMainForm.RefreshTreeDB(db: WideString); var oldActiveDatabase: WideString; - dbnode: PVirtualNode; + DBNode, FNode: PVirtualNode; + oldSelectedTable: TListNode; + TableHereHadFocus: Boolean; + Results: TMySQLQuery; + FocusChangeEvent: procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object; begin oldActiveDatabase := ActiveDatabase; - DBtree.ClearSelection; + oldSelectedTable := SelectedTable; DBNode := FindDBNode(db); + FNode := DBtree.FocusedNode; + TableHereHadFocus := FNode.Parent = DBNode; + // Suspend focus changing event, to avoid tab jumping + FocusChangeEvent := DBtree.OnFocusChanged; + DBtree.OnFocusChanged := nil; + // Refresh db node RefreshDbTableList(db); - DBTree.ReinitNode(dbnode, true); - DBtree.InvalidateChildren(dbnode, false); - ActiveDatabase := oldActiveDatabase; + DBTree.ReinitNode(DBNode, true); + DBtree.InvalidateChildren(DBNode, false); + // Set focus on previously focused table node + if TableHereHadFocus then begin + Results := FetchDbTableList(db); + while not Results.Eof do begin + // Need to check if table was renamed, in which case oldSelectedTable is no longer available + if (Results.Col(DBO_NAME) = oldSelectedTable.Text) + and (GetDBObjectType(Results) = oldSelectedTable.NodeType) then begin + SelectDBObject(oldSelectedTable.Text, oldSelectedTable.NodeType); + break; + end; + Results.Next; + end; + end; + // Reactivate focus changing event + DBtree.OnFocusChanged := FocusChangeEvent; end; diff --git a/source/routine_editor.dfm b/source/routine_editor.dfm index 383555b5..54fb75e5 100644 --- a/source/routine_editor.dfm +++ b/source/routine_editor.dfm @@ -85,7 +85,7 @@ object frmRoutineEditor: TfrmRoutineEditor Caption = 'Save' Default = True TabOrder = 12 - OnClick = PostChanges + OnClick = btnSaveClick end object btnDiscard: TButton Left = 84 diff --git a/source/routine_editor.pas b/source/routine_editor.pas index a86de120..f6a8a294 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -36,7 +36,7 @@ type lblSQLcode: TLabel; SynMemoBody: TSynMemo; procedure comboTypeSelect(Sender: TObject); - procedure PostChanges(Sender: TObject); + procedure btnSaveClick(Sender: TObject); procedure btnHelpClick(Sender: TObject); procedure editNameChange(Sender: TObject); procedure btnAddParamClick(Sender: TObject); @@ -69,12 +69,12 @@ type private { Private declarations } Parameters: TWideStringList; - FAlterRoutineName: WideString; FAlterRoutineType: String; public { Public declarations } constructor Create(AOwner: TComponent); override; procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); override; + procedure ApplyModifications; override; end; @@ -92,8 +92,7 @@ constructor TfrmRoutineEditor.Create(AOwner: TComponent); var i: Integer; begin - inherited Create(AOwner); - Align := alClient; + inherited; // Combo items in a .dfm are sporadically lost after an IDE restart, // so we set them here to avoid developer annoyance comboType.Items.Add('Procedure (doesn''t return a result)'); @@ -106,8 +105,6 @@ begin comboSecurity.Items.Add('Invoker'); for i := Low(Datatypes) to High(Datatypes) do comboReturns.Items.Add(Datatypes[i].Name); - SetWindowSizeGrip(Handle, True); - InheritFont(Font); Mainform.SynCompletionProposal.AddEditor(SynMemoBody); FixVT(listParameters); Parameters := TWideStringList.Create; @@ -124,11 +121,10 @@ var rx: TRegExpr; i: Integer; begin - MainForm.SetupSynEditors; - FAlterRoutineName := ObjectName; + inherited; if ObjectType = lntProcedure then FAlterRoutineType := 'PROCEDURE' else FAlterRoutineType := 'FUNCTION'; - editName.Text := FAlterRoutineName; + editName.Text := FEditObjectName; comboType.ItemIndex := 0; comboReturns.Text := ''; listParameters.Clear; @@ -137,16 +133,15 @@ begin comboSecurity.ItemIndex := 0; editComment.Clear; SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; - if FAlterRoutineName <> '' then begin + if FEditObjectName <> '' then begin // Editing existing routine - Mainform.SetEditorTabCaption(Self, FAlterRoutineName); Results := Mainform.Connection.GetResults('SELECT * FROM '+DBNAME_INFORMATION_SCHEMA+'.ROUTINES'+ ' WHERE ROUTINE_SCHEMA='+esc(Mainform.ActiveDatabase)+ - ' AND ROUTINE_NAME='+esc(FAlterRoutineName)+ + ' AND ROUTINE_NAME='+esc(FEditObjectName)+ ' AND ROUTINE_TYPE='+esc(FAlterRoutineType) ); if Results.RecordCount <> 1 then - Exception.Create('Cannot find properties of stored routine '+FAlterRoutineName); + Exception.Create('Cannot find properties of stored routine '+FEditObjectName); comboType.ItemIndex := ListIndexByRegExpr(comboType.Items, '^'+FAlterRoutineType+'\b'); chkDeterministic.Checked := Results.Col('IS_DETERMINISTIC') = 'YES'; comboReturns.Text := Results.Col('DTD_IDENTIFIER'); @@ -185,7 +180,6 @@ begin FreeAndNil(Results); end else begin editName.Text := 'Enter routine name'; - Mainform.SetEditorTabCaption(Self, ''); end; editNameChange(Self); comboTypeSelect(comboType); @@ -403,7 +397,14 @@ begin end; -procedure TfrmRoutineEditor.PostChanges(Sender: TObject); +procedure TfrmRoutineEditor.btnSaveClick(Sender: TObject); +begin + // Apply or OK button clicked + ApplyModifications; +end; + + +procedure TfrmRoutineEditor.ApplyModifications; var BaseSQL, TempSQL, FinalSQL, TempName: WideString; i: Integer; @@ -411,18 +412,8 @@ var ProcOrFunc: String; TargetExists: Boolean; begin - // Apply or OK button clicked + // Save changes ProcOrFunc := UpperCase(GetFirstWord(comboType.Text)); - if editName.Text = '' then begin - MessageDlg('Please specify the routine''s name.', mtError, [mbOK], 0); - editName.SetFocus; - Exit; - end else if (ProcOrFunc = 'FUNCTION') and (comboReturns.Text = '') then begin - MessageDlg('Please specify the function''s returning datatype.', mtError, [mbOK], 0); - comboReturns.SetFocus; - Exit; - end; - BaseSQL := ''; for i := 0 to Parameters.Count - 1 do begin par := explode(DELIM, Parameters[i]); @@ -448,18 +439,18 @@ begin // Create a temp routine, check for syntax errors, then drop the old routine and create it. // See also: http://dev.mysql.com/doc/refman/5.0/en/alter-procedure.html try - if FAlterRoutineName <> '' then begin + if FEditObjectName <> '' then begin // Create temp name i := 0; allRoutineNames := Mainform.Connection.GetCol('SELECT ROUTINE_NAME FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.'+Mainform.mask('ROUTINES')+ ' WHERE ROUTINE_SCHEMA = '+esc(Mainform.ActiveDatabase)+ ' AND ROUTINE_TYPE = '+esc(ProcOrFunc) ); - TargetExists := ((editName.Text <> FAlterRoutineName) or (ProcOrFunc <> FAlterRoutineType)) and + TargetExists := ((editName.Text <> FEditObjectName) or (ProcOrFunc <> FAlterRoutineType)) and (allRoutineNames.IndexOf(editName.Text) > -1); if TargetExists then begin if MessageDlg('Routine "'+editName.Text+'" already exists. Overwrite it?', - mtConfirmation, [mbOk, mbCancel], 0) = mrCancel then begin + mtConfirmation, [mbYes, mbNo], 0) = mrNo then begin Exit; end; end; @@ -474,7 +465,7 @@ begin // Drop temporary routine, used for syntax checking Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(TempName)); // Drop edited routine - Mainform.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(FAlterRoutineName)); + Mainform.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(FEditObjectName)); if TargetExists then begin // Drop target routine - overwriting has been confirmed, see above Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(editName.Text)); @@ -483,10 +474,10 @@ begin FinalSQL := 'CREATE '+ProcOrFunc+' '+Mainform.mask(editName.Text)+'(' + BaseSQL; Mainform.Connection.Query(FinalSQL); // Set editing name if create/alter query was successful - FAlterRoutineName := editName.Text; - FAlterRoutineType := ProcOrFunc; - Mainform.SetEditorTabCaption(Self, FAlterRoutineName); - Mainform.actRefresh.Execute; + FEditObjectName := editName.Text; + FAlterRoutineType := UpperCase(GetFirstWord(comboType.Text)); + Mainform.SetEditorTabCaption(Self, FEditObjectName); + Mainform.RefreshTreeDB(Mainform.ActiveDatabase); Modified := False; btnSave.Enabled := Modified; btnDiscard.Enabled := Modified; @@ -501,9 +492,10 @@ procedure TfrmRoutineEditor.btnDiscardClick(Sender: TObject); var t: TListNodeType; begin + Modified := False; if FAlterRoutineType = 'PROCEDURE' then t := lntProcedure else t := lntFunction; - Init(FAlterRoutineName, t); + Init(FEditObjectName, t); end; diff --git a/source/table_editor.pas b/source/table_editor.pas index 0bcd2a30..d21d25e4 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -170,7 +170,6 @@ type private { Private declarations } FLoaded: Boolean; - FAlterTableName: WideString; CreateCodeValid, AlterCodeValid: Boolean; FColumns, FKeys, FForeignKeys: TObjectList; DeletedKeys, DeletedForeignKeys: TWideStringList; @@ -190,6 +189,7 @@ type constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); override; + procedure ApplyModifications; override; end; @@ -207,12 +207,8 @@ const constructor TfrmTableEditor.Create(AOwner: TComponent); begin - inherited Create(AOwner); - // Do not set alClient via DFM! In conjunction with ExplicitXXX properties that - // repeatedly breaks the GUI layout when you reload the project - Align := alClient; + inherited; PageControlMain.Height := GetRegValue(REGNAME_TABLEEDITOR_TABSHEIGHT, PageControlMain.Height); - InheritFont(Font); FixVT(listColumns); FixVT(treeIndexes); FixVT(listForeignKeys); @@ -243,7 +239,7 @@ begin Mainform.SaveListSetup(listColumns); Mainform.SaveListSetup(treeIndexes); Mainform.SaveListSetup(listForeignKeys); - Inherited; + inherited; end; @@ -252,22 +248,16 @@ var CreateTable, AttrName, AttrValue: WideString; rx: TRegExpr; begin - Mainform.showstatus('Initializing editor ...'); - Screen.Cursor := crHourglass; + inherited; FLoaded := False; - // Start with "basic" tab activated when just called - if FAlterTableName <> ObjectName then - PageControlMain.ActivePage := tabBasic; comboEngine.Items := Mainform.Connection.TableEngines; comboEngine.ItemIndex := comboEngine.Items.IndexOf(Mainform.Connection.TableEngineDefault); comboCollation.Items := Mainform.Connection.CollationList; - FAlterTableName := ObjectName; listColumns.BeginUpdate; FColumns.Clear; btnClearIndexesClick(Self); btnClearForeignKeysClick(Self); - tabALTERcode.TabVisible := FAlterTableName <> ''; - MainForm.SetupSynEditors; + tabALTERcode.TabVisible := FEditObjectName <> ''; // Clear value editors memoComment.Text := ''; editAutoInc.Text := ''; @@ -279,16 +269,14 @@ begin memoUnionTables.Clear; comboInsertMethod.ItemIndex := -1; - if FAlterTableName = '' then begin + if FEditObjectName = '' then begin // Creating new table editName.Text := 'Enter table name'; - Mainform.SetEditorTabCaption(Self, ''); comboCollation.ItemIndex := comboCollation.Items.IndexOf(Mainform.Connection.GetVar('SHOW VARIABLES LIKE ''collation_database''', 1)); PageControlMain.ActivePage := tabBasic; end else begin // Editing existing table - editName.Text := FAlterTableName; - Mainform.SetEditorTabCaption(Self, FAlterTableName); + editName.Text := FEditObjectName; CreateTable := Mainform.SelectedTableCreateStatement; rx := TRegExpr.Create; rx.ModifierI := True; @@ -347,43 +335,47 @@ end; procedure TfrmTableEditor.btnDiscardClick(Sender: TObject); begin // Reinit GUI, discarding changes - Init(FAlterTableName); + Modified := False; + Init(FEditObjectName); end; procedure TfrmTableEditor.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +procedure TfrmTableEditor.ApplyModifications; var sql: WideString; i: Integer; Specs: TWideStringlist; Key: TForeignKey; Col: TTableColumn; - FocusChangeEvent: procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object; begin // Create or alter table - try - if FAlterTableName = '' then - sql := ComposeCreateStatement - else begin - sql := ComposeAlterStatement; - // Special case for altered foreign keys: These have to be dropped in a seperate query - // otherwise the server would return error 121 "Duplicate key on write or update" - // See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html : - // "You cannot add a foreign key and drop a foreign key in separate clauses of a single - // ALTER TABLE statement. Separate statements are required." - Specs := TWideStringList.Create; - for i:=0 to FForeignKeys.Count-1 do begin - Key := FForeignKeys[i] as TForeignKey; - if Key.Modified and (not Key.Added) then - Specs.Add('DROP FOREIGN KEY '+Mainform.mask(Key.KeyName)); - end; - if Specs.Count > 0 then - Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(FAlterTableName)+' '+ImplodeStr(', ', Specs)); + Specs := TWideStringList.Create; + if FEditObjectName = '' then + sql := ComposeCreateStatement + else begin + sql := ComposeAlterStatement; + // Special case for altered foreign keys: These have to be dropped in a seperate query + // otherwise the server would return error 121 "Duplicate key on write or update" + // See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html : + // "You cannot add a foreign key and drop a foreign key in separate clauses of a single + // ALTER TABLE statement. Separate statements are required." + for i:=0 to FForeignKeys.Count-1 do begin + Key := FForeignKeys[i] as TForeignKey; + if Key.Modified and (not Key.Added) then + Specs.Add('DROP FOREIGN KEY '+Mainform.mask(Key.KeyName)); end; + end; + try + if Specs.Count > 0 then + Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(FEditObjectName)+' '+ImplodeStr(', ', Specs)); Mainform.Connection.Query(sql); - // Set table name for altering if Apply was clicked - FAlterTableName := editName.Text; - tabALTERcode.TabVisible := FAlterTableName <> ''; + tabALTERcode.TabVisible := FEditObjectName <> ''; if chkCharsetConvert.Checked then begin // Autoadjust column collations for i:=0 to FColumns.Count-1 do begin @@ -392,15 +384,12 @@ begin Col.Collation := comboCollation.Text; end; end; - ResetModificationFlags; - - // Refresh db tree and reselect edited table node. - // Supress tab jumping, implicitely invoked by RefreshTreeDB. - FocusChangeEvent := Mainform.DBtree.OnFocusChanged; - Mainform.DBtree.OnFocusChanged := nil; + // Set table name for altering if Apply was clicked + FEditObjectName := editName.Text; + tabALTERcode.TabVisible := FEditObjectName <> ''; + Mainform.SetEditorTabCaption(Self, FEditObjectName); Mainform.RefreshTreeDB(Mainform.ActiveDatabase); - Mainform.DBtree.OnFocusChanged := FocusChangeEvent; - Mainform.SelectDBObject(FAlterTableName, lntTable); + ResetModificationFlags; except on E:Exception do MessageDlg(E.Message, mtError, [mbOk], 0); @@ -466,7 +455,7 @@ begin Mainform.showstatus('Composing ALTER statement ...'); Screen.Cursor := crHourglass; Specs := TWideStringlist.Create; - if editName.Text <> FAlterTableName then + if editName.Text <> FEditObjectName then Specs.Add('RENAME TO ' + Mainform.mask(editName.Text)); if memoComment.Tag = ModifiedFlag then Specs.Add('COMMENT=' + esc(memoComment.Text)); @@ -595,7 +584,7 @@ begin Specs.Add('ADD '+GetForeignKeySQL(i)); end; - Result := 'ALTER TABLE '+Mainform.mask(FAlterTableName) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); + Result := 'ALTER TABLE '+Mainform.mask(FEditObjectName) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); Result := Trim(Result); FreeAndNil(Specs); Mainform.showstatus; @@ -1731,7 +1720,7 @@ end; procedure TfrmTableEditor.chkCharsetConvertClick(Sender: TObject); begin - chkCharsetConvert.Enabled := (FAlterTablename <> '') and (comboCollation.ItemIndex > -1); + chkCharsetConvert.Enabled := (FEditObjectName <> '') and (comboCollation.ItemIndex > -1); listColumns.Repaint; Modification(Sender); end; diff --git a/source/trigger_editor.pas b/source/trigger_editor.pas index c5912d44..da6acaee 100644 --- a/source/trigger_editor.pas +++ b/source/trigger_editor.pas @@ -31,11 +31,11 @@ type var CurrentInput: WideString; var x, y: Integer; var CanExecute: Boolean); private { Private declarations } - FEditTriggerName: WideString; public { Public declarations } constructor Create(AOwner: TComponent); override; procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); override; + procedure ApplyModifications; override; end; implementation @@ -53,10 +53,8 @@ var col: TProposalColumn; i: Integer; begin - inherited Create(AOwner); - Align := alClient; + inherited; SynMemoStatement.Highlighter := Mainform.SynSQLSyn1; - InheritFont(Font); editName.MaxLength := NAME_LEN; comboTiming.Items.Text := 'BEFORE'+CRLF+'AFTER'; comboEvent.Items.Text := 'INSERT'+CRLF+'UPDATE'+CRLF+'DELETE'; @@ -78,8 +76,7 @@ procedure TfrmTriggerEditor.Init(ObjectName: WideString=''; ObjectType: TListNod var Definition, TableList: TMySQLQuery; begin - Mainform.SetupSynEditors; - FEditTriggerName := ObjectName; + inherited; editName.Text := ''; SynMemoStatement.Text := ''; comboEvent.ItemIndex := 0; @@ -93,20 +90,18 @@ begin end; if comboTable.Items.Count > 0 then comboTable.ItemIndex := 0; - if FEditTriggerName <> '' then begin + if FEditObjectName <> '' then begin // Edit mode - Mainform.SetEditorTabCaption(Self, FEditTriggerName); - editName.Text := FEditTriggerName; + editName.Text := FEditObjectName; Definition := Mainform.Connection.GetResults('SELECT '+ 'EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_STATEMENT, ACTION_TIMING '+ 'FROM information_schema.TRIGGERS '+ - 'WHERE TRIGGER_SCHEMA='+esc(Mainform.ActiveDatabase)+' AND TRIGGER_NAME='+esc(FEditTriggerName)); + 'WHERE TRIGGER_SCHEMA='+esc(Mainform.ActiveDatabase)+' AND TRIGGER_NAME='+esc(FEditObjectName)); comboTable.ItemIndex := comboTable.Items.IndexOf(Definition.Col('EVENT_OBJECT_TABLE')); comboTiming.ItemIndex := comboTiming.Items.IndexOf(UpperCase(Definition.Col('ACTION_TIMING'))); comboEvent.ItemIndex := comboEvent.Items.IndexOf(UpperCase(Definition.Col('EVENT_MANIPULATION'))); SynMemoStatement.Text := Definition.Col('ACTION_STATEMENT'); end else begin - Mainform.SetEditorTabCaption(Self, ''); editName.Text := 'Enter trigger name'; end; Modified := False; @@ -129,19 +124,25 @@ end; procedure TfrmTriggerEditor.btnDiscardClick(Sender: TObject); begin // Reinit editor, discarding changes - Init(FEditTriggerName); + Modified := False; + Init(FEditObjectName); end; procedure TfrmTriggerEditor.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +procedure TfrmTriggerEditor.ApplyModifications; var sql: WideString; - FocusChangeEvent: procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object; begin // Edit mode means we drop the trigger and recreate it, as there is no ALTER TRIGGER. try - if FEditTriggerName <> '' then - Mainform.Connection.Query('DROP TRIGGER '+Mainform.mask(FEditTriggerName)); + if FEditObjectName <> '' then + Mainform.Connection.Query('DROP TRIGGER '+Mainform.mask(FEditObjectName)); // CREATE // [DEFINER = { user | CURRENT_USER }] // TRIGGER trigger_name trigger_time trigger_event @@ -151,12 +152,12 @@ begin ' ON '+Mainform.mask(comboTable.Text)+ ' FOR EACH ROW '+SynMemoStatement.Text; Mainform.Connection.Query(sql); - FocusChangeEvent := Mainform.DBtree.OnFocusChanged; - Mainform.DBtree.OnFocusChanged := nil; + FEditObjectName := editName.Text; + Mainform.SetEditorTabCaption(Self, FEditObjectName); Mainform.RefreshTreeDB(Mainform.ActiveDatabase); - Mainform.DBtree.OnFocusChanged := FocusChangeEvent; - Mainform.SelectDBObject(editName.Text, lntTrigger); - Init(editName.Text); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; except on E:Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; diff --git a/source/view.pas b/source/view.pas index 51d23e1f..6e97745f 100644 --- a/source/view.pas +++ b/source/view.pas @@ -26,11 +26,11 @@ type procedure Modification(Sender: TObject); private { Private declarations } - FEditViewName: WideString; public { Public declarations } constructor Create(AOwner: TComponent); override; procedure Init(ObjectName: WideString=''; ObjectType: TListNodeType=lntNone); override; + procedure ApplyModifications; override; end; @@ -46,11 +46,9 @@ uses main; } constructor TfrmView.Create(AOwner: TComponent); begin - inherited Create(AOwner); - Align := alClient; + inherited; SynMemoSelect.Highlighter := Mainform.SynSQLSyn1; Mainform.SynCompletionProposal.AddEditor(SynMemoSelect); - InheritFont(Font); editName.MaxLength := NAME_LEN; end; @@ -64,16 +62,15 @@ var db: WideString; rx: TRegExpr; begin - FEditViewName := ObjectName; - if FEditViewName <> '' then begin + inherited; + if FEditObjectName <> '' then begin // Edit mode - editName.Text := FEditViewName; - Mainform.SetEditorTabCaption(Self, FEditViewName); + editName.Text := FEditObjectName; db := Mainform.ActiveDatabase; Results := Mainform.Connection.GetResults('SELECT * FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.VIEWS ' + - 'WHERE TABLE_SCHEMA = '+esc(db)+' AND TABLE_NAME = '+esc(FEditViewName)); + 'WHERE TABLE_SCHEMA = '+esc(db)+' AND TABLE_NAME = '+esc(FEditObjectName)); if Results.RecordCount = 0 then - raise Exception.Create('Can''t find view definition for "'+FEditViewName+'" in '+DBNAME_INFORMATION_SCHEMA); + raise Exception.Create('Can''t find view definition for "'+FEditObjectName+'" in '+DBNAME_INFORMATION_SCHEMA); // Algorithm is not changeable as we cannot look up its current state! rgAlgorithm.Enabled := False; rgAlgorithm.ItemIndex := 0; @@ -88,7 +85,6 @@ begin rx.Free; end else begin // Create mode - Mainform.SetEditorTabCaption(Self, ''); editName.Text := 'Enter view name'; rgAlgorithm.Enabled := True; rgAlgorithm.ItemIndex := 0; @@ -98,7 +94,6 @@ begin end; // Ensure name is validated editNameChange(Self); - MainForm.SetupSynEditors; Modified := False; btnSave.Enabled := Modified; btnDiscard.Enabled := Modified; @@ -129,7 +124,7 @@ procedure TfrmView.btnHelpClick(Sender: TObject); var keyword: String; begin - if FEditViewName = '' then + if FEditObjectName = '' then keyword := 'CREATE VIEW' else keyword := 'ALTER VIEW'; @@ -140,24 +135,31 @@ end; procedure TfrmView.btnDiscardClick(Sender: TObject); begin // Reinit editor, discarding changes - Init(FEditViewName); + Modified := False; + Init(FEditObjectName); end; {** - Apply changes: Compose and execute SQL + Apply changes } procedure TfrmView.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +procedure TfrmView.ApplyModifications; var sql, viewname, renamed: String; begin - // Compose CREATE or ALTER statement - if FEditViewName = '' then begin + // Save changes + if FEditObjectName = '' then begin sql := 'CREATE '; viewname := editName.Text; end else begin sql := 'ALTER '; - viewname := FEditViewName; + viewname := FEditObjectName; end; viewname := Mainform.mask(viewname); if rgAlgorithm.Enabled and (rgAlgorithm.ItemIndex > -1) then @@ -169,11 +171,16 @@ begin try Mainform.Connection.Query(sql); // Probably rename view - if (FEditViewName <> '') and (FEditViewName <> editName.Text) then begin + if (FEditObjectName <> '') and (FEditObjectName <> editName.Text) then begin renamed := Mainform.mask(editName.Text); Mainform.Connection.Query('RENAME TABLE '+viewname + ' TO '+renamed); end; + FEditObjectName := editName.Text; + Mainform.SetEditorTabCaption(Self, FEditObjectName); Mainform.RefreshTreeDB(Mainform.ActiveDatabase); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; except on E:Exception do MessageDlg(E.Message, mtError, [mbOk], 0);