Added TextChanged signal to TextField 01/40501/6
authorPaul Wisbey <p.wisbey@samsung.com>
Thu, 4 Jun 2015 10:57:59 +0000 (11:57 +0100)
committerPaul Wisbey <p.wisbey@samsung.com>
Thu, 4 Jun 2015 13:38:23 +0000 (14:38 +0100)
Change-Id: I7e0560b289d321db65d3a71de273b407c2f1f0f5

automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/text/text-control-interface.h
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/public-api/controls/text-controls/text-field.cpp
dali-toolkit/public-api/controls/text-controls/text-field.h

index a8be49e..d19b3a1 100644 (file)
@@ -55,11 +55,19 @@ const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decoration-bounding-b
 const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT    = "horizontal-alignment";
 const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT      = "vertical-alignment";
 
+static bool gTextChangedCallBackCalled;
 static bool gMaxCharactersCallBackCalled;
 
+static void TestTextChangedCallback( TextField control )
+{
+  tet_infoline(" TestTextChangedCallback");
+
+  gTextChangedCallBackCalled = true;
+}
+
 static void TestMaxLengthReachedCallback( TextField control )
 {
-  tet_infoline(" TestMaxLengthReachedCallbackCallback");
+  tet_infoline(" TestMaxLengthReachedCallback");
 
   gMaxCharactersCallBackCalled = true;
 }
@@ -332,6 +340,60 @@ int utcDaliTextFieldAtlasRenderP(void)
   END_TEST;
 }
 
+// Positive test for the text-changed signal.
+int utcDaliTextFieldTextChangedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add(field);
+
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::TEXT, "ABC" );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  application.SendNotification();
+
+  field.SetKeyInputFocus();
+
+  Dali::Integration::KeyEvent keyevent;
+  keyevent.keyName = "D";
+  keyevent.keyString = "D";
+  keyevent.keyCode = 0;
+  keyevent.keyModifier = 0;
+  keyevent.time = 0;
+  keyevent.state = Integration::KeyEvent::Down;
+
+  gTextChangedCallBackCalled = false;
+  application.ProcessEvent( keyevent );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
+// Negative test for the text-changed signal.
+int utcDaliTextFieldTextChangedN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedN");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add(field);
+
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT
+  DALI_TEST_CHECK( ! gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
 // Positive test for Max Characters reached signal.
 int utcDaliTextFieldMaxCharactersReachedP(void)
 {
index 11ec5c2..753d347 100644 (file)
@@ -119,6 +119,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-highlight-color",
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "decoration-bounding-box",              RECTANGLE, DECORATION_BOUNDING_BOX              )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "input-method-settings",                MAP,       INPUT_METHOD_SETTINGS                )
 
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "text-changed",       SIGNAL_TEXT_CHANGED )
 DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "max-length-reached", SIGNAL_MAX_LENGTH_REACHED )
 
 DALI_TYPE_REGISTRATION_END()
@@ -825,7 +826,11 @@ bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface*
   bool connected( true );
   Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
 
-  if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_CHANGED ) )
+  {
+    field.TextChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
   {
     field.MaxLengthReachedSignal().Connect( tracker, functor );
   }
@@ -838,6 +843,11 @@ bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface*
   return connected;
 }
 
+Toolkit::TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return mTextChangedSignal;
+}
+
 Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
 {
   return mMaxLengthReachedSignal;
@@ -1032,6 +1042,12 @@ void TextField::RequestTextRelayout()
   RelayoutRequest();
 }
 
+void TextField::TextChanged()
+{
+  Dali::Toolkit::TextField handle( GetOwner() );
+  mTextChangedSignal.Emit( handle );
+}
+
 void TextField::MaxLengthReached()
 {
   Dali::Toolkit::TextField handle( GetOwner() );
index 5e0df24..85b88e2 100644 (file)
@@ -80,6 +80,11 @@ public:
   static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
 
   /**
+   * @copydoc TextField::TextChangedSignal()
+   */
+  Toolkit::TextField::TextChangedSignalType&  TextChangedSignal();
+
+  /**
    * @copydoc TextField::MaxLengthReachedSignal()
    */
   Toolkit::TextField::MaxLengthReachedSignalType&  MaxLengthReachedSignal();
@@ -147,6 +152,11 @@ private: // From Control
   virtual void RequestTextRelayout();
 
   /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
    * @copydoc Text::ControlInterface::MaxLengthReached()
    */
   virtual void MaxLengthReached();
@@ -193,6 +203,7 @@ private: // Implementation
 private: // Data
 
   // Signals
+  Toolkit::TextField::TextChangedSignalType mTextChangedSignal;
   Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal;
 
   Text::ControllerPtr mController;
index 35761df..004609f 100644 (file)
@@ -494,6 +494,11 @@ void TextLabel::RequestTextRelayout()
   RelayoutRequest();
 }
 
