Merge "Previous model height return problem fixed" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 874503d..caefc0c
@@ -67,9 +67,9 @@ namespace Toolkit
 namespace Text
 {
 
-EventData::EventData( DecoratorPtr decorator )
+EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
 : mDecorator( decorator ),
-  mImfManager(),
+  mInputMethodContext( inputMethodContext ),
   mPlaceholderFont( NULL ),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
@@ -106,11 +106,12 @@ EventData::EventData( DecoratorPtr decorator )
   mAllTextSelected( false ),
   mUpdateInputStyle( false ),
   mPasswordInput( false ),
+  mCheckScrollAmount( false ),
   mIsPlaceholderPixelSize( false ),
   mIsPlaceholderElideEnabled( false ),
-  mPlaceholderEllipsisFlag( false )
+  mPlaceholderEllipsisFlag( false ),
+  mShiftSelectionFlag( true )
 {
-  mImfManager = ImfManager::Get();
 }
 
 EventData::~EventData()
@@ -178,7 +179,7 @@ bool Controller::Impl::ProcessInputEvents()
   if( mEventData->mUpdateCursorPosition ||
       mEventData->mUpdateHighlightBox )
   {
-    NotifyImfManager();
+    NotifyInputMethodContext();
   }
 
   // The cursor must also be repositioned after inserts into the model
@@ -327,9 +328,9 @@ bool Controller::Impl::ProcessInputEvents()
   return decoratorUpdated;
 }
 
-void Controller::Impl::NotifyImfManager()
+void Controller::Impl::NotifyInputMethodContext()
 {
-  if( mEventData && mEventData->mImfManager )
+  if( mEventData && mEventData->mInputMethodContext )
   {
     CharacterIndex cursorPosition = GetLogicalCursorPosition();
 
@@ -345,17 +346,17 @@ void Controller::Impl::NotifyImfManager()
       cursorPosition -= numberOfWhiteSpaces;
     }
 
-    mEventData->mImfManager.SetCursorPosition( cursorPosition );
-    mEventData->mImfManager.NotifyCursorPosition();
+    mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
+    mEventData->mInputMethodContext.NotifyCursorPosition();
   }
 }
 
-void Controller::Impl::NotifyImfMultiLineStatus()
+void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
 {
-  if ( mEventData )
+  if ( mEventData && mEventData->mInputMethodContext )
   {
     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
-    mEventData->mImfManager.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
+    mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
   }
 }
 
@@ -810,6 +811,36 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   Length paragraphCharacters = 0u;
 
   CalculateTextUpdateIndices( paragraphCharacters );
