1 // Copyright (c) 2011 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 #include "chrome/browser/printing/print_preview_tab_controller.h" 6 7 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/tabs/tab_strip_model.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser_list.h" 11 #include "chrome/browser/ui/browser_navigator.h" 12 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 13 #include "chrome/common/url_constants.h" 14 #include "content/browser/tab_contents/tab_contents.h" 15 #include "content/common/notification_details.h" 16 #include "content/common/notification_source.h" 17 18 namespace printing { 19 20 PrintPreviewTabController::PrintPreviewTabController() 21 : waiting_for_new_preview_page_(false) { 22 } 23 24 PrintPreviewTabController::~PrintPreviewTabController() {} 25 26 // static 27 PrintPreviewTabController* PrintPreviewTabController::GetInstance() { 28 if (!g_browser_process) 29 return NULL; 30 return g_browser_process->print_preview_tab_controller(); 31 } 32 33 // static 34 void PrintPreviewTabController::PrintPreview(TabContents* tab) { 35 if (tab->showing_interstitial_page()) 36 return; 37 38 printing::PrintPreviewTabController* tab_controller = 39 printing::PrintPreviewTabController::GetInstance(); 40 if (!tab_controller) 41 return; 42 tab_controller->GetOrCreatePreviewTab(tab); 43 } 44 45 TabContents* PrintPreviewTabController::GetOrCreatePreviewTab( 46 TabContents* initiator_tab) { 47 DCHECK(initiator_tab); 48 49 // Get the print preview tab for |initiator_tab|. 50 TabContents* preview_tab = GetPrintPreviewForTab(initiator_tab); 51 if (preview_tab) { 52 // Show current preview tab. 53 preview_tab->Activate(); 54 return preview_tab; 55 } 56 return CreatePrintPreviewTab(initiator_tab); 57 } 58 59 TabContents* PrintPreviewTabController::GetPrintPreviewForTab( 60 TabContents* tab) const { 61 PrintPreviewTabMap::const_iterator it = preview_tab_map_.find(tab); 62 if (it != preview_tab_map_.end()) 63 return tab; 64 65 for (it = preview_tab_map_.begin(); it != preview_tab_map_.end(); ++it) { 66 // If |tab| is an initiator tab. 67 if (tab == it->second) { 68 // Return the associated preview tab. 69 return it->first; 70 } 71 } 72 return NULL; 73 } 74 75 void PrintPreviewTabController::Observe(NotificationType type, 76 const NotificationSource& source, 77 const NotificationDetails& details) { 78 TabContents* source_tab = NULL; 79 NavigationController::LoadCommittedDetails* detail_info = NULL; 80 81 switch (type.value) { 82 case NotificationType::TAB_CONTENTS_DESTROYED: { 83 source_tab = Source<TabContents>(source).ptr(); 84 break; 85 } 86 case NotificationType::NAV_ENTRY_COMMITTED: { 87 NavigationController* controller = 88 Source<NavigationController>(source).ptr(); 89 source_tab = controller->tab_contents(); 90 detail_info = 91 Details<NavigationController::LoadCommittedDetails>(details).ptr(); 92 break; 93 } 94 default: { 95 NOTREACHED(); 96 break; 97 } 98 } 99 100 DCHECK(source_tab); 101 102 TabContents* preview_tab = GetPrintPreviewForTab(source_tab); 103 bool source_tab_is_preview_tab = (source_tab == preview_tab); 104 105 if (detail_info) { 106 PageTransition::Type transition_type = 107 detail_info->entry->transition_type(); 108 NavigationType::Type nav_type = detail_info->type; 109 110 // Don't update/erase the map entry if the page has not changed. 111 if (transition_type == PageTransition::RELOAD || 112 nav_type == NavigationType::SAME_PAGE) { 113 return; 114 } 115 116 // New |preview_tab| is created. Don't update/erase map entry. 117 if (waiting_for_new_preview_page_ && 118 transition_type == PageTransition::LINK && 119 nav_type == NavigationType::NEW_PAGE && 120 source_tab_is_preview_tab) { 121 waiting_for_new_preview_page_ = false; 122 return; 123 } 124 125 // User navigated to a preview tab using forward/back button. 126 if (source_tab_is_preview_tab && 127 transition_type == PageTransition::FORWARD_BACK && 128 nav_type == NavigationType::EXISTING_PAGE) { 129 return; 130 } 131 } 132 133 if (source_tab_is_preview_tab) { 134 // Remove the initiator tab's observers before erasing the mapping. 135 TabContents* initiator_tab = GetInitiatorTab(source_tab); 136 if (initiator_tab) 137 RemoveObservers(initiator_tab); 138 139 // Erase the map entry. 140 preview_tab_map_.erase(source_tab); 141 } else { 142 // |source_tab| is an initiator tab, update the map entry. 143 preview_tab_map_[preview_tab] = NULL; 144 } 145 RemoveObservers(source_tab); 146 } 147 148 // static 149 bool PrintPreviewTabController::IsPrintPreviewTab(TabContents* tab) { 150 const GURL& url = tab->GetURL(); 151 return (url.SchemeIs(chrome::kChromeUIScheme) && 152 url.host() == chrome::kChromeUIPrintHost); 153 } 154 155 TabContents* PrintPreviewTabController::GetInitiatorTab( 156 TabContents* preview_tab) { 157 PrintPreviewTabMap::iterator it = preview_tab_map_.find(preview_tab); 158 if (it != preview_tab_map_.end()) 159 return preview_tab_map_[preview_tab]; 160 return NULL; 161 } 162 163 TabContents* PrintPreviewTabController::CreatePrintPreviewTab( 164 TabContents* initiator_tab) { 165 Browser* current_browser = BrowserList::FindBrowserWithID( 166 initiator_tab->controller().window_id().id()); 167 // Add a new tab next to initiator tab. 168 browser::NavigateParams params(current_browser, 169 GURL(chrome::kChromeUIPrintURL), 170 PageTransition::LINK); 171 params.disposition = NEW_FOREGROUND_TAB; 172 params.tabstrip_index = current_browser->tabstrip_model()-> 173 GetWrapperIndex(initiator_tab) + 1; 174 browser::Navigate(¶ms); 175 TabContentsWrapper* preview_tab = params.target_contents; 176 preview_tab->tab_contents()->Activate(); 177 178 // Add an entry to the map. 179 preview_tab_map_[preview_tab->tab_contents()] = initiator_tab; 180 waiting_for_new_preview_page_ = true; 181 182 AddObservers(initiator_tab); 183 AddObservers(preview_tab->tab_contents()); 184 185 return preview_tab->tab_contents(); 186 } 187 188 void PrintPreviewTabController::AddObservers(TabContents* tab) { 189 registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, 190 Source<TabContents>(tab)); 191 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, 192 Source<NavigationController>(&tab->controller())); 193 } 194 195 void PrintPreviewTabController::RemoveObservers(TabContents* tab) { 196 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, 197 Source<TabContents>(tab)); 198 registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED, 199 Source<NavigationController>(&tab->controller())); 200 } 201 202 } // namespace printing 203