1// Copyright (c) 2012 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 CHROME_BROWSER_PRINTING_PRINT_PREVIEW_DIALOG_CONTROLLER_H_
6#define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_DIALOG_CONTROLLER_H_
7
8#include <map>
9
10#include "base/basictypes.h"
11#include "base/callback.h"
12#include "base/memory/ref_counted.h"
13#include "components/sessions/session_id.h"
14#include "content/public/browser/notification_observer.h"
15#include "content/public/browser/notification_registrar.h"
16
17class GURL;
18
19namespace content {
20struct LoadCommittedDetails;
21class RenderProcessHost;
22class WebContents;
23}
24
25namespace printing {
26
27// For print preview, the WebContents that initiates the printing operation is
28// the initiator, and the constrained dialog that shows the print preview is the
29// print preview dialog.
30// This class manages print preview dialog creation and destruction, and keeps
31// track of the 1:1 relationship between initiator tabs and print preview
32// dialogs.
33class PrintPreviewDialogController
34    : public base::RefCounted<PrintPreviewDialogController>,
35      public content::NotificationObserver {
36 public:
37  PrintPreviewDialogController();
38
39  static PrintPreviewDialogController* GetInstance();
40
41  // Initiate print preview for |initiator|.
42  // Call this instead of GetOrCreatePreviewDialog().
43  static void PrintPreview(content::WebContents* initiator);
44
45  // Get/Create the print preview dialog for |initiator|.
46  // Exposed for unit tests.
47  content::WebContents* GetOrCreatePreviewDialog(
48      content::WebContents* initiator);
49
50  // Returns the preview dialog for |contents|.
51  // Returns |contents| if |contents| is a preview dialog.
52  // Returns NULL if no preview dialog exists for |contents|.
53  content::WebContents* GetPrintPreviewForContents(
54      content::WebContents* contents) const;
55
56  // Returns the initiator for |preview_dialog|.
57  // Returns NULL if no initiator exists for |preview_dialog|.
58  content::WebContents* GetInitiator(content::WebContents* preview_dialog);
59
60  // Run |callback| on the dialog of each active print preview operation.
61  void ForEachPreviewDialog(
62      base::Callback<void(content::WebContents*)> callback);
63
64  // content::NotificationObserver implementation.
65  virtual void Observe(int type,
66                       const content::NotificationSource& source,
67                       const content::NotificationDetails& details) OVERRIDE;
68
69  // Returns true if |contents| is a print preview dialog.
70  static bool IsPrintPreviewDialog(content::WebContents* contents);
71
72  // Returns true if |url| is a print preview url.
73  static bool IsPrintPreviewURL(const GURL& url);
74
75  // Erase the initiator info associated with |preview_dialog|.
76  void EraseInitiatorInfo(content::WebContents* preview_dialog);
77
78  bool is_creating_print_preview_dialog() const {
79    return is_creating_print_preview_dialog_;
80  }
81
82 private:
83  friend class base::RefCounted<PrintPreviewDialogController>;
84
85  // 1:1 relationship between a print preview dialog and its initiator tab.
86  // Key: Print preview dialog.
87  // Value: Initiator.
88  typedef std::map<content::WebContents*, content::WebContents*>
89      PrintPreviewDialogMap;
90
91  virtual ~PrintPreviewDialogController();
92
93  // Handler for the RENDERER_PROCESS_CLOSED notification. This is observed when
94  // the initiator renderer crashed.
95  void OnRendererProcessClosed(content::RenderProcessHost* rph);
96
97  // Handler for the WEB_CONTENTS_DESTROYED notification. This is observed when
98  // either WebContents is closed.
99  void OnWebContentsDestroyed(content::WebContents* contents);
100
101  // Handler for the NAV_ENTRY_COMMITTED notification. This is observed when the
102  // renderer is navigated to a different page.
103  void OnNavEntryCommitted(content::WebContents* contents,
104                           content::LoadCommittedDetails* details);
105
106  // Creates a new print preview dialog.
107  content::WebContents* CreatePrintPreviewDialog(
108      content::WebContents* initiator);
109
110  // Helper function to store the title of the initiator associated with
111  // |preview_dialog| in |preview_dialog|'s PrintPreviewUI.
112  void SaveInitiatorTitle(content::WebContents* preview_dialog);
113
114  // Adds/Removes observers for notifications from |contents|.
115  void AddObservers(content::WebContents* contents);
116  void RemoveObservers(content::WebContents* contents);
117
118  // Removes WebContents when they close/crash/navigate.
119  void RemoveInitiator(content::WebContents* initiator);
120  void RemovePreviewDialog(content::WebContents* preview_dialog);
121
122  // Mapping between print preview dialog and the corresponding initiator.
123  PrintPreviewDialogMap preview_dialog_map_;
124
125  // A registrar for listening to notifications.
126  content::NotificationRegistrar registrar_;
127
128  // True if the controller is waiting for a new preview dialog via
129  // content::NAVIGATION_TYPE_NEW_PAGE.
130  bool waiting_for_new_preview_page_;
131
132  // Whether the PrintPreviewDialogController is in the middle of creating a
133  // print preview dialog.
134  bool is_creating_print_preview_dialog_;
135
136  DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogController);
137};
138
139}  // namespace printing
140
141#endif  // CHROME_BROWSER_PRINTING_PRINT_PREVIEW_DIALOG_CONTROLLER_H_
142