OLD | NEW |
(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/ash/app_list/apps_model_builder.h" |
| 6 |
| 7 #include "base/i18n/case_conversion.h" |
| 8 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/browser_process.h" |
| 10 #include "chrome/browser/extensions/extension_service.h" |
| 11 #include "chrome/browser/profiles/profile.h" |
| 12 #include "chrome/browser/ui/ash/app_list/extension_app_item.h" |
| 13 #include "chrome/common/chrome_notification_types.h" |
| 14 #include "chrome/common/extensions/extension.h" |
| 15 #include "content/public/browser/notification_service.h" |
| 16 #include "ui/base/l10n/l10n_util_collator.h" |
| 17 |
| 18 using extensions::Extension; |
| 19 |
| 20 namespace { |
| 21 |
| 22 const char* kSpecialApps[] = { |
| 23 extension_misc::kChromeAppId, |
| 24 extension_misc::kWebStoreAppId, |
| 25 }; |
| 26 |
| 27 // ModelItemSortData provides a string key to sort with |
| 28 // l10n_util::StringComparator. |
| 29 struct ModelItemSortData { |
| 30 explicit ModelItemSortData(app_list::AppListItemModel* app) |
| 31 : app(app), |
| 32 key(base::i18n::ToLower(UTF8ToUTF16(app->title()))) { |
| 33 } |
| 34 |
| 35 // Needed by StringComparator<Element> in SortVectorWithStringKey, which uses |
| 36 // this method to get a key to sort. |
| 37 const string16& GetStringKey() const { |
| 38 return key; |
| 39 } |
| 40 |
| 41 app_list::AppListItemModel* app; |
| 42 string16 key; |
| 43 }; |
| 44 |
| 45 // Returns true if given |extension_id| is listed in kSpecialApps. |
| 46 bool IsSpecialApp(const std::string& extension_id) { |
| 47 for (size_t i = 0; i < arraysize(kSpecialApps); ++i) { |
| 48 if (extension_id == kSpecialApps[i]) |
| 49 return true; |
| 50 } |
| 51 |
| 52 return false; |
| 53 } |
| 54 |
| 55 } // namespace |
| 56 |
| 57 AppsModelBuilder::AppsModelBuilder(Profile* profile, |
| 58 app_list::AppListModel::Apps* model) |
| 59 : profile_(profile), |
| 60 model_(model), |
| 61 special_apps_count_(0) { |
| 62 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 63 content::Source<Profile>(profile_)); |
| 64 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 65 content::Source<Profile>(profile_)); |
| 66 registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST, |
| 67 content::Source<Profile>(profile_)); |
| 68 } |
| 69 |
| 70 AppsModelBuilder::~AppsModelBuilder() { |
| 71 } |
| 72 |
| 73 void AppsModelBuilder::Build() { |
| 74 DCHECK(model_ && model_->item_count() == 0); |
| 75 CreateSpecialApps(); |
| 76 |
| 77 Apps apps; |
| 78 GetExtensionApps(&apps); |
| 79 |
| 80 SortAndPopulateModel(apps); |
| 81 HighlightApp(); |
| 82 } |
| 83 |
| 84 void AppsModelBuilder::SortAndPopulateModel(const Apps& apps) { |
| 85 // Just return if there is nothing to populate. |
| 86 if (apps.empty()) |
| 87 return; |
| 88 |
| 89 // Sort apps case insensitive alphabetically. |
| 90 std::vector<ModelItemSortData> sorted; |
| 91 for (Apps::const_iterator it = apps.begin(); it != apps.end(); ++it) |
| 92 sorted.push_back(ModelItemSortData(*it)); |
| 93 |
| 94 l10n_util::SortVectorWithStringKey(g_browser_process->GetApplicationLocale(), |
| 95 &sorted, |
| 96 false /* needs_stable_sort */); |
| 97 for (std::vector<ModelItemSortData>::const_iterator it = sorted.begin(); |
| 98 it != sorted.end(); |
| 99 ++it) { |
| 100 model_->Add(it->app); |
| 101 } |
| 102 } |
| 103 |
| 104 void AppsModelBuilder::InsertItemByTitle(app_list::AppListItemModel* app) { |
| 105 DCHECK(model_); |
| 106 |
| 107 icu::Locale locale(g_browser_process->GetApplicationLocale().c_str()); |
| 108 UErrorCode error = U_ZERO_ERROR; |
| 109 scoped_ptr<icu::Collator> collator( |
| 110 icu::Collator::createInstance(locale, error)); |
| 111 if (U_FAILURE(error)) |
| 112 collator.reset(); |
| 113 |
| 114 l10n_util::StringComparator<string16> c(collator.get()); |
| 115 ModelItemSortData data(app); |
| 116 for (size_t i = special_apps_count_; i < model_->item_count(); ++i) { |
| 117 ModelItemSortData current(model_->GetItemAt(i)); |
| 118 if (!c(current.key, data.key)) { |
| 119 model_->AddAt(i, app); |
| 120 return; |
| 121 } |
| 122 } |
| 123 model_->Add(app); |
| 124 } |
| 125 |
| 126 void AppsModelBuilder::GetExtensionApps(Apps* apps) { |
| 127 DCHECK(profile_); |
| 128 ExtensionService* service = profile_->GetExtensionService(); |
| 129 if (!service) |
| 130 return; |
| 131 |
| 132 // Get extension apps. |
| 133 const ExtensionSet* extensions = service->extensions(); |
| 134 for (ExtensionSet::const_iterator app = extensions->begin(); |
| 135 app != extensions->end(); ++app) { |
| 136 if ((*app)->ShouldDisplayInLauncher() && |
| 137 !IsSpecialApp((*app)->id())) { |
| 138 apps->push_back(new ExtensionAppItem(profile_, *app)); |
| 139 } |
| 140 } |
| 141 } |
| 142 |
| 143 void AppsModelBuilder::CreateSpecialApps() { |
| 144 DCHECK(model_ && model_->item_count() == 0); |
| 145 |
| 146 bool is_guest_session = Profile::IsGuestSession(); |
| 147 ExtensionService* service = profile_->GetExtensionService(); |
| 148 DCHECK(service); |
| 149 for (size_t i = 0; i < arraysize(kSpecialApps); ++i) { |
| 150 const std::string extension_id(kSpecialApps[i]); |
| 151 if (is_guest_session && extension_id == extension_misc::kWebStoreAppId) |
| 152 continue; |
| 153 |
| 154 const Extension* extension = service->GetInstalledExtension(extension_id); |
| 155 DCHECK(extension); |
| 156 |
| 157 model_->Add(new ExtensionAppItem(profile_, extension)); |
| 158 } |
| 159 |
| 160 special_apps_count_ = model_->item_count(); |
| 161 } |
| 162 |
| 163 int AppsModelBuilder::FindApp(const std::string& app_id) { |
| 164 DCHECK(model_); |
| 165 for (size_t i = special_apps_count_; i < model_->item_count(); ++i) { |
| 166 ChromeAppListItem* app = |
| 167 static_cast<ChromeAppListItem*>(model_->GetItemAt(i)); |
| 168 if (app->type() != ChromeAppListItem::TYPE_APP) |
| 169 continue; |
| 170 |
| 171 ExtensionAppItem* extension_item = static_cast<ExtensionAppItem*>(app); |
| 172 if (extension_item->extension_id() == app_id) |
| 173 return i; |
| 174 } |
| 175 |
| 176 return -1; |
| 177 } |
| 178 |
| 179 void AppsModelBuilder::HighlightApp() { |
| 180 DCHECK(model_); |
| 181 if (highlight_app_id_.empty()) |
| 182 return; |
| 183 |
| 184 int index = FindApp(highlight_app_id_); |
| 185 if (index == -1) |
| 186 return; |
| 187 |
| 188 model_->GetItemAt(index)->SetHighlighted(true); |
| 189 highlight_app_id_.clear(); |
| 190 } |
| 191 |
| 192 void AppsModelBuilder::Observe(int type, |
| 193 const content::NotificationSource& source, |
| 194 const content::NotificationDetails& details) { |
| 195 switch (type) { |
| 196 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
| 197 const Extension* extension = |
| 198 content::Details<const Extension>(details).ptr(); |
| 199 if (!extension->ShouldDisplayInLauncher()) |
| 200 return; |
| 201 |
| 202 if (FindApp(extension->id()) != -1) |
| 203 return; |
| 204 |
| 205 InsertItemByTitle(new ExtensionAppItem(profile_, extension)); |
| 206 HighlightApp(); |
| 207 break; |
| 208 } |
| 209 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
| 210 const Extension* extension = |
| 211 content::Details<extensions::UnloadedExtensionInfo>( |
| 212 details)->extension; |
| 213 int index = FindApp(extension->id()); |
| 214 if (index >= 0) |
| 215 model_->DeleteAt(index); |
| 216 break; |
| 217 } |
| 218 case chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST: { |
| 219 highlight_app_id_ = *content::Details<const std::string>(details).ptr(); |
| 220 HighlightApp(); |
| 221 break; |
| 222 } |
| 223 default: |
| 224 NOTREACHED(); |
| 225 } |
| 226 } |
OLD | NEW |