blob: 02d5db8b7d374898b3ca545ebf0d2c3546df673c [file] [log] [blame]
// Copyright (c) 2011 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 VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
#define VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
#pragma once
#include <list>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/composition_text.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/render_text.h"
#include "views/views_export.h"
namespace gfx {
class RenderText;
} // namespace gfx
namespace ui {
class Range;
} // namespace ui
namespace views {
namespace internal {
// Internal Edit class that keeps track of edits for undo/redo.
class Edit;
// C++ doesn't allow forward decl enum, so let's define here.
enum MergeType {
// The edit should not be merged with next edit. It still may
// be merged with an edit with MERGE_WITH_PREVIOUS.
DO_NOT_MERGE,
// The edit can be merged with next edit when possible.
MERGEABLE,
// Does the edit have to be merged with previous edit?
// This forces the merge even if the previous edit is marked
// as DO_NOT_MERGE.
MERGE_WITH_PREVIOUS,
};
} // namespace internal
// A model that represents a text content for TextfieldViews.
// It supports editing, selection and cursor manipulation.
class VIEWS_EXPORT TextfieldViewsModel {
public:
// Delegate interface implemented by the textfield view class to provided
// additional functionalities required by the model.
class VIEWS_EXPORT Delegate {
public:
// Called when the current composition text is confirmed or cleared.
virtual void OnCompositionTextConfirmedOrCleared() = 0;
protected:
virtual ~Delegate();
};
explicit TextfieldViewsModel(Delegate* delegate);
virtual ~TextfieldViewsModel();
void set_is_password(bool is_password) {
is_password_ = is_password;
}
// Edit related methods.
const 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 string16& text);
gfx::RenderText* render_text() { return render_text_.get(); }
// Inserts given |text| at the current cursor position.
// The current composition text will be cleared.
void InsertText(const string16& text) {
InsertTextInternal(text, false);
}
// Inserts a character at the current cursor position.
void InsertChar(char16 c) {
InsertTextInternal(string16(&c, 1), true);
}
// Replaces characters at the current position with characters in given text.
// The current composition text will be cleared.
void ReplaceText(const string16& text) {
ReplaceTextInternal(text, false);
}
// Replaces the char at the current position with given character.
void ReplaceChar(char16 c) {
ReplaceTextInternal(string16(&c, 1), true);
}
// Appends the text.
// The current composition text will be confirmed.
void Append(const string16& 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
// the deletion is successful.
// If there is composition text, it'll be deleted instead.
bool Delete();
// Deletes the first character before the current cursor position (as if, the
// the user has pressed backspace key in the textfield). Returns true if
// the removal is successful.
// If there is composition text, it'll be deleted instead.
bool Backspace();
// Cursor related methods.
// Returns the current cursor position.
size_t GetCursorPosition() const;
// Moves the cursor, see RenderText for additional details.
// The current composition text will be confirmed.
void MoveCursorLeft(gfx::BreakType break_type, bool select);
void MoveCursorRight(gfx::BreakType break_type, bool select);
// Moves the selection to the specified selection in |selection|.
// If there is composition text, it will be confirmed, which will update the
// selection range, and it overrides the selection_start to which the
// selection will move to.
bool MoveCursorTo(const gfx::SelectionModel& selection);
// Helper function to call MoveCursorTo on the TextfieldViewsModel.
bool MoveCursorTo(const gfx::Point& point, bool select);
// Selection related method
// Returns the selected text.
string16 GetSelectedText() const;
// Gets the selected range.
void GetSelectedRange(ui::Range* range) const;
// The current composition text will be confirmed. The selection starts with
// the range's start position, and ends with the range's end position,
// therefore the cursor position becomes the end position.
void SelectRange(const ui::Range& range);
void GetSelectionModel(gfx::SelectionModel* sel) const;
// The current composition text will be confirmed.
// render_text_'s selection model is set to |sel|.
void SelectSelectionModel(const gfx::SelectionModel& sel);
// Selects all text.
// The current composition text will be confirmed.
void SelectAll();
// Selects the word at which the cursor is currently positioned.
// The current composition text will be confirmed.
void SelectWord();
// Clears selection.
// The current composition text will be confirmed.
void ClearSelection();
// Returns true if there is an undoable edit.
bool CanUndo();
// Returns true if there is an redoable edit.
bool CanRedo();
// Undo edit. Returns true if undo changed the text.
bool Undo();
// Redo edit. Returns true if redo changed the text.
bool Redo();
// Returns visible text. If the field is password, it returns the
// sequence of "*".
string16 GetVisibleText() const;
// Cuts the currently selected text and puts it to clipboard. Returns true
// if text has changed after cutting.
bool Cut();
// Copies the currently selected text and puts it to clipboard.
void Copy();
// Pastes text from the clipboard at current cursor position. Returns true
// if text has changed after pasting.
bool Paste();
// Tells if any text is selected, even if the selection is in composition
// text.
bool HasSelection() const;
// Deletes the selected text. This method shouldn't be called with
// composition text.
void DeleteSelection();
// Deletes the selected text (if any) and insert text at given
// position.
void DeleteSelectionAndInsertTextAt(
const string16& text, size_t position);
// Retrieves the text content in a given range.
string16 GetTextFromRange(const ui::Range& range) const;
// Retrieves the range containing all text in the model.
void GetTextRange(ui::Range* range) const;
// Sets composition text and attributes. If there is composition text already,
// it’ll be replaced by the new one. Otherwise, current selection will be
// replaced. If there is no selection, the composition text will be inserted
// at the insertion point.
// Any changes to the model except text insertion will confirm the current
// composition text.
void SetCompositionText(const ui::CompositionText& composition);
// Converts current composition text into final content.
void ConfirmCompositionText();
// Removes current composition text.
void CancelCompositionText();
// Retrieves the range of current composition text.
void GetCompositionTextRange(ui::Range* range) const;
// Returns true if there is composition text.
bool HasCompositionText() const;
private:
friend class NativeTextfieldViews;
friend class NativeTextfieldViewsTest;
friend class TextfieldViewsModelTest;
friend class UndoRedo_BasicTest;
friend class UndoRedo_CutCopyPasteTest;
friend class UndoRedo_ReplaceTest;
friend class internal::Edit;
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_BasicTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest);
// Returns the visible text given |start| and |end|.
string16 GetVisibleText(size_t start, size_t end) const;
// Insert the given |text|. |mergeable| indicates if this insert
// operation can be merged to previous edit in the edit history.
void InsertTextInternal(const string16& text, bool mergeable);
// Replace the current text with the given |text|. |mergeable|
// indicates if this replace operation can be merged to previous
// edit in the edit history.
void ReplaceTextInternal(const string16& text, bool mergeable);
// Clears all edit history.
void ClearEditHistory();
// Clears redo history.
void ClearRedoHistory();
// Executes and records edit operations.
void ExecuteAndRecordDelete(size_t from, size_t to, bool mergeable);
void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
const string16& text);
void ExecuteAndRecordReplace(internal::MergeType merge_type,
size_t old_cursor_pos,
size_t new_cursor_pos,
const string16& text,
size_t new_text_start);
void ExecuteAndRecordInsert(const string16& text, bool mergeable);
// Adds or merge |edit| into edit history. Return true if the edit
// has been merged and must be deleted after redo.
bool AddOrMergeEditHistory(internal::Edit* edit);
// Modify the text buffer in following way:
// 1) Delete the string from |delete_from| to |delte_to|.
// 2) Insert the |new_text| at the index |new_text_insert_at|.
// Note that the index is after deletion.
// 3) Move the cursor to |new_cursor_pos|.
void ModifyText(size_t delete_from,
size_t delete_to,
const string16& new_text,
size_t new_text_insert_at,
size_t new_cursor_pos);
void ClearComposition();
// Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
// the View object.
Delegate* delegate_;
// The stylized text, cursor, selection, and the visual layout model.
scoped_ptr<gfx::RenderText> render_text_;
// True if the text is the password.
bool is_password_;
typedef std::list<internal::Edit*> EditHistory;
EditHistory edit_history_;
// An iterator that points to the current edit that can be undone.
// This iterator moves from the |end()|, meaining no edit to undo,
// to the last element (one before |end()|), meaning no edit to redo.
// There is no edit to undo (== end()) when:
// 1) in initial state. (nothing to undo)
// 2) very 1st edit is undone.
// 3) all edit history is removed.
// There is no edit to redo (== last element or no element) when:
// 1) in initial state. (nothing to redo)
// 2) new edit is added. (redo history is cleared)
// 3) redone all undone edits.
EditHistory::iterator current_edit_;
DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel);
};
} // namespace views
#endif // VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_