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

Unified Diff: chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc

Issue 23580008: Fixed problems with pin/unpin preferences changing for not running applications & icon order chang… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 56aeb37ee0f86ff44d6e4eeab512ff06be5e09b5..bd705a871a0322fd14af09fa5ad9476407e6ce21 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -445,15 +445,10 @@ void ChromeLauncherController::Unpin(ash::LauncherID id) {
} else {
oshima 2013/09/19 21:42:11 can you expland if else like if (... == TYPE_APP)
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 Ahhh! Good one! case combined!
// Prevent the removal of items upon unpin if it is locked by a running
// windowed V1 app.
- if (!controller->locked()) {
+ if (!controller->locked())
LauncherItemClosed(id);
- } else {
- int index = model_->ItemIndexByID(id);
- DCHECK_GE(index, 0);
- ash::LauncherItem item = model_->items()[index];
- item.type = ash::TYPE_WINDOWED_APP;
- model_->Set(index, item);
- }
+ else
+ UnpinRunningAppInternal(model_->ItemIndexByID(id));
}
if (CanPin())
PersistPinnedState();
@@ -740,6 +735,12 @@ void ChromeLauncherController::PersistPinnedState() {
return;
}
+ // With the alternate shelf layout, the app list is locked in position #0.
+ // Since the app list does not have any impact on the rest of the order,
+ // we need to keep track of its appearance so that the chrome icon position
+ // is at the proper location (backwards compatible).
+ int app_list_found = 0;
oshima 2013/09/19 21:42:11 maybe app_list_index_found, or found_app_list_inde
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 Done.
+
// Mutating kPinnedLauncherApps is going to notify us and trigger us to
// process the change. We don't want that to happen so remove ourselves as a
// listener.
@@ -757,7 +758,12 @@ void ChromeLauncherController::PersistPinnedState() {
updater->Append(app_value);
}
} else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
- PersistChromeItemIndex(i);
+ PersistChromeItemIndex(i - app_list_found);
+ } else if (model_->items()[i].type == ash::TYPE_APP_LIST &&
+ ash::switches::UseAlternateShelfLayout()) {
+ // With the new alternate shelf layout the app list can be pinned to the
+ // position 0 and should not be taken into account.
+ app_list_found = 1;
oshima 2013/09/19 21:42:11 why this is 1 not i?
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 Because all we do is to subtract 1 if the app list
}
}
}
@@ -1309,43 +1315,58 @@ void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) {
Unpin(launcher_id);
}
+int ChromeLauncherController::PinRunningAppInternal(
+ int index,
+ ash::LauncherID launcher_id) {
+ int running_index = model_->ItemIndexByID(launcher_id);
+ ash::LauncherItem item = model_->items()[running_index];
+ DCHECK(item.type == ash::TYPE_WINDOWED_APP ||
+ item.type == ash::TYPE_PLATFORM_APP);
+ item.type = ash::TYPE_APP_SHORTCUT;
+ model_->Set(running_index, item);
+ // The |LauncherModel|'s weight system might reposition the item to a
+ // new index, so we get the index again.
+ running_index = model_->ItemIndexByID(launcher_id);
+ if (running_index < index)
+ --index;
+ if (running_index != index)
+ MoveItemWithoutPinnedStateChangeNotification(running_index, index);
+ return index;
+}
+
+void ChromeLauncherController::UnpinRunningAppInternal(int index) {
+ DCHECK_GE(index, 0);
+ ash::LauncherItem item = model_->items()[index];
+ DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT);
+ item.type = ash::TYPE_WINDOWED_APP;
+ // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such
+ // we have to check here what this was before it got a shortcut.
+ if (HasItemController(item.id) &&
+ id_to_item_controller_map_[item.id]->type() ==
+ LauncherItemController::TYPE_APP)
+ item.type = ash::TYPE_PLATFORM_APP;
+ model_->Set(index, item);
+}
+
void ChromeLauncherController::UpdateAppLaunchersFromPref() {
- // Construct a vector representation of to-be-pinned apps from the pref.
+ // Note: This function has to make sure that it never changes a state which
+ // calls |PersistPinnedState()| - otherwise all kinds of problems can arise.
oshima 2013/09/19 21:42:11 add reference to bug? (assuming one of bugs listed
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 No it is not. This was meant to be a helper commen
+ // If it happens (due to some complicated observer interactions) it would be
+ // best to either add here
+ // base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_,
+ // true);
+ // or call |PersistPinnedState()| at the end. For now this is not necessary.
std::vector<std::string> pinned_apps;
- int chrome_icon_index = GetChromeIconIndexFromPref();
+ GetListOfPinnedAppsAndBrowser(&pinned_apps);
+
int index = 0;
int max_index = model_->item_count();
- // Using the alternate shelf layout the App Icon should be the first item in
- // the list thus start adding items at slot 1 (instead of slot 0).
+
+ // Using the alternate shelf layout the app list Icon should be the first item
+ // in the list thus start adding items at slot 1 (instead of slot 0).
if (ash::switches::UseAlternateShelfLayout()) {
++index;
++max_index;
- // The alternate shelf layout's icon position will always include the
- // AppLauncher which needs to be subtracted here.
- if (chrome_icon_index > 0)
- --chrome_icon_index;
- }
- const base::ListValue* pinned_apps_pref =
- profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
- for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
- it != pinned_apps_pref->end(); ++it) {
- // To preserve the Chrome icon position, we insert a dummy slot for it - if
- // the model has a Chrome item. While initializing we can come here with no
- // item in which case the count would be 1 or below.
- if (it - pinned_apps_pref->begin() == chrome_icon_index &&
- model_->item_count() > 1) {
- pinned_apps.push_back(extension_misc::kChromeAppId);
- }
-
- DictionaryValue* app = NULL;
- std::string app_id;
- if ((*it)->GetAsDictionary(&app) &&
- app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
- std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
- pinned_apps.end() &&
- app_tab_helper_->IsValidID(app_id)) {
- pinned_apps.push_back(app_id);
- }
}
// Walk the model and |pinned_apps| from the pref lockstep, adding and
@@ -1378,8 +1399,19 @@ void ChromeLauncherController::UpdateAppLaunchersFromPref() {
// do not call the model directly.
MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
} else {
- LauncherItemClosed(item.id);
- --max_index;
+ // Check if this is a platform or a windowed app.
+ if (item.type == ash::TYPE_APP_SHORTCUT &&
+ (id_to_item_controller_map_[item.id]->locked() ||
+ id_to_item_controller_map_[item.id]->type() ==
+ LauncherItemController::TYPE_APP)) {
+ // Note: This will not change the amount of items (|max_index|).
+ // Even changes to the actual |index| due to item weighting
+ // changes should be fine.
+ UnpinRunningAppInternal(index);
+ } else {
+ LauncherItemClosed(item.id);
+ --max_index;
+ }
}
--index;
}
@@ -1388,29 +1420,58 @@ void ChromeLauncherController::UpdateAppLaunchersFromPref() {
// is out of sync.
DCHECK(index <= max_index);
} else {
- // This app wasn't pinned before, insert a new entry.
- ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
- index = model_->ItemIndexByID(id);
+ // Check if the item was already running but not yet pinned.
+ ash::LauncherID launcher_id = GetLauncherIDForAppID(*pref_app_id);
+ if (launcher_id) {
+ // This app is running but not yet pinned. So pin and move it.
+ index = PinRunningAppInternal(index, launcher_id);
+ } else {
+ // This app wasn't pinned before, insert a new entry.
+ launcher_id = CreateAppShortcutLauncherItem(*pref_app_id, index);
+ index = model_->ItemIndexByID(launcher_id);
+ }
++pref_app_id;
}
}
+ // Since we are removing the currently existing shortcuts, but the chrome item
+ // might be in the middle of that area, we need to keep track of it, so that
+ // it can be shifted to the correct location afterwards.
+ // Note: This might still produce location shifts with windowed V1
+ // applications since they will be grouped at the moment between shortcuts.
+ // To address that problem we could either group them separately again - or
+ // we will have to remember all shelf item locations.
+ int chrome_index = -1;
+
// Remove any trailing existing items.
while (index < model_->item_count()) {
const ash::LauncherItem& item(model_->items()[index]);
- if (item.type == ash::TYPE_APP_SHORTCUT)
- LauncherItemClosed(item.id);
- else
+ if (item.type == ash::TYPE_APP_SHORTCUT) {
+ if (id_to_item_controller_map_[item.id]->locked() ||
+ id_to_item_controller_map_[item.id]->type() ==
+ LauncherItemController::TYPE_APP)
+ UnpinRunningAppInternal(index);
+ else
+ LauncherItemClosed(item.id);
+ } else {
+ if (item.type == ash::TYPE_BROWSER_SHORTCUT)
+ chrome_index = index;
++index;
+ }
}
// Append unprocessed items from the pref to the end of the model.
for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
- // Ignore the chrome icon.
- if (*pref_app_id != extension_misc::kChromeAppId)
+ // All items but the chrome shortcut needs to be added.
+ if (*pref_app_id != extension_misc::kChromeAppId) {
DoPinAppWithID(*pref_app_id);
+ } else if (chrome_index != -1) {
+ // The chrome item was in the middle of the to be removed items and needs
+ // now to be moved to the last possible location.
+ MoveItemWithoutPinnedStateChangeNotification(chrome_index,
+ model_->item_count() - 1);
oshima 2013/09/19 21:42:11 indent
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 Done.
+ }
}
-
}
void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
@@ -1562,7 +1623,7 @@ ash::LauncherID ChromeLauncherController::CreateBrowserShortcutLauncherItem() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
ash::LauncherID id = model_->next_id();
- size_t index = GetChromeIconIndexFromPref();
+ size_t index = GetChromeIconIndexForCreation();
model_->AddAt(index, browser_shortcut);
browser_item_controller_.reset(
new BrowserShortcutLauncherItemController(this, profile_));
@@ -1579,13 +1640,72 @@ int ChromeLauncherController::GetChromeIconIndexFromPref() const {
size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
const base::ListValue* pinned_apps_pref =
profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
- if (ash::switches::UseAlternateShelfLayout())
- return std::max(static_cast<size_t>(1),
- std::min(pinned_apps_pref->GetSize() + 1, index));
return std::max(static_cast<size_t>(0),
std::min(pinned_apps_pref->GetSize(), index));
}
+int ChromeLauncherController::GetChromeIconIndexForCreation() {
+ // We get the list of pinned apps as they currently would get pinned.
+ // Within this list the chrome icon will be the correct location.
+ std::vector<std::string> pinned_apps;
+ GetListOfPinnedAppsAndBrowser(&pinned_apps);
+
+ std::vector<std::string>::iterator it =
+ std::find(pinned_apps.begin(),
+ pinned_apps.end(),
+ extension_misc::kChromeAppId);
+ DCHECK(it != pinned_apps.end());
+ int index = it - pinned_apps.begin();
+
+ // Since this function returns the index of the item within the shelf, the
+ // app list item must be taken into account and for now the app list is always
+ // the left most item in the list.
+ if (ash::switches::UseAlternateShelfLayout())
+ ++index;
+
+ // We should do here a comparison between the is state and the "want to be"
+ // state since some apps might be able to pin but are not yet. Instead - for
+ // the time being we clamp against the amount of known items and wait for the
+ // next |UpdateAppLaunchersFromPref()| call to correct it - it will come since
+ // the pinning will be done then.
+ return std::min(model_->item_count(), index);
+}
+
+void ChromeLauncherController::GetListOfPinnedAppsAndBrowser(
+ std::vector<std::string>* pinned_apps) {
+ const base::ListValue* pinned_apps_pref =
+ profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
+
+ // Keep track of the addition of the chrome icon.
+ bool chrome_icon_added = false;
+ int chrome_icon_index = GetChromeIconIndexFromPref();
+ // Note: We do not need special handling for the app List here since it is
+ // either always at the start or the end of the list and it is not part of
+ // the pinned 'dynamic' items.
+ for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
+ it != pinned_apps_pref->end(); ++it) {
oshima 2013/09/19 21:42:11 since you need index anyway, using size_t index wo
Mr4D (OOO till 08-26) 2013/09/19 22:31:50 Done.
+ // We need to position the chrome icon relative to it's place in the pinned
+ // preference list - even if an item of that list isn't shown yet.
+ if (it - pinned_apps_pref->begin() == chrome_icon_index &&
+ model_->item_count() > 1) {
+ pinned_apps->push_back(extension_misc::kChromeAppId);
+ chrome_icon_added = true;
+ }
+
+ DictionaryValue* app = NULL;
+ std::string app_id;
+ if ((*it)->GetAsDictionary(&app) &&
+ app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
+ (std::find(pinned_apps->begin(), pinned_apps->end(), app_id) ==
+ pinned_apps->end()) && app_tab_helper_->IsValidID(app_id))
+ pinned_apps->push_back(app_id);
+ }
+
+ // If not added yet, the chrome item will be the final item in the list.
+ if (!chrome_icon_added)
+ pinned_apps->push_back(extension_misc::kChromeAppId);
+}
+
bool ChromeLauncherController::IsIncognito(
content::WebContents* web_contents) const {
const Profile* profile =

Powered by Google App Engine
This is Rietveld 408576698