cxgridcustompopupmenu.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 777 行 · 第 1/2 页

PAS
777
字号
{********************************************************************}
{                                                                    }
{       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 cxGridCustomPopupMenu;

{$I cxVer.inc}

interface

uses
  Windows, Messages, Classes, SysUtils, Controls, cxGridCustomView, Menus;

const
  cxhtGridBase = 1000;

type
  EcxGridPopupMenu = class(Exception);

  TcxGridViewHitType = (gvhtGridNone, gvhtGridTab, gvhtNone, gvhtTab, gvhtCell,
    gvhtExpandButton, gvhtRecord, gvhtNavigator, gvhtPreview, gvhtColumnHeader,
    gvhtColumnHeaderFilterButton, gvhtFilter, gvhtFooter, gvhtFooterCell,
    gvhtGroupFooter, gvhtGroupFooterCell, gvhtGroupByBox, gvhtIndicator,
    gvhtRowIndicator, gvhtRowLevelIndent, gvhtBand, gvhtBandHeader,
    gvhtRowCaption, gvhtSeparator, gvhtGroupSummary);

  TcxGridViewHitTypes = set of TcxGridViewHitType;

  TcxGridBeforePopupProc = procedure(ASenderMenu: TComponent;
    AHitTest: TcxCustomGridHitTest; X,Y: Integer; var AllowPopup: Boolean) of object;

  TcxGridOnPopupProc = procedure(ASenderMenu: TComponent;
    AHitTest: TcxCustomGridHitTest; X,Y: Integer) of object;

  TcxGridPopupMenuItemClickProc = procedure(ASender: TObject;
    AHitTest: TcxCustomGridHitTest; var AHandler: TNotifyEvent;
    AParams: TList; var AHandled: Boolean) of object;

  IDoPopup = interface
    ['{41999EDE-B9D9-4808-9D01-61B09DF700FA}']
    function GetPopupHandler: TcxGridOnPopupProc;
  end;

  IcxGridPopupMenu = interface
    ['{302C3B32-D753-43A6-BAE2-F513EB4F9399}']
    function CanPopup(AHitTest: TcxCustomGridHitTest): Boolean;
  end;

  TcxPopupMenuInfo = Class(TCollectionItem)
  private
    FPopupMenu: TComponent;
    FPopupProc: TcxGridOnPopupProc;
    FHitTypes: TcxGridViewHitTypes;
    FLocked: Boolean;
    FView: TcxCustomGridView;
    FViewClass: TcxCustomGridViewClass;
    function FindCorrectComponent(const AComponent: TComponent): TComponent;
    procedure SetPopupMenu(const AValue: TComponent);
    procedure SetView(const AValue: TcxCustomGridView);
    procedure SetViewClass(const Value: TcxCustomGridViewClass);
  protected
    FIsBuiltIn: Boolean;
    procedure BeginUpdate; virtual;
    procedure EndUpdate; virtual;
    function CanPopup(AHitTest: TcxCustomGridHitTest): Boolean;
    procedure DoChanged(const APopupMenu: TComponent; const AView: TcxCustomGridView;
      AViewClass: TcxCustomGridViewClass); virtual;
    property GridViewClass: TcxCustomGridViewClass read FViewClass write SetViewClass;
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property IsBuiltIn: Boolean read FIsBuiltIn;
  published
    property GridView: TcxCustomGridView read FView write SetView;
    property HitTypes: TcxGridViewHitTypes read FHitTypes write FHitTypes;
    property Index;
    property OnPopup: TcxGridOnPopupProc read FPopupProc write FPopupProc;
    property PopupMenu: TComponent read FPopupMenu write SetPopupMenu;
  end;

  TcxPopupMenuInfos = class(TCollection)
  private
    FOwner: TComponent;
    function GetItem(AIndex: Integer): TcxPopupMenuInfo;
    procedure SetItem(AIndex: Integer; const AValue: TcxPopupMenuInfo);
  protected
    function  GetOwner: TPersistent; override;
    function IsMenuInfoShortCut(AMenuInfo: TcxPopupMenuInfo;
      var Message: TWMKey): Boolean; virtual;
    function IsShortCut(var Message: TWMKey): Boolean; virtual;
    {$IFDEF DELPHI6}
    procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); override;
    {$ENDIF}
  public
    constructor Create(AOwner: TComponent); virtual;
    function GetSameMenuCount(const AMenu: TComponent): Integer;
    property Items[AIndex: Integer]: TcxPopupMenuInfo read GetItem write SetItem; default;
  end;

  TcxCustomGridPopupMenu = class(TComponent)
  private
    FPopupMenuInfos: TcxPopupMenuInfos;
    function GetMenuInfo(AIndex: Integer): TcxPopupMenuInfo;
    function GetMenuInfoCount: Integer;
    procedure SetPopupMenuInfos(const AValue: TcxPopupMenuInfos);
  protected
    procedure AddMenuInfo(const AMenu: TComponent; AHitTypes: TcxGridViewHitTypes;
      ADoPopupProc: TcxGridOnPopupProc; AViewClass: TcxCustomGridViewClass = nil;
      const AView: TcxCustomGridView = nil; AIsBuiltIn: Boolean = False);
    procedure AdjustMenuInfo(AMenuInfo: TcxPopupMenuInfo;
      const AMenu: TComponent; AHitTypes: TcxGridViewHitTypes;
      ADoPopupProc: TcxGridOnPopupProc; AViewClass: TcxCustomGridViewClass = nil;
      const AView: TcxCustomGridView = nil; AIsBuiltIn: Boolean = False);
    procedure ClearMenuInfosGridView(const AView: TcxCustomGridView = nil);
    function GetPopupMenuInfo(const AMenu: TComponent; const AView: TcxCustomGridView;
                  ASearchDefault: Boolean = True): TcxPopupMenuInfo; overload; virtual;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    property PopupMenuInfos: TcxPopupMenuInfos read FPopupMenuInfos write SetPopupMenuInfos;
    property MenuInfos[AIndex: Integer]: TcxPopupMenuInfo read GetMenuInfo; default;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function CheckShortCuts(var Message: TWMKeyDown): Boolean; virtual;
    function FindPopupMenuInfo(const AView: TcxCustomGridView;
      AHitType: TcxGridViewHitType; AHitTest: TcxCustomGridHitTest): TcxPopupMenuInfo; virtual;
    function GetPopupMenuInfo(const AMenu: TComponent; AViewClass: TcxCustomGridViewClass;
          ASearchDefault: Boolean = True): TcxPopupMenuInfo; overload; virtual;
    property Count: Integer read GetMenuInfoCount;
  end;

  TcxGridDefaultPopupMenu = class(TcxCustomGridPopupMenu)
  protected
    function GetPopupMenuInfo(const AMenu: TComponent; const AView: TcxCustomGridView;
                  ASearchDefault: Boolean = True): TcxPopupMenuInfo; overload; override;
    procedure InternalRegisterPopupMenu(const AMenu: TComponent;
      AHitTypes: TcxGridViewHitTypes; ADoPopupProc: TcxGridOnPopupProc;
      AViewClass: TcxCustomGridViewClass; AIsBuiltIn: Boolean = False); virtual;
  public
    function GetPopupMenuInfo(const AMenu: TComponent; AViewClass: TcxCustomGridViewClass;
          ASearchDefault: Boolean = True): TcxPopupMenuInfo; overload; override;
    procedure RegisterPopupMenu(const AMenu: TComponent; AHitTypes: TcxGridViewHitTypes;
        ADoPopupProc: TcxGridOnPopupProc; AViewClass: TcxCustomGridViewClass); virtual;
    procedure UnRegisterPopupMenu(const AMenu: TComponent; AViewClass: TcxCustomGridViewClass;
              AHitTypes: TcxGridViewHitTypes = []); virtual;
    property MenuInfos;
  end;

  TcxPopupMenuClass = class of TComponent;

  TcxPopupMenuClassInfoRec = class
  public
    MenuClass: TcxPopupMenuClass;
    HitTypes: TcxGridViewHitTypes;
    ViewClass: TcxCustomGridViewClass;
    constructor Create(AMenuClass: TcxPopupMenuClass; AHitTypes: TcxGridViewHitTypes;
      AViewClass: TcxCustomGridViewClass);
  end;

  TcxBuiltInPopupMenus = class
  private
    FInfoRecs: TList;
    function GetCount: Integer;
    function GetItem(AIndex: Integer): TcxPopupMenuClassInfoRec;
  protected
    function Add(AMenuClass: TcxPopupMenuClass; AHitTypes: TcxGridViewHitTypes;
      AViewClass: TcxCustomGridViewClass): TcxPopupMenuClassInfoRec;
    procedure Clear;
    procedure Delete(AIndex: Integer);
    procedure RegisterItemTo(ADefaultPopupMenu: TcxGridDefaultPopupMenu;
      AItemIndex: Integer);
    procedure Remove(APopupMenuClass: TcxPopupMenuClass);

    property Count: Integer read GetCount;
    property Items[AIndex: Integer]: TcxPopupMenuClassInfoRec read GetItem; default;
  public
    constructor Create;
    destructor Destroy; override;
    procedure RegisterItemsTo(ADefaultPopupMenu: TcxGridDefaultPopupMenu);
  end;

  function GetHitTypeByHitCode(AHitCode: Integer): TcxGridViewHitType;

  procedure RegisterPopupMenuClass(APopupMenuClass: TcxPopupMenuClass;
    AHitTypes: TcxGridViewHitTypes; AViewClass: TcxCustomGridViewClass);
  procedure UnregisterPopupMenuClass(APopupMenuClass: TcxPopupMenuClass);

