1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
6 #define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
11 #include "base/gtest_prod_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string16.h"
14 #include "third_party/skia/include/core/SkColor.h"
15 #include "ui/base/ime/composition_text.h"
16 #include "ui/gfx/rect.h"
17 #include "ui/gfx/render_text.h"
18 #include "ui/gfx/text_constants.h"
19 #include "ui/views/views_export.h"
29 // Internal Edit class that keeps track of edits for undo/redo.
32 // C++ doesn't allow forward decl enum, so let's define here.
34 // The edit should not be merged with next edit. It still may
35 // be merged with an edit with MERGE_WITH_PREVIOUS.
37 // The edit can be merged with next edit when possible.
39 // Does the edit have to be merged with previous edit?
40 // This forces the merge even if the previous edit is marked
45 } // namespace internal
47 // A model that represents a text content for TextfieldViews.
48 // It supports editing, selection and cursor manipulation.
49 class VIEWS_EXPORT TextfieldViewsModel
{
51 // Delegate interface implemented by the textfield view class to provided
52 // additional functionalities required by the model.
53 class VIEWS_EXPORT Delegate
{
55 // Called when the current composition text is confirmed or cleared.
56 virtual void OnCompositionTextConfirmedOrCleared() = 0;
62 explicit TextfieldViewsModel(Delegate
* delegate
);
63 virtual ~TextfieldViewsModel();
65 // Edit related methods.
67 const base::string16
& GetText() const;
68 // Sets the text. Returns true if the text has been modified. The
69 // current composition text will be confirmed first. Setting
70 // the same text will not add edit history because it's not user
71 // visible change nor user-initiated change. This allow a client
72 // code to set the same text multiple times without worrying about
73 // messing edit history.
74 bool SetText(const base::string16
& text
);
76 gfx::RenderText
* render_text() { return render_text_
.get(); }
78 // Inserts given |text| at the current cursor position.
79 // The current composition text will be cleared.
80 void InsertText(const base::string16
& text
) {
81 InsertTextInternal(text
, false);
84 // Inserts a character at the current cursor position.
85 void InsertChar(char16 c
) {
86 InsertTextInternal(base::string16(&c
, 1), true);
89 // Replaces characters at the current position with characters in given text.
90 // The current composition text will be cleared.
91 void ReplaceText(const base::string16
& text
) {
92 ReplaceTextInternal(text
, false);
95 // Replaces the char at the current position with given character.
96 void ReplaceChar(char16 c
) {
97 ReplaceTextInternal(base::string16(&c
, 1), true);
101 // The current composition text will be confirmed.
102 void Append(const base::string16
& text
);
104 // Deletes the first character after the current cursor position (as if, the
105 // the user has pressed delete key in the textfield). Returns true if
106 // the deletion is successful.
107 // If there is composition text, it'll be deleted instead.
110 // Deletes the first character before the current cursor position (as if, the
111 // the user has pressed backspace key in the textfield). Returns true if
112 // the removal is successful.
113 // If there is composition text, it'll be deleted instead.
116 // Cursor related methods.
118 // Returns the current cursor position.
119 size_t GetCursorPosition() const;
121 // Moves the cursor, see RenderText for additional details.
122 // The current composition text will be confirmed.
123 void MoveCursor(gfx::BreakType break_type
,
124 gfx::VisualCursorDirection direction
,
127 // Moves the selection to the specified selection in |selection|.
128 // If there is composition text, it will be confirmed, which will update the
129 // selection range, and it overrides the selection_start to which the
130 // selection will move to.
131 bool MoveCursorTo(const gfx::SelectionModel
& selection
);
133 // Helper function to call MoveCursorTo on the TextfieldViewsModel.
134 bool MoveCursorTo(const gfx::Point
& point
, bool select
);
136 // Selection related method
138 // Returns the selected text.
139 base::string16
GetSelectedText() const;
141 // The current composition text will be confirmed. The selection starts with
142 // the range's start position, and ends with the range's end position,
143 // therefore the cursor position becomes the end position.
144 void SelectRange(const gfx::Range
& range
);
146 // The current composition text will be confirmed.
147 // render_text_'s selection model is set to |sel|.
148 void SelectSelectionModel(const gfx::SelectionModel
& sel
);
150 // Select the entire text range. If |reversed| is true, the range will end at
151 // the logical beginning of the text; this generally shows the leading portion
152 // of text that overflows its display area.
153 // The current composition text will be confirmed.
154 void SelectAll(bool reversed
);
156 // Selects the word at which the cursor is currently positioned. If there is a
157 // non-empty selection, the selection bounds are extended to their nearest
159 // The current composition text will be confirmed.
163 // The current composition text will be confirmed.
164 void ClearSelection();
166 // Returns true if there is an undoable edit.
169 // Returns true if there is an redoable edit.
172 // Undo edit. Returns true if undo changed the text.
175 // Redo edit. Returns true if redo changed the text.
178 // Cuts the currently selected text and puts it to clipboard. Returns true
179 // if text has changed after cutting.
182 // Copies the currently selected text and puts it to clipboard. Returns true
183 // if something was copied to the clipboard.
186 // Pastes text from the clipboard at current cursor position. Returns true
187 // if any text is pasted.
190 // Tells if any text is selected, even if the selection is in composition
192 bool HasSelection() const;
194 // Deletes the selected text. This method shouldn't be called with
196 void DeleteSelection();
198 // Deletes the selected text (if any) and insert text at given
200 void DeleteSelectionAndInsertTextAt(
201 const base::string16
& text
, size_t position
);
203 // Retrieves the text content in a given range.
204 base::string16
GetTextFromRange(const gfx::Range
& range
) const;
206 // Retrieves the range containing all text in the model.
207 void GetTextRange(gfx::Range
* range
) const;
209 // Sets composition text and attributes. If there is composition text already,
210 // it'll be replaced by the new one. Otherwise, current selection will be
211 // replaced. If there is no selection, the composition text will be inserted
212 // at the insertion point.
213 // Any changes to the model except text insertion will confirm the current
215 void SetCompositionText(const ui::CompositionText
& composition
);
217 // Converts current composition text into final content.
218 void ConfirmCompositionText();
220 // Removes current composition text.
221 void CancelCompositionText();
223 // Retrieves the range of current composition text.
224 void GetCompositionTextRange(gfx::Range
* range
) const;
226 // Returns true if there is composition text.
227 bool HasCompositionText() const;
230 friend class NativeTextfieldViews
;
231 friend class NativeTextfieldViewsTest
;
232 friend class TextfieldViewsModelTest
;
233 friend class UndoRedo_BasicTest
;
234 friend class UndoRedo_CutCopyPasteTest
;
235 friend class UndoRedo_ReplaceTest
;
236 friend class internal::Edit
;
238 FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest
, UndoRedo_BasicTest
);
239 FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest
, UndoRedo_CutCopyPasteTest
);
240 FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest
, UndoRedo_ReplaceTest
);
242 // Insert the given |text|. |mergeable| indicates if this insert
243 // operation can be merged to previous edit in the edit history.
244 void InsertTextInternal(const base::string16
& text
, bool mergeable
);
246 // Replace the current text with the given |text|. |mergeable|
247 // indicates if this replace operation can be merged to previous
248 // edit in the edit history.
249 void ReplaceTextInternal(const base::string16
& text
, bool mergeable
);
251 // Clears all edit history.
252 void ClearEditHistory();
254 // Clears redo history.
255 void ClearRedoHistory();
257 // Executes and records edit operations.
258 void ExecuteAndRecordDelete(gfx::Range range
, bool mergeable
);
259 void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type
,
260 const base::string16
& text
);
261 void ExecuteAndRecordReplace(internal::MergeType merge_type
,
262 size_t old_cursor_pos
,
263 size_t new_cursor_pos
,
264 const base::string16
& text
,
265 size_t new_text_start
);
266 void ExecuteAndRecordInsert(const base::string16
& text
, bool mergeable
);
268 // Adds or merge |edit| into edit history. Return true if the edit
269 // has been merged and must be deleted after redo.
270 bool AddOrMergeEditHistory(internal::Edit
* edit
);
272 // Modify the text buffer in following way:
273 // 1) Delete the string from |delete_from| to |delte_to|.
274 // 2) Insert the |new_text| at the index |new_text_insert_at|.
275 // Note that the index is after deletion.
276 // 3) Move the cursor to |new_cursor_pos|.
277 void ModifyText(size_t delete_from
,
279 const base::string16
& new_text
,
280 size_t new_text_insert_at
,
281 size_t new_cursor_pos
);
283 void ClearComposition();
285 // Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
289 // The stylized text, cursor, selection, and the visual layout model.
290 scoped_ptr
<gfx::RenderText
> render_text_
;
292 typedef std::list
<internal::Edit
*> EditHistory
;
293 EditHistory edit_history_
;
295 // An iterator that points to the current edit that can be undone.
296 // This iterator moves from the |end()|, meaining no edit to undo,
297 // to the last element (one before |end()|), meaning no edit to redo.
298 // There is no edit to undo (== end()) when:
299 // 1) in initial state. (nothing to undo)
300 // 2) very 1st edit is undone.
301 // 3) all edit history is removed.
302 // There is no edit to redo (== last element or no element) when:
303 // 1) in initial state. (nothing to redo)
304 // 2) new edit is added. (redo history is cleared)
305 // 3) redone all undone edits.
306 EditHistory::iterator current_edit_
;
308 DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel
);
313 #endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_