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>
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;
+}
parser.GetErrorDescription().c_str() );
DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
-
}
else
{
}
DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
-
}
void Builder::AddConstants( const Property::Map& map )
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 );
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;
}
}
}
+ 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 )
: mOrientationDegrees( 0 ), // Portrait
mDefaultFontSize( -1 ),
mDefaultFontFamily(""),
- mThemeFile( DEFAULT_THEME ),
mFeedbackStyle( NULL )
{
// Add theme builder constants
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 );
}
}
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 )
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)
{
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 );
}
case StyleChange::THEME_CHANGE:
{
- const std::string& newTheme = styleMonitor.GetTheme();
- if( ! newTheme.empty() )
- {
- mThemeFile = newTheme;
- }
- else
- {
- mThemeFile = DEFAULT_THEME;
- }
-
- SetTheme();
+ SetTheme( styleMonitor.GetTheme() );
break;
}
}
/**
* @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.
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
"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"
}
}
}