Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/browser/ui/views/aura/launcher/chrome_launcher_delegate.cc

Issue 9570044: Rename chrome/browser/ui/views/{aura => ash}/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/views/aura/launcher/chrome_launcher_delegate.h"
6
7 #include "ash/launcher/launcher_model.h"
8 #include "ash/launcher/launcher_types.h"
9 #include "ash/wm/window_util.h"
10 #include "base/command_line.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/defaults.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/prefs/incognito_mode_prefs.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/prefs/scoped_user_pref_update.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/tabs/tab_strip_model.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
24 #include "chrome/browser/ui/views/aura/launcher/launcher_context_menu.h"
25 #include "chrome/browser/ui/views/aura/launcher/launcher_icon_loader.h"
26 #include "chrome/browser/ui/views/aura/launcher/launcher_updater.h"
27 #include "chrome/browser/web_applications/web_app.h"
28 #include "chrome/common/chrome_notification_types.h"
29 #include "chrome/common/extensions/extension.h"
30 #include "chrome/common/extensions/extension_resource.h"
31 #include "chrome/common/pref_names.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/web_contents.h"
34 #include "grit/theme_resources.h"
35 #include "ui/aura/window.h"
36 #include "ui/views/widget/widget.h"
37
38 namespace {
39
40 // See description in PersistPinnedState().
41 const char kAppIDPath[] = "id";
42 const char kAppTypePath[] = "type";
43 const char kAppTypeTab[] = "tab";
44 const char kAppTypeWindow[] = "window";
45
46 } // namespace
47
48 // ChromeLauncherDelegate::Item ------------------------------------------------
49
50 ChromeLauncherDelegate::Item::Item()
51 : item_type(TYPE_TABBED_BROWSER),
52 app_type(APP_TYPE_WINDOW),
53 updater(NULL),
54 pinned(false) {
55 }
56
57 ChromeLauncherDelegate::Item::~Item() {
58 }
59
60 // ChromeLauncherDelegate ------------------------------------------------------
61
62 // static
63 ChromeLauncherDelegate* ChromeLauncherDelegate::instance_ = NULL;
64
65 ChromeLauncherDelegate::ChromeLauncherDelegate(Profile* profile,
66 ash::LauncherModel* model)
67 : model_(model),
68 profile_(profile) {
69 if (!profile_) {
70 // Use the original profile as on chromeos we may get a temporary off the
71 // record profile.
72 profile_ = ProfileManager::GetDefaultProfile()->GetOriginalProfile();
73 }
74 instance_ = this;
75 model_->AddObserver(this);
76 app_icon_loader_.reset(new LauncherIconLoader(profile_, this));
77 registrar_.Add(this,
78 chrome::NOTIFICATION_EXTENSION_UNLOADED,
79 content::Source<Profile>(profile_));
80 }
81
82 ChromeLauncherDelegate::~ChromeLauncherDelegate() {
83 model_->RemoveObserver(this);
84 for (IDToItemMap::iterator i = id_to_item_map_.begin();
85 i != id_to_item_map_.end(); ++i) {
86 model_->RemoveItemAt(model_->ItemIndexByID(i->first));
87 }
88 if (instance_ == this)
89 instance_ = NULL;
90 }
91
92 void ChromeLauncherDelegate::Init() {
93 const base::ListValue* pinned_apps =
94 profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
95 for (size_t i = 0; i < pinned_apps->GetSize(); ++i) {
96 DictionaryValue* app = NULL;
97 if (pinned_apps->GetDictionary(i, &app)) {
98 std::string app_id, type_string;
99 if (app->GetString(kAppIDPath, &app_id) &&
100 app->GetString(kAppTypePath, &type_string) &&
101 app_icon_loader_->IsValidID(app_id)) {
102 AppType app_type = (type_string == kAppTypeWindow) ?
103 APP_TYPE_WINDOW : APP_TYPE_TAB;
104 CreateAppLauncherItem(NULL, app_id, app_type);
105 }
106 }
107 }
108 }
109
110 // static
111 void ChromeLauncherDelegate::RegisterUserPrefs(PrefService* user_prefs) {
112 // TODO: If we want to support multiple profiles this will likely need to be
113 // pushed to local state and we'll need to track profile per item.
114 user_prefs->RegisterListPref(prefs::kPinnedLauncherApps,
115 PrefService::SYNCABLE_PREF);
116 }
117
118 ash::LauncherID ChromeLauncherDelegate::CreateTabbedLauncherItem(
119 LauncherUpdater* updater) {
120 // Tabbed items always get a new item. Put the tabbed item before the app
121 // tabs. If there are no app tabs put it at the end.
122 int index = static_cast<int>(model_->items().size());
123 for (IDToItemMap::const_iterator i = id_to_item_map_.begin();
124 i != id_to_item_map_.end(); ++i) {
125 if (i->second.updater == updater) {
126 DCHECK_EQ(TYPE_APP, i->second.item_type);
127 index = std::min(index, model_->ItemIndexByID(i->first));
128 }
129 }
130 ash::LauncherID id = model_->next_id();
131 ash::LauncherItem item(ash::TYPE_TABBED);
132 model_->Add(index, item);
133 DCHECK(id_to_item_map_.find(id) == id_to_item_map_.end());
134 id_to_item_map_[id].item_type = TYPE_TABBED_BROWSER;
135 id_to_item_map_[id].updater = updater;
136 return id;
137 }
138
139 ash::LauncherID ChromeLauncherDelegate::CreateAppLauncherItem(
140 LauncherUpdater* updater,
141 const std::string& app_id,
142 AppType app_type) {
143 // See if we have a closed item that matches the app.
144 if (updater) {
145 for (IDToItemMap::iterator i = id_to_item_map_.begin();
146 i != id_to_item_map_.end(); ++i) {
147 if (i->second.updater == NULL && i->second.app_id == app_id &&
148 i->second.app_type == app_type) {
149 i->second.updater = updater;
150 return i->first;
151 }
152 }
153 }
154
155 // Newly created apps go after all existing apps. If there are no apps put it
156 // at after the tabbed item, and if there is no tabbed item put it at the end.
157 int item_count = static_cast<int>(model_->items().size());
158 int min_app_index = item_count;
159 int min_tab_index = min_app_index;
160 if (updater) {
161 for (IDToItemMap::const_iterator i = id_to_item_map_.begin();
162 i != id_to_item_map_.end(); ++i) {
163 if (i->second.updater == updater) {
164 if (i->second.item_type == TYPE_APP) {
165 min_app_index =
166 std::min(min_app_index, model_->ItemIndexByID(i->first));
167 } else {
168 min_tab_index =
169 std::min(min_app_index, model_->ItemIndexByID(i->first));
170 }
171 }
172 }
173 }
174 int insert_index = min_app_index != item_count ?
175 min_app_index : std::min(item_count, min_tab_index + 1);
176 ash::LauncherID id = model_->next_id();
177 ash::LauncherItem item(ash::TYPE_APP);
178 model_->Add(insert_index, item);
179 DCHECK(id_to_item_map_.find(id) == id_to_item_map_.end());
180 id_to_item_map_[id].item_type = TYPE_APP;
181 id_to_item_map_[id].app_type = app_type;
182 id_to_item_map_[id].app_id = app_id;
183 id_to_item_map_[id].updater = updater;
184 id_to_item_map_[id].pinned = updater == NULL;
185
186 app_icon_loader_->FetchImage(app_id);
187 return id;
188 }
189
190 void ChromeLauncherDelegate::ConvertAppToTabbed(ash::LauncherID id) {
191 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
192 DCHECK_EQ(TYPE_APP, id_to_item_map_[id].item_type);
193 DCHECK(!id_to_item_map_[id].pinned);
194 id_to_item_map_[id].item_type = TYPE_TABBED_BROWSER;
195 id_to_item_map_[id].app_id.clear();
196 }
197
198 void ChromeLauncherDelegate::ConvertTabbedToApp(ash::LauncherID id,
199 const std::string& app_id,
200 AppType app_type) {
201 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
202 DCHECK_EQ(TYPE_TABBED_BROWSER, id_to_item_map_[id].item_type);
203 DCHECK(!id_to_item_map_[id].pinned);
204 id_to_item_map_[id].item_type = TYPE_APP;
205 id_to_item_map_[id].app_type = app_type;
206 id_to_item_map_[id].app_id = app_id;
207
208 ash::LauncherItem item(ash::TYPE_APP);
209 item.id = id;
210 model_->Set(model_->ItemIndexByID(id), item);
211
212 app_icon_loader_->FetchImage(app_id);
213 }
214
215 void ChromeLauncherDelegate::LauncherItemClosed(ash::LauncherID id) {
216 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
217 if (id_to_item_map_[id].pinned) {
218 // The item is pinned, leave it in the launcher.
219 id_to_item_map_[id].updater = NULL;
220 } else {
221 id_to_item_map_.erase(id);
222 model_->RemoveItemAt(model_->ItemIndexByID(id));
223 }
224 }
225
226 void ChromeLauncherDelegate::AppIDChanged(ash::LauncherID id,
227 const std::string& app_id) {
228 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
229 id_to_item_map_[id].app_id = app_id;
230 PersistPinnedState();
231
232 app_icon_loader_->FetchImage(app_id);
233 }
234
235 bool ChromeLauncherDelegate::HasClosedAppItem(const std::string& app_id,
236 AppType app_type) {
237 for (IDToItemMap::const_iterator i = id_to_item_map_.begin();
238 i != id_to_item_map_.end(); ++i) {
239 if (!i->second.updater && i->second.item_type == TYPE_APP &&
240 i->second.app_type == app_type && i->second.app_id == app_id)
241 return true;
242 }
243 return false;
244 }
245
246 void ChromeLauncherDelegate::Pin(ash::LauncherID id) {
247 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
248 id_to_item_map_[id].pinned = true;
249 PersistPinnedState();
250 }
251
252 void ChromeLauncherDelegate::Unpin(ash::LauncherID id) {
253 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
254 id_to_item_map_[id].pinned = false;
255 if (!id_to_item_map_[id].updater)
256 LauncherItemClosed(id);
257 PersistPinnedState();
258 }
259
260 bool ChromeLauncherDelegate::IsPinned(ash::LauncherID id) {
261 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
262 return id_to_item_map_[id].pinned;
263 }
264
265 void ChromeLauncherDelegate::TogglePinned(ash::LauncherID id) {
266 if (id_to_item_map_.find(id) == id_to_item_map_.end())
267 return; // May happen if item closed with menu open.
268
269 if (IsPinned(id))
270 Unpin(id);
271 else
272 Pin(id);
273 }
274
275 bool ChromeLauncherDelegate::IsPinnable(ash::LauncherID id) {
276 return id_to_item_map_.find(id) != id_to_item_map_.end() &&
277 id_to_item_map_[id].item_type == TYPE_APP;
278 }
279
280 void ChromeLauncherDelegate::Open(ash::LauncherID id) {
281 if (id_to_item_map_.find(id) == id_to_item_map_.end())
282 return; // In case invoked from menu and item closed while menu up.
283
284 LauncherUpdater* updater = id_to_item_map_[id].updater;
285 if (updater) {
286 updater->window()->Show();
287 ash::wm::ActivateWindow(updater->window());
288 TabContentsWrapper* tab = updater->GetTab(id);
289 if (tab) {
290 updater->tab_model()->ActivateTabAt(
291 updater->tab_model()->GetIndexOfTabContents(tab), true);
292 }
293 } else {
294 DCHECK_EQ(TYPE_APP, id_to_item_map_[id].item_type);
295 if (id_to_item_map_[id].app_type == APP_TYPE_TAB) {
296 const Extension* extension =
297 profile_->GetExtensionService()->GetInstalledExtension(
298 id_to_item_map_[id].app_id);
299 DCHECK(extension);
300 Browser::OpenApplicationTab(GetProfileForNewWindows(), extension, GURL(),
301 NEW_FOREGROUND_TAB);
302 if (id_to_item_map_[id].updater)
303 id_to_item_map_[id].updater->window()->Show();
304 } else {
305 std::string app_name = web_app::GenerateApplicationNameFromExtensionId(
306 id_to_item_map_[id].app_id);
307 Browser* browser = Browser::CreateForApp(
308 Browser::TYPE_POPUP, app_name, gfx::Rect(),
309 GetProfileForNewWindows());
310 browser->window()->Show();
311 }
312 }
313 }
314
315 void ChromeLauncherDelegate::Close(ash::LauncherID id) {
316 if (id_to_item_map_.find(id) == id_to_item_map_.end())
317 return; // May happen if menu closed.
318
319 if (!id_to_item_map_[id].updater)
320 return; // TODO: maybe should treat as unpin?
321
322 TabContentsWrapper* tab = id_to_item_map_[id].updater->GetTab(id);
323 if (tab) {
324 content::WebContentsDelegate* delegate =
325 tab->web_contents()->GetDelegate();
326 if (delegate)
327 delegate->CloseContents(tab->web_contents());
328 else
329 delete tab;
330 } else {
331 views::Widget* widget = views::Widget::GetWidgetForNativeView(
332 id_to_item_map_[id].updater->window());
333 if (widget)
334 widget->Close();
335 }
336 }
337
338 bool ChromeLauncherDelegate::IsOpen(ash::LauncherID id) {
339 return id_to_item_map_.find(id) != id_to_item_map_.end() &&
340 id_to_item_map_[id].updater != NULL;
341 }
342
343 ChromeLauncherDelegate::AppType ChromeLauncherDelegate::GetAppType(
344 ash::LauncherID id) {
345 DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end());
346 return id_to_item_map_[id].app_type;
347 }
348
349 std::string ChromeLauncherDelegate::GetAppID(TabContentsWrapper* tab) {
350 return app_icon_loader_->GetAppID(tab);
351 }
352
353 void ChromeLauncherDelegate::SetAppImage(const std::string& id,
354 SkBitmap* image) {
355 for (IDToItemMap::const_iterator i = id_to_item_map_.begin();
356 i != id_to_item_map_.end(); ++i) {
357 if (i->second.app_id == id) {
358 int index = model_->ItemIndexByID(i->first);
359 ash::LauncherItem item = model_->items()[index];
360 item.image = image ? *image : Extension::GetDefaultIcon(true);
361 model_->Set(index, item);
362 // It's possible we're waiting on more than one item, so don't break.
363 }
364 }
365 }
366
367 void ChromeLauncherDelegate::CreateNewWindow() {
368 Browser::OpenEmptyWindow(GetProfileForNewWindows());
369 }
370
371 void ChromeLauncherDelegate::ItemClicked(const ash::LauncherItem& item) {
372 DCHECK(id_to_item_map_.find(item.id) != id_to_item_map_.end());
373 Open(item.id);
374 }
375
376 int ChromeLauncherDelegate::GetBrowserShortcutResourceId() {
377 return IDR_PRODUCT_LOGO_32;
378 }
379
380 string16 ChromeLauncherDelegate::GetTitle(const ash::LauncherItem& item) {
381 DCHECK(id_to_item_map_.find(item.id) != id_to_item_map_.end());
382 LauncherUpdater* updater = id_to_item_map_[item.id].updater;
383 if (updater) {
384 if (id_to_item_map_[item.id].item_type == TYPE_TABBED_BROWSER) {
385 return updater->tab_model()->GetActiveTabContents() ?
386 updater->tab_model()->GetActiveTabContents()->web_contents()->
387 GetTitle() : string16();
388 }
389 // Fall through to get title from extension.
390 }
391 const Extension* extension = profile_->GetExtensionService()->
392 GetInstalledExtension(id_to_item_map_[item.id].app_id);
393 return extension ? UTF8ToUTF16(extension->name()) : string16();
394 }
395
396 ui::MenuModel* ChromeLauncherDelegate::CreateContextMenu(
397 const ash::LauncherItem& item) {
398 return new LauncherContextMenu(this, item.id);
399 }
400
401 void ChromeLauncherDelegate::LauncherItemAdded(int index) {
402 }
403
404 void ChromeLauncherDelegate::LauncherItemRemoved(int index,
405 ash::LauncherID id) {
406 }
407
408 void ChromeLauncherDelegate::LauncherItemMoved(
409 int start_index,
410 int target_index) {
411 ash::LauncherID id = model_->items()[target_index].id;
412 if (id_to_item_map_.find(id) != id_to_item_map_.end() &&
413 id_to_item_map_[id].pinned) {
414 PersistPinnedState();
415 }
416 }
417
418 void ChromeLauncherDelegate::LauncherItemChanged(
419 int index,
420 const ash::LauncherItem& old_item) {
421 }
422
423 void ChromeLauncherDelegate::LauncherItemWillChange(int index) {
424 }
425
426 void ChromeLauncherDelegate::Observe(
427 int type,
428 const content::NotificationSource& source,
429 const content::NotificationDetails& details) {
430 DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED);
431 const Extension* extension =
432 content::Details<UnloadedExtensionInfo>(details)->extension;
433 UnpinAppsWithID(extension->id());
434 }
435
436 void ChromeLauncherDelegate::PersistPinnedState() {
437 ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
438 updater.Get()->Clear();
439 for (size_t i = 0; i < model_->items().size(); ++i) {
440 if (model_->items()[i].type == ash::TYPE_APP) {
441 ash::LauncherID id = model_->items()[i].id;
442 if (id_to_item_map_.find(id) != id_to_item_map_.end() &&
443 id_to_item_map_[id].pinned) {
444 base::DictionaryValue* app_value = new base::DictionaryValue;
445 app_value->SetString(kAppIDPath, id_to_item_map_[id].app_id);
446 const char* app_type_string =
447 id_to_item_map_[id].app_type == APP_TYPE_WINDOW ?
448 kAppTypeWindow : kAppTypeTab;
449 app_value->SetString(kAppTypePath, app_type_string);
450 updater.Get()->Append(app_value);
451 }
452 }
453 }
454 }
455
456 void ChromeLauncherDelegate::UnpinAppsWithID(const std::string& app_id) {
457 for (IDToItemMap::iterator i = id_to_item_map_.begin();
458 i != id_to_item_map_.end(); ) {
459 IDToItemMap::iterator current(i);
460 ++i;
461 if (current->second.app_id == app_id && current->second.pinned)
462 Unpin(current->first);
463 }
464 }
465
466 void ChromeLauncherDelegate::SetAppIconLoaderForTest(AppIconLoader* loader) {
467 app_icon_loader_.reset(loader);
468 }
469
470 Profile* ChromeLauncherDelegate::GetProfileForNewWindows() {
471 Profile* profile = ProfileManager::GetDefaultProfile();
472 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
473 IncognitoModePrefs::ShouldLaunchIncognito(
474 *CommandLine::ForCurrentProcess(),
475 profile->GetPrefs())) {
476 profile = profile->GetOffTheRecordProfile();
477 }
478 return profile;
479 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698