Home | History | Annotate | Download | only in textfield
      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.
      4 
      5 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
      6 #define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
      7 
      8 #include <list>
      9 #include <vector>
     10 
     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"
     20 
     21 namespace gfx {
     22 class RenderText;
     23 }  // namespace gfx
     24 
     25 namespace ui {
     26 class Range;
     27 }  // namespace ui
     28 
     29 namespace views {
     30 
     31 namespace internal {
     32 // Internal Edit class that keeps track of edits for undo/redo.
     33 class Edit;
     34 
     35 // C++ doesn't allow forward decl enum, so let's define here.
     36 enum MergeType {
     37   // The edit should not be merged with next edit. It still may
     38   // be merged with an edit with MERGE_WITH_PREVIOUS.
     39   DO_NOT_MERGE,
     40   // The edit can be merged with next edit when possible.
     41   MERGEABLE,
     42   // Does the edit have to be merged with previous edit?
     43   // This forces the merge even if the previous edit is marked
     44   // as DO_NOT_MERGE.
     45   MERGE_WITH_PREVIOUS,
     46 };
     47 
     48 }  // namespace internal
     49 
     50 // A model that represents a text content for TextfieldViews.
     51 // It supports editing, selection and cursor manipulation.
     52 class VIEWS_EXPORT TextfieldViewsModel {
     53  public:
     54   // Delegate interface implemented by the textfield view class to provided
     55   // additional functionalities required by the model.
     56   class VIEWS_EXPORT Delegate {
     57    public:
     58     // Called when the current composition text is confirmed or cleared.
     59     virtual void OnCompositionTextConfirmedOrCleared() = 0;
     60 
     61    protected:
     62     virtual ~Delegate();
     63   };
     64 
     65   explicit TextfieldViewsModel(Delegate* delegate);
     66   virtual ~TextfieldViewsModel();
     67 
     68   // Edit related methods.
     69 
     70   const string16& GetText() const;
     71   // Sets the text. Returns true if the text has been modified.  The
     72   // current composition text will be confirmed first.  Setting
     73   // the same text will not add edit history because it's not user
     74   // visible change nor user-initiated change. This allow a client
     75   // code to set the same text multiple times without worrying about
     76   // messing edit history.
     77   bool SetText(const string16& text);
     78 
     79   gfx::RenderText* render_text() { return render_text_.get(); }
     80 
     81   // Inserts given |text| at the current cursor position.
     82   // The current composition text will be cleared.
     83   void InsertText(const string16& text) {
     84     InsertTextInternal(text, false);
     85   }
     86 
     87   // Inserts a character at the current cursor position.
     88   void InsertChar(char16 c) {
     89     InsertTextInternal(string16(&c, 1), true);
     90   }
     91 
     92   // Replaces characters at the current position with characters in given text.
     93   // The current composition text will be cleared.
     94   void ReplaceText(const string16& text) {
     95     ReplaceTextInternal(text, false);
     96   }
     97 
     98   // Replaces the char at the current position with given character.
     99   void ReplaceChar(char16 c) {
    100     ReplaceTextInternal(string16(&c, 1), true);
    101   }
    102 
    103   // Appends the text.
    104   // The current composition text will be confirmed.
    105   void Append(const string16& text);
    106 
    107   // Deletes the first character after the current cursor position (as if, the
    108   // the user has pressed delete key in the textfield). Returns true if
    109   // the deletion is successful.
    110   // If there is composition text, it'll be deleted instead.
    111   bool Delete();
    112 
    113   // Deletes the first character before the current cursor position (as if, the
    114   // the user has pressed backspace key in the textfield). Returns true if
    115   // the removal is successful.
    116   // If there is composition text, it'll be deleted instead.
    117   bool Backspace();
    118 
    119   // Cursor related methods.
    120 
    121   // Returns the current cursor position.
    122   size_t GetCursorPosition() const;
    123 
    124   // Moves the cursor, see RenderText for additional details.
    125   // The current composition text will be confirmed.
    126   void MoveCursor(gfx::BreakType break_type,
    127                   gfx::VisualCursorDirection direction,
    128                   bool select);
    129 
    130   // Moves the selection to the specified selection in |selection|.
    131   // If there is composition text, it will be confirmed, which will update the
    132   // selection range, and it overrides the selection_start to which the
    133   // selection will move to.
    134   bool MoveCursorTo(const gfx::SelectionModel& selection);
    135 
    136   // Helper function to call MoveCursorTo on the TextfieldViewsModel.
    137   bool MoveCursorTo(const gfx::Point& point, bool select);
    138 
    139   // Selection related method
    140 
    141   // Returns the selected text.
    142   string16 GetSelectedText() const;
    143 
    144   // The current composition text will be confirmed. The selection starts with
    145   // the range's start position, and ends with the range's end position,
    146   // therefore the cursor position becomes the end position.
    147   void SelectRange(const ui::Range& range);
    148 
    149   // The current composition text will be confirmed.
    150   // render_text_'s selection model is set to |sel|.
    151   void SelectSelectionModel(const gfx::SelectionModel& sel);
    152 
    153   // Select the entire text range. If |reversed| is true, the range will end at
    154   // the logical beginning of the text; this generally shows the leading portion
    155   // of text that overflows its display area.
    156   // The current composition text will be confirmed.
    157   void SelectAll(bool reversed);
    158 
    159   // Selects the word at which the cursor is currently positioned. If there is a
    160   // non-empty selection, the selection bounds are extended to their nearest
    161   // word boundaries.
    162   // The current composition text will be confirmed.
    163   void SelectWord();
    164 
    165   // Clears selection.
    166   // The current composition text will be confirmed.
    167   void ClearSelection();
    168 
    169   // Returns true if there is an undoable edit.
    170   bool CanUndo();
    171 
    172   // Returns true if there is an redoable edit.
    173   bool CanRedo();
    174 
    175   // Undo edit. Returns true if undo changed the text.
    176   bool Undo();
    177 
    178   // Redo edit. Returns true if redo changed the text.
    179   bool Redo();
    180 
    181   // Cuts the currently selected text and puts it to clipboard. Returns true
    182   // if text has changed after cutting.
    183   bool Cut();
    184 
    185   // Copies the currently selected text and puts it to clipboard. Returns true
    186   // if something was copied to the clipboard.
    187   bool Copy();
    188 
    189   // Pastes text from the clipboard at current cursor position. Returns true
    190   // if any text is pasted.
    191   bool Paste();
    192 
    193   // Tells if any text is selected, even if the selection is in composition
    194   // text.
    195   bool HasSelection() const;
    196 
    197   // Deletes the selected text. This method shouldn't be called with
    198   // composition text.
    199   void DeleteSelection();
    200 
    201   // Deletes the selected text (if any) and insert text at given
    202   // position.
    203   void DeleteSelectionAndInsertTextAt(
    204       const string16& text, size_t position);
    205 
    206   // Retrieves the text content in a given range.
    207   string16 GetTextFromRange(const ui::Range& range) const;
    208 
    209   // Retrieves the range containing all text in the model.
    210   void GetTextRange(ui::Range* range) const;
    211 
    212   // Sets composition text and attributes. If there is composition text already,
    213   // it'll be replaced by the new one. Otherwise, current selection will be
    214   // replaced. If there is no selection, the composition text will be inserted
    215   // at the insertion point.
    216   // Any changes to the model except text insertion will confirm the current
    217   // composition text.
    218   void SetCompositionText(const ui::CompositionText& composition);
    219 
    220   // Converts current composition text into final content.
    221   void ConfirmCompositionText();
    222 
    223   // Removes current composition text.
    224   void CancelCompositionText();
    225 
    226   // Retrieves the range of current composition text.
    227   void GetCompositionTextRange(ui::Range* range) const;
    228 
    229   // Returns true if there is composition text.
    230   bool HasCompositionText() const;
    231 
    232  private:
    233   friend class NativeTextfieldViews;
    234   friend class NativeTextfieldViewsTest;
    235   friend class TextfieldViewsModelTest;
    236   friend class UndoRedo_BasicTest;
    237   friend class UndoRedo_CutCopyPasteTest;
    238   friend class UndoRedo_ReplaceTest;
    239   friend class internal::Edit;
    240 
    241   FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_BasicTest);
    242   FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest);
    243   FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest);
    244 
    245   // Insert the given |text|. |mergeable| indicates if this insert
    246   // operation can be merged to previous edit in the edit history.
    247   void InsertTextInternal(const string16& text, bool mergeable);
    248 
    249   // Replace the current text with the given |text|. |mergeable|
    250   // indicates if this replace operation can be merged to previous
    251   // edit in the edit history.
    252   void ReplaceTextInternal(const string16& text, bool mergeable);
    253 
    254   // Clears all edit history.
    255   void ClearEditHistory();
    256 
    257   // Clears redo history.
    258   void ClearRedoHistory();
    259 
    260   // Executes and records edit operations.
    261   void ExecuteAndRecordDelete(ui::Range range, bool mergeable);
    262   void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
    263                                         const string16& text);
    264   void ExecuteAndRecordReplace(internal::MergeType merge_type,
    265                                size_t old_cursor_pos,
    266                                size_t new_cursor_pos,
    267                                const string16& text,
    268                                size_t new_text_start);
    269   void ExecuteAndRecordInsert(const string16& text, bool mergeable);
    270 
    271   // Adds or merge |edit| into edit history. Return true if the edit
    272   // has been merged and must be deleted after redo.
    273   bool AddOrMergeEditHistory(internal::Edit* edit);
    274 
    275   // Modify the text buffer in following way:
    276   // 1) Delete the string from |delete_from| to |delte_to|.
    277   // 2) Insert the |new_text| at the index |new_text_insert_at|.
    278   //    Note that the index is after deletion.
    279   // 3) Move the cursor to |new_cursor_pos|.
    280   void ModifyText(size_t delete_from,
    281                   size_t delete_to,
    282                   const string16& new_text,
    283                   size_t new_text_insert_at,
    284                   size_t new_cursor_pos);
    285 
    286   void ClearComposition();
    287 
    288   // Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
    289   // the View object.
    290   Delegate* delegate_;
    291 
    292   // The stylized text, cursor, selection, and the visual layout model.
    293   scoped_ptr<gfx::RenderText> render_text_;
    294 
    295   typedef std::list<internal::Edit*> EditHistory;
    296   EditHistory edit_history_;
    297 
    298   // An iterator that points to the current edit that can be undone.
    299   // This iterator moves from the |end()|, meaining no edit to undo,
    300   // to the last element (one before |end()|), meaning no edit to redo.
    301   //  There is no edit to undo (== end()) when:
    302   // 1) in initial state. (nothing to undo)
    303   // 2) very 1st edit is undone.
    304   // 3) all edit history is removed.
    305   //  There is no edit to redo (== last element or no element) when:
    306   // 1) in initial state. (nothing to redo)
    307   // 2) new edit is added. (redo history is cleared)
    308   // 3) redone all undone edits.
    309   EditHistory::iterator current_edit_;
    310 
    311   DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel);
    312 };
    313 
    314 }  // namespace views
    315 
    316 #endif  // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
    317