Merge "Add ENABLE_SHIFT_SELECTION property" into devel/master
authorHyunJu Shin <hyunjushin@samsung.com>
Tue, 19 Dec 2017 07:30:35 +0000 (07:30 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Tue, 19 Dec 2017 07:30:35 +0000 (07:30 +0000)
1  2 
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-toolkit/devel-api/file.list
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller.cpp

@@@ -99,6 -99,7 +99,7 @@@ const char* const PROPERTY_NAME_PLACEHO
  const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR               = "placeholderTextColor";
  const char* const PROPERTY_NAME_ENABLE_SELECTION                     = "enableSelection";
  const char* const PROPERTY_NAME_PLACEHOLDER                          = "placeholder";
+ const char* const PROPERTY_NAME_ENABLE_SHIFT_SELECTION               = "enableShiftSelection";
  
  const int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
  
@@@ -314,38 -315,9 +315,38 @@@ bool DaliTestCheckMaps( const Property:
  
        if( NULL != valueSet )
        {
 -        if( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() )
 +        if( valueSet->GetType() == Dali::Property::STRING && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
          {
 -          tet_printf( "  Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
 +          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::BOOLEAN && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
 +        {
 +          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::INTEGER && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
 +        {
 +          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::FLOAT && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
 +        {
 +          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::VECTOR2 && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
 +        {
 +          Vector2 vector2Get = valueGet.second.Get<Vector2>();
 +          Vector2 vector2Set = valueSet->Get<Vector2>();
 +          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::VECTOR4 && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
 +        {
 +          Vector4 vector4Get = valueGet.second.Get<Vector4>();
 +          Vector4 vector4Set = valueSet->Get<Vector4>();
 +          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
            return false;
          }
        }
@@@ -536,6 -508,7 +537,7 @@@ int UtcDaliTextEditorGetPropertyP(void
    DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER ) == TextEditor::Property::PLACEHOLDER );
    DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT ) == DevelTextEditor::Property::PLACEHOLDER_TEXT );
    DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR ) == DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR );
+   DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_SHIFT_SELECTION ) == DevelTextEditor::Property::ENABLE_SHIFT_SELECTION );
  
    END_TEST;
  }
@@@ -814,6 -787,8 +816,6 @@@ int UtcDaliTextEditorSetPropertyP(void
  
    editor.SetProperty( TextEditor::Property::OUTLINE, outlineMapSet );
  
 -  outlineMapSet["color"] = "red";
 -  outlineMapSet["width"] = "2";
    outlineMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::OUTLINE );
    DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
    DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
@@@ -2175,6 -2150,52 +2177,52 @@@ int utcDaliTextEditorEvent07(void
  
    DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
  
+   // Disable Shift Selection
+   editor.SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false );
+   // Test to select some text in the right of the current cursor position
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   // Render and notify
+   application.SendNotification();
+   application.Render();
+   // Cut the selected text
+   application.ProcessEvent( GenerateKey( "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "x", "x", KEY_X_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   // Render and notify
+   application.SendNotification();
+   application.Render();
+   // The text isn't selected and not changed because of 'SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false )'
+   DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+   // Test to select some text in the left of the current cursor position
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   // Render and notify
+   application.SendNotification();
+   application.Render();
+   // Copy the selected text
+   application.ProcessEvent( GenerateKey( "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   application.ProcessEvent( GenerateKey( "c", "c", KEY_C_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+   // Render and notify
+   application.SendNotification();
+   application.Render();
+   // The text is not selected and not changed because of 'SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false )'
+   DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
    END_TEST;
  }
  
@@@ -2510,3 -2531,31 +2558,31 @@@ int UtcDaliTextEditorSetPaddingProperty
  
    END_TEST;
  }
+ int UtcDaliTextEditorEnableShiftSelectionProperty(void)
+ {
+   ToolkitTestApplication application;
+   tet_infoline("UtcDaliTextEditorEnableShiftSelectionProperty");
+   TextEditor editor = TextEditor::New();
+   DALI_TEST_CHECK( editor );
+   editor.SetSize( 300.f, 50.f );
+   editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+   editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+   Stage::GetCurrent().Add( editor );
+   application.SendNotification();
+   application.Render();
+   // The default value of ENABLE_SHIFT_SELECTION is 'true'.
+   DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION ), true, TEST_LOCATION );
+   // Check the enable shift selection property
+   editor.SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false );
+   DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION ), false, TEST_LOCATION );
+   application.SendNotification();
+   application.Render();
+   END_TEST;
+ }
@@@ -27,6 -27,7 +27,7 @@@
  #include <dali/integration-api/events/long-press-gesture-event.h>
  #include <dali-toolkit-test-suite-utils.h>
  #include <dali-toolkit/dali-toolkit.h>
