| 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/extensions/extension_menu_manager.h" | 5 #include "chrome/browser/extensions/menu_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "chrome/browser/extensions/extension_event_names.h" | 15 #include "chrome/browser/extensions/extension_event_names.h" |
| 16 #include "chrome/browser/extensions/extension_event_router.h" | 16 #include "chrome/browser/extensions/extension_event_router.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
| 18 #include "chrome/browser/extensions/extension_system.h" | 18 #include "chrome/browser/extensions/extension_system.h" |
| 19 #include "chrome/browser/extensions/extension_tab_helper.h" | 19 #include "chrome/browser/extensions/extension_tab_helper.h" |
| 20 #include "chrome/browser/extensions/extension_tab_util.h" | 20 #include "chrome/browser/extensions/extension_tab_util.h" |
| 21 #include "chrome/browser/extensions/state_store.h" | 21 #include "chrome/browser/extensions/state_store.h" |
| 22 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
| 23 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 23 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 24 #include "chrome/common/chrome_notification_types.h" | 24 #include "chrome/common/chrome_notification_types.h" |
| 25 #include "chrome/common/extensions/extension.h" | 25 #include "chrome/common/extensions/extension.h" |
| 26 #include "content/public/browser/notification_details.h" | 26 #include "content/public/browser/notification_details.h" |
| 27 #include "content/public/browser/notification_source.h" | 27 #include "content/public/browser/notification_source.h" |
| 28 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
| 29 #include "content/public/common/context_menu_params.h" | 29 #include "content/public/common/context_menu_params.h" |
| 30 #include "ui/base/text/text_elider.h" | 30 #include "ui/base/text/text_elider.h" |
| 31 #include "ui/gfx/favicon_size.h" | 31 #include "ui/gfx/favicon_size.h" |
| 32 | 32 |
| 33 using content::WebContents; | 33 using content::WebContents; |
| 34 | 34 |
| 35 namespace extensions { |
| 36 |
| 35 namespace { | 37 namespace { |
| 36 | 38 |
| 37 // Keys for serialization to and from Value to store in the preferences. | 39 // Keys for serialization to and from Value to store in the preferences. |
| 38 const char kContextMenusKey[] = "context_menus"; | 40 const char kContextMenusKey[] = "context_menus"; |
| 39 | 41 |
| 40 const char kCheckedKey[] = "checked"; | 42 const char kCheckedKey[] = "checked"; |
| 41 const char kContextsKey[] = "contexts"; | 43 const char kContextsKey[] = "contexts"; |
| 42 const char kDocumentURLPatternsKey[] = "document_url_patterns"; | 44 const char kDocumentURLPatternsKey[] = "document_url_patterns"; |
| 43 const char kEnabledKey[] = "enabled"; | 45 const char kEnabledKey[] = "enabled"; |
| 44 const char kIncognitoKey[] = "incognito"; | 46 const char kIncognitoKey[] = "incognito"; |
| 45 const char kParentUIDKey[] = "parent_uid"; | 47 const char kParentUIDKey[] = "parent_uid"; |
| 46 const char kStringUIDKey[] = "string_uid"; | 48 const char kStringUIDKey[] = "string_uid"; |
| 47 const char kTargetURLPatternsKey[] = "target_url_patterns"; | 49 const char kTargetURLPatternsKey[] = "target_url_patterns"; |
| 48 const char kTitleKey[] = "title"; | 50 const char kTitleKey[] = "title"; |
| 49 const char kTypeKey[] = "type"; | 51 const char kTypeKey[] = "type"; |
| 50 | 52 |
| 51 void SetIdKeyValue(base::DictionaryValue* properties, | 53 void SetIdKeyValue(base::DictionaryValue* properties, |
| 52 const char* key, | 54 const char* key, |
| 53 const ExtensionMenuItem::Id& id) { | 55 const MenuItem::Id& id) { |
| 54 if (id.uid == 0) | 56 if (id.uid == 0) |
| 55 properties->SetString(key, id.string_uid); | 57 properties->SetString(key, id.string_uid); |
| 56 else | 58 else |
| 57 properties->SetInteger(key, id.uid); | 59 properties->SetInteger(key, id.uid); |
| 58 } | 60 } |
| 59 | 61 |
| 60 ExtensionMenuItem::List MenuItemsFromValue(const std::string& extension_id, | 62 MenuItem::List MenuItemsFromValue(const std::string& extension_id, |
| 61 base::Value* value) { | 63 base::Value* value) { |
| 62 ExtensionMenuItem::List items; | 64 MenuItem::List items; |
| 63 | 65 |
| 64 base::ListValue* list = NULL; | 66 base::ListValue* list = NULL; |
| 65 if (!value || !value->GetAsList(&list)) | 67 if (!value || !value->GetAsList(&list)) |
| 66 return items; | 68 return items; |
| 67 | 69 |
| 68 for (size_t i = 0; i < list->GetSize(); ++i) { | 70 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 69 base::DictionaryValue* dict = NULL; | 71 base::DictionaryValue* dict = NULL; |
| 70 if (!list->GetDictionary(i, &dict)) | 72 if (!list->GetDictionary(i, &dict)) |
| 71 continue; | 73 continue; |
| 72 ExtensionMenuItem* item = ExtensionMenuItem::Populate( | 74 MenuItem* item = MenuItem::Populate( |
| 73 extension_id, *dict, NULL); | 75 extension_id, *dict, NULL); |
| 74 if (!item) | 76 if (!item) |
| 75 continue; | 77 continue; |
| 76 items.push_back(item); | 78 items.push_back(item); |
| 77 } | 79 } |
| 78 return items; | 80 return items; |
| 79 } | 81 } |
| 80 | 82 |
| 81 scoped_ptr<base::Value> MenuItemsToValue( | 83 scoped_ptr<base::Value> MenuItemsToValue(const MenuItem::List& items) { |
| 82 const ExtensionMenuItem::List& items) { | |
| 83 scoped_ptr<base::ListValue> list(new ListValue()); | 84 scoped_ptr<base::ListValue> list(new ListValue()); |
| 84 for (size_t i = 0; i < items.size(); ++i) | 85 for (size_t i = 0; i < items.size(); ++i) |
| 85 list->Append(items[i]->ToValue().release()); | 86 list->Append(items[i]->ToValue().release()); |
| 86 return scoped_ptr<Value>(list.release()); | 87 return scoped_ptr<Value>(list.release()); |
| 87 } | 88 } |
| 88 | 89 |
| 89 } // namespace | 90 } // namespace |
| 90 | 91 |
| 91 ExtensionMenuItem::ExtensionMenuItem(const Id& id, | 92 MenuItem::MenuItem(const Id& id, |
| 92 const std::string& title, | 93 const std::string& title, |
| 93 bool checked, | 94 bool checked, |
| 94 bool enabled, | 95 bool enabled, |
| 95 Type type, | 96 Type type, |
| 96 const ContextList& contexts) | 97 const ContextList& contexts) |
| 97 : id_(id), | 98 : id_(id), |
| 98 title_(title), | 99 title_(title), |
| 99 type_(type), | 100 type_(type), |
| 100 checked_(checked), | 101 checked_(checked), |
| 101 enabled_(enabled), | 102 enabled_(enabled), |
| 102 contexts_(contexts), | 103 contexts_(contexts), |
| 103 parent_id_(0) { | 104 parent_id_(0) { |
| 104 } | 105 } |
| 105 | 106 |
| 106 ExtensionMenuItem::~ExtensionMenuItem() { | 107 MenuItem::~MenuItem() { |
| 107 STLDeleteElements(&children_); | 108 STLDeleteElements(&children_); |
| 108 } | 109 } |
| 109 | 110 |
| 110 ExtensionMenuItem* ExtensionMenuItem::ReleaseChild(const Id& child_id, | 111 MenuItem* MenuItem::ReleaseChild(const Id& child_id, |
| 111 bool recursive) { | 112 bool recursive) { |
| 112 for (List::iterator i = children_.begin(); i != children_.end(); ++i) { | 113 for (List::iterator i = children_.begin(); i != children_.end(); ++i) { |
| 113 ExtensionMenuItem* child = NULL; | 114 MenuItem* child = NULL; |
| 114 if ((*i)->id() == child_id) { | 115 if ((*i)->id() == child_id) { |
| 115 child = *i; | 116 child = *i; |
| 116 children_.erase(i); | 117 children_.erase(i); |
| 117 return child; | 118 return child; |
| 118 } else if (recursive) { | 119 } else if (recursive) { |
| 119 child = (*i)->ReleaseChild(child_id, recursive); | 120 child = (*i)->ReleaseChild(child_id, recursive); |
| 120 if (child) | 121 if (child) |
| 121 return child; | 122 return child; |
| 122 } | 123 } |
| 123 } | 124 } |
| 124 return NULL; | 125 return NULL; |
| 125 } | 126 } |
| 126 | 127 |
| 127 void ExtensionMenuItem::GetFlattenedSubtree(ExtensionMenuItem::List* list) { | 128 void MenuItem::GetFlattenedSubtree(MenuItem::List* list) { |
| 128 list->push_back(this); | 129 list->push_back(this); |
| 129 for (List::iterator i = children_.begin(); i != children_.end(); ++i) | 130 for (List::iterator i = children_.begin(); i != children_.end(); ++i) |
| 130 (*i)->GetFlattenedSubtree(list); | 131 (*i)->GetFlattenedSubtree(list); |
| 131 } | 132 } |
| 132 | 133 |
| 133 std::set<ExtensionMenuItem::Id> ExtensionMenuItem::RemoveAllDescendants() { | 134 std::set<MenuItem::Id> MenuItem::RemoveAllDescendants() { |
| 134 std::set<Id> result; | 135 std::set<Id> result; |
| 135 for (List::iterator i = children_.begin(); i != children_.end(); ++i) { | 136 for (List::iterator i = children_.begin(); i != children_.end(); ++i) { |
| 136 ExtensionMenuItem* child = *i; | 137 MenuItem* child = *i; |
| 137 result.insert(child->id()); | 138 result.insert(child->id()); |
| 138 std::set<Id> removed = child->RemoveAllDescendants(); | 139 std::set<Id> removed = child->RemoveAllDescendants(); |
| 139 result.insert(removed.begin(), removed.end()); | 140 result.insert(removed.begin(), removed.end()); |
| 140 } | 141 } |
| 141 STLDeleteElements(&children_); | 142 STLDeleteElements(&children_); |
| 142 return result; | 143 return result; |
| 143 } | 144 } |
| 144 | 145 |
| 145 string16 ExtensionMenuItem::TitleWithReplacement( | 146 string16 MenuItem::TitleWithReplacement( |
| 146 const string16& selection, size_t max_length) const { | 147 const string16& selection, size_t max_length) const { |
| 147 string16 result = UTF8ToUTF16(title_); | 148 string16 result = UTF8ToUTF16(title_); |
| 148 // TODO(asargent) - Change this to properly handle %% escaping so you can | 149 // TODO(asargent) - Change this to properly handle %% escaping so you can |
| 149 // put "%s" in titles that won't get substituted. | 150 // put "%s" in titles that won't get substituted. |
| 150 ReplaceSubstringsAfterOffset(&result, 0, ASCIIToUTF16("%s"), selection); | 151 ReplaceSubstringsAfterOffset(&result, 0, ASCIIToUTF16("%s"), selection); |
| 151 | 152 |
| 152 if (result.length() > max_length) | 153 if (result.length() > max_length) |
| 153 result = ui::TruncateString(result, max_length); | 154 result = ui::TruncateString(result, max_length); |
| 154 return result; | 155 return result; |
| 155 } | 156 } |
| 156 | 157 |
| 157 bool ExtensionMenuItem::SetChecked(bool checked) { | 158 bool MenuItem::SetChecked(bool checked) { |
| 158 if (type_ != CHECKBOX && type_ != RADIO) | 159 if (type_ != CHECKBOX && type_ != RADIO) |
| 159 return false; | 160 return false; |
| 160 checked_ = checked; | 161 checked_ = checked; |
| 161 return true; | 162 return true; |
| 162 } | 163 } |
| 163 | 164 |
| 164 void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { | 165 void MenuItem::AddChild(MenuItem* item) { |
| 165 item->parent_id_.reset(new Id(id_)); | 166 item->parent_id_.reset(new Id(id_)); |
| 166 children_.push_back(item); | 167 children_.push_back(item); |
| 167 } | 168 } |
| 168 | 169 |
| 169 scoped_ptr<DictionaryValue> ExtensionMenuItem::ToValue() const { | 170 scoped_ptr<DictionaryValue> MenuItem::ToValue() const { |
| 170 scoped_ptr<DictionaryValue> value(new DictionaryValue); | 171 scoped_ptr<DictionaryValue> value(new DictionaryValue); |
| 171 // Should only be called for extensions with event pages, which only have | 172 // Should only be called for extensions with event pages, which only have |
| 172 // string IDs for items. | 173 // string IDs for items. |
| 173 DCHECK_EQ(0, id_.uid); | 174 DCHECK_EQ(0, id_.uid); |
| 174 value->SetString(kStringUIDKey, id_.string_uid); | 175 value->SetString(kStringUIDKey, id_.string_uid); |
| 175 value->SetBoolean(kIncognitoKey, id_.incognito); | 176 value->SetBoolean(kIncognitoKey, id_.incognito); |
| 176 value->SetInteger(kTypeKey, type_); | 177 value->SetInteger(kTypeKey, type_); |
| 177 if (type_ != SEPARATOR) | 178 if (type_ != SEPARATOR) |
| 178 value->SetString(kTitleKey, title_); | 179 value->SetString(kTitleKey, title_); |
| 179 if (type_ == CHECKBOX || type_ == RADIO) | 180 if (type_ == CHECKBOX || type_ == RADIO) |
| 180 value->SetBoolean(kCheckedKey, checked_); | 181 value->SetBoolean(kCheckedKey, checked_); |
| 181 value->SetBoolean(kEnabledKey, enabled_); | 182 value->SetBoolean(kEnabledKey, enabled_); |
| 182 value->Set(kContextsKey, contexts_.ToValue().release()); | 183 value->Set(kContextsKey, contexts_.ToValue().release()); |
| 183 if (parent_id_.get()) { | 184 if (parent_id_.get()) { |
| 184 DCHECK_EQ(0, parent_id_->uid); | 185 DCHECK_EQ(0, parent_id_->uid); |
| 185 value->SetString(kParentUIDKey, parent_id_->string_uid); | 186 value->SetString(kParentUIDKey, parent_id_->string_uid); |
| 186 } | 187 } |
| 187 value->Set(kDocumentURLPatternsKey, | 188 value->Set(kDocumentURLPatternsKey, |
| 188 document_url_patterns_.ToValue().release()); | 189 document_url_patterns_.ToValue().release()); |
| 189 value->Set(kTargetURLPatternsKey, target_url_patterns_.ToValue().release()); | 190 value->Set(kTargetURLPatternsKey, target_url_patterns_.ToValue().release()); |
| 190 return value.Pass(); | 191 return value.Pass(); |
| 191 } | 192 } |
| 192 | 193 |
| 193 // static | 194 // static |
| 194 ExtensionMenuItem* ExtensionMenuItem::Populate(const std::string& extension_id, | 195 MenuItem* MenuItem::Populate(const std::string& extension_id, |
| 195 const DictionaryValue& value, | 196 const DictionaryValue& value, |
| 196 std::string* error) { | 197 std::string* error) { |
| 197 bool incognito = false; | 198 bool incognito = false; |
| 198 if (!value.GetBoolean(kIncognitoKey, &incognito)) | 199 if (!value.GetBoolean(kIncognitoKey, &incognito)) |
| 199 return NULL; | 200 return NULL; |
| 200 Id id(incognito, extension_id); | 201 Id id(incognito, extension_id); |
| 201 if (!value.GetString(kStringUIDKey, &id.string_uid)) | 202 if (!value.GetString(kStringUIDKey, &id.string_uid)) |
| 202 return NULL; | 203 return NULL; |
| 203 int type_int; | 204 int type_int; |
| 204 Type type; | 205 Type type; |
| 205 if (!value.GetInteger(kTypeKey, &type_int)) | 206 if (!value.GetInteger(kTypeKey, &type_int)) |
| 206 return NULL; | 207 return NULL; |
| 207 type = static_cast<Type>(type_int); | 208 type = static_cast<Type>(type_int); |
| 208 std::string title; | 209 std::string title; |
| 209 if (type != SEPARATOR && !value.GetString(kTitleKey, &title)) | 210 if (type != SEPARATOR && !value.GetString(kTitleKey, &title)) |
| 210 return NULL; | 211 return NULL; |
| 211 bool checked; | 212 bool checked; |
| 212 if ((type == CHECKBOX || type == RADIO) && | 213 if ((type == CHECKBOX || type == RADIO) && |
| 213 !value.GetBoolean(kCheckedKey, &checked)) { | 214 !value.GetBoolean(kCheckedKey, &checked)) { |
| 214 return NULL; | 215 return NULL; |
| 215 } | 216 } |
| 216 bool enabled = true; | 217 bool enabled = true; |
| 217 if (!value.GetBoolean(kEnabledKey, &enabled)) | 218 if (!value.GetBoolean(kEnabledKey, &enabled)) |
| 218 return NULL; | 219 return NULL; |
| 219 ContextList contexts; | 220 ContextList contexts; |
| 220 Value* contexts_value = NULL; | 221 Value* contexts_value = NULL; |
| 221 if (!value.Get(kContextsKey, &contexts_value)) | 222 if (!value.Get(kContextsKey, &contexts_value)) |
| 222 return NULL; | 223 return NULL; |
| 223 if (!contexts.Populate(*contexts_value)) | 224 if (!contexts.Populate(*contexts_value)) |
| 224 return NULL; | 225 return NULL; |
| 225 | 226 |
| 226 scoped_ptr<ExtensionMenuItem> result(new ExtensionMenuItem( | 227 scoped_ptr<MenuItem> result(new MenuItem( |
| 227 id, title, checked, enabled, type, contexts)); | 228 id, title, checked, enabled, type, contexts)); |
| 228 | 229 |
| 229 if (!result->PopulateURLPatterns( | 230 if (!result->PopulateURLPatterns( |
| 230 value, kDocumentURLPatternsKey, kTargetURLPatternsKey, error)) | 231 value, kDocumentURLPatternsKey, kTargetURLPatternsKey, error)) |
| 231 return NULL; | 232 return NULL; |
| 232 | 233 |
| 233 // parent_id is filled in from the value, but it might not be valid. It's left | 234 // parent_id is filled in from the value, but it might not be valid. It's left |
| 234 // to be validated upon being added (via AddChildItem) to the menu manager. | 235 // to be validated upon being added (via AddChildItem) to the menu manager. |
| 235 scoped_ptr<Id> parent_id(new Id(incognito, extension_id)); | 236 scoped_ptr<Id> parent_id(new Id(incognito, extension_id)); |
| 236 if (value.HasKey(kParentUIDKey)) { | 237 if (value.HasKey(kParentUIDKey)) { |
| 237 if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) | 238 if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) |
| 238 return NULL; | 239 return NULL; |
| 239 result->parent_id_.swap(parent_id); | 240 result->parent_id_.swap(parent_id); |
| 240 } | 241 } |
| 241 return result.release(); | 242 return result.release(); |
| 242 } | 243 } |
| 243 | 244 |
| 244 bool ExtensionMenuItem::PopulateURLPatterns( | 245 bool MenuItem::PopulateURLPatterns(const DictionaryValue& properties, |
| 245 const DictionaryValue& properties, | 246 const char* document_url_patterns_key, |
| 246 const char* document_url_patterns_key, | 247 const char* target_url_patterns_key, |
| 247 const char* target_url_patterns_key, | 248 std::string* error) { |
| 248 std::string* error) { | |
| 249 if (properties.HasKey(document_url_patterns_key)) { | 249 if (properties.HasKey(document_url_patterns_key)) { |
| 250 ListValue* list = NULL; | 250 ListValue* list = NULL; |
| 251 if (!properties.GetList(document_url_patterns_key, &list)) | 251 if (!properties.GetList(document_url_patterns_key, &list)) |
| 252 return false; | 252 return false; |
| 253 if (!document_url_patterns_.Populate( | 253 if (!document_url_patterns_.Populate( |
| 254 *list, URLPattern::SCHEME_ALL, true, error)) { | 254 *list, URLPattern::SCHEME_ALL, true, error)) { |
| 255 return false; | 255 return false; |
| 256 } | 256 } |
| 257 } | 257 } |
| 258 if (properties.HasKey(target_url_patterns_key)) { | 258 if (properties.HasKey(target_url_patterns_key)) { |
| 259 ListValue* list = NULL; | 259 ListValue* list = NULL; |
| 260 if (!properties.GetList(target_url_patterns_key, &list)) | 260 if (!properties.GetList(target_url_patterns_key, &list)) |
| 261 return false; | 261 return false; |
| 262 if (!target_url_patterns_.Populate( | 262 if (!target_url_patterns_.Populate( |
| 263 *list, URLPattern::SCHEME_ALL, true, error)) { | 263 *list, URLPattern::SCHEME_ALL, true, error)) { |
| 264 return false; | 264 return false; |
| 265 } | 265 } |
| 266 } | 266 } |
| 267 return true; | 267 return true; |
| 268 } | 268 } |
| 269 | 269 |
| 270 ExtensionMenuManager::ExtensionMenuManager(Profile* profile) | 270 MenuManager::MenuManager(Profile* profile) |
| 271 : profile_(profile) { | 271 : profile_(profile) { |
| 272 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 272 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 273 content::Source<Profile>(profile)); | 273 content::Source<Profile>(profile)); |
| 274 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 274 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 275 content::Source<Profile>(profile)); | 275 content::Source<Profile>(profile)); |
| 276 | 276 |
| 277 extensions::StateStore* store = ExtensionSystem::Get(profile_)->state_store(); | 277 StateStore* store = ExtensionSystem::Get(profile_)->state_store(); |
| 278 if (store) | 278 if (store) |
| 279 store->RegisterKey(kContextMenusKey); | 279 store->RegisterKey(kContextMenusKey); |
| 280 } | 280 } |
| 281 | 281 |
| 282 ExtensionMenuManager::~ExtensionMenuManager() { | 282 MenuManager::~MenuManager() { |
| 283 MenuItemMap::iterator i; | 283 MenuItemMap::iterator i; |
| 284 for (i = context_items_.begin(); i != context_items_.end(); ++i) { | 284 for (i = context_items_.begin(); i != context_items_.end(); ++i) { |
| 285 STLDeleteElements(&(i->second)); | 285 STLDeleteElements(&(i->second)); |
| 286 } | 286 } |
| 287 } | 287 } |
| 288 | 288 |
| 289 std::set<std::string> ExtensionMenuManager::ExtensionIds() { | 289 std::set<std::string> MenuManager::ExtensionIds() { |
| 290 std::set<std::string> id_set; | 290 std::set<std::string> id_set; |
| 291 for (MenuItemMap::const_iterator i = context_items_.begin(); | 291 for (MenuItemMap::const_iterator i = context_items_.begin(); |
| 292 i != context_items_.end(); ++i) { | 292 i != context_items_.end(); ++i) { |
| 293 id_set.insert(i->first); | 293 id_set.insert(i->first); |
| 294 } | 294 } |
| 295 return id_set; | 295 return id_set; |
| 296 } | 296 } |
| 297 | 297 |
| 298 const ExtensionMenuItem::List* ExtensionMenuManager::MenuItems( | 298 const MenuItem::List* MenuManager::MenuItems( |
| 299 const std::string& extension_id) { | 299 const std::string& extension_id) { |
| 300 MenuItemMap::iterator i = context_items_.find(extension_id); | 300 MenuItemMap::iterator i = context_items_.find(extension_id); |
| 301 if (i != context_items_.end()) { | 301 if (i != context_items_.end()) { |
| 302 return &(i->second); | 302 return &(i->second); |
| 303 } | 303 } |
| 304 return NULL; | 304 return NULL; |
| 305 } | 305 } |
| 306 | 306 |
| 307 bool ExtensionMenuManager::AddContextItem( | 307 bool MenuManager::AddContextItem( |
| 308 const extensions::Extension* extension, | 308 const Extension* extension, |
| 309 ExtensionMenuItem* item) { | 309 MenuItem* item) { |
| 310 const std::string& extension_id = item->extension_id(); | 310 const std::string& extension_id = item->extension_id(); |
| 311 // The item must have a non-empty extension id, and not have already been | 311 // The item must have a non-empty extension id, and not have already been |
| 312 // added. | 312 // added. |
| 313 if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) | 313 if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) |
| 314 return false; | 314 return false; |
| 315 | 315 |
| 316 DCHECK_EQ(extension->id(), extension_id); | 316 DCHECK_EQ(extension->id(), extension_id); |
| 317 | 317 |
| 318 bool first_item = !ContainsKey(context_items_, extension_id); | 318 bool first_item = !ContainsKey(context_items_, extension_id); |
| 319 context_items_[extension_id].push_back(item); | 319 context_items_[extension_id].push_back(item); |
| 320 items_by_id_[item->id()] = item; | 320 items_by_id_[item->id()] = item; |
| 321 | 321 |
| 322 if (item->type() == ExtensionMenuItem::RADIO) { | 322 if (item->type() == MenuItem::RADIO) { |
| 323 if (item->checked()) | 323 if (item->checked()) |
| 324 RadioItemSelected(item); | 324 RadioItemSelected(item); |
| 325 else | 325 else |
| 326 SanitizeRadioList(context_items_[extension_id]); | 326 SanitizeRadioList(context_items_[extension_id]); |
| 327 } | 327 } |
| 328 | 328 |
| 329 // If this is the first item for this extension, start loading its icon. | 329 // If this is the first item for this extension, start loading its icon. |
| 330 if (first_item) | 330 if (first_item) |
| 331 icon_manager_.LoadIcon(extension); | 331 icon_manager_.LoadIcon(extension); |
| 332 | 332 |
| 333 return true; | 333 return true; |
| 334 } | 334 } |
| 335 | 335 |
| 336 bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, | 336 bool MenuManager::AddChildItem(const MenuItem::Id& parent_id, |
| 337 ExtensionMenuItem* child) { | 337 MenuItem* child) { |
| 338 ExtensionMenuItem* parent = GetItemById(parent_id); | 338 MenuItem* parent = GetItemById(parent_id); |
| 339 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || | 339 if (!parent || parent->type() != MenuItem::NORMAL || |
| 340 parent->incognito() != child->incognito() || | 340 parent->incognito() != child->incognito() || |
| 341 parent->extension_id() != child->extension_id() || | 341 parent->extension_id() != child->extension_id() || |
| 342 ContainsKey(items_by_id_, child->id())) | 342 ContainsKey(items_by_id_, child->id())) |
| 343 return false; | 343 return false; |
| 344 parent->AddChild(child); | 344 parent->AddChild(child); |
| 345 items_by_id_[child->id()] = child; | 345 items_by_id_[child->id()] = child; |
| 346 | 346 |
| 347 if (child->type() == ExtensionMenuItem::RADIO) | 347 if (child->type() == MenuItem::RADIO) |
| 348 SanitizeRadioList(parent->children()); | 348 SanitizeRadioList(parent->children()); |
| 349 return true; | 349 return true; |
| 350 } | 350 } |
| 351 | 351 |
| 352 bool ExtensionMenuManager::DescendantOf( | 352 bool MenuManager::DescendantOf(MenuItem* item, |
| 353 ExtensionMenuItem* item, | 353 const MenuItem::Id& ancestor_id) { |
| 354 const ExtensionMenuItem::Id& ancestor_id) { | |
| 355 // Work our way up the tree until we find the ancestor or NULL. | 354 // Work our way up the tree until we find the ancestor or NULL. |
| 356 ExtensionMenuItem::Id* id = item->parent_id(); | 355 MenuItem::Id* id = item->parent_id(); |
| 357 while (id != NULL) { | 356 while (id != NULL) { |
| 358 DCHECK(*id != item->id()); // Catch circular graphs. | 357 DCHECK(*id != item->id()); // Catch circular graphs. |
| 359 if (*id == ancestor_id) | 358 if (*id == ancestor_id) |
| 360 return true; | 359 return true; |
| 361 ExtensionMenuItem* next = GetItemById(*id); | 360 MenuItem* next = GetItemById(*id); |
| 362 if (!next) { | 361 if (!next) { |
| 363 NOTREACHED(); | 362 NOTREACHED(); |
| 364 return false; | 363 return false; |
| 365 } | 364 } |
| 366 id = next->parent_id(); | 365 id = next->parent_id(); |
| 367 } | 366 } |
| 368 return false; | 367 return false; |
| 369 } | 368 } |
| 370 | 369 |
| 371 bool ExtensionMenuManager::ChangeParent( | 370 bool MenuManager::ChangeParent(const MenuItem::Id& child_id, |
| 372 const ExtensionMenuItem::Id& child_id, | 371 const MenuItem::Id* parent_id) { |
| 373 const ExtensionMenuItem::Id* parent_id) { | 372 MenuItem* child = GetItemById(child_id); |
| 374 ExtensionMenuItem* child = GetItemById(child_id); | 373 MenuItem* new_parent = parent_id ? GetItemById(*parent_id) : NULL; |
| 375 ExtensionMenuItem* new_parent = parent_id ? GetItemById(*parent_id) : NULL; | |
| 376 if ((parent_id && (child_id == *parent_id)) || !child || | 374 if ((parent_id && (child_id == *parent_id)) || !child || |
| 377 (!new_parent && parent_id != NULL) || | 375 (!new_parent && parent_id != NULL) || |
| 378 (new_parent && (DescendantOf(new_parent, child_id) || | 376 (new_parent && (DescendantOf(new_parent, child_id) || |
| 379 child->incognito() != new_parent->incognito() || | 377 child->incognito() != new_parent->incognito() || |
| 380 child->extension_id() != new_parent->extension_id()))) | 378 child->extension_id() != new_parent->extension_id()))) |
| 381 return false; | 379 return false; |
| 382 | 380 |
| 383 ExtensionMenuItem::Id* old_parent_id = child->parent_id(); | 381 MenuItem::Id* old_parent_id = child->parent_id(); |
| 384 if (old_parent_id != NULL) { | 382 if (old_parent_id != NULL) { |
| 385 ExtensionMenuItem* old_parent = GetItemById(*old_parent_id); | 383 MenuItem* old_parent = GetItemById(*old_parent_id); |
| 386 if (!old_parent) { | 384 if (!old_parent) { |
| 387 NOTREACHED(); | 385 NOTREACHED(); |
| 388 return false; | 386 return false; |
| 389 } | 387 } |
| 390 ExtensionMenuItem* taken = | 388 MenuItem* taken = |
| 391 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); | 389 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); |
| 392 DCHECK(taken == child); | 390 DCHECK(taken == child); |
| 393 SanitizeRadioList(old_parent->children()); | 391 SanitizeRadioList(old_parent->children()); |
| 394 } else { | 392 } else { |
| 395 // This is a top-level item, so we need to pull it out of our list of | 393 // This is a top-level item, so we need to pull it out of our list of |
| 396 // top-level items. | 394 // top-level items. |
| 397 MenuItemMap::iterator i = context_items_.find(child->extension_id()); | 395 MenuItemMap::iterator i = context_items_.find(child->extension_id()); |
| 398 if (i == context_items_.end()) { | 396 if (i == context_items_.end()) { |
| 399 NOTREACHED(); | 397 NOTREACHED(); |
| 400 return false; | 398 return false; |
| 401 } | 399 } |
| 402 ExtensionMenuItem::List& list = i->second; | 400 MenuItem::List& list = i->second; |
| 403 ExtensionMenuItem::List::iterator j = std::find(list.begin(), list.end(), | 401 MenuItem::List::iterator j = std::find(list.begin(), list.end(), |
| 404 child); | 402 child); |
| 405 if (j == list.end()) { | 403 if (j == list.end()) { |
| 406 NOTREACHED(); | 404 NOTREACHED(); |
| 407 return false; | 405 return false; |
| 408 } | 406 } |
| 409 list.erase(j); | 407 list.erase(j); |
| 410 SanitizeRadioList(list); | 408 SanitizeRadioList(list); |
| 411 } | 409 } |
| 412 | 410 |
| 413 if (new_parent) { | 411 if (new_parent) { |
| 414 new_parent->AddChild(child); | 412 new_parent->AddChild(child); |
| 415 SanitizeRadioList(new_parent->children()); | 413 SanitizeRadioList(new_parent->children()); |
| 416 } else { | 414 } else { |
| 417 context_items_[child->extension_id()].push_back(child); | 415 context_items_[child->extension_id()].push_back(child); |
| 418 child->parent_id_.reset(NULL); | 416 child->parent_id_.reset(NULL); |
| 419 SanitizeRadioList(context_items_[child->extension_id()]); | 417 SanitizeRadioList(context_items_[child->extension_id()]); |
| 420 } | 418 } |
| 421 return true; | 419 return true; |
| 422 } | 420 } |
| 423 | 421 |
| 424 bool ExtensionMenuManager::RemoveContextMenuItem( | 422 bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) { |
| 425 const ExtensionMenuItem::Id& id) { | |
| 426 if (!ContainsKey(items_by_id_, id)) | 423 if (!ContainsKey(items_by_id_, id)) |
| 427 return false; | 424 return false; |
| 428 | 425 |
| 429 ExtensionMenuItem* menu_item = GetItemById(id); | 426 MenuItem* menu_item = GetItemById(id); |
| 430 DCHECK(menu_item); | 427 DCHECK(menu_item); |
| 431 std::string extension_id = menu_item->extension_id(); | 428 std::string extension_id = menu_item->extension_id(); |
| 432 MenuItemMap::iterator i = context_items_.find(extension_id); | 429 MenuItemMap::iterator i = context_items_.find(extension_id); |
| 433 if (i == context_items_.end()) { | 430 if (i == context_items_.end()) { |
| 434 NOTREACHED(); | 431 NOTREACHED(); |
| 435 return false; | 432 return false; |
| 436 } | 433 } |
| 437 | 434 |
| 438 bool result = false; | 435 bool result = false; |
| 439 std::set<ExtensionMenuItem::Id> items_removed; | 436 std::set<MenuItem::Id> items_removed; |
| 440 ExtensionMenuItem::List& list = i->second; | 437 MenuItem::List& list = i->second; |
| 441 ExtensionMenuItem::List::iterator j; | 438 MenuItem::List::iterator j; |
| 442 for (j = list.begin(); j < list.end(); ++j) { | 439 for (j = list.begin(); j < list.end(); ++j) { |
| 443 // See if the current top-level item is a match. | 440 // See if the current top-level item is a match. |
| 444 if ((*j)->id() == id) { | 441 if ((*j)->id() == id) { |
| 445 items_removed = (*j)->RemoveAllDescendants(); | 442 items_removed = (*j)->RemoveAllDescendants(); |
| 446 items_removed.insert(id); | 443 items_removed.insert(id); |
| 447 delete *j; | 444 delete *j; |
| 448 list.erase(j); | 445 list.erase(j); |
| 449 result = true; | 446 result = true; |
| 450 SanitizeRadioList(list); | 447 SanitizeRadioList(list); |
| 451 break; | 448 break; |
| 452 } else { | 449 } else { |
| 453 // See if the item to remove was found as a descendant of the current | 450 // See if the item to remove was found as a descendant of the current |
| 454 // top-level item. | 451 // top-level item. |
| 455 ExtensionMenuItem* child = (*j)->ReleaseChild(id, true /* recursive */); | 452 MenuItem* child = (*j)->ReleaseChild(id, true /* recursive */); |
| 456 if (child) { | 453 if (child) { |
| 457 items_removed = child->RemoveAllDescendants(); | 454 items_removed = child->RemoveAllDescendants(); |
| 458 items_removed.insert(id); | 455 items_removed.insert(id); |
| 459 SanitizeRadioList(GetItemById(*child->parent_id())->children()); | 456 SanitizeRadioList(GetItemById(*child->parent_id())->children()); |
| 460 delete child; | 457 delete child; |
| 461 result = true; | 458 result = true; |
| 462 break; | 459 break; |
| 463 } | 460 } |
| 464 } | 461 } |
| 465 } | 462 } |
| 466 DCHECK(result); // The check at the very top should have prevented this. | 463 DCHECK(result); // The check at the very top should have prevented this. |
| 467 | 464 |
| 468 // Clear entries from the items_by_id_ map. | 465 // Clear entries from the items_by_id_ map. |
| 469 std::set<ExtensionMenuItem::Id>::iterator removed_iter; | 466 std::set<MenuItem::Id>::iterator removed_iter; |
| 470 for (removed_iter = items_removed.begin(); | 467 for (removed_iter = items_removed.begin(); |
| 471 removed_iter != items_removed.end(); | 468 removed_iter != items_removed.end(); |
| 472 ++removed_iter) { | 469 ++removed_iter) { |
| 473 items_by_id_.erase(*removed_iter); | 470 items_by_id_.erase(*removed_iter); |
| 474 } | 471 } |
| 475 | 472 |
| 476 if (list.empty()) { | 473 if (list.empty()) { |
| 477 context_items_.erase(extension_id); | 474 context_items_.erase(extension_id); |
| 478 icon_manager_.RemoveIcon(extension_id); | 475 icon_manager_.RemoveIcon(extension_id); |
| 479 } | 476 } |
| 480 return result; | 477 return result; |
| 481 } | 478 } |
| 482 | 479 |
| 483 void ExtensionMenuManager::RemoveAllContextItems( | 480 void MenuManager::RemoveAllContextItems(const std::string& extension_id) { |
| 484 const std::string& extension_id) { | 481 MenuItem::List::iterator i; |
| 485 ExtensionMenuItem::List::iterator i; | |
| 486 for (i = context_items_[extension_id].begin(); | 482 for (i = context_items_[extension_id].begin(); |
| 487 i != context_items_[extension_id].end(); ++i) { | 483 i != context_items_[extension_id].end(); ++i) { |
| 488 ExtensionMenuItem* item = *i; | 484 MenuItem* item = *i; |
| 489 items_by_id_.erase(item->id()); | 485 items_by_id_.erase(item->id()); |
| 490 | 486 |
| 491 // Remove descendants from this item and erase them from the lookup cache. | 487 // Remove descendants from this item and erase them from the lookup cache. |
| 492 std::set<ExtensionMenuItem::Id> removed_ids = item->RemoveAllDescendants(); | 488 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); |
| 493 std::set<ExtensionMenuItem::Id>::const_iterator j; | 489 std::set<MenuItem::Id>::const_iterator j; |
| 494 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { | 490 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { |
| 495 items_by_id_.erase(*j); | 491 items_by_id_.erase(*j); |
| 496 } | 492 } |
| 497 } | 493 } |
| 498 STLDeleteElements(&context_items_[extension_id]); | 494 STLDeleteElements(&context_items_[extension_id]); |
| 499 context_items_.erase(extension_id); | 495 context_items_.erase(extension_id); |
| 500 icon_manager_.RemoveIcon(extension_id); | 496 icon_manager_.RemoveIcon(extension_id); |
| 501 } | 497 } |
| 502 | 498 |
| 503 ExtensionMenuItem* ExtensionMenuManager::GetItemById( | 499 MenuItem* MenuManager::GetItemById(const MenuItem::Id& id) const { |
| 504 const ExtensionMenuItem::Id& id) const { | 500 std::map<MenuItem::Id, MenuItem*>::const_iterator i = |
| 505 std::map<ExtensionMenuItem::Id, ExtensionMenuItem*>::const_iterator i = | |
| 506 items_by_id_.find(id); | 501 items_by_id_.find(id); |
| 507 if (i != items_by_id_.end()) | 502 if (i != items_by_id_.end()) |
| 508 return i->second; | 503 return i->second; |
| 509 else | 504 else |
| 510 return NULL; | 505 return NULL; |
| 511 } | 506 } |
| 512 | 507 |
| 513 void ExtensionMenuManager::RadioItemSelected(ExtensionMenuItem* item) { | 508 void MenuManager::RadioItemSelected(MenuItem* item) { |
| 514 // If this is a child item, we need to get a handle to the list from its | 509 // If this is a child item, we need to get a handle to the list from its |
| 515 // parent. Otherwise get a handle to the top-level list. | 510 // parent. Otherwise get a handle to the top-level list. |
| 516 const ExtensionMenuItem::List* list = NULL; | 511 const MenuItem::List* list = NULL; |
| 517 if (item->parent_id()) { | 512 if (item->parent_id()) { |
| 518 ExtensionMenuItem* parent = GetItemById(*item->parent_id()); | 513 MenuItem* parent = GetItemById(*item->parent_id()); |
| 519 if (!parent) { | 514 if (!parent) { |
| 520 NOTREACHED(); | 515 NOTREACHED(); |
| 521 return; | 516 return; |
| 522 } | 517 } |
| 523 list = &(parent->children()); | 518 list = &(parent->children()); |
| 524 } else { | 519 } else { |
| 525 if (context_items_.find(item->extension_id()) == context_items_.end()) { | 520 if (context_items_.find(item->extension_id()) == context_items_.end()) { |
| 526 NOTREACHED(); | 521 NOTREACHED(); |
| 527 return; | 522 return; |
| 528 } | 523 } |
| 529 list = &context_items_[item->extension_id()]; | 524 list = &context_items_[item->extension_id()]; |
| 530 } | 525 } |
| 531 | 526 |
| 532 // Find where |item| is in the list. | 527 // Find where |item| is in the list. |
| 533 ExtensionMenuItem::List::const_iterator item_location; | 528 MenuItem::List::const_iterator item_location; |
| 534 for (item_location = list->begin(); item_location != list->end(); | 529 for (item_location = list->begin(); item_location != list->end(); |
| 535 ++item_location) { | 530 ++item_location) { |
| 536 if (*item_location == item) | 531 if (*item_location == item) |
| 537 break; | 532 break; |
| 538 } | 533 } |
| 539 if (item_location == list->end()) { | 534 if (item_location == list->end()) { |
| 540 NOTREACHED(); // We should have found the item. | 535 NOTREACHED(); // We should have found the item. |
| 541 return; | 536 return; |
| 542 } | 537 } |
| 543 | 538 |
| 544 // Iterate backwards from |item| and uncheck any adjacent radio items. | 539 // Iterate backwards from |item| and uncheck any adjacent radio items. |
| 545 ExtensionMenuItem::List::const_iterator i; | 540 MenuItem::List::const_iterator i; |
| 546 if (item_location != list->begin()) { | 541 if (item_location != list->begin()) { |
| 547 i = item_location; | 542 i = item_location; |
| 548 do { | 543 do { |
| 549 --i; | 544 --i; |
| 550 if ((*i)->type() != ExtensionMenuItem::RADIO) | 545 if ((*i)->type() != MenuItem::RADIO) |
| 551 break; | 546 break; |
| 552 (*i)->SetChecked(false); | 547 (*i)->SetChecked(false); |
| 553 } while (i != list->begin()); | 548 } while (i != list->begin()); |
| 554 } | 549 } |
| 555 | 550 |
| 556 // Now iterate forwards from |item| and uncheck any adjacent radio items. | 551 // Now iterate forwards from |item| and uncheck any adjacent radio items. |
| 557 for (i = item_location + 1; i != list->end(); ++i) { | 552 for (i = item_location + 1; i != list->end(); ++i) { |
| 558 if ((*i)->type() != ExtensionMenuItem::RADIO) | 553 if ((*i)->type() != MenuItem::RADIO) |
| 559 break; | 554 break; |
| 560 (*i)->SetChecked(false); | 555 (*i)->SetChecked(false); |
| 561 } | 556 } |
| 562 } | 557 } |
| 563 | 558 |
| 564 static void AddURLProperty(DictionaryValue* dictionary, | 559 static void AddURLProperty(DictionaryValue* dictionary, |
| 565 const std::string& key, const GURL& url) { | 560 const std::string& key, const GURL& url) { |
| 566 if (!url.is_empty()) | 561 if (!url.is_empty()) |
| 567 dictionary->SetString(key, url.possibly_invalid_spec()); | 562 dictionary->SetString(key, url.possibly_invalid_spec()); |
| 568 } | 563 } |
| 569 | 564 |
| 570 void ExtensionMenuManager::ExecuteCommand( | 565 void MenuManager::ExecuteCommand(Profile* profile, |
| 571 Profile* profile, | 566 WebContents* web_contents, |
| 572 WebContents* web_contents, | 567 const content::ContextMenuParams& params, |
| 573 const content::ContextMenuParams& params, | 568 const MenuItem::Id& menu_item_id) { |
| 574 const ExtensionMenuItem::Id& menu_item_id) { | |
| 575 ExtensionEventRouter* event_router = profile->GetExtensionEventRouter(); | 569 ExtensionEventRouter* event_router = profile->GetExtensionEventRouter(); |
| 576 if (!event_router) | 570 if (!event_router) |
| 577 return; | 571 return; |
| 578 | 572 |
| 579 ExtensionMenuItem* item = GetItemById(menu_item_id); | 573 MenuItem* item = GetItemById(menu_item_id); |
| 580 if (!item) | 574 if (!item) |
| 581 return; | 575 return; |
| 582 | 576 |
| 583 // ExtensionService/Extension can be NULL in unit tests :( | 577 // ExtensionService/Extension can be NULL in unit tests :( |
| 584 ExtensionService* service = | 578 ExtensionService* service = |
| 585 ExtensionSystem::Get(profile_)->extension_service(); | 579 ExtensionSystem::Get(profile_)->extension_service(); |
| 586 const extensions::Extension* extension = service ? | 580 const Extension* extension = service ? |
| 587 service->extensions()->GetByID(menu_item_id.extension_id) : NULL; | 581 service->extensions()->GetByID(menu_item_id.extension_id) : NULL; |
| 588 | 582 |
| 589 if (item->type() == ExtensionMenuItem::RADIO) | 583 if (item->type() == MenuItem::RADIO) |
| 590 RadioItemSelected(item); | 584 RadioItemSelected(item); |
| 591 | 585 |
| 592 ListValue args; | 586 ListValue args; |
| 593 | 587 |
| 594 DictionaryValue* properties = new DictionaryValue(); | 588 DictionaryValue* properties = new DictionaryValue(); |
| 595 SetIdKeyValue(properties, "menuItemId", item->id()); | 589 SetIdKeyValue(properties, "menuItemId", item->id()); |
| 596 if (item->parent_id()) | 590 if (item->parent_id()) |
| 597 SetIdKeyValue(properties, "parentMenuItemId", item->id()); | 591 SetIdKeyValue(properties, "parentMenuItemId", item->id()); |
| 598 | 592 |
| 599 switch (params.media_type) { | 593 switch (params.media_type) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 621 | 615 |
| 622 args.Append(properties); | 616 args.Append(properties); |
| 623 | 617 |
| 624 // Add the tab info to the argument list. | 618 // Add the tab info to the argument list. |
| 625 // Note: web_contents only NULL in unit tests :( | 619 // Note: web_contents only NULL in unit tests :( |
| 626 if (web_contents) | 620 if (web_contents) |
| 627 args.Append(ExtensionTabUtil::CreateTabValue(web_contents)); | 621 args.Append(ExtensionTabUtil::CreateTabValue(web_contents)); |
| 628 else | 622 else |
| 629 args.Append(new DictionaryValue()); | 623 args.Append(new DictionaryValue()); |
| 630 | 624 |
| 631 if (item->type() == ExtensionMenuItem::CHECKBOX || | 625 if (item->type() == MenuItem::CHECKBOX || |
| 632 item->type() == ExtensionMenuItem::RADIO) { | 626 item->type() == MenuItem::RADIO) { |
| 633 bool was_checked = item->checked(); | 627 bool was_checked = item->checked(); |
| 634 properties->SetBoolean("wasChecked", was_checked); | 628 properties->SetBoolean("wasChecked", was_checked); |
| 635 | 629 |
| 636 // RADIO items always get set to true when you click on them, but CHECKBOX | 630 // RADIO items always get set to true when you click on them, but CHECKBOX |
| 637 // items get their state toggled. | 631 // items get their state toggled. |
| 638 bool checked = | 632 bool checked = |
| 639 (item->type() == ExtensionMenuItem::RADIO) ? true : !was_checked; | 633 (item->type() == MenuItem::RADIO) ? true : !was_checked; |
| 640 | 634 |
| 641 item->SetChecked(checked); | 635 item->SetChecked(checked); |
| 642 properties->SetBoolean("checked", item->checked()); | 636 properties->SetBoolean("checked", item->checked()); |
| 643 | 637 |
| 644 if (extension) | 638 if (extension) |
| 645 WriteToStorage(extension); | 639 WriteToStorage(extension); |
| 646 } | 640 } |
| 647 | 641 |
| 648 TabContents* tab_contents = web_contents ? | 642 TabContents* tab_contents = web_contents ? |
| 649 TabContents::FromWebContents(web_contents) : NULL; | 643 TabContents::FromWebContents(web_contents) : NULL; |
| 650 if (tab_contents && extension) { | 644 if (tab_contents && extension) { |
| 651 tab_contents->extension_tab_helper()->active_tab_permission_manager()-> | 645 tab_contents->extension_tab_helper()->active_tab_permission_manager()-> |
| 652 GrantIfRequested(extension); | 646 GrantIfRequested(extension); |
| 653 } | 647 } |
| 654 | 648 |
| 655 std::string json_args; | 649 std::string json_args; |
| 656 base::JSONWriter::Write(&args, &json_args); | 650 base::JSONWriter::Write(&args, &json_args); |
| 657 event_router->DispatchEventToExtension( | 651 event_router->DispatchEventToExtension( |
| 658 item->extension_id(), extension_event_names::kOnContextMenus, | 652 item->extension_id(), extension_event_names::kOnContextMenus, |
| 659 json_args, profile, GURL(), | 653 json_args, profile, GURL(), |
| 660 ExtensionEventRouter::USER_GESTURE_ENABLED); | 654 ExtensionEventRouter::USER_GESTURE_ENABLED); |
| 661 event_router->DispatchEventToExtension( | 655 event_router->DispatchEventToExtension( |
| 662 item->extension_id(), extension_event_names::kOnContextMenuClicked, | 656 item->extension_id(), extension_event_names::kOnContextMenuClicked, |
| 663 json_args, profile, GURL(), | 657 json_args, profile, GURL(), |
| 664 ExtensionEventRouter::USER_GESTURE_ENABLED); | 658 ExtensionEventRouter::USER_GESTURE_ENABLED); |
| 665 } | 659 } |
| 666 | 660 |
| 667 void ExtensionMenuManager::SanitizeRadioList( | 661 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) { |
| 668 const ExtensionMenuItem::List& item_list) { | 662 MenuItem::List::const_iterator i = item_list.begin(); |
| 669 ExtensionMenuItem::List::const_iterator i = item_list.begin(); | |
| 670 while (i != item_list.end()) { | 663 while (i != item_list.end()) { |
| 671 if ((*i)->type() != ExtensionMenuItem::RADIO) { | 664 if ((*i)->type() != MenuItem::RADIO) { |
| 672 ++i; | 665 ++i; |
| 673 break; | 666 break; |
| 674 } | 667 } |
| 675 | 668 |
| 676 // Uncheck any checked radio items in the run, and at the end reset | 669 // Uncheck any checked radio items in the run, and at the end reset |
| 677 // the appropriate one to checked. If no check radio items were found, | 670 // the appropriate one to checked. If no check radio items were found, |
| 678 // then check the first radio item in the run. | 671 // then check the first radio item in the run. |
| 679 ExtensionMenuItem::List::const_iterator last_checked = item_list.end(); | 672 MenuItem::List::const_iterator last_checked = item_list.end(); |
| 680 ExtensionMenuItem::List::const_iterator radio_run_iter; | 673 MenuItem::List::const_iterator radio_run_iter; |
| 681 for (radio_run_iter = i; radio_run_iter != item_list.end(); | 674 for (radio_run_iter = i; radio_run_iter != item_list.end(); |
| 682 ++radio_run_iter) { | 675 ++radio_run_iter) { |
| 683 if ((*radio_run_iter)->type() != ExtensionMenuItem::RADIO) { | 676 if ((*radio_run_iter)->type() != MenuItem::RADIO) { |
| 684 break; | 677 break; |
| 685 } | 678 } |
| 686 | 679 |
| 687 if ((*radio_run_iter)->checked()) { | 680 if ((*radio_run_iter)->checked()) { |
| 688 last_checked = radio_run_iter; | 681 last_checked = radio_run_iter; |
| 689 (*radio_run_iter)->SetChecked(false); | 682 (*radio_run_iter)->SetChecked(false); |
| 690 } | 683 } |
| 691 } | 684 } |
| 692 | 685 |
| 693 if (last_checked != item_list.end()) | 686 if (last_checked != item_list.end()) |
| 694 (*last_checked)->SetChecked(true); | 687 (*last_checked)->SetChecked(true); |
| 695 else | 688 else |
| 696 (*i)->SetChecked(true); | 689 (*i)->SetChecked(true); |
| 697 | 690 |
| 698 i = radio_run_iter; | 691 i = radio_run_iter; |
| 699 } | 692 } |
| 700 } | 693 } |
| 701 | 694 |
| 702 bool ExtensionMenuManager::ItemUpdated(const ExtensionMenuItem::Id& id) { | 695 bool MenuManager::ItemUpdated(const MenuItem::Id& id) { |
| 703 if (!ContainsKey(items_by_id_, id)) | 696 if (!ContainsKey(items_by_id_, id)) |
| 704 return false; | 697 return false; |
| 705 | 698 |
| 706 ExtensionMenuItem* menu_item = GetItemById(id); | 699 MenuItem* menu_item = GetItemById(id); |
| 707 DCHECK(menu_item); | 700 DCHECK(menu_item); |
| 708 | 701 |
| 709 if (menu_item->parent_id()) { | 702 if (menu_item->parent_id()) { |
| 710 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); | 703 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); |
| 711 } else { | 704 } else { |
| 712 std::string extension_id = menu_item->extension_id(); | 705 std::string extension_id = menu_item->extension_id(); |
| 713 MenuItemMap::iterator i = context_items_.find(extension_id); | 706 MenuItemMap::iterator i = context_items_.find(extension_id); |
| 714 if (i == context_items_.end()) { | 707 if (i == context_items_.end()) { |
| 715 NOTREACHED(); | 708 NOTREACHED(); |
| 716 return false; | 709 return false; |
| 717 } | 710 } |
| 718 SanitizeRadioList(i->second); | 711 SanitizeRadioList(i->second); |
| 719 } | 712 } |
| 720 | 713 |
| 721 return true; | 714 return true; |
| 722 } | 715 } |
| 723 | 716 |
| 724 void ExtensionMenuManager::WriteToStorage( | 717 void MenuManager::WriteToStorage(const Extension* extension) { |
| 725 const extensions::Extension* extension) { | |
| 726 if (!extension->has_lazy_background_page()) | 718 if (!extension->has_lazy_background_page()) |
| 727 return; | 719 return; |
| 728 const ExtensionMenuItem::List* top_items = MenuItems(extension->id()); | 720 const MenuItem::List* top_items = MenuItems(extension->id()); |
| 729 ExtensionMenuItem::List all_items; | 721 MenuItem::List all_items; |
| 730 if (top_items) { | 722 if (top_items) { |
| 731 for (ExtensionMenuItem::List::const_iterator i = top_items->begin(); | 723 for (MenuItem::List::const_iterator i = top_items->begin(); |
| 732 i != top_items->end(); ++i) { | 724 i != top_items->end(); ++i) { |
| 733 (*i)->GetFlattenedSubtree(&all_items); | 725 (*i)->GetFlattenedSubtree(&all_items); |
| 734 } | 726 } |
| 735 } | 727 } |
| 736 | 728 |
| 737 extensions::StateStore* store = ExtensionSystem::Get(profile_)->state_store(); | 729 StateStore* store = ExtensionSystem::Get(profile_)->state_store(); |
| 738 if (store) | 730 if (store) |
| 739 store->SetExtensionValue(extension->id(), kContextMenusKey, | 731 store->SetExtensionValue(extension->id(), kContextMenusKey, |
| 740 MenuItemsToValue(all_items)); | 732 MenuItemsToValue(all_items)); |
| 741 } | 733 } |
| 742 | 734 |
| 743 void ExtensionMenuManager::ReadFromStorage(const std::string& extension_id, | 735 void MenuManager::ReadFromStorage(const std::string& extension_id, |
| 744 scoped_ptr<base::Value> value) { | 736 scoped_ptr<base::Value> value) { |
| 745 const extensions::Extension* extension = | 737 const Extension* extension = |
| 746 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> | 738 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> |
| 747 GetByID(extension_id); | 739 GetByID(extension_id); |
| 748 if (!extension) | 740 if (!extension) |
| 749 return; | 741 return; |
| 750 | 742 |
| 751 ExtensionMenuItem::List items = MenuItemsFromValue(extension_id, value.get()); | 743 MenuItem::List items = MenuItemsFromValue(extension_id, value.get()); |
| 752 for (size_t i = 0; i < items.size(); ++i) { | 744 for (size_t i = 0; i < items.size(); ++i) { |
| 753 if (items[i]->parent_id()) { | 745 if (items[i]->parent_id()) { |
| 754 // Parent IDs are stored in the parent_id field for convenience, but | 746 // Parent IDs are stored in the parent_id field for convenience, but |
| 755 // they have not yet been validated. Separate them out here. | 747 // they have not yet been validated. Separate them out here. |
| 756 // Because of the order in which we store items in the prefs, parents will | 748 // Because of the order in which we store items in the prefs, parents will |
| 757 // precede children, so we should already know about any parent items. | 749 // precede children, so we should already know about any parent items. |
| 758 scoped_ptr<ExtensionMenuItem::Id> parent_id; | 750 scoped_ptr<MenuItem::Id> parent_id; |
| 759 parent_id.swap(items[i]->parent_id_); | 751 parent_id.swap(items[i]->parent_id_); |
| 760 AddChildItem(*parent_id, items[i]); | 752 AddChildItem(*parent_id, items[i]); |
| 761 } else { | 753 } else { |
| 762 AddContextItem(extension, items[i]); | 754 AddContextItem(extension, items[i]); |
| 763 } | 755 } |
| 764 } | 756 } |
| 765 } | 757 } |
| 766 | 758 |
| 767 void ExtensionMenuManager::Observe( | 759 void MenuManager::Observe(int type, |
| 768 int type, | 760 const content::NotificationSource& source, |
| 769 const content::NotificationSource& source, | 761 const content::NotificationDetails& details) { |
| 770 const content::NotificationDetails& details) { | |
| 771 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { | 762 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
| 772 // Remove menu items for disabled/uninstalled extensions. | 763 // Remove menu items for disabled/uninstalled extensions. |
| 773 const extensions::Extension* extension = | 764 const Extension* extension = |
| 774 content::Details<extensions::UnloadedExtensionInfo>(details)->extension; | 765 content::Details<UnloadedExtensionInfo>(details)->extension; |
| 775 if (ContainsKey(context_items_, extension->id())) { | 766 if (ContainsKey(context_items_, extension->id())) { |
| 776 RemoveAllContextItems(extension->id()); | 767 RemoveAllContextItems(extension->id()); |
| 777 } | 768 } |
| 778 } else if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { | 769 } else if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { |
| 779 const extensions::Extension* extension = | 770 const Extension* extension = |
| 780 content::Details<const extensions::Extension>(details).ptr(); | 771 content::Details<const Extension>(details).ptr(); |
| 781 extensions::StateStore* store = | 772 StateStore* store = ExtensionSystem::Get(profile_)->state_store(); |
| 782 ExtensionSystem::Get(profile_)->state_store(); | |
| 783 if (store && extension->has_lazy_background_page()) { | 773 if (store && extension->has_lazy_background_page()) { |
| 784 store->GetExtensionValue(extension->id(), kContextMenusKey, | 774 store->GetExtensionValue(extension->id(), kContextMenusKey, |
| 785 base::Bind(&ExtensionMenuManager::ReadFromStorage, | 775 base::Bind(&MenuManager::ReadFromStorage, |
| 786 AsWeakPtr(), extension->id())); | 776 AsWeakPtr(), extension->id())); |
| 787 } | 777 } |
| 788 } | 778 } |
| 789 } | 779 } |
| 790 | 780 |
| 791 const SkBitmap& ExtensionMenuManager::GetIconForExtension( | 781 const SkBitmap& MenuManager::GetIconForExtension( |
| 792 const std::string& extension_id) { | 782 const std::string& extension_id) { |
| 793 return icon_manager_.GetIcon(extension_id); | 783 return icon_manager_.GetIcon(extension_id); |
| 794 } | 784 } |
| 795 | 785 |
| 796 ExtensionMenuItem::Id::Id() | 786 MenuItem::Id::Id() |
| 797 : incognito(false), extension_id(""), uid(0), string_uid("") { | 787 : incognito(false), extension_id(""), uid(0), string_uid("") { |
| 798 } | 788 } |
| 799 | 789 |
| 800 ExtensionMenuItem::Id::Id(bool incognito, const std::string& extension_id) | 790 MenuItem::Id::Id(bool incognito, const std::string& extension_id) |
| 801 : incognito(incognito), extension_id(extension_id), uid(0), | 791 : incognito(incognito), extension_id(extension_id), uid(0), |
| 802 string_uid("") { | 792 string_uid("") { |
| 803 } | 793 } |
| 804 | 794 |
| 805 ExtensionMenuItem::Id::~Id() { | 795 MenuItem::Id::~Id() { |
| 806 } | 796 } |
| 807 | 797 |
| 808 bool ExtensionMenuItem::Id::operator==(const Id& other) const { | 798 bool MenuItem::Id::operator==(const Id& other) const { |
| 809 return (incognito == other.incognito && | 799 return (incognito == other.incognito && |
| 810 extension_id == other.extension_id && | 800 extension_id == other.extension_id && |
| 811 uid == other.uid && | 801 uid == other.uid && |
| 812 string_uid == other.string_uid); | 802 string_uid == other.string_uid); |
| 813 } | 803 } |
| 814 | 804 |
| 815 bool ExtensionMenuItem::Id::operator!=(const Id& other) const { | 805 bool MenuItem::Id::operator!=(const Id& other) const { |
| 816 return !(*this == other); | 806 return !(*this == other); |
| 817 } | 807 } |
| 818 | 808 |
| 819 bool ExtensionMenuItem::Id::operator<(const Id& other) const { | 809 bool MenuItem::Id::operator<(const Id& other) const { |
| 820 if (incognito < other.incognito) | 810 if (incognito < other.incognito) |
| 821 return true; | 811 return true; |
| 822 if (incognito == other.incognito) { | 812 if (incognito == other.incognito) { |
| 823 if (extension_id < other.extension_id) | 813 if (extension_id < other.extension_id) |
| 824 return true; | 814 return true; |
| 825 if (extension_id == other.extension_id) { | 815 if (extension_id == other.extension_id) { |
| 826 if (uid < other.uid) | 816 if (uid < other.uid) |
| 827 return true; | 817 return true; |
| 828 if (uid == other.uid) | 818 if (uid == other.uid) |
| 829 return string_uid < other.string_uid; | 819 return string_uid < other.string_uid; |
| 830 } | 820 } |
| 831 } | 821 } |
| 832 return false; | 822 return false; |
| 833 } | 823 } |
| 824 |
| 825 } // namespace extensions |
| OLD | NEW |