diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-02 21:24:22 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-02 21:24:22 +0000 |
commit | 72fc4b91fd45c00004a69790b59ba4917ba117ed (patch) | |
tree | 908a0e34be29a3206f88cac0064d43ec00db7ab9 /ui/views/focus/focus_search.cc | |
parent | d89ff811f8c0e5033a38273979d6b367ed057b0e (diff) | |
download | chromium_src-72fc4b91fd45c00004a69790b59ba4917ba117ed.zip chromium_src-72fc4b91fd45c00004a69790b59ba4917ba117ed.tar.gz chromium_src-72fc4b91fd45c00004a69790b59ba4917ba117ed.tar.bz2 |
Copy more focus manager into V2. Comment out a bunch of stuff and add stub impls of methods with TODOs so that it builds.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6334062
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73513 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/views/focus/focus_search.cc')
-rw-r--r-- | ui/views/focus/focus_search.cc | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/ui/views/focus/focus_search.cc b/ui/views/focus/focus_search.cc new file mode 100644 index 0000000..2050b1d --- /dev/null +++ b/ui/views/focus/focus_search.cc @@ -0,0 +1,274 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "ui/views/focus/focus_manager.h" +#include "ui/views/focus/focus_search.h" +#include "ui/views/view.h" + +namespace ui { + +FocusSearch::FocusSearch(View* root, bool cycle, bool accessibility_mode) + : root_(root), + cycle_(cycle), + accessibility_mode_(accessibility_mode) { +} + +View* FocusSearch::FindNextFocusableView(View* starting_view, + bool reverse, + Direction direction, + bool check_starting_view, + FocusTraversable** focus_traversable, + View** focus_traversable_view) { + *focus_traversable = NULL; + *focus_traversable_view = NULL; + + if (root_->child_count() == 0) { + NOTREACHED(); + // Nothing to focus on here. + return NULL; + } + + View* initial_starting_view = starting_view; + int starting_view_group = -1; + if (starting_view) + starting_view_group = starting_view->group(); + + if (!starting_view) { + // Default to the first/last child + starting_view = + reverse ? + root_->GetChildViewAt(root_->child_count() - 1) : + root_->GetChildViewAt(0); + // If there was no starting view, then the one we select is a potential + // focus candidate. + check_starting_view = true; + } else { + // The starting view should be a direct or indirect child of the root. + DCHECK(root_->Contains(starting_view)); + } + + View* v = NULL; + if (!reverse) { + v = FindNextFocusableViewImpl(starting_view, check_starting_view, + true, + (direction == DOWN) ? true : false, + starting_view_group, + focus_traversable, + focus_traversable_view); + } else { + // If the starting view is focusable, we don't want to go down, as we are + // traversing the view hierarchy tree bottom-up. + bool can_go_down = (direction == DOWN) && !IsFocusable(starting_view); + v = FindPreviousFocusableViewImpl(starting_view, check_starting_view, + true, + can_go_down, + starting_view_group, + focus_traversable, + focus_traversable_view); + } + + // Don't set the focus to something outside of this view hierarchy. + if (v && v != root_ && !root_->Contains(v)) + v = NULL; + + // If |cycle_| is true, prefer to keep cycling rather than returning NULL. + if (cycle_ && !v && initial_starting_view) { + v = FindNextFocusableView(NULL, reverse, direction, check_starting_view, + focus_traversable, focus_traversable_view); + DCHECK(IsFocusable(v)); + return v; + } + + // Doing some sanity checks. + if (v) { + DCHECK(IsFocusable(v)); + return v; + } + if (*focus_traversable) { + DCHECK(*focus_traversable_view); + return NULL; + } + // Nothing found. + return NULL; +} + +bool FocusSearch::IsViewFocusableCandidate(View* v, int skip_group_id) { + return IsFocusable(v) && + (v->IsGroupFocusTraversable() || skip_group_id == -1 || + v->group() != skip_group_id); +} + +bool FocusSearch::IsFocusable(View* v) { + if (accessibility_mode_) + return v && v->IsAccessibilityFocusableInRootView(); + + return v && v->IsFocusableInRootView(); +} + +View* FocusSearch::FindSelectedViewForGroup(View* view) { + // No group for that view. + if (view->IsGroupFocusTraversable() || view->group() == -1) + return view; + + View* selected_view = view->GetSelectedViewForGroup(view->group()); + if (selected_view) + return selected_view; + + // No view selected for that group, default to the specified view. + return view; +} + +View* FocusSearch::GetParent(View* v) { + return root_->Contains(v) ? v->parent() : NULL; +} + +// Strategy for finding the next focusable view: +// - keep going down the first child, stop when you find a focusable view or +// a focus traversable view (in that case return it) or when you reach a view +// with no children. +// - go to the right sibling and start the search from there (by invoking +// FindNextFocusableViewImpl on that view). +// - if the view has no right sibling, go up the parents until you find a parent +// with a right sibling and start the search from there. +View* FocusSearch::FindNextFocusableViewImpl( + View* starting_view, + bool check_starting_view, + bool can_go_up, + bool can_go_down, + int skip_group_id, + FocusTraversable** focus_traversable, + View** focus_traversable_view) { + if (check_starting_view) { + if (IsViewFocusableCandidate(starting_view, skip_group_id)) { + View* v = FindSelectedViewForGroup(starting_view); + // The selected view might not be focusable (if it is disabled for + // example). + if (IsFocusable(v)) + return v; + } + + *focus_traversable = starting_view->GetFocusTraversable(); + if (*focus_traversable) { + *focus_traversable_view = starting_view; + return NULL; + } + } + + // First let's try the left child. + if (can_go_down) { + if (starting_view->child_count() > 0) { + View* v = FindNextFocusableViewImpl(starting_view->GetChildViewAt(0), + true, false, true, skip_group_id, + focus_traversable, + focus_traversable_view); + if (v || *focus_traversable) + return v; + } + } + + // Then try the right sibling. + View* sibling = starting_view->GetNextFocusableView(); + if (sibling) { + View* v = FindNextFocusableViewImpl(sibling, + true, false, true, skip_group_id, + focus_traversable, + focus_traversable_view); + if (v || *focus_traversable) + return v; + } + + // Then go up to the parent sibling. + if (can_go_up) { + View* parent = GetParent(starting_view); + while (parent) { + sibling = parent->GetNextFocusableView(); + if (sibling) { + return FindNextFocusableViewImpl(sibling, + true, true, true, + skip_group_id, + focus_traversable, + focus_traversable_view); + } + parent = GetParent(parent); + } + } + + // We found nothing. + return NULL; +} + +// Strategy for finding the previous focusable view: +// - keep going down on the right until you reach a view with no children, if it +// it is a good candidate return it. +// - start the search on the left sibling. +// - if there are no left sibling, start the search on the parent (without going +// down). +View* FocusSearch::FindPreviousFocusableViewImpl( + View* starting_view, + bool check_starting_view, + bool can_go_up, + bool can_go_down, + int skip_group_id, + FocusTraversable** focus_traversable, + View** focus_traversable_view) { + // Let's go down and right as much as we can. + if (can_go_down) { + // Before we go into the direct children, we have to check if this view has + // a FocusTraversable. + *focus_traversable = starting_view->GetFocusTraversable(); + if (*focus_traversable) { + *focus_traversable_view = starting_view; + return NULL; + } + + if (starting_view->child_count() > 0) { + View* view = + starting_view->GetChildViewAt(starting_view->child_count() - 1); + View* v = FindPreviousFocusableViewImpl(view, true, false, true, + skip_group_id, + focus_traversable, + focus_traversable_view); + if (v || *focus_traversable) + return v; + } + } + + // Then look at this view. Here, we do not need to see if the view has + // a FocusTraversable, since we do not want to go down any more. + if (check_starting_view && + IsViewFocusableCandidate(starting_view, skip_group_id)) { + View* v = FindSelectedViewForGroup(starting_view); + // The selected view might not be focusable (if it is disabled for + // example). + if (IsFocusable(v)) + return v; + } + + // Then try the left sibling. + View* sibling = starting_view->GetPreviousFocusableView(); + if (sibling) { + return FindPreviousFocusableViewImpl(sibling, + true, true, true, + skip_group_id, + focus_traversable, + focus_traversable_view); + } + + // Then go up the parent. + if (can_go_up) { + View* parent = GetParent(starting_view); + if (parent) + return FindPreviousFocusableViewImpl(parent, + true, true, false, + skip_group_id, + focus_traversable, + focus_traversable_view); + } + + // We found nothing. + return NULL; +} + +} // namespace ui |