Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/app_list/apps_model_builder.h" | 5 #include "chrome/browser/ui/app_list/apps_model_builder.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
| 11 #include "chrome/browser/chrome_notification_types.h" | 11 #include "chrome/browser/chrome_notification_types.h" |
| 12 #include "chrome/browser/extensions/extension_prefs.h" | 12 #include "chrome/browser/extensions/extension_prefs.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/extensions/extension_sorting.h" | 14 #include "chrome/browser/extensions/extension_sorting.h" |
| 15 #include "chrome/browser/extensions/extension_system.h" | 15 #include "chrome/browser/extensions/extension_system.h" |
| 16 #include "chrome/browser/extensions/install_tracker.h" | 16 #include "chrome/browser/extensions/install_tracker.h" |
| 17 #include "chrome/browser/extensions/install_tracker_factory.h" | 17 #include "chrome/browser/extensions/install_tracker_factory.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/ui/app_list/extension_app_item.h" | 19 #include "chrome/browser/ui/app_list/extension_app_item.h" |
| 20 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/extensions/extension_constants.h" | 21 #include "chrome/common/extensions/extension_constants.h" |
| 22 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
| 23 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
| 24 #include "ui/gfx/image/image_skia.h" | 24 #include "ui/gfx/image/image_skia.h" |
| 25 | 25 |
| 26 using extensions::Extension; | 26 using extensions::Extension; |
| 27 using app_list::AppListItemModel; | |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 bool AppPrecedes(const ExtensionAppItem* app1, const ExtensionAppItem* app2) { | 31 bool AppPrecedes(const ExtensionAppItem* app1, const ExtensionAppItem* app2) { |
| 32 if (!app1) | |
| 33 return app2; // non-ExtensionAppItem follows ExtensionAppItem | |
| 34 if (!app2) | |
| 35 return true; // ExtensionAppItem preceeds non-ExtensionAppItem | |
|
jennyz
2013/10/03 20:45:51
Do you mean we should pass null for non-ExtensionA
| |
| 31 const syncer::StringOrdinal& page1 = app1->GetPageOrdinal(); | 36 const syncer::StringOrdinal& page1 = app1->GetPageOrdinal(); |
| 32 const syncer::StringOrdinal& page2 = app2->GetPageOrdinal(); | 37 const syncer::StringOrdinal& page2 = app2->GetPageOrdinal(); |
| 33 if (page1.LessThan(page2)) | 38 if (page1.LessThan(page2)) |
| 34 return true; | 39 return true; |
| 35 | 40 |
| 36 if (page1.Equals(page2)) | 41 if (page1.Equals(page2)) |
| 37 return app1->GetAppLaunchOrdinal().LessThan(app2->GetAppLaunchOrdinal()); | 42 return app1->GetAppLaunchOrdinal().LessThan(app2->GetAppLaunchOrdinal()); |
| 38 | 43 |
| 39 return false; | 44 return false; |
| 40 } | 45 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 return; | 106 return; |
| 102 model_->DeleteAt(i); | 107 model_->DeleteAt(i); |
| 103 } | 108 } |
| 104 | 109 |
| 105 void AppsModelBuilder::OnExtensionLoaded(const Extension* extension) { | 110 void AppsModelBuilder::OnExtensionLoaded(const Extension* extension) { |
| 106 if (!extension->ShouldDisplayInAppLauncher()) | 111 if (!extension->ShouldDisplayInAppLauncher()) |
| 107 return; | 112 return; |
| 108 | 113 |
| 109 const int existing_index = FindApp(extension->id()); | 114 const int existing_index = FindApp(extension->id()); |
| 110 if (existing_index != -1) { | 115 if (existing_index != -1) { |
| 111 GetAppAt(existing_index)->Reload(); | 116 GetAppAt(existing_index)->Update(); |
| 112 return; | 117 return; |
| 113 } | 118 } |
| 114 | 119 |
| 115 InsertApp(new ExtensionAppItem(profile_, | 120 InsertApp(new ExtensionAppItem(profile_, |
| 116 extension->id(), | 121 extension->id(), |
| 117 controller_, | 122 controller_, |
| 118 "", | 123 "", |
| 119 gfx::ImageSkia(), | 124 gfx::ImageSkia(), |
| 120 extension->is_platform_app())); | 125 extension->is_platform_app())); |
| 121 UpdateHighlight(); | 126 UpdateHighlight(); |
| 122 } | 127 } |
| 123 | 128 |
| 124 void AppsModelBuilder::OnExtensionUnloaded(const Extension* extension) { | 129 void AppsModelBuilder::OnExtensionUnloaded(const Extension* extension) { |
| 125 int index = FindApp(extension->id()); | 130 int index = FindApp(extension->id()); |
| 126 if (index < 0) | 131 if (index < 0) |
| 127 return; | 132 return; |
| 128 GetAppAt(index)->UpdateIcon(); | 133 GetAppAt(index)->Update(); |
| 129 } | 134 } |
| 130 | 135 |
| 131 void AppsModelBuilder::OnExtensionUninstalled(const Extension* extension) { | 136 void AppsModelBuilder::OnExtensionUninstalled(const Extension* extension) { |
| 132 int index = FindApp(extension->id()); | 137 int index = FindApp(extension->id()); |
| 133 if (index < 0) | 138 if (index < 0) |
| 134 return; | 139 return; |
| 135 model_->DeleteAt(index); | 140 model_->DeleteAt(index); |
| 136 } | 141 } |
| 137 | 142 |
| 138 void AppsModelBuilder::OnAppsReordered() { | 143 void AppsModelBuilder::OnAppsReordered() { |
| 139 ResortApps(); | 144 ResortApps(); |
| 140 } | 145 } |
| 141 | 146 |
| 142 void AppsModelBuilder::OnAppInstalledToAppList( | 147 void AppsModelBuilder::OnAppInstalledToAppList( |
| 143 const std::string& extension_id) { | 148 const std::string& extension_id) { |
| 144 SetHighlightedApp(extension_id); | 149 SetHighlightedApp(extension_id); |
| 145 } | 150 } |
| 146 | 151 |
| 147 void AppsModelBuilder::OnShutdown() { | 152 void AppsModelBuilder::OnShutdown() { |
| 148 if (tracker_) { | 153 if (tracker_) { |
| 149 tracker_->RemoveObserver(this); | 154 tracker_->RemoveObserver(this); |
| 150 tracker_ = NULL; | 155 tracker_ = NULL; |
| 151 } | 156 } |
| 152 } | 157 } |
| 153 | 158 |
| 154 void AppsModelBuilder::AddApps(const ExtensionSet* extensions, Apps* apps) { | 159 void AppsModelBuilder::AddApps(const ExtensionSet* extensions, |
| 160 ExtensionApps* apps) { | |
| 155 for (ExtensionSet::const_iterator app = extensions->begin(); | 161 for (ExtensionSet::const_iterator app = extensions->begin(); |
| 156 app != extensions->end(); ++app) { | 162 app != extensions->end(); ++app) { |
| 157 if (ShouldDisplayInAppLauncher(profile_, *app)) | 163 if (ShouldDisplayInAppLauncher(profile_, *app)) |
| 158 apps->push_back(new ExtensionAppItem(profile_, | 164 apps->push_back(new ExtensionAppItem(profile_, |
| 159 (*app)->id(), | 165 (*app)->id(), |
| 160 controller_, | 166 controller_, |
| 161 "", | 167 "", |
| 162 gfx::ImageSkia(), | 168 gfx::ImageSkia(), |
| 163 (*app)->is_platform_app())); | 169 (*app)->is_platform_app())); |
| 164 } | 170 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 183 // Start observing after model is built. | 189 // Start observing after model is built. |
| 184 tracker_->AddObserver(this); | 190 tracker_->AddObserver(this); |
| 185 } | 191 } |
| 186 | 192 |
| 187 void AppsModelBuilder::PopulateApps() { | 193 void AppsModelBuilder::PopulateApps() { |
| 188 ExtensionService* service = | 194 ExtensionService* service = |
| 189 extensions::ExtensionSystem::Get(profile_)->extension_service(); | 195 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 190 if (!service) | 196 if (!service) |
| 191 return; | 197 return; |
| 192 | 198 |
| 193 Apps apps; | 199 ExtensionApps apps; |
| 194 AddApps(service->extensions(), &apps); | 200 AddApps(service->extensions(), &apps); |
| 195 AddApps(service->disabled_extensions(), &apps); | 201 AddApps(service->disabled_extensions(), &apps); |
| 196 AddApps(service->terminated_extensions(), &apps); | 202 AddApps(service->terminated_extensions(), &apps); |
| 197 | 203 |
| 198 if (apps.empty()) | 204 if (apps.empty()) |
| 199 return; | 205 return; |
| 200 | 206 |
| 201 service->extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions(); | 207 service->extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions(); |
| 202 std::sort(apps.begin(), apps.end(), &AppPrecedes); | 208 std::sort(apps.begin(), apps.end(), &AppPrecedes); |
| 203 | 209 |
| 204 for (size_t i = 0; i < apps.size(); ++i) | 210 for (size_t i = 0; i < apps.size(); ++i) |
| 205 model_->Add(apps[i]); | 211 model_->Add(apps[i]); |
| 206 } | 212 } |
| 207 | 213 |
| 208 void AppsModelBuilder::ResortApps() { | 214 void AppsModelBuilder::ResortApps() { |
| 209 // Scan app items in |model_| and put the apps that do not have valid ordinals | 215 // Scan app items in |model_| and put the apps that do not have valid ordinals |
| 210 // into |invalid_ordinal_apps|. This is needed to handle uninstalling a | 216 // into |invalid_ordinal_apps|. This is needed to handle uninstalling a |
| 211 // terminated app case, where there is no unload notification and uninstall | 217 // terminated app case, where there is no unload notification and uninstall |
| 212 // notification comes in after the app's ordinals are cleared. | 218 // notification comes in after the app's ordinals are cleared. |
| 213 // See http://crbug.com/256749. | 219 // See http://crbug.com/256749. |
| 214 Apps apps; | 220 ExtensionApps apps; |
| 215 Apps invalid_ordinal_apps; | 221 ExtensionApps invalid_ordinal_apps; |
| 216 for (size_t i = 0; i < model_->item_count(); ++i) { | 222 for (size_t i = 0; i < model_->item_count(); ++i) { |
| 217 ExtensionAppItem* app = GetAppAt(i); | 223 ExtensionAppItem* app = GetExtensionAppAt(i); |
| 218 if (app->GetPageOrdinal().IsValid() && app->GetAppLaunchOrdinal().IsValid()) | 224 if (app->GetPageOrdinal().IsValid() && app->GetAppLaunchOrdinal().IsValid()) |
| 219 apps.push_back(app); | 225 apps.push_back(app); |
| 220 else | 226 else |
| 221 invalid_ordinal_apps.push_back(app); | 227 invalid_ordinal_apps.push_back(app); |
| 222 } | 228 } |
| 223 | 229 |
| 224 std::sort(apps.begin(), apps.end(), &AppPrecedes); | 230 std::sort(apps.begin(), apps.end(), &AppPrecedes); |
| 225 apps.insert( | 231 apps.insert( |
| 226 apps.end(), invalid_ordinal_apps.begin(), invalid_ordinal_apps.end()); | 232 apps.end(), invalid_ordinal_apps.begin(), invalid_ordinal_apps.end()); |
| 227 | 233 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 242 } | 248 } |
| 243 | 249 |
| 244 void AppsModelBuilder::InsertApp(ExtensionAppItem* app) { | 250 void AppsModelBuilder::InsertApp(ExtensionAppItem* app) { |
| 245 DCHECK(model_); | 251 DCHECK(model_); |
| 246 | 252 |
| 247 size_t start = 0; | 253 size_t start = 0; |
| 248 size_t end = model_->item_count(); | 254 size_t end = model_->item_count(); |
| 249 while (start < end) { | 255 while (start < end) { |
| 250 size_t mid = (start + end) / 2; | 256 size_t mid = (start + end) / 2; |
| 251 | 257 |
| 252 if (AppPrecedes(GetAppAt(mid), app)) | 258 if (AppPrecedes(GetExtensionAppAt(mid), app)) |
| 253 start = mid + 1; | 259 start = mid + 1; |
| 254 else | 260 else |
| 255 end = mid; | 261 end = mid; |
| 256 } | 262 } |
| 257 model_->AddAt(start, app); | 263 model_->AddAt(start, app); |
| 258 } | 264 } |
| 259 | 265 |
| 260 int AppsModelBuilder::FindApp(const std::string& app_id) { | 266 int AppsModelBuilder::FindApp(const std::string& app_id) { |
| 261 DCHECK(model_); | 267 DCHECK(model_); |
| 262 | 268 |
| 263 for (size_t i = 0; i < model_->item_count(); ++i) { | 269 for (size_t i = 0; i < model_->item_count(); ++i) { |
| 264 if (GetAppAt(i)->extension_id() == app_id) | 270 if (GetAppAt(i)->app_id() == app_id) |
| 265 return i; | 271 return i; |
| 266 } | 272 } |
| 267 | 273 |
| 268 return -1; | 274 return -1; |
| 269 } | 275 } |
| 270 | 276 |
| 271 void AppsModelBuilder::SetHighlightedApp(const std::string& extension_id) { | 277 void AppsModelBuilder::SetHighlightedApp(const std::string& extension_id) { |
| 272 if (extension_id == highlight_app_id_) | 278 if (extension_id == highlight_app_id_) |
| 273 return; | 279 return; |
| 274 ExtensionAppItem* old_app = GetApp(highlight_app_id_); | 280 AppListItemModel* old_app = GetApp(highlight_app_id_); |
| 275 if (old_app) | 281 if (old_app) |
| 276 old_app->SetHighlighted(false); | 282 old_app->SetHighlighted(false); |
| 277 highlight_app_id_ = extension_id; | 283 highlight_app_id_ = extension_id; |
| 278 ExtensionAppItem* new_app = GetApp(highlight_app_id_); | 284 AppListItemModel* new_app = GetApp(highlight_app_id_); |
| 279 highlighted_app_pending_ = !new_app; | 285 highlighted_app_pending_ = !new_app; |
| 280 if (new_app) | 286 if (new_app) |
| 281 new_app->SetHighlighted(true); | 287 new_app->SetHighlighted(true); |
| 282 } | 288 } |
| 283 | 289 |
| 284 ExtensionAppItem* AppsModelBuilder::GetApp( | 290 AppListItemModel* AppsModelBuilder::GetApp( |
| 285 const std::string& extension_id) { | 291 const std::string& extension_id) { |
| 286 DCHECK(model_); | 292 DCHECK(model_); |
| 287 if (extension_id.empty()) | 293 if (extension_id.empty()) |
| 288 return NULL; | 294 return NULL; |
| 289 | 295 |
| 290 int index = FindApp(extension_id); | 296 int index = FindApp(extension_id); |
| 291 if (index == -1) | 297 if (index == -1) |
| 292 return NULL; | 298 return NULL; |
| 293 return GetAppAt(index); | 299 return GetAppAt(index); |
| 294 } | 300 } |
| 295 | 301 |
| 296 void AppsModelBuilder::UpdateHighlight() { | 302 void AppsModelBuilder::UpdateHighlight() { |
| 297 DCHECK(model_); | 303 DCHECK(model_); |
| 298 if (!highlighted_app_pending_ || highlight_app_id_.empty()) | 304 if (!highlighted_app_pending_ || highlight_app_id_.empty()) |
| 299 return; | 305 return; |
| 300 | 306 |
| 301 int index = FindApp(highlight_app_id_); | 307 int index = FindApp(highlight_app_id_); |
| 302 if (index == -1) | 308 if (index == -1) |
| 303 return; | 309 return; |
| 304 | 310 |
| 305 model_->GetItemAt(index)->SetHighlighted(true); | 311 model_->GetItemAt(index)->SetHighlighted(true); |
| 306 highlighted_app_pending_ = false; | 312 highlighted_app_pending_ = false; |
| 307 } | 313 } |
| 308 | 314 |
| 309 ExtensionAppItem* AppsModelBuilder::GetAppAt(size_t index) { | 315 AppListItemModel* AppsModelBuilder::GetAppAt(size_t index) { |
| 310 DCHECK_LT(index, model_->item_count()); | 316 DCHECK_LT(index, model_->item_count()); |
| 311 ChromeAppListItem* item = | 317 return model_->GetItemAt(index); |
| 312 static_cast<ChromeAppListItem*>(model_->GetItemAt(index)); | 318 } |
| 313 DCHECK_EQ(item->type(), ChromeAppListItem::TYPE_APP); | |
| 314 | 319 |
| 315 return static_cast<ExtensionAppItem*>(item); | 320 ExtensionAppItem* AppsModelBuilder::GetExtensionAppAt(size_t index) { |
| 321 AppListItemModel* app = GetAppAt(index); | |
| 322 if (app->AppType() != ExtensionAppItem::ExtensionAppType()) | |
| 323 return NULL; | |
| 324 return static_cast<ExtensionAppItem*>(app); | |
| 316 } | 325 } |
| 317 | 326 |
| 318 void AppsModelBuilder::ListItemsAdded(size_t start, size_t count) { | 327 void AppsModelBuilder::ListItemsAdded(size_t start, size_t count) { |
| 319 } | 328 } |
| 320 | 329 |
| 321 void AppsModelBuilder::ListItemsRemoved(size_t start, size_t count) { | 330 void AppsModelBuilder::ListItemsRemoved(size_t start, size_t count) { |
| 322 } | 331 } |
| 323 | 332 |
| 324 void AppsModelBuilder::ListItemMoved(size_t index, size_t target_index) { | 333 void AppsModelBuilder::ListItemMoved(size_t index, size_t target_index) { |
| 325 if (ignore_changes_) | 334 if (ignore_changes_) |
| 326 return; | 335 return; |
| 327 | 336 |
| 328 ExtensionAppItem* prev = target_index > 0 ? GetAppAt(target_index - 1) : NULL; | 337 ExtensionAppItem* prev = target_index > 0 ? |
| 338 GetExtensionAppAt(target_index - 1) : NULL; | |
| 329 ExtensionAppItem* next = target_index + 1 < model_->item_count() ? | 339 ExtensionAppItem* next = target_index + 1 < model_->item_count() ? |
| 330 GetAppAt(target_index + 1) : NULL; | 340 GetExtensionAppAt(target_index + 1) : NULL; |
| 331 GetAppAt(target_index)->Move(prev, next); | 341 ExtensionAppItem* target_app = GetExtensionAppAt(target_index); |
| 342 target_app->Move(prev, next); | |
| 332 } | 343 } |
| 333 | 344 |
| 334 void AppsModelBuilder::ListItemsChanged(size_t start, size_t count) { | 345 void AppsModelBuilder::ListItemsChanged(size_t start, size_t count) { |
| 335 NOTREACHED(); | 346 NOTREACHED(); |
| 336 } | 347 } |
| OLD | NEW |