| OLD | NEW |
| (Empty) | |
| 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. |
| 4 |
| 5 #include "chrome/browser/ui/views/compact_nav/compact_location_bar_view_host.h" |
| 6 |
| 7 #if defined(TOOLKIT_USES_GTK) |
| 8 #include <gtk/gtk.h> |
| 9 #endif |
| 10 |
| 11 #include <algorithm> |
| 12 |
| 13 #include "base/i18n/rtl.h" |
| 14 #include "base/compiler_specific.h" |
| 15 #include "chrome/browser/browser_process.h" |
| 16 #include "chrome/browser/platform_util.h" |
| 17 #include "chrome/browser/ui/browser.h" |
| 18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 19 #include "chrome/browser/ui/view_ids.h" |
| 20 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" |
| 21 #include "chrome/browser/ui/views/compact_nav/compact_location_bar_view.h" |
| 22 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 23 #include "chrome/browser/ui/views/tabs/base_tab_strip.h" |
| 24 #include "content/browser/renderer_host/render_view_host.h" |
| 25 #include "content/browser/tab_contents/tab_contents.h" |
| 26 #include "content/browser/tab_contents/tab_contents_view.h" |
| 27 #include "content/common/notification_source.h" |
| 28 #include "ui/base/animation/slide_animation.h" |
| 29 #include "ui/base/keycodes/keyboard_codes.h" |
| 30 #include "ui/gfx/rect.h" |
| 31 #include "views/controls/scrollbar/native_scroll_bar.h" |
| 32 #include "views/events/event.h" |
| 33 #include "views/focus/external_focus_tracker.h" |
| 34 #include "views/focus/view_storage.h" |
| 35 #include "views/widget/root_view.h" |
| 36 #include "views/widget/widget.h" |
| 37 |
| 38 namespace { |
| 39 |
| 40 const int kHideTimeoutInSeconds = 2; |
| 41 // TODO(stevet): Share this with CompactLocationBarView. This is the actual |
| 42 // height, without the overlap added. |
| 43 const int kCompactNavbarSpacerHeight = 4; |
| 44 const int kBookmarkBarLocationBarOverlap = 2; |
| 45 const int kSpacerLocationbarOverlap = 1; |
| 46 |
| 47 } // namespace |
| 48 |
| 49 // An mouse event observer to detect a mouse click on |
| 50 // BrowserView's content area and hide the location bar. |
| 51 class MouseObserver : public MessageLoopForUI::Observer { |
| 52 public: |
| 53 MouseObserver(CompactLocationBarViewHost* host, BrowserView* view); |
| 54 ~MouseObserver(); |
| 55 |
| 56 // MessageLoopForUI::Observer overrides. |
| 57 #if defined(OS_WIN) |
| 58 virtual void WillProcessMessage(const MSG& native_event) OVERRIDE; |
| 59 virtual void DidProcessMessage(const MSG& native_event) OVERRIDE; |
| 60 #elif defined(OS_LINUX) |
| 61 virtual void WillProcessEvent(GdkEvent* native_event) OVERRIDE; |
| 62 virtual void DidProcessEvent(GdkEvent* native_event) OVERRIDE; |
| 63 #endif |
| 64 |
| 65 void Observe(MessageLoopForUI* loop); |
| 66 void StopObserving(MessageLoopForUI* loop); |
| 67 |
| 68 private: |
| 69 // TODO(mad): would be nice to have this on the views::Event class. |
| 70 bool IsMouseEvent(const views::NativeEvent& native_event); |
| 71 |
| 72 bool IsSameTopLevelWindow(views::NativeEvent native_event); |
| 73 |
| 74 // Tests if the event occurred on the content area, using |
| 75 // root window's coordinates. |
| 76 bool HitContentArea(int x, int y); |
| 77 |
| 78 // Tests if |p| in the root window's coordinate is within the |view|'s bound. |
| 79 bool HitOnScreen(const views::View* view, const gfx::Point& p); |
| 80 |
| 81 CompactLocationBarViewHost* host_; |
| 82 BrowserView* browser_view_; |
| 83 gfx::NativeView top_level_window_; |
| 84 bool observing_; |
| 85 |
| 86 DISALLOW_COPY_AND_ASSIGN(MouseObserver); |
| 87 }; |
| 88 |
| 89 MouseObserver::MouseObserver(CompactLocationBarViewHost* host, |
| 90 BrowserView* view) |
| 91 : host_(host), |
| 92 browser_view_(view), |
| 93 observing_(false) { |
| 94 top_level_window_ = browser_view_->GetWidget()->GetNativeView(); |
| 95 } |
| 96 |
| 97 MouseObserver::~MouseObserver() { |
| 98 StopObserving(MessageLoopForUI::current()); |
| 99 } |
| 100 |
| 101 #if defined(OS_WIN) |
| 102 void MouseObserver::WillProcessMessage(const MSG& native_event) {} |
| 103 void MouseObserver::DidProcessMessage(const MSG& native_event) { |
| 104 #elif defined(OS_LINUX) |
| 105 void MouseObserver::WillProcessEvent(GdkEvent* native_event) {} |
| 106 void MouseObserver::DidProcessEvent(GdkEvent* native_event) { |
| 107 #endif |
| 108 // Hide the location bar iff the mouse is pressed on the |
| 109 // BrowserView's content area. |
| 110 if (!IsMouseEvent(native_event)) |
| 111 return; |
| 112 views::MouseEvent event(native_event); |
| 113 if (event.type() == ui::ET_MOUSE_PRESSED && |
| 114 IsSameTopLevelWindow(native_event) && |
| 115 HitContentArea(event.x(), event.y())) { |
| 116 host_->Hide(true); |
| 117 } |
| 118 } |
| 119 |
| 120 void MouseObserver::Observe(MessageLoopForUI* loop) { |
| 121 if (!observing_) { |
| 122 loop->AddObserver(this); |
| 123 observing_ = true; |
| 124 } |
| 125 } |
| 126 |
| 127 void MouseObserver::StopObserving(MessageLoopForUI* loop) { |
| 128 if (observing_) { |
| 129 loop->RemoveObserver(this); |
| 130 observing_ = false; |
| 131 } |
| 132 } |
| 133 |
| 134 bool MouseObserver::IsMouseEvent(const views::NativeEvent& native_event) { |
| 135 #if defined(OS_WIN) |
| 136 return views::IsClientMouseEvent(native_event) || |
| 137 views::IsNonClientMouseEvent(native_event); |
| 138 #elif defined(OS_LINUX) |
| 139 return native_event->type == GDK_MOTION_NOTIFY || |
| 140 native_event->type == GDK_BUTTON_PRESS || |
| 141 native_event->type == GDK_2BUTTON_PRESS || |
| 142 native_event->type == GDK_3BUTTON_PRESS || |
| 143 native_event->type == GDK_BUTTON_RELEASE; |
| 144 #endif |
| 145 } |
| 146 |
| 147 // TODO(mad): Would be nice to have a NativeEvent -> NativeWindow mapping. |
| 148 // Then, with a GetTopLevel receiving a NativeWindow, we could do this in a |
| 149 // platform independent way. |
| 150 bool MouseObserver::IsSameTopLevelWindow(views::NativeEvent native_event) { |
| 151 #if defined(OS_WIN) |
| 152 return platform_util::GetTopLevel(native_event.hwnd) == top_level_window_; |
| 153 #elif defined(OS_LINUX) |
| 154 return gdk_window_get_toplevel( |
| 155 reinterpret_cast<GdkEventAny*>(native_event)->window) == |
| 156 top_level_window_->window; |
| 157 #endif |
| 158 } |
| 159 |
| 160 bool MouseObserver::HitContentArea(int x, int y) { |
| 161 gfx::Point p(x, y); |
| 162 // First, exclude the location bar as it's shown on top of |
| 163 // content area. |
| 164 if (HitOnScreen(host_->view(), p)) { |
| 165 return false; |
| 166 } |
| 167 // Treat the bookmark as a content area when it in detached mode. |
| 168 if (browser_view_->GetBookmarkBarView()->IsDetached() && |
| 169 browser_view_->IsBookmarkBarVisible() && |
| 170 HitOnScreen(browser_view_->GetBookmarkBarView(), p)) { |
| 171 return true; |
| 172 } |
| 173 if (HitOnScreen(browser_view_->GetContentsView(), p)) { |
| 174 return true; |
| 175 } |
| 176 return false; |
| 177 } |
| 178 |
| 179 bool MouseObserver::HitOnScreen(const views::View* view, const gfx::Point& p) { |
| 180 gfx::Point origin(0, 0); |
| 181 views::View::ConvertPointToScreen(view, &origin); |
| 182 gfx::Rect new_bounds(origin, view->size()); |
| 183 return new_bounds.Contains(p); |
| 184 } |
| 185 |
| 186 //////////////////////////////////////////////////////////////////////////////// |
| 187 // CompactLocationBarViewHost, public: |
| 188 |
| 189 CompactLocationBarViewHost::CompactLocationBarViewHost( |
| 190 BrowserView* browser_view) : DropdownBarHost(browser_view), |
| 191 current_tab_model_index_(-1), |
| 192 is_observing_(false) { |
| 193 auto_hide_timer_.reset(new base::OneShotTimer<CompactLocationBarViewHost>()); |
| 194 mouse_observer_.reset(new MouseObserver(this, browser_view)); |
| 195 CompactLocationBarView* clbv = new CompactLocationBarView(this); |
| 196 Init(clbv, clbv); |
| 197 } |
| 198 |
| 199 CompactLocationBarViewHost::~CompactLocationBarViewHost() { |
| 200 // This may happen if we are destroyed during cleanup. |
| 201 if (browser_view() && browser_view()->browser() && |
| 202 browser_view()->browser()->tabstrip_model()) { |
| 203 browser_view()->browser()->tabstrip_model()->RemoveObserver(this); |
| 204 } |
| 205 } |
| 206 |
| 207 CompactLocationBarView* CompactLocationBarViewHost:: |
| 208 GetCompactLocationBarView() { |
| 209 return static_cast<CompactLocationBarView*>(view()); |
| 210 } |
| 211 |
| 212 void CompactLocationBarViewHost::MoveWindowIfNecessary( |
| 213 const gfx::Rect& selection_rect, |
| 214 bool no_redraw) { |
| 215 // We only move the window if one is currently shown. If we don't check |
| 216 // this, then SetWidgetPosition below will end up making the Location Bar |
| 217 // visible. |
| 218 if (!IsVisible()) |
| 219 return; |
| 220 |
| 221 gfx::Rect new_pos = GetDialogPosition(selection_rect); |
| 222 SetDialogPosition(new_pos, no_redraw); |
| 223 |
| 224 // May need to redraw our frame to accommodate bookmark bar styles. |
| 225 view()->SchedulePaint(); |
| 226 } |
| 227 |
| 228 //////////////////////////////////////////////////////////////////////////////// |
| 229 // LocationBarView::Delegate implementation: |
| 230 TabContentsWrapper* CompactLocationBarViewHost::GetTabContentsWrapper() const { |
| 231 return browser_view()->browser()->GetSelectedTabContentsWrapper(); |
| 232 } |
| 233 |
| 234 InstantController* CompactLocationBarViewHost::GetInstant() { |
| 235 // TODO(stevet): Re-enable instant for compact nav. |
| 236 // return browser_view()->browser()->instant(); |
| 237 return NULL; |
| 238 } |
| 239 |
| 240 void CompactLocationBarViewHost::OnInputInProgress(bool in_progress) { |
| 241 } |
| 242 |
| 243 //////////////////////////////////////////////////////////////////////////////// |
| 244 // CompactLocationBarViewHost, views::AcceleratorTarget implementation: |
| 245 |
| 246 bool CompactLocationBarViewHost::AcceleratorPressed( |
| 247 const views::Accelerator& accelerator) { |
| 248 if (HasFocus()) { |
| 249 DCHECK(view() != NULL); |
| 250 views::FocusManager* focus_manager = view()->GetFocusManager(); |
| 251 if (focus_manager) |
| 252 focus_manager->ClearFocus(); |
| 253 } |
| 254 Hide(true); |
| 255 return false; |
| 256 } |
| 257 |
| 258 //////////////////////////////////////////////////////////////////////////////// |
| 259 // CompactLocationBarViewHost, views::DropdownBarHost implementation: |
| 260 |
| 261 gfx::Rect CompactLocationBarViewHost::GetDialogPosition( |
| 262 gfx::Rect avoid_overlapping_rect) { |
| 263 if (!browser_view() || !browser_view()->browser() || |
| 264 !browser_view()->browser()->tabstrip_model()) { |
| 265 return gfx::Rect(); |
| 266 } |
| 267 DCHECK_GE(current_tab_model_index_, 0); |
| 268 if (!browser_view()->browser()->tabstrip_model()->ContainsIndex( |
| 269 current_tab_model_index_)) { |
| 270 return gfx::Rect(); |
| 271 } |
| 272 |
| 273 gfx::Rect new_pos = GetBoundsUnderTab(current_tab_model_index_); |
| 274 |
| 275 if (animation_offset() > 0) |
| 276 new_pos.Offset(0, std::min(0, -animation_offset())); |
| 277 return new_pos; |
| 278 } |
| 279 |
| 280 void CompactLocationBarViewHost::SetDialogPosition(const gfx::Rect& new_pos, |
| 281 bool no_redraw) { |
| 282 if (new_pos.IsEmpty()) |
| 283 return; |
| 284 |
| 285 // Make sure the window edges are clipped to just the visible region. We need |
| 286 // to do this before changing position, so that when we animate the closure |
| 287 // of it it doesn't look like the window crumbles into the toolbar. |
| 288 UpdateWindowEdges(new_pos); |
| 289 |
| 290 // TODO(oshima): Animate the window clipping like find-bar. |
| 291 SetWidgetPositionNative(new_pos, no_redraw); |
| 292 } |
| 293 |
| 294 //////////////////////////////////////////////////////////////////////////////// |
| 295 // CompactLocationBarViewHost, views::TabStripModelObserver implementation: |
| 296 |
| 297 void CompactLocationBarViewHost::TabClosingAt(TabStripModel* tab_strip_model, |
| 298 TabContentsWrapper* contents, |
| 299 int index) { |
| 300 // TODO(stevet): We need to relocate the compact navigation bar if the |
| 301 // removed tab is not the one we are currently under but the tabstrip does |
| 302 // not have the ideal location yet because the tabs are animating at this |
| 303 // time. Need to investigate the best way to handle this case. |
| 304 Hide(false); |
| 305 } |
| 306 |
| 307 void CompactLocationBarViewHost::TabSelectedAt(TabContentsWrapper* old_contents, |
| 308 TabContentsWrapper* new_contents, |
| 309 int index, |
| 310 bool user_gesture) { |
| 311 current_tab_model_index_ = index; |
| 312 if (new_contents && new_contents->tab_contents()->is_loading()) { |
| 313 Show(false); |
| 314 } else { |
| 315 Hide(false); |
| 316 } |
| 317 } |
| 318 |
| 319 void CompactLocationBarViewHost::TabMoved(TabContentsWrapper* contents, |
| 320 int from_index, |
| 321 int to_index) { |
| 322 if (from_index == current_tab_model_index_) { |
| 323 UpdateOnTabChange(to_index, false); |
| 324 StartAutoHideTimer(); |
| 325 } |
| 326 } |
| 327 |
| 328 void CompactLocationBarViewHost::TabChangedAt(TabContentsWrapper* contents, |
| 329 int index, |
| 330 TabChangeType change_type) { |
| 331 if (IsCurrentTabIndex(index) && change_type == |
| 332 TabStripModelObserver::LOADING_ONLY) { |
| 333 bool was_not_visible = !IsVisible(); |
| 334 TabContents* tab_contents = contents->tab_contents(); |
| 335 Update(tab_contents, false); |
| 336 if (was_not_visible) { |
| 337 if (tab_contents->is_loading()) { |
| 338 // Register to NavigationController LOAD_STOP so that we can autohide |
| 339 // when loading is done. |
| 340 if (!registrar_.IsRegistered(this, NotificationType::LOAD_STOP, |
| 341 Source<NavigationController>(&tab_contents->controller()))) { |
| 342 registrar_.Add(this, NotificationType::LOAD_STOP, |
| 343 Source<NavigationController>(&tab_contents->controller())); |
| 344 } |
| 345 } else { |
| 346 StartAutoHideTimer(); |
| 347 } |
| 348 } |
| 349 } |
| 350 } |
| 351 |
| 352 void CompactLocationBarViewHost::ActiveTabClicked(int index) { |
| 353 UpdateOnTabChange(index, true); |
| 354 } |
| 355 |
| 356 //////////////////////////////////////////////////////////////////////////////// |
| 357 // CompactLocationBarViewHost, NotificationObserver implementation: |
| 358 |
| 359 void CompactLocationBarViewHost::Observe(NotificationType type, |
| 360 const NotificationSource& source, |
| 361 const NotificationDetails& details) { |
| 362 switch (type.value) { |
| 363 case NotificationType::LOAD_STOP: { |
| 364 StartAutoHideTimer(); |
| 365 // This is one shot deal... |
| 366 registrar_.Remove(this, NotificationType::LOAD_STOP, source); |
| 367 break; |
| 368 } |
| 369 default: |
| 370 NOTREACHED(); |
| 371 } |
| 372 } |
| 373 |
| 374 //////////////////////////////////////////////////////////////////////////////// |
| 375 // CompactLocationBarViewHost public: |
| 376 |
| 377 gfx::Rect CompactLocationBarViewHost::GetBoundsUnderTab(int model_index) const { |
| 378 DCHECK(!browser_view()->UseVerticalTabs()); |
| 379 |
| 380 // Get the position of the left-bottom corner of the tab on the |
| 381 // widget. The widget of the tab is same as the widget of the |
| 382 // BrowserView which is the parent of the host. |
| 383 BaseTabStrip* tabstrip = |
| 384 static_cast<BaseTabStrip*>(browser_view()->tabstrip()); |
| 385 gfx::Rect tab_bounds = |
| 386 tabstrip->ideal_bounds(tabstrip->ModelIndexToTabIndex(model_index)); |
| 387 gfx::Rect navbar_bounds(gfx::Point(tab_bounds.x(), tab_bounds.height()), |
| 388 view()->GetPreferredSize()); |
| 389 |
| 390 // Convert our point to be relative to the widget, since the native code that |
| 391 // draws the dropdown is not in the BrowserView coordinate system. |
| 392 gfx::Point origin = navbar_bounds.origin(); |
| 393 views::View::ConvertPointToWidget(browser_view(), &origin); |
| 394 navbar_bounds.set_origin(origin); |
| 395 |
| 396 // For RTL case x() defines tab right corner. |
| 397 if (base::i18n::IsRTL()) |
| 398 navbar_bounds.Offset(tab_bounds.width(), 0); |
| 399 navbar_bounds.Offset(tabstrip->x(), tabstrip->y()); |
| 400 |
| 401 // The compact location bar must be smaller than browser_width. |
| 402 int width = std::min(browser_view()->width(), |
| 403 view()->GetPreferredSize().width()); |
| 404 |
| 405 // Try to center around the tab. |
| 406 navbar_bounds.set_x(browser_view()->GetMirroredXInView( |
| 407 navbar_bounds.x()) - ((width - tab_bounds.width()) / 2)); |
| 408 |
| 409 // Adjust the location to create the illusion that the compact location bar |
| 410 // is a part of the spacer or bookmark bar, depending on which is showing. |
| 411 if (browser_view()->IsBookmarkBarVisible() && |
| 412 !browser_view()->GetBookmarkBarView()->IsDetached()) { |
| 413 // TODO(stevet): Compact location bar does not have right background image |
| 414 // yet, so kBookmarkBarLocationBarOverlap is tentative. Fix this once UI is |
| 415 // settled. This may be entirely replaced by a popup CLB, anyway. |
| 416 navbar_bounds.Offset(0, |
| 417 browser_view()->GetBookmarkBarView()->bounds().height() + |
| 418 kCompactNavbarSpacerHeight - kBookmarkBarLocationBarOverlap); |
| 419 } else { |
| 420 // TODO(stevet): kSpacerLocationbarOverlap is tentative as well, as above. |
| 421 navbar_bounds.Offset(0, kCompactNavbarSpacerHeight - |
| 422 kSpacerLocationbarOverlap); |
| 423 } |
| 424 |
| 425 // TODO(stevet): Adjust to the right if there is an info bar visible. |
| 426 return navbar_bounds.AdjustToFit(browser_view()->bounds()); |
| 427 } |
| 428 |
| 429 void CompactLocationBarViewHost::Update(TabContents* contents, bool animate) { |
| 430 // Don't animate if the bar is already shown. |
| 431 bool showing_in_same_tab = animation()->IsShowing() && IsCurrentTab(contents); |
| 432 current_tab_model_index_ = browser_view()->browser()->active_index(); |
| 433 Hide(false); |
| 434 GetCompactLocationBarView()->Update(contents); |
| 435 Show(animate && !showing_in_same_tab); |
| 436 // If the tab is loading, we must wait for the notification that it is done. |
| 437 if (contents && !contents->is_loading()) { |
| 438 // This will be a NOOP if we have focus. |
| 439 // We never want to stay up, unless we have focus. |
| 440 StartAutoHideTimer(); |
| 441 } |
| 442 } |
| 443 |
| 444 void CompactLocationBarViewHost::UpdateOnTabChange(int model_index, |
| 445 bool animate) { |
| 446 DCHECK_GE(model_index, 0); |
| 447 if (IsCurrentTabIndex(model_index) && animation()->IsShowing()) { |
| 448 return; |
| 449 } |
| 450 current_tab_model_index_ = model_index; |
| 451 Update(browser_view()->browser()->tabstrip_model()-> |
| 452 GetTabContentsAt(model_index)->tab_contents(), animate); |
| 453 } |
| 454 |
| 455 void CompactLocationBarViewHost::StartAutoHideTimer() { |
| 456 if (!IsVisible() || HasFocus()) |
| 457 return; |
| 458 |
| 459 if (auto_hide_timer_->IsRunning()) { |
| 460 // Restart the timer. |
| 461 auto_hide_timer_->Reset(); |
| 462 } else { |
| 463 auto_hide_timer_->Start(base::TimeDelta::FromSeconds(kHideTimeoutInSeconds), |
| 464 this, &CompactLocationBarViewHost::HideCallback); |
| 465 } |
| 466 } |
| 467 |
| 468 void CompactLocationBarViewHost::CancelAutoHideTimer() { |
| 469 auto_hide_timer_->Stop(); |
| 470 } |
| 471 |
| 472 void CompactLocationBarViewHost::SetEnabled(bool enabled) { |
| 473 if (enabled && !is_observing_) { |
| 474 browser_view()->browser()->tabstrip_model()->AddObserver(this); |
| 475 is_observing_ = true; |
| 476 } else { |
| 477 browser_view()->browser()->tabstrip_model()->RemoveObserver(this); |
| 478 is_observing_ = false; |
| 479 } |
| 480 } |
| 481 |
| 482 void CompactLocationBarViewHost::Show(bool animate) { |
| 483 CancelAutoHideTimer(); |
| 484 mouse_observer_->Observe(MessageLoopForUI::current()); |
| 485 DropdownBarHost::Show(animate); |
| 486 host()->Show(); |
| 487 } |
| 488 |
| 489 void CompactLocationBarViewHost::Hide(bool animate) { |
| 490 CancelAutoHideTimer(); |
| 491 mouse_observer_->StopObserving(MessageLoopForUI::current()); |
| 492 host()->Hide(); |
| 493 DropdownBarHost::Hide(animate); |
| 494 } |
| 495 |
| 496 //////////////////////////////////////////////////////////////////////////////// |
| 497 // CompactLocationBarViewHost private: |
| 498 bool CompactLocationBarViewHost::HasFocus() { |
| 499 DCHECK(view() != NULL); |
| 500 views::FocusManager* focus_manager = view()->GetFocusManager(); |
| 501 return focus_manager && view()->Contains(focus_manager->GetFocusedView()); |
| 502 } |
| 503 |
| 504 void CompactLocationBarViewHost::HideCallback() { |
| 505 if (IsVisible() && !HasFocus()) |
| 506 Hide(true); |
| 507 } |
| 508 |
| 509 bool CompactLocationBarViewHost::IsCurrentTabIndex(int index) { |
| 510 return current_tab_model_index_ == index; |
| 511 } |
| 512 |
| 513 bool CompactLocationBarViewHost::IsCurrentTab(TabContents* contents) { |
| 514 TabStripModel* tab_strip_model = browser_view()->browser()->tabstrip_model(); |
| 515 return tab_strip_model->ContainsIndex(current_tab_model_index_) && |
| 516 tab_strip_model->GetTabContentsAt(current_tab_model_index_)-> |
| 517 tab_contents() == contents; |
| 518 } |
| OLD | NEW |