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#include "chrome/browser/ui/browser_finder.h"
6
7#include "chrome/browser/profiles/profile.h"
8#include "chrome/browser/ui/browser_iterator.h"
9#include "chrome/browser/ui/browser_list.h"
10#include "chrome/browser/ui/browser_window.h"
11#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
12#include "chrome/browser/ui/tabs/tab_strip_model.h"
13#include "content/public/browser/navigation_controller.h"
14
15using content::WebContents;
16
17namespace {
18
19
20// Type used to indicate to match anything.
21const int kMatchAny                     = 0;
22
23// See BrowserMatches for details.
24const int kMatchOriginalProfile         = 1 << 0;
25const int kMatchCanSupportWindowFeature = 1 << 1;
26const int kMatchTabbed                  = 1 << 2;
27
28// Returns true if the specified |browser| matches the specified arguments.
29// |match_types| is a bitmask dictating what parameters to match:
30// . If it contains kMatchOriginalProfile then the original profile of the
31//   browser must match |profile->GetOriginalProfile()|. This is used to match
32//   incognito windows.
33// . If it contains kMatchCanSupportWindowFeature
34//   |CanSupportWindowFeature(window_feature)| must return true.
35// . If it contains kMatchTabbed, the browser must be a tabbed browser.
36bool BrowserMatches(Browser* browser,
37                    Profile* profile,
38                    Browser::WindowFeature window_feature,
39                    uint32 match_types) {
40  if (match_types & kMatchCanSupportWindowFeature &&
41      !browser->CanSupportWindowFeature(window_feature)) {
42    return false;
43  }
44
45  if (match_types & kMatchOriginalProfile) {
46    if (browser->profile()->GetOriginalProfile() !=
47        profile->GetOriginalProfile())
48      return false;
49  } else if (browser->profile() != profile) {
50    return false;
51  }
52
53  if (match_types & kMatchTabbed)
54    return browser->is_type_tabbed();
55
56  return true;
57}
58
59// Returns the first browser in the specified iterator that returns true from
60// |BrowserMatches|, or null if no browsers match the arguments. See
61// |BrowserMatches| for details on the arguments.
62template <class T>
63Browser* FindBrowserMatching(const T& begin,
64                             const T& end,
65                             Profile* profile,
66                             Browser::WindowFeature window_feature,
67                             uint32 match_types) {
68  for (T i = begin; i != end; ++i) {
69    if (BrowserMatches(*i, profile, window_feature, match_types))
70      return *i;
71  }
72  return NULL;
73}
74
75Browser* FindBrowserWithTabbedOrAnyType(Profile* profile,
76                                        chrome::HostDesktopType desktop_type,
77                                        bool match_tabbed,
78                                        bool match_original_profiles) {
79  BrowserList* browser_list_impl = BrowserList::GetInstance(desktop_type);
80  if (!browser_list_impl)
81    return NULL;
82  uint32 match_types = kMatchAny;
83  if (match_tabbed)
84    match_types |= kMatchTabbed;
85  if (match_original_profiles)
86    match_types |= kMatchOriginalProfile;
87  Browser* browser = FindBrowserMatching(browser_list_impl->begin_last_active(),
88                                         browser_list_impl->end_last_active(),
89                                         profile,
90                                         Browser::FEATURE_NONE,
91                                         match_types);
92  // Fall back to a forward scan of all Browsers if no active one was found.
93  return browser ? browser : FindBrowserMatching(browser_list_impl->begin(),
94                                                 browser_list_impl->end(),
95                                                 profile,
96                                                 Browser::FEATURE_NONE,
97                                                 match_types);
98}
99
100size_t GetBrowserCountImpl(Profile* profile,
101                           chrome::HostDesktopType desktop_type,
102                           uint32 match_types) {
103  BrowserList* browser_list_impl = BrowserList::GetInstance(desktop_type);
104  size_t count = 0;
105  if (browser_list_impl) {
106    for (BrowserList::const_iterator i = browser_list_impl->begin();
107         i != browser_list_impl->end(); ++i) {
108      if (BrowserMatches(*i, profile, Browser::FEATURE_NONE, match_types))
109        count++;
110    }
111  }
112  return count;
113}
114
115}  // namespace
116
117namespace chrome {
118
119Browser* FindTabbedBrowser(Profile* profile,
120                           bool match_original_profiles,
121                           HostDesktopType type) {
122  return FindBrowserWithTabbedOrAnyType(profile,
123                                        type,
124                                        true,
125                                        match_original_profiles);
126}
127
128Browser* FindAnyBrowser(Profile* profile,
129                        bool match_original_profiles,
130                        HostDesktopType type) {
131  return FindBrowserWithTabbedOrAnyType(profile,
132                                        type,
133                                        false,
134                                        match_original_profiles);
135}
136
137Browser* FindBrowserWithProfile(Profile* profile,
138                                HostDesktopType desktop_type) {
139  return FindBrowserWithTabbedOrAnyType(profile, desktop_type, false, false);
140}
141
142Browser* FindBrowserWithID(SessionID::id_type desired_id) {
143  for (BrowserIterator it; !it.done(); it.Next()) {
144    if (it->session_id().id() == desired_id)
145      return *it;
146  }
147  return NULL;
148}
149
150Browser* FindBrowserWithWindow(gfx::NativeWindow window) {
151  if (!window)
152    return NULL;
153  for (BrowserIterator it; !it.done(); it.Next()) {
154    Browser* browser = *it;
155    if (browser->window() && browser->window()->GetNativeWindow() == window)
156      return browser;
157  }
158  return NULL;
159}
160
161Browser* FindBrowserWithWebContents(const WebContents* web_contents) {
162  DCHECK(web_contents);
163  for (TabContentsIterator it; !it.done(); it.Next()) {
164    if (*it == web_contents)
165      return it.browser();
166  }
167  return NULL;
168}
169
170Browser* FindLastActiveWithProfile(Profile* profile, HostDesktopType type) {
171  BrowserList* list = BrowserList::GetInstance(type);
172  // We are only interested in last active browsers, so we don't fall back to
173  // all browsers like FindBrowserWith* do.
174  return FindBrowserMatching(list->begin_last_active(), list->end_last_active(),
175                             profile, Browser::FEATURE_NONE, kMatchAny);
176}
177
178Browser* FindLastActiveWithHostDesktopType(HostDesktopType type) {
179  BrowserList* browser_list_impl = BrowserList::GetInstance(type);
180  if (browser_list_impl)
181    return browser_list_impl->GetLastActive();
182  return NULL;
183}
184
185size_t GetTotalBrowserCount() {
186  size_t count = 0;
187  for (HostDesktopType t = HOST_DESKTOP_TYPE_FIRST; t < HOST_DESKTOP_TYPE_COUNT;
188       t = static_cast<HostDesktopType>(t + 1)) {
189    count += BrowserList::GetInstance(t)->size();
190  }
191  return count;
192}
193
194size_t GetTotalBrowserCountForProfile(Profile* profile) {
195  size_t count = 0;
196  for (HostDesktopType t = HOST_DESKTOP_TYPE_FIRST; t < HOST_DESKTOP_TYPE_COUNT;
197       t = static_cast<HostDesktopType>(t + 1)) {
198    count += GetBrowserCount(profile, t);
199  }
200  return count;
201}
202
203size_t GetBrowserCount(Profile* profile, HostDesktopType type) {
204  return GetBrowserCountImpl(profile, type, kMatchAny);
205}
206
207size_t GetTabbedBrowserCount(Profile* profile, HostDesktopType type) {
208  return GetBrowserCountImpl(profile, type, kMatchTabbed);
209}
210
211}  // namespace chrome
212