mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
* Add a binary editor to allow editing (var)binary and (tiny|medium|long)blob fields without messing up NULs etc.
* Add a few notes about where AVs seem to randomly occur when GridPost{Insert,Update,Delete} and EnsureDataLoaded invokes the query logic from outside the main thread. Fixes issue #659 as far as the grids go, but not for export functions.
This commit is contained in:
@ -39,6 +39,7 @@ uses
|
||||
view in '..\..\source\view.pas' {frmView},
|
||||
selectdbobject in '..\..\source\selectdbobject.pas' {frmSelectDBObject},
|
||||
texteditor in '..\..\source\texteditor.pas' {frmTextEditor},
|
||||
bineditor in '..\..\source\bineditor.pas' {frmBinEditor},
|
||||
grideditlinks in '..\..\source\grideditlinks.pas',
|
||||
uVistaFuncs in '..\..\source\uVistaFuncs.pas';
|
||||
|
||||
|
@ -63,6 +63,9 @@
|
||||
<DCCReference Include="..\..\source\about.pas">
|
||||
<Form>AboutBox</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\bineditor.pas">
|
||||
<Form>frmBinEditor</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\childwin.pas">
|
||||
<Form>MDIChild</Form>
|
||||
</DCCReference>
|
||||
@ -109,7 +112,6 @@
|
||||
<Form>MainForm</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\mysql_structures.pas" />
|
||||
<DCCReference Include="..\..\source\memoeditor.pas">
|
||||
<Form>frmMemoEditor</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\mysqlconn.pas" />
|
||||
@ -140,6 +142,9 @@
|
||||
<DCCReference Include="..\..\source\tbl_properties.pas">
|
||||
<Form>tbl_properties_form</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\texteditor.pas">
|
||||
<Form>frmTextEditor</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\threading.pas" />
|
||||
<DCCReference Include="..\..\source\updatecheck.pas">
|
||||
<Form>frmUpdateCheck</Form>
|
||||
|
97
source/bineditor.dfm
Normal file
97
source/bineditor.dfm
Normal file
@ -0,0 +1,97 @@
|
||||
object frmBinEditor: TfrmBinEditor
|
||||
Left = 0
|
||||
Top = 0
|
||||
BorderStyle = bsSizeToolWin
|
||||
Caption = 'Binary editor'
|
||||
ClientHeight = 95
|
||||
ClientWidth = 215
|
||||
Color = clBtnFace
|
||||
Constraints.MinHeight = 100
|
||||
Constraints.MinWidth = 130
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
Position = poMainFormCenter
|
||||
OnCloseQuery = FormCloseQuery
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
OnShow = FormShow
|
||||
DesignSize = (
|
||||
215
|
||||
95)
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object lblTextLength: TLabel
|
||||
Left = 103
|
||||
Top = 77
|
||||
Width = 65
|
||||
Height = 13
|
||||
Anchors = [akLeft, akBottom]
|
||||
BiDiMode = bdLeftToRight
|
||||
Caption = 'lblTextLength'
|
||||
ParentBiDiMode = False
|
||||
end
|
||||
object memoText: TTntMemo
|
||||
Left = 0
|
||||
Top = 0
|
||||
Width = 215
|
||||
Height = 72
|
||||
Align = alTop
|
||||
Anchors = [akLeft, akTop, akRight, akBottom]
|
||||
Lines.Strings = (
|
||||
'memoText')
|
||||
ScrollBars = ssBoth
|
||||
TabOrder = 0
|
||||
WantTabs = True
|
||||
OnChange = memoTextChange
|
||||
OnKeyDown = memoTextKeyDown
|
||||
end
|
||||
object tlbStandard: TToolBar
|
||||
Left = 0
|
||||
Top = 73
|
||||
Width = 97
|
||||
Height = 22
|
||||
Align = alNone
|
||||
Anchors = [akLeft, akBottom]
|
||||
Caption = 'tlbStandard'
|
||||
Images = MainForm.PngImageListMain
|
||||
ParentShowHint = False
|
||||
ShowHint = True
|
||||
TabOrder = 1
|
||||
object btnWrap: TToolButton
|
||||
Left = 0
|
||||
Top = 0
|
||||
Hint = 'Wrap long lines'
|
||||
Caption = 'Wrap long lines'
|
||||
ImageIndex = 62
|
||||
OnClick = btnWrapClick
|
||||
end
|
||||
object btnLoadBinary: TToolButton
|
||||
Left = 23
|
||||
Top = 0
|
||||
Hint = 'Load binary file'
|
||||
Caption = 'Load binary file'
|
||||
ImageIndex = 52
|
||||
OnClick = btnLoadBinaryClick
|
||||
end
|
||||
object btnCancel: TToolButton
|
||||
Left = 46
|
||||
Top = 0
|
||||
Hint = 'Cancel'
|
||||
Caption = 'Cancel'
|
||||
ImageIndex = 26
|
||||
OnClick = btnCancelClick
|
||||
end
|
||||
object btnApply: TToolButton
|
||||
Left = 69
|
||||
Top = 0
|
||||
Hint = 'Apply changes'
|
||||
Caption = 'Apply changes'
|
||||
ImageIndex = 55
|
||||
OnClick = btnApplyClick
|
||||
end
|
||||
end
|
||||
end
|
198
source/bineditor.pas
Normal file
198
source/bineditor.pas
Normal file
@ -0,0 +1,198 @@
|
||||
unit bineditor;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows, Classes, Graphics, Forms, Controls, helpers, StdCtrls, TntStdCtrls, Registry, VirtualTrees,
|
||||
ComCtrls, ToolWin, Dialogs, SysUtils;
|
||||
|
||||
{$I const.inc}
|
||||
|
||||
type
|
||||
TfrmBinEditor = class(TMemoEditor)
|
||||
memoText: TTntMemo;
|
||||
tlbStandard: TToolBar;
|
||||
btnWrap: TToolButton;
|
||||
btnLoadBinary: TToolButton;
|
||||
btnApply: TToolButton;
|
||||
btnCancel: TToolButton;
|
||||
lblTextLength: TLabel;
|
||||
procedure btnApplyClick(Sender: TObject);
|
||||
procedure btnCancelClick(Sender: TObject);
|
||||
procedure btnLoadBinaryClick(Sender: TObject);
|
||||
procedure btnWrapClick(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
procedure memoTextChange(Sender: TObject);
|
||||
procedure memoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FModified: Boolean;
|
||||
procedure SetModified(NewVal: Boolean);
|
||||
property Modified: Boolean read FModified write SetModified;
|
||||
public
|
||||
function GetText: WideString; override;
|
||||
procedure SetText(text: WideString); override;
|
||||
procedure SetMaxLength(len: integer); override;
|
||||
procedure SetFont(font: TFont); override;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses main;
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
function TfrmBinEditor.GetText: WideString;
|
||||
begin
|
||||
Result := '0x' + memoText.Text;
|
||||
end;
|
||||
|
||||
procedure TfrmBinEditor.SetText(text: WideString);
|
||||
begin
|
||||
// Skip '0x'.
|
||||
memoText.Text := Copy(text, 3);
|
||||
end;
|
||||
|
||||
procedure TfrmBinEditor.SetMaxLength(len: integer);
|
||||
begin
|
||||
// Input: Length in bytes.
|
||||
memoText.MaxLength := len * 2;
|
||||
end;
|
||||
|
||||
procedure TfrmBinEditor.SetFont(font: TFont);
|
||||
begin
|
||||
memoText.Font := font;
|
||||
end;
|
||||
|
||||
procedure TfrmBinEditor.FormCreate(Sender: TObject);
|
||||
begin
|
||||
InheritFont(Font);
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.FormDestroy(Sender: TObject);
|
||||
var
|
||||
reg: TRegistry;
|
||||
begin
|
||||
reg := TRegistry.Create;
|
||||
if reg.OpenKey(REGPATH, False) then begin
|
||||
reg.WriteInteger( REGNAME_EDITOR_WIDTH, Width );
|
||||
reg.WriteInteger( REGNAME_EDITOR_HEIGHT, Height );
|
||||
reg.CloseKey;
|
||||
end;
|
||||
reg.Free;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.FormShow(Sender: TObject);
|
||||
begin
|
||||
// Restore form dimensions
|
||||
Width := Mainform.GetRegValue(REGNAME_EDITOR_WIDTH, DEFAULT_EDITOR_WIDTH);
|
||||
Height := Mainform.GetRegValue(REGNAME_EDITOR_HEIGHT, DEFAULT_EDITOR_HEIGHT);
|
||||
// Fix label position:
|
||||
lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2;
|
||||
SetWindowSizeGrip(Handle, True);
|
||||
memoText.SelectAll;
|
||||
memoText.SetFocus;
|
||||
memoTextChange(Sender);
|
||||
Modified := False;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.memoTextKeyDown(Sender: TObject; var Key: Word; Shift:
|
||||
TShiftState);
|
||||
begin
|
||||
case Key of
|
||||
// Cancel by Escape
|
||||
VK_ESCAPE: btnCancelClick(Sender);
|
||||
// Apply changes and end editing by Ctrl + Enter
|
||||
VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmBinEditor.btnWrapClick(Sender: TObject);
|
||||
var
|
||||
WasModified: Boolean;
|
||||
begin
|
||||
Screen.Cursor := crHourglass;
|
||||
// Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified.
|
||||
WasModified := Modified;
|
||||
if memoText.ScrollBars = ssBoth then
|
||||
memoText.ScrollBars := ssVertical
|
||||
else
|
||||
memoText.ScrollBars := ssBoth;
|
||||
TToolbutton(Sender).Down := memoText.ScrollBars = ssVertical;
|
||||
Modified := WasModified;
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.btnLoadBinaryClick(Sender: TObject);
|
||||
var
|
||||
d: TOpenDialog;
|
||||
begin
|
||||
d := TOpenDialog.Create(Self);
|
||||
d.Filter := 'All binary files (*.*)|*.*';
|
||||
d.FilterIndex := 0;
|
||||
if d.Execute then try
|
||||
Screen.Cursor := crHourglass;
|
||||
memoText.Text := BinToWideHex(ReadBinaryFile(d.FileName, memoText.MaxLength));
|
||||
finally
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
d.Free;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.btnCancelClick(Sender: TObject);
|
||||
var
|
||||
DoPost: Boolean;
|
||||
begin
|
||||
if Modified then
|
||||
DoPost := MessageDlg('Apply modifications?', mtConfirmation, [mbYes, mbNo], 0) = mrYes
|
||||
else
|
||||
DoPost := False;
|
||||
if DoPost then
|
||||
TCustomVirtualStringTree(Owner).EndEditNode
|
||||
else
|
||||
TCustomVirtualStringTree(Owner).CancelEditNode;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
begin
|
||||
btnCancelClick(Sender);
|
||||
CanClose := False; // Done by editor link
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.btnApplyClick(Sender: TObject);
|
||||
begin
|
||||
TCustomVirtualStringTree(Owner).EndEditNode;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.memoTextChange(Sender: TObject);
|
||||
begin
|
||||
lblTextLength.Caption := FormatNumber(Length(memoText.Text) / 2) + ' bytes.';
|
||||
if memoText.MaxLength > 0 then
|
||||
lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength / 2)+')';
|
||||
Modified := True;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmBinEditor.SetModified(NewVal: Boolean);
|
||||
begin
|
||||
if FModified <> NewVal then begin
|
||||
FModified := NewVal;
|
||||
btnApply.Enabled := FModified;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
@ -1204,7 +1204,11 @@ begin
|
||||
rx.Expression := '^((tiny|medium|long)?text|(var)?char)\b(\(\d+\))?';
|
||||
if rx.Exec(ColType) then begin
|
||||
FDataGridResult.Columns[idx].IsText := True;
|
||||
if ColType = 'tinytext' then
|
||||
if rx.Match[4] <> '' then
|
||||
FDataGridResult.Columns[idx].MaxLength := MakeInt(rx.Match[4])
|
||||
else if ColType = 'tinytext' then
|
||||
// 255 is the width in bytes. If characters that use multiple bytes are
|
||||
// contained, the width in characters is decreased below this number.
|
||||
FDataGridResult.Columns[idx].MaxLength := 255
|
||||
else if ColType = 'text' then
|
||||
FDataGridResult.Columns[idx].MaxLength := 65535
|
||||
@ -1212,14 +1216,13 @@ begin
|
||||
FDataGridResult.Columns[idx].MaxLength := 16777215
|
||||
else if ColType = 'longtext' then
|
||||
FDataGridResult.Columns[idx].MaxLength := 4294967295
|
||||
else if rx.Match[4] <> '' then
|
||||
FDataGridResult.Columns[idx].MaxLength := MakeInt(rx.Match[4])
|
||||
else // Fallback for unknown column types
|
||||
else
|
||||
// Fallback for unknown column types
|
||||
FDataGridResult.Columns[idx].MaxLength := MaxInt;
|
||||
end;
|
||||
rx.Expression := '^((tiny|medium|long)?blob|(var)?binary|bit)\b';
|
||||
if rx.Exec(ColType) then
|
||||
FDataGridResult.Columns[idx].IsBlob := True;
|
||||
FDataGridResult.Columns[idx].IsBinary := True;
|
||||
if Copy(ColType, 1, 5) = 'enum(' then begin
|
||||
FDataGridResult.Columns[idx].IsEnum := True;
|
||||
FDataGridResult.Columns[idx].EnumVals := WideStrings.TWideStringList.Create;
|
||||
@ -2482,7 +2485,7 @@ begin
|
||||
else if ds.Fields[i].DataType in [ftWideString, ftMemo, ftWideMemo] then
|
||||
FQueryGridResult.Columns[i].IsText := True
|
||||
else if ds.Fields[i].DataType in [ftBlob] then
|
||||
FQueryGridResult.Columns[i].IsBlob := True;
|
||||
FQueryGridResult.Columns[i].IsBinary := True;
|
||||
end;
|
||||
SetLength(FQueryGridResult.Rows, 0);
|
||||
SetLength(FQueryGridResult.Rows, ds.RecordCount);
|
||||
@ -2491,8 +2494,8 @@ begin
|
||||
FQueryGridResult.Rows[i].Loaded := True;
|
||||
SetLength(FQueryGridResult.Rows[i].Cells, ds.FieldCount);
|
||||
for j:=0 to ds.FieldCount-1 do begin
|
||||
if FQueryGridResult.Columns[j].IsBlob then
|
||||
FQueryGridResult.Rows[i].Cells[j].Text := Utf8Decode(ds.Fields[j].AsString)
|
||||
if FQueryGridResult.Columns[j].IsBinary then
|
||||
FQueryGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
|
||||
else
|
||||
FQueryGridResult.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
|
||||
FQueryGridResult.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
|
||||
@ -3575,6 +3578,12 @@ begin
|
||||
end;
|
||||
|
||||
// Create instance of the progress form (but don't show it yet)
|
||||
// Todo: This apparently causes an exception if invoked via an event handler?
|
||||
// Classes.TStream.ReadComponent(???)
|
||||
// Classes.InternalReadComponentRes(???,???,???)
|
||||
// Classes.InitComponent(TfrmQueryProgress)
|
||||
// Classes.InitInheritedComponent($17E0710,TForm)
|
||||
// Forms.TCustomForm.Create(???)
|
||||
FProgressForm := TFrmQueryProgress.Create(Self);
|
||||
|
||||
{ Launch a thread of execution that passes the query to the server
|
||||
@ -5478,8 +5487,8 @@ begin
|
||||
for i := start to start + limit - 1 do begin
|
||||
SetLength(FDataGridResult.Rows[i].Cells, ds.Fields.Count);
|
||||
for j := 0 to ds.Fields.Count - 1 do begin
|
||||
if FDataGridResult.Columns[j].IsBlob then
|
||||
FDataGridResult.Rows[i].Cells[j].Text := Utf8Decode(ds.Fields[j].AsString)
|
||||
if FDataGridResult.Columns[j].IsBinary then
|
||||
FDataGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
|
||||
else
|
||||
FDataGridResult.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
|
||||
FDataGridResult.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
|
||||
@ -5489,6 +5498,7 @@ begin
|
||||
end;
|
||||
|
||||
MainForm.ShowStatus( STATUS_MSG_READY );
|
||||
// Todo: Seen an AV next line when this method was invoked via an event handler.
|
||||
FreeAndNil(ds);
|
||||
end;
|
||||
end;
|
||||
@ -5573,7 +5583,7 @@ begin
|
||||
else if r.Columns[Column].isText then
|
||||
if isNull then cl := $60CC60 else cl := clGreen
|
||||
// Text field
|
||||
else if r.Columns[Column].isBlob then
|
||||
else if r.Columns[Column].isBinary then
|
||||
if isNull then cl := $CC60CC else cl := clPurple
|
||||
else
|
||||
if isNull then cl := COLOR_NULLVALUE else cl := clWindowText;
|
||||
@ -5723,7 +5733,8 @@ begin
|
||||
if Row.Cells[i].Modified then begin
|
||||
Val := Row.Cells[i].NewText;
|
||||
if FDataGridResult.Columns[i].IsFloat then Val := FloatStr(Val);
|
||||
Val := esc(Val);
|
||||
if not FDataGridResult.Columns[i].IsBinary then Val := esc(Val);
|
||||
if FDataGridResult.Columns[i].IsBinary then CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + FDataGridResult.Columns[i].Name + '".');
|
||||
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
||||
sql := sql + ' ' + mask(FDataGridResult.Columns[i].Name) + '=' + Val + ', ';
|
||||
end;
|
||||
@ -5759,8 +5770,8 @@ begin
|
||||
ds := ExecSelectQuery(sql);
|
||||
if ds.RecordCount = 1 then begin
|
||||
for i := 0 to ds.FieldCount - 1 do begin
|
||||
if FDataGridResult.Columns[i].IsBlob then
|
||||
Row.Cells[i].Text := Utf8Decode(ds.Fields[i].AsString)
|
||||
if FDataGridResult.Columns[i].IsBinary then
|
||||
Row.Cells[i].Text := '0x' + BinToWideHex(ds.Fields[i].AsString)
|
||||
else
|
||||
Row.Cells[i].Text := ds.Fields[i].AsWideString;
|
||||
Row.Cells[i].IsNull := ds.Fields[i].IsNull;
|
||||
@ -5814,7 +5825,7 @@ begin
|
||||
KeyVal := Row.Cells[j].Text;
|
||||
// Quote if needed
|
||||
if FDataGridResult.Columns[j].IsFloat then KeyVal := FloatStr(KeyVal);
|
||||
KeyVal := esc(KeyVal);
|
||||
if not FDataGridResult.Columns[j].IsBinary then KeyVal := esc(KeyVal);
|
||||
if Row.Cells[j].IsNull then KeyVal := ' IS NULL'
|
||||
else KeyVal := '=' + KeyVal;
|
||||
Result := Result + mask(KeyCols[i]) + KeyVal + ' AND ';
|
||||
@ -5898,7 +5909,8 @@ begin
|
||||
Cols := Cols + mask(FDataGridResult.Columns[i].Name) + ', ';
|
||||
Val := Row.Cells[i].NewText;
|
||||
if FDataGridResult.Columns[i].IsFloat then Val := FloatStr(Val);
|
||||
Val := esc(Val);
|
||||
if not FDataGridResult.Columns[i].IsBinary then Val := esc(Val);
|
||||
if FDataGridResult.Columns[i].IsBinary then CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + FDataGridResult.Columns[i].Name + '".');
|
||||
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
||||
Vals := Vals + Val + ', ';
|
||||
end;
|
||||
@ -6080,7 +6092,10 @@ var
|
||||
DateTimeEditor: TDateTimeEditorLink;
|
||||
EnumEditor: TEnumEditorLink;
|
||||
begin
|
||||
if FDataGridResult.Columns[Column].IsText then begin
|
||||
if
|
||||
FDataGridResult.Columns[Column].IsText or
|
||||
FDataGridResult.Columns[Column].IsBinary
|
||||
then begin
|
||||
MemoEditor := TMemoEditorLink.Create;
|
||||
MemoEditor.MaxLength := FDataGridResult.Columns[Column].MaxLength;
|
||||
EditLink := MemoEditor;
|
||||
|
@ -4,8 +4,8 @@ unit grideditlinks;
|
||||
|
||||
interface
|
||||
|
||||
uses Windows, Forms, Graphics, messages, VirtualTrees, texteditor, ComCtrls, SysUtils, Classes,
|
||||
mysql_structures, Main, helpers, TntStdCtrls, WideStrings, StdCtrls;
|
||||
uses Windows, Forms, Graphics, messages, VirtualTrees, texteditor, bineditor, ComCtrls, SysUtils, Classes,
|
||||
mysql_structures, Main, ChildWin, helpers, TntStdCtrls, WideStrings, StdCtrls;
|
||||
|
||||
type
|
||||
TMemoEditorLink = class(TInterfacedObject, IVTEditLink)
|
||||
@ -95,6 +95,7 @@ end;
|
||||
function TMemoEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
|
||||
// Retrieves the true text bounds from the owner tree.
|
||||
var
|
||||
IsBinary: Boolean;
|
||||
Text: WideString;
|
||||
F: TFont;
|
||||
begin
|
||||
@ -110,11 +111,15 @@ begin
|
||||
F := TFont.Create;
|
||||
FTree.GetTextInfo(Node, Column, F, FTextBounds, Text);
|
||||
|
||||
IsBinary := MainForm.ChildWin.FDataGridResult.Columns[Column].IsBinary;
|
||||
|
||||
// Get wide text of the node.
|
||||
Text := FTree.Text[FNode, FColumn];
|
||||
|
||||
// Create the editor form
|
||||
FForm := TfrmTextEditor.Create(Ftree);
|
||||
// Create the text editor form
|
||||
if IsBinary then FForm := TfrmBinEditor.Create(Ftree)
|
||||
else FForm := TfrmTextEditor.Create(Ftree);
|
||||
|
||||
FForm.SetFont(F);
|
||||
FForm.SetText(Text);
|
||||
FForm.SetMaxLength(MaxLength);
|
||||
|
@ -51,7 +51,7 @@ type
|
||||
DataType: Byte; // @see constants in mysql_structures.pas
|
||||
MaxLength: Cardinal;
|
||||
IsPriPart: Boolean;
|
||||
IsBlob: Boolean;
|
||||
IsBinary: Boolean;
|
||||
IsText: Boolean;
|
||||
IsEnum: Boolean;
|
||||
IsInt: Boolean;
|
||||
@ -150,8 +150,12 @@ type
|
||||
function GetFileCharset(Stream: TFileStream): TFileCharset;
|
||||
function ReadTextfileChunk(Stream: TFileStream; FileCharset: TFileCharset; ChunkSize: Int64 = 0): WideString;
|
||||
function ReadTextfile(Filename: String): WideString;
|
||||
function ReadBinaryFile(Filename: String; MaxBytes: Int64): string;
|
||||
procedure CopyToClipboard(Value: WideString);
|
||||
procedure StreamToClipboard(S: TMemoryStream);
|
||||
function WideHexToBin(text: WideString): string;
|
||||
function BinToWideHex(bin: string): WideString;
|
||||
procedure CheckHex(text: WideString; errorMessage: string);
|
||||
|
||||
var
|
||||
MYSQL_KEYWORDS : TStringList;
|
||||
@ -194,6 +198,38 @@ var
|
||||
|
||||
|
||||
|
||||
function WideHexToBin(text: WideString): string;
|
||||
var
|
||||
buf: string;
|
||||
begin
|
||||
// Todo: test.
|
||||
buf := text;
|
||||
SetLength(Result, Length(text) div 2);
|
||||
HexToBin(@buf[1], @Result[1], Length(Result));
|
||||
end;
|
||||
|
||||
function BinToWideHex(bin: string): WideString;
|
||||
var
|
||||
buf: string;
|
||||
begin
|
||||
SetLength(buf, Length(bin) * 2);
|
||||
BinToHex(@bin[1], @buf[1], Length(buf));
|
||||
Result := buf;
|
||||
end;
|
||||
|
||||
procedure CheckHex(text: WideString; errorMessage: string);
|
||||
const
|
||||
allowed: string = '0123456789abcdefABCDEF';
|
||||
var
|
||||
i: Cardinal;
|
||||
begin
|
||||
for i := 1 to Length(text) do begin
|
||||
if Pos(text[i], allowed) < 1 then begin
|
||||
raise Exception.Create(errorMessage);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{***
|
||||
Convert a TStringList to a string using a separator-string
|
||||
@ -2444,6 +2480,17 @@ begin
|
||||
Stream.Free;
|
||||
end;
|
||||
|
||||
function ReadBinaryFile(Filename: String; MaxBytes: Int64): string;
|
||||
var
|
||||
Stream: TFileStream;
|
||||
begin
|
||||
Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone);
|
||||
Stream.Position := 0;
|
||||
if (MaxBytes < 1) or (MaxBytes > Stream.Size) then MaxBytes := Stream.Size;
|
||||
SetLength(Result, MaxBytes);
|
||||
Stream.Read(PChar(Result)^, Length(Result));
|
||||
Stream.Free;
|
||||
end;
|
||||
|
||||
{ TUniClipboard }
|
||||
|
||||
|
@ -1230,7 +1230,7 @@ var
|
||||
f : Textfile;
|
||||
tmppath : array[0..MAX_PATH] of char;
|
||||
Content : WideString;
|
||||
IsBlob : Boolean;
|
||||
IsBinary : Boolean;
|
||||
begin
|
||||
g := ChildWin.ActiveGrid;
|
||||
if g = nil then begin messagebeep(MB_ICONASTERISK); exit; end;
|
||||
@ -1238,19 +1238,19 @@ begin
|
||||
showstatus('Saving contents to file...');
|
||||
if g = Childwin.DataGrid then begin
|
||||
Content := Childwin.FDataGridResult.Rows[Childwin.DataGrid.FocusedNode.Index].Cells[Childwin.DataGrid.FocusedColumn].Text;
|
||||
IsBlob := Childwin.FDataGridResult.Columns[Childwin.DataGrid.FocusedColumn].IsBlob;
|
||||
IsBinary := Childwin.FDataGridResult.Columns[Childwin.DataGrid.FocusedColumn].IsBinary;
|
||||
end else begin
|
||||
Content := Childwin.FQueryGridResult.Rows[Childwin.QueryGrid.FocusedNode.Index].Cells[Childwin.QueryGrid.FocusedColumn].Text;
|
||||
IsBlob := Childwin.FQueryGridResult.Columns[Childwin.QueryGrid.FocusedColumn].IsBlob;
|
||||
IsBinary := Childwin.FQueryGridResult.Columns[Childwin.QueryGrid.FocusedColumn].IsBinary;
|
||||
end;
|
||||
childwin.logsql(g.Name);
|
||||
|
||||
GetTempPath(MAX_PATH, tmppath);
|
||||
filename := tmppath;
|
||||
filename := filename+'\'+APPNAME+'-preview.';
|
||||
if IsBlob then begin
|
||||
if IsBinary then begin
|
||||
if pos('JFIF', copy(Content, 0, 20)) <> 0 then
|
||||
filename := filename + 'jpg'
|
||||
filename := filename + 'jpeg'
|
||||
else if StrCmpBegin('GIF', Content) then
|
||||
filename := filename + 'gif'
|
||||
else if StrCmpBegin('BM', Content) then
|
||||
|
@ -4,7 +4,7 @@ interface
|
||||
|
||||
uses
|
||||
Windows, Classes, Graphics, Forms, Controls, helpers, StdCtrls, TntStdCtrls, Registry, VirtualTrees,
|
||||
ComCtrls, ToolWin, Dialogs;
|
||||
ComCtrls, ToolWin, Dialogs, SysUtils;
|
||||
|
||||
{$I const.inc}
|
||||
|
||||
@ -60,6 +60,7 @@ end;
|
||||
|
||||
procedure TfrmTextEditor.SetMaxLength(len: integer);
|
||||
begin
|
||||
// Input: Length in number of bytes.
|
||||
memoText.MaxLength := len;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user