mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 20:13:50 +02:00
402 lines
11 KiB
ObjectPascal
402 lines
11 KiB
ObjectPascal
unit BreakpointGroupFrame;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Math, Forms, Controls, ComCtrls, StdCtrls, ExtCtrls,
|
|
LCLType, Buttons, Graphics, Dialogs, laz.VirtualTrees, IDEImagesIntf,
|
|
DebuggerTreeView, Debugger, IdeDebuggerStringConstants, BaseDebugManager,
|
|
DebuggerDlg;
|
|
|
|
type
|
|
|
|
TBreakpointGroupFrame = class;
|
|
|
|
TBreakPointsDlgBase = class(TDebuggerDlg)
|
|
protected
|
|
FDraggingGroupHeader: Boolean;
|
|
procedure AcceptGroupHeaderDrop(ADroppedGroupFrame: TBreakpointGroupFrame; ATargetNode: PVirtualNode); virtual; abstract;
|
|
end;
|
|
|
|
TOnDeleteGroup = procedure(Sender: TBreakpointGroupFrame; BrkGroup: TIDEBreakPointGroup) of object;
|
|
|
|
TBreakpointGroupFrameKind = (bgfUngrouped, bgfGroup, bgfAddNewGroup, bgfAbandoned);
|
|
|
|
{ TBreakpointGroupFrame }
|
|
|
|
TBreakpointGroupFrame = class(TFrame)
|
|
BtnDelete: TSpeedButton;
|
|
Panel1: TPanel;
|
|
StaticText1: TStaticText;
|
|
StaticText2: TStaticText;
|
|
ToolBar1: TToolBar;
|
|
ToolButtonEnableAll: TToolButton;
|
|
ToolButtonDisableAll: TToolButton;
|
|
ToolButtonDivider1: TToolButton;
|
|
procedure BtnDeleteClick(Sender: TObject);
|
|
procedure FrameDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure FrameDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
procedure StaticText1MouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure ToolBar1EndDrag(Sender, Target: TObject; X, Y: Integer);
|
|
procedure ToolBar1StartDrag(Sender: TObject; var DragObject: TDragObject);
|
|
procedure ToolButtonDisableAllClick(Sender: TObject);
|
|
procedure ToolButtonEnableAllClick(Sender: TObject);
|
|
private
|
|
FGroupKind: TBreakpointGroupFrameKind;
|
|
FOnDeleteGroup: TOnDeleteGroup;
|
|
FOwner: TBreakPointsDlgBase;
|
|
FTree: TDbgTreeView;
|
|
FNode: PVirtualNode;
|
|
FBrkGroup: TIDEBreakPointGroup;
|
|
procedure DoBrkGroupFreed(Sender: TObject);
|
|
function GetCount: Integer;
|
|
function GetName: String;
|
|
function GetVisible: boolean;
|
|
protected
|
|
procedure SetVisible(Value: Boolean); reintroduce;
|
|
procedure VisibleChanged; override;
|
|
procedure CreateWnd; override;
|
|
public
|
|
constructor Create(TheOwner: TBreakPointsDlgBase; ATree: TDbgTreeView; ANode: PVirtualNode;
|
|
ABrkGroup: TIDEBreakPointGroup;
|
|
AGroupKind: TBreakpointGroupFrameKind = bgfGroup); reintroduce;
|
|
destructor Destroy; override;
|
|
procedure UpdateDisplay;
|
|
procedure UpdateButtons;
|
|
function Compare(AnOther: TBreakpointGroupFrame): integer;
|
|
|
|
property Visible: boolean read GetVisible write SetVisible;
|
|
property GroupKind: TBreakpointGroupFrameKind read FGroupKind;
|
|
property BrkGroup: TIDEBreakPointGroup read FBrkGroup;
|
|
property Tree: TDbgTreeView read FTree;
|
|
property Node: PVirtualNode read FNode;
|
|
property Name: String read GetName;
|
|
property Count: Integer read GetCount;
|
|
property OnDeleteGroup: TOnDeleteGroup read FOnDeleteGroup write FOnDeleteGroup;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
{ TBreakpointGroupFrame }
|
|
|
|
procedure TBreakpointGroupFrame.StaticText1MouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if ToolBar1.DragMode = dmAutomatic then
|
|
ToolBar1.BeginDrag(DragManager.DragImmediate, DragManager.DragThreshold);
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.ToolBar1EndDrag(Sender, Target: TObject; X,
|
|
Y: Integer);
|
|
begin
|
|
FOwner.FDraggingGroupHeader := False;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.ToolBar1StartDrag(Sender: TObject;
|
|
var DragObject: TDragObject);
|
|
begin
|
|
FOwner.FDraggingGroupHeader := True;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.ToolButtonDisableAllClick(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FOwner.BeginUpdate;
|
|
try
|
|
for i := 0 to DebugBoss.BreakPoints.Count - 1 do
|
|
if DebugBoss.BreakPoints[i].Group = BrkGroup then
|
|
DebugBoss.BreakPoints[i].Enabled := False;
|
|
finally
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.ToolButtonEnableAllClick(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FOwner.BeginUpdate;
|
|
try
|
|
for i := 0 to DebugBoss.BreakPoints.Count - 1 do
|
|
if DebugBoss.BreakPoints[i].Group = BrkGroup then
|
|
DebugBoss.BreakPoints[i].Enabled := True;
|
|
finally
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.BtnDeleteClick(Sender: TObject);
|
|
begin
|
|
if assigned(FOnDeleteGroup) then
|
|
FOnDeleteGroup(Self, FBrkGroup);
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.FrameDragDrop(Sender, Source: TObject; X,
|
|
Y: Integer);
|
|
var
|
|
NewGroup: TIDEBreakPointGroup;
|
|
VNode: PVirtualNode;
|
|
Brk: TIDEBreakPoint;
|
|
GroupName: String;
|
|
begin
|
|
NewGroup := FBrkGroup;
|
|
|
|
FOwner.BeginUpdate;
|
|
try
|
|
if FGroupKind = bgfAddNewGroup then begin
|
|
GroupName := '';
|
|
repeat
|
|
repeat
|
|
if not InputQuery(Caption, lisGroupNameInput, GroupName) then
|
|
exit;
|
|
|
|
if (GroupName = '') or (not TIDEBreakPointGroup.CheckName(GroupName)) then begin
|
|
if MessageDlg(Caption, lisGroupNameInvalid, mtError, [mbCancel, mbRetry], 0) <> mrRetry then
|
|
exit;
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
NewGroup := DebugBoss.BreakPointGroups.GetGroupByName(GroupName);
|
|
if NewGroup = nil then begin
|
|
NewGroup := TIDEBreakPointGroup(DebugBoss.BreakPointGroups.Add);
|
|
NewGroup.Name := GroupName;
|
|
break
|
|
end
|
|
else begin
|
|
case MessageDlg(Caption, Format(lisGroupAssignExisting,
|
|
[GroupName]), mtConfirmation, [mbYes, mbCancel, mbRetry], 0)
|
|
of
|
|
mrYes, mrOK: Break;
|
|
mrNo, mrCancel: exit;
|
|
mrRetry: ;
|
|
end;
|
|
end;
|
|
until false;
|
|
end;
|
|
|
|
if (Source = FTree) and (FTree.SelectedCount > 0) then begin
|
|
for VNode in FTree.SelectedNodes(True) do begin
|
|
Brk := TIDEBreakPoint(FTree.NodeItem[VNode]);
|
|
Brk.Group := NewGroup;
|
|
end;
|
|
end;
|
|
|
|
if (Source is TToolBar) and (TToolBar(Source).Owner is TBreakpointGroupFrame) then begin
|
|
FOwner.AcceptGroupHeaderDrop(TBreakpointGroupFrame(TToolBar(Source).Owner), FNode);
|
|
end;
|
|
|
|
finally
|
|
if FGroupKind = bgfAddNewGroup then
|
|
Visible := False;
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.FrameDragOver(Sender, Source: TObject; X,
|
|
Y: Integer; State: TDragState; var Accept: Boolean);
|
|
var
|
|
VNode: PVirtualNode;
|
|
Brk: TIDEBreakPoint;
|
|
begin
|
|
Accept := False;
|
|
|
|
if (Source = FTree) and (FTree.SelectedCount > 0) then begin
|
|
Accept := FGroupKind = bgfAddNewGroup;
|
|
if not Accept then begin
|
|
for VNode in FTree.SelectedNodes(True) do begin
|
|
Brk := TIDEBreakPoint(FTree.NodeItem[VNode]);
|
|
if Brk.Group <> FBrkGroup then begin
|
|
Accept := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if Accept and (State = dsDragMove) then begin
|
|
ToolBar1.Color := clHighlight;
|
|
ToolBar1.Font.Color := clHighlightText;
|
|
end
|
|
else begin
|
|
ToolBar1.Color := clBtnFace;
|
|
ToolBar1.Font.Color := clDefault;
|
|
end;
|
|
|
|
if (Source is TToolBar) and (TToolBar(Source).Owner is TBreakpointGroupFrame) then begin
|
|
Accept := (TToolBar(Source).Owner <> Self) and
|
|
(GroupKind in [bgfGroup, bgfUngrouped]);
|
|
end;
|
|
end;
|
|
|
|
function TBreakpointGroupFrame.GetCount: Integer;
|
|
begin
|
|
Result := FTree.ChildCount[FNode];
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.DoBrkGroupFreed(Sender: TObject);
|
|
begin
|
|
FBrkGroup := nil;
|
|
FGroupKind := bgfAbandoned;
|
|
Visible := False;
|
|
UpdateButtons;
|
|
end;
|
|
|
|
function TBreakpointGroupFrame.GetName: String;
|
|
begin
|
|
Result := StaticText1.Caption;
|
|
end;
|
|
|
|
function TBreakpointGroupFrame.GetVisible: boolean;
|
|
begin
|
|
Result := inherited Visible;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.SetVisible(Value: Boolean);
|
|
begin
|
|
if (Value = Visible) or
|
|
(Value and (FGroupKind = bgfAbandoned))
|
|
then
|
|
exit;
|
|
|
|
if not Value then
|
|
inherited SetVisible(Value);
|
|
FTree.IsVisible[FNode] := Value;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.VisibleChanged;
|
|
begin
|
|
inherited VisibleChanged;
|
|
if IsVisible then
|
|
FTree.NodeHeight[FNode] := min(40, Max(15, ToolBar1.Height));
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.CreateWnd;
|
|
begin
|
|
inherited CreateWnd;
|
|
FTree.NodeHeight[FNode] := min(40, Max(15, ToolBar1.Height));
|
|
end;
|
|
|
|
constructor TBreakpointGroupFrame.Create(TheOwner: TBreakPointsDlgBase;
|
|
ATree: TDbgTreeView; ANode: PVirtualNode; ABrkGroup: TIDEBreakPointGroup;
|
|
AGroupKind: TBreakpointGroupFrameKind);
|
|
begin
|
|
inherited Create(nil);
|
|
FOwner := TheOwner;
|
|
FTree := ATree;
|
|
FNode := ANode;
|
|
FBrkGroup := ABrkGroup;
|
|
FGroupKind := AGroupKind;
|
|
if FBrkGroup <> nil then
|
|
FBrkGroup.AddFreeNotification(@DoBrkGroupFreed)
|
|
else
|
|
if AGroupKind = bgfGroup then
|
|
FGroupKind := bgfUngrouped;
|
|
|
|
ToolBar1.Images := IDEImages.Images_16;
|
|
|
|
ToolButtonEnableAll.Caption := lisEnableAll;
|
|
ToolButtonEnableAll.Hint := lisDbgAllItemEnableHint;
|
|
ToolButtonEnableAll.ImageIndex := IDEImages.LoadImage('debugger_enable_all');
|
|
|
|
ToolButtonDisableAll.Caption := liswlDIsableAll;
|
|
ToolButtonDisableAll.Hint := lisDbgAllItemDisableHint;
|
|
ToolButtonDisableAll.ImageIndex := IDEImages.LoadImage('debugger_disable_all');
|
|
|
|
BtnDelete.Visible := FBrkGroup <> nil;
|
|
BtnDelete.Images := IDEImages.Images_16;
|
|
BtnDelete.ImageIndex := IDEImages.LoadImage('menu_close');
|
|
|
|
UpdateDisplay;
|
|
end;
|
|
|
|
destructor TBreakpointGroupFrame.Destroy;
|
|
begin
|
|
if FBrkGroup <> nil then
|
|
FBrkGroup.RemoveFreeNotification(@DoBrkGroupFreed);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.UpdateDisplay;
|
|
begin
|
|
UpdateButtons;
|
|
|
|
case FGroupKind of
|
|
bgfUngrouped: begin
|
|
StaticText1.Caption := BreakViewHeaderNoGroup;
|
|
StaticText2.Caption := Format(' (%d)', [FTree.ChildCount[FNode]]);
|
|
end;
|
|
bgfGroup: begin
|
|
if FBrkGroup <> nil then
|
|
StaticText1.Caption := FBrkGroup.Name;
|
|
StaticText2.Caption := Format(' (%d)', [Count]);
|
|
|
|
if (Count > 0) then
|
|
ToolBar1.DragMode := dmAutomatic
|
|
else
|
|
ToolBar1.DragMode := dmManual;
|
|
end;
|
|
bgfAddNewGroup: begin
|
|
StaticText1.Caption := BreakViewHeaderAddGroup;
|
|
StaticText2.Caption := '';
|
|
ToolBar1.Font.Style := [fsItalic];
|
|
end;
|
|
bgfAbandoned: ;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TBreakpointGroupFrame.UpdateButtons;
|
|
var
|
|
HasEnabled, HasDisabled: Boolean;
|
|
v: PVirtualNode;
|
|
b: TIDEBreakPoint;
|
|
begin
|
|
HasEnabled := False;
|
|
HasDisabled := False;
|
|
|
|
for v in FTree.VisibleChildNoInitNodes(Node) do begin
|
|
b := TIDEBreakPoint(FTree.NodeItem[v]);
|
|
if b = nil then continue;
|
|
HasEnabled := HasEnabled or b.Enabled;
|
|
HasDisabled := HasDisabled or not b.Enabled;
|
|
end;
|
|
|
|
ToolButtonDivider1.Visible := GroupKind in [bgfUngrouped, bgfGroup];
|
|
|
|
ToolButtonEnableAll.Visible := GroupKind in [bgfUngrouped, bgfGroup];
|
|
ToolButtonEnableAll.Enabled := (Count > 0) and HasDisabled;
|
|
|
|
ToolButtonDisableAll.Visible := GroupKind in [bgfUngrouped, bgfGroup];
|
|
ToolButtonDisableAll.Enabled := (Count > 0) and HasEnabled;
|
|
end;
|
|
|
|
function TBreakpointGroupFrame.Compare(AnOther: TBreakpointGroupFrame): integer;
|
|
begin
|
|
Result := ord(FGroupKind) - ord(AnOther.FGroupKind);
|
|
if Result <> 0 then
|
|
exit;
|
|
|
|
if FBrkGroup = nil then
|
|
exit(-1);
|
|
if AnOther.FBrkGroup = nil then
|
|
exit(1);
|
|
|
|
if (Count = 0) and (AnOther.Count > 0) then
|
|
exit(1);
|
|
if (Count > 0) and (AnOther.Count = 0) then
|
|
exit(-1);
|
|
|
|
Result := FBrkGroup.Index - AnOther.FBrkGroup.Index;
|
|
end;
|
|
|
|
end.
|
|
|