SpkToolbar: Fix crash when a popupmenu used by a button is destroyed.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8962 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-10-13 20:53:27 +00:00
parent a36b768a64
commit 6be867b8cd
7 changed files with 108 additions and 48 deletions

View File

@ -1166,6 +1166,7 @@ var
Tab: TSpkTab; Tab: TSpkTab;
Pane: TSpkPane; Pane: TSpkPane;
Item: TSpkBaseItem; Item: TSpkBaseItem;
i: Integer;
begin begin
inherited; inherited;
@ -1195,7 +1196,24 @@ begin
Pane := Item.Parent as TSpkPane; Pane := Item.Parent as TSpkPane;
Pane.FreeingItem(Item); Pane.FreeingItem(Item);
end; end;
end; end else
if AComponent is TCustomImageList then
begin
if AComponent = DisabledImages then
DisabledImages := nil;
if AComponent = DisabledLargeImages then
DisabledLargeImages := nil;
if AComponent = Images then
Images := nil;
if AComponent = LargeImages then
LargeImages := nil;
end else
if AComponent = FMenuButtonDropDownMenu then
FMenuButtonDropDownMenu := nil;
// Remove DropdownMenu from button items.
if AComponent is TPopupMenu then
Tabs.Notify(AComponent, Operation);
end; end;
procedure TSpkToolbar.NotifyAppearanceChanged; procedure TSpkToolbar.NotifyAppearanceChanged;

View File

@ -68,6 +68,8 @@ type
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); virtual; abstract; X, Y: Integer); virtual; abstract;
procedure Notify(Item: TComponent; Operation: TOperation); virtual; abstract;
function GetWidth: integer; virtual; abstract; function GetWidth: integer; virtual; abstract;
function GetTableBehaviour: TSpkItemTableBehaviour; virtual; abstract; function GetTableBehaviour: TSpkItemTableBehaviour; virtual; abstract;
function GetGroupBehaviour: TSpkItemGroupBehaviour; virtual; abstract; function GetGroupBehaviour: TSpkItemGroupBehaviour; virtual; abstract;

View File

@ -15,7 +15,7 @@ unit spkt_Buttons;
interface interface
uses uses LazLoggerBase,
Graphics, Classes, Types, Controls, Menus, ActnList, Math, Graphics, Classes, Types, Controls, Menus, ActnList, Math,
Dialogs, ImgList, Forms, Dialogs, ImgList, Forms,
SpkGUITools, SpkGraphTools, SpkMath, SpkGUITools, SpkGraphTools, SpkMath,
@ -127,6 +127,7 @@ type
function GetRootComponent: TComponent; function GetRootComponent: TComponent;
function IsRightToLeft: Boolean; function IsRightToLeft: Boolean;
procedure Notify(Item: TComponent; Operation: TOperation); override;
property ActionLink: TSpkButtonActionLink read FActionLink; property ActionLink: TSpkButtonActionLink read FActionLink;
property Checked: Boolean read GetChecked write SetChecked default false; property Checked: Boolean read GetChecked write SetChecked default false;
@ -528,6 +529,15 @@ begin
Result := (GetRootComponent as TControl).IsRightToLeft; Result := (GetRootComponent as TControl).IsRightToLeft;
end; end;
procedure TSpkBaseButton.Notify(Item: TComponent; Operation: TOperation);
begin
if (Operation = opRemove) and (Item = FDropDownMenu) then
begin
DropDownMenu := nil;
DebugLn('[TSpkBaseButton.Notify] Button "' + caption + '" removed ' + Item.ClassName);
end;
end;
procedure TSpkBaseButton.MouseDown(Button: TMouseButton; Shift: TShiftState; procedure TSpkBaseButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); X, Y: Integer);
begin begin

View File

@ -15,7 +15,7 @@ unit spkt_Items;
interface interface
uses uses LazLoggerBase,
Classes, Controls, SysUtils, Dialogs, Classes, Controls, SysUtils, Dialogs,
spkt_Appearance, spkt_Dispatch, spkt_BaseItem, spkt_Types, spkt_Appearance, spkt_Dispatch, spkt_BaseItem, spkt_Types,
spkt_Buttons, spkt_Checkboxes; spkt_Buttons, spkt_Checkboxes;
@ -102,11 +102,17 @@ begin
end; end;
procedure TSpkItems.Notify(Item: TComponent; Operation: TOperation); procedure TSpkItems.Notify(Item: TComponent; Operation: TOperation);
var
i: Integer;
baseItem: TSpkBaseItem;
begin begin
inherited Notify(Item, Operation); inherited Notify(Item, Operation);
DebugLn('[TSpkItems.Notify] Removing ' + Item.ClassName);
case Operation of case Operation of
opInsert: opInsert:
if Item is TSpkBaseItem then
begin begin
// Setting the dispatcher to nil will cause that during the ownership // Setting the dispatcher to nil will cause that during the ownership
// assignment, the Notify method will not be called // assignment, the Notify method will not be called
@ -122,17 +128,23 @@ begin
end; end;
opRemove: opRemove:
if not (csDestroying in Item.ComponentState) then if Item is TSpkBaseItem then
begin begin
TSpkBaseItem(Item).ToolbarDispatch := nil; if not (csDestroying in Item.ComponentState) then
TSpkBaseItem(Item).Appearance := nil; begin
TSpkBaseItem(Item).Images := nil; TSpkBaseItem(Item).ToolbarDispatch := nil;
TSpkBaseItem(Item).DisabledImages := nil; TSpkBaseItem(Item).Appearance := nil;
TSpkBaseItem(Item).LargeImages := nil; TSpkBaseItem(Item).Images := nil;
TSpkBaseItem(Item).DisabledLargeImages := nil; TSpkBaseItem(Item).DisabledImages := nil;
// TSpkBaseitem(Item).ImagesWidth := 0; TSpkBaseItem(Item).LargeImages := nil;
// TSpkBaseItem(Item).LargeImagesWidth := 0; TSpkBaseItem(Item).DisabledLargeImages := nil;
end; end;
end else
for i := 0 to Count-1 do
begin
baseItem := Items[i];
baseItem.Notify(Item, Operation);
end;
end; end;
end; end;

