summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/test/testing_browser_process.h9
-rw-r--r--chrome/views/controls/text_field.cc14
-rw-r--r--chrome/views/controls/text_field.h2
-rw-r--r--chrome/views/view_unittest.cc113
4 files changed, 134 insertions, 4 deletions
diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h
index e2fff16..a507586 100644
--- a/chrome/test/testing_browser_process.h
+++ b/chrome/test/testing_browser_process.h
@@ -17,6 +17,7 @@
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/common/clipboard_service.h"
#include "chrome/common/notification_service.h"
class TestingBrowserProcess : public BrowserProcess {
@@ -80,7 +81,11 @@ class TestingBrowserProcess : public BrowserProcess {
}
virtual ClipboardService* clipboard_service() {
- return NULL;
+ if (!clipboard_service_.get()) {
+ // Note that we need a MessageLoop for the next call to work.
+ clipboard_service_.reset(new ClipboardService);
+ }
+ return clipboard_service_.get();
}
virtual GoogleURLTracker* google_url_tracker() {
@@ -132,6 +137,8 @@ class TestingBrowserProcess : public BrowserProcess {
private:
NotificationService notification_service_;
scoped_ptr<base::WaitableEvent> shutdown_event_;
+ scoped_ptr<ClipboardService> clipboard_service_;
+
DISALLOW_COPY_AND_ASSIGN(TestingBrowserProcess);
};
diff --git a/chrome/views/controls/text_field.cc b/chrome/views/controls/text_field.cc
index 5114d83c..1485427 100644
--- a/chrome/views/controls/text_field.cc
+++ b/chrome/views/controls/text_field.cc
@@ -375,8 +375,9 @@ void TextField::Edit::SetBackgroundColor(COLORREF bg_color) {
bool TextField::Edit::IsCommandEnabled(int id) const {
switch (id) {
case IDS_UNDO: return !parent_->IsReadOnly() && !!CanUndo();
- case IDS_CUT: return !parent_->IsReadOnly() && !!CanCut();
- case IDS_COPY: return !!CanCopy();
+ case IDS_CUT: return !parent_->IsReadOnly() &&
+ !parent_->IsPassword() && !!CanCut();
+ case IDS_COPY: return !!CanCopy() && !parent_->IsPassword();
case IDS_PASTE: return !parent_->IsReadOnly() && !!CanPaste();
case IDS_SELECT_ALL: return !!CanSelectAll();
default: NOTREACHED();
@@ -412,6 +413,9 @@ void TextField::Edit::OnContextMenu(HWND window, const CPoint& point) {
}
void TextField::Edit::OnCopy() {
+ if (parent_->IsPassword())
+ return;
+
const std::wstring text(GetSelectedText());
if (!text.empty()) {
@@ -427,7 +431,7 @@ LRESULT TextField::Edit::OnCreate(CREATESTRUCT* create_struct) {
}
void TextField::Edit::OnCut() {
- if (parent_->IsReadOnly())
+ if (parent_->IsReadOnly() || parent_->IsPassword())
return;
OnCopy();
@@ -1032,6 +1036,10 @@ bool TextField::IsReadOnly() const {
return edit_ ? ((edit_->GetStyle() & ES_READONLY) != 0) : read_only_;
}
+bool TextField::IsPassword() const {
+ return GetStyle() & TextField::STYLE_PASSWORD;
+}
+
bool TextField::IsMultiLine() const {
return (style_ & STYLE_MULTILINE) != 0;
}
diff --git a/chrome/views/controls/text_field.h b/chrome/views/controls/text_field.h
index 2447e92..ffa5469 100644
--- a/chrome/views/controls/text_field.h
+++ b/chrome/views/controls/text_field.h
@@ -84,6 +84,8 @@ class TextField : public View {
void SetReadOnly(bool read_only);
bool IsReadOnly() const;
+ bool IsPassword() const;
+
// Whether the text field is multi-line or not, must be set when the text
// field is created, using StyleFlags.
bool IsMultiLine() const;
diff --git a/chrome/views/view_unittest.cc b/chrome/views/view_unittest.cc
index 60e54f0..182bfac 100644
--- a/chrome/views/view_unittest.cc
+++ b/chrome/views/view_unittest.cc
@@ -3,11 +3,14 @@
// found in the LICENSE file.
#include "base/message_loop.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/clipboard_service.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/path.h"
#include "chrome/common/notification_service.h"
#include "chrome/views/background.h"
#include "chrome/views/controls/button/checkbox.h"
+#include "chrome/views/controls/text_field.h"
#include "chrome/views/event.h"
#include "chrome/views/view.h"
#include "chrome/views/widget/root_view.h"
@@ -589,6 +592,116 @@ TEST_F(ViewTest, HitTestMasks) {
EXPECT_EQ(root_view, root_view->GetViewForPoint(v2_origin));
}
+#if defined(OS_WIN)
+// Tests that the TextField view respond appropiately to cut/copy/paste.
+TEST_F(ViewTest, TextFieldCutCopyPaste) {
+ const std::wstring kNormalText = L"Normal";
+ const std::wstring kReadOnlyText = L"Read only";
+ const std::wstring kPasswordText = L"Password! ** Secret stuff **";
+
+ ClipboardService* clipboard = g_browser_process->clipboard_service();
+
+ WidgetWin* window = new WidgetWin;
+ window->Init(NULL, gfx::Rect(0, 0, 100, 100), true);
+ RootView* root_view = window->GetRootView();
+
+ TextField* normal = new TextField();
+ TextField* read_only = new TextField();
+ read_only->SetReadOnly(true);
+ TextField* password = new TextField(TextField::STYLE_PASSWORD);
+
+ root_view->AddChildView(normal);
+ root_view->AddChildView(read_only);
+ root_view->AddChildView(password);
+
+ normal->SetText(kNormalText);
+ read_only->SetText(kReadOnlyText);
+ password->SetText(kPasswordText);
+
+ //
+ // Test cut.
+ //
+ ASSERT_TRUE(normal->GetNativeComponent());
+ normal->SelectAll();
+ ::SendMessage(normal->GetNativeComponent(), WM_CUT, 0, 0);
+
+ string16 result;
+ clipboard->ReadText(&result);
+ EXPECT_EQ(kNormalText, result);
+ normal->SetText(kNormalText); // Let's revert to the original content.
+
+ ASSERT_TRUE(read_only->GetNativeComponent());
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetNativeComponent(), WM_CUT, 0, 0);
+ result.clear();
+ clipboard->ReadText(&result);
+ // Cut should have failed, so the clipboard content should not have changed.
+ EXPECT_EQ(kNormalText, result);
+
+ ASSERT_TRUE(password->GetNativeComponent());
+ password->SelectAll();
+ ::SendMessage(password->GetNativeComponent(), WM_CUT, 0, 0);
+ result.clear();
+ clipboard->ReadText(&result);
+ // Cut should have failed, so the clipboard content should not have changed.
+ EXPECT_EQ(kNormalText, result);
+
+ //
+ // Test copy.
+ //
+
+ // Let's start with read_only as the clipboard already contains the content
+ // of normal.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetNativeComponent(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard->ReadText(&result);
+ EXPECT_EQ(kReadOnlyText, result);
+
+ normal->SelectAll();
+ ::SendMessage(normal->GetNativeComponent(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard->ReadText(&result);
+ EXPECT_EQ(kNormalText, result);
+
+ password->SelectAll();
+ ::SendMessage(password->GetNativeComponent(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard->ReadText(&result);
+ // We don't let you copy from a password field, clipboard should not have
+ // changed.
+ EXPECT_EQ(kNormalText, result);
+
+ //
+ // Test Paste.
+ //
+ // Note that we use GetWindowText instead of TextField::GetText below as the
+ // text in the TextField class is synced to the text of the HWND on
+ // WM_KEYDOWN messages that we are not simulating here.
+
+ // Attempting to copy kNormalText in a read-only text-field should fail.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetNativeComponent(), WM_KEYDOWN, 0, 0);
+ wchar_t buffer[1024] = { 0 };
+ ::GetWindowText(read_only->GetNativeComponent(), buffer, 1024);
+ EXPECT_EQ(kReadOnlyText, std::wstring(buffer));
+
+ password->SelectAll();
+ ::SendMessage(password->GetNativeComponent(), WM_PASTE, 0, 0);
+ ::GetWindowText(password->GetNativeComponent(), buffer, 1024);
+ EXPECT_EQ(kNormalText, std::wstring(buffer));
+
+ // Copy from read_only so the string we are pasting is not the same as the
+ // current one.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetNativeComponent(), WM_COPY, 0, 0);
+ normal->SelectAll();
+ ::SendMessage(normal->GetNativeComponent(), WM_PASTE, 0, 0);
+ ::GetWindowText(normal->GetNativeComponent(), buffer, 1024);
+ EXPECT_EQ(kReadOnlyText, std::wstring(buffer));
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// Dialogs' default button
////////////////////////////////////////////////////////////////////////////////