var
  BuiltInPopupMenuList: TcxBuiltInPopupMenus;

implementation

uses
  cxGridCustomTableView, cxGridTableView, Graphics, cxGridDetailsSite,
  cxGridRows, cxGridBandedTableView, cxGridCardView, cxControls;

function GetHitTypeByHitCode(AHitCode: Integer): TcxGridViewHitType;
const
  cxGridViewHitCodes: array[TcxGridViewHitType] of Integer = (htNone + cxhtGridBase,
    htTab + cxhtGridBase, htNone, htTab, htCell, htExpandButton, htRecord, htNavigator,
    htPreview, htColumnHeader, htColumnHeaderFilterButton, htFilter, htFooter, htFooterCell,
    htGroupFooter, htGroupFooterCell, htGroupByBox, htIndicator, htRowIndicator,
    htRowLevelIndent, htBand, htBandHeader, htRowCaption, htSeparator, htGroupSummary);
begin
  for Result := Low(Result) to High(Result) do
    if cxGridViewHitCodes[Result] = AHitCode then
      Exit;
  Result := TcxGridViewHitType(-1);
end;

{ TcxPopupMenuInfo }

procedure TcxPopupMenuInfo.BeginUpdate;
begin
  FLocked := True;
end;

procedure TcxPopupMenuInfo.EndUpdate;
begin
  FLocked := False;
