1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef IOS_CHROME_BROWSER_TABS_TAB_HELPER_DELEGATE_INSTALLER_H_ 6 #define IOS_CHROME_BROWSER_TABS_TAB_HELPER_DELEGATE_INSTALLER_H_ 7 8 #include "base/check.h" 9 #include "base/scoped_observer.h" 10 #import "ios/chrome/browser/main/browser.h" 11 #import "ios/chrome/browser/main/browser_observer.h" 12 #import "ios/chrome/browser/web_state_list/web_state_list.h" 13 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h" 14 15 // TabHelperDelegateInstaller is used to install a single delegate instance as 16 // the delegate for the tab helper associated with every WebState in a Browser's 17 // WebStateList. When a TabHelperDelegateInstaller or its associated Browser is 18 // destroyed, all tab helpers' delegates are reset to nullptr. Useful when a 19 // Browser-scoped object acts as the delegate for every tab helper. 20 // 21 // Usage example for a BrowserUserData that owns the tab helper delegates for 22 // FooTabHelper. Two installers are used, one for the main delegate that is set 23 // via FooTabHelper::SetDelegate(), and one for a UI delegate that is set via 24 // FooTabHelper::SetUIDelegate(): 25 // 26 // class FooBrowserAgent : public BrowserUserData<FooBrowserAgent> { 27 // public: 28 // ... 29 // private: 30 // explicit FooBrowserAgent(Browser* browser) 31 // : delegate_installer_(&tab_helper_delegate_, browser), 32 // ui_delegate_installer_(&tab_helper_ui_delegate_, browser) {} 33 // 34 // FooTabHelperDelegate tab_helper_delegate_; 35 // TabHelperDelegateInstaller<FooTabHelper, 36 // FooTabHelperDelegate> delegate_installer_; 37 // 38 // FooTabHelperUIDelegate tab_helper_ui_delegate_; 39 // TabHelperDelegateInstaller<FooTabHelper, 40 // FooTabHelperUIDelegate, 41 // &FooTabHelper::SetUIDelegate> 42 // ui_delegate_installer_; 43 // }; 44 template <class Helper, 45 class Delegate, 46 void (Helper::*SetDelFn)(Delegate*) = &Helper::SetDelegate> 47 class TabHelperDelegateInstaller { 48 public: TabHelperDelegateInstaller(Delegate * delegate,Browser * browser)49 TabHelperDelegateInstaller(Delegate* delegate, Browser* browser) 50 : installer_(delegate, browser->GetWebStateList()), 51 shutdown_helper_(&installer_, browser) {} 52 ~TabHelperDelegateInstaller() = default; 53 54 TabHelperDelegateInstaller(const TabHelperDelegateInstaller&) = delete; 55 TabHelperDelegateInstaller& operator=(const TabHelperDelegateInstaller&) = 56 delete; 57 58 private: 59 // Helper object that sets up the delegates for all Helpers in a Browser's 60 // WebStateList. 61 class Installer : public WebStateListObserver { 62 public: Installer(Delegate * delegate,WebStateList * web_state_list)63 Installer(Delegate* delegate, WebStateList* web_state_list) 64 : delegate_(delegate), web_state_list_(web_state_list) { 65 DCHECK(delegate_); 66 DCHECK(web_state_list_); 67 scoped_observer_.Add(web_state_list_); 68 for (int i = 0; i < web_state_list_->count(); ++i) { 69 SetTabHelperDelegate(web_state_list_->GetWebStateAt(i), delegate_); 70 } 71 } ~Installer()72 ~Installer() override { Disconnect(); } 73 74 // Uninstalls the delegate and stops observing the WebStateList. Disconnect()75 void Disconnect() { 76 if (!web_state_list_) 77 return; 78 for (int i = 0; i < web_state_list_->count(); ++i) { 79 SetTabHelperDelegate(web_state_list_->GetWebStateAt(i), nullptr); 80 } 81 scoped_observer_.Remove(web_state_list_); 82 web_state_list_ = nullptr; 83 } 84 85 private: 86 // WebStateListObserver: WebStateInsertedAt(WebStateList * web_state_list,web::WebState * web_state,int index,bool activating)87 void WebStateInsertedAt(WebStateList* web_state_list, 88 web::WebState* web_state, 89 int index, 90 bool activating) override { 91 SetTabHelperDelegate(web_state, delegate_); 92 } WebStateReplacedAt(WebStateList * web_state_list,web::WebState * old_web_state,web::WebState * new_web_state,int index)93 void WebStateReplacedAt(WebStateList* web_state_list, 94 web::WebState* old_web_state, 95 web::WebState* new_web_state, 96 int index) override { 97 SetTabHelperDelegate(old_web_state, nullptr); 98 SetTabHelperDelegate(new_web_state, delegate_); 99 } WillDetachWebStateAt(WebStateList * web_state_list,web::WebState * web_state,int index)100 void WillDetachWebStateAt(WebStateList* web_state_list, 101 web::WebState* web_state, 102 int index) override { 103 SetTabHelperDelegate(web_state, nullptr); 104 } 105 106 // Sets the delegate for |web_state|'s Helper to |delegate|. SetTabHelperDelegate(web::WebState * web_state,Delegate * delegate)107 void SetTabHelperDelegate(web::WebState* web_state, Delegate* delegate) { 108 (Helper::FromWebState(web_state)->*SetDelFn)(delegate); 109 } 110 111 // The delegate that is installed for each WebState in the WebStateList. 112 Delegate* delegate_ = nullptr; 113 // The WebStateList whose Helpers's delegates are being installed. 114 WebStateList* web_state_list_ = nullptr; 115 // Scoped observer for |web_state_list_|. 116 ScopedObserver<WebStateList, WebStateListObserver> scoped_observer_{this}; 117 }; 118 119 // Helper object that sets up the delegate installer and tears it down 120 // when the Browser is destroyed. 121 class BrowserShutdownHelper : public BrowserObserver { 122 public: BrowserShutdownHelper(Installer * installer,Browser * browser)123 BrowserShutdownHelper(Installer* installer, Browser* browser) 124 : installer_(installer) { 125 DCHECK(installer_); 126 DCHECK(browser); 127 scoped_observer_.Add(browser); 128 } 129 ~BrowserShutdownHelper() override = default; 130 131 private: 132 // BrowserObserver: BrowserDestroyed(Browser * browser)133 void BrowserDestroyed(Browser* browser) override { 134 installer_->Disconnect(); 135 scoped_observer_.Remove(browser); 136 } 137 138 // The installer used to set up the Delegates. 139 Installer* installer_ = nullptr; 140 // Scoped observer for the Browser. 141 ScopedObserver<Browser, BrowserObserver> scoped_observer_{this}; 142 }; 143 144 // Helper object that installs delegates for all the Browser's tab helpers. 145 Installer installer_; 146 // Helper object that sets up and tears down the Installer for a Browser. 147 BrowserShutdownHelper shutdown_helper_; 148 }; 149 150 #endif // IOS_CHROME_BROWSER_TABS_TAB_HELPER_DELEGATE_INSTALLER_H_ 151