diff --git a/source/connections.pas b/source/connections.pas index 3030ee44..ad753e68 100644 --- a/source/connections.pas +++ b/source/connections.pas @@ -737,7 +737,7 @@ procedure Tconnform.ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVi Column: TColumnIndex; out EditLink: IVTEditLink); begin // Use our own text editor to rename a session - EditLink := TInplaceEditorLink.Create(Sender as TVirtualStringTree); + EditLink := TInplaceEditorLink.Create(Sender as TVirtualStringTree, True); end; diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 68f27a5c..6416b249 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -706,6 +706,7 @@ type function HasResult: Boolean; virtual; abstract; function GetWhereClause: String; procedure CheckEditable; + function IsEditable: Boolean; procedure DeleteRow; function InsertRow: Int64; procedure SetCol(Column: Integer; NewText: String; Null: Boolean; IsFunction: Boolean); @@ -7989,6 +7990,19 @@ begin end; end; +function TDBQuery.IsEditable: Boolean; +begin + try + CheckEditable; + Result := True; + except + on E:EDbError do begin + FConnection.Log(lcDebug, E.Message); + Result := False; + end; + end; +end; + function TDBQuery.GetWhereClause: String; var diff --git a/source/grideditlinks.pas b/source/grideditlinks.pas index 6d7e5760..740cfd6e 100644 --- a/source/grideditlinks.pas +++ b/source/grideditlinks.pas @@ -36,6 +36,7 @@ type FOldWindowProc: TWndMethod; // Temporary switched to TempWindowProc to be able to catch Tab key FTableColumn: TTableColumn; FModified: Boolean; + FAllowEdit: Boolean; FBeginEditTime: Cardinal; procedure TempWindowProc(var Message: TMessage); procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -43,9 +44,12 @@ type procedure DoCancelEdit(Sender: TObject); function GetCellRect(InnerTextBounds: Boolean): TRect; public - property TableColumn: TTableColumn read FTableColumn write FTableColumn; // The table column of the cell being edited. Mostly used in data grids. - constructor Create; overload; // The original constructor, not used any more, throws an exception if you do - constructor Create(Tree: TVirtualStringTree); overload; virtual; // The right constructor, we need the Tree reference + // The table column of the cell being edited. Mostly used in data grids. + property TableColumn: TTableColumn read FTableColumn write FTableColumn; + // The original constructor, not used any more, throws an exception if you do + constructor Create; overload; + // The right constructor, we need the Tree reference + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); overload; virtual; destructor Destroy; override; function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall; function BeginEdit: Boolean; virtual; stdcall; @@ -63,7 +67,7 @@ type public MaxLength: Integer; TitleText: String; - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function CancelEdit: Boolean; override; @@ -90,7 +94,7 @@ type procedure TextChange(Sender: TObject); function MicroSecondsPrecision: Integer; public - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function EndEdit: Boolean; override; @@ -102,10 +106,11 @@ type private FCombo: TComboBox; procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure DoSelect(Sender: TObject); public ValueList, DisplayList: TStringList; AllowCustomText: Boolean; - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function EndEdit: Boolean; override; @@ -123,7 +128,7 @@ type procedure BtnCancelClick(Sender: TObject); public ValueList: TStringList; - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function EndEdit: Boolean; override; @@ -144,7 +149,7 @@ type public ButtonVisible: Boolean; TitleText: String; - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function CancelEdit: Boolean; override; @@ -173,7 +178,7 @@ type public DefaultType, OnUpdateType: TColumnDefaultType; DefaultText, OnUpdateText: String; - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function EndEdit: Boolean; override; @@ -199,7 +204,7 @@ type PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); procedure DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); public - constructor Create(Tree: TVirtualStringTree); override; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean); override; destructor Destroy; override; function BeginEdit: Boolean; override; function EndEdit: Boolean; override; @@ -232,7 +237,7 @@ begin [Self.ClassName, 'Create', Self.ClassName, 'Create(VirtualStringTree)']); end; -constructor TBaseGridEditorLink.Create(Tree: TVirtualStringTree); +constructor TBaseGridEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin inherited Create; FTree := Tree; @@ -243,6 +248,7 @@ begin FParentForm.Repaint; SendMessage(FParentForm.Handle, WM_SETREDRAW, 0, 0); FModified := False; + FAllowEdit := AllowEdit; end; destructor TBaseGridEditorLink.Destroy; @@ -333,7 +339,7 @@ begin Result := not FStopping; if FStopping then Exit; FStopping := True; - if FModified then + if FModified and FAllowEdit then FTree.Text[FNode, FColumn] := NewText; if FTree.CanFocus and (FLastKeyDown <> VK_TAB) then FTree.SetFocus; @@ -440,9 +446,9 @@ end; -constructor THexEditorLink.Create(Tree: TVirtualStringTree); +constructor THexEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; end; destructor THexEditorLink.Destroy; @@ -465,6 +471,7 @@ begin FForm.SetText(FCellText); FForm.SetTitleText(TitleText); FForm.SetMaxLength(MaxLength); + FForm.memoText.ReadOnly := not FAllowEdit; end; @@ -501,9 +508,9 @@ end; { DateTime editor } -constructor TDateTimeEditorLink.Create(Tree: TVirtualStringTree); +constructor TDateTimeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; FPanel := TPanel.Create(FParentForm); FPanel.Parent := FParentForm; @@ -519,6 +526,7 @@ begin FMaskEdit.OnKeyDown := DoKeyDown; FMaskEdit.OnKeyUp := DoKeyUp; FMaskEdit.OnChange := TextChange; + FMaskEdit.ReadOnly := not FAllowEdit; FMainControl := FMaskEdit; FUpDown := TUpDown.Create(FPanel); @@ -840,15 +848,16 @@ end; { Enum editor } -constructor TEnumEditorLink.Create(Tree: TVirtualStringTree); +constructor TEnumEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; AllowCustomText := False; FCombo := TComboBox.Create(FParentForm); FCombo.Hide; FCombo.Parent := FParentForm; FCombo.OnKeyDown := DoKeyDown; FCombo.OnExit := DoEndEdit; + FCombo.OnSelect := DoSelect; // Show some more than the default 8 items FCombo.DropDownCount := 16; ValueList := TStringList.Create; @@ -878,7 +887,7 @@ function TEnumEditorLink.EndEdit: Boolean; stdcall; var NewText: String; begin - if AllowCustomText then + if AllowCustomText and FAllowEdit then NewText := FCombo.Text else if (ValueList.Count > 0) and (FCombo.ItemIndex > -1) then NewText := ValueList[FCombo.ItemIndex] @@ -902,7 +911,7 @@ begin Items := ValueList; for i:=0 to Items.Count - 1 do FCombo.Items.Add(Items[i]); - if AllowCustomText then begin + if AllowCustomText and FAllowEdit then begin FCombo.Style := csDropDown; FCombo.Text := FCellText; end else begin @@ -930,12 +939,21 @@ begin end; +procedure TEnumEditorLink.DoSelect(Sender: TObject); +begin + // Read only mode? + if not FAllowEdit then begin + FCombo.ItemIndex := ValueList.IndexOf(FCellText); + end; +end; + + { SET editor } -constructor TSetEditorLink.Create(Tree: TVirtualStringTree); +constructor TSetEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; ValueList := TStringList.Create; FPanel := TPanel.Create(FParentForm); @@ -1016,6 +1034,7 @@ begin SelValues.DelimitedText := FCellText; for i:=0 to FCheckList.Items.Count-1 do begin FCheckList.Checked[i] := SelValues.IndexOf(FCheckList.Items[i]) > -1; + FCheckList.ItemEnabled[i] := FAllowEdit; end; SelValues.Free; end; @@ -1034,6 +1053,7 @@ begin FBtnOk.Left := margin; FBtnOk.Height := 24; FBtnOk.Top := FPanel.Height - 2*margin - FBtnOk.Height; + FBtnOk.Enabled := FAllowEdit; FBtnCancel.Width := FBtnOk.Width; FBtnCancel.Left := 2*margin + FBtnOk.Width; @@ -1044,6 +1064,7 @@ begin FCheckList.Left := margin; FCheckList.Width := FPanel.Width - 2*margin; FCheckList.Height := FBtnOk.Top - margin - FCheckList.Top; + // FCheckList.Enabled := FAllowEdit; // crashes with "cannot focus if disabled" end; @@ -1066,9 +1087,9 @@ end; { TInplaceEditorLink } -constructor TInplaceEditorLink.Create(Tree: TVirtualStringTree); +constructor TInplaceEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; ButtonVisible := false; FTextEditor := nil; @@ -1084,6 +1105,7 @@ begin FEdit.ParentColor := True; FEdit.BorderStyle := bsNone; FEdit.OnKeyDown := DoKeyDown; + FEdit.ReadOnly := not FAllowEdit; FMainControl := FEdit; FButton := TButton.Create(FPanel); @@ -1162,6 +1184,7 @@ begin FTextEditor.SetTitleText(TitleText); FTextEditor.Modified := FEdit.Modified; FTextEditor.SetMaxLength(Self.FMaxLength); + FTextEditor.memoText.ReadOnly := not FAllowEdit; FTextEditor.ShowModal; end; @@ -1197,13 +1220,13 @@ end; { Column default editor } -constructor TColumnDefaultEditorLink.Create(Tree: TVirtualStringTree); +constructor TColumnDefaultEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); const m = 5; var i: Integer; begin - inherited Create(Tree); + inherited; FPanel := TPanel.Create(FParentForm); FPanel.Hide; @@ -1547,9 +1570,9 @@ end; { Datatype selector } -constructor TDataTypeEditorLink.Create(Tree: TVirtualStringTree); +constructor TDataTypeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean); begin - inherited Create(Tree); + inherited; FTreeSelect := TVirtualStringTree.Create(FParentForm); FTreeSelect.Hide; diff --git a/source/insertfiles.pas b/source/insertfiles.pas index 1680674c..51d5ccdc 100644 --- a/source/insertfiles.pas +++ b/source/insertfiles.pas @@ -272,7 +272,7 @@ begin // Start cell editor Grid := Sender as TVirtualStringTree; if Column = ColValue then begin - EnumEditor := TEnumEditorLink.Create(Grid); + EnumEditor := TEnumEditorLink.Create(Grid, True); EnumEditor.AllowCustomText := True; EnumEditor.ValueList := TStringList.Create; EnumEditor.ValueList.Text := 'NULL'+CRLF+ diff --git a/source/main.pas b/source/main.pas index 48b5e184..6b5d2bfd 100644 --- a/source/main.pas +++ b/source/main.pas @@ -9344,9 +9344,11 @@ var Results: TDBQuery; RowNum: PInt64; Timestamp: Int64; - IsNull: Boolean; + IsNull, AllowEdit: Boolean; begin Results := GridResult(Sender); + if not Results.IsEditable then + Exit; RowNum := Sender.GetNodeData(Node); Results.RecNo := RowNum^; try @@ -9457,7 +9459,6 @@ procedure TMainForm.AnyGridEditing(Sender: TBaseVirtualTree; Node: begin Allowed := False; try - GridResult(Sender).CheckEditable; if not AnyGridEnsureFullRow(Sender as TVirtualStringTree, Node) then ErrorDialog(_('Could not load full row data.')) else begin @@ -9513,12 +9514,15 @@ var RowNum: PInt64; RefDb, RefTable: String; RefObj: TDBObject; + AllowEdit: Boolean; begin VT := Sender as TVirtualStringTree; Results := GridResult(VT); RowNum := VT.GetNodeData(Node); Results.RecNo := RowNum^; Conn := Results.Connection; + // Allow editing, or leave readonly mode + AllowEdit := Results.IsEditable; // Find foreign key values if AppSettings.ReadBool(asForeignDropDown) and (Sender = DataGrid) then begin @@ -9561,7 +9565,7 @@ begin ForeignResults := Conn.GetResults(SQL); if ForeignResults.RecordCount < ForeignItemsLimit then begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit); EditLink := EnumEditor; while not ForeignResults.Eof do begin EnumEditor.ValueList.Add(ForeignResults.Col(0)); @@ -9582,7 +9586,7 @@ begin FGridEditFunctionMode := FGridEditFunctionMode or Results.IsFunction(Column); if FGridEditFunctionMode then begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit); for idx:=Low(MySQLFunctions) to High(MySQLFunctions) do EnumEditor.ValueList.Add(MySQLFunctions[idx].Name + MySQLFunctions[idx].Declaration); EnumEditor.AllowCustomText := True; @@ -9593,17 +9597,17 @@ begin if Assigned(EditLink) then // Editor was created above, do nothing now else if (Results.DataType(Column).Index in [dtEnum, dtBool]) and AppSettings.ReadBool(asFieldEditorEnum) then begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit); EnumEditor.ValueList := Results.ValueList(Column); EditLink := EnumEditor; end else if (TypeCat = dtcText) or ((TypeCat in [dtcBinary, dtcSpatial]) and actBlobAsText.Checked) then begin - InplaceEditor := TInplaceEditorLink.Create(VT); + InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit); InplaceEditor.MaxLength := Results.MaxLength(Column); InplaceEditor.TitleText := Results.ColumnOrgNames[Column]; InplaceEditor.ButtonVisible := True; EditLink := InplaceEditor; end else if (TypeCat in [dtcBinary, dtcSpatial]) and AppSettings.ReadBool(asFieldEditorBinary) then begin - HexEditor := THexEditorLink.Create(VT); + HexEditor := THexEditorLink.Create(VT, AllowEdit); HexEditor.MaxLength := Results.MaxLength(Column); HexEditor.TitleText := Results.ColumnOrgNames[Column]; EditLink := HexEditor; @@ -9625,17 +9629,17 @@ begin NowText := NowText + '.' + StringOfChar('0', MicroSecondsPrecision); VT.Text[Node, Column] := NowText; end; - DateTimeEditor := TDateTimeEditorLink.Create(VT); + DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit); EditLink := DateTimeEditor; end else if AppSettings.ReadBool(asFieldEditorDatetime) and HandleUnixTimestampColumn(Sender, Column) then begin - DateTimeEditor := TDateTimeEditorLink.Create(VT); + DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit); EditLink := DateTimeEditor; end else if (Results.DataType(Column).Index = dtSet) and AppSettings.ReadBool(asFieldEditorSet) then begin - SetEditor := TSetEditorLink.Create(VT); + SetEditor := TSetEditorLink.Create(VT, AllowEdit); SetEditor.ValueList := Results.ValueList(Column); EditLink := SetEditor; end else begin - InplaceEditor := TInplaceEditorLink.Create(VT); + InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit); InplaceEditor.ButtonVisible := False; EditLink := InplaceEditor; end; @@ -12706,7 +12710,7 @@ var VT: TVirtualStringTree; begin VT := Sender as TVirtualStringTree; - InplaceEditor := TInplaceEditorLink.Create(VT); + InplaceEditor := TInplaceEditorLink.Create(VT, True); InplaceEditor.ButtonVisible := true; EditLink := InplaceEditor; end; diff --git a/source/routine_editor.pas b/source/routine_editor.pas index 33e98940..4863659b 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -395,7 +395,7 @@ begin if Column = 1 then EditLink := TStringEditLink.Create else if Column = 2 then begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.AllowCustomText := True; EnumEditor.ValueList := TStringList.Create; for DBDatatype in DBObject.Connection.Datatypes do begin @@ -406,7 +406,7 @@ begin end; EditLink := EnumEditor; end else if Column = 3 then begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList := TStringList.Create; EnumEditor.ValueList.Add('IN'); EnumEditor.ValueList.Add('OUT'); diff --git a/source/table_editor.pas b/source/table_editor.pas index 25e5e290..475e7aa5 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -1457,18 +1457,18 @@ begin Col := Sender.GetNodeData(Node); case Column of 2: begin // Datatype pulldown - DatatypeEditor := TDatatypeEditorLink.Create(VT); + DatatypeEditor := TDatatypeEditorLink.Create(VT, True); EditLink := DataTypeEditor; end; 9: begin // Collation pulldown - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList := TStringList.Create; EnumEditor.ValueList.Text := DBObject.Connection.CollationList.Text; EnumEditor.ValueList.Insert(0, ''); EditLink := EnumEditor; end; 7: begin - DefaultEditor := TColumnDefaultEditorLink.Create(VT); + DefaultEditor := TColumnDefaultEditorLink.Create(VT, True); DefaultEditor.DefaultType := Col.DefaultType; DefaultEditor.DefaultText := Col.DefaultText; DefaultEditor.OnUpdateType := Col.OnUpdateType; @@ -1476,7 +1476,7 @@ begin EditLink := DefaultEditor; end; 11: begin // Virtuality pulldown - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList := TStringList.Create; if DBObject.Connection.Parameters.IsMariaDB then EnumEditor.ValueList.CommaText := ',VIRTUAL,PERSISTENT' @@ -1485,7 +1485,7 @@ begin EditLink := EnumEditor; end else begin - Edit := TInplaceEditorLink.Create(VT); + Edit := TInplaceEditorLink.Create(VT, True); Edit.TitleText := VT.Header.Columns[Column].Text; Edit.ButtonVisible := True; EditLink := Edit; @@ -1798,18 +1798,18 @@ begin Level := (Sender as TVirtualStringtree).GetNodeLevel(Node); if (Level = 0) and (Column = 1) then begin // Index type pulldown - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList := TStringList.Create; EnumEditor.ValueList.CommaText := PKEY +','+ KEY +','+ UKEY +','+ FKEY +','+ SKEY; EditLink := EnumEditor; end else if (Level = 0) and (Column = 2) then begin // Algorithm pulldown - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList := Explode(',', ',BTREE,HASH,RTREE'); EditLink := EnumEditor; end else if (Level = 1) and (Column = 0) then begin // Column names pulldown - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); ColNode := listColumns.GetFirst; while Assigned(ColNode) do begin Col := listColumns.GetNodeData(ColNode); @@ -1819,7 +1819,7 @@ begin EnumEditor.AllowCustomText := True; // Allows adding a subpart in index parts: "TextCol(20)" EditLink := EnumEditor; end else - EditLink := TInplaceEditorLink.Create(VT); + EditLink := TInplaceEditorLink.Create(VT, True); end; @@ -2295,9 +2295,9 @@ begin // Init grid editor in foreign key list VT := Sender as TVirtualStringTree; case Column of - 0: EditLink := TInplaceEditorLink.Create(VT); + 0: EditLink := TInplaceEditorLink.Create(VT, True); 1: begin - SetEditor := TSetEditorLink.Create(VT); + SetEditor := TSetEditorLink.Create(VT, True); ColNode := listColumns.GetFirst; while Assigned(ColNode) do begin PCol := listColumns.GetNodeData(ColNode); @@ -2307,7 +2307,7 @@ begin EditLink := SetEditor; end; 2: begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.AllowCustomText := True; DBObjects := DBObject.Connection.GetDBObjects(DBObject.Connection.Database); for Obj in DBObjects do begin @@ -2318,7 +2318,7 @@ begin end; 3: begin Key := FForeignKeys[Node.Index]; - SetEditor := TSetEditorLink.Create(VT); + SetEditor := TSetEditorLink.Create(VT, True); Obj := DBObject.Connection.FindObject(DBObject.Database, Key.ReferenceTable); if Obj <> nil then begin Columns := Obj.TableColumns; @@ -2329,7 +2329,7 @@ begin EditLink := SetEditor; end; 4, 5: begin - EnumEditor := TEnumEditorLink.Create(VT); + EnumEditor := TEnumEditorLink.Create(VT, True); EnumEditor.ValueList.Text := 'RESTRICT'+CRLF+'CASCADE'+CRLF+'SET NULL'+CRLF+'NO ACTION'; EditLink := EnumEditor; end; diff --git a/source/texteditor.pas b/source/texteditor.pas index 388f9ed1..db143efd 100644 --- a/source/texteditor.pas +++ b/source/texteditor.pas @@ -68,6 +68,7 @@ type procedure SetMaxLength(len: integer); procedure SetFont(font: TFont); property Modified: Boolean read FModified write SetModified; + property memoText: TLineNormalizingMemo read FmemoText; end;