Unnecessary TextChanged callbacks are being called. 33/255233/10
authorJoogab Yun <joogab.yun@samsung.com>
Mon, 15 Mar 2021 10:17:04 +0000 (19:17 +0900)
committerJoogab Yun <joogab.yun@samsung.com>
Wed, 17 Mar 2021 06:48:19 +0000 (15:48 +0900)
Change it to be called only once at the end.

example)

Typing "호두" on the keyboard
Whenever COMMIT/PREEDIT in OnInputMethodContextEvent(), TextChanged callback is called

 OnTextFieldTextChanged(159) >  [ㅎ]   // PRE_EDIT
 OnTextFieldTextChanged(159) >  [호]   // PRE_EDIT
 OnTextFieldTextChanged(159) >  [혿]   // PRE_EDIT
 OnTextFieldTextChanged(159) >  []     // PRE_EDIT
 OnTextFieldTextChanged(159) >  [호]   // COMMIT
 OnTextFieldTextChanged(159) >  [호두] // PRE_EDIT

If you change the text to call the TextChanged callback only once at the end of the change,
 OnTextFieldTextChanged(159) >  [ㅎ]
 OnTextFieldTextChanged(159) >  [호]
 OnTextFieldTextChanged(159) >  [혿]
 OnTextFieldTextChanged(159) >  [호두]

Change-Id: I039263bc156f0be161f37eeb1d0e6ecf39f9536c

automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h

index d5a243c..06d3307 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -964,33 +964,113 @@ int utcDaliTextEditorTextChangedP(void)
 
   gTextChangedCallBackCalled = false;
   editor.SetProperty( TextEditor::Property::TEXT, "ABC" );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( gTextChangedCallBackCalled );
   DALI_TEST_CHECK( textChangedSignal );
 
-  application.SendNotification();
-
   editor.SetKeyInputFocus();
 
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( gTextChangedCallBackCalled );
 
   // Remove all text
   editor.SetProperty( TextField::Property::TEXT, "" );
+  application.SendNotification();
+  application.Render();
 
   // Pressing backspace key: TextChangedCallback should not be called when there is no text in texteditor.
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( !gTextChangedCallBackCalled );
 
   // Pressing delete key: TextChangedCallback should not be called when there is no text in texteditor.
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "Delete", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( !gTextChangedCallBackCalled );
 
   END_TEST;
 }
 
+int utcDaliTextEditorTextChangedWithInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorTextChangedWithInputMethodContext");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+
+  application.GetScene().Add( editor );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  editor.TextChangedSignal().Connect(&TestTextChangedCallback);
+  bool textChangedSignal = false;
+  editor.ConnectSignal( testTracker, "textChanged",   CallbackFunctor(&textChangedSignal) );
+
+
+  // get InputMethodContext
+  std::string text;
+  InputMethodContext::EventData imfEvent;
+  InputMethodContext inputMethodContext = DevelTextEditor::GetInputMethodContext( editor );
+
+  editor.SetKeyInputFocus();
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_EDITING, true );
+
+  // input text
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "ㅎ", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("ㅎ"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "호", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("호"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "혿", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("혿"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::COMMIT, "호", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "두", 1, 2 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("호두"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
 int utcDaliTextEditorInputStyleChanged01(void)
 {
   // The text-editor emits signals when the input style changes. These changes of style are
index b535059..0795816 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1034,33 +1034,113 @@ int utcDaliTextFieldTextChangedP(void)
 
   gTextChangedCallBackCalled = false;
   field.SetProperty( TextField::Property::TEXT, "ABC" );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( gTextChangedCallBackCalled );
   DALI_TEST_CHECK( textChangedSignal );
 
-  application.SendNotification();
-
   field.SetKeyInputFocus();
 
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( gTextChangedCallBackCalled );
 
   // Remove all text
   field.SetProperty( TextField::Property::TEXT, "" );
+  application.SendNotification();
+  application.Render();
 
   // Pressing backspace key: TextChangedCallback should not be called when there is no text in textfield.
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( !gTextChangedCallBackCalled );
 
   // Pressing delete key: TextChangedCallback should not be called when there is no text in textfield.
   gTextChangedCallBackCalled = false;
   application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "Delete", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldTextChangedWithInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedWithInputMethodContext");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+
+  application.GetScene().Add( field );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+  bool textChangedSignal = false;
+  field.ConnectSignal( testTracker, "textChanged",   CallbackFunctor(&textChangedSignal) );
+
+
+  // get InputMethodContext
+  std::string text;
+  InputMethodContext::EventData imfEvent;
+  InputMethodContext inputMethodContext = DevelTextField::GetInputMethodContext( field );
+
+  field.SetKeyInputFocus();
+  field.SetProperty( DevelTextField::Property::ENABLE_EDITING, true );
+
+  // input text
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "ㅎ", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("ㅎ"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "호", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("호"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "혿", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("혿"), TEST_LOCATION );
+
+  gTextChangedCallBackCalled = false;
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::COMMIT, "호", 0, 1 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "두", 1, 2 );
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
   DALI_TEST_CHECK( !gTextChangedCallBackCalled );
 
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("호두"), TEST_LOCATION );
+
   END_TEST;
 }
 
+
 // Negative test for the textChanged signal.
 int utcDaliTextFieldTextChangedN(void)
 {
@@ -1079,6 +1159,8 @@ int utcDaliTextFieldTextChangedN(void)
 
   gTextChangedCallBackCalled = false;
   field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( !gTextChangedCallBackCalled );
   DALI_TEST_CHECK( !textChangedSignal );
 
index 4e7d3f0..3d48333 100644 (file)
@@ -1384,7 +1384,7 @@ float TextEditor::GetHeightForWidth(float width)
 
 void TextEditor::ResizeActor(Actor& actor, const Vector2& size)
 {
-  if (actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
+  if(actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
   {
     actor.SetProperty(Actor::Property::SIZE, size);
   }
@@ -1446,6 +1446,14 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
     }
 
     RenderText(updateTextType);
+
+    // If there is text changed, callback is called.
+    if(mTextChanged)
+    {
+      Dali::Toolkit::TextEditor handle(GetOwner());
+      mTextChangedSignal.Emit(handle);
+      mTextChanged = false;
+    }
   }
 
   // The text-editor emits signals when the input style changes. These changes of style are
@@ -1661,8 +1669,7 @@ void TextEditor::CaretMoved(unsigned int position)
 
 void TextEditor::TextChanged()
 {
-  Dali::Toolkit::TextEditor handle(GetOwner());
-  mTextChangedSignal.Emit(handle);
+  mTextChanged = true;
 }
 
 void TextEditor::MaxLengthReached()
@@ -1984,7 +1991,8 @@ TextEditor::TextEditor()
   mHasBeenStaged(false),
   mScrollAnimationEnabled(false),
   mScrollBarEnabled(false),
-  mScrollStarted(false)
+  mScrollStarted(false),
+  mTextChanged(false)
 {
 }
 
index 866c444..4c408ca 100644 (file)
@@ -362,7 +362,7 @@ private: // Implementation
    * @param[in] actor The actor to be resized.
    * @param[in] size Size to change.
    */
-  void ResizeActor( Actor& actor, const Vector2& size );
+  void ResizeActor(Actor& actor, const Vector2& size);
 
   /**
    * @brief Render view, create and attach actor(s) to this text editor.
@@ -402,6 +402,7 @@ private: // Data
   bool  mScrollAnimationEnabled : 1;
   bool  mScrollBarEnabled : 1;
   bool  mScrollStarted : 1;
+  bool  mTextChanged : 1;
 
   struct AccessibleImpl : public DevelControl::AccessibleImpl,
                           public virtual Dali::Accessibility::Text,
index 8b60fbe..47b32e9 100644 (file)
@@ -1335,7 +1335,7 @@ float TextField::GetHeightForWidth(float width)
 
 void TextField::ResizeActor(Actor& actor, const Vector2& size)
 {
-  if (actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
+  if(actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
   {
     actor.SetProperty(Actor::Property::SIZE, size);
   }
@@ -1397,6 +1397,14 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
     }
 
     RenderText(updateTextType);
+
+    // If there is text changed, callback is called.
+    if(mTextChanged)
+    {
+      Dali::Toolkit::TextField handle(GetOwner());
+      mTextChangedSignal.Emit(handle);
+      mTextChanged = false;
+    }
   }
 
   // The text-field emits signals when the input style changes. These changes of style are
@@ -1689,8 +1697,7 @@ void TextField::CaretMoved(unsigned int position)
 
 void TextField::TextChanged()
 {
-  Dali::Toolkit::TextField handle(GetOwner());
-  mTextChangedSignal.Emit(handle);
+  mTextChanged = true;
 }
 
 void TextField::MaxLengthReached()
@@ -1867,7 +1874,8 @@ TextField::TextField()
   mAlignmentOffset(0.f),
   mRenderingBackend(DEFAULT_RENDERING_BACKEND),
   mExceedPolicy(Dali::Toolkit::TextField::EXCEED_POLICY_CLIP),
-  mHasBeenStaged(false)
+  mHasBeenStaged(false),
+  mTextChanged(false)
 {
 }
 
index 2fae0bb..07a7a37 100644 (file)
@@ -318,7 +318,7 @@ private: // Implementation
    * @param[in] actor The actor to be resized.
    * @param[in] size Size to change.
    */
-  void ResizeActor( Actor& actor, const Vector2& size );
+  void ResizeActor(Actor& actor, const Vector2& size);
 
   /**
    * @brief Render view, create and attach actor(s) to this Text Field.
@@ -357,6 +357,7 @@ private: // Data
   int   mRenderingBackend;
   int   mExceedPolicy;
   bool  mHasBeenStaged : 1;
+  bool  mTextChanged : 1;
 
 protected:
   struct AccessibleImpl : public DevelControl::AccessibleImpl,