[AT-SPI] Fix role setting
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / table-view / table-view-impl.cpp
old mode 100644 (file)
new mode 100755 (executable)
index b616fcf..4f27bba
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
 #include <dali/integration-api/debug.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
 using namespace Dali;
 
 namespace
@@ -47,7 +51,7 @@ bool FitToChild( Actor actor, Dimension::Type dimension )
 // currently not called from code so compiler will optimize these away, kept here for future debugging
 
 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
-#define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
+#define TV_LOG(fmt, args,...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
 //#define TABLEVIEW_DEBUG 1
 
 #if defined(TABLEVIEW_DEBUG)
@@ -65,7 +69,7 @@ void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
       if( data.actor )
       {
         actor = 'A';
-        actorName = data.actor.GetName();
+        actorName = data.actor.GetProperty< std::string >( Dali::Actor::Property::NAME );
       }
       TV_LOG("Array[%d,%d]=%c %s %d,%d,%d,%d  ", i, j, actor, actorName.c_str(),
           data.position.rowIndex, data.position.columnIndex,
@@ -134,8 +138,8 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cellPadding",    VECTOR2, CELL_
 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutRows",     MAP,     LAYOUT_ROWS    )
 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutColumns",  MAP,     LAYOUT_COLUMNS )
 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellIndex",                VECTOR2, CELL_INDEX                )
-DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "rowSpan",                  FLOAT,   ROW_SPAN                  )
-DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan",               FLOAT,   COLUMN_SPAN               )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "rowSpan",                  INTEGER, ROW_SPAN                  )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan",               INTEGER, COLUMN_SPAN               )
 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellHorizontalAlignment",  STRING,  CELL_HORIZONTAL_ALIGNMENT )
 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellVerticalAlignment",    STRING,  CELL_VERTICAL_ALIGNMENT   )
 
@@ -749,15 +753,15 @@ void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension )
 
     // update every column position in ColumnData array
     float cumulatedWidth = 0.0f;
-    for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
+    for( auto&& element : mColumnData )
     {
-      if( mColumnData[ column ].sizePolicy == Toolkit::TableView::FILL ||  mColumnData[ column ].sizePolicy == Toolkit::TableView::RELATIVE)
+      if( element.sizePolicy == Toolkit::TableView::FILL || element.sizePolicy == Toolkit::TableView::RELATIVE )
       {
-        mColumnData[ column ].size = mColumnData[ column ].fillRatio * remainingSize;
+        element.size = element.fillRatio * remainingSize;
       }
 
-      cumulatedWidth += mColumnData[ column ].size;
-      mColumnData[column].position = cumulatedWidth;
+      cumulatedWidth += element.size;
+      element.position = cumulatedWidth;
     }
 
     mColumnDirty = false;
@@ -795,11 +799,25 @@ void TableView::OnSizeSet( const Vector3& size )
   // rows and columns must be recalculated or the new size will not take effect.
   mRowDirty = mColumnDirty = true;
   RelayoutRequest();
