| Index: ui/views/controls/textfield/native_textfield_views.cc
|
| diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc
|
| deleted file mode 100644
|
| index e79c292c1b5d0c6825f297810708385a170b7e07..0000000000000000000000000000000000000000
|
| --- a/ui/views/controls/textfield/native_textfield_views.cc
|
| +++ /dev/null
|
| @@ -1,1528 +0,0 @@
|
| -// Copyright 2014 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 "ui/views/controls/textfield/native_textfield_views.h"
|
| -
|
| -#include <algorithm>
|
| -#include <set>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/debug/trace_event.h"
|
| -#include "base/i18n/case_conversion.h"
|
| -#include "base/logging.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "grit/ui_strings.h"
|
| -#include "third_party/icu/source/common/unicode/uchar.h"
|
| -#include "third_party/skia/include/core/SkColor.h"
|
| -#include "ui/base/clipboard/clipboard.h"
|
| -#include "ui/base/dragdrop/drag_drop_types.h"
|
| -#include "ui/base/dragdrop/drag_utils.h"
|
| -#include "ui/base/l10n/l10n_util.h"
|
| -#include "ui/base/ui_base_switches_util.h"
|
| -#include "ui/compositor/layer.h"
|
| -#include "ui/events/event.h"
|
| -#include "ui/gfx/canvas.h"
|
| -#include "ui/gfx/font_list.h"
|
| -#include "ui/gfx/insets.h"
|
| -#include "ui/gfx/range/range.h"
|
| -#include "ui/gfx/render_text.h"
|
| -#include "ui/gfx/text_constants.h"
|
| -#include "ui/native_theme/native_theme.h"
|
| -#include "ui/views/background.h"
|
| -#include "ui/views/border.h"
|
| -#include "ui/views/controls/focusable_border.h"
|
| -#include "ui/views/controls/menu/menu_item_view.h"
|
| -#include "ui/views/controls/menu/menu_model_adapter.h"
|
| -#include "ui/views/controls/menu/menu_runner.h"
|
| -#include "ui/views/controls/textfield/textfield.h"
|
| -#include "ui/views/controls/textfield/textfield_controller.h"
|
| -#include "ui/views/controls/textfield/textfield_views_model.h"
|
| -#include "ui/views/drag_utils.h"
|
| -#include "ui/views/ime/input_method.h"
|
| -#include "ui/views/metrics.h"
|
| -#include "ui/views/widget/widget.h"
|
| -
|
| -#if defined(USE_AURA)
|
| -#include "ui/base/cursor/cursor.h"
|
| -#endif
|
| -
|
| -#if defined(OS_WIN) && defined(USE_AURA)
|
| -#include "base/win/win_util.h"
|
| -#endif
|
| -
|
| -namespace {
|
| -
|
| -void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
|
| - DCHECK(src);
|
| -
|
| - gfx::Point new_origin = r->origin();
|
| - views::View::ConvertPointToScreen(src, &new_origin);
|
| - r->set_origin(new_origin);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace views {
|
| -
|
| -const char NativeTextfieldViews::kViewClassName[] =
|
| - "views/NativeTextfieldViews";
|
| -
|
| -NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
|
| - : textfield_(parent),
|
| - model_(new TextfieldViewsModel(this)),
|
| - text_border_(new FocusableBorder()),
|
| - is_cursor_visible_(false),
|
| - is_drop_cursor_visible_(false),
|
| - skip_input_method_cancel_composition_(false),
|
| - initiating_drag_(false),
|
| - cursor_timer_(this),
|
| - aggregated_clicks_(0) {
|
| - set_border(text_border_);
|
| - GetRenderText()->SetFontList(textfield_->font_list());
|
| - UpdateColorsFromTheme(GetNativeTheme());
|
| - set_context_menu_controller(this);
|
| - parent->set_context_menu_controller(this);
|
| - set_drag_controller(this);
|
| -}
|
| -
|
| -NativeTextfieldViews::~NativeTextfieldViews() {
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, View overrides:
|
| -
|
| -bool NativeTextfieldViews::OnMousePressed(const ui::MouseEvent& event) {
|
| - OnBeforeUserAction();
|
| - TrackMouseClicks(event);
|
| -
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (!(controller && controller->HandleMouseEvent(textfield_, event)) &&
|
| - !textfield_->OnMousePressed(event)) {
|
| - HandleMousePressEvent(event);
|
| - }
|
| -
|
| - OnAfterUserAction();
|
| - touch_selection_controller_.reset();
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::ExceededDragThresholdFromLastClickLocation(
|
| - const ui::MouseEvent& event) {
|
| - return ExceededDragThreshold(event.location() - last_click_location_);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::OnMouseDragged(const ui::MouseEvent& event) {
|
| - // Don't adjust the cursor on a potential drag and drop, or if the mouse
|
| - // movement from the last mouse click does not exceed the drag threshold.
|
| - if (initiating_drag_ || !ExceededDragThresholdFromLastClickLocation(event) ||
|
| - !event.IsOnlyLeftMouseButton()) {
|
| - return true;
|
| - }
|
| -
|
| - OnBeforeUserAction();
|
| - // TODO: Remove once NativeTextfield implementations are consolidated to
|
| - // Textfield.
|
| - if (!textfield_->OnMouseDragged(event)) {
|
| - MoveCursorTo(event.location(), true);
|
| - if (aggregated_clicks_ == 1) {
|
| - model_->SelectWord();
|
| - // Expand the selection so the initially selected word remains selected.
|
| - gfx::Range selection = GetRenderText()->selection();
|
| - const size_t min = std::min(selection.GetMin(),
|
| - double_click_word_.GetMin());
|
| - const size_t max = std::max(selection.GetMax(),
|
| - double_click_word_.GetMax());
|
| - const bool reversed = selection.is_reversed();
|
| - selection.set_start(reversed ? max : min);
|
| - selection.set_end(reversed ? min : max);
|
| - model_->SelectRange(selection);
|
| - }
|
| - SchedulePaint();
|
| - }
|
| - OnAfterUserAction();
|
| - return true;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnMouseReleased(const ui::MouseEvent& event) {
|
| - OnBeforeUserAction();
|
| - // TODO: Remove once NativeTextfield implementations are consolidated to
|
| - // Textfield.
|
| - textfield_->OnMouseReleased(event);
|
| - // Cancel suspected drag initiations, the user was clicking in the selection.
|
| - if (initiating_drag_ && MoveCursorTo(event.location(), false))
|
| - SchedulePaint();
|
| - initiating_drag_ = false;
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnGestureEvent(ui::GestureEvent* event) {
|
| - textfield_->OnGestureEvent(event);
|
| - if (event->handled())
|
| - return;
|
| -
|
| - switch (event->type()) {
|
| - case ui::ET_GESTURE_TAP_DOWN:
|
| - OnBeforeUserAction();
|
| - textfield_->RequestFocus();
|
| - // We don't deselect if the point is in the selection
|
| - // because TAP_DOWN may turn into a LONG_PRESS.
|
| - if (!GetRenderText()->IsPointInSelection(event->location()) &&
|
| - MoveCursorTo(event->location(), false))
|
| - SchedulePaint();
|
| - OnAfterUserAction();
|
| - event->SetHandled();
|
| - break;
|
| - case ui::ET_GESTURE_SCROLL_UPDATE:
|
| - OnBeforeUserAction();
|
| - if (MoveCursorTo(event->location(), true))
|
| - SchedulePaint();
|
| - OnAfterUserAction();
|
| - event->SetHandled();
|
| - break;
|
| - case ui::ET_GESTURE_SCROLL_END:
|
| - case ui::ET_SCROLL_FLING_START:
|
| - CreateTouchSelectionControllerAndNotifyIt();
|
| - event->SetHandled();
|
| - break;
|
| - case ui::ET_GESTURE_TAP:
|
| - if (event->details().tap_count() == 1) {
|
| - CreateTouchSelectionControllerAndNotifyIt();
|
| - } else {
|
| - OnBeforeUserAction();
|
| - SelectAll(false);
|
| - OnAfterUserAction();
|
| - event->SetHandled();
|
| - }
|
| - break;
|
| - case ui::ET_GESTURE_LONG_PRESS:
|
| - // If long press happens outside selection, select word and show context
|
| - // menu (If touch selection is enabled, context menu is shown by the
|
| - // |touch_selection_controller_|, hence we mark the event handled.
|
| - // Otherwise, the regular context menu will be shown by views).
|
| - // If long press happens in selected text and touch drag drop is enabled,
|
| - // we will turn off touch selection (if one exists) and let views do drag
|
| - // drop.
|
| - if (!GetRenderText()->IsPointInSelection(event->location())) {
|
| - OnBeforeUserAction();
|
| - model_->SelectWord();
|
| - touch_selection_controller_.reset(
|
| - ui::TouchSelectionController::create(this));
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - OnAfterUserAction();
|
| - if (touch_selection_controller_.get())
|
| - event->SetHandled();
|
| - } else if (switches::IsTouchDragDropEnabled()) {
|
| - initiating_drag_ = true;
|
| - touch_selection_controller_.reset();
|
| - } else {
|
| - if (!touch_selection_controller_.get())
|
| - CreateTouchSelectionControllerAndNotifyIt();
|
| - if (touch_selection_controller_.get())
|
| - event->SetHandled();
|
| - }
|
| - return;
|
| - case ui::ET_GESTURE_LONG_TAP:
|
| - if (!touch_selection_controller_.get())
|
| - CreateTouchSelectionControllerAndNotifyIt();
|
| -
|
| - // If touch selection is enabled, the context menu on long tap will be
|
| - // shown by the |touch_selection_controller_|, hence we mark the event
|
| - // handled so views does not try to show context menu on it.
|
| - if (touch_selection_controller_.get())
|
| - event->SetHandled();
|
| - break;
|
| - default:
|
| - View::OnGestureEvent(event);
|
| - return;
|
| - }
|
| - PlatformGestureEventHandling(event);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::OnKeyPressed(const ui::KeyEvent& event) {
|
| - // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on
|
| - // NativeTextfieldViews as it will never gain focus.
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::OnKeyReleased(const ui::KeyEvent& event) {
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -ui::TextInputClient* NativeTextfieldViews::GetTextInputClient() {
|
| - return textfield_->read_only() ? NULL : this;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetDropFormats(
|
| - int* formats,
|
| - std::set<OSExchangeData::CustomFormat>* custom_formats) {
|
| - if (!textfield_->enabled() || textfield_->read_only())
|
| - return false;
|
| - // TODO(msw): Can we support URL, FILENAME, etc.?
|
| - *formats = ui::OSExchangeData::STRING;
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->AppendDropFormats(formats, custom_formats);
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
|
| - int formats;
|
| - std::set<OSExchangeData::CustomFormat> custom_formats;
|
| - GetDropFormats(&formats, &custom_formats);
|
| - return textfield_->enabled() && !textfield_->read_only() &&
|
| - data.HasAnyFormat(formats, custom_formats);
|
| -}
|
| -
|
| -int NativeTextfieldViews::OnDragUpdated(const ui::DropTargetEvent& event) {
|
| - DCHECK(CanDrop(event.data()));
|
| -
|
| - const gfx::Range& selection = GetRenderText()->selection();
|
| - drop_cursor_position_ = GetRenderText()->FindCursorPosition(event.location());
|
| - bool in_selection = !selection.is_empty() &&
|
| - selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
|
| - is_drop_cursor_visible_ = !in_selection;
|
| - // TODO(msw): Pan over text when the user drags to the visible text edge.
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -
|
| - if (initiating_drag_) {
|
| - if (in_selection)
|
| - return ui::DragDropTypes::DRAG_NONE;
|
| - return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
|
| - ui::DragDropTypes::DRAG_MOVE;
|
| - }
|
| - return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnDragExited() {
|
| - is_drop_cursor_visible_ = false;
|
| - SchedulePaint();
|
| -}
|
| -
|
| -int NativeTextfieldViews::OnPerformDrop(const ui::DropTargetEvent& event) {
|
| - DCHECK(CanDrop(event.data()));
|
| -
|
| - is_drop_cursor_visible_ = false;
|
| -
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller) {
|
| - int drag_operation = controller->OnDrop(event.data());
|
| - if (drag_operation != ui::DragDropTypes::DRAG_NONE)
|
| - return drag_operation;
|
| - }
|
| -
|
| - DCHECK(!initiating_drag_ ||
|
| - !GetRenderText()->IsPointInSelection(event.location()));
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| -
|
| - gfx::SelectionModel drop_destination_model =
|
| - GetRenderText()->FindCursorPosition(event.location());
|
| - base::string16 text;
|
| - event.data().GetString(&text);
|
| - text = GetTextForDisplay(text);
|
| -
|
| - // Delete the current selection for a drag and drop within this view.
|
| - const bool move = initiating_drag_ && !event.IsControlDown() &&
|
| - event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
|
| - if (move) {
|
| - // Adjust the drop destination if it is on or after the current selection.
|
| - size_t drop = drop_destination_model.caret_pos();
|
| - drop -= GetSelectedRange().Intersect(gfx::Range(0, drop)).length();
|
| - model_->DeleteSelectionAndInsertTextAt(text, drop);
|
| - } else {
|
| - model_->MoveCursorTo(drop_destination_model);
|
| - // Drop always inserts text even if the textfield is not in insert mode.
|
| - model_->InsertText(text);
|
| - }
|
| - skip_input_method_cancel_composition_ = false;
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| - return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnDragDone() {
|
| - initiating_drag_ = false;
|
| - is_drop_cursor_visible_ = false;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
|
| - OnPaintBackground(canvas);
|
| - PaintTextAndCursor(canvas);
|
| - if (textfield_->draw_border())
|
| - OnPaintBorder(canvas);
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnFocus() {
|
| - NOTREACHED();
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnBlur() {
|
| - NOTREACHED();
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnNativeThemeChanged(const ui::NativeTheme* theme) {
|
| - UpdateColorsFromTheme(theme);
|
| -}
|
| -
|
| -void NativeTextfieldViews::SelectRect(const gfx::Point& start,
|
| - const gfx::Point& end) {
|
| - if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
|
| - return;
|
| -
|
| - gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
|
| - gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
|
| - gfx::SelectionModel selection(
|
| - gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
|
| - end_caret.caret_affinity());
|
| -
|
| - OnBeforeUserAction();
|
| - model_->SelectSelectionModel(selection);
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::MoveCaretTo(const gfx::Point& point) {
|
| - SelectRect(point, point);
|
| -}
|
| -
|
| -void NativeTextfieldViews::GetSelectionEndPoints(gfx::Rect* p1,
|
| - gfx::Rect* p2) {
|
| - gfx::RenderText* render_text = GetRenderText();
|
| - const gfx::SelectionModel& sel = render_text->selection_model();
|
| - gfx::SelectionModel start_sel =
|
| - render_text->GetSelectionModelForSelectionStart();
|
| - *p1 = render_text->GetCursorBounds(start_sel, true);
|
| - *p2 = render_text->GetCursorBounds(sel, true);
|
| -}
|
| -
|
| -gfx::Rect NativeTextfieldViews::GetBounds() {
|
| - return bounds();
|
| -}
|
| -
|
| -gfx::NativeView NativeTextfieldViews::GetNativeView() {
|
| - return GetWidget()->GetNativeView();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ConvertPointToScreen(gfx::Point* point) {
|
| - View::ConvertPointToScreen(this, point);
|
| -}
|
| -
|
| -void NativeTextfieldViews::ConvertPointFromScreen(gfx::Point* point) {
|
| - View::ConvertPointFromScreen(this, point);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::DrawsHandles() {
|
| - return false;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OpenContextMenu(const gfx::Point& anchor) {
|
| - touch_selection_controller_.reset();
|
| - ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
|
| -}
|
| -
|
| -gfx::NativeCursor NativeTextfieldViews::GetCursor(const ui::MouseEvent& event) {
|
| - bool in_selection = GetRenderText()->IsPointInSelection(event.location());
|
| - bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
|
| - bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
|
| -#if defined(USE_AURA)
|
| - return text_cursor ? ui::kCursorIBeam : ui::kCursorNull;
|
| -#elif defined(OS_WIN)
|
| - static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
|
| - static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
|
| - return text_cursor ? ibeam : arrow;
|
| -#endif
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, ContextMenuController overrides:
|
| -void NativeTextfieldViews::ShowContextMenuForView(
|
| - View* source,
|
| - const gfx::Point& point,
|
| - ui::MenuSourceType source_type) {
|
| - UpdateContextMenu();
|
| - if (context_menu_runner_->RunMenuAt(GetWidget(), NULL,
|
| - gfx::Rect(point, gfx::Size()), views::MenuItemView::TOPLEFT,
|
| - source_type,
|
| - MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
|
| - MenuRunner::MENU_DELETED)
|
| - return;
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, views::DragController overrides:
|
| -void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
|
| - const gfx::Point& press_pt,
|
| - OSExchangeData* data) {
|
| - DCHECK_NE(ui::DragDropTypes::DRAG_NONE,
|
| - GetDragOperationsForView(sender, press_pt));
|
| - data->SetString(GetSelectedText());
|
| - scoped_ptr<gfx::Canvas> canvas(
|
| - views::GetCanvasForDragImage(textfield_->GetWidget(), size()));
|
| - GetRenderText()->DrawSelectedTextForDrag(canvas.get());
|
| - drag_utils::SetDragImageOnDataObject(*canvas, size(),
|
| - press_pt.OffsetFromOrigin(),
|
| - data);
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnWriteDragData(data);
|
| -}
|
| -
|
| -int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
|
| - const gfx::Point& p) {
|
| - int drag_operations = ui::DragDropTypes::DRAG_COPY;
|
| - if (!textfield_->enabled() || textfield_->IsObscured() ||
|
| - !GetRenderText()->IsPointInSelection(p))
|
| - drag_operations = ui::DragDropTypes::DRAG_NONE;
|
| - else if (sender == this && !textfield_->read_only())
|
| - drag_operations =
|
| - ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnGetDragOperationsForTextfield(&drag_operations);
|
| - return drag_operations;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::CanStartDragForView(View* sender,
|
| - const gfx::Point& press_pt,
|
| - const gfx::Point& p) {
|
| - return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, NativeTextifieldWrapper overrides:
|
| -
|
| -base::string16 NativeTextfieldViews::GetText() const {
|
| - return model_->GetText();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateText() {
|
| - model_->SetText(GetTextForDisplay(textfield_->text()));
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - textfield_->NotifyAccessibilityEvent(
|
| - ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
|
| -}
|
| -
|
| -void NativeTextfieldViews::AppendText(const base::string16& text) {
|
| - if (text.empty())
|
| - return;
|
| - model_->Append(GetTextForDisplay(text));
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::InsertOrReplaceText(const base::string16& text) {
|
| - if (text.empty())
|
| - return;
|
| - model_->InsertText(text);
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -base::i18n::TextDirection NativeTextfieldViews::GetTextDirection() const {
|
| - return GetRenderText()->GetTextDirection();
|
| -}
|
| -
|
| -base::string16 NativeTextfieldViews::GetSelectedText() const {
|
| - return model_->GetSelectedText();
|
| -}
|
| -
|
| -void NativeTextfieldViews::SelectAll(bool reversed) {
|
| - model_->SelectAll(reversed);
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ClearSelection() {
|
| - model_->ClearSelection();
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateBorder() {
|
| - // By default, if a caller calls Textfield::RemoveBorder() and does not set
|
| - // any explicit margins, they should get zero margins. But also call
|
| - // UpdateXXXMargins() so we respect any explicitly-set margins.
|
| - //
|
| - // NOTE: If someday Textfield supports toggling |draw_border_| back on, we'll
|
| - // need to update this conditional to set the insets to their default values.
|
| - if (!textfield_->draw_border())
|
| - text_border_->SetInsets(0, 0, 0, 0);
|
| - UpdateHorizontalMargins();
|
| - UpdateVerticalMargins();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateTextColor() {
|
| - SetColor(textfield_->GetTextColor());
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateBackgroundColor() {
|
| - const SkColor color = textfield_->GetBackgroundColor();
|
| - set_background(Background::CreateSolidBackground(color));
|
| - GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateReadOnly() {
|
| - OnTextInputTypeChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateFont() {
|
| - GetRenderText()->SetFontList(textfield_->font_list());
|
| - OnCaretBoundsChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateIsObscured() {
|
| - GetRenderText()->SetObscured(textfield_->IsObscured());
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - OnTextInputTypeChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateEnabled() {
|
| - SetEnabled(textfield_->enabled());
|
| - SchedulePaint();
|
| - OnTextInputTypeChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateHorizontalMargins() {
|
| - int left, right;
|
| - if (!textfield_->GetHorizontalMargins(&left, &right))
|
| - return;
|
| - gfx::Insets inset = GetInsets();
|
| - text_border_->SetInsets(inset.top(), left, inset.bottom(), right);
|
| - OnBoundsChanged(GetBounds());
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateVerticalMargins() {
|
| - int top, bottom;
|
| - if (!textfield_->GetVerticalMargins(&top, &bottom))
|
| - return;
|
| - gfx::Insets inset = GetInsets();
|
| - text_border_->SetInsets(top, inset.left(), bottom, inset.right());
|
| - OnBoundsChanged(GetBounds());
|
| -}
|
| -
|
| -bool NativeTextfieldViews::IsIMEComposing() const {
|
| - return model_->HasCompositionText();
|
| -}
|
| -
|
| -const gfx::Range& NativeTextfieldViews::GetSelectedRange() const {
|
| - return GetRenderText()->selection();
|
| -}
|
| -
|
| -void NativeTextfieldViews::SelectRange(const gfx::Range& range) {
|
| - model_->SelectRange(range);
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - textfield_->NotifyAccessibilityEvent(
|
| - ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
|
| -}
|
| -
|
| -const gfx::SelectionModel& NativeTextfieldViews::GetSelectionModel() const {
|
| - return GetRenderText()->selection_model();
|
| -}
|
| -
|
| -void NativeTextfieldViews::SelectSelectionModel(
|
| - const gfx::SelectionModel& sel) {
|
| - model_->SelectSelectionModel(sel);
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -size_t NativeTextfieldViews::GetCursorPosition() const {
|
| - return model_->GetCursorPosition();
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetCursorEnabled() const {
|
| - return GetRenderText()->cursor_enabled();
|
| -}
|
| -
|
| -void NativeTextfieldViews::SetCursorEnabled(bool enabled) {
|
| - GetRenderText()->SetCursorEnabled(enabled);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::HandleKeyPressed(const ui::KeyEvent& e) {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - bool handled = false;
|
| - if (controller)
|
| - handled = controller->HandleKeyEvent(textfield_, e);
|
| - touch_selection_controller_.reset();
|
| - return handled || HandleKeyEvent(e);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::HandleKeyReleased(const ui::KeyEvent& e) {
|
| - return false; // crbug.com/127520
|
| -}
|
| -
|
| -void NativeTextfieldViews::HandleFocus() {
|
| - GetRenderText()->set_focused(true);
|
| - is_cursor_visible_ = true;
|
| - SchedulePaint();
|
| - GetInputMethod()->OnFocus();
|
| - OnCaretBoundsChanged();
|
| -
|
| - const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
|
| - if (caret_blink_ms != 0) {
|
| - base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&NativeTextfieldViews::UpdateCursor,
|
| - cursor_timer_.GetWeakPtr()),
|
| - base::TimeDelta::FromMilliseconds(caret_blink_ms));
|
| - }
|
| -}
|
| -
|
| -void NativeTextfieldViews::HandleBlur() {
|
| - GetRenderText()->set_focused(false);
|
| - GetInputMethod()->OnBlur();
|
| - // Stop blinking cursor.
|
| - cursor_timer_.InvalidateWeakPtrs();
|
| - if (is_cursor_visible_) {
|
| - is_cursor_visible_ = false;
|
| - RepaintCursor();
|
| - }
|
| -
|
| - touch_selection_controller_.reset();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ClearEditHistory() {
|
| - model_->ClearEditHistory();
|
| -}
|
| -
|
| -int NativeTextfieldViews::GetFontHeight() {
|
| - return GetRenderText()->font_list().GetHeight();
|
| -}
|
| -
|
| -int NativeTextfieldViews::GetTextfieldBaseline() const {
|
| - return GetRenderText()->GetBaseline();
|
| -}
|
| -
|
| -int NativeTextfieldViews::GetWidthNeededForText() const {
|
| - return GetRenderText()->GetContentWidth() + GetInsets().width();
|
| -}
|
| -
|
| -bool NativeTextfieldViews::HasTextBeingDragged() {
|
| - return initiating_drag_;
|
| -}
|
| -
|
| -gfx::Point NativeTextfieldViews::GetContextMenuLocation() {
|
| - return GetCaretBounds().bottom_right();
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
|
| -
|
| -bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller && controller->HandlesCommand(command_id))
|
| - return controller->IsCommandIdEnabled(command_id);
|
| -
|
| - bool editable = !textfield_->read_only();
|
| - base::string16 result;
|
| - switch (command_id) {
|
| - case IDS_APP_UNDO:
|
| - return editable && model_->CanUndo();
|
| - case IDS_APP_CUT:
|
| - return editable && model_->HasSelection() && !textfield_->IsObscured();
|
| - case IDS_APP_COPY:
|
| - return model_->HasSelection() && !textfield_->IsObscured();
|
| - case IDS_APP_PASTE:
|
| - ui::Clipboard::GetForCurrentThread()->ReadText(
|
| - ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
|
| - return editable && !result.empty();
|
| - case IDS_APP_DELETE:
|
| - return editable && model_->HasSelection();
|
| - case IDS_APP_SELECT_ALL:
|
| - return !model_->GetText().empty();
|
| - default:
|
| - return controller->IsCommandIdEnabled(command_id);
|
| - }
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id,
|
| - ui::Accelerator* accelerator) {
|
| - return false;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::IsItemForCommandIdDynamic(int command_id) const {
|
| - const TextfieldController* controller = textfield_->GetController();
|
| - return controller && controller->IsItemForCommandIdDynamic(command_id);
|
| -}
|
| -
|
| -base::string16 NativeTextfieldViews::GetLabelForCommandId(
|
| - int command_id) const {
|
| - const TextfieldController* controller = textfield_->GetController();
|
| - return controller ? controller->GetLabelForCommandId(command_id) :
|
| - base::string16();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ExecuteCommand(int command_id, int event_flags) {
|
| - touch_selection_controller_.reset();
|
| - if (!IsCommandIdEnabled(command_id))
|
| - return;
|
| -
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller && controller->HandlesCommand(command_id)) {
|
| - controller->ExecuteCommand(command_id, 0);
|
| - } else {
|
| - bool text_changed = false;
|
| - switch (command_id) {
|
| - case IDS_APP_UNDO:
|
| - OnBeforeUserAction();
|
| - text_changed = model_->Undo();
|
| - UpdateAfterChange(text_changed, text_changed);
|
| - OnAfterUserAction();
|
| - break;
|
| - case IDS_APP_CUT:
|
| - OnBeforeUserAction();
|
| - text_changed = Cut();
|
| - UpdateAfterChange(text_changed, text_changed);
|
| - OnAfterUserAction();
|
| - break;
|
| - case IDS_APP_COPY:
|
| - OnBeforeUserAction();
|
| - Copy();
|
| - OnAfterUserAction();
|
| - break;
|
| - case IDS_APP_PASTE:
|
| - OnBeforeUserAction();
|
| - text_changed = Paste();
|
| - UpdateAfterChange(text_changed, text_changed);
|
| - OnAfterUserAction();
|
| - break;
|
| - case IDS_APP_DELETE:
|
| - OnBeforeUserAction();
|
| - text_changed = model_->Delete();
|
| - UpdateAfterChange(text_changed, text_changed);
|
| - OnAfterUserAction();
|
| - break;
|
| - case IDS_APP_SELECT_ALL:
|
| - OnBeforeUserAction();
|
| - SelectAll(false);
|
| - UpdateAfterChange(false, true);
|
| - OnAfterUserAction();
|
| - break;
|
| - default:
|
| - controller->ExecuteCommand(command_id, 0);
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void NativeTextfieldViews::SetColor(SkColor value) {
|
| - GetRenderText()->SetColor(value);
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ApplyColor(SkColor value, const gfx::Range& range) {
|
| - GetRenderText()->ApplyColor(value, range);
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::SetStyle(gfx::TextStyle style, bool value) {
|
| - GetRenderText()->SetStyle(style, value);
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ApplyStyle(gfx::TextStyle style,
|
| - bool value,
|
| - const gfx::Range& range) {
|
| - GetRenderText()->ApplyStyle(style, value, range);
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
|
| - // Set the RenderText display area.
|
| - gfx::Insets insets = GetInsets();
|
| - gfx::Rect display_rect(insets.left(),
|
| - insets.top(),
|
| - width() - insets.width(),
|
| - height() - insets.height());
|
| - GetRenderText()->SetDisplayRect(display_rect);
|
| - OnCaretBoundsChanged();
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// NativeTextfieldViews, ui::TextInputClient implementation, private:
|
| -
|
| -void NativeTextfieldViews::SetCompositionText(
|
| - const ui::CompositionText& composition) {
|
| - if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
|
| - return;
|
| -
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| - model_->SetCompositionText(composition);
|
| - skip_input_method_cancel_composition_ = false;
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ConfirmCompositionText() {
|
| - if (!model_->HasCompositionText())
|
| - return;
|
| -
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| - model_->ConfirmCompositionText();
|
| - skip_input_method_cancel_composition_ = false;
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::ClearCompositionText() {
|
| - if (!model_->HasCompositionText())
|
| - return;
|
| -
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| - model_->CancelCompositionText();
|
| - skip_input_method_cancel_composition_ = false;
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::InsertText(const base::string16& text) {
|
| - // TODO(suzhe): Filter invalid characters.
|
| - if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
|
| - return;
|
| -
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| - if (GetRenderText()->insert_mode())
|
| - model_->InsertText(GetTextForDisplay(text));
|
| - else
|
| - model_->ReplaceText(GetTextForDisplay(text));
|
| - skip_input_method_cancel_composition_ = false;
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| -}
|
| -
|
| -void NativeTextfieldViews::InsertChar(base::char16 ch, int flags) {
|
| - if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
|
| - !ShouldInsertChar(ch, flags)) {
|
| - return;
|
| - }
|
| -
|
| - OnBeforeUserAction();
|
| - skip_input_method_cancel_composition_ = true;
|
| - if (GetRenderText()->insert_mode())
|
| - model_->InsertChar(ch);
|
| - else
|
| - model_->ReplaceChar(ch);
|
| - skip_input_method_cancel_composition_ = false;
|
| -
|
| - model_->SetText(GetTextForDisplay(GetText()));
|
| -
|
| - UpdateAfterChange(true, true);
|
| - OnAfterUserAction();
|
| -
|
| - if (textfield_->IsObscured()) {
|
| - const base::TimeDelta& reveal_duration =
|
| - textfield_->obscured_reveal_duration();
|
| - if (reveal_duration != base::TimeDelta()) {
|
| - const size_t change_offset = model_->GetCursorPosition();
|
| - DCHECK_GT(change_offset, 0u);
|
| - RevealObscuredChar(change_offset - 1, reveal_duration);
|
| - }
|
| - }
|
| -}
|
| -
|
| -gfx::NativeWindow NativeTextfieldViews::GetAttachedWindow() const {
|
| - // Imagine the following hierarchy.
|
| - // [NativeWidget A] - FocusManager
|
| - // [View]
|
| - // [NativeWidget B]
|
| - // [View]
|
| - // [View X]
|
| - // An important thing is that [NativeWidget A] owns Win32 input focus even
|
| - // when [View X] is logically focused by FocusManager. As a result, an Win32
|
| - // IME may want to interact with the native view of [NativeWidget A] rather
|
| - // than that of [NativeWidget B]. This is why we need to call
|
| - // GetTopLevelWidget() here.
|
| - return GetWidget()->GetTopLevelWidget()->GetNativeView();
|
| -}
|
| -
|
| -ui::TextInputType NativeTextfieldViews::GetTextInputType() const {
|
| - return textfield_->GetTextInputType();
|
| -}
|
| -
|
| -ui::TextInputMode NativeTextfieldViews::GetTextInputMode() const {
|
| - return ui::TEXT_INPUT_MODE_DEFAULT;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::CanComposeInline() const {
|
| - return true;
|
| -}
|
| -
|
| -gfx::Rect NativeTextfieldViews::GetCaretBounds() const {
|
| - // TextInputClient::GetCaretBounds is expected to return a value in screen
|
| - // coordinates.
|
| - gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
|
| - ConvertRectToScreen(this, &rect);
|
| - return rect;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetCompositionCharacterBounds(
|
| - uint32 index,
|
| - gfx::Rect* rect) const {
|
| - DCHECK(rect);
|
| - if (!HasCompositionText())
|
| - return false;
|
| - const gfx::Range& composition_range = GetRenderText()->GetCompositionRange();
|
| - DCHECK(!composition_range.is_empty());
|
| -
|
| - size_t text_index = composition_range.start() + index;
|
| - if (composition_range.end() <= text_index)
|
| - return false;
|
| - if (!GetRenderText()->IsCursorablePosition(text_index)) {
|
| - text_index = GetRenderText()->IndexOfAdjacentGrapheme(
|
| - text_index, gfx::CURSOR_BACKWARD);
|
| - }
|
| - if (text_index < composition_range.start())
|
| - return false;
|
| - const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
|
| - *rect = GetRenderText()->GetCursorBounds(caret, false);
|
| - ConvertRectToScreen(this, rect);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::HasCompositionText() const {
|
| - return model_->HasCompositionText();
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetTextRange(gfx::Range* range) const {
|
| - if (!ImeEditingAllowed())
|
| - return false;
|
| -
|
| - model_->GetTextRange(range);
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetCompositionTextRange(gfx::Range* range) const {
|
| - if (!ImeEditingAllowed())
|
| - return false;
|
| -
|
| - model_->GetCompositionTextRange(range);
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetSelectionRange(gfx::Range* range) const {
|
| - if (!ImeEditingAllowed())
|
| - return false;
|
| - *range = GetSelectedRange();
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::SetSelectionRange(const gfx::Range& range) {
|
| - if (!ImeEditingAllowed() || !range.IsValid())
|
| - return false;
|
| -
|
| - OnBeforeUserAction();
|
| - SelectRange(range);
|
| - OnAfterUserAction();
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::DeleteRange(const gfx::Range& range) {
|
| - if (!ImeEditingAllowed() || range.is_empty())
|
| - return false;
|
| -
|
| - OnBeforeUserAction();
|
| - model_->SelectRange(range);
|
| - if (model_->HasSelection()) {
|
| - model_->DeleteSelection();
|
| - UpdateAfterChange(true, true);
|
| - }
|
| - OnAfterUserAction();
|
| - return true;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::GetTextFromRange(
|
| - const gfx::Range& range,
|
| - base::string16* text) const {
|
| - if (!ImeEditingAllowed() || !range.IsValid())
|
| - return false;
|
| -
|
| - gfx::Range text_range;
|
| - if (!GetTextRange(&text_range) || !text_range.Contains(range))
|
| - return false;
|
| -
|
| - *text = model_->GetTextFromRange(range);
|
| - return true;
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnInputMethodChanged() {
|
| - // TODO(msw): NOTIMPLEMENTED(); see http://crbug.com/140402
|
| -}
|
| -
|
| -bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
|
| - base::i18n::TextDirection direction) {
|
| - // Restore text directionality mode when the indicated direction matches the
|
| - // current forced mode; otherwise, force the mode indicated. This helps users
|
| - // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
|
| - const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
|
| - gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
|
| - if (mode == GetRenderText()->directionality_mode())
|
| - GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
|
| - else
|
| - GetRenderText()->SetDirectionalityMode(mode);
|
| - SchedulePaint();
|
| - return true;
|
| -}
|
| -
|
| -void NativeTextfieldViews::ExtendSelectionAndDelete(
|
| - size_t before,
|
| - size_t after) {
|
| - gfx::Range range = GetSelectedRange();
|
| - DCHECK_GE(range.start(), before);
|
| -
|
| - range.set_start(range.start() - before);
|
| - range.set_end(range.end() + after);
|
| - gfx::Range text_range;
|
| - if (GetTextRange(&text_range) && text_range.Contains(range))
|
| - DeleteRange(range);
|
| -}
|
| -
|
| -void NativeTextfieldViews::EnsureCaretInRect(const gfx::Rect& rect) {
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnCandidateWindowShown() {
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnCandidateWindowUpdated() {
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnCandidateWindowHidden() {
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
|
| - if (skip_input_method_cancel_composition_)
|
| - return;
|
| - DCHECK(textfield_->GetInputMethod());
|
| - textfield_->GetInputMethod()->CancelComposition(textfield_);
|
| -}
|
| -
|
| -gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
|
| - return model_->render_text();
|
| -}
|
| -
|
| -base::string16 NativeTextfieldViews::GetTextForDisplay(
|
| - const base::string16& text) {
|
| - return textfield_->style() & Textfield::STYLE_LOWERCASE ?
|
| - base::i18n::ToLower(text) : text;
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
|
| - UpdateTextColor();
|
| - UpdateBackgroundColor();
|
| - gfx::RenderText* render_text = GetRenderText();
|
| - render_text->set_cursor_color(textfield_->GetTextColor());
|
| - render_text->set_selection_color(theme->GetSystemColor(
|
| - ui::NativeTheme::kColorId_TextfieldSelectionColor));
|
| - render_text->set_selection_background_focused_color(theme->GetSystemColor(
|
| - ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused));
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateCursor() {
|
| - const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
|
| - is_cursor_visible_ = !is_cursor_visible_ || (caret_blink_ms == 0);
|
| - RepaintCursor();
|
| - if (caret_blink_ms != 0) {
|
| - base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&NativeTextfieldViews::UpdateCursor,
|
| - cursor_timer_.GetWeakPtr()),
|
| - base::TimeDelta::FromMilliseconds(caret_blink_ms));
|
| - }
|
| -}
|
| -
|
| -void NativeTextfieldViews::RepaintCursor() {
|
| - gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
|
| - r.Inset(-1, -1, -1, -1);
|
| - SchedulePaintInRect(r);
|
| -}
|
| -
|
| -void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
|
| - TRACE_EVENT0("views", "NativeTextfieldViews::PaintTextAndCursor");
|
| - canvas->Save();
|
| - GetRenderText()->set_cursor_visible(!is_drop_cursor_visible_ &&
|
| - is_cursor_visible_ && !model_->HasSelection());
|
| - // Draw the text, cursor, and selection.
|
| - GetRenderText()->Draw(canvas);
|
| -
|
| - // Draw the detached drop cursor that marks where the text will be dropped.
|
| - if (is_drop_cursor_visible_)
|
| - GetRenderText()->DrawCursor(canvas, drop_cursor_position_);
|
| -
|
| - // Draw placeholder text if needed.
|
| - if (model_->GetText().empty() &&
|
| - !textfield_->GetPlaceholderText().empty()) {
|
| - canvas->DrawStringRect(
|
| - textfield_->GetPlaceholderText(),
|
| - GetRenderText()->font_list(),
|
| - textfield_->placeholder_text_color(),
|
| - GetRenderText()->display_rect());
|
| - }
|
| - canvas->Restore();
|
| -}
|
| -
|
| -bool NativeTextfieldViews::HandleKeyEvent(const ui::KeyEvent& key_event) {
|
| - // TODO(oshima): Refactor and consolidate with ExecuteCommand.
|
| - if (key_event.type() == ui::ET_KEY_PRESSED) {
|
| - ui::KeyboardCode key_code = key_event.key_code();
|
| - if (key_code == ui::VKEY_TAB || key_event.IsUnicodeKeyCode())
|
| - return false;
|
| -
|
| - OnBeforeUserAction();
|
| - const bool editable = !textfield_->read_only();
|
| - const bool readable = !textfield_->IsObscured();
|
| - const bool shift = key_event.IsShiftDown();
|
| - const bool control = key_event.IsControlDown();
|
| - const bool alt = key_event.IsAltDown() || key_event.IsAltGrDown();
|
| - bool text_changed = false;
|
| - bool cursor_changed = false;
|
| - switch (key_code) {
|
| - case ui::VKEY_Z:
|
| - if (control && !shift && !alt && editable)
|
| - cursor_changed = text_changed = model_->Undo();
|
| - else if (control && shift && !alt && editable)
|
| - cursor_changed = text_changed = model_->Redo();
|
| - break;
|
| - case ui::VKEY_Y:
|
| - if (control && !alt && editable)
|
| - cursor_changed = text_changed = model_->Redo();
|
| - break;
|
| - case ui::VKEY_A:
|
| - if (control && !alt) {
|
| - model_->SelectAll(false);
|
| - cursor_changed = true;
|
| - }
|
| - break;
|
| - case ui::VKEY_X:
|
| - if (control && !alt && editable && readable)
|
| - cursor_changed = text_changed = Cut();
|
| - break;
|
| - case ui::VKEY_C:
|
| - if (control && !alt && readable)
|
| - Copy();
|
| - break;
|
| - case ui::VKEY_V:
|
| - if (control && !alt && editable)
|
| - cursor_changed = text_changed = Paste();
|
| - break;
|
| - case ui::VKEY_RIGHT:
|
| - case ui::VKEY_LEFT: {
|
| - // We should ignore the alt-left/right keys because alt key doesn't make
|
| - // any special effects for them and they can be shortcut keys such like
|
| - // forward/back of the browser history.
|
| - if (alt)
|
| - break;
|
| - const gfx::Range selection_range = GetSelectedRange();
|
| - model_->MoveCursor(
|
| - control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK,
|
| - (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT,
|
| - shift);
|
| - cursor_changed = GetSelectedRange() != selection_range;
|
| - break;
|
| - }
|
| - case ui::VKEY_END:
|
| - case ui::VKEY_HOME:
|
| - if ((key_code == ui::VKEY_HOME) ==
|
| - (GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT))
|
| - model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift);
|
| - else
|
| - model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift);
|
| - cursor_changed = true;
|
| - break;
|
| - case ui::VKEY_BACK:
|
| - case ui::VKEY_DELETE:
|
| - if (!editable)
|
| - break;
|
| - if (!model_->HasSelection()) {
|
| - gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ?
|
| - gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
|
| - if (shift && control) {
|
| - // If both shift and control are pressed, then erase up to the
|
| - // beginning/end of the buffer in ChromeOS. In windows, do nothing.
|
| -#if defined(OS_WIN)
|
| - break;
|
| -#else
|
| - model_->MoveCursor(gfx::LINE_BREAK, direction, true);
|
| -#endif
|
| - } else if (control) {
|
| - // If only control is pressed, then erase the previous/next word.
|
| - model_->MoveCursor(gfx::WORD_BREAK, direction, true);
|
| - }
|
| - }
|
| - if (key_code == ui::VKEY_BACK)
|
| - model_->Backspace();
|
| - else if (shift && model_->HasSelection() && readable)
|
| - Cut();
|
| - else
|
| - model_->Delete();
|
| -
|
| - // Consume backspace and delete keys even if the edit did nothing. This
|
| - // prevents potential unintended side-effects of further event handling.
|
| - text_changed = true;
|
| - break;
|
| - case ui::VKEY_INSERT:
|
| - if (control && !shift && readable)
|
| - Copy();
|
| - else if (shift && !control && editable)
|
| - cursor_changed = text_changed = Paste();
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - // We must have input method in order to support text input.
|
| - DCHECK(textfield_->GetInputMethod());
|
| -
|
| - UpdateAfterChange(text_changed, cursor_changed);
|
| - OnAfterUserAction();
|
| - return (text_changed || cursor_changed);
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
|
| - if (!model_->MoveCursorTo(point, select))
|
| - return false;
|
| - OnCaretBoundsChanged();
|
| - return true;
|
| -}
|
| -
|
| -void NativeTextfieldViews::PropagateTextChange() {
|
| - textfield_->SyncText();
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
|
| - bool cursor_changed) {
|
| - if (text_changed) {
|
| - PropagateTextChange();
|
| - textfield_->NotifyAccessibilityEvent(
|
| - ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
|
| - }
|
| - if (cursor_changed) {
|
| - is_cursor_visible_ = true;
|
| - RepaintCursor();
|
| - if (!text_changed) {
|
| - // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
|
| - // this if only the selection changed.
|
| - textfield_->NotifyAccessibilityEvent(
|
| - ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
|
| - }
|
| - }
|
| - if (text_changed || cursor_changed) {
|
| - OnCaretBoundsChanged();
|
| - SchedulePaint();
|
| - }
|
| -}
|
| -
|
| -void NativeTextfieldViews::UpdateContextMenu() {
|
| - if (!context_menu_contents_.get()) {
|
| - context_menu_contents_.reset(new ui::SimpleMenuModel(this));
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
|
| - context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
|
| - context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
|
| - context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
|
| - IDS_APP_SELECT_ALL);
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->UpdateContextMenu(context_menu_contents_.get());
|
| -
|
| - context_menu_delegate_.reset(
|
| - new views::MenuModelAdapter(context_menu_contents_.get()));
|
| - context_menu_runner_.reset(
|
| - new MenuRunner(new views::MenuItemView(context_menu_delegate_.get())));
|
| - }
|
| -
|
| - context_menu_delegate_->BuildMenu(context_menu_runner_->GetMenu());
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnTextInputTypeChanged() {
|
| - // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
|
| - if (textfield_->GetInputMethod())
|
| - textfield_->GetInputMethod()->OnTextInputTypeChanged(textfield_);
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnCaretBoundsChanged() {
|
| - // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
|
| - if (textfield_->GetInputMethod())
|
| - textfield_->GetInputMethod()->OnCaretBoundsChanged(textfield_);
|
| -
|
| - // Notify selection controller
|
| - if (touch_selection_controller_.get())
|
| - touch_selection_controller_->SelectionChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnBeforeUserAction() {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnBeforeUserAction(textfield_);
|
| -}
|
| -
|
| -void NativeTextfieldViews::OnAfterUserAction() {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnAfterUserAction(textfield_);
|
| -}
|
| -
|
| -bool NativeTextfieldViews::Cut() {
|
| - if (!textfield_->read_only() && !textfield_->IsObscured() && model_->Cut()) {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnAfterCutOrCopy();
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::Copy() {
|
| - if (!textfield_->IsObscured() && model_->Copy()) {
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnAfterCutOrCopy();
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool NativeTextfieldViews::Paste() {
|
| - if (textfield_->read_only())
|
| - return false;
|
| -
|
| - const base::string16 original_text = GetText();
|
| - const bool success = model_->Paste();
|
| -
|
| - if (success) {
|
| - // As Paste is handled in model_->Paste(), the RenderText may contain
|
| - // upper case characters. This is not consistent with other places
|
| - // which keeps RenderText only containing lower case characters.
|
| - base::string16 new_text = GetTextForDisplay(GetText());
|
| - model_->SetText(new_text);
|
| -
|
| - TextfieldController* controller = textfield_->GetController();
|
| - if (controller)
|
| - controller->OnAfterPaste();
|
| - }
|
| - return success;
|
| -}
|
| -
|
| -void NativeTextfieldViews::TrackMouseClicks(const ui::MouseEvent& event) {
|
| - if (event.IsOnlyLeftMouseButton()) {
|
| - base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
|
| - if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
|
| - !ExceededDragThresholdFromLastClickLocation(event)) {
|
| - // Upon clicking after a triple click, the count should go back to double
|
| - // click and alternate between double and triple. This assignment maps
|
| - // 0 to 1, 1 to 2, 2 to 1.
|
| - aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
|
| - } else {
|
| - aggregated_clicks_ = 0;
|
| - }
|
| - last_click_time_ = event.time_stamp();
|
| - last_click_location_ = event.location();
|
| - }
|
| -}
|
| -
|
| -void NativeTextfieldViews::HandleMousePressEvent(const ui::MouseEvent& event) {
|
| - if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())
|
| - textfield_->RequestFocus();
|
| -
|
| - if (!event.IsOnlyLeftMouseButton())
|
| - return;
|
| -
|
| - initiating_drag_ = false;
|
| - bool can_drag = true;
|
| -
|
| - switch (aggregated_clicks_) {
|
| - case 0:
|
| - if (can_drag && GetRenderText()->IsPointInSelection(event.location()))
|
| - initiating_drag_ = true;
|
| - else
|
| - MoveCursorTo(event.location(), event.IsShiftDown());
|
| - break;
|
| - case 1:
|
| - MoveCursorTo(event.location(), false);
|
| - model_->SelectWord();
|
| - double_click_word_ = GetRenderText()->selection();
|
| - OnCaretBoundsChanged();
|
| - break;
|
| - case 2:
|
| - model_->SelectAll(false);
|
| - OnCaretBoundsChanged();
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - SchedulePaint();
|
| -}
|
| -
|
| -bool NativeTextfieldViews::ImeEditingAllowed() const {
|
| - // We don't allow the input method to retrieve or delete content from a
|
| - // password field.
|
| - ui::TextInputType t = GetTextInputType();
|
| - return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
|
| -}
|
| -
|
| -// static
|
| -bool NativeTextfieldViews::ShouldInsertChar(base::char16 ch, int flags) {
|
| - // Filter out all control characters, including tab and new line characters,
|
| - // and all characters with Alt modifier. But we need to allow characters with
|
| - // AltGr modifier.
|
| - // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
|
| - // flag that we don't care about.
|
| - return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
|
| - (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
|
| -}
|
| -
|
| -void NativeTextfieldViews::CreateTouchSelectionControllerAndNotifyIt() {
|
| - if (!touch_selection_controller_) {
|
| - touch_selection_controller_.reset(
|
| - ui::TouchSelectionController::create(this));
|
| - }
|
| - if (touch_selection_controller_)
|
| - touch_selection_controller_->SelectionChanged();
|
| -}
|
| -
|
| -void NativeTextfieldViews::PlatformGestureEventHandling(
|
| - const ui::GestureEvent* event) {
|
| -#if defined(OS_WIN) && defined(USE_AURA)
|
| - if (event->type() == ui::ET_GESTURE_TAP && !textfield_->read_only())
|
| - base::win::DisplayVirtualKeyboard();
|
| -#endif
|
| -}
|
| -
|
| -void NativeTextfieldViews::RevealObscuredChar(int index,
|
| - const base::TimeDelta& duration) {
|
| - GetRenderText()->SetObscuredRevealIndex(index);
|
| - SchedulePaint();
|
| -
|
| - if (index != -1) {
|
| - obscured_reveal_timer_.Start(
|
| - FROM_HERE,
|
| - duration,
|
| - base::Bind(&NativeTextfieldViews::RevealObscuredChar,
|
| - base::Unretained(this), -1, base::TimeDelta()));
|
| - }
|
| -}
|
| -
|
| -} // namespace views
|
|
|