diff options
34 files changed, 2020 insertions, 3011 deletions
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc index a67a739..ac910f1 100644 --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc @@ -208,9 +208,9 @@ class SectionRowView : public views::View { int end_x = bounds.width(); views::View* decorated = child_at(2); if (decorated->visible()) { - decorated->SizeToPreferredSize(); - decorated->SetX(bounds.width() - decorated->bounds().width()); - decorated->SetY(bounds.y()); + const int preferred_width = decorated->GetPreferredSize().width(); + decorated->SetBounds(bounds.width() - preferred_width, bounds.y(), + preferred_width, bounds.height()); end_x = decorated->bounds().x() - kAroundTextPadding; } diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.cc b/chrome/browser/ui/views/autofill/decorated_textfield.cc index fa3e816..94e8202 100644 --- a/chrome/browser/ui/views/autofill/decorated_textfield.cc +++ b/chrome/browser/ui/views/autofill/decorated_textfield.cc @@ -10,7 +10,6 @@ #include "ui/views/background.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/focusable_border.h" -#include "ui/views/controls/textfield/native_textfield_views.h" #include "ui/views/controls/textfield/textfield_controller.h" namespace { @@ -25,38 +24,28 @@ namespace autofill { // static const char DecoratedTextfield::kViewClassName[] = "autofill/DecoratedTextfield"; -const int DecoratedTextfield::kMagicInsetNumber = 6; - DecoratedTextfield::DecoratedTextfield( const base::string16& default_value, const base::string16& placeholder, views::TextfieldController* controller) - : border_(new views::FocusableBorder()), - invalid_(false), + : invalid_(false), editable_(true) { UpdateBackground(); - - set_border(border_); - // Removes the border from |native_wrapper_|. - RemoveBorder(); + UpdateBorder(); set_placeholder_text(placeholder); SetText(default_value); SetController(controller); - SetHorizontalMargins(0, 0); } DecoratedTextfield::~DecoratedTextfield() {} void DecoratedTextfield::SetInvalid(bool invalid) { - invalid_ = invalid; - if (!editable_) + if (invalid_ == invalid) return; - if (invalid) - border_->SetColor(kWarningColor); - else - border_->UseDefaultColor(); + invalid_ = invalid; + UpdateBorder(); SchedulePaint(); } @@ -65,14 +54,7 @@ void DecoratedTextfield::SetEditable(bool editable) { return; editable_ = editable; - if (editable) { - SetInvalid(invalid_); - UseDefaultBackgroundColor(); - } else { - border_->SetColor(SK_ColorTRANSPARENT); - SetBackgroundColor(SK_ColorTRANSPARENT); - } - + UpdateBorder(); UpdateBackground(); SetEnabled(editable); IconChanged(); @@ -111,10 +93,7 @@ void DecoratedTextfield::SetTooltipIcon(const base::string16& text) { } base::string16 DecoratedTextfield::GetPlaceholderText() const { - if (!editable_) - return base::string16(); - - return views::Textfield::GetPlaceholderText(); + return editable_ ? views::Textfield::GetPlaceholderText() : base::string16(); } const char* DecoratedTextfield::GetClassName() const { @@ -125,25 +104,14 @@ views::View* DecoratedTextfield::GetEventHandlerForRect(const gfx::Rect& rect) { views::View* handler = views::Textfield::GetEventHandlerForRect(rect); if (handler->GetClassName() == TooltipIcon::kViewClassName) return handler; - return textfield_view_; -} - -void DecoratedTextfield::OnFocus() { - views::Textfield::OnFocus(); - SchedulePaint(); -} - -void DecoratedTextfield::OnBlur() { - views::Textfield::OnBlur(); - SchedulePaint(); + return this; } gfx::Size DecoratedTextfield::GetPreferredSize() { - int w = views::Textfield::GetPreferredSize().width(); - views::LabelButton button(NULL, base::string16()); - button.SetStyle(views::Button::STYLE_BUTTON); - int h = button.GetPreferredSize().height(); - return gfx::Size(w, h - kMagicInsetNumber); + static const int height = + views::LabelButton(NULL, base::string16()).GetPreferredSize().height(); + const gfx::Size size = views::Textfield::GetPreferredSize(); + return gfx::Size(size.width(), std::max(size.height(), height)); } void DecoratedTextfield::Layout() { @@ -157,29 +125,45 @@ void DecoratedTextfield::Layout() { bounds.right() - icon_size.width() - kTextfieldIconPadding; // Vertically centered. int y = bounds.y() + (bounds.height() - icon_size.height()) / 2; - icon_view_->SetBounds(x, - y, - icon_size.width(), - icon_size.height()); + icon_view_->SetBounds(x, y, icon_size.width(), icon_size.height()); } } void DecoratedTextfield::UpdateBackground() { + if (editable_) + UseDefaultBackgroundColor(); + else + SetBackgroundColor(SK_ColorTRANSPARENT); set_background( views::Background::CreateSolidBackground(GetBackgroundColor())); } -void DecoratedTextfield::IconChanged() { - // Don't show the icon if nothing else is showing. - icon_view_->SetVisible(editable_ || !text().empty()); +void DecoratedTextfield::UpdateBorder() { + views::FocusableBorder* border = new views::FocusableBorder(); + if (invalid_) + border->SetColor(kWarningColor); + else if (!editable_) + border->SetColor(SK_ColorTRANSPARENT); - int icon_space = icon_view_ ? + const gfx::Insets insets = GetInsets(); + int left = icon_view_ ? icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding : 0; + int right = 0; + if (base::i18n::IsRTL()) + std::swap(left, right); + border->SetInsets(insets.top(), insets.left() + left, insets.bottom(), + insets.right() + right); + set_border(border); +} - bool is_rtl = base::i18n::IsRTL(); - SetHorizontalMargins(is_rtl ? icon_space : 0, is_rtl ? 0 : icon_space); +void DecoratedTextfield::IconChanged() { + // Don't show the icon if nothing else is showing. + const bool visible = editable_ || !text().empty(); + if (icon_view_->visible() == visible) + return; - Layout(); + icon_view_->SetVisible(visible); + UpdateBorder(); SchedulePaint(); } diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.h b/chrome/browser/ui/views/autofill/decorated_textfield.h index 69d6a3c..5a4d348 100644 --- a/chrome/browser/ui/views/autofill/decorated_textfield.h +++ b/chrome/browser/ui/views/autofill/decorated_textfield.h @@ -11,7 +11,7 @@ #include "ui/views/controls/textfield/textfield.h" namespace views { -class FocusableBorder; +class ImageView; class TextfieldController; } @@ -36,8 +36,7 @@ class DecoratedTextfield : public views::Textfield { void SetEditable(bool editable); bool editable() const { return editable_; } - // Sets the icon to be displayed inside the textfield at the end of the - // text. + // Sets the icon to display inside the textfield at the end of the text. void SetIcon(const gfx::Image& icon); // Sets a tooltip for this field. This will override the icon set with @@ -52,28 +51,18 @@ class DecoratedTextfield : public views::Textfield { virtual gfx::Size GetPreferredSize() OVERRIDE; virtual void Layout() OVERRIDE; virtual views::View* GetEventHandlerForRect(const gfx::Rect& rect) OVERRIDE; - virtual void OnFocus() OVERRIDE; - virtual void OnBlur() OVERRIDE; private: FRIEND_TEST_ALL_PREFIXES(DecoratedTextfieldTest, HeightMatchesButton); - // Updates the background of |this| after it may have changed. This is - // necessary for the sake of the padding around the native textfield. + // Updates the background after its color may have changed. void UpdateBackground(); - // Called to update the layout after SetIcon or SetTooltipIcon has been - // called. - void IconChanged(); - - // This number corresponds to the number of pixels in the images that - // are used to draw a views button which are above or below the actual border. - // This number is encoded in the button assets themselves, so there's no other - // way to get it than to hardcode it here. - static const int kMagicInsetNumber; + // Updates the border after its color or insets may have changed. + void UpdateBorder(); - // We draw the border. - views::FocusableBorder* border_; // Weak. + // Called to update the layout after SetIcon or SetTooltipIcon was called. + void IconChanged(); // The view that holds the icon at the end of the textfield. scoped_ptr<views::ImageView> icon_view_; diff --git a/chrome/browser/ui/views/autofill/decorated_textfield_unittest.cc b/chrome/browser/ui/views/autofill/decorated_textfield_unittest.cc deleted file mode 100644 index d027dd5..0000000 --- a/chrome/browser/ui/views/autofill/decorated_textfield_unittest.cc +++ /dev/null @@ -1,23 +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 "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/views/autofill/decorated_textfield.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/controls/button/label_button.h" - -namespace autofill { - -TEST(DecoratedTextfieldTest, HeightMatchesButton) { - DecoratedTextfield textfield(base::ASCIIToUTF16("default"), - base::ASCIIToUTF16("placeholder"), - NULL); - views::LabelButton button(NULL, base::ASCIIToUTF16("anyoldtext"));; - button.SetStyle(views::Button::STYLE_BUTTON); - EXPECT_EQ(button.GetPreferredSize().height() - - DecoratedTextfield::kMagicInsetNumber, - textfield.GetPreferredSize().height()); -} - -} // namespace autofill diff --git a/chrome/browser/ui/views/cookie_info_view.cc b/chrome/browser/ui/views/cookie_info_view.cc index cea3dd4..09a66c7 100644 --- a/chrome/browser/ui/views/cookie_info_view.cc +++ b/chrome/browser/ui/views/cookie_info_view.cc @@ -128,7 +128,7 @@ void CookieInfoView::AddLabelRow(int layout_id, views::GridLayout* layout, // Now that the Textfield is in the view hierarchy, it can be initialized. text_field->SetReadOnly(true); - text_field->RemoveBorder(); + text_field->set_border(NULL); // Color these borderless text areas the same as the containing dialog. text_field->SetBackgroundColor(GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_DialogBackground)); diff --git a/chrome/browser/ui/views/dropdown_bar_host.h b/chrome/browser/ui/views/dropdown_bar_host.h index 935866a..6221079 100644 --- a/chrome/browser/ui/views/dropdown_bar_host.h +++ b/chrome/browser/ui/views/dropdown_bar_host.h @@ -11,7 +11,6 @@ #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" -#include "ui/views/controls/textfield/textfield.h" #include "ui/views/focus/focus_manager.h" class BrowserView; diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index a87902d..6b9ef16 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc @@ -28,6 +28,7 @@ #include "ui/base/theme_provider.h" #include "ui/events/event.h" #include "ui/gfx/canvas.h" +#include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" @@ -85,6 +86,10 @@ FindBarView::FindBarView(FindBarHost* host) find_text_->set_default_width_in_chars(kDefaultCharWidth); find_text_->SetController(this); find_text_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FIND)); + // The find bar textfield has a background image instead of a border. + const gfx::Insets insets = find_text_->GetInsets(); + find_text_->set_border( + views::Border::CreateEmptyBorder(insets.top(), 0, insets.bottom(), 2)); AddChildView(find_text_); @@ -339,14 +344,6 @@ void FindBarView::Layout() { find_previous_button_->height()); } -void FindBarView::ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) { - if (details.is_add && details.child == this) { - find_text_->SetHorizontalMargins(0, 2); // Left and Right margins. - find_text_->RemoveBorder(); // We draw our own border (a background image). - } -} - gfx::Size FindBarView::GetPreferredSize() { gfx::Size prefsize = find_text_->GetPreferredSize(); prefsize.set_height(preferred_height_); diff --git a/chrome/browser/ui/views/find_bar_view.h b/chrome/browser/ui/views/find_bar_view.h index d251095..7c41f36 100644 --- a/chrome/browser/ui/views/find_bar_view.h +++ b/chrome/browser/ui/views/find_bar_view.h @@ -70,8 +70,6 @@ class FindBarView : public DropdownBarView, virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; virtual void Layout() OVERRIDE; virtual gfx::Size GetPreferredSize() OVERRIDE; - virtual void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) OVERRIDE; // views::ButtonListener: virtual void ButtonPressed(views::Button* sender, diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 57ae514..d79cf62 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc @@ -906,7 +906,9 @@ void LocationBarView::Layout() { } } - omnibox_view_->SetHorizontalMargins(0, omnibox_view_margin); + const gfx::Insets insets = omnibox_view_->GetInsets(); + omnibox_view_->set_border(views::Border::CreateEmptyBorder( + insets.top(), insets.left(), insets.bottom(), omnibox_view_margin)); // Layout |ime_inline_autocomplete_view_| next to the user input. if (ime_inline_autocomplete_view_->visible()) { diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index b92cb69..b302ca3 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h @@ -59,6 +59,7 @@ struct SSLStatus; namespace views { class BubbleDelegateView; class ImageButton; +class ImageView; class Label; class LabelButton; class Widget; diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 4ba3789..48427d2 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc @@ -44,7 +44,6 @@ #include "ui/gfx/selection_model.h" #include "ui/views/border.h" #include "ui/views/button_drag_utils.h" -#include "ui/views/controls/textfield/native_textfield_views.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/ime/input_method.h" #include "ui/views/layout/fill_layout.h" @@ -143,7 +142,7 @@ OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller, ime_candidate_window_open_(false), select_all_on_mouse_release_(false), select_all_on_gesture_tap_(false) { - RemoveBorder(); + set_border(NULL); set_id(VIEW_ID_OMNIBOX); SetFontList(font_list); } @@ -176,7 +175,7 @@ void OmniboxViewViews::Init() { // Initialize the popup view using the same font. popup_view_.reset(OmniboxPopupContentsView::Create( - font_list(), this, model(), location_bar_view_)); + GetFontList(), this, model(), location_bar_view_)); #if defined(OS_CHROMEOS) chromeos::input_method::InputMethodManager::Get()-> @@ -192,15 +191,14 @@ const char* OmniboxViewViews::GetClassName() const { } void OmniboxViewViews::OnGestureEvent(ui::GestureEvent* event) { - views::Textfield::OnGestureEvent(event); if (!HasFocus() && event->type() == ui::ET_GESTURE_TAP_DOWN) { select_all_on_gesture_tap_ = true; // If we're trying to select all on tap, invalidate any saved selection lest // restoring it fights with the "select all" action. saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); - return; } + if (select_all_on_gesture_tap_ && event->type() == ui::ET_GESTURE_TAP) SelectAll(false); @@ -213,6 +211,8 @@ void OmniboxViewViews::OnGestureEvent(ui::GestureEvent* event) { event->type() == ui::ET_GESTURE_LONG_TAP) { select_all_on_gesture_tap_ = false; } + + views::Textfield::OnGestureEvent(event); } void OmniboxViewViews::GetAccessibleState(ui::AccessibleViewState* state) { @@ -674,7 +674,9 @@ base::string16 OmniboxViewViews::GetGrayTextAutocompletion() const { } int OmniboxViewViews::GetTextWidth() const { - return textfield_view_->GetWidthNeededForText(); + // Returns the width necessary to display the current text, including any + // necessary space for the cursor or border/margin. + return GetRenderText()->GetContentWidth() + GetInsets().width(); } int OmniboxViewViews::GetWidth() const { @@ -694,6 +696,54 @@ bool OmniboxViewViews::IsImeShowingPopup() const { #endif } +bool OmniboxViewViews::IsCommandIdEnabled(int command_id) const { + if (command_id == IDS_APP_PASTE) + return !read_only() && !GetClipboardText().empty(); + if (command_id == IDS_PASTE_AND_GO) + return !read_only() && model()->CanPasteAndGo(GetClipboardText()); + if (command_id == IDS_SHOW_URL) + return controller()->GetToolbarModel()->WouldReplaceURL(); + return Textfield::IsCommandIdEnabled(command_id) || + command_updater()->IsCommandEnabled(command_id); +} + +bool OmniboxViewViews::IsItemForCommandIdDynamic(int command_id) const { + return command_id == IDS_PASTE_AND_GO; +} + +base::string16 OmniboxViewViews::GetLabelForCommandId(int command_id) const { + DCHECK_EQ(IDS_PASTE_AND_GO, command_id); + return l10n_util::GetStringUTF16( + model()->IsPasteAndSearch(GetClipboardText()) ? + IDS_PASTE_AND_SEARCH : IDS_PASTE_AND_GO); +} + +void OmniboxViewViews::ExecuteCommand(int command_id, int event_flags) { + switch (command_id) { + // These commands don't invoke the popup via OnBefore/AfterPossibleChange(). + case IDS_PASTE_AND_GO: + model()->PasteAndGo(GetClipboardText()); + break; + case IDS_SHOW_URL: + ShowURL(); + break; + case IDC_EDIT_SEARCH_ENGINES: + command_updater()->ExecuteCommand(command_id); + break; + + default: + OnBeforePossibleChange(); + if (command_id == IDS_APP_PASTE) + OnPaste(); + else if (Textfield::IsCommandIdEnabled(command_id)) + Textfield::ExecuteCommand(command_id, event_flags); + else + command_updater()->ExecuteCommand(command_id); + OnAfterPossibleChange(); + break; + } +} + //////////////////////////////////////////////////////////////////////////////// // OmniboxViewViews, views::TextfieldController implementation: @@ -851,56 +901,6 @@ void OmniboxViewViews::UpdateContextMenu(ui::SimpleMenuModel* menu_contents) { IDS_EDIT_SEARCH_ENGINES); } -bool OmniboxViewViews::IsCommandIdEnabled(int command_id) const { - if (command_id == IDS_APP_PASTE) - return !read_only() && !GetClipboardText().empty(); - if (command_id == IDS_PASTE_AND_GO) - return !read_only() && model()->CanPasteAndGo(GetClipboardText()); - if (command_id == IDS_SHOW_URL) - return controller()->GetToolbarModel()->WouldReplaceURL(); - return command_updater()->IsCommandEnabled(command_id); -} - -bool OmniboxViewViews::IsItemForCommandIdDynamic(int command_id) const { - return command_id == IDS_PASTE_AND_GO; -} - -base::string16 OmniboxViewViews::GetLabelForCommandId(int command_id) const { - DCHECK_EQ(IDS_PASTE_AND_GO, command_id); - return l10n_util::GetStringUTF16( - model()->IsPasteAndSearch(GetClipboardText()) ? - IDS_PASTE_AND_SEARCH : IDS_PASTE_AND_GO); -} - -bool OmniboxViewViews::HandlesCommand(int command_id) const { - // See description in OnPaste() for details on why we need to handle paste. - return command_id == IDS_APP_PASTE; -} - -void OmniboxViewViews::ExecuteCommand(int command_id, int event_flags) { - switch (command_id) { - // These commands don't invoke the popup via OnBefore/AfterPossibleChange(). - case IDS_PASTE_AND_GO: - model()->PasteAndGo(GetClipboardText()); - break; - case IDS_SHOW_URL: - ShowURL(); - break; - case IDC_EDIT_SEARCH_ENGINES: - command_updater()->ExecuteCommand(command_id); - break; - - default: - OnBeforePossibleChange(); - if (command_id == IDS_APP_PASTE) - OnPaste(); - else - command_updater()->ExecuteCommand(command_id); - OnAfterPossibleChange(); - break; - } -} - #if defined(OS_CHROMEOS) void OmniboxViewViews::CandidateWindowOpened( chromeos::input_method::InputMethodManager* manager) { diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h index 70ee35c..07154a3 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h @@ -110,6 +110,10 @@ class OmniboxViewViews virtual int GetWidth() const OVERRIDE; virtual bool IsImeComposing() const OVERRIDE; virtual bool IsImeShowingPopup() const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; + virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; + virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; // views::TextfieldController: virtual void ContentsChanged(views::Textfield* sender, @@ -126,11 +130,6 @@ class OmniboxViewViews std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE; virtual int OnDrop(const ui::OSExchangeData& data) OVERRIDE; virtual void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) OVERRIDE; - virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; - virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; - virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; - virtual bool HandlesCommand(int command_id) const OVERRIDE; - virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; #if defined(OS_CHROMEOS) // chromeos::input_method::InputMethodManager::CandidateWindowObserver: diff --git a/chrome/browser/ui/views/password_generation_bubble_view.cc b/chrome/browser/ui/views/password_generation_bubble_view.cc index 7aa8e27..c93243d 100644 --- a/chrome/browser/ui/views/password_generation_bubble_view.cc +++ b/chrome/browser/ui/views/password_generation_bubble_view.cc @@ -68,7 +68,6 @@ TextfieldWrapper::TextfieldWrapper(views::Textfield* textfield, views::ImageButton* image_button) : textfield_(textfield), image_button_(image_button) { - textfield_->RemoveBorder(); set_border(views::Border::CreateSolidBorder(kWrapperBorderSize, SK_ColorGRAY)); diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 2a0a6f4..ed7f12b 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1695,7 +1695,6 @@ 'browser/ui/views/accelerator_table_unittest.cc', 'browser/ui/views/accessibility/accessibility_event_router_views_unittest.cc', 'browser/ui/views/autofill/autofill_dialog_views_unittest.cc', - 'browser/ui/views/autofill/decorated_textfield_unittest.cc', 'browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc', 'browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc', 'browser/ui/views/bookmarks/bookmark_context_menu_test.cc', diff --git a/content/browser/web_contents/touch_editable_impl_aura.cc b/content/browser/web_contents/touch_editable_impl_aura.cc index ed002c7..8bf497d 100644 --- a/content/browser/web_contents/touch_editable_impl_aura.cc +++ b/content/browser/web_contents/touch_editable_impl_aura.cc @@ -251,7 +251,7 @@ gfx::Rect TouchEditableImplAura::GetBounds() { return rwhva_ ? rwhva_->GetNativeView()->bounds() : gfx::Rect(); } -gfx::NativeView TouchEditableImplAura::GetNativeView() { +gfx::NativeView TouchEditableImplAura::GetNativeView() const { return rwhva_ ? rwhva_->GetNativeView()->GetRootWindow() : NULL; } diff --git a/content/browser/web_contents/touch_editable_impl_aura.h b/content/browser/web_contents/touch_editable_impl_aura.h index 1855f1d..2758702 100644 --- a/content/browser/web_contents/touch_editable_impl_aura.h +++ b/content/browser/web_contents/touch_editable_impl_aura.h @@ -57,7 +57,7 @@ class CONTENT_EXPORT TouchEditableImplAura virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE; virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE; virtual gfx::Rect GetBounds() OVERRIDE; - virtual gfx::NativeView GetNativeView() OVERRIDE; + virtual gfx::NativeView GetNativeView() const OVERRIDE; virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE; virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE; virtual bool DrawsHandles() OVERRIDE; diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc index 302514d..bbdd17f 100644 --- a/ui/app_list/views/folder_header_view.cc +++ b/ui/app_list/views/folder_header_view.cc @@ -68,11 +68,12 @@ FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate) views::ImageButton::ALIGN_MIDDLE); AddChildView(back_button_); - folder_name_view_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); + folder_name_view_->SetFontList( + rb.GetFontList(ui::ResourceBundle::MediumFont)); folder_name_view_->set_placeholder_text_color(kHintTextColor); folder_name_view_->set_placeholder_text( rb.GetLocalizedString(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)); - folder_name_view_->RemoveBorder(); + folder_name_view_->set_border(NULL); folder_name_view_->SetBackgroundColor(kContentsBackgroundColor); folder_name_view_->SetController(this); AddChildView(folder_name_view_); diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc index c975177..fb742d6 100644 --- a/ui/app_list/views/search_box_view.cc +++ b/ui/app_list/views/search_box_view.cc @@ -63,8 +63,8 @@ SearchBoxView::SearchBoxView(SearchBoxViewDelegate* delegate, AddChildView(menu_button_); #endif - search_box_->RemoveBorder(); - search_box_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); + search_box_->set_border(NULL); + search_box_->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont)); search_box_->set_placeholder_text_color(kHintTextColor); search_box_->SetController(this); AddChildView(search_box_); diff --git a/ui/base/touch/touch_editing_controller.h b/ui/base/touch/touch_editing_controller.h index 58bcb45..1c6a8fa 100644 --- a/ui/base/touch/touch_editing_controller.h +++ b/ui/base/touch/touch_editing_controller.h @@ -38,7 +38,7 @@ class UI_BASE_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate { virtual gfx::Rect GetBounds() = 0; // Gets the NativeView hosting the client. - virtual gfx::NativeView GetNativeView() = 0; + virtual gfx::NativeView GetNativeView() const = 0; // Converts a point to/from screen coordinates from/to client view. virtual void ConvertPointToScreen(gfx::Point* point) = 0; 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 e79c292..0000000 --- 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 diff --git a/ui/views/controls/textfield/native_textfield_views.h b/ui/views/controls/textfield/native_textfield_views.h deleted file mode 100644 index dc5fed3..0000000 --- a/ui/views/controls/textfield/native_textfield_views.h +++ /dev/null @@ -1,397 +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. - -#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_ -#define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_ - -#include "base/memory/weak_ptr.h" -#include "base/strings/string16.h" -#include "base/timer/timer.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/base/touch/touch_editing_controller.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/selection_model.h" -#include "ui/views/border.h" -#include "ui/views/context_menu_controller.h" -#include "ui/views/controls/textfield/textfield_views_model.h" -#include "ui/views/drag_controller.h" -#include "ui/views/view.h" - -namespace base { -class Time; -} - -namespace gfx { -class Canvas; -} - -namespace views { - -class FocusableBorder; -class MenuModelAdapter; -class MenuRunner; -class Textfield; - -// A views/skia textfield implementation. No platform-specific code is used. -// TODO(msw): Merge views::NativeTextfieldViews and views::Textfield classes. -class VIEWS_EXPORT NativeTextfieldViews : public View, - public ui::TouchEditable, - public ContextMenuController, - public DragController, - public ui::TextInputClient, - public TextfieldViewsModel::Delegate { - public: - explicit NativeTextfieldViews(Textfield* parent); - virtual ~NativeTextfieldViews(); - - // View overrides: - virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE; - virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; - virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; - virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; - virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; - virtual bool GetDropFormats( - int* formats, - std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE; - virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE; - virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE; - virtual void OnDragExited() OVERRIDE; - virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE; - virtual void OnDragDone() OVERRIDE; - virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE; - virtual ui::TextInputClient* GetTextInputClient() OVERRIDE; - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; - virtual void OnFocus() OVERRIDE; - virtual void OnBlur() OVERRIDE; - virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE; - - // ui::TouchEditable overrides: - virtual void SelectRect(const gfx::Point& start, - const gfx::Point& end) OVERRIDE; - virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE; - virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE; - virtual gfx::Rect GetBounds() OVERRIDE; - virtual gfx::NativeView GetNativeView() OVERRIDE; - virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE; - virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE; - virtual bool DrawsHandles() OVERRIDE; - virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE; - - // ContextMenuController overrides: - virtual void ShowContextMenuForView(View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) OVERRIDE; - - // Overridden from DragController: - virtual void WriteDragDataForView(View* sender, - const gfx::Point& press_pt, - ui::OSExchangeData* data) OVERRIDE; - virtual int GetDragOperationsForView(View* sender, - const gfx::Point& p) OVERRIDE; - virtual bool CanStartDragForView(View* sender, - const gfx::Point& press_pt, - const gfx::Point& p) OVERRIDE; - - // Gets the currently displayed text. - base::string16 GetText() const; - - // Updates the text displayed to the text held by the parent Textfield. - void UpdateText(); - - // Adds the specified text to the text already displayed. - void AppendText(const base::string16& text); - - // Inserts |text| at the current cursor position, replacing any selected text. - void InsertOrReplaceText(const base::string16& text); - - // Returns the text direction. - base::i18n::TextDirection GetTextDirection() const; - - // Returns the currently selected text. - base::string16 GetSelectedText() const; - - // Select the entire text range. If |reversed| is true, the range will end at - // the logical beginning of the text; this generally shows the leading portion - // of text that overflows its display area. - void SelectAll(bool reversed); - - // Clears the selection within the textfield and sets the caret to the end. - void ClearSelection(); - - // Updates whether there is a visible border. - void UpdateBorder(); - - // Updates the painted text color. - void UpdateTextColor(); - - // Updates the painted background color. - void UpdateBackgroundColor(); - - // Updates the read-only state. - void UpdateReadOnly(); - - // Updates the font used to render the text. - void UpdateFont(); - - // Updates the obscured state of the text for passwords, etc. - void UpdateIsObscured(); - - // Updates the enabled state. - void UpdateEnabled(); - - // Updates the horizontal and vertical margins. - void UpdateHorizontalMargins(); - void UpdateVerticalMargins(); - - // Returns whether or not an IME is composing text. - bool IsIMEComposing() const; - - // Gets the selected logical text range. - const gfx::Range& GetSelectedRange() const; - - // Selects the specified logical text range. - void SelectRange(const gfx::Range& range); - - // Gets the text selection model. - const gfx::SelectionModel& GetSelectionModel() const; - - // Sets the specified text selection model. - void SelectSelectionModel(const gfx::SelectionModel& sel); - - // Returns the current cursor position. - size_t GetCursorPosition() const; - - // Get or set whether or not the cursor is enabled. - bool GetCursorEnabled() const; - void SetCursorEnabled(bool enabled); - - // Invoked when the parent views::Textfield receives key events. - // returns true if the event was processed. - bool HandleKeyPressed(const ui::KeyEvent& e); - bool HandleKeyReleased(const ui::KeyEvent& e); - - // Invoked when the parent views:Textfield gains or loses focus. - void HandleFocus(); - void HandleBlur(); - - // Set the text colors; see views::Textfield for details. - void SetColor(SkColor value); - void ApplyColor(SkColor value, const gfx::Range& range); - - // Set the text styles; see the corresponding Textfield functions for details. - void SetStyle(gfx::TextStyle style, bool value); - void ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range); - - // Clears the Edit history. - void ClearEditHistory(); - - // Get the height in pixels of the fonts used. - int GetFontHeight(); - - // Returns the text baseline; this value does not include any insets. - int GetTextfieldBaseline() const; - - // Returns the width necessary to display the current text, including any - // necessary space for the cursor or border/margin. - int GetWidthNeededForText() const; - - // Returns whether this view is the origin of an ongoing drag operation. - bool HasTextBeingDragged(); - - // Returns the location for keyboard-triggered context menus. - gfx::Point GetContextMenuLocation(); - - // ui::SimpleMenuModel::Delegate overrides - virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; - virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; - virtual bool GetAcceleratorForCommandId( - int command_id, - ui::Accelerator* accelerator) OVERRIDE; - virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; - virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; - virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; - - // class name of internal - static const char kViewClassName[]; - - protected: - // View override. - virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; - - private: - friend class NativeTextfieldViewsTest; - friend class TouchSelectionControllerImplTest; - - // Overridden from ui::TextInputClient: - virtual void SetCompositionText( - const ui::CompositionText& composition) OVERRIDE; - virtual void ConfirmCompositionText() OVERRIDE; - virtual void ClearCompositionText() OVERRIDE; - virtual void InsertText(const base::string16& text) OVERRIDE; - virtual void InsertChar(base::char16 ch, int flags) OVERRIDE; - virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE; - virtual ui::TextInputType GetTextInputType() const OVERRIDE; - virtual ui::TextInputMode GetTextInputMode() const OVERRIDE; - virtual bool CanComposeInline() const OVERRIDE; - virtual gfx::Rect GetCaretBounds() const OVERRIDE; - virtual bool GetCompositionCharacterBounds(uint32 index, - gfx::Rect* rect) const OVERRIDE; - virtual bool HasCompositionText() const OVERRIDE; - virtual bool GetTextRange(gfx::Range* range) const OVERRIDE; - virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE; - virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE; - virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE; - virtual bool DeleteRange(const gfx::Range& range) OVERRIDE; - virtual bool GetTextFromRange(const gfx::Range& range, - base::string16* text) const OVERRIDE; - virtual void OnInputMethodChanged() OVERRIDE; - virtual bool ChangeTextDirectionAndLayoutAlignment( - base::i18n::TextDirection direction) OVERRIDE; - virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE; - virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE; - virtual void OnCandidateWindowShown() OVERRIDE; - virtual void OnCandidateWindowUpdated() OVERRIDE; - virtual void OnCandidateWindowHidden() OVERRIDE; - - // Overridden from TextfieldViewsModel::Delegate: - virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE; - - // Returns the TextfieldViewsModel's text/cursor/selection rendering model. - gfx::RenderText* GetRenderText() const; - - // Converts |text| according to the current style, e.g. STYLE_LOWERCASE. - base::string16 GetTextForDisplay(const base::string16& text); - - // Updates any colors that have not been explicitly set from the theme. - void UpdateColorsFromTheme(const ui::NativeTheme* theme); - - // A callback function to periodically update the cursor state. - void UpdateCursor(); - - // Repaint the cursor. - void RepaintCursor(); - - // Update the cursor_bounds and text_offset. - void UpdateCursorBoundsAndTextOffset(size_t cursor_pos, bool insert_mode); - - void PaintTextAndCursor(gfx::Canvas* canvas); - - // Handle the keyevent. - bool HandleKeyEvent(const ui::KeyEvent& key_event); - - // Helper function to call MoveCursorTo on the TextfieldViewsModel. - bool MoveCursorTo(const gfx::Point& point, bool select); - - // Utility function to inform the parent views::Textfield (and any controller) - // that the text in the textfield has changed. - void PropagateTextChange(); - - // Does necessary updates when the text and/or cursor position changes. - void UpdateAfterChange(bool text_changed, bool cursor_changed); - - // Utility function to prepare the context menu. - void UpdateContextMenu(); - - // Convenience method to call InputMethod::OnTextInputTypeChanged(); - void OnTextInputTypeChanged(); - - // Convenience method to call InputMethod::OnCaretBoundsChanged(); - void OnCaretBoundsChanged(); - - // Convenience method to call TextfieldController::OnBeforeUserAction(); - void OnBeforeUserAction(); - - // Convenience method to call TextfieldController::OnAfterUserAction(); - void OnAfterUserAction(); - - // Calls |model_->Cut()| and notifies TextfieldController on success. - bool Cut(); - - // Calls |model_->Copy()| and notifies TextfieldController on success. - bool Copy(); - - // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged() - // explicitly if paste succeeded. - bool Paste(); - - // Tracks the mouse clicks for single/double/triple clicks. - void TrackMouseClicks(const ui::MouseEvent& event); - - // Handles mouse press events. - void HandleMousePressEvent(const ui::MouseEvent& event); - - // Returns true if the current text input type allows access by the IME. - bool ImeEditingAllowed() const; - - // Returns true if distance between |event| and |last_click_location_| - // exceeds the drag threshold. - bool ExceededDragThresholdFromLastClickLocation(const ui::MouseEvent& event); - - // Checks if a char is ok to be inserted into the textfield. The |ch| is a - // modified character, i.e., modifiers took effect when generating this char. - static bool ShouldInsertChar(base::char16 ch, int flags); - - void CreateTouchSelectionControllerAndNotifyIt(); - - // Platform specific gesture event handling. - void PlatformGestureEventHandling(const ui::GestureEvent* event); - - // Reveals the obscured char at |index| for the given |duration|. If |index| - // is -1, existing revealed index will be cleared. - void RevealObscuredChar(int index, const base::TimeDelta& duration); - - // The parent views::Textfield, the owner of this object. - Textfield* textfield_; - - // The text model. - scoped_ptr<TextfieldViewsModel> model_; - - // The focusable border. This is always non-NULL, but may not actually be - // drawn. If it is not drawn, then by default it's also zero-sized unless the - // Textfield has explicitly-set margins. - FocusableBorder* text_border_; - - // The text editing cursor visibility. - bool is_cursor_visible_; - - // The drop cursor is a visual cue for where dragged text will be dropped. - bool is_drop_cursor_visible_; - // Position of the drop cursor, if it is visible. - gfx::SelectionModel drop_cursor_position_; - - // True if InputMethod::CancelComposition() should not be called. - bool skip_input_method_cancel_composition_; - - // Is the user potentially dragging and dropping from this view? - bool initiating_drag_; - - // A runnable method factory for callback to update the cursor. - base::WeakPtrFactory<NativeTextfieldViews> cursor_timer_; - - // State variables used to track double and triple clicks. - size_t aggregated_clicks_; - base::TimeDelta last_click_time_; - gfx::Point last_click_location_; - gfx::Range double_click_word_; - - // Context menu related members. - scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; - scoped_ptr<views::MenuModelAdapter> context_menu_delegate_; - scoped_ptr<views::MenuRunner> context_menu_runner_; - - scoped_ptr<ui::TouchSelectionController> touch_selection_controller_; - - // A timer to control the duration of showing the last typed char in - // obscured text. When the timer is running, the last typed char is shown - // and when the time expires, the last typed char is obscured. - base::OneShotTimer<NativeTextfieldViews> obscured_reveal_timer_; - - DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViews); -}; - -} // namespace views - -#endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_ diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 69adbb7..afef279 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc @@ -6,34 +6,52 @@ #include <string> -#include "base/command_line.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" +#include "base/debug/trace_event.h" +#include "base/i18n/case_conversion.h" +#include "grit/ui_strings.h" #include "ui/base/accessibility/accessible_view_state.h" -#include "ui/base/ime/text_input_type.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/drag_utils.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_switches.h" +#include "ui/base/ui_base_switches_util.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/insets.h" -#include "ui/gfx/range/range.h" -#include "ui/gfx/selection_model.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/background.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/native/native_view_host.h" -#include "ui/views/controls/textfield/native_textfield_views.h" #include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/drag_utils.h" +#include "ui/views/ime/input_method.h" +#include "ui/views/metrics.h" #include "ui/views/painter.h" #include "ui/views/views_delegate.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 { // Default placeholder text color. const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; -gfx::FontList GetDefaultFontList() { - return ResourceBundle::GetSharedInstance().GetFontList( - ResourceBundle::BaseFont); +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 @@ -55,22 +73,26 @@ size_t Textfield::GetCaretBlinkMs() { } Textfield::Textfield() - : textfield_view_(NULL), + : model_(new TextfieldViewsModel(this)), controller_(NULL), style_(STYLE_DEFAULT), - font_list_(GetDefaultFontList()), read_only_(false), default_width_in_chars_(0), - draw_border_(true), text_color_(SK_ColorBLACK), use_default_text_color_(true), background_color_(SK_ColorWHITE), use_default_background_color_(true), - horizontal_margins_were_set_(false), - vertical_margins_were_set_(false), placeholder_text_color_(kDefaultPlaceholderTextColor), text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), + skip_input_method_cancel_composition_(false), + is_cursor_visible_(false), + is_drop_cursor_visible_(false), + initiating_drag_(false), + aggregated_clicks_(0), weak_ptr_factory_(this) { + set_context_menu_controller(this); + set_drag_controller(this); + set_border(new FocusableBorder()); SetFocusable(true); if (ViewsDelegate::views_delegate) { @@ -83,23 +105,28 @@ Textfield::Textfield() } Textfield::Textfield(StyleFlags style) - : textfield_view_(NULL), + : model_(new TextfieldViewsModel(this)), controller_(NULL), style_(style), - font_list_(GetDefaultFontList()), read_only_(false), default_width_in_chars_(0), - draw_border_(true), text_color_(SK_ColorBLACK), use_default_text_color_(true), background_color_(SK_ColorWHITE), use_default_background_color_(true), - horizontal_margins_were_set_(false), - vertical_margins_were_set_(false), placeholder_text_color_(kDefaultPlaceholderTextColor), text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), + skip_input_method_cancel_composition_(false), + is_cursor_visible_(false), + is_drop_cursor_visible_(false), + initiating_drag_(false), + aggregated_clicks_(0), weak_ptr_factory_(this) { + set_context_menu_controller(this); + set_drag_controller(this); + set_border(new FocusableBorder()); SetFocusable(true); + if (IsObscured()) SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); @@ -126,11 +153,10 @@ TextfieldController* Textfield::GetController() const { void Textfield::SetReadOnly(bool read_only) { // Update read-only without changing the focusable state (or active, etc.). read_only_ = read_only; - if (textfield_view_) { - textfield_view_->UpdateReadOnly(); - textfield_view_->UpdateTextColor(); - textfield_view_->UpdateBackgroundColor(); - } + if (GetInputMethod()) + GetInputMethod()->OnTextInputTypeChanged(this); + SetColor(GetTextColor()); + UpdateBackgroundColor(); } bool Textfield::IsObscured() const { @@ -145,14 +171,11 @@ void Textfield::SetObscured(bool obscured) { style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED); SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); } - if (textfield_view_) - textfield_view_->UpdateIsObscured(); -} - -ui::TextInputType Textfield::GetTextInputType() const { - if (read_only() || !enabled()) - return ui::TEXT_INPUT_TYPE_NONE; - return text_input_type_; + GetRenderText()->SetObscured(obscured); + OnCaretBoundsChanged(); + if (GetInputMethod()) + GetInputMethod()->OnTextInputTypeChanged(this); + SchedulePaint(); } void Textfield::SetTextInputType(ui::TextInputType type) { @@ -162,47 +185,51 @@ void Textfield::SetTextInputType(ui::TextInputType type) { SetObscured(should_be_obscured); } -void Textfield::SetText(const base::string16& text) { - text_ = text; - if (textfield_view_) - textfield_view_->UpdateText(); +void Textfield::SetText(const base::string16& new_text) { + model_->SetText(GetTextForDisplay(new_text)); + OnCaretBoundsChanged(); + SchedulePaint(); + NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true); } -void Textfield::AppendText(const base::string16& text) { - text_ += text; - if (textfield_view_) - textfield_view_->AppendText(text); +void Textfield::AppendText(const base::string16& new_text) { + if (new_text.empty()) + return; + model_->Append(GetTextForDisplay(new_text)); + OnCaretBoundsChanged(); + SchedulePaint(); } -void Textfield::InsertOrReplaceText(const base::string16& text) { - if (textfield_view_) { - textfield_view_->InsertOrReplaceText(text); - text_ = textfield_view_->GetText(); - } +void Textfield::InsertOrReplaceText(const base::string16& new_text) { + if (new_text.empty()) + return; + model_->InsertText(new_text); + OnCaretBoundsChanged(); + SchedulePaint(); } base::i18n::TextDirection Textfield::GetTextDirection() const { - return textfield_view_ ? - textfield_view_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION; + return GetRenderText()->GetTextDirection(); } void Textfield::SelectAll(bool reversed) { - if (textfield_view_) - textfield_view_->SelectAll(reversed); + model_->SelectAll(reversed); + OnCaretBoundsChanged(); + SchedulePaint(); } base::string16 Textfield::GetSelectedText() const { - return textfield_view_ ? textfield_view_->GetSelectedText() : - base::string16(); + return model_->GetSelectedText(); } -void Textfield::ClearSelection() const { - if (textfield_view_) - textfield_view_->ClearSelection(); +void Textfield::ClearSelection() { + model_->ClearSelection(); + OnCaretBoundsChanged(); + SchedulePaint(); } bool Textfield::HasSelection() const { - return textfield_view_ && !textfield_view_->GetSelectedRange().is_empty(); + return !GetSelectedRange().is_empty(); } SkColor Textfield::GetTextColor() const { @@ -217,14 +244,12 @@ SkColor Textfield::GetTextColor() const { void Textfield::SetTextColor(SkColor color) { text_color_ = color; use_default_text_color_ = false; - if (textfield_view_) - textfield_view_->UpdateTextColor(); + SetColor(color); } void Textfield::UseDefaultTextColor() { use_default_text_color_ = true; - if (textfield_view_) - textfield_view_->UpdateTextColor(); + SetColor(GetTextColor()); } SkColor Textfield::GetBackgroundColor() const { @@ -239,165 +264,90 @@ SkColor Textfield::GetBackgroundColor() const { void Textfield::SetBackgroundColor(SkColor color) { background_color_ = color; use_default_background_color_ = false; - if (textfield_view_) - textfield_view_->UpdateBackgroundColor(); + UpdateBackgroundColor(); } void Textfield::UseDefaultBackgroundColor() { use_default_background_color_ = true; - if (textfield_view_) - textfield_view_->UpdateBackgroundColor(); + UpdateBackgroundColor(); } bool Textfield::GetCursorEnabled() const { - return textfield_view_ && textfield_view_->GetCursorEnabled(); + return GetRenderText()->cursor_enabled(); } void Textfield::SetCursorEnabled(bool enabled) { - if (textfield_view_) - textfield_view_->SetCursorEnabled(enabled); -} - -void Textfield::SetFontList(const gfx::FontList& font_list) { - font_list_ = font_list; - if (textfield_view_) - textfield_view_->UpdateFont(); - PreferredSizeChanged(); + GetRenderText()->SetCursorEnabled(enabled); } -const gfx::Font& Textfield::GetPrimaryFont() const { - return font_list_.GetPrimaryFont(); -} - -void Textfield::SetFont(const gfx::Font& font) { - SetFontList(gfx::FontList(font)); -} - -void Textfield::SetHorizontalMargins(int left, int right) { - if (horizontal_margins_were_set_ && - left == margins_.left() && right == margins_.right()) { - return; - } - margins_.Set(margins_.top(), left, margins_.bottom(), right); - horizontal_margins_were_set_ = true; - if (textfield_view_) - textfield_view_->UpdateHorizontalMargins(); - PreferredSizeChanged(); +const gfx::FontList& Textfield::GetFontList() const { + return GetRenderText()->font_list(); } -void Textfield::SetVerticalMargins(int top, int bottom) { - if (vertical_margins_were_set_ && - top == margins_.top() && bottom == margins_.bottom()) { - return; - } - margins_.Set(top, margins_.left(), bottom, margins_.right()); - vertical_margins_were_set_ = true; - if (textfield_view_) - textfield_view_->UpdateVerticalMargins(); +void Textfield::SetFontList(const gfx::FontList& font_list) { + GetRenderText()->SetFontList(font_list); + OnCaretBoundsChanged(); PreferredSizeChanged(); } -void Textfield::RemoveBorder() { - if (!draw_border_) - return; - - draw_border_ = false; - if (textfield_view_) - textfield_view_->UpdateBorder(); -} - base::string16 Textfield::GetPlaceholderText() const { return placeholder_text_; } -bool Textfield::GetHorizontalMargins(int* left, int* right) { - if (!horizontal_margins_were_set_) - return false; - - *left = margins_.left(); - *right = margins_.right(); - return true; -} - -bool Textfield::GetVerticalMargins(int* top, int* bottom) { - if (!vertical_margins_were_set_) - return false; - - *top = margins_.top(); - *bottom = margins_.bottom(); - return true; -} - -void Textfield::UpdateAllProperties() { - if (textfield_view_) { - textfield_view_->UpdateText(); - textfield_view_->UpdateTextColor(); - textfield_view_->UpdateBackgroundColor(); - textfield_view_->UpdateReadOnly(); - textfield_view_->UpdateFont(); - textfield_view_->UpdateEnabled(); - textfield_view_->UpdateBorder(); - textfield_view_->UpdateIsObscured(); - textfield_view_->UpdateHorizontalMargins(); - textfield_view_->UpdateVerticalMargins(); - } -} - -void Textfield::SyncText() { - if (textfield_view_) { - base::string16 new_text = textfield_view_->GetText(); - if (new_text != text_) { - text_ = new_text; - if (controller_) - controller_->ContentsChanged(this, text_); - } - } -} - bool Textfield::IsIMEComposing() const { - return textfield_view_ && textfield_view_->IsIMEComposing(); + return model_->HasCompositionText(); } const gfx::Range& Textfield::GetSelectedRange() const { - return textfield_view_->GetSelectedRange(); + return GetRenderText()->selection(); } void Textfield::SelectRange(const gfx::Range& range) { - textfield_view_->SelectRange(range); + model_->SelectRange(range); + OnCaretBoundsChanged(); + SchedulePaint(); + NotifyAccessibilityEvent( + ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); } const gfx::SelectionModel& Textfield::GetSelectionModel() const { - return textfield_view_->GetSelectionModel(); + return GetRenderText()->selection_model(); } void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { - textfield_view_->SelectSelectionModel(sel); + model_->SelectSelectionModel(sel); + OnCaretBoundsChanged(); + SchedulePaint(); } size_t Textfield::GetCursorPosition() const { - return textfield_view_->GetCursorPosition(); + return model_->GetCursorPosition(); } void Textfield::SetColor(SkColor value) { - return textfield_view_->SetColor(value); + GetRenderText()->SetColor(value); + SchedulePaint(); } void Textfield::ApplyColor(SkColor value, const gfx::Range& range) { - return textfield_view_->ApplyColor(value, range); + GetRenderText()->ApplyColor(value, range); + SchedulePaint(); } void Textfield::SetStyle(gfx::TextStyle style, bool value) { - return textfield_view_->SetStyle(style, value); + GetRenderText()->SetStyle(style, value); + SchedulePaint(); } void Textfield::ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range) { - return textfield_view_->ApplyStyle(style, value, range); + GetRenderText()->ApplyStyle(style, value, range); + SchedulePaint(); } void Textfield::ClearEditHistory() { - textfield_view_->ClearEditHistory(); + model_->ClearEditHistory(); } void Textfield::SetAccessibleName(const base::string16& name) { @@ -405,7 +355,7 @@ void Textfield::SetAccessibleName(const base::string16& name) { } void Textfield::ExecuteCommand(int command_id) { - textfield_view_->ExecuteCommand(command_id, ui::EF_NONE); + ExecuteCommand(command_id, ui::EF_NONE); } void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { @@ -413,35 +363,20 @@ void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { } bool Textfield::HasTextBeingDragged() { - return textfield_view_->HasTextBeingDragged(); + return initiating_drag_; } //////////////////////////////////////////////////////////////////////////////// // Textfield, View overrides: -void Textfield::Layout() { - if (textfield_view_) { - textfield_view_->SetBoundsRect(GetContentsBounds()); - textfield_view_->Layout(); - } -} - int Textfield::GetBaseline() const { - gfx::Insets insets = GetTextInsets(); - const int baseline = textfield_view_ ? - textfield_view_->GetTextfieldBaseline() : font_list_.GetBaseline(); - return insets.top() + baseline; + return GetInsets().top() + GetRenderText()->GetBaseline(); } gfx::Size Textfield::GetPreferredSize() { - gfx::Insets insets = GetTextInsets(); - - const int font_height = textfield_view_ ? textfield_view_->GetFontHeight() : - font_list_.GetHeight(); - return gfx::Size( - GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_) - + insets.width(), - font_height + insets.height()); + const gfx::Insets& insets = GetInsets(); + return gfx::Size(GetFontList().GetExpectedTextWidth(default_width_in_chars_) + + insets.width(), GetFontList().GetHeight() + insets.height()); } void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) { @@ -455,35 +390,248 @@ bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { } void Textfield::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); + OnPaintBackground(canvas); + PaintTextAndCursor(canvas); + OnPaintBorder(canvas); if (NativeViewHost::kRenderNativeControlFocus) Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); } -bool Textfield::OnKeyPressed(const ui::KeyEvent& e) { - return textfield_view_ && textfield_view_->HandleKeyPressed(e); -} +bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { + bool handled = controller_ && controller_->HandleKeyEvent(this, event); + touch_selection_controller_.reset(); + if (handled) + return true; + + // TODO(oshima): Refactor and consolidate with ExecuteCommand. + if (event.type() == ui::ET_KEY_PRESSED) { + ui::KeyboardCode key_code = event.key_code(); + if (key_code == ui::VKEY_TAB || event.IsUnicodeKeyCode()) + return false; + + gfx::RenderText* render_text = GetRenderText(); + const bool editable = !read_only(); + const bool readable = !IsObscured(); + const bool shift = event.IsShiftDown(); + const bool control = event.IsControlDown(); + const bool alt = event.IsAltDown() || event.IsAltGrDown(); + bool text_changed = false; + bool cursor_changed = false; + + OnBeforeUserAction(); + 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 = render_text->selection(); + model_->MoveCursor( + control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, + (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, + shift); + cursor_changed = render_text->selection() != selection_range; + break; + } + case ui::VKEY_END: + case ui::VKEY_HOME: + if ((key_code == ui::VKEY_HOME) == + (render_text->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 shift and control are pressed, erase up to the next line break + // on Linux and ChromeOS. Otherwise, do nothing. +#if defined(OS_LINUX) + model_->MoveCursor(gfx::LINE_BREAK, direction, true); +#else + break; +#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(GetInputMethod()); + UpdateAfterChange(text_changed, cursor_changed); + OnAfterUserAction(); + return (text_changed || cursor_changed); + } + return false; +} + +bool Textfield::OnMousePressed(const ui::MouseEvent& event) { + OnBeforeUserAction(); + TrackMouseClicks(event); + + if (!controller_ || !controller_->HandleMouseEvent(this, event)) { + if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) + RequestFocus(); + + if (event.IsOnlyLeftMouseButton()) { + 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 Textfield::OnKeyReleased(const ui::KeyEvent& e) { - return textfield_view_ && textfield_view_->HandleKeyReleased(e); + OnAfterUserAction(); + touch_selection_controller_.reset(); + return true; } -bool Textfield::OnMouseDragged(const ui::MouseEvent& e) { - if (!e.IsOnlyRightMouseButton()) - return View::OnMouseDragged(e); +bool Textfield::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_ || !event.IsOnlyLeftMouseButton() || + !ExceededDragThreshold(event.location() - last_click_location_)) { + return true; + } + + if (!event.IsOnlyRightMouseButton()) { + OnBeforeUserAction(); + 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 Textfield::OnMouseReleased(const ui::MouseEvent& event) { + OnBeforeUserAction(); + // Cancel suspected drag initiations, the user was clicking in the selection. + if (initiating_drag_ && MoveCursorTo(event.location(), false)) + SchedulePaint(); + initiating_drag_ = false; + OnAfterUserAction(); +} + void Textfield::OnFocus() { - if (textfield_view_) - textfield_view_->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) { + cursor_repaint_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(caret_blink_ms), this, + &Textfield::UpdateCursor); + } + View::OnFocus(); SchedulePaint(); } void Textfield::OnBlur() { - if (textfield_view_) - textfield_view_->HandleBlur(); + GetRenderText()->set_focused(false); + GetInputMethod()->OnBlur(); + cursor_repaint_timer_.Stop(); + if (is_cursor_visible_) { + is_cursor_visible_ = false; + RepaintCursor(); + } + + touch_selection_controller_.reset(); // Border typically draws focus indicator. SchedulePaint(); @@ -496,9 +644,9 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { state->state |= ui::AccessibilityTypes::STATE_READONLY; if (IsObscured()) state->state |= ui::AccessibilityTypes::STATE_PROTECTED; - state->value = text_; + state->value = text(); - const gfx::Range range = textfield_view_->GetSelectedRange(); + const gfx::Range range = GetSelectedRange(); state->selection_start = range.start(); state->selection_end = range.end(); @@ -510,43 +658,679 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { } ui::TextInputClient* Textfield::GetTextInputClient() { - return textfield_view_ ? textfield_view_->GetTextInputClient() : NULL; + return read_only_ ? NULL : this; } gfx::Point Textfield::GetKeyboardContextMenuLocation() { - return textfield_view_ ? textfield_view_->GetContextMenuLocation() : - View::GetKeyboardContextMenuLocation(); + return GetCaretBounds().bottom_right(); +} + +void Textfield::OnNativeThemeChanged(const ui::NativeTheme* theme) { + UpdateColorsFromTheme(theme); } void Textfield::OnEnabledChanged() { View::OnEnabledChanged(); - if (textfield_view_) - textfield_view_->UpdateEnabled(); -} - -void Textfield::ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) { - if (details.is_add && !textfield_view_ && GetWidget()) { - // The textfield view's lifetime is managed by the view hierarchy. - textfield_view_ = new NativeTextfieldViews(this); - AddChildViewAt(textfield_view_, 0); - Layout(); - UpdateAllProperties(); - } + if (GetInputMethod()) + GetInputMethod()->OnTextInputTypeChanged(this); + SchedulePaint(); } const char* Textfield::GetClassName() const { return kViewClassName; } +gfx::NativeCursor Textfield::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 +} + +void Textfield::OnGestureEvent(ui::GestureEvent* event) { + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + OnBeforeUserAction(); + 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(); + } +#if defined(OS_WIN) && defined(USE_AURA) + if (!read_only()) + base::win::DisplayVirtualKeyboard(); +#endif + 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_) + event->SetHandled(); + } else if (switches::IsTouchDragDropEnabled()) { + initiating_drag_ = true; + touch_selection_controller_.reset(); + } else { + if (!touch_selection_controller_) + CreateTouchSelectionControllerAndNotifyIt(); + if (touch_selection_controller_) + event->SetHandled(); + } + return; + case ui::ET_GESTURE_LONG_TAP: + if (!touch_selection_controller_) + 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_) + event->SetHandled(); + break; + default: + return; + } +} + +bool Textfield::GetDropFormats( + int* formats, + std::set<OSExchangeData::CustomFormat>* custom_formats) { + if (!enabled() || read_only()) + return false; + // TODO(msw): Can we support URL, FILENAME, etc.? + *formats = ui::OSExchangeData::STRING; + if (controller_) + controller_->AppendDropFormats(formats, custom_formats); + return true; +} + +bool Textfield::CanDrop(const OSExchangeData& data) { + int formats; + std::set<OSExchangeData::CustomFormat> custom_formats; + GetDropFormats(&formats, &custom_formats); + return enabled() && !read_only() && + data.HasAnyFormat(formats, custom_formats); +} + +int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) { + DCHECK(CanDrop(event.data())); + gfx::RenderText* render_text = GetRenderText(); + const gfx::Range& selection = render_text->selection(); + drop_cursor_position_ = render_text->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 Textfield::OnDragExited() { + is_drop_cursor_visible_ = false; + SchedulePaint(); +} + +int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) { + DCHECK(CanDrop(event.data())); + is_drop_cursor_visible_ = false; + + if (controller_) { + int drag_operation = controller_->OnDrop(event.data()); + if (drag_operation != ui::DragDropTypes::DRAG_NONE) + return drag_operation; + } + + gfx::RenderText* render_text = GetRenderText(); + DCHECK(!initiating_drag_ || + !render_text->IsPointInSelection(event.location())); + OnBeforeUserAction(); + skip_input_method_cancel_composition_ = true; + + gfx::SelectionModel drop_destination_model = + render_text->FindCursorPosition(event.location()); + base::string16 new_text; + event.data().GetString(&new_text); + new_text = GetTextForDisplay(new_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 pos = drop_destination_model.caret_pos(); + pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length(); + model_->DeleteSelectionAndInsertTextAt(new_text, pos); + } else { + model_->MoveCursorTo(drop_destination_model); + // Drop always inserts text even if the textfield is not in insert mode. + model_->InsertText(new_text); + } + skip_input_method_cancel_composition_ = false; + UpdateAfterChange(true, true); + OnAfterUserAction(); + return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; +} + +void Textfield::OnDragDone() { + initiating_drag_ = false; + is_drop_cursor_visible_ = false; +} + +void Textfield::OnBoundsChanged(const gfx::Rect& previous_bounds) { + GetRenderText()->SetDisplayRect(GetContentsBounds()); + OnCaretBoundsChanged(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, TextfieldViewsModel::Delegate overrides: + +void Textfield::OnCompositionTextConfirmedOrCleared() { + if (!skip_input_method_cancel_composition_) + GetInputMethod()->CancelComposition(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, ContextMenuController overrides: + +void Textfield::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; +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, views::DragController overrides: + +void Textfield::WriteDragDataForView(views::View* sender, + const gfx::Point& press_pt, + OSExchangeData* data) { + DCHECK_NE(ui::DragDropTypes::DRAG_NONE, + GetDragOperationsForView(sender, press_pt)); + data->SetString(model_->GetSelectedText()); + scoped_ptr<gfx::Canvas> canvas( + views::GetCanvasForDragImage(GetWidget(), size())); + GetRenderText()->DrawSelectedTextForDrag(canvas.get()); + drag_utils::SetDragImageOnDataObject(*canvas, size(), + press_pt.OffsetFromOrigin(), + data); + if (controller_) + controller_->OnWriteDragData(data); +} + +int Textfield::GetDragOperationsForView(views::View* sender, + const gfx::Point& p) { + int drag_operations = ui::DragDropTypes::DRAG_COPY; + if (!enabled() || IsObscured() || !GetRenderText()->IsPointInSelection(p)) + drag_operations = ui::DragDropTypes::DRAG_NONE; + else if (sender == this && !read_only()) + drag_operations = + ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY; + if (controller_) + controller_->OnGetDragOperationsForTextfield(&drag_operations); + return drag_operations; +} + +bool Textfield::CanStartDragForView(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) { + return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt); +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, ui::TouchEditable overrides: + +void Textfield::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 Textfield::MoveCaretTo(const gfx::Point& point) { + SelectRect(point, point); +} + +void Textfield::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 Textfield::GetBounds() { + return bounds(); +} + +gfx::NativeView Textfield::GetNativeView() const { + return GetWidget()->GetNativeView(); +} + +void Textfield::ConvertPointToScreen(gfx::Point* point) { + View::ConvertPointToScreen(this, point); +} + +void Textfield::ConvertPointFromScreen(gfx::Point* point) { + View::ConvertPointFromScreen(this, point); +} + +bool Textfield::DrawsHandles() { + return false; +} + +void Textfield::OpenContextMenu(const gfx::Point& anchor) { + touch_selection_controller_.reset(); + ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU); +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, ui::SimpleMenuModel::Delegate overrides: + +bool Textfield::IsCommandIdChecked(int command_id) const { + return true; +} + +bool Textfield::IsCommandIdEnabled(int command_id) const { + base::string16 result; + bool editable = !read_only(); + switch (command_id) { + case IDS_APP_UNDO: + return editable && model_->CanUndo(); + case IDS_APP_CUT: + return editable && model_->HasSelection() && !IsObscured(); + case IDS_APP_COPY: + return model_->HasSelection() && !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 !text().empty(); + default: + return false; + } +} + +bool Textfield::GetAcceleratorForCommandId(int command_id, + ui::Accelerator* accelerator) { + return false; +} + +void Textfield::ExecuteCommand(int command_id, int event_flags) { + touch_selection_controller_.reset(); + if (!IsCommandIdEnabled(command_id)) + return; + + 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: + NOTREACHED(); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, ui::TextInputClient overrides: + +void Textfield::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 Textfield::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 Textfield::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 Textfield::InsertText(const base::string16& new_text) { + // TODO(suzhe): Filter invalid characters. + if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty()) + return; + + OnBeforeUserAction(); + skip_input_method_cancel_composition_ = true; + if (GetRenderText()->insert_mode()) + model_->InsertText(GetTextForDisplay(new_text)); + else + model_->ReplaceText(GetTextForDisplay(new_text)); + skip_input_method_cancel_composition_ = false; + UpdateAfterChange(true, true); + OnAfterUserAction(); +} + +void Textfield::InsertChar(base::char16 ch, int flags) { + // Filter out all control characters, including tab and new line characters, + // and all characters with Alt modifier. But allow characters with the AltGr + // modifier. On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a + // different flag that we don't care about. + const bool should_insert_char = ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && + (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; + if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char) + 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(text())); + + UpdateAfterChange(true, true); + OnAfterUserAction(); + + if (IsObscured() && obscured_reveal_duration_ != base::TimeDelta()) { + const size_t change_offset = model_->GetCursorPosition(); + DCHECK_GT(change_offset, 0u); + RevealObscuredChar(change_offset - 1, obscured_reveal_duration_); + } +} + +gfx::NativeWindow Textfield::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 Textfield::GetTextInputType() const { + if (read_only() || !enabled()) + return ui::TEXT_INPUT_TYPE_NONE; + return text_input_type_; +} + +ui::TextInputMode Textfield::GetTextInputMode() const { + return ui::TEXT_INPUT_MODE_DEFAULT; +} + +bool Textfield::CanComposeInline() const { + return true; +} + +gfx::Rect Textfield::GetCaretBounds() const { + gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds(); + ConvertRectToScreen(this, &rect); + return rect; +} + +bool Textfield::GetCompositionCharacterBounds(uint32 index, + gfx::Rect* rect) const { + DCHECK(rect); + if (!HasCompositionText()) + return false; + gfx::RenderText* render_text = GetRenderText(); + const gfx::Range& composition_range = render_text->GetCompositionRange(); + DCHECK(!composition_range.is_empty()); + + size_t text_index = composition_range.start() + index; + if (composition_range.end() <= text_index) + return false; + if (!render_text->IsCursorablePosition(text_index)) { + text_index = render_text->IndexOfAdjacentGrapheme( + text_index, gfx::CURSOR_BACKWARD); + } + if (text_index < composition_range.start()) + return false; + const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD); + *rect = render_text->GetCursorBounds(caret, false); + ConvertRectToScreen(this, rect); + return true; +} + +bool Textfield::HasCompositionText() const { + return model_->HasCompositionText(); +} + +bool Textfield::GetTextRange(gfx::Range* range) const { + if (!ImeEditingAllowed()) + return false; + + model_->GetTextRange(range); + return true; +} + +bool Textfield::GetCompositionTextRange(gfx::Range* range) const { + if (!ImeEditingAllowed()) + return false; + + model_->GetCompositionTextRange(range); + return true; +} + +bool Textfield::GetSelectionRange(gfx::Range* range) const { + if (!ImeEditingAllowed()) + return false; + *range = GetRenderText()->selection(); + return true; +} + +bool Textfield::SetSelectionRange(const gfx::Range& range) { + if (!ImeEditingAllowed() || !range.IsValid()) + return false; + + OnBeforeUserAction(); + SelectRange(range); + OnAfterUserAction(); + return true; +} + +bool Textfield::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 Textfield::GetTextFromRange(const gfx::Range& range, + base::string16* range_text) const { + if (!ImeEditingAllowed() || !range.IsValid()) + return false; + + gfx::Range text_range; + if (!GetTextRange(&text_range) || !text_range.Contains(range)) + return false; + + *range_text = model_->GetTextFromRange(range); + return true; +} + +void Textfield::OnInputMethodChanged() {} + +bool Textfield::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 Textfield::ExtendSelectionAndDelete(size_t before, size_t after) { + gfx::Range range = GetRenderText()->selection(); + 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 Textfield::EnsureCaretInRect(const gfx::Rect& rect) {} + +void Textfield::OnCandidateWindowShown() {} + +void Textfield::OnCandidateWindowUpdated() {} + +void Textfield::OnCandidateWindowHidden() {} + +//////////////////////////////////////////////////////////////////////////////// +// Textfield, protected: + +gfx::RenderText* Textfield::GetRenderText() const { + return model_->render_text(); +} + //////////////////////////////////////////////////////////////////////////////// // Textfield, private: -gfx::Insets Textfield::GetTextInsets() const { - gfx::Insets insets = GetInsets(); - if (draw_border_ && textfield_view_) - insets += textfield_view_->GetInsets(); - return insets; +base::string16 Textfield::GetTextForDisplay(const base::string16& raw) { + return style_ & Textfield::STYLE_LOWERCASE ? base::i18n::ToLower(raw) : raw; } void Textfield::AccessibilitySetValue(const base::string16& new_value) { @@ -556,4 +1340,200 @@ void Textfield::AccessibilitySetValue(const base::string16& new_value) { } } +void Textfield::UpdateBackgroundColor() { + const SkColor color = GetBackgroundColor(); + set_background(Background::CreateSolidBackground(color)); + GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF); + SchedulePaint(); +} + +void Textfield::UpdateColorsFromTheme(const ui::NativeTheme* theme) { + gfx::RenderText* render_text = GetRenderText(); + render_text->SetColor(GetTextColor()); + UpdateBackgroundColor(); + render_text->set_cursor_color(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 Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) { + if (text_changed) { + if (controller_) + controller_->ContentsChanged(this, text()); + NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true); + } + if (cursor_changed) { + is_cursor_visible_ = true; + RepaintCursor(); + if (cursor_repaint_timer_.IsRunning()) + cursor_repaint_timer_.Reset(); + if (!text_changed) { + // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire + // this if only the selection changed. + NotifyAccessibilityEvent( + ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); + } + } + if (text_changed || cursor_changed) { + OnCaretBoundsChanged(); + SchedulePaint(); + } +} + +void Textfield::UpdateCursor() { + const size_t caret_blink_ms = Textfield::GetCaretBlinkMs(); + is_cursor_visible_ = !is_cursor_visible_ || (caret_blink_ms == 0); + RepaintCursor(); +} + +void Textfield::RepaintCursor() { + gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds()); + r.Inset(-1, -1, -1, -1); + SchedulePaintInRect(r); +} + +void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) { + TRACE_EVENT0("views", "Textfield::PaintTextAndCursor"); + canvas->Save(); + gfx::RenderText* render_text = GetRenderText(); + render_text->set_cursor_visible(!is_drop_cursor_visible_ && + is_cursor_visible_ && !model_->HasSelection()); + // Draw the text, cursor, and selection. + render_text->Draw(canvas); + + // Draw the detached drop cursor that marks where the text will be dropped. + if (is_drop_cursor_visible_) + render_text->DrawCursor(canvas, drop_cursor_position_); + + // Draw placeholder text if needed. + if (text().empty() && !GetPlaceholderText().empty()) { + canvas->DrawStringRect(GetPlaceholderText(), GetFontList(), + placeholder_text_color(), render_text->display_rect()); + } + canvas->Restore(); +} + +bool Textfield::MoveCursorTo(const gfx::Point& point, bool select) { + if (!model_->MoveCursorTo(point, select)) + return false; + OnCaretBoundsChanged(); + return true; +} + +void Textfield::OnCaretBoundsChanged() { + if (GetInputMethod()) + GetInputMethod()->OnCaretBoundsChanged(this); + if (touch_selection_controller_) + touch_selection_controller_->SelectionChanged(); +} + +void Textfield::OnBeforeUserAction() { + if (controller_) + controller_->OnBeforeUserAction(this); +} + +void Textfield::OnAfterUserAction() { + if (controller_) + controller_->OnAfterUserAction(this); +} + +bool Textfield::Cut() { + if (!read_only() && !IsObscured() && model_->Cut()) { + if (controller_) + controller_->OnAfterCutOrCopy(); + return true; + } + return false; +} + +bool Textfield::Copy() { + if (!IsObscured() && model_->Copy()) { + if (controller_) + controller_->OnAfterCutOrCopy(); + return true; + } + return false; +} + +bool Textfield::Paste() { + if (read_only()) + return false; + + const base::string16 original_text = text(); + if (model_->Paste()) { + // 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(text()); + model_->SetText(new_text); + if (controller_) + controller_->OnAfterPaste(); + return true; + } + return false; +} + +void Textfield::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); + if (controller_) + controller_->UpdateContextMenu(context_menu_contents_.get()); + context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get())); + } +} + +void Textfield::TrackMouseClicks(const ui::MouseEvent& event) { + if (event.IsOnlyLeftMouseButton()) { + base::TimeDelta time_delta = event.time_stamp() - last_click_time_; + if (time_delta.InMilliseconds() <= GetDoubleClickInterval() && + !ExceededDragThreshold(event.location() - last_click_location_)) { + // 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(); + } +} + +bool Textfield::ImeEditingAllowed() const { + // Disallow input method editing of password fields. + ui::TextInputType t = GetTextInputType(); + return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD); +} + +void Textfield::RevealObscuredChar(int index, const base::TimeDelta& duration) { + GetRenderText()->SetObscuredRevealIndex(index); + SchedulePaint(); + + if (index != -1) { + obscured_reveal_timer_.Start(FROM_HERE, duration, + base::Bind(&Textfield::RevealObscuredChar, base::Unretained(this), + -1, base::TimeDelta())); + } +} + +void Textfield::CreateTouchSelectionControllerAndNotifyIt() { + if (!touch_selection_controller_) { + touch_selection_controller_.reset( + ui::TouchSelectionController::create(this)); + } + if (touch_selection_controller_) + touch_selection_controller_->SelectionChanged(); +} + } // namespace views diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index 90eaa98..e5dd73f 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h @@ -12,39 +12,35 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" -#include "base/time/time.h" -#include "build/build_config.h" +#include "base/timer/timer.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_type.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/base/touch/touch_editing_controller.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/font_list.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/range/range.h" #include "ui/gfx/selection_model.h" #include "ui/gfx/text_constants.h" +#include "ui/views/context_menu_controller.h" +#include "ui/views/controls/textfield/textfield_views_model.h" +#include "ui/views/drag_controller.h" #include "ui/views/view.h" -#if !defined(OS_LINUX) -#include "base/logging.h" -#endif - -namespace gfx { -class Range; -class ImageSkia; -} - -namespace ui { -class TextInputClient; -} // namespace ui - namespace views { -class ImageView; -class NativeTextfieldViews; +class MenuRunner; class Painter; class TextfieldController; -// This class implements a View that wraps a native text (edit) field. -class VIEWS_EXPORT Textfield : public View { +// A views/skia textfield implementation. No platform-specific code is used. +class VIEWS_EXPORT Textfield : public View, + public TextfieldViewsModel::Delegate, + public ContextMenuController, + public DragController, + public ui::TouchEditable, + public ui::TextInputClient { public: // The textfield's class name. static const char kViewClassName[]; @@ -75,35 +71,23 @@ class VIEWS_EXPORT Textfield : public View { bool IsObscured() const; void SetObscured(bool obscured); - // Gets/sets the duration to reveal the last typed char when the obscured bit - // is set. A duration of zero effectively disables the feature. Other values - // cause the last typed char to be shown for the defined duration. Note this - // only works with NativeTextfieldViews. - const base::TimeDelta& obscured_reveal_duration() const { - return obscured_reveal_duration_; - } - void set_obscured_reveal_duration(const base::TimeDelta& duration) { - obscured_reveal_duration_ = duration; - } - - // Gets/Sets the input type of this textfield. - ui::TextInputType GetTextInputType() const; + // Sets the input type of this textfield. void SetTextInputType(ui::TextInputType type); - // Gets/Sets the text currently displayed in the Textfield. - const base::string16& text() const { return text_; } + // Gets the text currently displayed in the Textfield. + const base::string16& text() const { return model_->text(); } // Sets the text currently displayed in the Textfield. This doesn't // change the cursor position if the current cursor is within the // new text's range, or moves the cursor to the end if the cursor is // out of the new text's range. - void SetText(const base::string16& text); + void SetText(const base::string16& new_text); // Appends the given string to the previously-existing text in the field. - void AppendText(const base::string16& text); + void AppendText(const base::string16& new_text); - // Inserts |text| at the current cursor position, replacing any selected text. - void InsertOrReplaceText(const base::string16& text); + // Inserts |new_text| at the cursor position, replacing any selected text. + void InsertOrReplaceText(const base::string16& new_text); // Returns the text direction. base::i18n::TextDirection GetTextDirection() const; @@ -117,7 +101,7 @@ class VIEWS_EXPORT Textfield : public View { void SelectAll(bool reversed); // Clears the selection within the edit field and sets the caret to the end. - void ClearSelection() const; + void ClearSelection(); // Checks if there is any selected text. bool HasSelection() const; @@ -142,29 +126,14 @@ class VIEWS_EXPORT Textfield : public View { void SetCursorEnabled(bool enabled); // Gets/Sets the fonts used when rendering the text within the Textfield. - const gfx::FontList& font_list() const { return font_list_; } + const gfx::FontList& GetFontList() const; void SetFontList(const gfx::FontList& font_list); - const gfx::Font& GetPrimaryFont() const; - void SetFont(const gfx::Font& font); - - // Sets the left and right margin (in pixels) within the text box. On Windows - // this is accomplished by packing the left and right margin into a single - // 32 bit number, so the left and right margins are effectively 16 bits. - void SetHorizontalMargins(int left, int right); - - // Sets the top and bottom margins (in pixels) within the textfield. - // NOTE: in most cases height could be changed instead. - void SetVerticalMargins(int top, int bottom); // Sets the default width of the text control. See default_width_in_chars_. void set_default_width_in_chars(int default_width) { default_width_in_chars_ = default_width; } - // Removes the border from the edit box, giving it a 2D look. - bool draw_border() const { return draw_border_; } - void RemoveBorder(); - // Sets the text to display when empty. void set_placeholder_text(const base::string16& text) { placeholder_text_ = text; @@ -176,24 +145,6 @@ class VIEWS_EXPORT Textfield : public View { placeholder_text_color_ = color; } - // Getter for the horizontal margins that were set. Returns false if - // horizontal margins weren't set. - bool GetHorizontalMargins(int* left, int* right); - - // Getter for the vertical margins that were set. Returns false if vertical - // margins weren't set. - bool GetVerticalMargins(int* top, int* bottom); - - // Updates all properties on the textfield. This is invoked internally. - // Users of Textfield never need to invoke this directly. - void UpdateAllProperties(); - - // Invoked by the edit control when the value changes. This method set - // the text_ member variable to the value contained in edit control. - // This is important because the edit control can be replaced if it has - // been deleted during a window close. - void SyncText(); - // Returns whether or not an IME is composing text. bool IsIMEComposing() const; @@ -234,61 +185,188 @@ class VIEWS_EXPORT Textfield : public View { void SetFocusPainter(scoped_ptr<Painter> focus_painter); - // Provided only for testing: - NativeTextfieldViews* GetTextfieldViewForTesting() const { - return textfield_view_; - } - // Returns whether there is a drag operation originating from the textfield. bool HasTextBeingDragged(); - // Overridden from View: - virtual void Layout() OVERRIDE; + // View overrides: + // TODO(msw): Match declaration and definition order to View. virtual int GetBaseline() const OVERRIDE; virtual gfx::Size GetPreferredSize() OVERRIDE; virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE; virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE; virtual void OnEnabledChanged() OVERRIDE; virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; - virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE; - virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE; - virtual bool OnMouseDragged(const ui::MouseEvent& e) OVERRIDE; + virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; + virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; + virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; + virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; virtual void OnFocus() OVERRIDE; virtual void OnBlur() OVERRIDE; virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; virtual ui::TextInputClient* GetTextInputClient() OVERRIDE; virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE; - - protected: - virtual void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) OVERRIDE; + virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE; virtual const char* GetClassName() const OVERRIDE; + virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE; + virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; + virtual bool GetDropFormats( + int* formats, + std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE; + virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE; + virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE; + virtual void OnDragExited() OVERRIDE; + virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE; + virtual void OnDragDone() OVERRIDE; + virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; + + // TextfieldViewsModel::Delegate overrides: + virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE; + + // ContextMenuController overrides: + virtual void ShowContextMenuForView(View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) OVERRIDE; + + // DragController overrides: + virtual void WriteDragDataForView(View* sender, + const gfx::Point& press_pt, + ui::OSExchangeData* data) OVERRIDE; + virtual int GetDragOperationsForView(View* sender, + const gfx::Point& p) OVERRIDE; + virtual bool CanStartDragForView(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) OVERRIDE; + + // ui::TouchEditable overrides: + virtual void SelectRect(const gfx::Point& start, + const gfx::Point& end) OVERRIDE; + virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE; + virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE; + virtual gfx::Rect GetBounds() OVERRIDE; + virtual gfx::NativeView GetNativeView() const OVERRIDE; + virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE; + virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE; + virtual bool DrawsHandles() OVERRIDE; + virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE; + + // ui::SimpleMenuModel::Delegate overrides: + virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) OVERRIDE; + virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; + + // ui::TextInputClient overrides: + virtual void SetCompositionText( + const ui::CompositionText& composition) OVERRIDE; + virtual void ConfirmCompositionText() OVERRIDE; + virtual void ClearCompositionText() OVERRIDE; + virtual void InsertText(const base::string16& text) OVERRIDE; + virtual void InsertChar(base::char16 ch, int flags) OVERRIDE; + virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE; + virtual ui::TextInputType GetTextInputType() const OVERRIDE; + virtual ui::TextInputMode GetTextInputMode() const OVERRIDE; + virtual bool CanComposeInline() const OVERRIDE; + virtual gfx::Rect GetCaretBounds() const OVERRIDE; + virtual bool GetCompositionCharacterBounds(uint32 index, + gfx::Rect* rect) const OVERRIDE; + virtual bool HasCompositionText() const OVERRIDE; + virtual bool GetTextRange(gfx::Range* range) const OVERRIDE; + virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE; + virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE; + virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE; + virtual bool DeleteRange(const gfx::Range& range) OVERRIDE; + virtual bool GetTextFromRange(const gfx::Range& range, + base::string16* text) const OVERRIDE; + virtual void OnInputMethodChanged() OVERRIDE; + virtual bool ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection direction) OVERRIDE; + virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE; + virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE; + virtual void OnCandidateWindowShown() OVERRIDE; + virtual void OnCandidateWindowUpdated() OVERRIDE; + virtual void OnCandidateWindowHidden() OVERRIDE; - // The object that actually implements the native textfield view. - // TODO(msw): Merge views::NativeTextfieldViews and views::Textfield classes. - NativeTextfieldViews* textfield_view_; + protected: + // Returns the TextfieldViewsModel's text/cursor/selection rendering model. + gfx::RenderText* GetRenderText() const; private: - // Returns the insets to the rectangle where text is actually painted. - gfx::Insets GetTextInsets() const; + friend class TextfieldTest; + friend class TouchSelectionControllerImplTest; + + // Converts the raw text according to the current style, e.g. STYLE_LOWERCASE. + base::string16 GetTextForDisplay(const base::string16& raw); // Handles a request to change the value of this text field from software // using an accessibility API (typically automation software, screen readers // don't normally use this). Sets the value and clears the selection. void AccessibilitySetValue(const base::string16& new_value); + // Updates the painted background color. + void UpdateBackgroundColor(); + + // Updates any colors that have not been explicitly set from the theme. + void UpdateColorsFromTheme(const ui::NativeTheme* theme); + + // Does necessary updates when the text and/or cursor position changes. + void UpdateAfterChange(bool text_changed, bool cursor_changed); + + // A callback function to periodically update the cursor state. + void UpdateCursor(); + + // Repaint the cursor. + void RepaintCursor(); + + void PaintTextAndCursor(gfx::Canvas* canvas); + + // Helper function to call MoveCursorTo on the TextfieldViewsModel. + bool MoveCursorTo(const gfx::Point& point, bool select); + + // Convenience method to call InputMethod::OnCaretBoundsChanged(); + void OnCaretBoundsChanged(); + + // Convenience method to call TextfieldController::OnBeforeUserAction(); + void OnBeforeUserAction(); + + // Convenience method to call TextfieldController::OnAfterUserAction(); + void OnAfterUserAction(); + + // Calls |model_->Cut()| and notifies TextfieldController on success. + bool Cut(); + + // Calls |model_->Copy()| and notifies TextfieldController on success. + bool Copy(); + + // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged() + // explicitly if paste succeeded. + bool Paste(); + + // Utility function to prepare the context menu. + void UpdateContextMenu(); + + // Tracks the mouse clicks for single/double/triple clicks. + void TrackMouseClicks(const ui::MouseEvent& event); + + // Returns true if the current text input type allows access by the IME. + bool ImeEditingAllowed() const; + + // Reveals the obscured char at |index| for the given |duration|. If |index| + // is -1, existing revealed index will be cleared. + void RevealObscuredChar(int index, const base::TimeDelta& duration); + + void CreateTouchSelectionControllerAndNotifyIt(); + + // The text model. + scoped_ptr<TextfieldViewsModel> model_; + // This is the current listener for events from this Textfield. TextfieldController* controller_; // The mask of style options for this Textfield. StyleFlags style_; - // The fonts used to render the text in the Textfield. - gfx::FontList font_list_; - - // The text displayed in the Textfield. - base::string16 text_; - // True if this Textfield cannot accept input and is read-only. bool read_only_; @@ -296,8 +374,7 @@ class VIEWS_EXPORT Textfield : public View { // This will be reported as the "desired size". Defaults to 0. int default_width_in_chars_; - // Whether the border is drawn. - bool draw_border_; + scoped_ptr<Painter> focus_painter_; // Text color. Only used if |use_default_text_color_| is false. SkColor text_color_; @@ -311,13 +388,6 @@ class VIEWS_EXPORT Textfield : public View { // Should we use the system background color instead of |background_color_|? bool use_default_background_color_; - // Holds inner textfield margins. - gfx::Insets margins_; - - // Holds whether margins were set. - bool horizontal_margins_were_set_; - bool vertical_margins_were_set_; - // Text to display when empty. base::string16 placeholder_text_; @@ -333,11 +403,40 @@ class VIEWS_EXPORT Textfield : public View { // The duration to reveal the last typed char for obscured textfields. base::TimeDelta obscured_reveal_duration_; + // True if InputMethod::CancelComposition() should not be called. + bool skip_input_method_cancel_composition_; + + // The text editing cursor repaint timer and visibility. + base::RepeatingTimer<Textfield> cursor_repaint_timer_; + bool is_cursor_visible_; + + // The drop cursor is a visual cue for where dragged text will be dropped. + bool is_drop_cursor_visible_; + gfx::SelectionModel drop_cursor_position_; + + // Is the user potentially dragging and dropping from this view? + bool initiating_drag_; + + // State variables used to track double and triple clicks. + size_t aggregated_clicks_; + base::TimeDelta last_click_time_; + gfx::Point last_click_location_; + gfx::Range double_click_word_; + + scoped_ptr<ui::TouchSelectionController> touch_selection_controller_; + + // A timer to control the duration of showing the last typed char in + // obscured text. When the timer is running, the last typed char is shown + // and when the time expires, the last typed char is obscured. + base::OneShotTimer<Textfield> obscured_reveal_timer_; + + // Context menu related members. + scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; + scoped_ptr<views::MenuRunner> context_menu_runner_; + // Used to bind callback functions to this object. base::WeakPtrFactory<Textfield> weak_ptr_factory_; - scoped_ptr<Painter> focus_painter_; - DISALLOW_COPY_AND_ASSIGN(Textfield); }; diff --git a/ui/views/controls/textfield/textfield_controller.cc b/ui/views/controls/textfield/textfield_controller.cc index e825796..1d90f3c0 100644 --- a/ui/views/controls/textfield/textfield_controller.cc +++ b/ui/views/controls/textfield/textfield_controller.cc @@ -23,20 +23,4 @@ int TextfieldController::OnDrop(const ui::OSExchangeData& data) { return ui::DragDropTypes::DRAG_NONE; } -bool TextfieldController::IsCommandIdEnabled(int command_id) const { - return false; -} - -bool TextfieldController::IsItemForCommandIdDynamic(int command_id) const { - return false; -} - -base::string16 TextfieldController::GetLabelForCommandId(int command_id) const { - return base::string16(); -} - -bool TextfieldController::HandlesCommand(int command_id) const { - return false; -} - } // namespace views diff --git a/ui/views/controls/textfield/textfield_controller.h b/ui/views/controls/textfield/textfield_controller.h index bebec1c..be9b938 100644 --- a/ui/views/controls/textfield/textfield_controller.h +++ b/ui/views/controls/textfield/textfield_controller.h @@ -79,26 +79,6 @@ class VIEWS_EXPORT TextfieldController { // Gives the controller a chance to modify the context menu contents. virtual void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) {} - // Returns true if the |command_id| should be enabled in the context menu. - virtual bool IsCommandIdEnabled(int command_id) const; - - // Returns true if the item label for the |command_id| is dynamic in the - // context menu. - virtual bool IsItemForCommandIdDynamic(int command_id) const; - - // Returns the label string for the |coomand_id|. - virtual base::string16 GetLabelForCommandId(int command_id) const; - - // Returns whether the controller handles the specified command. This is used - // to handle a command the textfield would normally handle. For example, to - // have the controller handle |IDS_APP_PASTE| override and return true if - // |command_id| == |IDS_APP_PASTE|. - // This is only invoked if the command is enabled. - virtual bool HandlesCommand(int command_id) const; - - // Execute context menu command specified by |command_id|. - virtual void ExecuteCommand(int command_id, int event_flag) {} - protected: virtual ~TextfieldController() {} }; diff --git a/ui/views/controls/textfield/native_textfield_views_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 54f7337..4cd3663 100644 --- a/ui/views/controls/textfield/native_textfield_views_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc @@ -2,7 +2,7 @@ // 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 "ui/views/controls/textfield/textfield.h" #include <set> #include <string> @@ -25,10 +25,10 @@ #include "ui/base/ime/text_input_client.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_switches.h" +#include "ui/base/ui_base_switches_util.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/render_text.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/focus/focus_manager.h" @@ -119,16 +119,11 @@ class GestureEventForTest : public ui::GestureEvent { namespace views { -// TODO(oshima): Move tests that are independent of TextfieldViews to -// textfield_unittests.cc once we move the test utility functions -// from chrome/browser/automation/ to ui/base/test/. -class NativeTextfieldViewsTest : public ViewsTestBase, - public TextfieldController { +class TextfieldTest : public ViewsTestBase, public TextfieldController { public: - NativeTextfieldViewsTest() + TextfieldTest() : widget_(NULL), textfield_(NULL), - textfield_view_(NULL), model_(NULL), input_method_(NULL), on_before_user_action_(0), @@ -184,10 +179,7 @@ class NativeTextfieldViewsTest : public ViewsTestBase, View* container = new View(); widget_->SetContentsView(container); container->AddChildView(textfield_); - - textfield_view_ = textfield_->GetTextfieldViewForTesting(); - DCHECK(textfield_view_); - textfield_view_->SetBoundsRect(params.bounds); + textfield_->SetBoundsRect(params.bounds); textfield_->set_id(1); for (int i = 1; i < count; i++) { @@ -196,7 +188,7 @@ class NativeTextfieldViewsTest : public ViewsTestBase, textfield->set_id(i + 1); } - model_ = textfield_view_->model_.get(); + model_ = textfield_->model_.get(); model_->ClearEditHistory(); input_method_ = new MockInputMethod(); @@ -208,12 +200,12 @@ class NativeTextfieldViewsTest : public ViewsTestBase, } ui::MenuModel* GetContextMenuModel() { - textfield_view_->UpdateContextMenu(); - return textfield_view_->context_menu_contents_.get(); + textfield_->UpdateContextMenu(); + return textfield_->context_menu_contents_.get(); } ui::TouchSelectionController* GetTouchSelectionController() { - return textfield_view_->touch_selection_controller_.get(); + return textfield_->touch_selection_controller_.get(); } protected: @@ -270,27 +262,22 @@ class NativeTextfieldViewsTest : public ViewsTestBase, } int GetCursorPositionX(int cursor_pos) { - gfx::RenderText* render_text = textfield_view_->GetRenderText(); - return render_text->GetCursorBounds( + return textfield_->GetRenderText()->GetCursorBounds( gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x(); } // Get the current cursor bounds. gfx::Rect GetCursorBounds() { - gfx::RenderText* render_text = textfield_view_->GetRenderText(); - gfx::Rect bounds = render_text->GetUpdatedCursorBounds(); - return bounds; + return textfield_->GetRenderText()->GetUpdatedCursorBounds(); } // Get the cursor bounds of |sel|. gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) { - gfx::RenderText* render_text = textfield_view_->GetRenderText(); - gfx::Rect bounds = render_text->GetCursorBounds(sel, true); - return bounds; + return textfield_->GetRenderText()->GetCursorBounds(sel, true); } gfx::Rect GetDisplayRect() { - return textfield_view_->GetRenderText()->display_rect(); + return textfield_->GetRenderText()->display_rect(); } // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and @@ -299,10 +286,10 @@ class NativeTextfieldViewsTest : public ViewsTestBase, gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2); ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click); + textfield_->OnMousePressed(click); ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMouseReleased(release); + textfield_->OnMouseReleased(release); } // This is to avoid double/triple click. @@ -310,16 +297,16 @@ class NativeTextfieldViewsTest : public ViewsTestBase, ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click); + textfield_->OnMousePressed(click); ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMouseReleased(release); + textfield_->OnMouseReleased(release); } // Wrap for visibility in test classes. ui::TextInputType GetTextInputType() { - return textfield_view_->GetTextInputType(); + return textfield_->GetTextInputType(); } void VerifyTextfieldContextMenuContents(bool textfield_has_selection, @@ -339,7 +326,6 @@ class NativeTextfieldViewsTest : public ViewsTestBase, Widget* widget_; TestTextfield* textfield_; - NativeTextfieldViews* textfield_view_; TextfieldViewsModel* model_; // The string from Controller::ContentsChanged callback. @@ -355,10 +341,10 @@ class NativeTextfieldViewsTest : public ViewsTestBase, int on_after_user_action_; private: - DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViewsTest); + DISALLOW_COPY_AND_ASSIGN(TextfieldTest); }; -TEST_F(NativeTextfieldViewsTest, ModelChangesTest) { +TEST_F(TextfieldTest, ModelChangesTest) { InitTextfield(Textfield::STYLE_DEFAULT); // TextfieldController::ContentsChanged() shouldn't be called when changing @@ -366,12 +352,12 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTest) { last_contents_.clear(); textfield_->SetText(ASCIIToUTF16("this is")); - EXPECT_STR_EQ("this is", model_->GetText()); + EXPECT_STR_EQ("this is", model_->text()); EXPECT_STR_EQ("this is", textfield_->text()); EXPECT_TRUE(last_contents_.empty()); textfield_->AppendText(ASCIIToUTF16(" a test")); - EXPECT_STR_EQ("this is a test", model_->GetText()); + EXPECT_STR_EQ("this is a test", model_->text()); EXPECT_STR_EQ("this is a test", textfield_->text()); EXPECT_TRUE(last_contents_.empty()); @@ -381,7 +367,7 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTest) { EXPECT_TRUE(last_contents_.empty()); } -TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) { +TEST_F(TextfieldTest, ModelChangesTestLowerCase) { // Check if |model_|'s text is properly lowercased for STYLE_LOWERCASE. InitTextfield(Textfield::STYLE_LOWERCASE); EXPECT_EQ(0U, textfield_->GetCursorPosition()); @@ -390,19 +376,17 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) { textfield_->SetText(ASCIIToUTF16("THIS IS")); EXPECT_EQ(7U, textfield_->GetCursorPosition()); - EXPECT_STR_EQ("this is", model_->GetText()); - EXPECT_STR_EQ("THIS IS", textfield_->text()); + EXPECT_STR_EQ("this is", textfield_->text()); EXPECT_TRUE(last_contents_.empty()); textfield_->AppendText(ASCIIToUTF16(" A TEST")); EXPECT_EQ(7U, textfield_->GetCursorPosition()); - EXPECT_STR_EQ("this is a test", model_->GetText()); - EXPECT_STR_EQ("THIS IS A TEST", textfield_->text()); + EXPECT_STR_EQ("this is a test", textfield_->text()); EXPECT_TRUE(last_contents_.empty()); } -TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) { +TEST_F(TextfieldTest, ModelChangesTestLowerCaseI18n) { // Check if lower case conversion works for non-ASCII characters. InitTextfield(Textfield::STYLE_LOWERCASE); EXPECT_EQ(0U, textfield_->GetCursorPosition()); @@ -413,9 +397,6 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) { EXPECT_EQ(6U, textfield_->GetCursorPosition()); // Zenkaku Japanese "abcabc" EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"), - model_->GetText()); - // Zenkaku Japanese "ABCabc" - EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"), textfield_->text()); EXPECT_TRUE(last_contents_.empty()); @@ -425,15 +406,11 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) { // Zenkaku Japanese "abcabcxyzxyz" EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43" L"\xFF58\xFF59\xFF5A\xFF58\xFF59\xFF5A"), - model_->GetText()); - // Zenkaku Japanese "ABCabcXYZxyz" - EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43" - L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"), textfield_->text()); EXPECT_TRUE(last_contents_.empty()); } -TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) { +TEST_F(TextfieldTest, ModelChangesTestLowerCaseWithLocale) { // Check if lower case conversion honors locale properly. std::string locale = l10n_util::GetApplicationLocale(""); base::i18n::SetICUDefaultLocale("tr"); @@ -445,8 +422,7 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) { // Turkish 'I' should be converted to dotless 'i' (U+0131). textfield_->SetText(WideToUTF16(L"I")); EXPECT_EQ(1U, textfield_->GetCursorPosition()); - EXPECT_EQ(WideToUTF16(L"\x0131"), model_->GetText()); - EXPECT_EQ(WideToUTF16(L"I"), textfield_->text()); + EXPECT_EQ(WideToUTF16(L"\x0131"), textfield_->text()); EXPECT_TRUE(last_contents_.empty()); base::i18n::SetICUDefaultLocale(locale); @@ -454,12 +430,11 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) { // On default (en) locale, 'I' should be converted to 'i'. textfield_->SetText(WideToUTF16(L"I")); EXPECT_EQ(1U, textfield_->GetCursorPosition()); - EXPECT_EQ(WideToUTF16(L"i"), model_->GetText()); - EXPECT_EQ(WideToUTF16(L"I"), textfield_->text()); + EXPECT_EQ(WideToUTF16(L"i"), textfield_->text()); EXPECT_TRUE(last_contents_.empty()); } -TEST_F(NativeTextfieldViewsTest, KeyTest) { +TEST_F(TextfieldTest, KeyTest) { InitTextfield(Textfield::STYLE_DEFAULT); // Event flags: key, alt, shift, ctrl, caps-lock. SendKeyEvent(ui::VKEY_T, false, true, false, false); @@ -473,7 +448,7 @@ TEST_F(NativeTextfieldViewsTest, KeyTest) { EXPECT_STR_EQ("TexT!1!1", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) { +TEST_F(TextfieldTest, ControlAndSelectTest) { // Insert a test string in a textfield. InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("one two three")); @@ -508,7 +483,7 @@ TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) { EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText()); } -TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) { +TEST_F(TextfieldTest, InsertionDeletionTest) { // Insert a test string in a textfield. InitTextfield(Textfield::STYLE_DEFAULT); for (size_t i = 0; i < 10; i++) @@ -535,13 +510,13 @@ TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) { SendKeyEvent(ui::VKEY_BACK, false, false, true, false); EXPECT_STR_EQ("one two three ", textfield_->text()); - // Delete text preceeding the cursor in chromeos, do nothing in windows. + // Delete to a line break on Linux and ChromeOS, no-op on Windows. SendKeyEvent(ui::VKEY_LEFT, false, false, true, false); SendKeyEvent(ui::VKEY_BACK, false, true, true, false); -#if defined(OS_WIN) - EXPECT_STR_EQ("one two three ", textfield_->text()); -#else +#if defined(OS_LINUX) EXPECT_STR_EQ("three ", textfield_->text()); +#else + EXPECT_STR_EQ("one two three ", textfield_->text()); #endif // Delete the next word from cursor. @@ -550,17 +525,17 @@ TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) { SendKeyEvent(ui::VKEY_DELETE, false, false, true, false); EXPECT_STR_EQ(" two three four", textfield_->text()); - // Delete text following the cursor in chromeos, do nothing in windows. + // Delete to a line break on Linux and ChromeOS, no-op on Windows. SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false); SendKeyEvent(ui::VKEY_DELETE, false, true, true, false); -#if defined(OS_WIN) - EXPECT_STR_EQ(" two three four", textfield_->text()); -#else +#if defined(OS_LINUX) EXPECT_STR_EQ(" two", textfield_->text()); +#else + EXPECT_STR_EQ(" two three four", textfield_->text()); #endif } -TEST_F(NativeTextfieldViewsTest, PasswordTest) { +TEST_F(TextfieldTest, PasswordTest) { InitTextfield(Textfield::STYLE_OBSCURED); EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType()); EXPECT_TRUE(textfield_->enabled()); @@ -575,11 +550,11 @@ TEST_F(NativeTextfieldViewsTest, PasswordTest) { SetClipboardText("foo"); // Cut and copy should be disabled. - EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); - textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); + EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); + textfield_->ExecuteCommand(IDS_APP_CUT, 0); SendKeyEvent(ui::VKEY_X, false, true); - EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); - textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); + EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); + textfield_->ExecuteCommand(IDS_APP_COPY, 0); SendKeyEvent(ui::VKEY_C, false, true); SendKeyEvent(ui::VKEY_INSERT, false, true); EXPECT_STR_EQ("foo", base::string16(GetClipboardText())); @@ -589,15 +564,15 @@ TEST_F(NativeTextfieldViewsTest, PasswordTest) { SendKeyEvent(ui::VKEY_DELETE, true, false); // Paste should work normally. - EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); - textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); + EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); + textfield_->ExecuteCommand(IDS_APP_PASTE, 0); SendKeyEvent(ui::VKEY_V, false, true); SendKeyEvent(ui::VKEY_INSERT, true, false); EXPECT_STR_EQ("foo", base::string16(GetClipboardText())); EXPECT_STR_EQ("foofoofoo", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, InputTypeSetsObscured) { +TEST_F(TextfieldTest, InputTypeSetsObscured) { InitTextfield(Textfield::STYLE_DEFAULT); // Defaults to TEXT @@ -609,7 +584,7 @@ TEST_F(NativeTextfieldViewsTest, InputTypeSetsObscured) { EXPECT_TRUE(textfield_->IsObscured()); } -TEST_F(NativeTextfieldViewsTest, ObscuredSetsInputType) { +TEST_F(TextfieldTest, ObscuredSetsInputType) { InitTextfield(Textfield::STYLE_DEFAULT); // Defaults to TEXT @@ -622,7 +597,7 @@ TEST_F(NativeTextfieldViewsTest, ObscuredSetsInputType) { EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType()); } -TEST_F(NativeTextfieldViewsTest, TextInputType) { +TEST_F(TextfieldTest, TextInputType) { InitTextfield(Textfield::STYLE_DEFAULT); // Defaults to TEXT @@ -644,7 +619,7 @@ TEST_F(NativeTextfieldViewsTest, TextInputType) { EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType()); } -TEST_F(NativeTextfieldViewsTest, OnKeyPressReturnValueTest) { +TEST_F(TextfieldTest, OnKeyPressReturnValueTest) { InitTextfield(Textfield::STYLE_DEFAULT); // Character keys will be handled by input method. @@ -707,7 +682,7 @@ TEST_F(NativeTextfieldViewsTest, OnKeyPressReturnValueTest) { textfield_->clear(); } -TEST_F(NativeTextfieldViewsTest, CursorMovement) { +TEST_F(TextfieldTest, CursorMovement) { InitTextfield(Textfield::STYLE_DEFAULT); // Test with trailing whitespace. @@ -757,7 +732,7 @@ TEST_F(NativeTextfieldViewsTest, CursorMovement) { EXPECT_STR_EQ("one two", last_contents_); } -TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) { +TEST_F(TextfieldTest, FocusTraversalTest) { InitTextfields(Textfield::STYLE_DEFAULT, 3); textfield_->RequestFocus(); @@ -789,16 +764,16 @@ TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) { EXPECT_EQ(3, GetFocusedView()->id()); ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click); + textfield_->OnMousePressed(click); EXPECT_EQ(1, GetFocusedView()->id()); } -TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) { +TEST_F(TextfieldTest, ContextMenuDisplayTest) { InitTextfield(Textfield::STYLE_DEFAULT); EXPECT_TRUE(textfield_->context_menu_controller()); textfield_->SetText(ASCIIToUTF16("hello world")); ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE); - textfield_view_->ClearEditHistory(); + textfield_->ClearEditHistory(); EXPECT_TRUE(GetContextMenuModel()); VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel()); @@ -816,7 +791,7 @@ TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) { VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel()); } -TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) { +TEST_F(TextfieldTest, DoubleAndTripleClickTest) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), @@ -829,25 +804,25 @@ TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) { ui::EF_LEFT_MOUSE_BUTTON); // Test for double click. - textfield_view_->OnMousePressed(click); - textfield_view_->OnMouseReleased(release); + textfield_->OnMousePressed(click); + textfield_->OnMouseReleased(release); EXPECT_TRUE(textfield_->GetSelectedText().empty()); - textfield_view_->OnMousePressed(double_click); - textfield_view_->OnMouseReleased(release); + textfield_->OnMousePressed(double_click); + textfield_->OnMouseReleased(release); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); // Test for triple click. - textfield_view_->OnMousePressed(click); - textfield_view_->OnMouseReleased(release); + textfield_->OnMousePressed(click); + textfield_->OnMouseReleased(release); EXPECT_STR_EQ("hello world", textfield_->GetSelectedText()); // Another click should reset back to double click. - textfield_view_->OnMousePressed(click); - textfield_view_->OnMouseReleased(release); + textfield_->OnMousePressed(click); + textfield_->OnMouseReleased(release); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); } -TEST_F(NativeTextfieldViewsTest, DragToSelect) { +TEST_F(TextfieldTest, DragToSelect) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); const int kStart = GetCursorPositionX(5); @@ -864,28 +839,28 @@ TEST_F(NativeTextfieldViewsTest, DragToSelect) { ui::EF_LEFT_MOUSE_BUTTON, 0); ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click_a); + textfield_->OnMousePressed(click_a); EXPECT_TRUE(textfield_->GetSelectedText().empty()); // Check that dragging left selects the beginning of the string. - textfield_view_->OnMouseDragged(drag_left); + textfield_->OnMouseDragged(drag_left); base::string16 text_left = textfield_->GetSelectedText(); EXPECT_STR_EQ("hello", text_left); // Check that dragging right selects the rest of the string. - textfield_view_->OnMouseDragged(drag_right); + textfield_->OnMouseDragged(drag_right); base::string16 text_right = textfield_->GetSelectedText(); EXPECT_STR_EQ(" world", text_right); // Check that releasing in the same location does not alter the selection. - textfield_view_->OnMouseReleased(release); + textfield_->OnMouseReleased(release); EXPECT_EQ(text_right, textfield_->GetSelectedText()); // Check that dragging from beyond the text length works too. - textfield_view_->OnMousePressed(click_b); - textfield_view_->OnMouseDragged(drag_left); - textfield_view_->OnMouseReleased(release); + textfield_->OnMousePressed(click_b); + textfield_->OnMouseDragged(drag_left); + textfield_->OnMouseReleased(release); EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText()); } #if defined(OS_WIN) -TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) { +TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); @@ -897,31 +872,31 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) { // Ensure that disabled textfields do not accept drops. textfield_->SetEnabled(false); - EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats)); + EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats)); EXPECT_EQ(0, formats); EXPECT_TRUE(custom_formats.empty()); - EXPECT_FALSE(textfield_view_->CanDrop(data)); + EXPECT_FALSE(textfield_->CanDrop(data)); textfield_->SetEnabled(true); // Ensure that read-only textfields do not accept drops. textfield_->SetReadOnly(true); - EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats)); + EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats)); EXPECT_EQ(0, formats); EXPECT_TRUE(custom_formats.empty()); - EXPECT_FALSE(textfield_view_->CanDrop(data)); + EXPECT_FALSE(textfield_->CanDrop(data)); textfield_->SetReadOnly(false); // Ensure that enabled and editable textfields do accept drops. - EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); + EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); EXPECT_EQ(ui::OSExchangeData::STRING, formats); EXPECT_TRUE(custom_formats.empty()); - EXPECT_TRUE(textfield_view_->CanDrop(data)); + EXPECT_TRUE(textfield_->CanDrop(data)); gfx::Point drop_point(GetCursorPositionX(6), 0); ui::DropTargetEvent drop(data, drop_point, drop_point, ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE); EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE, - textfield_view_->OnDragUpdated(drop)); - EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_view_->OnPerformDrop(drop)); + textfield_->OnDragUpdated(drop)); + EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop)); EXPECT_STR_EQ("hello string world", textfield_->text()); // Ensure that textfields do not accept non-OSExchangeData::STRING types. @@ -935,11 +910,11 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) { ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL); bad_data.SetDownloadFileInfo(download); #endif - EXPECT_FALSE(textfield_view_->CanDrop(bad_data)); + EXPECT_FALSE(textfield_->CanDrop(bad_data)); } #endif -TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) { +TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello string world")); @@ -949,44 +924,44 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) { const gfx::Range kStringRange(6, 12); textfield_->SelectRange(kStringRange); const gfx::Point kStringPoint(GetCursorPositionX(9), 0); - textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data); + textfield_->WriteDragDataForView(NULL, kStringPoint, &data); EXPECT_TRUE(data.GetString(&string)); EXPECT_EQ(textfield_->GetSelectedText(), string); // Ensure that disabled textfields do not support drag operations. textfield_->SetEnabled(false); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, - textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); + textfield_->GetDragOperationsForView(NULL, kStringPoint)); textfield_->SetEnabled(true); // Ensure that textfields without selections do not support drag operations. textfield_->ClearSelection(); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, - textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); + textfield_->GetDragOperationsForView(NULL, kStringPoint)); textfield_->SelectRange(kStringRange); // Ensure that password textfields do not support drag operations. textfield_->SetObscured(true); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, - textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); + textfield_->GetDragOperationsForView(NULL, kStringPoint)); textfield_->SetObscured(false); // Ensure that textfields only initiate drag operations inside the selection. ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(press_event); + textfield_->OnMousePressed(press_event); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, - textfield_view_->GetDragOperationsForView(NULL, gfx::Point())); - EXPECT_FALSE(textfield_view_->CanStartDragForView(NULL, gfx::Point(), - gfx::Point())); + textfield_->GetDragOperationsForView(NULL, gfx::Point())); + EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(), + gfx::Point())); EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, - textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); - EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, kStringPoint, - gfx::Point())); + textfield_->GetDragOperationsForView(NULL, kStringPoint)); + EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint, + gfx::Point())); // Ensure that textfields support local moves. EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, - textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint)); + textfield_->GetDragOperationsForView(textfield_, kStringPoint)); } -TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) { +TEST_F(TextfieldTest, DragAndDrop_ToTheRight) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); @@ -1001,30 +976,28 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) { gfx::Point point(GetCursorPositionX(3), 0); ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click_a); - EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_, - click_a.location(), gfx::Point())); - operations = textfield_view_->GetDragOperationsForView(textfield_view_, - click_a.location()); + textfield_->OnMousePressed(click_a); + EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), + gfx::Point())); + operations = textfield_->GetDragOperationsForView(textfield_, + click_a.location()); EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, operations); - textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data); + textfield_->WriteDragDataForView(NULL, click_a.location(), &data); EXPECT_TRUE(data.GetString(&string)); EXPECT_EQ(textfield_->GetSelectedText(), string); - EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); + EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); EXPECT_EQ(ui::OSExchangeData::STRING, formats); EXPECT_TRUE(custom_formats.empty()); // Drop "ello" after "w". const gfx::Point kDropPoint(GetCursorPositionX(7), 0); - EXPECT_TRUE(textfield_view_->CanDrop(data)); + EXPECT_TRUE(textfield_->CanDrop(data)); ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations); - EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, - textfield_view_->OnDragUpdated(drop_a)); - EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, - textfield_view_->OnPerformDrop(drop_a)); + EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a)); + EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a)); EXPECT_STR_EQ("h welloorld", textfield_->text()); - textfield_view_->OnDragDone(); + textfield_->OnDragDone(); // Undo/Redo the drag&drop change. SendKeyEvent(ui::VKEY_Z, false, true); @@ -1041,7 +1014,7 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) { EXPECT_STR_EQ("h welloorld", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) { +TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); @@ -1056,30 +1029,28 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) { gfx::Point point(GetCursorPositionX(7), 0); ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click_a); - EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_, - click_a.location(), gfx::Point())); - operations = textfield_view_->GetDragOperationsForView(textfield_view_, - click_a.location()); + textfield_->OnMousePressed(click_a); + EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), + gfx::Point())); + operations = textfield_->GetDragOperationsForView(textfield_, + click_a.location()); EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, operations); - textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data); + textfield_->WriteDragDataForView(NULL, click_a.location(), &data); EXPECT_TRUE(data.GetString(&string)); EXPECT_EQ(textfield_->GetSelectedText(), string); - EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); + EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); EXPECT_EQ(ui::OSExchangeData::STRING, formats); EXPECT_TRUE(custom_formats.empty()); // Drop " worl" after "h". - EXPECT_TRUE(textfield_view_->CanDrop(data)); + EXPECT_TRUE(textfield_->CanDrop(data)); gfx::Point drop_point(GetCursorPositionX(1), 0); ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations); - EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, - textfield_view_->OnDragUpdated(drop_a)); - EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, - textfield_view_->OnPerformDrop(drop_a)); + EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a)); + EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a)); EXPECT_STR_EQ("h worlellod", textfield_->text()); - textfield_view_->OnDragDone(); + textfield_->OnDragDone(); // Undo/Redo the drag&drop change. SendKeyEvent(ui::VKEY_Z, false, true); @@ -1096,7 +1067,7 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) { EXPECT_STR_EQ("h worlellod", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) { +TEST_F(TextfieldTest, DragAndDrop_Canceled) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); @@ -1105,28 +1076,28 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) { gfx::Point point(GetCursorPositionX(8), 0); ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(click); + textfield_->OnMousePressed(click); ui::OSExchangeData data; - textfield_view_->WriteDragDataForView(NULL, click.location(), &data); - EXPECT_TRUE(textfield_view_->CanDrop(data)); + textfield_->WriteDragDataForView(NULL, click.location(), &data); + EXPECT_TRUE(textfield_->CanDrop(data)); // Drag the text over somewhere valid, outside the current selection. gfx::Point drop_point(GetCursorPositionX(2), 0); ui::DropTargetEvent drop(data, drop_point, drop_point, ui::DragDropTypes::DRAG_MOVE); - EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_view_->OnDragUpdated(drop)); + EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop)); // "Cancel" the drag, via move and release over the selection, and OnDragDone. gfx::Point drag_point(GetCursorPositionX(9), 0); ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point, ui::EF_LEFT_MOUSE_BUTTON, 0); ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMouseDragged(drag); - textfield_view_->OnMouseReleased(release); - textfield_view_->OnDragDone(); + textfield_->OnMouseDragged(drag); + textfield_->OnMouseReleased(release); + textfield_->OnDragDone(); EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) { +TEST_F(TextfieldTest, ReadOnlyTest) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("read only")); textfield_->SetReadOnly(true); @@ -1150,24 +1121,24 @@ TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) { // Cut should be disabled. SetClipboardText("Test"); - EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); - textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); + EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); + textfield_->ExecuteCommand(IDS_APP_CUT, 0); SendKeyEvent(ui::VKEY_X, false, true); SendKeyEvent(ui::VKEY_DELETE, true, false); EXPECT_STR_EQ("Test", base::string16(GetClipboardText())); EXPECT_STR_EQ("read only", textfield_->text()); // Paste should be disabled. - EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); - textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); + EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); + textfield_->ExecuteCommand(IDS_APP_PASTE, 0); SendKeyEvent(ui::VKEY_V, false, true); SendKeyEvent(ui::VKEY_INSERT, true, false); EXPECT_STR_EQ("read only", textfield_->text()); // Copy should work normally. SetClipboardText("Test"); - EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); - textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); + EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); + textfield_->ExecuteCommand(IDS_APP_COPY, 0); EXPECT_STR_EQ("read only", base::string16(GetClipboardText())); SetClipboardText("Test"); SendKeyEvent(ui::VKEY_C, false, true); @@ -1192,7 +1163,7 @@ TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) { EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); } -TEST_F(NativeTextfieldViewsTest, TextInputClientTest) { +TEST_F(TextfieldTest, TextInputClientTest) { InitTextfield(Textfield::STYLE_DEFAULT); ui::TextInputClient* client = textfield_->GetTextInputClient(); EXPECT_TRUE(client); @@ -1297,7 +1268,7 @@ TEST_F(NativeTextfieldViewsTest, TextInputClientTest) { EXPECT_TRUE(textfield_->GetTextInputClient()); } -TEST_F(NativeTextfieldViewsTest, UndoRedoTest) { +TEST_F(TextfieldTest, UndoRedoTest) { InitTextfield(Textfield::STYLE_DEFAULT); SendKeyEvent(ui::VKEY_A); EXPECT_STR_EQ("a", textfield_->text()); @@ -1392,14 +1363,14 @@ TEST_F(NativeTextfieldViewsTest, UndoRedoTest) { EXPECT_STR_EQ("", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, CutCopyPaste) { +TEST_F(TextfieldTest, CutCopyPaste) { InitTextfield(Textfield::STYLE_DEFAULT); // Ensure IDS_APP_CUT cuts. textfield_->SetText(ASCIIToUTF16("123")); textfield_->SelectAll(false); - EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); - textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); + EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); + textfield_->ExecuteCommand(IDS_APP_CUT, 0); EXPECT_STR_EQ("123", base::string16(GetClipboardText())); EXPECT_STR_EQ("", textfield_->text()); @@ -1423,8 +1394,8 @@ TEST_F(NativeTextfieldViewsTest, CutCopyPaste) { // Ensure IDS_APP_COPY copies. textfield_->SetText(ASCIIToUTF16("789")); textfield_->SelectAll(false); - EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); - textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); + EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); + textfield_->ExecuteCommand(IDS_APP_COPY, 0); EXPECT_STR_EQ("789", base::string16(GetClipboardText())); // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing. @@ -1446,8 +1417,8 @@ TEST_F(NativeTextfieldViewsTest, CutCopyPaste) { // also ensure that [Ctrl]+[Alt]+[V] does nothing. SetClipboardText("abc"); textfield_->SetText(base::string16()); - EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); - textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); + EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); + textfield_->ExecuteCommand(IDS_APP_PASTE, 0); EXPECT_STR_EQ("abc", textfield_->text()); SendKeyEvent(ui::VKEY_V, false, true); EXPECT_STR_EQ("abcabc", textfield_->text()); @@ -1463,7 +1434,7 @@ TEST_F(NativeTextfieldViewsTest, CutCopyPaste) { EXPECT_STR_EQ("abcabcabc", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, OvertypeMode) { +TEST_F(TextfieldTest, OvertypeMode) { InitTextfield(Textfield::STYLE_DEFAULT); // Overtype mode should be disabled (no-op [Insert]). textfield_->SetText(ASCIIToUTF16("2")); @@ -1473,7 +1444,7 @@ TEST_F(NativeTextfieldViewsTest, OvertypeMode) { EXPECT_STR_EQ("12", textfield_->text()); } -TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) { +TEST_F(TextfieldTest, TextCursorDisplayTest) { InitTextfield(Textfield::STYLE_DEFAULT); // LTR-RTL string in LTR context. SendKeyEvent('a'); @@ -1525,7 +1496,7 @@ TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) { EXPECT_LT(prev_x, x); } -TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) { +TEST_F(TextfieldTest, TextCursorDisplayInRTLTest) { std::string locale = l10n_util::GetApplicationLocale(""); base::i18n::SetICUDefaultLocale("he"); @@ -1583,7 +1554,7 @@ TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) { base::i18n::SetICUDefaultLocale(locale); } -TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) { +TEST_F(TextfieldTest, HitInsideTextAreaTest) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); std::vector<gfx::Rect> cursor_bounds; @@ -1638,7 +1609,7 @@ TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) { } } -TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) { +TEST_F(TextfieldTest, HitOutsideTextAreaTest) { InitTextfield(Textfield::STYLE_DEFAULT); // LTR-RTL string in LTR context. @@ -1670,7 +1641,7 @@ TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) { EXPECT_EQ(bound, GetCursorBounds()); } -TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) { +TEST_F(TextfieldTest, HitOutsideTextAreaInRTLTest) { std::string locale = l10n_util::GetApplicationLocale(""); base::i18n::SetICUDefaultLocale("he"); @@ -1706,7 +1677,7 @@ TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) { base::i18n::SetICUDefaultLocale(locale); } -TEST_F(NativeTextfieldViewsTest, OverflowTest) { +TEST_F(TextfieldTest, OverflowTest) { InitTextfield(Textfield::STYLE_DEFAULT); base::string16 str; @@ -1732,7 +1703,7 @@ TEST_F(NativeTextfieldViewsTest, OverflowTest) { EXPECT_EQ(501U, textfield_->GetCursorPosition()); } -TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) { +TEST_F(TextfieldTest, OverflowInRTLTest) { std::string locale = l10n_util::GetApplicationLocale(""); base::i18n::SetICUDefaultLocale("he"); @@ -1763,7 +1734,7 @@ TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) { base::i18n::SetICUDefaultLocale(locale); } -TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) { +TEST_F(TextfieldTest, GetCompositionCharacterBoundsTest) { InitTextfield(Textfield::STYLE_DEFAULT); base::string16 str; @@ -1786,8 +1757,8 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) { gfx::Rect cursor_bounds = GetCursorBounds(); gfx::Point top_left(prev_cursor.x(), prev_cursor.y()); gfx::Point bottom_right(cursor_bounds.x(), prev_cursor.bottom()); - views::View::ConvertPointToScreen(textfield_view_, &top_left); - views::View::ConvertPointToScreen(textfield_view_, &bottom_right); + views::View::ConvertPointToScreen(textfield_, &top_left); + views::View::ConvertPointToScreen(textfield_, &bottom_right); char_rect_in_screen_coord[i].set_origin(top_left); char_rect_in_screen_coord[i].set_width(bottom_right.x() - top_left.x()); char_rect_in_screen_coord[i].set_height(bottom_right.y() - top_left.y()); @@ -1807,7 +1778,7 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) { EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect)); } -TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) { +TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) { InitTextfield(Textfield::STYLE_DEFAULT); const base::char16 kUtf16Chars[] = { @@ -1844,7 +1815,7 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) { // The word we select by double clicking should remain selected regardless of // where we drag the mouse afterwards without releasing the left button. -TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) { +TEST_F(TextfieldTest, KeepInitiallySelectedWord) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("abc def ghi")); @@ -1861,69 +1832,64 @@ TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) { ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle, ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - textfield_view_->OnMousePressed(press_event); + textfield_->OnMousePressed(press_event); EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange()); // Drag the mouse to the beginning of the textfield. ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning, ui::EF_LEFT_MOUSE_BUTTON, 0); - textfield_view_->OnMouseDragged(drag_event); + textfield_->OnMouseDragged(drag_event); EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange()); } -// Touch selection and draggin currently only works for chromeos. +// Touch selection and dragging currently only works for chromeos. #if defined(OS_CHROMEOS) -TEST_F(NativeTextfieldViewsTest, TouchSelectionAndDraggingTest) { +TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); EXPECT_FALSE(GetTouchSelectionController()); - const int eventX = GetCursorPositionX(2); - const int eventY = 0; + const int x = GetCursorPositionX(2); + GestureEventForTest tap(ui::ET_GESTURE_TAP, x, 0, 1.0f, 0.0f); + GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, x, 0, 0.0f, 0.0f); + GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, x, 0, 0.0f, 0.0f); CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); // Tapping on the textfield should turn on the TouchSelectionController. - GestureEventForTest tap(ui::ET_GESTURE_TAP, eventX, eventY, 1.0f, 0.0f); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); EXPECT_TRUE(GetTouchSelectionController()); // Un-focusing the textfield should reset the TouchSelectionController - textfield_view_->GetFocusManager()->ClearFocus(); + textfield_->GetFocusManager()->ClearFocus(); EXPECT_FALSE(GetTouchSelectionController()); // With touch editing enabled, long press should not show context menu. // Instead, select word and invoke TouchSelectionController. - GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, eventX, eventY, 0.0f, - 0.0f); - textfield_view_->OnGestureEvent(&tap_down); - GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, eventX, eventY, - 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&long_press); + textfield_->OnGestureEvent(&tap_down); + textfield_->OnGestureEvent(&long_press); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); EXPECT_TRUE(GetTouchSelectionController()); - // Long pressing again in the selecting region should not do anything since - // touch drag drop is not yet enabled. - textfield_view_->OnGestureEvent(&tap_down); - textfield_view_->OnGestureEvent(&long_press); + // With touch drag drop enabled, long pressing in the selected region should + // start a drag and remove TouchSelectionController. + ASSERT_TRUE(switches::IsTouchDragDropEnabled()); + textfield_->OnGestureEvent(&tap_down); + textfield_->OnGestureEvent(&long_press); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); - EXPECT_TRUE(GetTouchSelectionController()); - EXPECT_TRUE(long_press.handled()); + EXPECT_FALSE(GetTouchSelectionController()); - // After enabling touch drag drop, long pressing in the selected region should - // start a drag and remove TouchSelectionController. + // After disabling touch drag drop, long pressing again in the selection + // region should not do anything. CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchDragDrop); - textfield_view_->OnGestureEvent(&tap_down); - - // Create a new long press event since the previous one is not marked handled. - GestureEventForTest long_press2(ui::ET_GESTURE_LONG_PRESS, eventX, eventY, - 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&long_press2); + switches::kDisableTouchDragDrop); + ASSERT_FALSE(switches::IsTouchDragDropEnabled()); + textfield_->OnGestureEvent(&tap_down); + textfield_->OnGestureEvent(&long_press); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); - EXPECT_FALSE(GetTouchSelectionController()); + EXPECT_TRUE(GetTouchSelectionController()); + EXPECT_TRUE(long_press.handled()); } -TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) { +TEST_F(TextfieldTest, TouchScrubbingSelection) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("hello world")); EXPECT_FALSE(GetTouchSelectionController()); @@ -1936,26 +1902,26 @@ TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) { GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0, 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&tap_down); + textfield_->OnGestureEvent(&tap_down); GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, scrubbing_start, 0, 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&tap_cancel); + textfield_->OnGestureEvent(&tap_cancel); GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, scrubbing_start, 0, 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&scroll_begin); + textfield_->OnGestureEvent(&scroll_begin); GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, scrubbing_end, 0, scrubbing_end - scrubbing_start, 0.0f); - textfield_view_->OnGestureEvent(&scroll_update); + textfield_->OnGestureEvent(&scroll_update); GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0, 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&scroll_end); + textfield_->OnGestureEvent(&scroll_end); GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&end); + textfield_->OnGestureEvent(&end); // In the end, part of text should have been selected and handles should have // appeared. @@ -1964,8 +1930,8 @@ TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) { } #endif -// Long_Press gesture in NativeTextfieldViews can initiate a drag and drop now. -TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) { +// Long_Press gesture in Textfield can initiate a drag and drop now. +TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(ASCIIToUTF16("Hello string world")); @@ -1980,12 +1946,12 @@ TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) { // Create a long press event in the selected region should start a drag. GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, kStringPoint.x(), kStringPoint.y(), 0.0f, 0.0f); - textfield_view_->OnGestureEvent(&long_press); - EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, - kStringPoint, kStringPoint)); + textfield_->OnGestureEvent(&long_press); + EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint, + kStringPoint)); } -TEST_F(NativeTextfieldViewsTest, GetTextfieldBaseline_FontFallbackTest) { +TEST_F(TextfieldTest, GetTextfieldBaseline_FontFallbackTest) { InitTextfield(Textfield::STYLE_DEFAULT); textfield_->SetText(UTF8ToUTF16("abc")); const int old_baseline = textfield_->GetBaseline(); diff --git a/ui/views/controls/textfield/textfield_views_model.cc b/ui/views/controls/textfield/textfield_views_model.cc index 6179e8f..355fa1c 100644 --- a/ui/views/controls/textfield/textfield_views_model.cc +++ b/ui/views/controls/textfield/textfield_views_model.cc @@ -306,22 +306,18 @@ TextfieldViewsModel::~TextfieldViewsModel() { ClearComposition(); } -const base::string16& TextfieldViewsModel::GetText() const { - return render_text_->text(); -} - -bool TextfieldViewsModel::SetText(const base::string16& text) { +bool TextfieldViewsModel::SetText(const base::string16& new_text) { bool changed = false; if (HasCompositionText()) { ConfirmCompositionText(); changed = true; } - if (GetText() != text) { + if (text() != new_text) { if (changed) // No need to remember composition. Undo(); size_t old_cursor = GetCursorPosition(); // SetText moves the cursor to the end. - size_t new_cursor = text.length(); + size_t new_cursor = new_text.length(); SelectAll(false); // If there is a composition text, don't merge with previous edit. // Otherwise, force merge the edits. @@ -329,7 +325,7 @@ bool TextfieldViewsModel::SetText(const base::string16& text) { changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS, old_cursor, new_cursor, - text, + new_text, 0U); render_text_->SetCursorPosition(new_cursor); } @@ -337,14 +333,14 @@ bool TextfieldViewsModel::SetText(const base::string16& text) { return changed; } -void TextfieldViewsModel::Append(const base::string16& text) { +void TextfieldViewsModel::Append(const base::string16& new_text) { if (HasCompositionText()) ConfirmCompositionText(); size_t save = GetCursorPosition(); MoveCursor(gfx::LINE_BREAK, render_text_->GetVisualDirectionOfLogicalEnd(), false); - InsertText(text); + InsertText(new_text); render_text_->SetCursorPosition(save); ClearSelection(); } @@ -359,7 +355,7 @@ bool TextfieldViewsModel::Delete() { DeleteSelection(); return true; } - if (GetText().length() > GetCursorPosition()) { + if (text().length() > GetCursorPosition()) { size_t cursor_position = GetCursorPosition(); size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( cursor_position, gfx::CURSOR_FORWARD); @@ -383,8 +379,7 @@ bool TextfieldViewsModel::Backspace() { size_t cursor_position = GetCursorPosition(); if (cursor_position > 0) { // Delete one code point, which may be two UTF-16 words. - size_t previous_char = - gfx::UTF16OffsetToIndex(GetText(), cursor_position, -1); + size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1); ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true); return true; } @@ -424,8 +419,8 @@ bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { } base::string16 TextfieldViewsModel::GetSelectedText() const { - return GetText().substr(render_text_->selection().GetMin(), - render_text_->selection().length()); + return text().substr(render_text_->selection().GetMin(), + render_text_->selection().length()); } void TextfieldViewsModel::SelectRange(const gfx::Range& range) { @@ -479,7 +474,7 @@ bool TextfieldViewsModel::Undo() { if (HasCompositionText()) // safe guard for release build. CancelCompositionText(); - base::string16 old = GetText(); + base::string16 old = text(); size_t old_cursor = GetCursorPosition(); (*current_edit_)->Commit(); (*current_edit_)->Undo(this); @@ -488,7 +483,7 @@ bool TextfieldViewsModel::Undo() { current_edit_ = edit_history_.end(); else current_edit_--; - return old != GetText() || old_cursor != GetCursorPosition(); + return old != text() || old_cursor != GetCursorPosition(); } bool TextfieldViewsModel::Redo() { @@ -502,10 +497,10 @@ bool TextfieldViewsModel::Redo() { current_edit_ = edit_history_.begin(); else current_edit_ ++; - base::string16 old = GetText(); + base::string16 old = text(); size_t old_cursor = GetCursorPosition(); (*current_edit_)->Redo(this); - return old != GetText() || old_cursor != GetCursorPosition(); + return old != text() || old_cursor != GetCursorPosition(); } bool TextfieldViewsModel::Cut() { @@ -558,25 +553,26 @@ void TextfieldViewsModel::DeleteSelection() { } void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( - const base::string16& text, size_t position) { + const base::string16& new_text, + size_t position) { if (HasCompositionText()) CancelCompositionText(); ExecuteAndRecordReplace(DO_NOT_MERGE, GetCursorPosition(), - position + text.length(), - text, + position + new_text.length(), + new_text, position); } base::string16 TextfieldViewsModel::GetTextFromRange( const gfx::Range& range) const { - if (range.IsValid() && range.GetMin() < GetText().length()) - return GetText().substr(range.GetMin(), range.length()); + if (range.IsValid() && range.GetMin() < text().length()) + return text().substr(range.GetMin(), range.length()); return base::string16(); } void TextfieldViewsModel::GetTextRange(gfx::Range* range) const { - *range = gfx::Range(0, GetText().length()); + *range = gfx::Range(0, text().length()); } void TextfieldViewsModel::SetCompositionText( @@ -590,7 +586,7 @@ void TextfieldViewsModel::SetCompositionText( return; size_t cursor = GetCursorPosition(); - base::string16 new_text = GetText(); + base::string16 new_text = text(); render_text_->SetText(new_text.insert(cursor, composition.text)); gfx::Range range(cursor, cursor + composition.text.length()); render_text_->SetCompositionRange(range); @@ -619,10 +615,10 @@ void TextfieldViewsModel::SetCompositionText( void TextfieldViewsModel::ConfirmCompositionText() { DCHECK(HasCompositionText()); gfx::Range range = render_text_->GetCompositionRange(); - base::string16 text = GetText().substr(range.start(), range.length()); + base::string16 composition = text().substr(range.start(), range.length()); // TODO(oshima): current behavior on ChromeOS is a bit weird and not // sure exactly how this should work. Find out and fix if necessary. - AddOrMergeEditHistory(new InsertEdit(false, text, range.start())); + AddOrMergeEditHistory(new InsertEdit(false, composition, range.start())); render_text_->SetCursorPosition(range.end()); ClearComposition(); if (delegate_) @@ -633,7 +629,7 @@ void TextfieldViewsModel::CancelCompositionText() { DCHECK(HasCompositionText()); gfx::Range range = render_text_->GetCompositionRange(); ClearComposition(); - base::string16 new_text = GetText(); + base::string16 new_text = text(); render_text_->SetText(new_text.erase(range.start(), range.length())); render_text_->SetCursorPosition(range.start()); if (delegate_) @@ -652,23 +648,28 @@ bool TextfieldViewsModel::HasCompositionText() const { return !render_text_->GetCompositionRange().is_empty(); } +void TextfieldViewsModel::ClearEditHistory() { + STLDeleteElements(&edit_history_); + current_edit_ = edit_history_.end(); +} + ///////////////////////////////////////////////////////////////// // TextfieldViewsModel: private -void TextfieldViewsModel::InsertTextInternal(const base::string16& text, +void TextfieldViewsModel::InsertTextInternal(const base::string16& new_text, bool mergeable) { if (HasCompositionText()) { CancelCompositionText(); - ExecuteAndRecordInsert(text, mergeable); + ExecuteAndRecordInsert(new_text, mergeable); } else if (HasSelection()) { ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE, - text); + new_text); } else { - ExecuteAndRecordInsert(text, mergeable); + ExecuteAndRecordInsert(new_text, mergeable); } } -void TextfieldViewsModel::ReplaceTextInternal(const base::string16& text, +void TextfieldViewsModel::ReplaceTextInternal(const base::string16& new_text, bool mergeable) { if (HasCompositionText()) { CancelCompositionText(); @@ -676,7 +677,7 @@ void TextfieldViewsModel::ReplaceTextInternal(const base::string16& text, size_t cursor = GetCursorPosition(); const gfx::SelectionModel& model = render_text_->selection_model(); // When there is no selection, the default is to replace the next grapheme - // with |text|. So, need to find the index of next grapheme first. + // with |new_text|. So, need to find the index of next grapheme first. size_t next = render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); if (next == model.caret_pos()) @@ -685,12 +686,7 @@ void TextfieldViewsModel::ReplaceTextInternal(const base::string16& text, render_text_->SelectRange(gfx::Range(next, model.caret_pos())); } // Edit history is recorded in InsertText. - InsertTextInternal(text, mergeable); -} - -void TextfieldViewsModel::ClearEditHistory() { - STLDeleteElements(&edit_history_); - current_edit_ = edit_history_.end(); + InsertTextInternal(new_text, mergeable); } void TextfieldViewsModel::ClearRedoHistory() { @@ -709,9 +705,9 @@ void TextfieldViewsModel::ClearRedoHistory() { void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) { size_t old_text_start = range.GetMin(); - const base::string16 text = GetText().substr(old_text_start, range.length()); + const base::string16 old_text = text().substr(old_text_start, range.length()); bool backward = range.is_reversed(); - Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); + Edit* edit = new DeleteEdit(mergeable, old_text, old_text_start, backward); bool delete_edit = AddOrMergeEditHistory(edit); edit->Redo(this); if (delete_edit) @@ -719,7 +715,8 @@ void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range, } void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( - MergeType merge_type, const base::string16& new_text) { + MergeType merge_type, + const base::string16& new_text) { size_t new_text_start = render_text_->selection().GetMin(); size_t new_cursor_pos = new_text_start + new_text.length(); ExecuteAndRecordReplace(merge_type, @@ -751,9 +748,9 @@ void TextfieldViewsModel::ExecuteAndRecordReplace( delete edit; } -void TextfieldViewsModel::ExecuteAndRecordInsert(const base::string16& text, +void TextfieldViewsModel::ExecuteAndRecordInsert(const base::string16& new_text, bool mergeable) { - Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition()); + Edit* edit = new InsertEdit(mergeable, new_text, GetCursorPosition()); bool delete_edit = AddOrMergeEditHistory(edit); edit->Redo(this); if (delete_edit) @@ -787,12 +784,12 @@ void TextfieldViewsModel::ModifyText(size_t delete_from, size_t new_text_insert_at, size_t new_cursor_pos) { DCHECK_LE(delete_from, delete_to); - base::string16 text = GetText(); + base::string16 old_text = text(); ClearComposition(); if (delete_from != delete_to) - render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); + render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); if (!new_text.empty()) - render_text_->SetText(text.insert(new_text_insert_at, new_text)); + render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); render_text_->SetCursorPosition(new_cursor_pos); // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). // This looks fine feature and we may want to do the same. diff --git a/ui/views/controls/textfield/textfield_views_model.h b/ui/views/controls/textfield/textfield_views_model.h index bc1de88..ab5d0c8 100644 --- a/ui/views/controls/textfield/textfield_views_model.h +++ b/ui/views/controls/textfield/textfield_views_model.h @@ -64,21 +64,20 @@ class VIEWS_EXPORT TextfieldViewsModel { // Edit related methods. - const base::string16& GetText() const; - // Sets the text. Returns true if the text has been modified. The - // current composition text will be confirmed first. Setting - // the same text will not add edit history because it's not user - // visible change nor user-initiated change. This allow a client - // code to set the same text multiple times without worrying about - // messing edit history. - bool SetText(const base::string16& text); + const base::string16& text() const { return render_text_->text(); } + // Sets the text. Returns true if the text has been modified. The current + // composition text will be confirmed first. Setting the same text will not + // add edit history because it's not user visible change nor user-initiated + // change. This allow a client code to set the same text multiple times + // without worrying about messing edit history. + bool SetText(const base::string16& new_text); gfx::RenderText* render_text() { return render_text_.get(); } - // Inserts given |text| at the current cursor position. + // Inserts given |new_text| at the current cursor position. // The current composition text will be cleared. - void InsertText(const base::string16& text) { - InsertTextInternal(text, false); + void InsertText(const base::string16& new_text) { + InsertTextInternal(new_text, false); } // Inserts a character at the current cursor position. @@ -88,8 +87,8 @@ class VIEWS_EXPORT TextfieldViewsModel { // Replaces characters at the current position with characters in given text. // The current composition text will be cleared. - void ReplaceText(const base::string16& text) { - ReplaceTextInternal(text, false); + void ReplaceText(const base::string16& new_text) { + ReplaceTextInternal(new_text, false); } // Replaces the char at the current position with given character. @@ -99,7 +98,7 @@ class VIEWS_EXPORT TextfieldViewsModel { // Appends the text. // The current composition text will be confirmed. - void Append(const base::string16& text); + void Append(const base::string16& new_text); // Deletes the first character after the current cursor position (as if, the // the user has pressed delete key in the textfield). Returns true if @@ -195,10 +194,9 @@ class VIEWS_EXPORT TextfieldViewsModel { // composition text. void DeleteSelection(); - // Deletes the selected text (if any) and insert text at given - // position. - void DeleteSelectionAndInsertTextAt( - const base::string16& text, size_t position); + // Deletes the selected text (if any) and insert text at given position. + void DeleteSelectionAndInsertTextAt(const base::string16& new_text, + size_t position); // Retrieves the text content in a given range. base::string16 GetTextFromRange(const gfx::Range& range) const; @@ -226,9 +224,10 @@ class VIEWS_EXPORT TextfieldViewsModel { // Returns true if there is composition text. bool HasCompositionText() const; + // Clears all edit history. + void ClearEditHistory(); + private: - friend class NativeTextfieldViews; - friend class NativeTextfieldViewsTest; friend class TextfieldViewsModelTest; friend class UndoRedo_BasicTest; friend class UndoRedo_CutCopyPasteTest; @@ -239,17 +238,14 @@ class VIEWS_EXPORT TextfieldViewsModel { FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest); FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest); - // Insert the given |text|. |mergeable| indicates if this insert + // Insert the given |new_text|. |mergeable| indicates if this insert // operation can be merged to previous edit in the edit history. - void InsertTextInternal(const base::string16& text, bool mergeable); + void InsertTextInternal(const base::string16& new_text, bool mergeable); - // Replace the current text with the given |text|. |mergeable| + // Replace the current text with the given |new_text|. |mergeable| // indicates if this replace operation can be merged to previous // edit in the edit history. - void ReplaceTextInternal(const base::string16& text, bool mergeable); - - // Clears all edit history. - void ClearEditHistory(); + void ReplaceTextInternal(const base::string16& new_text, bool mergeable); // Clears redo history. void ClearRedoHistory(); @@ -257,13 +253,13 @@ class VIEWS_EXPORT TextfieldViewsModel { // Executes and records edit operations. void ExecuteAndRecordDelete(gfx::Range range, bool mergeable); void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type, - const base::string16& text); + const base::string16& new_text); void ExecuteAndRecordReplace(internal::MergeType merge_type, size_t old_cursor_pos, size_t new_cursor_pos, - const base::string16& text, + const base::string16& new_text, size_t new_text_start); - void ExecuteAndRecordInsert(const base::string16& text, bool mergeable); + void ExecuteAndRecordInsert(const base::string16& new_text, bool mergeable); // Adds or merge |edit| into edit history. Return true if the edit // has been merged and must be deleted after redo. diff --git a/ui/views/controls/textfield/textfield_views_model_unittest.cc b/ui/views/controls/textfield/textfield_views_model_unittest.cc index 4fa0d9c..a5331b8 100644 --- a/ui/views/controls/textfield/textfield_views_model_unittest.cc +++ b/ui/views/controls/textfield/textfield_views_model_unittest.cc @@ -74,74 +74,72 @@ TEST_F(TextfieldViewsModelTest, EditString) { TextfieldViewsModel model(NULL); // append two strings model.Append(ASCIIToUTF16("HILL")); - EXPECT_STR_EQ("HILL", model.GetText()); + EXPECT_STR_EQ("HILL", model.text()); model.Append(ASCIIToUTF16("WORLD")); - EXPECT_STR_EQ("HILLWORLD", model.GetText()); + EXPECT_STR_EQ("HILLWORLD", model.text()); // Insert "E" to make hello model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('E'); - EXPECT_STR_EQ("HEILLWORLD", model.GetText()); + EXPECT_STR_EQ("HEILLWORLD", model.text()); // Replace "I" with "L" model.ReplaceChar('L'); - EXPECT_STR_EQ("HELLLWORLD", model.GetText()); + EXPECT_STR_EQ("HELLLWORLD", model.text()); model.ReplaceChar('L'); model.ReplaceChar('O'); - EXPECT_STR_EQ("HELLOWORLD", model.GetText()); + EXPECT_STR_EQ("HELLOWORLD", model.text()); // Delete 6th char "W", then delete 5th char O" EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Delete()); - EXPECT_STR_EQ("HELLOORLD", model.GetText()); + EXPECT_STR_EQ("HELLOORLD", model.text()); EXPECT_TRUE(model.Backspace()); EXPECT_EQ(4U, model.GetCursorPosition()); - EXPECT_STR_EQ("HELLORLD", model.GetText()); + EXPECT_STR_EQ("HELLORLD", model.text()); // Move the cursor to start. backspace should fail. model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); EXPECT_FALSE(model.Backspace()); - EXPECT_STR_EQ("HELLORLD", model.GetText()); + EXPECT_STR_EQ("HELLORLD", model.text()); // Move the cursor to the end. delete should fail. model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_FALSE(model.Delete()); - EXPECT_STR_EQ("HELLORLD", model.GetText()); + EXPECT_STR_EQ("HELLORLD", model.text()); // but backspace should work. EXPECT_TRUE(model.Backspace()); - EXPECT_STR_EQ("HELLORL", model.GetText()); + EXPECT_STR_EQ("HELLORL", model.text()); MoveCursorTo(model, 5); model.ReplaceText(ASCIIToUTF16(" WOR")); - EXPECT_STR_EQ("HELLO WORL", model.GetText()); + EXPECT_STR_EQ("HELLO WORL", model.text()); } TEST_F(TextfieldViewsModelTest, EditString_SimpleRTL) { TextfieldViewsModel model(NULL); // Append two strings. model.Append(WideToUTF16(L"\x05d0\x05d1\x05d2")); - EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.text()); model.Append(WideToUTF16(L"\x05e0\x05e1\x05e2")); - EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"), - model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"), model.text()); // Insert 0x05f0. MoveCursorTo(model, 1); model.InsertChar(0x05f0); EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"), - model.GetText()); + model.text()); // Replace "\x05d1" with "\x05f1". model.ReplaceChar(0x05f1); EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"), - model.GetText()); + model.text()); // Delete and backspace. EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Delete()); - EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"), - model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"), model.text()); EXPECT_TRUE(model.Backspace()); EXPECT_EQ(2U, model.GetCursorPosition()); - EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.text()); } TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { @@ -156,12 +154,10 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { // Append two Hindi strings. model.Append(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915")); - EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), - model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), model.text()); model.Append(WideToUTF16(L"\x0915\x094d\x092e\x094d")); EXPECT_EQ(WideToUTF16( - L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), - model.GetText()); + L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), model.text()); // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete // font support for some scripts - http://crbug.com/106450 @@ -175,7 +171,7 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { model.InsertChar('a'); EXPECT_EQ(WideToUTF16( L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), - model.GetText()); + model.text()); // ReplaceChar will replace the whole grapheme. model.ReplaceChar('b'); @@ -185,7 +181,7 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { #if defined(OS_LINUX) EXPECT_EQ(WideToUTF16( L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), - model.GetText()); + model.text()); #endif EXPECT_EQ(4U, model.GetCursorPosition()); } @@ -198,12 +194,11 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { #if defined(OS_LINUX) EXPECT_TRUE(model.Delete()); EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), - model.GetText()); - MoveCursorTo(model, model.GetText().length()); - EXPECT_EQ(model.GetText().length(), model.GetCursorPosition()); + model.text()); + MoveCursorTo(model, model.text().length()); + EXPECT_EQ(model.text().length(), model.GetCursorPosition()); EXPECT_TRUE(model.Backspace()); - EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"), - model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"), model.text()); #endif // Test cursor position and deletion for Hindi Virama. @@ -226,7 +221,7 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { MoveCursorTo(model, 2); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Backspace()); - EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.text()); #endif model.SetText(WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9")); @@ -235,19 +230,18 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { EXPECT_TRUE(model.Delete()); EXPECT_TRUE(model.Delete()); EXPECT_TRUE(model.Delete()); - EXPECT_EQ(WideToUTF16(L""), model.GetText()); + EXPECT_EQ(WideToUTF16(L""), model.text()); // The first 2 characters are not strong directionality characters. model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC")); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(model.Backspace()); - EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"), - model.GetText()); + EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"), model.text()); } TEST_F(TextfieldViewsModelTest, EmptyString) { TextfieldViewsModel model(NULL); - EXPECT_EQ(base::string16(), model.GetText()); + EXPECT_EQ(base::string16(), model.text()); EXPECT_EQ(base::string16(), model.GetSelectedText()); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); @@ -395,26 +389,26 @@ TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL" EXPECT_TRUE(model.Backspace()); - EXPECT_STR_EQ("HLO", model.GetText()); + EXPECT_STR_EQ("HLO", model.text()); model.Append(ASCIIToUTF16("ILL")); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO" EXPECT_TRUE(model.Delete()); - EXPECT_STR_EQ("HILL", model.GetText()); + EXPECT_STR_EQ("HILL", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I" model.InsertChar('E'); - EXPECT_STR_EQ("HELL", model.GetText()); + EXPECT_STR_EQ("HELL", model.text()); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H" model.ReplaceChar('B'); - EXPECT_STR_EQ("BELL", model.GetText()); + EXPECT_STR_EQ("BELL", model.text()); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL" model.ReplaceChar('E'); - EXPECT_STR_EQ("BEE", model.GetText()); + EXPECT_STR_EQ("BEE", model.text()); } TEST_F(TextfieldViewsModelTest, Word) { @@ -461,7 +455,7 @@ TEST_F(TextfieldViewsModelTest, Word) { EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); model.ReplaceChar('4'); EXPECT_EQ(base::string16(), model.GetSelectedText()); - EXPECT_STR_EQ("42", model.GetText()); + EXPECT_STR_EQ("42", model.text()); } TEST_F(TextfieldViewsModelTest, SetText) { @@ -469,7 +463,7 @@ TEST_F(TextfieldViewsModelTest, SetText) { model.Append(ASCIIToUTF16("HELLO")); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetText(ASCIIToUTF16("GOODBYE")); - EXPECT_STR_EQ("GOODBYE", model.GetText()); + EXPECT_STR_EQ("GOODBYE", model.text()); // SetText move the cursor to the end of the new text. EXPECT_EQ(7U, model.GetCursorPosition()); model.SelectAll(false); @@ -500,14 +494,14 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { EXPECT_FALSE(model.Cut()); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_EQ(initial_clipboard_text, clipboard_text); - EXPECT_STR_EQ("HELLO WORLD", model.GetText()); + EXPECT_STR_EQ("HELLO WORLD", model.text()); EXPECT_EQ(11U, model.GetCursorPosition()); // Copy with an empty selection should do nothing. model.Copy(); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_EQ(initial_clipboard_text, clipboard_text); - EXPECT_STR_EQ("HELLO WORLD", model.GetText()); + EXPECT_STR_EQ("HELLO WORLD", model.text()); EXPECT_EQ(11U, model.GetCursorPosition()); // Cut on obscured (password) text should do nothing. @@ -516,7 +510,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { EXPECT_FALSE(model.Cut()); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_EQ(initial_clipboard_text, clipboard_text); - EXPECT_STR_EQ("HELLO WORLD", model.GetText()); + EXPECT_STR_EQ("HELLO WORLD", model.text()); EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText()); // Copy on obscured text should do nothing. @@ -524,7 +518,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { EXPECT_FALSE(model.Copy()); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_EQ(initial_clipboard_text, clipboard_text); - EXPECT_STR_EQ("HELLO WORLD", model.GetText()); + EXPECT_STR_EQ("HELLO WORLD", model.text()); EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText()); // Cut with non-empty selection. @@ -534,7 +528,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { EXPECT_TRUE(model.Cut()); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_STR_EQ("WORLD", clipboard_text); - EXPECT_STR_EQ("HELLO ", model.GetText()); + EXPECT_STR_EQ("HELLO ", model.text()); EXPECT_EQ(6U, model.GetCursorPosition()); // Copy with non-empty selection. @@ -542,17 +536,17 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { EXPECT_TRUE(model.Copy()); clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); EXPECT_STR_EQ("HELLO ", clipboard_text); - EXPECT_STR_EQ("HELLO ", model.GetText()); + EXPECT_STR_EQ("HELLO ", model.text()); EXPECT_EQ(6U, model.GetCursorPosition()); // Test that paste works regardless of the obscured bit. model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("HELLO HELLO ", model.GetText()); + EXPECT_STR_EQ("HELLO HELLO ", model.text()); EXPECT_EQ(12U, model.GetCursorPosition()); model.render_text()->SetObscured(true); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("HELLO HELLO HELLO ", model.GetText()); + EXPECT_STR_EQ("HELLO HELLO HELLO ", model.text()); EXPECT_EQ(18U, model.GetCursorPosition()); } @@ -856,7 +850,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { model.GetTextRange(&range); EXPECT_EQ(10U, range.end()); - EXPECT_STR_EQ("1234567890", model.GetText()); + EXPECT_STR_EQ("1234567890", model.text()); model.GetCompositionTextRange(&range); EXPECT_EQ(gfx::Range(5, 8), range); @@ -873,31 +867,31 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { EXPECT_EQ(5U, model.GetCursorPosition()); model.SetCompositionText(composition); - EXPECT_STR_EQ("1234567890", model.GetText()); + EXPECT_STR_EQ("1234567890", model.text()); EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890"))); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); - EXPECT_STR_EQ("1234567890678", model.GetText()); + EXPECT_STR_EQ("1234567890678", model.text()); model.InsertText(UTF8ToUTF16("-")); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("1234567890-", model.GetText()); + EXPECT_STR_EQ("1234567890-", model.text()); EXPECT_FALSE(model.HasCompositionText()); EXPECT_FALSE(model.HasSelection()); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_STR_EQ("-", model.GetSelectedText()); model.SetCompositionText(composition); - EXPECT_STR_EQ("1234567890678", model.GetText()); + EXPECT_STR_EQ("1234567890678", model.text()); model.ReplaceText(UTF8ToUTF16("-")); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("1234567890-", model.GetText()); + EXPECT_STR_EQ("1234567890-", model.text()); EXPECT_FALSE(model.HasCompositionText()); EXPECT_FALSE(model.HasSelection()); @@ -905,40 +899,40 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { model.Append(UTF8ToUTF16("-")); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("1234567890-678-", model.GetText()); + EXPECT_STR_EQ("1234567890-678-", model.text()); model.SetCompositionText(composition); model.Delete(); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("1234567890-678-", model.GetText()); + EXPECT_STR_EQ("1234567890-678-", model.text()); model.SetCompositionText(composition); model.Backspace(); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("1234567890-678-", model.GetText()); + EXPECT_STR_EQ("1234567890-678-", model.text()); model.SetText(base::string16()); model.SetCompositionText(composition); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678", model.GetText()); + EXPECT_STR_EQ("678", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); model.SetCompositionText(composition); model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("676788", model.GetText()); + EXPECT_STR_EQ("676788", model.text()); EXPECT_EQ(6U, model.GetCursorPosition()); model.SetCompositionText(composition); model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("676788678", model.GetText()); + EXPECT_STR_EQ("676788678", model.text()); model.SetText(base::string16()); model.SetCompositionText(composition); @@ -950,13 +944,13 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678678", model.GetText()); + EXPECT_STR_EQ("678678", model.text()); model.SetCompositionText(composition); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678", model.GetText()); + EXPECT_STR_EQ("678", model.text()); model.SetCompositionText(composition); gfx::SelectionModel sel( @@ -965,25 +959,25 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { model.MoveCursorTo(sel); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678678", model.GetText()); + EXPECT_STR_EQ("678678", model.text()); model.SetCompositionText(composition); model.SelectRange(gfx::Range(0, 3)); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678", model.GetText()); + EXPECT_STR_EQ("678", model.text()); model.SetCompositionText(composition); model.SelectAll(false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678", model.GetText()); + EXPECT_STR_EQ("678", model.text()); model.SetCompositionText(composition); model.SelectWord(); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - EXPECT_STR_EQ("678", model.GetText()); + EXPECT_STR_EQ("678", model.text()); model.SetCompositionText(composition); model.ClearSelection(); @@ -1000,66 +994,66 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) { model.InsertChar('a'); EXPECT_FALSE(model.Redo()); // nothing to redo EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("a", model.GetText()); + EXPECT_STR_EQ("a", model.text()); // Continuous inserts are treated as one edit. model.InsertChar('b'); model.InsertChar('c'); - EXPECT_STR_EQ("abc", model.GetText()); + EXPECT_STR_EQ("abc", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("a", model.GetText()); + EXPECT_STR_EQ("a", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); // Undoing further shouldn't change the text. EXPECT_FALSE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_FALSE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); // Redoing to the latest text. EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("a", model.GetText()); + EXPECT_STR_EQ("a", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("abc", model.GetText()); + EXPECT_STR_EQ("abc", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); // Backspace =============================== EXPECT_TRUE(model.Backspace()); - EXPECT_STR_EQ("ab", model.GetText()); + EXPECT_STR_EQ("ab", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("abc", model.GetText()); + EXPECT_STR_EQ("abc", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ab", model.GetText()); + EXPECT_STR_EQ("ab", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); // Continous backspaces are treated as one edit. EXPECT_TRUE(model.Backspace()); EXPECT_TRUE(model.Backspace()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); // Extra backspace shouldn't affect the history. EXPECT_FALSE(model.Backspace()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ab", model.GetText()); + EXPECT_STR_EQ("ab", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("abc", model.GetText()); + EXPECT_STR_EQ("abc", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("a", model.GetText()); + EXPECT_STR_EQ("a", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); // Clear history model.ClearEditHistory(); EXPECT_FALSE(model.Undo()); EXPECT_FALSE(model.Redo()); - EXPECT_STR_EQ("a", model.GetText()); + EXPECT_STR_EQ("a", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); // Delete =============================== @@ -1067,28 +1061,28 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) { model.ClearEditHistory(); MoveCursorTo(model, 2); EXPECT_TRUE(model.Delete()); - EXPECT_STR_EQ("ABDE", model.GetText()); + EXPECT_STR_EQ("ABDE", model.text()); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(model.Delete()); - EXPECT_STR_EQ("BDE", model.GetText()); + EXPECT_STR_EQ("BDE", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABDE", model.GetText()); + EXPECT_STR_EQ("ABDE", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABDE", model.GetText()); + EXPECT_STR_EQ("ABDE", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); // Continous deletes are treated as one edit. EXPECT_TRUE(model.Delete()); EXPECT_TRUE(model.Delete()); - EXPECT_STR_EQ("AB", model.GetText()); + EXPECT_STR_EQ("AB", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABDE", model.GetText()); + EXPECT_STR_EQ("ABDE", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("AB", model.GetText()); + EXPECT_STR_EQ("AB", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); } @@ -1096,60 +1090,60 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) { // This is to test the undo/redo behavior of omnibox. TextfieldViewsModel model(NULL); model.InsertChar('w'); - EXPECT_STR_EQ("w", model.GetText()); + EXPECT_STR_EQ("w", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); model.SetText(ASCIIToUTF16("www.google.com")); EXPECT_EQ(14U, model.GetCursorPosition()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); model.SelectRange(gfx::Range(14, 1)); model.InsertChar('w'); - EXPECT_STR_EQ("ww", model.GetText()); + EXPECT_STR_EQ("ww", model.text()); model.SetText(ASCIIToUTF16("www.google.com")); model.SelectRange(gfx::Range(14, 2)); model.InsertChar('w'); - EXPECT_STR_EQ("www", model.GetText()); + EXPECT_STR_EQ("www", model.text()); model.SetText(ASCIIToUTF16("www.google.com")); model.SelectRange(gfx::Range(14, 3)); model.InsertChar('.'); - EXPECT_STR_EQ("www.", model.GetText()); + EXPECT_STR_EQ("www.", model.text()); model.SetText(ASCIIToUTF16("www.google.com")); model.SelectRange(gfx::Range(14, 4)); model.InsertChar('y'); - EXPECT_STR_EQ("www.y", model.GetText()); + EXPECT_STR_EQ("www.y", model.text()); model.SetText(ASCIIToUTF16("www.youtube.com")); - EXPECT_STR_EQ("www.youtube.com", model.GetText()); + EXPECT_STR_EQ("www.youtube.com", model.text()); EXPECT_EQ(15U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_FALSE(model.Undo()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("www.youtube.com", model.GetText()); + EXPECT_STR_EQ("www.youtube.com", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); } @@ -1158,24 +1152,24 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BackspaceThenSetText) { // This is to test the undo/redo behavior of omnibox. TextfieldViewsModel model(NULL); model.InsertChar('w'); - EXPECT_STR_EQ("w", model.GetText()); + EXPECT_STR_EQ("w", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); model.SetText(ASCIIToUTF16("www.google.com")); EXPECT_EQ(14U, model.GetCursorPosition()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); model.SetText(ASCIIToUTF16("www.google.com")); // Confirm the text. model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(14U, model.GetCursorPosition()); EXPECT_TRUE(model.Backspace()); EXPECT_TRUE(model.Backspace()); - EXPECT_STR_EQ("www.google.c", model.GetText()); + EXPECT_STR_EQ("www.google.c", model.text()); // Autocomplete sets the text model.SetText(ASCIIToUTF16("www.google.com/search=www.google.c")); - EXPECT_STR_EQ("www.google.com/search=www.google.c", model.GetText()); + EXPECT_STR_EQ("www.google.com/search=www.google.c", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.c", model.GetText()); + EXPECT_STR_EQ("www.google.c", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("www.google.com", model.GetText()); + EXPECT_STR_EQ("www.google.com", model.text()); } TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { @@ -1185,133 +1179,133 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { // Cut model.SelectRange(gfx::Range(1, 3)); model.Cut(); - EXPECT_STR_EQ("ADE", model.GetText()); + EXPECT_STR_EQ("ADE", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_FALSE(model.Undo()); // no more undo - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ADE", model.GetText()); + EXPECT_STR_EQ("ADE", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); // no more redo - EXPECT_STR_EQ("ADE", model.GetText()); + EXPECT_STR_EQ("ADE", model.text()); model.Paste(); model.Paste(); model.Paste(); - EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCBCDE", model.text()); EXPECT_EQ(7U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCDE", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ADE", model.GetText()); + EXPECT_STR_EQ("ADE", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_FALSE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); // Redoing SetText + EXPECT_STR_EQ("ABCDE", model.text()); // Redoing SetText EXPECT_EQ(5U, model.GetCursorPosition()); // Redo EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ADE", model.GetText()); + EXPECT_STR_EQ("ADE", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCDE", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCBCDE", model.text()); EXPECT_EQ(7U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); // with SelectRange model.SelectRange(gfx::Range(1, 3)); EXPECT_TRUE(model.Cut()); - EXPECT_STR_EQ("ABCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCDE", model.text()); EXPECT_EQ(1U, model.GetCursorPosition()); model.SelectRange(gfx::Range(1, 1)); EXPECT_FALSE(model.Cut()); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("ABCBCDEBC", model.GetText()); + EXPECT_STR_EQ("ABCBCDEBC", model.text()); EXPECT_EQ(9U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCDE", model.text()); EXPECT_EQ(7U, model.GetCursorPosition()); // empty cut shouldn't create an edit. EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); + EXPECT_STR_EQ("ABCBCBCDE", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); // Copy ResetModel(&model); model.SetText(ASCIIToUTF16("12345")); - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); model.SelectRange(gfx::Range(1, 3)); model.Copy(); // Copy "23" - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); model.Paste(); // Paste "23" into "23". - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); model.Paste(); - EXPECT_STR_EQ("1232345", model.GetText()); + EXPECT_STR_EQ("1232345", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); // TODO(oshima): We need to change the return type from bool to enum. EXPECT_FALSE(model.Undo()); // No text change. - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_FALSE(model.Undo()); // Redo EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("12345", model.GetText()); + EXPECT_STR_EQ("12345", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("12345", model.GetText()); // For 1st paste + EXPECT_STR_EQ("12345", model.text()); // For 1st paste EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("1232345", model.GetText()); + EXPECT_STR_EQ("1232345", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); - EXPECT_STR_EQ("1232345", model.GetText()); + EXPECT_STR_EQ("1232345", model.text()); // Test using SelectRange model.SelectRange(gfx::Range(1, 3)); model.Copy(); - EXPECT_STR_EQ("1232345", model.GetText()); + EXPECT_STR_EQ("1232345", model.text()); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("123234523", model.GetText()); + EXPECT_STR_EQ("123234523", model.text()); EXPECT_EQ(9U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("1232345", model.GetText()); + EXPECT_STR_EQ("1232345", model.text()); EXPECT_EQ(7U, model.GetCursorPosition()); } @@ -1322,14 +1316,14 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) { model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('b'); // Moving the cursor shouldn't create a new edit. - EXPECT_STR_EQ("ab", model.GetText()); + EXPECT_STR_EQ("ab", model.text()); EXPECT_FALSE(model.Redo()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_FALSE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ab", model.GetText()); + EXPECT_STR_EQ("ab", model.text()); EXPECT_EQ(2U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); } @@ -1339,20 +1333,20 @@ void RunInsertReplaceTest(TextfieldViewsModel& model) { model.InsertChar('1'); model.InsertChar('2'); model.InsertChar('3'); - EXPECT_STR_EQ("a123d", model.GetText()); + EXPECT_STR_EQ("a123d", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("abcd", model.GetText()); + EXPECT_STR_EQ("abcd", model.text()); EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_FALSE(model.Undo()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("abcd", model.GetText()); + EXPECT_STR_EQ("abcd", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); // By SetText EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("a123d", model.GetText()); + EXPECT_STR_EQ("a123d", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); } @@ -1363,20 +1357,20 @@ void RunOverwriteReplaceTest(TextfieldViewsModel& model) { model.ReplaceChar('2'); model.ReplaceChar('3'); model.ReplaceChar('4'); - EXPECT_STR_EQ("a1234", model.GetText()); + EXPECT_STR_EQ("a1234", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("abcd", model.GetText()); + EXPECT_STR_EQ("abcd", model.text()); EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_FALSE(model.Undo()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("abcd", model.GetText()); + EXPECT_STR_EQ("abcd", model.text()); EXPECT_EQ(4U, model.GetCursorPosition()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("a1234", model.GetText()); + EXPECT_STR_EQ("a1234", model.text()); EXPECT_EQ(5U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); } @@ -1453,38 +1447,38 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { model.SetText(ASCIIToUTF16("ABCDE")); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('x'); - EXPECT_STR_EQ("ABCDEx", model.GetText()); + EXPECT_STR_EQ("ABCDEx", model.text()); EXPECT_TRUE(model.Undo()); // set composition should forget undone edit. model.SetCompositionText(composition); EXPECT_TRUE(model.HasCompositionText()); EXPECT_TRUE(model.HasSelection()); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); // Accepting composition model.ConfirmCompositionText(); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("", model.GetText()); + EXPECT_STR_EQ("", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_FALSE(model.Redo()); // Canceling composition model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); model.SetCompositionText(composition); - EXPECT_STR_EQ("abcABCDEabc", model.GetText()); + EXPECT_STR_EQ("abcABCDEabc", model.text()); model.CancelCompositionText(); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_FALSE(model.Redo()); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_FALSE(model.Redo()); // SetText with the same text as the result. @@ -1492,13 +1486,13 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { model.SetText(ASCIIToUTF16("ABCDE")); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); model.SetText(ASCIIToUTF16("ABCDEabc")); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); EXPECT_FALSE(model.Redo()); // SetText with the different text than the result should not @@ -1507,13 +1501,13 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { model.SetText(ASCIIToUTF16("ABCDE")); model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); - EXPECT_STR_EQ("ABCDEabc", model.GetText()); + EXPECT_STR_EQ("ABCDEabc", model.text()); model.SetText(ASCIIToUTF16("1234")); - EXPECT_STR_EQ("1234", model.GetText()); + EXPECT_STR_EQ("1234", model.text()); EXPECT_TRUE(model.Undo()); - EXPECT_STR_EQ("ABCDE", model.GetText()); + EXPECT_STR_EQ("ABCDE", model.text()); EXPECT_TRUE(model.Redo()); - EXPECT_STR_EQ("1234", model.GetText()); + EXPECT_STR_EQ("1234", model.text()); EXPECT_FALSE(model.Redo()); // TODO(oshima): We need MockInputMethod to test the behavior with IME. diff --git a/ui/views/ime/input_method_bridge.cc b/ui/views/ime/input_method_bridge.cc index fcc5916..b6106d8 100644 --- a/ui/views/ime/input_method_bridge.cc +++ b/ui/views/ime/input_method_bridge.cc @@ -172,7 +172,7 @@ bool InputMethodBridge::IsCandidatePopupOpen() const { } // Overridden from TextInputClient. Forward an event from the system-wide IME -// to the text input |client|, which is e.g. views::NativeTextfieldViews. +// to the text input |client|, which is e.g. views::Textfield. void InputMethodBridge::SetCompositionText( const ui::CompositionText& composition) { TextInputClient* client = GetTextInputClient(); diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc index 67882bf..729e20f 100644 --- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc +++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc @@ -8,10 +8,10 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/base/touch/touch_editing_controller.h" #include "ui/base/ui_base_switches.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" #include "ui/gfx/render_text.h" -#include "ui/views/controls/textfield/native_textfield_views.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/views_test_base.h" #include "ui/views/touchui/touch_selection_controller_impl.h" @@ -51,7 +51,6 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { TouchSelectionControllerImplTest() : widget_(NULL), textfield_(NULL), - textfield_view_(NULL), views_tsc_factory_(new ViewsTouchSelectionControllerFactory) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableTouchEditing); @@ -78,26 +77,23 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { widget_->SetContentsView(container); container->AddChildView(textfield_); - textfield_view_ = textfield_->GetTextfieldViewForTesting(); textfield_->SetBoundsRect(params.bounds); - textfield_view_->SetBoundsRect(params.bounds); textfield_->set_id(1); widget_->Show(); - DCHECK(textfield_view_); textfield_->RequestFocus(); } protected: gfx::Point GetCursorPosition(const gfx::SelectionModel& sel) { - gfx::RenderText* render_text = textfield_view_->GetRenderText(); + gfx::RenderText* render_text = textfield_->GetRenderText(); gfx::Rect cursor_bounds = render_text->GetCursorBounds(sel, true); return gfx::Point(cursor_bounds.x(), cursor_bounds.y()); } TouchSelectionControllerImpl* GetSelectionController() { return static_cast<TouchSelectionControllerImpl*>( - textfield_view_->touch_selection_controller_.get()); + textfield_->touch_selection_controller_.get()); } void SimulateSelectionHandleDrag(gfx::Point p, int selection_handle) { @@ -142,13 +138,12 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { } gfx::RenderText* GetRenderText() { - return textfield_view_->GetRenderText(); + return textfield_->GetRenderText(); } Widget* widget_; Textfield* textfield_; - NativeTextfieldViews* textfield_view_; scoped_ptr<ViewsTouchSelectionControllerFactory> views_tsc_factory_; private: @@ -161,7 +156,7 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { // handle 1's position is matched against the start of selection or the end. #define VERIFY_HANDLE_POSITIONS(cursor_at_selection_handle_1) \ { \ - gfx::SelectionModel sel = textfield_view_->GetSelectionModel(); \ + gfx::SelectionModel sel = textfield_->GetSelectionModel(); \ if (textfield_->HasSelection()) { \ EXPECT_TRUE(IsSelectionHandle1Visible()); \ EXPECT_TRUE(IsSelectionHandle2Visible()); \ @@ -200,7 +195,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) { // Tap the textfield to invoke touch selection. ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); // Test selecting a range. textfield_->SelectRange(gfx::Range(3, 7)); @@ -221,7 +216,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) { // Test with focus re-gained. widget_->GetFocusManager()->SetFocusedView(textfield_); EXPECT_FALSE(GetSelectionController()); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); VERIFY_HANDLE_POSITIONS(false); } @@ -232,7 +227,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) { // Tap the textfield to invoke touch selection. ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); // Test cursor at run boundary and with empty selection. textfield_->SelectSelectionModel( @@ -280,15 +275,15 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) { // Tap the textfield to invoke touch selection. ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); textfield_->SelectRange(gfx::Range(3, 7)); EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "tfie"); VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 2 to right by 3 chars. - const gfx::Font& font = textfield_->GetPrimaryFont(); - int x = font.GetStringWidth(ASCIIToUTF16("ld ")); + const gfx::FontList& font_list = textfield_->GetFontList(); + int x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("ld "), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "tfield "); VERIFY_HANDLE_POSITIONS(false); @@ -300,13 +295,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) { VERIFY_HANDLE_POSITIONS(true); // Drag selection handle 1 across selection handle 2. - x = font.GetStringWidth(ASCIIToUTF16("textfield with ")); + x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("textfield with "), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "with "); VERIFY_HANDLE_POSITIONS(true); // Drag selection handle 2 across selection handle 1. - x = font.GetStringWidth(ASCIIToUTF16("with selected ")); + x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("with selected "), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "selected "); VERIFY_HANDLE_POSITIONS(false); @@ -318,7 +313,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { // Tap the textfield to invoke touch selection. ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); // Select [c] from left to right. textfield_->SelectRange(gfx::Range(2, 3)); @@ -326,14 +321,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 2 to right by 1 char. - const gfx::Font& font = textfield_->GetPrimaryFont(); - int x = font.GetStringWidth(WideToUTF16(L"\x05e3")); + const gfx::FontList& font_list = textfield_->GetFontList(); + int x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e3"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 1 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"b")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"b"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); @@ -344,13 +339,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 1 to right by 1 char. - x = font.GetStringWidth(WideToUTF16(L"\x05e3")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e3"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); // Drag selection handle 2 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"b")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"b"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); @@ -369,14 +364,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { Need further investigation on whether this is a bug in Pango and how to work around it. // Drag selection handle 2 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"\x05e2")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); */ // Drag selection handle 1 to right by 1 char. - x = font.GetStringWidth(WideToUTF16(L"d")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"d"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3" L"d"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); @@ -388,14 +383,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { /* TODO(xji): see detail of above commented out test case. // Drag selection handle 1 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"\x05e2")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); */ // Drag selection handle 2 to right by 1 char. - x = font.GetStringWidth(WideToUTF16(L"d")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"d"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3" L"d"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); @@ -406,13 +401,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 2 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"c")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"c"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 1 to right by 1 char. - x = font.GetStringWidth(WideToUTF16(L"\x05e2")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); @@ -423,13 +418,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { VERIFY_HANDLE_POSITIONS(false); // Drag selection handle 1 to left by 1 char. - x = font.GetStringWidth(WideToUTF16(L"c")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"c"), font_list); SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(true); // Drag selection handle 2 to right by 1 char. - x = font.GetStringWidth(WideToUTF16(L"\x05e2")); + x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list); SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText()); VERIFY_HANDLE_POSITIONS(false); @@ -447,7 +442,7 @@ TEST_F(TouchSelectionControllerImplTest, // Tap the textfield to invoke selection. ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0); - textfield_view_->OnGestureEvent(&tap); + textfield_->OnGestureEvent(&tap); // Select some text such that one handle is hidden. textfield_->SelectRange(gfx::Range(10, textfield_text.length())); diff --git a/ui/views/view.cc b/ui/views/view.cc index b77358d..4419a07 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc @@ -1331,7 +1331,7 @@ void View::NotifyAccessibilityEvent( if (ViewsDelegate::views_delegate) ViewsDelegate::views_delegate->NotifyAccessibilityEvent(this, event_type); - if (send_native_event) { + if (send_native_event && GetWidget()) { if (!native_view_accessibility_) native_view_accessibility_ = NativeViewAccessibility::Create(this); if (native_view_accessibility_) diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 57ca371..432d904 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -217,8 +217,6 @@ 'controls/table/table_view.h', 'controls/table/table_view_observer.h', 'controls/table/table_view_row_background_painter.h', - 'controls/textfield/native_textfield_views.cc', - 'controls/textfield/native_textfield_views.h', 'controls/textfield/textfield.cc', 'controls/textfield/textfield.h', 'controls/textfield/textfield_controller.cc', @@ -761,7 +759,7 @@ 'controls/table/table_view_unittest.cc', 'controls/table/test_table_model.cc', 'controls/table/test_table_model.h', - 'controls/textfield/native_textfield_views_unittest.cc', + 'controls/textfield/textfield_unittest.cc', 'controls/textfield/textfield_views_model_unittest.cc', 'controls/tree/tree_view_unittest.cc', 'corewm/capture_controller_unittest.cc', diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 9e460b4..2cc5fc6 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h @@ -757,7 +757,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, private: friend class ComboboxTest; - friend class NativeTextfieldViewsTest; + friend class TextfieldTest; // Sets the value of |disable_inactive_rendering_|. If the value changes, // both the NonClientView and WidgetDelegate are notified. |