+
+  // Check whether the indices for updating the text is valid
+  if ( numberOfCharacters > 0u &&
+       ( mTextUpdateInfo.mParagraphCharacterIndex >= numberOfCharacters ||
+         mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
+  {
+    std::string currentText;
+    Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
+
+    DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
+    DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
+
+    // Dump mTextUpdateInfo
+    DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
+
+    return false;
+  }
+
   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
 
   if( mTextUpdateInfo.mClearAll ||
@@ -888,7 +919,7 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       TextAbstraction::FontDescription defaultFontDescription;
       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
 
-      if( IsShowingPlaceholderText() && ( NULL != mEventData->mPlaceholderFont ) )
+      if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
       {
         // If the placeholder font is set specifically, only placeholder font is changed.
         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
@@ -1144,7 +1175,7 @@ float Controller::Impl::GetDefaultFontLineHeight()
 
 void Controller::Impl::OnCursorKeyEvent( const Event& event )
 {
-  if( NULL == mEventData )
+  if( NULL == mEventData || !IsShowingRealText() )
   {
     // Nothing to do if there is no text input.
     return;
@@ -1159,14 +1190,28 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   {
     if( mEventData->mPrimaryCursorPosition > 0u )
     {
-      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
+      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
+      {
+        mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
+      }
     }
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
     if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
     {
-      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
+      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
+      {
+        mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
+      }
     }
   }
   else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
@@ -1251,7 +1296,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
     mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
   }
 
-  if ( isShiftModifier && IsShowingRealText() )
+  if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
   {
     // Handle text selection
     bool selecting = false;
@@ -1274,11 +1319,11 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
 
     if ( selecting )
     {
-      // Notify the cursor position to the imf manager.
-      if( mEventData->mImfManager )
+      // Notify the cursor position to the InputMethodContext.
+      if( mEventData->mInputMethodContext )
       {
-        mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
-        mEventData->mImfManager.NotifyCursorPosition();
+        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mInputMethodContext.NotifyCursorPosition();
       }
 
       ChangeState( EventData::SELECTING );
@@ -1350,11 +1395,11 @@ void Controller::Impl::OnTapEvent( const Event& event )
       mEventData->mScrollAfterUpdatePosition = true;
       mEventData->mUpdateInputStyle = true;
 
-      // Notify the cursor position to the imf manager.
-      if( mEventData->mImfManager )
+      // Notify the cursor position to the InputMethodContext.
+      if( mEventData->mInputMethodContext )
       {
-        mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
-        mEventData->mImfManager.NotifyCursorPosition();
+        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mInputMethodContext.NotifyCursorPosition();
       }
     }
     else if( 2u == tapCount )
@@ -1940,6 +1985,8 @@ void Controller::Impl::RepositionSelectionHandles()
   if( selectionStart == selectionEnd )
   {
     // Nothing to select if handles are in the same place.
+    // So, deactive Highlight box.
+    mEventData->mDecorator->SetHighlightActive( false );
     return;
   }
 
@@ -2291,7 +2338,7 @@ void Controller::Impl::RepositionSelectionHandles()
   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
 
-  mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize );
+  mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
 
   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
   {
@@ -2318,9 +2365,6 @@ void Controller::Impl::RepositionSelectionHandles()
                                          secondaryCursorInfo.lineHeight );
   }
 
-  // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
-  mEventData->mPrimaryCursorPosition = ( indicesSwapped ) ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
-
   // Set the flag to update the decorator.
   mEventData->mDecoratorUpdated = true;
 }
@@ -2373,13 +2417,16 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY,
     mEventData->mUpdateRightSelectionPosition = true;
     mEventData->mUpdateHighlightBox = true;
 
-    // It may happen an IMF commit event arrives before the selection event
-    // if the IMF manager is in pre-edit state. The commit event will set the
+    // It may happen an InputMethodContext commit event arrives before the selection event
+    // if the InputMethodContext is in pre-edit state. The commit event will set the
     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
     // to false, the highlight box won't be updated.
     mEventData->mUpdateCursorPosition = false;
 
     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
+
+    // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
+    mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
   }
   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
   {
@@ -2501,8 +2548,11 @@ void Controller::Impl::ChangeState( EventData::State newState )
         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
         mEventData->mDecorator->StopCursorBlink();
         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        }
         mEventData->mDecorator->SetHighlightActive( true );
         if( mEventData->mGrabHandlePopupEnabled )
         {
@@ -2546,7 +2596,7 @@ void Controller::Impl::ChangeState( EventData::State newState )
           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
           mEventData->mDecorator->SetHighlightActive( false );
         }
-        else
+        else if ( mEventData->mGrabHandleEnabled )
         {
           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
         }
@@ -2568,7 +2618,10 @@ void Controller::Impl::ChangeState( EventData::State newState )
           mEventData->mDecorator->StartCursorBlink();
         }
         // Grab handle is not shown until a tap is received whilst EDITING
-        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHighlightActive( false );
@@ -2584,8 +2637,11 @@ void Controller::Impl::ChangeState( EventData::State newState )
         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
         mEventData->mDecorator->StopCursorBlink();
         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        }
         mEventData->mDecorator->SetHighlightActive( true );
         if( mEventData->mGrabHandlePopupEnabled )
         {
@@ -2603,7 +2659,10 @@ void Controller::Impl::ChangeState( EventData::State newState )
         {
           mEventData->mDecorator->StartCursorBlink();
         }
-        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHighlightActive( false );
@@ -2624,7 +2683,10 @@ void Controller::Impl::ChangeState( EventData::State newState )
           mEventData->mDecorator->StartCursorBlink();
         }
 
-        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
         mEventData->mDecorator->SetHighlightActive( false );
@@ -2711,6 +2773,13 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
   Text::GetCursorPosition( parameters,
                            cursorInfo );
 
+  // Adds Outline offset.
+  const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
+  cursorInfo.primaryPosition.x += outlineWidth;
+  cursorInfo.primaryPosition.y += outlineWidth;
+  cursorInfo.secondaryPosition.x += outlineWidth;
+  cursorInfo.secondaryPosition.y += outlineWidth;
+
   if( isMultiLine )
   {
     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.