#include "ui/base/accelerators/accelerator_manager.h"
#include <ostream>
#include "base/check.h"
#include "base/containers/contains.h"
namespace ui {
AcceleratorManager::AcceleratorManager() = default;
AcceleratorManager::~AcceleratorManager() = default;
void AcceleratorManager::Register(
const std::vector<ui::Accelerator>& accelerators,
HandlerPriority priority,
AcceleratorTarget* target) {
DCHECK(target);
for (const ui::Accelerator& accelerator : accelerators) {
accelerators_.GetOrInsertDefault(accelerator)
.RegisterWithPriority(target, priority);
}
}
void AcceleratorManager::Unregister(const Accelerator& accelerator,
AcceleratorTarget* target) {
DCHECK(target);
AcceleratorTargetInfo* target_info = accelerators_.Find(accelerator);
DCHECK(target_info) << "Unregistering non-existing accelerator";
const bool was_registered = target_info->Unregister(target);
DCHECK(was_registered) << "Unregistering accelerator for wrong target";
if (!target_info->HasTargets())
accelerators_.Erase(accelerator);
}
void AcceleratorManager::UnregisterAll(AcceleratorTarget* target) {
for (auto map_iter = accelerators_.begin();
map_iter != accelerators_.end();) {
AcceleratorTargetInfo& target_info = map_iter->second;
const bool was_registered = target_info.Unregister(target);
if (was_registered && !target_info.HasTargets()) {
Accelerator key_to_remove = map_iter->first;
++map_iter;
accelerators_.Erase(key_to_remove);
continue;
}
DCHECK(target_info.HasTargets());
++map_iter;
}
}
bool AcceleratorManager::IsRegistered(const Accelerator& accelerator) const {
const AcceleratorTargetInfo* target_info = accelerators_.Find(accelerator);
DCHECK(!target_info || target_info->HasTargets());
return target_info != nullptr;
}
bool AcceleratorManager::Process(const Accelerator& accelerator) {
const AcceleratorTargetInfo* target_info = accelerators_.Find(accelerator);
if (!target_info)
return false;
DCHECK(target_info->HasTargets());
AcceleratorTargetInfo target_info_copy(*target_info);
return target_info_copy.TryProcess(accelerator);
}
bool AcceleratorManager::HasPriorityHandler(
const Accelerator& accelerator) const {
const AcceleratorTargetInfo* target_info = accelerators_.Find(accelerator);
return target_info && target_info->HasPriorityHandler();
}
AcceleratorManager::AcceleratorTargetInfo::AcceleratorTargetInfo() = default;
AcceleratorManager::AcceleratorTargetInfo::AcceleratorTargetInfo(
const AcceleratorManager::AcceleratorTargetInfo& other) = default;
AcceleratorManager::AcceleratorTargetInfo&
AcceleratorManager::AcceleratorTargetInfo::operator=(
const AcceleratorManager::AcceleratorTargetInfo& other) = default;
AcceleratorManager::AcceleratorTargetInfo::~AcceleratorTargetInfo() = default;
void AcceleratorManager::AcceleratorTargetInfo::RegisterWithPriority(
AcceleratorTarget* target,
HandlerPriority priority) {
DCHECK(!Contains(target)) << "Registering the same target multiple times";
if (priority == kHighPriority) {
DCHECK(!has_priority_handler_)
<< "Only one high-priority handler can be registered";
targets_.push_front(target);
has_priority_handler_ = true;
} else {
if (has_priority_handler_) {
DCHECK(!targets_.empty());
targets_.insert(++targets_.begin(), target);
} else {
targets_.push_front(target);
}
}
DCHECK(!targets_.empty());
}
bool AcceleratorManager::AcceleratorTargetInfo::Unregister(
AcceleratorTarget* target) {
DCHECK(!targets_.empty());
if (targets_.front() == target)
has_priority_handler_ = false;
auto iter = std::find(targets_.begin(), targets_.end(), target);
if (iter != targets_.end()) {
targets_.erase(iter);
return true;
}
return false;
}
bool AcceleratorManager::AcceleratorTargetInfo::TryProcess(
const Accelerator& accelerator) {
DCHECK(!targets_.empty());
for (AcceleratorTarget* target : targets_) {
if (target->CanHandleAccelerators() &&
target->AcceleratorPressed(accelerator)) {
return true;
}
}
return false;
}
bool AcceleratorManager::AcceleratorTargetInfo::HasPriorityHandler() const {
DCHECK(!targets_.empty());
return has_priority_handler_ && targets_.front()->CanHandleAccelerators();
}
bool AcceleratorManager::AcceleratorTargetInfo::Contains(
AcceleratorTarget* target) const {
DCHECK(target);
return base::Contains(targets_, target);
}
}