1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef ASH_PUBLIC_CPP_SHELF_MODEL_H_ 6 #define ASH_PUBLIC_CPP_SHELF_MODEL_H_ 7 8 #include <map> 9 #include <memory> 10 11 #include "ash/public/cpp/ash_public_export.h" 12 #include "ash/public/cpp/shelf_item.h" 13 #include "base/macros.h" 14 #include "base/observer_list.h" 15 16 class AppWindowLauncherItemController; 17 18 namespace ash { 19 20 class ShelfItemDelegate; 21 class ShelfModelObserver; 22 23 // An id for the AppList item, which is added in the ShelfModel constructor. 24 // Generated as crx_file::id_util::GenerateId("org.chromium.applist") 25 ASH_PUBLIC_EXPORT extern const char kAppListId[]; 26 27 // An id for the BackButton item, which is added in the ShelfModel constructor. 28 // Generated as crx_file::id_util::GenerateId("org.chromium.backbutton") 29 ASH_PUBLIC_EXPORT extern const char kBackButtonId[]; 30 31 // Model used for shelf items. Owns ShelfItemDelegates but does not create them. 32 class ASH_PUBLIC_EXPORT ShelfModel { 33 public: 34 // Get or set a weak pointer to the singleton ShelfModel instance, not owned. 35 static ShelfModel* Get(); 36 static void SetInstance(ShelfModel* shelf_model); 37 38 // Used to mark the current shelf model mutation as user-triggered, while 39 // the instance of this class is in scope. 40 class ScopedUserTriggeredMutation { 41 public: ScopedUserTriggeredMutation(ShelfModel * model)42 explicit ScopedUserTriggeredMutation(ShelfModel* model) : model_(model) { 43 model_->current_mutation_is_user_triggered_++; 44 } 45 ~ScopedUserTriggeredMutation()46 ~ScopedUserTriggeredMutation() { 47 model_->current_mutation_is_user_triggered_--; 48 DCHECK_GE(model_->current_mutation_is_user_triggered_, 0); 49 } 50 51 private: 52 ShelfModel* model_ = nullptr; 53 }; 54 55 ShelfModel(); 56 ~ShelfModel(); 57 58 // Pins an app with |app_id| to shelf. A running instance will get pinned. 59 // If there is no running instance, a new shelf item is created and pinned. 60 void PinAppWithID(const std::string& app_id); 61 62 // Checks if the app with |app_id_| is pinned to the shelf. 63 bool IsAppPinned(const std::string& app_id); 64 65 // Unpins app item with |app_id|. 66 void UnpinAppWithID(const std::string& app_id); 67 68 // Cleans up the ShelfItemDelegates. 69 void DestroyItemDelegates(); 70 71 // Adds a new item to the model. Returns the resulting index. 72 int Add(const ShelfItem& item); 73 74 // Adds the item. |index| is the requested insertion index, which may be 75 // modified to meet type-based ordering. Returns the actual insertion index. 76 int AddAt(int index, const ShelfItem& item); 77 78 // Removes the item at |index|. 79 void RemoveItemAt(int index); 80 81 // Removes the item with id |shelf_id| and passes ownership of its 82 // ShelfItemDelegate to the caller. This is useful if you want to remove an 83 // item from the shelf temporarily and be able to restore its behavior later. 84 std::unique_ptr<ShelfItemDelegate> RemoveItemAndTakeShelfItemDelegate( 85 const ShelfID& shelf_id); 86 87 // Returns whether the item with the given index can be swapped with the 88 // next (or previous) item. Example cases when a swap cannot happen are: 89 // trying to swap the first item with the previous one, trying to swap 90 // the last item with the next one, trying to swap a pinned item with an 91 // unpinned item. 92 bool CanSwap(int index, bool with_next) const; 93 94 // Swaps the item at the given index with the next one if |with_next| is 95 // true, or with the previous one if |with_next| is false. Returns true 96 // if the requested swap has happened, and false otherwise. 97 bool Swap(int index, bool with_next); 98 99 // Moves the item at |index| to |target_index|. |target_index| is in terms 100 // of the model *after* the item at |index| is removed. 101 void Move(int index, int target_index); 102 103 // Resets the item at the specified index. The item's id should not change. 104 void Set(int index, const ShelfItem& item); 105 106 // Updates the items' |is_on_active_desk| from the given vector 107 // |items_desk_updates|. Items whose indices are not included in 108 // |items_desk_updates| will remain unchanged. 109 struct ItemDeskUpdate { 110 // The index of the item being updated. 111 int index = -1; 112 // The new value of the item's |ShelfItem::is_on_active_desk|. 113 bool is_on_active_desk = false; 114 }; 115 void UpdateItemsForDeskChange( 116 const std::vector<ItemDeskUpdate>& items_desk_updates); 117 118 // Returns the ID of the currently active item, or an empty ShelfID if 119 // nothing is currently active. active_shelf_id()120 const ShelfID& active_shelf_id() const { return active_shelf_id_; } 121 122 // Returns whether the mutation that is currently being made in the model 123 // was user-triggered. is_current_mutation_user_triggered()124 bool is_current_mutation_user_triggered() const { 125 return current_mutation_is_user_triggered_ > 0; 126 } 127 128 // Sets |shelf_id| to be the newly active shelf item. 129 void SetActiveShelfID(const ShelfID& shelf_id); 130 131 // Notifies observers that the status of the item corresponding to |id| 132 // has changed. 133 void OnItemStatusChanged(const ShelfID& id); 134 135 // Notifies observers that an item has been dragged off the shelf (it is still 136 // being dragged). 137 void OnItemRippedOff(); 138 139 // Notifies observers that an item that was dragged off the shelf has been 140 // dragged back onto the shelf (it is still being dragged). 141 void OnItemReturnedFromRipOff(int index); 142 143 // Update the ShelfItem with |app_id| to set whether the item currently has a 144 // notification. 145 void UpdateItemNotification(const std::string& app_id, bool has_badge); 146 147 // Returns the index of the item with id |shelf_id|, or -1 if none exists. 148 int ItemIndexByID(const ShelfID& shelf_id) const; 149 150 // Returns the |index| of the item matching |type| in |items_|. 151 // Returns -1 if the matching item is not found. 152 int GetItemIndexForType(ShelfItemType type); 153 154 // Returns the index of the first running application or the index where the 155 // first running application would go if there are no running (non pinned) 156 // applications yet. 157 int FirstRunningAppIndex() const; 158 159 // Returns an iterator into items() for the item with the specified id, or 160 // items().end() if there is no item with the specified id. 161 ShelfItems::const_iterator ItemByID(const ShelfID& shelf_id) const; 162 163 // Returns the index of the matching ShelfItem or -1 if the |app_id| doesn't 164 // match a ShelfItem. 165 int ItemIndexByAppID(const std::string& app_id) const; 166 items()167 const ShelfItems& items() const { return items_; } item_count()168 int item_count() const { return static_cast<int>(items_.size()); } 169 170 // Sets |item_delegate| for the given |shelf_id| and takes ownership. 171 void SetShelfItemDelegate(const ShelfID& shelf_id, 172 std::unique_ptr<ShelfItemDelegate> item_delegate); 173 174 // Returns ShelfItemDelegate for |shelf_id|, or nullptr if none exists. 175 ShelfItemDelegate* GetShelfItemDelegate(const ShelfID& shelf_id) const; 176 177 // Returns AppWindowLauncherItemController for |shelf_id|, or nullptr if none 178 // exists. 179 AppWindowLauncherItemController* GetAppWindowLauncherItemController( 180 const ShelfID& shelf_id); 181 182 void AddObserver(ShelfModelObserver* observer); 183 void RemoveObserver(ShelfModelObserver* observer); 184 185 private: 186 // Makes sure |index| is in line with the type-based order of items. If that 187 // is not the case, adjusts index by shifting it to the valid range and 188 // returns the new value. 189 int ValidateInsertionIndex(ShelfItemType type, int index) const; 190 191 ShelfItems items_; 192 193 // The shelf ID of the currently active shelf item, or an empty ID if 194 // nothing is active. 195 ShelfID active_shelf_id_; 196 197 // A counter to determine whether any mutation currently in progress in 198 // the model is the result of a manual user intervention. If a shelf item 199 // is added once an app has been installed, it is not considered a direct 200 // user interaction. 201 int current_mutation_is_user_triggered_ = 0; 202 203 base::ObserverList<ShelfModelObserver>::Unchecked observers_; 204 205 std::map<ShelfID, std::unique_ptr<ShelfItemDelegate>> 206 id_to_item_delegate_map_; 207 208 DISALLOW_COPY_AND_ASSIGN(ShelfModel); 209 }; 210 211 } // namespace ash 212 213 #endif // ASH_PUBLIC_CPP_SHELF_MODEL_H_ 214