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

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

Powered by Google App Engine
This is Rietveld 408576698