Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / view_id_util.mm
blob6dd19ada9446ddcd3a0825dc8d061254d930b300
1 // Copyright (c) 2011 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.
5 #import "chrome/browser/ui/cocoa/view_id_util.h"
7 #import <Cocoa/Cocoa.h>
9 #include <map>
10 #include <utility>
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
17 namespace {
19 // TODO(suzhe): After migrating to Mac OS X 10.6, we may use Objective-C's new
20 // "Associative References" feature to attach the ViewID to the view directly
21 // rather than using a separated map.
22 typedef std::map<NSView*, ViewID> ViewIDMap;
24 static base::LazyInstance<ViewIDMap> g_view_id_map = LAZY_INSTANCE_INITIALIZER;
26 // Returns the view's nearest descendant (including itself) with a specific
27 // ViewID, or nil if no subview has that ViewID.
28 NSView* FindViewWithID(NSView* view, ViewID viewID) {
29   if ([view viewID] == viewID)
30     return view;
32   for (NSView* subview in [view subviews]) {
33     NSView* result = FindViewWithID(subview, viewID);
34     if (result != nil)
35       return result;
36   }
37   return nil;
40 }  // anonymous namespace
42 namespace view_id_util {
44 void SetID(NSView* view, ViewID viewID) {
45   DCHECK(view);
46   DCHECK(viewID != VIEW_ID_NONE);
47   // We handle VIEW_ID_TAB_0 to VIEW_ID_TAB_LAST in GetView() function directly.
48   DCHECK(!((viewID >= VIEW_ID_TAB_0) && (viewID <= VIEW_ID_TAB_LAST)));
49   g_view_id_map.Get()[view] = viewID;
52 void UnsetID(NSView* view) {
53   DCHECK(view);
54   g_view_id_map.Get().erase(view);
57 NSView* GetView(NSWindow* window, ViewID viewID) {
58   DCHECK(viewID != VIEW_ID_NONE);
59   DCHECK(window);
61   // As tabs can be created, destroyed or rearranged dynamically, we handle them
62   // here specially.
63   if (viewID >= VIEW_ID_TAB_0 && viewID <= VIEW_ID_TAB_LAST) {
64     BrowserWindowController* windowController = [window windowController];
65     DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
66     TabStripController* tabStripController =
67         [windowController tabStripController];
68     DCHECK(tabStripController);
69     NSUInteger count = [tabStripController viewsCount];
70     DCHECK(count);
71     NSUInteger index =
72         (viewID == VIEW_ID_TAB_LAST ? count - 1 : viewID - VIEW_ID_TAB_0);
73     return index < count ? [tabStripController viewAtIndex:index] : nil;
74   }
76   return FindViewWithID([[window contentView] superview], viewID);
79 }  // namespace view_id_util
81 @implementation NSView (ViewID)
83 - (ViewID)viewID {
84   ViewIDMap* map = g_view_id_map.Pointer();
85   ViewIDMap::const_iterator iter = map->find(self);
86   return iter != map->end() ? iter->second : VIEW_ID_NONE;
89 - (NSView*)ancestorWithViewID:(ViewID)viewID {
90   NSView* ancestor = self;
91   while (ancestor && [ancestor viewID] != viewID)
92     ancestor = [ancestor superview];
93   return ancestor;
96 @end