Home | History | Annotate | Download | only in printing
      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(&params);
    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