+void TextLabel::TextChanged()
+{
+  // TextLabel does not provide a signal for this
+}
+
 void TextLabel::MaxLengthReached()
 {
   // Pure Virtual from TextController Interface, only needed when inputting text
index 3e0fd35..54b30dd 100644 (file)
@@ -98,6 +98,11 @@ private: // From Control
   virtual void RequestTextRelayout();
 
   /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
    * @copydoc Text::ControlInterface::MaxLengthReached()
    */
   virtual void MaxLengthReached();
index d7ed8f4..e485be9 100644 (file)
@@ -50,6 +50,11 @@ public:
   virtual void RequestTextRelayout() = 0;
 
   /**
+   * @brief Called to signal that text has been inserted or deleted.
+   */
+  virtual void TextChanged() = 0;
+
+  /**
    * @brief Called when the number of characters to be inserted exceeds the maximum limit
    */
   virtual void MaxLengthReached() = 0;
index 3020e67..ab2764c 100644 (file)
@@ -231,6 +231,12 @@ struct Controller::Impl
    */
   void QueueModifyEvent( ModifyEvent::Type type )
   {
+    if( ModifyEvent::TEXT_REPLACED == type)
+    {
+      // Cancel previously queued inserts etc.
+      mModifyEvents.clear();
+    }
+
     ModifyEvent event;
     event.type = type;
     mModifyEvents.push_back( event );
index e07e29c..889ca68 100644 (file)
@@ -73,9 +73,6 @@ void Controller::EnableTextInput( DecoratorPtr decorator )
 
 void Controller::SetText( const std::string& text )
 {
-  // Cancel previously queued inserts etc.
-  mImpl->mModifyEvents.clear();
-
   // Remove the previously set text
   ResetText();
 
@@ -126,6 +123,9 @@ void Controller::SetText( const std::string& text )
 
   // Reset keyboard as text changed
   mImpl->ResetImfManager();
+
+  // Do this last since it provides callbacks into application code
+  mImpl->mControlInterface.TextChanged();
 }
 
 void Controller::GetText( std::string& text ) const
@@ -1089,6 +1089,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
 {
   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
 
+  bool textChanged( false );
+
   if( mImpl->mEventData &&
       keyEvent.state == KeyEvent::Down )
   {
@@ -1131,6 +1133,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
         {
           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
         }
+
+        textChanged = true;
       }
     }
     else
@@ -1141,6 +1145,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->ClearPreEditFlag();
 
       InsertText( keyString, COMMIT );
+
+      textChanged = true;
     }
 
     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
@@ -1148,6 +1154,12 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
     mImpl->RequestRelayout();
   }
 
+  if( textChanged )
+  {
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.TextChanged();
+  }
+
   return false;
 }
 
@@ -1261,9 +1273,10 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
 
-    mImpl->mControlInterface.MaxLengthReached();
-
     mImpl->ResetImfManager();
+
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.MaxLengthReached();
   }
 }
 
@@ -1432,6 +1445,9 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
   {
     mImpl->mOperationsPending = ALL_OPERATIONS;
     mImpl->RequestRelayout();
+
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.TextChanged();
   }
 
   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
@@ -1453,9 +1469,6 @@ void Controller::ShowPlaceholderText()
 
     mImpl->mEventData->mIsShowingPlaceholderText = true;
 
-    // Cancel previously queued inserts etc.
-    mImpl->mModifyEvents.clear();
-
     // Disable handles when showing place-holder text
     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
index 5340137..3a833f3 100644 (file)
@@ -59,6 +59,11 @@ TextField TextField::DownCast( BaseHandle handle )
   return Control::DownCast<TextField, Internal::TextField>(handle);
 }
 
+TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).TextChangedSignal();
+}
+
 TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
 {
   return Dali::Toolkit::GetImpl( *this ).MaxLengthReachedSignal();
index 1f6df9b..4f3da41 100644 (file)
@@ -38,6 +38,7 @@ class TextField;
  *  * Signals
  * | %Signal Name           | Method                                              |
  * |------------------------|-----------------------------------------------------|
+ * | text-changed           | @ref TextChangedSignal()                            |
  * | max-length-reached     | @ref MaxLengthReachedSignal()                       |
  *
  */
@@ -109,6 +110,7 @@ public:
   // Type Defs
 
   /// @brief Max Characters Exceed signal type;
+  typedef Signal<void ( TextField ) > TextChangedSignalType;
   typedef Signal<void ( TextField ) > MaxLengthReachedSignalType;
 
   /**
@@ -158,6 +160,17 @@ public:
   // Signals
 
   /**
+   * @brief This signal is emitted when the text changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TextField textField );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  TextChangedSignalType& TextChangedSignal();
+
+  /**
    * @brief This signal is emitted when inserted text exceeds the maximum character limit.
    *
    * A callback of the following type may be connected: