{ $Id$ } { ---------------------------------------------- breakpointsdlg.pp - Overview of breakpoints ---------------------------------------------- @created(Fri Dec 14st WET 2001) @lastmod($Date$) @author(Shane Miller) @author(Marc Weustink ) This unit contains the Breakpoint dialog. *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** } unit BreakPointsDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LazFileUtils, Forms, Controls, Dialogs, IDEWindowIntf, DebuggerStrConst, Menus, ComCtrls, Debugger, DebuggerDlg, ActnList, MainBase, IDEImagesIntf, DbgIntfDebuggerBase, DbgIntfMiscClasses, SourceEditor, MainIntf; type TBreakPointsDlgState = ( bpdsItemsNeedUpdate ); TBreakPointsDlgStates = set of TBreakPointsDlgState; { TBreakPointsDlg } TBreakPointsDlg = class(TDebuggerDlg) actAddSourceBP: TAction; actAddAddressBP: TAction; actAddWatchPoint: TAction; actGroupSetNone: TAction; actGroupSetNew: TAction; actShow: TAction; actProperties: TAction; actToggleCurrentEnable: TAction; actDeleteAllInSrc: TAction; actEnableSelected: TAction; actDisableSelected: TAction; actDeleteSelected: TAction; actEnableAll: TAction; actDisableAll: TAction; actDeleteAll: TAction; actEnableAllInSrc: TAction; actDisableAllInSrc: TAction; ActionList1: TActionList; lvBreakPoints: TListView; popGroupSep: TMenuItem; popGroupSetNew: TMenuItem; popGroupSetNone: TMenuItem; popGroup: TMenuItem; popAddWatchPoint: TMenuItem; popAddAddressBP: TMenuItem; N0: TMenuItem; popShow: TMenuItem; mnuPopup: TPopupMenu; popAdd: TMenuItem; popAddSourceBP: TMenuItem; N1: TMenuItem; //-------------- popProperties: TMenuItem; popEnabled: TMenuItem; popDelete: TMenuItem; N2: TMenuItem; //-------------- popDisableAll: TMenuItem; popEnableAll: TMenuItem; popDeleteAll: TMenuItem; N3: TMenuItem; //-------------- popDisableAllSameSource: TMenuItem; popEnableAllSameSource: TMenuItem; popDeleteAllSameSource: TMenuItem; ToolBar1: TToolBar; ToolButtonAdd: TToolButton; ToolButtonProperties: TToolButton; ToolSep2: TToolButton; ToolButtonEnable: TToolButton; ToolButtonDisable: TToolButton; ToolButtonTrash: TToolButton; ToolSep1: TToolButton; ToolButtonEnableAll: TToolButton; ToolButtonDisableAll: TToolButton; ToolButtonTrashAll: TToolButton; procedure actAddAddressBPExecute(Sender: TObject); procedure actAddSourceBPExecute(Sender: TObject); procedure actAddWatchPointExecute(Sender: TObject); procedure actDisableSelectedExecute(Sender: TObject); procedure actEnableSelectedExecute(Sender: TObject); procedure actGroupSetNoneExecute(Sender: TObject); procedure actGroupSetNewExecute(Sender: TObject); procedure actShowExecute(Sender: TObject); procedure BreakpointsDlgCREATE(Sender: TObject); procedure lvBreakPointsClick(Sender: TObject); procedure lvBreakPointsDBLCLICK(Sender: TObject); procedure lvBreakPointsSelectItem(Sender: TObject; {%H-}Item: TListItem; {%H-}Selected: Boolean); procedure mnuPopupPopup(Sender: TObject); procedure popDeleteAllSameSourceCLICK(Sender: TObject); procedure popDisableAllSameSourceCLICK(Sender: TObject); procedure popEnableAllSameSourceCLICK(Sender: TObject); procedure popPropertiesClick(Sender: TObject); procedure popEnabledClick(Sender: TObject); procedure popDeleteClick(Sender: TObject); procedure popDisableAllClick(Sender: TObject); procedure popEnableAllClick(Sender: TObject); procedure popDeleteAllClick(Sender: TObject); private FBaseDirectory: string; FStates: TBreakPointsDlgStates; FLockActionUpdate: Integer; procedure BreakPointAdd(const {%H-}ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); procedure BreakPointUpdate(const ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); procedure BreakPointRemove(const {%H-}ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); procedure SetBaseDirectory(const AValue: string); procedure popSetGroupItemClick(Sender: TObject); procedure SetGroup(const NewGroup: TIDEBreakPointGroup); procedure UpdateItem(const AnItem: TListItem; const ABreakpoint: TIDEBreakPoint); procedure UpdateAll; procedure DeleteSelectedBreakpoints; procedure JumpToCurrentBreakPoint; procedure ShowProperties; protected procedure DoBreakPointsChanged; override; procedure DoBeginUpdate; override; procedure DoEndUpdate; override; procedure DisableAllActions; function ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean; procedure ColSizeSetter(AColId: Integer; ASize: Integer); public constructor Create(AOwner: TComponent); override; public property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; property BreakPoints; end; function GetBreakPointStateDescription(ABreakpoint: TBaseBreakpoint): string; function GetBreakPointActionsDescription(ABreakpoint: TBaseBreakpoint): string; implementation {$R *.lfm} uses LazarusIDEStrConsts, BaseDebugManager; var BreakPointDlgWindowCreator: TIDEWindowCreator; const COL_BREAK_STATE = 1; COL_BREAK_FILE = 2; COL_BREAK_LINE = 3; COL_BREAK_CONDITION = 4; COL_BREAK_ACTION = 5; COL_BREAK_PASS = 6; COL_BREAK_GROUP = 7; COL_WIDTHS: Array[0..6] of integer = ( 50, 150, 100, 75, 150, 100, 80); function BreakPointDlgColSizeGetter(AForm: TCustomForm; AColId: Integer; var ASize: Integer): Boolean; begin Result := AForm is TBreakPointsDlg; if Result then Result := TBreakPointsDlg(AForm).ColSizeGetter(AColId, ASize); end; procedure BreakPointDlgColSizeSetter(AForm: TCustomForm; AColId: Integer; ASize: Integer); begin if AForm is TBreakPointsDlg then TBreakPointsDlg(AForm).ColSizeSetter(AColId, ASize); end; function GetBreakPointStateDescription(ABreakpoint: TBaseBreakpoint): string; var DEBUG_STATE: array[Boolean, TValidState] of ShortString; begin DEBUG_STATE[false, vsUnknown]:=lisOff; DEBUG_STATE[false, vsValid]:=lisBPSDisabled; DEBUG_STATE[false, vsInvalid]:=lisInvalidOff; DEBUG_STATE[false, vsPending]:=lisInvalidOff; DEBUG_STATE[true, vsUnknown]:=lisOn; DEBUG_STATE[true, vsValid]:=lisBPSEnabled; DEBUG_STATE[true, vsInvalid]:=lisInvalidOn; DEBUG_STATE[true, vsPending]:=lisPendingOn; Result:=DEBUG_STATE[ABreakpoint.Enabled,ABreakpoint.Valid]; end; function GetBreakPointActionsDescription(ABreakpoint: TBaseBreakpoint): string; var DEBUG_ACTION: array[TIDEBreakPointAction] of ShortString; CurBreakPoint: TIDEBreakPoint; Action: TIDEBreakPointAction; begin Result := ''; DEBUG_ACTION[bpaStop]:=lisBreak; DEBUG_ACTION[bpaEnableGroup]:=lisEnableGroups; DEBUG_ACTION[bpaDisableGroup]:=lisDisableGroups; DEBUG_ACTION[bpaLogMessage]:=lisLogMessage; DEBUG_ACTION[bpaEValExpression]:=lisLogEvalExpression; DEBUG_ACTION[bpaLogCallStack]:=lisLogCallStack; DEBUG_ACTION[bpaTakeSnapshot]:=lisTakeSnapshot; if ABreakpoint is TIDEBreakPoint then begin CurBreakPoint:=TIDEBreakPoint(ABreakpoint); for Action := Low(TIDEBreakPointAction) to High(TIDEBreakPointAction) do if Action in CurBreakpoint.Actions then begin if Result <> '' then Result := Result + ', '; Result := Result + DEBUG_ACTION[Action] end; end; end; procedure TBreakPointsDlg.BreakPointAdd(const ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); var Item: TListItem; n: Integer; begin Item := lvBreakPoints.Items.FindData(ABreakpoint); if Item = nil then begin Item := lvBreakPoints.Items.Add; Item.Data := ABreakPoint; for n := 0 to 5 do Item.SubItems.Add(''); end; UpdateItem(Item, ABreakPoint); end; procedure TBreakPointsDlg.BreakPointUpdate(const ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); var Item: TListItem; begin if ABreakpoint = nil then Exit; Item := lvBreakPoints.Items.FindData(ABreakpoint); if Item = nil then BreakPointAdd(ASender, ABreakPoint) else begin if UpdateCount>0 then begin Include(FStates,bpdsItemsNeedUpdate); exit; end; UpdateItem(Item, ABreakPoint); end; end; procedure TBreakPointsDlg.BreakPointRemove(const ASender: TIDEBreakPoints; const ABreakpoint: TIDEBreakPoint); begin lvBreakPoints.Items.FindData(ABreakpoint).Free; end; procedure TBreakPointsDlg.SetBaseDirectory(const AValue: string); begin if FBaseDirectory=AValue then exit; FBaseDirectory:=AValue; UpdateAll; end; procedure TBreakPointsDlg.SetGroup(const NewGroup: TIDEBreakPointGroup); var OldGroup: TIDEBreakPointGroup; OldGroups: TList; i: Integer; PrevChoice: TModalResult; begin PrevChoice := mrNone; OldGroups := TList.Create; try for i := 0 to lvBreakPoints.Items.Count - 1 do if lvBreakPoints.Items[i].Selected then begin OldGroup := TIDEBreakPoint(lvBreakPoints.Items[i].Data).Group; TIDEBreakPoint(lvBreakPoints.Items[i].Data).Group := NewGroup; if (OldGroup <> nil) and (OldGroup.Count = 0) and (OldGroups.IndexOf(OldGroup) < 0) then OldGroups.Add(OldGroup); end; finally while OldGroups.Count > 0 do begin OldGroup := TIDEBreakPointGroup(OldGroups[0]); OldGroups.Delete(0); if not (PrevChoice in [mrYesToAll, mrNoToAll]) then begin if OldGroups.Count > 0 then PrevChoice := MessageDlg(Caption, Format(lisGroupEmptyDelete + lisGroupEmptyDeleteMore, [OldGroup.Name, LineEnding, OldGroups.Count]), mtConfirmation, mbYesNo + [mbYesToAll, mbNoToAll], 0) else PrevChoice := MessageDlg(Caption, Format(lisGroupEmptyDelete, [OldGroup.Name]), mtConfirmation, mbYesNo, 0); end; if PrevChoice in [mrYes, mrYesToAll] then OldGroup.Free; end; OldGroups.Free; end; end; constructor TBreakPointsDlg.Create(AOwner: TComponent); var i: Integer; begin inherited; Name:='BreakPointsDlg'; BreakpointsNotification.OnAdd := @BreakPointAdd; BreakpointsNotification.OnUpdate := @BreakPointUpdate; BreakpointsNotification.OnRemove := @BreakPointRemove; ActionList1.Images := IDEImages.Images_16; ToolBar1.Images := IDEImages.Images_16; mnuPopup.Images := IDEImages.Images_16; lvBreakPoints.SmallImages := IDEImages.Images_16; ToolButtonAdd.ImageIndex := IDEImages.LoadImage('laz_add'); actEnableSelected.Caption := lisDbgItemEnable; actEnableSelected.Hint := lisDbgItemEnableHint; actEnableSelected.ImageIndex := IDEImages.LoadImage('debugger_enable'); actDisableSelected.Caption := lisDbgItemDisable; actDisableSelected.Hint := lisDbgItemDisableHint; actDisableSelected.ImageIndex := IDEImages.LoadImage('debugger_disable'); actDeleteSelected.Caption := lisBtnDelete; actDeleteSelected.Hint := lisDbgItemDeleteHint; actDeleteSelected.ImageIndex := IDEImages.LoadImage('laz_delete'); actEnableAll.Caption := lisEnableAll; actEnableAll.Hint := lisDbgAllItemEnableHint; actEnableAll.ImageIndex := IDEImages.LoadImage('debugger_enable_all'); actDisableAll.Caption := liswlDIsableAll; actDisableAll.Hint := lisDbgAllItemDisableHint; actDisableAll.ImageIndex := IDEImages.LoadImage('debugger_disable_all'); actDeleteAll.Caption := lisDeleteAll; actDeleteAll.Hint := lisDbgAllItemDeleteHint; actDeleteAll.ImageIndex := IDEImages.LoadImage('menu_clean'); actProperties.Caption:= liswlProperties; actProperties.Hint := lisDbgBreakpointPropertiesHint; actProperties.ImageIndex := IDEImages.LoadImage('menu_environment_options'); actToggleCurrentEnable.Caption:= lisBtnEnabled; actEnableAllInSrc.Caption:= lisEnableAllInSameSource; actDisableAllInSrc.Caption:= lisDisableAllInSameSource; actDeleteAllInSrc.Caption:= lisDeleteAllInSameSource; for i := low(COL_WIDTHS) to high(COL_WIDTHS) do lvBreakPoints.Column[i].Width := COL_WIDTHS[i]; FLockActionUpdate := 0; end; procedure TBreakPointsDlg.BreakpointsDlgCREATE(Sender: TObject); begin Caption:= lisMenuViewBreakPoints; lvBreakPoints.Align:=alClient; lvBreakPoints.Columns[0].Caption:= lisOIPState; lvBreakPoints.Columns[1].Caption:= lisFilenameAddress; lvBreakPoints.Columns[2].Caption:= lisLineLength; lvBreakPoints.Columns[3].Caption:= lisCondition; lvBreakPoints.Columns[4].Caption:= lisLazBuildABOAction; lvBreakPoints.Columns[5].Caption:= lisPassCount; lvBreakPoints.Columns[6].Caption:= lisGroup; actShow.Caption := lisViewSource; popAdd.Caption:= lisAdd; actAddSourceBP.Caption := lisSourceBreakpoint; actAddAddressBP.Caption := lisAddressBreakpoint; actAddWatchPoint.Caption := lisWatchPoint; popGroup.Caption := lisGroup; actGroupSetNew.Caption := lisGroupSetNew; actGroupSetNone.Caption := lisGroupSetNone; end; procedure TBreakPointsDlg.actEnableSelectedExecute(Sender: TObject); var n: Integer; Item: TListItem; begin try DisableAllActions; for n := 0 to lvBreakPoints.Items.Count -1 do begin Item := lvBreakPoints.Items[n]; if Item.Selected then TIDEBreakPoint(Item.Data).Enabled := True; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.actGroupSetNewExecute(Sender: TObject); var GroupName: String; NewGroup: TIDEBreakPointGroup; begin GroupName := ''; if not InputQuery(Caption, lisGroupNameInput, GroupName) then Exit; if GroupName = '' then begin if MessageDlg(Caption, lisGroupNameEmptyClearInstead, mtConfirmation, mbYesNo, 0) = mrYes then Exit; NewGroup := nil; end else begin NewGroup := DebugBoss.BreakPointGroups.GetGroupByName(GroupName); if NewGroup = nil then begin if not TIDEBreakPointGroup.CheckName(GroupName) then begin MessageDlg(Caption, lisGroupNameInvalid, mtError, [mbOk], 0); Exit; end; NewGroup := TIDEBreakPointGroup(DebugBoss.BreakPointGroups.Add); try NewGroup.Name := GroupName; except NewGroup.Free; raise; end; end else if MessageDlg(Caption, Format(lisGroupAssignExisting, [GroupName]), mtConfirmation, mbYesNo, 0) <> mrYes then Exit; end; SetGroup(NewGroup); end; procedure TBreakPointsDlg.actGroupSetNoneExecute(Sender: TObject); begin SetGroup(nil); end; procedure TBreakPointsDlg.popSetGroupItemClick(Sender: TObject); var Group: TIDEBreakPointGroup; begin Group := DebugBoss.BreakPointGroups.GetGroupByName((Sender as TMenuItem).Caption); if Group = nil then raise Exception.CreateFmt('Group %s not found', [(Sender as TMenuItem).Caption]); SetGroup(Group); end; procedure TBreakPointsDlg.actShowExecute(Sender: TObject); begin JumpToCurrentBreakPoint; end; procedure TBreakPointsDlg.actDisableSelectedExecute(Sender: TObject); var n: Integer; Item: TListItem; begin try DisableAllActions; for n := 0 to lvBreakPoints.Items.Count -1 do begin Item := lvBreakPoints.Items[n]; if Item.Selected then TIDEBreakPoint(Item.Data).Enabled := False; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.actAddSourceBPExecute(Sender: TObject); var NewBreakpoint: TIDEBreakPoint; SrcEdit: TSourceEditor; begin SrcEdit := SourceEditorManager.GetActiveSE; if SrcEdit <> nil then NewBreakpoint := BreakPoints.Add(SrcEdit.FileName, SrcEdit.CurrentCursorYLine, True) else NewBreakpoint := BreakPoints.Add('', 0, True); if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then begin NewBreakpoint.EndUpdate; UpdateAll; end else ReleaseRefAndNil(NewBreakpoint); end; procedure TBreakPointsDlg.actAddWatchPointExecute(Sender: TObject); var NewBreakpoint: TIDEBreakPoint; begin NewBreakpoint := BreakPoints.Add('', wpsGlobal, wpkWrite, True); if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then begin NewBreakpoint.EndUpdate; UpdateAll; end else ReleaseRefAndNil(NewBreakpoint); end; procedure TBreakPointsDlg.actAddAddressBPExecute(Sender: TObject); var NewBreakpoint: TIDEBreakPoint; begin NewBreakpoint := BreakPoints.Add(0, True); if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then begin NewBreakpoint.EndUpdate; UpdateAll; end else ReleaseRefAndNil(NewBreakpoint); end; procedure TBreakPointsDlg.lvBreakPointsClick(Sender: TObject); begin lvBreakPointsSelectItem(nil, nil, False); end; procedure TBreakPointsDlg.lvBreakPointsDBLCLICK(Sender: TObject); begin lvBreakPointsSelectItem(nil, nil, False); JumpToCurrentBreakPoint; end; procedure TBreakPointsDlg.lvBreakPointsSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); var ItemSelected: Boolean; SelCanEnable, SelCanDisable: Boolean; AllCanEnable, AllCanDisable: Boolean; CurBreakPoint: TIDEBreakPoint; i: Integer; begin if FLockActionUpdate > 0 then exit; ItemSelected := lvBreakPoints.Selected <> nil; if ItemSelected then CurBreakPoint := TIDEBreakPoint(lvBreakPoints.Selected.Data) else CurBreakPoint := nil; SelCanEnable := False; SelCanDisable := False; AllCanEnable := False; allCanDisable := False; for i := 0 to lvBreakPoints.Items.Count - 1 do begin if lvBreakPoints.Items[i].Data = nil then continue; if lvBreakPoints.Items[i].Selected then begin SelCanEnable := SelCanEnable or not TIDEBreakPoint(lvBreakPoints.Items[i].Data).Enabled; SelCanDisable := SelCanDisable or TIDEBreakPoint(lvBreakPoints.Items[i].Data).Enabled; end; AllCanEnable := AllCanEnable or not TIDEBreakPoint(lvBreakPoints.Items[i].Data).Enabled; AllCanDisable := AllCanDisable or TIDEBreakPoint(lvBreakPoints.Items[i].Data).Enabled; end; actToggleCurrentEnable.Enabled := ItemSelected; actToggleCurrentEnable.Checked := (CurBreakPoint <> nil) and CurBreakPoint.Enabled; actEnableSelected.Enabled := SelCanEnable; actDisableSelected.Enabled := SelCanDisable; actDeleteSelected.Enabled := ItemSelected; actEnableAll.Enabled := AllCanEnable; actDisableAll.Enabled := AllCanDisable; actDeleteAll.Enabled := lvBreakPoints.Items.Count > 0; actEnableAllInSrc.Enabled := ItemSelected; actDisableAllInSrc.Enabled := ItemSelected; actDeleteAllInSrc.Enabled := ItemSelected; actProperties.Enabled := ItemSelected; actShow.Enabled := ItemSelected; popGroup.Enabled := ItemSelected; actGroupSetNew.Enabled := ItemSelected; actGroupSetNone.Enabled := ItemSelected; end; procedure TBreakPointsDlg.mnuPopupPopup(Sender: TObject); var i: Integer; MenuItem: TMenuItem; begin for i := popGroup.Count - 1 downto popGroup.IndexOf(popGroupSep) +1 do popGroup.Items[i].Free; for i := 0 to DebugBoss.BreakPointGroups.Count - 1 do begin MenuItem := TMenuItem.Create(popGroup); MenuItem.Caption := DebugBoss.BreakPointGroups[i].Name; MenuItem.OnClick := @popSetGroupItemClick; popGroup.Add(MenuItem); end; popGroupSep.Visible := DebugBoss.BreakPointGroups.Count <> 0; end; procedure TBreakPointsDlg.popDeleteAllSameSourceCLICK(Sender: TObject); var n: Integer; Item: TListItem; CurItem: TListItem; CurBreakPoint: TIDEBreakPoint; Filename: String; begin try DisableAllActions; CurItem:=lvBreakPoints.Selected; if (CurItem=nil) then exit; Filename:=TIDEBreakpoint(CurItem.Data).Source; if MessageDlg(lisDeleteAllBreakpoints, Format(lisDeleteAllBreakpoints2, [Filename]), mtConfirmation,[mbYes,mbCancel],0)<>mrYes then exit; for n := lvBreakPoints.Items.Count - 1 downto 0 do begin Item := lvBreakPoints.Items[n]; CurBreakPoint:=TIDEBreakPoint(Item.Data); if CompareFilenames(CurBreakPoint.Source,Filename)=0 then ReleaseRefAndNil(CurBreakPoint); end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popDisableAllSameSourceCLICK(Sender: TObject); var n: Integer; Item: TListItem; CurItem: TListItem; CurBreakPoint: TIDEBreakPoint; Filename: String; begin try DisableAllActions; CurItem:=lvBreakPoints.Selected; if (CurItem=nil) then exit; Filename:=TIDEBreakpoint(CurItem.Data).Source; for n := 0 to lvBreakPoints.Items.Count - 1 do begin Item := lvBreakPoints.Items[n]; CurBreakPoint:=TIDEBreakPoint(Item.Data); if CompareFilenames(CurBreakPoint.Source,Filename)=0 then CurBreakPoint.Enabled := False; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popEnableAllSameSourceCLICK(Sender: TObject); var n: Integer; Item: TListItem; CurItem: TListItem; CurBreakPoint: TIDEBreakPoint; Filename: String; begin try DisableAllActions; CurItem:=lvBreakPoints.Selected; if (CurItem=nil) then exit; Filename:=TIDEBreakpoint(CurItem.Data).Source; for n := 0 to lvBreakPoints.Items.Count - 1 do begin Item := lvBreakPoints.Items[n]; CurBreakPoint:=TIDEBreakPoint(Item.Data); if CompareFilenames(CurBreakPoint.Source,Filename)=0 then CurBreakPoint.Enabled := True; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popDeleteAllClick(Sender: TObject); var n: Integer; begin try DisableAllActions; if MessageDlg(lisDeleteAllBreakpoints, lisDeleteAllBreakpoints, mtConfirmation,[mbYes,mbCancel],0)<>mrYes then exit; lvBreakPoints.BeginUpdate; try for n := lvBreakPoints.Items.Count - 1 downto 0 do TIDEBreakPoint(lvBreakPoints.Items[n].Data).ReleaseReference; finally lvBreakPoints.EndUpdate; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popDeleteClick(Sender: TObject); begin try DisableAllActions; DeleteSelectedBreakpoints; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popDisableAllClick(Sender: TObject); var n: Integer; Item: TListItem; begin try DisableAllActions; for n := 0 to lvBreakPoints.Items.Count - 1 do begin Item := lvBreakPoints.Items[n]; if Item.Data <> nil then TIDEBreakPoint(Item.Data).Enabled := False; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popEnableAllClick(Sender: TObject); var n: Integer; Item: TListItem; begin try DisableAllActions; for n := 0 to lvBreakPoints.Items.Count - 1 do begin Item := lvBreakPoints.Items[n]; if Item.Data <> nil then TIDEBreakPoint(Item.Data).Enabled := True; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popEnabledClick(Sender: TObject); var n: Integer; Item: TListItem; Enable: Boolean; begin try DisableAllActions; Item:=lvBreakPoints.Selected; if (Item=nil) then exit; Enable := not TIDEBreakPoint(Item.Data).Enabled; if lvBreakPoints.SelCount > 1 then begin for n := 0 to lvBreakPoints.Items.Count -1 do begin Item := lvBreakPoints.Items[n]; if Item.Selected then TIDEBreakPoint(Item.Data).Enabled := Enable; end; end else begin TIDEBreakPoint(Item.Data).Enabled:= Enable; end; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.popPropertiesClick(Sender: TObject); begin try DisableAllActions; ShowProperties; finally lvBreakPointsSelectItem(nil, nil, False); end; end; procedure TBreakPointsDlg.DoEndUpdate; begin inherited DoEndUpdate; if bpdsItemsNeedUpdate in FStates then UpdateAll; lvBreakPointsSelectItem(nil, nil, False); end; procedure TBreakPointsDlg.DisableAllActions; var i: Integer; begin for i := 0 to ActionList1.ActionCount - 1 do (ActionList1.Actions[i] as TAction).Enabled := False; actAddSourceBP.Enabled := True; actAddAddressBP.Enabled := True; actAddWatchPoint.Enabled := True; end; function TBreakPointsDlg.ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean; begin if (AColId - 1 >= 0) and (AColId - 1 < lvBreakPoints.ColumnCount) then begin ASize := lvBreakPoints.Column[AColId - 1].Width; Result := ASize <> COL_WIDTHS[AColId - 1]; end else Result := False; end; procedure TBreakPointsDlg.ColSizeSetter(AColId: Integer; ASize: Integer); begin case AColId of COL_BREAK_STATE: lvBreakPoints.Column[0].Width := ASize; COL_BREAK_FILE: lvBreakPoints.Column[1].Width := ASize; COL_BREAK_LINE: lvBreakPoints.Column[2].Width := ASize; COL_BREAK_CONDITION: lvBreakPoints.Column[3].Width := ASize; COL_BREAK_ACTION: lvBreakPoints.Column[4].Width := ASize; COL_BREAK_PASS: lvBreakPoints.Column[5].Width := ASize; COL_BREAK_GROUP: lvBreakPoints.Column[6].Width := ASize; end; end; procedure TBreakPointsDlg.UpdateItem(const AnItem: TListItem; const ABreakpoint: TIDEBreakPoint); var s, Filename: String; begin // Filename/Address // Line/Length // Condition // Action // Pass Count // Group // state AnItem.Caption := GetBreakPointStateDescription(ABreakpoint); AnItem.ImageIndex := GetBreakPointImageIndex(ABreakpoint); // filename/address case ABreakpoint.Kind of bpkSource: begin Filename:=ABreakpoint.Source; if BaseDirectory<>'' then Filename:=CreateRelativePath(Filename,BaseDirectory); AnItem.SubItems[0] := Filename; // line if ABreakpoint.Line > 0 then AnItem.SubItems[1] := IntToStr(ABreakpoint.Line) else AnItem.SubItems[1] := ''; end; bpkAddress: begin // todo: how to define digits count? 8 or 16 depends on gdb pointer size for platform AnItem.SubItems[0] := '$' + IntToHex(ABreakpoint.Address, 8); end; bpkData: begin AnItem.SubItems[0] := ABreakpoint.WatchData; case ABreakpoint.WatchScope of wpsGlobal: s:= lisWatchScopeGlobal; wpsLocal: s:= lisWatchScopeLocal; else s := ''; end; s := s +' / '; case ABreakpoint.WatchKind of wpkRead: s := s + lisWatchKindRead; wpkReadWrite: s := s + lisWatchKindReadWrite; wpkWrite: s := s + lisWatchKindWrite; end; AnItem.SubItems[1] := s; end; end; // expression AnItem.SubItems[2] := ABreakpoint.Expression; // actions AnItem.SubItems[3] := GetBreakPointActionsDescription(ABreakpoint); // hitcount AnItem.SubItems[4] := IntToStr(ABreakpoint.HitCount); // group if ABreakpoint.Group = nil then AnItem.SubItems[5] := '' else AnItem.SubItems[5] := ABreakpoint.Group.Name; lvBreakPointsSelectItem(nil, nil, False); end; procedure TBreakPointsDlg.UpdateAll; var i: Integer; CurItem: TListItem; begin if UpdateCount>0 then begin Include(FStates,bpdsItemsNeedUpdate); exit; end; Exclude(FStates,bpdsItemsNeedUpdate); inc(FLockActionUpdate); for i:=0 to lvBreakPoints.Items.Count-1 do begin CurItem:=lvBreakPoints.Items[i]; UpdateItem(CurItem,TIDEBreakPoint(CurItem.Data)); end; dec(FLockActionUpdate); lvBreakPointsSelectItem(nil, nil, False); end; procedure TBreakPointsDlg.DeleteSelectedBreakpoints; var Item: TListItem; CurBreakPoint: TIDEBreakPoint; Msg: String; List: TList; n, Idx: Integer; begin Idx := lvBreakPoints.ItemIndex; Item:=lvBreakPoints.Selected; if Item = nil then exit; if lvBreakPoints.SelCount = 1 then begin CurBreakPoint:=TIDEBreakPoint(Item.Data); case CurBreakPoint.Kind of bpkSource: Msg := Format(lisDeleteBreakpointAtLine, [LineEnding, CurBreakPoint.Source, CurBreakPoint.Line]); bpkAddress: Msg := Format(lisDeleteBreakpointForAddress, ['$' + IntToHex(CurBreakPoint.Address, 8)]); bpkData: Msg := Format(lisDeleteBreakpointForWatch, [CurBreakPoint.WatchData]); end; end else Msg := lisDeleteAllSelectedBreakpoints; if MessageDlg(Msg, mtConfirmation, [mbYes,mbCancel],0) <> mrYes then exit; if lvBreakPoints.SelCount = 1 then begin TBaseBreakPoint(Item.Data).ReleaseReference; end else begin List := TList.Create; for n := 0 to lvBreakPoints.Items.Count - 1 do begin Item := lvBreakPoints.Items[n]; if Item.Selected then List.Add(Item.Data); end; lvBreakPoints.BeginUpdate; try for n := 0 to List.Count - 1 do TBaseBreakPoint(List[n]).ReleaseReference; finally lvBreakPoints.EndUpdate; end; List.Free; end; if Idx > lvBreakPoints.Items.Count - 1 then Idx := lvBreakPoints.Items.Count - 1; if Idx >= 0 then lvBreakPoints.ItemIndex := Idx; end; procedure TBreakPointsDlg.JumpToCurrentBreakPoint; var CurItem: TListItem; CurBreakPoint: TIDEBreakPoint; begin CurItem:=lvBreakPoints.Selected; if CurItem=nil then exit; CurBreakPoint:=TIDEBreakPoint(CurItem.Data); if CurBreakPoint.Kind = bpkSource then MainIDE.DoJumpToSourcePosition(CurBreakPoint.Source, 0, CurBreakPoint.Line, 0, [jfAddJumpPoint, jfFocusEditor, jfMarkLine, jfSearchVirtualFullPath]); end; procedure TBreakPointsDlg.ShowProperties; var Item: TListItem; CurBreakPoint: TIDEBreakPoint; begin Item:=lvBreakPoints.Selected; if Item = nil then exit; CurBreakPoint:=TIDEBreakPoint(Item.Data); DebugBoss.ShowBreakPointProperties(CurBreakPoint); end; procedure TBreakPointsDlg.DoBreakPointsChanged; var i: Integer; begin lvBreakPoints.Items.Clear; if BreakPoints <> nil then begin for i:=0 to BreakPoints.Count-1 do BreakPointUpdate(BreakPoints, BreakPoints.Items[i]); end; end; procedure TBreakPointsDlg.DoBeginUpdate; begin inherited DoBeginUpdate; DisableAllActions; end; initialization BreakPointDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtBreakpoints]); BreakPointDlgWindowCreator.OnCreateFormProc := @CreateDebugDialog; BreakPointDlgWindowCreator.OnSetDividerSize := @BreakPointDlgColSizeSetter; BreakPointDlgWindowCreator.OnGetDividerSize := @BreakPointDlgColSizeGetter; BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakState', COL_BREAK_STATE, @drsColWidthState); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakFile', COL_BREAK_FILE, @drsBreakPointColWidthFile); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakLine', COL_BREAK_LINE, @drsBreakPointColWidthLine); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakCondition', COL_BREAK_CONDITION, @drsBreakPointColWidthCondition); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakAction', COL_BREAK_ACTION, @drsBreakPointColWidthAction); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakPassCnt', COL_BREAK_PASS, @drsBreakPointColWidthPassCount); BreakPointDlgWindowCreator.DividerTemplate.Add('ColumnBreakGroup', COL_BREAK_GROUP, @drsBreakPointColWidthGroup); BreakPointDlgWindowCreator.CreateSimpleLayout; end.