Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / input_method / candidate_window_controller_impl.cc
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 "chrome/browser/chromeos/input_method/candidate_window_controller_impl.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "ash/ime/infolist_window.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/wm/window_util.h"
14 #include "base/logging.h"
15 #include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
16 #include "ui/gfx/screen.h"
17 #include "ui/views/widget/widget.h"
18
19 namespace chromeos {
20 namespace input_method {
21
22 namespace {
23
24 }  // namespace
25
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()));
33 }
34
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);
40   }
41 }
42
43 void CandidateWindowControllerImpl::InitCandidateWindowView() {
44   if (candidate_window_view_)
45     return;
46
47   aura::Window* active_window = ash::wm::GetActiveWindow();
48   candidate_window_view_ =
49       new ash::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);
57   widget->Show();
58   FOR_EACH_OBSERVER(CandidateWindowController::Observer, observers_,
59                     CandidateWindowOpened());
60 }
61
62 void CandidateWindowControllerImpl::Hide() {
63   if (candidate_window_view_)
64     candidate_window_view_->GetWidget()->Close();
65   if (infolist_window_)
66     infolist_window_->HideImmediately();
67 }
68
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();
78
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";
83     return;
84   }
85
86   cursor_bounds_ = cursor_bounds;
87   composition_head_ = composition_head;
88
89   // Remember the cursor bounds.
90   if (candidate_window_view_)
91     candidate_window_view_->SetCursorBounds(cursor_bounds, composition_head);
92
93   // Mode indicator controller also needs the cursor bounds.
94   mode_indicator_controller_->SetCursorBounds(cursor_bounds);
95 }
96
97 void CandidateWindowControllerImpl::FocusStateChanged(bool is_focused) {
98   mode_indicator_controller_->FocusStateChanged(is_focused);
99 }
100
101 void CandidateWindowControllerImpl::UpdateLookupTable(
102     const ui::CandidateWindow& candidate_window,
103     bool visible) {
104   // If it's not visible, hide the lookup table and return.
105   if (!visible) {
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();
112     return;
113   }
114
115   if (!candidate_window_view_)
116     InitCandidateWindowView();
117   candidate_window_view_->UpdateCandidates(candidate_window);
118   candidate_window_view_->ShowLookupTable();
119
120   bool has_highlighted = false;
121   std::vector<ui::InfolistEntry> infolist_entries;
122   candidate_window.GetInfolistEntries(&infolist_entries, &has_highlighted);
123
124   // If there is no change, just return.
125   if (latest_infolist_entries_ == infolist_entries)
126     return;
127
128   latest_infolist_entries_ = infolist_entries;
129
130   if (infolist_entries.empty()) {
131     if (infolist_window_)
132       infolist_window_->HideImmediately();
133     return;
134   }
135
136   // Highlight moves out of the infolist entries.
137   if (!has_highlighted) {
138     if (infolist_window_)
139       infolist_window_->HideWithDelay();
140     return;
141   }
142
143   if (infolist_window_) {
144     infolist_window_->Relayout(infolist_entries);
145   } else {
146     infolist_window_ = new ash::ime::InfolistWindow(
147         candidate_window_view_, infolist_entries);
148     infolist_window_->InitWidget();
149     infolist_window_->GetWidget()->AddObserver(this);
150   }
151   infolist_window_->ShowWithDelay();
152 }
153
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();
160     return;
161   }
162   if (!candidate_window_view_)
163     InitCandidateWindowView();
164   candidate_window_view_->UpdatePreeditText(text);
165   candidate_window_view_->ShowPreeditText();
166 }
167
168 void CandidateWindowControllerImpl::OnCandidateCommitted(int index) {
169   FOR_EACH_OBSERVER(CandidateWindowController::Observer, observers_,
170                     CandidateClicked(index));
171 }
172
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());
184   }
185 }
186
187 void CandidateWindowControllerImpl::AddObserver(
188     CandidateWindowController::Observer* observer) {
189   observers_.AddObserver(observer);
190 }
191
192 void CandidateWindowControllerImpl::RemoveObserver(
193     CandidateWindowController::Observer* observer) {
194   observers_.RemoveObserver(observer);
195 }
196
197 }  // namespace input_method
198 }  // namespace chromeos