OLD | NEW |
(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) { |
| 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 bool cursor_changed = false; |
| 188 if (cursor_pos_ != pos) { |
| 189 cursor_pos_ = pos; |
| 190 cursor_changed = true; |
| 191 } |
| 192 if (!select) |
| 193 ClearSelection(); |
| 194 return cursor_changed; |
| 195 } |
| 196 |
| 197 gfx::Rect TextfieldViewsModel::GetCursorBounds(const gfx::Font& font) const { |
| 198 string16 text = GetVisibleText(); |
| 199 int x = font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_))); |
| 200 int h = font.GetHeight(); |
| 201 DCHECK(x >= 0); |
| 202 if (text.length() == cursor_pos_) { |
| 203 return gfx::Rect(x, 0, 0, h); |
| 204 } else { |
| 205 int x_end = |
| 206 font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_ + 1U))); |
| 207 return gfx::Rect(x, 0, x_end - x, h); |
| 208 } |
| 209 } |
| 210 |
| 211 string16 TextfieldViewsModel::GetSelectedText() const { |
| 212 return text_.substr( |
| 213 std::min(cursor_pos_, selection_begin_), |
| 214 std::abs(static_cast<long>(cursor_pos_ - selection_begin_))); |
| 215 } |
| 216 |
| 217 void TextfieldViewsModel::SelectAll() { |
| 218 cursor_pos_ = 0; |
| 219 selection_begin_ = text_.length(); |
| 220 } |
| 221 |
| 222 void TextfieldViewsModel::ClearSelection() { |
| 223 selection_begin_ = cursor_pos_; |
| 224 } |
| 225 |
| 226 bool TextfieldViewsModel::HasSelection() const { |
| 227 return selection_begin_ != cursor_pos_; |
| 228 } |
| 229 |
| 230 void TextfieldViewsModel::DeleteSelection() { |
| 231 DCHECK(HasSelection()); |
| 232 size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_begin_)); |
| 233 size_t begin = std::min(cursor_pos_, selection_begin_); |
| 234 text_.erase(begin, n); |
| 235 cursor_pos_ = begin; |
| 236 ClearSelection(); |
| 237 } |
| 238 |
| 239 string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const { |
| 240 DCHECK(end >= begin); |
| 241 if (is_password_) { |
| 242 return string16(end - begin, '*'); |
| 243 } |
| 244 return text_.substr(begin, end - begin); |
| 245 } |
| 246 |
| 247 } // namespace views |
OLD | NEW |