app_info_permissions_panel.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/apps/app_info_dialog/app_info_permissions_panel.h"
6
7#include <string>
8#include <vector>
9
10#include "apps/app_load_service.h"
11#include "apps/saved_files_service.h"
12#include "base/files/file_path.h"
13#include "chrome/grit/generated_resources.h"
14#include "extensions/common/extension.h"
15#include "extensions/common/permissions/api_permission.h"
16#include "extensions/common/permissions/permissions_data.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/views/controls/button/label_button.h"
19#include "ui/views/controls/label.h"
20#include "ui/views/layout/box_layout.h"
21#include "ui/views/layout/grid_layout.h"
22#include "ui/views/layout/layout_constants.h"
23#include "ui/views/view.h"
24#include "ui/views/widget/widget.h"
25
26AppInfoPermissionsPanel::AppInfoPermissionsPanel(
27    Profile* profile,
28    const extensions::Extension* app)
29    : AppInfoPanel(profile, app),
30      active_permissions_heading_(NULL),
31      active_permissions_list_(NULL),
32      retained_files_heading_(NULL),
33      retained_files_list_(NULL),
34      revoke_file_permissions_button_(NULL) {
35  // Create UI elements.
36  CreateActivePermissionsControl();
37  CreateRetainedFilesControl();
38
39  // Layout elements.
40  SetLayoutManager(
41      new views::BoxLayout(views::BoxLayout::kVertical,
42                           0,
43                           0,
44                           views::kUnrelatedControlVerticalSpacing));
45
46  LayoutActivePermissionsControl();
47  LayoutRetainedFilesControl();
48}
49
50AppInfoPermissionsPanel::~AppInfoPermissionsPanel() {
51  // Destroy view children before their models.
52  RemoveAllChildViews(true);
53}
54
55// Given a list of strings, returns a view containing a list of these strings
56// as bulleted items.
57views::View* AppInfoPermissionsPanel::CreateBulletedListView(
58    const std::vector<base::string16>& messages,
59    bool allow_multiline,
60    gfx::ElideBehavior elide_behavior) {
61  const int kSpacingBetweenBulletAndStartOfText = 5;
62
63  views::View* list_view = new views::View();
64  views::GridLayout* layout = new views::GridLayout(list_view);
65  list_view->SetLayoutManager(layout);
66
67  // Create 2 columns: one for the bullet, one for the bullet text.
68  static const int kColumnSetId = 1;
69  views::ColumnSet* column_set = layout->AddColumnSet(kColumnSetId);
70  column_set->AddColumn(views::GridLayout::FILL,
71                        views::GridLayout::LEADING,
72                        0,
73                        views::GridLayout::USE_PREF,
74                        0,
75                        0);
76  column_set->AddPaddingColumn(0, kSpacingBetweenBulletAndStartOfText);
77  column_set->AddColumn(views::GridLayout::FILL,
78                        views::GridLayout::LEADING,
79                        1,
80                        views::GridLayout::USE_PREF,
81                        0,
82                        0);
83
84  for (std::vector<base::string16>::const_iterator it = messages.begin();
85       it != messages.end();
86       ++it) {
87    views::Label* permission_label = new views::Label(*it);
88    permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
89
90    if (allow_multiline)
91      permission_label->SetMultiLine(true);
92    else
93      permission_label->SetElideBehavior(elide_behavior);
94
95    // Extract only the bullet from the IDS_EXTENSION_PERMISSION_LINE text.
96    views::Label* bullet_label = new views::Label(l10n_util::GetStringFUTF16(
97        IDS_EXTENSION_PERMISSION_LINE, base::string16()));
98
99    // Add a padding row before every item except the first
100    if (it != messages.begin())
101      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
102
103    layout->StartRow(1, kColumnSetId);
104    layout->AddView(bullet_label);
105    layout->AddView(permission_label);
106  }
107
108  return list_view;
109}
110
111void AppInfoPermissionsPanel::CreateActivePermissionsControl() {
112  std::vector<base::string16> permission_strings =
113      GetActivePermissionMessages();
114  if (permission_strings.empty()) {
115    views::Label* no_permissions_text = new views::Label(
116        l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_NO_PERMISSIONS_TEXT));
117    no_permissions_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
118    active_permissions_list_ = no_permissions_text;
119  } else {
120    active_permissions_heading_ = CreateHeading(l10n_util::GetStringUTF16(
121        IDS_APPLICATION_INFO_ACTIVE_PERMISSIONS_TEXT));
122    active_permissions_list_ =
123        CreateBulletedListView(permission_strings, true, gfx::NO_ELIDE);
124  }
125}
126
127void AppInfoPermissionsPanel::CreateRetainedFilesControl() {
128  const std::vector<base::string16> retained_file_permission_messages =
129      GetRetainedFilePaths();
130
131  if (!retained_file_permission_messages.empty()) {
132    revoke_file_permissions_button_ = new views::LabelButton(
133        this,
134        l10n_util::GetStringUTF16(
135            IDS_APPLICATION_INFO_REVOKE_RETAINED_FILE_PERMISSIONS_BUTTON_TEXT));
136    revoke_file_permissions_button_->SetStyle(views::Button::STYLE_BUTTON);
137
138    retained_files_heading_ = CreateHeading(l10n_util::GetStringUTF16(
139        IDS_APPLICATION_INFO_RETAINED_FILE_PERMISSIONS_TEXT));
140    retained_files_list_ = CreateBulletedListView(
141        retained_file_permission_messages, false, gfx::ELIDE_MIDDLE);
142  }
143}
144
145void AppInfoPermissionsPanel::LayoutActivePermissionsControl() {
146  if (active_permissions_list_) {
147    views::View* vertical_stack = CreateVerticalStack();
148    if (active_permissions_heading_)
149      vertical_stack->AddChildView(active_permissions_heading_);
150    vertical_stack->AddChildView(active_permissions_list_);
151
152    AddChildView(vertical_stack);
153  }
154}
155
156void AppInfoPermissionsPanel::LayoutRetainedFilesControl() {
157  if (retained_files_list_) {
158    DCHECK(retained_files_heading_);
159    DCHECK(revoke_file_permissions_button_);
160
161    // Add a sub-view so the revoke button is right-aligned.
162    views::View* right_aligned_button = new views::View();
163    views::BoxLayout* right_aligned_horizontal_layout =
164        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
165    right_aligned_horizontal_layout->set_main_axis_alignment(
166        views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
167    right_aligned_button->SetLayoutManager(right_aligned_horizontal_layout);
168    right_aligned_button->AddChildView(revoke_file_permissions_button_);
169
170    views::View* vertical_stack = CreateVerticalStack();
171    vertical_stack->AddChildView(retained_files_heading_);
172    vertical_stack->AddChildView(retained_files_list_);
173    vertical_stack->AddChildView(right_aligned_button);
174
175    AddChildView(vertical_stack);
176  }
177}
178
179void AppInfoPermissionsPanel::ButtonPressed(views::Button* sender,
180                                            const ui::Event& event) {
181  if (sender == revoke_file_permissions_button_) {
182    RevokeFilePermissions();
183  } else {
184    NOTREACHED();
185  }
186}
187
188const std::vector<base::string16>
189AppInfoPermissionsPanel::GetActivePermissionMessages() const {
190  return app_->permissions_data()->GetPermissionMessageStrings();
191}
192
193const std::vector<base::string16>
194AppInfoPermissionsPanel::GetRetainedFilePaths() const {
195  std::vector<base::string16> retained_file_paths;
196  if (app_->permissions_data()->HasAPIPermission(
197          extensions::APIPermission::kFileSystem)) {
198    std::vector<apps::SavedFileEntry> retained_file_entries =
199        apps::SavedFilesService::Get(profile_)->GetAllFileEntries(app_->id());
200    for (std::vector<apps::SavedFileEntry>::const_iterator it =
201             retained_file_entries.begin();
202         it != retained_file_entries.end();
203         ++it) {
204      retained_file_paths.push_back(it->path.LossyDisplayName());
205    }
206  }
207  return retained_file_paths;
208}
209
210void AppInfoPermissionsPanel::RevokeFilePermissions() {
211  apps::SavedFilesService::Get(profile_)->ClearQueue(app_);
212  apps::AppLoadService::Get(profile_)->RestartApplicationIfRunning(app_->id());
213
214  GetWidget()->Close();
215}
216