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

Side by Side Diff: chrome/browser/cocoa/bookmark_bar_controller.mm

Issue 373022: Enable and implement last 2 items in bookmark bar context menu: "Open... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 #include "app/l10n_util_mac.h" 5 #include "app/l10n_util_mac.h"
6 #include "app/resource_bundle.h" 6 #include "app/resource_bundle.h"
7 #include "base/mac_util.h" 7 #include "base/mac_util.h"
8 #include "base/sys_string_conversions.h" 8 #include "base/sys_string_conversions.h"
9 #include "chrome/browser/bookmarks/bookmark_editor.h" 9 #include "chrome/browser/bookmarks/bookmark_editor.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h" 10 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #include "chrome/browser/browser.h" 11 #include "chrome/browser/browser.h"
12 #include "chrome/browser/browser_list.h" 12 #include "chrome/browser/browser_list.h"
13 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" 13 #import "chrome/browser/cocoa/bookmark_bar_bridge.h"
14 #import "chrome/browser/cocoa/bookmark_bar_constants.h" 14 #import "chrome/browser/cocoa/bookmark_bar_constants.h"
15 #import "chrome/browser/cocoa/bookmark_bar_controller.h" 15 #import "chrome/browser/cocoa/bookmark_bar_controller.h"
16 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" 16 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h"
17 #import "chrome/browser/cocoa/bookmark_bar_view.h" 17 #import "chrome/browser/cocoa/bookmark_bar_view.h"
18 #import "chrome/browser/cocoa/bookmark_button_cell.h" 18 #import "chrome/browser/cocoa/bookmark_button_cell.h"
19 #import "chrome/browser/cocoa/bookmark_editor_controller.h" 19 #import "chrome/browser/cocoa/bookmark_editor_controller.h"
20 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" 20 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h"
21 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" 21 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
22 #import "chrome/browser/cocoa/event_utils.h" 22 #import "chrome/browser/cocoa/event_utils.h"
23 #import "chrome/browser/cocoa/menu_button.h" 23 #import "chrome/browser/cocoa/menu_button.h"
24 #import "chrome/browser/cocoa/toolbar_controller.h" 24 #import "chrome/browser/cocoa/toolbar_controller.h"
25 #import "chrome/browser/cocoa/view_resizer.h" 25 #import "chrome/browser/cocoa/view_resizer.h"
26 #include "chrome/browser/metrics/user_metrics.h"
26 #include "chrome/browser/profile.h" 27 #include "chrome/browser/profile.h"
27 #include "chrome/browser/tab_contents/tab_contents.h" 28 #include "chrome/browser/tab_contents/tab_contents.h"
28 #include "chrome/browser/tab_contents/tab_contents_view.h" 29 #include "chrome/browser/tab_contents/tab_contents_view.h"
29 #include "chrome/common/pref_names.h" 30 #include "chrome/common/pref_names.h"
30 #include "chrome/common/pref_service.h" 31 #include "chrome/common/pref_service.h"
31 #include "grit/app_resources.h" 32 #include "grit/app_resources.h"
32 #include "grit/generated_resources.h" 33 #include "grit/generated_resources.h"
33 #include "grit/theme_resources.h" 34 #include "grit/theme_resources.h"
34 #include "skia/ext/skia_utils_mac.h" 35 #include "skia/ext/skia_utils_mac.h"
35 #import "third_party/mozilla/include/NSPasteboard+Utils.h" 36 #import "third_party/mozilla/include/NSPasteboard+Utils.h"
(...skipping 21 matching lines...) Expand all
57 - (void)resizeButtons; 58 - (void)resizeButtons;
58 - (void)centerNoItemsLabel; 59 - (void)centerNoItemsLabel;
59 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node; 60 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node;
60 @end 61 @end
61 62
62 @implementation BookmarkBarController 63 @implementation BookmarkBarController
63 64
64 - (id)initWithBrowser:(Browser*)browser 65 - (id)initWithBrowser:(Browser*)browser
65 initialWidth:(float)initialWidth 66 initialWidth:(float)initialWidth
66 compressDelegate:(id<ToolbarCompressable>)compressDelegate 67 compressDelegate:(id<ToolbarCompressable>)compressDelegate
67 resizeDelegate:(id<ViewResizer>)resizeDelegate 68 resizeDelegate:(id<ViewResizer>)resizeDelegate {
68 urlDelegate:(id<BookmarkURLOpener>)urlDelegate {
69 if ((self = [super initWithNibName:@"BookmarkBar" 69 if ((self = [super initWithNibName:@"BookmarkBar"
70 bundle:mac_util::MainAppBundle()])) { 70 bundle:mac_util::MainAppBundle()])) {
71 browser_ = browser; 71 browser_ = browser;
72 initialWidth_ = initialWidth; 72 initialWidth_ = initialWidth;
73 bookmarkModel_ = browser_->profile()->GetBookmarkModel(); 73 bookmarkModel_ = browser_->profile()->GetBookmarkModel();
74 buttons_.reset([[NSMutableArray alloc] init]); 74 buttons_.reset([[NSMutableArray alloc] init]);
75 compressDelegate_ = compressDelegate; 75 compressDelegate_ = compressDelegate;
76 resizeDelegate_ = resizeDelegate; 76 resizeDelegate_ = resizeDelegate;
77 urlDelegate_ = urlDelegate;
78 tabObserver_.reset( 77 tabObserver_.reset(
79 new TabStripModelObserverBridge(browser_->tabstrip_model(), self)); 78 new TabStripModelObserverBridge(browser_->tabstrip_model(), self));
80 79
81 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 80 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
82 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]); 81 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
83 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]); 82 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]);
84 } 83 }
85 return self; 84 return self;
86 } 85 }
87 86
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 } 297 }
299 298
300 - (BookmarkNode*)nodeFromButton:(id)button { 299 - (BookmarkNode*)nodeFromButton:(id)button {
301 NSCell* cell = [button cell]; 300 NSCell* cell = [button cell];
302 BookmarkNode* node = static_cast<BookmarkNode*>( 301 BookmarkNode* node = static_cast<BookmarkNode*>(
303 [[cell representedObject] pointerValue]); 302 [[cell representedObject] pointerValue]);
304 DCHECK(node); 303 DCHECK(node);
305 return node; 304 return node;
306 } 305 }
307 306
308 // At this time, the only item which ever gets disabled is "Open All 307 // At this time, the only items which ever get disabled are the "Open All
309 // Bookmarks". 308 // Bookmarks" options.
310 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { 309 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
311 SEL action = [item action]; 310 SEL action = [item action];
312 if ((action == @selector(openAllBookmarks:)) && 311 if (((action == @selector(openAllBookmarks:)) ||
312 (action == @selector(openAllBookmarksNewWindow:)) ||
313 (action == @selector(openAllBookmarksIncognitoWindow:))) &&
313 (![buttons_ count])) { 314 (![buttons_ count])) {
314 return NO; 315 return NO;
315 } 316 }
316 return YES; 317 return YES;
317 } 318 }
318 319
320 // Actually open the URL. This is the last chance for a unit test to
321 // override.
322 - (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition {
323 BrowserList::GetLastActive()->OpenURL(url, GURL(), disposition,
324 PageTransition::AUTO_BOOKMARK);
325 }
326
319 - (IBAction)openBookmark:(id)sender { 327 - (IBAction)openBookmark:(id)sender {
320 BookmarkNode* node = [self nodeFromButton:sender]; 328 BookmarkNode* node = [self nodeFromButton:sender];
321 [urlDelegate_ openBookmarkURL:node->GetURL() 329 WindowOpenDisposition disposition =
322 disposition:event_utils::WindowOpenDispositionFromNSEvent( 330 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
323 [NSApp currentEvent])]; 331 [self openURL:node->GetURL() disposition:disposition];
324 } 332 }
325 333
326 // Given a NSMenuItem tag, return the appropriate bookmark node id. 334 // Given a NSMenuItem tag, return the appropriate bookmark node id.
327 - (int64)nodeIdFromMenuTag:(int32)tag { 335 - (int64)nodeIdFromMenuTag:(int32)tag {
328 return menuTagMap_[tag]; 336 return menuTagMap_[tag];
329 } 337 }
330 338
331 // Create and return a new tag for the given node id. 339 // Create and return a new tag for the given node id.
332 - (int32)menuTagFromNodeId:(int64)menuid { 340 - (int32)menuTagFromNodeId:(int64)menuid {
333 int tag = seedId_++; 341 int tag = seedId_++;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 if (menu == [self offTheSideMenu]) 476 if (menu == [self offTheSideMenu])
469 [self buildOffTheSideMenu]; 477 [self buildOffTheSideMenu];
470 } 478 }
471 479
472 // As a convention we set the menu's delegate to be the button's cell 480 // As a convention we set the menu's delegate to be the button's cell
473 // so we can easily obtain bookmark info. Convention applied in 481 // so we can easily obtain bookmark info. Convention applied in
474 // -[BookmarkButtonCell menu]. 482 // -[BookmarkButtonCell menu].
475 483
476 - (IBAction)openBookmarkInNewForegroundTab:(id)sender { 484 - (IBAction)openBookmarkInNewForegroundTab:(id)sender {
477 BookmarkNode* node = [self nodeFromMenuItem:sender]; 485 BookmarkNode* node = [self nodeFromMenuItem:sender];
478 [urlDelegate_ openBookmarkURL:node->GetURL() disposition:NEW_FOREGROUND_TAB]; 486 [self openURL:node->GetURL() disposition:NEW_FOREGROUND_TAB];
479 } 487 }
480 488
481 - (IBAction)openBookmarkInNewWindow:(id)sender { 489 - (IBAction)openBookmarkInNewWindow:(id)sender {
482 BookmarkNode* node = [self nodeFromMenuItem:sender]; 490 BookmarkNode* node = [self nodeFromMenuItem:sender];
483 [urlDelegate_ openBookmarkURL:node->GetURL() disposition:NEW_WINDOW]; 491 [self openURL:node->GetURL() disposition:NEW_WINDOW];
484 } 492 }
485 493
486 - (IBAction)openBookmarkInIncognitoWindow:(id)sender { 494 - (IBAction)openBookmarkInIncognitoWindow:(id)sender {
487 BookmarkNode* node = [self nodeFromMenuItem:sender]; 495 BookmarkNode* node = [self nodeFromMenuItem:sender];
488 [urlDelegate_ openBookmarkURL:node->GetURL() disposition:OFF_THE_RECORD]; 496 [self openURL:node->GetURL() disposition:OFF_THE_RECORD];
489 } 497 }
490 498
491 - (IBAction)editBookmark:(id)sender { 499 - (IBAction)editBookmark:(id)sender {
492 BookmarkNode* node = [self nodeFromMenuItem:sender]; 500 BookmarkNode* node = [self nodeFromMenuItem:sender];
493 501
494 if (node->is_folder()) { 502 if (node->is_folder()) {
495 BookmarkNameFolderController* controller = 503 BookmarkNameFolderController* controller =
496 [[BookmarkNameFolderController alloc] 504 [[BookmarkNameFolderController alloc]
497 initWithParentWindow:[[self view] window] 505 initWithParentWindow:[[self view] window]
498 profile:browser_->profile() 506 profile:browser_->profile()
(...skipping 27 matching lines...) Expand all
526 owner:nil]; 534 owner:nil];
527 [pasteboard setDataForURL:url title:title]; 535 [pasteboard setDataForURL:url title:title];
528 } 536 }
529 537
530 - (IBAction)deleteBookmark:(id)sender { 538 - (IBAction)deleteBookmark:(id)sender {
531 BookmarkNode* node = [self nodeFromMenuItem:sender]; 539 BookmarkNode* node = [self nodeFromMenuItem:sender];
532 bookmarkModel_->Remove(node->GetParent(), 540 bookmarkModel_->Remove(node->GetParent(),
533 node->GetParent()->IndexOfChild(node)); 541 node->GetParent()->IndexOfChild(node));
534 } 542 }
535 543
536 - (void)openBookmarkNodesRecursive:(BookmarkNode*)node { 544 // An ObjC version of bookmark_utils::OpenAllImpl().
545 - (void)openBookmarkNodesRecursive:(BookmarkNode*)node
546 disposition:(WindowOpenDisposition)disposition {
537 for (int i = 0; i < node->GetChildCount(); i++) { 547 for (int i = 0; i < node->GetChildCount(); i++) {
538 BookmarkNode* child = node->GetChild(i); 548 BookmarkNode* child = node->GetChild(i);
539 if (child->is_url()) 549 if (child->is_url()) {
540 [urlDelegate_ openBookmarkURL:child->GetURL() 550 [self openURL:child->GetURL() disposition:disposition];
541 disposition:NEW_BACKGROUND_TAB]; 551 // We revert to a basic disposition in case the initial
542 else 552 // disposition opened a new window.
543 [self openBookmarkNodesRecursive:child]; 553 disposition = NEW_BACKGROUND_TAB;
554 } else {
555 [self openBookmarkNodesRecursive:child disposition:disposition];
556 }
544 } 557 }
545 } 558 }
546 559
547 - (IBAction)openAllBookmarks:(id)sender { 560 - (IBAction)openAllBookmarks:(id)sender {
548 // TODO(jrg): 561 // TODO(jrg):
549 // Is there an easier way to get a non-const root node for the bookmark bar? 562 // Is there an easier way to get a non-const root node for the bookmark bar?
550 // I can't iterate over them unless it's non-const. 563 // I can't iterate over them unless it's non-const.
564 BookmarkNode* node = const_cast<BookmarkNode*>(
565 bookmarkModel_->GetBookmarkBarNode());
566 [self openBookmarkNodesRecursive:node disposition:NEW_FOREGROUND_TAB];
567 UserMetrics::RecordAction(L"OpenAllBookmarks", browser_->profile());
568 }
551 569
552 BookmarkNode* node = (BookmarkNode*)bookmarkModel_->GetBookmarkBarNode(); 570 - (IBAction)openAllBookmarksNewWindow:(id)sender {
553 [self openBookmarkNodesRecursive:node]; 571 BookmarkNode* node = const_cast<BookmarkNode*>(
572 bookmarkModel_->GetBookmarkBarNode());
573 [self openBookmarkNodesRecursive:node disposition:NEW_WINDOW];
574 UserMetrics::RecordAction(L"OpenAllBookmarksNewWindow", browser_->profile());
575 }
576
577 - (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
578 BookmarkNode* node = const_cast<BookmarkNode*>(
579 bookmarkModel_->GetBookmarkBarNode());
580 [self openBookmarkNodesRecursive:node disposition:OFF_THE_RECORD];
581 UserMetrics::RecordAction(L"OpenAllBookmarksIncognitoWindow", browser_->profil e());
554 } 582 }
555 583
556 // May be called from the bar or from a folder button. 584 // May be called from the bar or from a folder button.
557 // If called from a button, that button becomes the parent. 585 // If called from a button, that button becomes the parent.
558 - (IBAction)addPage:(id)sender { 586 - (IBAction)addPage:(id)sender {
559 const BookmarkNode* parent = [self nodeFromMenuItem:sender]; 587 const BookmarkNode* parent = [self nodeFromMenuItem:sender];
560 if (!parent) 588 if (!parent)
561 parent = bookmarkModel_->GetBookmarkBarNode(); 589 parent = bookmarkModel_->GetBookmarkBarNode();
562 BookmarkEditor::Show([[self view] window], 590 BookmarkEditor::Show([[self view] window],
563 browser_->profile(), 591 browser_->profile(),
(...skipping 29 matching lines...) Expand all
593 // TODO(jrg): move much of the cell config into the BookmarkButtonCell class. 621 // TODO(jrg): move much of the cell config into the BookmarkButtonCell class.
594 - (NSCell*)cellForBookmarkNode:(const BookmarkNode*)node { 622 - (NSCell*)cellForBookmarkNode:(const BookmarkNode*)node {
595 NSString* title = base::SysWideToNSString(node->GetTitle()); 623 NSString* title = base::SysWideToNSString(node->GetTitle());
596 BookmarkButtonCell* cell = 624 BookmarkButtonCell* cell =
597 [[[BookmarkButtonCell alloc] initTextCell:nil] autorelease]; 625 [[[BookmarkButtonCell alloc] initTextCell:nil] autorelease];
598 DCHECK(cell); 626 DCHECK(cell);
599 [cell setRepresentedObject:[NSValue valueWithPointer:node]]; 627 [cell setRepresentedObject:[NSValue valueWithPointer:node]];
600 628
601 NSImage* image = [self getFavIconForNode:node]; 629 NSImage* image = [self getFavIconForNode:node];
602 [cell setBookmarkCellText:title image:image]; 630 [cell setBookmarkCellText:title image:image];
603 [cell setMenu:buttonContextMenu_]; 631 if (node->is_folder())
632 [cell setMenu:[[self view] menu]];
633 else
634 [cell setMenu:buttonContextMenu_];
604 return cell; 635 return cell;
605 } 636 }
606 637
607 // Return an appropriate width for the given bookmark button cell. 638 // Return an appropriate width for the given bookmark button cell.
608 // The "+2" is needed because, sometimes, Cocoa is off by a tad. 639 // The "+2" is needed because, sometimes, Cocoa is off by a tad.
609 // Example: for a bookmark named "Moma" or "SFGate", it is one pixel 640 // Example: for a bookmark named "Moma" or "SFGate", it is one pixel
610 // too small. For "FBL" it is 2 pixels too small. 641 // too small. For "FBL" it is 2 pixels too small.
611 // For a bookmark named "SFGateFooWoo", it is just fine. 642 // For a bookmark named "SFGateFooWoo", it is just fine.
612 - (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell { 643 - (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell {
613 CGFloat desired = [cell cellSize].width + 2; 644 CGFloat desired = [cell cellSize].width + 2;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 // We may have just crossed a threshold to enable the off-the-side 694 // We may have just crossed a threshold to enable the off-the-side
664 // button. 695 // button.
665 [self showOrHideOffTheSideButton]; 696 [self showOrHideOffTheSideButton];
666 } 697 }
667 698
668 - (IBAction)openBookmarkMenuItem:(id)sender { 699 - (IBAction)openBookmarkMenuItem:(id)sender {
669 int64 tag = [self nodeIdFromMenuTag:[sender tag]]; 700 int64 tag = [self nodeIdFromMenuTag:[sender tag]];
670 const BookmarkNode* node = bookmarkModel_->GetNodeByID(tag); 701 const BookmarkNode* node = bookmarkModel_->GetNodeByID(tag);
671 WindowOpenDisposition disposition = 702 WindowOpenDisposition disposition =
672 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 703 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
673 [urlDelegate_ openBookmarkURL:node->GetURL() disposition:disposition]; 704 [self openURL:node->GetURL() disposition:disposition];
674 } 705 }
675 706
676 // Create buttons for all items in the bookmark node tree. 707 // Create buttons for all items in the bookmark node tree.
677 // 708 //
678 // TODO(jrg): write a "build bar" so there is a nice spot for things 709 // TODO(jrg): write a "build bar" so there is a nice spot for things
679 // like the contextual menu which is invoked when not over a 710 // like the contextual menu which is invoked when not over a
680 // bookmark. On Safari that menu has a "new folder" option. 711 // bookmark. On Safari that menu has a "new folder" option.
681 - (void)addNodesToButtonList:(const BookmarkNode*)node { 712 - (void)addNodesToButtonList:(const BookmarkNode*)node {
682 BOOL hidden = (node->GetChildCount() == 0) ? NO : YES; 713 BOOL hidden = (node->GetChildCount() == 0) ? NO : YES;
683 NSView* item = [buttonView_ noItemTextfield]; 714 NSView* item = [buttonView_ noItemTextfield];
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 } 904 }
874 } 905 }
875 } 906 }
876 907
877 // TODO(jrg): for now this is brute force. 908 // TODO(jrg): for now this is brute force.
878 - (void)nodeChildrenReordered:(BookmarkModel*)model 909 - (void)nodeChildrenReordered:(BookmarkModel*)model
879 node:(const BookmarkNode*)node { 910 node:(const BookmarkNode*)node {
880 [self loaded:model]; 911 [self loaded:model];
881 } 912 }
882 913
883 - (void)setUrlDelegate:(id<BookmarkURLOpener>)urlDelegate {
884 urlDelegate_ = urlDelegate;
885 }
886
887 - (NSArray*)buttons { 914 - (NSArray*)buttons {
888 return buttons_.get(); 915 return buttons_.get();
889 } 916 }
890 917
891 - (NSButton*)offTheSideButton { 918 - (NSButton*)offTheSideButton {
892 return offTheSideButton_; 919 return offTheSideButton_;
893 } 920 }
894 921
895 - (NSButton*)otherBookmarksButton { 922 - (NSButton*)otherBookmarksButton {
896 return otherBookmarksButton_.get(); 923 return otherBookmarksButton_.get();
897 } 924 }
898 925
899 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node { 926 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node {
900 if (node->is_folder()) 927 if (node->is_folder())
901 return folderImage_; 928 return folderImage_;
902 929
903 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node); 930 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node);
904 if (!favIcon.isNull()) 931 if (!favIcon.isNull())
905 return gfx::SkBitmapToNSImage(favIcon); 932 return gfx::SkBitmapToNSImage(favIcon);
906 933
907 return defaultImage_; 934 return defaultImage_;
908 } 935 }
909 936
910 @end 937 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/bookmark_bar_controller.h ('k') | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698