////////////////////////////////////////////////// // CRControls // Copyright (c) 2000-2006 Core Lab. All right reserved. // CRGrid component ////////////////////////////////////////////////// {$IFNDEF CLR} {$I CRGrid.inc} unit CRGrid; {$ENDIF} interface uses {$IFDEF VER6P} Variants, {$ENDIF} Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, DBGrids, DB, StdCtrls, Menus, DBAccess, ComCtrls; type TCRDBGrid = class; { TCRColumn } TSortOrder = (soNone, soAsc, soDesc); TSummaryMode = (smNone, smSum, smAvr, smMax, smMin, smLabel); TOnMemoClick = procedure (Sender: TObject; Column: TColumn) of object; TCRColumnTitle = class(TColumnTitle) private function GetCaption: string; function IsCaptionStored: boolean; protected procedure SetCaption(const Value: string); published property Caption: string read GetCaption write SetCaption stored IsCaptionStored; end; TCRColumn = class (TColumn) private FMinWidth: integer; FTotalString: string; FTotalValue: Variant; FTotalLoaded: boolean; FSummaryMode: TSummaryMode; FTotalFloat: extended; FTotalInt: int64; FFloatDigits: integer; FFloatPrecision: integer; FFloatFormat: TFloatFormat; FFilterExpression: string; FTableSpacePercent: double; function GetSortOrder: TSortOrder; procedure SetSortOrder(Value: TSortOrder); function GetSortSequence: integer; procedure SetSortSequence(Value: integer); function GetTotalString: string; function GetTotalValue: Variant; procedure SetSummaryMode(Value: TSummaryMode); procedure SetFloatDigits(const Value: integer); procedure SetFloatFormat(const Value: TFloatFormat); procedure SetFloatPrecision(const Value: integer); procedure SetFilterExpression(const Value: string); procedure SetWidth(const Value: integer); function GetWidth: integer; procedure SetVisible(Value: Boolean); function GetVisible: Boolean; procedure ResetTotal; procedure LoadTotal; procedure SetTotal; function CanBeSorted: boolean; protected function CreateTitle: TColumnTitle; override; procedure ChangedTitle(Rebild: boolean); function GetFilterExpression(const RawFilter: string): string; public constructor Create(Collection: TCollection); override; procedure Assign(Source: TPersistent); override; property TotalString: string read GetTotalString write FTotalString; property TotalValue: Variant read GetTotalValue; published property Width: integer read GetWidth write SetWidth; property Visible: Boolean read GetVisible write SetVisible; property FilterExpression: string read FFilterExpression write SetFilterExpression; property MinWidth: integer read FMinWidth write FMinWidth default 0; property SortOrder: TSortOrder read GetSortOrder write SetSortOrder default soNone; property SortSequence: integer read GetSortSequence write SetSortSequence default 0; property SummaryMode: TSummaryMode read FSummaryMode write SetSummaryMode default smNone; property FloatFormat: TFloatFormat read FFloatFormat write SetFloatFormat default ffGeneral; property FloatPrecision: integer read FFloatPrecision write SetFloatPrecision default 0; property FloatDigits: integer read FFloatDigits write SetFloatDigits default 0; end; TCRDBGridColumns = class(TDBGridColumns) private function GetColumn(Index: Integer): TCRColumn; procedure SetColumn(Index: Integer; Value: TCRColumn); procedure ColumnAdded; public property Items[Index: Integer]: TCRColumn read GetColumn write SetColumn; default; end; { TGridTitleEdit } TCRGridTitleEdit = class(TCustomStaticText) private FCRDBGrid: TCRDBGrid; FEdit: TEdit; FAsFilter: boolean; FActiveColumn: TColumn; FFilterExpressions: array of string; FEditingFilter: boolean; procedure SetCRDBGrid(const Value: TCRDBGrid); procedure FEditKeyPress(Sender: TObject; var Key: char); procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL; procedure FEditKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); procedure FEditChange(Sender: TObject); procedure FEditExit(Sender: TObject); procedure ProcessEdit; procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; procedure GotoUpperCell; procedure GotoLowerCell; procedure GotoNextCell; procedure GotoPrevCell; procedure SetEditingFilter(const Value: boolean); procedure PostFilter; protected procedure PaintWindow(DC: HDC); override; procedure KeyDown(var Key: word; Shift: TShiftState); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override; procedure DoExit; override; procedure WMChar(var Message: TWMChar); message WM_CHAR; public constructor Create(AOwner: TComponent); override; procedure SetFocus; override; procedure ActivateAt(ARect: TRect; ActiveColumn: TColumn; AsFilter: boolean); procedure SetClientRect(ARect: TRect); procedure StartEdit; procedure StopEdit(AcceptChanges: boolean); property CRDBGrid: TCRDBGrid read FCRDBGrid write SetCRDBGrid; property Edit: TEdit read FEdit; property EditingFilter: boolean read FEditingFilter write SetEditingFilter; end; { TMemoEditorForm } TMemoEditorForm = class (TCustomForm) private FMemo: TMemo; FOKBtn: TButton; FCancelBtn: TButton; FReadOnly: boolean; FCheckBox: TCheckBox; procedure SetReadOnly(const Value: boolean); procedure MemoKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); procedure CheckBoxClick(Sender: tobject); public constructor Create(AOwner: TComponent); override; function CloseQuery: boolean; override; property ReadOnly: boolean read FReadOnly write SetReadOnly; end; { TCRDBGrid } TCRDBGridOptionEx = (dgeEnableSort, dgeFilterBar, dgeLocalFilter, {$IFNDEF DAC450}dgeLocalSorting, {$ENDIF}dgeRecordCount, dgeSearchBar, dgeStretch, dgeSummary); TCRDBGridOptionsEx = set of TCRDBGridOptionEx; TGridDrawStateEx = set of (geHighlight, geActiveRow, geMultiSelected); TGetCellParamsEvent = procedure (Sender: TObject; Field: TField; AFont: TFont; var Background: TColor; State: TGridDrawState; StateEx: TGridDrawStateEx) of object; TSortColInfo = class public Index: integer; Desc: boolean; end; TIndicatorColButton = (icbNone, icbMenu, icbFilter, icbSearch); {$IFDEF VER6P} TCRGridDataLink = class(TGridDataLink) protected FDataSetChanging: boolean; procedure DataSetChanged; override; end; {$ENDIF} TCRDBGrid = class(TCustomDBGrid) private FDefaultDrawing: boolean; FOptionsEx: TCRDBGridOptionsEx; FSoft: boolean; FOnGetCellParams: TGetCellParamsEvent; FExecSorting: boolean; FExecColAjust: boolean; FSortInfo: TList; FActiveRowSelected: boolean; FTitleButtonDown: integer; FTitleBarUp: boolean; FOldTitleButtonDown: integer; FCellButtonDown: integer; FCellButtonRow: integer; FCellButtonCol: integer; FCellButtonPressed: boolean; FCellButtonRect: TRect; FCellButtonBRect: TRect; FTotalYOffset: integer; FOnMemoClick: TOnMemoClick; FLevelDelimiterChar: char; FIndicatorColBtnDown: TIndicatorColButton; FOldIndicatorColBtnDown: TIndicatorColButton; FOptionsMenu: TPopupMenu; FOptionsMenuDef: TPopupMenu; CRGridTitleEdit: TCRGridTitleEdit; FStatusRect: TRect; FFiltered: boolean; FContinueEditingFilter: boolean; FMemoWidth: integer; FMemoHeight: integer; FMemoWordWrap: boolean; procedure SetOptionsEx(Value: TCRDBGridOptionsEx); procedure UpdateHeaderHeight; procedure RecordChanged(Field: TField); procedure DrawButton(X,Y: integer; State: boolean); function IsOnButton(X, Y: integer): boolean; function GetButtonRect(Cell: TGridCoord): TRect; procedure SetLevelDelimiterchar(const Value: char); procedure WMSetCursor(var Message: TWMSetCursor); message WM_SetCursor; function CalcSearchBar(Column: TColumn): TRect; function CalcFilterBar(Column: TColumn): TRect; function MouseInFilterBar(X, Y: integer; Column: TColumn = nil): boolean; function MouseInFilterEdit(X, Y: integer; Column: TColumn = nil): boolean; function MouseInSortBar(X, Y: integer; Column: TColumn = nil): boolean; function MouseInSortEdit(X,Y: integer;Column: TColumn = nil): boolean; function MouseInLowerstLevel(X, Y: integer; Column: TColumn = nil): boolean; procedure DoOnMemoClick(Column: TColumn); procedure DrawTitleBarCell(Canvas: TCanvas; Column: TColumn; Rect: TRect; Text: string); procedure DrawTitleIndicatorCell(Canvas: TCanvas; ARect: TRect); function GetIndicatorButton(X,Y: integer): TIndicatorColButton; procedure IndicatorClick(Button: TIndicatorColButton; X, Y: integer); procedure BuildMenu; procedure FilteredItemClick(Sender: TObject); procedure FilterItemClick(Sender: TObject); procedure SearchItemClick(Sender: TObject); procedure CalcTableSpacePercent; procedure SetFiltered(const Value: boolean); procedure UpdateRowCount; function GetColumns: TCRDBGridColumns; procedure SetColumns(const Value: TCRDBGridColumns); protected FHeaderHeight: integer; FExecSizing: boolean; function GetClientRect: TRect; override; procedure Loaded; override; function CreateColumns: TDBGridColumns; override; {$IFDEF VER6P} function CreateDataLink: TGridDataLink; override; {$ENDIF} procedure Reorder; function FindSortColInfo(Index: integer; var SortNum: integer): TSortColInfo; procedure ColWidthsChanged; override; procedure Resize; override; procedure ResizeColumns(ResizedColumn: integer = -1); function EndColumnDrag(var Origin, Destination: integer; const MousePt: TPoint): boolean; override; procedure DrawColumnCell(const Rect: TRect; DataCol: integer; Column: TColumn; State: TGridDrawState); override; procedure GetCellProps(Field: TField; AFont: TFont; var Background: TColor; State: TGridDrawState; StateEx:TGridDrawStateEx); dynamic; procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; 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 LinkActive(Value: boolean); override; procedure Paint;override; procedure ResetTotals; procedure LoadTotals; function CanEditShow: boolean; override; procedure TopLeftChanged; override; procedure DoExit; override; procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL; procedure TitleClick(Column: TColumn); override; procedure MoveColRow(ACol, ARow: Longint; MoveAnchor, Show: Boolean); function DataToRawColumn(ACol: Integer): Integer; procedure InvalidateCol(ACol: Longint); procedure InvalidateRow(ARow: Longint); procedure LayoutChanged; override; property DefaultRowHeight; property DataLink; public function GetGridSize: integer; constructor Create(Owner: TComponent); override; procedure DataChanged; //override; destructor Destroy; override; procedure ClearSorting; procedure ClearFilters; procedure ActivateFilterEdit(Column: TColumn); procedure ActivateSearchEdit(Column: TColumn); property Canvas; property SelectedRows; procedure CalcTitleLevel(Level: integer; var aRect: TRect); function GetTitleLevel(Level: integer): TRect; procedure ApplyFilter; procedure AdjustColumns; property Col; property Row; property TopRow; property LeftCol; property OptionsMenu: TPopupMenu read FOptionsMenu write FOptionsMenu; published property DefaultDrawing: boolean read FDefaultDrawing write FDefaultDrawing default True; property LevelDelimiterChar: char read FLevelDelimiterchar write SetLevelDelimiterchar default '|'; property Filtered: boolean read FFiltered write SetFiltered default True; property OptionsEx: TCRDBGridOptionsEx read FOptionsEx write SetOptionsEx default [dgeEnableSort, dgeLocalFilter, {$IFNDEF DAC450}dgeLocalSorting, {$ENDIF}dgeRecordCount]; property OnMemoClick: TOnMemoClick read FOnMemoClick write FOnMemoClick; property OnGetCellParams: TGetCellParamsEvent read FOnGetCellParams write FOnGetCellParams; property Align; property Anchors; property BiDiMode; property BorderStyle; property Color; property Columns: TCRDBGridColumns read GetColumns write SetColumns stored False; property Constraints; property Ctl3D; property DataSource; property DragCursor; property DragMode; property Enabled; property FixedColor; property Font; property ImeMode; property ImeName; property Options; 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 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 OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDock; property OnStartDrag; property OnTitleClick; end; resourcestring SFiltered = 'Filtered'; SFilterBar = 'Filter bar'; SSearchBar = 'Search bar'; sWordWrap = 'Word Wrap'; SOK = '&OK'; SCancel = '&Cancel'; SClose = '&Close'; fmtModifiedWarning = 'Field "%s" is modified. Save?'; implementation uses Math, CRParser, MemDS {$IFDEF CLR} ,MemUtils ,System.Threading, Types, WinUtils {$ENDIF} ; {$R CRGrid.res} var bmpSortAsc: TBitmap; bmpSortDesc: TBitmap; DrawBitmap: TBitmap; bmpFilter: TBitmap; bmpSearch: TBitmap; bmpMenu: TBitmap; bmpActiveFilter: TBitmap; bmpEditMode: TBitmap; UserCount: integer; type TInthernalEdit = class(TEdit) end; {$IFNDEF CLR} _TCustomGrid = class(TCustomGrid) end; {$ENDIF} function GetCaptionDepth(const Str: string; Delim: char): integer; var i: integer; St: string; begin Result := 0; if Str = '' then Exit; Result := 1; i := Pos(Delim, Str); St := Str; while i > 0 do begin Inc(Result); St[i] := #255; i := Pos(Delim, St); end; end; function GetCaptionLevel(const Str: string; Level: integer; Delim: char): string; var i,j: integer; St: string; begin j := 0; Result := ''; if Str = '' then Exit; i := Pos(Delim, Str); St := Str; while (Level > 0) and (I > 0) do begin Dec(Level); St[i] := #255; if Level <= -2 then begin Result := Copy(St, j + 1, i - 1); exit; end; j := i; i := Pos(Delim, St); end; if Level <= 0 then begin if i = 0 then i := Length(St) + j else Dec(i); Result := Copy(Str, j + 1, i - j); exit; end; end; { TCRColumn } function TCRColumn.GetSortOrder: TSortOrder; var SortColInfo: TSortColInfo; NumSort: integer; begin if not CanBeSorted then begin Result := soNone; exit; end; SortColInfo := TCRDBGrid(Grid).FindSortColInfo(Index, NumSort); if SortColInfo <> nil then if SortColInfo.Desc then Result := soDesc else Result := soAsc else Result := soNone; end; procedure TCRColumn.SetSortOrder(Value: TSortOrder); var SortColInfo: TSortColInfo; NumSort: integer; begin if not CanBeSorted then Exit; SortColInfo := TCRDBGrid(Grid).FindSortColInfo(Index, NumSort); if SortColInfo <> nil then begin case Value of soNone: begin if NumSort > 0 then Dec(NumSort); TSortColInfo(TCRDBGrid(Grid).FSortInfo[NumSort]).Free; TCRDBGrid(Grid).FSortInfo.Delete(NumSort) end; soAsc: SortColInfo.Desc := False; soDesc: SortColInfo.Desc := True; end; TCRDBGrid(Grid).Reorder; end else if Value <> soNone then begin SortColInfo := TSortColInfo.Create; SortColInfo.Index := Index; SortColInfo.Desc := Value = soDesc; TCRDBGrid(Grid).FSortInfo.Add(SortColInfo); TCRDBGrid(Grid).Reorder; end; end; function TCRColumn.GetSortSequence: integer; begin TCRDBGrid(Grid).FindSortColInfo(Index, Result); end; procedure TCRColumn.SetFilterExpression(const Value: string); begin FFilterExpression := Value; end; procedure TCRColumn.SetSortSequence(Value: integer); begin end; function TCRColumn.GetTotalString: string; begin if Assigned(Field) and (Field.DataSet.Active) then if (FSummaryMode = smNone) then Result := '' else begin if not FTotalLoaded then LoadTotal; Result := FTotalString end else Result := ''; end; function TCRColumn.GetTotalValue: Variant; begin Result := Unassigned; if Assigned(Field) and (Field.DataSet.Active) then if (SummaryMode = smLabel) then Result := FTotalString else if (FSummaryMode = smNone) then Result := Unassigned else begin if not FTotalLoaded then LoadTotal; Result := FTotalValue end else Result := Unassigned; end; procedure TCRColumn.ResetTotal; begin FTotalLoaded := False; end; procedure TCRColumn.LoadTotal; begin if (SummaryMode <> smLabel) and Assigned (Field) then begin TCRDBGrid(Grid).LoadTotals; if Assigned (Field) then case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: if SummaryMode = smAvr then begin FTotalValue := FTotalFloat; FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits) end else begin FTotalValue := {$IFNDEF VER6P}Integer({$ENDIF}FTotalInt{$IFNDEF VER6P}){$ENDIF}; FTotalString := IntToStr(FTotalInt); end; ftFloat, ftCurrency: begin FTotalValue := FTotalFloat; FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); end; else begin FTotalValue := Unassigned; FTotalString := ''; end; end end; end; procedure TCRColumn.SetSummaryMode(Value: TSummaryMode); begin if Value <> smNone then if (Value <> smLabel) and Assigned(Field) then if not (Field.DataType in [ftSmallint, ftInteger, ftWord, ftLargeint, ftFloat, ftCurrency]) then Value := smNone; if FSummaryMode <> Value then begin FSummaryMode := Value; ResetTotal; if Assigned(Grid) then Grid.Invalidate; end; end; procedure TCRColumn.SetTotal; begin FTotalLoaded := True; if (SummaryMode <> smLabel) and Assigned (Field) then case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: if SummaryMode = smAvr then begin FTotalValue := FTotalFloat; FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits) end else begin FTotalValue := {$IFNDEF VER6P}Integer({$ENDIF}FTotalInt{$IFNDEF VER6P}){$ENDIF}; FTotalString := IntToStr(FTotalInt); end; ftFloat, ftCurrency: begin FTotalValue := FTotalFloat; FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); end; else begin FTotalValue := Unassigned; FTotalString := ''; end; end end; procedure TCRColumn.SetFloatDigits(const Value: integer); begin FFloatDigits := Value; if (SummaryMode <> smLabel) and Assigned (Field) then begin case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: if SummaryMode = smAvr then FTotalString := FloatToStrF(FTotalFloat,FFloatFormat,FFloatPrecision,FFloatDigits); ftFloat, ftCurrency: FTotalString := FloatToStrF(FTotalFloat,FFloatFormat,FFloatPrecision,FFloatDigits); end; if Assigned(Grid)then Grid.Invalidate; end; end; procedure TCRColumn.SetFloatFormat(const Value: TFloatFormat); begin FFloatFormat := Value; if (SummaryMode <> smLabel) and Assigned(Field) then begin case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: if SummaryMode = smAvr then FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); ftFloat, ftCurrency: FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); end; if Assigned(Grid) then Grid.Invalidate; end; end; procedure TCRColumn.SetFloatPrecision(const Value: integer); begin FFloatPrecision := Value; if (SummaryMode <> smLabel) and Assigned(Field) then begin case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: if SummaryMode = smAvr then FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); ftFloat, ftCurrency: FTotalString := FloatToStrF(FTotalFloat, FFloatFormat, FFloatPrecision, FFloatDigits); end; if Assigned(Grid) then Grid.Invalidate; end; end; procedure TCRColumn.Assign(Source: TPersistent); begin if Source is TCRColumn then begin if Assigned(Collection) then Collection.BeginUpdate; inherited Assign(Source); try FSummaryMode := TCRColumn(Source).FSummaryMode; FMinWidth := TCRColumn(Source).FMinWidth; FTotalString := TCRColumn(Source).FTotalString; FTotalValue := TCRColumn(Source).FTotalValue; FTotalLoaded := TCRColumn(Source).FTotalLoaded; FSummaryMode := TCRColumn(Source).FSummaryMode; FTotalFloat := TCRColumn(Source).FTotalFloat; FTotalInt := TCRColumn(Source).FTotalInt; FFloatDigits := TCRColumn(Source).FFloatDigits; FFloatPrecision := TCRColumn(Source).FFloatPrecision; FFloatFormat := TCRColumn(Source).FFloatFormat; finally if Assigned(Collection) then Collection.EndUpdate; end; end else inherited Assign(Source); end; function TCRColumn.CanBeSorted: boolean; begin if Assigned(Field) then Result := {$IFNDEF DAC600} (Field.FieldKind = fkData) and {$ENDIF} not (Field.DataType in [ftFmtMemo, ftMemo{$IFNDEF VER4}, ftOraClob {$ENDIF}]) else Result := False; end; function TCRColumn.GetFilterExpression(const RawFilter: string): string; function GetSignString(var ConstStr: string): string; var Buf: string; begin Result := ''; ConstStr := ''; Buf := Trim(RawFilter); if Buf = '' then Exit; case Buf[1] of '=': begin Result := '='; ConstStr := Copy(Buf, 2, Length(Buf) - 1); end; '<', '>': begin if (Length(Buf) >= 2) and ((Buf[2] = '=') or (Buf[2] = '>')) then begin Result := Copy(Buf, 1, 2); ConstStr := Copy(Buf, 3, Length(Buf) - 2); end else begin Result := Buf[1]; ConstStr := Copy(Buf, 2, Length(Buf) - 1); end; end; else begin Result := '='; ConstStr := Copy(Buf, 1, Length(Buf)); end; end; ConstStr := TrimLeft(ConstStr); end; var Sign, ConstStr: string; s: string; i: integer; begin Result := ''; if RawFilter = '' then Exit; if Assigned (Field) then begin Sign := GetSignString(ConstStr); if (Sign = '') or (ConstStr = '') then Exit; case Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: StrToInt(ConstStr); // test for exception ftFloat, ftCurrency: StrToFloat(ConstStr); // test for exception ftDate: begin StrToDate(ConstStr); // test for exception ConstStr := '''' + ConstStr + ''''; end; ftDateTime: begin StrToDateTime(ConstStr); // test for exception ConstStr := '''' + ConstStr + ''''; end; ftTime: begin StrToTime(ConstStr); // test for exception ConstStr := '''' + ConstStr + ''''; end; ftString,ftWideString: begin if not (dgeLocalFilter in TCRDBGrid(Grid).OptionsEx) and ((Sign = '=') or (Sign = '<>')) then begin for i := 1 to Length(ConstStr) do if ConstStr[i] = '*' then ConstStr[i] := '%'; if Sign = '=' then Sign := ' LIKE ' else Sign := ' NOT LIKE '; end; if (Field.DataSet is TCustomDADataSet) and (TCustomDADataSet(Field.DataSet).Options.QuoteNames) then Result := TDBAccessUtils.QuoteName(TCustomDADataSet(Field.DataSet), Field.FieldName) + Sign + AnsiQuotedStr(ConstStr,'''') else Result := Field.FieldName + Sign + AnsiQuotedStr(ConstStr,''''); Exit; end; ftBoolean: begin /// (cr12227) if (TBooleanField(Field).DisplayValues <> '') and (pos(';', TBooleanField(Field).DisplayValues) > 0) then begin s := copy(TBooleanField(Field).DisplayValues, 0, pos(';', TBooleanField(Field).DisplayValues) - 1); if AnsiUpperCase(ConstStr) = AnsiUpperCase(s) then begin result := Field.FieldName + Sign + 'True'; Exit; end else begin s := copy(TBooleanField(Field).DisplayValues, pos(';', TBooleanField(Field).DisplayValues) + 1, length(TBooleanField(Field).DisplayValues)); if AnsiUpperCase(ConstStr) = AnsiUpperCase(s) then begin result := Field.FieldName + Sign + 'False'; Exit; end; end; end; end; end; end; Result := Field.FieldName + Sign + ConstStr; end; procedure TCRColumn.ChangedTitle(Rebild: boolean); begin if Rebild then if Assigned(Grid) then TCRDBGrid(Grid).LayoutChanged; end; function TCRColumn.CreateTitle: TColumnTitle; begin Result := TCRColumnTitle.Create(Self); end; constructor TCRColumn.Create(Collection: TCollection); begin inherited; FMinWidth := 0; TCRDBGridColumns(Collection).ColumnAdded; end; procedure TCRColumn.SetWidth(const Value: integer); begin if Value > FMinWidth then inherited Width := Value else inherited Width := FMinWidth //if assigned(grid) then // FTableSpaceProcent := Width / TCRDBGrid(grid).GetGridSize; end; function TCRColumn.GetWidth: integer; begin Result := inherited Width; end; procedure TCRColumn.SetVisible(Value: Boolean); var OldVisible: boolean; begin OldVisible := inherited Visible; inherited Visible := Value; if (OldVisible <> Value) and Assigned(Grid) and (dgeStretch in TCRDBGrid(Grid).OptionsEx) and (not TCRDBGrid(Grid).FExecSizing) then begin TCRDBGrid(Grid).FExecSizing := True; TCRDBGrid(Grid).ResizeColumns; TCRDBGrid(Grid).FExecSizing := False; end; end; function TCRColumn.GetVisible: Boolean; begin Result := inherited Visible; end; { TCRDBGridColumns } function TCRDBGridColumns.GetColumn(Index: Integer): TCRColumn; begin Result := TCRColumn(inherited Items[Index]); end; procedure TCRDBGridColumns.SetColumn(Index: Integer; Value: TCRColumn); begin inherited Items[Index] := Value; end; procedure TCRDBGridColumns.ColumnAdded; begin TCRDBGrid(Grid).CalcTableSpacePercent; end; { TCRDBGrid } procedure UsesBitmap; begin if UserCount = 0 then DrawBitmap := TBitmap.Create; Inc(UserCount); end; procedure ReleaseBitmap; begin Dec(UserCount); if UserCount = 0 then DrawBitmap.Free; end; constructor TCRDBGrid.Create(Owner: TComponent); begin inherited Create(Owner); Columns.State := csDefault; FSortInfo := TList.Create; FOptionsMenuDef := TPopupMenu.Create(Self); FFiltered := True; UsesBitmap; FOnMemoClick := nil; FLevelDelimiterChar := '|'; inherited DefaultDrawing := False; FDefaultDrawing := True; FSoft := False; SetOptionsEx([dgeEnableSort, dgeLocalFilter, {$IFNDEF DAC450}dgeLocalSorting, {$ENDIF}dgeRecordCount]); DefaultColWidth := 60; // DEBUG FExecSizing := False; FTitleButtonDown := -1; FOldTitleButtonDown := -1; FIndicatorColBtnDown := icbNone; FOldIndicatorColBtnDown := icbNone; FCellButtonDown := -1; CRGridTitleEdit := TCRGridTitleEdit.Create(Self); InsertControl(CRGridTitleEdit); BuildMenu; end; procedure TCRDBGRid.ActivateSearchEdit(Column: TColumn); var CellRect: TRect; begin if not (Assigned(Column) and (dgeSearchBar in OptionsEx)) then Exit; CellRect := CalcSearchBar(Column); InflateRect(CellRect, -5, -5); if not (dgRowLines in Options) then Dec(CellRect.Top); CRGridTitleEdit.ActivateAt(CellRect, Column, False); end; destructor TCRDBGrid.Destroy; begin ReleaseBitmap; ClearSorting; ClearFilters; FSortInfo.Free; FOptionsMenuDef.Free; inherited; end; procedure TCRDBGrid.Loaded; var Stretched: Boolean; begin Stretched := False; if dgeStretch in OptionsEx then begin Stretched := True; Exclude(FOptionsEx, dgeStretch); end; inherited; if Stretched then Include(FOptionsEx, dgeStretch); CalcTableSpacePercent; FOptionsMenuDef.Items[0].Checked := FFiltered; FOptionsMenuDef.Items[2].Checked := dgeFilterBar in OptionsEx; FOptionsMenuDef.Items[3].Checked := dgeSearchBar in OptionsEx; end; function TCRDBGrid.CreateColumns: TDBGridColumns; begin Result := TCRDBGridColumns.Create(Self, TCRColumn); end; {$IFDEF VER6P} function TCRDBGrid.CreateDataLink: TGridDataLink; begin Result := TCRGridDataLink.Create(Self); end; {$ENDIF} procedure TCRDBGrid.Resize; begin inherited; CRGridTitleEdit.StopEdit(False); if (dgeStretch in FOptionsEx) and not(csLoading in ComponentState) and (not FExecSizing) then begin FExecSizing := True; try ResizeColumns; finally FExecSizing := False; end; end; if CRGridTitleEdit.Focused then begin if CRGridTitleEdit.FAsFilter then ActivateFilterEdit(CRGridTitleEdit.FActiveColumn) else ActivateSearchEdit(CRGridTitleEdit.FActiveColumn); end; Invalidate; end; procedure TCRDBGrid.ColWidthsChanged; var i: integer; ResizedColumn: integer; begin if (dgeStretch in FOptionsEx) and not(csLoading in ComponentState) and (not FExecSizing) then begin FExecSizing := True; ResizedColumn := -1; for i := 0 to Columns.Count - 1 do if ColWidths[i + IndicatorOffset] <> Columns[i].Width then begin ResizedColumn := i; break; end; if ResizedColumn <> -1 then begin if ColWidths[ResizedColumn + IndicatorOffset] <= TCRColumn(Columns[ResizedColumn]).MinWidth then ColWidths[ResizedColumn + IndicatorOffset] := TCRColumn(Columns[ResizedColumn]).MinWidth; ResizeColumns(ResizedColumn); //ResizeColumns(-1); end; FExecSizing := False; end else if not (csLoading in ComponentState) and (not FExecSizing) then CalcTableSpacePercent; inherited; end; function TCRDBGrid.GetGridSize: integer; begin Result := ClientWidth - 1; if dgIndicator in Options then Dec(Result, IndicatorWidth); if dgColLines in Options then Dec(Result, Columns.Count*GridLineWidth); end; procedure TCRDBGrid.ResizeColumns(ResizedColumn: integer); const MinWidth = 10; var i: integer; GridSize, ColumnsSize:integer; UnresizedSize: integer; K: double; Curr,Prev: double; Width: integer; MinimizeRest: boolean; VisiblePercent: double; //Sized : integer; function Max(i1,i2: integer): integer; begin if i1 > i2 then Result := i1 else Result := i2 end; begin if Columns.Count = 0 then Exit; GridSize := ClientWidth - 1; if dgIndicator in Options then Dec(GridSize, IndicatorWidth); if dgColLines in Options then for i := 0 to Columns.Count - 1 do if TCRColumn(Columns[i]).Visible then Dec(GridSize, GridLineWidth); if ResizedColumn > -1 then begin ColumnsSize := 0; UnresizedSize := 0; MinimizeRest := False; for i := 0 to Columns.Count - 1 do begin if i <= ResizedColumn then begin Inc(UnresizedSize, ColWidths[i + IndicatorOffset]); if i = ResizedColumn then if ColumnsSize + ColWidths[i + IndicatorOffset] + (Columns.Count - i) * MinWidth > GridSize then begin ColWidths[i + IndicatorOffset] := GridSize - ColumnsSize - (Columns.Count - i - 1) * MinWidth; MinimizeRest := True; end else if i = Columns.Count - 1 then ColWidths[i + IndicatorOffset] := GridSize - ColumnsSize; end else if MinimizeRest {(ResizedColumn >= 0) and (ColumnsSize + (Columns.Count - i)*MinWidth >= GridSize)} then ColWidths[i + IndicatorOffset] := MinWidth; Inc(ColumnsSize, ColWidths[i + IndicatorOffset]); end; if ColumnsSize = UnresizedSize then Exit; K := (GridSize - UnresizedSize) / (ColumnsSize - UnresizedSize); ColumnsSize := 0; Prev := 0; for i := 0 to Columns.Count - 1 do begin if i <= ResizedColumn then Curr := Prev + ColWidths[i + IndicatorOffset] else begin Curr := Prev + ColWidths[i + IndicatorOffset]*K; if i < Columns.Count - 1 then Width := Round(Curr - Prev) else Width := GridSize - ColumnsSize; if Width < TCRColumn(Columns[i]).MinWidth then Width := TCRColumn(Columns[i]).MinWidth; ColWidths[i + IndicatorOffset] := Width; end; Inc(ColumnsSize, ColWidths[i + IndicatorOffset]); Prev := Curr; end; CalcTableSpacePercent; end else begin // for full resize Inc(GridSize,2); if (dgeStretch in FOptionsEx) then begin VisiblePercent := 0; for i := 0 to Columns.Count - 1 do if TCRColumn(Columns[i]).Visible then VisiblePercent := VisiblePercent + TCRColumn(Columns[i]).FTableSpacePercent; if VisiblePercent < 0.0001 then VisiblePercent := 1; end else VisiblePercent := 1; for i := 0 to Columns.Count - 1 do ColWidths[i + IndicatorOffset] := Trunc(TCRColumn(Columns[i]).FTableSpacePercent * GridSize / VisiblePercent); end; end; { Grid drawing } procedure TCRDBGrid.GetCellProps(Field: TField; AFont: TFont; var Background: TColor; State: TGridDrawState; StateEx: TGridDrawStateEx); begin if Assigned(FOnGetCellParams) then FOnGetCellParams(Self, Field, AFont, Background, State, StateEx); end; procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: integer; const Text: string; Alignment: TAlignment; ARightToLeft: boolean); const AlignFlags : array [TAlignment] of integer = ( DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX, DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX, DT_CENTER or DT_WORDBREAK 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 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 := Max(Width, Right - Left); Height := Max(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); 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; function TCRDBGrid.GetButtonRect(Cell: TGridCoord): TRect; var aCellRect: TRect; begin aCellRect := CellRect(Cell.X, Cell.Y); if (aCellRect.Right - aCellRect.Left < aCellRect.Bottom - aCellRect.Top + 5) then begin Result := Rect(0,0,0,0); exit; end; Result.Left := aCellRect.Right - (aCellRect.Bottom - aCellRect.Top)+1; Result.Right := aCellRect.Right-1; Result.Top := aCellRect.Top+1; Result.Bottom := aCellRect.Bottom-1; end; function TCRDBGrid.IsOnButton(X, Y: integer): boolean; var Cell: TGridCoord; Column: TColumn; aCellRect: TRect; ButtonRect: TRect; begin Cell := MouseCoord(X,Y); Column := Columns[RawToDataColumn(Cell.X)]; // detecting - is there a button on cell? if Assigned(Column.Field) then Result := Column.Field.DataType in [ftMemo,ftFmtMemo {$IFNDEF VER4}, ftOraClob {$ENDIF}] else Result := False; aCellRect := CellRect(Cell.X, Cell.Y); //Result := Result and (gdSelected in State); if Result and (aCellRect.Right - aCellRect.Left < aCellRect.Bottom - aCellRect.Top + 5) then Result := False; if Result then begin // button present ButtonRect := GetButtonRect(Cell); Result := PtInRect(ButtonRect,Point(X,Y)) end else // there is no button on cell Result := False; end; procedure TCRDBGrid.DrawButton(X,Y: integer; State: boolean); var ButtonRect: TRect; Cell: TGridCoord; Hi, i, Diam: integer; Flag: integer; begin Cell.X := X; Cell.Y := Y; ButtonRect := GetButtonRect(Cell); Canvas.Brush.Style := bsSolid; Canvas.Brush.Color := clBtnFace; Canvas.FillRect(ButtonRect); Canvas.Pen.Color := clBlack; Canvas.Pen.Style := psSolid; Canvas.Brush.Color := clBlack; if State then Flag := BDR_SUNKENINNER else Flag := BDR_RAISEDINNER; DrawEdge(Canvas.Handle, ButtonRect, Flag, BF_TOPLEFT ); InflateRect(ButtonRect, -1, -1); DrawEdge(Canvas.Handle, ButtonRect, Flag, BF_BOTTOMRIGHT); InflateRect(ButtonRect, 1, 1); Canvas.MoveTo(ButtonRect.Left, ButtonRect.Bottom - 1); Canvas.LineTo(ButtonRect.Right - 1, ButtonRect.Bottom - 1); Canvas.LineTo(ButtonRect.Right - 1, ButtonRect.Top - 1); Diam := (ButtonRect.Bottom - ButtonRect.Top) div 7; Hi := (ButtonRect.Bottom - ButtonRect.Top - Diam) div 2; inc(ButtonRect.Left,Diam * 2 - 1); if State then begin inc(ButtonRect.Left); inc(ButtonRect.Top); end; for i := 0 to 2 do Canvas.Ellipse(ButtonRect.Left + i * Diam * 2 ,ButtonRect.Top + Hi, ButtonRect.Left + i * Diam * 2 + Diam, ButtonRect.Top + Hi + Diam); end; procedure TCRDBGrid.DrawColumnCell(const Rect: TRect; DataCol: integer; Column: TColumn; State: TGridDrawState); const ThreeDot = '...'; var NewBackgrnd: TColor; Field: TField; Value: string; TextWidth: integer; ThreeDotWidth: integer; Alignment: TAlignment; ColWidth: integer; StateEx: TGridDrawStateEx; TextMargin: integer; i: integer; isDrawButton: boolean; OldCanvasFont : TFont; begin Field := Column.Field; if Assigned(Column.Field) then begin Value := Column.Field.DisplayText; isDrawButton := Column.Field.DataType in [ftMemo, ftFmtMemo {$IFNDEF VER4}, ftOraClob {$ENDIF}]; end else begin Value := ''; isDrawButton := False; end; isDrawButton := isDrawButton and (gdSelected in State) and not (dgRowSelect in Options); if isDrawButton and (Rect.Right - Rect.Left < Rect.Bottom - Rect.Top + 5) then isDrawButton := False; Alignment := Column.Alignment; if Alignment = taRightJustify then TextMargin:= 4 else TextMargin := 2; ThreeDotWidth := Canvas.TextWidth(ThreeDot); TextWidth := Canvas.TextWidth(Value) + TextMargin; OldCanvasFont := TFont.Create; OldCanvasFont.Assign(Canvas.Font); try ColWidth := Column.Width; // changes font and brush Canvas.Font.Assign(OldCanvasFont); finally OldCanvasFont.Free; end; if isDrawButton then begin ColWidth := ColWidth - (Rect.Bottom - Rect.Top); end; if TextWidth > ColWidth then begin if Field is TNumericField then begin for i := 1 to Length(Value) do if (Value[i] >= '0') and (Value[i] <= '9') then Value[i] := '#'; end else begin while (TextWidth > ColWidth) and (Length(Value) > 1) do begin SetLength(Value, Length(Value) - 1); TextWidth := Canvas.TextWidth(Value) + TextMargin + ThreeDotWidth; end; Value := Value + ThreeDot; end; Alignment := taLeftJustify; end; if HighlightCell(Col, Row, Value, State) then begin Include(StateEx, geHighlight); if not FActiveRowSelected then Include(StateEx, geMultiSelected); end; if FActiveRowSelected then Include(StateEx, geActiveRow); if HighlightCell(Col, Row, Value, State) then begin Canvas.Brush.Color := clHighlight; Canvas.Font.Color := clHighlightText; end; if Enabled then begin NewBackgrnd := Canvas.Brush.Color; GetCellProps(Field, Canvas.Font, NewBackgrnd, State, StateEx); Canvas.Brush.Color := NewBackgrnd; end else Canvas.Font.Color := clGrayText; if FDefaultDrawing then WriteText(Canvas, Rect, 2, 2, Value, Alignment, UseRightToLeftAlignmentForField(Column.Field, Alignment)); if FDefaultDrawing and (gdSelected in State) and ((dgAlwaysShowSelection in Options) or Focused) and not (csDesigning in ComponentState) and not (dgRowSelect in Options) and (UpdateLock = 0) and (ValidParentForm(Self).ActiveControl = Self) then Windows.DrawFocusRect(Canvas.Handle, Rect); inherited DrawColumnCell(Rect, DataCol, Column, State); if isDrawButton then if FCellButtonDown > -1 then DrawButton(Col, Row, FCellButtonPressed) else DrawButton(COl, Row, False); end; procedure TCRDBGrid.ClearSorting; var i: integer; begin for i := 0 to FSortInfo.Count - 1 do TSortColInfo(FSortInfo[i]).Free; FSortInfo.Clear; end; procedure TCRDBGrid.ClearFilters; var i: integer; begin for i := 0 to Columns.Count - 1 do TCRColumn(Columns[i]).FilterExpression := ''; end; function TCRDBGrid.FindSortColInfo(Index: integer; var SortNum: integer): TSortColInfo; var i: integer; begin Result := nil; SortNum := 0; for i := 0 to FSortInfo.Count - 1 do if TSortColInfo(FSortInfo[i]).Index = Index then begin Result := TSortColInfo(FSortInfo[i]); if FSortInfo.Count > 1 then SortNum := i + 1; break; end; end; function TCRDBGrid.GetTitleLevel(Level: integer): TRect; begin if Columns.Count = 0 then begin Result := Rect(0, 0, 0, 0); Exit; end; Result.Top := Level*(DefaultRowHeight + 1); Result.Bottom := Result.Top + (DefaultRowHeight + 1); Result.Left := 0; Result.Right := 0; if dgRowLines in Options then dec(Result.Bottom); end; procedure TCRDBGrid.CalcTitleLevel(Level: integer; var aRect: TRect); var X: TRect; begin if Columns.Count = 0 then begin aRect.Top := 0; aRect.Bottom:= 0; Exit; end; X := GetTitleLevel(Level); aRect.Top := X.Top; aRect.Bottom := X.Bottom; end; procedure TCRDBGrid.DrawCell(ACol,ARow: longint; ARect: TRect; AState: TGridDrawState); var FrameOffs: Byte; procedure DrawTitleCell(ACol, ARow: integer; Column: TColumn; var AState: TGridDrawState); const ScrollArrows: array [boolean, boolean] of integer = ((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT)); var MasterCol: TColumn; CellRect: TRect; TitleRect, TextRect, ButtonRect: TRect; LastTextRect,LastTitleRect: TRect; i: integer; InBiDiMode: boolean; ArrowX, ArrowY: integer; SortColInfo: TSortColInfo; OldBkMode: integer; OldTextColor: TColor; SortNum: integer; Caption: string; CaptionWidth: integer; CharWidth: integer; CurLevel: integer; LevelHeight: integer; CurCaption: string; lvCheckLeft, lvCheckRight, lvShowCaption, lvUpBorder, lvDownBorder, lvLeftBorder, lvRightBorder, lvCheckTextWidth : boolean; TmpCaption: string; lvTmpCol: TColumn; lvTmpColIndex: integer; lvCaptionXOffset: integer; lvCaptionAligment : TAlignment; CellFlag: cardinal; CaptionDepth: integer; PressOffset: integer; begin CellRect := CalcTitleRect(Column, ARow, MasterCol); TitleRect := CellRect; if MasterCol = nil then begin Canvas.FillRect(ARect); Exit; end; // Prevent from drawing areas for SEARCH and FILTER Bars if dgeFilterBar in OptionsEx then dec(TitleRect.Bottom,DefaultRowHeight + 10); if dgeSearchBar in OptionsEx then dec(TitleRect.Bottom,DefaultRowHeight + 10); Canvas.Font := MasterCol.Title.Font; Canvas.Brush.Color := MasterCol.Title.Color; Canvas.FillRect(ARect); TextRect := TitleRect; Caption := MasterCol.Title.Caption; lvCheckLeft := True; lvCheckRight := True; lvShowCaption:= True; lvLeftBorder := True; lvRightBorder:= True; if TCRColumnTitle(MasterCol.Title).IsCaptionStored then CaptionDepth := GetCaptionDepth(Caption,FLevelDelimiterChar) else CaptionDepth := 1; FrameOffs := 1; if (Column.Index = FTitleButtonDown) and (dgRowLines in Options) then PressOffset := 1 else PressOffset := 0; for CurLevel := 0 to FHeaderHeight - 1 do begin // Check dependencies if TCRColumnTitle(MasterCol.Title).IsCaptionStored then CurCaption := GetCaptionLevel(Caption,CurLevel,FLevelDelimiterChar) else if CurLevel = 0 then CurCaption := Caption else CurCaption := ''; lvDownBorder := (FHeaderHeight - 1 = CurLevel) or (GetCaptionLevel(Caption,CurLevel+1,FLevelDelimiterChar)<>''); lvUpBorder := (CurCaption <> ''); lvCaptionXOffset := 0; if CurCaption <> '' then begin if lvCheckLeft then begin lvLeftBorder := True; lvShowCaption:= True; if (Column.Index = 0) or (CurLevel = (CaptionDepth-1)) then lvCheckLeft := False else begin lvTmpColIndex := Column.Index-1; while lvTmpColIndex >= 0 do begin lvTmpCol := TColumn(MasterCol.Collection.Items[lvTmpColIndex]); tmpCaption := GetCaptionLevel(lvTmpCol.Title.Caption,CurLevel,FLevelDelimiterChar); if UpperCase(tmpCaption) <> UpperCase(CurCaption) then begin if lvTmpColIndex = Column.Index - 1 then lvCheckLeft := False; break; end else begin lvShowCaption := False; lvLeftBorder := False; inc(lvCaptionXOffset, lvTmpCol.Width); if dgColLines in Options then inc(lvCaptionXOffset); dec(lvTmpColIndex) end; end; end; end; if lvCheckRight then begin lvRightBorder := True; if (Column.Index = MasterCol.Collection.Count - 1) or (CurLevel = (CaptionDepth-1)) then lvCheckRight := False else begin lvTmpColIndex := Column.Index+1; lvTmpCol := TColumn(MasterCol.Collection.Items[lvTmpColIndex]); tmpCaption := GetCaptionLevel(lvTmpCol.Title.Caption,CurLevel,FLevelDelimiterChar); if UpperCase(tmpCaption) <> UpperCase(CurCaption) then lvCheckRight := False else lvRightBorder := False; end; end; end; //Check if we need to control caption width if Column.Index = MasterCol.Collection.Count - 1 then lvCheckTextWidth := True else begin lvTmpColIndex := Column.Index+1; lvTmpCol := TColumn(MasterCol.Collection.Items[lvTmpColIndex]); tmpCaption := GetCaptionLevel(lvTmpCol.Title.Caption,CurLevel,FLevelDelimiterChar); if UpperCase(tmpCaption) <> UpperCase(CurCaption) then lvCheckTextWidth := True else lvCheckTextWidth := False; end; // draw text for level TitleRect := CellRect; CalcTitleLevel(CurLevel,TitleRect); TextRect := TitleRect; InflateRect(TextRect,-1,-1); if not lvRightBorder then begin inc(TextRect.Right); if (dgColLines in Options) then inc(TextRect.Right); end; if CurLevel <> (CaptionDepth-1) then begin Canvas.Font := Self.TitleFont; Canvas.Brush.Color := Self.FixedColor; lvCaptionAligment := taLeftJustify; end else begin Canvas.Font := MasterCol.Title.Font; Canvas.Brush.Color := MasterCol.Title.Color; lvCaptionAligment := MasterCol.Title.Alignment; end; Canvas.FillRect(TextRect); if lvShowCaption then begin CaptionWidth := Canvas.TextWidth(CurCaption); if lvCheckTextWidth and (CaptionWidth > TextRect.Right - TextRect.Left) then begin while (CaptionWidth > TextRect.Right - TextRect.Left) and (Length(CurCaption) > 1) do begin SetLength(CurCaption, Length(CurCaption) - 1); CaptionWidth := Canvas.TextWidth(CurCaption) + Canvas.TextWidth('...'); end; CurCaption := CurCaption + '...'; end; WriteText(Canvas, TextRect, FrameOffs + PressOffset, FrameOffs + PressOffset, CurCaption, lvCaptionAligment, IsRightToLeft); end else if CurCaption = '' then WriteText(Canvas, TextRect, FrameOffs, FrameOffs, '', lvCaptionAligment, IsRightToLeft) else begin // mean there is coninue of previous column if dgColLines in Options then begin dec(TextRect.Left,1); dec(lvCaptionXOffset,1); end; CaptionWidth := Canvas.TextWidth(CurCaption) - lvCaptionXOffset; if lvCheckTextWidth and (CaptionWidth > TextRect.Right - TextRect.Left) then begin while (CaptionWidth > TextRect.Right - TextRect.Left) and (Length(CurCaption) > 1) do begin SetLength(CurCaption, Length(CurCaption) - 1); CaptionWidth := Canvas.TextWidth(CurCaption) + Canvas.TextWidth('...') - lvCaptionXOffset; end; CurCaption := CurCaption + '...'; end; WriteText(Canvas, TextRect, FrameOffs - lvCaptionXOffset, FrameOffs, CurCaption, lvCaptionAligment, IsRightToLeft); end; // draw borders for level CellFlag := BDR_RAISEDINNER; if (FTitleButtonDown = Column.Index)and(CurLevel >= CaptionDepth-1) then CellFlag := BDR_SUNKENINNER; if not lvDownBorder then begin Inc(TitleRect.Bottom,1); Canvas.Pen.Color := clBtnFace; Canvas.MoveTo(TitleRect.Left,TitleRect.Bottom - 2); Canvas.LineTo(TitleRect.Right + 1, TitleRect.Bottom - 2); if dgRowLines in Options then begin Canvas.MoveTo(TitleRect.Left, TitleRect.Bottom - 1); Canvas.LineTo(TitleRect.Right + 1, TitleRect.Bottom - 1); end; end; if not lvUpBorder then begin Canvas.Pen.Color := clBtnFace; Canvas.MoveTo(TitleRect.Left, TitleRect.Top); Canvas.LineTo(TitleRect.Right + 1, TitleRect.Top); end; if lvRightBorder then begin if (dgRowLines in Options) and (dgColLines in Options) then DrawEdge(Canvas.Handle, TitleRect, CellFlag, BF_RIGHT); end else Inc(TitleRect.Right,1); if dgColLines in Options then begin Canvas.Pen.Color := clBlack; Canvas.MoveTo(TitleRect.Right, TitleRect.Top); Canvas.LineTo(TitleRect.Right, TitleRect.Bottom + 1); end; if lvDownBorder and ((dgRowLines in Options) and (dgColLines in Options)) then begin // if not(dgRowlines in Options) then // Inc(TitleRect.Bottom); DrawEdge(Canvas.Handle, TitleRect, CellFlag, BF_BOTTOM); end; if dgRowLines in Options then begin Canvas.Pen.Color := clBlack; Canvas.MoveTo(TitleRect.Left,TitleRect.Bottom); Canvas.LineTo(TitleRect.Right + 1,TitleRect.Bottom); end; if lvUpBorder and ((dgRowLines in Options) and (dgColLines in Options)) then DrawEdge(Canvas.Handle, TitleRect, CellFlag, BF_TOP); if lvLeftBorder and ((dgRowLines in Options) and (dgColLines in Options)) then DrawEdge(Canvas.Handle, TitleRect, CellFlag, BF_LEFT); end; // Draw sort indicators SortColInfo := FindSortColInfo(MasterCol.Index, SortNum); if (SortColInfo <> nil) then begin i := SaveDC(Canvas.Handle); try if SortNum = 0 then case Column.Title.Alignment of taRightJustify: ArrowX := TextRect.Left + 2; else ArrowX := TextRect.Right - 12; end else begin Canvas.Font := TitleFont; CharWidth := Canvas.TextWidth('0'); ArrowX := TextRect.Right - 12 - CharWidth - 2; end; CaptionWidth := GetCaptionDepth(Caption, FLevelDelimiterChar); CalcTitleLevel(CaptionWidth - 1, TextRect); ArrowY := TextRect.Top + ((TextRect.Bottom - TextRect.Top - bmpSortAsc.Height) div 2); CurCaption := GetCaptionLevel(Caption, CaptionWidth - 1, FLevelDelimiterChar); CaptionWidth := Canvas.TextWidth(CurCaption); case Column.Title.Alignment of taLeftJustify: begin if TextRect.Left + CaptionWidth + 20 < ArrowX then ArrowX := TextRect.Left + CaptionWidth + 20; if TextRect.Left + CaptionWidth + 4 > ArrowX then begin ArrowX := TextRect.Left + CaptionWidth + 4; IntersectClipRect(Canvas.Handle, TextRect.Left, TextRect.Top, TextRect.Right - 1, TextRect.Bottom); end; end; taRightJustify: begin if TextRect.Right - CaptionWidth - 20 > ArrowX + 10 then ArrowX := TextRect.Right - CaptionWidth - 30; if TextRect.Right - CaptionWidth - 4 < ArrowX + 10 then begin ArrowX := TextRect.Right - CaptionWidth - 14; IntersectClipRect(Canvas.Handle, TextRect.Left, TextRect.Top, TextRect.Right - 1, TextRect.Bottom); end; end; taCenter: begin if TextRect.Left + CaptionWidth + (TextRect.Right - TextRect.Left - CaptionWidth) div 2 + 4 > ArrowX then begin ArrowX := TextRect.Left + CaptionWidth + (TextRect.Right - TextRect.Left - CaptionWidth) div 2 + 4; IntersectClipRect(Canvas.Handle, TextRect.Left, TextRect.Top, TextRect.Right - 1, TextRect.Bottom); end; end; end; if SortColInfo.Desc then Canvas.Draw(ArrowX + PressOffset, ArrowY + PressOffset, bmpSortDesc) else Canvas.Draw(ArrowX + PressOffset, ArrowY + PressOffset, bmpSortAsc); if SortNum > 0 then begin OldBkMode := SetBkMode(Canvas.Handle, TRANSPARENT); OldTextColor := GetTextColor(Canvas.Handle); SetTextColor(Canvas.Handle, clWhite); ArrowY := TextRect.Top + ((TextRect.Bottom - TextRect.Top - canvas.textHeight('X')) div 2); Canvas.TextOut(ArrowX + 12 + PressOffset, ArrowY + PressOffset, IntToStr(SortNum)); SetTextColor(Canvas.Handle, clGray); Canvas.TextOut(ArrowX + 11 + PressOffset, ArrowY - 1 + PressOffset, IntToStr(SortNum)); SetBkMode(Canvas.Handle, OldBkMode); SetTextColor(Canvas.Handle, OldTextColor); Canvas.Font := MasterCol.Title.Font; end; finally RestoreDC(Canvas.Handle, i); end; end; if dgeFilterBar in OptionsEx then begin TitleRect.Top := TitleRect.Bottom; if dgRowLines in Options then Inc(TitleRect.Top); // if not(dgRowLines in Options) then // Dec(TitleRect.Top); TitleRect.Bottom := TitleRect.Top + DefaultRowHeight + 9; if CRGridTitleEdit.EditingFilter then DrawTitleBarCell(Canvas,Column,TitleRect, CRGridTitleEdit.FFilterExpressions[Column.Index]) else DrawTitleBarCell(Canvas,Column,TitleRect,TCRColumn(Column).FilterExpression); end; if dgeSearchBar in OptionsEx then begin TitleRect.Top := TitleRect.Bottom ; if dgRowLines in Options then Inc(TitleRect.Top); TitleRect.Bottom := TitleRect.Top + DefaultRowHeight + 9; // if not(dgRowLines in Options) then // Dec(TitleRect.Top); DrawTitleBarCell(Canvas,Column,TitleRect,''); end; AState := AState - [gdFixed]; // prevent box drawing later end; var DrawColumn: TColumn; begin if (ARow = 0) and (dgTitles in Options) then begin if ACol >= IndicatorOffset then begin DrawColumn := Columns[ACol - IndicatorOffset]; DrawTitleCell(ACol - IndicatorOffset, ARow, DrawColumn, AState); end else begin inherited DrawCell(ACol, ARow, ARect, AState); DrawTitleIndicatorCell(Canvas,ARect); end end else begin if DataLink.Active then if dgTitles in Options then FActiveRowSelected := ARow - 1 = DataLink.ActiveRecord else FActiveRowSelected := ARow = DataLink.ActiveRecord else FActiveRowSelected := False; inherited DrawCell(ACol, ARow, ARect, AState); if gdFixed in AState then begin if dgColLines in Options then begin Canvas.Pen.color := clBlack; Canvas.Pen.style := psSolid; Canvas.MoveTo(aRect.Right, aRect.Top); Canvas.LineTo(aRect.Right, aRect.Bottom + 1); end; if dgRowLines in Options then begin Canvas.Pen.color := clBlack; Canvas.Pen.style := psSolid; Canvas.MoveTo(aRect.Left, aRect.Bottom); Canvas.LineTo(aRect.Right, aRect.Bottom); end; end end; end; procedure TCRDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); var State: TGridState; DrawInfo: TGridDrawInfo; Index: longint; Pos, Ofs: integer; OldActive: integer; Cell: TGridCoord; i: integer; Column: TColumn; Value: string; ColWidth, ValueWidth: integer; begin FExecColAjust := False; if FGridState = gsNormal then begin CalcDrawInfo(DrawInfo); CalcSizingState(X, Y, State, Index, Pos, Ofs, DrawInfo); end else State := FGridState; if not (State in [gsColSizing]) and DataLink.Active then begin if (Button = mbLeft) and (dgTitles in Options) then begin Cell := MouseCoord(X,Y); if Cell.X >= IndicatorOffset then begin if not (dgRowSelect in Options) and (Cell.Y >= FixedRows) and (TopRow + Cell.Y - FixedRows = Row) and IsOnButton(X,Y) then begin FCellButtonDown := RawToDataColumn(Cell.X); FCellButtonRow := Cell.Y; FCellButtonCol := Cell.X; FCellButtonBRect := GetButtonRect(Cell); FCellButtonRect := CellRect(Cell.X,Cell.Y); //Paint; // ?? HideEditor; DrawButton(Cell.X,Cell.Y,PtInRect(FCellButtonBRect,Point(x,y))); FCellButtonPressed := True; //invalidaterect(GetButtonRect(Cell)); Exit; end; if Cell.Y = 0 then begin Column := Columns[RawToDataColumn(Cell.X)]; if MouseInFilterEdit(X, Y, Column) then begin FContinueEditingFilter := True; ActivateFilterEdit(Column); Exit; end else if MouseInSortEdit(X, Y, Column) then begin ActivateSearchEdit(Column); Exit; end; end; if DataLink.Active and (Cell.Y < FixedRows) and (dgeEnableSort in OptionsEx) and MouseInLowerstLevel(X, Y, nil) then begin i := FTitleButtonDown; FTitleButtonDown := RawToDataColumn(Cell.X); FOldTitleButtonDown := FTitleButtonDown; if i > -1 then InvalidateCol(i+1); invalidatecol(FTitleButtonDown+1); end; end else begin FIndicatorColBtnDown := GetIndicatorButton(X,Y); FOldIndicatorColBtnDown := FIndicatorColBtnDown; if FIndicatorColBtnDown <> icbNone then InvalidateCol(0); end; end; end; if (mbLeft = Button) and (State = gsColSizing) and DataLink.Active then begin if ssDouble in Shift then begin Index := Min(RawToDataColumn(MouseCoord(X, Y).X), RawToDataColumn(MouseCoord(X - 7, Y).X)); if Index < 0 then Index := Columns.Count - 1; Column := Columns[Index]; ColWidth := 0; OldActive := DataLink.ActiveRecord; try for i := TopRow - 1 to VisibleRowCount - 1 do begin Datalink.ActiveRecord := i; if Assigned(Column.Field) then Value := Column.Field.DisplayText else Value := ''; ValueWidth := Canvas.TextWidth(Value); if ValueWidth > ColWidth then ColWidth := ValueWidth; end; finally DataLink.ActiveRecord := OldActive; end; //Column.Width := ColWidth + 4; ColWidths[Index + IndicatorOffset] := ColWidth + 4; FExecColAjust := True; //MessageBox(0, PChar('Row ' + IntToStr(Row) + #13'Row Count ' + IntToStr(RowCount) + #13'TopRow ' + IntToStr(TopRow) + #13'Vis ' + IntToStr(VisibleRowCount)), '', MB_OK); end; if CRGridTitleEdit.Focused or CRGridTitleEdit.Edit.Focused then begin SendMessage(Handle, WM_SETREDRAW, 0, 0); try inherited; CRGridTitleEdit.Visible := True; CRGridTitleEdit.SetFocus; finally SendMessage(Handle, WM_SETREDRAW, 1, 0); end; Column := CRGridTitleEdit.FActiveColumn; if CRGridTitleEdit.FAsFilter then begin ActivateFilterEdit(Column); Exit; end else ActivateSearchEdit(Column); end; end; InvalidateRect(Handle,{$IFNDEF CLR}@{$ENDIF}FStatusRect,False); CRGridTitleEdit.EditingFilter := False; FContinueEditingFilter := False; inherited; end; procedure TCRDBGrid.MouseMove(Shift: TShiftState; X, Y: integer); var State: TGridState; DrawInfo: TGridDrawInfo; Index: Longint; Pos, Ofs: integer; // Column:TColumn; // Cell: TGridCoord; Rect: TRect; Col: TColumn; begin inherited; if FGridState = gsNormal then begin CalcDrawInfo(DrawInfo); CalcSizingState(X, Y, State, Index, Pos, Ofs, DrawInfo); end else State := FGridState; if FCellButtonDown > -1 then begin FCellButtonPressed := PtInRect(FCellButtonBRect,Point(x,y)); DrawButton(FCellButtonCol,FCellButtonRow,FCellButtonPressed); end; if (ssLeft in Shift) and (FOldTitleButtonDown > -1) then begin Rect := CalcTitleRect(Columns[FOldTitleButtonDown], 0, Col); if dgeSearchBar in OptionsEx then Dec(Rect.Bottom,DefaultRowHeight + 10); if dgeFilterBar in OptionsEx then Dec(Rect.Bottom,DefaultRowHeight + 10); if (FTitleButtonDown = -1) and PtInRect(Rect,Point(X,Y)) then begin FTitleButtonDown := FOldTitleButtonDown; InvalidateCol(FTitleButtonDown + 1); end else if (FTitleButtonDown > -1) and ((Y < Rect.Top) or (Y > Rect.Bottom) or ((X < Self.Left) and (Columns[FTitleButtonDown].Index = 0)) or ((X > Self.Left + Self.Width) and (Columns[FTitleButtonDown].Index = Columns.Count - 1))) then begin Index := FTitleButtonDown + 1; FTitleButtonDown := -1; InvalidateCol(Index) end; end; if (ssLeft in Shift) and (FOldIndicatorColBtnDown <> icbNone) then begin if (FIndicatorColBtnDown = icbNone) and (GetIndicatorButton(X, Y) = FOldIndicatorColBtnDown) then begin FIndicatorColBtnDown := FOldIndicatorColBtnDown; InvalidateCol(0); end else if (FIndicatorColBtnDown <> icbNone) and (FIndicatorColBtnDown <> GetIndicatorButton(X, Y)) then begin FIndicatorColBtnDown := icbNone; InvalidateCol(0) end; end; { if not (State in [gsColSizing]) and DataLink.Active then begin Cell := MouseCoord(X,Y); if (Cell.X >= IndicatorOffset) and (Cell.Y >= 0) and (ngTitles in FOptions) and (Cell.Y = 0) then begin FTitleButtonDown := RawToDataColumn(Cell.X); Paint; // ?? end else begin FTitleButtonDown := -1; Paint; // ?? end; end;} end; procedure TCRDBGrid.Reorder; var i: integer; St: string; begin if DataLink.Active and {$IFDEF DAC450} (DataLink.DataSet is TCustomDADataSet) {$ELSE} ( ((DataLink.DataSet is TCustomDADataSet) and not(dgeLocalSorting in OptionsEx)) or ((DataLink.DataSet is TMemDataSet) and (dgeLocalSorting in OptionsEx)) ) {$ENDIF} then begin St := ''; for i := 0 to FSortInfo.Count - 1 do if TCRColumn(Columns[TSortColInfo(FSortInfo[i]).Index]).CanBeSorted then begin if St <> '' then St := St + ','; {$IFNDEF DAC450} if dgeLocalSorting in OptionsEx then St := St + '''' + Columns[TSortColInfo(FSortInfo[i]).Index].Field.FieldName + '''' else {$ENDIF} St := St + IntToStr(Columns[TSortColInfo(FSortInfo[i]).Index].Field.FieldNo); if TSortColInfo(FSortInfo[i]).Desc then St := St + ' DESC'; end; {$IFNDEF DAC450} if dgeLocalSorting in OptionsEx then TMemDataSet(DataLink.DataSet).IndexFieldNames := St else {$ENDIF} begin TCustomDADataSet(DataLink.DataSet).SetOrderBy(St); DataLink.DataSet.Open; end; end; end; procedure TCRDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); var State: TGridState; DrawInfo: TGridDrawInfo; Index, i: Longint; Pos, Ofs: integer; Column: TColumn; Cell: TGridCoord; SortColInfo: TSortColInfo; Desc: boolean; SortColNum: integer; LastBtn: integer; Widths: array of integer; begin if FGridState = gsNormal then begin CalcDrawInfo(DrawInfo); CalcSizingState(X, Y, State, Index, Pos, Ofs, DrawInfo); end else State := FGridState; if (mbLeft = Button) and (State = gsColSizing) and DataLink.Active then begin if CRGridTitleEdit.Focused then begin inherited; Column := CRGridTitleEdit.FActiveColumn; if CRGridTitleEdit.FAsFilter then begin ActivateFilterEdit(Column); end else ActivateSearchEdit(Column); end; end; FTitleBarUp := False; if not (State in [gsColSizing]) and DataLink.Active and not FExecColAjust then begin Cell := MouseCoord(X,Y); if not (dgRowSelect in Options) then if FCellButtonDown > -1 then begin DrawButton(Cell.X,Cell.Y,False); if FCellButtonDown = RawToDataColumn(Cell.X) then if FCellButtonPressed then begin FCellButtonDown := -1; FCellButtonRow := -1; FCellButtonCol := -1; DoOnMemoClick(Columns[RawToDataColumn(Cell.X)]); invalidate; end; end; FCellButtonDown := -1; FCellButtonRow := -1; FCellButtonCol := -1; LastBtn := FTitleButtonDown; FOldTitleButtonDown := -1; if FTitleButtonDown > -1 then begin invalidatecol(FTitleButtonDown + 1); FTitleButtonDown := - 1; end; if (Button = mbLeft) and (Cell.Y = 0) and (dgTitles in Options) then begin if Cell.X >= IndicatorOffset then begin Column := Columns[RawToDataColumn(Cell.X)]; if not (MouseInSortBar(X,Y,Column) or MouseInFilterBar(X,Y,Column)) then begin FTitleBarUp := True; if TCRColumn(Column).CanBeSorted and (dgeEnableSort in OptionsEx) and MouseInLowerstLevel(X,Y,Column) and (LastBtn = Column.Index) then begin FExecSorting := True; BeginLayout; try SetLength(Widths, Columns.Count); for i := 0 to Columns.Count - 1 do Widths[i] := Columns[i].Width; if (DataLink.DataSet <> nil) and {$IFDEF DAC450} (DataLink.DataSet is TCustomDADataSet) {$ELSE} ( ((DataLink.DataSet is TCustomDADataSet) and not(dgeLocalSorting in OptionsEx)) or ((DataLink.DataSet is TMemDataSet) and (dgeLocalSorting in OptionsEx)) ) {$ENDIF} then begin SortColInfo := FindSortColInfo(Column.Index, SortColNum); Desc := (SortColInfo <> nil) and not SortColInfo.Desc; if (ssCtrl in Shift) and (SortColInfo <> nil) then begin SortColInfo.Free; if SortColNum > 0 then Dec(SortColNum); FSortInfo.Delete(SortColNum); end else begin if not (ssShift in Shift) then ClearSorting; if not (ssShift in Shift) or (SortColInfo = nil) then begin SortColInfo := TSortColInfo.Create; SortColInfo.Index := Column.Index; FSortInfo.Add(SortColInfo); end; SortColInfo.Desc := Desc; end; Reorder; end; finally EndLayout; for i := 0 to Columns.Count - 1 do Columns[i].Width := Widths[i]; FExecSorting := False; end; end; end; end else if FIndicatorColBtnDown <> icbNone then begin FIndicatorColBtnDown := icbNone; InvalidateCol(0); IndicatorClick(FOldIndicatorColBtnDown, X, Y); end; end; FOldIndicatorColBtnDown := icbNone; end; inherited; FTitleBarUp := False; end; procedure TCRDBGrid.LinkActive(Value: boolean); var St: string; Parser: TParser; Code: integer; Lex: string; i: integer; FieldName: string; SortColInfo: TSortColInfo; Ind: integer; begin inherited; // need to make header to have multilines CRGridTitleEdit.StopEdit(False); if not FExecSorting then begin ClearSorting; if Value and (DataLink.DataSet is TCustomDADataSet) and TCustomDADataSet(DataLink.DataSet).IsQuery then begin St := TCustomDADataSet(DataLink.DataSet).GetOrderBy; //St := GetOrderBy(TOraDataSet(DataLink.DataSet).SQL.Text); //St := ''; if St <> '' then begin Parser := TParser.Create(PChar(St)); try Parser.QuotedString := True; repeat SortColInfo := nil; Code := Parser.GetNext(Lex); case Code of lcString: if Lex[1] = '"' then begin Lex := Copy(Lex, 2, Length(Lex) - 2); if Lex <> '' then Code := lcIdent; end; lcNumber: try Ind := StrToInt(Lex); if Ind <= DataLink.DataSet.FieldDefs.Count then begin Lex := DataLink.DataSet.FieldDefs[Ind - 1].Name; Code := lcIdent; end; except Exit; end; end; if Code <> lcIdent then Exit; FieldName := UpperCase(Lex); Code := Parser.GetNext(Lex); if Lex = '.' then begin Code := Parser.GetNext(Lex); if Code = lcIdent then begin FieldName := UpperCase(Lex); Code := Parser.GetNext(Lex); end else Exit; end; for i := 0 to Columns.Count - 1 do if (Columns[i].Field <> nil) and (UpperCase(Columns[i].Field.FieldName) = FieldName) then begin SortColInfo := TSortColInfo.Create; SortColInfo.Index := i; SortColInfo.Desc := False; FSortInfo.Add(SortColInfo); break; end; if UpperCase(Lex) = 'DESC' then begin if SortColInfo <> nil then SortColInfo.Desc := True; Code := Parser.GetNext(Lex); end else if UpperCase(Lex) = 'ASC' then Code := Parser.GetNext(Lex) else if (Code <> lcEnd) and (Lex <> ',') then Exit; until Code = lcEnd; finally Parser.Free; end; end; end; end; if Value then RecordChanged(nil); Invalidate; end; procedure TCRDBGrid.UpdateHeaderHeight; var Cur, i: integer; aHeight: integer; begin if not (dgTitles in Options) then begin RowHeights[0]:= DefaultRowHeight; Exit; end; FHeaderHeight := 1; for i := 0 to Columns.Count - 1 do begin if TCRColumnTitle(Columns[i].Title).IsCaptionStored then Cur := GetCaptionDepth(Columns[i].Title.Caption,FLevelDelimiterChar) else Cur := 1; if Cur > FHeaderHeight then FHeaderHeight := Cur; end; aHeight := (DefaultRowHeight + 1) * FHeaderHeight; // if dgRowLines in Options then // aHeight := aHeight + FHeaderHeight; // if not (dgRowLines in Options) then // Dec(aHeight); // because of always-border cells if dgeFilterBar in OptionsEx then aHeight := aHeight + DefaultRowHeight + 10; if dgeSearchBar in OptionsEx then aHeight := aHeight + DefaultRowHeight + 10; RowHeights[0]:= aHeight - 1; end; procedure TCRDBGrid.SetOptionsEx(Value: TCRDBGridOptionsEx); begin if FOptionsEx <> Value then begin if ((dgeFilterbar in FOptionsEx) <> (dgeFilterBar in Value)) or ((dgeSearchbar in FOptionsEx) <> (dgeSearchBar in Value)) then begin FOptionsEx := Value; FOptionsMenuDef.Items[2].Checked := dgeFilterBar in FOptionsEx; FOptionsMenuDef.Items[3].Checked := dgeSearchBar in FOptionsEx; LayoutChanged; UpdateRowCount; Invalidate; Exit; end; FOptionsEx := Value; if (dgeStretch in FOptionsEx) then begin if not FSoft and not (csLoading in ComponentState) then begin FExecSizing := True; ResizeColumns; FExecSizing := False; end; FSoft := True; end else FSoft := False; Invalidate; end; end; function TCRDBGrid.GetClientRect: TRect; begin Result := inherited GetClientRect; if dgRowLines in options then Inc(Result.Bottom); if [dgeSummary,dgeRecordCount] * FOptionsEx <> [] then Dec(Result.Bottom,DefaultRowHeight + 2); end; procedure TCRDBGrid.LayoutChanged; begin inherited; CRGridTitleEdit.StopEdit(False); UpdateHeaderHeight; //DoubleBuffered := true; end; procedure TCRDBGrid.Paint; var TotalWidth: integer; TotalYOffs: integer; TotalHeight: integer; TmpText: string; procedure PaintStatusLine(YOffset: integer); var Column: TCRColumn; MasterCol: TColumn; BrdRect: TRect; CellRect: TRect; ColIndex: integer; FullRect: TRect; RightBorder: integer; OldDC: HDC; begin OldDC := Canvas.Handle; Canvas.Handle := 0; try FullRect := Rect(0, FTotalYOffset, TotalWidth, FTotalYOffset + DefaultRowHeight + 2); FStatusRect := FullRect; // if dgRowLines in Options then // Inc(FullRect.Top); Canvas.FillRect(FullRect); with Canvas do begin Pen.Color := clBlack; Pen.Style := psSolid; if dgRowLines in Options then begin MoveTo(FullRect.Left, FullRect.Top - 1); LineTo(FullRect.Right, FullRect.Top - 1); MoveTo(FullRect.Left, FullRect.Bottom - 2); LineTo(FullRect.Right, FullRect.Bottom - 2); end; if dgColLines in Options then begin Dec(FullRect.Right); MoveTo(FullRect.Right, FullRect.Top); LineTo(FullRect.Right, FullRect.Bottom + 2); // MoveTo(FullRect.Left , FullRect.Bottom + 2); // LineTo(FullRect.Left, FullRect.Top); end; if (dgRowLines in Options) and (dgColLines in Options) then begin Dec(FullRect.Bottom, 2); DrawEdge(Canvas.Handle, FullRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT); DrawEdge(Canvas.Handle, FullRect, BDR_RAISEDINNER, BF_TOPLEFT); end; end; if (Columns.Count > 0) and (dgeSummary in FOptionsEx) then begin RightBorder := GetClientRect.Right - 1; for ColIndex := RawToDataColumn(LeftCol) to Columns.Count - 1 do begin Column := TCRColumn(Columns[ColIndex]); CellRect := CalcTitleRect(Column, 0, MasterCol); if (CellRect.Left <> 0) or (CellRect.Right <> 0) or (CellRect.Top <> 0) or (CellRect.Bottom <> 0) then begin CellRect.Top := YOffset; CellRect.Bottom := CellRect.Top + DefaultRowHeight; if Column.SummaryMode <> smNone then begin tmpText := TCRColumn(Column).TotalString; InflateRect(CellRect, 0, -2); if tmpText <> '' then WriteText(Canvas, CellRect, 3, 0, tmpText, Column.Alignment,True); InflateRect(CellRect, 0, 2); if dgColLines in Options then begin if dgRowLines in Options then begin BrdRect := CellRect; Inc(BrdRect.Bottom); DrawEdge(Canvas.Handle, BrdRect, BDR_RAISEDINNER, BF_RIGHT); DrawEdge(Canvas.Handle, BrdRect, BDR_RAISEDINNER, BF_LEFT); BrdRect.Right := CellRect.Left - 1; BrdRect.Left := BrdRect.Right - 1; DrawEdge(Canvas.Handle, BrdRect, BDR_RAISEDINNER, BF_RIGHT); Dec(BrdRect.Bottom); end; Canvas.Pen.Color := clBlack; Canvas.MoveTo(CellRect.Left - 1, CellRect.Top - 1); Canvas.LineTo(CellRect.Left - 1, CellRect.Bottom + 3); BrdRect.Left := CellRect.Right + 1; BrdRect.Right:= BrdRect.Left + 1; if Column.Index < MasterCol.Collection.Count - 1 then begin Inc(BrdRect.Bottom); DrawEdge(Canvas.Handle, BrdRect, BDR_RAISEDINNER, BF_LEFT); Dec(BrdRect.Bottom); Canvas.Pen.Color := clBlack; Canvas.MoveTo(CellRect.Right, CellRect.Top - 1); Canvas.LineTo(CellRect.Right, CellRect.Bottom + 3); end; end; end; end; if dgeRecordCount in FOptionsEx then begin CellRect := FullRect; InflateRect(CellRect, -2, -2); CellRect.Right := RightBorder; if DataLink.Active then tmpText := IntToStr(DataLink.DataSet.RecNo) + '/' + IntToStr(DataLink.DataSet.RecordCount) else tmpText := '';//'Records count : INACTIVE'; WriteText(Canvas, CellRect, 0, 0, tmpText, taLeftJustify,True); end; end; end else begin if dgeRecordCount in FOptionsEx then begin CellRect := FullRect; InflateRect(CellRect, -2, -2); if DataLink.Active then tmpText := IntToStr(DataLink.DataSet.RecNo) + '/' + IntToStr(DataLink.DataSet.RecordCount) else tmpText := '';//'Records count : INACTIVE'; WriteText(Canvas, CellRect, 0, 0, tmpText, taLeftJustify,True); end; end; finally Canvas.Handle := OldDC; end; end; {$IFNDEF CLR}//TODO var Opt: TGridOptions; Last: TGridOptions; {$ENDIF} begin {$IFNDEF CLR}//TODO Opt := _TCustomGrid(Self).Options; Last := Opt; Opt := Opt - [goFixedVertLine , goFixedHorzLine]; _TCustomGrid(Self).Options := Opt; {$ENDIF} inherited; // Draw standart grid with Canvas do begin TotalHeight := GetClientRect.Bottom; TotalYOffs := TotalHeight; TotalWidth := GetClientRect.Right; FTotalYOffset := TotalYOffs; Canvas.Font.Assign(TitleFont); Canvas.Brush.Color := clBtnFace; if [dgeSummary,dgeRecordCount] * FOptionsEx <> [] then PaintStatusLine(FTotalYOffset); end; //_TCustomGrid(Self).Options := Last; end; procedure TCRDBGrid.LoadTotals; var ColNom: integer; Mode: TSummaryMode; BookM: TBookmark; Col: TCRColumn; DataSet: TDataSet; Field: TField; begin if not ((dgeSummary in OptionsEx) and DataLink.Active) or (Columns.Count = 0) then Exit; BookM := DataLink.DataSet.GetBookMark; try DataSet := DataLink.DataSet; DataSet.DisableControls; for ColNom := 0 to Columns.Count - 1 do begin if (TCRColumn(Columns[ColNom]).SummaryMode <> smLabel) and (not TCRColumn(Columns[ColNom]).FTotalLoaded)and(Assigned(Columns[ColNom].Field)) then begin Col := TCRColumn(Columns[ColNom]); Field := Col.Field; if Col.SummaryMode = smMin then Col.FTotalInt := Field.AsInteger else Col.FTotalInt := 0; if Col.SummaryMode = smMin then Col.FTotalFloat := Field.AsFloat else Col.FTotalFloat := 0; Col.FTotalString:= ''; Col.FTotalValue:= Unassigned; end; end; DataSet.First; while not DataSet.Eof do begin for ColNom := 0 to Columns.Count - 1 do if (not TCRColumn(Columns[ColNom]).FTotalLoaded) and Assigned(TCRColumn(Columns[ColNom]).Field) then begin Col := TCRColumn(Columns.Items[ColNom]); Field := Col.Field; Mode := Col.SummaryMode; case Col.Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: case Mode of smSum: Col.FTotalInt := Col.FTotalInt + Field.AsInteger; smAvr: Col.FTotalInt := Col.FTotalInt + Field.AsInteger; smMax: if Col.FTotalInt < Field.AsInteger then Col.FTotalInt := Field.AsInteger; smMin: if Col.FTotalInt > Field.AsInteger then Col.FTotalInt := Field.AsInteger; end; ftFloat, ftCurrency: case Mode of smSum: Col.FTotalFloat := Col.FTotalFloat + Field.AsFloat; smAvr: Col.FTotalFloat := Col.FTotalFloat + Field.AsFloat; smMax: if Col.FTotalFloat < Field.AsFloat then Col.FTotalFloat := Field.AsFloat; smMin: if Col.FTotalFloat > Field.AsFloat then Col.FTotalFloat := Field.AsFloat; end; end; end; DataSet.Next; end; for ColNom := 0 to Columns.Count - 1 do if (not TCRColumn(Columns[ColNom]).FTotalLoaded) and Assigned(TCRColumn(Columns[ColNom]).Field) then begin Col := TCRColumn(Columns.Items[ColNom]); if (Col.SummaryMode = smAvr) and (DataLink.DataSet.RecordCount > 0) then case Col.Field.DataType of ftSmallint, ftInteger, ftWord, ftLargeint: Col.FTotalFloat := Col.FTotalInt / DataLink.DataSet.RecordCount; ftFloat, ftCurrency: Col.FTotalFloat := Col.FTotalFloat / DataLink.DataSet.RecordCount; end; Col.SetTotal; end; finally DataLink.DataSet.GotoBookMark(BookM); DataLink.DataSet.FreeBookMark(BookM); DataLink.DataSet.EnableControls; end; end; procedure TCRDBGrid.DataChanged; begin ResetTotals; LoadTotals; invalidate; end; procedure TCRDBGrid.RecordChanged(Field: TField); var i: integer; begin if not HandleAllocated then Exit; if Field = nil then DataChanged else begin for i := 0 to Columns.Count - 1 do if Columns[i].Field = Field then TCRColumn(Columns[i]).ResetTotal; LoadTotals; Invalidate; end; inherited; end; procedure TCRDBGrid.ResetTotals; var i: integer; begin for i := 0 to Columns.Count - 1 do TCRColumn(Columns[i]).ResetTotal; end; function TCRDBGrid.EndColumnDrag(var Origin, Destination: integer; const MousePt: TPoint): boolean; var Mx,Mn, Oi: integer; begin Result := inherited EndColumnDrag(Origin, Destination, MousePt); if Result and (Origin <> Destination) then begin if Origin > Destination then begin Mx := Origin; Mn := Destination end else begin Mx := Destination; Mn := Origin end; Dec(mx); Dec(mn); for Oi := 0 to FSortInfo.Count - 1 do begin if TSortColInfo(FSortInfo[Oi]).Index = Origin - 1 then begin TSortColInfo(FSortInfo[Oi]).Index := Destination - 1; //TSortColInfo(FSortInfo[Oi]).Desc := not TSortColInfo(FSortInfo[Oi]).Desc; continue; end; if (TSortColInfo(FSortInfo[Oi]).Index > Mx)or(TSortColInfo(FSortInfo[Oi]).Index < Mn) then continue; if Destination < Origin then Inc(TSortColInfo(FSortInfo[Oi]).Index) else Dec(TSortColInfo(FSortInfo[Oi]).Index); end; end; end; procedure TCRDBGrid.SetLevelDelimiterchar(const Value: char); begin FLevelDelimiterchar := Value; end; procedure TCRDBGrid.WMSetCursor(var Message: TWMSetCursor); var P: TPoint; begin GetCursorPos(P); P := ScreenToClient(P); if MouseInSortEdit(p.x,p.y) or MouseInFilterEdit(p.x,p.y) then Windows.SetCursor(LoadCursor(0, IDC_IBEAM)) else inherited; end; function TCRDBGrid.MouseInSortBar(X,Y: integer; Column: TColumn = nil): boolean; var Index: integer; Rect: TRect; begin Result := False; if not (dgeSearchBar in OptionsEx) then Exit; if Column = nil then begin Index := DataToRawColumn(MouseCoord(X,Y).X); Column := Columns[Index]; end; Rect := CalcSearchBar(Column); Result := PtInRect(Rect,Point(x,y)); end; function TCRDBGrid.MouseInSortEdit(X,Y: integer; Column: TColumn = nil): boolean; var Index: integer; Rect: TRect; begin Result := False; if not (dgeSearchBar in OptionsEx) then exit; if Column = nil then begin Index := RawToDataColumn(MouseCoord(X,Y).X); if Index < 0 then exit; Column := Columns[Index]; end; Rect := CalcSearchBar(Column); InflateRect(Rect, -5, -5); Result := PtInRect(Rect,Point(x,y)) and TCRColumn(Column).CanBeSorted; end; function TCRDBGrid.MouseInFilterBar(X,Y: integer; Column: TColumn = nil): boolean; var Index: integer; Rect: TRect; begin Result := False; if not (dgeFilterBar in OptionsEx) then Exit; if Column = nil then begin Index := DataToRawColumn(MouseCoord(X,Y).X); if Index < 0 then Exit; Column := Columns[Index]; end; Rect := CalcFilterBar(Column); Result := PtInRect(Rect, Point(x,y)); end; function TCRDBGrid.MouseInFilterEdit(X,Y: integer; Column: TColumn = nil): boolean; var Index: integer; Rect: TRect; begin Result := False; if not (dgeFilterBar in OptionsEx) then Exit; if Column = nil then begin Index := RawToDataColumn(MouseCoord(X, Y).X); if Index < 0 then Exit; Column := Columns[Index]; end; Rect := CalcFilterBar(Column); InflateRect(rect, -5, -5); Result := PtInRect(Rect, Point(x,y)) and TCRColumn(Column).CanBeSorted; end; function TCRDBGrid.CalcSearchBar(Column: TColumn): TRect; var Rect: TRect; MasterCol: TColumn; aRow: integer; begin aRow := 0; Rect := CalcTitleRect(Column,aRow,MasterCol); Rect.Top := Rect.Bottom - (DefaultRowHeight + 9); if not (dgeSearchBar in OptionsEx) then begin Result.Top := Result.Bottom; exit; end; Result := Rect; end; function TCRDBGrid.CalcFilterBar(Column: TColumn): TRect; var Rect: TRect; MasterCol: TColumn; aRow: integer; begin aRow := 0; Rect := CalcTitleRect(Column, aRow, MasterCol); if dgeSearchBar in OptionsEx then begin Rect.Bottom := Rect.Bottom - (DefaultRowHeight + 9); if dgRowLines in Options then Dec(Rect.Bottom); end; Rect.Top := Rect.Bottom - (DefaultRowHeight + 9); // if not (dgRowLines in Options) then // Inc(Rect.Top); Result := Rect; if not (dgeFilterBar in OptionsEx) then begin Result.Top := Result.Bottom; exit; end; end; procedure TCRDBGrid.ActivateFilterEdit(Column: TColumn); var CellRect: TRect; begin if not (Assigned(Column) and (dgeFilterBar in OptionsEx)) then Exit; CellRect := CalcFilterBar(Column); InflateRect(CellRect, -5, -5); if not (dgRowLines in Options) then Dec(CellRect.Top); CRGridTitleEdit.ActivateAt(CellRect, Column, True); end; procedure TCRDBGrid.DoOnMemoClick(Column: TColumn); var Window: TMemoEditorForm; begin if Assigned(FOnMemoClick) then FOnMemoClick(Self, Column) else begin Window := TMemoEditorForm.Create(GetParentForm(Self)); try Window.FMemo.Text := AdjustLineBreaks(Column.Field.AsString); Window.ReadOnly := ReadOnly or Column.Field.ReadOnly or not (dgEditing in Options); Window.Caption := Column.Field.DisplayName; if (FMemoWidth > 0) and (FMemoHeight > 0) then begin Window.Width := FMemoWidth; Window.Height := FMemoHeight; end; Window.FCheckBox.Checked := FMemoWordWrap; if Window.ShowModal = mrOK then begin DataLink.DataSet.Edit; Column.Field.AsString := Window.FMemo.Text; end; FMemoWidth := Window.Width; FMemoHeight := Window.Height; FMemoWordWrap := Window.FCheckBox.Checked; finally Window.Free; end; end; end; function TCRDBGrid.MouseInLowerstLevel(X, Y: integer; Column: TColumn = nil): boolean; var Index: integer; Rect: TRect; MasterCol: TColumn; begin Result := False; if Column = nil then begin Index := RawToDataColumn(MouseCoord(X, Y).X); if Index < 0 then exit; Column := Columns[Index]; end; Index := 0; Rect := CalcTitleRect(Column, Index, MasterCol); Index := GetCaptionDepth(Column.Title.Caption, FLevelDelimiterChar); if Index > 0 then begin Index := (Index-1) * (DefaultRowHeight + 1); Rect.Top := Index; Rect.Bottom := CalcFilterBar(Column).top; Result := PtInRect(Rect, Point(X, Y)); end else Result := True; end; procedure TCRDBGrid.DrawTitleBarCell(Canvas: TCanvas; Column: TColumn; Rect: TRect; Text: string); var TextRect: TRect; begin Canvas.Brush.Color := clBtnFace; Canvas.Brush.Style := bsSolid; Canvas.FillRect(Rect); if (dgRowLines in Options) and (dgColLines in Options) then begin DrawEdge(Canvas.Handle, Rect, BDR_RAISEDINNER, BF_BOTTOMRIGHT); DrawEdge(Canvas.Handle, Rect, BDR_RAISEDINNER, BF_TOPLEFT); end; if TCRColumn(column).CanBeSorted then begin if (dgRowLines in Options) and (dgColLines in Options) then begin InflateRect(Rect, -4, -4); if Rect.Right > Rect.Left then begin DrawEdge(Canvas.Handle, Rect, BDR_SUNKENINNER, BF_TOPLEFT); Rect.Bottom := Rect.Bottom + 1; DrawEdge(Canvas.Handle, Rect, BDR_SUNKENINNER, BF_BOTTOMRIGHT); InflateRect(Rect, 1, 1); DrawEdge(Canvas.Handle, Rect, BDR_SUNKENOUTER, BF_TOPLEFT); DrawEdge(Canvas.Handle, Rect, BDR_SUNKENOUTER, BF_BOTTOMRIGHT); InflateRect(Rect, 3, 3); Rect.Bottom := Rect.Bottom - 1; end else InflateRect(Rect, 4, 4); end; TextRect := Rect; InflateRect(TextRect, -5, -5); TextRect.Bottom := TextRect.Top + DefaultRowHeight; if TextRect.Right >= TextRect.Left then begin Canvas.Brush.Color := clWindow; Canvas.Brush.Style := bsSolid; Canvas.FillRect(TextRect); end; InflateRect(TextRect, -2, -2); if (Text <> '') and (TextRect.Right >= TextRect.Left) then WriteText(Canvas, TextRect, 0, 0, Text, taLeftJustify, True); end; Canvas.Pen.Color := clBlack; if dgRowLines in options then begin Canvas.MoveTo(Rect.Left, Rect.Bottom); Canvas.LineTo(Rect.Right + 1, Rect.Bottom); end; if dgColLines in options then begin Canvas.MoveTo(Rect.Right, Rect.Top); Canvas.LineTo(Rect.Right, Rect.Bottom); end; end; procedure TCRDBGrid.DrawTitleIndicatorCell(Canvas: TCanvas; ARect: TRect); procedure DrawButton(Rect: TRect; Bmp: TBitmap; IsPressed: boolean); var Delta, Flag, PressOffset: integer; begin PressOffset := 0; Delta := Ceil((Rect.Bottom - Rect.Top - Bmp.Height) / 2); if ((dgRowLines in Options) and (dgColLines in Options)) {or PtInRect(Rect,P)} then begin if IsPressed then begin PressOffset := 1; Flag := BDR_SUNKENINNER end else Flag := BDR_RAISEDINNER; DrawEdge(Canvas.Handle, Rect, Flag, BF_BOTTOMRIGHT); DrawEdge(Canvas.Handle, Rect, Flag, BF_TOPLEFT); end; Canvas.Draw(Rect.Left + 1 + PressOffset, Rect.Top + Delta + PressOffset, Bmp); if dgRowLines in Options then begin Canvas.Pen.Color := clBlack; Canvas.MoveTo(Rect.Left, Rect.Bottom); Canvas.LineTo(Rect.Right + 1, Rect.Bottom); end; end; var Rect: TRect; Bmp: TBitmap; i: integer; begin Canvas.FillRect(ARect); Rect := ARect; if dgeSearchBar in OptionsEx then begin Rect.Top := Rect.Bottom - DefaultRowHeight - 9; if not((dgRowLines in Options) or (dgeFilterBar in OptionsEx)) then Inc(Rect.Top); DrawButton(Rect, bmpSearch, FIndicatorColBtnDown = icbSearch); Dec(Rect.Bottom, DefaultRowHeight + 9); if dgRowLines in Options then Dec(Rect.Bottom) end; if dgeFilterBar in OptionsEx then begin Rect.Top := Rect.Bottom - DefaultRowHeight - 9; if not((dgRowLines in Options) or (dgeSearchBar in OptionsEx)) then Inc(Rect.Top); if CRGridTitleEdit.EditingFilter then Bmp := bmpEditMode else if FFiltered then begin Bmp := bmpFilter; for i := 0 to Columns.Count - 1 do if TCRColumn(Columns[i]).FilterExpression <> '' then begin Bmp := bmpActiveFilter; Break; end; end else Bmp := bmpFilter; DrawButton(Rect, Bmp, FIndicatorColBtnDown = icbFilter); Dec(Rect.Bottom, DefaultRowHeight + 9); if (dgRowLines in Options) then Dec(Rect.Bottom); end; Rect.Top := ARect.Top; if not(dgRowLines in Options) and ((dgeSearchBar in OptionsEx) xor (dgeFilterBar in OptionsEx)) then Inc(Rect.Bottom); DrawButton(Rect, bmpMenu, FIndicatorColBtnDown = icbMenu); Canvas.Pen.Color := clBlack; if dgColLines in Options then begin Canvas.MoveTo(ARect.Right, ARect.Top); Canvas.LineTo(ARect.Right, ARect.Bottom + 1); end; end; function TCRDBGrid.GetIndicatorButton(X, Y: integer): TIndicatorColButton; var Rect: TRect; begin Result := icbNone; Rect := CellRect(0,0); if dgeSearchBar in OptionsEx then begin Rect.Top := Rect.Bottom - DefaultRowHeight - 9; if not((dgRowLines in Options) or (dgeFilterBar in OptionsEx)) then Inc(Rect.Top); if PtInRect(Rect,Point(X,Y)) then Result := icbSearch; Dec(Rect.Bottom, DefaultRowHeight + 9); if dgRowLines in Options then Dec(Rect.Bottom); end; if dgeFilterBar in OptionsEx then begin Rect.Top := Rect.Bottom - DefaultRowHeight - 9; if not((dgRowLines in Options) or (dgeSearchBar in OptionsEx)) then Inc(Rect.Top); if PtInRect(Rect,Point(X,Y)) then Result := icbFilter; Dec(Rect.Bottom, DefaultRowHeight + 9); if dgRowLines in Options then Dec(Rect.Bottom); end; Rect.Top := CellRect(0,0).Top; if not(dgRowLines in Options) and ((dgeSearchBar in OptionsEx) xor (dgeFilterBar in OptionsEx)) then Inc(Rect.Bottom); if PtInRect(Rect,Point(X,Y)) then Result := icbMenu; end; procedure TCRDBGrid.IndicatorClick(Button: TIndicatorColButton; X, Y: integer); var P: TPoint; begin EditorMode := False; case Button of icbFilter: FilterItemClick(FOptionsMenuDef.Items[2]); // watch it icbSearch: SearchItemClick(FOptionsMenuDef.Items[3]); // watch it icbMenu: begin P := ClientToScreen(Point(X, Y)); if FOptionsMenu <> nil then FOptionsMenu.Popup(P.x, P.y) else FOptionsMenuDef.Popup(P.x, P.y); end; end; end; procedure TCRDBGrid.BuildMenu; var Item: TMenuitem; begin while FOptionsMenuDef.Items.Count > 0 do FOptionsMenuDef.Items.Delete(0); Item := TMenuItem.Create(Self); Item.Caption := SFiltered; Item.OnClick := FilteredItemClick; Item.Checked := FFiltered; FOptionsMenuDef.Items.Add(Item); Item := TMenuItem.Create(Self); Item.Caption := '-'; FOptionsMenuDef.Items.Add(Item); Item := TMenuItem.Create(Self); Item.Caption := SFilterBar; Item.OnClick := FilterItemClick; Item.Checked := dgeFilterBar in OptionsEx; FOptionsMenuDef.Items.Add(Item); Item := TMenuItem.Create(Self); Item.Caption := SSearchBar; Item.OnClick := SearchItemClick; Item.Checked := dgeSearchBar in OptionsEx; FOptionsMenuDef.Items.Add(Item); end; procedure TCRDBGrid.FilterItemClick(Sender: TObject); begin if dgeFilterBar in OptionsEx then begin OptionsEx := OptionsEx - [dgeFilterBar]; UpdateRowCount; end else OptionsEx := OptionsEx + [dgeFilterBar]; (Sender as TMenuItem).Checked := dgeFilterBar in OptionsEx; end; procedure TCRDBGrid.SearchItemClick(Sender: TObject); begin if dgeSearchBar in OptionsEx then begin OptionsEx := OptionsEx - [dgeSearchBar]; UpdateRowCount; end else OptionsEx := OptionsEx + [dgeSearchBar]; (Sender as TMenuItem).Checked := dgeSearchBar in OptionsEx; end; procedure TCRDBGrid.CalcTableSpacePercent; var ColumnsSize, i: integer; begin ColumnsSize := 0; for i := 0 to Columns.count - 1 do if ColWidths[i + IndicatorOffset] > 0 then ColumnsSize := ColumnsSize + ColWidths[i + IndicatorOffset]; for i := 0 to Columns.Count - 1 do if ColumnsSize > 0 then TCRColumn(Columns[i]).FTableSpacePercent := ColWidths[i + IndicatorOffset] / ColumnsSize; end; procedure TCRDBGrid.KeyDown(var Key: word; Shift: TShiftState); var Column: TColumn; i: integer; procedure ActivateEdit; begin if dgeSearchBar in OptionsEx then begin ActivateSearchEdit(Column); Key := 0; end else if dgeFilterBar in OptionsEx then begin ActivateFilterEdit(Column); Key := 0; end; end; begin case Key of VK_UP: if (dgTitles in Options) and (Row = 1) and ((Shift = [ssShift]) or (DataLink.Active and ((DataLink.DataSet.RecNo = 1) or (DataLink.DataSet.recordcount = 0)))) then begin Column := Columns[RawToDataColumn(Col)]; if TCRColumn(Column).CanBeSorted then ActivateEdit; end; VK_TAB: if (dgTitles in Options) and (Row = 1) and (Col = IndicatorOffset) and (Shift = [ssShift]) then begin for i := Columns.Count - 1 downto 0 do if TCRColumn(Columns[i]).CanBeSorted then begin Column := Columns[i]; MoveColRow(DataToRawColumn(i), TopRow, True, True); Break; end; if Column <> nil then ActivateEdit; end; VK_RETURN: begin if SelectedField is TMemoField then begin DoOnMemoClick(Columns[RawToDataColumn(Col)]); Key := 0; HideEditor; end; end; end; case Key of VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END : InvalidateRect(Handle,{$IFNDEF CLR}@{$ENDIF}FStatusRect,False); end; inherited; end; function TCRDBGrid.CanEditShow: boolean; begin if (Columns.Count > 0) and Assigned(SelectedField) and (SelectedField is TMemoField) then Result := False else Result := inherited CanEditShow; end; procedure TCRDBGrid.TopLeftChanged; {$IFDEF VER4} var R: TRect; DrawInfo: TGridDrawInfo; {$ENDIF} begin inherited; {$IFDEF VER4} if HandleAllocated and (dgTitles in Options) then begin CalcFixedInfo(DrawInfo); R := Rect(0, 0, Width, DrawInfo.Vert.FixedBoundary); InvalidateRect(Handle, {$IFNDEF CLR}@{$ENDIF}R, False); end; {$ENDIF} InvalidateRect(Handle,{$IFNDEF CLR}@{$ENDIF}FStatusRect,False); end; procedure TCRDBGrid.SetFiltered(const Value: boolean); begin if FFiltered <> Value then begin FFiltered := Value; FOptionsMenuDef.Items[0].Checked := FFiltered; if (DataSource = nil) or (DataSource.DataSet = nil) then Exit; if Value then ApplyFilter; if dgeLocalFilter in OptionsEx then DataSource.DataSet.Filtered := Value else begin if not Value then if DataLink.DataSet is TCustomDADataSet then TCustomDADataSet(DataSource.DataSet).FilterSQL := ''; end; end end; procedure TCRDBGrid.UpdateRowCount; begin with DataLink do if Active and (RecordCount > 0) and HandleAllocated then begin RowCount := 1000; BufferCount := VisibleRowCount; if dgTitles in Options then RowCount := RecordCount + 1 else RowCount := RecordCount; end; Invalidate; end; procedure TCRDBGrid.ApplyFilter; var i: integer; St, FilterText: string; OldActiveColumn: integer; begin if not FFiltered then Exit; FilterText := ''; for i := 0 to Columns.Count - 1 do begin St := TCRColumn(Columns[i]).GetFilterExpression(TCRColumn(Columns[i]).FilterExpression); if St <> '' then begin if FilterText <> '' then FilterText := FilterText + ' AND '; FilterText := FilterText + St; end; end; if dgeLocalFilter in OptionsEx then begin DataSource.DataSet.Filter := FilterText; DataSource.DataSet.Filtered := FFiltered; // TOraDataSet(DataSource.DataSet).Filtered := FilterText <> ''; end else if DataSource.DataSet is TCustomDADataSet then begin OldActiveColumn := -1; if CRGridTitleEdit.FActiveColumn <> nil then for i := 0 to Columns.Count - 1 do if CRGridTitleEdit.FActiveColumn = Columns[i] then begin OldActiveColumn := i; Break; end; CRGridTitleEdit.FActiveColumn := nil; TCustomDADataSet(DataSource.DataSet).FilterSQL := FilterText; if OldActiveColumn <> -1 then CRGridTitleEdit.FActiveColumn := Columns[OldActiveColumn]; for i := 0 to High(CRGridTitleEdit.FFilterExpressions) do TCRColumn(Columns[i]).FilterExpression := CRGridTitleEdit.FFilterExpressions[i]; end; ResetTotals; LoadTotals; end; procedure TCRDBGrid.FilteredItemClick(Sender: TObject); begin Filtered := not Filtered; (Sender as TMenuItem).Checked := FFiltered; end; procedure TCRDBGrid.DoExit; begin inherited; if not FContinueEditingFilter then CRGridTitleEdit.EditingFilter := False else FContinueEditingFilter := False; end; procedure TCRDBGrid.MoveColRow(ACol, ARow: Longint; MoveAnchor, Show: Boolean); begin inherited MoveColRow(ACol, ARow, MoveAnchor, Show); end; function TCRDBGrid.DataToRawColumn(ACol: Integer): Integer; begin Result := inherited DataToRawColumn(ACol); end; procedure TCRDBGrid.InvalidateCol(ACol: Longint); begin inherited InvalidateCol(ACol); end; procedure TCRDBGrid.InvalidateRow(ARow: Longint); begin inherited InvalidateRow(ARow); end; procedure TCRDBGrid.AdjustColumns; var Width: array of integer; i, j, OldActive: integer; CurWidth: Integer; begin if not DataLink.Active then Exit; SetLength(Width, Columns.Count); OldActive := DataLink.ActiveRecord; try for i := TopRow - 1 to VisibleRowCount - 1 do begin Datalink.ActiveRecord := i; for j := 0 to Columns.Count - 1 do begin if Assigned(Columns[j].Field) then CurWidth := Canvas.TextWidth(Columns[j].Field.DisplayText) else CurWidth := 0; if CurWidth > Width[j] then Width[j] := CurWidth; end; end; finally DataLink.ActiveRecord := OldActive; end; for i := 0 to Columns.Count - 1 do begin CurWidth := Canvas.TextWidth(Columns[i].Title.Caption); if CurWidth > Width[i] then ColWidths[i + IndicatorOffset] := CurWidth + 4 else ColWidths[i + IndicatorOffset] := Width[i] + 4; end; end; function TCRDBGrid.GetColumns: TCRDBGridColumns; begin Result := TCRDBGridColumns(inherited Columns); end; procedure TCRDBGrid.SetColumns(const Value: TCRDBGridColumns); begin inherited Columns.Assign(Value); end; procedure TCRDBGrid.WMMouseWheel(var Message: TWMMouseWheel); begin if Message.WheelDelta > 0 then SendMessage(Handle, WM_KEYDOWN, VK_UP, 0) else SendMessage(Handle, WM_KEYDOWN, VK_DOWN, 0); end; procedure TCRDBGrid.TitleClick(Column: TColumn); begin if FTitleBarUp then inherited TitleClick(Column); end; { TCRColumnTitle } function TCRColumnTitle.GetCaption: string; begin Result := inherited Caption; end; function TCRColumnTitle.IsCaptionStored: boolean; begin Result := (cvTitleCaption in Column.AssignedValues) and (Caption <> DefaultCaption); end; procedure TCRColumnTitle.SetCaption(const Value: string); begin if Value <> inherited Caption then begin inherited Caption := Value; TCRColumn(Column).ChangedTitle(True); end; end; { TCRGridTitleEdit } procedure TCRGridTitleEdit.ActivateAt(ARect: TRect; ActiveColumn: TColumn; AsFilter: boolean); begin if not Assigned(CRDBGrid) then Exit; try StopEdit(True); FEdit.Visible := False; FAsFilter := AsFilter; FActiveColumn := ActiveColumn; SetClientRect(ARect); if AsFilter then begin if EditingFilter then Caption := FFilterExpressions[FActiveColumn.Index] else Caption := TCRColumn(FActiveColumn).FilterExpression; end else Caption := ''; finally Visible := True; SetFocus; end; end; constructor TCRGridTitleEdit.Create(AOwner: TComponent); begin inherited; if AOwner is TCRDBGrid then CRDBGrid := AOwner as TCRDBGrid; Visible := False; AutoSize := False; Anchors := Anchors + [akRight]; Width := 0; Height := 0; FEdit := TEdit.Create(Self); FEdit.Visible := False; FEdit.TabStop := False; FEdit.BorderStyle := bsNone; FEdit.Width := 0; FEdit.Height := 0; InsertControl(FEdit); FEdit.Parent := Self; FEdit.ParentFont := False; FEdit.OnKeyPress := FEditKeyPress; FEdit.OnKeyDown := FEditKeyDown; FEdit.OnChange := FEditChange; FEdit.OnExit := FEditExit; end; procedure TCRGridTitleEdit.DoExit; begin inherited; FEdit.Visible := False; Visible := False; end; procedure TCRGridTitleEdit.FEditChange(Sender: TObject); begin if not FEdit.Modified then Exit; if FAsFilter then EditingFilter := True else ProcessEdit; end; procedure TCRGridTitleEdit.FEditExit(Sender: TObject); begin StopEdit(True); end; procedure TCRGridTitleEdit.WMMouseWheel(var Message: TWMMouseWheel); begin if Message.WheelDelta > 0 then SendMessage(Handle, WM_KEYDOWN, VK_UP, 0) else SendMessage(Handle, WM_KEYDOWN, VK_DOWN, 0); end; procedure TCRGridTitleEdit.FEditKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); var OldKey: word; OldWidth : integer; begin OldKey := Key; Key := 0; case OldKey of VK_RETURN: begin OldWidth := Self.Width; StopEdit(True); Self.Width := OldWidth; Visible := True; SetFocus; end; VK_ESCAPE: begin StopEdit(False); Visible := True; SetFocus; end; VK_UP: GotoUpperCell; VK_DOWN: GotoLowerCell; VK_TAB: begin if Shift = [ssShift] then GotoPrevCell else if Shift = [] then GotoNextCell; end; else Key := OldKey; end; end; procedure TCRGridTitleEdit.FEditKeyPress(Sender: TObject; var Key: char); begin if (Key = #13) or (Key = #27) then Key := #0; end; procedure TCRGridTitleEdit.GotoLowerCell; begin if Assigned(CRDBGrid) then begin if FAsFilter then begin StopEdit(True); EditingFilter := False; if dgeSearchBar in CRDBGrid.OptionsEx then begin CRDBGrid.ActivateSearchEdit(FActiveColumn); Exit; end; end; with CRDBGrid do if DataLink.Active then begin Col := DataToRawColumn(FActiveColumn.Index); DataLink.DataSet.MoveBy(TopRow - Row); end; CRDBGrid.SetFocus; end; end; procedure TCRGridTitleEdit.GotoNextCell; var i, Start: integer; begin if not (Assigned(FActiveColumn) and Assigned(CRDBGrid)) then Exit; StopEdit(True); if FAsFilter then begin Start := 0; for i := FActiveColumn.Index + 1 to CRDBGrid.Columns.Count - 1 do if TCRColumn(CRDBGrid.Columns[i]).CanBeSorted then begin CRDBGrid.MoveColRow(CRDBGrid.DataToRawColumn(i), CRDBGrid.TopRow, True, True); CRDBGrid.ActivateFilterEdit(CRDBGrid.Columns[i]); Exit; end; EditingFilter := False; end else Start := FActiveColumn.Index + 1; if dgeSearchBar in CRDBGrid.OptionsEx then for i := Start to CRDBGrid.Columns.Count - 1 do if TCRColumn(CRDBGrid.Columns[i]).CanBeSorted then begin CRDBGrid.MoveColRow(CRDBGrid.DataToRawColumn(i), CRDBGrid.TopRow, True, True); CRDBGrid.ActivateSearchEdit(CRDBGrid.Columns[i]); Exit; end; with CRDBGrid do if DataLink.Active then begin LeftCol := 1; Col := DataToRawColumn(0); DataLink.DataSet.MoveBy(TopRow - Row); end; CRDBGrid.SetFocus; end; procedure TCRGridTitleEdit.GotoPrevCell; var i, Start: integer; begin if not (Assigned(FActiveColumn) and Assigned(CRDBGrid)) then Exit; StopEdit(True); if not FAsFilter then begin Start := CRDBGrid.Columns.Count - 1; for i := FActiveColumn.Index - 1 downto 0 do if TCRColumn(CRDBGrid.Columns[i]).CanBeSorted then begin CRDBGrid.MoveColRow(CRDBGrid.DataToRawColumn(i), CRDBGrid.TopRow, True, True); CRDBGrid.ActivateSearchEdit(CRDBGrid.Columns[i]); Exit; end; end else Start := FActiveColumn.Index - 1; if dgeFilterBar in CRDBGrid.OptionsEx then for i := Start downto 0 do if TCRColumn(CRDBGrid.Columns[i]).CanBeSorted then begin CRDBGrid.MoveColRow(CRDBGrid.DataToRawColumn(i), CRDBGrid.TopRow, True, True); CRDBGrid.ActivateFilterEdit(CRDBGrid.Columns[i]); Exit; end; end; procedure TCRGridTitleEdit.GotoUpperCell; begin if not FAsFilter and (dgeFilterBar in CRDBGrid.OptionsEx) and Assigned(CRDBGrid) then begin CRDBGrid.ActivateFilterEdit(FActiveColumn); end; end; procedure TCRGridTitleEdit.KeyDown(var Key: word; Shift: TShiftState); var OldKey: word; begin inherited; OldKey := Key; Key := 0; case OldKey of VK_RETURN : StartEdit; VK_UP: GotoUpperCell; VK_DOWN: GotoLowerCell; VK_RIGHT: GotoNextCell; VK_LEFT: GotoPrevCell; VK_TAB: begin if Shift = [ssShift] then GotoPrevCell else if Shift = [] then GotoNextCell; end; VK_ESCAPE: if EditingFilter then begin SetLength(FFilterExpressions,0); EditingFilter := False; Caption := TCRColumn(FActiveColumn).FilterExpression; CRDBGrid.InvalidateRow(0); Invalidate; end; else Key := OldKey; end; end; procedure TCRGridTitleEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); begin inherited; if Focused and (Button = mbLeft) then StartEdit; end; procedure TCRGridTitleEdit.PaintWindow(DC: HDC); var Rect: TRect; Brush: THandle; OldBrush: THandle; OldFont: THandle; BrushColor: TColor; FontColor: TColor; begin Rect := GetClientRect; if Focused then begin BrushColor := clHighlight; FontColor := clWhite; end else begin BrushColor := Color; FontColor := Font.Color; end; Brush := CreateSolidBrush(ColorToRGB(BrushColor)); try OldBrush := SelectObject(DC, Brush); FillRect(DC, Rect, Brush); if Focused then DrawFocusRect(DC, Rect); InflateRect(Rect, -2, -2); SetTextColor(DC, ColorToRGB(FontColor)); SetBkColor(DC, ColorToRGB(BrushColor)); OldFont := SelectObject(DC, Font.Handle); DrawText(DC, PChar(Caption), Length(Caption), Rect, DT_LEFT or DT_VCENTER); SelectObject(DC, OldFont); SelectObject(DC, OldBrush); finally DeleteObject(Brush); end; end; procedure TCRGridTitleEdit.PostFilter; var i: integer; begin StopEdit(True); if (CRDBGrid = nil) or (Length(FFilterExpressions) = 0) then Exit; for i := 0 to High(FFilterExpressions) do begin TCRColumn(CRDBGrid.Columns[i]).FilterExpression := FFilterExpressions[i]; end; CRDBGrid.ApplyFilter; end; procedure TCRGridTitleEdit.ProcessEdit; begin if (FActiveColumn = nil) or (CRDBGrid = nil) or not FEdit.Modified then Exit; if FAsFilter then with CRDBGrid do begin try TCRColumn(FActiveColumn).GetFilterExpression(FEdit.Text); FFilterExpressions[FActiveColumn.Index] := FEdit.Text; Self.Caption := FFilterExpressions[FActiveColumn.Index]; except on EConvertError do begin FEdit.SelectAll; raise; end; end; end else try with FActiveColumn.Field do DataSet.Locate(FieldName, {$IFDEF CLR}Variant{$ENDIF}(FEdit.Text), [loCaseInsensitive,loPartialKey]); except on EConvertError do Exit; end; end; procedure TCRGridTitleEdit.SetClientRect(ARect: TRect); begin Top := ARect.Top; Left := ARect.Left; Width := ARect.Right - ARect.Left; Height := CRDBGrid.DefaultRowHeight; FEdit.Top := 2; FEdit.Left := 2; FEdit.Width := Width - 2; FEdit.Height := Height - 2; end; procedure TCRGridTitleEdit.SetCRDBGrid(const Value: TCRDBGrid); begin FCRDBGrid := Value; end; procedure TCRGridTitleEdit.SetEditingFilter(const Value: boolean); var i: integer; begin if FEditingFilter <> Value then begin FEditingFilter := Value; if Assigned(CRDBGrid) then begin if not Value then begin PostFilter; CRDBGrid.FContinueEditingFilter := False; end else with CRDBGrid do begin SetLength(FFilterExpressions, Columns.Count); for i := 0 to Columns.Count - 1 do FFilterExpressions[i] := TCRColumn(Columns[i]).FilterExpression; end; end; if Assigned(CRDBGrid) and (dgIndicator in CRDBGrid.Options) then CRDBGrid.InvalidateCol(0); end; end; procedure TCRGridTitleEdit.SetFocus; begin inherited; Invalidate; end; procedure TCRGridTitleEdit.StartEdit; begin if CRDBGrid = nil then Exit; if FAsFilter then begin FEdit.Text := Caption; end else FEdit.Text := ''; FEdit.Font := CRDBGrid.Font; FEdit.Modified := False; FEdit.Visible := True; FEdit.SetFocus; Invalidate; end; procedure TCRGridTitleEdit.StopEdit(AcceptChanges: boolean); begin if not FEdit.Visible then Exit; if AcceptChanges then ProcessEdit; CRDBGrid.FContinueEditingFilter := EditingFilter; FEdit.Modified := False; FEdit.Visible := False; if AcceptChanges then EditingFilter := False; Invalidate; // Visible := True; // SetFocus; end; procedure TCRGridTitleEdit.WMChar(var Message: TWMChar); begin inherited; if (Message.CharCode > 0) and (Message.CharCode <> VK_TAB) and (Message.CharCode <> VK_ESCAPE) then begin StartEdit; if Message.CharCode <> VK_RETURN then SendMessage(FEdit.Handle, Message.Msg , {$IFDEF VER9P}Message.CharCode{$ELSE}TMessage(Message).WParam{$ENDIF}, {$IFDEF VER9P}Message.KeyData{$ELSE}TMessage(Message).LParam{$ENDIF}); end; end; procedure TCRGridTitleEdit.WMGetDlgCode(var Message: TWMGetDlgCode); begin Message.Result := Message.Result or DLGC_WANTARROWS; if Assigned(CRDBGrid) and (dgTabs in CRDBGrid.Options) then Message.Result := Message.Result or DLGC_WANTTAB; end; { TMemoEditorForm } function TMemoEditorForm.CloseQuery: boolean; begin Result := inherited CloseQuery; if FMemo.Modified and (ModalResult <> mrOK) then case MessageDlg(Format(fmtModifiedWarning,[Caption]), mtConfirmation, mbYesNoCancel, 0) of mrYes: ModalResult := mrOK; mrCancel: Result := False; end; end; constructor TMemoEditorForm.Create(AOwner: TComponent); {$IFDEF CLR} var Cookie: LockCookie; {$ENDIF} begin {$IFDEF CLR} Cookie := GlobalNameSpace.UpgradeToWriterLock(MaxInt); try inherited CreateNew(AOwner); finally GlobalNameSpace.DowngradeFromWriterLock(Cookie); end; {$ELSE} GlobalNameSpace.BeginWrite; try CreateNew(AOwner); finally GlobalNameSpace.EndWrite; end; {$ENDIF} Visible := False; Position := poScreenCenter; Width := 530; Height := 308; BorderStyle := bsSizeable; BorderIcons := [biSystemMenu]; ParentFont := True; Constraints.MinHeight := 100; Constraints.MinWidth := 260; FMemo := TMemo.Create(Self); InsertControl(FMemo); FMemo.Top := 0; FMemo.Height := 270; FMemo.Align := alTop; FMemo.Anchors := FMemo.Anchors + [akBottom]; FMemo.ScrollBars := ssBoth; FMemo.OnKeyDown := MemoKeyDown; FCheckBox := TCheckBox.Create(Self); InsertControl(FCheckBox); FCheckBox.Caption := sWordWrap; FCheckBox.Left := 8; FCheckBox.Top := 282; FCheckBox.Anchors := [akLeft, akBottom]; FCheckBox.OnClick := CheckBoxClick; FCancelBtn := TButton.Create(Self); InsertControl(FCancelBtn); FCancelBtn.Top := 278; FCancelBtn.Left := Width - FCancelBtn.Width - 4; FCancelBtn.Anchors := [akRight, akBottom]; FCancelBtn.Caption := SCancel; FCancelBtn.Cancel := True; FCancelBtn.ModalResult := mrCancel; FOKBtn := TButton.Create(Self); InsertControl(FOKBtn); FOKBtn.Top := FCancelBtn.Top; FOKBtn.Left := FCancelBtn.Left - FOKBtn.Width - 4; FOKBtn.Anchors := [akRight, akBottom]; FOKBtn.Caption := SOK; FOKBtn.ModalResult := mrOK; FOKBtn.TabOrder := 1; end; procedure TMemoEditorForm.MemoKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin case key of VK_RETURN: if Shift = [ssCtrl] then ModalResult := mrOK; VK_ESCAPE: ModalResult := mrCancel; end; end; procedure TMemoEditorForm.CheckBoxClick(Sender: tobject); begin FMemo.WordWrap := FCheckBox.Checked; end; procedure TMemoEditorForm.SetReadOnly(const Value: boolean); begin if FReadOnly <> Value then begin FReadOnly := Value; FOKBtn.Visible := not Value; FMemo.ReadOnly := Value; if Value then FCancelBtn.Caption := SClose else FCancelBtn.Caption := SCancel; end; end; {$IFDEF VER6P} { TCRGridDataLink } procedure TCRGridDataLink.DataSetChanged; begin inherited; if FDataSetChanging or (DataSet.State <> dsBrowse) then Exit; FDataSetChanging := True; try TCRDBGrid(Grid).DataChanged; finally FDataSetChanging := False; end; end; {$ENDIF} initialization bmpSortAsc := TBitmap.Create; bmpSortAsc.Handle := LoadBitmap(hInstance, 'SORTASC'); bmpSortAsc.Transparent := True; bmpSortDesc := TBitmap.Create; bmpSortDesc.Handle := LoadBitmap(hInstance, 'SORTDESC'); bmpSortDesc.Transparent := True; bmpFilter := TBitmap.Create; bmpFilter.Handle := LoadBitmap(hInstance, 'FILTER'); bmpFilter.Transparent := True; bmpSearch := TBitmap.Create; bmpSearch.Handle := LoadBitmap(hInstance, 'SEARCH'); bmpSearch.Transparent := True; bmpMenu := TBitmap.Create; bmpMenu.Handle := LoadBitmap(hInstance, 'MENU'); bmpMenu.Transparent := True; bmpActiveFilter := TBitmap.Create; bmpActiveFilter.Handle := LoadBitmap(hInstance, 'ACTIVE_FILTER'); bmpActiveFilter.Transparent := True; bmpEditMode := TBitmap.Create; bmpEditMode.Handle := LoadBitmap(hInstance, 'EDIT'); bmpEditMode.Transparent := True; finalization bmpSortDesc.Free; bmpSortAsc.Free; bmpFilter.Free; bmpSearch.Free; bmpMenu.Free; bmpActiveFilter.Free; bmpEditMode.Free; end.