Implemented WeakHandle in dali-core 38/46038/3
authorRichard Huang <r.huang@samsung.com>
Thu, 13 Aug 2015 10:10:25 +0000 (11:10 +0100)
committerRichard Huang <r.huang@samsung.com>
Fri, 14 Aug 2015 14:03:02 +0000 (07:03 -0700)
WeakHandle stores a weak pointer to an internal Dali object. The handle to the object
can be accessed if the object exists, and such access is not reference counted. When
the object is deleted, the weak pointer will be set to NULL, and any further attmpt
to access to a deleted object will return an empty handle.

Change-Id: I56c8b0ea398f22c1d735270e6287124bdcea740b

automated-tests/src/dali-devel/CMakeLists.txt
automated-tests/src/dali-devel/utc-Dali-WeakHandle.cpp [new file with mode: 0644]
dali/devel-api/file.list
dali/devel-api/object/weak-handle.cpp [new file with mode: 0644]
dali/devel-api/object/weak-handle.h [new file with mode: 0644]

index a63f773..dbd5168 100644 (file)
@@ -23,6 +23,7 @@ SET(TC_SOURCES
         utc-Dali-SignalDelegate.cpp
         utc-Dali-Scripting.cpp
         utc-Dali-Shader.cpp
+        utc-Dali-WeakHandle.cpp
 )
 
 LIST(APPEND TC_SOURCES
diff --git a/automated-tests/src/dali-devel/utc-Dali-WeakHandle.cpp b/automated-tests/src/dali-devel/utc-Dali-WeakHandle.cpp
new file mode 100644 (file)
index 0000000..fedb2e1
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/object/weak-handle.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+namespace
+{
+
+/*******************************************************************************
+ *
+ * Custom Actor
+ *
+ ******************************************************************************/
+namespace Impl
+{
+struct MyTestCustomActor : public CustomActorImpl
+{
+  typedef Signal< void ()> SignalType;
+  typedef Signal< void (float)> SignalTypeFloat;
+
+  MyTestCustomActor() : CustomActorImpl( ActorFlags( REQUIRES_TOUCH_EVENTS ) )
+  { }
+
+  virtual ~MyTestCustomActor()
+  { }
+
+  void ResetCallStack()
+  {
+  }
+
+  // From CustomActorImpl
+  virtual void OnStageConnection( int depth )
+  {
+  }
+  virtual void OnStageDisconnection()
+  {
+  }
+  virtual void OnChildAdd(Actor& child)
+  {
+  }
+  virtual void OnChildRemove(Actor& child)
+  {
+  }
+  virtual void OnSizeSet(const Vector3& targetSize)
+  {
+  }
+  virtual void OnSizeAnimation(Animation& animation, const Vector3& targetSize)
+  {
+  }
+  virtual bool OnTouchEvent(const TouchEvent& event)
+  {
+    return true;
+  }
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    return true;
+  }
+  virtual bool OnWheelEvent(const WheelEvent& event)
+  {
+    return true;
+  }
+  virtual bool OnKeyEvent(const KeyEvent& event)
+  {
+    return true;
+  }
+  virtual void OnKeyInputFocusGained()
+  {
+  }
+  virtual void OnKeyInputFocusLost()
+  {
+  }
+  virtual Vector3 GetNaturalSize()
+  {
+    return Vector3( 0.0f, 0.0f, 0.0f );
+  }
+
+  virtual float GetHeightForWidth( float width )
+  {
+    return 0.0f;
+  }
+
+  virtual float GetWidthForHeight( float height )
+  {
+    return 0.0f;
+  }
+
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container )
+  {
+  }
+
+  virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+  {
+  }
+
+  virtual void OnCalculateRelayoutSize( Dimension::Type dimension )
+  {
+  }
+
+  virtual float CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension )
+  {
+    return 0.0f;
+  }
+
+  virtual void OnLayoutNegotiated( float size, Dimension::Type dimension )
+  {
+  }
+
+  virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS )
+  {
+    return false;
+  }
+
+public:
+
+  SignalType mSignal;
+};
+
+}; // namespace Impl
+
+class MyTestCustomActor : public CustomActor
+{
+public:
+
+  typedef Signal< void ()> SignalType;
+  typedef Signal< void (float)> SignalTypeFloat;
+
+  MyTestCustomActor()
+  {
+  }
+
+  static MyTestCustomActor New()
+  {
+    Impl::MyTestCustomActor* p = new Impl::MyTestCustomActor;
+    return MyTestCustomActor( *p ); // takes ownership
+  }
+
+  virtual ~MyTestCustomActor()
+  {
+  }
+
+  static MyTestCustomActor DownCast( BaseHandle handle )
+  {
+    MyTestCustomActor result;
+
+    CustomActor custom = Dali::CustomActor::DownCast( handle );
+    if ( custom )
+    {
+      CustomActorImpl& customImpl = custom.GetImplementation();
+
+      Impl::MyTestCustomActor* impl = dynamic_cast<Impl::MyTestCustomActor*>(&customImpl);
+
+      if (impl)
+      {
+        result = MyTestCustomActor(customImpl.GetOwner());
+      }
+    }
+
+    return result;
+  }
+
+  SignalType& GetCustomSignal()
+  {
+    Dali::RefObject& obj = GetImplementation();
+    return static_cast<Impl::MyTestCustomActor&>( obj ).mSignal;
+  }
+
+  MyTestCustomActor(Internal::CustomActor* internal)
+  : CustomActor(internal)
+  {
+  }
+
+  MyTestCustomActor( Impl::MyTestCustomActor& impl )
+  : CustomActor( impl )
+  {
+  }
+};
+
+}
+
+int UtcDaliWeakHandleBaseConstructorVoid(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandleBase::WeakHandleBase()");
+
+  WeakHandleBase object;
+
+  DALI_TEST_CHECK(!object.GetBaseHandle());
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseConstructorWithHandle(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandleBase::WeakHandleBase(Handle)");
+
+  Handle emptyHandle;
+  WeakHandleBase emptyObject(emptyHandle);
+  DALI_TEST_CHECK(!emptyObject.GetBaseHandle());
+
+  Actor actor = Actor::New();
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseCopyConstructor(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandleBase::WeakHandleBase(const WeakHandleBase&)");
+
+  Actor actor = Actor::New();
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  WeakHandleBase copy(object);
+  DALI_TEST_CHECK(copy.GetBaseHandle() == actor);
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseAssignmentOperator(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandleBase::operator=");
+
+  Actor actor = Actor::New();
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  WeakHandleBase copy = object;
+  DALI_TEST_CHECK(copy.GetBaseHandle() == actor);
+  DALI_TEST_EQUALS(1, actor.GetBaseObject().ReferenceCount(), TEST_LOCATION); // reference count of the actor is not increased
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseEqualityOperatorP(void)
+{
+  TestApplication application;
+  tet_infoline("Positive Test Dali::WeakHandleBase::operator==");
+
+  WeakHandleBase object;
+  WeakHandleBase theSameObject;
+  DALI_TEST_CHECK(object == theSameObject);
+
+  Actor actor = Actor::New();
+
+  object = WeakHandleBase(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  theSameObject = object;
+  DALI_TEST_CHECK(theSameObject.GetBaseHandle() == actor);
+  DALI_TEST_CHECK(object == theSameObject);
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseEqualityOperatorN(void)
+{
+  TestApplication application;
+  tet_infoline("Negative Test Dali::WeakHandleBase::operator==");
+
+  Actor actor = Actor::New();
+
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  Actor differentActor = Actor::New();
+  WeakHandleBase aDifferentWeakHandleBase(differentActor);
+
+  DALI_TEST_CHECK(!(object == aDifferentWeakHandleBase));
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseInequalityOperatorP(void)
+{
+  TestApplication application;
+  tet_infoline("Positive Test Dali::WeakHandleBase::operator!=");
+
+  Actor actor = Actor::New();
+
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  Actor differentActor = Actor::New();
+  WeakHandleBase aDifferentWeakHandleBase(differentActor);
+
+  DALI_TEST_CHECK(object != aDifferentWeakHandleBase);
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseInequalityOperatorN(void)
+{
+  TestApplication application;
+  tet_infoline("Negative Test Dali::WeakHandleBase::operator!=");
+
+  Actor actor = Actor::New();
+
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  WeakHandleBase theSameWeakHandleBase = object;
+
+  DALI_TEST_CHECK(!(object != theSameWeakHandleBase));
+  END_TEST;
+}
+
+int UtcDaliWeakHandleBaseGetBaseHandle(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandleBase::GetBaseHandle()");
+
+  Handle emptyHandle;
+  WeakHandleBase emptyObject(emptyHandle);
+  DALI_TEST_CHECK(!emptyObject.GetBaseHandle());
+
+  Actor actor = Actor::New();
+  WeakHandleBase object(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == actor);
+
+  WeakHandleBase theSameObject = WeakHandleBase(actor);
+  DALI_TEST_CHECK(object.GetBaseHandle() == theSameObject.GetBaseHandle());
+
+  Actor differentActor = Actor::New();
+  WeakHandleBase aDifferentWeakHandleBase(differentActor);
+  DALI_TEST_CHECK(object.GetBaseHandle() != aDifferentWeakHandleBase.GetBaseHandle());
+
+  END_TEST;
+}
+
+int UtcDaliWeakHandleGetHandle(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::WeakHandle::GetHandle()");
+
+  Actor actor = Actor::New();
+  WeakHandle<Actor> object(actor);
+  DALI_TEST_CHECK(object.GetHandle() == actor);
+
+  MyTestCustomActor customActor = MyTestCustomActor::New();
+  WeakHandle<MyTestCustomActor> customObject(customActor);
+  DALI_TEST_CHECK(customObject.GetHandle() == customActor);
+
+  DALI_TEST_CHECK(object.GetHandle() != customObject.GetHandle());
+
+  END_TEST;
+}
+
+
+
index 967fc28..5186f52 100644 (file)
@@ -9,6 +9,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/images/atlas.cpp \
   $(devel_api_src_dir)/images/distance-field.cpp \
   $(devel_api_src_dir)/object/property-buffer.cpp \
+  $(devel_api_src_dir)/object/weak-handle.cpp \
   $(devel_api_src_dir)/rendering/cull-face.cpp \
   $(devel_api_src_dir)/rendering/geometry.cpp \
   $(devel_api_src_dir)/rendering/material.cpp \
@@ -40,7 +41,8 @@ devel_api_core_images_header_files = \
 
 devel_api_core_object_header_files = \
   $(devel_api_src_dir)/object/property-buffer.h \
-  $(devel_api_src_dir)/object/type-registry-helper.h
+  $(devel_api_src_dir)/object/type-registry-helper.h \
+  $(devel_api_src_dir)/object/weak-handle.h
 
 devel_api_core_rendering_header_files = \
   $(devel_api_src_dir)/rendering/cull-face.h \
diff --git a/dali/devel-api/object/weak-handle.cpp b/dali/devel-api/object/weak-handle.cpp
new file mode 100644 (file)
index 0000000..94bb88f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/common/object-impl.h>
+
+namespace Dali
+{
+
+struct WeakHandleBase::Impl : public Internal::Object::Observer
+{
+  // Construction
+  Impl()
+  : mObject( NULL )
+  {
+  }
+
+  // Construction
+  Impl( Handle& handle )
+  : mObject( NULL )
+  {
+    if(handle)
+    {
+      mObject = static_cast<Internal::Object*>( handle.GetObjectPtr() );
+      if(mObject)
+      {
+        mObject->AddObserver( *this );
+      }
+    }
+  }
+
+  // Destruction
+  ~Impl()
+  {
+    if( mObject )
+    {
+      mObject->RemoveObserver( *this );
+    }
+  }
+
+  /**
+   * From Object::Observer
+   */
+  virtual void SceneObjectAdded( Internal::Object& object )
+  {
+  }
+
+  /**
+   * From Object::Observer
+   */
+  virtual void SceneObjectRemoved( Internal::Object& object )
+  {
+  }
+
+  /**
+   * From Object::Observer
+   */
+  virtual void ObjectDestroyed( Internal::Object& object )
+  {
+    mObject = NULL;
+  }
+
+  // Data
+  Internal::Object* mObject;
+};
+
+WeakHandleBase::WeakHandleBase()
+: mImpl( new Impl() )
+{
+}
+
+WeakHandleBase::WeakHandleBase( Handle& handle )
+: mImpl( new Impl( handle ) )
+{
+}
+
+WeakHandleBase::~WeakHandleBase()
+{
+  delete mImpl;
+  mImpl = NULL;
+}
+
+WeakHandleBase::WeakHandleBase(const WeakHandleBase& handle)
+: mImpl( NULL )
+{
+  Handle object = handle.GetBaseHandle();
+  mImpl = new Impl(object);
+}
+
+WeakHandleBase& WeakHandleBase::operator=( const WeakHandleBase& rhs )
+{
+  if( this != &rhs )
+  {
+    delete mImpl;
+
+    Handle handle = rhs.GetBaseHandle();
+    mImpl = new Impl(handle);
+  }
+
+  return *this;
+}
+
+bool WeakHandleBase::operator==( const WeakHandleBase& rhs ) const
+{
+  return this->mImpl->mObject == rhs.mImpl->mObject;
+}
+
+bool WeakHandleBase::operator!=( const WeakHandleBase& rhs ) const
+{
+  return !( *this == rhs );
+}
+
+Handle WeakHandleBase::GetBaseHandle() const
+{
+  return Handle( mImpl->mObject );
+}
+
+} // Dali
diff --git a/dali/devel-api/object/weak-handle.h b/dali/devel-api/object/weak-handle.h
new file mode 100644 (file)
index 0000000..2e24758
--- /dev/null
@@ -0,0 +1,220 @@
+#ifndef __DALI_WEAK_HANDLE_H__
+#define __DALI_WEAK_HANDLE_H__
+
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/object/handle.h>
+#include <dali/public-api/actors/custom-actor.h>
+
+namespace Dali
+{
+
+/**
+ * @brief Base class to store a weak pointer to an internal Dali object. The handle to the object
+ * can be accessed if the object exists, and such access is not reference counted. When the object
+ * is deleted, the weak pointer will be set to NULL, and any further attmpt to access to a deleted
+ * object will return an empty handle.
+ *
+ */
+class DALI_IMPORT_API WeakHandleBase
+{
+
+public:
+
+  /**
+   * @brief Default constructor which provides an uninitialized Dali::WeakHandleBase.
+   */
+  WeakHandleBase();
+
+  /**
+   * @brief This constructor creates a weak handle of the Dali object.
+   *
+   * @param [in] handle A reference to the handle of the Dali object.
+   */
+  WeakHandleBase( Handle& handle );
+
+  /**
+   * @brief Destructor to free resources.
+   */
+  ~WeakHandleBase();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param [in] handle A reference to the copied WeakHandleBase
+   */
+  WeakHandleBase(const WeakHandleBase& handle);
+
+  /**
+   * @brief Assignment operator.
+   *
+   * It makes this WeakHandleBase point to the same internal Dali object as the copied WeakHandleBase
+   * @param [in] rhs  A reference to the copied WeakHandleBase
+   * @return A reference to this WeakHandleBase
+   */
+  WeakHandleBase& operator=( const WeakHandleBase& rhs );
+
+  /**
+   * @brief Equality operator overload.
+   *
+   * @param [in] rhs A reference to the compared WeakHandleBase.
+   * @return true if the handle points to the same Dali resource, or if both are uninitialized.
+   */
+  bool operator==(const WeakHandleBase& rhs) const;
+
+  /**
+   * @brief Inequality operator overload.
+   *
+   * @param [in] rhs A reference to the compared WeakHandleBase.
+   * @return true if the handle points to the different Dali resources.
+   */
+  bool operator!=(const WeakHandleBase& rhs) const;
+
+  /**
+   * @brief Gets the handle to the Dali object.
+   *
+   * @return The handle of the Dali object pointed by this WeakHandleBase or an empty handle if the Dali object doesn't exist.
+   */
+  Handle GetBaseHandle() const;
+
+protected:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+/**
+ * @brief Type CustomActors support
+ */
+template <typename Type>
+struct CustomActors
+{
+  /**
+   * This flag tells Dali if a class is derived from CustomActor.
+   */
+  enum { IS_CUSTOM_ACTOR = __is_base_of(Dali::CustomActor, Type) };
+};
+
+template <typename Type>
+struct TypeCustomActors : public CustomActors< Type >
+{
+};
+
+template < bool CustomActorType >
+class InternalTypeName
+{
+public: // Typedefs
+
+  typedef Dali::Internal::CustomActor InternalObjectType;
+};
+
+template <>
+class InternalTypeName< false >
+{
+public: // Typedefs
+
+  typedef Dali::Internal::Actor InternalObjectType;
+};
+
+/**
+ * @brief Weak handle for the given type of Dali object.
+ */
+template < class T >
+class WeakHandle : public WeakHandleBase
+{
+public: // Typedefs
+
+  typedef typename InternalTypeName< TypeCustomActors<T>::IS_CUSTOM_ACTOR >::InternalObjectType InternalObjectType;
+
+public:
+
+  /**
+   * @copydoc Dali::WeakHandleBase::WeakHandleBase()
+   */
+  WeakHandle()
+  : WeakHandleBase()
+  {
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::WeakHandleBase(Handle&)
+   */
+  WeakHandle( T& handle )
+  : WeakHandleBase( handle )
+  {
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::~WeakHandleBase()
+   */
+  ~WeakHandle() {}
+
+  /**
+   * @copydoc Dali::WeakHandleBase::WeakHandleBase(const WeakHandleBase&)
+   */
+  WeakHandle(const WeakHandle& handle)
+  : WeakHandleBase( handle )
+  {
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::operator=()
+   */
+  WeakHandle& operator=( const WeakHandle& rhs )
+  {
+    WeakHandleBase::operator=(rhs);
+    return *this;
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::operator==()
+   */
+  bool operator==(const WeakHandle& rhs) const
+  {
+    return WeakHandleBase::operator==(rhs);
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::operator!=()
+   */
+  bool operator!=(const WeakHandle& rhs) const
+  {
+    return WeakHandleBase::operator!=(rhs);
+  }
+
+  /**
+   * @copydoc Dali::WeakHandleBase::GetHandle()
+   */
+  T GetHandle()
+  {
+    Handle handle( GetBaseHandle() );
+    if( handle )
+    {
+      return T( reinterpret_cast< InternalObjectType* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      return T();
+    }
+  }
+};
+
+} // namespace Dali
+
+#endif // __DALI_WEAK_HANDLE_H__