diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 00:34:05 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 00:34:05 +0000 |
commit | 2362e4fe2905ab75d3230ebc3e307ae53e2b8362 (patch) | |
tree | e6d88357a2021811e0e354f618247217be8bb3da /views/focus/focus_manager.h | |
parent | db23ac3e713dc17509b2b15d3ee634968da45715 (diff) | |
download | chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.zip chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.tar.gz chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.tar.bz2 |
Move src/chrome/views to src/views. RS=darin http://crbug.com/11387
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15604 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/focus/focus_manager.h')
-rw-r--r-- | views/focus/focus_manager.h | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/views/focus/focus_manager.h b/views/focus/focus_manager.h new file mode 100644 index 0000000..8c33036 --- /dev/null +++ b/views/focus/focus_manager.h @@ -0,0 +1,343 @@ +// Copyright (c) 2006-2008 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. + +#ifndef VIEWS_FOCUS_FOCUS_MANAGER_H_ +#define VIEWS_FOCUS_FOCUS_MANAGER_H_ + +#include "base/basictypes.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif +#include <vector> +#include <map> + +#include "views/accelerator.h" + +// The FocusManager class is used to handle focus traversal, store/restore +// focused views and handle keyboard accelerators. +// +// There are 2 types of focus: +// - the native focus, which is the focus that an HWND has. +// - the view focus, which is the focus that a views::View has. +// +// Each native view must register with their Focus Manager so the focus manager +// gets notified when they are focused (and keeps track of the native focus) and +// as well so that the tab key events can be intercepted. +// They can provide when they register a View that is kept in synch in term of +// focus. This is used in NativeControl for example, where a View wraps an +// actual native window. +// This is already done for you if you subclass the NativeControl class or if +// you use the HWNDView class. +// +// When creating a top window, if it derives from WidgetWin, the +// |has_own_focus_manager| of the Init method lets you specify whether that +// window should have its own focus manager (so focus traversal stays confined +// in that window). If you are not deriving from WidgetWin or one of its +// derived classes (Window, FramelessWindow, ConstrainedWindow), you must +// create a FocusManager when the window is created (it is automatically deleted +// when the window is destroyed). +// +// The FocusTraversable interface exposes the methods a class should implement +// in order to be able to be focus traversed when tab key is pressed. +// RootViews implement FocusTraversable. +// The FocusManager contains a top FocusTraversable instance, which is the top +// RootView. +// +// If you just use views, then the focus traversal is handled for you by the +// RootView. The default traversal order is the order in which the views have +// been added to their container. You can modify this order by using the View +// method SetNextFocusableView(). +// +// If you are embedding a native view containing a nested RootView (for example +// by adding a NativeControl that contains a WidgetWin as its native +// component), then you need to: +// - override the View::GetFocusTraversable() method in your outter component. +// It should return the RootView of the inner component. This is used when +// the focus traversal traverse down the focus hierarchy to enter the nested +// RootView. In the example mentioned above, the NativeControl overrides +// GetFocusTraversable() and returns hwnd_view_container_->GetRootView(). +// - call RootView::SetFocusTraversableParent() on the nested RootView and point +// it to the outter RootView. This is used when the focus goes out of the +// nested RootView. In the example: +// hwnd_view_container_->GetRootView()->SetFocusTraversableParent( +// native_control->GetRootView()); +// - call RootView::SetFocusTraversableParentView() on the nested RootView with +// the parent view that directly contains the native window. This is needed +// when traversing up from the nested RootView to know which view to start +// with when going to the next/previous view. +// In our example: +// hwnd_view_container_->GetRootView()->SetFocusTraversableParent( +// native_control); +// +// Note that FocusTraversable do not have to be RootViews: TabContents is +// FocusTraversable. + +namespace views { + +class View; +class RootView; + +// The FocusTraversable interface is used by components that want to process +// focus traversal events (due to Tab/Shift-Tab key events). +class FocusTraversable { + public: + // The direction in which the focus traversal is going. + // TODO (jcampan): add support for lateral (left, right) focus traversal. The + // goal is to switch to focusable views on the same level when using the arrow + // keys (ala Windows: in a dialog box, arrow keys typically move between the + // dialog OK, Cancel buttons). + enum Direction { + UP = 0, + DOWN + }; + + // Should find the next view that should be focused and return it. If a + // FocusTraversable is found while searching for the focusable view, NULL + // should be returned, focus_traversable should be set to the FocusTraversable + // and focus_traversable_view should be set to the view associated with the + // FocusTraversable. + // This call should return NULL if the end of the focus loop is reached. + // - |starting_view| is the view that should be used as the starting point + // when looking for the previous/next view. It may be NULL (in which case + // the first/last view should be used depending if normal/reverse). + // - |reverse| whether we should find the next (reverse is false) or the + // previous (reverse is true) view. + // - |direction| specifies whether we are traversing down (meaning we should + // look into child views) or traversing up (don't look at child views). + // - |dont_loop| if true specifies that if there is a loop in the focus + // hierarchy, we should keep traversing after the last view of the loop. + // - |focus_traversable| is set to the focus traversable that should be + // traversed if one is found (in which case the call returns NULL). + // - |focus_traversable_view| is set to the view associated with the + // FocusTraversable set in the previous parameter (it is used as the + // starting view when looking for the next focusable view). + + virtual View* FindNextFocusableView(View* starting_view, + bool reverse, + Direction direction, + bool dont_loop, + FocusTraversable** focus_traversable, + View** focus_traversable_view) = 0; + + // Should return the parent FocusTraversable. + // The top RootView which is the top FocusTraversable returns NULL. + virtual FocusTraversable* GetFocusTraversableParent() = 0; + + // This should return the View this FocusTraversable belongs to. + // It is used when walking up the view hierarchy tree to find which view + // should be used as the starting view for finding the next/previous view. + virtual View* GetFocusTraversableParentView() = 0; +}; + +// The KeystrokeListener interface is used by components (such as the +// ExternalTabContainer class) which need a crack at handling all +// keystrokes. +class KeystrokeListener { + public: + // If this returns true, then the component handled the keystroke and ate + // it. +#if defined(OS_WIN) + virtual bool ProcessKeyStroke(HWND window, UINT message, WPARAM wparam, + LPARAM lparam) = 0; +#endif +}; + +// This interface should be implemented by classes that want to be notified when +// the focus is about to change. See the Add/RemoveFocusChangeListener methods. +class FocusChangeListener { + public: + virtual void FocusWillChange(View* focused_before, View* focused_now) = 0; +}; + +class FocusManager { + public: +#if defined(OS_WIN) + // Creates a FocusManager for the specified window. Top level windows + // must invoked this when created. + // The RootView specified should be the top RootView of the window. + // This also invokes InstallFocusSubclass. + static FocusManager* CreateFocusManager(HWND window, RootView* root_view); + + // Subclasses the specified window. The subclassed window procedure listens + // for WM_SETFOCUS notification and keeps the FocusManager's focus owner + // property in sync. + // It's not necessary to explicitly invoke Uninstall, it's automatically done + // when the window is destroyed and Uninstall wasn't invoked. + static void InstallFocusSubclass(HWND window, View* view); + + // Uninstalls the window subclass installed by InstallFocusSubclass. + static void UninstallFocusSubclass(HWND window); + + static FocusManager* GetFocusManager(HWND window); + + // Message handlers (for messages received from registered windows). + // Should return true if the message should be forwarded to the window + // original proc function, false otherwise. + bool OnSetFocus(HWND window); + bool OnNCDestroy(HWND window); + // OnKeyDown covers WM_KEYDOWN and WM_SYSKEYDOWN. + bool OnKeyDown(HWND window, + UINT message, + WPARAM wparam, + LPARAM lparam); + bool OnKeyUp(HWND window, + UINT message, + WPARAM wparam, + LPARAM lparam); + // OnPostActivate is called after WM_ACTIVATE has been propagated to the + // DefWindowProc. + bool OnPostActivate(HWND window, int activation_state, int minimized_state); +#endif + + // Returns true is the specified is part of the hierarchy of the window + // associated with this FocusManager. + bool ContainsView(View* view); + + // Advances the focus (backward if reverse is true). + void AdvanceFocus(bool reverse); + + // The FocusManager is handling the selected view for the RootView. + View* GetFocusedView() const { return focused_view_; } + void SetFocusedView(View* view); + + // Clears the focused view. The window associated with the top root view gets + // the native focus (so we still get keyboard events). + void ClearFocus(); + + // Clears the HWND that has the focus by focusing the HWND from the top + // RootView (so we still get keyboard events). + // Note that this does not change the currently focused view. + void ClearHWNDFocus(); + +#if defined(OS_WIN) + // Focus the specified |hwnd| without changing the focused view. + void FocusHWND(HWND hwnd); +#endif + + // Validates the focused view, clearing it if the window it belongs too is not + // attached to the window hierarchy anymore. + void ValidateFocusedView(); + +#if defined(OS_WIN) + // Returns the view associated with the specified window if any. + // If |look_in_parents| is true, it goes up the window parents until it find + // a view. + static View* GetViewForWindow(HWND window, bool look_in_parents); +#endif + + // Stores and restores the focused view. Used when the window becomes + // active/inactive. + void StoreFocusedView(); + void RestoreFocusedView(); + + // Clears the stored focused view. + void ClearStoredFocusedView(); + + // Returns the FocusManager of the parent window of the window that is the + // root of this FocusManager. This is useful with ConstrainedWindows that have + // their own FocusManager and need to return focus to the browser when closed. + FocusManager* GetParentFocusManager() const; + + // Register a keyboard accelerator for the specified target. If an + // AcceleratorTarget is already registered for that accelerator, it is + // returned. + // Note that we are currently limited to accelerators that are either: + // - a key combination including Ctrl or Alt + // - the escape key + // - the enter key + // - any F key (F1, F2, F3 ...) + // - any browser specific keys (as available on special keyboards) + AcceleratorTarget* RegisterAccelerator(const Accelerator& accelerator, + AcceleratorTarget* target); + + // Unregister the specified keyboard accelerator for the specified target. + void UnregisterAccelerator(const Accelerator& accelerator, + AcceleratorTarget* target); + + // Unregister all keyboard accelerator for the specified target. + void UnregisterAccelerators(AcceleratorTarget* target); + + // Activate the target associated with the specified accelerator if any. + // Returns true if an accelerator was activated. + bool ProcessAccelerator(const Accelerator& accelerator); + + // Called by a RootView when a view within its hierarchy is removed from its + // parent. This will only be called by a RootView in a hierarchy of Widgets + // that this FocusManager is attached to the parent Widget of. + void ViewRemoved(View* parent, View* removed); + + void AddKeystrokeListener(KeystrokeListener* listener); + void RemoveKeystrokeListener(KeystrokeListener* listener); + + // Adds/removes a listener. The FocusChangeListener is notified every time + // the focused view is about to change. + void AddFocusChangeListener(FocusChangeListener* listener); + void RemoveFocusChangeListener(FocusChangeListener* listener); + + // Returns the AcceleratorTarget that should be activated for the specified + // keyboard accelerator, or NULL if no view is registered for that keyboard + // accelerator. + // TODO(finnur): http://b/1307173 Make this private once the bug is fixed. + AcceleratorTarget* GetTargetForAccelerator( + const Accelerator& accelerator) const; + + private: +#if defined(OS_WIN) + explicit FocusManager(HWND root, RootView* root_view); +#endif + ~FocusManager(); + + // Returns the next focusable view. + View* GetNextFocusableView(View* starting_view, bool reverse, bool dont_loop); + + // Returns the last view of the focus traversal hierarchy. + View* FindLastFocusableView(); + + // Returns the focusable view found in the FocusTraversable specified starting + // at the specified view. This traverses down along the FocusTraversable + // hierarchy. + // Returns NULL if no focusable view were found. + View* FindFocusableView(FocusTraversable* focus_traversable, + View* starting_view, + bool reverse, + bool dont_loop); + + // The RootView of the window associated with this FocusManager. + RootView* top_root_view_; + + // The view that currently is focused. + View* focused_view_; + + // The storage id used in the ViewStorage to store/restore the view that last + // had focus. + int stored_focused_view_storage_id_; + +#if defined(OS_WIN) + // The window associated with this focus manager. + HWND root_; +#endif + + // Used to allow setting the focus on an HWND without changing the currently + // focused view. + bool ignore_set_focus_msg_; + + // The accelerators and associated targets. + typedef std::map<Accelerator, AcceleratorTarget*> AcceleratorMap; + AcceleratorMap accelerators_; + + // The list of registered keystroke listeners + typedef std::vector<KeystrokeListener*> KeystrokeListenerList; + KeystrokeListenerList keystroke_listeners_; + + // The list of registered FocusChange listeners. + typedef std::vector<FocusChangeListener*> FocusChangeListenerList; + FocusChangeListenerList focus_change_listeners_; + + DISALLOW_COPY_AND_ASSIGN(FocusManager); +}; + +} // namespace views + +#endif // VIEWS_FOCUS_FOCUS_MANAGER_H_ |