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