Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media_galleries / media_galleries_dialog_controller.cc
blob91d0bd3f94fa847ceff00938cd6775566853dae2
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.
5 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
7 #include "base/base_paths.h"
8 #include "base/path_service.h"
9 #include "base/stl_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
13 #include "chrome/browser/extensions/extension_prefs.h"
14 #include "chrome/browser/media_galleries/media_file_system_registry.h"
15 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/storage_monitor/storage_info.h"
18 #include "chrome/browser/storage_monitor/storage_monitor.h"
19 #include "chrome/browser/ui/chrome_select_file_policy.h"
20 #include "chrome/common/extensions/permissions/media_galleries_permission.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_view.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/permissions/permissions_data.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/models/simple_menu_model.h"
28 #include "ui/base/text/bytes_formatting.h"
30 using extensions::APIPermission;
31 using extensions::Extension;
33 namespace {
35 // Comparator for sorting GalleryPermissionsVector -- sorts
36 // allowed galleries low, and then sorts by absolute path.
37 bool GalleriesVectorComparator(
38 const MediaGalleriesDialogController::GalleryPermission& a,
39 const MediaGalleriesDialogController::GalleryPermission& b) {
40 if (a.allowed && !b.allowed)
41 return true;
42 if (!a.allowed && b.allowed)
43 return false;
45 return a.pref_info.AbsolutePath() < b.pref_info.AbsolutePath();
48 } // namespace
50 class GalleryContextMenuModel : public ui::SimpleMenuModel::Delegate {
51 public:
52 explicit GalleryContextMenuModel(MediaGalleriesDialogController* controller)
53 : controller_(controller), id_(kInvalidMediaGalleryPrefId) {}
54 virtual ~GalleryContextMenuModel() {}
56 void set_media_gallery_pref_id(MediaGalleryPrefId id) {
57 id_ = id;
60 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
61 return false;
63 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
64 return true;
66 virtual bool IsCommandIdVisible(int command_id) const OVERRIDE {
67 return true;
70 virtual bool GetAcceleratorForCommandId(
71 int command_id, ui::Accelerator* accelerator) OVERRIDE {
72 return false;
75 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
76 controller_->DidForgetGallery(id_);
79 private:
80 MediaGalleriesDialogController* controller_;
81 MediaGalleryPrefId id_;
84 MediaGalleriesDialogController::MediaGalleriesDialogController(
85 content::WebContents* web_contents,
86 const Extension& extension,
87 const base::Closure& on_finish)
88 : web_contents_(web_contents),
89 extension_(&extension),
90 on_finish_(on_finish) {
91 preferences_ =
92 g_browser_process->media_file_system_registry()->GetPreferences(
93 GetProfile());
94 // Passing unretained pointer is safe, since the dialog controller
95 // is self-deleting, and so won't be deleted until it can be shown
96 // and then closed.
97 preferences_->EnsureInitialized(
98 base::Bind(&MediaGalleriesDialogController::OnPreferencesInitialized,
99 base::Unretained(this)));
101 gallery_menu_model_.reset(new GalleryContextMenuModel(this));
102 ui::SimpleMenuModel* menu_model =
103 new ui::SimpleMenuModel(gallery_menu_model_.get());
104 menu_model->AddItem(
105 1, l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_DELETE));
106 context_menu_model_.reset(menu_model);
109 void MediaGalleriesDialogController::OnPreferencesInitialized() {
110 InitializePermissions();
112 dialog_.reset(MediaGalleriesDialog::Create(this));
114 StorageMonitor::GetInstance()->AddObserver(this);
116 preferences_->AddGalleryChangeObserver(this);
119 MediaGalleriesDialogController::MediaGalleriesDialogController(
120 const extensions::Extension& extension)
121 : web_contents_(NULL),
122 extension_(&extension),
123 preferences_(NULL) {}
125 MediaGalleriesDialogController::~MediaGalleriesDialogController() {
126 if (StorageMonitor::GetInstance())
127 StorageMonitor::GetInstance()->RemoveObserver(this);
129 if (select_folder_dialog_.get())
130 select_folder_dialog_->ListenerDestroyed();
133 base::string16 MediaGalleriesDialogController::GetHeader() const {
134 return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER,
135 base::UTF8ToUTF16(extension_->name()));
138 base::string16 MediaGalleriesDialogController::GetSubtext() const {
139 extensions::MediaGalleriesPermission::CheckParam copy_to_param(
140 extensions::MediaGalleriesPermission::kCopyToPermission);
141 extensions::MediaGalleriesPermission::CheckParam delete_param(
142 extensions::MediaGalleriesPermission::kDeletePermission);
143 bool has_copy_to_permission =
144 extensions::PermissionsData::CheckAPIPermissionWithParam(
145 extension_, APIPermission::kMediaGalleries, &copy_to_param);
146 bool has_delete_permission =
147 extensions::PermissionsData::CheckAPIPermissionWithParam(
148 extension_, APIPermission::kMediaGalleries, &delete_param);
150 int id;
151 if (has_copy_to_permission)
152 id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_WRITE;
153 else if (has_delete_permission)
154 id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_DELETE;
155 else
156 id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_ONLY;
158 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()));
161 base::string16 MediaGalleriesDialogController::GetUnattachedLocationsHeader()
162 const {
163 return l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_UNATTACHED_LOCATIONS);
166 // TODO(gbillock): Call this something a bit more connected to the
167 // messaging in the dialog.
168 bool MediaGalleriesDialogController::HasPermittedGalleries() const {
169 for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
170 iter != known_galleries_.end(); ++iter) {
171 if (iter->second.allowed)
172 return true;
175 // Do this? Views did.
176 if (new_galleries_.size() > 0)
177 return true;
179 return false;
182 // Note: sorts by display criterion: GalleriesVectorComparator.
183 void MediaGalleriesDialogController::FillPermissions(
184 bool attached,
185 MediaGalleriesDialogController::GalleryPermissionsVector* permissions)
186 const {
187 for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
188 iter != known_galleries_.end(); ++iter) {
189 if (attached == iter->second.pref_info.IsGalleryAvailable())
190 permissions->push_back(iter->second);
192 for (GalleryPermissionsVector::const_iterator iter = new_galleries_.begin();
193 iter != new_galleries_.end(); ++iter) {
194 if (attached == iter->pref_info.IsGalleryAvailable())
195 permissions->push_back(*iter);
198 std::sort(permissions->begin(), permissions->end(),
199 GalleriesVectorComparator);
202 MediaGalleriesDialogController::GalleryPermissionsVector
203 MediaGalleriesDialogController::AttachedPermissions() const {
204 GalleryPermissionsVector attached;
205 FillPermissions(true, &attached);
206 return attached;
209 MediaGalleriesDialogController::GalleryPermissionsVector
210 MediaGalleriesDialogController::UnattachedPermissions() const {
211 GalleryPermissionsVector unattached;
212 FillPermissions(false, &unattached);
213 return unattached;
216 void MediaGalleriesDialogController::OnAddFolderClicked() {
217 base::FilePath default_path =
218 extensions::file_system_api::GetLastChooseEntryDirectory(
219 extensions::ExtensionPrefs::Get(GetProfile()), extension_->id());
220 if (default_path.empty())
221 PathService::Get(base::DIR_USER_DESKTOP, &default_path);
222 select_folder_dialog_ =
223 ui::SelectFileDialog::Create(this, new ChromeSelectFilePolicy(NULL));
224 select_folder_dialog_->SelectFile(
225 ui::SelectFileDialog::SELECT_FOLDER,
226 l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY_TITLE),
227 default_path,
228 NULL,
230 base::FilePath::StringType(),
231 web_contents_->GetView()->GetTopLevelNativeWindow(),
232 NULL);
235 void MediaGalleriesDialogController::DidToggleGalleryId(
236 MediaGalleryPrefId gallery_id,
237 bool enabled) {
238 // Check known galleries.
239 KnownGalleryPermissions::iterator iter =
240 known_galleries_.find(gallery_id);
241 if (iter != known_galleries_.end()) {
242 if (iter->second.allowed == enabled)
243 return;
245 iter->second.allowed = enabled;
246 if (ContainsKey(toggled_galleries_, gallery_id))
247 toggled_galleries_.erase(gallery_id);
248 else
249 toggled_galleries_.insert(gallery_id);
250 return;
253 // Don't sort -- the dialog is open, and we don't want to adjust any
254 // positions for future updates to the dialog contents until they are
255 // redrawn.
258 void MediaGalleriesDialogController::DidToggleNewGallery(
259 const MediaGalleryPrefInfo& gallery,
260 bool enabled) {
261 for (GalleryPermissionsVector::iterator iter = new_galleries_.begin();
262 iter != new_galleries_.end(); ++iter) {
263 if (iter->pref_info.path == gallery.path &&
264 iter->pref_info.device_id == gallery.device_id) {
265 iter->allowed = enabled;
266 return;
271 void MediaGalleriesDialogController::DidForgetGallery(
272 MediaGalleryPrefId pref_id) {
273 DCHECK(preferences_);
274 preferences_->ForgetGalleryById(pref_id);
277 void MediaGalleriesDialogController::DialogFinished(bool accepted) {
278 // The dialog has finished, so there is no need to watch for more updates
279 // from |preferences_|. Do this here and not in the dtor since this is the
280 // only non-test code path that deletes |this|. The test ctor never adds
281 // this observer in the first place.
282 preferences_->RemoveGalleryChangeObserver(this);
284 if (accepted)
285 SavePermissions();
287 on_finish_.Run();
288 delete this;
291 content::WebContents* MediaGalleriesDialogController::web_contents() {
292 return web_contents_;
295 void MediaGalleriesDialogController::FileSelected(const base::FilePath& path,
296 int /*index*/,
297 void* /*params*/) {
298 extensions::file_system_api::SetLastChooseEntryDirectory(
299 extensions::ExtensionPrefs::Get(GetProfile()),
300 extension_->id(),
301 path);
303 // Try to find it in the prefs.
304 MediaGalleryPrefInfo gallery;
305 bool gallery_exists = preferences_->LookUpGalleryByPath(path, &gallery);
306 if (gallery_exists && !gallery.IsBlackListedType()) {
307 // The prefs are in sync with |known_galleries_|, so it should exist in
308 // |known_galleries_| as well. User selecting a known gallery effectively
309 // just sets the gallery to permitted.
310 DCHECK(ContainsKey(known_galleries_, gallery.pref_id));
311 dialog_->UpdateGalleries();
312 return;
315 // Try to find it in |new_galleries_| (user added same folder twice).
316 for (GalleryPermissionsVector::iterator iter = new_galleries_.begin();
317 iter != new_galleries_.end(); ++iter) {
318 if (iter->pref_info.path == gallery.path &&
319 iter->pref_info.device_id == gallery.device_id) {
320 iter->allowed = true;
321 dialog_->UpdateGalleries();
322 return;
326 // Lastly, if not found, add a new gallery to |new_galleries_|.
327 // Note that it will have prefId = kInvalidMediaGalleryPrefId.
328 new_galleries_.push_back(GalleryPermission(gallery, true));
329 dialog_->UpdateGalleries();
332 void MediaGalleriesDialogController::OnRemovableStorageAttached(
333 const StorageInfo& info) {
334 UpdateGalleriesOnDeviceEvent(info.device_id());
337 void MediaGalleriesDialogController::OnRemovableStorageDetached(
338 const StorageInfo& info) {
339 UpdateGalleriesOnDeviceEvent(info.device_id());
342 void MediaGalleriesDialogController::OnPermissionAdded(
343 MediaGalleriesPreferences* /* prefs */,
344 const std::string& extension_id,
345 MediaGalleryPrefId /* pref_id */) {
346 if (extension_id != extension_->id())
347 return;
348 UpdateGalleriesOnPreferencesEvent();
351 void MediaGalleriesDialogController::OnPermissionRemoved(
352 MediaGalleriesPreferences* /* prefs */,
353 const std::string& extension_id,
354 MediaGalleryPrefId /* pref_id */) {
355 if (extension_id != extension_->id())
356 return;
357 UpdateGalleriesOnPreferencesEvent();
360 void MediaGalleriesDialogController::OnGalleryAdded(
361 MediaGalleriesPreferences* /* prefs */,
362 MediaGalleryPrefId /* pref_id */) {
363 UpdateGalleriesOnPreferencesEvent();
366 void MediaGalleriesDialogController::OnGalleryRemoved(
367 MediaGalleriesPreferences* /* prefs */,
368 MediaGalleryPrefId /* pref_id */) {
369 UpdateGalleriesOnPreferencesEvent();
372 void MediaGalleriesDialogController::OnGalleryInfoUpdated(
373 MediaGalleriesPreferences* prefs,
374 MediaGalleryPrefId pref_id) {
375 const MediaGalleriesPrefInfoMap& pref_galleries =
376 preferences_->known_galleries();
377 MediaGalleriesPrefInfoMap::const_iterator pref_it =
378 pref_galleries.find(pref_id);
379 if (pref_it == pref_galleries.end())
380 return;
381 const MediaGalleryPrefInfo& gallery_info = pref_it->second;
382 UpdateGalleriesOnDeviceEvent(gallery_info.device_id);
385 void MediaGalleriesDialogController::InitializePermissions() {
386 known_galleries_.clear();
387 const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
388 for (MediaGalleriesPrefInfoMap::const_iterator iter = galleries.begin();
389 iter != galleries.end();
390 ++iter) {
391 const MediaGalleryPrefInfo& gallery = iter->second;
392 if (gallery.type == MediaGalleryPrefInfo::kBlackListed) {
393 continue;
396 known_galleries_[iter->first] = GalleryPermission(gallery, false);
399 MediaGalleryPrefIdSet permitted =
400 preferences_->GalleriesForExtension(*extension_);
402 for (MediaGalleryPrefIdSet::iterator iter = permitted.begin();
403 iter != permitted.end(); ++iter) {
404 if (ContainsKey(toggled_galleries_, *iter))
405 continue;
406 DCHECK(ContainsKey(known_galleries_, *iter));
407 known_galleries_[*iter].allowed = true;
411 void MediaGalleriesDialogController::SavePermissions() {
412 media_galleries::UsageCount(media_galleries::SAVE_DIALOG);
413 for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
414 iter != known_galleries_.end(); ++iter) {
415 bool changed = preferences_->SetGalleryPermissionForExtension(
416 *extension_, iter->first, iter->second.allowed);
417 if (changed) {
418 if (iter->second.allowed)
419 media_galleries::UsageCount(media_galleries::DIALOG_PERMISSION_ADDED);
420 else
421 media_galleries::UsageCount(media_galleries::DIALOG_PERMISSION_REMOVED);
425 for (GalleryPermissionsVector::const_iterator iter = new_galleries_.begin();
426 iter != new_galleries_.end(); ++iter) {
427 media_galleries::UsageCount(media_galleries::DIALOG_GALLERY_ADDED);
428 // If the user added a gallery then unchecked it, forget about it.
429 if (!iter->allowed)
430 continue;
432 // TODO(gbillock): Should be adding volume metadata during FileSelected.
433 const MediaGalleryPrefInfo& gallery = iter->pref_info;
434 MediaGalleryPrefId id = preferences_->AddGallery(
435 gallery.device_id, gallery.path, MediaGalleryPrefInfo::kUserAdded,
436 gallery.volume_label, gallery.vendor_name, gallery.model_name,
437 gallery.total_size_in_bytes, gallery.last_attach_time, 0, 0, 0);
438 preferences_->SetGalleryPermissionForExtension(*extension_, id, true);
442 void MediaGalleriesDialogController::UpdateGalleriesOnPreferencesEvent() {
443 // Merge in the permissions from |preferences_|. Afterwards,
444 // |known_galleries_| may contain galleries that no longer belong there,
445 // but the code below will put |known_galleries_| back in a consistent state.
446 InitializePermissions();
448 // Look for duplicate entries in |new_galleries_| in case one was added
449 // in another dialog.
450 for (KnownGalleryPermissions::iterator it = known_galleries_.begin();
451 it != known_galleries_.end();
452 ++it) {
453 GalleryPermission& gallery = it->second;
454 for (GalleryPermissionsVector::iterator new_it = new_galleries_.begin();
455 new_it != new_galleries_.end();
456 ++new_it) {
457 if (new_it->pref_info.path == gallery.pref_info.path &&
458 new_it->pref_info.device_id == gallery.pref_info.device_id) {
459 // Found duplicate entry. Get the existing permission from it and then
460 // remove it.
461 gallery.allowed = new_it->allowed;
462 new_galleries_.erase(new_it);
463 break;
468 dialog_->UpdateGalleries();
471 void MediaGalleriesDialogController::UpdateGalleriesOnDeviceEvent(
472 const std::string& device_id) {
473 dialog_->UpdateGalleries();
476 ui::MenuModel* MediaGalleriesDialogController::GetContextMenuModel(
477 MediaGalleryPrefId id) {
478 gallery_menu_model_->set_media_gallery_pref_id(id);
479 return context_menu_model_.get();
482 Profile* MediaGalleriesDialogController::GetProfile() {
483 return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
486 // MediaGalleries dialog -------------------------------------------------------
488 MediaGalleriesDialog::~MediaGalleriesDialog() {}