Prevented json array of numbers appending on merge 09/56809/8
authorDavid Steele <david.steele@samsung.com>
Tue, 12 Jan 2016 17:37:42 +0000 (17:37 +0000)
committerDavid Steele <david.steele@samsung.com>
Thu, 21 Jan 2016 11:41:33 +0000 (11:41 +0000)
If 2 JSON files are merged into the same JSON parser (by calling Parse(first) then
calling Parse(second) ), then currently, nodes in the tree with the same
key but with differing types are overridden, but object and array
types are merged.

This is problematic for styling, where colors are represented as JSON arrays.

Changed matching arrays of numbers to override rather than merge.

Change-Id: Ia7a37a16919aa8648e7fe34430c5abf04cfaddb4
Signed-off-by: David Steele <david.steele@partner.samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-JsonParser.cpp
dali-toolkit/internal/builder/builder-impl.cpp
dali-toolkit/internal/builder/json-parser-state.cpp
dali-toolkit/internal/builder/tree-node-manipulator.cpp
dali-toolkit/internal/styling/style-manager-impl.cpp
dali-toolkit/internal/styling/style-manager-impl.h
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json

index 1f2c667..1fafb16 100644 (file)
@@ -722,3 +722,37 @@ int UtcDaliJsonParserMethod11(void)
   tet_result(TET_PASS);
   END_TEST;
 }
+
+
+int UtcDaliJsonParserMerge1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("JSON tree merge");
+
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'styles':                                                             \
+  {                                                                     \
+    'button':                                                           \
+    {                                                                   \
+      'backgroundColor':[0.8, 0.0, 1.0, 1.0],                           \
+      'foregroundColor':[1, 1, 1, 1]                                    \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+  JsonParser testParser = JsonParser::New();
+
+  testParser.Parse( s1 );
+
+  parser.Parse( s1 );
+  parser.Parse( s1 ); // Merge the tree into itself. The value array should not grow.
+
+  DALI_TEST_CHECK(parser.GetRoot());
+
+  CompareTrees( *parser.GetRoot(), *testParser.GetRoot() );
+
+  END_TEST;
+}
index 1535eeb..de40d44 100644 (file)
@@ -1117,7 +1117,6 @@ void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::U
                       parser.GetErrorDescription().c_str() );
 
     DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
-
   }
   else
   {
@@ -1155,7 +1154,6 @@ void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::U
   }
 
   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
-
 }
 
 void Builder::AddConstants( const Property::Map& map )
@@ -1359,9 +1357,9 @@ Builder::Builder()
   mParser = Dali::Toolkit::JsonParser::New();
 
   Property::Map defaultDirs;
-  defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]  = DALI_IMAGE_DIR;
-  defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ]  = DALI_SOUND_DIR;
-  defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
+  defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]       = DALI_IMAGE_DIR;
+  defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ]       = DALI_SOUND_DIR;
+  defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ]       = DALI_STYLE_DIR;
   defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR;
 
   AddConstants( defaultDirs );
index afa9e59..3691838 100644 (file)
@@ -318,8 +318,13 @@ TreeNode* JsonParserState::NewNode(const char* name, TreeNode::NodeType type)
       TreeNodeManipulator modify(node);
 
       modify.SetName(name);
-      // Set the type of the existing node, this may remove children where necessary
-      // (changing from container type to value type)
+
+      // Set the type of the existing node.
+      // Where the new type is different, then any children of this node will
+      // be deleted.
+      // When the type is an array of numbers, then this will also remove any children
+      // When the type is an object or other array, then the children will not be removed,
+      // but will instead follow these replace rules.
       modify.SetType(type);
 
       mCurrent = modify;
index 926842a..4357cb8 100644 (file)
@@ -291,6 +291,19 @@ void TreeNodeManipulator::SetType( TreeNode::NodeType type)
       }
     }
   }
+  else if( TreeNode::ARRAY == mNode->mType )
+  {
+    if( mNode->mFirstChild != NULL )
+    {
+      TreeNode::NodeType type = mNode->mFirstChild->GetType();
+
+      if( TreeNode::FLOAT == type || TreeNode::INTEGER == type )
+      {
+        // Arrays of numbers should be replaced, not appended to.
+        RemoveChildren();
+      }
+    }
+  }
 }
 
 void TreeNodeManipulator::SetName( const char* name )
