Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / app_list_model.cc
index 40bb8e9..c2c8237 100644 (file)
@@ -4,27 +4,26 @@
 
 #include "ui/app_list/app_list_model.h"
 
-#include "ui/app_list/app_list_item_model.h"
+#include <string>
+
+#include "ui/app_list/app_list_folder_item.h"
+#include "ui/app_list/app_list_item.h"
 #include "ui/app_list/app_list_model_observer.h"
 #include "ui/app_list/search_box_model.h"
-#include "ui/app_list/search_result.h"
 
 namespace app_list {
 
-AppListModel::User::User() : active(false) {}
-
-AppListModel::User::~User() {}
-
 AppListModel::AppListModel()
-    : item_list_(new AppListItemList),
+    : top_level_item_list_(new AppListItemList),
       search_box_(new SearchBoxModel),
       results_(new SearchResults),
-      signed_in_(false),
-      status_(STATUS_NORMAL) {
+      status_(STATUS_NORMAL),
+      state_(INVALID_STATE),
+      folders_enabled_(false) {
+  top_level_item_list_->AddObserver(this);
 }
 
-AppListModel::~AppListModel() {
-}
+AppListModel::~AppListModel() { top_level_item_list_->RemoveObserver(this); }
 
 void AppListModel::AddObserver(AppListModelObserver* observer) {
   observers_.AddObserver(observer);
@@ -44,21 +43,372 @@ void AppListModel::SetStatus(Status status) {
                     OnAppListModelStatusChanged());
 }
 
-void AppListModel::SetUsers(const Users& users) {
-  users_ = users;
+void AppListModel::SetState(State state) {
+  if (state_ == state)
+    return;
+
+  State old_state = state_;
+
+  state_ = state;
+
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListModelStateChanged(old_state, state_));
+}
+
+AppListItem* AppListModel::FindItem(const std::string& id) {
+  AppListItem* item = top_level_item_list_->FindItem(id);
+  if (item)
+    return item;
+  for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
+    AppListItem* child_item =
+        top_level_item_list_->item_at(i)->FindChildItem(id);
+    if (child_item)
+      return child_item;
+  }
+  return NULL;
+}
+
+AppListFolderItem* AppListModel::FindFolderItem(const std::string& id) {
+  AppListItem* item = top_level_item_list_->FindItem(id);
+  if (item && item->GetItemType() == AppListFolderItem::kItemType)
+    return static_cast<AppListFolderItem*>(item);
+  DCHECK(!item);
+  return NULL;
+}
+
+AppListItem* AppListModel::AddItem(scoped_ptr<AppListItem> item) {
+  DCHECK(!item->IsInFolder());
+  DCHECK(!top_level_item_list()->FindItem(item->id()));
+  return AddItemToItemListAndNotify(item.Pass());
+}
+
+AppListItem* AppListModel::AddItemToFolder(scoped_ptr<AppListItem> item,
+                                           const std::string& folder_id) {
+  if (folder_id.empty())
+    return AddItem(item.Pass());
+  DVLOG(2) << "AddItemToFolder: " << item->id() << ": " << folder_id;
+  CHECK_NE(folder_id, item->folder_id());
+  DCHECK_NE(AppListFolderItem::kItemType, item->GetItemType());
+  AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
+  if (!dest_folder)
+    return NULL;
+  DCHECK(!dest_folder->item_list()->FindItem(item->id()))
+      << "Already in folder: " << dest_folder->id();
+  return AddItemToFolderItemAndNotify(dest_folder, item.Pass());
+}
+
+const std::string AppListModel::MergeItems(const std::string& target_item_id,
+                                           const std::string& source_item_id) {
+  if (!folders_enabled()) {
+    LOG(ERROR) << "MergeItems called with folders disabled.";
+    return "";
+  }
+  DVLOG(2) << "MergeItems: " << source_item_id << " -> " << target_item_id;
+
+  if (target_item_id == source_item_id) {
+    LOG(WARNING) << "MergeItems tried to drop item onto itself ("
+                 << source_item_id << " -> " << target_item_id << ").";
+    return "";
+  }
+
+  // Find the target item.
+  AppListItem* target_item = top_level_item_list_->FindItem(target_item_id);
+  if (!target_item) {
+    LOG(ERROR) << "MergeItems: Target no longer exists.";
+    return "";
+  }
+
+  AppListItem* source_item = FindItem(source_item_id);
+  if (!source_item) {
+    LOG(ERROR) << "MergeItems: Source no longer exists.";
+    return "";
+  }
+
+  // If the target item is a folder, just add the source item to it.
+  if (target_item->GetItemType() == AppListFolderItem::kItemType) {
+    AppListFolderItem* target_folder =
+        static_cast<AppListFolderItem*>(target_item);
+    if (target_folder->folder_type() == AppListFolderItem::FOLDER_TYPE_OEM) {
+      LOG(WARNING) << "MergeItems called with OEM folder as target";
+      return "";
+    }
+    scoped_ptr<AppListItem> source_item_ptr = RemoveItem(source_item);
+    source_item_ptr->set_position(
+        target_folder->item_list()->CreatePositionBefore(
+            syncer::StringOrdinal()));
+    AddItemToFolderItemAndNotify(target_folder, source_item_ptr.Pass());
+    return target_folder->id();
+  }
+
+  // Otherwise remove the source item and target item from their current
+  // location, they will become owned by the new folder.
+  scoped_ptr<AppListItem> source_item_ptr = RemoveItem(source_item);
+  CHECK(source_item_ptr);
+  // Note: This would fail if |target_item_id == source_item_id|, except we
+  // checked that they are distinct at the top of this method.
+  scoped_ptr<AppListItem> target_item_ptr =
+      top_level_item_list_->RemoveItem(target_item_id);
+  CHECK(target_item_ptr);
+
+  // Create a new folder in the same location as the target item.
+  std::string new_folder_id = AppListFolderItem::GenerateId();
+  DVLOG(2) << "Creating folder for merge: " << new_folder_id;
+  scoped_ptr<AppListItem> new_folder_ptr(new AppListFolderItem(
+      new_folder_id, AppListFolderItem::FOLDER_TYPE_NORMAL));
+  new_folder_ptr->set_position(target_item_ptr->position());
+  AppListFolderItem* new_folder = static_cast<AppListFolderItem*>(
+      AddItemToItemListAndNotify(new_folder_ptr.Pass()));
+
+  // Add the items to the new folder.
+  target_item_ptr->set_position(
+      new_folder->item_list()->CreatePositionBefore(
+          syncer::StringOrdinal()));
+  AddItemToFolderItemAndNotify(new_folder, target_item_ptr.Pass());
+  source_item_ptr->set_position(
+      new_folder->item_list()->CreatePositionBefore(
+          syncer::StringOrdinal()));
+  AddItemToFolderItemAndNotify(new_folder, source_item_ptr.Pass());
+
+  return new_folder->id();
+}
+
+void AppListModel::MoveItemToFolder(AppListItem* item,
+                                    const std::string& folder_id) {
+  DVLOG(2) << "MoveItemToFolder: " << folder_id
+           << " <- " << item->ToDebugString();
+  if (item->folder_id() == folder_id)
+    return;
+  AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
+  scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
+  if (dest_folder) {
+    CHECK(!item->IsInFolder());
+    AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
+  } else {
+    AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
+  }
+}
+
+bool AppListModel::MoveItemToFolderAt(AppListItem* item,
+                                      const std::string& folder_id,
+                                      syncer::StringOrdinal position) {
+  DVLOG(2) << "MoveItemToFolderAt: " << folder_id
+           << "[" << position.ToDebugString() << "]"
+           << " <- " << item->ToDebugString();
+  if (item->folder_id() == folder_id)
+    return false;
+  AppListFolderItem* src_folder = FindOrCreateFolderItem(item->folder_id());
+  if (src_folder &&
+      src_folder->folder_type() == AppListFolderItem::FOLDER_TYPE_OEM) {
+    LOG(WARNING) << "MoveItemToFolderAt called with OEM folder as source";
+    return false;
+  }
+  AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
+  scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
+  if (dest_folder) {
+    item_ptr->set_position(
+        dest_folder->item_list()->CreatePositionBefore(position));
+    AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
+  } else {
+    item_ptr->set_position(
+        top_level_item_list_->CreatePositionBefore(position));
+    AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
+  }
+  return true;
+}
+
+void AppListModel::SetItemPosition(AppListItem* item,
+                                   const syncer::StringOrdinal& new_position) {
+  if (!item->IsInFolder()) {
+    top_level_item_list_->SetItemPosition(item, new_position);
+    // Note: this will trigger OnListItemMoved which will signal observers.
+    // (This is done this way because some View code still moves items within
+    // the item list directly).
+    return;
+  }
+  AppListFolderItem* folder = FindFolderItem(item->folder_id());
+  DCHECK(folder);
+  folder->item_list()->SetItemPosition(item, new_position);
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemUpdated(item));
+}
+
+void AppListModel::SetItemName(AppListItem* item, const std::string& name) {
+  item->SetName(name);
+  DVLOG(2) << "AppListModel::SetItemName: " << item->ToDebugString();
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemUpdated(item));
+}
+
+void AppListModel::SetItemNameAndShortName(AppListItem* item,
+                                           const std::string& name,
+                                           const std::string& short_name) {
+  item->SetNameAndShortName(name, short_name);
+  DVLOG(2) << "AppListModel::SetItemNameAndShortName: "
+           << item->ToDebugString();
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemUpdated(item));
+}
+
+void AppListModel::DeleteItem(const std::string& id) {
+  AppListItem* item = FindItem(id);
+  if (!item)
+    return;
+  if (!item->IsInFolder()) {
+    DCHECK_EQ(0u, item->ChildItemCount())
+        << "Invalid call to DeleteItem for item with children: " << id;
+    FOR_EACH_OBSERVER(AppListModelObserver,
+                      observers_,
+                      OnAppListItemWillBeDeleted(item));
+    top_level_item_list_->DeleteItem(id);
+    FOR_EACH_OBSERVER(AppListModelObserver, observers_, OnAppListItemDeleted());
+    return;
+  }
+  AppListFolderItem* folder = FindFolderItem(item->folder_id());
+  DCHECK(folder) << "Folder not found for item: " << item->ToDebugString();
+  scoped_ptr<AppListItem> child_item = RemoveItemFromFolder(folder, item);
+  DCHECK_EQ(item, child_item.get());
   FOR_EACH_OBSERVER(AppListModelObserver,
                     observers_,
-                    OnAppListModelUsersChanged());
+                    OnAppListItemWillBeDeleted(item));
+  child_item.reset();  // Deletes item.
+  FOR_EACH_OBSERVER(AppListModelObserver, observers_, OnAppListItemDeleted());
+}
+
+void AppListModel::NotifyExtensionPreferenceChanged() {
+  for (size_t i = 0; i < top_level_item_list_->item_count(); ++i)
+    top_level_item_list_->item_at(i)->OnExtensionPreferenceChanged();
 }
 