+
+  Control::OnSizeSet( size );
 }
 
 void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
 {
   // Go through the layout data
+  float totalWidth = 0.0;
+
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>() );
+
+  if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+  {
+    for (auto&& element : mColumnData)
+    {
+      totalWidth += element.size;
+    }
+  }
+
   for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
   {
     for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
@@ -814,41 +832,54 @@ void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
       if( actor &&  position.rowIndex == row && position.columnIndex == column )
       {
         // Anchor actor to top left of the cell
-        actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-        actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+        if( actor.GetProperty( Actor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+        {
+          actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+        }
+        actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+
+        Padding padding = actor.GetProperty<Vector4>( Actor::Property::PADDING );
 
-        Padding padding;
-        actor.GetPadding( padding );
+        float left = (column > 0) ? mColumnData[column - 1].position : 0.f;
+        float right;
+
+        if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+        {
+          right = totalWidth - left;
+          left = right - mColumnData[column].size;
+        }
+        else
+        {
+          right = left + mColumnData[column].size;
+        }
 
-        float left = column > 0 ? mColumnData[column-1].position : 0.f;
-        float right = mColumnData[column+position.columnSpan-1].position;
         float top = row > 0 ? mRowData[row-1].position : 0.f;
         float bottom = mRowData[row+position.rowSpan-1].position;
 
         if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
         {
-          actor.SetX( left + mPadding.width + padding.left );
+          actor.SetProperty( Actor::Property::POSITION_X,  left + mPadding.width + padding.left );
         }
         else if( cellData.horizontalAlignment ==  HorizontalAlignment::RIGHT )
         {
-          actor.SetX( right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
+          actor.SetProperty( Actor::Property::POSITION_X,  right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
         }
         else //if( cellData.horizontalAlignment ==  HorizontalAlignment::CENTER )
         {
-          actor.SetX( (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
+          actor.SetProperty( Actor::Property::POSITION_X,  (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
         }
 
         if( cellData.verticalAlignment == VerticalAlignment::TOP )
         {
-          actor.SetY( top + mPadding.height + padding.top );
+          actor.SetProperty( Actor::Property::POSITION_Y,  top + mPadding.height + padding.top );
         }
         else if( cellData.verticalAlignment == VerticalAlignment::BOTTOM )
         {
-          actor.SetY( bottom - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
+          actor.SetProperty( Actor::Property::POSITION_Y,  bottom - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
         }
         else //if( cellData.verticalAlignment = VerticalAlignment::CENTER )
         {
-          actor.SetY( (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
+          actor.SetProperty( Actor::Property::POSITION_Y,  (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
         }
       }
     }
@@ -961,98 +992,101 @@ Property::Value TableView::GetProperty( BaseObject* object, Property::Index inde
 
 void TableView::OnChildAdd( Actor& child )
 {
-  Control::OnChildAdd( child );
-
-  if( mLayoutingChild )
+  if( ! mLayoutingChild )
   {
-    // we're in the middle of laying out children so no point doing anything here
-    return;
-  }
+    // Ensure we're not in the middle of laying out children
 
-  // Check child properties on actor to decide its position inside the table
-  HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
-  VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
+    // Check child properties on actor to decide its position inside the table
+    HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
+    VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
 
-  if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ) != Property::NONE )
-  {
-    std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ).Get<std::string >();
-    Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
-                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE,
-                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
-                                                            horizontalAlignment );
-  }
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ) != Property::NONE )
+    {
+      std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ).Get<std::string >();
+      Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
+                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                              horizontalAlignment );
+    }
 
-  if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ) != Property::NONE )
-  {
-    std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ).Get<std::string >();
-    Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
-                                                          VERTICAL_ALIGNMENT_STRING_TABLE,
-                                                          VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
-                                                          verticalAlignment );
-  }
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ) != Property::NONE )
+    {
+      std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ).Get<std::string >();
+      Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
+                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                            verticalAlignment );
+    }
 
-  Toolkit::TableView::CellPosition cellPosition;
-  if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE )
-  {
-    cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get<float>() );
-  }
+    Toolkit::TableView::CellPosition cellPosition;
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE )
+    {
+      cellPosition.rowSpan = child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get< int >();
+    }
 
-  if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE )
-  {
-    cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get<float>() );
-  }
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE )
+    {
+      cellPosition.columnSpan = child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get< int >();
+    }
 
-  if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_INDEX ) != Property::NONE )
-  {
-    Vector2 indices = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_INDEX ).Get<Vector2 >();
-    cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
-    cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_INDEX ) != Property::NONE )
+    {
+      Vector2 indices = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_INDEX ).Get<Vector2 >();
+      cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
+      cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
 
-    AddChild( child, cellPosition );
-    SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
+      AddChild( child, cellPosition );
+      SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
+    }
+    else
+    {
+      bool availableCellFound = false;
 
-    // Do not continue
-    return;
-  }
+      // Find the first available cell to store the actor in
+      const unsigned int rowCount = mCellData.GetRows();
+      const unsigned int columnCount = mCellData.GetColumns();
+      for( unsigned int row = 0; row < rowCount && !availableCellFound; ++row )
+      {
+        for( unsigned int column = 0; column < columnCount && !availableCellFound; ++column )
+        {
+          if( !(mCellData[ row ][ column ].actor) )
+          {
+            // Put the actor in the cell
+            CellData data;
+            data.actor = child;
+            data.position.columnIndex = column;
+            data.position.rowIndex = row;
+            data.horizontalAlignment = horizontalAlignment;
+            data.verticalAlignment = verticalAlignment;
+            mCellData[ row ][ column ] = data;
+
+            availableCellFound = true;
+            break;
+          }
+        }
+      }
 
-  // Find the first available cell to store the actor in
-  const unsigned int rowCount = mCellData.GetRows();
-  const unsigned int columnCount = mCellData.GetColumns();
-  for( unsigned int row = 0; row < rowCount; ++row )
-  {
-    for( unsigned int column = 0; column < columnCount; ++column )
-    {
-      if( !(mCellData[ row ][ column ].actor) )
+      if( ! availableCellFound )
       {
-        // Put the actor in the cell
+        // No empty cells, so increase size of the table
+        unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
+        ResizeContainers( rowCount + 1, newColumnCount );
+
+        // Put the actor in the first cell of the new row
         CellData data;
         data.actor = child;
-        data.position.columnIndex = column;
-        data.position.rowIndex = row;
+        data.position.rowIndex = rowCount;
+        data.position.columnIndex = 0;
         data.horizontalAlignment = horizontalAlignment;
         data.verticalAlignment = verticalAlignment;
-        mCellData[ row ][ column ] = data;
-
-        // Don't continue
-        RelayoutRequest();
-        return;
+        mCellData[ rowCount ][ 0 ] = data;
       }
+
+      RelayoutRequest();
     }
   }
 