View File

@ -15,7 +15,7 @@ unit spkt_Pane;
interface interface
uses uses LazLoggerBase,
Graphics, Controls, Classes, SysUtils, Math, Dialogs, Graphics, Controls, Classes, SysUtils, Math, Dialogs,
SpkGraphTools, SpkGUITools, SpkMath, SpkGraphTools, SpkGUITools, SpkMath,
spkt_Appearance, spkt_Const, spkt_Dispatch, spkt_Exceptions, spkt_Appearance, spkt_Const, spkt_Dispatch, spkt_Exceptions,
@ -172,7 +172,7 @@ type
function Add: TSpkPane; function Add: TSpkPane;
function Insert(AIndex: integer): TSpkPane; function Insert(AIndex: integer): TSpkPane;
// *** Reaction to changes in the list *** // *** Reaction to changes ***
procedure Notify(Item: TComponent; Operation: TOperation); override; procedure Notify(Item: TComponent; Operation: TOperation); override;
procedure Update; override; procedure Update; override;
@ -398,11 +398,11 @@ begin
// Pane label // Pane label
ABuffer.Canvas.Font.Assign(FAppearance.Pane.CaptionFont); ABuffer.Canvas.Font.Assign(FAppearance.Pane.CaptionFont);
w := ABuffer.Canvas.TextWidth(FCaption); // Panel label width
// Handle visibility of 'More options' button to set Pane label pos // Handle visibility of 'More options' button to set Pane label position
if FShowMoreOptionsButton then if FShowMoreOptionsButton then
begin begin
w := ABuffer.Canvas.TextWidth(FCaption);
if isRTL then if isRTL then
x := FRect.Right - (FRect.Width - PaneMoreOptionsButtonWidth - w) div 2 - w x := FRect.Right - (FRect.Width - PaneMoreOptionsButtonWidth - w) div 2 - w
else else
@ -1347,10 +1347,16 @@ begin
end; end;
procedure TSpkPanes.Notify(Item: TComponent; Operation: TOperation); procedure TSpkPanes.Notify(Item: TComponent; Operation: TOperation);
var
i: Integer;
pane: TSpkPane;
begin begin
inherited Notify(Item, Operation); inherited Notify(Item, Operation);
DebugLn('[TSpkPanes.Notify] Removing ' + Item.ClassName);
case Operation of case Operation of
opInsert: opInsert:
if Item is TSpkPane then
begin begin
// Setting the dispatcher to nil will cause that during the // Setting the dispatcher to nil will cause that during the
// ownership assignment, the Notify method will not be called // ownership assignment, the Notify method will not be called
@ -1365,17 +1371,24 @@ begin
TSpkPane(Item).ToolbarDispatch := FToolbarDispatch; TSpkPane(Item).ToolbarDispatch := FToolbarDispatch;
end; end;
opRemove: opRemove:
if not(csDestroying in Item.ComponentState) then if Item is TSpkPane then
begin begin
TSpkPane(Item).ToolbarDispatch := nil; if not(csDestroying in Item.ComponentState) then
TSpkPane(Item).Appearance := nil; begin
TSpkPane(Item).Images := nil; TSpkPane(Item).ToolbarDispatch := nil;
TSpkPane(Item).DisabledImages := nil; TSpkPane(Item).Appearance := nil;
TSpkPane(Item).LargeImages := nil; TSpkPane(Item).Images := nil;
TSpkPane(Item).DisabledLargeImages := nil; TSpkPane(Item).DisabledImages := nil;
// TSpkPane(Item).ImagesWidth := 0; TSpkPane(Item).LargeImages := nil;
// TSpkPane(Item).LargeImagesWidth := 0; TSpkPane(Item).DisabledLargeImages := nil;
end; end;
end else
for i := 0 to Count-1 do
begin
pane := Items[i];
DebugLn(['pane ', pane.Caption]);
pane.Items.Notify(Item, Operation);
end;
end; end;
end; end;

View File

