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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: views/controls/textfield/textfield_views_model.cc
diff --git a/views/controls/textfield/textfield_views_model.cc b/views/controls/textfield/textfield_views_model.cc
index ef12404fdfd4f1094dfa9c5682f2753b84982f21..6e3ebf7f5301159719ae4bde025e9882d2dcbd7a 100644
--- a/views/controls/textfield/textfield_views_model.cc
+++ b/views/controls/textfield/textfield_views_model.cc
@@ -18,9 +18,15 @@
namespace views {
-TextfieldViewsModel::TextfieldViewsModel()
- : cursor_pos_(0),
- selection_begin_(0),
+TextfieldViewsModel::Delegate::~Delegate() {
+}
+
+TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
+ : delegate_(delegate),
+ cursor_pos_(0),
+ selection_start_(0),
+ composition_start_(0),
+ composition_end_(0),
is_password_(false) {
}
@@ -30,57 +36,159 @@ TextfieldViewsModel::~TextfieldViewsModel() {
void TextfieldViewsModel::GetFragments(TextFragments* fragments) const {
DCHECK(fragments);
fragments->clear();
- if (HasSelection()) {
- int begin = std::min(selection_begin_, cursor_pos_);
- int end = std::max(selection_begin_, cursor_pos_);
- if (begin != 0) {
- fragments->push_back(TextFragment(0, begin, false));
+ if (HasCompositionText()) {
+ if (composition_start_)
+ fragments->push_back(TextFragment(0, composition_start_, false, false));
+
+ size_t selection_start = std::min(selection_start_, cursor_pos_);
+ size_t selection_end = std::max(selection_start_, cursor_pos_);
+ size_t last_end = composition_start_;
+ for (ui::CompositionUnderlines::const_iterator i =
+ composition_underlines_.begin();
+ i != composition_underlines_.end(); ++i) {
+ size_t fragment_start =
+ std::min(i->start_offset, i->end_offset) + composition_start_;
+ size_t fragment_end =
+ std::max(i->start_offset, i->end_offset) + composition_start_;
+
+ fragment_start = std::max(last_end, fragment_start);
+ fragment_end = std::min(fragment_end, composition_end_);
+
+ if (fragment_start >= fragment_end)
+ break;
+
+ // If there is no selection, then just add a text fragment with underline.
+ if (selection_start == selection_end) {
+ if (last_end < fragment_start) {
+ fragments->push_back(
+ TextFragment(last_end, fragment_start, false, false));
+ }
+ fragments->push_back(
+ TextFragment(fragment_start, fragment_end, false, true));
+ last_end = fragment_end;
+ continue;
+ }
+
+ size_t end = std::min(fragment_start, selection_start);
+ if (last_end < end)
+ fragments->push_back(TextFragment(last_end, end, false, false));
+
+ last_end = fragment_end;
+
+ if (selection_start < fragment_start) {
+ end = std::min(selection_end, fragment_start);
+ fragments->push_back(TextFragment(selection_start, end, true, false));
+ selection_start = end;
+ } else if (selection_start > fragment_start) {
+ end = std::min(selection_start, fragment_end);
+ fragments->push_back(TextFragment(fragment_start, end, false, true));
+ fragment_start = end;
+ if (fragment_start == fragment_end)
+ continue;
+ }
+
+ if (fragment_start < selection_end) {
+ DCHECK_EQ(selection_start, fragment_start);
+ end = std::min(fragment_end, selection_end);
+ fragments->push_back(TextFragment(fragment_start, end, true, true));
+ fragment_start = end;
+ selection_start = end;
+ if (fragment_start == fragment_end)
+ continue;
+ }
+
+ DCHECK_LT(fragment_start, fragment_end);
+ fragments->push_back(
+ TextFragment(fragment_start, fragment_end, false, true));
}
- fragments->push_back(TextFragment(begin, end, true));
- int len = text_.length();
- if (end != len) {
- fragments->push_back(TextFragment(end, len, false));
+
+ if (last_end < composition_end_) {
+ if (selection_start < selection_end) {
+ DCHECK_LE(last_end, selection_start);
+ if (last_end < selection_start) {
+ fragments->push_back(
+ TextFragment(last_end, selection_start, false, false));
+ }
+ fragments->push_back(
+ TextFragment(selection_start, selection_end, true, false));
+ if (selection_end < composition_end_) {
+ fragments->push_back(
+ TextFragment(selection_end, composition_end_, false, false));
+ }
+ } else {
+ fragments->push_back(
+ TextFragment(last_end, composition_end_, false, false));
+ }
}
+
+ size_t len = text_.length();
+ if (composition_end_ < len)
+ fragments->push_back(TextFragment(composition_end_, len, false, false));
+ } else if (HasSelection()) {
+ size_t start = std::min(selection_start_, cursor_pos_);
+ size_t end = std::max(selection_start_, cursor_pos_);
+ if (start)
+ fragments->push_back(TextFragment(0, start, false, false));
+ fragments->push_back(TextFragment(start, end, true, false));
+ size_t len = text_.length();
+ if (end != len)
+ fragments->push_back(TextFragment(end, len, false, false));
} else {
- fragments->push_back(TextFragment(0, text_.length(), false));
+ fragments->push_back(TextFragment(0, text_.length(), false, false));
}
}
bool TextfieldViewsModel::SetText(const string16& text) {
- bool changed = text_ != text;
- if (changed) {
+ bool changed = false;
+ if (HasCompositionText()) {
+ ConfirmCompositionText();
+ changed = true;
+ }
+ if (text_ != text) {
text_ = text;
if (cursor_pos_ > text.length()) {
cursor_pos_ = text.length();
}
+ changed = true;
}
ClearSelection();
return changed;
}
-void TextfieldViewsModel::Insert(char16 c) {
- if (HasSelection())
+void TextfieldViewsModel::InsertText(const string16& text) {
+ if (HasCompositionText())
+ ClearCompositionText();
+ else if (HasSelection())
DeleteSelection();
- text_.insert(cursor_pos_, 1, c);
- cursor_pos_++;
+ text_.insert(cursor_pos_, text);
+ cursor_pos_ += text.size();
ClearSelection();
}
-void TextfieldViewsModel::Replace(char16 c) {
- if (!HasSelection())
- Delete();
- Insert(c);
+void TextfieldViewsModel::ReplaceText(const string16& text) {
+ if (HasCompositionText())
+ ClearCompositionText();
+ else if (!HasSelection())
+ SelectRange(ui::Range(cursor_pos_, cursor_pos_ + text.length()));
+ InsertText(text);
}
void TextfieldViewsModel::Append(const string16& text) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
text_ += text;
}
bool TextfieldViewsModel::Delete() {
+ if (HasCompositionText()) {
+ ClearCompositionText();
+ return true;
+ }
if (HasSelection()) {
DeleteSelection();
return true;
- } else if (text_.length() > cursor_pos_) {
+ }
+ if (text_.length() > cursor_pos_) {
text_.erase(cursor_pos_, 1);
return true;
}
@@ -88,10 +196,15 @@ bool TextfieldViewsModel::Delete() {
}
bool TextfieldViewsModel::Backspace() {
+ if (HasCompositionText()) {
+ ClearCompositionText();
+ return true;
+ }
if (HasSelection()) {
DeleteSelection();
return true;
- } else if (cursor_pos_ > 0) {
+ }
+ if (cursor_pos_ > 0) {
cursor_pos_--;
text_.erase(cursor_pos_, 1);
ClearSelection();
@@ -101,13 +214,15 @@ bool TextfieldViewsModel::Backspace() {
}
void TextfieldViewsModel::MoveCursorLeft(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
// TODO(oshima): support BIDI
if (select) {
if (cursor_pos_ > 0)
cursor_pos_--;
} else {
if (HasSelection())
- cursor_pos_ = std::min(cursor_pos_, selection_begin_);
+ cursor_pos_ = std::min(cursor_pos_, selection_start_);
else if (cursor_pos_ > 0)
cursor_pos_--;
ClearSelection();
@@ -115,12 +230,14 @@ void TextfieldViewsModel::MoveCursorLeft(bool select) {
}
void TextfieldViewsModel::MoveCursorRight(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
// TODO(oshima): support BIDI
if (select) {
cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
} else {
if (HasSelection())
- cursor_pos_ = std::max(cursor_pos_, selection_begin_);
+ cursor_pos_ = std::max(cursor_pos_, selection_start_);
else
cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
ClearSelection();
@@ -128,6 +245,8 @@ void TextfieldViewsModel::MoveCursorRight(bool select) {
}
void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
// 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
@@ -162,6 +281,8 @@ void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) {
}
void TextfieldViewsModel::MoveCursorToNextWord(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
base::BreakIterator iter(&text_, base::BreakIterator::BREAK_WORD);
bool success = iter.Init();
DCHECK(success);
@@ -179,19 +300,25 @@ void TextfieldViewsModel::MoveCursorToNextWord(bool select) {
ClearSelection();
}
-void TextfieldViewsModel::MoveCursorToStart(bool select) {
+void TextfieldViewsModel::MoveCursorToHome(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
cursor_pos_ = 0;
if (!select)
ClearSelection();
}
void TextfieldViewsModel::MoveCursorToEnd(bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
cursor_pos_ = text_.length();
if (!select)
ClearSelection();
}
bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
bool cursor_changed = false;
if (cursor_pos_ != pos) {
cursor_pos_ = pos;
@@ -217,48 +344,54 @@ gfx::Rect TextfieldViewsModel::GetCursorBounds(const gfx::Font& font) const {
string16 TextfieldViewsModel::GetSelectedText() const {
return text_.substr(
- std::min(cursor_pos_, selection_begin_),
- std::abs(static_cast<long>(cursor_pos_ - selection_begin_)));
+ std::min(cursor_pos_, selection_start_),
+ std::abs(static_cast<long>(cursor_pos_ - selection_start_)));
}
void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const {
- *range = ui::Range(selection_begin_, cursor_pos_);
+ *range = ui::Range(selection_start_, cursor_pos_);
}
void TextfieldViewsModel::SelectRange(const ui::Range& range) {
- selection_begin_ = GetSafePosition(range.start());
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ selection_start_ = GetSafePosition(range.start());
cursor_pos_ = GetSafePosition(range.end());
}
void TextfieldViewsModel::SelectAll() {
+ if (HasCompositionText())
+ ConfirmCompositionText();
// SelectAll selects towards the end.
cursor_pos_ = text_.length();
- selection_begin_ = 0;
+ selection_start_ = 0;
}
void TextfieldViewsModel::SelectWord() {
- // First we setup selection_begin_ and cursor_pos_. There are so many cases
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ // First we setup selection_start_ and cursor_pos_. There are so many cases
// because we try to emulate what select-word looks like in a gtk textfield.
// See associated testcase for different cases.
if (cursor_pos_ > 0 && cursor_pos_ < text_.length()) {
if (isalnum(text_[cursor_pos_])) {
- selection_begin_ = cursor_pos_;
+ selection_start_ = cursor_pos_;
cursor_pos_++;
} else
- selection_begin_ = cursor_pos_ - 1;
+ selection_start_ = cursor_pos_ - 1;
} else if (cursor_pos_ == 0) {
- selection_begin_ = cursor_pos_;
+ selection_start_ = cursor_pos_;
if (text_.length() > 0)
cursor_pos_++;
} else {
- selection_begin_ = cursor_pos_ - 1;
+ selection_start_ = cursor_pos_ - 1;
}
- // Now we move selection_begin_ to beginning of selection. Selection boundary
+ // Now we move selection_start_ to beginning of selection. Selection boundary
// is defined as the position where we have alpha-num character on one side
// and non-alpha-num char on the other side.
- for (; selection_begin_ > 0; selection_begin_--) {
- if (IsPositionAtWordSelectionBoundary(selection_begin_))
+ for (; selection_start_ > 0; selection_start_--) {
+ if (IsPositionAtWordSelectionBoundary(selection_start_))
break;
}
@@ -272,11 +405,13 @@ void TextfieldViewsModel::SelectWord() {
}
void TextfieldViewsModel::ClearSelection() {
- selection_begin_ = cursor_pos_;
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ selection_start_ = cursor_pos_;
}
bool TextfieldViewsModel::Cut() {
- if (HasSelection()) {
+ if (!HasCompositionText() && HasSelection()) {
ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
->GetClipboard()).WriteText(GetSelectedText());
DeleteSelection();
@@ -286,7 +421,7 @@ bool TextfieldViewsModel::Cut() {
}
void TextfieldViewsModel::Copy() {
- if (HasSelection()) {
+ if (!HasCompositionText() && HasSelection()) {
ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
->GetClipboard()).WriteText(GetSelectedText());
}
@@ -297,7 +432,9 @@ bool TextfieldViewsModel::Paste() {
views::ViewsDelegate::views_delegate->GetClipboard()
->ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
if (!result.empty()) {
- if (HasSelection())
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ else if (HasSelection())
DeleteSelection();
text_.insert(cursor_pos_, result);
cursor_pos_ += result.length();
@@ -308,23 +445,94 @@ bool TextfieldViewsModel::Paste() {
}
bool TextfieldViewsModel::HasSelection() const {
- return selection_begin_ != cursor_pos_;
+ return selection_start_ != cursor_pos_;
}
void TextfieldViewsModel::DeleteSelection() {
+ DCHECK(!HasCompositionText());
DCHECK(HasSelection());
- size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_begin_));
- size_t begin = std::min(cursor_pos_, selection_begin_);
+ size_t n = std::abs(static_cast<long>(cursor_pos_ - selection_start_));
+ size_t begin = std::min(cursor_pos_, selection_start_);
text_.erase(begin, n);
cursor_pos_ = begin;
ClearSelection();
}
+string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const {
+ if (range.IsValid() && range.GetMin() < text_.length())
+ return text_.substr(range.GetMin(), range.length());
+ return string16();
+}
+
+void TextfieldViewsModel::GetTextRange(ui::Range* range) const {
+ *range = ui::Range(0, text_.length());
+}
+
+void TextfieldViewsModel::SetCompositionText(
+ const ui::CompositionText& composition) {
+ if (HasCompositionText())
+ ClearCompositionText();
+ else if (HasSelection())
+ DeleteSelection();
+
+ if (composition.text.empty())
+ return;
+
+ size_t length = composition.text.length();
+ text_.insert(cursor_pos_, composition.text);
+ composition_start_ = cursor_pos_;
+ composition_end_ = composition_start_ + length;
+ composition_underlines_ = composition.underlines;
+
+ if (composition.selection.IsValid()) {
+ selection_start_ =
+ std::min(composition_start_ + composition.selection.start(),
+ composition_end_);
+ cursor_pos_ =
+ std::min(composition_start_ + composition.selection.end(),
+ composition_end_);
+ } else {
+ cursor_pos_ = composition_end_;
+ ClearSelection();
+ }
+}
+
+void TextfieldViewsModel::ConfirmCompositionText() {
+ DCHECK(HasCompositionText());
+ cursor_pos_ = composition_end_;
+ composition_start_ = composition_end_ = string16::npos;
+ composition_underlines_.clear();
+ ClearSelection();
+ if (delegate_)
+ delegate_->OnCompositionTextConfirmedOrCleared();
+}
+
+void TextfieldViewsModel::ClearCompositionText() {
+ DCHECK(HasCompositionText());
+ text_.erase(composition_start_, composition_end_ - composition_start_);
+ cursor_pos_ = composition_start_;
+ composition_start_ = composition_end_ = string16::npos;
+ composition_underlines_.clear();
+ ClearSelection();
+ if (delegate_)
+ delegate_->OnCompositionTextConfirmedOrCleared();
+}
+
+void TextfieldViewsModel::GetCompositionTextRange(ui::Range* range) const {
+ if (HasCompositionText())
+ *range = ui::Range(composition_start_, composition_end_);
+ else
+ *range = ui::Range::InvalidRange();
+}
+
+bool TextfieldViewsModel::HasCompositionText() const {
+ return composition_start_ != composition_end_;
+}
+
string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const {
DCHECK(end >= begin);
- if (is_password_) {
+ if (is_password_)
return string16(end - begin, '*');
- }
return text_.substr(begin, end - begin);
}

Powered by Google App Engine
This is Rietveld 408576698