OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/mac/bundle_locations.h" | 9 #include "base/mac/bundle_locations.h" |
10 #include "base/mac/sdk_forward_declarations.h" | 10 #include "base/mac/sdk_forward_declarations.h" |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 deltaScrollerY(0.0), | 117 deltaScrollerY(0.0), |
118 minimumY(0.0), | 118 minimumY(0.0), |
119 screenBottomY(0.0), | 119 screenBottomY(0.0), |
120 oldWindowY(0.0), | 120 oldWindowY(0.0), |
121 folderY(0.0), | 121 folderY(0.0), |
122 folderTop(0.0) {} | 122 folderTop(0.0) {} |
123 }; | 123 }; |
124 | 124 |
125 NSRect GetFirstButtonFrameForHeight(CGFloat height) { | 125 NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
126 CGFloat y = height - bookmarks::kBookmarkFolderButtonHeight - | 126 CGFloat y = height - bookmarks::kBookmarkFolderButtonHeight - |
127 bookmarks::BookmarkTopVerticalPadding(); | 127 bookmarks::kBookmarkTopVerticalPadding; |
128 return NSMakeRect(0, y, bookmarks::kDefaultBookmarkWidth, | 128 return NSMakeRect(0, y, bookmarks::kDefaultBookmarkWidth, |
129 bookmarks::kBookmarkFolderButtonHeight); | 129 bookmarks::kBookmarkFolderButtonHeight); |
130 } | 130 } |
131 | 131 |
132 } // namespace | 132 } // namespace |
133 | 133 |
134 namespace bookmarks { | |
135 | |
136 CGFloat BookmarkTopVerticalPadding() { | |
137 return bookmarks::BookmarkVerticalPadding(); | |
138 } | |
139 | |
140 CGFloat BookmarkBottomVerticalPadding() { | |
141 return ui::MaterialDesignController::IsModeMaterial() | |
142 ? 0 : bookmarks::BookmarkVerticalPadding(); | |
143 } | |
144 | |
145 } // bookmarks | |
146 | |
147 | 134 |
148 // Required to set the right tracking bounds for our fake menus. | 135 // Required to set the right tracking bounds for our fake menus. |
149 @interface NSView(Private) | 136 @interface NSView(Private) |
150 - (void)_updateTrackingAreas; | 137 - (void)_updateTrackingAreas; |
151 @end | 138 @end |
152 | 139 |
153 @interface BookmarkBarFolderController () | 140 @interface BookmarkBarFolderController () |
154 - (void)configureWindow; | 141 - (void)configureWindow; |
155 - (void)addOrUpdateScrollTracking; | 142 - (void)addOrUpdateScrollTracking; |
156 - (void)removeScrollTracking; | 143 - (void)removeScrollTracking; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 // Note: we don't need to | 311 // Note: we don't need to |
325 // [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 312 // [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
326 // Because all of our performSelector: calls use withDelay: which | 313 // Because all of our performSelector: calls use withDelay: which |
327 // retains us. | 314 // retains us. |
328 [super dealloc]; | 315 [super dealloc]; |
329 } | 316 } |
330 | 317 |
331 - (void)awakeFromNib { | 318 - (void)awakeFromNib { |
332 NSRect windowFrame = [[self window] frame]; | 319 NSRect windowFrame = [[self window] frame]; |
333 NSRect scrollViewFrame = [scrollView_ frame]; | 320 NSRect scrollViewFrame = [scrollView_ frame]; |
334 padding_ = NSWidth(windowFrame) - NSWidth(scrollViewFrame); | 321 // Each menu row spans the entire width of the menu. |
335 // In Material Design, each menu row spans the entire width of the menu. | 322 scrollViewFrame.size.width += NSWidth(windowFrame) - NSWidth(scrollViewFrame); |
336 if (ui::MaterialDesignController::IsModeMaterial()) { | 323 scrollViewFrame.origin.x = 0; |
337 scrollViewFrame.size.width += padding_; | 324 // If we leave the scrollview's vertical position and height as is, it will |
338 scrollViewFrame.origin.x = 0; | 325 // cover the menu's rounded corners and we'll get a rectangular menu. |
339 // If we leave the scrollview's vertical position and height as is, it will | 326 scrollViewFrame.origin.y += bookmarks::kBookmarkVerticalPadding; |
340 // cover the menu's rounded corners and we'll get a rectangular menu. | 327 scrollViewFrame.size.height -= 2 * bookmarks::kBookmarkVerticalPadding; |
341 scrollViewFrame.origin.y += bookmarks::BookmarkVerticalPadding(); | 328 [scrollView_ setFrame:scrollViewFrame]; |
342 scrollViewFrame.size.height -= 2 * bookmarks::BookmarkVerticalPadding(); | 329 padding_ = 0; |
343 [scrollView_ setFrame:scrollViewFrame]; | |
344 padding_ = 0; | |
345 } | |
346 verticalScrollArrowHeight_ = NSHeight([scrollUpArrowView_ frame]); | 330 verticalScrollArrowHeight_ = NSHeight([scrollUpArrowView_ frame]); |
347 | 331 |
348 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 332 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
349 NSImage* image = rb.GetNativeImageNamed(IDR_MENU_OVERFLOW_DOWN).ToNSImage(); | 333 NSImage* image = rb.GetNativeImageNamed(IDR_MENU_OVERFLOW_DOWN).ToNSImage(); |
350 [[scrollUpArrowView_.subviews objectAtIndex:0] setImage:image]; | 334 [[scrollUpArrowView_.subviews objectAtIndex:0] setImage:image]; |
351 | 335 |
352 image = rb.GetNativeImageNamed(IDR_MENU_OVERFLOW_UP).ToNSImage(); | 336 image = rb.GetNativeImageNamed(IDR_MENU_OVERFLOW_UP).ToNSImage(); |
353 [[scrollDownArrowView_.subviews objectAtIndex:0] setImage:image]; | 337 [[scrollDownArrowView_.subviews objectAtIndex:0] setImage:image]; |
354 } | 338 } |
355 | 339 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 NSImage* image = child ? [barController_ faviconForNode:child | 377 NSImage* image = child ? [barController_ faviconForNode:child |
394 forADarkTheme:NO] | 378 forADarkTheme:NO] |
395 : nil; | 379 : nil; |
396 BookmarkContextMenuCocoaController* menuController = | 380 BookmarkContextMenuCocoaController* menuController = |
397 [barController_ menuController]; | 381 [barController_ menuController]; |
398 BookmarkBarFolderButtonCell* cell = | 382 BookmarkBarFolderButtonCell* cell = |
399 [BookmarkBarFolderButtonCell buttonCellForNode:child | 383 [BookmarkBarFolderButtonCell buttonCellForNode:child |
400 text:nil | 384 text:nil |
401 image:image | 385 image:image |
402 menuController:menuController]; | 386 menuController:menuController]; |
403 if (ui::MaterialDesignController::IsModeMaterial()) { | 387 [cell setTag:kMaterialMenuButtonTypeWithLimitedClickFeedback]; |
404 [cell setTag:kMaterialMenuButtonTypeWithLimitedClickFeedback]; | |
405 } else { | |
406 [cell setTag:kStandardButtonTypeWithLimitedClickFeedback]; | |
407 } | |
408 return cell; | 388 return cell; |
409 } | 389 } |
410 | 390 |
411 // Redirect to our logic shared with BookmarkBarController. | 391 // Redirect to our logic shared with BookmarkBarController. |
412 - (IBAction)openBookmarkFolderFromButton:(id)sender { | 392 - (IBAction)openBookmarkFolderFromButton:(id)sender { |
413 [folderTarget_ openBookmarkFolderFromButton:sender]; | 393 [folderTarget_ openBookmarkFolderFromButton:sender]; |
414 } | 394 } |
415 | 395 |
416 // Create a bookmark button for the given node using frame. | 396 // Create a bookmark button for the given node using frame. |
417 // | 397 // |
(...skipping 28 matching lines...) Expand all Loading... |
446 // limited by the abolute minimum and maximum allowable widths. | 426 // limited by the abolute minimum and maximum allowable widths. |
447 frame.size.width = | 427 frame.size.width = |
448 std::min(std::max(bookmarks::kBookmarkMenuButtonMinimumWidth, | 428 std::min(std::max(bookmarks::kBookmarkMenuButtonMinimumWidth, |
449 std::max(frame.size.width, desired)), | 429 std::max(frame.size.width, desired)), |
450 bookmarks::kBookmarkMenuButtonMaximumWidth); | 430 bookmarks::kBookmarkMenuButtonMaximumWidth); |
451 | 431 |
452 BookmarkButton* button = [[[BookmarkButton alloc] initWithFrame:frame] | 432 BookmarkButton* button = [[[BookmarkButton alloc] initWithFrame:frame] |
453 autorelease]; | 433 autorelease]; |
454 DCHECK(button); | 434 DCHECK(button); |
455 | 435 |
456 // Folder menu buttons have a flat background color in Material Design. | 436 // Folder menu buttons have a flat background color. |
457 if (ui::MaterialDesignController::IsModeMaterial()) { | 437 [button setBackgroundColor: |
458 [button setBackgroundColor: | 438 [BookmarkBarFolderWindowContentView backgroundColor]]; |
459 [BookmarkBarFolderWindowContentView backgroundColor]]; | |
460 } | |
461 [button setCell:cell]; | 439 [button setCell:cell]; |
462 [button setDelegate:self]; | 440 [button setDelegate:self]; |
463 if (node) { | 441 if (node) { |
464 if (node->is_folder()) { | 442 if (node->is_folder()) { |
465 [button setTarget:self]; | 443 [button setTarget:self]; |
466 [button setAction:@selector(openBookmarkFolderFromButton:)]; | 444 [button setAction:@selector(openBookmarkFolderFromButton:)]; |
467 } else { | 445 } else { |
468 // Make the button do something. | 446 // Make the button do something. |
469 [button setTarget:barController_]; | 447 [button setTarget:barController_]; |
470 [button setAction:@selector(openBookmark:)]; | 448 [button setAction:@selector(openBookmark:)]; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 // is bottom of button's parent view. | 524 // is bottom of button's parent view. |
547 NSPoint buttonBottomLeftInScreen = ui::ConvertPointFromWindowToScreen( | 525 NSPoint buttonBottomLeftInScreen = ui::ConvertPointFromWindowToScreen( |
548 [parentButton_ window], | 526 [parentButton_ window], |
549 [parentButton_ convertPoint:NSZeroPoint toView:nil]); | 527 [parentButton_ convertPoint:NSZeroPoint toView:nil]); |
550 NSPoint bookmarkBarBottomLeftInScreen = ui::ConvertPointFromWindowToScreen( | 528 NSPoint bookmarkBarBottomLeftInScreen = ui::ConvertPointFromWindowToScreen( |
551 [parentButton_ window], | 529 [parentButton_ window], |
552 [[parentButton_ superview] convertPoint:NSZeroPoint toView:nil]); | 530 [[parentButton_ superview] convertPoint:NSZeroPoint toView:nil]); |
553 newWindowTopLeft = NSMakePoint( | 531 newWindowTopLeft = NSMakePoint( |
554 buttonBottomLeftInScreen.x, | 532 buttonBottomLeftInScreen.x, |
555 bookmarkBarBottomLeftInScreen.y + bookmarks::kBookmarkBarMenuOffset); | 533 bookmarkBarBottomLeftInScreen.y + bookmarks::kBookmarkBarMenuOffset); |
556 if (!ui::MaterialDesignController::IsModeMaterial()) { | |
557 newWindowTopLeft.y += bookmarks::kBookmarkBarButtonOffset; | |
558 } | |
559 // Make sure the window is on-screen; if not, push left or right. It is | 534 // Make sure the window is on-screen; if not, push left or right. It is |
560 // intentional that top level folders "push left" or "push right" slightly | 535 // intentional that top level folders "push left" or "push right" slightly |
561 // different than subfolders. | 536 // different than subfolders. |
562 NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; | 537 NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
563 // Test if window goes off-screen on the right side. | 538 // Test if window goes off-screen on the right side. |
564 CGFloat spillOff = | 539 CGFloat spillOff = |
565 newWindowTopLeft.x + windowWidth - NSMaxX(screenVisibleFrame); | 540 newWindowTopLeft.x + windowWidth - NSMaxX(screenVisibleFrame); |
566 if (spillOff > 0.0) { | 541 if (spillOff > 0.0) { |
567 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, | 542 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, |
568 NSMinX(screenVisibleFrame)); | 543 NSMinX(screenVisibleFrame)); |
(...skipping 10 matching lines...) Expand all Loading... |
579 (windowHeight > availableVerticalSpace)) { | 554 (windowHeight > availableVerticalSpace)) { |
580 newWindowTopLeft.y = std::min( | 555 newWindowTopLeft.y = std::min( |
581 newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), | 556 newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), |
582 NSMaxY(screenVisibleFrame)); | 557 NSMaxY(screenVisibleFrame)); |
583 } | 558 } |
584 } else { | 559 } else { |
585 // Parent is a folder: expose as much as we can vertically; grow right/left. | 560 // Parent is a folder: expose as much as we can vertically; grow right/left. |
586 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; | 561 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; |
587 NSPoint topOfWindow = | 562 NSPoint topOfWindow = |
588 NSMakePoint(0, NSMaxY([parentButton_ frame]) + | 563 NSMakePoint(0, NSMaxY([parentButton_ frame]) + |
589 bookmarks::BookmarkTopVerticalPadding()); | 564 bookmarks::kBookmarkTopVerticalPadding); |
590 topOfWindow = ui::ConvertPointFromWindowToScreen( | 565 topOfWindow = ui::ConvertPointFromWindowToScreen( |
591 [parentButton_ window], | 566 [parentButton_ window], |
592 [[parentButton_ superview] convertPoint:topOfWindow toView:nil]); | 567 [[parentButton_ superview] convertPoint:topOfWindow toView:nil]); |
593 newWindowTopLeft.y = topOfWindow.y; | 568 newWindowTopLeft.y = topOfWindow.y; |
594 } | 569 } |
595 return newWindowTopLeft; | 570 return newWindowTopLeft; |
596 } | 571 } |
597 | 572 |
598 // Set our window level to the right spot so we're above the menubar, dock, etc. | 573 // Set our window level to the right spot so we're above the menubar, dock, etc. |
599 // Factored out so we can override/noop in a unit test. | 574 // Factored out so we can override/noop in a unit test. |
600 - (void)configureWindowLevel { | 575 - (void)configureWindowLevel { |
601 [[self window] setLevel:NSPopUpMenuWindowLevel]; | 576 [[self window] setLevel:NSPopUpMenuWindowLevel]; |
602 } | 577 } |
603 | 578 |
604 - (int)menuHeightForButtonCount:(int)buttonCount { | 579 - (int)menuHeightForButtonCount:(int)buttonCount { |
605 // This does not take into account any padding which may be required at the | 580 // This does not take into account any padding which may be required at the |
606 // top and/or bottom of the window. | 581 // top and/or bottom of the window. |
607 return (buttonCount * bookmarks::kBookmarkFolderButtonHeight) + | 582 return (buttonCount * bookmarks::kBookmarkFolderButtonHeight) + |
608 bookmarks::BookmarkTopVerticalPadding() + | 583 bookmarks::kBookmarkTopVerticalPadding + |
609 bookmarks::BookmarkBottomVerticalPadding(); | 584 bookmarks::kBookmarkBottomVerticalPadding; |
610 } | 585 } |
611 | 586 |
612 - (void)adjustWindowLeft:(CGFloat)windowLeft | 587 - (void)adjustWindowLeft:(CGFloat)windowLeft |
613 size:(NSSize)windowSize | 588 size:(NSSize)windowSize |
614 scrollingBy:(CGFloat)scrollDelta { | 589 scrollingBy:(CGFloat)scrollDelta { |
615 // Callers of this function should make adjustments to the vertical | 590 // Callers of this function should make adjustments to the vertical |
616 // attributes of the folder view only (height, scroll position). | 591 // attributes of the folder view only (height, scroll position). |
617 // This function will then make appropriate layout adjustments in order | 592 // This function will then make appropriate layout adjustments in order |
618 // to accommodate screen/dock margins, scroll-up and scroll-down arrow | 593 // to accommodate screen/dock margins, scroll-up and scroll-down arrow |
619 // presentation, etc. | 594 // presentation, etc. |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 windowWidth, height); | 857 windowWidth, height); |
883 [window setFrame:windowFrame display:NO]; | 858 [window setFrame:windowFrame display:NO]; |
884 | 859 |
885 NSRect folderFrame = NSMakeRect(0, 0, windowWidth, height); | 860 NSRect folderFrame = NSMakeRect(0, 0, windowWidth, height); |
886 // Each menu button is 24pt tall but its highlight is only 20pt - effectively | 861 // Each menu button is 24pt tall but its highlight is only 20pt - effectively |
887 // each menu button includes 4pts of vertical padding. This wasn't a problem | 862 // each menu button includes 4pts of vertical padding. This wasn't a problem |
888 // pre-Material, but now that the |scrollView_| is shorter we have an extra | 863 // pre-Material, but now that the |scrollView_| is shorter we have an extra |
889 // 4pt of padding pushing the topmost item beyond the top of the | 864 // 4pt of padding pushing the topmost item beyond the top of the |
890 // |scrollView_|. Scoot the |folderView_| down by this padding to avoid | 865 // |scrollView_|. Scoot the |folderView_| down by this padding to avoid |
891 // clipping the topmost item. | 866 // clipping the topmost item. |
892 if (ui::MaterialDesignController::IsModeMaterial()) { | 867 folderFrame.origin.y -= bookmarks::kBookmarkVerticalPadding; |
893 folderFrame.origin.y -= bookmarks::BookmarkVerticalPadding(); | |
894 } | |
895 [folderView_ setFrame:folderFrame]; | 868 [folderView_ setFrame:folderFrame]; |
896 | 869 |
897 // For some reason, when opening a "large" bookmark folder (containing 12 or | 870 // For some reason, when opening a "large" bookmark folder (containing 12 or |
898 // more items) using the keyboard, the scroll view seems to want to be | 871 // more items) using the keyboard, the scroll view seems to want to be |
899 // offset by default: [ http://crbug.com/101099 ]. Explicitly reseting the | 872 // offset by default: [ http://crbug.com/101099 ]. Explicitly reseting the |
900 // scroll position here is a bit hacky, but it does seem to work. | 873 // scroll position here is a bit hacky, but it does seem to work. |
901 [[scrollView_ contentView] scrollToPoint:NSZeroPoint]; | 874 [[scrollView_ contentView] scrollToPoint:NSZeroPoint]; |
902 | 875 |
903 NSSize newSize = NSMakeSize(windowWidth, 0.0); | 876 NSSize newSize = NSMakeSize(windowWidth, 0.0); |
904 [self adjustWindowLeft:newWindowTopLeft.x size:newSize scrollingBy:0.0]; | 877 [self adjustWindowLeft:newWindowTopLeft.x size:newSize scrollingBy:0.0]; |
(...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1789 int destIndex = [self indexForDragToPoint:point]; | 1762 int destIndex = [self indexForDragToPoint:point]; |
1790 int numButtons = static_cast<int>([buttons_ count]); | 1763 int numButtons = static_cast<int>([buttons_ count]); |
1791 | 1764 |
1792 // If it's a drop strictly between existing buttons or at the very beginning | 1765 // If it's a drop strictly between existing buttons or at the very beginning |
1793 if (destIndex >= 0 && destIndex < numButtons) { | 1766 if (destIndex >= 0 && destIndex < numButtons) { |
1794 // ... put the indicator right between the buttons. | 1767 // ... put the indicator right between the buttons. |
1795 BookmarkButton* button = | 1768 BookmarkButton* button = |
1796 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)]; | 1769 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)]; |
1797 DCHECK(button); | 1770 DCHECK(button); |
1798 NSRect buttonFrame = [button frame]; | 1771 NSRect buttonFrame = [button frame]; |
1799 y = NSMaxY(buttonFrame) + 0.5 * bookmarks::BookmarkTopVerticalPadding(); | 1772 y = NSMaxY(buttonFrame) + 0.5 * bookmarks::kBookmarkTopVerticalPadding; |
1800 | 1773 |
1801 // If it's a drop at the end (past the last button, if there are any) ... | 1774 // If it's a drop at the end (past the last button, if there are any) ... |
1802 } else if (destIndex == numButtons) { | 1775 } else if (destIndex == numButtons) { |
1803 // and if it's past the last button ... | 1776 // and if it's past the last button ... |
1804 if (numButtons > 0) { | 1777 if (numButtons > 0) { |
1805 // ... find the last button, and put the indicator below it. | 1778 // ... find the last button, and put the indicator below it. |
1806 BookmarkButton* button = | 1779 BookmarkButton* button = |
1807 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)]; | 1780 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)]; |
1808 DCHECK(button); | 1781 DCHECK(button); |
1809 NSRect buttonFrame = [button frame]; | 1782 NSRect buttonFrame = [button frame]; |
1810 y = buttonFrame.origin.y - | 1783 y = buttonFrame.origin.y - |
1811 0.5 * bookmarks::BookmarkBottomVerticalPadding(); | 1784 0.5 * bookmarks::kBookmarkBottomVerticalPadding; |
1812 | 1785 |
1813 } | 1786 } |
1814 } else { | 1787 } else { |
1815 NOTREACHED(); | 1788 NOTREACHED(); |
1816 } | 1789 } |
1817 | 1790 |
1818 return y; | 1791 return y; |
1819 } | 1792 } |
1820 | 1793 |
1821 - (Profile*)profile { | 1794 - (Profile*)profile { |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2117 | 2090 |
2118 - (void)setIgnoreAnimations:(BOOL)ignore { | 2091 - (void)setIgnoreAnimations:(BOOL)ignore { |
2119 ignoreAnimations_ = ignore; | 2092 ignoreAnimations_ = ignore; |
2120 } | 2093 } |
2121 | 2094 |
2122 - (BookmarkButton*)buttonThatMouseIsIn { | 2095 - (BookmarkButton*)buttonThatMouseIsIn { |
2123 return buttonThatMouseIsIn_; | 2096 return buttonThatMouseIsIn_; |
2124 } | 2097 } |
2125 | 2098 |
2126 @end // BookmarkBarFolderController | 2099 @end // BookmarkBarFolderController |
OLD | NEW |