home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 October
/
Chip_2001-10_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d456
/
DCSLIB25.ZIP
/
DCDBGrids.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-06-28
|
197KB
|
6,726 lines
{
BUSINESS CONSULTING
s a i n t - p e t e r s b u r g
Components Library for Borland Delphi 4.x - 6.x
Copyright (c) 1998-2001 Alex'EM
}
unit DCDBGrids;
{$R-}
{$G+}
interface
{$I DCConst.inc}
uses
Windows, SysUtils, Messages, Classes, Controls, Forms, StdCtrls,
{$IFDEF DELPHI_V6}
Variants,
{$ENDIF}
Graphics, DCGrids, grids, DBCtrls, Db, Menus, ImgList, DbTables, DCConst, DCEditTools;
type
TColumnValue = (cvColor, cvWidth, cvFont, cvAlignment, cvReadOnly, cvTitleColor,
cvTitleCaption, cvTitleAlignment, cvTitleFont, cvImeMode, cvImeName, cvDisplayFormat);
TColumnValues = set of TColumnValue;
const
ColumnTitleValues = [cvTitleColor..cvTitleFont];
CM_DEFERLAYOUT = WM_USER + 100;
db_TitleGridDelimiter = #13#10;
db_LinesGridDelimiter = #10;
{ TColumn defines internal storage for column attributes. If IsStored is
True, values assigned to properties are stored in this object, the grid-
or field-based default sources are not modified. Values read from
properties are the previously assigned value, if any, or the grid- or
field-based default values if nothing has been assigned to that property.
This class also publishes the column attribute properties for persistent
storage.
If IsStored is True, the column does not maintain local storage of
property values. Assignments to column properties are passed through to
the underlying grid- or field-based default sources. }
type
TColumn = class;
TDCCustomDBGrid = class;
TColumnTitle = class(TPersistent)
private
FColumn: TColumn;
FCaption: string;
FFont: TFont;
FColor: TColor;
FAlignment: TAlignment;
procedure FontChanged(Sender: TObject);
function GetAlignment: TAlignment;
function GetColor: TColor;
function GetCaption: string;
function GetFont: TFont;
function IsAlignmentStored: Boolean;
function IsColorStored: Boolean;
function IsFontStored: Boolean;
function IsCaptionStored: Boolean;
procedure SetAlignment(Value: TAlignment);
procedure SetColor(Value: TColor);
procedure SetFont(Value: TFont);
procedure SetCaption(const Value: string); virtual;
protected
procedure RefreshDefaultFont;
public
constructor Create(Column: TColumn);
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
function DefaultAlignment: TAlignment;
function DefaultColor: TColor;
function DefaultFont: TFont;
function DefaultCaption: string;
procedure RestoreDefaults; virtual;
property Column: TColumn read FColumn;
published
property Alignment: TAlignment read GetAlignment write SetAlignment
stored IsAlignmentStored;
property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
property Color: TColor read GetColor write SetColor stored IsColorStored;
property Font: TFont read GetFont write SetFont stored IsFontStored;
end;
TColumnButtonStyle = (cbsAuto, cbsEllipsis, cbsNone);
TColumnIndexStyle = (idxNone, idxAscending, idxDescending);
TColumn = class(TCollectionItem)
private
FField: TField;
FFieldName: string;
FColor: TColor;
FWidth: Integer;
FTitle: TColumnTitle;
FFont: TFont;
FImeMode: TImeMode;
FImeName: TImeName;
FPickList: TStrings;
FPopupMenu: TPopupMenu;
FDropDownRows: Cardinal;
FButtonStyle: TColumnButtonStyle;
FAlignment: TAlignment;
FReadonly: Boolean;
FAssignedValues: TColumnValues;
FVisible: Boolean;
FExpanded: Boolean;
FStored: Boolean;
FIndexStyle: TColumnIndexStyle;
FIndexed: Boolean;
FItemIndex: Integer;
FDisplayFormat: string;
FTag: integer;
FResize: boolean;
FComment: string;
FWordBreak: boolean;
procedure FontChanged(Sender: TObject);
function GetAlignment: TAlignment;
function GetColor: TColor;
function GetExpanded: Boolean;
function GetField: TField;
function GetFont: TFont;
function GetImeMode: TImeMode;
function GetImeName: TImeName;
function GetParentColumn: TColumn;
function GetPickList: TStrings;
function GetReadOnly: Boolean;
function GetShowing: Boolean;
function GetWidth: Integer;
function GetVisible: Boolean;
function IsAlignmentStored: Boolean;
function IsColorStored: Boolean;
function IsFontStored: Boolean;
function IsImeModeStored: Boolean;
function IsImeNameStored: Boolean;
function IsReadOnlyStored: Boolean;
function IsWidthStored: Boolean;
procedure SetAlignment(Value: TAlignment); virtual;
procedure SetButtonStyle(Value: TColumnButtonStyle);
procedure SetColor(Value: TColor);
procedure SetExpanded(Value: Boolean);
procedure SetField(Value: TField); virtual;
procedure SetFieldName(const Value: String);
procedure SetFont(Value: TFont);
procedure SetImeMode(Value: TImeMode); virtual;
procedure SetImeName(Value: TImeName); virtual;
procedure SetPickList(Value: TStrings);
procedure SetPopupMenu(Value: TPopupMenu);
procedure SetReadOnly(Value: Boolean); virtual;
procedure SetTitle(Value: TColumnTitle);
procedure SetWidth(Value: Integer); virtual;
procedure SetVisible(Value: Boolean);
function GetExpandable: Boolean;
procedure SetIndexed(Value: Boolean);
procedure SetItemIndex(Value: Integer);
procedure SetIndexStyle(const Value: TColumnIndexStyle);
procedure SetDisplayFormat(const Value: string);
procedure SetComment(const Value: string);
procedure SetWordBreak(const Value: boolean);
protected
function CreateTitle: TColumnTitle; virtual;
function GetGrid: TDCCustomDBGrid;
function GetDisplayName: string; override;
procedure RefreshDefaultFont;
procedure SetIndex(Value: Integer); override;
property IsStored: Boolean read FStored write FStored default True;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
function DefaultAlignment: TAlignment;
function DefaultColor: TColor;
function DefaultFont: TFont;
function DefaultImeMode: TImeMode;
function DefaultImeName: TImeName;
function DefaultReadOnly: Boolean;
function DefaultWidth: Integer;
function Depth: Integer;
procedure RestoreDefaults; virtual;
property Grid: TDCCustomDBGrid read GetGrid;
property AssignedValues: TColumnValues read FAssignedValues;
property Expandable: Boolean read GetExpandable;
property Field: TField read GetField write SetField;
property ParentColumn: TColumn read GetParentColumn;
property Showing: Boolean read GetShowing;
published
property Alignment: TAlignment read GetAlignment write SetAlignment
stored IsAlignmentStored;
property ButtonStyle: TColumnButtonStyle read FButtonStyle write SetButtonStyle
default cbsAuto;
property Color: TColor read GetColor write SetColor stored IsColorStored;
property DropDownRows: Cardinal read FDropDownRows write FDropDownRows default 7;
property Expanded: Boolean read GetExpanded write SetExpanded default False;
property FieldName: String read FFieldName write SetFieldName;
property Font: TFont read GetFont write SetFont stored IsFontStored;
property ImeMode: TImeMode read GetImeMode write SetImeMode stored IsImeModeStored;
property ImeName: TImeName read GetImeName write SetImeName stored IsImeNameStored;
property PickList: TStrings read GetPickList write SetPickList;
property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
property ReadOnly: Boolean read GetReadOnly write SetReadOnly
stored IsReadOnlyStored;
property Title: TColumnTitle read FTitle write SetTitle;
property Width: Integer read GetWidth write SetWidth stored IsWidthStored;
property Visible: Boolean read GetVisible write SetVisible default True;
property IndexStyle: TColumnIndexStyle read FIndexStyle write SetIndexStyle default idxNone;
property Indexed: Boolean read FIndexed write SetIndexed default False;
property ItemIndex: Integer read FItemIndex write SetItemIndex default -1;
property DisplayFormat: string read FDisplayFormat write SetDisplayFormat;
property Tag: integer read FTag write FTag default 0;
property Resize: boolean read FResize write FResize default True;
property Comment: string read FComment write SetComment;
property WordBreak: boolean read FWordBreak write SetWordBreak;
end;
TColumnClass = class of TColumn;
TDBGridColumnsState = (csDefault, csCustomized);
TDBGridColumns = class(TCollection)
private
FGrid: TDCCustomDBGrid;
function GetColumn(Index: Integer): TColumn;
function InternalAdd: TColumn;
procedure SetColumn(Index: Integer; Value: TColumn);
procedure SetState(NewState: TDBGridColumnsState);
function GetState: TDBGridColumnsState;
protected
function GetOwner: TPersistent; override;
procedure Update(Item: TCollectionItem); override;
public
constructor Create(Grid: TDCCustomDBGrid; ColumnClass: TColumnClass);
function Add: TColumn;
procedure LoadFromFile(const Filename: string);
procedure LoadFromStream(S: TStream);
procedure RestoreDefaults;
procedure RebuildColumns;
procedure SaveToFile(const Filename: string);
procedure SaveToStream(S: TStream);
property State: TDBGridColumnsState read GetState write SetState;
property Grid: TDCCustomDBGrid read FGrid;
property Items[Index: Integer]: TColumn read GetColumn write SetColumn; default;
end;
TGridDataLink = class(TDataLink)
private
FGrid: TDCCustomDBGrid;
FFieldCount: Integer;
FFieldMap: array of Integer;
FModified: Boolean;
FInUpdateData: Boolean;
FSparseMap: Boolean;
function GetDefaultFields: Boolean;
function GetFields(I: Integer): TField;
protected
procedure ActiveChanged; override;
procedure BuildAggMap;
procedure DataSetChanged; override;
procedure DataSetScrolled(Distance: Integer); override;
procedure FocusControl(Field: TFieldRef); override;
procedure EditingChanged; override;
function IsAggRow(Value: Integer): Boolean; virtual;
procedure LayoutChanged; override;
procedure RecordChanged(Field: TField); override;
procedure UpdateData; override;
function GetMappedIndex(ColIndex: Integer): Integer;
public
constructor Create(AGrid: TDCCustomDBGrid);
destructor Destroy; override;
function AddMapping(const FieldName: string): Boolean;
procedure ClearMapping;
procedure Modified;
procedure Reset;
property DefaultFields: Boolean read GetDefaultFields;
property FieldCount: Integer read FFieldCount;
property Fields[I: Integer]: TField read GetFields;
property SparseMap: Boolean read FSparseMap write FSparseMap;
end;
TBookmarkList = class
private
FList: TStringList;
FGrid: TDCCustomDBGrid;
FCache: TBookmarkStr;
FCacheIndex: Integer;
FCacheFind: Boolean;
FLinkActive: Boolean;
function GetCount: Integer;
function GetCurrentRowSelected: Boolean;
function GetItem(Index: Integer): TBookmarkStr;
procedure SetCurrentRowSelected(Value: Boolean);
protected
function CurrentRow: TBookmarkStr;
function Compare(const Item1, Item2: TBookmarkStr): Integer;
procedure LinkActive(Value: Boolean);
procedure StringsChanged(Sender: TObject);
public
constructor Create(AGrid: TDCCustomDBGrid);
destructor Destroy; override;
procedure Clear; // free all bookmarks
procedure Delete; // delete all selected rows from dataset
function Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
function IndexOf(const Item: TBookmarkStr): Integer;
function Refresh: Boolean;// drop orphaned bookmarks; True = orphans found
procedure Save(List: TStringList);
procedure SelectAll;
procedure Load(List: TStringList);
property Count: Integer read GetCount;
property CurrentRowSelected: Boolean read GetCurrentRowSelected
write SetCurrentRowSelected;
property Items[Index: Integer]: TBookmarkStr read GetItem; default;
end;
TDBGridOption = (dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect,
dgAlwaysShowSelection, dgConfirmDelete, dgCancelOnExit, dgMultiSelect,
dgMarker, dgTitleClicked, dgUserRowHeight, dgRowSizing, dgHighlightRow,
dgFlatButtons, dgCompleteLines, dgAutoSize);
TDBGridOptionEx =(dgeInsertSelect, dgeMarkerMenu, dgeShadowSelection,
dgeDrawMemoAsText);
TDBGridOptions = set of TDBGridOption;
TDBGridOptionsEx = set of TDBGridOptionEx;
{ The DBGrid's DrawDataCell virtual method and OnDrawDataCell event are only
called when the grid's Columns.State is csDefault. This is for compatibility
with existing code. These routines don't provide sufficient information to
determine which column is being drawn, so the column attributes aren't
easily accessible in these routines. Column attributes also introduce the
possibility that a column's field may be nil, which would break existing
DrawDataCell code. DrawDataCell, OnDrawDataCell, and DefaultDrawDataCell
are obsolete, retained for compatibility purposes. }
TDrawDataCellEvent = procedure (Sender: TObject; const Rect: TRect; Field: TField;
State: TGridDrawState) of object;
{ The DBGrid's DrawColumnCell virtual method and OnDrawColumnCell event are
always called, when the grid has defined column attributes as well as when
it is in default mode. These new routines provide the additional
information needed to access the column attributes for the cell being
drawn, and must support nil fields. }
TDrawColumnCellEvent = procedure (Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState) of object;
TDBGridClickEvent = procedure (Column: TColumn) of object;
TDBGridClipEvent = procedure (Sender: TObject; X, Y : LongInt; var Show: boolean) of object;
TDBGridCommentEvent = procedure(Sender: TObject; Mode: integer; Column: TColumn) of object;
TDBGridUpdMessageEvent = procedure(Sender: TObject; Canvas: TCanvas; ARect: TRect;
UpdateMessage: string) of object;
TDBGridDrawCompleteEvent = procedure(Sender: TObject; Canvas: TCanvas; ARect: TRect;
Selected: boolean; ARow: integer; var DefaultDrawing: boolean) of object;
TBookmarkInfo = record
Row: integer;
Bookmark: TBookmark;
ActiveRecord: integer;
end;
TDCCustomDBGrid = class(TDCCustomGrid)
private
FBookmarks: TBookmarkList;
FColumnCell: integer;
FColumns: TDBGridColumns;
FClipDown: boolean;
FClipPopup: TObject;
FClipPopupVisible: boolean;
FCurrentCol: Integer;
FCurrentPos: array[1..2] of TBookmarkInfo;
FDataLink: TGridDataLink;
FDataVisible: boolean;
FDBObject: TDCDBObject;
FDefaultDrawing: Boolean;
FDragCol: TColumn;
FDrawColumn: TColumn;
FEditText: string;
FFirstGridCell: integer;
FFrozenCols: integer;
FImageChangeLink: TChangeLink;
FImages: TImageList;
FInColExit: Boolean;
FIsESCKey: Boolean;
FLayoutFromDataset: Boolean;
FLayoutLock: Byte;
FMousePoint: TPoint;
FOnCellClick: TDBGridClickEvent;
FOnCellDblClick: TDBGridClickEvent;
FOnClipButtonClick: TNotifyEvent;
FOnClipClick: TDBGridClipEvent;
FOnColumnComment: TDBGridCommentEvent;
FOnColumnMoved: TMovedEvent;
FOnColEnter: TNotifyEvent;
FOnColExit: TNotifyEvent;
FOnDrawColumnCell: TDrawColumnCellEvent;
FOnDrawCompleteLine: TDBGridDrawCompleteEvent;
FOnDrawDataCell: TDrawDataCellEvent;
FOnEditButtonClick: TNotifyEvent;
FOnPaintEmptyMessage: TDBGridUpdMessageEvent;
FOnTitleClick:TDBGridClickEvent;
FOptions: TDBGridOptions;
FOptionsEx: TDBGridOptionsEx;
FOriginalImeMode: TImeMode;
FOriginalImeName: TImeName;
FPopupTitle: TPopupMenu;
FReadOnly: Boolean;
FSelecting: Boolean;
FSelectionAnchor: TBookmarkStr;
FSelfChangingTitleFont: Boolean;
FSelRow: Integer;
FSizingIndex: integer;
FSizingOff: integer;
FTitleFont: TFont;
FTitleOffset, FIndicatorOffset: Byte;
FUpdateLock: Byte;
FUserChange: Boolean;
FVisibleColumns: TList;
function AcquireFocus: Boolean;
function BoxRectEx(ALeft, ATop, ARight, ABottom: Longint): TRect;
procedure ClearSelection;
procedure DataChanged;
procedure DoSelection(Select: Boolean; Direction: Integer; Shift: TShiftState);
procedure EditingChanged;
function GetDataSource: TDataSource;
function GetDBObject: TDCDBObject;
function GetFieldCount: Integer;
function GetFields(FieldIndex: Integer): TField;
function GetFrozenCols: integer;
function GetPosition: TBookMark;
function GetSelectedField: TField;
function GetSelectedIndex: Integer;
procedure ImageListChange(Sender: TObject);
procedure InternalLayout;
function LeftTitleButton(Row, Col: integer): boolean;
procedure MoveCol(RawCol, Direction: Integer);
procedure NextRow(Select: Boolean);
procedure PriorRow(Select: Boolean);
function PtInExpandButton(X,Y: Integer; var MasterCol: TColumn): Boolean;
procedure ReadColumns(Reader: TReader);
procedure RecordChanged(Field: TField);
procedure SetIme;
procedure SetClipDown(const Value: boolean);
procedure SetColumns(Value: TDBGridColumns);
procedure SetDataSource(Value: TDataSource);
procedure SetDataVisible(const Value: boolean);
procedure SetDBObject(const Value: TDCDBObject);
procedure SetFrozenCols(Value: integer);
procedure SetImages(const Value: TImageList);
procedure SetOptions(Value: TDBGridOptions);
procedure SetOptionsEx(const Value: TDBGridOptionsEx);
procedure SetPopupTitle(const Value: TPopupMenu);
procedure SetPosition(const Value: TBookMark);
procedure SetSelectedField(Value: TField);
procedure SetSelectedIndex(Value: Integer);
procedure SetTitleFont(Value: TFont);
procedure SetTitleHeight;
procedure TitleFontChanged(Sender: TObject);
procedure UpdateData;
procedure UpdateActive;
procedure UpdateIme;
procedure UpdateScrollBar;
procedure UpdateRowCount;
procedure WriteColumns(Writer: TWriter);
protected
FUpdateFields: Boolean;
FAcquireFocus: Boolean;
function RawToDataColumn(ACol: Integer): Integer; override;
function DataToRawColumn(ACol: Integer): Integer;
function AcquireLayoutLock: Boolean;
procedure CreateParams(var Params: TCreateParams); override;
procedure BeginLayout; override;
procedure BeginUpdate;
procedure CalcSizingState(X, Y: Integer; var State: TGridState;
var Index: Longint; var SizingPos, SizingOfs: Integer;
var FixedInfo: TGridDrawInfo); override;
procedure CancelLayout;
function CanEditAcceptKey(Key: Char): Boolean; override;
function CanEditModify: Boolean; override;
function CanEditShow: Boolean; override;
procedure CellClick(Column: TColumn); dynamic;
procedure CellDblClick(Column: TColumn); dynamic;
procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
function CalcTitleRect(Col: TColumn; ARow: Integer;
var MasterCol: TColumn): TRect;
function ColumnAtDepth(Col: TColumn; ADepth: Integer): TColumn;
procedure ColEnter; dynamic;
procedure ColExit; dynamic;
procedure ColWidthsChanged; override;
function CreateColumns: TDBGridColumns; dynamic;
function CreateEditor: TInplaceEdit; override;
procedure CreateWnd; override;
procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED;
procedure CMExit(var Message: TMessage); message CM_EXIT;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
procedure CMDeferLayout(var Message); message CM_DEFERLAYOUT;
procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
procedure WMIMEStartComp(var Message: TMessage); message WM_IME_STARTCOMPOSITION;
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus(var Message: TMessage); message WM_KILLFOCUS;
procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure CMCancelMode(var Message: TCMCancelMode); message CM_CANCELMODE;
procedure WMChar(var Msg: TWMChar); message WM_CHAR;
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
procedure DeferLayout;
procedure DefineFieldMap; virtual;
procedure DefineProperties(Filer: TFiler); override;
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
procedure DrawDataCell(const Rect: TRect; Field: TField;
State: TGridDrawState); dynamic; { obsolete }
procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
Column: TColumn; State: TGridDrawState); dynamic;
procedure EditButtonClick; dynamic;
procedure EndLayout; override;
procedure EndUpdate;
function GetColField(DataCol: Integer): TField;
function GetEditLimit: Integer; override;
function GetEditMask(ACol, ARow: Longint): string; override;
function GetEditText(ACol, ARow: Longint): string; override;
function GetFieldValue(ACol: Integer): string;
function HighlightCell(DataCol, DataRow: Integer; const Value: string;
AState: TGridDrawState): Boolean; virtual;
procedure KeyPress(var Key: Char); override;
procedure InvalidateTitles;
procedure InvalidateSelected;
procedure LayoutChanged; virtual;
procedure LinkActive(Value: Boolean); virtual;
procedure Loaded; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
procedure DoColumnComment(Mode: integer; Column: TColumn); virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Scroll(Distance: Integer); virtual;
procedure SetColumnAttributes; virtual;
procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
function SelectCell(ACol, ARow: Longint): Boolean; override;
function StoreColumns: Boolean;
function MouseUpBeforeDblClk: boolean; dynamic;
procedure TimedScroll(Direction: TGridScrollDirection); override;
procedure TitleClick(Column: TColumn); dynamic;
procedure ClipClick; dynamic;
procedure TopLeftChanged; override;
function UseRightToLeftAlignmentForField(const AField: TField;
Alignment: TAlignment): Boolean;
function BeginColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean; override;
function CheckColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean; override;
function EndColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean; override;
procedure ClipButtonClick(Sender: TObject); virtual;
function GetPopupMenu: TPopupMenu; override;
function DataVisible: boolean; virtual;
function DrawTitleCell(ACanvas: TCanvas; ACol, ARow: Integer; ARect: TRect;
BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint; override;
function GetBorderStyle: TEdgeBorderStyle; override;
function FlatButtons: boolean; override;
procedure DoColumnClick(Shift: TShiftState; ColIndex: integer); override;
procedure CreateCellDragImage(ACol, ARow: integer; var DragImages: TImageList); override;
function CanColResize(ACol: integer): boolean; override;
property Columns: TDBGridColumns read FColumns write SetColumns;
property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing default True;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property DataLink: TGridDataLink read FDataLink;
property IndicatorOffset: Byte read FIndicatorOffset;
property LayoutLock: Byte read FLayoutLock;
property Options: TDBGridOptions read FOptions write SetOptions
default [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines,
dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
property OptionsEx: TDBGridOptionsEx read FOptionsEx write SetOptionsEx
default [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText
{$IFNDEF DELPHI_V5UP}, dgeInsertSelect {$ENDIF}];
property ParentColor default False;
property ReadOnly: Boolean read FReadOnly write FReadOnly default False;
property SelectedRows: TBookmarkList read FBookmarks;
property TitleFont: TFont read FTitleFont write SetTitleFont;
property UpdateLock: Byte read FUpdateLock;
property OnColEnter: TNotifyEvent read FOnColEnter write FOnColEnter;
property OnColExit: TNotifyEvent read FOnColExit write FOnColExit;
property OnDrawDataCell: TDrawDataCellEvent read FOnDrawDataCell
write FOnDrawDataCell; { obsolete }
property OnDrawColumnCell: TDrawColumnCellEvent read FOnDrawColumnCell
write FOnDrawColumnCell;
property OnEditButtonClick: TNotifyEvent read FOnEditButtonClick
write FOnEditButtonClick;
property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
property OnCellClick: TDBGridClickEvent read FOnCellClick write FOnCellClick;
property OnCellDblClick: TDBGridClickEvent read FOnCellDblClick write FOnCellDblClick;
property OnTitleClick: TDBGridClickEvent read FOnTitleClick write FOnTitleClick;
property OnClipClick: TDBGridClipEvent read FOnClipClick write FOnClipClick;
property Position: TBookMark read GetPosition write SetPosition;
property FrozenCols: Integer read GetFrozenCols write SetFrozenCols default 0;
property OnClipButtonClick: TNotifyEvent read FOnClipButtonClick write FOnClipButtonClick;
property PopupTitle: TPopupMenu read FPopupTitle write SetPopupTitle;
property DBObject: TDCDBObject read GetDBObject write SetDBObject;
property OnColumnComment: TDBGridCommentEvent read FOnColumnComment write FOnColumnComment;
property OnPaintEmptyMessage: TDBGridUpdMessageEvent read FOnPaintEmptyMessage write FOnPaintEmptyMessage;
property OnDrawCompleteLine: TDBGridDrawCompleteEvent read FOnDrawCompleteLine write FOnDrawCompleteLine;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DefaultDrawDataCell(const Rect: TRect; Field: TField;
State: TGridDrawState); { obsolete }
procedure DefaultDrawColumnCell(const Rect: TRect; DataCol: Integer;
Column: TColumn; State: TGridDrawState);
procedure DefaultHandler(var Msg); override;
procedure RowHeightsChanged; override;
function ExecuteAction(Action: TBasicAction): Boolean; override;
procedure ShowPopupEditor(Column: TColumn; X: Integer = Low(Integer);
Y: Integer = Low(Integer)); dynamic;
function UpdateAction(Action: TBasicAction): Boolean; override;
function ValidFieldIndex(FieldIndex: Integer): Boolean;
function GetDataValue(Column: TColumn): string; virtual;
function ValidBookmark(Bookmark: TBookmark): boolean;
procedure SavePosition;
procedure RestPosition;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
function GroupingEnabled: boolean; override;
procedure Paint; override;
property EditorMode;
property FieldCount: Integer read GetFieldCount;
property Fields[FieldIndex: Integer]: TField read GetFields;
property SelectedField: TField read GetSelectedField write SetSelectedField;
property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
property Images: TImageList read FImages write SetImages;
property ClipDown: boolean read FClipDown write SetClipDown;
property Col;
property Row;
procedure ShowClipPopup;
procedure HideClipPopup;
procedure SelectItems(Mode: TSelectMode);
function CellRect(ACol, ARow: Longint): TRect;
function MouseCoord(X, Y: Longint): TGridCoord;
property DataSetVisible: boolean read FDataVisible write SetDataVisible;
end;
TDCDBGrid = class(TDCCustomDBGrid)
public
property Canvas;
property SelectedRows;
property Position;
published
property Align;
property Anchors;
property BiDiMode;
property BorderStyle;
property Color;
property Columns stored False; //StoreColumns;
property Constraints;
property Ctl3D;
property DataSource;
property DefaultDrawing;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property FixedColor;
property Font;
property ImeMode;
property ImeName;
property Options;
property OptionsEx;
property ParentBiDiMode;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property ShowHint;
property TabOrder;
property TabStop;
property TitleFont;
property Visible;
property OnCellClick;
property OnCellDblClick;
property OnColEnter;
property OnColExit;
property OnColumnMoved;
property OnDrawDataCell; { obsolete }
property OnDrawColumnCell;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEditButtonClick;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDock;
property OnStartDrag;
property OnTitleClick;
property Images;
property DefaultRowHeight;
property OnClipClick;
property FrozenCols;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnClipButtonClick;
property PopupTitle;
property DBObject;
property OnColumnComment;
property OnPaintEmptyMessage;
property OnDrawCompleteLine;
end;
const
IndicatorWidth = 12;
MarkerWidth = 16;
IndexTitleWidth = 11;
implementation
uses DBConsts, Dialogs, DCPopupWindow, DCEditButton, DCChoice;
{$R *.RES}
const
MaxMapSize = (MaxInt div 2) div SizeOf(Integer); { 250 million }
type
TSelection = record
StartPos, EndPos: Integer;
end;
TPrivateDataSet = class(TDataSet)
end;
var
DrawBitmap, TempBitmap: TBitmap;
UserCount: Integer;
{ Error reporting }
procedure RaiseGridError(const S: string);
begin
raise EInvalidGridOperation.Create(S);
end;
procedure KillMessage(Wnd: HWnd; Msg: Integer);
// Delete the requested message from the queue, but throw back
// any WM_QUIT msgs that PeekMessage may also return
var
M: TMsg;
begin
M.Message := 0;
if PeekMessage(M, Wnd, Msg, Msg, pm_Remove) and (M.Message = WM_QUIT) then
PostQuitMessage(M.wparam);
end;
function GetTextHeight(DC: HDC; Value: string): integer;
var
R: TRect;
begin
R := Rect(0, 0, 500, 0);
DrawText(DC, PChar(Value), -1, R, DT_CALCRECT or DT_LEFT or
DT_WORDBREAK or DT_NOPREFIX);
Result := R.Bottom;
end;
function GetTextHeightEx(Canvas: TCanvas; Value: string): integer;
var
R: TRect;
P: TPoint;
begin
R := Rect(0, 0, MaxInt, MaxInt);
P := DrawHighLightText(Canvas, PChar(Value), R, 0, DT_LEFT);
Result := P.Y;
end;
function GetTextWidth(DC: HDC; Value: string): integer;
var
R: TRect;
begin
R := Rect(0, 0, 500, 0);
DrawText(DC, PChar(Value), -1, R, DT_CALCRECT or DT_LEFT or
DT_WORDBREAK or DT_NOPREFIX);
Result := R.Right;
end;
function GetTextWidthEx(Canvas: TCanvas; Value: string): integer;
var
R: TRect;
P: TPoint;
begin
R := Rect(0, 0, 500, 0);
P := DrawHighLightText(Canvas, PChar(Value), R, 0, DT_LEFT or DT_WORDBREAK or DT_NOPREFIX);
Result := P.X;
end;
function GetMultiLineHeight(Font: TFont; Value: string;
ACanvas: TCanvas = nil) : Longint;
var
Canvas: TCanvas;
begin
if ACanvas = nil then
begin
Canvas := nil;
try
Canvas := TCanvas.Create;
Canvas.Handle := GetDC(0);
Canvas.Font := Font;
Result := _intMax(GetTextHeightEx(Canvas, Value), GetTextHeightEx(Canvas, 'Wg')) + 4;
finally
ReleaseDC(0, Canvas.Handle);
Canvas.Handle := 0;
Canvas.Free;
end
end
else
Result := _intMax(GetTextHeightEx(ACanvas, Value), GetTextHeightEx(ACanvas, 'Wg')) + 4;
end;
{ TDBGridInplaceEdit }
{ TDBGridInplaceEdit adds support for a button on the in-place editor,
which can be used to drop down a table-based lookup list, a stringlist-based
pick list, or (if button style is esEllipsis) fire the grid event
OnEditButtonClick. }
type
TEditStyle = (esSimple, esEllipsis, esPickList, esDataList);
TPopupListbox = class;
TDBGridInplaceEdit = class(TInplaceEdit)
private
FButtonWidth: Integer;
FDataList: TDBLookupListBox;
FPickList: TPopupListbox;
FActiveList: TWinControl;
FLookupSource: TDatasource;
FEditStyle: TEditStyle;
FListVisible: Boolean;
FTracking: Boolean;
FPressed: Boolean;
procedure ListMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SetEditStyle(Value: TEditStyle);
procedure StopTracking;
procedure TrackButton(X,Y: Integer);
procedure CMCancelMode(var Message: TCMCancelMode); message CM_CancelMode;
procedure WMCancelMode(var Message: TMessage); message WM_CancelMode;
procedure WMKillFocus(var Message: TMessage); message WM_KillFocus;
procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message wm_LButtonDblClk;
procedure WMPaint(var Message: TWMPaint); message wm_Paint;
procedure WMSetCursor(var Message: TWMSetCursor); message WM_SetCursor;
function OverButton(const P: TPoint): Boolean;
function ButtonRect: TRect;
protected
procedure BoundsChanged; override;
procedure CloseUp(Accept: Boolean);
procedure DoDropDownKeys(var Key: Word; Shift: TShiftState);
procedure DropDown;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure PaintWindow(DC: HDC); override;
procedure UpdateContents; override;
procedure WndProc(var Message: TMessage); override;
property EditStyle: TEditStyle read FEditStyle write SetEditStyle;
property ActiveList: TWinControl read FActiveList write FActiveList;
property DataList: TDBLookupListBox read FDataList;
property PickList: TPopupListbox read FPickList;
public
constructor Create(Owner: TComponent); override;
end;
{ TPopupListbox }
TPopupListbox = class(TCustomListbox)
private
FSearchText: String;
FSearchTickCount: Longint;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure KeyPress(var Key: Char); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
end;
procedure TPopupListBox.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
Style := Style or WS_BORDER;
ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
AddBiDiModeExStyle(ExStyle);
WindowClass.Style := CS_SAVEBITS;
end;
end;
procedure TPopupListbox.CreateWnd;
begin
inherited CreateWnd;
Windows.SetParent(Handle, 0);
CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
end;
procedure TPopupListbox.Keypress(var Key: Char);
var
TickCount: Integer;
begin
case Key of
#8, #27: FSearchText := '';
#32..#255:
begin
TickCount := GetTickCount;
if TickCount - FSearchTickCount > 2000 then FSearchText := '';
FSearchTickCount := TickCount;
if Length(FSearchText) < 32 then FSearchText := FSearchText + Key;
SendMessage(Handle, LB_SelectString, WORD(-1), Longint(PChar(FSearchText)));
Key := #0;
end;
end;
inherited Keypress(Key);
end;
procedure TPopupListbox.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
TDBGridInPlaceEdit(Owner).CloseUp((X >= 0) and (Y >= 0) and
(X < Width) and (Y < Height));
end;
constructor TDBGridInplaceEdit.Create(Owner: TComponent);
begin
inherited Create(Owner);
FLookupSource := TDataSource.Create(Self);
FButtonWidth := GetSystemMetrics(SM_CXVSCROLL);
FEditStyle := esSimple;
end;
procedure TDBGridInplaceEdit.BoundsChanged;
var
R: TRect;
begin
SetRect(R, 2, 2, Width - 2, Height);
if FEditStyle <> esSimple then
if not TDCCustomDBGrid(Owner).UseRightToLeftAlignment then
Dec(R.Right, FButtonWidth)
else
Inc(R.Left, FButtonWidth - 2);
SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@R));
SendMessage(Handle, EM_SCROLLCARET, 0, 0);
if SysLocale.FarEast then
SetImeCompositionWindow(Font, R.Left, R.Top);
end;
procedure TDBGridInplaceEdit.CloseUp(Accept: Boolean);
var
MasterField: TField;
ListValue: Variant;
begin
if FListVisible then
begin
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
if FActiveList = FDataList then
ListValue := FDataList.KeyValue
else
if FPickList.ItemIndex <> -1 then
ListValue := FPickList.Items[FPicklist.ItemIndex];
SetWindowPos(FActiveList.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
FListVisible := False;
if Assigned(FDataList) then
FDataList.ListSource := nil;
FLookupSource.Dataset := nil;
Invalidate;
if Accept then
if FActiveList = FDataList then
with TDCCustomDBGrid(Grid), Columns[SelectedIndex].Field do
begin
MasterField := DataSet.FieldByName(KeyFields);
if MasterField.CanModify then
begin
DataSet.Edit;
MasterField.Value := ListValue;
end;
end
else
if (not VarIsNull(ListValue)) and EditCanModify then
with TDCCustomDBGrid(Grid), Columns[SelectedIndex].Field do
Text := ListValue;
end;
end;
procedure TDBGridInplaceEdit.DoDropDownKeys(var Key: Word; Shift: TShiftState);
begin
case Key of
VK_UP, VK_DOWN:
if ssAlt in Shift then
begin
if FListVisible then CloseUp(True) else DropDown;
Key := 0;
end;
VK_RETURN, VK_ESCAPE:
if FListVisible and not (ssAlt in Shift) then
begin
CloseUp(Key = VK_RETURN);
Key := 0;
end;
end;
end;
procedure TDBGridInplaceEdit.DropDown;
var
P: TPoint;
I,J,Y: Integer;
Column: TColumn;
begin
if not FListVisible and Assigned(FActiveList) then
begin
FActiveList.Width := Width;
with TDCCustomDBGrid(Grid) do
Column := Columns[SelectedIndex];
if FActiveList = FDataList then
with Column.Field do
begin
FDataList.Color := Color;
FDataList.Font := Font;
FDataList.RowCount := Column.DropDownRows;
FLookupSource.DataSet := LookupDataSet;
FDataList.KeyField := LookupKeyFields;
FDataList.ListField := LookupResultField;
FDataList.ListSource := FLookupSource;
FDataList.KeyValue := DataSet.FieldByName(KeyFields).Value;
{ J := Column.DefaultWidth;
if J > FDataList.ClientWidth then
FDataList.ClientWidth := J;
} end
else
begin
FPickList.Color := Color;
FPickList.Font := Font;
FPickList.Items := Column.Picklist;
if FPickList.Items.Count >= Integer(Column.DropDownRows) then
FPickList.Height := Integer(Column.DropDownRows) * FPickList.ItemHeight + 4
else
FPickList.Height := FPickList.Items.Count * FPickList.ItemHeight + 4;
if Column.Field.IsNull then
FPickList.ItemIndex := -1
else
FPickList.ItemIndex := FPickList.Items.IndexOf(Column.Field.Text);
J := FPickList.ClientWidth;
for I := 0 to FPickList.Items.Count - 1 do
begin
Y := FPickList.Canvas.TextWidth(FPickList.Items[I]);
if Y > J then J := Y;
end;
FPickList.ClientWidth := J;
end;
P := Parent.ClientToScreen(Point(Left, Top));
Y := P.Y + Height;
if Y + FActiveList.Height > Screen.Height then Y := P.Y - FActiveList.Height;
SetWindowPos(FActiveList.Handle, HWND_TOP, P.X, Y, 0, 0,
SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
FListVisible := True;
Invalidate;
Windows.SetFocus(Handle);
end;
end;
type
TWinControlCracker = class(TWinControl) end;
procedure TDBGridInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
if (EditStyle = esEllipsis) and (Key = VK_RETURN) and (Shift = [ssCtrl]) then
begin
TDCCustomDBGrid(Grid).EditButtonClick;
KillMessage(Handle, WM_CHAR);
end
else
inherited KeyDown(Key, Shift);
end;
procedure TDBGridInplaceEdit.ListMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
CloseUp(PtInRect(FActiveList.ClientRect, Point(X, Y)));
end;
procedure TDBGridInplaceEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if (Button = mbLeft) and (FEditStyle <> esSimple) and
OverButton(Point(X,Y)) then
begin
if FListVisible then
CloseUp(False)
else
begin
MouseCapture := True;
FTracking := True;
TrackButton(X, Y);
if Assigned(FActiveList) then
DropDown;
end;
end;
inherited MouseDown(Button, Shift, X, Y);
end;
procedure TDBGridInplaceEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
var
ListPos: TPoint;
MousePos: TSmallPoint;
begin
if FTracking then
begin
TrackButton(X, Y);
if FListVisible then
begin
ListPos := FActiveList.ScreenToClient(ClientToScreen(Point(X, Y)));
if PtInRect(FActiveList.ClientRect, ListPos) then
begin
StopTracking;
MousePos := PointToSmallPoint(ListPos);
SendMessage(FActiveList.Handle, WM_LBUTTONDOWN, 0, Integer(MousePos));
Exit;
end;
end;
end;
inherited MouseMove(Shift, X, Y);
end;
procedure TDBGridInplaceEdit.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
WasPressed: Boolean;
begin
WasPressed := FPressed;
StopTracking;
if (Button = mbLeft) and (FEditStyle = esEllipsis) and WasPressed then
TDCCustomDBGrid(Grid).EditButtonClick;
inherited MouseUp(Button, Shift, X, Y);
end;
procedure TDBGridInplaceEdit.PaintWindow(DC: HDC);
var
R: TRect;
Flags: Integer;
W, X, Y: Integer;
begin
if FEditStyle <> esSimple then
begin
R := ButtonRect;
Flags := 0;
if FEditStyle in [esDataList, esPickList] then
begin
if FActiveList = nil then
Flags := DFCS_INACTIVE
else if FPressed then
Flags := DFCS_FLAT or DFCS_PUSHED;
DrawFrameControl(DC, R, DFC_SCROLL, Flags or DFCS_SCROLLCOMBOBOX);
end
else { esEllipsis }
begin
if FPressed then Flags := BF_FLAT;
DrawEdge(DC, R, EDGE_RAISED, BF_RECT or BF_MIDDLE or Flags);
X := R.Left + ((R.Right - R.Left) shr 1) - 1 + Ord(FPressed);
Y := R.Top + ((R.Bottom - R.Top) shr 1) - 1 + Ord(FPressed);
W := FButtonWidth shr 3;
if W = 0 then W := 1;
PatBlt(DC, X, Y, W, W, BLACKNESS);
PatBlt(DC, X - (W * 2), Y, W, W, BLACKNESS);
PatBlt(DC, X + (W * 2), Y, W, W, BLACKNESS);
end;
ExcludeClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);
end;
inherited PaintWindow(DC);
end;
procedure TDBGridInplaceEdit.SetEditStyle(Value: TEditStyle);
begin
if Value = FEditStyle then Exit;
FEditStyle := Value;
case Value of
esPickList:
begin
if FPickList = nil then
begin
FPickList := TPopupListbox.Create(Self);
FPickList.Visible := False;
FPickList.Parent := Self;
FPickList.OnMouseUp := ListMouseUp;
FPickList.IntegralHeight := True;
FPickList.ItemHeight := 11;
end;
FActiveList := FPickList;
end;
esDataList:
begin
if FDataList = nil then
begin
FDataList := TPopupDataList.Create(Self);
FDataList.Visible := False;
FDataList.Parent := Self;
FDataList.OnMouseUp := ListMouseUp;
end;
FActiveList := FDataList;
end;
else { cbsNone, cbsEllipsis, or read only field }
FActiveList := nil;
end;
with TDCCustomDBGrid(Grid) do
Self.ReadOnly := Columns[SelectedIndex].ReadOnly;
Repaint;
end;
procedure TDBGridInplaceEdit.StopTracking;
begin
if FTracking then
begin
TrackButton(-1, -1);
FTracking := False;
MouseCapture := False;
end;
end;
procedure TDBGridInplaceEdit.TrackButton(X,Y: Integer);
var
NewState: Boolean;
R: TRect;
begin
R := ButtonRect;
NewState := PtInRect(R, Point(X, Y));
if FPressed <> NewState then
begin
FPressed := NewState;
InvalidateRect(Handle, @R, False);
end;
end;
procedure TDBGridInplaceEdit.UpdateContents;
var
Column: TColumn;
NewStyle: TEditStyle;
MasterField: TField;
begin
with TDCCustomDBGrid(Grid) do
begin
if Columns.Count <= SelectedIndex then Exit;
Column := Columns[SelectedIndex];
end;
NewStyle := esSimple;
case Column.ButtonStyle of
cbsEllipsis: NewStyle := esEllipsis;
cbsAuto:
if Assigned(Column.Field) then
with Column.Field do
begin
{ Show the dropdown button only if the field is editable }
if FieldKind = fkLookup then
begin
MasterField := Dataset.FieldByName(KeyFields);
{ Column.DefaultReadonly will always be True for a lookup field.
Test if Column.ReadOnly has been assigned a value of True }
if Assigned(MasterField) and MasterField.CanModify and
not ((cvReadOnly in Column.AssignedValues) and Column.ReadOnly) then
with TDCCustomDBGrid(Grid) do
if not ReadOnly and DataLink.Active and not Datalink.ReadOnly then
NewStyle := esDataList
end
else
if Assigned(Column.Picklist) and (Column.PickList.Count > 0) and
not Column.Readonly then
NewStyle := esPickList
else if DataType in [ftDataset, ftReference] then
NewStyle := esEllipsis;
end;
end;
EditStyle := NewStyle;
inherited UpdateContents;
Font.Assign(Column.Font);
end;
procedure TDBGridInplaceEdit.CMCancelMode(var Message: TCMCancelMode);
begin
if (Message.Sender <> Self) and (Message.Sender <> FActiveList) then
CloseUp(False);
end;
procedure TDBGridInplaceEdit.WMCancelMode(var Message: TMessage);
begin
StopTracking;
inherited;
end;
procedure TDBGridInplaceEdit.WMKillFocus(var Message: TMessage);
var
ARect: TRect;
begin
if not SysLocale.FarEast then inherited
else
begin
ImeName := Screen.DefaultIme;
ImeMode := imDontCare;
inherited;
if HWND(Message.WParam) <> TDCCustomDBGrid(Grid).Handle then
ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
end;
CloseUp(False);
with TDCCustomDBGrid(Grid) do
begin
if dgHighlightRow in Options then
begin
ARect := BoxRectEx(0 , Row , ColCount-1, Row );
ValidateRect(Handle, @ARect);
InvalidateRect(Handle, @ARect, False);
end;
end;
end;
function TDBGridInplaceEdit.ButtonRect: TRect;
begin
if not TDCCustomDBGrid(Owner).UseRightToLeftAlignment then
Result := Rect(Width - FButtonWidth, 0, Width, Height)
else
Result := Rect(0, 0, FButtonWidth, Height);
end;
function TDBGridInplaceEdit.OverButton(const P: TPoint): Boolean;
begin
Result := PtInRect(ButtonRect, P);
end;
procedure TDBGridInplaceEdit.WMLButtonDblClk(var Message: TWMLButtonDblClk);
begin
with Message do
if (FEditStyle <> esSimple) and OverButton(Point(XPos, YPos)) then
Exit;
inherited;
end;
procedure TDBGridInplaceEdit.WMPaint(var Message: TWMPaint);
begin
PaintHandler(Message);
end;
procedure TDBGridInplaceEdit.WMSetCursor(var Message: TWMSetCursor);
var
P: TPoint;
begin
GetCursorPos(P);
P := ScreenToClient(P);
if (FEditStyle <> esSimple) and OverButton(P) then
Windows.SetCursor(LoadCursor(0, idc_Arrow))
else
inherited;
end;
procedure TDBGridInplaceEdit.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_KEYDOWN, WM_SYSKEYDOWN, WM_CHAR:
if EditStyle in [esPickList, esDataList] then
with TWMKey(Message) do
begin
DoDropDownKeys(CharCode, KeyDataToShiftState(KeyData));
if (CharCode <> 0) and FListVisible then
begin
with TMessage(Message) do
SendMessage(FActiveList.Handle, Msg, WParam, LParam);
Exit;
end;
end
end;
inherited;
end;
{ TGridDataLink }
type
TIntArray = array[0..MaxMapSize] of Integer;
PIntArray = ^TIntArray;
constructor TGridDataLink.Create(AGrid: TDCCustomDBGrid);
begin
inherited Create;
FGrid := AGrid;
VisualControl := True;
end;
destructor TGridDataLink.Destroy;
begin
ClearMapping;
inherited Destroy;
end;
function TGridDataLink.GetDefaultFields: Boolean;
var
I: Integer;
begin
Result := True;
if DataSet <> nil then Result := DataSet.DefaultFields;
if Result and SparseMap then
for I := 0 to FFieldCount-1 do
if FFieldMap[I] < 0 then
begin
Result := False;
Exit;
end;
end;
function TGridDataLink.GetFields(I: Integer): TField;
begin
if (0 <= I) and (I < FFieldCount) and (FFieldMap[I] >= 0) and (FFieldMap[I] < DataSet.FieldList.Count) then
Result := DataSet.FieldList[FFieldMap[I]]
else
Result := nil;
end;
function TGridDataLink.AddMapping(const FieldName: string): Boolean;
var
Field: TField;
NewSize: Integer;
begin
Result := True;
if FFieldCount >= MaxMapSize then RaiseGridError(STooManyColumns);
if SparseMap then
Field := DataSet.FindField(FieldName)
else
Field := DataSet.FieldByName(FieldName);
if FFieldCount = Length(FFieldMap) then
begin
NewSize := Length(FFieldMap);
if NewSize = 0 then
NewSize := 8
else
Inc(NewSize, NewSize);
if (NewSize < FFieldCount) then
NewSize := FFieldCount + 1;
if (NewSize > MaxMapSize) then
NewSize := MaxMapSize;
SetLength(FFieldMap, NewSize);
end;
if Assigned(Field) then
begin
FFieldMap[FFieldCount] := Dataset.FieldList.IndexOfObject(Field);
Field.FreeNotification(FGrid);
end
else
FFieldMap[FFieldCount] := -1;
Inc(FFieldCount);
end;
procedure TGridDataLink.ActiveChanged;
begin
FGrid.LinkActive(Active);
FModified := False;
end;
procedure TGridDataLink.ClearMapping;
begin
FFieldMap := nil;
FFieldCount := 0;
end;
procedure TGridDataLink.Modified;
begin
FModified := True;
end;
procedure TGridDataLink.DataSetChanged;
begin
FGrid.DataChanged;
FModified := False;
end;
procedure TGridDataLink.DataSetScrolled(Distance: Integer);
begin
FGrid.Scroll(Distance);
end;
procedure TGridDataLink.LayoutChanged;
var
SaveState: Boolean;
begin
{ FLayoutFromDataset determines whether default column width is forced to
be at least wide enough for the column title. }
SaveState := FGrid.FLayoutFromDataset;
FGrid.FLayoutFromDataset := True;
try
FGrid.LayoutChanged;
finally
FGrid.FLayoutFromDataset := SaveState;
end;
inherited LayoutChanged;
end;
procedure TGridDataLink.FocusControl(Field: TFieldRef);
begin
if Assigned(Field) and Assigned(Field^) then
begin
FGrid.SelectedField := Field^;
if (FGrid.SelectedField = Field^) and FGrid.AcquireFocus then
begin
Field^ := nil;
FGrid.ShowEditor;
end;
end;
end;
procedure TGridDataLink.EditingChanged;
begin
FGrid.EditingChanged;
end;
procedure TGridDataLink.RecordChanged(Field: TField);
begin
FGrid.RecordChanged(Field);
FModified := False;
end;
procedure TGridDataLink.UpdateData;
begin
FInUpdateData := True;
try
if FModified then FGrid.UpdateData;
FModified := False;
finally
FInUpdateData := False;
end;
end;
function TGridDataLink.GetMappedIndex(ColIndex: Integer): Integer;
begin
if (0 <= ColIndex) and (ColIndex < FFieldCount) then
Result := FFieldMap[ColIndex]
else
Result := -1;
end;
procedure TGridDataLink.Reset;
begin
if FModified then RecordChanged(nil) else Dataset.Cancel;
end;
function TGridDataLink.IsAggRow(Value: Integer): Boolean;
begin
Result := False;
end;
procedure TGridDataLink.BuildAggMap;
begin
end;
{ TColumnTitle }
constructor TColumnTitle.Create(Column: TColumn);
begin
inherited Create;
FColumn := Column;
FFont := TFont.Create;
FFont.Assign(DefaultFont);
FFont.OnChange := FontChanged;
end;
destructor TColumnTitle.Destroy;
begin
FFont.Free;
inherited Destroy;
end;
procedure TColumnTitle.Assign(Source: TPersistent);
begin
if Source is TColumnTitle then
begin
if cvTitleAlignment in TColumnTitle(Source).FColumn.FAssignedValues then
Alignment := TColumnTitle(Source).Alignment;
if cvTitleColor in TColumnTitle(Source).FColumn.FAssignedValues then
Color := TColumnTitle(Source).Color;
if cvTitleCaption in TColumnTitle(Source).FColumn.FAssignedValues then
Caption := TColumnTitle(Source).Caption;
if cvTitleFont in TColumnTitle(Source).FColumn.FAssignedValues then
Font := TColumnTitle(Source).Font;
end
else
inherited Assign(Source);
end;
function TColumnTitle.DefaultAlignment: TAlignment;
begin
Result := taLeftJustify;
end;
function TColumnTitle.DefaultColor: TColor;
var
Grid: TDCCustomDBGrid;
begin
Grid := FColumn.GetGrid;
if Assigned(Grid) then
Result := Grid.FixedColor
else
Result := clBtnFace;
end;
function TColumnTitle.DefaultFont: TFont;
var
Grid: TDCCustomDBGrid;
begin
Grid := FColumn.GetGrid;
if Assigned(Grid) then
Result := Grid.TitleFont
else
Result := FColumn.Font;
end;
function TColumnTitle.DefaultCaption: string;
var
Field: TField;
begin
Field := FColumn.Field;
if Assigned(Field) then
Result := Field.DisplayName
else
Result := FColumn.FieldName;
end;
procedure TColumnTitle.FontChanged(Sender: TObject);
begin
Include(FColumn.FAssignedValues, cvTitleFont);
FColumn.Changed(True);
end;
function TColumnTitle.GetAlignment: TAlignment;
begin
if cvTitleAlignment in FColumn.FAssignedValues then
Result := FAlignment
else
Result := DefaultAlignment;
end;
function TColumnTitle.GetColor: TColor;
begin
if cvTitleColor in FColumn.FAssignedValues then
Result := FColor
else
Result := DefaultColor;
end;
function TColumnTitle.GetCaption: string;
begin
if cvTitleCaption in FColumn.FAssignedValues then
Result := FCaption
else
Result := DefaultCaption;
end;
function TColumnTitle.GetFont: TFont;
var
Save: TNotifyEvent;
Def: TFont;
begin
if not (cvTitleFont in FColumn.FAssignedValues) then
begin
Def := DefaultFont;
if (FFont.Handle <> Def.Handle) or (FFont.Color <> Def.Color) then
begin
Save := FFont.OnChange;
FFont.OnChange := nil;
FFont.Assign(DefaultFont);
FFont.OnChange := Save;
end;
end;
Result := FFont;
end;
function TColumnTitle.IsAlignmentStored: Boolean;
begin
Result := (cvTitleAlignment in FColumn.FAssignedValues) and
(FAlignment <> DefaultAlignment);
end;
function TColumnTitle.IsColorStored: Boolean;
begin
Result := (cvTitleColor in FColumn.FAssignedValues) and
(FColor <> DefaultColor);
end;
function TColumnTitle.IsFontStored: Boolean;
begin
Result := (cvTitleFont in FColumn.FAssignedValues);
end;
function TColumnTitle.IsCaptionStored: Boolean;
begin
Result := (cvTitleCaption in FColumn.FAssignedValues) and
(FCaption <> DefaultCaption);
end;
procedure TColumnTitle.RefreshDefaultFont;
var
Save: TNotifyEvent;
begin
if (cvTitleFont in FColumn.FAssignedValues) then Exit;
Save := FFont.OnChange;
FFont.OnChange := nil;
try
FFont.Assign(DefaultFont);
finally
FFont.OnChange := Save;
end;
end;
procedure TColumnTitle.RestoreDefaults;
var
FontAssigned: Boolean;
begin
FontAssigned := cvTitleFont in FColumn.FAssignedValues;
FColumn.FAssignedValues := FColumn.FAssignedValues - ColumnTitleValues;
FCaption := '';
RefreshDefaultFont;
{ If font was assigned, changing it back to default may affect grid title
height, and title height changes require layout and redraw of the grid. }
FColumn.Changed(FontAssigned);
end;
procedure TColumnTitle.SetAlignment(Value: TAlignment);
begin
if (cvTitleAlignment in FColumn.FAssignedValues) and (Value = FAlignment) then Exit;
FAlignment := Value;
Include(FColumn.FAssignedValues, cvTitleAlignment);
FColumn.Changed(False);
end;
procedure TColumnTitle.SetColor(Value: TColor);
begin
if (cvTitleColor in FColumn.FAssignedValues) and (Value = FColor) then Exit;
FColor := Value;
Include(FColumn.FAssignedValues, cvTitleColor);
FColumn.Changed(False);
end;
procedure TColumnTitle.SetFont(Value: TFont);
begin
FFont.Assign(Value);
end;
procedure TColumnTitle.SetCaption(const Value: string);
var
Grid: TDCCustomDBGrid;
begin
Grid := Column.GetGrid;
if Column.IsStored then
begin
if (cvTitleCaption in FColumn.FAssignedValues) and (Value = FCaption) then Exit;
FCaption := Value;
Include(Column.FAssignedValues, cvTitleCaption);
Column.Changed(False);
end
else
begin
if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Column.Field) then
Column.Field.DisplayLabel := Value;
end;
if Assigned(Grid) and (Grid.LayoutLock = 0) then Grid.InternalLayout;
end;
{ TColumn }
constructor TColumn.Create(Collection: TCollection);
var
Grid: TDCCustomDBGrid;
begin
Grid := nil;
if Assigned(Collection) and (Collection is TDBGridColumns) then
Grid := TDBGridColumns(Collection).Grid;
if Assigned(Grid) then Grid.BeginLayout;
try
inherited Create(Collection);
FDropDownRows := 7;
FButtonStyle := cbsAuto;
FFont := TFont.Create;
FFont.Assign(DefaultFont);
FFont.OnChange := FontChanged;
FImeMode := imDontCare;
FImeName := Screen.DefaultIme;
FTitle := CreateTitle;
FVisible := True;
FExpanded := True;
FStored := True;
FItemIndex := -1;
FTag := 0;
FResize := True;
FComment := '';
FWordBreak := False;
finally
if Assigned(Grid) then Grid.EndLayout;
end;
end;
destructor TColumn.Destroy;
begin
FTitle.Free;
FFont.Free;
FPickList.Free;
inherited Destroy;
end;
procedure TColumn.Assign(Source: TPersistent);
begin
if Source is TColumn then
begin
if Assigned(Collection) then Collection.BeginUpdate;
try
RestoreDefaults;
FieldName := TColumn(Source).FieldName;
if cvColor in TColumn(Source).AssignedValues then
Color := TColumn(Source).Color;
if cvWidth in TColumn(Source).AssignedValues then
begin
FWidth := TColumn(Source).FWidth;
FAssignedValues := FAssignedValues + [cvWidth];
end;
if cvFont in TColumn(Source).AssignedValues then
Font := TColumn(Source).Font;
if cvImeMode in TColumn(Source).AssignedValues then
ImeMode := TColumn(Source).ImeMode;
if cvImeName in TColumn(Source).AssignedValues then
ImeName := TColumn(Source).ImeName;
if cvAlignment in TColumn(Source).AssignedValues then
Alignment := TColumn(Source).Alignment;
if cvReadOnly in TColumn(Source).AssignedValues then
ReadOnly := TColumn(Source).ReadOnly;
Title := TColumn(Source).Title;
DropDownRows := TColumn(Source).DropDownRows;
ButtonStyle := TColumn(Source).ButtonStyle;
PickList := TColumn(Source).PickList;
PopupMenu := TColumn(Source).PopupMenu;
FVisible := TColumn(Source).FVisible;
FExpanded := TColumn(Source).FExpanded;
FItemIndex := TColumn(Source).FItemIndex;
FIndexed := TColumn(Source).FIndexed;
FIndexStyle := TColumn(Source).FIndexStyle;
FDisplayFormat := TColumn(Source).FDisplayFormat;
FTag := TColumn(Source).FTag;
FResize := TColumn(Source).FResize;
FComment := TColumn(Source).FComment;
FWordBreak := TColumn(Source).FWordBreak;
finally
if Assigned(Collection) then Collection.EndUpdate;
end;
end
else
inherited Assign(Source);
end;
function TColumn.CreateTitle: TColumnTitle;
begin
Result := TColumnTitle.Create(Self);
end;
function TColumn.DefaultAlignment: TAlignment;
begin
if Assigned(Field) then
Result := FField.Alignment
else
Result := taLeftJustify;
end;
function TColumn.DefaultColor: TColor;
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
if Assigned(Grid) then
Result := Grid.Color
else
Result := clWindow;
end;
function TColumn.DefaultFont: TFont;
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
if Assigned(Grid) then
Result := Grid.Font
else
Result := FFont;
end;
function TColumn.DefaultImeMode: TImeMode;
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
if Assigned(Grid) then
Result := Grid.ImeMode
else
Result := FImeMode;
end;
function TColumn.DefaultImeName: TImeName;
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
if Assigned(Grid) then
Result := Grid.ImeName
else
Result := FImeName;
end;
function TColumn.DefaultReadOnly: Boolean;
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
Result := (Assigned(Grid) and Grid.ReadOnly) or
(Assigned(Field) and FField.ReadOnly);
end;
function TColumn.DefaultWidth: Integer;
var
W: Integer;
RestoreCanvas: Boolean;
TM: TTextMetric;
BitmapsOffset: Integer;
begin
if GetGrid = nil then
begin
Result := 64;
Exit;
end;
with GetGrid do
begin
if Assigned(Field) then
begin
RestoreCanvas := not HandleAllocated or not GetTextMetrics(Canvas.Handle, TM);
if RestoreCanvas then Canvas.Handle := GetDC(0);
try
Canvas.Font := Self.Font;
GetTextMetrics(Canvas.Handle, TM);
Result := Field.DisplayWidth * (Canvas.TextWidth('0') - TM.tmOverhang)
+ TM.tmOverhang + 4;
if dgTitles in Options then
begin
Canvas.Font := Title.Font;
if (Grid <> nil) and (dgTitleClicked in Grid.Options) and FIndexed
then BitmapsOffset := IndexTitleWidth else BitmapsOffset := 0;
if (Grid.Images <> nil) and (FItemIndex <> -1)
then Inc(BitmapsOffset,Grid.Images.Width+2);
W := GetTextWidthEx(Canvas, Title.Caption) +
4 + BitmapsOffset+ TM.tmOverhang + 4;
if Result < W then
Result := W;
end;
finally
if RestoreCanvas then
begin
ReleaseDC(0, Canvas.Handle);
Canvas.Handle := 0;
end;
end;
end
else
Result := DefaultColWidth;
end;
end;
procedure TColumn.FontChanged;
begin
Include(FAssignedValues, cvFont);
Title.RefreshDefaultFont;
Changed(False);
end;
function TColumn.GetAlignment: TAlignment;
begin
if cvAlignment in FAssignedValues then
Result := FAlignment
else
Result := DefaultAlignment;
end;
function TColumn.GetColor: TColor;
begin
if cvColor in FAssignedValues then
Result := FColor
else
Result := DefaultColor;
end;
function TColumn.GetExpanded: Boolean;
begin
Result := FExpanded and Expandable;
end;
function TColumn.GetField: TField;
var
Grid: TDCCustomDBGrid;
begin { Returns Nil if FieldName can't be found in dataset }
Grid := GetGrid;
if (FField = nil) and (Length(FFieldName) > 0) and Assigned(Grid) and
Assigned(Grid.DataLink.DataSet) then
with Grid.Datalink.Dataset do
if Active or (not DefaultFields) then
SetField(FindField(FieldName));
Result := FField;
end;
function TColumn.GetFont: TFont;
var
Save: TNotifyEvent;
begin
if not (cvFont in FAssignedValues) and (FFont.Handle <> DefaultFont.Handle) then
begin
Save := FFont.OnChange;
FFont.OnChange := nil;
FFont.Assign(DefaultFont);
FFont.OnChange := Save;
end;
Result := FFont;
end;
function TColumn.GetGrid: TDCCustomDBGrid;
begin
if Assigned(Collection) and (Collection is TDBGridColumns) then
Result := TDBGridColumns(Collection).Grid
else
Result := nil;
end;
function TColumn.GetDisplayName: string;
begin
Result := FFieldName;
if Result = '' then Result := inherited GetDisplayName;
end;
function TColumn.GetImeMode: TImeMode;
begin
if cvImeMode in FAssignedValues then
Result := FImeMode
else
Result := DefaultImeMode;
end;
function TColumn.GetImeName: TImeName;
begin
if cvImeName in FAssignedValues then
Result := FImeName
else
Result := DefaultImeName;
end;
function TColumn.GetParentColumn: TColumn;
var
Col: TColumn;
Fld: TField;
I: Integer;
begin
Result := nil;
Fld := Field;
if (Fld <> nil) and (Fld.ParentField <> nil) and (Collection <> nil) then
for I := Index - 1 downto 0 do
begin
Col := TColumn(Collection.Items[I]);
if Fld.ParentField = Col.Field then
begin
Result := Col;
Exit;
end;
end;
end;
function TColumn.GetPickList: TStrings;
begin
if FPickList = nil then
FPickList := TStringList.Create;
Result := FPickList;
end;
function TColumn.GetReadOnly: Boolean;
begin
if cvReadOnly in FAssignedValues then
Result := FReadOnly
else
Result := DefaultReadOnly;
end;
function TColumn.GetShowing: Boolean;
var
Col: TColumn;
begin
Result := not Expanded and Visible;
if Result then
begin
Col := Self;
repeat
Col := Col.ParentColumn;
until (Col = nil) or not Col.Expanded;
Result := Col = nil;
end;
end;
function TColumn.GetVisible: Boolean;
var
Col: TColumn;
begin
Result := FVisible;
if Result then
begin
Col := ParentColumn;
Result := Result and ((Col = nil) or Col.Visible);
end;
end;
function TColumn.GetWidth: Integer;
begin
if not( Showing or
((Grid <> nil) and (csWriting in Grid.ComponentState) )) then
begin
if (Grid <> nil) and not (dgColLines in Grid.Options) then
Result := 0
else
Result := -1
end
else if cvWidth in FAssignedValues then
Result := FWidth
else
Result := DefaultWidth;
end;
function TColumn.IsAlignmentStored: Boolean;
begin
Result := (cvAlignment in FAssignedValues) and (FAlignment <> DefaultAlignment);
end;
function TColumn.IsColorStored: Boolean;
begin
Result := (cvColor in FAssignedValues) and (FColor <> DefaultColor);
end;
function TColumn.IsFontStored: Boolean;
begin
Result := (cvFont in FAssignedValues);
end;
function TColumn.IsImeModeStored: Boolean;
begin
Result := (cvImeMode in FAssignedValues) and (FImeMode <> DefaultImeMode);
end;
function TColumn.IsImeNameStored: Boolean;
begin
Result := (cvImeName in FAssignedValues) and (FImeName <> DefaultImeName);
end;
function TColumn.IsReadOnlyStored: Boolean;
begin
Result := (cvReadOnly in FAssignedValues) and (FReadOnly <> DefaultReadOnly);
end;
function TColumn.IsWidthStored: Boolean;
begin
Result := (cvWidth in FAssignedValues) and (FWidth <> DefaultWidth);
end;
procedure TColumn.RefreshDefaultFont;
var
Save: TNotifyEvent;
begin
if cvFont in FAssignedValues then Exit;
Save := FFont.OnChange;
FFont.OnChange := nil;
try
FFont.Assign(DefaultFont);
finally
FFont.OnChange := Save;
end;
end;
procedure TColumn.RestoreDefaults;
var
FontAssigned: Boolean;
begin
FontAssigned := cvFont in FAssignedValues;
FTitle.RestoreDefaults;
FAssignedValues := [];
RefreshDefaultFont;
FPickList.Free;
FPickList := nil;
ButtonStyle := cbsAuto;
Changed(FontAssigned);
end;
procedure TColumn.SetAlignment(Value: TAlignment);
var
Grid: TDCCustomDBGrid;
begin
if IsStored then
begin
if (cvAlignment in FAssignedValues) and (Value = FAlignment) then Exit;
FAlignment := Value;
Include(FAssignedValues, cvAlignment);
Changed(False);
end
else
begin
Grid := GetGrid;
if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Field) then
Field.Alignment := Value;
end;
end;
procedure TColumn.SetButtonStyle(Value: TColumnButtonStyle);
begin
if Value = FButtonStyle then Exit;
FButtonStyle := Value;
Changed(False);
end;
procedure TColumn.SetColor(Value: TColor);
begin
if (cvColor in FAssignedValues) and (Value = FColor) then Exit;
FColor := Value;
Include(FAssignedValues, cvColor);
Changed(False);
end;
procedure TColumn.SetField(Value: TField);
begin
if FField = Value then Exit;
FField := Value;
if Assigned(Value) then
FFieldName := Value.FullName;
if not IsStored then
begin
if Value = nil then
FFieldName := '';
RestoreDefaults;
end;
Changed(False);
end;
procedure TColumn.SetFieldName(const Value: String);
var
AField: TField;
Grid: TDCCustomDBGrid;
begin
AField := nil;
Grid := GetGrid;
if Assigned(Grid) and Assigned(Grid.DataLink.DataSet) and
not (csLoading in Grid.ComponentState) and (Length(Value) > 0) then
AField := Grid.DataLink.DataSet.FindField(Value); { no exceptions }
FFieldName := Value;
SetField(AField);
Changed(False);
end;
procedure TColumn.SetFont(Value: TFont);
begin
FFont.Assign(Value);
Include(FAssignedValues, cvFont);
Changed(False);
end;
procedure TColumn.SetImeMode(Value: TImeMode);
begin
if (cvImeMode in FAssignedValues) or (Value <> DefaultImeMode) then
begin
FImeMode := Value;
Include(FAssignedValues, cvImeMode);
end;
Changed(False);
end;
procedure TColumn.SetImeName(Value: TImeName);
begin
if (cvImeName in FAssignedValues) or (Value <> DefaultImeName) then
begin
FImeName := Value;
Include(FAssignedValues, cvImeName);
end;
Changed(False);
end;
procedure TColumn.SetIndex(Value: Integer);
var
Grid: TDCCustomDBGrid;
Fld: TField;
I, OldIndex: Integer;
Col: TColumn;
begin
OldIndex := Index;
Grid := GetGrid;
if IsStored then
begin
Grid.BeginLayout;
try
I := OldIndex + 1; // move child columns along with parent
while (I < Collection.Count) and (TColumn(Collection.Items[I]).ParentColumn = Self) do
Inc(I);
Dec(I);
if OldIndex > Value then // column moving left
begin
while I > OldIndex do
begin
Collection.Items[I].Index := Value;
Inc(OldIndex);
end;
inherited SetIndex(Value);
end
else
begin
inherited SetIndex(Value);
while I > OldIndex do
begin
Collection.Items[OldIndex].Index := Value;
Dec(I);
end;
end;
finally
Grid.EndLayout;
end;
end
else
begin
if (Grid <> nil) and Grid.Datalink.Active then
begin
if Grid.AcquireLayoutLock then
try
Col := Grid.ColumnAtDepth(Grid.Columns[Value], Depth);
if (Col <> nil) then
begin
Fld := Col.Field;
if Assigned(Fld) then
Field.Index := Fld.Index;
end;
finally
Grid.EndLayout;
end;
end;
inherited SetIndex(Value);
end;
end;
procedure TColumn.SetPickList(Value: TStrings);
begin
if Value = nil then
begin
FPickList.Free;
FPickList := nil;
Exit;
end;
PickList.Assign(Value);
end;
procedure TColumn.SetPopupMenu(Value: TPopupMenu);
begin
FPopupMenu := Value;
if Value <> nil then Value.FreeNotification(GetGrid);
end;
procedure TColumn.SetReadOnly(Value: Boolean);
var
Grid: TDCCustomDBGrid;
begin
Grid := GetGrid;
if not IsStored and Assigned(Grid) and Grid.Datalink.Active and Assigned(Field) then
Field.ReadOnly := Value
else
begin
if (cvReadOnly in FAssignedValues) and (Value = FReadOnly) then Exit;
FReadOnly := Value;
Include(FAssignedValues, cvReadOnly);
Changed(False);
end;
end;
procedure TColumn.SetTitle(Value: TColumnTitle);
begin
FTitle.Assign(Value);
end;
procedure TColumn.SetWidth(Value: Integer);
var
Grid: TDCCustomDBGrid;
TM: TTextMetric;
DoSetWidth: Boolean;
begin
DoSetWidth := IsStored;
if not DoSetWidth then
begin
Grid := GetGrid;
if Assigned(Grid) then
begin
if Grid.HandleAllocated and Assigned(Field) and Grid.FUpdateFields then
with Grid do
begin
Canvas.Font := Self.Font;
GetTextMetrics(Canvas.Handle, TM);
Field.DisplayWidth := (Value + (TM.tmAveCharWidth div 2) - TM.tmOverhang - 3)
div TM.tmAveCharWidth;
end;
if (not Grid.FLayoutFromDataset) or (cvWidth in FAssignedValues) then
DoSetWidth := True;
end
else
DoSetWidth := True;
end;
if DoSetWidth then
begin
if ((cvWidth in FAssignedValues) or (Value <> DefaultWidth))
and (Value <> -1) and (Value <> 0) then
begin
FWidth := Value;
Include(FAssignedValues, cvWidth);
end;
Changed(False);
end;
end;
procedure TColumn.SetVisible(Value: Boolean);
begin
if Value <> FVisible then
begin
FVisible := Value;
Width := Width;
// Changed(True);
end;
end;
procedure TColumn.SetExpanded(Value: Boolean);
const
Direction: array [Boolean] of ShortInt = (-1,1);
var
Grid: TDCCustomDBGrid;
WasShowing: Boolean;
begin
if Value <> FExpanded then
begin
Grid := GetGrid;
WasShowing := (Grid <> nil) and Grid.Columns[Grid.SelectedIndex].Showing;
FExpanded := Value;
Changed(True);
if (Grid <> nil) and WasShowing then
begin
if not Grid.Columns[Grid.SelectedIndex].Showing then
// The selected cell was hidden by this expand operation
// Select 1st child (next col = 1) when parent is expanded
// Select child's parent (prev col = -1) when parent is collapsed
Grid.MoveCol(Grid.Col, Direction[FExpanded]);
end;
end;
end;
function TColumn.Depth: Integer;
var
Col: TColumn;
begin
Result := 0;
Col := ParentColumn;
if Col <> nil then Result := Col.Depth + 1;
end;
function TColumn.GetExpandable: Boolean;
var
Fld: TField;
begin
Fld := Field;
Result := (Fld <> nil) and (Fld.DataType in [ftADT, ftArray]);
end;
procedure TColumn.SetIndexed(Value: Boolean);
begin
if Value = FIndexed then Exit;
FIndexed := Value;
Changed(False);
end;
procedure TColumn.SetItemIndex(Value: Integer);
begin
if Value <> FItemIndex then
begin
FItemIndex := Value;
Changed(False);
end;
end;
procedure TColumn.SetIndexStyle(const Value: TColumnIndexStyle);
begin
if Value <> FIndexStyle then
begin
FIndexStyle := Value;
Changed(False);
end;
end;
procedure TColumn.SetDisplayFormat(const Value: string);
begin
if Value <> FDisplayFormat then
begin
FDisplayFormat := Value;
Changed(False);
end;
end;
procedure TColumn.SetComment(const Value: string);
begin
FComment := Value;
end;
procedure TColumn.SetWordBreak(const Value: boolean);
begin
if Value <> FWordBreak then
begin
FWordBreak := Value;
Changed(False);
end;
end;
{ TDBGridColumns }
constructor TDBGridColumns.Create(Grid: TDCCustomDBGrid; ColumnClass: TColumnClass);
begin
inherited Create(ColumnClass);
FGrid := Grid;
end;
function TDBGridColumns.Add: TColumn;
begin
Result := TColumn(inherited Add);
end;
function TDBGridColumns.GetColumn(Index: Integer): TColumn;
begin
Result := TColumn(inherited Items[Index]);
end;
function TDBGridColumns.GetOwner: TPersistent;
begin
Result := FGrid;
end;
procedure TDBGridColumns.LoadFromFile(const Filename: string);
var
S: TFileStream;
begin
S := TFileStream.Create(Filename, fmOpenRead);
try
LoadFromStream(S);
finally
S.Free;
end;
end;
type
TColumnsWrapper = class(TComponent)
private
FColumns: TDBGridColumns;
published
property Columns: TDBGridColumns read FColumns write FColumns;
end;
procedure TDBGridColumns.LoadFromStream(S: TStream);
var
Wrapper: TColumnsWrapper;
begin
Wrapper := TColumnsWrapper.Create(nil);
try
Wrapper.Columns := FGrid.CreateColumns;
S.ReadComponent(Wrapper);
Assign(Wrapper.Columns);
finally
Wrapper.Columns.Free;
Wrapper.Free;
end;
end;
procedure TDBGridColumns.RestoreDefaults;
var
I: Integer;
begin
BeginUpdate;
try
for I := 0 to Count-1 do
Items[I].RestoreDefaults;
finally
EndUpdate;
end;
end;
procedure TDBGridColumns.RebuildColumns;
procedure AddFields(Fields: TFields; Depth: Integer);
var
I: Integer;
begin
Inc(Depth);
for I := 0 to Fields.Count-1 do
begin
Add.FieldName := Fields[I].FullName;
if Fields[I].DataType in [ftADT, ftArray] then
AddFields((Fields[I] as TObjectField).Fields, Depth);
end;
end;
begin
if Assigned(FGrid) and Assigned(FGrid.DataSource) and
Assigned(FGrid.Datasource.Dataset) then
begin
FGrid.BeginLayout;
try
Clear;
AddFields(FGrid.Datasource.Dataset.Fields, 0);
finally
FGrid.EndLayout;
end
end
else
Clear;
end;
procedure TDBGridColumns.SaveToFile(const Filename: string);
var
S: TStream;
begin
S := TFileStream.Create(Filename, fmCreate);
try
SaveToStream(S);
finally
S.Free;
end;
end;
procedure TDBGridColumns.SaveToStream(S: TStream);
var
Wrapper: TColumnsWrapper;
begin
Wrapper := TColumnsWrapper.Create(nil);
try
Wrapper.Columns := Self;
S.WriteComponent(Wrapper);
finally
Wrapper.Free;
end;
end;
procedure TDBGridColumns.SetColumn(Index: Integer; Value: TColumn);
begin
Items[Index].Assign(Value);
end;
procedure TDBGridColumns.SetState(NewState: TDBGridColumnsState);
begin
if NewState = State then Exit;
if NewState = csDefault then
Clear
else
RebuildColumns;
end;
procedure TDBGridColumns.Update(Item: TCollectionItem);
var
Raw: Integer;
begin
if (Grid = nil) or (csLoading in Grid.ComponentState) then Exit;
if Item = nil then
begin
Grid.LayoutChanged;
Grid.UpdateColWidths(-1, True)
end
else begin
Raw := FGrid.DataToRawColumn(Item.Index);
Grid.InvalidateCol(Raw);
if TColumn(Item).Resize then
Grid.FSizingIndex := Raw
else
Grid.FSizingIndex := -1;
Grid.ColWidths[Raw] := TColumn(Item).Width;
end;
end;
function TDBGridColumns.InternalAdd: TColumn;
begin
Result := Add;
Result.IsStored := False;
end;
function TDBGridColumns.GetState: TDBGridColumnsState;
begin
Result := TDBGridColumnsState((Count > 0) and Items[0].IsStored);
end;
{ TBookmarkList }
constructor TBookmarkList.Create(AGrid: TDCCustomDBGrid);
begin
inherited Create;
FList := TStringList.Create;
FList.OnChange := StringsChanged;
FGrid := AGrid;
end;
destructor TBookmarkList.Destroy;
begin
Clear;
FList.Free;
inherited Destroy;
end;
procedure TBookmarkList.Clear;
begin
if FList.Count = 0 then Exit;
FList.Clear;
FGrid.FSelecting := False;
FGrid.Invalidate;
end;
function TBookmarkList.Compare(const Item1, Item2: TBookmarkStr): Integer;
begin
with FGrid.Datalink.Datasource.Dataset do
Result := CompareBookmarks(TBookmark(Item1), TBookmark(Item2));
end;
function TBookmarkList.CurrentRow: TBookmarkStr;
begin
if not FLinkActive then RaiseGridError(sDataSetClosed);
Result := FGrid.Datalink.Datasource.Dataset.Bookmark;
end;
function TBookmarkList.GetCurrentRowSelected: Boolean;
var
Index: Integer;
begin
Result := Find(CurrentRow, Index);
end;
function TBookmarkList.Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
var
L, H, I, C: Integer;
begin
if (Item = FCache) and (FCacheIndex >= 0) then
begin
Index := FCacheIndex;
Result := FCacheFind;
Exit;
end;
Result := False;
L := 0;
H := FList.Count - 1;
{
while L <= H do
begin
I := (L + H) shr 1;
C := Compare(FList[I], Item);
if C < 0 then L := I + 1 else
begin
H := I - 1;
if C = 0 then
begin
Result := True;
L := I;
end;
end;
end;
}
for I := 0 to H do
begin
C := Compare(FList[I], Item);
if C = 0 then
begin
Result := True;
L := I;
Break;
end;
end;
Index := L;
FCache := Item;
FCacheIndex := Index;
FCacheFind := Result;
end;
function TBookmarkList.GetCount: Integer;
begin
Result := FList.Count;
end;
function TBookmarkList.GetItem(Index: Integer): TBookmarkStr;
begin
Result := FList[Index];
end;
function TBookmarkList.IndexOf(const Item: TBookmarkStr): Integer;
begin
if not Find(Item, Result) then
Result := -1;
end;
procedure TBookmarkList.LinkActive(Value: Boolean);
begin
Clear;
FLinkActive := Value;
end;
procedure TBookmarkList.Delete;
var
I: Integer;
begin
with FGrid.Datalink.Datasource.Dataset do
begin
DisableControls;
try
for I := FList.Count-1 downto 0 do
begin
Bookmark := FList[I];
Delete;
FList.Delete(I);
end;
finally
EnableControls;
end;
end;
end;
function TBookmarkList.Refresh: Boolean;
var
I: Integer;
Valid: boolean;
begin
Result := False;
if FGrid.DataLink.Dataset = nil then Exit;
with FGrid.DataLink.Dataset do
try
CheckBrowseMode;
for I := FList.Count - 1 downto 0 do
begin
try
Valid := BookmarkValid(TBookmark(FList[I]));
except
Valid := False;
end;
if not Valid then
begin
Result := True;
FList.Delete(I);
end;
end;
finally
UpdateCursorPos;
if Result then FGrid.Invalidate;
end;
end;
procedure TBookmarkList.SetCurrentRowSelected(Value: Boolean);
var
Index: Integer;
Current: TBookmarkStr;
begin
Current := CurrentRow;
if (Length(Current) = 0) or (Find(Current, Index) = Value) then Exit;
if Value then
begin
FList.Insert(Index, Current);
end
else
FList.Delete(Index);
with FGrid.Datalink do
if (DataSet <> nil) and DataSet.ControlsDisabled then Exit;
FGrid.InvalidateRow(FGrid.Row);
end;
procedure TBookmarkList.StringsChanged(Sender: TObject);
begin
FCache := '';
FCacheIndex := -1;
end;
procedure TBookmarkList.Load(List: TStringList);
begin
FList.Assign(List);
InvalidateRect(FGrid.Handle, nil, False);
end;
procedure TBookmarkList.Save(List: TStringList);
var
I: Integer;
begin
List.BeginUpdate;
try
List.Clear;
for I := 0 to FList.Count - 1 do
List.Add(FList.Strings[I])
finally
List.EndUpdate;
end;
end;
procedure TBookmarkList.SelectAll;
var
AList: TStringList;
begin
if FGrid.DataLink.DataSet <> nil then with FGrid.DataLink.DataSet do
begin
FGrid.SavePosition;
AList := TStringList.Create;
DisableControls;
try
First;
while not Eof do
begin
AList.Add(CurrentRow);
Next;
end;
Load(AList);
finally
AList.Free;
FGrid.RestPosition;
EnableControls;
end;
end;
end;
{ TDCCustomDBGrid }
procedure UsesBitmap;
begin
if UserCount = 0 then
begin
DrawBitmap := TBitmap.Create;
TempBitmap := TBitmap.Create;
end;
Inc(UserCount);
end;
procedure ReleaseBitmap;
begin
Dec(UserCount);
if UserCount = 0 then
begin
DrawBitmap.Free;
TempBitmap.Free;
end;
end;
procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
const Text: string; Alignment: TAlignment; ARightToLeft: Boolean; AWordBreak: boolean);
const
AlignFlags : array [TAlignment] of Integer =
( DT_LEFT or DT_EXPANDTABS or DT_NOPREFIX,
DT_RIGHT or DT_EXPANDTABS or DT_NOPREFIX,
DT_CENTER or DT_EXPANDTABS or DT_NOPREFIX );
RTL: array [Boolean] of Integer = (0, DT_RTLREADING);
var
B, R: TRect;
Hold, Left: Integer;
I: TColorRef;
begin
I := ColorToRGB(ACanvas.Brush.Color);
if (GetNearestColor(ACanvas.Handle, I) = I) and not AWordBreak then
begin { Use ExtTextOut for solid colors }
{ In BiDi, because we changed the window origin, the text that does not
change alignment, actually gets its alignment changed. }
if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then
ChangeBiDiModeAlignment(Alignment);
case Alignment of
taLeftJustify:
Left := ARect.Left + DX;
taRightJustify:
Left := ARect.Right - ACanvas.TextWidth(Text) - 3;
else { taCenter }
Left := ARect.Left + (ARect.Right - ARect.Left) shr 1
- (ACanvas.TextWidth(Text) shr 1);
end;
ACanvas.TextRect(ARect, Left, ARect.Top + DY, Text);
end
else
begin { Use FillRect and Drawtext for dithered colors }
DrawBitmap.Canvas.Lock;
try
with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
begin { brush origin tics in painting / scrolling. }
Width := _intMax(Width, Right - Left);
Height := _intMax(Height, Bottom - Top);
R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
B := Rect(0, 0, Right - Left, Bottom - Top);
end;
with DrawBitmap.Canvas do
begin
Font := ACanvas.Font;
Font.Color := ACanvas.Font.Color;
Brush := ACanvas.Brush;
Brush.Style := bsSolid;
FillRect(B);
SetBkMode(Handle, TRANSPARENT);
if (ACanvas.CanvasOrientation = coRightToLeft) then
ChangeBiDiModeAlignment(Alignment);
if AWordBreak then
DrawText(Handle, PChar(Text), Length(Text), R,
AlignFlags[Alignment] or RTL[ARightToLeft] or DT_WORDBREAK)
else
DrawText(Handle, PChar(Text), Length(Text), R,
AlignFlags[Alignment] or RTL[ARightToLeft])
end;
if (ACanvas.CanvasOrientation = coRightToLeft) then
begin
Hold := ARect.Left;
ARect.Left := ARect.Right;
ARect.Right := Hold;
end;
ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
finally
DrawBitmap.Canvas.Unlock;
end;
end;
end;
constructor TDCCustomDBGrid.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
inherited DefaultDrawing := False;
FAcquireFocus := True;
FTitleOffset := 1;
FIndicatorOffset := 1;
FUpdateFields := True;
FOptions := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
FOptionsEx := [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText
{$IFNDEF DELPHI_V5UP}, dgeInsertSelect {$ENDIF}];
if SysLocale.PriLangID = LANG_KOREAN then Include(FOptions, dgAlwaysShowEditor);
DesignOptionsBoost := [goColSizing];
VirtualView := True;
UsesBitmap;
ScrollBars := ssHorizontal;
inherited Options := [goFixedHorzLine, goFixedVertLine, goHorzLine,
goVertLine, goColSizing, goColMoving, goTabs, goEditing];
FColumns := CreateColumns;
FVisibleColumns := TList.Create;
inherited RowCount := 2;
inherited ColCount := 2;
FDataLink := TGridDataLink.Create(Self);
Color := clWindow;
ParentColor := False;
FTitleFont := TFont.Create;
FTitleFont.OnChange := TitleFontChanged;
FSaveCellExtents := False;
FUserChange := True;
FDefaultDrawing := True;
FBookmarks := TBookmarkList.Create(Self);
ClickedCol := -1;
FCurrentCol := -1;
FMousePoint := Point(-1,-1);
FFrozenCols := 0;
FClipDown := False;
FFirstGridCell := 0;
FDBObject := TDCDBObject.Create;
FImageChangeLink := TChangeLink.Create;
FImageChangeLink.OnChange := ImageListChange;
HideEditor;
FDataVisible := True;
FColumnCell := -1;
FSizingIndex := -1;
end;
destructor TDCCustomDBGrid.Destroy;
begin
if Assigned(FClipPopup) then
TDBClipPopup(FClipPopup).Free;
if Assigned(FCurrentPos[1].Bookmark) then FreeMem(FCurrentPos[1].Bookmark);
if Assigned(FCurrentPos[2].Bookmark) then FreeMem(FCurrentPos[2].Bookmark);
FImageChangeLink.Free;
FColumns.Free;
FColumns := nil;
FVisibleColumns.Free;
FVisibleColumns := nil;
FDataLink.Free;
FDataLink := nil;
FTitleFont.Free;
FTitleFont := nil;
FBookmarks.Free;
FBookmarks := nil;
ReleaseBitmap;
FDBObject.Free;
FDBObject := nil;
inherited Destroy;
end;
function TDCCustomDBGrid.AcquireFocus: Boolean;
begin
Result := True;
if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
begin
SetFocus;
Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
end;
end;
function TDCCustomDBGrid.RawToDataColumn(ACol: Integer): Integer;
begin
Result := ACol - FIndicatorOffset;
end;
function TDCCustomDBGrid.DataToRawColumn(ACol: Integer): Integer;
begin
Result := ACol + FIndicatorOffset;
end;
function TDCCustomDBGrid.AcquireLayoutLock: Boolean;
begin
Result := (FUpdateLock = 0) and (FLayoutLock = 0);
if Result then BeginLayout;
end;
procedure TDCCustomDBGrid.BeginLayout;
begin
BeginUpdate;
if (FLayoutLock = 0) and Assigned(Columns) then Columns.BeginUpdate;
Inc(FLayoutLock);
end;
procedure TDCCustomDBGrid.BeginUpdate;
begin
Inc(FUpdateLock);
end;
procedure TDCCustomDBGrid.CancelLayout;
begin
if FLayoutLock > 0 then
begin
if FLayoutLock = 1 then
Columns.EndUpdate;
Dec(FLayoutLock);
EndUpdate;
end;
end;
function TDCCustomDBGrid.CanEditAcceptKey(Key: Char): Boolean;
begin
with Columns[SelectedIndex] do
Result := FDatalink.Active and Assigned(Field) and Field.IsValidChar(Key);
end;
function TDCCustomDBGrid.CanEditModify: Boolean;
begin
Result := False;
if not ReadOnly and FDatalink.Active and not FDatalink.Readonly then
with Columns[SelectedIndex] do
if not ReadOnly and Assigned(Field) and Field.CanModify
and (not (Field.DataType in ftNonTextTypes) or Assigned(Field.OnSetText)) then
begin
FDatalink.Edit;
Result := FDatalink.Editing;
if Result then FDatalink.Modified;
end;
end;
function TDCCustomDBGrid.CanEditShow: Boolean;
begin
Result := (LayoutLock = 0) and inherited CanEditShow;
end;
procedure TDCCustomDBGrid.CellClick(Column: TColumn);
begin
if Assigned(FOnCellClick) then FOnCellClick(Column);
end;
procedure TDCCustomDBGrid.ColEnter;
begin
UpdateIme;
if Assigned(FOnColEnter) then FOnColEnter(Self);
end;
procedure TDCCustomDBGrid.ColExit;
begin
if Assigned(FOnColExit) then FOnColExit(Self);
end;
procedure TDCCustomDBGrid.ColumnMoved(FromIndex, ToIndex: Longint);
begin
inherited;
FromIndex := RawToDataColumn(FromIndex);
ToIndex := RawToDataColumn(ToIndex);
Columns[FromIndex].Index := ToIndex;
if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, FromIndex, ToIndex);
end;
procedure TDCCustomDBGrid.ColWidthsChanged;
var
I: Integer;
begin
if not UpdateLocked and (FDatalink.Active or (FColumns.State = csCustomized)) and
AcquireLayoutLock then
try
inherited ColWidthsChanged;
for I := FIndicatorOffset to ColCount - 1 do
FColumns[I - FIndicatorOffset].Width := ColWidths[I];
finally
EndLayout;
end;
end;
function TDCCustomDBGrid.CreateColumns: TDBGridColumns;
begin
Result := TDBGridColumns.Create(Self, TColumn);
end;
function TDCCustomDBGrid.CreateEditor: TInplaceEdit;
begin
Result := TDBGridInplaceEdit.Create(Self);
end;
procedure TDCCustomDBGrid.CreateWnd;
begin
BeginUpdate; { prevent updates in WMSize message that follows WMCreate }
try
inherited CreateWnd;
finally
EndUpdate;
end;
UpdateRowCount;
UpdateActive;
UpdateScrollBar;
FOriginalImeName := ImeName;
FOriginalImeMode := ImeMode;
FClipPopup := TDBClipPopup.Create(Self);
end;
procedure TDCCustomDBGrid.DataChanged;
begin
if not HandleAllocated then Exit;
SelectedRows.StringsChanged(nil);
UpdateRowCount;
UpdateScrollBar;
UpdateActive;
invalidate;
end;
procedure TDCCustomDBGrid.DefaultHandler(var Msg);
var
P: TPopupMenu;
Cell: TGridCoord;
begin
inherited DefaultHandler(Msg);
if TMessage(Msg).Msg = wm_RButtonUp then
with TWMRButtonUp(Msg) do
begin
Cell := MouseCoord(XPos, YPos);
if (Cell.X < FIndicatorOffset) or (Cell.Y < 0) then Exit;
P := Columns[RawToDataColumn(Cell.X)].PopupMenu;
if (P <> nil) and P.AutoPopup then
begin
SendCancelMode(nil);
P.PopupComponent := Self;
with ClientToScreen(SmallPointToPoint(Pos)) do
P.Popup(X, Y);
Result := 1;
end;
end;
end;
procedure TDCCustomDBGrid.DeferLayout;
var
M: TMsg;
begin
if HandleAllocated and
not PeekMessage(M, Handle, CM_DEFERLAYOUT, CM_DEFERLAYOUT, pm_NoRemove) then
PostMessage(Handle, CM_DEFERLAYOUT, 0, 0);
CancelLayout;
end;
procedure TDCCustomDBGrid.DefineFieldMap;
var
I: Integer;
begin
if FColumns.State = csCustomized then
begin { Build the column/field map from the column attributes }
DataLink.SparseMap := True;
for I := 0 to FColumns.Count-1 do
FDataLink.AddMapping(FColumns[I].FieldName);
end
else { Build the column/field map from the field list order }
begin
FDataLink.SparseMap := False;
with Datalink.Dataset do
for I := 0 to FieldList.Count - 1 do
with FieldList[I] do if Visible then Datalink.AddMapping(FullName);
end;
end;
function TDCCustomDBGrid.UseRightToLeftAlignmentForField(const AField: TField;
Alignment: TAlignment): Boolean;
begin
Result := False;
if IsRightToLeft then
Result := OkToChangeFieldAlignment(AField, Alignment);
end;
procedure TDCCustomDBGrid.DefaultDrawDataCell(const Rect: TRect; Field: TField;
State: TGridDrawState);
var
Alignment: TAlignment;
Value: string;
AWordBreak: boolean;
begin
Alignment := taLeftJustify;
Value := '';
AWordBreak := False;
if Assigned(Field) then
begin
Alignment := Field.Alignment;
if Assigned(FDrawColumn) then
begin
Value := GetDataValue(FDrawColumn);
AWordBreak := FDrawColumn.WordBreak;
end
else
Value := Field.DisplayText;
end;
WriteText(Canvas, Rect, 2, 2, Value, Alignment,
UseRightToLeftAlignmentForField(Field, Alignment), AWordBreak);
end;
procedure TDCCustomDBGrid.DefaultDrawColumnCell(const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
Value: string;
begin
Value := GetDataValue(Column);
with Column do
WriteText(Canvas, Rect, 2, 2, Value, Alignment,
UseRightToLeftAlignmentForField(Field, Alignment), WordBreak);
end;
procedure TDCCustomDBGrid.ReadColumns(Reader: TReader);
begin
Columns.Clear;
Reader.ReadValue;
Reader.ReadCollection(Columns);
end;
procedure TDCCustomDBGrid.WriteColumns(Writer: TWriter);
begin
Writer.WriteCollection(Columns);
end;
procedure TDCCustomDBGrid.DefineProperties(Filer: TFiler);
begin
Filer.DefineProperty('Columns', ReadColumns, WriteColumns,
((Columns.State = csCustomized) and (Filer.Ancestor = nil)) or
((Filer.Ancestor <> nil) and
((Columns.State <> TDCCustomDBGrid(Filer.Ancestor).Columns.State) or
{$IFDEF DELPHI_V6}
(not CollectionsEqual(Columns, TDCCustomDBGrid(Filer.Ancestor).Columns,
Self, TDCCustomDBGrid(Filer.Ancestor)))
{$ELSE}
(not CollectionsEqual(Columns, TDCCustomDBGrid(Filer.Ancestor).Columns))
{$ENDIF}
)));
end;
function TDCCustomDBGrid.ColumnAtDepth(Col: TColumn; ADepth: Integer): TColumn;
begin
Result := Col;
while (Result <> nil) and (Result.Depth > ADepth) do
Result := Result.ParentColumn;
end;
function TDCCustomDBGrid.CalcTitleRect(Col: TColumn; ARow: Integer;
var MasterCol: TColumn): TRect;
var
I,J: Integer;
InBiDiMode: Boolean;
DrawInfo: TGridDrawInfo;
begin
MasterCol := ColumnAtDepth(Col, ARow);
if MasterCol = nil then Exit;
I := DataToRawColumn(MasterCol.Index);
if (I >= LeftCol) or (I < FixedCols) then
J := MasterCol.Depth
else
begin
I := LeftCol;
if Col.Depth > ARow then
J := ARow
else
J := Col.Depth;
end;
Result := CellRect(I, J);
InBiDiMode := UseRightToLeftAlignment and
(Canvas.CanvasOrientation = coLeftToRight);
for I := Col.Index to Columns.Count-1 do
begin
if ColumnAtDepth(Columns[I], ARow) <> MasterCol then Break;
if not InBiDiMode then
begin
J := CellRect(DataToRawColumn(I), ARow).Right;
if J = 0 then Break;
Result.Right := _intMax(Result.Right, J);
end
else
begin
J := CellRect(DataToRawColumn(I), ARow).Left;
if J >= ClientWidth then Break;
Result.Left := J;
end;
end;
J := Col.Depth;
if (J <= ARow) and (J < FixedRows-1) then
begin
CalcFixedInfo(DrawInfo);
Result.Bottom := DrawInfo.Vert.FixedBoundary - DrawInfo.Vert.EffectiveLineWidth;
end;
end;
function TDCCustomDBGrid.DrawTitleCell(ACanvas: TCanvas; ACol,
ARow: Integer; ARect: TRect; BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint;
const
ScrollArrows: array [Boolean, Boolean] of Integer =
((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT));
ColumnIndexStyle : array [TColumnIndexStyle] of Integer =
(nbmIndexNone,nbmIndexAsc,nbmIndexDesc);
AlignFlags : array [TAlignment] of Integer =
( DT_LEFT or DT_NOPREFIX,
DT_RIGHT or DT_NOPREFIX,
DT_CENTER or DT_NOPREFIX );
var
Column, MasterCol: TColumn;
TextRect, ButtonRect, DrawRect: TRect;
I: Integer;
InBiDiMode: Boolean;
function DoPaint(Canvas: TCanvas; DrawRect: TRect): TPoint;
var
P: TPoint;
begin
TextRect := DrawRect;
Canvas.Font := MasterCol.Title.Font;
Canvas.Font.Color := ColorToRGB(MasterCol.Title.Font.Color);
Canvas.Brush.Color := MasterCol.Title.Color;
I := GetSystemMetrics(SM_CXHSCROLL);
if ((DrawRect.Right - DrawRect.Left) > I) and MasterCol.Expandable and ADraw then
begin
Dec(TextRect.Right, I);
ButtonRect := DrawRect;
ButtonRect.Left := TextRect.Right;
I := SaveDC(Canvas.Handle);
try
if AFillRect then Canvas.FillRect(ButtonRect);
InflateRect(ButtonRect, -1, -1);
IntersectClipRect(Canvas.Handle, ButtonRect.Left,
ButtonRect.Top, ButtonRect.Right, ButtonRect.Bottom);
InflateRect(ButtonRect, 1, 1);
{ DrawFrameControl doesn't draw properly when orienatation has changed.
It draws as ExtTextOut does. }
InBiDiMode := Canvas.CanvasOrientation = coRightToLeft;
if InBiDiMode then { stretch the arrows box }
Inc(ButtonRect.Right, GetSystemMetrics(SM_CXHSCROLL) + 4);
DrawFrameControl(Canvas.Handle, ButtonRect, DFC_SCROLL,
ScrollArrows[InBiDiMode, MasterCol.Expanded] or DFCS_FLAT);
finally
RestoreDC(Canvas.Handle, I);
end;
end;
if AFillRect then FillRect(Canvas.Handle, TextRect, Canvas.Brush.Handle);
if BorderState = dsDown then
begin
TextRect.Left := TextRect.Left + 3;
TextRect.Top := TextRect.Top + 1;
end
else
TextRect.Left := TextRect.Left + 2;
if (MasterCol.Grid.Images <> nil) and (MasterCol.ItemIndex <> -1) and
((TextRect.Right - TextRect.Left) > 0)
then begin
Column.Grid.Images.Draw(Canvas, TextRect.Left, TextRect.Top, Column.ItemIndex);
TextRect.Left := TextRect.Left + Column.Grid.Images.Width+2;
end;
if TextRect.Left < TextRect.Right then
begin
SetTextColor(Canvas.Handle, Canvas.Font.Color);
case MasterCol.Title.Alignment of
taLeftJustify:
if ADraw then
P := DrawHighLightText(Canvas, PChar(MasterCol.Title.Caption),
TextRect, 1, DT_NOPREFIX)
else
P := DrawHighLightText(Canvas, PChar(MasterCol.Title.Caption),
TextRect, 0, DT_NOPREFIX);
taCenter, taRightJustify:
begin
if MasterCol.Indexed and (MasterCol.IndexStyle <> idxNone) then
Dec(TextRect.Right, IndexTitleWidth + 2);
P := DrawTitleRect(Canvas, TextRect, MasterCol.Title.Caption,
MasterCol.Title.Alignment, ADraw);
end;
end;
Result.Y := P.Y;
Result.X := TextRect.Left - DrawRect.Left + P.X + 2;
if MasterCol.Indexed and ((MasterCol.IndexStyle <> idxNone) and
((P.X + IndexTitleWidth) < (TextRect.Right - TextRect.Left)) or not ADraw)
then begin
if ADraw then begin
if MasterCol.Title.Alignment = taCenter then
P.X := (TextRect.Right + TextRect.Left - P.X) div 2 + P.X - 1;
GDGetImages.Draw(Canvas, TextRect.Left + P.X, TextRect.Top, ColumnIndexStyle[Column.IndexStyle]);
end;
Inc(Result.X, IndexTitleWidth);
end
else
Inc(Result.X, 2);
end;
end;
begin
Column := Columns[ACol];
MasterCol := ColumnAtDepth(Column, ARow);
with ARect do
if Right-Left = 0 then Exit;
if MasterCol = nil then
begin
if AFillRect and ADraw then Canvas.FillRect(ARect);
with ARect do Result := Point(Right-Left, Bottom-Top);
Exit;
end;
if AFillRect then
begin
DrawBitmap.Width := ARect.Right - ARect.Left;
DrawBitmap.Height := ARect.Bottom - ARect.Top;
with DrawBitmap do
begin
DrawRect := Rect(0,0, Width, Height);
Result := DoPaint(Canvas, DrawRect);
end;
if ADraw then ACanvas.Draw(ARect.Left, ARect.Top, DrawBitmap);
end
else
Result := DoPaint(ACanvas, ARect);
end;
procedure TDCCustomDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
FrameOffs: Byte;
BorderState: TDrawBorerState;
BorderStyle: TEdgeBorderStyle;
TitleRect: TRect;
MasterCol: TColumn;
Indicators: TImageList;
function RowIsMultiSelected: Boolean;
var
Index: Integer;
begin
Result := (dgMultiSelect in Options) and Datalink.Active and
FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
end;
var
OldActive: Integer;
Indicator: Integer;
Highlight: Boolean;
Value: string;
MultiSelected, FrozenCol: Boolean;
ALeft, ATop: Integer;
BRect: TRect;
function IsColFirstVisible(ACol: integer): boolean;
var
AFirst: Integer;
begin
AFirst := 0;
while (AFirst < Columns.Count-1) and (Columns[AFirst].Visible = False) do
Inc(AFirst);
if LeftCol - FIndicatorOffset > AFirst then AFirst := 0;
Result := Assigned(DataLink) and DataLink.Active and (dgMarker in Options) and
(ACol = LeftCol - FIndicatorOffset + AFirst);
end;
procedure DrawMarker(BRect: TRect);
begin
Canvas.Brush.Color := FixedColor;
Canvas.FillRect(BRect);
if FBookMarks.CurrentRowSelected then
begin
Indicators.Draw(Canvas, BRect.Right - (MarkerWidth div 2)-4,
(BRect.Top + BRect.Bottom - Indicators.Height) shr 1, nbmCheck);
end;
if BorderStyle <> ebsNone then
begin
if BorderStyle = ebsShadowFlat then
begin
if not (dgColLines in Options) then
BRect.Left := BRect.Left - 2
else begin
BRect.Left := BRect.Left - 1;
BRect.Right := BRect.Right + 1;
end;
BRect.Top := BRect.Top - 1;
BRect.Bottom := BRect.Bottom + 1;
end;
if FrozenCol then InflateRect(BRect, -1, -1);
DrawGridFrameBorder(Canvas, BRect, BorderStyle, dsUp, FixedColor);
end;
end;
begin
if [csDestroying, csLoading] * ComponentState <> [] then
begin
Canvas.Brush.Color := Color;
Canvas.FillRect(ARect);
Exit;
end;
Indicators := GDGetImages;
BorderStyle := GetBorderStyle;
if (ClickedCol <> -1) and (ACol= ClickedCol) and (ARow < FTitleOffset) then
BorderState := dsDown
else
BorderState := dsUp;
Dec(ARow, FTitleOffset);
Dec(ACol, FIndicatorOffset);
if (gdFixed in AState) and (ACol >= 0) and (ACol < FFrozenCols) and (ARow >= 0) then
FrozenCol := True
else
FrozenCol := False;
if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
[dgRowLines, dgColLines]) and not FrozenCol
then begin
InflateRect(ARect, -1, -1);
FrameOffs := 1;
end
else
FrameOffs := 2;
if (gdFixed in AState) and (ACol < 0)
then begin
if (dgMarker in Options) and (ACol = -1) and (ARow >= 0) and
Assigned(DataLink) and DataLink.Active then
begin
if not RectVisible(Canvas.Handle, CellRect(LeftCol, ARow + FTitleOffset)) then
begin
OldActive := FDataLink.ActiveRecord;
try
FDataLink.ActiveRecord := ARow;
InflateRect(ARect, 1, 1);
DrawMarker(ARect);
finally
FDataLink.ActiveRecord := OldActive;
end;
end;
Exit;
end;
Canvas.Brush.Color := FixedColor;
Canvas.FillRect(ARect);
if ([dgIndicator, dgMarker] * Options = [dgIndicator, dgMarker]) and (ACol = -2)
or
([dgIndicator, dgMarker] * Options = [dgIndicator]) and (ACol = -1)
then begin
if Assigned(DataLink) and DataLink.Active then
begin
MultiSelected := False;
if ARow >= 0 then
begin
OldActive := FDataLink.ActiveRecord;
try
FDatalink.ActiveRecord := ARow;
MultiSelected := RowIsMultiselected;
finally
FDatalink.ActiveRecord := OldActive;
end;
end;
if (ARow = FDataLink.ActiveRecord) or MultiSelected
then begin
Indicator := nbmArrow;
if FDataLink.DataSet <> nil then
case FDataLink.DataSet.State of
dsEdit : Indicator := nbmEdit;
dsInsert: Indicator := nbmInsert;
dsBrowse:
if MultiSelected then
if (ARow <> FDatalink.ActiveRecord) then
Indicator := nbmMultiDot
else
Indicator := nbmMultiArrow; // multiselected and current row
end;
ALeft := ARect.Right - Indicators.Width - FrameOffs;
if Canvas.CanvasOrientation = coRightToLeft then Inc(ALeft);
Indicators.Draw(Canvas, ALeft,
(ARect.Top + ARect.Bottom - Indicators.Height) shr 1, Indicator, True);
if ARow = FDatalink.ActiveRecord then
FSelRow := ARow + FTitleOffset;
end;
end;
end;
if (ARow < 0) and (dgeMarkerMenu in OptionsEx) and
( ((ACol = -1) and (dgIndicator in Options) and not (dgMarker in Options) ) or
((ACol = -2) and (dgIndicator in Options) and (dgMarker in Options) ) )
then begin
ALeft := (ARect.Right + ARect.Left - Indicators.Width - FrameOffs) shr 1 + 1;
ATop := (ARect.Top + ARect.Bottom - Indicators.Height) shr 1;
if FClipDown then
begin
if [dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines] then
Indicators.Draw(Canvas, ALeft, ATop+1, nbmMain)
else
Indicators.Draw(Canvas, ALeft-1, ATop, nbmMain);
InflateRect(ARect, 1, 1);
DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsDown, FixedColor);
end
else begin
Indicators.Draw(Canvas, ALeft-1, ATop, nbmMain);
InflateRect(ARect, 1, 1);
DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
end;
Exit;
end;
if (ARow < 0) and (ACol = -1) and (dgMarker in Options)
then begin
ALeft := (ARect.Right + ARect.Left - Indicators.Width - FrameOffs) shr 1 + 1;
ATop := (ARect.Top + ARect.Bottom - Indicators.Height) shr 1 - 1;
Indicators.Draw(Canvas, ALeft-1, ATop, nbmCheckHrd);
InflateRect(ARect, 1, 1);
DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
Exit;
end;
end
else with Canvas do
begin
FDrawColumn := Columns[ACol];
if not (gdFixed in AState) or FrozenCol then
begin
Font := FDrawColumn.Font;
Brush.Color := FDrawColumn.Color;
end;
if (ARow < 0) then
begin
if not FDrawColumn.Showing then Exit;
TitleRect := CalcTitleRect(FDrawColumn, ARow + FTitleOffset, MasterCol);
TitleRect.Right := ARect.Right;
DrawTitleCell(Canvas, ACol, ARow + FTitleOffset, TitleRect, BorderState, True, True);
end
else if (FDataLink = nil) or not FDataLink.Active then
begin
if not FDrawColumn.Showing then Exit;
FillRect(ARect);
end
else
begin
OldActive := FDataLink.ActiveRecord;
try
FDataLink.ActiveRecord := ARow;
if IsColFirstVisible(ACol) then
begin
BRect := ARect;
if (dgIndicator in Options)
then BRect.Left := IndicatorWidth + 1
else BRect.Left := 0;
BRect.Right := BRect.Left + MarkerWidth;
if ACol < (FixedCols - FIndicatorOffset) then InflateRect(BRect, 1, 1);
DrawMarker(BRect);
end;
if not FDrawColumn.Showing then Exit;
if (gdFixed in AState) and not FrozenCol then
begin
Font := FDrawColumn.Title.Font;
Brush.Color := FDrawColumn.Title.Color;
end
else
begin
Font := FDrawColumn.Font;
Brush.Color := FDrawColumn.Color;
end;
Value := GetDataValue(FDrawColumn);
if FrozenCol and (ARow = Row - FTitleOffset) and
(dgRowSelect in Options) then
AState := AState + [gdSelected];
Highlight := HighlightCell(ACol, ARow, Value, AState);
if (dgHighlightRow in Options) and
((dgAlwaysShowSelection in Options) or Focused)
then begin
if OldActive = ARow then
begin
if ACol >= 0 then
begin
if not Focused and (dgeShadowSelection in OptionsEx) then
Brush.Color := clShadowed
else begin
Brush.Color := clHighlight;
Font.Color := clHighlightText;
end;
end;
AState := AState + [gdSelected];
end;
if Highlight then
begin
if not Focused and (dgeShadowSelection in OptionsEx) then
Brush.Color := clShadowed
else begin
Brush.Color := clRowHighlight;
Font.Color := clTextHighlight;
end;
AState := AState + [gdFocused];
end;
end
else if Highlight then
begin
if not Focused and (dgeShadowSelection in OptionsEx) then
Brush.Color := clShadowed
else begin
Brush.Color := clHighlight;
Font.Color := clHighlightText;
end;
AState := AState + [gdSelected];
end;
if not Enabled then
Font.Color := clGrayText;
if FDefaultDrawing and (ARect.Right - ARect.Left > 0) then
begin
WriteText(Canvas, ARect, 2, 2, Value, FDrawColumn.Alignment,
UseRightToLeftAlignmentForField(FDrawColumn.Field, FDrawColumn.Alignment), FDrawColumn.WordBreak);
end;
if Columns.State = csDefault then
DrawDataCell(ARect, FDrawColumn.Field, AState);
DrawColumnCell(ARect, ACol, FDrawColumn, AState);
finally
FDataLink.ActiveRecord := OldActive;
end;
if FDefaultDrawing and (gdSelected in AState)
and ((dgAlwaysShowSelection in Options) or Focused)
and not (csDesigning in ComponentState)
and not (dgRowSelect in Options)
and (UpdateLock = 0)
and (ValidParentForm(Self).ActiveControl = Self)
and not (dgHighlightRow in Options) then
Windows.DrawFocusRect(Handle, ARect);
end;
end;
if (gdFixed in AState) and (([dgRowLines, dgColLines] * Options =
[dgRowLines, dgColLines]) or (dgFlatButtons in Options)) and
not FrozenCol then
begin
InflateRect(ARect, 1, 1);
DrawGridFrameBorder(Canvas, ARect, BorderStyle, BorderState, FixedColor);
end;
end;
procedure TDCCustomDBGrid.DrawDataCell(const Rect: TRect; Field: TField;
State: TGridDrawState);
begin
if Assigned(FOnDrawDataCell) then FOnDrawDataCell(Self, Rect, Field, State);
end;
procedure TDCCustomDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;
Column: TColumn; State: TGridDrawState);
begin
if Assigned(OnDrawColumnCell) then
OnDrawColumnCell(Self, Rect, DataCol, Column, State);
end;
procedure TDCCustomDBGrid.EditButtonClick;
begin
if Assigned(FOnEditButtonClick) then
FOnEditButtonClick(Self)
else
ShowPopupEditor(Columns[SelectedIndex]);
end;
procedure TDCCustomDBGrid.EditingChanged;
begin
if dgIndicator in Options then InvalidateCell(0, FSelRow);
end;
procedure TDCCustomDBGrid.EndLayout;
begin
if FLayoutLock > 0 then
begin
try
try
if FLayoutLock = 1 then
InternalLayout;
finally
if FLayoutLock = 1 then
FColumns.EndUpdate;
end;
finally
Dec(FLayoutLock);
EndUpdate;
end;
end;
end;
procedure TDCCustomDBGrid.EndUpdate;
begin
if FUpdateLock > 0 then
Dec(FUpdateLock);
end;
function TDCCustomDBGrid.GetColField(DataCol: Integer): TField;
begin
Result := nil;
if (DataCol >= 0) and FDatalink.Active and (DataCol < Columns.Count) then
Result := Columns[DataCol].Field;
end;
function TDCCustomDBGrid.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
function TDCCustomDBGrid.GetEditLimit: Integer;
begin
Result := 0;
if Assigned(SelectedField) and (SelectedField.DataType = ftString) then
Result := SelectedField.Size;
end;
function TDCCustomDBGrid.GetEditMask(ACol, ARow: Longint): string;
begin
Result := '';
if FDatalink.Active then
with Columns[RawToDataColumn(ACol)] do
if Assigned(Field) then
Result := Field.EditMask;
end;
function TDCCustomDBGrid.GetEditText(ACol, ARow: Longint): string;
begin
Result := '';
if FDatalink.Active then
with Columns[RawToDataColumn(ACol)] do
if Assigned(Field) then
Result := Field.Text;
FEditText := Result;
end;
function TDCCustomDBGrid.GetFieldCount: Integer;
begin
Result := FDatalink.FieldCount;
end;
function TDCCustomDBGrid.GetFields(FieldIndex: Integer): TField;
begin
Result := FDatalink.Fields[FieldIndex];
end;
function TDCCustomDBGrid.GetFieldValue(ACol: Integer): string;
var
Field: TField;
begin
Result := '';
Field := GetColField(ACol);
if Field <> nil then Result := Field.DisplayText;
end;
function TDCCustomDBGrid.GetSelectedField: TField;
var
Index: Integer;
begin
Index := SelectedIndex;
if Index <> -1 then
Result := Columns[Index].Field
else
Result := nil;
end;
function TDCCustomDBGrid.GetSelectedIndex: Integer;
begin
Result := RawToDataColumn(Col);
end;
function TDCCustomDBGrid.HighlightCell(DataCol, DataRow: Integer;
const Value: string; AState: TGridDrawState): Boolean;
var
Index: Integer;
begin
Result := False;
if (dgMultiSelect in Options) and Datalink.Active then
Result := FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
if not Result then
Result := (gdSelected in AState)
and ((dgAlwaysShowSelection in Options) or Focused or
((InplaceEditor <> nil) and InplaceEditor.Focused))
{ updatelock eliminates flicker when tabbing between rows }
and ((UpdateLock = 0) or (dgRowSelect in Options));
end;
procedure TDCCustomDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
var
KeyDownEvent: TKeyEvent;
procedure Tab(GoForward: Boolean);
var
ACol, Original: Integer;
begin
ACol := Col;
Original := ACol;
BeginUpdate; { Prevent highlight flicker on tab to next/prior row }
try
while True do
begin
if GoForward then
Inc(ACol) else
Dec(ACol);
if ACol >= ColCount then
begin
NextRow(False);
ACol := FIndicatorOffset;
end
else if ACol < FIndicatorOffset then
begin
PriorRow(False);
ACol := ColCount - FIndicatorOffset;
end;
if ACol = Original then Exit;
if TabStops[ACol] then
begin
MoveCol(ACol, 0);
Exit;
end;
end;
finally
EndUpdate;
end;
end;
function DeletePrompt: Boolean;
var
Msg: string;
begin
if (FBookmarks.Count > 1) then
Msg := SDeleteMultipleRecordsQuestion
else
Msg := SDeleteRecordQuestion;
Result := not (dgConfirmDelete in Options) or
(MessageDlg(Msg, mtConfirmation, mbOKCancel, 0) <> idCancel);
end;
const
RowMovementKeys = [VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END];
begin
if not DataVisible then Exit;
if FClipPopupVisible then
begin
if Key = VK_ESCAPE then
HideClipPopup
else
TDBClipPopup(FClipPopup).KeyDown(Key, Shift);
Key := 0;
Exit;
end;
KeyDownEvent := OnKeyDown;
if Assigned(KeyDownEvent) then KeyDownEvent(Self, Key, Shift);
if not FDatalink.Active or not CanGridAcceptKey(Key, Shift) then Exit;
if UseRightToLeftAlignment then
if Key = VK_LEFT then
Key := VK_RIGHT
else if Key = VK_RIGHT then
Key := VK_LEFT;
with FDatalink.DataSet do
if ssCtrl in Shift then
begin
if (Key in RowMovementKeys) then ClearSelection;
case Key of
VK_UP, VK_PRIOR: FDataLink.MoveBy(-FDatalink.ActiveRecord);
VK_DOWN, VK_NEXT: FDataLink.MoveBy(FDatalink.BufferCount - FDatalink.ActiveRecord - 1);
VK_LEFT: MoveCol(FIndicatorOffset, 1);
VK_RIGHT: MoveCol(ColCount - 1, -1);
VK_HOME: First;
VK_END: Last;
VK_DELETE:
if not ReadOnly and not IsEmpty and CanModify and DeletePrompt then
if FBookmarks.Count > 0 then
FBookmarks.Delete
else
Delete;
65:{A} SelectItems(smSelect);
end
end
else
case Key of
VK_UP: PriorRow(True);
VK_DOWN: NextRow(True);
VK_LEFT:
if (dgRowSelect in Options) then
PriorRow(False) else
MoveCol(Col - 1, -1);
VK_RIGHT:
if (dgRowSelect in Options) then
NextRow(False) else
MoveCol(Col + 1, 1);
VK_HOME:
if (ColCount = FIndicatorOffset+1)
or (dgRowSelect in Options) then
begin
ClearSelection;
First;
end
else
MoveCol(FIndicatorOffset, 1);
VK_END:
if (ColCount = FIndicatorOffset+1)
or (dgRowSelect in Options) then
begin
ClearSelection;
Last;
end
else
MoveCol(ColCount - 1, -1);
VK_NEXT:
begin
ClearSelection;
FDataLink.MoveBy(VisibleRowCount);
end;
VK_PRIOR:
begin
ClearSelection;
FDataLink.MoveBy(-VisibleRowCount);
end;
VK_INSERT:
if (dgeInsertSelect in OptionsEx) and
(dgMarker in Options) and FDatalink.Active then
begin
try
BeginUpdate;
FSelectionAnchor := FBookmarks.CurrentRow;
FBookmarks.CurrentRowSelected := not FBookmarks.CurrentRowSelected;
FSelecting := True;
NextRow(True);
finally
EndUpdate;
end
end
else
if CanModify and not ReadOnly and (dgEditing in Options) then
begin
ClearSelection;
Insert;
end;
VK_TAB: if not (ssAlt in Shift) then Tab(not (ssShift in Shift));
VK_ESCAPE:
begin
inherited;
if Key = VK_ESCAPE then
begin
if SysLocale.PriLangID = LANG_KOREAN then
FIsESCKey := True;
FDatalink.Reset;
ClearSelection;
if not (dgAlwaysShowEditor in Options) then HideEditor;
end;
end;
VK_F2: EditorMode := True;
end;
end;
procedure TDCCustomDBGrid.KeyPress(var Key: Char);
begin
if not DataVisible then Exit;
if (DragState <> dsNone) then
begin
inherited;
Exit;
end;
FIsESCKey := False;
if not (dgAlwaysShowEditor in Options) and (Key = Char(VK_RETURN)) then
FDatalink.UpdateData;
inherited KeyPress(Key);
end;
procedure TDCCustomDBGrid.SetTitleHeight;
var
I, D, B: Integer;
Heights: array of Integer;
P: TPoint;
begin
Canvas.Font := Font;
B := GetSystemMetrics(SM_CYHSCROLL);
if dgTitles in Options then
begin
SetLength(Heights, FTitleOffset+1);
for I := 0 to FColumns.Count-1 do
begin
Canvas.Font := FColumns[I].Title.Font;
D := FColumns[I].Depth;
if D <= High(Heights) then
begin
P.Y := GetTextHeightEx(Canvas, FColumns[I].Title.Caption);
if P.Y > 0 then Inc(P.Y, 4);
if (Images <> nil) and (FColumns[I].ItemIndex <> -1) then
if P.Y < (Images.Height + 3) then P.Y := Images.Height + 3;
if FColumns[I].Expandable and (B > P.Y) then P.Y := B;
Heights[D] := _intMax(P.Y, Heights[D]);
end;
end;
if Heights[0] = 0 then
begin
Canvas.Font := FTitleFont;
Heights[0] := Canvas.TextHeight('Wg') + 4;
end;
for I := 0 to High(Heights)-1 do
RowHeights[I] := Heights[I];
end;
end;
{ InternalLayout is called with layout locks and column locks in effect }
procedure TDCCustomDBGrid.InternalLayout;
function FieldIsMapped(F: TField): Boolean;
var
X: Integer;
begin
Result := False;
if F = nil then Exit;
for X := 0 to FDatalink.FieldCount-1 do
if FDatalink.Fields[X] = F then
begin
Result := True;
Exit;
end;
end;
procedure CheckForPassthroughs; // check for Columns.State flip-flop
var
SeenPassthrough: Boolean;
I, J: Integer;
Column: TColumn;
begin
SeenPassthrough := False;
for I := 0 to FColumns.Count-1 do
if not FColumns[I].IsStored then
SeenPassthrough := True
else if SeenPassthrough then
begin // we have both persistent and non-persistent columns. Kill the latter
for J := FColumns.Count-1 downto 0 do
begin
Column := FColumns[J];
if not Column.IsStored then
Column.Free;
end;
Exit;
end;
end;
procedure ResetColumnFieldBindings;
var
I, J, K: Integer;
Fld: TField;
Column: TColumn;
begin
if FColumns.State = csDefault then
begin
{ Destroy columns whose fields have been destroyed or are no longer
in field map }
if (not FDataLink.Active) and (FDatalink.DefaultFields) then
FColumns.Clear
else
for J := FColumns.Count-1 downto 0 do
with FColumns[J] do
if not Assigned(Field)
or not FieldIsMapped(Field) then Free;
I := FDataLink.FieldCount;
if (I = 0) and (FColumns.Count = 0) then Inc(I);
for J := 0 to I-1 do
begin
Fld := FDatalink.Fields[J];
if Assigned(Fld) then
begin
K := J;
{ Pointer compare is valid here because the grid sets matching
column.field properties to nil in response to field object
free notifications. Closing a dataset that has only default
field objects will destroy all the fields and set associated
column.field props to nil. }
while (K < FColumns.Count) and (FColumns[K].Field <> Fld) do
Inc(K);
if K < FColumns.Count then
Column := FColumns[K]
else
begin
Column := FColumns.InternalAdd;
Column.Field := Fld;
if Column.Field.Tag = -1 then Column.Visible := False;
end;
end
else
Column := FColumns.InternalAdd;
Column.Index := J;
end;
end
else
begin
{ Force columns to reaquire fields (in case dataset has changed) }
for I := 0 to FColumns.Count-1 do
FColumns[I].Field := nil;
end;
end;
procedure MeasureTitleHeights;
var
K: Integer;
RestoreCanvas: Boolean;
begin
RestoreCanvas := not HandleAllocated;
if RestoreCanvas then Canvas.Handle := GetDC(0);
try
Canvas.Font := Font;
K := Canvas.TextHeight('Wg') + 3;
if dgRowLines in Options then
Inc(K, GridLineWidth);
// DefaultRowHeight := K;
// New 29/09/1998
if not (dgUserRowHeight in Options) then DefaultRowHeight := K;
SetTitleHeight;
finally
if RestoreCanvas then
begin
ReleaseDC(0, Canvas.Handle);
Canvas.Handle := 0;
end;
end;
end;
var
I, J: Integer;
begin
if ([csLoading, csDestroying] * ComponentState) <> [] then Exit;
if HandleAllocated then KillMessage(Handle, CM_DEFERLAYOUT);
CheckForPassthroughs;
FIndicatorOffset := 0;
if dgIndicator in Options then Inc(FIndicatorOffset);
if dgMarker in Options then Inc(FIndicatorOffset);
FDatalink.ClearMapping;
if FDatalink.Active then DefineFieldMap;
DoubleBuffered := (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView;
ResetColumnFieldBindings;
FVisibleColumns.Clear;
for I := 0 to FColumns.Count-1 do
if FColumns[I].Showing then FVisibleColumns.Add(FColumns[I]);
ColCount := FColumns.Count + FIndicatorOffset;
FTitleOffset := 0;
if dgTitles in Options then
begin
FTitleOffset := 1;
if (FDatalink <> nil) and (FDatalink.Dataset <> nil)
and FDatalink.Dataset.ObjectView then
begin
for I := 0 to FColumns.Count-1 do
begin
if FColumns[I].Showing then
begin
J := FColumns[I].Depth;
if J >= FTitleOffset then FTitleOffset := J+1;
end;
end;
end;
end;
MeasureTitleHeights;
SetColumnAttributes;
UpdateRowCount;
UpdateActive;
if dgAutoSize in Options then
begin
if FSizingIndex > -1 then
begin
I := FSizingIndex;
FSizingIndex := -1;
UpdateColWidths(I, i <> ColCount - 1);
end
else
UpdateColWidths(-1, True);
if FColumns.Count > 0 then
for I := FIndicatorOffset to ColCount - 1 do
FColumns[I - FIndicatorOffset].Width := ColWidths[I];
end
else
invalidate;
end;
procedure TDCCustomDBGrid.LayoutChanged;
begin
if AcquireLayoutLock then
EndLayout;
end;
procedure TDCCustomDBGrid.LinkActive(Value: Boolean);
var
Comp: TComponent;
I: Integer;
begin
if not Value then HideEditor;
FBookmarks.LinkActive(Value);
try
LayoutChanged;
finally
for I := ComponentCount-1 downto 0 do
begin
Comp := Components[I]; // Free all the popped-up subgrids
if (Comp is TDCCustomDBGrid)
and (TDCCustomDBGrid(Comp).DragKind = dkDock) then
Comp.Free;
end;
UpdateScrollBar;
if Value and (dgAlwaysShowEditor in Options) then ShowEditor;
end;
end;
procedure TDCCustomDBGrid.Loaded;
begin
inherited Loaded;
if FColumns.Count > 0 then
ColCount := FColumns.Count;
LayoutChanged;
end;
function TDCCustomDBGrid.PtInExpandButton(X,Y: Integer; var MasterCol: TColumn): Boolean;
var
Cell: TGridCoord;
R: TRect;
begin
MasterCol := nil;
Result := False;
Cell := MouseCoord(X,Y);
if (Cell.Y < FTitleOffset) and FDatalink.Active
and (Cell.X >= FIndicatorOffset)
and (RawToDataColumn(Cell.X) < Columns.Count) then
begin
R := CalcTitleRect(Columns[RawToDataColumn(Cell.X)], Cell.Y, MasterCol);
if not UseRightToLeftAlignment then
R.Left := R.Right - GetSystemMetrics(SM_CXHSCROLL)
else
R.Right := R.Left + GetSystemMetrics(SM_CXHSCROLL);
Result := MasterCol.Expandable and PtInRect(R, Point(X,Y));
end;
end;
function TDCCustomDBGrid.LeftTitleButton(Row, Col: integer): boolean;
begin
Result := ([dgIndicator, dgTitles]*Options=[dgIndicator, dgTitles]) and
(Row=0) and (Col=0);
end;
procedure TDCCustomDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
Cell: TGridCoord;
OldCol,OldRow: Integer;
MasterCol: TColumn;
GridOptions: TGridOptions;
AX, AY: integer;
AOnMouseDown: TMouseEvent;
Msg: TMsg;
R: TRect;
begin
if not AcquireFocus or not DataVisible then Exit;
AX := X; AY := Y;
if (X > 0) and (Y > 0) then
Cell := MouseCoord(X, Y)
else begin
Cell.X := 0;
Cell.Y := -1;
end;
R := CellRect(Cell.X, Cell.Y);
if IsRectEmpty(R) then Exit;
if (ssDouble in Shift) and (Button = mbLeft) then
begin
if (Cell.X >= FIndicatorOffset) and
(Cell.Y >= FTitleOffset) then
begin
if MouseUpBeforeDblClk then
begin
{WM_LBUTTONUP}
case Integer(GetMessage(Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST)) of
-1:;
0 :
begin
PostQuitMessage(Msg.WParam);
end;
else
DispatchMessage(Msg);
end;
end;
DblClick;
if Cell.Y >= FTitleOffset then CellDblClick(Columns[SelectedIndex]);
Exit;
end;
Shift := Shift - [ssDouble];
end;
FMousePoint := Point(X,Y);
if (dgTitleClicked in Options) and (Button = mbLeft) and not Sizing(X, Y)
and (Cell.Y=0) and FDatalink.Active and
not ( ([dgMarker,dgIndicator]*Options=[dgMarker,dgIndicator]) and (Cell.X = 1) or
([dgMarker,dgIndicator]*Options=[dgMarker] ) and (Cell.X = 0))
then begin
ClickedCol := Cell.X;
end;
if (Button = mbLeft) and LeftTitleButton(Cell.X,Cell.Y) and
(dgeMarkerMenu in OptionsEx) then
begin
ClipClick;
Exit;
end;
if FClipPopupVisible then HideClipPopup;
if Sizing(X, Y) then
begin
FDatalink.UpdateData;
HideEditor;
inherited MouseDown(Button, Shift, X, Y);
Exit;
end
else
FSizingIndex := -1;
if (Cell.X < 0) and (Cell.Y < 0) then
begin
inherited MouseDown(Button, Shift, X, Y);
Exit;
end;
if (DragKind = dkDock) and (Cell.X < FIndicatorOffset) and
(Cell.Y < FTitleOffset) and (not (csDesigning in ComponentState)) then
begin
BeginDrag(False);
Exit;
end;
if PtInExpandButton(X,Y, MasterCol) then
begin
MasterCol.Expanded := not MasterCol.Expanded;
ReleaseCapture;
UpdateDesigner;
Exit;
end;
if ((csDesigning in ComponentState) or (dgColumnResize in Options)) and
(Cell.Y < FTitleOffset) then
begin
FDataLink.UpdateData;
HideEditor;
//inherited MouseDown(Button, Shift, X, Y);
if (dgTitleClicked in Options) and FDatalink.Active and (Button = mbLeft) and
( ([dgMarker,dgIndicator]*Options=[dgMarker,dgIndicator]) and (Cell.X > 1) or
([dgMarker,dgIndicator]*Options=[dgIndicator] ) and (Cell.X > 0) or
([dgMarker,dgIndicator]*Options=[dgMarker] ) and (Cell.X > 0) or
([dgMarker,dgIndicator]*Options=[] ) )
then begin
GridOptions := inherited Options;
inherited Options := inherited Options - [goColMoving];
inherited MouseDown(Button, Shift, X, Y);
inherited Options := GridOptions;
end
else inherited MouseDown(Button, Shift, X, Y);
Exit;
end;
if FDatalink.Active then
with Cell do
begin
BeginUpdate; { eliminates highlight flicker when selection moves }
try
FDatalink.UpdateData; // validate before moving
HideEditor;
OldCol := Col;
OldRow := Row;
if (Y >= FTitleOffset) and (Y - Row <> 0) then
FDatalink.MoveBy(Y - Row);
//if (X >= FIndicatorOffset) then
//New 29091998
if (X >= (FixedCols - FrozenCols)) then
MoveCol(X, 0);
if (dgMultiSelect in Options) and FDatalink.Active then
with FBookmarks do
begin
FSelecting := False;
if ssCtrl in Shift then
CurrentRowSelected := not CurrentRowSelected
else
begin
Clear;
CurrentRowSelected := True;
end;
end;
if (dgMarker in Options) and FDatalink.Active and
(X < FIndicatorOffset) and
( ((dgIndicator in Options) and (X=1)) or
(not(dgIndicator in Options) and (X=0)) ) and
(Button = mbLeft)
then
with FBookmarks do
begin
FSelecting := False;
CurrentRowSelected := not CurrentRowSelected;
InvalidateCell(Cell.X, Cell.Y);
end;
if (Button = mbLeft) and
(((X = OldCol) and (Y = OldRow)) or (dgAlwaysShowEditor in Options)) then
ShowEditor { put grid in edit mode }
else
InvalidateEditor; { draw editor, if needed }
finally
EndUpdate;
AOnMouseDown := OnMouseDown;
if Assigned(AOnMouseDown) then AOnMouseDown(Self, Button, Shift, AX, AY);
end;
end;
end;
procedure TDCCustomDBGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
var
Cell: TGridCoord;
OldCurrentCol: integer;
begin
if not DataVisible then Exit;
Cell := MouseCoord(X,Y);
OldCurrentCol := FCurrentCol;
if Cell.Y = 0 then FCurrentCol := Cell.X else FCurrentCol := -1;
if (DragState = dsNone) and
(Cell.X >= FixedCols) and (ClickedCol=FCurrentCol) and (ClickedCol <> -1) and
(FGridState <> gsColMoving) and
((Abs(FMousePoint.X - X) > 5) or (Abs(FMousePoint.Y - Y) > 5) ) then
begin
FGridState := gsColMoving;
inherited MouseDown(mbLeft, Shift, FMousePoint.X, FMousePoint.Y);
if (FGridState = gsColMoving) or (DragState = dsColMoving) then Exit;
end;
inherited MouseMove(Shift, X, Y);
if (ClickedCol <> -1) and (FCurrentCol <> OldCurrentCol) and
(FGridState <> gsColMoving) and (DragState = dsNone)
and not
((ClickedCol = 0) and not(dgIndicator in Options) and (dgMarker in Options)) or
((ClickedCol = 1) and (dgIndicator in Options) and (dgMarker in Options))
then begin
InvalidateCell(ClickedCol, 0);
end;
if (Cell.Y < FTitleOffset) and (RawToDataColumn(Cell.X)>=0) and (Columns.Count > 0) then
begin
FColumnCell := RawToDataColumn(Cell.X);
DoColumnComment(MODE_SHOWWINDOW, Columns[FColumnCell]);
end
else begin
DoColumnComment(MODE_HIDEWINDOW, nil);
{Γ±≥αΓΦ≥ⁿ ∩≡εΓσ≡Ω≤ φα ∩εΣ±Γσ≥Ω≤ hinta σ±δΦ ≥σΩ±≥ φσ ∩ε∞σ∙ασ≥± Γ ≈σΘΩσ}
end;
end;
procedure TDCCustomDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
Cell : TGridCoord;
SaveState: TGridState;
SaveDragState: TDragGridState;
MouseClick: boolean;
OldClickedCol, NewSize: integer;
R: TRect;
begin
SaveState := FGridState;
SaveDragState := DragState;
MouseClick := (ClickedCol <> -1) and (ClickedCol=FCurrentCol);
Cell := MouseCoord(X,Y);
inherited MouseUp(Button, Shift, X, Y);
if (SaveState = gsColSizing) and (FSizingIndex < FixedCols) then
begin
R := CellRect(FSizingIndex, Cell.Y);
NewSize := X - R.Left + FSizingOff;
if NewSize < 5 then NewSize := 5;
ColWidths[FSizingIndex] := NewSize;
UpdateDesigner;
end;
if (Button = mbLeft) and (ClickedCol <> -1) then
begin
OldClickedCol := ClickedCol;
ClickedCol := -1;
InvalidateCell(OldClickedCol, 0);
end;
if (SaveState = gsRowSizing) or (SaveState = gsColSizing) or
((InplaceEditor <> nil) and (InplaceEditor.Visible) and
(PtInRect(InplaceEditor.BoundsRect, Point(X,Y)))) then Exit;
if (Button = mbLeft) and (Cell.X >= FIndicatorOffset) and(Cell.Y >= 0) and
(SaveState <> gsColMoving) and (RawToDataColumn(Cell.X) < Columns.Count) and
(SaveDragState <> dsColMoving) and (SaveDragState <>dsHeaderMoving)
then begin
if (Cell.Y < FTitleOffset) and MouseClick then
DoColumnClick(Shift, Cell.X)
else
CellClick(Columns[SelectedIndex]);
end;
end;
procedure TDCCustomDBGrid.MoveCol(RawCol, Direction: Integer);
var
OldCol: Integer;
begin
FDatalink.UpdateData;
if RawCol >= ColCount then
RawCol := ColCount - 1;
//if RawCol < FIndicatorOffset then RawCol := FIndicatorOffset;
//30/09/1998
if RawCol < FixedCols - FrozenCols then RawCol := FixedCols- FrozenCols;
if Direction <> 0 then
begin
while (RawCol < ColCount) and (RawCol >= FIndicatorOffset) and
(ColWidths[RawCol] <= 0) do
Inc(RawCol, Direction);
if (RawCol >= ColCount) or (RawCol < FIndicatorOffset) then Exit;
end;
OldCol := Col;
if RawCol <> OldCol then
begin
if not FInColExit then
begin
FInColExit := True;
try
ColExit;
finally
FInColExit := False;
end;
if Col <> OldCol then Exit;
end;
if not (dgAlwaysShowEditor in Options) then HideEditor;
LockWindowUpdate(Handle);
Col := RawCol;
LockWindowUpdate(0);
ColEnter;
end;
end;
procedure TDCCustomDBGrid.Notification(AComponent: TComponent;
Operation: TOperation);
var
I: Integer;
NeedLayout: Boolean;
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) then
begin
if (AComponent is TPopupMenu) then
begin
for I := 0 to Columns.Count-1 do
if Columns[I].PopupMenu = AComponent then
Columns[I].PopupMenu := nil;
end
else if (FDataLink <> nil) then
if (AComponent = DataSource) then
DataSource := nil
else if (AComponent is TField) then
begin
NeedLayout := False;
BeginLayout;
try
for I := 0 to Columns.Count-1 do
with Columns[I] do
if Field = AComponent then
begin
Field := nil;
NeedLayout := True;
end;
finally
if NeedLayout and Assigned(FDatalink.Dataset)
and not FDatalink.Dataset.ControlsDisabled then
EndLayout
else
DeferLayout;
end;
end;
end;
if (Operation = opRemove) and (AComponent = FImages) then FImages := nil;
end;
procedure TDCCustomDBGrid.RecordChanged(Field: TField);
var
I: Integer;
CField: TField;
begin
if not HandleAllocated then Exit;
if Field = nil then
Invalidate
else
begin
for I := 0 to Columns.Count - 1 do
if Columns[I].Field = Field then
InvalidateCol(DataToRawColumn(I));
end;
CField := SelectedField;
if ((Field = nil) or (CField = Field)) and
(Assigned(CField) and (CField.Text <> FEditText) and
((SysLocale.PriLangID <> LANG_KOREAN) or FIsESCKey)) then
begin
InvalidateEditor;
if InplaceEditor <> nil then InplaceEditor.Deselect;
end;
end;
procedure TDCCustomDBGrid.Scroll(Distance: Integer);
var
OldRect, NewRect: TRect;
RowHeight: Integer;
begin
if not HandleAllocated then Exit;
OldRect := BoxRectEx(0, Row, ColCount - 1, Row);
if (FDataLink.ActiveRecord >= RowCount - FTitleOffset) then UpdateRowCount;
UpdateScrollBar;
UpdateActive;
NewRect := BoxRectEx(0, Row, ColCount - 1, Row);
ValidateRect(Handle, @OldRect);
InvalidateRect(Handle, @OldRect, False);
InvalidateRect(Handle, @NewRect, False);
if Distance <> 0 then
begin
HideEditor;
try
if Abs(Distance) > VisibleRowCount then
begin
Invalidate;
Exit;
end
else
begin
RowHeight := DefaultRowHeight;
if dgRowLines in Options then Inc(RowHeight, GridLineWidth);
if (dgIndicator in Options) or
(dgMarker in Options) then
begin
OldRect := BoxRectEx(0, FSelRow, ColCount - 1, FSelRow);
InvalidateRect(Handle, @OldRect, False);
end;
NewRect := BoxRectEx(0, FTitleOffset, ColCount - 1, 1000);
ScrollWindowEx(Handle, 0, -RowHeight * Distance, @NewRect, @NewRect,
0, nil, SW_Invalidate);
if (dgIndicator in Options) or
(dgMarker in Options) then
begin
NewRect := BoxRectEx(0, Row, ColCount - 1, Row);
InvalidateRect(Handle, @NewRect, False);
end;
end;
finally
if dgAlwaysShowEditor in Options then ShowEditor;
end;
end;
if UpdateLock = 0 then Update;
end;
procedure TDCCustomDBGrid.SetColumns(Value: TDBGridColumns);
begin
Columns.Assign(Value);
end;
function ReadOnlyField(Field: TField): Boolean;
var
MasterField: TField;
begin
Result := Field.ReadOnly;
if not Result and (Field.FieldKind = fkLookup) then
begin
Result := True;
if Field.DataSet = nil then Exit;
MasterField := Field.Dataset.FindField(Field.KeyFields);
if MasterField = nil then Exit;
Result := MasterField.ReadOnly;
end;
end;
procedure TDCCustomDBGrid.SetColumnAttributes;
var
I: Integer;
begin
for I := 0 to FColumns.Count-1 do
with FColumns[I] do
begin
TabStops[I + FIndicatorOffset] := Showing and not ReadOnly and DataLink.Active and
Assigned(Field) and not (Field.FieldKind = fkCalculated) and not ReadOnlyField(Field);
ColWidths[I + FIndicatorOffset] := Width;
end;
if (dgIndicator in Options) then
ColWidths[0] := IndicatorWidth;
if (dgMarker in Options) then
if (dgIndicator in Options) then
ColWidths[1] := MarkerWidth
else
ColWidths[0] := MarkerWidth;
SetFrozenCols(FFrozenCols)
end;
procedure TDCCustomDBGrid.SetDataSource(Value: TDataSource);
begin
FBookmarks.Clear;
if Value = FDatalink.Datasource then Exit;
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
LinkActive(FDataLink.Active);
end;
procedure TDCCustomDBGrid.SetEditText(ACol, ARow: Longint; const Value: string);
begin
FEditText := Value;
end;
procedure TDCCustomDBGrid.SetOptions(Value: TDBGridOptions);
const
LayoutOptions = [dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
dgColLines, dgRowLines, dgRowSelect, dgAlwaysShowSelection, dgMarker,
dgTitleClicked, dgHighlightRow, dgCompleteLines];
var
NewGridOptions: TGridOptions;
ChangedOptions: TDBGridOptions;
begin
if FOptions <> Value then
begin
NewGridOptions := [];
if dgColLines in Value then
NewGridOptions := NewGridOptions + [goFixedVertLine, goVertLine];
if dgRowLines in Value then
NewGridOptions := NewGridOptions + [goFixedHorzLine, goHorzLine];
if dgColumnResize in Value then
NewGridOptions := NewGridOptions + [goColSizing, goColMoving];
if dgTabs in Value then Include(NewGridOptions, goTabs);
if dgRowSelect in Value then
begin
Include(NewGridOptions, goRowSelect);
Exclude(Value, dgAlwaysShowEditor);
Exclude(Value, dgEditing);
end;
if dgHighlightRow in Value then
begin
Exclude(Value, dgRowSelect);
end;
if dgEditing in Value then Include(NewGridOptions, goEditing);
if dgAlwaysShowEditor in Value then Include(NewGridOptions, goAlwaysShowEditor);
if dgMultiSelect in (FOptions - Value) then FBookmarks.Clear;
if dgMultiSelect in Value then Value := Value - [dgMarker];
if dgRowSizing in Value then
begin
NewGridOptions := NewGridOptions + [goRowSizing];
Value := Value +[dgUserRowHeight];
end;
if dgFlatButtons in Value then
NewGridOptions := NewGridOptions - [goFixedHorzLine, goFixedVertLine];
inherited Options := NewGridOptions;
ChangedOptions := (FOptions + Value) - (FOptions * Value);
FOptions := Value;
GridOptions := [];
if dgAutoSize in Value then GridOptions := GridOptions + [goAutoSize];
if ChangedOptions * LayoutOptions <> [] then LayoutChanged;
if [dgFlatButtons, dgAutoSize] * ChangedOptions <> [] then
begin
LockUpdate;
if dgAutoSize in ChangedOptions then ScrollBars := ScrollBars;
RecreateWnd;
UnlockUpdate;
if dgAutoSize in ChangedOptions then LayoutChanged;
end;
end;
end;
procedure TDCCustomDBGrid.SetSelectedField(Value: TField);
var
I: Integer;
begin
if Value = nil then Exit;
for I := 0 to Columns.Count - 1 do
if Columns[I].Field = Value then
MoveCol(DataToRawColumn(I), 0);
end;
procedure TDCCustomDBGrid.SetSelectedIndex(Value: Integer);
begin
MoveCol(DataToRawColumn(Value), 0);
end;
procedure TDCCustomDBGrid.SetTitleFont(Value: TFont);
begin
FTitleFont.Assign(Value);
if (dgTitles in Options) and HandleAllocated then LayoutChanged;
end;
function TDCCustomDBGrid.StoreColumns: Boolean;
begin
Result := Columns.State = csCustomized;
end;
procedure TDCCustomDBGrid.TimedScroll(Direction: TGridScrollDirection);
begin
if FDatalink.Active then
begin
with FDatalink do
begin
if sdUp in Direction then
begin
FDataLink.MoveBy(-ActiveRecord - 1);
Exclude(Direction, sdUp);
end;
if sdDown in Direction then
begin
FDataLink.MoveBy(RecordCount - ActiveRecord);
Exclude(Direction, sdDown);
end;
end;
if Direction <> [] then inherited TimedScroll(Direction);
end;
end;
procedure TDCCustomDBGrid.TitleClick(Column: TColumn);
begin
if Assigned(FOnTitleClick) then FOnTitleClick(Column);
end;
procedure TDCCustomDBGrid.ClipClick;
begin
if FClipPopupVisible then
HideClipPopup
else
ShowClipPopup;
end;
procedure TDCCustomDBGrid.TitleFontChanged(Sender: TObject);
begin
if (not FSelfChangingTitleFont) and not (csLoading in ComponentState) then
ParentFont := False;
if dgTitles in Options then LayoutChanged;
end;
procedure TDCCustomDBGrid.UpdateActive;
var
NewRow: Integer;
Field: TField;
begin
if FDatalink.Active and HandleAllocated and not (csLoading in ComponentState) then
begin
if FDatalink.DataSet.Active and (FDatalink.ActiveRecord = FDatalink.RecordCount)
then begin
FDatalink.DataSet.Prior;
FDatalink.DataSet.Next;
end;
NewRow := FDatalink.ActiveRecord + FTitleOffset;
if Row <> NewRow then
begin
if not (dgAlwaysShowEditor in Options) then HideEditor;
MoveColRow(Col, NewRow, False, False);
InvalidateEditor;
end;
Field := SelectedField;
if Assigned(Field) and (Field.Text <> FEditText) then
InvalidateEditor;
end;
end;
procedure TDCCustomDBGrid.UpdateData;
var
Field: TField;
begin
Field := SelectedField;
if Assigned(Field) then
Field.Text := FEditText;
end;
procedure TDCCustomDBGrid.UpdateRowCount;
var
OldRowCount: Integer;
begin
OldRowCount := RowCount;
if RowCount <= FTitleOffset then RowCount := FTitleOffset + 1;
FixedRows := FTitleOffset;
with FDataLink do
if not Active or (RecordCount = 0) or not HandleAllocated then
RowCount := 1 + FTitleOffset
else
begin
RowCount := 1000;
FDataLink.BufferCount := VisibleRowCount;
RowCount := RecordCount + FTitleOffset;
if (dgRowSelect in Options) then
TopRow := FixedRows;
UpdateActive;
end;
if OldRowCount <> RowCount then UpdateScrollBar;
end;
procedure TDCCustomDBGrid.UpdateScrollBar;
var
SIOld, SINew: TScrollInfo;
begin
if FDatalink.Active and HandleAllocated then
begin
ShowScrollBar(Self.Handle, SB_VERT, True);
with FDatalink.DataSet do
begin
SIOld.cbSize := sizeof(SIOld);
SIOld.fMask := SIF_ALL;
GetScrollInfo(Self.Handle, SB_VERT, SIOld);
SINew := SIOld;
if IsSequenced then
begin
SINew.nMin := 1;
SINew.nPage := Self.VisibleRowCount;
SINew.nMax := Integer(DWORD(RecordCount) + SINew.nPage - 1);
if State in [dsInactive, dsBrowse, dsEdit] then
SINew.nPos := RecNo; // else keep old pos
end
else
begin
SINew.nMin := 0;
SINew.nPage := 0;
SINew.nMax := 4;
if FDataLink.BOF then SINew.nPos := 0
else if FDataLink.EOF then SINew.nPos := 4
else SINew.nPos := 2;
end;
if (SINew.nMin <> SIOld.nMin) or (SINew.nMax <> SIOld.nMax) or
(SINew.nPage <> SIOld.nPage) or (SINew.nPos <> SIOld.nPos) then
SetScrollInfo(Self.Handle, SB_VERT, SINew, True);
end;
end
else begin
if HandleAllocated then ShowScrollBar(Self.Handle, SB_VERT, False);
end;
end;
function TDCCustomDBGrid.ValidFieldIndex(FieldIndex: Integer): Boolean;
begin
Result := DataLink.GetMappedIndex(FieldIndex) >= 0;
end;
procedure TDCCustomDBGrid.CMParentFontChanged(var Message: TMessage);
begin
inherited;
if ParentFont then
begin
FSelfChangingTitleFont := True;
try
TitleFont := Font;
finally
FSelfChangingTitleFont := False;
end;
LayoutChanged;
end;
end;
procedure TDCCustomDBGrid.CMBiDiModeChanged(var Message: TMessage);
var
Loop: Integer;
begin
inherited;
for Loop := 0 to ComponentCount - 1 do
if Components[Loop] is TDCCustomDBGrid then
with Components[Loop] as TDCCustomDBGrid do
{ Changing the window, echos down to the subgrid }
if Parent <> nil then
Parent.BiDiMode := Self.BiDiMode;
end;
procedure TDCCustomDBGrid.CMExit(var Message: TMessage);
begin
try
if FDatalink.Active then
with FDatalink.Dataset do
if (dgCancelOnExit in Options) and (State = dsInsert) and
not Modified and not FDatalink.FModified then
Cancel else
FDataLink.UpdateData;
HideClipPopup;
DoColumnComment(MODE_HIDEWINDOW, nil);
except
SetFocus;
raise;
end;
inherited;
end;
procedure TDCCustomDBGrid.CMFontChanged(var Message: TMessage);
var
I: Integer;
begin
inherited;
BeginLayout;
try
for I := 0 to Columns.Count-1 do
Columns[I].RefreshDefaultFont;
finally
EndLayout;
end;
end;
procedure TDCCustomDBGrid.CMDeferLayout(var Message);
begin
if AcquireLayoutLock then
EndLayout
else
DeferLayout;
end;
procedure TDCCustomDBGrid.CMDesignHitTest(var Msg: TCMDesignHitTest);
var
MasterCol: TColumn;
begin
inherited;
if (Msg.Result = 1) and ((FDataLink = nil) or
((Columns.State = csDefault) and
(FDataLink.DefaultFields or (not FDataLink.Active)))) then
Msg.Result := 0
else if (Msg.Result = 0) and (FDataLink <> nil) and (FDataLink.Active)
and (Columns.State = csCustomized)
and PtInExpandButton(Msg.XPos, Msg.YPos, MasterCol) then
Msg.Result := 1;
end;
procedure TDCCustomDBGrid.WMSetCursor(var Msg: TWMSetCursor);
begin
if (csDesigning in ComponentState) and
((FDataLink = nil) or
((Columns.State = csDefault) and
(FDataLink.DefaultFields or not FDataLink.Active)))
then
Windows.SetCursor(LoadCursor(0, IDC_ARROW))
else begin
if not DataVisible then
Windows.SetCursor(LoadCursor(0, IDC_ARROW))
else
inherited;
end;
end;
procedure TDCCustomDBGrid.WMSize(var Message: TWMSize);
begin
UpdateColWidths(-1, True);
inherited;
if UpdateLock = 0 then UpdateRowCount;
InvalidateTitles;
if not DataVisible or (Footers.Height > 0) then Invalidate;
end;
procedure TDCCustomDBGrid.WMVScroll(var Message: TWMVScroll);
var
SI: TScrollInfo;
begin
if not AcquireFocus and not DataVisible then Exit;
if FDatalink.Active then
with Message, FDataLink.DataSet do
case ScrollCode of
SB_LINEUP: FDataLink.MoveBy(-FDatalink.ActiveRecord - 1);
SB_LINEDOWN: FDataLink.MoveBy(FDatalink.RecordCount - FDatalink.ActiveRecord);
SB_PAGEUP: FDataLink.MoveBy(-VisibleRowCount);
SB_PAGEDOWN: FDataLink.MoveBy(VisibleRowCount);
SB_THUMBPOSITION:
begin
if IsSequenced then
begin
SI.cbSize := sizeof(SI);
SI.fMask := SIF_ALL;
GetScrollInfo(Self.Handle, SB_VERT, SI);
if SI.nTrackPos <= 1 then First
else if SI.nTrackPos >= RecordCount then Last
else RecNo := SI.nTrackPos;
end
else
case Pos of
0: First;
1: FDataLink.MoveBy(-VisibleRowCount);
2: Exit;
3: FDataLink.MoveBy(VisibleRowCount);
4: Last;
end;
end;
SB_BOTTOM: Last;
SB_TOP: First;
end;
end;
procedure TDCCustomDBGrid.SetIme;
var
Column: TColumn;
begin
if not SysLocale.FarEast then Exit;
ImeName := FOriginalImeName;
ImeMode := FOriginalImeMode;
Column := Columns[SelectedIndex];
if Column.IsImeNameStored then ImeName := Column.ImeName;
if Column.IsImeModeStored then ImeMode := Column.ImeMode;
if InplaceEditor <> nil then
begin
TDBGridInplaceEdit(Self).ImeName := ImeName;
TDBGridInplaceEdit(Self).ImeMode := ImeMode;
end;
end;
procedure TDCCustomDBGrid.UpdateIme;
begin
if not SysLocale.FarEast then Exit;
SetIme;
SetImeName(ImeName);
SetImeMode(Handle, ImeMode);
end;
procedure TDCCustomDBGrid.WMIMEStartComp(var Message: TMessage);
begin
inherited;
ShowEditor;
end;
procedure TDCCustomDBGrid.WMSetFocus(var Message: TWMSetFocus);
begin
if not ((InplaceEditor <> nil) and
(Message.FocusedWnd = InplaceEditor.Handle)) then SetIme;
inherited;
if InplaceEditor = nil then
begin
MoveCol(Col, 1);
InvalidateSelected;
end;
end;
procedure TDCCustomDBGrid.WMKillFocus(var Message: TMessage);
begin
if not SysLocale.FarEast then inherited
else
begin
ImeName := Screen.DefaultIme;
ImeMode := imDontCare;
inherited;
if not ((InplaceEditor <> nil) and
(HWND(Message.WParam) = InplaceEditor.Handle)) then
ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
end;
if FClipPopupVisible then HideClipPopup;
InvalidateSelected;
end;
{ Defer action processing to datalink }
function TDCCustomDBGrid.ExecuteAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink <> nil) and DataLink.ExecuteAction(Action);
end;
function TDCCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
end;
procedure TDCCustomDBGrid.ShowPopupEditor(Column: TColumn; X, Y: Integer);
var
SubGrid: TDCCustomDBGrid;
DS: TDataSource;
I: Integer;
FloatRect: TRect;
Cmp: TControl;
begin
if not ((Column.Field <> nil) and (Column.Field is TDataSetField)) then Exit;
// find existing popup for this column field, if any, and show it
for I := 0 to ComponentCount-1 do
if Components[I] is TDCCustomDBGrid then
begin
SubGrid := TDCCustomDBGrid(Components[I]);
if (SubGrid.DataSource <> nil) and
(SubGrid.DataSource.DataSet = (Column.Field as TDatasetField).NestedDataset) then
begin
SubGrid.Parent.Show;
SubGrid.SetFocus;
Exit;
end;
end;
// create another instance of this kind of grid
SubGrid := TDCCustomDBGrid(TComponentClass(Self.ClassType).Create(Self));
try
DS := TDataSource.Create(SubGrid); // incestuous, but easy cleanup
DS.Dataset := (Column.Field as TDatasetField).NestedDataset;
SubGrid.DataSource := DS;
SubGrid.Columns.State := Columns.State;
SubGrid.Columns[0].Expanded := True;
SubGrid.Visible := False;
SubGrid.FloatingDockSiteClass := TCustomDockForm;
FloatRect.TopLeft := ClientToScreen(CellRect(Col, Row).BottomRight);
if X > Low(Integer) then FloatRect.Left := X;
if Y > Low(Integer) then FloatRect.Top := Y;
FloatRect.Right := FloatRect.Left + Width;
FloatRect.Bottom := FloatRect.Top + Height;
SubGrid.ManualFloat(FloatRect);
// SubGrid.ManualDock(nil,nil,alClient);
SubGrid.Parent.BiDiMode := Self.BiDiMode; { This carries the BiDi setting }
I := SubGrid.CellRect(SubGrid.ColCount-1, 0).Right;
if (I > 0) and (I < Screen.Width div 2) then
SubGrid.Parent.ClientWidth := I
else
SubGrid.Parent.Width := Screen.Width div 4;
SubGrid.Parent.Height := Screen.Height div 4;
SubGrid.Align := alClient;
SubGrid.DragKind := dkDock;
SubGrid.Color := Color;
SubGrid.Ctl3D := Ctl3D;
SubGrid.Cursor := Cursor;
SubGrid.Enabled := Enabled;
SubGrid.FixedColor := FixedColor;
SubGrid.Font := Font;
SubGrid.HelpContext := HelpContext;
SubGrid.IMEMode := IMEMode;
SubGrid.IMEName := IMEName;
SubGrid.Options := Options;
Cmp := Self;
while (Cmp <> nil) and (TDCCustomDBGrid(Cmp).PopupMenu = nil) do
Cmp := Cmp.Parent;
if Cmp <> nil then
SubGrid.PopupMenu := TDCCustomDBGrid(Cmp).PopupMenu;
SubGrid.TitleFont := TitleFont;
SubGrid.Visible := True;
SubGrid.Parent.Show;
except
SubGrid.Free;
raise;
end;
end;
procedure TDCCustomDBGrid.CalcSizingState(X, Y: Integer;
var State: TGridState; var Index, SizingPos, SizingOfs: Integer;
var FixedInfo: TGridDrawInfo);
var
R: TGridCoord;
EffectiveOptions: TGridOptions;
AWidth, i, j: integer;
procedure CalcAxisState(const AxisInfo: TGridAxisDrawInfo; Pos: Integer;
NewState: TGridState);
var
I, Line, Back, Range, J: Integer;
begin
if UseRightToLeftAlignment then
Pos := ClientWidth - Pos;
with AxisInfo do
begin
Range := EffectiveLineWidth;
Back := 0;
if Range < 7 then
begin
Range := 7;
Back := (Range - EffectiveLineWidth) shr 1;
end;
Line := FixedBoundary - AWidth;
J := FixedCols - FrozenCols;
for I := J to GridCellCount - 1 do
begin
if (I < FixedCols) or (I >= FirstGridCell) then
Inc(Line, GetExtent(I));
if Line > (GridBoundary - Back + Range) then Break;
if (Pos >= Line - Back) and (Pos <= Line - Back + Range) then
begin
State := NewState;
SizingPos := Line;
SizingOfs := Line - Pos;
Index := I;
Exit;
end;
if (I < FixedCols) or (I >= FirstGridCell) then
Inc(Line, EffectiveLineWidth);
end;
if (GridBoundary = GridExtent) and (Pos >= GridExtent - Back)
and (Pos <= GridExtent) then
begin
State := NewState;
SizingPos := GridExtent;
SizingOfs := GridExtent - Pos;
Index := I;
end;
end;
end;
function XOutsideHorzFixedBoundary: Boolean;
begin
with FixedInfo do
if not UseRightToLeftAlignment then
Result := X > (Horz.FixedBoundary-AWidth)
else
Result := X < ClientWidth - (Horz.FixedBoundary-AWidth);
end;
function XOutsideOrEqualHorzFixedBoundary: Boolean;
begin
with FixedInfo do
if not UseRightToLeftAlignment then
Result := X >= (Horz.FixedBoundary-AWidth)
else
Result := X <= ClientWidth - (Horz.FixedBoundary-AWidth);
end;
begin
if FrozenCols = 0 then
inherited CalcSizingState(X, Y, State, Index, SizingPos, SizingOfs, FixedInfo)
else begin
AWidth := 0;
State := gsNormal;
Index := -1;
EffectiveOptions := inherited Options;
if csDesigning in ComponentState then
EffectiveOptions := EffectiveOptions + DesignOptionsBoost;
if [goColSizing, goRowSizing] * EffectiveOptions <> [] then
with FixedInfo do
begin
Vert.GridExtent := ClientHeight;
Horz.GridExtent := ClientWidth;
with Horz do
begin
j := FixedCols - FrozenCols;
for i := j to FixedCols - 1 do Inc(AWidth, GetExtent(i));
end;
if (XOutsideHorzFixedBoundary) and (goColSizing in EffectiveOptions) then
begin
if Y >= Vert.FixedBoundary then Exit;
CalcAxisState(Horz, X, gsColSizing);
end
else if (Y > Vert.FixedBoundary) and (goRowSizing in EffectiveOptions) then
begin
if XOutsideOrEqualHorzFixedBoundary then Exit;
CalcAxisState(Vert, Y, gsRowSizing);
end;
end;
end;
with FixedInfo.Horz do
begin
if (State = gsColSizing) and ((FixedCols - FrozenCols) < Index) and
(Index = LastFullVisibleCell+1) and (LeftCol >= FindicatorOffset) and
((Columns[LeftCol - FIndicatorOffset].Width + FixedBoundary) > GridBoundary) then
Index := LeftCol;
end;
R := MouseCoord(X, Y);
R.X := RawToDataColumn(R.X);
if (State = gsColSizing) and (FDataLink <> nil)
and (FDatalink.Dataset <> nil) and FDataLink.Dataset.ObjectView then
begin
if (R.X >= 0) and (R.X < Columns.Count) and (Columns[R.X].Depth > R.Y) then
State := gsNormal;
end;
if (State = gsColSizing) and not(csDesigning in ComponentState) then
begin
R.X := RawToDataColumn(Index);
if (R.X >= 0) and (R.X < Columns.Count) and not Columns[R.X].Resize then
State := gsNormal;
end;
if State <> gsNormal then
begin
FSizingIndex := Index;
FSizingOff := SizingOfs;
end;
end;
function TDCCustomDBGrid.CheckColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean;
var
I, ARow: Integer;
DestCol: TColumn;
begin
Result := inherited CheckColumnDrag(Origin, Destination, MousePt);
if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
begin
assert(FDragCol <> nil);
ARow := FDragCol.Depth;
if Destination <> Origin then
begin
DestCol := ColumnAtDepth(Columns[RawToDataColumn(Destination)], ARow);
if DestCol.ParentColumn <> FDragCol.ParentColumn then
if Destination < Origin then
DestCol := Columns[FDragCol.ParentColumn.Index+1]
else
begin
I := DestCol.Index;
while DestCol.ParentColumn <> FDragCol.ParentColumn do
begin
Dec(I);
DestCol := Columns[I];
end;
end;
if (DestCol.Index > FDragCol.Index) then
begin
I := DestCol.Index + 1;
while (I < Columns.Count) and (ColumnAtDepth(Columns[I],ARow) = DestCol) do
Inc(I);
DestCol := Columns[I-1];
end;
Destination := DataToRawColumn(DestCol.Index);
end;
end;
end;
function TDCCustomDBGrid.BeginColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean;
var
I, ARow: Integer;
begin
Result := inherited BeginColumnDrag(Origin, Destination, MousePt);
if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
begin
ARow := MouseCoord(MousePt.X, MousePt.Y).Y;
FDragCol := ColumnAtDepth(Columns[RawToDataColumn(Origin)], ARow);
if FDragCol = nil then Exit;
I := DataToRawColumn(FDragCol.Index);
if Origin <> I then Origin := I;
Destination := Origin;
end;
end;
function TDCCustomDBGrid.EndColumnDrag(var Origin, Destination: Integer;
const MousePt: TPoint): Boolean;
begin
Result := inherited EndColumnDrag(Origin, Destination, MousePt);
FDragCol := nil;
end;
procedure TDCCustomDBGrid.InvalidateTitles;
var
R, R1: TRect;
DrawInfo: TGridDrawInfo;
begin
if HandleAllocated and (dgTitles in Options) and (FDatalink <> nil) and
(FDatalink.Dataset <> nil) then
begin
CalcDrawInfo(DrawInfo);
with DrawInfo.Horz do
begin
R1 := CellRect(LeftCol + VisibleColCount, 0);
if not IsRectEmpty(R1) and (FFirstGridCell > FirstGridCell) then
begin
R := Rect(R1.Left, 0, R1.Right, DrawInfo.Vert.FixedBoundary);
InvalidateRect(Handle, @R, False);
end;
FFirstGridCell := FirstGridCell;
end;
end;
end;
procedure TDCCustomDBGrid.TopLeftChanged;
begin
if LeftCol < FixedCols then LeftCol := FixedCols;
InvalidateTitles;
inherited TopLeftChanged;
end;
procedure TDCCustomDBGrid.RowHeightsChanged;
var
i, HeightChanged, DefaultHeight : Integer;
begin
HeightChanged := -1;
DefaultHeight := DefaultRowHeight;
for i := Ord(dgTitles in Options) to RowCount do
if RowHeights[i] <> DefaultHeight then
begin
HeightChanged := i;
Break;
end;
if HeightChanged <> -1 then
begin
DefaultRowHeight := RowHeights[i];
//New 03031999
//RecreateWnd;
if FLayoutLock = 0 then InternalLayout;
end;
SetTitleHeight;
inherited;
end;
procedure TDCCustomDBGrid.SetFrozenCols(Value: integer);
var
FixCount, I: Integer;
Changed: boolean;
begin
Changed := False;
FixCount := _intMax(Value, 0) + IndicatorOffset;
if DataLink.Active and not (csLoading in ComponentState) and
(ColCount > IndicatorOffset + 1) then
begin
FixCount := _intMin(FixCount, ColCount-1);
if (FFrozenCols <> Value) or (FixCount <> FixedCols) then
begin
LockWindowUpdate(Handle);
FixedCols := FixCount;
Col := FixedCols - FrozenCols;
LockWindowUpdate(0);
for I := 1 to _intMin(FixedCols, ColCount-1) do TabStops[I] := False;
Changed := True;
end
end;
if not Changed then FixedCols := _intMin(ColCount -1, FixCount);
FFrozenCols := FixCount - IndicatorOffset;
end;
function TDCCustomDBGrid.GetFrozenCols: integer;
begin
if DataLink.Active then Result := FixedCols - IndicatorOffset
else Result := FFrozenCols;
end;
procedure TDCCustomDBGrid.SavePosition;
begin
if Assigned(DataSource) and Assigned(DataSource.DataSet) and
Datasource.DataSet.Active and (TPrivateDataSet(DataSource.DataSet).BookmarkSize > 0)
then begin
with Datasource.DataSet do
begin
if Assigned(FCurrentPos[1].Bookmark) then FreeBookmark(FCurrentPos[1].Bookmark);
if Assigned(FCurrentPos[2].Bookmark) then FreeBookmark(FCurrentPos[2].Bookmark);
DisableControls;
Prior;
if not Bof then
begin
FCurrentPos[1].Row := Row;
FCurrentPos[1].Bookmark := GetBookmark;
FCurrentPos[1].ActiveRecord := DataLink.ActiveRecord;
Next;
end
else
FCurrentPos[1].Bookmark := nil;
FCurrentPos[2].Row := Row;
FCurrentPos[2].Bookmark := GetBookmark;
FCurrentPos[2].ActiveRecord := DataLink.ActiveRecord;
EnableControls;
end;
end;
end;
function TDCCustomDBGrid.GetPosition: TBookmark;
begin
Result := FCurrentPos[2].Bookmark;
end;
procedure TDCCustomDBGrid.RestPosition;
procedure LocateBookmark(BookamarkInfo: TBookmarkInfo);
var
ARow, BRow, i, j: integer;
begin
with TPrivateDataSet(DataSource.DataSet) do
begin
CheckBrowseMode;
DoBeforeScroll;
DataLink.ActiveRecord := BookamarkInfo.ActiveRecord;
InternalGotoBookmark(BookamarkInfo.Bookmark);
Resync([rmExact]);
ARow := Row;
BRow := BookamarkInfo.Row;
if BRow > ARow then
begin
i := BRow - FTitleOffset; j := 0;
while (i>0) and not FDatalink.DataSet.Bof do
begin
FDatalink.MoveBy(-1); inc(j); dec(i);
end;
if FDatalink.DataSet.Bof then Dec(j);
FDatalink.MoveBy(j);
end
else begin
if BRow < ARow then
begin
i := RowCount - BRow - 1; j := 0;
while (i>0) and not FDatalink.DataSet.Eof do
begin
FDatalink.MoveBy(1); inc(j); dec(i);
end;
if FDatalink.DataSet.Eof then Dec(j);
FDatalink.MoveBy(-j);
end
else begin
FDatalink.MoveBy(-ARow + 1);
FDatalink.MoveBy(ARow - 1);
end;
end;
DoAfterScroll;
end;
end;
begin
if Assigned(DataSource) and Assigned(DataSource.DataSet) and
Datasource.DataSet.Active and (TPrivateDataSet(DataSource.DataSet).BookmarkSize > 0)
then begin
Datasource.DataSet.DisableControls;
if not(Assigned(FCurrentPos[2].Bookmark) and ValidBookmark(FCurrentPos[2].Bookmark))
then begin
if Assigned(FCurrentPos[1].Bookmark) and ValidBookmark(FCurrentPos[1].Bookmark) then
LocateBookmark(FCurrentPos[1])
else
DataSource.DataSet.First;
end
else LocateBookmark(FCurrentPos[2]);
Datasource.DataSet.EnableControls;
end;
end;
procedure TDCCustomDBGrid.SetPosition(const Value: TBookmark);
begin
FCurrentPos[2].Bookmark := Value;
end;
procedure TDCCustomDBGrid.SetClipDown(const Value: boolean);
begin
if FClipDown <> Value then
begin
FClipDown := Value;
if (dgIndicator in Options) then InvalidateCell(0, 0);
end;
end;
procedure TDCCustomDBGrid.HideClipPopup;
begin
FClipPopupVisible := False;
TDCClipPopup(FClipPopup).Hide;
ClickedCol := -1;
SetClipDown(False);
end;
procedure TDCCustomDBGrid.ShowClipPopup;
var
Show: boolean;
R: TRect;
begin
Show := True;
FClipPopupVisible := True;
R := CellRect(0,0);
TDBClipPopup(FClipPopup).Hide;
TDBClipPopup(FClipPopup).AddButtons;
TDBClipPopup(FClipPopup).SetBoundsEx(R.Left, R.Bottom,
TDBClipPopup(FClipPopup).Width, TDBClipPopup(FClipPopup).Height);
if Assigned(FOnClipClick) then
FOnClipClick(FClipPopup, TDBClipPopup(FClipPopup).Left,
TDBClipPopup(FClipPopup).Top, Show);
if Show then
begin
ClipDown := not ClipDown;
TDBClipPopup(FClipPopup).OnButtonClick := ClipButtonClick;
TDBClipPopup(FClipPopup).Show;
end
else
HideClipPopup;
end;
procedure TDCCustomDBGrid.CMCancelMode(var Message: TCMCancelMode);
begin
inherited;
if (Message.Sender <> Self) and FClipPopupVisible and
(Message.Sender <> FClipPopup)
then HideClipPopup;
end;
procedure TDCCustomDBGrid.WMNCLButtonDown(var Message: TWMNCLButtonDown);
begin
inherited;
if FClipPopupVisible then HideClipPopup;
end;
procedure TDCCustomDBGrid.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
with Params do
begin
if NewStyleControls and Ctl3D then
ExStyle := ExStyle and not WS_EX_CLIENTEDGE
else
Style := Style and not WS_BORDER;
end;
end;
procedure TDCCustomDBGrid.InvalidateSelected;
var
Rect: TRect;
begin
if not HandleAllocated then Exit;
Rect := BoxRectEx(0, Row , ColCount-1, Row );
InvalidateRect(Handle, @Rect, False);
ProcessPaintMessages;
end;
procedure TDCCustomDBGrid.SetImages(const Value: TImageList);
begin
FImages := Value;
Invalidate;
end;
procedure TDCCustomDBGrid.ClipButtonClick(Sender: TObject);
begin
HideClipPopup;
if Assigned(FOnClipButtonClick) then FOnClipButtonClick(Sender);
end;
function TDCCustomDBGrid.SelectCell(ACol, ARow: Integer): Boolean;
var
OldRect, NewRect: TRect;
begin
Result := inherited SelectCell(ACol, ARow);
if Result and (ARow<>Row) then
begin
OldRect := BoxRectEx(0 , Row , ColCount-1, Row );
NewRect := BoxRectEx(0 , ARow, ColCount-1, ARow);
ValidateRect(Handle, @OldRect);
InvalidateRect(Handle, @OldRect, False);
InvalidateRect(Handle, @NewRect, False);
end;
end;
function TDCCustomDBGrid.GetPopupMenu: TPopupMenu;
var
P: TPoint;
Cell: TGridCoord;
begin
GetCursorPos(P);
P := ScreenToClient(P);
Cell := MouseCoord(P.X, P.Y);
with Cell do
if (Y < FTitleOffset) and (X > 0) and (X >= FIndicatorOffset) and
Assigned(FPopupTitle) then
Result := FPopupTitle
else
Result := inherited GetPopupMenu;
end;
procedure TDCCustomDBGrid.SetPopupTitle(const Value: TPopupMenu);
begin
FPopupTitle := Value;
end;
function TDCCustomDBGrid.DoMouseWheelDown(Shift: TShiftState;
MousePos: TPoint): Boolean;
var
MouseWheelDownEvent: TMouseWheelUpDownEvent;
begin
Result := False;
MouseWheelDownEvent := OnMouseWheelDown;
if Assigned(MouseWheelDownEvent) then
MouseWheelDownEvent(Self, Shift, MousePos, Result);
if not Result and (DragState = dsNone) and (DataSource <> nil) and
(DataSource.DataSet <> nil) and PtInRect(ClientRect, ScreenToClient(MousePos)) then
begin
NextRow(True);
Result := True;
end;
end;
function TDCCustomDBGrid.DoMouseWheelUp(Shift: TShiftState;
MousePos: TPoint): Boolean;
var
MouseWheelUpEvent: TMouseWheelUpDownEvent;
begin
Result := False;
MouseWheelUpEvent := OnMouseWheelDown;
if Assigned(MouseWheelUpEvent) then
MouseWheelUpEvent(Self, Shift, MousePos, Result);
if not Result and (DragState = dsNone) and (DataSource <> nil) and
(DataSource.DataSet <> nil) and PtInRect(ClientRect, ScreenToClient(MousePos)) then
begin
PriorRow(True);
Result := True;
end;
end;
procedure TDCCustomDBGrid.DoSelection(Select: Boolean; Direction: Integer;
Shift: TShiftState);
var
AddAfter: Boolean;
begin
AddAfter := False;
BeginUpdate;
try
if (dgMultiSelect in Options) and FDatalink.Active then
begin
if Select and (ssShift in Shift) then
begin
if not FSelecting then
begin
FSelectionAnchor := FBookmarks.CurrentRow;
FBookmarks.CurrentRowSelected := True;
FSelecting := True;
AddAfter := True;
end
else
with FBookmarks do
begin
AddAfter := Compare(CurrentRow, FSelectionAnchor) <> -Direction;
if not AddAfter then
CurrentRowSelected := False;
end
end
else
ClearSelection;
end
else if (dgMarker in Options) and FDatalink.Active then
begin
if Select and (ssShift in Shift) then
begin
FSelectionAnchor := FBookmarks.CurrentRow;
FBookmarks.CurrentRowSelected := not FBookmarks.CurrentRowSelected;
FSelecting := True;
AddAfter := False;
end;
end;
FDatalink.MoveBy(Direction);
if AddAfter then FBookmarks.CurrentRowSelected := True;
finally
EndUpdate;
end;
end;
procedure TDCCustomDBGrid.NextRow(Select: Boolean);
begin
with FDatalink.Dataset do
begin
if (State = dsInsert) and not Modified and not FDatalink.FModified then
if FDataLink.Eof then Exit else Cancel
else
DoSelection(Select, 1, []);
if FDataLink.Eof and CanModify and not ReadOnly and (dgEditing in Options) then
Append;
end;
end;
procedure TDCCustomDBGrid.PriorRow(Select: Boolean);
begin
with FDatalink.Dataset do
if (State = dsInsert) and not Modified and FDataLink.EOF and
not FDatalink.FModified then
Cancel
else
DoSelection(Select, -1, []);
end;
procedure TDCCustomDBGrid.ClearSelection;
begin
if (dgMultiSelect in Options) then
begin
FBookmarks.Clear;
FSelecting := False;
end;
end;
function TDCCustomDBGrid.GetDBObject: TDCDBObject;
begin
Result := FDBObject;
end;
procedure TDCCustomDBGrid.SetDBObject(const Value: TDCDBObject);
begin
FDBObject.Assign(Value);
end;
function TDCCustomDBGrid.GetDataValue(Column: TColumn): string;
begin
if Assigned(Column.Field) then
with Column do
begin
if DisplayFormat = '' then
begin
case Field.DataType of
ftMemo:
if dgeDrawMemoAsText in OptionsEx then
Result := Field.AsString
else
Result := Field.DisplayText
else
Result := Field.DisplayText
end
end
else
try
case Field.DataType of
ftFloat:
Result := Format(DisplayFormat, [Field.AsFloat]);
ftCurrency:
Result := Format(DisplayFormat, [Field.AsCurrency]);
ftBCD:
Result := Format(DisplayFormat, [Field.AsFloat]);
ftMemo:
if dgeDrawMemoAsText in OptionsEx then
Result := Field.AsString
else
Result := Field.DisplayText;
ftDate, ftTime, ftDateTime:
DateTimeToString(Result, DisplayFormat, Field.AsDateTime);
else
Result := Format(DisplayFormat, [Field.DisplayText]);
end;
except
Result := Field.DisplayText
end;
end
else
Result := '';
end;
procedure TDCCustomDBGrid.DoColumnComment(Mode: integer; Column: TColumn);
begin
if (FColumnCell <> -1) and (Mode = MODE_HIDEWINDOW) then
begin
if Assigned(FOnColumnComment) then FOnColumnComment(Self, Mode, Column);
FColumnCell := -1;
end
else
if Assigned(FOnColumnComment) then FOnColumnComment(Self, Mode, Column);
end;
procedure TDCCustomDBGrid.CMMouseLeave(var Message: TMessage);
begin
inherited;
DoColumnComment(MODE_HIDEWINDOW, nil);
end;
procedure TDCCustomDBGrid.Paint;
var
DrawInfo: TGridDrawInfo;
ARow, CurRow: integer;
ARect, BRect: TRect;
BorderStyle: TEdgeBorderStyle;
LineColor: TColor;
UpdateRect, FooterRect: TRect;
DefaultDrawing: boolean;
SaveIndex: integer;
begin
if (dgCompleteLines in Options) and not(dgAutoSize in Options) then
begin
CalcDrawInfo(DrawInfo);
SaveIndex := SaveDC(Canvas.Handle);
UpdateRect := Canvas.ClipRect;
FooterRect := Footers.BoundsRect;
with UpdateRect do
begin
Bottom := FooterRect.Top;
Left := DrawInfo.Horz.GridBoundary;
Right := DrawInfo.Horz.GridExtent;
ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
end;
inherited;
RestoreDC(Canvas.Handle, SaveIndex);
if not IsRectEmpty(FooterRect) then
with FooterRect do
ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
with DrawInfo do
begin
if Horz.GridBoundary < Horz.GridExtent then
begin
CurRow := 0;
if ColorToRGB(Color) = clSilver then
LineColor := clGray
else
LineColor := clSilver;
BorderStyle := GetBorderStyle;
if FTitleOffset > 0 then
begin
if Columns.Count > 0 then
Canvas.Brush.Color := Columns[Columns.Count-1].Title.Color
else
Canvas.Brush.Color := FixedColor;
ARect := Rect(Horz.GridBoundary, 0, Horz.GridExtent, 0);
while CurRow < FTitleOffset do
begin
ARect.Bottom := ARect.Bottom + RowHeights[CurRow];
BRect := ARect;
InflateRect(BRect, 1, 1);
if RectVisible(Canvas.Handle, BRect) then
begin
if RectVisible(Canvas.Handle, ARect) then
begin
Canvas.FillRect(ARect);
if BorderStyle <> ebsNone then
begin
ARect.Right := ARect.Right + 1;
if BorderStyle = ebsShadowFlat then
begin
InflateRect(ARect, 1, 1);
DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
InflateRect(ARect, -1, -1);
end
else
DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
ARect.Right := ARect.Right - 1;
end;
end;
if dgRowLines in FOptions then
begin
if dgFlatButtons in FOptions then
Canvas.Pen.Color := FixedColor
else
Canvas.Pen.Color := clBlack;
Canvas.MoveTo(ARect.Left, ARect.Bottom);
Canvas.LineTo(ARect.Right, ARect.Bottom);
end;
end;
Inc(CurRow);
ARect.Top := ARect.Bottom;
end;
end;
while (CurRow < Vert.GridCellCount) and
(ARect.Top < UpdateRect.Bottom) do
begin
if dgRowLines in FOptions then
begin
ARect.Bottom := ARect.Bottom + RowHeights[CurRow] +1;
ARect.Top := ARect.Top + 1;
end
else begin
ARect.Bottom := ARect.Bottom + RowHeights[CurRow];
ARect.Top := ARect.Top;
end;
if RectVisible(Canvas.Handle, ARect) and
((dgRowSelect in Options) or (dgHighlightRow in Options)) and
((dgAlwaysShowSelection in Options) or Focused) and
FDataLink.Active then
begin
if (FDataLink.ActiveRecord = (CurRow-FTitleOffset)) then
begin
if Focused or not(dgeShadowSelection in OptionsEx) then
begin
Canvas.Brush.Color := clHighlight
end
else begin
if dgAlwaysShowSelection in Options then
Canvas.Brush.Color := clShadowed;
end;
end
else
Canvas.Brush.Color := Self.Color;
end
else
Canvas.Brush.Color := Self.Color;
Canvas.Pen.Color := FixedColor;
if Assigned(FOnDrawCompleteLine) then
begin
DefaultDrawing := True;
ARow := CurRow-FTitleOffset;
FOnDrawCompleteLine(Self, Canvas, ARect, Focused, ARow, DefaultDrawing);
if DefaultDrawing then Canvas.FillRect(ARect);
end
else
Canvas.FillRect(ARect);
ARect.Top := ARect.Top - 1;
ARect.Bottom := ARect.Bottom;
if (dgRowLines in FOptions) and RectVisible(Canvas.Handle, ARect) then
begin
Canvas.Pen.Color := LineColor;
Canvas.MoveTo(ARect.Left, ARect.Bottom);
Canvas.LineTo(ARect.Right, ARect.Bottom);
end;
Inc(CurRow);
ARect.Top := ARect.Bottom;
end;
end;
if ARect.Top < UpdateRect.Bottom then
begin
BRect := ClientRect;
if Vert.GridBoundary < Vert.GridExtent then
begin
ARect.Top := Vert.GridBoundary;
ARect.Bottom := Vert.GridExtent;
Canvas.Brush.Color := Self.Color;
Canvas.FillRect(ARect);
end;
end;
end;
end
else
inherited;
end;
function TDCCustomDBGrid.BoxRectEx(ALeft, ATop, ARight,
ABottom: Integer): TRect;
begin
Result := BoxRect(ALeft, ATop, ARight, ABottom);
if dgCompleteLines in Options then Result.Right := Width;
end;
function TDCCustomDBGrid.CellRect(ACol, ARow: Integer): TRect;
begin
Result := inherited CellRect(ACol, ARow);
end;
function TDCCustomDBGrid.MouseCoord(X, Y: Integer): TGridCoord;
begin
Result := inherited MouseCoord(X, Y);
end;
function TDCCustomDBGrid.DataVisible: boolean;
begin
Result := (csDesigning in ComponentState) or
(FDataVisible and (FColumns.Count <> 0) and
(((DataSource <> nil) and (DataSource.DataSet <> nil) and (FDatalink.Fields[0] <> nil)) or
(FColumns[0].FFieldName <> '')));
end;
procedure TDCCustomDBGrid.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
{ inherited; }
end;
procedure TDCCustomDBGrid.WMPaint(var Message: TWMPaint);
var
PS: TPaintStruct;
EmptyMessage: string;
R, R1: TRect;
MBitmap, OBitmap: HBITMAP;
MDC, DC: HDC;
Flags: integer;
begin
if not DataVisible then
begin
if Message.DC <> 0 then
begin
if not (csCustomPaint in ControlState) and (ControlCount = 0) then
inherited
else
PaintHandler(Message);
end
else
begin
ShowScrollBar(Handle, SB_HORZ, False);
ShowScrollBar(Handle, SB_VERT, False);
GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top); R1 := R;
DC := GetDC(0);
MBitmap := CreateCompatibleBitmap(DC, R.Right, R.Bottom);
ReleaseDC(0, DC);
MDC := CreateCompatibleDC(0);
OBitmap := SelectObject(MDC, MBitmap);
try
DC := BeginPaint(Handle, PS);
Canvas.Handle := MDC;
Canvas.Brush.Color := Self.Color;
Canvas.Font := Self.Font;
EmptyMessage := LoadStr(RES_STRN_MSG_DBGCEM);
Flags := DT_END_ELLIPSIS or DT_CENTER;
if Assigned(FOnPaintEmptyMessage) then
FOnPaintEmptyMessage(Self, Canvas, R, EmptyMessage)
else begin
Canvas.Lock;
Canvas.FillRect(R);
InflateRect(R, -5, -5);
DrawHighLightText(Canvas, PChar(EmptyMessage), R, 1, Flags or DT_WORDBREAK);
Canvas.UnLock;
end;
BitBlt(DC, 0, 0, R1.Right, R1.Bottom, MDC, 0, 0, SRCCOPY);
EndPaint(Handle, PS);
finally
SelectObject(MDC, OBitmap);
DeleteDC(MDC);
DeleteObject(MBitmap);
Canvas.Handle := 0;
end;
end;
end
else
inherited;
end;
function TDCCustomDBGrid.MouseUpBeforeDblClk: boolean;
begin
Result := True;
end;
procedure TDCCustomDBGrid.WMChar(var Msg: TWMChar);
begin
if not DataVisible then
Exit
else
inherited;
end;
procedure TDCCustomDBGrid.ImageListChange(Sender: TObject);
begin
invalidate;
end;
procedure TDCCustomDBGrid.SetDataVisible(const Value: boolean);
begin
if FDataVisible <> Value then
begin
FDataVisible := Value;
invalidate;
end;
end;
procedure TDCCustomDBGrid.WMNCCalcSize(var Message: TWMNCCalcSize);
begin
inherited;
if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
InflateRect(Message.CalcSize_Params^.rgrc[0], -1, -1);
end;
procedure TDCCustomDBGrid.WMNCPaint(var Message: TMessage);
var
R, R1: TRect;
DC: HDC;
ScrollW, ScrollH: integer;
Brush: HBRUSH;
ScrollInfo: TScrollInfo;
IScroll, VScroll, HScroll: boolean;
begin
inherited;
if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
begin
DC := GetWindowDC(Handle);
Brush := CreateSolidBrush(ColorToRGB(clBtnFace));
try
GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top);
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_ALL;
IScroll := GetScrollInfo(Self.Handle, SB_HORZ, ScrollInfo);
HScroll := IScroll and (ScrollInfo.nMin <> ScrollInfo.nMax);
IScroll := GetScrollInfo(Self.Handle, SB_VERT, ScrollInfo);
VScroll := IScroll and (ScrollInfo.nMin <> ScrollInfo.nMax);
if DataVisible and HScroll and VScroll then
begin
ScrollW := GetSystemMetrics(SM_CXVSCROLL);
ScrollH := GetSystemMetrics(SM_CYVSCROLL);
R1 := Rect(R.Right - ScrollW-1, R.Bottom - ScrollH-1, R.Right-1, R.Bottom-1);
FrameRect(DC, R1, Brush);
end;
DrawEdge(DC, R, BDR_SUNKENOUTER, BF_TOPLEFT);
DrawEdge(DC, R, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
finally
DeleteObject(Brush);
ReleaseDC(Handle, DC);
end;
end;
end;
procedure TDCCustomDBGrid.WMHScroll(var Message: TWMHScroll);
begin
if not DataVisible then Exit;
inherited;
end;
function TDCCustomDBGrid.ValidBookmark(Bookmark: TBookmark): boolean;
begin
try
with TPrivateDataSet(DataSource.DataSet) do
Result := not(Eof and Bof) and (BookmarkSize > 0);
Result := Result and DataSource.Dataset.BookmarkValid(Bookmark)
except
Result := False;
end;
end;
function TDCCustomDBGrid.GetBorderStyle: TEdgeBorderStyle;
begin
if not((dgColLines in Options) and (dgRowLines in Options)) then
begin
if dgFlatButtons in Options then
Result := ebsShadowFlat
else
Result := ebsNone
end
else begin
if ColorToRGB(Color) = ColorToRGB(FixedColor) then
Result := ebsNone
else
begin
if dgFlatButtons in Options then
Result := ebsFlat
else
Result := ebsNormal;
end;
end;
end;
function TDCCustomDBGrid.GroupingEnabled: boolean;
begin
Result := False;
end;
function TDCCustomDBGrid.FlatButtons: boolean;
begin
Result := dgFlatButtons in Options;
end;
procedure TDCCustomDBGrid.DoColumnClick(Shift: TShiftState;
ColIndex: integer);
var
i: integer;
begin
inherited;
if (RawToDataColumn(ColIndex) < Columns.Count) then
begin
if Columns[RawToDataColumn(ColIndex)].Indexed then
for i := 0 to Columns.Count-1 do
begin
if i = RawToDataColumn(ColIndex) then
begin
if Columns[i].IndexStyle < High(TColumnIndexStyle)
then Columns[i].IndexStyle := Succ(Columns[i].IndexStyle)
else Columns[i].IndexStyle := Pred(Columns[i].IndexStyle);
InvalidateCell(DataToRawColumn(i),0);
end
else
if not(ssShift in Shift) then
begin
if Columns[i].Indexed and
(Columns[i].IndexStyle <> Low(TColumnIndexStyle))
then begin
Columns[i].IndexStyle := Low(TColumnIndexStyle);
InvalidateCell(DataToRawColumn(i),0);
end;
end;
end;
TitleClick(Columns[RawToDataColumn(ColIndex)])
end;
end;
procedure TDCCustomDBGrid.CreateCellDragImage(ACol, ARow: integer;
var DragImages: TImageList);
const
DragTextOffset = 5;
var
ABitmap: TBitmap;
AText: string;
P: TPoint;
R, ARect: TRect;
begin
inherited;
exit;
if Columns.Count > 0 then
begin
AText := GetDataValue(Columns[0]);
ABitmap := TBitmap.Create;
R := Rect(0, 0, 500, 0);
P := DrawHighLightText(Canvas, PChar(AText), R, 0, DT_LEFT);
P.X := Columns[0].Width;
Inc(P.X, DragTextOffset + DragTextOffset div 2);
with ABitmap do
begin
Width := _intMin(P.X, 200);
Height := _intMax(P.Y, DefaultRowHeight);
ARect := Rect(0, 0, Width, Height);
Canvas.Brush.Color := FixedColor;
Canvas.Font.Assign(Font);
Canvas.FillRect(ARect);
DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_RECT);
ARect.Top := (ARect.Top + ARect.Bottom - P.Y) div 2;
ARect.Left := DragTextOffset;
ARect.Right := ARect.Right - DragTextOffset;
DrawHighLightText(Canvas, PChar(AText), ARect, 1, DT_LEFT or DT_END_ELLIPSIS);
end;
if DragImages = nil then
begin
DragImages := TImageList.CreateSize(ABitmap.Width, ABitmap.Height);
DragImages.AddMasked(ABitmap, clNone);
end;
end;
end;
procedure TDCCustomDBGrid.SelectItems(Mode: TSelectMode);
begin
case Mode of
smSelect: FBookmarks.SelectAll;
smDeselect: FBookmarks.Clear;
end;
end;
function TDCCustomDBGrid.CanColResize(ACol: integer): boolean;
var
i: integer;
begin
Result := inherited CanColResize(ACol);
i := RawToDataColumn(ACol);
if Result and (i >= 0) then
with Columns[i] do Result := Visible and (Resize or (csDesigning in ComponentState));
end;
procedure TDCCustomDBGrid.SetOptionsEx(const Value: TDBGridOptionsEx);
var
ChangedOptions: TDBGridOptionsEx;
begin
if FOptionsEx <> Value then
begin
ChangedOptions := (FOptionsEx + Value) - (FOptionsEx * Value);
FOptionsEx := Value;
if [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText] * ChangedOptions <> [] then
begin
invalidate;
end;
end;
end;
procedure TDCCustomDBGrid.CellDblClick(Column: TColumn);
begin
if Assigned(FOnCellDblClick) then FOnCellDblClick(Column);
end;
end.