@ -20,7 +20,7 @@ unit spkt_Tab;
interface interface
uses uses LazLoggerBase,
Graphics, Controls, Classes, SysUtils, Math, Graphics, Controls, Classes, SysUtils, Math,
SpkMath, SpkMath,
spkt_Appearance, spkt_Const, spkt_Dispatch, spkt_Exceptions, spkt_Appearance, spkt_Const, spkt_Dispatch, spkt_Exceptions,
@ -686,11 +686,17 @@ begin
end; end;
procedure TSpkTabs.Notify(Item: TComponent; Operation: TOperation); procedure TSpkTabs.Notify(Item: TComponent; Operation: TOperation);
var
i: Integer;
tab: TSpkTab;
begin begin
inherited Notify(Item, Operation); inherited Notify(Item, Operation);
DebugLn('[TSpkTabs.Notify] Removing ' + Item.ClassName);
case Operation of case Operation of
opInsert: opInsert:
if Item is TSpkTab then
begin begin
// Setting the dispatcher to nil will cause that during the // Setting the dispatcher to nil will cause that during the
// ownership assignment, the Notify method will not be called // ownership assignment, the Notify method will not be called
@ -705,17 +711,23 @@ begin
TSpkTab(Item).ToolbarDispatch := self.FToolbarDispatch; TSpkTab(Item).ToolbarDispatch := self.FToolbarDispatch;
end; end;
opRemove: opRemove:
if not(csDestroying in Item.ComponentState) then if (Item is TSpkTab) then
begin begin
TSpkTab(Item).ToolbarDispatch := nil; if not(csDestroying in Item.ComponentState) then
TSpkTab(Item).Appearance := nil; begin
TSpkTab(Item).Images := nil; TSpkTab(Item).ToolbarDispatch := nil;
TSpkTab(Item).DisabledImages := nil; TSpkTab(Item).Appearance := nil;
TSpkTab(Item).LargeImages := nil; TSpkTab(Item).Images := nil;
TSpkTab(Item).DisabledLargeImages := nil; TSpkTab(Item).DisabledImages := nil;
// TSpkTab(Item).ImagesWidth := 0; TSpkTab(Item).LargeImages := nil;
// TSpkTab(Item).LargeImagesWidth := 0; TSpkTab(Item).DisabledLargeImages := nil;
end; end;
end else
for i := 0 to Count-1 do
begin
tab := Items[i];
tab.Panes.Notify(Item, Operation);
end;
end; end;
end; end;

View File

@ -28,24 +28,19 @@ type
FListState: TSpkListState; FListState: TSpkListState;
FRootComponent: TComponent; FRootComponent: TComponent;
// *** Metody reakcji na zmiany w liœcie *** // *** Methods responding to changes ***
// *** Methods responding to changes in list ***
procedure Notify({%H-}Item: TComponent; {%H-}Operation: TOperation); virtual; procedure Notify({%H-}Item: TComponent; {%H-}Operation: TOperation); virtual;
procedure Update; virtual; procedure Update; virtual;
// *** Wewnêtrzne metody dodawania i wstawiania elementów ***
// *** Gettery i settery ***
// *** Internal methods for adding and inserting elements *** // *** Internal methods for adding and inserting elements ***
// *** Getters and setters *** // *** Getters and setters ***
function GetItems(AIndex: integer): TComponent; virtual; function GetItems(AIndex: integer): TComponent; virtual;
public public
// *** Konstruktor, destruktor *** // *** Constructor, destructor ***
constructor Create(ARootComponent : TComponent); reintroduce; virtual; constructor Create(ARootComponent : TComponent); reintroduce; virtual;
destructor Destroy; override; destructor Destroy; override;
// *** Obs³uga listy ***
// *** List operations *** // *** List operations ***
procedure AddItem(AItem: TComponent); procedure AddItem(AItem: TComponent);
procedure InsertItem(AIndex: integer; AItem: TComponent); procedure InsertItem(AIndex: integer; AItem: TComponent);
@ -58,8 +53,7 @@ type
procedure Exchange(item1, item2: integer); procedure Exchange(item1, item2: integer);
procedure Move(IndexFrom, IndexTo: integer); procedure Move(IndexFrom, IndexTo: integer);
// *** Reader, writer i obs³uga designtime i DFM *** // *** Reader, writer and operation designtime and DFM/LFM
// *** Reader, writer and operation designtime and DFM
procedure WriteNames(Writer: TWriter); virtual; procedure WriteNames(Writer: TWriter); virtual;
procedure ReadNames(Reader: TReader); virtual; procedure ReadNames(Reader: TReader); virtual;
procedure ProcessNames(Owner: TComponent); virtual; procedure ProcessNames(Owner: TComponent); virtual;
@ -74,7 +68,6 @@ type
FParent: TComponent; FParent: TComponent;
FCollection: TSpkCollection; FCollection: TSpkCollection;
public public
// *** Obs³uga parenta ***
// *** Parent operations *** // *** Parent operations ***
function HasParent: boolean; override; function HasParent: boolean; override;
function GetParentComponent: TComponent; override; function GetParentComponent: TComponent; override;