Implement a new datatype selector for the table editor, including groups, datatype colors and help hints. Fixes issue #1214 and issue #1165 .

This commit is contained in:
Ansgar Becker
2009-07-07 23:31:16 +00:00
parent 6e28b38208
commit e2b252a906
5 changed files with 533 additions and 83 deletions

View File

@ -193,6 +193,44 @@ type
procedure SetBounds(R: TRect); virtual; stdcall;
end;
TDataTypeEditorLink = class(TInterfacedObject, IVTEditLink)
private
FTree: TVirtualStringTree;
FTreeSelect: TVirtualStringTree;
FMemoHelp: TMemo;
FNode: PVirtualNode;
FColumn: TColumnIndex;
FTextBounds: TRect;
FStopping: Boolean;
FFinalKeyDown: Integer;
FOldWndProc: TWndMethod;
procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure EditWndProc(var Message: TMessage);
procedure DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
procedure DoTreeSelectInitNode(Sender: TBaseVirtualTree;
ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
procedure DoTreeSelectInitChildren(Sender: TBaseVirtualTree;
Node: PVirtualNode; var ChildCount: Cardinal);
procedure DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode);
procedure DoTreeSelectPaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType);
procedure DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode:
PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean);
procedure DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
public
Datatype: TDatatypeIndex;
constructor Create(Tree: TVirtualStringTree); overload;
destructor Destroy; override;
function BeginEdit: Boolean; virtual; stdcall;
function CancelEdit: Boolean; virtual; stdcall;
function EndEdit: Boolean; virtual; stdcall;
function GetBounds: TRect; virtual; stdcall;
function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall;
procedure ProcessMessage(var Message: TMessage); virtual; stdcall;
procedure SetBounds(R: TRect); virtual; stdcall;
end;
function GetColumnDefaultType(var Text: WideString): TColumnDefaultType;
function GetColumnDefaultClause(DefaultType: TColumnDefaultType; Text: WideString): WideString;
@ -1413,4 +1451,292 @@ begin
end;
{ Datatype selector }
constructor TDataTypeEditorLink.Create(Tree: TVirtualStringTree);
var
ParentControl: TWinControl;
begin
inherited Create;
FTree := Tree;
// Enable mouse scrolling on FtreeSelect, plus ensure the
// tree is not partly hidden when it pops up in a bottom cell
ParentControl := GetParentForm(FTree);
// Avoid flicker
SendMessage(ParentControl.Handle, WM_SETREDRAW, 0, 0);
FTreeSelect := TVirtualStringTree.Create(FTree);
FTreeSelect.TreeOptions.PaintOptions := FTreeSelect.TreeOptions.PaintOptions
- [toShowTreeLines, toShowButtons, toShowRoot]
+ [toHotTrack, toUseExplorerTheme, toHideTreeLinesIfThemed];
FTreeSelect.TreeOptions.SelectionOptions := FTreeSelect.TreeOptions.SelectionOptions
+ [toFullRowSelect];
FTreeSelect.Header.Columns.Add;
FTreeSelect.Header.AutoSizeIndex := 0;
FTreeSelect.Header.Options := FTreeSelect.Header.Options + [hoAutoResize];
FTreeSelect.Parent := ParentControl;
FTreeSelect.TextMargin := 0;
FTreeSelect.RootNodeCount := Length(DatatypeCategories);
FTreeSelect.OnGetText := DoTreeSelectGetText;
FTreeSelect.OnInitNode := DoTreeSelectInitNode;
FTreeSelect.OnInitChildren := DoTreeSelectInitChildren;
FTreeSelect.OnKeyDown := DoKeyDown;
FTreeSelect.OnHotChange := DoTreeSelectHotChange;
FTreeSelect.OnPaintText := DoTreeSelectPaintText;
FTreeSelect.Hide;
FOldWndProc := FTreeSelect.WindowProc;
FTreeSelect.WindowProc := EditWndProc;
FMemoHelp := TMemo.Create(FTree);
FMemoHelp.Parent := ParentControl;
FMemoHelp.Color := clInfoBk;
FMemoHelp.Font.Color := clInfoText;
FMemoHelp.BorderStyle := bsNone;
FMemoHelp.BevelKind := bkFlat;
FMemoHelp.BevelInner := bvNone;
FMemoHelp.Hide;
end;
destructor TDataTypeEditorLink.Destroy;
begin
inherited;
FreeAndNil(FTreeSelect);
FreeAndNil(FMemoHelp);
if FFinalKeyDown = VK_TAB then begin
SendMessage(FTree.Handle, WM_KEYDOWN, FFinalKeyDown, 0);
SendMessage(FTree.Handle, WM_KEYDOWN, VK_F2, 0);
end;
end;
function TDataTypeEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
var
NodeText: WideString;
dt: TDatatype;
CatNode, TypeNode: PVirtualNode;
begin
Result := not FStopping;
if not Result then
Exit;
FNode := Node;
FColumn := Column;
FTree.GetTextInfo(FNode, FColumn, FTreeSelect.Font, FTextBounds, NodeText);
// Highlighted cell has white font, fix that
FTreeSelect.Font.Color := FTree.Font.Color;
// Find and select current datatype in tree
dt := GetDataTypeByName(NodeText);
CatNode := FTreeSelect.GetFirst;
while Assigned(CatNode) do begin
if CatNode.Index = Cardinal(dt.Category) then begin
TypeNode := FTreeSelect.GetFirstChild(CatNode);
while Assigned(TypeNode) do begin
if FTreeSelect.Text[TypeNode, 0] = NodeText then begin
FTreeSelect.FocusedNode := TypeNode;
FTreeSelect.Selected[TypeNode] := True;
break;
end;
TypeNode := FTreeSelect.GetNextSibling(TypeNode);
end;
end;
CatNode := FTreeSelect.GetNextSibling(CatNode);
end;
if Assigned(FTreeSelect.FocusedNode) then
FTreeSelect.ScrollIntoView(FTreeSelect.FocusedNode, True);
FTreeSelect.OnFocusChanging := DoTreeSelectFocusChanging;
FTreeSelect.OnFocusChanged := DoTreeSelectFocusChanged;
end;
function TDataTypeEditorLink.BeginEdit: Boolean;
begin
Result := not FStopping;
if Result then begin
SendMessage(FTreeSelect.Parent.Handle, WM_SETREDRAW, 1, 0);
FTreeSelect.Show;
FTreeSelect.SetFocus;
end;
end;
function TDataTypeEditorLink.CancelEdit: Boolean;
begin
Result := not FStopping;
if Result then begin
FStopping := True;
FTree.CancelEditNode;
if FTree.CanFocus then
FTree.SetFocus;
end;
end;
function TDataTypeEditorLink.EndEdit: Boolean;
var
newtext: WideString;
begin
Result := not FStopping;
if Not Result then
Exit;
newtext := FTreeSelect.Text[FTreeSelect.FocusedNode, 0];
if newtext <> FTree.Text[FNode, FColumn] then
FTree.Text[FNode, FColumn] := newtext;
if FTree.CanFocus then
FTree.SetFocus;
end;
function TDataTypeEditorLink.GetBounds: TRect;
begin
Result := FTreeSelect.BoundsRect;
end;
procedure TDataTypeEditorLink.SetBounds(R: TRect);
begin
// Set position of tree. As the tree's parent is mainform, not listcolumns, add listcolumn's x + y positions
FTreeSelect.SetBounds(R.Left + FTree.ClientOrigin.X,
R.Top + FTree.ClientOrigin.Y - FTreeSelect.Header.Height - GetSystemMetrics(SM_CYMENU),
R.Right-R.Left,
250);
end;
procedure TDataTypeEditorLink.ProcessMessage(var Message: TMessage);
begin
FTreeSelect.WindowProc(Message);
end;
procedure TDataTypeEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
FFinalKeyDown := Key;
case Key of
// Cancel by Escape
VK_ESCAPE: FTree.CancelEditNode;
// Apply changes and end editing by [Ctrl +] Enter or Tab
VK_RETURN, VK_TAB: FTree.EndEditNode;
end;
end;
procedure TDataTypeEditorLink.EditWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_CHAR:
if not (TWMChar(Message).CharCode in [VK_ESCAPE, VK_TAB]) then
FOldWndProc(Message);
WM_GETDLGCODE:
Message.Result := Message.Result or DLGC_WANTARROWS or DLGC_WANTALLKEYS or DLGC_WANTTAB;
else
FOldWndProc(Message);
end;
end;
procedure TDataTypeEditorLink.DoTreeSelectInitNode(Sender: TBaseVirtualTree;
ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
// First level nodes always expanded
if Sender.GetNodeLevel(Node) = 0 then
InitialStates := InitialStates + [ivsExpanded, ivsHasChildren];
end;
procedure TDataTypeEditorLink.DoTreeSelectInitChildren(Sender: TBaseVirtualTree;
Node: PVirtualNode; var ChildCount: Cardinal);
var
i: Integer;
begin
// Tell number of datatypes per category
ChildCount := 0;
if Sender.GetNodeLevel(Node) = 0 then for i:=Low(Datatypes) to High(Datatypes) do begin
if Datatypes[i].Category = DatatypeCategories[Node.Index].Index then
Inc(ChildCount);
end;
end;
procedure TDataTypeEditorLink.DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
i: Integer;
Counter: Cardinal;
begin
// Get cell text
case Sender.GetNodeLevel(Node) of
0: CellText := DatatypeCategories[Node.Index].Name;
1: begin
Counter := 0;
for i:=Low(Datatypes) to High(Datatypes) do begin
if Datatypes[i].Category = DatatypeCategories[Node.Parent.Index].Index then begin
Inc(Counter);
if Counter = Node.Index+1 then begin
CellText := Datatypes[i].Name;
break;
end;
end;
end;
end;
end;
end;
procedure TDataTypeEditorLink.DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode);
var
R: TRect;
NodeText: WideString;
bmp: TBitMap;
begin
// Display help box for hovered datatype
FMemoHelp.Clear;
if Assigned(NewNode) and (Sender.GetNodeLevel(NewNode) = 1) then begin
R := FTreeSelect.GetDisplayRect(NewNode, 0, False);
NodeText := FTreeSelect.Text[NewNode, 0];
FMemoHelp.Width := Min(250, FTreeSelect.Left);
FMemoHelp.Left := FTreeSelect.Left - FMemoHelp.Width + (Integer(FTreeSelect.Indent) Div 2);
FMemoHelp.Top := FTreeSelect.Top + R.Top + 3;
FMemoHelp.Text := GetDatatypeByName(NodeText).Description;
// Calc height of memo
bmp := TBitMap.Create;
bmp.Canvas.Font.Assign(FMemoHelp.Font);
R := Rect(0, 0, FMemoHelp.Width, 0);
DrawText(bmp.Canvas.Handle, PChar(FMemoHelp.Text), Length(FMemoHelp.Text), R, DT_WORDBREAK or DT_CALCRECT);
FreeAndNil(bmp);
FMemoHelp.Height := R.Bottom + 2;
FMemoHelp.Show;
end;
if FMemoHelp.GetTextLen = 0 then
FMemoHelp.Hide;
end;
procedure TDataTypeEditorLink.DoTreeSelectPaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType);
begin
// Give datatype column specific color, as set in preferences
case Sender.GetNodeLevel(Node) of
0: TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold];
1: if not (vsSelected in Node.States) then
TargetCanvas.Font.Color := DatatypeCategories[Node.Parent.Index].Color;
end;
end;
procedure TDataTypeEditorLink.DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode:
PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean);
begin
// Allow only 2nd level datatypes to be focused, not their category
Allowed := Sender.GetNodeLevel(NewNode) = 1;
end;
procedure TDataTypeEditorLink.DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
begin
// Datatype selected - end editing
FTree.EndEditNode;
end;
end.