-void AppListModel::SetSignedIn(bool signed_in) {
-  if (signed_in_ == signed_in)
+void AppListModel::SetFoldersEnabled(bool folders_enabled) {
+  folders_enabled_ = folders_enabled;
+  if (folders_enabled)
     return;
+  // Remove child items from folders.
+  std::vector<std::string> folder_ids;
+  for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
+    AppListItem* item = top_level_item_list_->item_at(i);
+    if (item->GetItemType() != AppListFolderItem::kItemType)
+      continue;
+    AppListFolderItem* folder = static_cast<AppListFolderItem*>(item);
+    if (folder->folder_type() == AppListFolderItem::FOLDER_TYPE_OEM)
+      continue;  // Do not remove OEM folders.
+    while (folder->item_list()->item_count()) {
+      scoped_ptr<AppListItem> child = folder->item_list()->RemoveItemAt(0);
+      child->set_folder_id("");
+      AddItemToItemListAndNotifyUpdate(child.Pass());
+    }
+    folder_ids.push_back(folder->id());
+  }
+  // Delete folders.
+  for (size_t i = 0; i < folder_ids.size(); ++i)
+    DeleteItem(folder_ids[i]);
+}
+
+std::vector<SearchResult*> AppListModel::FilterSearchResultsByDisplayType(
+    SearchResults* results,
+    SearchResult::DisplayType display_type,
+    size_t max_results) {
+  std::vector<SearchResult*> matches;
+  for (size_t i = 0; i < results->item_count(); ++i) {
+    SearchResult* item = results->GetItemAt(i);
+    if (item->display_type() == display_type) {
+      matches.push_back(item);
+      if (matches.size() == max_results)
+        break;
+    }
+  }
+  return matches;
+}
+
+// Private methods
 
