2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "item-factory-wrapper.h"
22 #include <dali/public-api/common/vector-wrapper.h>
23 #include <dali/devel-api/object/weak-handle.h>
24 #include <dali-toolkit/devel-api/builder/builder.h>
25 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
26 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
30 #include <dali-wrapper.h>
31 #include <shared/api-function.h>
32 #include <shared/object-template-helper.h>
40 v8::Persistent<v8::ObjectTemplate> ItemFactoryWrapper::mItemFactoryTemplate;
45 typedef std::vector< Property::Map > ItemDataContainer;
47 // Implementation of ItemFactory for providing actors to ItemView
48 class ItemFactory : public Toolkit::ItemFactory
54 * @param application class, stored as reference
57 : mJsonFileLoaded(false),
60 mBuilder = Toolkit::Builder::New();
64 * Set the name of the JSON file which defines the templates of items.
65 * @param jsonFile The JSON file
67 void SetJsonTemplateFile(std::string jsonFile)
69 if(mJsonFile != jsonFile)
72 LoadJsonFile(mJsonFile);
74 // Check whether any layout activated in ItemView
75 Toolkit::ItemView itemView = mItemView.GetHandle();
76 if(itemView && itemView.GetActiveLayout() != NULL)
78 // Refresh ItemView if item templates are changed
85 * Returns the name of the JSON file.
86 * @return The JSON file name
88 std::string GetJsonTemplate()
94 * Set the data to be used to create new items.
96 * If ItemView is already created, this will immediately update ItemView with the
99 * The data is an array of property maps in which each map contains the data for
100 * each item, including the template to be used to build the actor and the pairs
101 * of key/value to be used to replace the constants defined in the template.
102 * The order of property maps in the array represents the actual order of items
105 * @param data The array of property maps
107 void SetData(ItemDataContainer data)
109 ItemDataContainer currentData = mData;
111 mNumberOfItems = mData.size();
113 // Check whether any layout activated in ItemView
114 Toolkit::ItemView itemView = mItemView.GetHandle();
115 if(itemView && itemView.GetActiveLayout() != NULL)
117 unsigned int currentNumberOfItems = currentData.size();
118 unsigned int newNumberOfItems = data.size();
120 // Check whether any items added or deleted from the data
121 // which requires ItemView to be refreshed with the new data
122 if(currentNumberOfItems != newNumberOfItems)
128 for( unsigned int itemId = 0; itemId < newNumberOfItems; itemId++)
130 // Check whether the item is already built in ItemView
131 Actor itemActor = itemView.GetItem(itemId);
134 // Check if the item needs to be rebuilt
135 if( !V8Utils::IsPropertyMapIdentical(currentData[itemId], data[itemId]) )
137 // Rebuild the item with the new data
138 Actor newItemActor = NewItem(itemId);
140 // Replace the old item with the new one
141 itemView.ReplaceItem( Toolkit::Item( itemId, newItemActor ), 0.0f );
153 ItemDataContainer GetData()
159 * Store a weak handle of ItemView in order to access ItemView APIs
160 * from this ItemFactory implementation
163 void SetItemView(Toolkit::ItemView itemView)
165 mItemView = itemView;
168 public: // From Toolkit::ItemFactory
171 * Query the number of items available from the factory.
172 * The maximum available item has an ID of GetNumberOfItems() - 1.
174 virtual unsigned int GetNumberOfItems()
176 return mJsonFileLoaded ? mNumberOfItems : 0;
180 * Create an Actor to represent a visible item.
182 * @return the created actor.
184 virtual Actor NewItem(unsigned int itemId)
186 std::string itemTemplate;
188 Property::Map constantsMap = mData[itemId];
189 for ( unsigned int i = 0, count = constantsMap.Count(); i < count; ++i )
191 Property::Value& constantValue = constantsMap.GetValue(i);
192 if(constantsMap.GetKey(i) == "template")
194 constantValue.Get(itemTemplate);
198 mBuilder.AddConstant( constantsMap.GetKey(i), constantValue );
202 Actor item = Actor::DownCast( mBuilder.Create(itemTemplate) );
209 * Load the JSON file.
210 * @param The JSON file name
212 void LoadJsonFile(std::string jsonFile)
217 V8Utils::GetFileContents(jsonFile, data);
219 mBuilder.LoadFromString(data);
221 mJsonFileLoaded = true;
225 // printf("invalid JSON data\n");
226 mJsonFileLoaded = false;
232 std::string mJsonFile;
233 bool mJsonFileLoaded;
234 Toolkit::Builder mBuilder;
235 unsigned int mNumberOfItems;
236 ItemDataContainer mData;
237 WeakHandle< Toolkit::ItemView > mItemView;
242 ItemFactoryWrapper::ItemFactoryWrapper( Toolkit::ItemFactory& factory, GarbageCollectorInterface& gc )
243 : BaseWrappedObject( BaseWrappedObject::ITEMFACTORY , gc ),
244 mItemFactory( factory )
248 ItemFactoryWrapper::~ItemFactoryWrapper()
252 v8::Handle<v8::Object> ItemFactoryWrapper::WrapItemFactory(v8::Isolate* isolate, Toolkit::ItemFactory& factory )
254 v8::EscapableHandleScope handleScope( isolate );
255 v8::Local<v8::ObjectTemplate> objectTemplate;
257 objectTemplate = GetItemFactoryTemplate( isolate );
259 // create an instance of the template
260 v8::Local<v8::Object> localObject = objectTemplate->NewInstance();
262 // create the ItemFactory wrapper
263 ItemFactoryWrapper* pointer = new ItemFactoryWrapper( factory, Dali::V8Plugin::DaliWrapper::Get().GetDaliGarbageCollector() );
265 // assign the JavaScript object to the wrapper.
266 pointer->SetJavascriptObject( isolate, localObject );
268 return handleScope.Escape( localObject );
271 v8::Local<v8::ObjectTemplate> ItemFactoryWrapper::GetItemFactoryTemplate( v8::Isolate* isolate)
273 v8::EscapableHandleScope handleScope( isolate );
274 v8::Local<v8::ObjectTemplate> objectTemplate;
276 if( mItemFactoryTemplate.IsEmpty() )
278 objectTemplate = MakeItemFactoryTemplate( isolate );
279 mItemFactoryTemplate.Reset( isolate, objectTemplate );
283 // get the object template
284 objectTemplate = v8::Local<v8::ObjectTemplate>::New( isolate, mItemFactoryTemplate );
286 return handleScope.Escape( objectTemplate );
289 v8::Handle<v8::ObjectTemplate> ItemFactoryWrapper::MakeItemFactoryTemplate( v8::Isolate* isolate )
291 v8::EscapableHandleScope handleScope( isolate );
293 v8::Local<v8::ObjectTemplate> objTemplate = v8::ObjectTemplate::New();
295 objTemplate->SetInternalFieldCount( BaseWrappedObject::FIELD_COUNT );
297 // set property setter and getter
298 objTemplate->SetNamedPropertyHandler( ItemFactoryWrapper::PropertyGet, ItemFactoryWrapper::PropertySet);
300 return handleScope.Escape( objTemplate );
303 void ItemFactoryWrapper::NewItemFactory( const v8::FunctionCallbackInfo< v8::Value >& args)
305 v8::Isolate* isolate = args.GetIsolate();
306 v8::HandleScope handleScope( isolate);
308 if( !args.IsConstructCall() )
310 DALI_SCRIPT_EXCEPTION( isolate, "ItemFactory constructor called without 'new'" );
314 Toolkit::ItemFactory* factory = new ItemFactory();
316 v8::Local<v8::Object> localObject = WrapItemFactory( isolate, *factory );
317 args.GetReturnValue().Set( localObject );
320 Toolkit::ItemFactory& ItemFactoryWrapper::GetItemFactoryFromParams( int paramIndex,
322 v8::Isolate* isolate,
323 const v8::FunctionCallbackInfo< v8::Value >& args )
327 v8::HandleScope handleScope( isolate );
328 BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( paramIndex, BaseWrappedObject::ITEMFACTORY, isolate, args );
332 ItemFactoryWrapper* wrapper = static_cast< ItemFactoryWrapper *>(wrappedObject);
333 return wrapper->GetItemFactory();
337 DALI_SCRIPT_EXCEPTION( isolate, "no valid ItemFactory parameter" );
338 Toolkit::ItemFactory* dummyFactory = new ItemFactory();
339 return *dummyFactory; // avoid build error
343 ItemFactoryWrapper* ItemFactoryWrapper::Unwrap( v8::Isolate* isolate, v8::Handle< v8::Object> obj)
345 v8::HandleScope handleScope( isolate );
347 v8::Local<v8::External> field = v8::Local<v8::External>::Cast( obj->GetInternalField(0) );
348 void* ptr = field->Value();
349 return static_cast< ItemFactoryWrapper *>(ptr);
352 void ItemFactoryWrapper::PropertyGet( v8::Local<v8::String> propertyName,
353 const v8::PropertyCallbackInfo<v8::Value>& info)
355 v8::Isolate* isolate = info.GetIsolate();
356 v8::HandleScope handleScope( isolate );
358 // get the property name
359 std::string name = V8Utils::v8StringToStdString( propertyName );
361 if( std::isupper( name[0] ))
367 ItemFactoryWrapper* itemFactoryWrapper = Unwrap( isolate, info.This() );
368 if( !itemFactoryWrapper )
373 ItemFactory& factory = static_cast<ItemFactory&>( itemFactoryWrapper->GetItemFactory() );
375 if( name == "jsonTemplateFile" )
377 std::string jsonTemplateFile = factory.GetJsonTemplate();
378 info.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, jsonTemplateFile.c_str()));
380 else if( name == "data" )
382 ItemDataContainer data = factory.GetData();
383 unsigned int itemCount = data.size();
385 v8::Local<v8::Array> array= v8::Array::New( isolate, itemCount );
386 for( unsigned int i = 0; i < itemCount; i++)
388 v8::Local<v8::Object> mapObject = v8::Object::New( isolate );
389 V8Utils::CreatePropertyMap( isolate, data[i], mapObject );
391 array->Set( i, mapObject);
394 info.GetReturnValue().Set(array);
398 std::string error="Invalid property Get for "+name + "\n";
399 DALI_SCRIPT_EXCEPTION( isolate, error );
403 void ItemFactoryWrapper::PropertySet( v8::Local<v8::String> propertyName,
404 v8::Local<v8::Value> javaScriptValue,
405 const v8::PropertyCallbackInfo<v8::Value>& info)
408 v8::Isolate* isolate = info.GetIsolate();
409 v8::HandleScope handleScope( isolate );
411 // get the property name
412 std::string name = V8Utils::v8StringToStdString( propertyName );
415 ItemFactoryWrapper* itemFactoryWrapper = Unwrap( isolate, info.This() );
416 if( !itemFactoryWrapper )
421 ItemFactory& factory = static_cast<ItemFactory&>( itemFactoryWrapper->GetItemFactory() );
423 if( name == "jsonTemplateFile" && javaScriptValue->IsString() )
425 std::string jsonTemplateFile = V8Utils::v8StringToStdString( javaScriptValue );
426 factory.SetJsonTemplateFile(jsonTemplateFile);
428 else if( name == "data" && javaScriptValue->IsArray() )
430 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(javaScriptValue);
432 ItemDataContainer data;
434 for( unsigned int i = 0; i < array->Length(); ++i )
436 v8::Local<v8::Value> itemData = array->Get(i);
438 if( itemData->IsObject() )
440 Dali::Property::Map map = V8Utils::GetPropertyMapFromObject( isolate, itemData->ToObject() );
445 factory.SetData(data);
449 std::string error = "Invalid property Set for " + name + "\n";
450 DALI_SCRIPT_EXCEPTION( isolate, error );
454 Toolkit::ItemFactory& ItemFactoryWrapper::GetItemFactory()
459 void ItemFactoryWrapper::SetItemView(Toolkit::ItemFactory& itemFactory, Toolkit::ItemView itemView)
461 ItemFactory& factory = static_cast<ItemFactory&>( itemFactory );
462 factory.SetItemView(itemView);
465 } // namespace V8Plugin