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.
5 #include "chrome/browser/chromeos/input_method/candidate_window_controller_impl.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/window_util.h"
13 #include "base/logging.h"
14 #include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
15 #include "ui/chromeos/ime/infolist_window.h"
16 #include "ui/gfx/screen.h"
17 #include "ui/views/widget/widget.h"
20 namespace input_method
{
26 CandidateWindowControllerImpl::CandidateWindowControllerImpl()
27 : candidate_window_view_(NULL
),
28 infolist_window_(NULL
) {
29 IMEBridge::Get()->SetCandidateWindowHandler(this);
30 // Create the mode indicator controller.
31 mode_indicator_controller_
.reset(
32 new ModeIndicatorController(InputMethodManager::Get()));
35 CandidateWindowControllerImpl::~CandidateWindowControllerImpl() {
36 IMEBridge::Get()->SetCandidateWindowHandler(NULL
);
37 if (candidate_window_view_
) {
38 candidate_window_view_
->RemoveObserver(this);
39 candidate_window_view_
->GetWidget()->RemoveObserver(this);
43 void CandidateWindowControllerImpl::InitCandidateWindowView() {
44 if (candidate_window_view_
)
47 aura::Window
* active_window
= ash::wm::GetActiveWindow();
48 candidate_window_view_
=
49 new ui::ime::CandidateWindowView(ash::Shell::GetContainer(
50 active_window
? active_window
->GetRootWindow()
51 : ash::Shell::GetTargetRootWindow(),
52 ash::kShellWindowId_SettingBubbleContainer
));
53 candidate_window_view_
->AddObserver(this);
54 candidate_window_view_
->SetCursorBounds(cursor_bounds_
, composition_head_
);
55 views::Widget
* widget
= candidate_window_view_
->InitWidget();
56 widget
->AddObserver(this);
58 FOR_EACH_OBSERVER(CandidateWindowController::Observer
, observers_
,
59 CandidateWindowOpened());
62 void CandidateWindowControllerImpl::Hide() {
63 if (candidate_window_view_
)
64 candidate_window_view_
->GetWidget()->Close();
66 infolist_window_
->HideImmediately();
69 void CandidateWindowControllerImpl::SetCursorBounds(
70 const gfx::Rect
& cursor_bounds
,
71 const gfx::Rect
& composition_head
) {
72 // A workaround for http://crosbug.com/6460. We should ignore very short Y
73 // move to prevent the window from shaking up and down.
74 const int kKeepPositionThreshold
= 2; // px
75 gfx::Rect last_bounds
;
76 if (candidate_window_view_
)
77 last_bounds
= candidate_window_view_
->GetAnchorRect();
79 const int delta_y
= abs(last_bounds
.y() - cursor_bounds
.y());
80 if ((last_bounds
.x() == cursor_bounds
.x()) &&
81 (delta_y
<= kKeepPositionThreshold
)) {
82 DVLOG(1) << "Ignored set_cursor_bounds signal to prevent window shake";
86 cursor_bounds_
= cursor_bounds
;
87 composition_head_
= composition_head
;
89 // Remember the cursor bounds.
90 if (candidate_window_view_
)
91 candidate_window_view_
->SetCursorBounds(cursor_bounds
, composition_head
);
93 // Mode indicator controller also needs the cursor bounds.
94 mode_indicator_controller_
->SetCursorBounds(cursor_bounds
);
97 void CandidateWindowControllerImpl::FocusStateChanged(bool is_focused
) {
98 mode_indicator_controller_
->FocusStateChanged(is_focused
);
101 void CandidateWindowControllerImpl::UpdateLookupTable(
102 const ui::CandidateWindow
& candidate_window
,
104 // If it's not visible, hide the lookup table and return.
106 if (candidate_window_view_
)
107 candidate_window_view_
->HideLookupTable();
108 if (infolist_window_
)
109 infolist_window_
->HideImmediately();
110 // TODO(nona): Introduce unittests for crbug.com/170036.
111 latest_infolist_entries_
.clear();
115 if (!candidate_window_view_
)
116 InitCandidateWindowView();
117 candidate_window_view_
->UpdateCandidates(candidate_window
);
118 candidate_window_view_
->ShowLookupTable();
120 bool has_highlighted
= false;
121 std::vector
<ui::InfolistEntry
> infolist_entries
;
122 candidate_window
.GetInfolistEntries(&infolist_entries
, &has_highlighted
);
124 // If there is no change, just return.
125 if (latest_infolist_entries_
== infolist_entries
)
128 latest_infolist_entries_
= infolist_entries
;
130 if (infolist_entries
.empty()) {
131 if (infolist_window_
)
132 infolist_window_
->HideImmediately();
136 // Highlight moves out of the infolist entries.
137 if (!has_highlighted
) {
138 if (infolist_window_
)
139 infolist_window_
->HideWithDelay();
143 if (infolist_window_
) {
144 infolist_window_
->Relayout(infolist_entries
);
146 infolist_window_
= new ui::ime::InfolistWindow(
147 candidate_window_view_
, infolist_entries
);
148 infolist_window_
->InitWidget();
149 infolist_window_
->GetWidget()->AddObserver(this);
151 infolist_window_
->ShowWithDelay();
154 void CandidateWindowControllerImpl::UpdatePreeditText(
155 const base::string16
& text
, unsigned int cursor
, bool visible
) {
156 // If it's not visible, hide the preedit text and return.
157 if (!visible
|| text
.empty()) {
158 if (candidate_window_view_
)
159 candidate_window_view_
->HidePreeditText();
162 if (!candidate_window_view_
)
163 InitCandidateWindowView();
164 candidate_window_view_
->UpdatePreeditText(text
);
165 candidate_window_view_
->ShowPreeditText();
168 void CandidateWindowControllerImpl::OnCandidateCommitted(int index
) {
169 FOR_EACH_OBSERVER(CandidateWindowController::Observer
, observers_
,
170 CandidateClicked(index
));
173 void CandidateWindowControllerImpl::OnWidgetClosing(views::Widget
* widget
) {
174 if (infolist_window_
&& widget
== infolist_window_
->GetWidget()) {
175 widget
->RemoveObserver(this);
176 infolist_window_
= NULL
;
177 } else if (candidate_window_view_
&&
178 widget
== candidate_window_view_
->GetWidget()) {
179 widget
->RemoveObserver(this);
180 candidate_window_view_
->RemoveObserver(this);
181 candidate_window_view_
= NULL
;
182 FOR_EACH_OBSERVER(CandidateWindowController::Observer
, observers_
,
183 CandidateWindowClosed());
187 void CandidateWindowControllerImpl::AddObserver(
188 CandidateWindowController::Observer
* observer
) {
189 observers_
.AddObserver(observer
);
192 void CandidateWindowControllerImpl::RemoveObserver(
193 CandidateWindowController::Observer
* observer
) {
194 observers_
.RemoveObserver(observer
);
197 } // namespace input_method
198 } // namespace chromeos