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