| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" | 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "ash/ash_switches.h" | 9 #include "ash/ash_switches.h" |
| 10 #include "ash/desktop_background/desktop_background_controller.h" | 10 #include "ash/desktop_background/desktop_background_controller.h" |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 Profile* profile, | 326 Profile* profile, |
| 327 ash::LauncherModel* model) { | 327 ash::LauncherModel* model) { |
| 328 // We do not check here for re-creation of the ChromeLauncherController since | 328 // We do not check here for re-creation of the ChromeLauncherController since |
| 329 // it appears that it might be intentional that the ChromeLauncherController | 329 // it appears that it might be intentional that the ChromeLauncherController |
| 330 // can be re-created. | 330 // can be re-created. |
| 331 instance_ = new ChromeLauncherController(profile, model); | 331 instance_ = new ChromeLauncherController(profile, model); |
| 332 return instance_; | 332 return instance_; |
| 333 } | 333 } |
| 334 | 334 |
| 335 void ChromeLauncherController::Init() { | 335 void ChromeLauncherController::Init() { |
| 336 CreateBrowserShortcutLauncherItem(); |
| 336 UpdateAppLaunchersFromPref(); | 337 UpdateAppLaunchersFromPref(); |
| 337 CreateBrowserShortcutLauncherItem(); | |
| 338 | 338 |
| 339 // TODO(sky): update unit test so that this test isn't necessary. | 339 // TODO(sky): update unit test so that this test isn't necessary. |
| 340 if (ash::Shell::HasInstance()) { | 340 if (ash::Shell::HasInstance()) { |
| 341 SetShelfAutoHideBehaviorFromPrefs(); | 341 SetShelfAutoHideBehaviorFromPrefs(); |
| 342 SetShelfAlignmentFromPrefs(); | 342 SetShelfAlignmentFromPrefs(); |
| 343 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); | 343 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); |
| 344 if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() || | 344 if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() || |
| 345 !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)-> | 345 !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)-> |
| 346 HasUserSetting()) { | 346 HasUserSetting()) { |
| 347 // This causes OnIsSyncingChanged to be called when the value of | 347 // This causes OnIsSyncingChanged to be called when the value of |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 } | 429 } |
| 430 | 430 |
| 431 if (CanPin()) | 431 if (CanPin()) |
| 432 PersistPinnedState(); | 432 PersistPinnedState(); |
| 433 } | 433 } |
| 434 | 434 |
| 435 void ChromeLauncherController::Unpin(ash::LauncherID id) { | 435 void ChromeLauncherController::Unpin(ash::LauncherID id) { |
| 436 DCHECK(HasItemController(id)); | 436 DCHECK(HasItemController(id)); |
| 437 | 437 |
| 438 LauncherItemController* controller = id_to_item_controller_map_[id]; | 438 LauncherItemController* controller = id_to_item_controller_map_[id]; |
| 439 if (controller->type() == LauncherItemController::TYPE_APP) { | 439 if (controller->type() == LauncherItemController::TYPE_APP || |
| 440 int index = model_->ItemIndexByID(id); | 440 controller->locked()) { |
| 441 DCHECK_GE(index, 0); | 441 UnpinRunningAppInternal(model_->ItemIndexByID(id)); |
| 442 ash::LauncherItem item = model_->items()[index]; | |
| 443 item.type = ash::TYPE_PLATFORM_APP; | |
| 444 model_->Set(index, item); | |
| 445 } else { | 442 } else { |
| 446 // Prevent the removal of items upon unpin if it is locked by a running | 443 LauncherItemClosed(id); |
| 447 // windowed V1 app. | |
| 448 if (!controller->locked()) { | |
| 449 LauncherItemClosed(id); | |
| 450 } else { | |
| 451 int index = model_->ItemIndexByID(id); | |
| 452 DCHECK_GE(index, 0); | |
| 453 ash::LauncherItem item = model_->items()[index]; | |
| 454 item.type = ash::TYPE_WINDOWED_APP; | |
| 455 model_->Set(index, item); | |
| 456 } | |
| 457 } | 444 } |
| 458 if (CanPin()) | 445 if (CanPin()) |
| 459 PersistPinnedState(); | 446 PersistPinnedState(); |
| 460 } | 447 } |
| 461 | 448 |
| 462 bool ChromeLauncherController::IsPinned(ash::LauncherID id) { | 449 bool ChromeLauncherController::IsPinned(ash::LauncherID id) { |
| 463 int index = model_->ItemIndexByID(id); | 450 int index = model_->ItemIndexByID(id); |
| 464 if (index < 0) | 451 if (index < 0) |
| 465 return false; | 452 return false; |
| 466 ash::LauncherItemType type = model_->items()[index].type; | 453 ash::LauncherItemType type = model_->items()[index].type; |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 if (ignore_persist_pinned_state_change_) | 720 if (ignore_persist_pinned_state_change_) |
| 734 return; | 721 return; |
| 735 // It is a coding error to call PersistPinnedState() if the pinned apps are | 722 // It is a coding error to call PersistPinnedState() if the pinned apps are |
| 736 // not user-editable. The code should check earlier and not perform any | 723 // not user-editable. The code should check earlier and not perform any |
| 737 // modification actions that trigger persisting the state. | 724 // modification actions that trigger persisting the state. |
| 738 if (!CanPin()) { | 725 if (!CanPin()) { |
| 739 NOTREACHED() << "Can't pin but pinned state being updated"; | 726 NOTREACHED() << "Can't pin but pinned state being updated"; |
| 740 return; | 727 return; |
| 741 } | 728 } |
| 742 | 729 |
| 730 // With the alternate shelf layout, the app list is locked in position #0. |
| 731 // Since the app list does not have any impact on the rest of the order, |
| 732 // we need to keep track of its appearance so that the chrome icon position |
| 733 // is at the proper location (backwards compatible). |
| 734 size_t app_list_index_offset = 0; |
| 735 |
| 743 // Mutating kPinnedLauncherApps is going to notify us and trigger us to | 736 // Mutating kPinnedLauncherApps is going to notify us and trigger us to |
| 744 // process the change. We don't want that to happen so remove ourselves as a | 737 // process the change. We don't want that to happen so remove ourselves as a |
| 745 // listener. | 738 // listener. |
| 746 pref_change_registrar_.Remove(prefs::kPinnedLauncherApps); | 739 pref_change_registrar_.Remove(prefs::kPinnedLauncherApps); |
| 747 { | 740 { |
| 748 ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps); | 741 ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps); |
| 749 updater->Clear(); | 742 updater->Clear(); |
| 750 for (size_t i = 0; i < model_->items().size(); ++i) { | 743 for (size_t i = 0; i < model_->items().size(); ++i) { |
| 751 if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) { | 744 if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) { |
| 752 ash::LauncherID id = model_->items()[i].id; | 745 ash::LauncherID id = model_->items()[i].id; |
| 753 if (HasItemController(id) && IsPinned(id)) { | 746 if (HasItemController(id) && IsPinned(id)) { |
| 754 base::DictionaryValue* app_value = ash::CreateAppDict( | 747 base::DictionaryValue* app_value = ash::CreateAppDict( |
| 755 id_to_item_controller_map_[id]->app_id()); | 748 id_to_item_controller_map_[id]->app_id()); |
| 756 if (app_value) | 749 if (app_value) |
| 757 updater->Append(app_value); | 750 updater->Append(app_value); |
| 758 } | 751 } |
| 759 } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) { | 752 } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) { |
| 760 PersistChromeItemIndex(i); | 753 PersistChromeItemIndex(i - app_list_index_offset); |
| 754 } else if (model_->items()[i].type == ash::TYPE_APP_LIST && |
| 755 ash::switches::UseAlternateShelfLayout()) { |
| 756 // With the new alternate shelf layout the app list can be pinned to the |
| 757 // position 0 and should not be taken into account. |
| 758 app_list_index_offset = 1; |
| 761 } | 759 } |
| 762 } | 760 } |
| 763 } | 761 } |
| 764 pref_change_registrar_.Add( | 762 pref_change_registrar_.Add( |
| 765 prefs::kPinnedLauncherApps, | 763 prefs::kPinnedLauncherApps, |
| 766 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref, | 764 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref, |
| 767 base::Unretained(this))); | 765 base::Unretained(this))); |
| 768 } | 766 } |
| 769 | 767 |
| 770 ash::LauncherModel* ChromeLauncherController::model() { | 768 ash::LauncherModel* ChromeLauncherController::model() { |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 PersistPinnedState(); | 1300 PersistPinnedState(); |
| 1303 } | 1301 } |
| 1304 } | 1302 } |
| 1305 | 1303 |
| 1306 void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) { | 1304 void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) { |
| 1307 ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id); | 1305 ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id); |
| 1308 if (launcher_id && IsPinned(launcher_id)) | 1306 if (launcher_id && IsPinned(launcher_id)) |
| 1309 Unpin(launcher_id); | 1307 Unpin(launcher_id); |
| 1310 } | 1308 } |
| 1311 | 1309 |
| 1310 int ChromeLauncherController::PinRunningAppInternal( |
| 1311 int index, |
| 1312 ash::LauncherID launcher_id) { |
| 1313 int running_index = model_->ItemIndexByID(launcher_id); |
| 1314 ash::LauncherItem item = model_->items()[running_index]; |
| 1315 DCHECK(item.type == ash::TYPE_WINDOWED_APP || |
| 1316 item.type == ash::TYPE_PLATFORM_APP); |
| 1317 item.type = ash::TYPE_APP_SHORTCUT; |
| 1318 model_->Set(running_index, item); |
| 1319 // The |LauncherModel|'s weight system might reposition the item to a |
| 1320 // new index, so we get the index again. |
| 1321 running_index = model_->ItemIndexByID(launcher_id); |
| 1322 if (running_index < index) |
| 1323 --index; |
| 1324 if (running_index != index) |
| 1325 model_->Move(running_index, index); |
| 1326 return index; |
| 1327 } |
| 1328 |
| 1329 void ChromeLauncherController::UnpinRunningAppInternal(int index) { |
| 1330 DCHECK_GE(index, 0); |
| 1331 ash::LauncherItem item = model_->items()[index]; |
| 1332 DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT); |
| 1333 item.type = ash::TYPE_WINDOWED_APP; |
| 1334 // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such |
| 1335 // we have to check here what this was before it got a shortcut. |
| 1336 if (HasItemController(item.id) && |
| 1337 id_to_item_controller_map_[item.id]->type() == |
| 1338 LauncherItemController::TYPE_APP) |
| 1339 item.type = ash::TYPE_PLATFORM_APP; |
| 1340 model_->Set(index, item); |
| 1341 } |
| 1342 |
| 1312 void ChromeLauncherController::UpdateAppLaunchersFromPref() { | 1343 void ChromeLauncherController::UpdateAppLaunchersFromPref() { |
| 1313 // Construct a vector representation of to-be-pinned apps from the pref. | 1344 // There are various functions which will trigger a |PersistPinnedState| call |
| 1314 std::vector<std::string> pinned_apps; | 1345 // like a direct call to |DoPinAppWithID|, or an indirect call to the menu |
| 1315 int chrome_icon_index = GetChromeIconIndexFromPref(); | 1346 // model which will use weights to re-arrange the icons to new positions. |
| 1347 // Since this function is meant to synchronize the "is state" with the |
| 1348 // "sync state", it makes no sense to store any changes by this function back |
| 1349 // into the pref state. Therefore we tell |persistPinnedState| to ignore any |
| 1350 // invocations while we are running. |
| 1351 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true); |
| 1352 std::vector<std::string> pinned_apps = GetListOfPinnedAppsAndBrowser(); |
| 1353 |
| 1316 int index = 0; | 1354 int index = 0; |
| 1317 int max_index = model_->item_count(); | 1355 int max_index = model_->item_count(); |
| 1318 // Using the alternate shelf layout the App Icon should be the first item in | 1356 |
| 1319 // the list thus start adding items at slot 1 (instead of slot 0). | 1357 // Using the alternate shelf layout the app list Icon should be the first item |
| 1320 if (ash::switches::UseAlternateShelfLayout()) { | 1358 // in the list thus start adding items at slot 1 (instead of slot 0). |
| 1359 if (ash::switches::UseAlternateShelfLayout() && |
| 1360 model_->item_count() && model_->items()[0].type == ash::TYPE_APP_LIST) { |
| 1321 ++index; | 1361 ++index; |
| 1322 ++max_index; | 1362 ++max_index; |
| 1323 // The alternate shelf layout's icon position will always include the | |
| 1324 // AppLauncher which needs to be subtracted here. | |
| 1325 if (chrome_icon_index > 0) | |
| 1326 --chrome_icon_index; | |
| 1327 } | |
| 1328 const base::ListValue* pinned_apps_pref = | |
| 1329 profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps); | |
| 1330 for (base::ListValue::const_iterator it(pinned_apps_pref->begin()); | |
| 1331 it != pinned_apps_pref->end(); ++it) { | |
| 1332 // To preserve the Chrome icon position, we insert a dummy slot for it - if | |
| 1333 // the model has a Chrome item. While initializing we can come here with no | |
| 1334 // item in which case the count would be 1 or below. | |
| 1335 if (it - pinned_apps_pref->begin() == chrome_icon_index && | |
| 1336 model_->item_count() > 1) { | |
| 1337 pinned_apps.push_back(extension_misc::kChromeAppId); | |
| 1338 } | |
| 1339 | |
| 1340 DictionaryValue* app = NULL; | |
| 1341 std::string app_id; | |
| 1342 if ((*it)->GetAsDictionary(&app) && | |
| 1343 app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) && | |
| 1344 std::find(pinned_apps.begin(), pinned_apps.end(), app_id) == | |
| 1345 pinned_apps.end() && | |
| 1346 app_tab_helper_->IsValidID(app_id)) { | |
| 1347 pinned_apps.push_back(app_id); | |
| 1348 } | |
| 1349 } | 1363 } |
| 1350 | 1364 |
| 1351 // Walk the model and |pinned_apps| from the pref lockstep, adding and | 1365 // Walk the model and |pinned_apps| from the pref lockstep, adding and |
| 1352 // removing items as necessary. NB: This code uses plain old indexing instead | 1366 // removing items as necessary. NB: This code uses plain old indexing instead |
| 1353 // of iterators because of model mutations as part of the loop. | 1367 // of iterators because of model mutations as part of the loop. |
| 1354 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin()); | 1368 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin()); |
| 1355 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) { | 1369 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) { |
| 1356 // If the next app launcher according to the pref is present in the model, | 1370 // If the next app launcher according to the pref is present in the model, |
| 1357 // delete all app launcher entries in between. | 1371 // delete all app launcher entries in between. |
| 1358 if (*pref_app_id == extension_misc::kChromeAppId || | 1372 if (*pref_app_id == extension_misc::kChromeAppId || |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1369 item.type == ash::TYPE_BROWSER_SHORTCUT) || | 1383 item.type == ash::TYPE_BROWSER_SHORTCUT) || |
| 1370 (entry != id_to_item_controller_map_.end() && | 1384 (entry != id_to_item_controller_map_.end() && |
| 1371 entry->second->app_id() == *pref_app_id)) { | 1385 entry->second->app_id() == *pref_app_id)) { |
| 1372 ++pref_app_id; | 1386 ++pref_app_id; |
| 1373 break; | 1387 break; |
| 1374 } else { | 1388 } else { |
| 1375 if (item.type == ash::TYPE_BROWSER_SHORTCUT) { | 1389 if (item.type == ash::TYPE_BROWSER_SHORTCUT) { |
| 1376 // We cannot delete the browser shortcut. As such we move it up by | 1390 // We cannot delete the browser shortcut. As such we move it up by |
| 1377 // one. To avoid any side effects from our pinned state observer, we | 1391 // one. To avoid any side effects from our pinned state observer, we |
| 1378 // do not call the model directly. | 1392 // do not call the model directly. |
| 1379 MoveItemWithoutPinnedStateChangeNotification(index, index + 1); | 1393 model_->Move(index, index + 1); |
| 1380 } else { | 1394 } else { |
| 1381 LauncherItemClosed(item.id); | 1395 // Check if this is a platform or a windowed app. |
| 1382 --max_index; | 1396 if (item.type == ash::TYPE_APP_SHORTCUT && |
| 1397 (id_to_item_controller_map_[item.id]->locked() || |
| 1398 id_to_item_controller_map_[item.id]->type() == |
| 1399 LauncherItemController::TYPE_APP)) { |
| 1400 // Note: This will not change the amount of items (|max_index|). |
| 1401 // Even changes to the actual |index| due to item weighting |
| 1402 // changes should be fine. |
| 1403 UnpinRunningAppInternal(index); |
| 1404 } else { |
| 1405 LauncherItemClosed(item.id); |
| 1406 --max_index; |
| 1407 } |
| 1383 } | 1408 } |
| 1384 --index; | 1409 --index; |
| 1385 } | 1410 } |
| 1386 } | 1411 } |
| 1387 // If the item wasn't found, that means id_to_item_controller_map_ | 1412 // If the item wasn't found, that means id_to_item_controller_map_ |
| 1388 // is out of sync. | 1413 // is out of sync. |
| 1389 DCHECK(index <= max_index); | 1414 DCHECK(index <= max_index); |
| 1390 } else { | 1415 } else { |
| 1391 // This app wasn't pinned before, insert a new entry. | 1416 // Check if the item was already running but not yet pinned. |
| 1392 ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index); | 1417 ash::LauncherID launcher_id = GetLauncherIDForAppID(*pref_app_id); |
| 1393 index = model_->ItemIndexByID(id); | 1418 if (launcher_id) { |
| 1419 // This app is running but not yet pinned. So pin and move it. |
| 1420 index = PinRunningAppInternal(index, launcher_id); |
| 1421 } else { |
| 1422 // This app wasn't pinned before, insert a new entry. |
| 1423 launcher_id = CreateAppShortcutLauncherItem(*pref_app_id, index); |
| 1424 ++max_index; |
| 1425 index = model_->ItemIndexByID(launcher_id); |
| 1426 } |
| 1394 ++pref_app_id; | 1427 ++pref_app_id; |
| 1395 } | 1428 } |
| 1396 } | 1429 } |
| 1397 | 1430 |
| 1431 // Since we are removing the currently existing shortcuts, but the chrome item |
| 1432 // might be in the middle of that area, we need to keep track of it, so that |
| 1433 // it can be shifted to the correct location afterwards. |
| 1434 // Note: This might still produce location shifts with windowed V1 |
| 1435 // applications since they will be grouped at the moment between shortcuts. |
| 1436 // To address that problem we could either group them separately again - or |
| 1437 // we will have to remember all shelf item locations. |
| 1438 int chrome_index = -1; |
| 1439 |
| 1398 // Remove any trailing existing items. | 1440 // Remove any trailing existing items. |
| 1399 while (index < model_->item_count()) { | 1441 while (index < model_->item_count()) { |
| 1400 const ash::LauncherItem& item(model_->items()[index]); | 1442 const ash::LauncherItem& item(model_->items()[index]); |
| 1401 if (item.type == ash::TYPE_APP_SHORTCUT) | 1443 if (item.type == ash::TYPE_APP_SHORTCUT) { |
| 1402 LauncherItemClosed(item.id); | 1444 if (id_to_item_controller_map_[item.id]->locked() || |
| 1403 else | 1445 id_to_item_controller_map_[item.id]->type() == |
| 1446 LauncherItemController::TYPE_APP) |
| 1447 UnpinRunningAppInternal(index); |
| 1448 else |
| 1449 LauncherItemClosed(item.id); |
| 1450 } else { |
| 1451 if (item.type == ash::TYPE_BROWSER_SHORTCUT) |
| 1452 chrome_index = index; |
| 1404 ++index; | 1453 ++index; |
| 1454 } |
| 1405 } | 1455 } |
| 1406 | 1456 |
| 1407 // Append unprocessed items from the pref to the end of the model. | 1457 // Append unprocessed items from the pref to the end of the model. |
| 1408 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) { | 1458 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) { |
| 1409 // Ignore the chrome icon. | 1459 // All items but the chrome shortcut needs to be added. |
| 1410 if (*pref_app_id != extension_misc::kChromeAppId) | 1460 if (*pref_app_id != extension_misc::kChromeAppId) { |
| 1411 DoPinAppWithID(*pref_app_id); | 1461 DoPinAppWithID(*pref_app_id); |
| 1462 } else if (chrome_index != -1) { |
| 1463 // The chrome item was in the middle of the to be removed items and needs |
| 1464 // now to be moved to the last possible location. |
| 1465 model_->Move(chrome_index, model_->item_count() - 1); |
| 1466 } |
| 1412 } | 1467 } |
| 1413 | |
| 1414 } | 1468 } |
| 1415 | 1469 |
| 1416 void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs( | 1470 void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs( |
| 1417 ash::ShelfAutoHideBehavior behavior, | 1471 ash::ShelfAutoHideBehavior behavior, |
| 1418 aura::RootWindow* root_window) { | 1472 aura::RootWindow* root_window) { |
| 1419 const char* value = NULL; | 1473 const char* value = NULL; |
| 1420 switch (behavior) { | 1474 switch (behavior) { |
| 1421 case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS: | 1475 case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS: |
| 1422 value = ash::kShelfAutoHideBehaviorAlways; | 1476 value = ash::kShelfAutoHideBehaviorAlways; |
| 1423 break; | 1477 break; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1555 return static_cast<BrowserShortcutLauncherItemController*>( | 1609 return static_cast<BrowserShortcutLauncherItemController*>( |
| 1556 id_to_item_controller_map_[id]); | 1610 id_to_item_controller_map_[id]); |
| 1557 } | 1611 } |
| 1558 | 1612 |
| 1559 ash::LauncherID ChromeLauncherController::CreateBrowserShortcutLauncherItem() { | 1613 ash::LauncherID ChromeLauncherController::CreateBrowserShortcutLauncherItem() { |
| 1560 ash::LauncherItem browser_shortcut; | 1614 ash::LauncherItem browser_shortcut; |
| 1561 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT; | 1615 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT; |
| 1562 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 1616 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 1563 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32); | 1617 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32); |
| 1564 ash::LauncherID id = model_->next_id(); | 1618 ash::LauncherID id = model_->next_id(); |
| 1565 size_t index = GetChromeIconIndexFromPref(); | 1619 size_t index = GetChromeIconIndexForCreation(); |
| 1566 model_->AddAt(index, browser_shortcut); | 1620 model_->AddAt(index, browser_shortcut); |
| 1567 browser_item_controller_.reset( | 1621 browser_item_controller_.reset( |
| 1568 new BrowserShortcutLauncherItemController(this, profile_)); | 1622 new BrowserShortcutLauncherItemController(this, profile_)); |
| 1569 id_to_item_controller_map_[id] = browser_item_controller_.get(); | 1623 id_to_item_controller_map_[id] = browser_item_controller_.get(); |
| 1570 id_to_item_controller_map_[id]->set_launcher_id(id); | 1624 id_to_item_controller_map_[id]->set_launcher_id(id); |
| 1571 return id; | 1625 return id; |
| 1572 } | 1626 } |
| 1573 | 1627 |
| 1574 void ChromeLauncherController::PersistChromeItemIndex(int index) { | 1628 void ChromeLauncherController::PersistChromeItemIndex(int index) { |
| 1575 profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index); | 1629 profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index); |
| 1576 } | 1630 } |
| 1577 | 1631 |
| 1578 int ChromeLauncherController::GetChromeIconIndexFromPref() const { | 1632 int ChromeLauncherController::GetChromeIconIndexFromPref() const { |
| 1579 size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex); | 1633 size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex); |
| 1580 const base::ListValue* pinned_apps_pref = | 1634 const base::ListValue* pinned_apps_pref = |
| 1581 profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps); | 1635 profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps); |
| 1582 if (ash::switches::UseAlternateShelfLayout()) | |
| 1583 return std::max(static_cast<size_t>(1), | |
| 1584 std::min(pinned_apps_pref->GetSize() + 1, index)); | |
| 1585 return std::max(static_cast<size_t>(0), | 1636 return std::max(static_cast<size_t>(0), |
| 1586 std::min(pinned_apps_pref->GetSize(), index)); | 1637 std::min(pinned_apps_pref->GetSize(), index)); |
| 1587 } | 1638 } |
| 1588 | 1639 |
| 1640 int ChromeLauncherController::GetChromeIconIndexForCreation() { |
| 1641 // We get the list of pinned apps as they currently would get pinned. |
| 1642 // Within this list the chrome icon will be the correct location. |
| 1643 std::vector<std::string> pinned_apps = GetListOfPinnedAppsAndBrowser(); |
| 1644 |
| 1645 std::vector<std::string>::iterator it = |
| 1646 std::find(pinned_apps.begin(), |
| 1647 pinned_apps.end(), |
| 1648 std::string(extension_misc::kChromeAppId)); |
| 1649 DCHECK(it != pinned_apps.end()); |
| 1650 int index = it - pinned_apps.begin(); |
| 1651 |
| 1652 // Since this function returns the index of the item within the shelf, the |
| 1653 // app list item must be taken into account and for now the app list is always |
| 1654 // the left most item in the list. |
| 1655 if (ash::switches::UseAlternateShelfLayout() && |
| 1656 model_->item_count() && model_->items()[0].type == ash::TYPE_APP_LIST) |
| 1657 ++index; |
| 1658 |
| 1659 // We should do here a comparison between the is state and the "want to be" |
| 1660 // state since some apps might be able to pin but are not yet. Instead - for |
| 1661 // the time being we clamp against the amount of known items and wait for the |
| 1662 // next |UpdateAppLaunchersFromPref()| call to correct it - it will come since |
| 1663 // the pinning will be done then. |
| 1664 return std::min(model_->item_count(), index); |
| 1665 } |
| 1666 |
| 1667 std::vector<std::string> |
| 1668 ChromeLauncherController::GetListOfPinnedAppsAndBrowser() { |
| 1669 std::vector<std::string> pinned_apps; |
| 1670 const base::ListValue* pinned_apps_pref = |
| 1671 profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps); |
| 1672 |
| 1673 // Keep track of the addition of the chrome icon. |
| 1674 bool chrome_icon_added = false; |
| 1675 size_t chrome_icon_index = GetChromeIconIndexFromPref(); |
| 1676 // Note: We do not need special handling for the app List here since it is |
| 1677 // either always at the start or the end of the list and it is not part of |
| 1678 // the pinned 'dynamic' items. |
| 1679 for (size_t index = 0; index < pinned_apps_pref->GetSize(); ++index) { |
| 1680 // We need to position the chrome icon relative to it's place in the pinned |
| 1681 // preference list - even if an item of that list isn't shown yet. |
| 1682 if (index == chrome_icon_index) { |
| 1683 pinned_apps.push_back(extension_misc::kChromeAppId); |
| 1684 chrome_icon_added = true; |
| 1685 } |
| 1686 |
| 1687 const DictionaryValue* app = NULL; |
| 1688 std::string app_id; |
| 1689 if (pinned_apps_pref->GetDictionary(index, &app) && |
| 1690 app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) && |
| 1691 (std::find(pinned_apps.begin(), pinned_apps.end(), app_id) == |
| 1692 pinned_apps.end()) && app_tab_helper_->IsValidID(app_id)) |
| 1693 pinned_apps.push_back(app_id); |
| 1694 } |
| 1695 |
| 1696 // If not added yet, the chrome item will be the final item in the list. |
| 1697 if (!chrome_icon_added) |
| 1698 pinned_apps.push_back(extension_misc::kChromeAppId); |
| 1699 return pinned_apps; |
| 1700 } |
| 1701 |
| 1589 bool ChromeLauncherController::IsIncognito( | 1702 bool ChromeLauncherController::IsIncognito( |
| 1590 content::WebContents* web_contents) const { | 1703 const content::WebContents* web_contents) const { |
| 1591 const Profile* profile = | 1704 const Profile* profile = |
| 1592 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 1705 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 1593 return profile->IsOffTheRecord() && !profile->IsGuestSession(); | 1706 return profile->IsOffTheRecord() && !profile->IsGuestSession(); |
| 1594 } | 1707 } |
| 1595 | 1708 |
| 1596 void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension( | 1709 void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension( |
| 1597 const std::string& app_id) { | 1710 const std::string& app_id) { |
| 1598 // This function cannot rely on the controller's enumeration functionality | 1711 // This function cannot rely on the controller's enumeration functionality |
| 1599 // since the extension has already be unloaded. | 1712 // since the extension has already be unloaded. |
| 1600 const BrowserList* ash_browser_list = | 1713 const BrowserList* ash_browser_list = |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1612 browser_to_close.push_back(browser); | 1725 browser_to_close.push_back(browser); |
| 1613 } | 1726 } |
| 1614 } | 1727 } |
| 1615 while (!browser_to_close.empty()) { | 1728 while (!browser_to_close.empty()) { |
| 1616 TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model(); | 1729 TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model(); |
| 1617 tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE); | 1730 tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE); |
| 1618 browser_to_close.pop_back(); | 1731 browser_to_close.pop_back(); |
| 1619 } | 1732 } |
| 1620 } | 1733 } |
| 1621 | 1734 |
| 1622 void | |
| 1623 ChromeLauncherController::MoveItemWithoutPinnedStateChangeNotification( | |
| 1624 int source_index, int target_index) { | |
| 1625 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true); | |
| 1626 model_->Move(source_index, target_index); | |
| 1627 } | |
| 1628 | |
| 1629 void ChromeLauncherController::RegisterLauncherItemDelegate() { | 1735 void ChromeLauncherController::RegisterLauncherItemDelegate() { |
| 1630 // TODO(simon.hong81): Register LauncherItemDelegate when LauncherItemDelegate | 1736 // TODO(simon.hong81): Register LauncherItemDelegate when LauncherItemDelegate |
| 1631 // is created. | 1737 // is created. |
| 1632 ash::LauncherItemDelegateManager* manager = | 1738 ash::LauncherItemDelegateManager* manager = |
| 1633 ash::Shell::GetInstance()->launcher_item_delegate_manager(); | 1739 ash::Shell::GetInstance()->launcher_item_delegate_manager(); |
| 1634 manager->RegisterLauncherItemDelegate(ash::TYPE_APP_PANEL, this); | 1740 manager->RegisterLauncherItemDelegate(ash::TYPE_APP_PANEL, this); |
| 1635 manager->RegisterLauncherItemDelegate(ash::TYPE_APP_SHORTCUT, this); | 1741 manager->RegisterLauncherItemDelegate(ash::TYPE_APP_SHORTCUT, this); |
| 1636 manager->RegisterLauncherItemDelegate(ash::TYPE_BROWSER_SHORTCUT, this); | 1742 manager->RegisterLauncherItemDelegate(ash::TYPE_BROWSER_SHORTCUT, this); |
| 1637 manager->RegisterLauncherItemDelegate(ash::TYPE_PLATFORM_APP, this); | 1743 manager->RegisterLauncherItemDelegate(ash::TYPE_PLATFORM_APP, this); |
| 1638 manager->RegisterLauncherItemDelegate(ash::TYPE_WINDOWED_APP, this); | 1744 manager->RegisterLauncherItemDelegate(ash::TYPE_WINDOWED_APP, this); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1674 } | 1780 } |
| 1675 | 1781 |
| 1676 void ChromeLauncherController::ReleaseProfile() { | 1782 void ChromeLauncherController::ReleaseProfile() { |
| 1677 if (app_sync_ui_state_) | 1783 if (app_sync_ui_state_) |
| 1678 app_sync_ui_state_->RemoveObserver(this); | 1784 app_sync_ui_state_->RemoveObserver(this); |
| 1679 | 1785 |
| 1680 PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this); | 1786 PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this); |
| 1681 | 1787 |
| 1682 pref_change_registrar_.RemoveAll(); | 1788 pref_change_registrar_.RemoveAll(); |
| 1683 } | 1789 } |
| OLD | NEW |