+ #include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
  #include "toolkit-clipboard.h"
  
  using namespace Dali;
@@@ -99,6 -100,7 +100,7 @@@ const char* const PROPERTY_NAME_PIXEL_S
  const char* const PROPERTY_NAME_ENABLE_SELECTION                     = "enableSelection";
  const char* const PROPERTY_NAME_PLACEHOLDER                          = "placeholder";
  const char* const PROPERTY_NAME_ELLIPSIS                             = "ellipsis";
+ const char* const PROPERTY_NAME_ENABLE_SHIFT_SELECTION               = "enableShiftSelection";
  
  const int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
  
@@@ -329,65 -331,39 +331,65 @@@ bool DaliTestCheckMaps( const Property:
      {
        const KeyValuePair& valueGet = fontStyleMapGet.GetKeyValue( index );
  
 -      if( valueGet.first.type == Property::Key::STRING )
 +      Property::Value* valueSet = NULL;
 +      if ( valueGet.first.type == Property::Key::INDEX )
        {
 -        Property::Value* valueSet = fontStyleMapSet.Find( valueGet.first.stringKey );
 -        if( NULL != valueSet )
 +        valueSet = fontStyleMapSet.Find( valueGet.first.indexKey );
 +      }
 +      else
 +      {
 +        // Get Key is a string so searching Set Map for a string key
 +        valueSet = fontStyleMapSet.Find( valueGet.first.stringKey );
 +      }
 +
 +      if( NULL != valueSet )
 +      {
 +        if( valueSet->GetType() == Dali::Property::STRING && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
          {
 -          if( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() )
 -          {
 -            tet_printf( "  Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
 -            return false;
 -          }
 +          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
 +          return false;
          }
 -        else
 +        else if( valueSet->GetType() == Dali::Property::BOOLEAN && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
          {
 -          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
 +          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::INTEGER && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
 +        {
 +          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::FLOAT && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
 +        {
 +          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::VECTOR2 && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
 +        {
 +          Vector2 vector2Get = valueGet.second.Get<Vector2>();
 +          Vector2 vector2Set = valueSet->Get<Vector2>();
 +          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
 +          return false;
 +        }
 +        else if( valueSet->GetType() == Dali::Property::VECTOR4 && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
 +        {
 +          Vector4 vector4Get = valueGet.second.Get<Vector4>();
 +          Vector4 vector4Set = valueSet->Get<Vector4>();
 +          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
            return false;
          }
        }
        else
        {
 -        Property::Value* valueSet = fontStyleMapSet.Find( valueGet.first.indexKey );
 -        if( NULL != valueSet )
 +        if ( valueGet.first.type == Property::Key::INDEX )
          {
 -          if( valueGet.second.Get<int>() != valueSet->Get<int>() )
 -          {
 -            tet_printf( "  Integer Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
 -            return false;
 -          }
 +          tet_printf( "  The key %d doesn't exist.", valueGet.first.indexKey );
          }
          else
          {
 -          tet_printf( "  The Int key %d doesn't exist.", valueGet.first.indexKey );
 -          return false;
 +          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
          }
 +        return false;
        }
      }
    }
@@@ -539,6 -515,7 +541,7 @@@ int UtcDaliTextFieldGetPropertyP(void
    DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_SELECTION ) == TextField::Property::ENABLE_SELECTION );
    DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER ) == TextField::Property::PLACEHOLDER );
    DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS ) == TextField::Property::ELLIPSIS );
+   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_SHIFT_SELECTION ) == DevelTextField::Property::ENABLE_SHIFT_SELECTION );
  
    END_TEST;
  }
