1// Copyright (c) 2012 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 "ui/base/accelerators/accelerator_manager.h"
6
7#include <algorithm>
8
9#include "base/logging.h"
10
11namespace ui {
12
13AcceleratorManager::AcceleratorManager() {
14}
15
16AcceleratorManager::~AcceleratorManager() {
17}
18
19void AcceleratorManager::Register(const Accelerator& accelerator,
20                                  HandlerPriority priority,
21                                  AcceleratorTarget* target) {
22  AcceleratorTargetList& targets = accelerators_[accelerator].second;
23  DCHECK(std::find(targets.begin(), targets.end(), target) == targets.end())
24      << "Registering the same target multiple times";
25
26  // All priority accelerators go to the front of the line.
27  if (priority) {
28    DCHECK(!accelerators_[accelerator].first)
29        << "Only one _priority_ handler can be registered";
30    targets.push_front(target);
31    // Mark that we have a priority accelerator at the front.
32    accelerators_[accelerator].first = true;
33    return;
34  }
35
36  // We are registering a normal priority handler. If no priority accelerator
37  // handler has been registered before us, just add the new handler to the
38  // front. Otherwise, register it after the first (only) priority handler.
39  if (!accelerators_[accelerator].first)
40    targets.push_front(target);
41  else
42    targets.insert(++targets.begin(), target);
43}
44
45void AcceleratorManager::Unregister(const Accelerator& accelerator,
46                                    AcceleratorTarget* target) {
47  AcceleratorMap::iterator map_iter = accelerators_.find(accelerator);
48  if (map_iter == accelerators_.end()) {
49    NOTREACHED() << "Unregistering non-existing accelerator";
50    return;
51  }
52
53  AcceleratorTargetList* targets = &map_iter->second.second;
54  AcceleratorTargetList::iterator target_iter =
55      std::find(targets->begin(), targets->end(), target);
56  if (target_iter == targets->end()) {
57    NOTREACHED() << "Unregistering accelerator for wrong target";
58    return;
59  }
60
61  // Check to see if we have a priority handler and whether we are removing it.
62  if (accelerators_[accelerator].first && target_iter == targets->begin()) {
63    // We've are taking the priority accelerator away, flip the priority flag.
64    accelerators_[accelerator].first = false;
65  }
66
67  targets->erase(target_iter);
68}
69
70void AcceleratorManager::UnregisterAll(AcceleratorTarget* target) {
71  for (AcceleratorMap::iterator map_iter = accelerators_.begin();
72       map_iter != accelerators_.end(); ++map_iter) {
73    AcceleratorTargetList* targets = &map_iter->second.second;
74    targets->remove(target);
75  }
76}
77
78bool AcceleratorManager::Process(const Accelerator& accelerator) {
79  bool result = false;
80  AcceleratorMap::iterator map_iter = accelerators_.find(accelerator);
81  if (map_iter != accelerators_.end()) {
82    // We have to copy the target list here, because an AcceleratorPressed
83    // event handler may modify the list.
84    AcceleratorTargetList targets(map_iter->second.second);
85    for (AcceleratorTargetList::iterator iter = targets.begin();
86         iter != targets.end(); ++iter) {
87      if ((*iter)->CanHandleAccelerators() &&
88          (*iter)->AcceleratorPressed(accelerator)) {
89        result = true;
90        break;
91      }
92    }
93  }
94  return result;
95}
96
97AcceleratorTarget* AcceleratorManager::GetCurrentTarget(
98    const Accelerator& accelerator) const {
99  AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator);
100  if (map_iter == accelerators_.end() || map_iter->second.second.empty())
101    return NULL;
102  return map_iter->second.second.front();
103}
104
105bool AcceleratorManager::HasPriorityHandler(
106    const Accelerator& accelerator) const {
107  AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator);
108  if (map_iter == accelerators_.end() || map_iter->second.second.empty())
109    return false;
110
111  // Check if we have a priority handler. If not, there's no more work needed.
112  if (!map_iter->second.first)
113    return false;
114
115  // If the priority handler says it cannot handle the accelerator, we must not
116  // count it as one.
117  return map_iter->second.second.front()->CanHandleAccelerators();
118}
119
120}  // namespace ui
121