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/ime/input_method_base.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "ui/base/ime/input_method_delegate.h"
11#include "ui/base/ime/input_method_observer.h"
12#include "ui/base/ime/text_input_client.h"
13#include "ui/base/ime/text_input_focus_manager.h"
14#include "ui/base/ui_base_switches_util.h"
15#include "ui/events/event.h"
16
17namespace ui {
18
19InputMethodBase::InputMethodBase()
20  : delegate_(NULL),
21    text_input_client_(NULL),
22    system_toplevel_window_focused_(false) {
23}
24
25InputMethodBase::~InputMethodBase() {
26  FOR_EACH_OBSERVER(InputMethodObserver,
27                    observer_list_,
28                    OnInputMethodDestroyed(this));
29}
30
31void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) {
32  delegate_ = delegate;
33}
34
35void InputMethodBase::Init(bool focused) {
36  if (focused)
37    OnFocus();
38}
39
40void InputMethodBase::OnFocus() {
41  DCHECK(!system_toplevel_window_focused_);
42  system_toplevel_window_focused_ = true;
43}
44
45void InputMethodBase::OnBlur() {
46  DCHECK(system_toplevel_window_focused_);
47  system_toplevel_window_focused_ = false;
48}
49
50void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) {
51  SetFocusedTextInputClientInternal(client);
52}
53
54void InputMethodBase::DetachTextInputClient(TextInputClient* client) {
55  if (text_input_client_ != client)
56    return;
57  SetFocusedTextInputClientInternal(NULL);
58}
59
60TextInputClient* InputMethodBase::GetTextInputClient() const {
61  if (switches::IsTextInputFocusManagerEnabled())
62    return TextInputFocusManager::GetInstance()->GetFocusedTextInputClient();
63
64  return system_toplevel_window_focused_ ? text_input_client_ : NULL;
65}
66
67void InputMethodBase::OnTextInputTypeChanged(const TextInputClient* client) {
68  if (!IsTextInputClientFocused(client))
69    return;
70  NotifyTextInputStateChanged(client);
71}
72
73TextInputType InputMethodBase::GetTextInputType() const {
74  TextInputClient* client = GetTextInputClient();
75  return client ? client->GetTextInputType() : TEXT_INPUT_TYPE_NONE;
76}
77
78TextInputMode InputMethodBase::GetTextInputMode() const {
79  TextInputClient* client = GetTextInputClient();
80  return client ? client->GetTextInputMode() : TEXT_INPUT_MODE_DEFAULT;
81}
82
83bool InputMethodBase::CanComposeInline() const {
84  TextInputClient* client = GetTextInputClient();
85  return client ? client->CanComposeInline() : true;
86}
87
88void InputMethodBase::ShowImeIfNeeded() {
89  FOR_EACH_OBSERVER(InputMethodObserver, observer_list_, OnShowImeIfNeeded());
90}
91
92void InputMethodBase::AddObserver(InputMethodObserver* observer) {
93  observer_list_.AddObserver(observer);
94}
95
96void InputMethodBase::RemoveObserver(InputMethodObserver* observer) {
97  observer_list_.RemoveObserver(observer);
98}
99
100bool InputMethodBase::IsTextInputClientFocused(const TextInputClient* client) {
101  return client && (client == GetTextInputClient());
102}
103
104bool InputMethodBase::IsTextInputTypeNone() const {
105  return GetTextInputType() == TEXT_INPUT_TYPE_NONE;
106}
107
108void InputMethodBase::OnInputMethodChanged() const {
109  TextInputClient* client = GetTextInputClient();
110  if (!IsTextInputTypeNone())
111    client->OnInputMethodChanged();
112}
113
114bool InputMethodBase::DispatchKeyEventPostIME(
115    const ui::KeyEvent& event) const {
116  if (!delegate_)
117    return false;
118
119  return delegate_->DispatchKeyEventPostIME(event);
120}
121
122void InputMethodBase::NotifyTextInputStateChanged(
123    const TextInputClient* client) {
124  FOR_EACH_OBSERVER(InputMethodObserver,
125                    observer_list_,
126                    OnTextInputStateChanged(client));
127}
128
129void InputMethodBase::SetFocusedTextInputClientInternal(
130    TextInputClient* client) {
131  if (switches::IsTextInputFocusManagerEnabled())
132    return;
133
134  TextInputClient* old = text_input_client_;
135  if (old == client)
136    return;
137  OnWillChangeFocusedClient(old, client);
138  text_input_client_ = client;  // NULL allowed.
139  OnDidChangeFocusedClient(old, client);
140  NotifyTextInputStateChanged(text_input_client_);
141}
142
143void InputMethodBase::OnCandidateWindowShown() {
144  base::MessageLoop::current()->PostTask(
145      FROM_HERE,
146      base::Bind(&InputMethodBase::CandidateWindowShownCallback, AsWeakPtr()));
147}
148
149void InputMethodBase::OnCandidateWindowUpdated() {
150  base::MessageLoop::current()->PostTask(
151      FROM_HERE,
152      base::Bind(&InputMethodBase::CandidateWindowUpdatedCallback,
153                 AsWeakPtr()));
154}
155
156void InputMethodBase::OnCandidateWindowHidden() {
157  base::MessageLoop::current()->PostTask(
158      FROM_HERE,
159      base::Bind(&InputMethodBase::CandidateWindowHiddenCallback, AsWeakPtr()));
160}
161
162void InputMethodBase::CandidateWindowShownCallback() {
163  if (TextInputClient* text_input_client = GetTextInputClient())
164    text_input_client->OnCandidateWindowShown();
165}
166
167void InputMethodBase::CandidateWindowUpdatedCallback() {
168  if (TextInputClient* text_input_client = GetTextInputClient())
169    text_input_client->OnCandidateWindowUpdated();
170}
171
172void InputMethodBase::CandidateWindowHiddenCallback() {
173  if (TextInputClient* text_input_client = GetTextInputClient())
174    text_input_client->OnCandidateWindowHidden();
175}
176
177}  // namespace ui
178