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

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

Issue 5857002: no native implementation of Textfield. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove selection_end and add tests Created 10 years 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
(Empty)
1 // Copyright (c) 2010 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 "views/controls/textfield/textfield_views_model.h"
6
7 #include <algorithm>
8
9 #include "base/i18n/break_iterator.h"
10 #include "base/logging.h"
11 #include "base/utf_string_conversions.h"
12 #include "gfx/font.h"
13
14 namespace views {
15
16 TextfieldViewsModel::TextfieldViewsModel()
17 : cursor_pos_(0),
18 selection_begin_(0),
19 is_password_(false) {
20 }
21
22 TextfieldViewsModel::~TextfieldViewsModel() {
23 }
24
25 void TextfieldViewsModel::GetFragments(TextFragments* fragments) const {
26 DCHECK(fragments);
27 fragments->clear();
28 if (HasSelection()) {
29 int begin = std::min(selection_begin_, cursor_pos_);
30 int end = std::max(selection_begin_, cursor_pos_);
31 if (begin != 0) {
32 fragments->push_back(TextFragment(0, begin, false));
33 }
34 fragments->push_back(TextFragment(begin, end, true));
35 int len = text_.length();
36 if (end != len) {
37 fragments->push_back(TextFragment(end, len, false));
38 }
39 } else {
40 fragments->push_back(TextFragment(0, text_.length(), false));
41 }
42 }
43
44 bool TextfieldViewsModel::SetText(const string16& text) {
45 bool changed = text_ != text;
46 if (changed) {
47 text_ = text;
48 if (cursor_pos_ > text.length()) {
49 cursor_pos_ = text.length();
50 }
51 }
52 ClearSelection();
53 return changed;
54 }
55
56 void TextfieldViewsModel::Insert(char16 c) {
57 if (HasSelection())
58 DeleteSelection();
59 text_.insert(cursor_pos_, 1, c);
60 cursor_pos_++;
61 ClearSelection();
62 }
63
64 void TextfieldViewsModel::Replace(char16 c) {
65 if (!HasSelection())
66 Delete();
67 Insert(c);
68 }
69
70 void TextfieldViewsModel::Append(const string16& text) {
71 text_ += text;
72 }
73
74 bool TextfieldViewsModel::Delete() {
75 if (HasSelection()) {
76 DeleteSelection();
77 return true;
78 } else if (text_.length() > cursor_pos_) {
79 text_.erase(cursor_pos_, 1);
80 return true;
81 }
82 return false;
83 }
84
85 bool TextfieldViewsModel::Backspace() {
86 if (HasSelection()) {
87 DeleteSelection();
88 return true;
89 } else if(cursor_pos_ > 0) {
sky 2010/12/16 22:43:04 nit: space between if and (
oshima 2010/12/16 23:50:02 Done.
90 cursor_pos_--;
91 text_.erase(cursor_pos_, 1);
92 ClearSelection();
93 return true;
94 }
95 return false;
96 }
97
98 void TextfieldViewsModel::MoveCursorLeft(bool select) {
99 // TODO(oshima): support BIDI
100 if (select) {
101 if (cursor_pos_ > 0)
102 cursor_pos_--;
103 } else {
104 if (HasSelection())
105 cursor_pos_ = std::min(cursor_pos_, selection_begin_);
106 else if (cursor_pos_ > 0)
107 cursor_pos_--;
108 ClearSelection();
109 }
110 }
111
112 void TextfieldViewsModel::MoveCursorRight(bool select) {
113 // TODO(oshima): support BIDI
114 if (select) {
115 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
116 } else {
117 if (HasSelection())
118 cursor_pos_ = std::max(cursor_pos_, selection_begin_);
119 else
120 cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
121 ClearSelection();
122 }
123 }
124
125 void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) {
126 // Notes: We always iterate words from the begining.
127 // This is probably fast enough for our usage, but we may
128 // want to modify WordIterator so that it can start from the
129 // middle of string and advance backwards.
130 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD);
131 bool success = iter.Init();
132 DCHECK(success);
133 if (!success)
134 return;
135 int prev = 0;
136 while (iter.Advance()) {
137 if (iter.IsWord()) {
138 size_t begin = iter.pos() - iter.GetString().length();
139 if (begin == cursor_pos_) {
140 // The cursor is at the beginning of a word.
141 // Move to previous word.
142 cursor_pos_ = prev;
143 } else if(iter.pos() >= cursor_pos_) {
144 // The cursor is in the middle or at the end of a word.
145 // Move to the top of current word.
146 cursor_pos_ = begin;
147 } else {
148 prev = iter.pos() - iter.GetString().length();
149 continue;
150 }
151 if (!select)
152 ClearSelection();
153 break;
154 }
155 }
156 }
157
158 void TextfieldViewsModel::MoveCursorToNextWord(bool select) {
159 base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD);
160 bool success = iter.Init();
161 DCHECK(success);
162 if (!success)
163 return;
164 while (iter.Advance()) {
165 if (iter.IsWord() && iter.pos() > cursor_pos_) {
166 cursor_pos_ = iter.pos();
167 if (!select)
168 ClearSelection();
169 break;
170 }
171 }
172 }
173
174 void TextfieldViewsModel::MoveCursorToStart(bool select) {
175 cursor_pos_ = 0;
176 if (!select)
177 ClearSelection();
178 }
179
180 void TextfieldViewsModel::MoveCursorToEnd(bool select) {
181 cursor_pos_ = text_.length();
182 if (!select)
183 ClearSelection();
184 }
185
186 bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) {
187 if (cursor_pos_ != pos) {
188 cursor_pos_ = pos;
189 if (!select)
190 ClearSelection();
191 return true;
192 }
sky 2010/12/16 22:43:04 Do you need an else case if !select that clears se
oshima 2010/12/16 23:50:02 Done.
193 return false;
194 }
195
196 gfx::Rect TextfieldViewsModel::GetCursorBounds(const gfx::Font& font) const {
197 string16 text = GetVisibleText();
198 int x = font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_)));
199 int h = font.GetHeight();
200 DCHECK(x >= 0);
201 if (text.length() == cursor_pos_) {
202 return gfx::Rect(x, 0, 0, h);
203 } else {
204 int x_end =
205 font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_ + 1U)));
206 return gfx::Rect(x, 0, x_end - x, h);
207 }
208 }
209
210 string16 TextfieldViewsModel::GetSelectedText() const {
211 return text_.substr(
212 std::min(cursor_pos_, selection_begin_),
213 std::abs(static_cast<long>(cursor_pos_ - selection_begin_)));
214 }
215
216 void TextfieldViewsModel::SelectAll() {
217 cursor_pos_ = 0;
218 selection_begin_ = text_.length();
219 }
220
221 void TextfieldViewsModel::ClearSelection() {
222 selection_begin_ = cursor_pos_;
223 }
224
225 bool TextfieldViewsModel::HasSelection() const {
226 return selection_begin_ != cursor_pos_;
227 }
228
229 void TextfieldViewsModel::DeleteSelection() {
230 DCHECK(HasSelection());
231 size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_begin_));
232 size_t begin = std::min(cursor_pos_, selection_begin_);
233 text_.erase(begin, n);
234 cursor_pos_ = begin;
235 ClearSelection();
236 }
237
238 string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const {
239 DCHECK(end >= begin);
240 if (is_password_) {
241 return string16(end - begin, '*');
242 }
243 return text_.substr(begin, end - begin);
244 }
245
246 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698