index 5178020..85aa069 100644 (file)
@@ -101,7 +101,6 @@ StyleManager::StyleManager()
 : mOrientationDegrees( 0 ),  // Portrait
   mDefaultFontSize( -1 ),
   mDefaultFontFamily(""),
-  mThemeFile( DEFAULT_THEME ),
   mFeedbackStyle( NULL )
 {
   // Add theme builder constants
@@ -131,7 +130,7 @@ void StyleManager::SetOrientationValue( int orientation )
     mOrientationDegrees = orientation;
     // TODO: if orientation changed, apply the new style to all controls
     // dont want to really do the whole load from file again if the bundle contains both portrait & landscape
-    SetTheme();
+    SetTheme( mThemeFile );
   }
 }
 
@@ -184,15 +183,13 @@ bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& va
 
 void StyleManager::RequestThemeChange( const std::string& themeFile )
 {
-  mThemeFile = themeFile;
-
-  // need to do style change synchronously as app might create a UI control on the next line
-  SetTheme();
+  SetTheme( themeFile );
 }
 
 void StyleManager::RequestDefaultTheme()
 {
-  RequestThemeChange( DEFAULT_THEME );
+  std::string empty;
+  SetTheme( empty );
 }
 
 void StyleManager::ApplyThemeStyle( Toolkit::Control control )
@@ -256,12 +253,22 @@ Toolkit::StyleManager::StyleChangeSignalType& StyleManager::StyleChangeSignal()
   return mStyleChangeSignal;
 }
 
-
-void StyleManager::SetTheme()
+void StyleManager::SetTheme( const std::string& themeFile )
 {
+  bool themeLoaded = false;
+
   mThemeBuilder = CreateBuilder( mThemeBuilderConstants );
 
-  if( LoadJSON( mThemeBuilder, mThemeFile ) )
+  // Always load the default theme first, then merge in the custom theme if present
+  themeLoaded = LoadJSON( mThemeBuilder, DEFAULT_THEME );
+
+  if( ! themeFile.empty() )
+  {
+    mThemeFile = themeFile;
+    themeLoaded = LoadJSON( mThemeBuilder, mThemeFile );
+  }
+
+  if( themeLoaded )
   {
     if(mFeedbackStyle)
     {
@@ -398,7 +405,7 @@ void StyleManager::OnOrientationChanged( Orientation orientation )
   mOrientation = orientation;
   // TODO: if orientation changed, apply the new style to all controls
   // dont want to really do the whole load from file again if the bundle contains both portrait & landscape
-  SetTheme();
+  SetTheme( mThemeFile );
 }
 
 
@@ -436,17 +443,7 @@ void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::T
 
     case StyleChange::THEME_CHANGE:
     {
-      const std::string& newTheme = styleMonitor.GetTheme();
-      if( ! newTheme.empty() )
-      {
-        mThemeFile = newTheme;
-      }
-      else
-      {
-        mThemeFile = DEFAULT_THEME;
-      }
-
-      SetTheme();
+      SetTheme( styleMonitor.GetTheme() );
       break;
     }
   }
index 0eec891..294e601 100644 (file)
@@ -144,8 +144,9 @@ private:
 
   /**
    * @brief Set the current theme. Called only once per event processing cycle.
+   * @param[in] themeFile The name of the theme file to read.
    */
-  void SetTheme();
+  void SetTheme( const std::string& themeFile );
 
   /**
    * @brief Internal helper method to read a file from file system.
@@ -248,9 +249,7 @@ private:
   int mOrientationDegrees;            ///< Directly set value of orientation
 
   int mDefaultFontSize;               ///< Logical size, not a point-size
-
   std::string mDefaultFontFamily;
-
   std::string mThemeFile;             ///< The full path of the current theme file
 
   Property::Map mThemeBuilderConstants;   ///< Contants to give the theme builder
index 3717470..ab9c802 100644 (file)
@@ -142,6 +142,14 @@ distributing this software or its derivatives.
       "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
       "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
       "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
+    },
+    "popup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png"
+    },
+    "confirmationpopup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png"
     }
   }
 }