mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-25 02:49:36 +01:00
1031 lines
32 KiB
ObjectPascal
1031 lines
32 KiB
ObjectPascal
unit WatchInspectToolbar;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
// LCL
|
|
Forms, Controls, ComCtrls, Buttons, StdCtrls, ExtCtrls, Menus, LCLType, EditBtn,
|
|
// LazUtils
|
|
LazClasses,
|
|
// LazControls
|
|
SpinEx,
|
|
// IdeIntf
|
|
IDEImagesIntf, IdeDebuggerWatchValueIntf,
|
|
// Debugger
|
|
LazDebuggerIntf, IdeDebuggerStringConstants, ArrayNavigationFrame,
|
|
IdeDebuggerOpts, Debugger, IdeDebuggerBackendValueConv, IdeDebuggerBase,
|
|
IdeDebuggerDisplayFormats, WatchPropertyDlg, ProjectDebugLink, IdeDebuggerValueFormatter;
|
|
|
|
type
|
|
|
|
TEvalHistDirection=(EHDNone,EHDUp,EHDDown);
|
|
TEvalHistDirectionChangedEvent = procedure(Sender: TObject; NewDir: TEvalHistDirection) of object;
|
|
|
|
TInspectWatchBeforeUdateEvent = function(ASender: TObject): boolean of object;
|
|
TInspectWatchUpdatedEvent = procedure (const ASender: TIdeWatches; const AWatch: TIdeWatch) of object;
|
|
|
|
{ TWatchInspectNav }
|
|
|
|
TWatchInspectNav = class(TFrame)
|
|
btnDisplayFormat: TToolButton;
|
|
edFilter: TEditButton;
|
|
MenuItem1: TMenuItem;
|
|
MenuItem2: TMenuItem;
|
|
MenuItem3: TMenuItem;
|
|
mnuHistory: TPopupMenu;
|
|
Panel1: TPanel;
|
|
EdInspect: TComboBox;
|
|
popConverter: TPopupMenu;
|
|
popValFormatter: TPopupMenu;
|
|
BtnExecute: TSpeedButton;
|
|
ToolBar1: TToolBar;
|
|
btnPower: TToolButton;
|
|
tbDivPower: TToolButton;
|
|
btnBackward: TToolButton;
|
|
btnForward: TToolButton;
|
|
tbDivForwBackw: TToolButton;
|
|
btnUseInstance: TToolButton;
|
|
btnFunctionEval: TToolButton;
|
|
btnUseConverter: TToolButton;
|
|
btnUseValFormatter: TToolButton;
|
|
tbDivFlags: TToolButton;
|
|
btnColClass: TToolButton;
|
|
btnColType: TToolButton;
|
|
btnColVisibility: TToolButton;
|
|
tbDivCol: TToolButton;
|
|
ArrayNavigationBar1: TArrayNavigationBar;
|
|
tbDivArray: TToolButton;
|
|
BtnAddWatch: TToolButton;
|
|
BtnInspect: TToolButton;
|
|
BtnEvaluate: TToolButton;
|
|
tbDivAdd: TToolButton;
|
|
btnEvalHistory: TToolButton;
|
|
btnWordWrap: TToolButton;
|
|
procedure BtnAddWatchClick(Sender: TObject);
|
|
procedure btnBackwardClick(Sender: TObject);
|
|
procedure btnColTypeClick(Sender: TObject);
|
|
procedure btnDisplayFormatClick(Sender: TObject);
|
|
procedure BtnEvaluateClick(Sender: TObject);
|
|
procedure btnForwardClick(Sender: TObject);
|
|
procedure btnFunctionEvalClick(Sender: TObject);
|
|
procedure BtnInspectClick(Sender: TObject);
|
|
procedure btnPowerClick(Sender: TObject);
|
|
procedure btnWordWrapClick(Sender: TObject);
|
|
procedure EdInspectChange(Sender: TObject);
|
|
procedure EdInspectEditingDone(Sender: TObject);
|
|
procedure EdInspectKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure FrameResize(Sender: TObject);
|
|
procedure MenuItem1Click(Sender: TObject);
|
|
procedure BtnExecuteClick(Sender: TObject);
|
|
private const
|
|
MAX_HISTORY = 1000;
|
|
private
|
|
FAllowMemDump: Boolean;
|
|
FDisplayFormat: TWatchDisplayFormat;
|
|
FDefaultEvalOpts: TWatcheEvaluateFlags;
|
|
FOnAddEvaluateClicked: TNotifyEvent;
|
|
FOnAddInspectClicked: TNotifyEvent;
|
|
FOnAddWatchClicked: TNotifyEvent;
|
|
FOnBeforeEvaluate: TInspectWatchBeforeUdateEvent;
|
|
FOnClear: TNotifyEvent;
|
|
FOnColumnsChanged: TNotifyEvent;
|
|
FOnDisplayFormatChanged: TNotifyEvent;
|
|
FOnEvalHistDirectionChanged: TEvalHistDirectionChangedEvent;
|
|
FOnWatchUpdated: TInspectWatchUpdatedEvent;
|
|
FCurrentWatchValue: TIdeWatchValue;
|
|
FEvalHistDirection: TEvalHistDirection;
|
|
FExpression: String;
|
|
FHistoryListMaxCount: integer;
|
|
FHistoryList: TStrings;
|
|
FBrowseHistoryIndex: Integer;
|
|
FBrowseHistory: TStringList;
|
|
FOnWordWrapChanged: TNotifyEvent;
|
|
FPowerImgIdx, FPowerImgIdxGrey: Integer;
|
|
|
|
FThreadsMonitor: TIdeThreadsMonitor;
|
|
FCallStackMonitor: TIdeCallStackMonitor;
|
|
FInspectWatches: TCurrentWatches;
|
|
FUpdateCount: Integer;
|
|
FExecAfterUpdate: Boolean;
|
|
FInSetButtonDown: Boolean;
|
|
|
|
procedure ArrayNavSizeChanged(Sender: TObject);
|
|
procedure DoDbgValFormatterMenuClicked(Sender: TObject);
|
|
procedure DoBackConverterChanged(Sender: TObject);
|
|
procedure DoValFormatterChanged(Sender: TObject);
|
|
procedure DoDbpConvMenuClicked(Sender: TObject);
|
|
function GetDbgValueFormatter: TIdeDbgValueFormatterSelector;
|
|
function GetSkipDbgValueFormatter: Boolean;
|
|
function GetDisplayFormat: TWatchDisplayFormat;
|
|
function GetButtonDown(AIndex: Integer): Boolean;
|
|
function GetButtonEnabled(AIndex: Integer): Boolean;
|
|
function GetDropDownOpen: boolean;
|
|
function GetExpression: String;
|
|
function GetOnArrayNavChanged(AIndex: Integer): TArrayNavChangeEvent;
|
|
procedure SetButtonEnabled(AIndex: Integer; AValue: Boolean);
|
|
procedure SetButtorDown(AIndex: Integer; AValue: Boolean);
|
|
procedure SetHistoryList(AValue: TStrings);
|
|
procedure SetOnArrayNavChanged(AIndex: Integer; AValue: TArrayNavChangeEvent);
|
|
function GetShowButtons(AIndex: Integer): Boolean;
|
|
procedure SetShowButtons(AIndex: Integer; AValue: Boolean);
|
|
|
|
procedure AddToHistory(AnExpression: String);
|
|
procedure DoClear;
|
|
procedure DoWatchUpdated(AWatch: TIdeWatch);
|
|
procedure DoDisplaySettingsUpdated;
|
|
protected
|
|
procedure VisibleChanged; override;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Init(AWatchesMonitor: TIdeWatchesMonitor;
|
|
AThreadsMonitor: TIdeThreadsMonitor;
|
|
ACallStackMonitor: TIdeCallStackMonitor;
|
|
ADefaultEvalOpts: TWatcheEvaluateFlags
|
|
);
|
|
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
|
|
procedure InitWatch(AWatch: TIdeWatch);
|
|
procedure ReadFromWatch(AWatch: TWatch; AlternateExpression: String = '');
|
|
|
|
procedure Execute(const AnExpression: ansistring; ASkipHistory: Boolean = False);
|
|
procedure UpdateData(AForceClear: Boolean = False);// context changed instead
|
|
procedure DoContextChanged;
|
|
|
|
procedure FocusEnterExpression;
|
|
procedure GoPrevBrowseEntry;
|
|
procedure GoNextBrowseEntry;
|
|
procedure DeleteLastHistoryIf(AnExpression: String);
|
|
|
|
property Expression: String read GetExpression;
|
|
property Watches: TCurrentWatches read FInspectWatches;
|
|
property CurrentWatchValue: TIdeWatchValue read FCurrentWatchValue;
|
|
property DefaultEvalOpts: TWatcheEvaluateFlags read FDefaultEvalOpts write FDefaultEvalOpts;
|
|
property HistoryList: TStrings read FHistoryList write SetHistoryList;
|
|
property HistoryListMaxCount: integer read FHistoryListMaxCount write FHistoryListMaxCount;
|
|
property DisplayFormat: TWatchDisplayFormat read GetDisplayFormat;
|
|
property DbgValueFormatter: TIdeDbgValueFormatterSelector read GetDbgValueFormatter;
|
|
property SkipDbgValueFormatter: Boolean read GetSkipDbgValueFormatter;
|
|
property EvalHistDirection: TEvalHistDirection read FEvalHistDirection;
|
|
property DropDownOpen: boolean read GetDropDownOpen;
|
|
published
|
|
property ShowInspectColumns: Boolean index 0 read GetShowButtons write SetShowButtons;
|
|
property ShowArrayNav: Boolean index 1 read GetShowButtons write SetShowButtons;
|
|
property ShowAddWatch: Boolean index 2 read GetShowButtons write SetShowButtons;
|
|
property ShowAddInspect: Boolean index 3 read GetShowButtons write SetShowButtons;
|
|
property ShowAddEval: Boolean index 4 read GetShowButtons write SetShowButtons;
|
|
property ShowEvalHist: Boolean index 5 read GetShowButtons write SetShowButtons;
|
|
property ShowCallFunction: Boolean index 6 read GetShowButtons write SetShowButtons;
|
|
property ShowDisplayFormat: Boolean index 7 read GetShowButtons write SetShowButtons;
|
|
property ShowWordWrap: Boolean index 8 read GetShowButtons write SetShowButtons;
|
|
property AllowMemDump: Boolean read FAllowMemDump write FAllowMemDump;
|
|
|
|
property ColClassIsDown: Boolean index 0 read GetButtonDown;
|
|
property ColTypeIsDown: Boolean index 1 read GetButtonDown;
|
|
property ColVisibilityIsDown: Boolean index 2 read GetButtonDown;
|
|
property PowerIsDown: Boolean index 3 read GetButtonDown;
|
|
property UseInstanceIsDown: Boolean index 4 read GetButtonDown;
|
|
property WordWrapIsDown: Boolean index 5 read GetButtonDown write SetButtorDown;
|
|
|
|
property ColClassEnabled: Boolean index 0 read GetButtonEnabled write SetButtonEnabled;
|
|
property ColTypeEnabled: Boolean index 1 read GetButtonEnabled write SetButtonEnabled;
|
|
property ColVisibilityEnabled: Boolean index 2 read GetButtonEnabled write SetButtonEnabled;
|
|
|
|
property OnBeforeEvaluate: TInspectWatchBeforeUdateEvent read FOnBeforeEvaluate write FOnBeforeEvaluate;
|
|
property OnWatchUpdated: TInspectWatchUpdatedEvent read FOnWatchUpdated write FOnWatchUpdated;
|
|
property OnClear: TNotifyEvent read FOnClear write FOnClear;
|
|
property OnColumnsChanged: TNotifyEvent read FOnColumnsChanged write FOnColumnsChanged;
|
|
property OnAddWatchClicked: TNotifyEvent read FOnAddWatchClicked write FOnAddWatchClicked;
|
|
property OnAddEvaluateClicked: TNotifyEvent read FOnAddEvaluateClicked write FOnAddEvaluateClicked;
|
|
property OnAddInspectClicked: TNotifyEvent read FOnAddInspectClicked write FOnAddInspectClicked;
|
|
property OnArrayIndexChanged: TArrayNavChangeEvent index 0 read GetOnArrayNavChanged write SetOnArrayNavChanged;
|
|
property OnArrayPageSize: TArrayNavChangeEvent index 1 read GetOnArrayNavChanged write SetOnArrayNavChanged;
|
|
property OnDisplayFormatChanged: TNotifyEvent read FOnDisplayFormatChanged write FOnDisplayFormatChanged;
|
|
property OnEvalHistDirectionChanged: TEvalHistDirectionChangedEvent read FOnEvalHistDirectionChanged write FOnEvalHistDirectionChanged;
|
|
property OnWordWrapChanged: TNotifyEvent read FOnWordWrapChanged write FOnWordWrapChanged;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
procedure AddToStr(var txt: string; add, sep: string);
|
|
begin
|
|
if (txt = add) then
|
|
exit;
|
|
if txt <> '' then txt := txt + sep;
|
|
txt := txt + add;
|
|
end;
|
|
|
|
{ TWatchInspectNav }
|
|
|
|
function TWatchInspectNav.GetShowButtons(AIndex: Integer): Boolean;
|
|
begin
|
|
case AIndex of
|
|
0: Result := btnColClass.Visible;
|
|
1: Result := ArrayNavigationBar1.Visible;
|
|
2: Result := BtnAddWatch.Visible;
|
|
3: Result := BtnInspect.Visible;
|
|
4: Result := BtnEvaluate.Visible;
|
|
5: Result := btnEvalHistory.Visible;
|
|
6: Result := btnFunctionEval .Visible;
|
|
7: Result := btnDisplayFormat.Visible;
|
|
8: Result := btnWordWrap.Visible;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.SetOnArrayNavChanged(AIndex: Integer;
|
|
AValue: TArrayNavChangeEvent);
|
|
begin
|
|
case AIndex of
|
|
0: ArrayNavigationBar1.OnIndexChanged := AValue;
|
|
1: ArrayNavigationBar1.OnPageSize := AValue;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.MenuItem1Click(Sender: TObject);
|
|
begin
|
|
if Sender = MenuItem3 then begin
|
|
FEvalHistDirection := EHDDown;
|
|
btnEvalHistory.ImageIndex := IDEImages.LoadImage('callstack_goto');
|
|
end
|
|
else
|
|
if Sender = MenuItem2 then begin
|
|
FEvalHistDirection := EHDUp;
|
|
btnEvalHistory.ImageIndex := IDEImages.LoadImage('evaluate_up');
|
|
end
|
|
else begin
|
|
FEvalHistDirection := EHDNone;
|
|
btnEvalHistory.ImageIndex := IDEImages.LoadImage('evaluate_no_hist');
|
|
end;
|
|
if FOnEvalHistDirectionChanged <> nil then
|
|
FOnEvalHistDirectionChanged(Self, FEvalHistDirection);
|
|
FrameResize(nil);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.BtnExecuteClick(Sender: TObject);
|
|
begin
|
|
DoClear;
|
|
ReleaseRefAndNil(FCurrentWatchValue);
|
|
FInspectWatches.Clear;
|
|
Execute(EdInspect.Text);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.EdInspectKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if (Key = VK_RETURN) then
|
|
EdInspectEditingDone(nil)
|
|
else
|
|
if (Key = VK_UP) or (Key = VK_DOWN) then
|
|
EdInspect.DroppedDown := True;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.FrameResize(Sender: TObject);
|
|
begin
|
|
ToolBar1.InvalidatePreferredSize;
|
|
Height := ToolBar1.Top + ToolBar1.Height;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.EdInspectEditingDone(Sender: TObject);
|
|
begin
|
|
if FExpression = EdInspect.Text then
|
|
exit;
|
|
Execute(EdInspect.Text);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnColTypeClick(Sender: TObject);
|
|
begin
|
|
if FOnColumnsChanged <> nil then
|
|
FOnColumnsChanged(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnDisplayFormatClick(Sender: TObject);
|
|
var
|
|
r: TWatchResultDataKind;
|
|
d: TWatchPropertyDlg;
|
|
begin
|
|
r := rdkUnknown;
|
|
if (FCurrentWatchValue <> nil) and (FCurrentWatchValue.Validity = ddsValid) and
|
|
(FCurrentWatchValue.ResultData <> nil)
|
|
then
|
|
r := FCurrentWatchValue.ResultData.ValueKind;
|
|
d := TWatchPropertyDlg.Create(Self.Owner, FDisplayFormat, r, FAllowMemDump, False);
|
|
if d.ShowModal = mrOK then begin
|
|
FDisplayFormat := d.DisplayFormat;
|
|
// DoDisplaySettingsUpdated;
|
|
if FOnDisplayFormatChanged <> nil then
|
|
FOnDisplayFormatChanged(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.BtnEvaluateClick(Sender: TObject);
|
|
begin
|
|
if FOnAddEvaluateClicked <> nil then
|
|
FOnAddEvaluateClicked(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnForwardClick(Sender: TObject);
|
|
begin
|
|
GoNextBrowseEntry;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnFunctionEvalClick(Sender: TObject);
|
|
begin
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.BtnInspectClick(Sender: TObject);
|
|
begin
|
|
if FOnAddInspectClicked <> nil then
|
|
FOnAddInspectClicked(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnBackwardClick(Sender: TObject);
|
|
begin
|
|
GoPrevBrowseEntry;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.BtnAddWatchClick(Sender: TObject);
|
|
begin
|
|
if FOnAddWatchClicked <> nil then
|
|
FOnAddWatchClicked(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnPowerClick(Sender: TObject);
|
|
begin
|
|
if btnPower.Down
|
|
then begin
|
|
btnPower.ImageIndex := FPowerImgIdx;
|
|
DoClear; // todo: only get result data released
|
|
ReleaseRefAndNil(FCurrentWatchValue);
|
|
FInspectWatches.Clear;
|
|
UpdateData;
|
|
end
|
|
else begin
|
|
btnPower.ImageIndex := FPowerImgIdxGrey;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.btnWordWrapClick(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnWordWrapChanged) and not FInSetButtonDown then
|
|
FOnWordWrapChanged(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.EdInspectChange(Sender: TObject);
|
|
begin
|
|
BtnExecute.Enabled := EdInspect.Text <> '';
|
|
BtnAddWatch.Enabled := EdInspect.Text <> '';
|
|
BtnEvaluate.Enabled := EdInspect.Text <> '';
|
|
BtnInspect.Enabled := EdInspect.Text <> '';
|
|
end;
|
|
|
|
function TWatchInspectNav.GetOnArrayNavChanged(AIndex: Integer
|
|
): TArrayNavChangeEvent;
|
|
begin
|
|
case AIndex of
|
|
0: Result := ArrayNavigationBar1.OnIndexChanged;
|
|
1: Result := ArrayNavigationBar1.OnPageSize;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.SetButtonEnabled(AIndex: Integer; AValue: Boolean);
|
|
begin
|
|
case AIndex of
|
|
0: btnColClass.Enabled := AValue;
|
|
1: btnColType.Enabled := AValue;
|
|
2: btnColVisibility.Enabled := AValue;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.SetButtorDown(AIndex: Integer; AValue: Boolean);
|
|
begin
|
|
FInSetButtonDown := True;
|
|
case AIndex of
|
|
5: btnWordWrap.Down := AValue;
|
|
end;
|
|
FInSetButtonDown := False;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetButtonDown(AIndex: Integer): Boolean;
|
|
begin
|
|
case AIndex of
|
|
0: Result := btnColClass.Down;
|
|
1: Result := btnColType.Down;
|
|
2: Result := btnColVisibility.Down;
|
|
3: Result := btnPower.Down;
|
|
4: Result := btnUseInstance.Down;
|
|
5: Result := btnWordWrap.Down;
|
|
end;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetButtonEnabled(AIndex: Integer): Boolean;
|
|
begin
|
|
case AIndex of
|
|
0: Result := btnColClass.Enabled;
|
|
1: Result := btnColType.Enabled;
|
|
2: Result := btnColVisibility.Enabled;
|
|
end;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetDropDownOpen: boolean;
|
|
begin
|
|
Result := EdInspect.Focused and EdInspect.DroppedDown;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetExpression: String;
|
|
begin
|
|
Result := EdInspect.Text;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoDbgValFormatterMenuClicked(Sender: TObject);
|
|
begin
|
|
btnUseValFormatter.Tag := TMenuItem(Sender).Tag;
|
|
btnUseValFormatter.Caption := TMenuItem(Sender).Caption;
|
|
FrameResize(nil);
|
|
DoDisplaySettingsUpdated;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoValFormatterChanged(Sender: TObject);
|
|
function MnItm(c: String; e: TNotifyEvent; t: SizeInt): TMenuItem;
|
|
begin
|
|
Result := TMenuItem.Create(Self);
|
|
Result.Caption := c;
|
|
Result.OnClick := e;
|
|
Result.Tag := t;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
begin
|
|
popValFormatter.Items.Clear;
|
|
|
|
popValFormatter.Items.Add(MnItm(drsDebugValFormatter, @DoDbgValFormatterMenuClicked, -2));
|
|
popValFormatter.Items.Add(MnItm(drsNoValFormatter, @DoDbgValFormatterMenuClicked, -1));
|
|
|
|
for i := 0 to DebuggerOptions.ValueFormatterConfig.Count - 1 do
|
|
popValFormatter.Items.Add(MnItm(DebuggerOptions.ValueFormatterConfig[i].Name, @DoDbgValFormatterMenuClicked, PtrInt(DebuggerOptions.ValueFormatterConfig[i])));
|
|
for i := 0 to DbgProjectLink.ValueFormatterConfig.Count - 1 do
|
|
popValFormatter.Items.Add(MnItm(DbgProjectLink.ValueFormatterConfig[i].Name, @DoDbgValFormatterMenuClicked, PtrInt(DbgProjectLink.ValueFormatterConfig[i])));
|
|
|
|
btnUseValFormatter.Visible := DebuggerOptions.ValueFormatterConfig.Count + DbgProjectLink.ValueFormatterConfig.Count > 0;
|
|
btnUseValFormatter.Tag := -2;
|
|
btnUseValFormatter.Caption := drsDebugValFormatter;
|
|
FrameResize(nil);
|
|
DoDisplaySettingsUpdated;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetDisplayFormat: TWatchDisplayFormat;
|
|
begin
|
|
if btnDisplayFormat.Visible then
|
|
Result := FDisplayFormat
|
|
else
|
|
Result := DefaultWatchDisplayFormat;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.ArrayNavSizeChanged(Sender: TObject);
|
|
begin
|
|
FrameResize(nil);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoDbpConvMenuClicked(Sender: TObject);
|
|
begin
|
|
btnUseConverter.Tag := TMenuItem(Sender).Tag;
|
|
btnUseConverter.Caption := TMenuItem(Sender).Caption;
|
|
FrameResize(nil);
|
|
UpdateData;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetDbgValueFormatter: TIdeDbgValueFormatterSelector;
|
|
begin
|
|
Result := nil;
|
|
if (btnUseValFormatter.Tag=-1) or (btnUseValFormatter.Tag=-2) then
|
|
exit;
|
|
Result := TIdeDbgValueFormatterSelector(btnUseValFormatter.Tag);
|
|
if (DebuggerOptions.ValueFormatterConfig.IndexOf(Result) < 0) and
|
|
(DbgProjectLink.ValueFormatterConfig.IndexOf(Result) < 0)
|
|
then
|
|
Result := nil;
|
|
end;
|
|
|
|
function TWatchInspectNav.GetSkipDbgValueFormatter: Boolean;
|
|
begin
|
|
Result := btnUseValFormatter.Tag = -1;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoBackConverterChanged(Sender: TObject);
|
|
function MnItm(c: String; e: TNotifyEvent; t: SizeInt): TMenuItem;
|
|
begin
|
|
Result := TMenuItem.Create(Self);
|
|
Result.Caption := c;
|
|
Result.OnClick := e;
|
|
Result.Tag := t;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
begin
|
|
popConverter.Items.Clear;
|
|
|
|
popConverter.Items.Add(MnItm(drsDebugConverter, @DoDbpConvMenuClicked, -2));
|
|
popConverter.Items.Add(MnItm(drsNoDebugConverter, @DoDbpConvMenuClicked, -1));
|
|
|
|
for i := 0 to DebuggerOptions.BackendConverterConfig.Count - 1 do
|
|
popConverter.Items.Add(MnItm(DebuggerOptions.BackendConverterConfig[i].Name, @DoDbpConvMenuClicked, PtrInt(DebuggerOptions.BackendConverterConfig[i])));
|
|
for i := 0 to DbgProjectLink.BackendConverterConfig.Count - 1 do
|
|
popConverter.Items.Add(MnItm(DbgProjectLink.BackendConverterConfig[i].Name, @DoDbpConvMenuClicked, PtrInt(DbgProjectLink.BackendConverterConfig[i])));
|
|
|
|
btnUseConverter.Visible := DebuggerOptions.BackendConverterConfig.Count + DbgProjectLink.BackendConverterConfig.Count > 0;
|
|
btnUseConverter.Tag := -2;
|
|
btnUseConverter.Caption := drsDebugConverter;
|
|
FrameResize(nil);
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.SetHistoryList(AValue: TStrings);
|
|
begin
|
|
if FHistoryList = AValue then Exit;
|
|
FHistoryList := AValue;
|
|
if FHistoryList <> nil then
|
|
EdInspect.Items.Assign(FHistoryList);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.SetShowButtons(AIndex: Integer; AValue: Boolean);
|
|
begin
|
|
case AIndex of
|
|
0: begin
|
|
btnColClass.Visible := AValue;
|
|
btnColType.Visible := AValue;
|
|
btnColVisibility.Visible := AValue;
|
|
end;
|
|
1: ArrayNavigationBar1.Visible := AValue;
|
|
2: BtnAddWatch.Visible := AValue;
|
|
3: BtnInspect.Visible := AValue;
|
|
4: BtnEvaluate.Visible := AValue;
|
|
5: btnEvalHistory.Visible := AValue;
|
|
6: begin
|
|
btnFunctionEval.Visible := AValue;
|
|
if not AValue then
|
|
btnFunctionEval.Down := False;
|
|
end;
|
|
7: btnDisplayFormat.Visible := AValue;
|
|
8: btnWordWrap.Visible := AValue;
|
|
end;
|
|
|
|
tbDivCol.Visible := (ShowInspectColumns or ShowDisplayFormat);
|
|
tbDivArray.Visible := (ShowArrayNav);
|
|
tbDivAdd.Visible := (ShowAddWatch or ShowAddEval or ShowAddInspect) and
|
|
ShowEvalHist;
|
|
FrameResize(nil);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.AddToHistory(AnExpression: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inc(FBrowseHistoryIndex);
|
|
while FBrowseHistory.Count > FBrowseHistoryIndex do
|
|
FBrowseHistory.Delete(FBrowseHistoryIndex);
|
|
while FBrowseHistory.Count > MAX_HISTORY - 1 do
|
|
FBrowseHistory.Delete(0);
|
|
if (FBrowseHistory.Count = 0) or (FBrowseHistory[FBrowseHistory.Count-1] <> AnExpression)
|
|
then
|
|
FBrowseHistoryIndex := FBrowseHistory.Add(AnExpression);
|
|
|
|
if FHistoryList <> nil then begin
|
|
if (FHistoryList.Count = 0) or
|
|
(AnsiCompareText(FHistoryList[0], AnExpression) <> 0)
|
|
then begin
|
|
for i:=FHistoryList.Count-1 downto 0 do
|
|
if AnsiCompareText(FHistoryList[i], AnExpression) = 0 then
|
|
FHistoryList.Delete(i);
|
|
|
|
FHistoryList.Insert(0, AnExpression);
|
|
|
|
if FHistoryListMaxCount > 0 then
|
|
while FHistoryList.Count > FHistoryListMaxCount do
|
|
FHistoryList.Delete(FHistoryList.Count-1);
|
|
end;
|
|
EdInspect.Items.Assign(FHistoryList);
|
|
end
|
|
else
|
|
EdInspect.Items.Insert(0, AnExpression);
|
|
end;
|
|
|
|
constructor TWatchInspectNav.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FBrowseHistory := TStringList.Create;
|
|
|
|
EdInspect.TextHint := drsEnterExpression;
|
|
|
|
ToolBar1.Images := IDEImages.Images_16;
|
|
|
|
FPowerImgIdx := IDEImages.LoadImage('debugger_power');
|
|
FPowerImgIdxGrey := IDEImages.LoadImage('debugger_power_grey');
|
|
btnPower.ImageIndex := FPowerImgIdx;
|
|
btnPower.Caption := '';
|
|
btnPower.Hint := drsDisableEnableUpdatesForTh;
|
|
|
|
btnBackward.ImageIndex := IDEImages.LoadImage('arrow_left');
|
|
btnBackward.Caption := '';
|
|
btnForward.ImageIndex := IDEImages.LoadImage('arrow_right');
|
|
btnForward.Caption := '';
|
|
|
|
btnUseInstance.Caption := drsUseInstanceClass;
|
|
btnUseInstance.Hint := drsUseInstanceClassHint;
|
|
|
|
BtnEvaluate.Caption := drsUseFunctionCalls;
|
|
BtnEvaluate.Hint := drsUseFunctionCallsHint;
|
|
|
|
btnColClass.Hint := lisInspectShowColClass;
|
|
btnColType.Hint := lisInspectShowColType;
|
|
btnColVisibility.Hint := lisInspectShowColVisibility;
|
|
btnWordWrap.Hint := lisWordWrapBtnHint;
|
|
|
|
btnWordWrap.ImageIndex := IDEImages.LoadImage('line_wrap');
|
|
|
|
BtnAddWatch.ImageIndex := IDEImages.LoadImage('debugger_watches');
|
|
BtnAddWatch.Caption := drsAddWatch;
|
|
BtnEvaluate.ImageIndex := IDEImages.LoadImage('debugger_evaluate');
|
|
BtnEvaluate.Caption := drsEvaluate;
|
|
BtnInspect.ImageIndex := IDEImages.LoadImage('debugger_inspect');
|
|
BtnInspect.Caption := drsInspect;
|
|
|
|
edFilter.Images := IDEImages.Images_16;
|
|
edFilter.ImageIndex := IDEImages.LoadImage('btnfiltercancel');
|
|
|
|
btnEvalHistory.Caption := drsHistory;
|
|
btnEvalHistory.ImageIndex := IDEImages.LoadImage('evaluate_no_hist');
|
|
mnuHistory.Items[0].Caption := drsNoHistoryKept;
|
|
mnuHistory.Items[1].Caption := drsInsertResultAtTopOfHistor;
|
|
mnuHistory.Items[2].Caption := drsAppendResultAtBottomOfHis;
|
|
|
|
FDisplayFormat := DefaultWatchDisplayFormat;
|
|
|
|
btnDisplayFormat.Caption := 'Display-Format';
|
|
|
|
btnBackward.Enabled := False;
|
|
btnForward.Enabled := False;
|
|
|
|
btnColClass.Enabled := False;
|
|
btnColType.Enabled := False;
|
|
btnColVisibility.Enabled := False;
|
|
|
|
FEvalHistDirection:=EHDNone;
|
|
|
|
btnBackward.Enabled := False;
|
|
btnForward.Enabled := False;
|
|
|
|
ArrayNavigationBar1.OnSizeChanged := @ArrayNavSizeChanged;
|
|
|
|
DebuggerOptions.BackendConverterConfig.AddChangeNotification(@DoBackConverterChanged);
|
|
DbgProjectLink.BackendConverterConfig.AddChangeNotification(@DoBackConverterChanged);
|
|
DoBackConverterChanged(nil);
|
|
|
|
DebuggerOptions.ValueFormatterConfig.AddChangeNotification(@DoValFormatterChanged);
|
|
DbgProjectLink.ValueFormatterConfig.AddChangeNotification(@DoValFormatterChanged);
|
|
DoValFormatterChanged(nil);
|
|
|
|
EdInspectChange(nil);
|
|
end;
|
|
|
|
destructor TWatchInspectNav.Destroy;
|
|
begin
|
|
DebuggerOptions.BackendConverterConfig.RemoveChangeNotification(@DoBackConverterChanged);
|
|
DbgProjectLink.BackendConverterConfig.RemoveChangeNotification(@DoBackConverterChanged);
|
|
DebuggerOptions.ValueFormatterConfig.RemoveChangeNotification(@DoValFormatterChanged);
|
|
DbgProjectLink.ValueFormatterConfig.RemoveChangeNotification(@DoValFormatterChanged);
|
|
inherited Destroy;
|
|
FBrowseHistory.Free;
|
|
ReleaseRefAndNil(FCurrentWatchValue);
|
|
FreeAndNil(FInspectWatches);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.Init(AWatchesMonitor: TIdeWatchesMonitor;
|
|
AThreadsMonitor: TIdeThreadsMonitor; ACallStackMonitor: TIdeCallStackMonitor;
|
|
ADefaultEvalOpts: TWatcheEvaluateFlags);
|
|
begin
|
|
FInspectWatches := TCurrentWatches.Create(AWatchesMonitor);
|
|
FCallStackMonitor := ACallStackMonitor;
|
|
FThreadsMonitor := AThreadsMonitor;
|
|
FDefaultEvalOpts := ADefaultEvalOpts;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.BeginUpdate;
|
|
begin
|
|
if FUpdateCount = 0 then
|
|
FExecAfterUpdate := False;
|
|
inc(FUpdateCount);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.EndUpdate;
|
|
begin
|
|
if FUpdateCount > 0 then
|
|
dec(FUpdateCount);
|
|
if (FUpdateCount = 0) and FExecAfterUpdate then
|
|
UpdateData(True);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.InitWatch(AWatch: TIdeWatch);
|
|
var
|
|
Opts: TWatcheEvaluateFlags;
|
|
Conv: TIdeDbgValueConvertSelector;
|
|
ValForm: TIdeDbgValueFormatterSelector;
|
|
begin
|
|
Opts := AWatch.EvaluateFlags;
|
|
if btnUseInstance.Down then
|
|
include(Opts, defClassAutoCast);
|
|
if btnFunctionEval.Down then
|
|
include(Opts, defAllowFunctionCall);
|
|
|
|
Conv := nil;
|
|
case btnUseConverter.Tag of
|
|
-2: ;
|
|
-1: include(Opts, defSkipValConv);
|
|
otherwise begin
|
|
Conv := TIdeDbgValueConvertSelector(btnUseConverter.Tag);
|
|
if (DebuggerOptions.BackendConverterConfig.IndexOf(Conv) < 0) and
|
|
(DbgProjectLink.BackendConverterConfig.IndexOf(Conv) < 0)
|
|
then
|
|
Conv := nil;
|
|
end
|
|
end;
|
|
AWatch.DbgBackendConverter := Conv;
|
|
|
|
ValForm := nil;
|
|
case btnUseValFormatter.Tag of
|
|
-2: ;
|
|
-1: include(Opts, defSkipValueFormatter);
|
|
otherwise begin
|
|
ValForm := TIdeDbgValueFormatterSelector(btnUseValFormatter.Tag);
|
|
if (DebuggerOptions.ValueFormatterConfig.IndexOf(ValForm) < 0) and
|
|
(DbgProjectLink.ValueFormatterConfig.IndexOf(ValForm) < 0)
|
|
then
|
|
ValForm := nil;
|
|
end
|
|
end;
|
|
AWatch.DbgValueFormatter := ValForm;
|
|
|
|
AWatch.EvaluateFlags := Opts;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.ReadFromWatch(AWatch: TWatch;
|
|
AlternateExpression: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
btnUseInstance.Down := defClassAutoCast in AWatch.EvaluateFlags;
|
|
btnFunctionEval.Down := defAllowFunctionCall in AWatch.EvaluateFlags;
|
|
|
|
if defSkipValConv in AWatch.EvaluateFlags then begin
|
|
if popConverter.Items.Count > 1 then
|
|
popConverter.Items[1].Click;
|
|
end
|
|
else if AWatch.DbgBackendConverter = nil then begin
|
|
if popConverter.Items.Count > 0 then
|
|
popConverter.Items[0].Click;
|
|
end
|
|
else begin
|
|
i := popConverter.Items.Count - 1;
|
|
while i >= 0 do begin
|
|
if popConverter.Items[i].Tag = PtrUInt(AWatch.DbgBackendConverter) then begin
|
|
popConverter.Items[i].Click;
|
|
break;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
if defSkipValueFormatter in AWatch.EvaluateFlags then begin
|
|
if popValFormatter.Items.Count > 1 then
|
|
popValFormatter.Items[1].Click;
|
|
end
|
|
else if AWatch.DbgValueFormatter = nil then begin
|
|
if popValFormatter.Items.Count > 0 then
|
|
popValFormatter.Items[0].Click;
|
|
end
|
|
else begin
|
|
i := popValFormatter.Items.Count - 1;
|
|
while i >= 0 do begin
|
|
if popValFormatter.Items[i].Tag = PtrUInt(AWatch.DbgValueFormatter) then begin
|
|
popValFormatter.Items[i].Click;
|
|
break;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
if AlternateExpression <> '' then
|
|
Execute(AlternateExpression)
|
|
else
|
|
Execute(AWatch.Expression);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.Execute(const AnExpression: ansistring;
|
|
ASkipHistory: Boolean);
|
|
begin
|
|
if not ASkipHistory then
|
|
AddToHistory(AnExpression);
|
|
|
|
FExpression := AnExpression;
|
|
EdInspect.Text := FExpression;
|
|
EdInspectChange(nil);
|
|
ArrayNavigationBar1.Index := 0;
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoContextChanged;
|
|
begin
|
|
if (not btnPower.Down) or (not Visible) then exit;
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.FocusEnterExpression;
|
|
begin
|
|
if IsVisible then
|
|
EdInspect.SetFocus;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.GoPrevBrowseEntry;
|
|
begin
|
|
if FBrowseHistoryIndex <= 0 then
|
|
exit;
|
|
|
|
if FBrowseHistoryIndex >= FBrowseHistory.Count then
|
|
FBrowseHistoryIndex := FBrowseHistory.Count - 1;
|
|
if FBrowseHistoryIndex <= 0 then
|
|
exit;
|
|
|
|
dec(FBrowseHistoryIndex);
|
|
Execute(FBrowseHistory[FBrowseHistoryIndex], True);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.GoNextBrowseEntry;
|
|
begin
|
|
if FBrowseHistoryIndex >= FBrowseHistory.Count -1 then
|
|
exit;
|
|
|
|
if FBrowseHistoryIndex < 0 then
|
|
FBrowseHistoryIndex := 0;
|
|
|
|
inc(FBrowseHistoryIndex);
|
|
Execute(FBrowseHistory[FBrowseHistoryIndex], True);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DeleteLastHistoryIf(AnExpression: String);
|
|
begin
|
|
if (FBrowseHistory.Count > 0) and (FBrowseHistory[FBrowseHistory.Count-1] = AnExpression)
|
|
then
|
|
FBrowseHistory.Delete(FBrowseHistory.Count-1);
|
|
|
|
if (FHistoryList <> nil) and (FHistoryList.Count > 0) and (FHistoryList[0] = AnExpression)
|
|
then
|
|
FHistoryList.Delete(0);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.UpdateData(AForceClear: Boolean);
|
|
var
|
|
Opts: TWatcheEvaluateFlags;
|
|
AWatch: TCurrentWatch;
|
|
tid, idx: Integer;
|
|
stack: TIdeCallStack;
|
|
expr: String;
|
|
Conv: TIdeDbgValueConvertSelector;
|
|
begin
|
|
if FUpdateCount > 0 then begin
|
|
FExecAfterUpdate := True;
|
|
exit;
|
|
end;
|
|
FExecAfterUpdate := False;
|
|
|
|
if AForceClear then
|
|
FInspectWatches.Clear;
|
|
|
|
btnBackward.Enabled := FBrowseHistoryIndex > 0;
|
|
btnForward.Enabled := FBrowseHistoryIndex < FBrowseHistory.Count - 1;
|
|
|
|
expr := trim(FExpression);
|
|
if expr = '' then begin
|
|
ReleaseRefAndNil(FCurrentWatchValue);
|
|
DoClear;
|
|
exit;
|
|
end;
|
|
|
|
if FOnBeforeEvaluate = nil then
|
|
exit;
|
|
if not FOnBeforeEvaluate(Self) then
|
|
exit;
|
|
|
|
if (FCallStackMonitor = nil) or (FThreadsMonitor = nil)
|
|
// or (DebugBoss.State <> dsPause)
|
|
then
|
|
exit;
|
|
|
|
tid := FThreadsMonitor.CurrentThreads.CurrentThreadId;
|
|
stack := FCallStackMonitor.CurrentCallStackList.EntriesForThreads[tid];
|
|
idx := 0;
|
|
if stack <> nil then
|
|
idx := stack.CurrentIndex;
|
|
|
|
Opts := FDefaultEvalOpts;
|
|
if btnUseInstance.Down then
|
|
include(Opts, defClassAutoCast);
|
|
if btnFunctionEval.Down then
|
|
include(Opts, defAllowFunctionCall);
|
|
|
|
Conv := nil;
|
|
case btnUseConverter.Tag of
|
|
-2: ;
|
|
-1: include(Opts, defSkipValConv);
|
|
otherwise begin
|
|
Conv := TIdeDbgValueConvertSelector(btnUseConverter.Tag);
|
|
if (DebuggerOptions.BackendConverterConfig.IndexOf(Conv) < 0) and
|
|
(DbgProjectLink.BackendConverterConfig.IndexOf(Conv) < 0)
|
|
then
|
|
Conv := nil;
|
|
end
|
|
end;
|
|
|
|
if (FCurrentWatchValue <> nil) and
|
|
(FCurrentWatchValue.Expression = expr) and
|
|
(FCurrentWatchValue.EvaluateFlags = Opts) and
|
|
(FCurrentWatchValue.ThreadId = tid) and
|
|
(FCurrentWatchValue.StackFrame = idx) and
|
|
(FCurrentWatchValue.Watch <> nil) and
|
|
(FCurrentWatchValue.Watch.DbgBackendConverter = Conv)
|
|
then begin
|
|
FCurrentWatchValue.Value;
|
|
DoWatchUpdated(FCurrentWatchValue.Watch);
|
|
exit;
|
|
end;
|
|
|
|
ReleaseRefAndNil(FCurrentWatchValue);
|
|
|
|
FInspectWatches.BeginUpdate;
|
|
AWatch := FInspectWatches.Find(expr);
|
|
if AWatch = nil then begin
|
|
FInspectWatches.Clear;
|
|
AWatch := FInspectWatches.Add(expr);
|
|
ArrayNavigationBar1.Index := 0;
|
|
end;
|
|
AWatch.EvaluateFlags := Opts;
|
|
AWatch.DbgBackendConverter := Conv;
|
|
AWatch.Enabled := True;
|
|
AWatch.RepeatCount := 0;
|
|
if ArrayNavigationBar1.Visible then
|
|
AWatch.RepeatCount := ArrayNavigationBar1.PageSize;
|
|
FInspectWatches.EndUpdate;
|
|
FCurrentWatchValue := AWatch.Values[tid, idx];
|
|
if FCurrentWatchValue <> nil then begin
|
|
FCurrentWatchValue.AddReference;
|
|
FCurrentWatchValue.Value;
|
|
end;
|
|
DoWatchUpdated(AWatch);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoClear;
|
|
begin
|
|
if FOnClear <> nil then
|
|
FOnClear(Self);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoWatchUpdated(AWatch: TIdeWatch);
|
|
begin
|
|
if FOnWatchUpdated <> nil then
|
|
FOnWatchUpdated(FInspectWatches, AWatch);
|
|
end;
|
|
|
|
procedure TWatchInspectNav.DoDisplaySettingsUpdated;
|
|
begin
|
|
if FOnDisplayFormatChanged <> nil then
|
|
FOnDisplayFormatChanged(Self)
|
|
else
|
|
if FCurrentWatchValue <> nil then
|
|
DoWatchUpdated(FCurrentWatchValue.Watch)
|
|
else
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TWatchInspectNav.VisibleChanged;
|
|
begin
|
|
inherited VisibleChanged;
|
|
if IsControlVisible then
|
|
FrameResize(nil);
|
|
end;
|
|
|
|
end.
|
|
|