14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/extension_app_model_builder.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <algorithm>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/auto_reset.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/prefs/pref_service.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/extension_prefs.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/install_tracker.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/install_tracker_factory.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/extension_app_item.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/common/extensions/extension_set.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/pref_names.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_service.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/gfx/image/image_skia.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using extensions::Extension;
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool ShouldDisplayInAppLauncher(Profile* profile,
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                scoped_refptr<const Extension> app) {
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If it's the web store, check the policy.
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool blocked_by_policy =
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (app->id() == extension_misc::kWebStoreAppId ||
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       app->id() == extension_misc::kEnterpriseWebStoreAppId) &&
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon);
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return app->ShouldDisplayInAppLauncher() && !blocked_by_policy;
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ExtensionAppModelBuilder::ExtensionAppModelBuilder(
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Profile* profile,
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    app_list::AppListModel* model,
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AppListControllerDelegate* controller)
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : profile_(profile),
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      controller_(controller),
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_(model),
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      highlighted_app_pending_(false),
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tracker_(NULL) {
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->item_list()->AddObserver(this);
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  BuildModel();
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OnShutdown();
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->item_list()->RemoveObserver(this);
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnBeginExtensionInstall(
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const ExtensionInstallParams& params) {
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!params.is_app || params.is_ephemeral)
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionAppItem* existing_item = GetExtensionAppItem(params.extension_id);
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (existing_item) {
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    existing_item->SetIsInstalling(true);
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  InsertApp(new ExtensionAppItem(profile_,
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 params.extension_id,
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 params.extension_name,
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 params.installing_icon,
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 params.is_platform_app));
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SetHighlightedApp(params.extension_id);
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnDownloadProgress(
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& extension_id,
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int percent_downloaded) {
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* item = GetExtensionAppItem(extension_id);
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item)
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  item->SetPercentDownloaded(percent_downloaded);
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnInstallFailure(
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& extension_id) {
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  model_->item_list()->DeleteItem(extension_id);
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnExtensionLoaded(const Extension* extension) {
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!extension->ShouldDisplayInAppLauncher())
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (existing_item) {
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    existing_item->Reload();
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  InsertApp(new ExtensionAppItem(profile_,
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 extension->id(),
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 "",
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 gfx::ImageSkia(),
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 extension->is_platform_app()));
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateHighlight();
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension* extension) {
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* item = GetExtensionAppItem(extension->id());
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item)
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  item->UpdateIcon();
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnExtensionUninstalled(
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const Extension* extension) {
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->item_list()->DeleteItem(extension->id());
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnAppsReordered() {
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Do nothing; App List order does not track extensions order.
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnAppInstalledToAppList(
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& extension_id) {
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetHighlightedApp(extension_id);
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::OnShutdown() {
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (tracker_) {
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tracker_->RemoveObserver(this);
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tracker_ = NULL;
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::AddApps(const ExtensionSet* extensions,
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       ExtensionAppList* apps) {
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ExtensionSet::const_iterator app = extensions->begin();
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       app != extensions->end(); ++app) {
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (ShouldDisplayInAppLauncher(profile_, *app))
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      apps->push_back(new ExtensionAppItem(profile_,
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           (*app)->id(),
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           "",
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           gfx::ImageSkia(),
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           (*app)->is_platform_app()));
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ExtensionAppModelBuilder::BuildModel() {
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Delete any extension apps.
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->item_list()->DeleteItemsByType(ExtensionAppItem::kAppType);
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (tracker_)
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tracker_->RemoveObserver(this);
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  tracker_ = controller_->GetInstallTrackerFor(profile_);
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  PopulateApps();
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateHighlight();
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Start observing after model is built.
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (tracker_)
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tracker_->AddObserver(this);
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::PopulateApps() {
1690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ExtensionSet extensions;
1700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  controller_->GetApps(profile_, &extensions);
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppList apps;
1720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  AddApps(&extensions, &apps);
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (apps.empty())
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (size_t i = 0; i < apps.size(); ++i)
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    InsertApp(apps[i]);
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem* app) {
1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->item_list()->AddItem(app);
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::SetHighlightedApp(
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& extension_id) {
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (extension_id == highlight_app_id_)
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* old_app = GetExtensionAppItem(highlight_app_id_);
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (old_app)
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    old_app->SetHighlighted(false);
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  highlight_app_id_ = extension_id;
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* new_app = GetExtensionAppItem(highlight_app_id_);
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  highlighted_app_pending_ = !new_app;
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (new_app)
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    new_app->SetHighlighted(true);
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& extension_id) {
2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  app_list::AppListItemModel* item =
2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      model_->item_list()->FindItem(extension_id);
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  LOG_IF(ERROR, item &&
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)         item->GetAppType() != ExtensionAppItem::kAppType)
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      << "App Item matching id: " << extension_id
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      << " has incorrect type: '" << item->GetAppType() << "'";
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return static_cast<ExtensionAppItem*>(item);
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ExtensionAppModelBuilder::UpdateHighlight() {
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(model_);
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!highlighted_app_pending_ || highlight_app_id_.empty())
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppItem* item = GetExtensionAppItem(highlight_app_id_);
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item)
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  item->SetHighlighted(true);
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  highlighted_app_pending_ = false;
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ExtensionAppModelBuilder::OnListItemMoved(
2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    size_t from_index,
2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    size_t to_index,
2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    app_list::AppListItemModel* item) {
2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // This will get called from AppListItemList::ListItemMoved after
2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // set_position is called for the item.
2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  app_list::AppListItemList* item_list = model_->item_list();
2288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (item->GetAppType() != ExtensionAppItem::kAppType)
2298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ExtensionAppItem* prev = NULL;
2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t idx = to_index; idx > 0; --idx) {
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    app_list::AppListItemModel* item = item_list->item_at(idx - 1);
2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (item->GetAppType() == ExtensionAppItem::kAppType) {
2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      prev = static_cast<ExtensionAppItem*>(item);
2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ExtensionAppItem* next = NULL;
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    app_list::AppListItemModel* item = item_list->item_at(idx + 1);
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (item->GetAppType() == ExtensionAppItem::kAppType) {
2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      next = static_cast<ExtensionAppItem*>(item);
2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // item->Move will call set_position, overriding the item's position.
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (prev || next)
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    static_cast<ExtensionAppItem*>(item)->Move(prev, next);
2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
251