1e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes// Use of this source code is governed by a BSD-style license that can be
3e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes// found in the LICENSE file.
4e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
5e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/browser/ui/views/uninstall_view.h"
6e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
7e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "base/message_loop/message_loop.h"
8e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "base/process/launch.h"
9e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "base/run_loop.h"
10e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/browser/browser_process.h"
11e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/browser/shell_integration.h"
12e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/browser/ui/uninstall_browser_prompt.h"
13e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/common/chrome_result_codes.h"
14e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/grit/chromium_strings.h"
15e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/installer/util/browser_distribution.h"
16e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "chrome/installer/util/shell_util.h"
17e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/base/l10n/l10n_util.h"
18e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/controls/button/checkbox.h"
19e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/controls/combobox/combobox.h"
20e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/controls/label.h"
21e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/layout/grid_layout.h"
22e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/layout/layout_constants.h"
23e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes#include "ui/views/widget/widget.h"
24e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
25e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott HughesUninstallView::UninstallView(int* user_selection,
26e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                             const base::Closure& quit_closure)
278d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    : confirm_label_(NULL),
28e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes      delete_profile_(NULL),
298d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath      change_default_browser_(NULL),
30e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes      browsers_combo_(NULL),
318d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath      user_selection_(*user_selection),
32e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes      quit_closure_(quit_closure) {
338d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath  SetupControls();
34e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes}
358d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
36e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott HughesUninstallView::~UninstallView() {
37  // Exit the message loop we were started with so that uninstall can continue.
38  quit_closure_.Run();
39
40  // Delete Combobox as it holds a reference to us.
41  delete browsers_combo_;
42}
43
44void UninstallView::SetupControls() {
45  using views::ColumnSet;
46  using views::GridLayout;
47
48  GridLayout* layout = GridLayout::CreatePanel(this);
49  SetLayoutManager(layout);
50
51  // Message to confirm uninstallation.
52  int column_set_id = 0;
53  ColumnSet* column_set = layout->AddColumnSet(column_set_id);
54  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
55                        GridLayout::USE_PREF, 0, 0);
56  layout->StartRow(0, column_set_id);
57  confirm_label_ = new views::Label(
58      l10n_util::GetStringUTF16(IDS_UNINSTALL_VERIFY));
59  confirm_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
60  layout->AddView(confirm_label_);
61
62  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
63
64  // The "delete profile" check box.
65  ++column_set_id;
66  column_set = layout->AddColumnSet(column_set_id);
67  column_set->AddPaddingColumn(0, views::kPanelHorizIndentation);
68  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
69                        GridLayout::USE_PREF, 0, 0);
70  layout->StartRow(0, column_set_id);
71  delete_profile_ = new views::Checkbox(
72      l10n_util::GetStringUTF16(IDS_UNINSTALL_DELETE_PROFILE));
73  layout->AddView(delete_profile_);
74
75  // Set default browser combo box. If the default should not or cannot be
76  // changed, widgets are not shown. We assume here that if Chrome cannot
77  // be set programatically as default, neither can any other browser (for
78  // instance because the OS doesn't permit that).
79  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
80  if (dist->GetDefaultBrowserControlPolicy() !=
81          BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED &&
82      ShellIntegration::GetDefaultBrowser() == ShellIntegration::IS_DEFAULT &&
83      (ShellIntegration::CanSetAsDefaultBrowser() !=
84          ShellIntegration::SET_DEFAULT_INTERACTIVE)) {
85    browsers_.reset(new BrowsersMap());
86    ShellUtil::GetRegisteredBrowsers(dist, browsers_.get());
87    if (!browsers_->empty()) {
88      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
89
90      ++column_set_id;
91      column_set = layout->AddColumnSet(column_set_id);
92      column_set->AddPaddingColumn(0, views::kPanelHorizIndentation);
93      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
94                            GridLayout::USE_PREF, 0, 0);
95      column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
96      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
97                            GridLayout::USE_PREF, 0, 0);
98      layout->StartRow(0, column_set_id);
99      change_default_browser_ = new views::Checkbox(
100          l10n_util::GetStringUTF16(IDS_UNINSTALL_SET_DEFAULT_BROWSER));
101      change_default_browser_->set_listener(this);
102      layout->AddView(change_default_browser_);
103      browsers_combo_ = new views::Combobox(this);
104      layout->AddView(browsers_combo_);
105      browsers_combo_->SetEnabled(false);
106    }
107  }
108
109  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
110}
111
112bool UninstallView::Accept() {
113  user_selection_ = content::RESULT_CODE_NORMAL_EXIT;
114  if (delete_profile_->checked())
115    user_selection_ = chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE;
116  if (change_default_browser_ && change_default_browser_->checked()) {
117    BrowsersMap::const_iterator i = browsers_->begin();
118    std::advance(i, browsers_combo_->selected_index());
119    base::LaunchOptions options;
120    options.start_hidden = true;
121    base::LaunchProcess(i->second, options, NULL);
122  }
123  return true;
124}
125
126bool UninstallView::Cancel() {
127  user_selection_ = chrome::RESULT_CODE_UNINSTALL_USER_CANCEL;
128  return true;
129}
130
131base::string16 UninstallView::GetDialogButtonLabel(
132    ui::DialogButton button) const {
133  // Label the OK button 'Uninstall'; Cancel remains the same.
134  if (button == ui::DIALOG_BUTTON_OK)
135    return l10n_util::GetStringUTF16(IDS_UNINSTALL_BUTTON_TEXT);
136  return views::DialogDelegateView::GetDialogButtonLabel(button);
137}
138
139void UninstallView::ButtonPressed(views::Button* sender,
140                                  const ui::Event& event) {
141  if (change_default_browser_ == sender) {
142    // Disable the browsers combobox if the user unchecks the checkbox.
143    DCHECK(browsers_combo_);
144    browsers_combo_->SetEnabled(change_default_browser_->checked());
145  }
146}
147
148base::string16 UninstallView::GetWindowTitle() const {
149  return l10n_util::GetStringUTF16(IDS_UNINSTALL_CHROME);
150}
151
152int UninstallView::GetItemCount() const {
153  DCHECK(!browsers_->empty());
154  return browsers_->size();
155}
156
157base::string16 UninstallView::GetItemAt(int index) {
158  DCHECK_LT(index, static_cast<int>(browsers_->size()));
159  BrowsersMap::const_iterator i = browsers_->begin();
160  std::advance(i, index);
161  return i->first;
162}
163
164namespace chrome {
165
166int ShowUninstallBrowserPrompt() {
167  DCHECK(base::MessageLoopForUI::IsCurrent());
168  int result = content::RESULT_CODE_NORMAL_EXIT;
169
170  // Take a reference on g_browser_process while showing the dialog. This is
171  // done because the dialog uses the views framework which may increment
172  // and decrement the module ref count during the course of displaying UI and
173  // this code can be called while the module refcount is still at 0.
174  // Note that this reference is never released, as this code is shown on a path
175  // that immediately exits Chrome anyway.
176  // See http://crbug.com/241366 for details.
177  g_browser_process->AddRefModule();
178
179  base::RunLoop run_loop;
180  UninstallView* view = new UninstallView(&result,
181                                          run_loop.QuitClosure());
182  views::DialogDelegate::CreateDialogWidget(view, NULL, NULL)->Show();
183  run_loop.Run();
184  return result;
185}
186
187}  // namespace chrome
188