Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(387)

Side by Side Diff: ios/chrome/browser/ui/bookmarks/bookmark_menu_view.mm

Issue 2586993002: Upstream Chrome on iOS source code [3/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
6
7 #include <memory>
8
9 #include "base/mac/foundation_util.h"
10 #include "base/mac/objc_property_releaser.h"
11 #include "base/mac/scoped_nsobject.h"
12 #include "components/bookmarks/browser/bookmark_model.h"
13 #include "components/bookmarks/browser/bookmark_model_observer.h"
14 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
15 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
16 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
17 #include "ios/chrome/browser/experimental_flags.h"
18 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_cell.h"
19 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
20 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
21 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
22 #include "ios/chrome/browser/ui/ui_util.h"
23 #import "ios/chrome/browser/ui/uikit_ui_util.h"
24 #include "ios/chrome/grit/ios_strings.h"
25 #import "ios/third_party/material_components_ios/src/components/Ink/src/Material Ink.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/models/tree_node_iterator.h"
28
29 using bookmarks::BookmarkNode;
30
31 @interface BookmarkMenuView ()<BookmarkModelBridgeObserver,
32 MDCInkTouchControllerDelegate,
33 UITableViewDataSource,
34 UITableViewDelegate> {
35 // A bridge to receive bookmark model observer callbacks.
36 std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge;
37
38 base::mac::ObjCPropertyReleaser _propertyReleaser_BookmarkMenuView;
39 }
40 @property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel;
41 // This array directly represents the rows that show up in the table.
42 @property(nonatomic, retain) NSMutableArray* menuItems;
43 // The primary menu item is blue instead of gray.
44 @property(nonatomic, retain) BookmarkMenuItem* primaryMenuItem;
45 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
46 @property(nonatomic, retain) UITableView* tableView;
47 @property(nonatomic, retain) MDCInkTouchController* inkTouchController;
48
49 // Updates the data model, and the UI.
50 - (void)reloadData;
51
52 // Creates the views for this class.
53 - (void)createViews;
54
55 @end
56
57 @implementation BookmarkMenuView
58 @synthesize bookmarkModel = _bookmarkModel;
59 @synthesize delegate = _delegate;
60 @synthesize menuItems = _menuItems;
61 @synthesize primaryMenuItem = _primaryMenuItem;
62 @synthesize browserState = _browserState;
63 @synthesize tableView = _tableView;
64 @synthesize inkTouchController = _inkTouchController;
65
66 - (id)initWithFrame:(CGRect)frame {
67 NOTREACHED();
68 return nil;
69 }
70
71 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
72 frame:(CGRect)frame {
73 self = [super initWithFrame:frame];
74 if (self) {
75 _propertyReleaser_BookmarkMenuView.Init(self, [BookmarkMenuView class]);
76
77 _browserState = browserState;
78
79 // Set up connection to the BookmarkModel.
80 _bookmarkModel =
81 ios::BookmarkModelFactory::GetForBrowserState(_browserState);
82 // Set up observers.
83 _modelBridge.reset(
84 new bookmarks::BookmarkModelBridge(self, _bookmarkModel));
85
86 self.menuItems = [NSMutableArray array];
87
88 [self createViews];
89 }
90 return self;
91 }
92
93 - (void)dealloc {
94 self.tableView.delegate = nil;
95 self.tableView.dataSource = nil;
96 [super dealloc];
97 }
98
99 - (void)createViews {
100 // Make the table view.
101 self.tableView = base::scoped_nsobject<UITableView>(
102 [[UITableView alloc] initWithFrame:self.bounds]);
103 [self addSubview:self.tableView];
104 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
105 self.tableView.delegate = self;
106 self.tableView.dataSource = self;
107 self.tableView.scrollsToTop = NO;
108 [self reloadData];
109
110 // Set up ink touch controller.
111 base::scoped_nsobject<MDCInkTouchController> inkTouchController(
112 [[MDCInkTouchController alloc] initWithView:self.tableView]);
113 self.inkTouchController = inkTouchController;
114 self.inkTouchController.delegate = self;
115 self.inkTouchController.delaysInkSpread = YES;
116 }
117
118 - (void)layoutSubviews {
119 [super layoutSubviews];
120 self.tableView.frame = self.bounds;
121 }
122
123 - (void)reloadData {
124 if (!self.bookmarkModel->loaded())
125 return;
126
127 BookmarkMenuItem* primaryItem = [self.primaryMenuItem parentItem];
128
129 [self.menuItems removeAllObjects];
130
131 const BookmarkNode* mobileBookmarks = self.bookmarkModel->mobile_node();
132 const BookmarkNode* bookmarkBar = self.bookmarkModel->bookmark_bar_node();
133 const BookmarkNode* otherBookmarks = self.bookmarkModel->other_node();
134
135 // The first section is always visible.
136 base::scoped_nsobject<NSMutableArray> topSection(
137 [[NSMutableArray alloc] init]);
138 [self.menuItems addObject:topSection];
139
140 if (experimental_flags::IsAllBookmarksEnabled()) {
141 // All Items is always visible.
142 [topSection addObject:[BookmarkMenuItem allMenuItem]];
143 }
144 // Bookmarks Bar, Mobile Bookmarks and Other Bookmarks are special folders and
145 // are shown at the top if they contain anything.
146 if (!mobileBookmarks->empty() ||
147 !experimental_flags::IsAllBookmarksEnabled()) {
148 [topSection
149 addObject:[BookmarkMenuItem folderMenuItemForNode:mobileBookmarks
150 rootAncestor:mobileBookmarks]];
151 }
152 if (!bookmarkBar->empty()) {
153 [topSection addObject:[BookmarkMenuItem folderMenuItemForNode:bookmarkBar
154 rootAncestor:bookmarkBar]];
155 }
156 if (!otherBookmarks->empty()) {
157 [topSection
158 addObject:[BookmarkMenuItem folderMenuItemForNode:otherBookmarks
159 rootAncestor:otherBookmarks]];
160 }
161
162 // The second section contains all the top level folders (except for the
163 // permanent nodes).
164 base::scoped_nsobject<NSMutableArray> folderSection(
165 [[NSMutableArray alloc] init]);
166 std::vector<const BookmarkNode*> rootLevelFolders =
167 RootLevelFolders(self.bookmarkModel);
168 bookmark_utils_ios::SortFolders(&rootLevelFolders);
169 for (auto node : rootLevelFolders) {
170 [folderSection addObject:[BookmarkMenuItem folderMenuItemForNode:node
171 rootAncestor:node]];
172 }
173 if ([folderSection count]) {
174 // Add the title and the divider at the top of the section.
175 [folderSection
176 insertObject:[BookmarkMenuItem sectionMenuItemWithTitle:
177 l10n_util::GetNSString(
178 IDS_IOS_BOOKMARK_FOLDERS_LABEL)]
179 atIndex:0];
180 [folderSection insertObject:[BookmarkMenuItem dividerMenuItem] atIndex:0];
181 [self.menuItems addObject:folderSection];
182 }
183
184 // If the currently selected menuitem is no longer present in the menu, then
185 // select the first item in the top section instead.
186 if (![topSection containsObject:primaryItem] &&
187 ![folderSection containsObject:primaryItem]) {
188 self.primaryMenuItem = [topSection firstObject];
189 [self.delegate bookmarkMenuView:self selectedMenuItem:self.primaryMenuItem];
190 }
191
192 [self.tableView reloadData];
193 }
194
195 - (BookmarkMenuItem*)defaultMenuItem {
196 // The first item in the first section.
197 DCHECK([[self.menuItems firstObject] firstObject]);
198 return [[self.menuItems firstObject] firstObject];
199 }
200
201 - (BookmarkMenuItem*)menuItemAtIndexPath:(NSIndexPath*)indexPath {
202 return self.menuItems[indexPath.section][indexPath.row];
203 }
204
205 #pragma mark UIView method
206
207 - (void)didMoveToSuperview {
208 [super didMoveToSuperview];
209 // The background color depends on where in the view hierachy the menu is.
210 // For example, the menu may be moved to a slide over panel if the
211 // horizontal size class changes from regular to compact.
212 self.tableView.backgroundColor = bookmark_utils_ios::menuBackgroundColor();
213 }
214
215 #pragma mark BookmarkModelBridgeObserver
216
217 - (void)bookmarkModelLoaded {
218 [self reloadData];
219 }
220
221 - (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode {
222 [self reloadData];
223 }
224
225 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode {
226 [self reloadData];
227 }
228
229 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode
230 movedFromParent:(const BookmarkNode*)oldParent
231 toParent:(const BookmarkNode*)newParent {
232 if (self.primaryMenuItem.type == bookmarks::MenuItemFolder &&
233 bookmarkNode->is_folder()) {
234 // Checking which folder moved and if the current folder was implicated is
235 // complicated and not worth the effort. Just rebuild a new primaryMenu item
236 // unconditionally, this is simpler.
237 const BookmarkNode* currentFolder = self.primaryMenuItem.folder;
238 BookmarkMenuItem* menuItem = [BookmarkMenuItem
239 folderMenuItemForNode:currentFolder
240 rootAncestor:RootLevelFolderForNode(currentFolder,
241 self.bookmarkModel)];
242 if (menuItem != self.primaryMenuItem) {
243 self.primaryMenuItem = menuItem;
244 [self.delegate bookmarkMenuView:self
245 selectedMenuItem:self.primaryMenuItem];
246 }
247 }
248 [self reloadData];
249 }
250
251 - (void)bookmarkNodeDeleted:(const BookmarkNode*)node
252 fromFolder:(const BookmarkNode*)parentFolder {
253 // If the current folder or one of its ancestor has been deleted, the
254 // selection needs to move up to a non deleted ancestor. This check is made
255 // more complex as by the time this method is called |node| is no longer in
256 // the hierarchy : its parent is already set to null.
257
258 if (self.primaryMenuItem.type != bookmarks::MenuItemFolder) {
259 // If the object currently selected is not a folder, just reload.
260 [self reloadData];
261 return;
262 }
263
264 if (parentFolder == self.primaryMenuItem.folder || !node->is_folder()) {
265 // A child of the selected folder has been deleted or a url not visible in
266 // the UI right now has been deleted. Nothing to do as the menu itself needs
267 // no change.
268 return;
269 }
270
271 if (node == self.primaryMenuItem.rootAncestor) {
272 // The deleted node is the root node of the current selected folder. Move to
273 // all items.
274 self.primaryMenuItem = [BookmarkMenuItem allMenuItem];
275 [self.delegate bookmarkMenuView:self selectedMenuItem:self.primaryMenuItem];
276 [self reloadData];
277 return;
278 }
279
280 const BookmarkNode* root =
281 RootLevelFolderForNode(parentFolder, self.bookmarkModel);
282
283 if (root != self.primaryMenuItem.rootAncestor) {
284 // The deleted folder is not in the same hierarchy as the current selected
285 // folder, there is nothing to reload unless the deleted folder is a root
286 // node.
287 if (!root)
288 [self reloadData];
289 return;
290 }
291
292 if (node == self.primaryMenuItem.folder) {
293 // The simple case where the deleted folder is the one currently in the UI.
294 // At this point the deleted folder is known to not be a root node:
295 DCHECK_NE(self.primaryMenuItem.folder, self.primaryMenuItem.rootAncestor);
296 // Simply move to the parent.
297 self.primaryMenuItem =
298 [BookmarkMenuItem folderMenuItemForNode:parentFolder rootAncestor:root];
299 [self.delegate bookmarkMenuView:self selectedMenuItem:self.primaryMenuItem];
300 [self reloadData];
301 }
302
303 // The only case left is when the deleted folder used to be an ancestor of the
304 // selected folder. This is easy to infer, if the selected folder is no longer
305 // present in the common root hierarchy, this means it was deleted as well.
306 ui::TreeNodeIterator<const BookmarkNode> iterator(root);
307 while (iterator.has_next()) {
308 if (self.primaryMenuItem.folder == iterator.Next())
309 return; // Nothing to do.
310 }
311 // The current folder was not found, relocate to the first non deleted
312 // ancestor.
313 self.primaryMenuItem =
314 [BookmarkMenuItem folderMenuItemForNode:parentFolder rootAncestor:root];
315 [self.delegate bookmarkMenuView:self selectedMenuItem:self.primaryMenuItem];
316 [self reloadData];
317 }
318
319 - (void)bookmarkModelRemovedAllNodes {
320 [self reloadData];
321 }
322
323 #pragma mark UITableViewDataSource
324
325 - (UITableViewCell*)tableView:(UITableView*)tableView
326 cellForRowAtIndexPath:(NSIndexPath*)indexPath {
327 BookmarkMenuCell* cell = [tableView
328 dequeueReusableCellWithIdentifier:[BookmarkMenuCell reuseIdentifier]];
329 if (!cell) {
330 cell = [[[BookmarkMenuCell alloc]
331 initWithStyle:UITableViewCellStyleDefault
332 reuseIdentifier:[BookmarkMenuCell reuseIdentifier]] autorelease];
333 }
334 cell.selectionStyle = UITableViewCellSelectionStyleNone;
335 BookmarkMenuItem* menuItem = [self menuItemAtIndexPath:indexPath];
336 BOOL primary =
337 [[self.primaryMenuItem parentItem] isEqual:[menuItem parentItem]];
338 [cell updateWithBookmarkMenuItem:menuItem primary:primary];
339 if (primary && bookmark_utils_ios::bookmarkMenuIsInSlideInPanel()) {
340 [tableView selectRowAtIndexPath:indexPath
341 animated:NO
342 scrollPosition:UITableViewScrollPositionNone];
343 }
344 return cell;
345 }
346
347 - (NSInteger)tableView:(UITableView*)tableView
348 numberOfRowsInSection:(NSInteger)section {
349 return [self.menuItems[section] count];
350 }
351
352 - (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
353 return [self.menuItems count];
354 }
355
356 #pragma mark UITableViewDelegate
357
358 - (CGFloat)tableView:(UITableView*)tableView
359 heightForRowAtIndexPath:(NSIndexPath*)indexPath {
360 BookmarkMenuItem* menuItem = [self menuItemAtIndexPath:indexPath];
361 return [menuItem height];
362 }
363
364 - (NSIndexPath*)tableView:(UITableView*)tableView
365 willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
366 BookmarkMenuItem* menuItem = [self menuItemAtIndexPath:indexPath];
367 return [menuItem canBeSelected] ? indexPath : nil;
368 }
369
370 - (void)tableView:(UITableView*)tableView
371 didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
372 BookmarkMenuItem* menuItem = [self menuItemAtIndexPath:indexPath];
373 [self.delegate bookmarkMenuView:self selectedMenuItem:menuItem];
374 }
375
376 - (CGFloat)tableView:(UITableView*)tableView
377 heightForHeaderInSection:(NSInteger)section {
378 return 8.0;
379 }
380
381 - (CGFloat)tableView:(UITableView*)tableView
382 heightForFooterInSection:(NSInteger)section {
383 BOOL isLastSection = [tableView numberOfSections] == (section + 1);
384 return isLastSection ? 8.0 : 0.0;
385 }
386
387 - (UIView*)tableView:(UITableView*)tableView
388 viewForHeaderInSection:(NSInteger)section {
389 return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
390 }
391
392 - (UIView*)tableView:(UITableView*)tableView
393 viewForFooterInSection:(NSInteger)section {
394 return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
395 }
396
397 #pragma mark MDCInkTouchControllerDelegate
398
399 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController
400 shouldProcessInkTouchesAtTouchLocation:(CGPoint)location {
401 NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:location];
402 BookmarkMenuItem* menuItem = [self menuItemAtIndexPath:indexPath];
403 return menuItem.type == bookmarks::MenuItemAll ||
404 menuItem.type == bookmarks::MenuItemFolder;
405 }
406
407 - (MDCInkView*)inkTouchController:(MDCInkTouchController*)inkTouchController
408 inkViewAtTouchLocation:(CGPoint)location {
409 NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:location];
410 BookmarkMenuCell* cell = base::mac::ObjCCastStrict<BookmarkMenuCell>(
411 [self.tableView cellForRowAtIndexPath:indexPath]);
412 return cell.inkView;
413 }
414
415 #pragma mark Public Methods
416
417 - (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem {
418 if ([self.primaryMenuItem isEqual:menuItem])
419 return;
420
421 self.primaryMenuItem = menuItem;
422 [self.tableView reloadData];
423 }
424
425 - (void)setScrollsToTop:(BOOL)scrollsToTop {
426 self.tableView.scrollsToTop = scrollsToTop;
427 }
428
429 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h ('k') | ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698