end;

function TcxPopupMenuInfo.CanPopup(AHitTest: TcxCustomGridHitTest): Boolean;
var
  APopupMenuIntf: IcxGridPopupMenu;
begin
  if (PopupMenu <> nil) and Supports(PopupMenu, IcxGridPopupMenu, APopupMenuIntf) then
    Result := APopupMenuIntf.CanPopup(AHitTest)
  else
    Result := True;
end;

procedure TcxPopupMenuInfo.DoChanged(const APopupMenu: TComponent;
  const AView: TcxCustomGridView; AViewClass: TcxCustomGridViewClass);
var
  AMenuInfo: TcxPopupMenuInfo;
  MenuInfos: TcxPopupMenuInfos;
begin
  AMenuInfo := nil;
  if FLocked then exit;
  MenuInfos := TcxPopupMenuInfos(Collection);
  if Assigned(AView) then
    AMenuInfo :=
        TcxCustomGridPopupMenu(MenuInfos.GetOwner).GetPopupMenuInfo(APopupMenu, AView)
  else
  begin
    if Assigned(AViewClass) and (MenuInfos.GetOwner is TcxGridDefaultPopupMenu) then
    AMenuInfo :=
        TcxGridDefaultPopupMenu(MenuInfos.GetOwner).GetPopupMenuInfo(APopupMenu, AViewClass);
  end;
  if (AMenuInfo <> nil) and (MenuInfos.GetOwner <> nil) and
    not (csLoading in (MenuInfos.GetOwner as TComponent).ComponentState) then
    Raise EcxGridPopupMenu.Create(
      Format('This PopupMenuInfo is already registered. Index: %d',[AMenuInfo.Index]));
