Componentes.Terceros.DevExp.../internal/x.36/1/ExpressQuantumGrid 6/Sources/cxGridPopupMenu.pas
2008-09-04 11:31:51 +00:00

482 lines
18 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressQuantumGrid Utils }
{ }
{ Copyright (c) 1998-2008 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 cxGridPopupMenu;
{$I cxVer.inc}
interface
uses
Windows, Messages,
{$IFDEF DELPHI6}
Types,
{$ENDIF}
SysUtils, Classes, Controls, cxGrid, cxGridCustomView,
cxGridUIHelper, cxGridUICustomTableHelper, cxGridUITableHelper,
cxGridUIBandedTableHelper, cxGridUICardHelper, cxGridCustomPopupMenu;
type
TcxGridPopupMenu = class(TcxCustomGridPopupMenu)
private
FAlwaysFireOnPopup: Boolean;
FGrid: TcxGrid;
FGridDefaultPopupMenu: TcxGridDefaultPopupMenu;
FGridOperationHelper: TcxGridOperationHelper;
FHitGridView: TcxCustomGridView;
FHitPoint: TPoint;
FHitTest: TcxCustomGridHitTest;
FHitType: TcxGridViewHitType;
FMouseupNotification: TcxCustomGridNotification;
FOnClick: TcxGridPopupMenuItemClickProc;
FOnPopup: TcxGridBeforePopupProc;
FUseBuiltInPopupMenus: Boolean;
procedure CreateBuiltInPopupMenus;
procedure FreeBuiltInPopupMenus;
function GetPopupMenus: TcxPopupMenuInfos;
procedure SetUseBuiltInPopupMenus(const Value: Boolean);
procedure SetGrid(const AValue: TcxGrid);
procedure SetPopupMenus(const AValue: TcxPopupMenuInfos);
function TryPopupAsIcxPopupMenuIntf(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
function TryPopupAsIDoPopupIntf(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
function TryPopupAsVCLPopupMenu(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
protected
function DoOnPopup(ASenderMenu: TComponent;
AHitTest: TcxCustomGridHitTest; X,Y: Integer): Boolean; virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function DoPopup(AAPPSKeyPressed: Boolean): Boolean; virtual;
function GetPopupMenuInfo(const AMenu: TComponent; const AView: TcxCustomGridView;
SearchDefault: Boolean = True): TcxPopupMenuInfo; override;
property GridOperationHelper: TcxGridOperationHelper read FGridOperationHelper;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function CheckShortCuts(var Message: TWMKeyDown): Boolean; override;
function FindPopupMenuInfo(const AView: TcxCustomGridView;
AHitType: TcxGridViewHitType; AHitTest: TcxCustomGridHitTest): TcxPopupMenuInfo; override;
function GetBuiltInPopupMenuByClass(const AMenuClass: TcxPopupMenuClass): TComponent;
procedure RegisterPopupMenu(const AMenu: TComponent; AHitTypes: TcxGridViewHitTypes;
ADoPopupProc: TcxGridOnPopupProc; const AView: TcxCustomGridView); overload; virtual;
procedure RegisterPopupMenu(const AMenu: TComponent; AHitTypes: TcxGridViewHitTypes;
ADoPopupProc: TcxGridOnPopupProc; AViewClass: TcxCustomGridViewClass); overload; virtual;
procedure UnregisterPopupMenu(const AMenu: TComponent; const AGridView: TcxCustomGridView;
AHitTypes: TcxGridViewHitTypes = []); overload; virtual;
procedure UnregisterPopupMenu(const AMenu: TComponent; AGridViewClass: TcxCustomGridViewClass;
AHitTypes: TcxGridViewHitTypes = []); overload; virtual;
property BuiltInPopupMenus: TcxGridDefaultPopupMenu read FGridDefaultPopupMenu;
property HitGridView: TcxCustomGridView read FHitGridView;
property HitPoint: TPoint read FHitPoint;
property HitTest: TcxCustomGridHitTest read FHitTest;
property HitType: TcxGridViewHitType read FHitType;
published
property Grid: TcxGrid read FGrid write SetGrid;
property PopupMenus: TcxPopupMenuInfos read GetPopupMenus write SetPopupMenus;
property UseBuiltInPopupMenus: Boolean read FUseBuiltInPopupMenus write
SetUseBuiltInPopupMenus default True;
property OnMenuItemClick: TcxGridPopupMenuItemClickProc read FOnClick write FOnClick;
property OnPopup: TcxGridBeforePopupProc read FOnPopup write FOnPopup;
property AlwaysFireOnPopup: Boolean read FAlwaysFireOnPopup write FAlwaysFireOnPopup default False;
end;
var
ActiveGridPopupMenu: TcxGridPopupMenu;
implementation
uses
Forms, cxGridLevel, Dialogs, cxGridStdPopupMenu, Menus, cxGridCustomTableView, cxControls;
type
TcxGridContextPopupNotification = class(TcxCustomGridNotification)
private
FGridPopupMenu: TcxGridPopupMenu;
protected
procedure Notify(AKind: TcxGridNotificationKind; AData: TObject; var AHandled: Boolean); override;
function NotificationKinds: TcxGridNotificationKinds; override;
end;
PWMKeyDown = ^TWMKeyDown;
TcxCustomGridCellViewInfoAccess = class(TcxCustomGridCellViewInfo);
TcxCustomGridViewInfoAccess = class(TcxCustomGridViewInfo);
procedure TcxGridContextPopupNotification.Notify(AKind: TcxGridNotificationKind;
AData: TObject; var AHandled: Boolean);
begin
case (AKind) of
gnkContextMenu:
begin
Application.ProcessMessages;
AHandled := FGridPopupMenu.DoPopup(Boolean(AData));
end;
gnkKeyDown:
begin
FGridPopupMenu.CheckShortCuts(PWMKeyDown(AData)^);
end;
end;
end;
function TcxGridContextPopupNotification.NotificationKinds: TcxGridNotificationKinds;
begin
Result := [gnkContextMenu, gnkKeyDown];
end;
{TcxGridPopupMenu}
constructor TcxGridPopupMenu.Create (AOwner: TComponent);
begin
inherited Create(AOwner);
FAlwaysFireOnPopup := False;
FGridDefaultPopupMenu := TcxGridDefaultPopupMenu.Create(Self);
FUseBuiltInPopupMenus := True;
CreateBuiltInPopupMenus;
FGridOperationHelper := TcxGridOperationHelper.Create(Self);
FMouseupNotification := TcxGridContextPopupNotification.Create;
TcxGridContextPopupNotification(FMouseupNotification).FGridPopupMenu := self;
end;
destructor TcxGridPopupMenu.Destroy;
begin
FreeBuiltInPopupMenus;
FreeAndNil(FGridOperationHelper);
FreeAndNil(FGridDefaultPopupMenu);
if Grid <> nil then
Grid.UnregisterNotification(FMouseupNotification);
FreeAndNil(FMouseupNotification);
inherited Destroy;
end;
function TcxGridPopupMenu.CheckShortCuts(var Message: TWMKeyDown): Boolean;
begin
Result := inherited CheckShortCuts(Message);
if not Result then
Result := FGridDefaultPopupMenu.CheckShortCuts(Message);
end;
function TcxGridPopupMenu.GetBuiltInPopupMenuByClass(
const AMenuClass: TcxPopupMenuClass): TComponent;
var
I: Integer;
begin
Result := nil;
for I := 0 to FGridDefaultPopupMenu.Count - 1 do
if Assigned(FGridDefaultPopupMenu[i].PopupMenu) and
(FGridDefaultPopupMenu[i].PopupMenu.ClassType = AMenuClass) then
begin
Result := FGridDefaultPopupMenu[i].PopupMenu;
break;
end;
end;
function TcxGridPopupMenu.FindPopupMenuInfo(const AView: TcxCustomGridView;
AHitType: TcxGridViewHitType; AHitTest: TcxCustomGridHitTest): TcxPopupMenuInfo;
begin
Result := inherited FindPopupMenuInfo(AView, AHitType, AHitTest);
if Result = nil then
Result := FGridDefaultPopupMenu.FindPopupMenuInfo(AView, AHitType, AHitTest);
end;
function TcxGridPopupMenu.GetPopupMenuInfo(const AMenu: TComponent;
const AView: TcxCustomGridView; SearchDefault: Boolean = True): TcxPopupMenuInfo;
var
I : Integer;
begin
Result := nil;
for I := 0 to Count - 1 do
If (AMenu = MenuInfos[I].PopupMenu) and (AView = MenuInfos[I].GridView) then
begin
Result := MenuInfos[I];
Result.Index := I;
break;
end;
if SearchDefault and not Assigned(Result) then
Result := FGridDefaultPopupMenu.GetPopupMenuInfo(AMenu,
TcxCustomGridViewClass(AView.ClassType));
end;
procedure TcxGridPopupMenu.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = Grid) then
FGrid := nil;
end;
procedure TcxGridPopupMenu.RegisterPopupMenu(const AMenu: TComponent;
AHitTypes: TcxGridViewHitTypes; ADoPopupProc: TcxGridOnPopupProc;
const AView: TcxCustomGridView);
begin
if not Assigned(AView) then exit;
AdjustMenuInfo(GetPopupMenuInfo(AMenu, AView), AMenu, AHitTypes, ADoPopupProc,
nil, AView);
end;
procedure TcxGridPopupMenu.RegisterPopupMenu(const AMenu: TComponent;
AHitTypes: TcxGridViewHitTypes; ADoPopupProc: TcxGridOnPopupProc;
AViewClass: TcxCustomGridViewClass);
begin
FGridDefaultPopupMenu.RegisterPopupMenu(AMenu, AHitTypes, ADoPopupProc, AViewClass);
end;
procedure TcxGridPopupMenu.UnregisterPopupMenu(const AMenu: TComponent;
const AGridView: TcxCustomGridView; AHitTypes: TcxGridViewHitTypes);
var
AMenuInfo: TcxPopupMenuInfo;
begin
AMenuInfo := GetPopupMenuInfo(AMenu, AGridView, false);
If (AMenuInfo <> nil) then
If AMenuInfo.HitTypes = AHitTypes then
AMenuInfo.Free
else
AMenuInfo.HitTypes := AMenuInfo.HitTypes - AHitTypes;
end;
procedure TcxGridPopupMenu.UnregisterPopupMenu(const AMenu: TComponent;
AGridViewClass: TcxCustomGridViewClass; AHitTypes: TcxGridViewHitTypes = []);
begin
FGridDefaultPopupMenu.UnRegisterPopupMenu(AMenu, AGridViewClass, AHitTypes);
end;
function TcxGridPopupMenu.DoOnPopup(ASenderMenu: TComponent;
AHitTest: TcxCustomGridHitTest; X,
Y: Integer): Boolean;
begin
Result := True;
if Assigned(FOnPopup) then
FOnPopup(ASenderMenu, AHitTest, X, Y, Result);
end;
function TcxGridPopupMenu.DoPopup(AAPPSKeyPressed: Boolean): Boolean;
function DoAutoPopup(AMenuInfo:TcxPopupMenuInfo; AHitTest: TcxCustomGridHitTest;
APoint: TPoint): Boolean;
begin
Result := Assigned(AMenuInfo.PopupMenu);
if Result then
Result := TryPopupAsIDoPopupIntf(AMenuInfo.PopupMenu, AHitTest, APoint) or
TryPopupAsIcxPopupMenuIntf(AMenuInfo.PopupMenu, AHitTest, APoint) or
TryPopupAsVCLPopupMenu(AMenuInfo.PopupMenu, AHitTest, APoint);
end;
function DoPopupByAPPSKey(var AHitCode: Integer; var APoint: TPoint): Boolean;
var
AViewInfo: TcxCustomGridCellViewInfo;
ABounds: TRect;
begin
Result := FHitGridView is TcxCustomGridTableView;
if not Result then Exit;
with TcxCustomGridTableView(FHitGridView).Controller do
begin
if (FocusedRecord <> nil) then
begin
if not FocusedRecord.Visible then
MakeFocusedRecordVisible;
if (FocusedItem <> nil) and (FocusedItem.FocusedCellViewInfo <> nil) then
begin
ABounds := FocusedItem.FocusedCellViewInfo.ContentBounds;
AViewInfo := FocusedItem.FocusedCellViewInfo;
end
else
begin
ABounds := FocusedRecord.ViewInfo.ContentBounds;
if ABounds.Left < 0 then
ABounds.Left := 0;
AViewInfo := FocusedRecord.ViewInfo;
end;
with ABounds do
APoint := Point(Left, Bottom);
FHitTest := TcxCustomGridCellViewInfoAccess(AViewInfo).GetHitTestClass.Instance(APoint);
TcxCustomGridCellViewInfoAccess(AViewInfo).InitHitTest(FHitTest);
end
else
begin
APoint := Point(0,0);
FHitTest := TcxGridViewNoneHitTest.Instance(APoint);
TcxCustomGridViewInfoAccess(FHitGridView.Site.ViewInfo).InitHitTest(FHitTest);
end;
AHitCode := FHitTest.HitTestCode;
FHitPoint := APoint;
APoint := FHitGridView.Site.ClientToScreen(APoint);
end;
end;
function InternalPopup(AHitType: TcxGridViewHitType; APoint: TPoint;
AHitTest: TcxCustomGridHitTest): Boolean;
var
AMenuInfo: TcxPopupMenuInfo;
begin
Result := False;
if FHitGridView = nil then Exit;
AMenuInfo := FindPopupMenuInfo(FHitGridView.PatternGridView, AHitType, AHitTest);
if AMenuInfo = nil then
Exit;
if Assigned(AMenuInfo.OnPopup) then
begin
if Assigned(AMenuInfo.PopupMenu) or FAlwaysFireOnPopup then
begin
if DoOnPopup(AMenuInfo.PopupMenu, AHitTest, APoint.X, APoint.Y) then
AMenuInfo.OnPopup(AMenuInfo.PopupMenu, AHitTest, APoint.X, APoint.Y);
Result := True;
end;
end
else
Result := DoAutoPopup(AMenuInfo, AHitTest, APoint);
end;
var
AHitCode: Integer;
APoint: TPoint;
begin
Result := True;
FHitGridView := Grid.FocusedView;
ActiveGridPopupMenu := Self;
AHitCode := 0;
if AAPPSKeyPressed then
Result := DoPopupByAPPSKey(AHitCode, APoint)
else
begin
GetCursorPos(APoint);
FHitPoint := Grid.ScreenToClient(APoint);
FHitTest := Grid.ViewInfo.GetHitTest(FHitPoint.X, FHitPoint.Y);
AHitCode := FHitTest.HitTestCode;
if (FHitGridView = nil) or
not PtInRect(FHitGridView.Site.ClientRect, FHitGridView.Site.ScreenToClient(APoint)) then
AHitCode := AHitCode + cxhtGridBase;
end;
if Result then
begin
FHitType := GetHitTypeByHitCode(AHitCode);
Result := InternalPopup(FHitType, APoint, FHitTest);
end;
end;
procedure TcxGridPopupMenu.CreateBuiltInPopupMenus;
begin
BuiltInPopupMenuList.RegisterItemsTo(FGridDefaultPopupMenu);
end;
procedure TcxGridPopupMenu.FreeBuiltInPopupMenus;
var
I: Integer;
begin
for I := FGridDefaultPopupMenu.Count - 1 downto 0 do
if FGridDefaultPopupMenu[I].IsBuiltIn then
FGridDefaultPopupMenu[I].Free;
end;
function TcxGridPopupMenu.GetPopupMenus: TcxPopupMenuInfos;
begin
Result := PopupMenuInfos;
end;
procedure TcxGridPopupMenu.SetUseBuiltInPopupMenus(const Value: Boolean);
begin
if FUseBuiltInPopupMenus <> Value then
if Value then
CreateBuiltInPopupMenus
else
FreeBuiltInPopupMenus;
FUseBuiltInPopupMenus := Value;
end;
procedure TcxGridPopupMenu.SetGrid(const AValue: TcxGrid);
begin
if FGrid <> AValue then
begin
FGridOperationHelper.Grid := AValue;
if (FGrid <> nil) and not (csDestroying in FGrid.ComponentState) then
begin
FGrid.UnregisterNotification(FMouseupNotification);
FGrid.RemoveFreeNotification(self);
ClearMenuInfosGridView;
end;
FGrid := AValue;
if FGrid <> nil then
begin
FGrid.FreeNotification(self);
FGrid.RegisterNotification(FMouseupNotification);
end;
end;
end;
procedure TcxGridPopupMenu.SetPopupMenus(const AValue: TcxPopupMenuInfos);
begin
PopupMenuInfos.Assign(AValue);
end;
function TcxGridPopupMenu.TryPopupAsIcxPopupMenuIntf(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
var
AIcxPopupMenuIntf: IcxPopupMenu;
begin
Result := False;
if APopupMenu = nil then
Exit;
Result := Supports(APopupMenu, IcxPopupMenu, AIcxPopupMenuIntf);
if Result and DoOnPopup(APopupMenu, AHitTest, APoint.X, APoint.Y) then
AIcxPopupMenuIntf.Popup(APoint.X, APoint.Y);
end;
function TcxGridPopupMenu.TryPopupAsIDoPopupIntf(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
var
AIDoPopupIntf: IDoPopup;
begin
Result := False;
if APopupMenu = nil then
Exit;
Result := Supports(APopupMenu, IDoPopup, AIDoPopupIntf);
if Result and DoOnPopup(APopupMenu, AHitTest, APoint.X, APoint.Y) then
TcxGridOnPopupProc(AIDoPopupIntf.GetPopupHandler)(
APopupMenu, AHitTest, APoint.X, APoint.Y);
end;
function TcxGridPopupMenu.TryPopupAsVCLPopupMenu(APopupMenu: TComponent;
AHitTest: TcxCustomGridHitTest; APoint: TPoint): Boolean;
begin
Result := False;
if APopupMenu = nil then
Exit;
Result :=
(APopupMenu is TPopupMenu) or (APopupMenu.InheritsFrom(TPopupMenu));
if Result and DoOnPopup(APopupMenu, AHitTest, APoint.X, APoint.Y) then
begin
TPopupMenu(APopupMenu).PopupComponent := FHitGridView;
TPopupMenu(APopupMenu).Popup(APoint.X, APoint.Y);
end;
end;
end.