@@@ -869,6 -846,8 +872,6 @@@ int UtcDaliTextFieldSetPropertyP(void
  
    field.SetProperty( TextField::Property::OUTLINE, outlineMapSet );
  
 -  outlineMapSet["color"] = "red";
 -  outlineMapSet["width"] = "2";
    outlineMapGet = field.GetProperty<Property::Map>( TextField::Property::OUTLINE );
    DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
    DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
@@@ -2747,3 -2726,31 +2750,31 @@@ int UtcDaliTextFieldSetPaddingProperty(
  
    END_TEST;
  }
+ int UtcDaliTextFieldEnableShiftSelectionProperty(void)
+ {
+   ToolkitTestApplication application;
+   tet_infoline("UtcDaliTextFieldEnableShiftSelectionProperty");
+   TextField field = TextField::New();
+   DALI_TEST_CHECK( field );
+   field.SetSize( 300.f, 50.f );
+   field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+   field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+   Stage::GetCurrent().Add( field );
+   application.SendNotification();
+   application.Render();
+   // The default value of ENABLE_SHIFT_SELECTION is 'true'.
+   DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_SHIFT_SELECTION ), true, TEST_LOCATION );
+   // Check the enable shift selection property
+   field.SetProperty( DevelTextField::Property::ENABLE_SHIFT_SELECTION, false );
+   DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_SHIFT_SELECTION ), false, TEST_LOCATION );
+   application.SendNotification();
+   application.Render();
+   END_TEST;
+ }
@@@ -28,6 -28,7 +28,6 @@@ devel_api_src_files = 
    $(devel_api_src_dir)/image-loader/async-image-loader-devel.cpp \
    $(devel_api_src_dir)/image-loader/atlas-upload-observer.cpp \
    $(devel_api_src_dir)/image-loader/image-atlas.cpp \
 -  $(devel_api_src_dir)/image-loader/texture-manager.cpp \
    $(devel_api_src_dir)/scripting/script.cpp \
    $(devel_api_src_dir)/styling/style-manager-devel.cpp \
    $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \
@@@ -93,7 -94,6 +93,7 @@@ devel_api_visuals_header_files = 
    $(devel_api_src_dir)/visuals/image-visual-properties-devel.h \
    $(devel_api_src_dir)/visuals/image-visual-actions-devel.h \
    $(devel_api_src_dir)/visuals/animated-gradient-visual-properties-devel.h \
 +  $(devel_api_src_dir)/visuals/text-visual-properties-devel.h \
    $(devel_api_src_dir)/visuals/visual-properties-devel.h
  
  devel_api_shadow_view_header_files = \
@@@ -106,7 -106,8 +106,7 @@@ devel_api_focus_manager_header_files = 
  devel_api_image_loader_header_files = \
    $(devel_api_src_dir)/image-loader/async-image-loader-devel.h \
    $(devel_api_src_dir)/image-loader/atlas-upload-observer.h \
 -  $(devel_api_src_dir)/image-loader/image-atlas.h \
 -  $(devel_api_src_dir)/image-loader/texture-manager.h
 +  $(devel_api_src_dir)/image-loader/image-atlas.h
  
  devel_api_scripting_header_files = \
    $(devel_api_src_dir)/scripting/script.h \
@@@ -128,6 -129,7 +128,7 @@@ devel_api_super_blur_view_header_files 
  
  devel_api_text_controls_header_files = \
    $(devel_api_src_dir)/controls/text-controls/text-editor-devel.h \
+   $(devel_api_src_dir)/controls/text-controls/text-field-devel.h \
    $(devel_api_src_dir)/controls/text-controls/text-label-devel.h \
    $(devel_api_src_dir)/controls/text-controls/text-selection-popup.h \
    $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.h
@@@ -108,7 -108,8 +108,8 @@@ EventData::EventData( DecoratorPtr deco
    mPasswordInput( false ),
    mIsPlaceholderPixelSize( false ),
    mIsPlaceholderElideEnabled( false ),
-   mPlaceholderEllipsisFlag( false )
+   mPlaceholderEllipsisFlag( false ),
+   mShiftSelectionFlag( true )
  {
    mImfManager = ImfManager::Get();
  }
@@@ -1251,7 -1252,7 +1252,7 @@@ void Controller::Impl::OnCursorKeyEvent
      mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
    }
  
-   if ( isShiftModifier && IsShowingRealText() )
+   if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
    {
      // Handle text selection
      bool selecting = false;
@@@ -2291,7 -2292,7 +2292,7 @@@ void Controller::Impl::RepositionSelect
    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() )
    {
@@@ -2711,13 -2712,6 +2712,13 @@@ void Controller::Impl::GetCursorPositio
    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.
@@@ -466,6 -466,16 +466,16 @@@ bool Controller::IsSelectionEnabled() c
    return mImpl->mEventData->mSelectionEnabled;
  }
  
+ void Controller::SetShiftSelectionEnabled( bool enabled )
+ {
+   mImpl->mEventData->mShiftSelectionFlag = enabled;
+ }
+ bool Controller::IsShiftSelectionEnabled() const
+ {
+   return mImpl->mEventData->mShiftSelectionFlag;
+ }
  // public : Update
  
  void Controller::SetText( const std::string& text )
@@@ -3387,7 -3397,7 +3397,7 @@@ bool Controller::DoRelayout( const Size
      const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
      const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
      const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
 -    float outlineWidth = mImpl->mModel->GetOutlineWidth();
 +    const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
  
      // Set the layout parameters.
      Layout::Parameters layoutParameters( size,