end;

function TcxPopupMenuInfo.FindCorrectComponent(const AComponent: TComponent): TComponent;
var
  AOwner: TComponent;
begin
  Result := AComponent;
  if not Assigned(AComponent) then
    Exit;
  AOwner := TComponent(TcxPopupMenuInfos(Collection).GetOwner);
  while AOwner.InheritsFrom(TcxCustomGridPopupMenu) do
    AOwner := TcxCustomGridPopupMenu(AOwner).Owner;
  with AOwner do
    if (csUpdating in ComponentState) then
    begin
      Result := FindComponent(AComponent.Name);
      if not Assigned(Result) or (Result.ClassType <> AComponent.ClassType) then
        Result := AComponent;
    end;
end;

procedure TcxPopupMenuInfo.SetPopupMenu(const AValue: TComponent);
begin
  if FPopupMenu <> AValue then
  begin
    if (TcxPopupMenuInfos(Collection).GetSameMenuCount(FPopupMenu) = 1) and
      (FPopupMenu <> nil) and not (csDestroying in FPopupMenu.ComponentState) then
      FPopupMenu.RemoveFreeNotification(TComponent(TcxPopupMenuInfos(Collection).GetOwner));
    DoChanged(AValue, FView, FViewClass);
    if FIsBuiltIn then
    begin
      FIsBuiltIn := False;
      FreeAndNil(FPopupMenu);
    end;
    FPopupMenu := AValue;
    if FPopupMenu <> nil then
      FPopupMenu.FreeNotification(TComponent(TcxPopupMenuInfos(Collection).GetOwner));
  end;
end;

procedure TcxPopupMenuInfo.SetView(const AValue: TcxCustomGridView);
begin
  if FView <> AValue then
  begin
    if Assigned(FView) and not (csDestroying in FView.ComponentState) then
      FView.RemoveFreeNotification(TComponent(TcxPopupMenuInfos(Collection).GetOwner));
    DoChanged(FPopupMenu, AValue, FViewClass);
    FView := AValue;
    if Assigned(FView) then
      FView.FreeNotification(TComponent(TcxPopupMenuInfos(Collection).GetOwner));
  end;
end;

procedure TcxPopupMenuInfo.SetViewClass(
  const Value: TcxCustomGridViewClass);
begin
  DoChanged(FPopupMenu, FView, Value);
  FViewClass := Value;
end;

destructor TcxPopupMenuInfo.Destroy;
begin
  if FIsBuiltIn then
    FreeAndNil(FPopupMenu);
  inherited Destroy;
end;

procedure TcxPopupMenuInfo.Assign(Source: TPersistent);
var
  AMenuInfo: TcxPopupMenuInfo;
begin
  if Source is TcxPopupMenuInfo then
  begin
    if Collection <> nil then
      Collection.BeginUpdate;
    try
      BeginUpdate;
      try
        AMenuInfo := TcxPopupMenuInfo(Source);
        Index := AMenuInfo.Index;
        PopupMenu := FindCorrectComponent(AMenuInfo.PopupMenu);
        OnPopup := AMenuInfo.OnPopup;
        HitTypes := AMenuInfo.HitTypes;
        GridView := TcxCustomGridView(FindCorrectComponent(AMenuInfo.GridView));
        GridViewClass := AMenuInfo.GridViewClass;
      finally
        EndUpdate;
      end;
    finally
      if Collection <> nil then
        Collection.EndUpdate;
    end;
  end
  else
    inherited;
end;

{ TcxCustomGridPopupMenu }

constructor TcxCustomGridPopupMenu.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FPopupMenuInfos := TcxPopupMenuInfos.Create(Self);
end;

destructor TcxCustomGridPopupMenu.Destroy;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?