1// Copyright 2014 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/views/profiles/user_manager_view.h"
6
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/lifetime/application_lifetime.h"
9#include "chrome/browser/profiles/profile_manager.h"
10#include "chrome/browser/profiles/profile_metrics.h"
11#include "chrome/browser/profiles/profile_window.h"
12#include "chrome/browser/profiles/profiles_state.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_dialogs.h"
15#include "chrome/browser/ui/browser_finder.h"
16#include "chrome/browser/ui/browser_window.h"
17#include "chrome/browser/ui/user_manager.h"
18#include "chrome/browser/ui/views/auto_keep_alive.h"
19#include "chrome/grit/chromium_strings.h"
20#include "content/public/browser/web_contents.h"
21#include "ui/base/l10n/l10n_util.h"
22#include "ui/gfx/screen.h"
23#include "ui/views/controls/webview/webview.h"
24#include "ui/views/layout/fill_layout.h"
25#include "ui/views/view.h"
26#include "ui/views/widget/widget.h"
27#include "ui/views/window/dialog_client_view.h"
28
29#if defined(OS_WIN)
30#include "chrome/browser/shell_integration.h"
31#include "ui/base/win/shell.h"
32#include "ui/views/win/hwnd_util.h"
33#endif
34
35namespace {
36
37// An open User Manager window. There can only be one open at a time. This
38// is reset to NULL when the window is closed.
39UserManagerView* instance_ = NULL;
40
41} // namespace
42
43// UserManager -----------------------------------------------------------------
44
45void UserManager::Show(
46    const base::FilePath& profile_path_to_focus,
47    profiles::UserManagerTutorialMode tutorial_mode,
48    profiles::UserManagerProfileSelected profile_open_action) {
49  ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::OPEN_USER_MANAGER);
50  if (instance_) {
51    // If we are showing the User Manager after locking a profile, change the
52    // active profile to Guest.
53    profiles::SetActiveProfileToGuestIfLocked();
54
55    // If there's a user manager window open already, just activate it.
56    instance_->GetWidget()->Activate();
57    return;
58  }
59
60  // Create the guest profile, if necessary, and open the user manager
61  // from the guest profile.
62  profiles::CreateGuestProfileForUserManager(
63      profile_path_to_focus,
64      tutorial_mode,
65      profile_open_action,
66      base::Bind(&UserManagerView::OnGuestProfileCreated,
67                 base::Passed(make_scoped_ptr(new UserManagerView)),
68                 profile_path_to_focus));
69}
70
71void UserManager::Hide() {
72  if (instance_)
73    instance_->GetWidget()->Close();
74}
75
76bool UserManager::IsShowing() {
77  return instance_ ? instance_->GetWidget()->IsActive() : false;
78}
79
80// UserManagerView -------------------------------------------------------------
81
82UserManagerView::UserManagerView()
83    : web_view_(NULL),
84      keep_alive_(new AutoKeepAlive(NULL)) {
85}
86
87UserManagerView::~UserManagerView() {
88}
89
90// static
91void UserManagerView::OnGuestProfileCreated(
92    scoped_ptr<UserManagerView> instance,
93    const base::FilePath& profile_path_to_focus,
94    Profile* guest_profile,
95    const std::string& url) {
96  // If we are showing the User Manager after locking a profile, change the
97  // active profile to Guest.
98  profiles::SetActiveProfileToGuestIfLocked();
99
100  DCHECK(!instance_);
101  instance_ = instance.release();  // |instance_| takes over ownership.
102  instance_->Init(profile_path_to_focus, guest_profile, GURL(url));
103}
104
105void UserManagerView::Init(
106    const base::FilePath& profile_path_to_focus,
107    Profile* guest_profile,
108    const GURL& url) {
109  web_view_ = new views::WebView(guest_profile);
110  web_view_->set_allow_accelerators(true);
111  AddChildView(web_view_);
112  SetLayoutManager(new views::FillLayout);
113  AddAccelerator(ui::Accelerator(ui::VKEY_W, ui::EF_CONTROL_DOWN));
114
115  // If the user manager is being displayed from an existing profile, use
116  // its last active browser to determine where the user manager should be
117  // placed.  This is used so that we can center the dialog on the correct
118  // monitor in a multiple-monitor setup.
119  //
120  // If |profile_path_to_focus| is empty (for example, starting up chrome
121  // when all existing profiles are locked) or we can't find an active
122  // browser, bounds will remain empty and the user manager will be centered on
123  // the default monitor by default.
124  gfx::Rect bounds;
125  if (!profile_path_to_focus.empty()) {
126    ProfileManager* manager = g_browser_process->profile_manager();
127    if (manager) {
128      Profile* profile = manager->GetProfileByPath(profile_path_to_focus);
129      DCHECK(profile);
130      Browser* browser = chrome::FindLastActiveWithProfile(profile,
131          chrome::GetActiveDesktop());
132      if (browser) {
133        gfx::NativeView native_view =
134            views::Widget::GetWidgetForNativeWindow(
135                browser->window()->GetNativeWindow())->GetNativeView();
136        bounds = gfx::Screen::GetScreenFor(native_view)->
137            GetDisplayNearestWindow(native_view).work_area();
138        bounds.ClampToCenteredSize(gfx::Size(UserManager::kWindowWidth,
139                                             UserManager::kWindowHeight));
140      }
141    }
142  }
143
144  DialogDelegate::CreateDialogWidgetWithBounds(this, NULL, NULL, bounds);
145
146  // Since the User Manager can be the only top level window, we don't
147  // want to accidentally quit all of Chrome if the user is just trying to
148  // unfocus the selected pod in the WebView.
149  GetDialogClientView()->RemoveAccelerator(
150      ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
151
152#if defined(OS_WIN)
153  // Set the app id for the task manager to the app id of its parent
154  ui::win::SetAppIdForWindow(
155      ShellIntegration::GetChromiumModelIdForProfile(
156          guest_profile->GetPath()),
157      views::HWNDForWidget(GetWidget()));
158#endif
159  GetWidget()->Show();
160
161  web_view_->LoadInitialURL(url);
162  web_view_->RequestFocus();
163}
164
165bool UserManagerView::AcceleratorPressed(const ui::Accelerator& accelerator) {
166  DCHECK_EQ(ui::VKEY_W, accelerator.key_code());
167  DCHECK_EQ(ui::EF_CONTROL_DOWN, accelerator.modifiers());
168  GetWidget()->Close();
169  return true;
170}
171
172gfx::Size UserManagerView::GetPreferredSize() const {
173  return gfx::Size(UserManager::kWindowWidth, UserManager::kWindowHeight);
174}
175
176bool UserManagerView::CanResize() const {
177  return true;
178}
179
180bool UserManagerView::CanMaximize() const {
181  return true;
182}
183
184bool UserManagerView::CanMinimize() const {
185  return true;
186}
187
188base::string16 UserManagerView::GetWindowTitle() const {
189  return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
190}
191
192int UserManagerView::GetDialogButtons() const {
193  return ui::DIALOG_BUTTON_NONE;
194}
195
196void UserManagerView::WindowClosing() {
197  // Now that the window is closed, we can allow a new one to be opened.
198  // (WindowClosing comes in asynchronously from the call to Close() and we
199  // may have already opened a new instance).
200  if (instance_ == this)
201    instance_ = NULL;
202}
203
204bool UserManagerView::UseNewStyleForThisDialog() const {
205  return false;
206}
207