| Index: chrome/browser/ui/webui/ntp/app_launcher_handler.cc
|
| diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
|
| index d0b075db106d60b779bef20b5b5e4abacb3bfc34..03b1ebea1a74fc2df1aa6b24fd3a47439a77bc26 100644
|
| --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
|
| +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
|
| @@ -72,7 +72,8 @@ AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service)
|
| : extension_service_(extension_service),
|
| ignore_changes_(false),
|
| attempted_bookmark_app_install_(false),
|
| - has_loaded_apps_(false) {
|
| + has_loaded_apps_(false),
|
| + uninstall_from_page_(false) {
|
| }
|
|
|
| AppLauncherHandler::~AppLauncherHandler() {}
|
| @@ -165,15 +166,8 @@ void AppLauncherHandler::CreateAppInfo(const Extension* extension,
|
| }
|
| value->SetInteger("app_launch_index", app_launch_index);
|
|
|
| - int page_index = prefs->GetPageIndex(extension->id());
|
| - if (page_index < 0) {
|
| - // Make sure every app has a page index (some predate the page index).
|
| - // The webstore app should be on the first page.
|
| - page_index = extension->id() == extension_misc::kWebStoreAppId ?
|
| - 0 : prefs->GetNaturalAppPageIndex();
|
| - prefs->SetPageIndex(extension->id(), page_index);
|
| - }
|
| - value->SetInteger("page_index", page_index);
|
| + EnsureAppHasPageIndex(service, extension->id());
|
| + value->SetInteger("page_index", prefs->GetPageIndex(extension->id()));
|
| }
|
|
|
| WebUIMessageHandler* AppLauncherHandler::Attach(WebUI* web_ui) {
|
| @@ -183,6 +177,9 @@ WebUIMessageHandler* AppLauncherHandler::Attach(WebUI* web_ui) {
|
| }
|
|
|
| void AppLauncherHandler::RegisterMessages() {
|
| + web_ui_->RegisterMessageCallback("deleteAppsPage",
|
| + base::Bind(&AppLauncherHandler::HandleDeleteAppsPage,
|
| + base::Unretained(this)));
|
| web_ui_->RegisterMessageCallback("getApps",
|
| base::Bind(&AppLauncherHandler::HandleGetApps,
|
| base::Unretained(this)));
|
| @@ -210,8 +207,8 @@ void AppLauncherHandler::RegisterMessages() {
|
| web_ui_->RegisterMessageCallback("promoSeen",
|
| base::Bind(&AppLauncherHandler::HandlePromoSeen,
|
| base::Unretained(this)));
|
| - web_ui_->RegisterMessageCallback("saveAppPageName",
|
| - base::Bind(&AppLauncherHandler::HandleSaveAppPageName,
|
| + web_ui_->RegisterMessageCallback("saveAppsPageName",
|
| + base::Bind(&AppLauncherHandler::HandleSaveAppsPageName,
|
| base::Unretained(this)));
|
| web_ui_->RegisterMessageCallback("generateAppForLink",
|
| base::Bind(&AppLauncherHandler::HandleGenerateAppForLink,
|
| @@ -289,18 +286,41 @@ void AppLauncherHandler::Observe(int type,
|
| content::Details<UnloadedExtensionInfo>(details)->reason ==
|
| extension_misc::UNLOAD_REASON_UNINSTALL));
|
| if (app_info.get()) {
|
| + scoped_ptr<base::FundamentalValue>
|
| + from_page(Value::CreateBooleanValue(uninstall_from_page_));
|
| web_ui_->CallJavascriptFunction(
|
| - "ntp4.appRemoved", *app_info, *uninstall_value);
|
| + "ntp4.appRemoved", *app_info, *uninstall_value, *from_page);
|
| + uninstall_from_page_ = false;
|
| + }
|
| + break;
|
| + }
|
| + case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: {
|
| + DictionaryValue pages;
|
| + const ExtensionList* extensions = extension_service_->extensions();
|
| + ExtensionPrefs* prefs = extension_service_->extension_prefs();
|
| + for (ExtensionList::const_iterator it = extensions->begin();
|
| + it != extensions->end(); ++it) {
|
| + if (!IsAppExcludedFromList(*it)) {
|
| + std::string page_index =
|
| + base::IntToString(prefs->GetPageIndex((*it)->id()));
|
| + if (!pages.HasKey(page_index))
|
| + pages.Set(page_index, new DictionaryValue());
|
| + DictionaryValue* page;
|
| + CHECK(pages.GetDictionary(page_index, &page));
|
| + page->SetString(
|
| + base::IntToString(prefs->GetAppLaunchIndex((*it)->id())),
|
| + (*it)->id());
|
| + }
|
| }
|
| + web_ui_->CallJavascriptFunction("ntp4.appsReordered", pages);
|
| break;
|
| }
|
| - case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED:
|
| - // The promo may not load until a couple seconds after the first NTP view,
|
| - // so we listen for the load notification and notify the NTP when ready.
|
| - case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED:
|
| - // TODO(estade): try to get rid of this inefficient operation.
|
| + case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED: {
|
| + // The promo may not load until a couple seconds after the first NTP view,
|
| + // so we listen for the load notification and notify the NTP when ready.
|
| HandleGetApps(NULL);
|
| break;
|
| + }
|
| case chrome::NOTIFICATION_PREF_CHANGED: {
|
| DictionaryValue dictionary;
|
| FillAppDictionary(&dictionary);
|
| @@ -322,6 +342,18 @@ void AppLauncherHandler::Observe(int type,
|
| }
|
| }
|
|
|
| +// static
|
| +void AppLauncherHandler::EnsureAppHasPageIndex(ExtensionService* service,
|
| + const std::string& id) {
|
| + if (service->extension_prefs()->GetPageIndex(id) < 0) {
|
| + // Make sure every app has a page index (some predate the page index).
|
| + // The webstore app should be on the first page.
|
| + int page_index = id == extension_misc::kWebStoreAppId ?
|
| + 0 : service->extension_prefs()->GetNaturalAppPageIndex();
|
| + service->extension_prefs()->SetPageIndex(id, page_index);
|
| + }
|
| +}
|
| +
|
| void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
|
| // CreateAppInfo and ClearPageIndex can change the extension prefs.
|
| AutoReset<bool> auto_reset(&ignore_changes_, true);
|
| @@ -396,10 +428,10 @@ void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
|
| ListValue* list = update.Get();
|
| list->Set(0, Value::CreateStringValue(
|
| l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME)));
|
| - dictionary->Set("appPageNames",
|
| + dictionary->Set("appsPageNames",
|
| static_cast<ListValue*>(list->DeepCopy()));
|
| } else {
|
| - dictionary->Set("appPageNames",
|
| + dictionary->Set("appsPageNames",
|
| static_cast<ListValue*>(app_page_names->DeepCopy()));
|
| }
|
| }
|
| @@ -426,6 +458,79 @@ void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) {
|
| dictionary->SetString("promoExpire", data.expire);
|
| }
|
|
|
| +void AppLauncherHandler::HandleDeleteAppsPage(const ListValue* args) {
|
| + double page_index_double;
|
| + CHECK(args->GetDouble(0, &page_index_double) && page_index_double >= 0);
|
| + size_t page_index = static_cast<size_t>(page_index_double);
|
| +
|
| + AutoReset<bool> auto_reset(&ignore_changes_, true);
|
| +
|
| + DeleteAppsPageRange(page_index, 1);
|
| +}
|
| +
|
| +void AppLauncherHandler::CondenseAppsPages() {
|
| + std::vector<bool> has_apps;
|
| + const ExtensionList* extensions = extension_service_->extensions();
|
| + for (ExtensionList::const_iterator it = extensions->begin();
|
| + it != extensions->end(); ++it) {
|
| + if (!IsAppExcludedFromList(*it)) {
|
| + EnsureAppHasPageIndex(extension_service_, (*it)->id());
|
| + size_t page_index =
|
| + extension_service_->extension_prefs()->GetPageIndex((*it)->id());
|
| + if (has_apps.size() < page_index + 1)
|
| + has_apps.resize(page_index + 1);
|
| + has_apps[page_index] = true;
|
| + }
|
| + }
|
| +
|
| + // Delete empty ranges of apps pages.
|
| + int first_empty = -1;
|
| + for (size_t i = 0; i < has_apps.size(); ++i) {
|
| + if (!has_apps[i]) {
|
| + if (first_empty == -1)
|
| + first_empty = i;
|
| + } else if (first_empty != -1) {
|
| + DeleteAppsPageRange(first_empty, i - first_empty);
|
| + has_apps.erase(has_apps.begin() + first_empty, has_apps.begin() + i);
|
| + i -= (i - first_empty);
|
| + first_empty = -1;
|
| + }
|
| + }
|
| + // Make sure there are no pending empty apps pages at the end of our list.
|
| + CHECK_EQ(first_empty, -1);
|
| +}
|
| +
|
| +void AppLauncherHandler::DeleteAppsPageRange(size_t index, size_t how_many) {
|
| + // Delete the apps page name from our prefs.
|
| + PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs();
|
| + ListPrefUpdate update(prefs, prefs::kNTPAppPageNames);
|
| + ListValue* list = update.Get();
|
| +
|
| + // Index checking is done within list->Remove() and will return false if an
|
| + // index to remove is negative or larger than the size of the list. This is
|
| + // intentionally left un-CHECK()-ed in the case that there's a skew between
|
| + // the list pref size and the last page index of all the apps.
|
| + for (size_t i = 0; i < how_many; ++i)
|
| + list->Remove(index, NULL);
|
| +
|
| + // Move apps that were on a page past the one we're deleting to their newly
|
| + // adjusted page index.
|
| + ExtensionPrefs* ext_prefs = extension_service_->extension_prefs();
|
| + const ExtensionList* extensions = extension_service_->extensions();
|
| + for (ExtensionList::const_iterator it = extensions->begin();
|
| + it != extensions->end(); ++it) {
|
| + // Ignore extensions and the cloud print app (but handle CWS app).
|
| + if (!IsAppExcludedFromList(*it)) {
|
| + size_t apps_page_index =
|
| + static_cast<size_t>(ext_prefs->GetPageIndex((*it)->id()));
|
| + // Don't delete pages with apps still on them.
|
| + CHECK(apps_page_index < index || apps_page_index >= (index + how_many));
|
| + if (apps_page_index >= (index + how_many))
|
| + ext_prefs->SetPageIndex((*it)->id(), apps_page_index - how_many);
|
| + }
|
| + }
|
| +}
|
| +
|
| void AppLauncherHandler::HandleGetApps(const ListValue* args) {
|
| DictionaryValue dictionary;
|
|
|
| @@ -456,6 +561,7 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) {
|
| ignore_changes_ = false;
|
| }
|
|
|
| + CondenseAppsPages();
|
| SetAppToBeHighlighted();
|
| FillAppDictionary(&dictionary);
|
| web_ui_->CallJavascriptFunction("getAppsCallback", dictionary);
|
| @@ -617,6 +723,9 @@ void AppLauncherHandler::HandleUninstallApp(const ListValue* args) {
|
| AutoReset<bool> auto_reset(&ignore_changes_, true);
|
| ExtensionUninstallAccepted();
|
| } else {
|
| + // We don't use an AutoReset<bool> here as the uninstall dialog runs in a
|
| + // different thread so it's not sync.
|
| + uninstall_from_page_ = true;
|
| GetExtensionUninstallDialog()->ConfirmUninstall(extension);
|
| }
|
| }
|
| @@ -687,7 +796,7 @@ void AppLauncherHandler::HandlePromoSeen(const ListValue* args) {
|
| extension_misc::PROMO_BUCKET_BOUNDARY);
|
| }
|
|
|
| -void AppLauncherHandler::HandleSaveAppPageName(const ListValue* args) {
|
| +void AppLauncherHandler::HandleSaveAppsPageName(const ListValue* args) {
|
| string16 name;
|
| CHECK(args->GetString(0, &name));
|
|
|
|
|