View File

@ -769,18 +769,6 @@ type
prefEnableEnumEditor,
prefEnableSetEditor,
prefEnableNullBG : Boolean;
prefFieldColorNumeric,
prefFieldColorText,
prefFieldColorBinary,
prefFieldColorDatetime,
prefFieldColorEnum,
prefFieldColorSet,
prefNullColorNumeric,
prefNullColorText,
prefNullColorBinary,
prefNullColorDatetime,
prefNullColorEnum,
prefNullColorSet,
prefNullColorDefault,
prefNullBG : TColor;
CreateDatabaseForm : TCreateDatabaseForm;
@ -1336,12 +1324,14 @@ begin
FixVT(DataGrid);
FixVT(QueryGrid);
// Load color settings
prefFieldColorNumeric := GetRegValue(REGNAME_FIELDCOLOR_NUMERIC, DEFAULT_FIELDCOLOR_NUMERIC);
prefFieldColorText := GetRegValue(REGNAME_FIELDCOLOR_TEXT, DEFAULT_FIELDCOLOR_TEXT);
prefFieldColorBinary := GetRegValue(REGNAME_FIELDCOLOR_BINARY, DEFAULT_FIELDCOLOR_BINARY);
prefFieldColorDatetime := GetRegValue(REGNAME_FIELDCOLOR_DATETIME, DEFAULT_FIELDCOLOR_DATETIME);
prefFieldColorEnum := GetRegValue(REGNAME_FIELDCOLOR_ENUM, DEFAULT_FIELDCOLOR_ENUM);
prefFieldColorSet := GetRegValue(REGNAME_FIELDCOLOR_SET, DEFAULT_FIELDCOLOR_SET);
DatatypeCategories[Integer(dtcInteger)].Color := GetRegValue(REGNAME_FIELDCOLOR_NUMERIC, DEFAULT_FIELDCOLOR_NUMERIC);
DatatypeCategories[Integer(dtcReal)].Color := GetRegValue(REGNAME_FIELDCOLOR_NUMERIC, DEFAULT_FIELDCOLOR_NUMERIC);
DatatypeCategories[Integer(dtcText)].Color := GetRegValue(REGNAME_FIELDCOLOR_TEXT, DEFAULT_FIELDCOLOR_TEXT);
DatatypeCategories[Integer(dtcBinary)].Color := GetRegValue(REGNAME_FIELDCOLOR_BINARY, DEFAULT_FIELDCOLOR_BINARY);
DatatypeCategories[Integer(dtcTemporal)].Color := GetRegValue(REGNAME_FIELDCOLOR_DATETIME, DEFAULT_FIELDCOLOR_DATETIME);
DatatypeCategories[Integer(dtcIntegerNamed)].Color := GetRegValue(REGNAME_FIELDCOLOR_ENUM, DEFAULT_FIELDCOLOR_ENUM);
DatatypeCategories[Integer(dtcSet)].Color := GetRegValue(REGNAME_FIELDCOLOR_SET, DEFAULT_FIELDCOLOR_SET);
DatatypeCategories[Integer(dtcSetNamed)].Color := GetRegValue(REGNAME_FIELDCOLOR_SET, DEFAULT_FIELDCOLOR_SET);
prefNullBG := GetRegValue(REGNAME_BG_NULL, DEFAULT_BG_NULL);
CalcNullColors;
// Editor enablings
@ -7368,14 +7358,11 @@ end;
procedure TMainForm.CalcNullColors;
var
i: Integer;
begin
prefNullColorNumeric := ColorAdjustBrightness(prefFieldColorNumeric, COLORSHIFT_NULLFIELDS);
prefNullColorText := ColorAdjustBrightness(prefFieldColorText, COLORSHIFT_NULLFIELDS);
prefNullColorBinary := ColorAdjustBrightness(prefFieldColorBinary, COLORSHIFT_NULLFIELDS);
prefNullColorDatetime := ColorAdjustBrightness(prefFieldColorDatetime, COLORSHIFT_NULLFIELDS);
prefNullColorEnum := ColorAdjustBrightness(prefFieldColorEnum, COLORSHIFT_NULLFIELDS);
prefNullColorSet := ColorAdjustBrightness(prefFieldColorSet, COLORSHIFT_NULLFIELDS);
prefNullColorDefault := ColorAdjustBrightness(clWindow, COLORSHIFT_NULLFIELDS);
for i:=Low(DatatypeCategories) to High(DatatypeCategories) do
DatatypeCategories[i].NullColor := ColorAdjustBrightness(DatatypeCategories[i].Color, COLORSHIFT_NULLFIELDS);
end;
@ -7387,7 +7374,6 @@ procedure TMainForm.GridPaintText(Sender: TBaseVirtualTree; const
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType:
TVSTTextType);
var
isNull: Boolean;
cl: TColor;
r: PGridResult;
begin
@ -7404,34 +7390,15 @@ begin
if r.Columns[Column].IsPriPart then
TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold];
// NULL value
isNull := r.Rows[Node.Index].Cells[Column].IsNull;
// Do not apply any color on a selected, highlighted cell to keep readability
if (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn) then
cl := clHighlightText
else if vsSelected in Node.States then
cl := clBlack
// Numeric field
else if r.Columns[Column].DatatypeCat in [dtcInteger, dtcReal] then
if isNull then cl := prefNullColorNumeric else cl := prefFieldColorNumeric
// Date field
else if r.Columns[Column].DatatypeCat = dtcTemporal then
if isNull then cl := prefNullColorDatetime else cl := prefFieldColorDatetime
// Text field
else if r.Columns[Column].DatatypeCat = dtcText then
if isNull then cl := prefNullColorText else cl := prefFieldColorText
// Text field
else if r.Columns[Column].DatatypeCat = dtcBinary then
if isNull then cl := prefNullColorBinary else cl := prefFieldColorBinary
// Enum field
else if r.Columns[Column].DatatypeCat = dtcIntegerNamed then
if isNull then cl := prefNullColorEnum else cl := prefFieldColorEnum
// Set field
else if r.Columns[Column].DatatypeCat = dtcSetNamed then
if isNull then cl := prefNullColorSet else cl := prefFieldColorSet
else if r.Rows[Node.Index].Cells[Column].IsNull then
cl := DatatypeCategories[Integer(r.Columns[Column].DatatypeCat)].NullColor
else
if isNull then cl := prefNullColorDefault else cl := clWindowText;
cl := DatatypeCategories[Integer(r.Columns[Column].DatatypeCat)].Color;
TargetCanvas.Font.Color := cl;
end;