-  signed_in_ = signed_in;
+void AppListModel::OnListItemMoved(size_t from_index,
+                                   size_t to_index,
+                                   AppListItem* item) {
   FOR_EACH_OBSERVER(AppListModelObserver,
                     observers_,
-                    OnAppListModelSigninStatusChanged());
+                    OnAppListItemUpdated(item));
+}
+
+AppListFolderItem* AppListModel::FindOrCreateFolderItem(
+    const std::string& folder_id) {
+  if (folder_id.empty())
+    return NULL;
+
+  AppListFolderItem* dest_folder = FindFolderItem(folder_id);
+  if (dest_folder)
+    return dest_folder;
+
+  if (!folders_enabled()) {
+    LOG(ERROR) << "Attempt to create folder item when disabled: " << folder_id;
+    return NULL;
+  }
+
+  DVLOG(2) << "Creating new folder: " << folder_id;
+  scoped_ptr<AppListFolderItem> new_folder(
+      new AppListFolderItem(folder_id, AppListFolderItem::FOLDER_TYPE_NORMAL));
+  new_folder->set_position(
+      top_level_item_list_->CreatePositionBefore(syncer::StringOrdinal()));
+  AppListItem* new_folder_item = AddItemToItemListAndNotify(new_folder.Pass());
+  return static_cast<AppListFolderItem*>(new_folder_item);
+}
+
+AppListItem* AppListModel::AddItemToItemListAndNotify(
+    scoped_ptr<AppListItem> item_ptr) {
+  DCHECK(!item_ptr->IsInFolder());
+  AppListItem* item = top_level_item_list_->AddItem(item_ptr.Pass());
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemAdded(item));
+  return item;
+}
+
+AppListItem* AppListModel::AddItemToItemListAndNotifyUpdate(
+    scoped_ptr<AppListItem> item_ptr) {
+  DCHECK(!item_ptr->IsInFolder());
+  AppListItem* item = top_level_item_list_->AddItem(item_ptr.Pass());
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemUpdated(item));
+  return item;
+}
+
+AppListItem* AppListModel::AddItemToFolderItemAndNotify(
+    AppListFolderItem* folder,
+    scoped_ptr<AppListItem> item_ptr) {
+  CHECK_NE(folder->id(), item_ptr->folder_id());
+  AppListItem* item = folder->item_list()->AddItem(item_ptr.Pass());
+  item->set_folder_id(folder->id());
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListItemUpdated(item));
+  return item;
+}
+
+scoped_ptr<AppListItem> AppListModel::RemoveItem(AppListItem* item) {
+  if (!item->IsInFolder())
+    return top_level_item_list_->RemoveItem(item->id());
+
+  AppListFolderItem* folder = FindFolderItem(item->folder_id());
+  return RemoveItemFromFolder(folder, item);
+}
+
+scoped_ptr<AppListItem> AppListModel::RemoveItemFromFolder(
+    AppListFolderItem* folder,
+    AppListItem* item) {
+  std::string folder_id = folder->id();
+  CHECK_EQ(item->folder_id(), folder_id);
+  scoped_ptr<AppListItem> result = folder->item_list()->RemoveItem(item->id());
+  result->set_folder_id("");
+  if (folder->item_list()->item_count() == 0) {
+    DVLOG(2) << "Deleting empty folder: " << folder->ToDebugString();
+    DeleteItem(folder_id);
+  }
+  return result.Pass();
 }
 
 }  // namespace app_list