From b7d9e2f8494fd2f9a130ac81df5d1b580713d0cd Mon Sep 17 00:00:00 2001 From: Sir Rufo Date: Thu, 17 Apr 2025 18:45:23 +0200 Subject: [PATCH 1/3] remove all hacks --- Src/FmMain.pas | 20 ---------------- Src/FrOverview.dfm | 4 ++-- Src/FrOverview.pas | 52 ----------------------------------------- Src/IntfFrameMgrs.pas | 3 --- Src/UMainDisplayMgr.pas | 28 ---------------------- 5 files changed, 2 insertions(+), 105 deletions(-) diff --git a/Src/FmMain.pas b/Src/FmMain.pas index 8bffbe2b8..770455f0e 100644 --- a/Src/FmMain.pas +++ b/Src/FmMain.pas @@ -522,12 +522,6 @@ TMainForm = class(THelpAwareForm) /// Object that manages favourites. fFavouritesMgr: TFavouritesManager; - /// Handles the WM_POWERBROADCAST messages to detect and - /// respond to hibernation messages. - /// !! HACK necessary as part of the fix for an obscure bug. See - /// https://github.com/delphidabbler/codesnip/issues/70 - procedure WMPowerBroadcast(var Msg: TMessage); message WM_POWERBROADCAST; - /// Displays view item given by TViewItemAction instance /// referenced by Sender and adds to history list. procedure ActViewItemExecute(Sender: TObject); @@ -1586,19 +1580,5 @@ procedure TMainForm.splitVertCanResize(Sender: TObject; Accept := False; end; -procedure TMainForm.WMPowerBroadcast(var Msg: TMessage); -begin - // !! HACK - // Sometimes when the computer is resumed from hibernation the tree view in - // the overview frame is destroyed and recreated by Windows. Unfortunately the - // IView instances associated with the recreated tree nodes are lost. - // Attempting to read those (now nil) IView instances was resulting in an - // access violation. - case Msg.WParam of - PBT_APMSUSPEND: - fMainDisplayMgr._HACK_PrepareForHibernate; - end; -end; - end. diff --git a/Src/FrOverview.dfm b/Src/FrOverview.dfm index 159f3cddc..b47989bbd 100644 --- a/Src/FrOverview.dfm +++ b/Src/FrOverview.dfm @@ -1,9 +1,9 @@ inherited OverviewFrame: TOverviewFrame inherited pnlTitle: TPanel inherited lblTitle: TLabel - Width = 54 + Width = 53 Caption = 'Overview' - ExplicitWidth = 54 + ExplicitWidth = 53 end object tbarOverview: TToolBar Left = 224 diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas index 9cf76a2a8..e608e6d4a 100644 --- a/Src/FrOverview.pas +++ b/Src/FrOverview.pas @@ -26,29 +26,6 @@ interface type - // !! HACK - // Horrible hack to expose CreateWnd for overiding TTreeView.CreateWnd for the - // existing TTreeView component of TOverviewFrame. The hack avoids having to - // remove the component and replacing it with a descendant class that is - // manually constructed at run time. - // This is here to enable the tree view to be recreated with correctly - // instantiated TViewItemTreeNode nodes after Windows recreates the tree - // behind the scenes after resuming from hibernation. - // I am deeply ashamed of this hack. - TTreeView = class(ComCtrls.TTreeView) - strict private - var - _HACK_fOnAfterCreateNilViews: TNotifyEvent; - protected - procedure CreateWnd; override; - public - /// !! HACK. Event triggered after the inherited CreateWnd is - /// called. Only called if the tree view has nil references to IView - /// objects. - property _HACK_OnAfterCreateNilViews: TNotifyEvent - read _HACK_fOnAfterCreateNilViews write _HACK_fOnAfterCreateNilViews; - end; - { TOverviewFrame: Titled frame that displays lists of snippets grouped in various ways and @@ -237,10 +214,6 @@ TTVDraw = class(TSnippetsTVDraw) procedure RestoreTreeState; {Restores last saved treeview expansion state from memory. } - /// !! HACK: Sets an event handler on the tree view to work - /// around a bug that can occur after resuming from hibernation. - /// Method of IOverviewDisplayMgr. - procedure _HACK_SetHibernateHandler(const AHandler: TNotifyEvent); { IPaneInfo } function IsInteractive: Boolean; {Checks if the pane is currently interactive with user. @@ -982,12 +955,6 @@ procedure TOverviewFrame.UpdateTreeState(const State: TTreeNodeAction); end; end; -procedure TOverviewFrame._HACK_SetHibernateHandler( - const AHandler: TNotifyEvent); -begin - tvSnippets._HACK_OnAfterCreateNilViews := AHandler; -end; - { TOverviewFrame.TTVDraw } function TOverviewFrame.TTVDraw.IsSectionHeadNode( @@ -1026,24 +993,5 @@ function TOverviewFrame.TTVDraw.IsUserDefinedNode( Result := False; end; -{ TTreeView } - -procedure TTreeView.CreateWnd; -var - HasNilViews: Boolean; - Node: TTreeNode; -begin - inherited; - HasNilViews := False; - for Node in Items do - begin - HasNilViews := not Assigned((Node as TViewItemTreeNode).ViewItem); - if HasNilViews then - Break; - end; - if HasNilViews and Assigned(_HACK_fOnAfterCreateNilViews) then - _HACK_fOnAfterCreateNilViews(Self); -end; - end. diff --git a/Src/IntfFrameMgrs.pas b/Src/IntfFrameMgrs.pas index b3cb76101..5e5a9d5b2 100644 --- a/Src/IntfFrameMgrs.pas +++ b/Src/IntfFrameMgrs.pas @@ -146,9 +146,6 @@ interface /// Restore expand / collapse state of treeview to last save /// state. procedure RestoreTreeState; - /// !! HACK: Sets an event handler on the tree view to work - /// around a bug that can occur after resuming from hibernation. - procedure _HACK_SetHibernateHandler(const AHandler: TNotifyEvent); end; type diff --git a/Src/UMainDisplayMgr.pas b/Src/UMainDisplayMgr.pas index 0c64a17d5..15020fb34 100644 --- a/Src/UMainDisplayMgr.pas +++ b/Src/UMainDisplayMgr.pas @@ -165,11 +165,6 @@ TMainDisplayMgr = class(TObject) procedure DisplayViewItem(ViewItem: IView; Mode: TDetailPageDisplayMode); overload; - /// !! HACK event handle to redisplay the overview pane treeview. - /// Called only if Windows has mysteriously recreated the treeview and lost - /// necessary object references. - procedure _HACK_HibernateHandler(Sender: TObject); - public /// Object contructor. Sets up object to work with given frame /// manager objects. @@ -297,13 +292,6 @@ TMainDisplayMgr = class(TObject) /// Prepares display ready for database to be reloaded. procedure PrepareForDBReload; - /// !!HACK: gets the overview frame prepared for program - /// hibernation. - /// Saves the overview tree view state ready for restoring after - /// hibernation if Windows has recreated the overview pane's treeview, - /// losing necessary IView object references.. - procedure _HACK_PrepareForHibernate; - end; @@ -704,21 +692,5 @@ procedure TMainDisplayMgr.UpdateOverviewTreeState(const State: TTreeNodeAction); (fOverviewMgr as IOverviewDisplayMgr).UpdateTreeState(State); end; -procedure TMainDisplayMgr._HACK_HibernateHandler(Sender: TObject); -begin - (fOverviewMgr as IOverviewDisplayMgr).Display(Query.Selection, True); - (fOverviewMgr as IOverviewDisplayMgr).RestoreTreeState; - // disable this handler until next resume from hibernation - (fOverviewMgr as IOverviewDisplayMgr)._HACK_SetHibernateHandler(nil); -end; - -procedure TMainDisplayMgr._HACK_PrepareForHibernate; -begin - (fOverviewMgr as IOverviewDisplayMgr).SaveTreeState; - (fOverviewMgr as IOverviewDisplayMgr)._HACK_SetHibernateHandler( - _HACK_HibernateHandler - ); -end; - end. From 292d7c7533e80d24b4efd74a5f3634fc351b011e Mon Sep 17 00:00:00 2001 From: Sir Rufo Date: Thu, 17 Apr 2025 18:45:51 +0200 Subject: [PATCH 2/3] remove all hacks --- Src/IntfFrameMgrs.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/IntfFrameMgrs.pas b/Src/IntfFrameMgrs.pas index 5e5a9d5b2..813d320ad 100644 --- a/Src/IntfFrameMgrs.pas +++ b/Src/IntfFrameMgrs.pas @@ -19,7 +19,6 @@ interface uses // Delphi SHDocVw, ActiveX, - Classes, // !! For HACK // Project Browser.IntfDocHostUI, DB.USnippet, Compilers.UGlobals, UCommandBars, UView; From 9c7423c147d01a834f21d601321d84005f71d321 Mon Sep 17 00:00:00 2001 From: Sir Rufo Date: Thu, 17 Apr 2025 18:58:10 +0200 Subject: [PATCH 3/3] manage IView references in list --- Src/FrOverview.pas | 6 +++++- Src/UOverviewTreeBuilder.pas | 21 +++++++++++++++++---- Src/UViewItemTreeNode.pas | 18 ++++++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas index e608e6d4a..8355d9ad6 100644 --- a/Src/FrOverview.pas +++ b/Src/FrOverview.pas @@ -18,6 +18,7 @@ interface uses // Delphi + Generics.Collections, ComCtrls, Controls, Classes, Windows, ExtCtrls, StdCtrls, ToolWin, Menus, // Project DB.USnippet, FrTitled, IntfFrameMgrs, IntfNotifier, UCommandBars, @@ -88,6 +89,7 @@ TTVDraw = class(TSnippetsTVDraw) end; var + fViewStore : TList; // Stores the references of the Views fTVDraw: TTVDraw; // Object that renders tree view nodes fNotifier: INotifier; // Notifies app of user initiated events fCanChange: Boolean; // Whether selected node allowed to change @@ -284,6 +286,7 @@ constructor TOverviewFrame.Create(AOwner: TComponent); TabIdx: Integer; // loops through tabs begin inherited; + fViewStore := TList.Create; // Create delegated (contained) command bar manager for toolbar and popup menu fCommandBars := TCommandBarMgr.Create(Self); fCommandBars.AddCommandBar( @@ -319,6 +322,7 @@ destructor TOverviewFrame.Destroy; fSelectedItem := nil; fSnippetList.Free; // does not free referenced snippets fCommandBars.Free; + fViewStore.Free; inherited; end; @@ -520,7 +524,7 @@ procedure TOverviewFrame.Redisplay; Exit; // Build new treeview using grouping determined by selected tab Builder := BuilderClasses[tcDisplayStyle.TabIndex].Create( - tvSnippets, fSnippetList + tvSnippets, fSnippetList, fViewStore ); Builder.Build; // Restore state of treeview based on last time it was displayed diff --git a/Src/UOverviewTreeBuilder.pas b/Src/UOverviewTreeBuilder.pas index 87a32f23c..7e0e835e3 100644 --- a/Src/UOverviewTreeBuilder.pas +++ b/Src/UOverviewTreeBuilder.pas @@ -18,6 +18,7 @@ interface uses // Delphu + Generics.Collections, ComCtrls, // Project DB.USnippet, UGroups, UView, UViewItemTreeNode; @@ -34,11 +35,14 @@ TOverviewTreeBuilder = class abstract(TObject) var fTreeView: TTreeView; // Value of TreeView property fSnippetList: TSnippetList; // Value of SnippetList property + fViewStore : TList; strict protected property TreeView: TTreeView read fTreeView; {Reference to treeview populated by class} property SnippetList: TSnippetList read fSnippetList; {List of snippets to be displayed in treeview} + property ViewStore : TList read fViewStore; + {List of views attached to treeview nodes} function AddViewItemNode(const ParentNode: TViewItemTreeNode; ViewItem: IView): TViewItemTreeNode; {Adds a new node to the tree view that represents a view item. @@ -57,7 +61,7 @@ TOverviewTreeBuilder = class abstract(TObject) @return Required view item object. } public - constructor Create(const TV: TTreeView; const SnippetList: TSnippetList); + constructor Create(const TV: TTreeView; const SnippetList: TSnippetList; const ViewStore : TList); {Class constructor. Sets up object to populate a treeview with a list of snippets. @param TV [in] Treeview control to be populated. @@ -177,7 +181,9 @@ procedure TOverviewTreeBuilder.Build; ParentNode: TViewItemTreeNode; // each section node in tree Grouping: TGrouping; // groups snippets Group: TGroupItem; // each group of snippets + View: IView; begin + ViewStore.Clear; // Create required grouping of snippets Grouping := CreateGrouping; try @@ -186,11 +192,17 @@ procedure TOverviewTreeBuilder.Build; begin if not Group.IsEmpty or Preferences.ShowEmptySections then begin - ParentNode := AddViewItemNode(nil, CreateViewItemForGroup(Group)); + View := CreateViewItemForGroup(Group); + ParentNode := AddViewItemNode(nil, View); + ViewStore.Add(View); for Snippet in Group.SnippetList do + begin + View := TViewFactory.CreateSnippetView(Snippet); AddViewItemNode( - ParentNode, TViewFactory.CreateSnippetView(Snippet) + ParentNode, View ); + ViewStore.Add(View); + end; end; end; finally @@ -199,7 +211,7 @@ procedure TOverviewTreeBuilder.Build; end; constructor TOverviewTreeBuilder.Create(const TV: TTreeView; - const SnippetList: TSnippetList); + const SnippetList: TSnippetList; const ViewStore : TList); {Class constructor. Sets up object to populate a treeview with a list of snippets. @param TV [in] Treeview control to be populated. @@ -209,6 +221,7 @@ constructor TOverviewTreeBuilder.Create(const TV: TTreeView; inherited Create; fTreeView := TV; fSnippetList := SnippetList; + fViewStore := ViewStore; end; { TOverviewCategorisedTreeBuilder } diff --git a/Src/UViewItemTreeNode.pas b/Src/UViewItemTreeNode.pas index 44e258c24..51180997c 100644 --- a/Src/UViewItemTreeNode.pas +++ b/Src/UViewItemTreeNode.pas @@ -31,14 +31,28 @@ interface } TViewItemTreeNode = class(TTreeNode) strict private - var fViewItem: IView; // Value of ViewItem property + function GetViewItem: IView; + procedure SetViewItem(const Value: IView); + published // Value of ViewItem property public - property ViewItem: IView read fViewItem write fViewItem; + property ViewItem: IView read GetViewItem write SetViewItem; {View item associated with tree node} end; implementation +{ TViewItemTreeNode } + +function TViewItemTreeNode.GetViewItem: IView; +begin + Result := IView(Data); +end; + +procedure TViewItemTreeNode.SetViewItem(const Value: IView); +begin + Data := Pointer(Value); +end; + end.