Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: views/controls/textfield/textfield_views_model.cc

Issue 6675005: Integrate the new input method API for Views into Chromium. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "views/controls/textfield/textfield_views_model.h" 5 #include "views/controls/textfield/textfield_views_model.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/i18n/break_iterator.h" 9 #include "base/i18n/break_iterator.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "ui/base/clipboard/clipboard.h" 12 #include "ui/base/clipboard/clipboard.h"
13 #include "ui/base/clipboard/scoped_clipboard_writer.h" 13 #include "ui/base/clipboard/scoped_clipboard_writer.h"
14 #include "ui/base/range/range.h" 14 #include "ui/base/range/range.h"
15 #include "ui/gfx/font.h" 15 #include "ui/gfx/font.h"
16 #include "views/controls/textfield/textfield.h" 16 #include "views/controls/textfield/textfield.h"
17 #include "views/views_delegate.h" 17 #include "views/views_delegate.h"
18 18
19 namespace views { 19 namespace views {
20 20
21 TextfieldViewsModel::TextfieldViewsModel() 21 TextfieldViewsModel::Delegate::~Delegate() {
22 : cursor_pos_(0), 22 }
23 selection_begin_(0), 23
24 TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
25 : delegate_(delegate),
26 cursor_pos_(0),
27 selection_start_(0),
28 composition_start_(0),
29 composition_end_(0),
24 is_password_(false) { 30 is_password_(false) {
25 } 31 }
26 32
27 TextfieldViewsModel::~TextfieldViewsModel() { 33 TextfieldViewsModel::~TextfieldViewsModel() {
28 } 34 }
29 35
30 void TextfieldViewsModel::GetFragments(TextFragments* fragments) const { 36 void TextfieldViewsModel::GetFragments(TextFragments* fragments) const {
31 DCHECK(fragments); 37 DCHECK(fragments);
32 fragments->clear(); 38 fragments->clear();
33 if (HasSelection()) { 39 if (HasCompositionText()) {
34 int begin = std::min(selection_begin_, cursor_pos_); 40 if (composition_start_)
35 int end = std::max(selection_begin_, cursor_pos_); 41 fragments->push_back(TextFragment(0, composition_start_, false, false));
36 if (begin != 0) { 42
37 fragments->push_back(TextFragment(0, begin, false)); 43 size_t selection_start = std::min(selection_start_, cursor_pos_);
44 size_t selection_end = std::max(selection_start_, cursor_pos_);
45 size_t last_end = composition_start_;
46 for (ui::CompositionUnderlines::const_iterator i =
47 composition_underlines_.begin();
48 i != composition_underlines_.end(); ++i) {
49 size_t fragment_start =
50 std::min(i->start_offset, i->end_offset) + composition_start_;
51 size_t fragment_end =
52 std::max(i->start_offset, i->end_offset) + composition_start_;
53
54 fragment_start = std::max(last_end, fragment_start);
55 fragment_end = std::min(fragment_end, composition_end_);
56
57 if (fragment_start >= fragment_end)
58 break;
59
60 // If there is no selection, then just add a text fragment with underline.
61 if (selection_start == selection_end) {
62 if (last_end < fragment_start) {
63 fragments->push_back(
64 TextFragment(last_end, fragment_start, false, false));
65 }
66 fragments->push_back(
67 TextFragment(fragment_start, fragment_end, false, true));
68 last_end = fragment_end;
69 continue;
70 }
71
72 size_t end = std::min(fragment_start, selection_start);
73 if (last_end < end)
74 fragments->push_back(TextFragment(last_end, end, false, false));
75
76 last_end = fragment_end;
77
78 if (selection_start < fragment_start) {
79 end = std::min(selection_end, fragment_start);
80 fragments->push_back(TextFragment(selection_start, end, true, false));
81 selection_start = end;
82 } else if (selection_start > fragment_start) {
83 end = std::min(selection_start, fragment_end);
84 fragments->push_back(TextFragment(fragment_start, end, false, true));
85 fragment_start = end;
86 if (fragment_start == fragment_end)
87 continue;
88 }
89
90 if (fragment_start < selection_end) {
91 DCHECK_EQ(selection_start, fragment_start);
92 end = std::min(fragment_end, selection_end);
93 fragments->push_back(TextFragment(fragment_start, end, true, true));
94 fragment_start = end;
95 selection_start = end;
96 if (fragment_start == fragment_end)
97 continue;
98 }
99
100 DCHECK_LT(fragment_start, fragment_end);
101 fragments->push_back(
102 TextFragment(fragment_start, fragment_end, false, true));
38 } 103 }
39 fragments->push_back(TextFragment(begin, end, true)); 104
40 int len = text_.length(); 105 if (last_end < composition_end_) {
41 if (end != len) { 106 if (selection_start < selection_end) {
42 fragments->push_back(TextFragment(end, len, false)); 107 DCHECK_LE(last_end, selection_start);
108 if (last_end < selection_start) {
109 fragments->push_back(
110 TextFragment(last_end, selection_start, false, false));
111 }
112 fragments->push_back(
113 TextFragment(selection_start, selection_end, true, false));
114 if (selection_end < composition_end_) {
115 fragments->push_back(
116 TextFragment(selection_end, composition_end_, false, false));
117 }
118 } else {
119 fragments->push_back(
120 TextFragment(last_end, composition_end_, false, false));
121 }
43 } 122 }
123
124 size_t len = text_.length();
125 if (composition_end_ < len)
126 fragments->push_back(TextFragment(composition_end_, len, false, false));
127 } else if (HasSelection()) {
128 size_t start = std::min(selection_start_, cursor_pos_);
129 size_t end = std::max(selection_start_, cursor_pos_);
130 if (start)
131 fragments->push_back(TextFragment(0, start, false, false));
132 fragments->push_back(TextFragment(start, end, true, false));
133 size_t len = text_.length();
134 if (end != len)
135 fragments->push_back(TextFragment(end, len, false, false));
44 } else { 136 } else {
45 fragments->push_back(TextFragment(0, text_.length(), false)); 137 fragments->push_back(TextFragment(0, text_.length(), false, false));
46 } 138 }
47 } 139 }
48 140
49 bool TextfieldViewsModel::SetText(const string16& text) { 141 bool TextfieldViewsModel::SetText(const string16& text) {
50 bool changed = text_ != text; 142 bool changed = false;
51 if (changed) { 143 if (HasCompositionText()) {
144 ConfirmCompositionText();
145 changed = true;
146 }
147 if (text_ != text) {
52 text_ = text; 148 text_ = text;
53 if (cursor_pos_ > text.length()) { 149 if (cursor_pos_ > text.length()) {
54 cursor_pos_ = text.length(); 150 cursor_pos_ = text.length();
55 } 151 }
152 changed = true;
56 } 153 }
57 ClearSelection(); 154 ClearSelection();
58 return changed; 155 return changed;
59 } 156 }
60 157
61 void TextfieldViewsModel::Insert(char16 c) { 158 void TextfieldViewsModel::InsertText(const string16& text) {
62 if (HasSelection()) 159 if (HasCompositionText())
160 ClearCompositionText();
161 else if (HasSelection())
63 DeleteSelection(); 162 DeleteSelection();
64 text_.insert(cursor_pos_, 1, c); 163 text_.insert(cursor_pos_, text);
65 cursor_pos_++; 164 cursor_pos_ += text.size();
66 ClearSelection(); 165 ClearSelection();
67 } 166 }
68 167
69 void TextfieldViewsModel::Replace(char16 c) { 168 void TextfieldViewsModel::ReplaceText(const string16& text) {
70 if (!HasSelection()) 169 if (HasCompositionText())
71 Delete(); 170 ClearCompositionText();
72 Insert(c); 171 else if (!HasSelection())
172 SelectRange(ui::Range(cursor_pos_, cursor_pos_ + text.length()));
173 InsertText(text);
73 } 174 }
74 175
75 void TextfieldViewsModel::Append(const string16& text) { 176 void TextfieldViewsModel::Append(const string16& text) {
177 if (HasCompositionText())
178 ConfirmCompositionText();
76 text_ += text; 179 text_ += text;
77 } 180 }
78 181
79 bool TextfieldViewsModel::Delete() { 182 bool TextfieldViewsModel::Delete() {
183 if (HasCompositionText()) {
184 ClearCompositionText();
185 return true;
186 }
80 if (HasSelection()) { 187 if (HasSelection()) {
81 DeleteSelection(); 188 DeleteSelection();
82 return true; 189 return true;
83 } else if (text_.length() > cursor_pos_) { 190 }
191 if (text_.length() > cursor_pos_) {
84 text_.erase(cursor_pos_, 1); 192 text_.erase(cursor_pos_, 1);
85 return true; 193 return true;
86 } 194 }
87 return false; 195 return false;
88 } 196 }
89 197
90 bool TextfieldViewsModel::Backspace() { 198 bool TextfieldViewsModel::Backspace() {
199 if (HasCompositionText()) {
200 ClearCompositionText();
201 return true;
202 }
91 if (HasSelection()) { 203 if (HasSelection()) {
92 DeleteSelection(); 204 DeleteSelection();
93 return true; 205 return true;
94 } else if (cursor_pos_ > 0) { 206 }
207 if (cursor_pos_ > 0) {
95 cursor_pos_--; 208 cursor_pos_--;
96 text_.erase(cursor_pos_, 1); 209 text_.erase(cursor_pos_, 1);
97 ClearSelection(); 210 ClearSelection();
98 return true; 211 return true;
99 } 212 }
100 return false; 213 return false;
101 } 214 }
102 215
103 void TextfieldViewsModel::MoveCursorLeft(bool select) { 216 void TextfieldViewsModel::MoveCursorLeft(bool select) {
217 if (HasCompositionText())
218 ConfirmCompositionText();
104 // TODO(oshima): support BIDI 219 // TODO(oshima): support BIDI
105 if (select) { 220 if (select) {
106 if (cursor_pos_ > 0) 221 if (cursor_pos_ > 0)
107 cursor_pos_--; 222 cursor_pos_--;
108 } else { 223 } else {
109 if (HasSelection()) 224 if (HasSelection())
110 cursor_pos_ = std::min(cursor_pos_, selection_begin_); 225 cursor_pos_ = std::min(cursor_pos_, selection_start_);
111 else if (cursor_pos_ > 0) 226 else if (cursor_pos_ > 0)
112 cursor_pos_--; 227 cursor_pos_--;
113 ClearSelection(); 228 ClearSelection();
114 } 229 }
115 } 230 }
116 231
117 void TextfieldViewsModel::MoveCursorRight(bool select) { 232 void TextfieldViewsModel::MoveCursorRight(bool select) {
233 if (HasCompositionText())
234 ConfirmCompositionText();
118 // TODO(oshima): support BIDI 235 // TODO(oshima): support BIDI
119 if (select) { 236 if (select) {
120 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1); 237 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
121 } else { 238 } else {
122 if (HasSelection()) 239 if (HasSelection())
123 cursor_pos_ = std::max(cursor_pos_, selection_begin_); 240 cursor_pos_ = std::max(cursor_pos_, selection_start_);
124 else 241 else
125 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1); 242 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
126 ClearSelection(); 243 ClearSelection();
127 } 244 }
128 } 245 }
129 246
130 void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) { 247 void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) {
248 if (HasCompositionText())
249 ConfirmCompositionText();
131 // Notes: We always iterate words from the begining. 250 // Notes: We always iterate words from the begining.
132 // This is probably fast enough for our usage, but we may 251 // This is probably fast enough for our usage, but we may
133 // want to modify WordIterator so that it can start from the 252 // want to modify WordIterator so that it can start from the
134 // middle of string and advance backwards. 253 // middle of string and advance backwards.
135 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD); 254 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD);
136 bool success = iter.Init(); 255 bool success = iter.Init();
137 DCHECK(success); 256 DCHECK(success);
138 if (!success) 257 if (!success)
139 return; 258 return;
140 int last = 0; 259 int last = 0;
(...skipping 14 matching lines...) Expand all
155 } 274 }
156 } 275 }
157 } 276 }
158 277
159 cursor_pos_ = last; 278 cursor_pos_ = last;
160 if (!select) 279 if (!select)
161 ClearSelection(); 280 ClearSelection();
162 } 281 }
163 282
164 void TextfieldViewsModel::MoveCursorToNextWord(bool select) { 283 void TextfieldViewsModel::MoveCursorToNextWord(bool select) {
284 if (HasCompositionText())
285 ConfirmCompositionText();
165 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD); 286 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD);
166 bool success = iter.Init(); 287 bool success = iter.Init();
167 DCHECK(success); 288 DCHECK(success);
168 if (!success) 289 if (!success)
169 return; 290 return;
170 size_t pos = 0; 291 size_t pos = 0;
171 while (iter.Advance()) { 292 while (iter.Advance()) {
172 pos = iter.pos(); 293 pos = iter.pos();
173 if (iter.IsWord() && pos > cursor_pos_) { 294 if (iter.IsWord() && pos > cursor_pos_) {
174 break; 295 break;
175 } 296 }
176 } 297 }
177 cursor_pos_ = pos; 298 cursor_pos_ = pos;
178 if (!select) 299 if (!select)
179 ClearSelection(); 300 ClearSelection();
180 } 301 }
181 302
182 void TextfieldViewsModel::MoveCursorToStart(bool select) { 303 void TextfieldViewsModel::MoveCursorToHome(bool select) {
304 if (HasCompositionText())
305 ConfirmCompositionText();
183 cursor_pos_ = 0; 306 cursor_pos_ = 0;
184 if (!select) 307 if (!select)
185 ClearSelection(); 308 ClearSelection();
186 } 309 }
187 310
188 void TextfieldViewsModel::MoveCursorToEnd(bool select) { 311 void TextfieldViewsModel::MoveCursorToEnd(bool select) {
312 if (HasCompositionText())
313 ConfirmCompositionText();
189 cursor_pos_ = text_.length(); 314 cursor_pos_ = text_.length();
190 if (!select) 315 if (!select)
191 ClearSelection(); 316 ClearSelection();
192 } 317 }
193 318
194 bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) { 319 bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) {
320 if (HasCompositionText())
321 ConfirmCompositionText();
195 bool cursor_changed = false; 322 bool cursor_changed = false;
196 if (cursor_pos_ != pos) { 323 if (cursor_pos_ != pos) {
197 cursor_pos_ = pos; 324 cursor_pos_ = pos;
198 cursor_changed = true; 325 cursor_changed = true;
199 } 326 }
200 if (!select) 327 if (!select)
201 ClearSelection(); 328 ClearSelection();
202 return cursor_changed; 329 return cursor_changed;
203 } 330 }
204 331
205 gfx::Rect TextfieldViewsModel::GetCursorBounds(const gfx::Font& font) const { 332 gfx::Rect TextfieldViewsModel::GetCursorBounds(const gfx::Font& font) const {
206 string16 text = GetVisibleText(); 333 string16 text = GetVisibleText();
207 int x = font.GetStringWidth(text.substr(0U, cursor_pos_)); 334 int x = font.GetStringWidth(text.substr(0U, cursor_pos_));
208 int h = font.GetHeight(); 335 int h = font.GetHeight();
209 DCHECK(x >= 0); 336 DCHECK(x >= 0);
210 if (text.length() == cursor_pos_) { 337 if (text.length() == cursor_pos_) {
211 return gfx::Rect(x, 0, 0, h); 338 return gfx::Rect(x, 0, 0, h);
212 } else { 339 } else {
213 int x_end = font.GetStringWidth(text.substr(0U, cursor_pos_ + 1U)); 340 int x_end = font.GetStringWidth(text.substr(0U, cursor_pos_ + 1U));
214 return gfx::Rect(x, 0, x_end - x, h); 341 return gfx::Rect(x, 0, x_end - x, h);
215 } 342 }
216 } 343 }
217 344
218 string16 TextfieldViewsModel::GetSelectedText() const { 345 string16 TextfieldViewsModel::GetSelectedText() const {
219 return text_.substr( 346 return text_.substr(
220 std::min(cursor_pos_, selection_begin_), 347 std::min(cursor_pos_, selection_start_),
221 std::abs(static_cast<long>(cursor_pos_ - selection_begin_))); 348 std::abs(static_cast<long>(cursor_pos_ - selection_start_)));
222 } 349 }
223 350
224 void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const { 351 void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const {
225 *range = ui::Range(selection_begin_, cursor_pos_); 352 *range = ui::Range(selection_start_, cursor_pos_);
226 } 353 }
227 354
228 void TextfieldViewsModel::SelectRange(const ui::Range& range) { 355 void TextfieldViewsModel::SelectRange(const ui::Range& range) {
229 selection_begin_ = GetSafePosition(range.start()); 356 if (HasCompositionText())
357 ConfirmCompositionText();
358 selection_start_ = GetSafePosition(range.start());
230 cursor_pos_ = GetSafePosition(range.end()); 359 cursor_pos_ = GetSafePosition(range.end());
231 } 360 }
232 361
233 void TextfieldViewsModel::SelectAll() { 362 void TextfieldViewsModel::SelectAll() {
363 if (HasCompositionText())
364 ConfirmCompositionText();
234 // SelectAll selects towards the end. 365 // SelectAll selects towards the end.
235 cursor_pos_ = text_.length(); 366 cursor_pos_ = text_.length();
236 selection_begin_ = 0; 367 selection_start_ = 0;
237 } 368 }
238 369
239 void TextfieldViewsModel::SelectWord() { 370 void TextfieldViewsModel::SelectWord() {
240 // First we setup selection_begin_ and cursor_pos_. There are so many cases 371 if (HasCompositionText())
372 ConfirmCompositionText();
373 // First we setup selection_start_ and cursor_pos_. There are so many cases
241 // because we try to emulate what select-word looks like in a gtk textfield. 374 // because we try to emulate what select-word looks like in a gtk textfield.
242 // See associated testcase for different cases. 375 // See associated testcase for different cases.
243 if (cursor_pos_ > 0 && cursor_pos_ < text_.length()) { 376 if (cursor_pos_ > 0 && cursor_pos_ < text_.length()) {
244 if (isalnum(text_[cursor_pos_])) { 377 if (isalnum(text_[cursor_pos_])) {
245 selection_begin_ = cursor_pos_; 378 selection_start_ = cursor_pos_;
246 cursor_pos_++; 379 cursor_pos_++;
247 } else 380 } else
248 selection_begin_ = cursor_pos_ - 1; 381 selection_start_ = cursor_pos_ - 1;
249 } else if (cursor_pos_ == 0) { 382 } else if (cursor_pos_ == 0) {
250 selection_begin_ = cursor_pos_; 383 selection_start_ = cursor_pos_;
251 if (text_.length() > 0) 384 if (text_.length() > 0)
252 cursor_pos_++; 385 cursor_pos_++;
253 } else { 386 } else {
254 selection_begin_ = cursor_pos_ - 1; 387 selection_start_ = cursor_pos_ - 1;
255 } 388 }
256 389
257 // Now we move selection_begin_ to beginning of selection. Selection boundary 390 // Now we move selection_start_ to beginning of selection. Selection boundary
258 // is defined as the position where we have alpha-num character on one side 391 // is defined as the position where we have alpha-num character on one side
259 // and non-alpha-num char on the other side. 392 // and non-alpha-num char on the other side.
260 for (; selection_begin_ > 0; selection_begin_--) { 393 for (; selection_start_ > 0; selection_start_--) {
261 if (IsPositionAtWordSelectionBoundary(selection_begin_)) 394 if (IsPositionAtWordSelectionBoundary(selection_start_))
262 break; 395 break;
263 } 396 }
264 397
265 // Now we move cursor_pos_ to end of selection. Selection boundary 398 // Now we move cursor_pos_ to end of selection. Selection boundary
266 // is defined as the position where we have alpha-num character on one side 399 // is defined as the position where we have alpha-num character on one side
267 // and non-alpha-num char on the other side. 400 // and non-alpha-num char on the other side.
268 for (; cursor_pos_ < text_.length(); cursor_pos_++) { 401 for (; cursor_pos_ < text_.length(); cursor_pos_++) {
269 if (IsPositionAtWordSelectionBoundary(cursor_pos_)) 402 if (IsPositionAtWordSelectionBoundary(cursor_pos_))
270 break; 403 break;
271 } 404 }
272 } 405 }
273 406
274 void TextfieldViewsModel::ClearSelection() { 407 void TextfieldViewsModel::ClearSelection() {
275 selection_begin_ = cursor_pos_; 408 if (HasCompositionText())
409 ConfirmCompositionText();
410 selection_start_ = cursor_pos_;
276 } 411 }
277 412
278 bool TextfieldViewsModel::Cut() { 413 bool TextfieldViewsModel::Cut() {
279 if (HasSelection()) { 414 if (!HasCompositionText() && HasSelection()) {
280 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 415 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
281 ->GetClipboard()).WriteText(GetSelectedText()); 416 ->GetClipboard()).WriteText(GetSelectedText());
282 DeleteSelection(); 417 DeleteSelection();
283 return true; 418 return true;
284 } 419 }
285 return false; 420 return false;
286 } 421 }
287 422
288 void TextfieldViewsModel::Copy() { 423 void TextfieldViewsModel::Copy() {
289 if (HasSelection()) { 424 if (!HasCompositionText() && HasSelection()) {
290 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 425 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
291 ->GetClipboard()).WriteText(GetSelectedText()); 426 ->GetClipboard()).WriteText(GetSelectedText());
292 } 427 }
293 } 428 }
294 429
295 bool TextfieldViewsModel::Paste() { 430 bool TextfieldViewsModel::Paste() {
296 string16 result; 431 string16 result;
297 views::ViewsDelegate::views_delegate->GetClipboard() 432 views::ViewsDelegate::views_delegate->GetClipboard()
298 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 433 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
299 if (!result.empty()) { 434 if (!result.empty()) {
300 if (HasSelection()) 435 if (HasCompositionText())
436 ConfirmCompositionText();
437 else if (HasSelection())
301 DeleteSelection(); 438 DeleteSelection();
302 text_.insert(cursor_pos_, result); 439 text_.insert(cursor_pos_, result);
303 cursor_pos_ += result.length(); 440 cursor_pos_ += result.length();
304 ClearSelection(); 441 ClearSelection();
305 return true; 442 return true;
306 } 443 }
307 return false; 444 return false;
308 } 445 }
309 446
310 bool TextfieldViewsModel::HasSelection() const { 447 bool TextfieldViewsModel::HasSelection() const {
311 return selection_begin_ != cursor_pos_; 448 return selection_start_ != cursor_pos_;
312 } 449 }
313 450
314 void TextfieldViewsModel::DeleteSelection() { 451 void TextfieldViewsModel::DeleteSelection() {
452 DCHECK(!HasCompositionText());
315 DCHECK(HasSelection()); 453 DCHECK(HasSelection());
316 size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_begin_)); 454 size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_start_));
317 size_t begin = std::min(cursor_pos_, selection_begin_); 455 size_t begin = std::min(cursor_pos_, selection_start_);
318 text_.erase(begin, n); 456 text_.erase(begin, n);
319 cursor_pos_ = begin; 457 cursor_pos_ = begin;
320 ClearSelection(); 458 ClearSelection();
321 } 459 }
322 460
461 string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const {
462 if (range.IsValid() && range.GetMin() < text_.length())
463 return text_.substr(range.GetMin(), range.length());
464 return string16();
465 }
466
467 void TextfieldViewsModel::GetTextRange(ui::Range* range) const {
468 *range = ui::Range(0, text_.length());
469 }
470
471 void TextfieldViewsModel::SetCompositionText(
472 const ui::CompositionText& composition) {
473 if (HasCompositionText())
474 ClearCompositionText();
475 else if (HasSelection())
476 DeleteSelection();
477
478 if (composition.text.empty())
479 return;
480
481 size_t length = composition.text.length();
482 text_.insert(cursor_pos_, composition.text);
483 composition_start_ = cursor_pos_;
484 composition_end_ = composition_start_ + length;
485 composition_underlines_ = composition.underlines;
486
487 if (composition.selection.IsValid()) {
488 selection_start_ =
489 std::min(composition_start_ + composition.selection.start(),
490 composition_end_);
491 cursor_pos_ =
492 std::min(composition_start_ + composition.selection.end(),
493 composition_end_);
494 } else {
495 cursor_pos_ = composition_end_;
496 ClearSelection();
oshima 2011/03/24 22:58:47 I believe there should be no selection at this poi
James Su 2011/03/25 05:57:21 changing the value of cursor_pos_ will create a se
497 }
498 }
499
500 void TextfieldViewsModel::ConfirmCompositionText() {
501 DCHECK(HasCompositionText());
502 cursor_pos_ = composition_end_;
503 composition_start_ = composition_end_ = string16::npos;
504 composition_underlines_.clear();
505 ClearSelection();
506 if (delegate_)
507 delegate_->OnCompositionTextConfirmedOrCleared();
508 }
509
510 void TextfieldViewsModel::ClearCompositionText() {
511 DCHECK(HasCompositionText());
512 text_.erase(composition_start_, composition_end_ - composition_start_);
513 cursor_pos_ = composition_start_;
514 composition_start_ = composition_end_ = string16::npos;
515 composition_underlines_.clear();
516 ClearSelection();
517 if (delegate_)
518 delegate_->OnCompositionTextConfirmedOrCleared();
519 }
520
521 void TextfieldViewsModel::GetCompositionTextRange(ui::Range* range) const {
522 if (HasCompositionText())
523 *range = ui::Range(composition_start_, composition_end_);
524 else
525 *range = ui::Range::InvalidRange();
526 }
527
528 bool TextfieldViewsModel::HasCompositionText() const {
529 return composition_start_ != composition_end_;
530 }
531
323 string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const { 532 string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const {
324 DCHECK(end >= begin); 533 DCHECK(end >= begin);
325 if (is_password_) { 534 if (is_password_)
326 return string16(end - begin, '*'); 535 return string16(end - begin, '*');
327 }
328 return text_.substr(begin, end - begin); 536 return text_.substr(begin, end - begin);
329 } 537 }
330 538
331 bool TextfieldViewsModel::IsPositionAtWordSelectionBoundary(size_t pos) { 539 bool TextfieldViewsModel::IsPositionAtWordSelectionBoundary(size_t pos) {
332 return (isalnum(text_[pos - 1]) && !isalnum(text_[pos])) || 540 return (isalnum(text_[pos - 1]) && !isalnum(text_[pos])) ||
333 (!isalnum(text_[pos - 1]) && isalnum(text_[pos])); 541 (!isalnum(text_[pos - 1]) && isalnum(text_[pos]));
334 } 542 }
335 543
336 size_t TextfieldViewsModel::GetSafePosition(size_t position) const { 544 size_t TextfieldViewsModel::GetSafePosition(size_t position) const {
337 if (position > text_.length()) { 545 if (position > text_.length()) {
338 return text_.length(); 546 return text_.length();
339 } 547 }
340 return position; 548 return position;
341 } 549 }
342 550
343 } // namespace views 551 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698