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

Side by Side Diff: chrome/browser/ui/views/compact_nav/compact_location_bar_view_host.cc

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

Powered by Google App Engine
This is Rietveld 408576698