| Index: chrome/browser/ui/intents/intents_model.cc | 
| diff --git a/chrome/browser/ui/intents/intents_model.cc b/chrome/browser/ui/intents/intents_model.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..81147249d076cbbf0b55c22aec38b8f0ddd763ab | 
| --- /dev/null | 
| +++ b/chrome/browser/ui/intents/intents_model.cc | 
| @@ -0,0 +1,152 @@ | 
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "chrome/browser/ui/intents/intents_model.h" | 
| +#include "base/string_split.h" | 
| +#include "base/string_util.h" | 
| +#include "base/stringprintf.h" | 
| +#include "base/utf_string_conversions.h" | 
| +#include "chrome/browser/intents/web_intents_registry.h" | 
| + | 
| +ServiceTreeNode::ServiceTreeNode(const string16& title) | 
| +  : IntentsTreeNode(title, IntentsTreeNode::TYPE_SERVICE), | 
| +    blocked_(false), | 
| +    disabled_(false) {} | 
| + | 
| +ServiceTreeNode::~ServiceTreeNode() {} | 
| + | 
| +IntentsModel::IntentsModel(WebIntentsRegistry* intents_registry) | 
| +    : ui::TreeNodeModel<IntentsTreeNode>(new IntentsTreeNode()), | 
| +      intents_registry_(intents_registry), | 
| +      batch_update_(0) { | 
| +  LoadModel(); | 
| +} | 
| + | 
| +IntentsModel::~IntentsModel() {} | 
| + | 
| +void IntentsModel::AddIntentsTreeObserver(Observer* observer) { | 
| +  intents_observer_list_.AddObserver(observer); | 
| +  // Call super so that TreeNodeModel can notify, too. | 
| +  ui::TreeNodeModel<IntentsTreeNode>::AddObserver(observer); | 
| +} | 
| + | 
| +void IntentsModel::RemoveIntentsTreeObserver(Observer* observer) { | 
| +  intents_observer_list_.RemoveObserver(observer); | 
| +  // Call super so that TreeNodeModel doesn't have dead pointers. | 
| +  ui::TreeNodeModel<IntentsTreeNode>::RemoveObserver(observer); | 
| +} | 
| + | 
| +string16 IntentsModel::GetTreeNodeId(IntentsTreeNode* node) { | 
| +  if (node->Type() == IntentsTreeNode::TYPE_ORIGIN) | 
| +    return node->GetTitle(); | 
| + | 
| +  // TODO(gbillock): handle TYPE_SERVICE when/if we ever want to do | 
| +  // specific managing of them. | 
| + | 
| +  return string16(); | 
| +} | 
| + | 
| +IntentsTreeNode* IntentsModel::GetTreeNode(std::string path_id) { | 
| +  if (path_id.empty()) | 
| +    return GetRoot(); | 
| + | 
| +  std::vector<std::string> node_ids; | 
| +  base::SplitString(path_id, ',', &node_ids); | 
| + | 
| +  for (int i = 0; i < GetRoot()->child_count(); ++i) { | 
| +    IntentsTreeNode* node = GetRoot()->GetChild(i); | 
| +    if (UTF16ToUTF8(node->GetTitle()) == node_ids[0]) { | 
| +      if (node_ids.size() == 1) | 
| +        return node; | 
| +    } | 
| +  } | 
| + | 
| +  // TODO: support service nodes? | 
| +  return NULL; | 
| +} | 
| + | 
| +void IntentsModel::GetChildNodeList(IntentsTreeNode* parent, | 
| +                                    int start, int count, | 
| +                                    base::ListValue* nodes) { | 
| +  for (int i = 0; i < count; ++i) { | 
| +    base::DictionaryValue* dict = new base::DictionaryValue; | 
| +    IntentsTreeNode* child = parent->GetChild(start + i); | 
| +    GetIntentsTreeNodeDictionary(*child, dict); | 
| +    nodes->Append(dict); | 
| +  } | 
| +} | 
| + | 
| +void IntentsModel::GetIntentsTreeNodeDictionary(const IntentsTreeNode& node, | 
| +                                                base::DictionaryValue* dict) { | 
| +  if (node.Type() == IntentsTreeNode::TYPE_ROOT) { | 
| +    return; | 
| +  } | 
| + | 
| +  if (node.Type() == IntentsTreeNode::TYPE_ORIGIN) { | 
| +    dict->SetString("site", node.GetTitle()); | 
| +    dict->SetBoolean("hasChildren", node.child_count() > 0); | 
| +    return; | 
| +  } | 
| + | 
| +  if (node.Type() == IntentsTreeNode::TYPE_SERVICE) { | 
| +    const ServiceTreeNode* snode = static_cast<const ServiceTreeNode*>(&node); | 
| +    dict->SetString("site", snode->GetTitle()); | 
| +    dict->SetString("name", snode->ServiceName()); | 
| +    dict->SetString("url", snode->ServiceUrl()); | 
| +    dict->SetString("icon", snode->IconUrl()); | 
| +    dict->SetString("action", snode->Action()); | 
| +    dict->Set("types", snode->Types().DeepCopy()); | 
| +    dict->SetBoolean("blocked", snode->IsBlocked()); | 
| +    dict->SetBoolean("disabled", snode->IsDisabled()); | 
| +    return; | 
| +  } | 
| +} | 
| + | 
| +void IntentsModel::LoadModel() { | 
| +  NotifyObserverBeginBatch(); | 
| +  intents_registry_->GetAllIntentProviders(this); | 
| +} | 
| + | 
| +void IntentsModel::OnIntentsQueryDone( | 
| +    WebIntentsRegistry::QueryID query_id, | 
| +    const std::vector<WebIntentData>& intents) { | 
| +  for (size_t i = 0; i < intents.size(); ++i) { | 
| +    // Eventually do some awesome sorting, grouping, clustering stuff here. | 
| +    // For now, just stick it in the model flat. | 
| +    IntentsTreeNode* n = new IntentsTreeNode(ASCIIToUTF16( | 
| +        intents[i].service_url.host())); | 
| +    ServiceTreeNode* ns = new ServiceTreeNode(ASCIIToUTF16( | 
| +        intents[i].service_url.host())); | 
| +    ns->SetServiceName(intents[i].title); | 
| +    ns->SetServiceUrl(ASCIIToUTF16(intents[i].service_url.spec())); | 
| +    GURL icon_url = intents[i].service_url.GetOrigin().Resolve("/favicon.ico"); | 
| +    ns->SetIconUrl(ASCIIToUTF16(icon_url.spec())); | 
| +    ns->SetAction(intents[i].action); | 
| +    ns->AddType(intents[i].type); | 
| +    // Won't generate a notification. OK for now as the next line will. | 
| +    n->Add(ns, 0); | 
| +    Add(GetRoot(), n, GetRoot()->child_count()); | 
| +  } | 
| + | 
| +  NotifyObserverEndBatch(); | 
| +} | 
| + | 
| +void IntentsModel::NotifyObserverBeginBatch() { | 
| +  // Only notify the model once if we're batching in a nested manner. | 
| +  if (batch_update_++ == 0) { | 
| +    FOR_EACH_OBSERVER(Observer, | 
| +                      intents_observer_list_, | 
| +                      TreeModelBeginBatch(this)); | 
| +  } | 
| +} | 
| + | 
| +void IntentsModel::NotifyObserverEndBatch() { | 
| +  // Only notify the observers if this is the outermost call to EndBatch() if | 
| +  // called in a nested manner. | 
| +  if (--batch_update_ == 0) { | 
| +    FOR_EACH_OBSERVER(Observer, | 
| +                      intents_observer_list_, | 
| +                      TreeModelEndBatch(this)); | 
| +  } | 
| +} | 
|  |