View File

@ -7,7 +7,7 @@ unit mysql_structures;
interface
uses
Classes, Widestrings;
Classes, Widestrings, Graphics;
{$I const.inc}
@ -22,13 +22,14 @@ type
dtPoint, dtLinestring, dtPolygon, dtGeometry, dtMultipoint, dtMultilinestring, dtMultipolygon, dtGeometrycollection);
// MySQL data type categorization
TDatatypeCategoryIndex = (dtcInteger, dtcReal, dtcTemporal, dtcText, dtcBinary,
dtcIntegerNamed, dtcSet, dtcSetNamed, dtcSpatial);
TDatatypeCategoryIndex = (dtcInteger, dtcIntegerNamed, dtcReal, dtcText, dtcBinary, dtcTemporal,
dtcSpatial, dtcSet, dtcSetNamed);
// MySQL data type structure
TDatatype = record
Index: TDatatypeIndex;
Name: String[18];
Description: String;
HasLength: Boolean; // Can have Length- or Set-attribute?
RequiresLength: Boolean; // Must have a Length- or Set-attribute?
HasUnsigned: Boolean; // Can be unsigned?
@ -43,6 +44,8 @@ type
TDatatypeCategory = record
Index: TDatatypeCategoryIndex;
Name: String[32];
Color: TColor;
NullColor: TColor;
end;
// MySQL functions structure
@ -103,6 +106,9 @@ var
(
Index: dtTinyint;
Name: 'TINYINT';
Description: 'TINYINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A very small integer. The signed range is -128 to 127. ' +
'The unsigned range is 0 to 255.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -114,6 +120,9 @@ var
(
Index: dtSmallint;
Name: 'SMALLINT';
Description: 'SMALLINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A small integer. The signed range is -32768 to 32767. ' +
'The unsigned range is 0 to 65535.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -125,6 +134,9 @@ var
(
Index: dtMediumint;
Name: 'MEDIUMINT';
Description: 'MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A medium-sized integer. The signed range is -8388608 to 8388607. ' +
'The unsigned range is 0 to 16777215.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -136,6 +148,9 @@ var
(
Index: dtInt;
Name: 'INT';
Description: 'INT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A normal-size integer. The signed range is -2147483648 to 2147483647. ' +
'The unsigned range is 0 to 4294967295.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -147,6 +162,9 @@ var
(
Index: dtBigint;
Name: 'BIGINT';
Description: 'BIGINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A large integer. The signed range is -9223372036854775808 to ' +
'9223372036854775807. The unsigned range is 0 to 18446744073709551615.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -158,6 +176,12 @@ var
(
Index: dtFloat;
Name: 'FLOAT';
Description: 'FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A small (single-precision) floating-point number. Allowable values are '+
'-3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to '+
'3.402823466E+38. These are the theoretical limits, based on the IEEE '+
'standard. The actual range might be slightly smaller depending on your '+
'hardware or operating system.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -169,6 +193,12 @@ var
(
Index: dtDouble;
Name: 'DOUBLE';
Description: 'DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A normal-size (double-precision) floating-point number. Allowable ' +
'values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and ' +
'2.2250738585072014E-308 to 1.7976931348623157E+308. These are the ' +
'theoretical limits, based on the IEEE standard. The actual range might ' +
'be slightly smaller depending on your hardware or operating system.';
HasLength: True;
RequiresLength: False;
HasUnsigned: True;
@ -180,6 +210,14 @@ var
(
Index: dtDecimal;
Name: 'DECIMAL';
Description: 'DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]' + CRLF +
'A packed "exact" fixed-point number. M is the total number of digits ' +
'(the precision) and D is the number of digits after the decimal point ' +
'(the scale). The decimal point and (for negative numbers) the "-" sign ' +
'are not counted in M. If D is 0, values have no decimal point or ' +
'fractional part. The maximum number of digits (M) for DECIMAL is 65. ' +
'The maximum number of supported decimals (D) is 30. If D is omitted, ' +
'the default is 0. If M is omitted, the default is 10.';
HasLength: True;
RequiresLength: True;
HasUnsigned: True;
@ -191,6 +229,10 @@ var
(
Index: dtDate;
Name: 'DATE';
Description: 'DATE' + CRLF +
'A date. The supported range is ''1000-01-01'' to ''9999-12-31''. MySQL ' +
'displays DATE values in ''YYYY-MM-DD'' format, but allows assignment of ' +
'values to DATE columns using either strings or numbers.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -202,6 +244,10 @@ var
(
Index: dtTime;
Name: 'TIME';
Description: 'TIME' + CRLF +
'A time. The range is ''-838:59:59'' to ''838:59:59''. MySQL displays TIME ' +
'values in ''HH:MM:SS'' format, but allows assignment of values to TIME ' +
'columns using either strings or numbers.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -213,6 +259,13 @@ var
(
Index: dtYear;
Name: 'YEAR';
Description: 'YEAR[(2|4)]' + CRLF +
'A year in two-digit or four-digit format. The default is four-digit ' +
'format. In four-digit format, the allowable values are 1901 to 2155, ' +
'and 0000. In two-digit format, the allowable values are 70 to 69, ' +
'representing years from 1970 to 2069. MySQL displays YEAR values in ' +
'YYYY format, but allows you to assign values to YEAR columns using ' +
'either strings or numbers.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -224,6 +277,11 @@ var
(
Index: dtDatetime;
Name: 'DATETIME';
Description: 'DATETIME' + CRLF +
'A date and time combination. The supported range is ''1000-01-01 ' +
'00:00:00'' to ''9999-12-31 23:59:59''. MySQL displays DATETIME values in ' +
'''YYYY-MM-DD HH:MM:SS'' format, but allows assignment of values to ' +
'DATETIME columns using either strings or numbers.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -235,6 +293,13 @@ var
(
Index: dtTimestamp;
Name: 'TIMESTAMP';
Description: 'TIMESTAMP' + CRLF +
'A timestamp. The range is ''1970-01-01 00:00:01'' UTC to ''2038-01-09 ' +
'03:14:07'' UTC. TIMESTAMP values are stored as the number of seconds ' +
'since the epoch (''1970-01-01 00:00:00'' UTC). A TIMESTAMP cannot ' +
'represent the value ''1970-01-01 00:00:00'' because that is equivalent to ' +
'0 seconds from the epoch and the value 0 is reserved for representing ' +
'''0000-00-00 00:00:00'', the "zero" TIMESTAMP value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -246,6 +311,12 @@ var
(
Index: dtCHAR;
Name: 'CHAR';
Description: 'CHAR[(M)]' + CRLF +
'A fixed-length string that is always right-padded with spaces to the ' +
'specified length when stored. M represents the column length in ' +
'characters. The range of M is 0 to 255. If M is omitted, the length is 1.' + CRLF + CRLF +
'*Note*: Trailing spaces are removed when CHAR values are retrieved ' +
'unless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.';
HasLength: True;
RequiresLength: True;
HasUnsigned: False;
@ -258,6 +329,16 @@ var
(
Index: dtVarchar;
Name: 'VARCHAR';
Description: 'VARCHAR(M)' + CRLF +
'A variable-length string. M represents the maximum column length in ' +
'characters. The range of M is 0 to 65,535. The effective maximum length ' +
'of a VARCHAR is subject to the maximum row size (65,535 bytes, which is ' +
'shared among all columns) and the character set used. For example, utf8 ' +
'characters can require up to three bytes per character, so a VARCHAR ' +
'column that uses the utf8 character set can be declared to be a maximum ' +
'of 21,844 characters. ' + CRLF + CRLF +
'*Note*: MySQL 5.1 follows the standard SQL specification, and does not ' +
'remove trailing spaces from VARCHAR values.';
HasLength: True;
RequiresLength: True;
HasUnsigned: False;
@ -270,6 +351,11 @@ var
(
Index: dtTinytext;
Name: 'TINYTEXT';
Description: 'TINYTEXT' + CRLF +
'A TEXT column with a maximum length of 255 (28 - 1) characters. The ' +
'effective maximum length is less if the value contains multi-byte ' +
'characters. Each TINYTEXT value is stored using a one-byte length ' +
'prefix that indicates the number of bytes in the value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -281,6 +367,14 @@ var
(
Index: dtText;
Name: 'TEXT';
Description: 'TEXT[(M)]' + CRLF +
'A TEXT column with a maximum length of 65,535 (216 - 1) characters. The ' +
'effective maximum length is less if the value contains multi-byte ' +
'characters. Each TEXT value is stored using a two-byte length prefix ' +
'that indicates the number of bytes in the value. ' + CRLF +
'An optional length M can be given for this type. If this is done, MySQL ' +
'creates the column as the smallest TEXT type large enough to hold ' +
'values M characters long.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -292,6 +386,11 @@ var
(
Index: dtMediumtext;
Name: 'MEDIUMTEXT';
Description: 'MEDIUMTEXT' + CRLF +
'A TEXT column with a maximum length of 16,777,215 (224 - 1) characters. ' +
'The effective maximum length is less if the value contains multi-byte ' +
'characters. Each MEDIUMTEXT value is stored using a three-byte length ' +
'prefix that indicates the number of bytes in the value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -303,6 +402,14 @@ var
(
Index: dtLongtext;
Name: 'LONGTEXT';
Description: 'LONGTEXT' + CRLF +
'A TEXT column with a maximum length of 4,294,967,295 or 4GB (232 - 1) ' +
'characters. The effective maximum length is less if the value contains ' +
'multi-byte characters. The effective maximum length of LONGTEXT columns ' +
'also depends on the configured maximum packet size in the client/server ' +
'protocol and available memory. Each LONGTEXT value is stored using a ' +
'four-byte length prefix that indicates the number of bytes in the ' +
'value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -314,6 +421,10 @@ var
(
Index: dtBinary;
Name: 'BINARY';
Description: 'BINARY(M)' + CRLF +
'The BINARY type is similar to the CHAR type, but stores binary byte ' +
'strings rather than non-binary character strings. M represents the ' +
'column length in bytes.';
HasLength: True;
RequiresLength: True;
HasUnsigned: False;
@ -326,6 +437,10 @@ var
(
Index: dtVarbinary;
Name: 'VARBINARY';
Description: 'VARBINARY(M)' + CRLF +
'The VARBINARY type is similar to the VARCHAR type, but stores binary ' +
'byte strings rather than non-binary character strings. M represents the ' +
'maximum column length in bytes.';
HasLength: True;
RequiresLength: True;
HasUnsigned: False;
@ -338,6 +453,10 @@ var
(
Index: dtTinyblob;
Name: 'TINYBLOB';
Description: 'TINYBLOB' + CRLF +
'A BLOB column with a maximum length of 255 (28 - 1) bytes. Each ' +
'TINYBLOB value is stored using a one-byte length prefix that indicates ' +
'the number of bytes in the value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -349,6 +468,13 @@ var
(
Index: dtBlob;
Name: 'BLOB';
Description: 'BLOB[(M)]' + CRLF +
'A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each ' +
'BLOB value is stored using a two-byte length prefix that indicates the ' +
'number of bytes in the value. ' + CRLF +
'An optional length M can be given for this type. If this is done, MySQL ' +
'creates the column as the smallest BLOB type large enough to hold ' +
'values M bytes long.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -360,6 +486,10 @@ var
(
Index: dtMediumblob;
Name: 'MEDIUMBLOB';
Description: 'MEDIUMBLOB' + CRLF +
'A BLOB column with a maximum length of 16,777,215 (224 - 1) bytes. Each ' +
'MEDIUMBLOB value is stored using a three-byte length prefix that ' +
'indicates the number of bytes in the value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -371,6 +501,12 @@ var
(
Index: dtLongblob;
Name: 'LONGBLOB';
Description: 'LONGBLOB' + CRLF +
'A BLOB column with a maximum length of 4,294,967,295 or 4GB (232 - 1) ' +
'bytes. The effective maximum length of LONGBLOB columns depends on the ' +
'configured maximum packet size in the client/server protocol and ' +
'available memory. Each LONGBLOB value is stored using a four-byte ' +
'length prefix that indicates the number of bytes in the value.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -382,6 +518,11 @@ var
(
Index: dtEnum;
Name: 'ENUM';
Description: 'ENUM(''value1'',''value2'',...)' + CRLF +
'An enumeration. A string object that can have only one value, chosen ' +
'from the list of values ''value1'', ''value2'', ..., NULL or the special '''' ' +
'error value. An ENUM column can have a maximum of 65,535 distinct ' +
'values. ENUM values are represented internally as integers.';
HasLength: True; // Obviously this is not meant as "length", but as "set of values"
RequiresLength: True;
HasUnsigned: False;
@ -394,6 +535,11 @@ var
(
Index: dtSet;
Name: 'SET';
Description: 'SET(''value1'',''value2'',...)' + CRLF +
'A set. A string object that can have zero or more values, each of which ' +
'must be chosen from the list of values ''value1'', ''value2'', ... A SET ' +
'column can have a maximum of 64 members. SET values are represented ' +
'internally as integers.';
HasLength: True; // Same as for ENUM
RequiresLength: True;
HasUnsigned: False;
@ -406,6 +552,9 @@ var
(
Index: dtBit;
Name: 'BIT';
Description: 'BIT[(M)]' + CRLF +
'A bit-field type. M indicates the number of bits per value, from 1 to ' +
'64. The default is 1 if M is omitted.';
HasLength: True;
RequiresLength: False;
HasUnsigned: False;
@ -417,6 +566,8 @@ var
(
Index: dtPoint;
Name: 'POINT';
Description: 'POINT(x,y)' + CRLF +
'Constructs a WKB Point using its coordinates.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -428,6 +579,10 @@ var
(
Index: dtLinestring;
Name: 'LINESTRING';
Description: 'LINESTRING(pt1,pt2,...)' + CRLF +
'Constructs a WKB LineString value from a number of WKB Point arguments. ' +
'If any argument is not a WKB Point, the return value is NULL. If the ' +
'number of Point arguments is less than two, the return value is NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -439,6 +594,10 @@ var
(
Index: dtPolygon;
Name: 'POLYGON';
Description: 'POLYGON(ls1,ls2,...)' + CRLF +
'Constructs a WKB Polygon value from a number of WKB LineString ' +
'arguments. If any argument does not represent the WKB of a LinearRing ' +
'(that is, not a closed and simple LineString) the return value is NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -450,6 +609,7 @@ var
(
Index: dtGeometry;
Name: 'GEOMETRY';
Description: '';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -461,6 +621,9 @@ var
(
Index: dtMultipoint;
Name: 'MULTIPOINT';
Description: 'MULTIPOINT(pt1,pt2,...)' + CRLF +
'Constructs a WKB MultiPoint value using WKB Point arguments. If any ' +
'argument is not a WKB Point, the return value is NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -472,6 +635,9 @@ var
(
Index: dtMultilinestring;
Name: 'MULTILINESTRING';
Description: 'MULTILINESTRING(ls1,ls2,...)' + CRLF +
'Constructs a WKB MultiLineString value using WKB LineString arguments. ' +
'If any argument is not a WKB LineString, the return value is NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -483,6 +649,10 @@ var
(
Index: dtMultipolygon;
Name: 'MULTIPOLYGON';
Description: 'MULTIPOLYGON(poly1,poly2,...)' + CRLF +
'Constructs a WKB MultiPolygon value from a set of WKB Polygon ' +
'arguments. If any argument is not a WKB Polygon, the return value is ' +
'NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;
@ -494,6 +664,9 @@ var
(
Index: dtGeometrycollection;
Name: 'GEOMETRYCOLLECTION';
Description: 'GEOMETRYCOLLECTION(g1,g2,...)' + CRLF +
'Constructs a WKB GeometryCollection. If any argument is not a ' +
'well-formed WKB representation of a geometry, the return value is NULL.';
HasLength: False;
RequiresLength: False;
HasUnsigned: False;

View File

@ -128,7 +128,7 @@ type
implementation
uses main, helpers;
uses main, helpers, mysql_structures;
{$R *.DFM}
@ -243,12 +243,14 @@ begin
Mainform.prefCSVSeparator := editCSVSeparator.Text;
Mainform.prefCSVEncloser := editCSVEncloser.Text;
Mainform.prefCSVTerminator := editCSVTerminator.Text;
Mainform.prefFieldColorNumeric := cboxNumeric.Selected;
Mainform.prefFieldColorText := cboxText.Selected;
Mainform.prefFieldColorBinary := cboxBinary.Selected;
Mainform.prefFieldColorDatetime := cboxDatetime.Selected;
Mainform.prefFieldColorEnum := cboxEnum.Selected;
Mainform.prefFieldColorSet := cboxSet.Selected;
DatatypeCategories[Integer(dtcInteger)].Color := cboxNumeric.Selected;
DatatypeCategories[Integer(dtcReal)].Color := cboxNumeric.Selected;
DatatypeCategories[Integer(dtcText)].Color := cboxText.Selected;
DatatypeCategories[Integer(dtcBinary)].Color := cboxBinary.Selected;
DatatypeCategories[Integer(dtcTemporal)].Color := cboxDatetime.Selected;
DatatypeCategories[Integer(dtcIntegerNamed)].Color := cboxEnum.Selected;
DatatypeCategories[Integer(dtcSet)].Color := cboxSet.Selected;
DatatypeCategories[Integer(dtcSetNamed)].Color := cboxSet.Selected;
Mainform.prefNullBG := cboxNullBg.Selected;
Mainform.CalcNullColors;
Mainform.DataGrid.Repaint;

View File

@ -1040,29 +1040,13 @@ begin
TextColor := TargetCanvas.Font.Color;
case Column of
2: case dt.Category of
dtcInteger, dtcReal: TextColor := Mainform.prefFieldColorNumeric;
dtcTemporal: TextColor := Mainform.prefFieldColorDateTime;
dtcText: TextColor := Mainform.prefFieldColorText;
dtcBinary: TextColor := Mainform.prefFieldColorBinary;
dtcIntegerNamed: TextColor := Mainform.prefFieldColorEnum;
dtcSet, dtcSetNamed: TextColor := Mainform.prefFieldColorSet;
// TODO: catSpatial
else TextColor := TargetCanvas.Font.Color;
end;
2: TextColor := DatatypeCategories[Integer(dt.Category)].Color;
6: case GetColumnDefaultType(Default) of
cdtNull, cdtNullUpdateTS:
case dt.Category of
dtcInteger, dtcReal: TextColor := Mainform.prefNullColorNumeric;
dtcTemporal: TextColor := Mainform.prefNullColorDateTime;
dtcText: TextColor := Mainform.prefNullColorText;
dtcBinary: TextColor := Mainform.prefNullColorBinary;
dtcIntegerNamed: TextColor := Mainform.prefNullColorEnum;
dtcSet, dtcSetNamed: TextColor := Mainform.prefNullColorSet;
end;
TextColor := DatatypeCategories[Integer(dt.Category)].NullColor;
cdtCurTS, cdtCurTSUpdateTS:
TextColor := Mainform.prefFieldColorDateTime;
TextColor := DatatypeCategories[Integer(dtcTemporal)].Color;
cdtAutoInc:
TextColor := clNavy;
end;
@ -1154,17 +1138,15 @@ procedure TfrmTableEditor.listColumnsCreateEditor(Sender: TBaseVirtualTree;
var
EnumEditor: TEnumEditorLink;
DefaultEditor: TColumnDefaultEditorLink;
i: Integer;
DatatypeEditor: TDatatypeEditorLink;
Props: TWideStringlist;
begin
// Start cell editor
case Column of
2: begin // Datatype pulldown
EnumEditor := TEnumEditorLink.Create;
EnumEditor.ValueList := TWideStringList.Create;
for i:=Low(Datatypes) to High(Datatypes) do
EnumEditor.ValueList.Add(Datatypes[i].Name);
EditLink := EnumEditor;
DatatypeEditor := TDatatypeEditorLink.Create(Sender as TVirtualStringTree);
DatatypeEditor.Datatype := dtDateTime;
EditLink := DataTypeEditor;
end;
8: begin // Collation pulldown
EnumEditor := TEnumEditorLink.Create;