-  // No empty cells, so increase size of the table
-  unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
-  ResizeContainers( rowCount + 1, newColumnCount );
-
-  // Put the actor in the first cell of the new row
-  CellData data;
-  data.actor = child;
-  data.position.rowIndex = rowCount;
-  data.position.columnIndex = 0;
-  data.horizontalAlignment = horizontalAlignment;
-  data.verticalAlignment = verticalAlignment;
-  mCellData[ rowCount ][ 0 ] = data;
-  RelayoutRequest();
+  Control::OnChildAdd( child );
 }
 
 void TableView::OnChildRemove( Actor& child )
@@ -1073,12 +1107,11 @@ void TableView::OnChildRemove( Actor& child )
 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
   mCellData( initialRows, initialColumns ),
+  mPreviousFocusedActor(),
   mLayoutingChild( false ),
   mRowDirty( true ),     // Force recalculation first time
   mColumnDirty( true )
 {
-  mCurrentColumn = 0;
-  mCurrentRow = 0;
   SetKeyboardNavigationSupport( true );
   ResizeContainers( initialRows, initialColumns );
 }
@@ -1087,8 +1120,13 @@ void TableView::OnInitialize()
 {
   // Make self as keyboard focusable and focus group
   Actor self = Self();
-  self.SetKeyboardFocusable(true);
+  self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
   SetAsKeyboardFocusGroup(true);
+
+  DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) {
+    return std::unique_ptr< Dali::Accessibility::Accessible >(
+      new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TABLE ) );
+  } );
 }
 
 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
@@ -1182,7 +1220,7 @@ void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
                                          void(TableView::*funcFit)(unsigned int),
                                          const Property::Value& value )
 {
-  Property::Map* map = value.GetMap();
+  const Property::Map* map = value.GetMap();
   if( map )
   {
     unsigned int index(0);
@@ -1400,29 +1438,37 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki
       // Move the focus if we haven't lost it.
       if(!focusLost)
       {
-        // Save the new focus cell positions of TableView.
-        mCurrentColumn = currentColumn;
-        mCurrentRow = currentRow;
-
         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+
+        // Save the focused actor in the TableView.
+        mPreviousFocusedActor = nextFocusableActor;
       }
     }
     else
     {
-      // The current focused actor is not within TableView.
-      // This means that the TableView has gained the Focus again.
+      // The current focused actor is not within this TableView.
 
       unsigned int numberOfColumns = GetColumns();
       unsigned int numberOfRows = GetRows();
 
-      if( (mCurrentRow != 0 && mCurrentColumn != 0) && // Last saved cell was not the first cell
-          (mCurrentRow != numberOfRows - 1 && mCurrentColumn != numberOfColumns - 1) ) // Last saved cell was not the last cell
+      // Check whether the previous focused actor is a focus group (i.e. a layout container)
+      bool wasFocusedOnLayoutContainer = false;
+      Actor previousFocusedActor = mPreviousFocusedActor.GetHandle();
+      if( previousFocusedActor )
       {
-        // This condition handles the cases when parent TableView gained the focus again after the child layout
-        // container (i.e. TableView) has no more items (i.e. actors) to be focused on in a given direction.
+        Toolkit::Control control = Toolkit::Control::DownCast( previousFocusedActor );
+        if( control )
+        {
+          Internal::Control& controlImpl = static_cast<Internal::Control&>(control.GetImplementation());
+          wasFocusedOnLayoutContainer = controlImpl.IsKeyboardFocusGroup();
+        }
+      }
 
-        // Move the focus to next cell towards the given direction in a TableView if the last saved cell was not the first or last cell.
-        nextFocusableActor = GetNextKeyboardFocusableActor(GetChildAt(Toolkit::TableView::CellPosition(mCurrentRow, mCurrentColumn)), direction, loopEnabled);
+      // Check whether the previous focused actor is a layout container and also a child of this TableView
+      Toolkit::TableView::CellPosition position;
+      if( wasFocusedOnLayoutContainer && FindChildPosition( previousFocusedActor, position ) )
+      {
+        nextFocusableActor = GetNextKeyboardFocusableActor(previousFocusedActor, direction, loopEnabled);
       }
       else
       {