{********************************************************************} { } { Developer Express Visual Component Library } { ExpressQuantumGrid } { } { Copyright (c) 1998-2009 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSQUANTUMGRID AND ALL } { ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {********************************************************************} unit cxGridStructureNavigator; // TODO transparency {$I cxVer.inc} interface uses {$IFDEF DELPHI6} DesignIntf, {$ELSE} DsgnIntf, {$ENDIF} Windows, Messages, TypInfo, Classes, SysUtils, Controls, Graphics, Forms, Menus, ExtCtrls, Buttons, cxControls, cxClasses, cxGraphics, cxDesignWindows, cxGridCommon, cxGrid, cxGridLevel, cxGridCustomView, cxViewEditor; const CM_DeferUpdate = WM_DX + 25; type TcxGridStructureControl = class; TcxGridStructureNavigator = class; TcxGridColorIndex = (ciGrid, ciLevel, ciView); { TcxGridStructureControlViewInfo } TcxGridStructureControlRowViewInfo = class Bounds: TRect; LevelBounds: TRect; LevelContentBounds: TRect; LevelHighlighted: Boolean; LevelSelected: Boolean; LevelText: string; LevelTextArea: TRect; ViewBounds: TRect; ViewContentBounds: TRect; ViewHighlighted: Boolean; ViewSelected: Boolean; ViewText: string; ViewTextArea: TRect; TreeLineVertCount: Integer; TreeLineIsParent: Boolean; TreeLineIsLast: Boolean; end; TcxGridStructureControlRowsViewInfo = class(TcxObjectList) private function GetItem(Index: Integer): TcxGridStructureControlRowViewInfo; public property Items[Index: Integer]: TcxGridStructureControlRowViewInfo read GetItem; default; end; TcxGridStructureControlViewInfo = class private FCanvas: TcxCanvas; FStructureControl: TcxGridStructureControl; FTextHeight: Integer; FRowHeight: Integer; FRows: TcxGridStructureControlRowsViewInfo; function GetCanvas: TcxCanvas; function GetGrid: TcxCustomGrid; function GetLevelByIndex(AIndex: Integer): TcxGridLevel; procedure GetLevelInfo(AIndex: Integer; var ALevelText, AViewText: string; var ALevelIndex: Integer; var AIsParent, AIsLast: Boolean); function GetRowCount: Integer; public Bounds: TRect; constructor Create(AStructureControl: TcxGridStructureControl); destructor Destroy; override; procedure Calculate; function GetContentColor: TColor; function GetContentFont: TFont; function GetContentFontColor: TColor; function GetGridColor(AHighlighted: Boolean): TColor; function GetHighlightedFontColor: TColor; function GetLevelColor(AHighlighted: Boolean): TColor; function GetRowBorderColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; function GetRowColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; function GetRowTextColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; function GetSelectedColor(AHighlighted: Boolean): TColor; function GetSelectedFontColor: TColor; function GetViewColor(AHighlighted: Boolean): TColor; procedure Paint; property Canvas: TcxCanvas read GetCanvas; property Grid: TcxCustomGrid read GetGrid; property StructureControl: TcxGridStructureControl read FStructureControl; property Rows: TcxGridStructureControlRowsViewInfo read FRows; end; { TcxGridStructureControl } TcxGridStructureControlSelectComponentEvent = procedure(AObject: TPersistent; AClearSelection: Boolean) of object; TcxGridStructureControlHitTest = (htNowhere, htLevel, htView); TcxGridStructureControlHitInfo = record HitTest: TcxGridStructureControlHitTest; RowIndex: Integer; end; TcxGridStructureControl = class(TcxControl) private FGrid: TcxCustomGrid; FHitInfo: TcxGridStructureControlHitInfo; FLockCount: Integer; FMayFocused: Boolean; FMouseDownHitInfo: TcxGridStructureControlHitInfo; FMousePressed: Boolean; FMultiSelect: Boolean; FViewInfo: TcxGridStructureControlViewInfo; FOnDrawBackground: TNotifyEvent; FOnSelectComponent: TcxGridStructureControlSelectComponentEvent; FOnSelectionChanged: TNotifyEvent; procedure ClearSelection; procedure SetGrid(Value: TcxCustomGrid); procedure SetMultiSelect(Value: Boolean); protected 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 Paint; override; procedure AddToSelection(AObject: TPersistent; AClearSelection: Boolean); procedure CancelPressed(P: TPoint); procedure CheckMousePos(P: TPoint); procedure BoundsChanged; override; procedure DoDrawBackground; virtual; procedure FontChanged; override; function GetComponentByHitInfo(AHitInfo: TcxGridStructureControlHitInfo): TComponent; function GetCursor(X, Y: Integer): TCursor; override; function MayFocus: Boolean; override; procedure MouseLeave(AControl: TControl); override; procedure SelectComponent(AObject: TPersistent; AClearSelection: Boolean = True); procedure SelectionChanged; virtual; procedure SetPressed(APressed: Boolean); procedure UpdateContent; virtual; procedure UpdateHighlighted; property LockCount: Integer read FLockCount; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure BeginUpdate; procedure Changed; procedure EndUpdate; function GetHitInfo(P: TPoint): TcxGridStructureControlHitInfo; function GetLevelByRowIndex(ARowIndex: Integer): TcxGridLevel; function GetSelectedLevel: TcxGridLevel; procedure GetSelection(ASelectionList: TList); procedure GetSelectionLevels(ASelectionList: TList); function GetSelectionLevelCount: Integer; // function GetSelectedView: TcxCustomGridView; procedure GetSelectionViews(ASelectionList: TList); function GetSelectionViewCount: Integer; procedure SyncSelection(ASelectionList: TList); property Grid: TcxCustomGrid read FGrid write SetGrid; property Keys; property MayFocused: Boolean read FMayFocused write FMayFocused; property MultiSelect: Boolean read FMultiSelect write SetMultiSelect; property ViewInfo: TcxGridStructureControlViewInfo read FViewInfo; property OnKeyPress; property OnDrawBackground: TNotifyEvent read FOnDrawBackground write FOnDrawBackground; property OnSelectComponent: TcxGridStructureControlSelectComponentEvent read FOnSelectComponent write FOnSelectComponent; property OnSelectionChanged: TNotifyEvent read FOnSelectionChanged write FOnSelectionChanged; end; { TcxGridStructureHelper } TcxGridLevelViewList = class(TcxGridViewList) private FLevel: TcxGridLevel; protected procedure GetViewNames; override; public constructor Create(ALevel: TcxGridLevel); property Level: TcxGridLevel read FLevel; end; TcxGridStructureHelper = class private FPopupMenu: TPopupMenu; FPopupMenuLevel: TcxGridLevel; FStructureControl: TcxGridStructureControl; FOnUpdateDesigner: TNotifyEvent; procedure CreateLevelClick(Sender: TObject); procedure CreateViewClick(Sender: TObject); procedure SelectViewClick(Sender: TObject); procedure DeleteLevelClick(Sender: TObject); procedure MoveLevelClick(Sender: TObject); protected FPopupMenuView: TcxCustomGridView; FViewMenuProvider: TcxCustomGridViewMenuProvider; function CanAddComponent: Boolean; function CanDeleteComponent(AComponent: TComponent): Boolean; procedure ExecuteLevelViewsMenuItem(ALevel: TcxGridLevel; AMenuItem: TMenuItem); procedure FillLevelViewsMenu(AMenu: TMenuItem; ALevel: TcxGridLevel; AOnClick: TNotifyEvent); procedure StructureControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure UpdateDesigner; public constructor Create(AStructureControl: TcxGridStructureControl); virtual; destructor Destroy; override; property StructureControl: TcxGridStructureControl read FStructureControl; property OnUpdateDesigner: TNotifyEvent read FOnUpdateDesigner write FOnUpdateDesigner; end; { TcxGridStructureNavigator } TcxGridStructureNavigator = class(TcxCustomGridStructureNavigator) private FCloseButton: TSpeedButton; FCustomizeButton: TSpeedButton; FDefaultLevel: TcxGridLevel; FDefaultView: TcxCustomGridView; FDesignHelper: TcxDesignHelper; FMakeSelectionVisible: Boolean; FSeparator: TBevel; FStructureControl: TcxGridStructureControl; FStructureHelper: TcxGridStructureHelper; procedure CloseButtonClick(Sender: TObject); procedure CustomizeButtonClick(Sender: TObject); procedure UpdateDesigner(Sender: TObject); procedure CMDeferUpdate(var Message: TMessage); message CM_DeferUpdate; protected procedure Paint; override; procedure Calculate; function CalculateBoundsRect: TRect; override; procedure Changed; override; procedure CreateDefaultComponents; procedure DrawBackground(ACanvas: TcxCanvas); virtual; procedure DrawStructureControlBackground(Sender: TObject); function GetClientBounds: TRect; override; function GetDefaultViewClass: TcxCustomGridViewClass; virtual; function GetDesigner: IDesigner; procedure NotifyEditors; procedure SelectComponent(AObject: TPersistent; AClearSelection: Boolean); property MakeSelectionVisible: Boolean read FMakeSelectionVisible write FMakeSelectionVisible; public constructor Create(AGrid: TcxCustomGrid); override; destructor Destroy; override; procedure BeforeGridLoading; override; function IsObjectSelected(AObject: TPersistent): Boolean; override; procedure SelectionChanged(ASelection: TList); override; procedure SelectObject(AObject: TPersistent; AClearSelection: Boolean); override; procedure SelectObjects(AObjects: TList); override; procedure UnselectObject(AObject: TPersistent); override; end; function GenLevelName(AGrid: TcxCustomGrid; ALevel: TcxGridLevel): string; function GenViewName(AOwnerComponent: TComponent; AView: TcxCustomGridView): string; procedure FillRegisteredViewsMenu(AMenu: TMenuItem; AOnClick: TNotifyEvent); implementation uses Math, dxOffice11, cxLookAndFeelPainters, cxCustomData, cxGridDBTableView, cxGridEditor, cxLibraryConsts; const ButtonBorderSize = 1; ButtonOffset = 2; CloseButtonHeight = 13; CloseButtonWidth = 14; FrameBorderSize = 1; LevelIndent = 16; RowBorderWidth = 1; RowOffset = 2; TextOffset = 2; NavigatorOffset = 12; // strings SCustomizeText = 'Customize...'; // TODO res SSubStr = 'TcxGrid'; cxGridDesignLevelColor = 15851215{16248036}; cxGridDesignLevelHotColor = 13747387; cxGridDesignLevelBorderColor = 13547166; cxGridDesignLevelHotBorderColor = 12033927; cxGridDesignGridColor = 12639424; cxGridDesignGridHotColor = 10800292; cxGridDesignGridBorderColor = 10526880; cxGridDesignGridHotBorderColor = clDkGray; type TcxCustomGridAccess = class(TcxCustomGrid); function GenLevelName(AGrid: TcxCustomGrid; ALevel: TcxGridLevel): string; begin Result := CreateUniqueName(AGrid.Owner, AGrid, ALevel, ScxGridPrefixName, ''); end; function GenViewName(AOwnerComponent: TComponent; AView: TcxCustomGridView): string; begin Result := CreateUniqueName(AOwnerComponent.Owner, AOwnerComponent, AView, ScxGridPrefixName, ''); end; procedure FillRegisteredViewsMenu(AMenu: TMenuItem; AOnClick: TNotifyEvent); var I: Integer; begin for I := 0 to cxGridRegisteredViews.Count - 1 do begin if (I <> 0) and (Pos('DB', cxGridRegisteredViews.Descriptions[I]) = 1) and (Pos('DB', cxGridRegisteredViews.Descriptions[I - 1]) <> 1) then AMenu.Add(CreateMenuItem(AMenu.Owner, '-')); AMenu.Add(CreateMenuItem(AMenu.Owner, cxGridRegisteredViews.Descriptions[I], AOnClick, True, I)); end; end; procedure CreateCloseBitmap(ABitmap: TBitmap); var ACanvas: TcxCanvas; R: TRect; begin R := Rect(0, 0, CloseButtonWidth, CloseButtonHeight); with ABitmap do begin Width := R.Right - R.Left; Height := R.Bottom - R.Top; Canvas.Brush.Color := clBtnFace; Canvas.FillRect(R); ACanvas := TcxCanvas.Create(Canvas); try TcxUltraFlatLookAndFeelPainter.DrawButtonCross(ACanvas, R, clBtnText, cxbsNormal); finally ACanvas.Free; end; end; end; {$IFDEF DELPHI6} { TDesignNotificationHandler } type TDesignNotificationHandler = class(TInterfacedPersistent, IDesignNotification) private FGrids: TList; protected // IDesignNotification procedure ItemDeleted(const ADesigner: IDesigner; AItem: TPersistent); procedure ItemInserted(const ADesigner: IDesigner; AItem: TPersistent); procedure ItemsModified(const ADesigner: IDesigner); procedure SelectionChanged(const ADesigner: IDesigner; const ASelection: IDesignerSelections); procedure DesignerOpened(const ADesigner: IDesigner; AResurrecting: Boolean); procedure DesignerClosed(const ADesigner: IDesigner; AGoingDormant: Boolean); public constructor Create; virtual; destructor Destroy; override; procedure RegisterGrid(AGrid: TcxCustomGrid); procedure UnregisterGrid(AGrid: TcxCustomGrid); end; var DesignNotificationHandler: TDesignNotificationHandler; constructor TDesignNotificationHandler.Create; begin inherited; FGrids := TList.Create; RegisterDesignNotification(Self); end; destructor TDesignNotificationHandler.Destroy; begin UnregisterDesignNotification(Self); FGrids.Free; inherited; end; procedure TDesignNotificationHandler.ItemDeleted(const ADesigner: IDesigner; AItem: TPersistent); begin end; procedure TDesignNotificationHandler.ItemInserted(const ADesigner: IDesigner; AItem: TPersistent); begin end; procedure TDesignNotificationHandler.ItemsModified(const ADesigner: IDesigner); begin end; procedure TDesignNotificationHandler.SelectionChanged(const ADesigner: IDesigner; const ASelection: IDesignerSelections); var ASelectionList: TList; I: Integer; begin ASelectionList := TList.Create; try ConvertSelectionToList(ASelection, ASelectionList); for I := 0 to FGrids.Count - 1 do TcxCustomGrid(FGrids[I]).StructureNavigator.SelectionChanged(ASelectionList); finally ASelectionList.Free; end; end; procedure TDesignNotificationHandler.DesignerOpened(const ADesigner: IDesigner; AResurrecting: Boolean); begin end; procedure TDesignNotificationHandler.DesignerClosed(const ADesigner: IDesigner; AGoingDormant: Boolean); begin end; procedure TDesignNotificationHandler.RegisterGrid(AGrid: TcxCustomGrid); begin FGrids.Add(AGrid); end; procedure TDesignNotificationHandler.UnregisterGrid(AGrid: TcxCustomGrid); begin FGrids.Remove(AGrid); end; {$ENDIF} { TcxGridStructureControlRowsViewInfo } function TcxGridStructureControlRowsViewInfo.GetItem(Index: Integer): TcxGridStructureControlRowViewInfo; begin Result := TcxGridStructureControlRowViewInfo(inherited Items[Index]); end; { TcxGridStructureControlViewInfo } constructor TcxGridStructureControlViewInfo.Create(AStructureControl: TcxGridStructureControl); begin inherited Create; FStructureControl := AStructureControl; FRows := TcxGridStructureControlRowsViewInfo.Create; end; destructor TcxGridStructureControlViewInfo.Destroy; begin FRows.Free; FreeAndNil(FCanvas); inherited Destroy; end; procedure TcxGridStructureControlViewInfo.Calculate; var ASelection: TList; W, H: Integer; I, ALevelOffset, ATop: Integer; ARow: TcxGridStructureControlRowViewInfo; begin // TODO: ref if Grid = nil then Exit; ASelection := TList.Create; try // save selection StructureControl.GetSelection(ASelection); // Init Canvas.Font := GetContentFont; FTextHeight := Canvas.TextHeight('Wg'); FRowHeight := 2 * RowOffset + 2 * RowBorderWidth + 2 * TextOffset + FTextHeight; // Rows FRows.Clear; H := GetRowCount * FRowHeight; Bounds := Rect(0, 0, 0, H); ATop := 0; for I := 0 to GetRowCount - 1 do begin ARow := TcxGridStructureControlRowViewInfo.Create; GetLevelInfo(I, ARow.LevelText, ARow.ViewText, ARow.TreeLineVertCount, ARow.TreeLineIsParent, ARow.TreeLineIsLast); // Level ARow.LevelTextArea := Rect(0, ATop, Canvas.TextWidth(ARow.LevelText), ATop + FTextHeight); OffsetRect(ARow.LevelTextArea, TextOffset, TextOffset); ARow.LevelContentBounds := ARow.LevelTextArea; InflateRect(ARow.LevelContentBounds, TextOffset, TextOffset); OffsetRect(ARow.LevelTextArea, RowBorderWidth, RowBorderWidth); OffsetRect(ARow.LevelContentBounds, RowBorderWidth, RowBorderWidth); ARow.LevelBounds := ARow.LevelContentBounds; InflateRect(ARow.LevelBounds, RowBorderWidth, RowBorderWidth); ARow.Bounds := ARow.LevelBounds; OffsetRect(ARow.LevelBounds, RowOffset, RowOffset); OffsetRect(ARow.LevelContentBounds, RowOffset, RowOffset); OffsetRect(ARow.LevelTextArea, RowOffset, RowOffset); //InflateRect(ARow.Bounds, RowOffset, RowOffset); OffsetRect(ARow.Bounds, RowOffset, RowOffset); // Indent ALevelOffset := ARow.TreeLineVertCount * (LevelIndent + RowOffset); OffsetRect(ARow.LevelBounds, ALevelOffset, 0); OffsetRect(ARow.LevelContentBounds, ALevelOffset, 0); OffsetRect(ARow.LevelTextArea, ALevelOffset, 0); OffsetRect(ARow.Bounds, ALevelOffset, 0); // View if (I > 0) and (ARow.ViewText <> '') then begin W := 2 * RowBorderWidth + 2 * TextOffset + Canvas.TextWidth(ARow.ViewText); ARow.ViewBounds := Rect(ARow.LevelBounds.Right - RowBorderWidth, ARow.LevelBounds.Top, ARow.LevelBounds.Right - RowBorderWidth + W, ARow.LevelBounds.Bottom); ARow.ViewContentBounds := ARow.ViewBounds; InflateRect(ARow.ViewContentBounds, -RowBorderWidth, -RowBorderWidth); ARow.ViewTextArea := ARow.ViewContentBounds; InflateRect(ARow.ViewTextArea, -TextOffset, -TextOffset); Inc(ARow.Bounds.Right, W - RowBorderWidth); end; FRows.Add(ARow); Bounds.Right := Max(Bounds.Right, ARow.Bounds.Right + RowOffset); Inc(ATop, FRowHeight); end; Bounds.Bottom := ATop; // restore selection StructureControl.SyncSelection(ASelection); finally ASelection.Free; end; end; function TcxGridStructureControlViewInfo.GetContentColor: TColor; begin Result := clWhite; end; function TcxGridStructureControlViewInfo.GetContentFont: TFont; begin Result := StructureControl.Font; end; function TcxGridStructureControlViewInfo.GetContentFontColor: TColor; begin Result := clBlack; end; function TcxGridStructureControlViewInfo.GetGridColor(AHighlighted: Boolean): TColor; begin if AHighlighted then Result := cxGridDesignGridHotColor else Result := cxGridDesignGridColor; end; function TcxGridStructureControlViewInfo.GetHighlightedFontColor: TColor; begin Result := GetContentFontColor; end; function TcxGridStructureControlViewInfo.GetLevelColor(AHighlighted: Boolean): TColor; begin if AHighlighted then Result := cxGridDesignLevelHotColor else Result := cxGridDesignLevelColor; end; function TcxGridStructureControlViewInfo.GetRowBorderColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; begin if ASelected then if AHighlighted then Result := cxGridDesignSelectedHotBorderColor else Result := cxGridDesignSelectedBorderColor else case AColorIndex of ciLevel: if AHighlighted then Result := cxGridDesignLevelHotBorderColor else Result := cxGridDesignLevelBorderColor; ciView: Result := cxGridDesignViewBorderColor; else if AHighlighted then Result := cxGridDesignGridHotBorderColor else Result := cxGridDesignGridBorderColor; end; end; function TcxGridStructureControlViewInfo.GetRowColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; begin if ASelected then Result := GetSelectedColor(AHighlighted) else case AColorIndex of ciLevel: Result := GetLevelColor(AHighlighted); ciView: Result := GetViewColor(AHighlighted); else Result := GetGridColor(AHighlighted); end; end; function TcxGridStructureControlViewInfo.GetRowTextColor(AColorIndex: TcxGridColorIndex; ASelected, AHighlighted: Boolean): TColor; begin if ASelected then Result := GetSelectedFontColor else if AHighlighted then Result := GetHighlightedFontColor else Result := GetContentFontColor; end; function TcxGridStructureControlViewInfo.GetSelectedColor(AHighlighted: Boolean): TColor; begin if AHighlighted then Result := cxGridDesignSelectedHotColor else Result := cxGridDesignSelectedColor; end; function TcxGridStructureControlViewInfo.GetSelectedFontColor: TColor; begin Result := GetContentFontColor; end; function TcxGridStructureControlViewInfo.GetViewColor(AHighlighted: Boolean): TColor; begin if AHighlighted then Result := cxGridDesignViewHotColor else Result := cxGridDesignViewColor; end; procedure TcxGridStructureControlViewInfo.Paint; procedure SetFontAndBrush(ASelected, AHighlighted: Boolean; AColorIndex: TcxGridColorIndex); begin Canvas.Brush.Color := GetRealColor(GetRowColor(AColorIndex, ASelected, AHighlighted)); Canvas.Font.Color := GetRealColor(GetRowTextColor(AColorIndex, ASelected, AHighlighted)); {if AHighlighted then Canvas.Font.Style := Canvas.Font.Style + [fsUnderline] else Canvas.Font.Style := Canvas.Font.Style - [fsUnderline];} end; procedure DrawCell(ACellRect, ATextRect: TRect; const AText: string); begin Canvas.FillRect(ACellRect); Canvas.Brush.Style := bsClear; Canvas.DrawText(AText, ATextRect, cxAlignLeft or cxAlignVCenter or cxSingleLine); Canvas.Brush.Style := bsSolid; end; procedure DrawRows; var I: Integer; ARow: TcxGridStructureControlRowViewInfo; AColorIndex: TcxGridColorIndex; begin for I := 0 to Rows.Count - 1 do begin ARow := Rows[I]; // Level if I = 0 then AColorIndex := ciGrid else AColorIndex := ciLevel; Canvas.FrameRect(ARow.LevelBounds, GetRealColor(GetRowBorderColor(AColorIndex, ARow.LevelSelected, ARow.LevelHighlighted)), RowBorderWidth); SetFontAndBrush(ARow.LevelSelected, ARow.LevelHighlighted, AColorIndex); DrawCell(ARow.LevelContentBounds, ARow.LevelTextArea, ARow.LevelText); // View if not IsRectEmpty(ARow.ViewBounds) then begin Canvas.FrameRect(ARow.ViewBounds, GetRealColor(GetRowBorderColor(ciView, ARow.ViewSelected, ARow.ViewHighlighted)), RowBorderWidth); SetFontAndBrush(ARow.ViewSelected, ARow.ViewHighlighted, ciView); DrawCell(ARow.ViewContentBounds, ARow.ViewTextArea, ARow.ViewText); end; Canvas.ExcludeClipRect(ARow.Bounds); end; end; begin // Rows Canvas.Font := GetContentFont; DrawRows; // Background StructureControl.DoDrawBackground; end; function TcxGridStructureControlViewInfo.GetCanvas: TcxCanvas; begin if StructureControl.HandleAllocated then begin if FCanvas <> nil then FreeAndNil(FCanvas); Result := StructureControl.Canvas; end else begin if FCanvas = nil then FCanvas := TcxScreenCanvas.Create; Result := FCanvas; end; end; function TcxGridStructureControlViewInfo.GetGrid: TcxCustomGrid; begin Result := StructureControl.Grid; end; function TcxGridStructureControlViewInfo.GetLevelByIndex(AIndex: Integer): TcxGridLevel; var ACurrent: Integer; procedure CalculateCount(ALevel: TcxGridLevel); var I: Integer; begin if ALevel = nil then Exit; if ACurrent = AIndex then Result := ALevel else begin Inc(ACurrent); for I := 0 to ALevel.Count - 1 do begin CalculateCount(ALevel[I]); if Result <> nil then Break; end; end; end; begin Result := nil; ACurrent := 0; if (Grid <> nil) and (Grid.Levels <> nil) then CalculateCount(Grid.Levels); end; procedure TcxGridStructureControlViewInfo.GetLevelInfo(AIndex: Integer; var ALevelText, AViewText: string; var ALevelIndex: Integer; var AIsParent, AIsLast: Boolean); function GetCompName(AComponent: TComponent): string; begin Result := AComponent.Name; if Result = '' then Result := '< >'; end; var ALevel: TcxGridLevel; begin ALevelText := ''; AViewText := ''; ALevelIndex := 0; AIsParent := False; AIsLast := False; ALevel := GetLevelByIndex(AIndex); if ALevel <> nil then begin AIsParent := ALevel.Count > 0; AIsLast := (ALevel.Parent <> nil) and (ALevel.Parent[ALevel.Parent.Count - 1] = ALevel); if ALevel.IsRoot then // TODO: IsRoot ALevelText := GetCompName(Grid) else begin ALevelText := GetCompName(ALevel); if ALevel.GridView <> nil then AViewText := GetCompName(ALevel.GridView); end; end; ALevelIndex := 0; while ALevel <> nil do begin if ALevel.IsRoot then // TODO: IsRoot Break else begin Inc(ALevelIndex); ALevel := ALevel.Parent; end; end; end; function TcxGridStructureControlViewInfo.GetRowCount: Integer; procedure CalculateCount(ALevel: TcxGridLevel); var I: Integer; begin Inc(Result, ALevel.Count); for I := 0 to ALevel.Count - 1 do CalculateCount(ALevel[I]); end; begin if Grid = nil then Result := 0 else begin Result := 1; // Root if Grid.Levels <> nil then CalculateCount(Grid.Levels); end; end; { TcxGridStructureControl } constructor TcxGridStructureControl.Create(AOwner: TComponent); begin inherited Create(AOwner); FViewInfo := TcxGridStructureControlViewInfo.Create(Self); end; destructor TcxGridStructureControl.Destroy; begin FreeAndNil(FViewInfo); inherited Destroy; end; procedure TcxGridStructureControl.BeginUpdate; begin Inc(FLockCount); end; procedure TcxGridStructureControl.Changed; begin if LockCount = 0 then UpdateContent; end; procedure TcxGridStructureControl.EndUpdate; begin Dec(FLockCount); Changed; end; function TcxGridStructureControl.GetHitInfo(P: TPoint): TcxGridStructureControlHitInfo; var I: Integer; begin Result.HitTest := htNowhere; Result.RowIndex := -1; for I := 0 to ViewInfo.Rows.Count - 1 do if PtInRect(ViewInfo.Rows[I].Bounds, P) then begin Result.RowIndex := I; if PtInRect(ViewInfo.Rows[I].LevelBounds, P) then begin Result.HitTest := htLevel; Break; end else if PtInRect(ViewInfo.Rows[I].ViewBounds, P) then begin Result.HitTest := htView; Break; end; end; end; function TcxGridStructureControl.GetLevelByRowIndex(ARowIndex: Integer): TcxGridLevel; begin Result := ViewInfo.GetLevelByIndex(ARowIndex); end; function TcxGridStructureControl.GetSelectedLevel: TcxGridLevel; var ASelectionList: TList; begin Result := nil; ASelectionList := TList.Create; try GetSelectionLevels(ASelectionList); if ASelectionList.Count = 1 then Result := TcxGridLevel(ASelectionList[0]); finally ASelectionList.Free; end; end; procedure TcxGridStructureControl.GetSelection(ASelectionList: TList); var I: Integer; ALevel: TcxGridLevel; begin ASelectionList.Clear; for I := 0 to ViewInfo.Rows.Count - 1 do begin ALevel := ViewInfo.GetLevelByIndex(I); if Assigned(ALevel) then begin if ViewInfo.Rows[I].LevelSelected then begin if ALevel.IsRoot then // TODO: IsRoot ASelectionList.Add(Grid) else ASelectionList.Add(ALevel); end; if ViewInfo.Rows[I].ViewSelected and (ALevel.GridView <> nil) then ASelectionList.Add(ALevel.GridView); end; end; end; procedure TcxGridStructureControl.GetSelectionLevels(ASelectionList: TList); var I: Integer; begin GetSelection(ASelectionList); for I := ASelectionList.Count - 1 downto 0 do if not (TObject(ASelectionList[I]) is TcxGridLevel) then ASelectionList.Delete(I); end; function TcxGridStructureControl.GetSelectionLevelCount: Integer; var ASelectionList: TList; begin ASelectionList := TList.Create; try GetSelectionLevels(ASelectionList); Result := ASelectionList.Count; finally ASelectionList.Free; end; end; procedure TcxGridStructureControl.GetSelectionViews(ASelectionList: TList); var I: Integer; begin GetSelection(ASelectionList); for I := ASelectionList.Count - 1 downto 0 do if not (TObject(ASelectionList[I]) is TcxCustomGridView) then ASelectionList.Delete(I); end; function TcxGridStructureControl.GetSelectionViewCount: Integer; var ASelectionList: TList; begin ASelectionList := TList.Create; try GetSelectionViews(ASelectionList); Result := ASelectionList.Count; finally ASelectionList.Free; end; end; procedure TcxGridStructureControl.SyncSelection(ASelectionList: TList); procedure CheckLevel(ARow: TcxGridStructureControlRowViewInfo; AComponent: TComponent); var ASelected: Boolean; begin ASelected := ASelectionList.IndexOf(AComponent) <> -1; if ARow.LevelSelected <> ASelected then begin ARow.LevelSelected := ASelected; InvalidateRect(ARow.LevelBounds, False); end; end; procedure CheckView(ARow: TcxGridStructureControlRowViewInfo; AComponent: TComponent); var ASelected: Boolean; begin ASelected := ASelectionList.IndexOf(AComponent) <> -1; if ARow.ViewSelected <> ASelected then begin ARow.ViewSelected := ASelected; InvalidateRect(ARow.ViewBounds, False); end; end; var I: Integer; ALevel: TcxGridLevel; begin for I := 0 to ViewInfo.Rows.Count - 1 do begin ALevel := ViewInfo.GetLevelByIndex(I); if Assigned(ALevel) then if ALevel.IsRoot then // TODO: IsRoot CheckLevel(ViewInfo.Rows[I], Grid) else begin CheckLevel(ViewInfo.Rows[I], ALevel); if ALevel.GridView <> nil then CheckView(ViewInfo.Rows[I], ALevel.GridView); end; end; end; procedure TcxGridStructureControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AComponent: TComponent; begin FMouseDownHitInfo := GetHitInfo(Point(X, Y)); if Button in [mbLeft, mbRight] then begin AComponent := GetComponentByHitInfo(FMouseDownHitInfo); if AComponent <> nil then SelectComponent(AComponent, (Button = mbRight) or not MultiSelect or not (ssShift in Shift)); SetPressed(True); CheckMousePos(Point(X, Y)); end; inherited; end; procedure TcxGridStructureControl.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited; CheckMousePos(Point(X, Y)); end; procedure TcxGridStructureControl.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; if Button in [mbLeft, mbRight] then CancelPressed(Point(X, Y)); end; procedure TcxGridStructureControl.Paint; begin ViewInfo.Paint; end; procedure TcxGridStructureControl.AddToSelection(AObject: TPersistent; AClearSelection: Boolean); function IsEquals(AList1, AList2: TList): Boolean; var I: Integer; begin Result := AList1.Count = AList2.Count; if Result then for I := 0 to AList1.Count - 1 do if AList1[I] <> AList2[I] then begin Result := False; Break; end; end; var APrevSelection, ASelection: TList; begin APrevSelection := TList.Create; ASelection := TList.Create; try GetSelection(APrevSelection); if not AClearSelection then GetSelection(ASelection); if (AObject <> nil) and (ASelection.Remove(AObject) = -1) then ASelection.Add(AObject); if not IsEquals(ASelection, APrevSelection) then begin SyncSelection(ASelection); SelectionChanged; end; finally ASelection.Free; APrevSelection.Free; end; end; procedure TcxGridStructureControl.CancelPressed(P: TPoint); begin SetPressed(False); CheckMousePos(P); end; procedure TcxGridStructureControl.CheckMousePos(P: TPoint); begin FHitInfo := GetHitInfo(P); UpdateHighlighted; end; procedure TcxGridStructureControl.BoundsChanged; begin inherited; Changed; end; procedure TcxGridStructureControl.DoDrawBackground; begin if Assigned(FOnDrawBackground) then FOnDrawBackground(Self) else begin Canvas.Brush.Color := ViewInfo.GetContentColor; Canvas.FillRect(ClientRect); end; end; procedure TcxGridStructureControl.FontChanged; begin inherited; Changed; end; function TcxGridStructureControl.GetComponentByHitInfo(AHitInfo: TcxGridStructureControlHitInfo): TComponent; var ALevel: TcxGridLevel; begin Result := nil; if AHitInfo.RowIndex = -1 then Exit; ALevel := ViewInfo.GetLevelByIndex(AHitInfo.RowIndex); if ALevel = nil then Exit; if AHitInfo.HitTest = htLevel then begin if ALevel.IsRoot then // TODO Result := Grid else Result := ALevel; end else if AHitInfo.HitTest = htView then begin if ALevel.GridView <> nil then Result := ALevel.GridView; end; end; function TcxGridStructureControl.GetCursor(X, Y: Integer): TCursor; begin if GetHitInfo(Point(X, Y)).HitTest in [htLevel, htView] then Result := crcxHandPoint else Result := inherited GetCursor(X, Y); end; function TcxGridStructureControl.MayFocus: Boolean; begin Result := FMayFocused; end; procedure TcxGridStructureControl.MouseLeave(AControl: TControl); begin CheckMousePos(Point(-1, -1)); end; procedure TcxGridStructureControl.SelectComponent(AObject: TPersistent; AClearSelection: Boolean = True); begin {$IFNDEF DELPHI6} if not Assigned(FOnSelectComponent) then {$ENDIF} AddToSelection(AObject, AClearSelection); if Assigned(FOnSelectComponent) then FOnSelectComponent(AObject, AClearSelection); end; procedure TcxGridStructureControl.SelectionChanged; begin if Assigned(FOnSelectionChanged) then FOnSelectionChanged(Self); end; procedure TcxGridStructureControl.SetPressed(APressed: Boolean); begin if FMousePressed <> APressed then begin FMousePressed := APressed; // TODO end; end; procedure TcxGridStructureControl.UpdateContent; begin ViewInfo.Calculate; Invalidate; end; procedure TcxGridStructureControl.UpdateHighlighted; procedure CheckLevel(ARow: TcxGridStructureControlRowViewInfo; AHighlighted: Boolean); begin if ARow.LevelHighlighted <> AHighlighted then begin ARow.LevelHighlighted := AHighlighted; InvalidateRect(ARow.LevelBounds, False); end; end; procedure CheckView(ARow: TcxGridStructureControlRowViewInfo; AHighlighted: Boolean); begin if ARow.ViewHighlighted <> AHighlighted then begin ARow.ViewHighlighted := AHighlighted; InvalidateRect(ARow.ViewBounds, False); end; end; var I: Integer; AHitInfo: TcxGridStructureControlHitInfo; begin for I := 0 to ViewInfo.Rows.Count - 1 do begin if FMousePressed then AHitInfo := FMouseDownHitInfo else AHitInfo := FHitInfo; if AHitInfo.HitTest = htLevel then begin CheckLevel(ViewInfo.Rows[I], (AHitInfo.RowIndex = I)); CheckView(ViewInfo.Rows[I], False); end else if AHitInfo.HitTest = htView then begin CheckLevel(ViewInfo.Rows[I], False); CheckView(ViewInfo.Rows[I], (AHitInfo.RowIndex = I)); end else begin CheckLevel(ViewInfo.Rows[I], False); CheckView(ViewInfo.Rows[I], False); end; end; end; procedure TcxGridStructureControl.ClearSelection; begin AddToSelection(nil, True); end; procedure TcxGridStructureControl.SetGrid(Value: TcxCustomGrid); begin if FGrid <> Value then begin FGrid := Value; Changed; end; end; procedure TcxGridStructureControl.SetMultiSelect(Value: Boolean); begin if FMultiSelect <> Value then begin FMultiSelect := Value; ClearSelection; end; end; { TcxGridLevelViewList } constructor TcxGridLevelViewList.Create(ALevel: TcxGridLevel); begin FLevel := ALevel; inherited Create(GetObjectDesigner(ALevel)); end; procedure TcxGridLevelViewList.GetViewNames; var I: Integer; AView: TcxCustomGridView; begin inherited; for I := ViewNames.Count - 1 downto 0 do begin AView := Views[I]; if (AView.Repository = nil) and (AView.StorageControl <> Level.Control) then ViewNames.Delete(I); end; end; { TcxGridStructureHelper } constructor TcxGridStructureHelper.Create(AStructureControl: TcxGridStructureControl); begin inherited Create; FStructureControl := AStructureControl; FStructureControl.OnMouseDown := StructureControlMouseDown; end; destructor TcxGridStructureHelper.Destroy; begin FViewMenuProvider.Free; FreeAndNil(FPopupMenu); inherited Destroy; end; function TcxGridStructureHelper.CanAddComponent: Boolean; begin Result := cxDesignWindows.CanAddComponent(StructureControl.Grid.Owner); end; function TcxGridStructureHelper.CanDeleteComponent(AComponent: TComponent): Boolean; var AOwner: TComponent; begin if AComponent = nil then AOwner := StructureControl.Grid.Owner else AOwner := AComponent.Owner; Result := cxDesignWindows.CanDeleteComponent(AOwner, AComponent); end; procedure TcxGridStructureHelper.ExecuteLevelViewsMenuItem(ALevel: TcxGridLevel; AMenuItem: TMenuItem); var ALevelViewList: TcxGridLevelViewList; AView: TcxCustomGridView; begin ALevelViewList := TcxGridLevelViewList.Create(ALevel); try AView := ALevelViewList.Views[AMenuItem.MenuIndex]; if ALevel.GridView <> AView then begin ALevel.GridView := AView; UpdateDesigner; end; finally ALevelViewList.Free; end; end; procedure TcxGridStructureHelper.FillLevelViewsMenu(AMenu: TMenuItem; ALevel: TcxGridLevel; AOnClick: TNotifyEvent); var ALevelViewList: TcxGridLevelViewList; I: Integer; begin ALevelViewList := TcxGridLevelViewList.Create(ALevel); try for I := 0 to ALevelViewList.ViewNames.Count - 1 do AMenu.Add(CreateMenuItem(AMenu.Owner, ALevelViewList.ViewNames[I], AOnClick)); if ALevel.GridView <> nil then AMenu[ALevelViewList.GetViewIndex(ALevel.GridView)].Checked := True; finally ALevelViewList.Free; end; AMenu.Add(CreateMenuItem(AMenu.Owner, '-')); AMenu.Add(CreateMenuItem(AMenu.Owner, 'None', AOnClick, True, -1, ALevel.GridView = nil)); end; procedure TcxGridStructureHelper.StructureControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); function IsViewEmpty(AView: TcxCustomGridView): Boolean; begin Result := AView.DataController.ItemCount = 0; end; procedure PrepareGridMenu; begin FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, 'Add Level', CreateLevelClick, CanAddComponent)); end; procedure PrepareLevelMenu; var AMenuItem: TMenuItem; begin AMenuItem := CreateMenuItem(FPopupMenu, 'Create View', nil, CanAddComponent); FPopupMenu.Items.Add(AMenuItem); FillRegisteredViewsMenu(AMenuItem, CreateViewClick); AMenuItem := CreateMenuItem(FPopupMenu, 'Select View'); FPopupMenu.Items.Add(AMenuItem); FillLevelViewsMenu(AMenuItem, FPopupMenuLevel, SelectViewClick); PrepareGridMenu; FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, '-')); FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, 'Delete Level', DeleteLevelClick, CanDeleteComponent(FPopupMenuLevel))); FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, '-')); FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, 'Move Level Up', MoveLevelClick, FPopupMenuLevel.Index > 0, -1)); FPopupMenu.Items.Add(CreateMenuItem(FPopupMenu, 'Move Level Down', MoveLevelClick, FPopupMenuLevel.Index < FPopupMenuLevel.Parent.Count - 1, 1)); end; function PrepareViewMenu(AView: TcxCustomGridView): TcxCustomGridViewMenuProvider; var I: Integer; AMenuItem: TMenuItem; begin FPopupMenuView := AView; Result := CreateViewMenuProvider(AView); if Result = nil then Exit; for I := 0 to Result.Items.Count - 1 do begin AMenuItem := CreateMenuItem(FPopupMenu, ''); Result.Items[I].Prepare(AMenuItem); FPopupMenu.Items.Add(AMenuItem); end; end; var AHitInfo: TcxGridStructureControlHitInfo; P: TPoint; begin if Button <> mbRight then Exit; P := Point(X, Y); AHitInfo := FStructureControl.GetHitInfo(P); if AHitInfo.HitTest <> htNowhere then begin if FPopupMenu = nil then FPopupMenu := TPopupMenu.Create(nil); while FPopupMenu.Items.Count > 0 do FPopupMenu.Items[0].Free; FPopupMenuLevel := FStructureControl.GetLevelByRowIndex(AHitInfo.RowIndex); if FPopupMenuLevel <> nil then begin if FPopupMenuLevel.IsRoot then PrepareGridMenu else if AHitInfo.HitTest = htLevel then PrepareLevelMenu else begin FViewMenuProvider.Free; FViewMenuProvider := PrepareViewMenu(FPopupMenuLevel.GridView); end; P := FStructureControl.ClientToScreen(P); FPopupMenu.Popup(P.X, P.Y); FStructureControl.CancelPressed(Point(-1, -1)); end; end; end; procedure TcxGridStructureHelper.UpdateDesigner; begin if Assigned(FOnUpdateDesigner) then FOnUpdateDesigner(Self); end; procedure TcxGridStructureHelper.CreateLevelClick(Sender: TObject); var ALevel: TcxGridLevel; begin StructureControl.BeginUpdate; try ALevel := FPopupMenuLevel.Add; ALevel.Name := GenLevelName(StructureControl.Grid, ALevel); StructureControl.SelectComponent(ALevel); UpdateDesigner; finally StructureControl.EndUpdate; end; end; procedure TcxGridStructureHelper.CreateViewClick(Sender: TObject); var AViewClass: TcxCustomGridViewClass; AView: TcxCustomGridView; begin AViewClass := TcxCustomGridViewClass( cxGridRegisteredViews[((Sender as TMenuItem).Tag)]); StructureControl.BeginUpdate; try AView := StructureControl.Grid.CreateView(AViewClass); AView.Name := GenViewName(StructureControl.Grid, AView); RestoreViewFromTemplate(GetViewTemplateRegKey, AView); FPopupMenuLevel.GridView := AView; StructureControl.SelectComponent(AView); UpdateDesigner; finally StructureControl.EndUpdate; end; end; procedure TcxGridStructureHelper.SelectViewClick(Sender: TObject); begin ExecuteLevelViewsMenuItem(FPopupMenuLevel, Sender as TMenuItem); end; procedure TcxGridStructureHelper.DeleteLevelClick(Sender: TObject); begin StructureControl.BeginUpdate; try StructureControl.SelectComponent(FPopupMenuLevel.GetParentComponent); FPopupMenuLevel.Free; UpdateDesigner; finally StructureControl.EndUpdate; end; end; procedure TcxGridStructureHelper.MoveLevelClick(Sender: TObject); var ASelection: TList; begin ASelection := TList.Create; try StructureControl.GetSelection(ASelection); FPopupMenuLevel.Index := FPopupMenuLevel.Index + Integer(TMenuItem(Sender).Tag); UpdateDesigner; StructureControl.SyncSelection(ASelection); finally ASelection.Free; end; end; { TcxGridStructureNavigator } constructor TcxGridStructureNavigator.Create(AGrid: TcxCustomGrid); begin inherited; FMakeSelectionVisible := True; FStructureControl := TcxGridStructureControl.Create(Self); with FStructureControl do begin SetBounds(0, 0, 0, 0); Grid := Self.Grid; {$IFDEF DELPHI6} MultiSelect := True; {$ENDIF} OnDrawBackground := DrawStructureControlBackground; OnSelectComponent := Self.SelectComponent; Parent := Self; end; FStructureHelper := TcxGridStructureHelper.Create(FStructureControl); FStructureHelper.OnUpdateDesigner := UpdateDesigner; FCloseButton := TSpeedButton.Create(Self); with FCloseButton do begin CreateCloseBitmap(Glyph); Flat := True; SetBounds(0, 0, 0, 0); OnClick := CloseButtonClick; Parent := Self; end; FCustomizeButton := TSpeedButton.Create(Self); with FCustomizeButton do begin Caption := SCustomizeText; Flat := True; SetBounds(0, 0, 0, 0); OnClick := CustomizeButtonClick; Parent := Self; end; FSeparator := TBevel.Create(Self); with FSeparator do begin Shape := bsTopLine; SetBounds(0, 0, 0, 0); Parent := Self; end; CreateDefaultComponents; FDesignHelper := TcxDesignHelper.Create(Grid); {$IFDEF DELPHI6} DesignNotificationHandler.RegisterGrid(Grid); {$ENDIF} end; destructor TcxGridStructureNavigator.Destroy; begin {$IFDEF DELPHI6} DesignNotificationHandler.UnregisterGrid(Grid); {$ENDIF} FreeAndNil(FDesignHelper); FreeAndNil(FStructureHelper); inherited Destroy; end; procedure TcxGridStructureNavigator.Paint; begin // Border Canvas.FrameRect(ClientRect, clWindowFrame, FrameBorderSize); // Background DrawBackground(Canvas); end; (* procedure TcxGridStructureNavigator.Calculate; var R: TRect; ACanvas: TcxCanvas; ACloseButtonSize: TSize; ACloseButtonArea: TRect; ACustomizeButtonArea: TRect; ASeparatorArea: TRect; ASeparatorHeight: Integer; begin FStructureControl.ViewInfo.Calculate; R := FStructureControl.ViewInfo.Bounds; OffsetRect(R, FrameBorderSize, FrameBorderSize); FStructureControl.BoundsRect := R; // Calc Customize Button ASeparatorHeight := ButtonOffset * 2; ACanvas := FStructureControl.ViewInfo.Canvas; ACanvas.Font := FCustomizeButton.Font; ACloseButtonSize.cx := 2 * TextOffset + ACanvas.TextWidth(SCustomizeText) + 2 * ButtonBorderSize; ACloseButtonSize.cy := 2 * TextOffset + ACanvas.TextHeight(SCustomizeText) + 2 * ButtonBorderSize; ACustomizeButtonArea := Rect(R.Left, R.Bottom + ASeparatorHeight, R.Left + 2 * ButtonOffset + ACloseButtonSize.cx, R.Bottom + ASeparatorHeight + 2 * ButtonOffset + ACloseButtonSize.cy); FCustomizeButton.SetBounds(ACustomizeButtonArea.Left + ButtonOffset, ACustomizeButtonArea.Top + ButtonOffset, ACloseButtonSize.cx, ACloseButtonSize.cy); ASeparatorArea := Rect(ACustomizeButtonArea.Left, ACustomizeButtonArea.Top - ASeparatorHeight, ACustomizeButtonArea.Right, ACustomizeButtonArea.Top); if R.Right < ACustomizeButtonArea.Right then R.Right := ACustomizeButtonArea.Right; FSeparator.BoundsRect := Rect(ASeparatorArea.Left + ButtonOffset, ASeparatorArea.Top + ButtonOffset, R.Right - ButtonOffset, ASeparatorArea.Bottom); // Calc Close Button ACloseButtonArea := Rect(R.Right, R.Top, R.Right + 2 * ButtonOffset + CloseButtonWidth + 2 * ButtonBorderSize, R.Top + 2 * ButtonOffset + CloseButtonHeight + 2 * ButtonBorderSize); FCloseButton.SetBounds(ACloseButtonArea.Left + ButtonOffset, ACloseButtonArea.Top + ButtonOffset, CloseButtonWidth + 2 * ButtonBorderSize, CloseButtonHeight + 2 * ButtonBorderSize); if R.Bottom < ACloseButtonArea.Bottom then R.Bottom := ACloseButtonArea.Bottom; // Total Area R.Right := ACloseButtonArea.Right; R.Bottom := ACustomizeButtonArea.Bottom; InflateRect(R, FrameBorderSize, FrameBorderSize); SetBounds(Left, Top, R.Right - R.Left, R.Bottom - R.Top); end; *) procedure TcxGridStructureNavigator.Calculate; var R: TRect; ACanvas: TcxCanvas; ACloseButtonSize: TSize; // ACloseButtonArea: TRect; ACustomizeButtonArea: TRect; ASeparatorArea: TRect; ASeparatorHeight: Integer; begin FStructureControl.ViewInfo.Calculate; R := FStructureControl.ViewInfo.Bounds; OffsetRect(R, FrameBorderSize, FrameBorderSize); FStructureControl.BoundsRect := R; // Calc Customize Button ASeparatorHeight := ButtonOffset * 2; ACanvas := FStructureControl.ViewInfo.Canvas; ACanvas.Font := FCustomizeButton.Font; ACloseButtonSize.cx := 2 * TextOffset + ACanvas.TextWidth(SCustomizeText) + 2 * ButtonBorderSize; ACloseButtonSize.cy := 2 * TextOffset + ACanvas.TextHeight(SCustomizeText) + 2 * ButtonBorderSize; ACustomizeButtonArea := Rect(R.Left, R.Bottom + ASeparatorHeight, R.Left + 2 * ButtonOffset + ACloseButtonSize.cx, R.Bottom + ASeparatorHeight + 2 * ButtonOffset + ACloseButtonSize.cy); FCustomizeButton.SetBounds(ACustomizeButtonArea.Left + ButtonOffset, ACustomizeButtonArea.Top + ButtonOffset, ACloseButtonSize.cx, ACloseButtonSize.cy); ASeparatorArea := Rect(ACustomizeButtonArea.Left, ACustomizeButtonArea.Top - ASeparatorHeight, ACustomizeButtonArea.Right, ACustomizeButtonArea.Top); if R.Right < ACustomizeButtonArea.Right then R.Right := ACustomizeButtonArea.Right; FSeparator.BoundsRect := Rect(ASeparatorArea.Left + ButtonOffset, ASeparatorArea.Top + ButtonOffset, R.Right - ButtonOffset, ASeparatorArea.Bottom); {// Calc Close Button ACloseButtonArea := Rect(R.Right, R.Top, R.Right + 2 * ButtonOffset + CloseButtonWidth + 2 * ButtonBorderSize, R.Top + 2 * ButtonOffset + CloseButtonHeight + 2 * ButtonBorderSize); FCloseButton.SetBounds(ACloseButtonArea.Left + ButtonOffset, ACloseButtonArea.Top + ButtonOffset, CloseButtonWidth + 2 * ButtonBorderSize, CloseButtonHeight + 2 * ButtonBorderSize); if R.Bottom < ACloseButtonArea.Bottom then R.Bottom := ACloseButtonArea.Bottom; // Total Area R.Right := ACloseButtonArea.Right; } R.Bottom := ACustomizeButtonArea.Bottom; InflateRect(R, FrameBorderSize, FrameBorderSize); SetBounds(Left, Top, R.Right - R.Left, R.Bottom - R.Top); end; function TcxGridStructureNavigator.CalculateBoundsRect: TRect; begin Result := Rect(0, 0, Width, Height); OffsetRect(Result, Grid.ClientBounds.Right - Result.Right - NavigatorOffset, Grid.ClientBounds.Bottom - Result.Bottom - NavigatorOffset); end; procedure TcxGridStructureNavigator.Changed; begin if FStructureControl = nil then Exit; Calculate; inherited Changed; FStructureControl.Invalidate; NotifyEditors; end; procedure TcxGridStructureNavigator.CreateDefaultComponents; var AViewClass: TcxCustomGridViewClass; begin if Grid.ViewCount <> 0 then Exit; AViewClass := GetDefaultViewClass; if AViewClass <> nil then begin FDefaultView := Grid.CreateView(AViewClass); FDefaultView.Name := GenViewName(Grid, FDefaultView); RestoreViewFromTemplate(GetViewTemplateRegKey, FDefaultView); // TODO: load default FDefaultLevel := Grid.Levels.Add; FDefaultLevel.Name := GenLevelName(Grid, FDefaultLevel); FDefaultLevel.GridView := FDefaultView; end; end; procedure TcxGridStructureNavigator.DrawBackground(ACanvas: TcxCanvas); begin FillTubeGradientRect(ACanvas.Handle, ClientBounds, clWhite, {16248293}16115935{15785423}, False); end; procedure TcxGridStructureNavigator.DrawStructureControlBackground(Sender: TObject); begin MoveWindowOrg(FStructureControl.Canvas.Handle, -FStructureControl.Left, -FStructureControl.Top); DrawBackground(FStructureControl.Canvas); MoveWindowOrg(FStructureControl.Canvas.Handle, FStructureControl.Left, FStructureControl.Top); end; function TcxGridStructureNavigator.GetClientBounds: TRect; begin Result := inherited GetClientBounds; InflateRect(Result, -FrameBorderSize, -FrameBorderSize); end; function TcxGridStructureNavigator.GetDefaultViewClass: TcxCustomGridViewClass; begin Result := TcxCustomGridAccess(Grid).GetDefaultViewClass; if Result = nil then Result := TcxGridDBTableView; end; function TcxGridStructureNavigator.GetDesigner: IDesigner; begin Result := GetObjectDesigner(Grid); end; procedure TcxGridStructureNavigator.NotifyEditors; var Msg: TMsg; begin if not HandleAllocated then Exit; if not PeekMessage(Msg, Handle, CM_DeferUpdate, CM_DeferUpdate, PM_NOREMOVE) then PostMessage(Handle, CM_DeferUpdate, 0, 0); end; procedure TcxGridStructureNavigator.CloseButtonClick(Sender: TObject); begin // TODO: // Visible := False; end; procedure TcxGridStructureNavigator.CustomizeButtonClick(Sender: TObject); begin // TODO: if GetDesigner <> nil then ShowGridEditor(GetDesigner, Grid); end; procedure TcxGridStructureNavigator.SelectComponent(AObject: TPersistent; AClearSelection: Boolean); begin if AClearSelection then FDesignHelper.SelectObject(AObject, True, False) else FDesignHelper.ChangeSelection(AObject); end; procedure TcxGridStructureNavigator.UpdateDesigner(Sender: TObject); begin if GetDesigner <> nil then GetDesigner.Modified; end; procedure TcxGridStructureNavigator.CMDeferUpdate(var Message: TMessage); begin UpdateDesignFormEditors(Grid); end; procedure TcxGridStructureNavigator.BeforeGridLoading; begin FreeAndNil(FDefaultLevel); FreeAndNil(FDefaultView); end; function TcxGridStructureNavigator.IsObjectSelected(AObject: TPersistent): Boolean; begin Result := FDesignHelper.IsObjectSelected(AObject); end; procedure TcxGridStructureNavigator.SelectionChanged(ASelection: TList); procedure MakeObjectVisible(AObject: TPersistent); begin //!!! columns/rows/bands/chartitems? if (AObject is TcxGridLevel) or (AObject is TcxCustomGridView) then begin if AObject is TcxCustomGridView then AObject := TcxCustomGridView(AObject).Level; if (AObject <> nil) and (TcxGridLevel(AObject).Control = Grid) then TcxGridLevel(AObject).MakeVisible; end; end; begin if MakeSelectionVisible and (ASelection.Count = 1) then MakeObjectVisible(ASelection[0]); FStructureControl.SyncSelection(ASelection); if Grid.HandleAllocated then RedrawWindow(Grid.Handle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN); end; procedure TcxGridStructureNavigator.SelectObject(AObject: TPersistent; AClearSelection: Boolean); begin MakeSelectionVisible := False; try SelectComponent(AObject, AClearSelection); finally MakeSelectionVisible := True; end; end; procedure TcxGridStructureNavigator.SelectObjects(AObjects: TList); begin MakeSelectionVisible := False; try FDesignHelper.SetSelection(AObjects); finally MakeSelectionVisible := True; end; end; procedure TcxGridStructureNavigator.UnselectObject(AObject: TPersistent); begin MakeSelectionVisible := False; try FDesignHelper.UnselectObject(AObject); finally MakeSelectionVisible := True; end; end; initialization cxGridStructureNavigatorClass := TcxGridStructureNavigator; {$IFDEF DELPHI6} DesignNotificationHandler := TDesignNotificationHandler.Create; {$ENDIF} finalization {$IFDEF DELPHI6} FreeAndNil(DesignNotificationHandler); {$ENDIF} end.