Home | History | Annotate | Download | only in cocoa
      1 // Copyright (c) 2010 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 "chrome/browser/ui/cocoa/view_id_util.h"
      6 
      7 #import <Cocoa/Cocoa.h>
      8 
      9 #include <map>
     10 #include <utility>
     11 
     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"
     16 
     17 namespace {
     18 
     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;
     23 
     24 static base::LazyInstance<ViewIDMap> g_view_id_map(base::LINKER_INITIALIZED);
     25 
     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;
     31 
     32   for (NSView* subview in [view subviews]) {
     33     NSView* result = FindViewWithID(subview, viewID);
     34     if (result != nil)
     35       return result;
     36   }
     37   return nil;
     38 }
     39 
     40 }  // anonymous namespace
     41 
     42 namespace view_id_util {
     43 
     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;
     50 }
     51 
     52 void UnsetID(NSView* view) {
     53   DCHECK(view);
     54   g_view_id_map.Get().erase(view);
     55 }
     56 
     57 NSView* GetView(NSWindow* window, ViewID viewID) {
     58   DCHECK(viewID != VIEW_ID_NONE);
     59   DCHECK(window);
     60 
     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   }
     75 
     76   return FindViewWithID([[window contentView] superview], viewID);
     77 }
     78 
     79 }  // namespace view_id_util
     80 
     81 @implementation NSView (ViewID)
     82 
     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;
     87 }
     88 
     89 @end
     90