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

Unified Diff: views/controls/textfield/textfield_view_model.cc

Issue 5857002: no native implementation of Textfield. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: " 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 side-by-side diff with in-line comments
Download patch
Index: views/controls/textfield/textfield_view_model.cc
diff --git a/views/controls/textfield/textfield_view_model.cc b/views/controls/textfield/textfield_view_model.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fbea8fcd0a73bee729f0cdc0640e0e959759eecb
--- /dev/null
+++ b/views/controls/textfield/textfield_view_model.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/controls/textfield/textfield_view_model.h"
+
+#include <algorithm>
+
+#include "base/i18n/word_iterator.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "gfx/font.h"
+
+namespace views {
+
+TextfieldViewModel::TextfieldViewModel()
+ : cursor_pos_(0),
+ begin_(0),
+ end_(0),
+ is_password_(false) {
+}
+
+TextfieldViewModel::~TextfieldViewModel() {
+}
+
+void TextfieldViewModel::PopulateFragments(TextFragments* fragments) const {
+ DCHECK(fragments);
+ fragments->clear();
+ if (HasSelection()) {
+ int begin = std::min(begin_, end_);
+ int end = std::max(begin_, end_);
+ if (begin != 0) {
+ fragments->push_back(TextFragment(0, begin, false));
+ }
+ fragments->push_back(TextFragment(begin, end, true));
+ int len = text_.length();
+ if (end != len) {
+ fragments->push_back(TextFragment(end, len, false));
+ }
+ } else {
+ fragments->push_back(TextFragment(0, text_.length(), false));
+ }
+}
+
+bool TextfieldViewModel::SetText(const string16& text) {
+ bool changed = text_ != text;
+ if (changed) {
+ text_ = text;
+ if (cursor_pos_ > text.length()) {
+ cursor_pos_ = text.length();
+ }
+ }
+ ClearSelection();
+ return changed;
+}
+
+void TextfieldViewModel::Insert(char16 c) {
+ if (HasSelection())
+ DeleteSelection();
+ text_.insert(cursor_pos_, 1, c);
sky 2010/12/15 20:31:27 Meta question. Isn't it possible for a visual char
oshima 2010/12/16 01:15:19 Yes, you're correct. This only works in UTF16/UCS-
+ cursor_pos_++;
+}
+
+void TextfieldViewModel::Replace(char16 c) {
+ if (!HasSelection())
+ Delete();
+ Insert(c);
+}
+
+void TextfieldViewModel::Append(const string16& text) {
+ text_ += text;
+}
+
+bool TextfieldViewModel::Delete() {
+ if (HasSelection()) {
+ DeleteSelection();
+ return true;
+ } else if (text_.length() > cursor_pos_) {
+ text_.erase(cursor_pos_, 1);
+ return true;
+ }
+ return false;
+}
+
+bool TextfieldViewModel::Backspace() {
+ if (HasSelection()) {
+ DeleteSelection();
+ return true;
+ } else if(cursor_pos_ > 0) {
+ cursor_pos_--;
+ text_.erase(cursor_pos_, 1);
+ return true;
+ }
+ return false;
+}
+
+void TextfieldViewModel::MoveCursorLeft(bool select) {
+ // support bidi
+ int old = cursor_pos_;
+ if (cursor_pos_ > 0)
+ cursor_pos_--;
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+}
+
+void TextfieldViewModel::MoveCursorRight(bool select) {
+ int old = cursor_pos_;
+ // support bidi
+ cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+}
+
+void TextfieldViewModel::MoveCursorToPreviousWord(bool select) {
+ // Notes: We always iterate words from the begining.
+ // This is probably fast enough for our usage, but we may
+ // want to modify WordIterator so that it can start from the
+ // middle of string and adnvace backwards.
sky 2010/12/15 20:31:27 adnvace -> advance
oshima 2010/12/16 01:15:19 Done.
+ WordIterator iter(&text_, WordIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return;
+ int prev = 0;
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ int old = cursor_pos_;
+ size_t begin = iter.pos() - iter.GetWord().length();
+ if (begin == cursor_pos_) {
+ // The cursor is at the beginning of a word.
+ // Move to previous word.
+ cursor_pos_ = prev;
+ } else if(iter.pos() >= cursor_pos_) {
+ // The cursor is in the middle or at the end of a word.
+ // Move to the top of current word.
+ cursor_pos_ = begin;
+ } else {
+ prev = iter.pos() - iter.GetWord().length();
+ continue;
+ }
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+ break;
+ }
+ }
+}
+
+void TextfieldViewModel::MoveCursorToNextWord(bool select) {
+ WordIterator iter(&text_, WordIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return;
+ while (iter.Advance()) {
+ if (iter.IsWord() && iter.pos() > cursor_pos_) {
+ int old = cursor_pos_;
+ cursor_pos_ = iter.pos();
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+ break;
+ }
+ }
+}
+
+void TextfieldViewModel::MoveCursorToStart(bool select) {
+ int old = cursor_pos_;
+ cursor_pos_ = 0;
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+}
+
+void TextfieldViewModel::MoveCursorToEnd(bool select) {
+ int old = cursor_pos_;
+ cursor_pos_ = text_.length();
+ if (select)
+ Select(old, cursor_pos_);
+ else
+ ClearSelection();
+}
+
+bool TextfieldViewModel::MoveCursorTo(size_t pos, bool select) {
+ if (cursor_pos_ != pos) {
+ if (select)
+ Select(cursor_pos_, pos);
+ else
+ ClearSelection();
+ cursor_pos_ = pos;
+ return true;
+ }
+ return false;
+}
+
+gfx::Rect TextfieldViewModel::GetCursorBounds(const gfx::Font& font) const {
+ string16 text = GetVisibleText();
+ int x = font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_)));
+ int h = font.GetHeight();
+ DCHECK(x >= 0);
+ if (text.length() == cursor_pos_) {
+ return gfx::Rect(x, 0, 0, h);
+ } else {
+ int x_end =
+ font.GetStringWidth(UTF16ToWide(text.substr(0U, cursor_pos_ + 1U)));
+ return gfx::Rect(x, 0, x_end - x, h);
+ }
+}
+
+string16 TextfieldViewModel::GetSelectedText() const {
+ return text_.substr(std::min(begin_, end_),
+ std::abs(static_cast<long>(end_ - begin_)));
sky 2010/12/15 20:31:27 static_cast<size_t>
oshima 2010/12/16 01:15:19 size_t is unsigned. using long to make it signed f
+}
+
+void TextfieldViewModel::SelectAll() {
+ begin_ = 0;
+ end_ = text_.length();
sky 2010/12/15 20:31:27 Select(0, text_.length())
oshima 2010/12/16 01:15:19 Done.
+}
+
+void TextfieldViewModel::ClearSelection() {
+ begin_ = end_ = cursor_pos_;
+}
+
+void TextfieldViewModel::Select(size_t old, size_t end) {
+ if (old == end) return; // no action
+
+ DCHECK(0 <= old && old <= text_.length());
+ DCHECK(0 <= end && old <= text_.length());
+ if (!HasSelection()) {
+ // first time
+ begin_ = old;
+ end_ = end;
+ } else {
+ end_ = end;
+ }
+}
+
+bool TextfieldViewModel::HasSelection() const {
+ return begin_ != end_;
+}
+
+void TextfieldViewModel::DeleteSelection() {
+ DCHECK(HasSelection());
+ size_t n = std::abs(static_cast<long>(end_ - begin_));
sky 2010/12/15 20:31:27 static_cast<size_t>
oshima 2010/12/16 01:15:19 same here.
+ size_t begin = std::min(begin_, end_);
+ text_.erase(begin, n);
+ cursor_pos_ = begin;
+ ClearSelection();
+}
+
+string16 TextfieldViewModel::GetVisibleText(size_t begin, size_t end) const {
+ DCHECK(end >= begin);
+ if (is_password_) {
+ return string16(end - begin, '*');
+ }
+ return text_.substr(begin, end - begin);
+}
+
+} // namespace views

Powered by Google App Engine
This is Rietveld 408576698