TizenRefApp-7822 Implement an ability to get parent view from any child object 24/105824/3
authorEugene Kurzberg <i.kurtsberg@samsung.com>
Mon, 19 Dec 2016 14:09:06 +0000 (16:09 +0200)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Wed, 21 Dec 2016 10:55:34 +0000 (02:55 -0800)
Implemented possibility to tie several Control objects to one Evas_Object
and retrieve them by type.
Added possibility to determine whether Control object is derived from a
specific base class.

Change-Id: Icea9712952fa794df21a63afcc1a4382695625e6
Signed-off-by: Eugene Kurzberg <i.kurtsberg@samsung.com>
12 files changed:
lib-apps-common/inc/Ui/Control.h
lib-apps-common/inc/Ui/GenContainer.h
lib-apps-common/inc/Ui/Navigator.h
lib-apps-common/inc/Ui/View.h
lib-apps-common/src/Ui/Control.cpp
lib-apps-common/src/Ui/GenItem.cpp
lib-apps-common/src/Ui/Naviframe.cpp
lib-apps-common/src/Ui/Navigator.cpp
lib-apps-common/src/Ui/TabNavigator.cpp
lib-apps-common/src/Ui/View.cpp
lib-apps-common/src/Ui/Window.cpp
lib-contacts/src/Contacts/Details/BasicInfoItem.cpp

index d4d086d..725a009 100644 (file)
 
 #include <Elementary.h>
 #include <tizen.h>
+#include <typeinfo>
+
+/**
+ * @brief Define class type so it can be detected from a more derived class instance.
+ * @details Overrides hasType() method by checking against the given static type
+ *          and all base types recursively.
+ */
+#define DEFINE_CLASS_TYPE(classType, baseClassType) \
+       virtual bool hasType(const std::type_info &type) const override \
+       { \
+               return typeid(classType) == type || baseClassType::hasType(type); \
+       }
 
 namespace Ui
 {
        /**
-        * @brief Basic Control types.
-        */
-       enum ControlType
-       {
-               TypeControl,
-               TypeWindow,
-               TypeView,
-               TypeMax
-       };
-
-       /**
         * @brief Evas_Object wrapper.
         * @details Ties the lifetime of this object to the underlying Evas_Object.
         * @remark Should always be allocated with operator "new".
@@ -41,13 +42,11 @@ namespace Ui
        class EXPORT_API Control
        {
        public:
-               Control(int type = TypeControl);
+               Control();
                Control(const Control &that) = delete;
-               Control(Control &&that) = delete;
                virtual ~Control();
 
-               Control & operator=(const Control &that) = delete;
-               Control & operator=(Control &&that) = delete;
+               Control &operator=(const Control &that) = delete;
 
                /**
                 * @brief Create underlying Evas_Object by calling onCreate()
@@ -69,35 +68,43 @@ namespace Ui
                void resetCreateTimer();
 
                /**
-                * @return Control type.
+                * @return Underlying Evas_Object.
                 */
-               int getType() const;
+               Evas_Object *getEvasObject() const;
 
+               /**@{*/
                /**
-                * @return Underlying Evas_Object.
+                * @brief Get Control object from Evas_Object by type.
+                * @remark The specified type should be either the most derived class or
+                *         should be defined using DEFINE_CLASS_TYPE macro in the respective class.
+                * @param[in]   object  Evas_Object that belongs to some Control
+                * @return Control of the specified type tied to Evas_Object or nullptr if none.
                 */
-               Evas_Object *getEvasObject() const;
+               template <typename ControlType = Control>
+               static ControlType *getControl(Evas_Object *object);
+               static Control *getControl(Evas_Object *object, const std::type_info &type);
+               /**@}*/
 
+               /**@{*/
                /**
                 * @brief Find closest parent Control by type.
-                * @param[in]   object  Child object
-                * @param[in]   type    Control type
-                * @return Control if found, otherwise nullptr.
+                * @see Control::getControl()
                 */
-               template <typename ControlType>
-               ControlType *findParent() const;
-               Control *findParent(int type) const;
-
+               static Control *findParent(Evas_Object *object, const std::type_info &type);
                template <typename ControlType>
                static ControlType *findParent(Evas_Object *object);
-               static Control *findParent(Evas_Object *object, int type);
+               template <typename ControlType>
+               ControlType *findParent() const;
+               /**@}*/
 
                /**
-                * @brief Get Control object from Evas_Object
-                * @param[in]   object  Evas_Object that belongs to some Control
-                * @return Control tied to Evas_Object
+                * @brief Check if the object has a specified type or is derived from it.
+                * @details A base class MUST override this method using DEFINE_CLASS_TYPE macro
+                *          to allow detecting it from a more derived class instance.
+                * @param[in]   type    Type info to check against
+                * @return Whether the object has a specified type.
                 */
-               static Control *getControl(Evas_Object *object);
+               virtual bool hasType(const std::type_info &type) const { return typeid(Control) == type; }
 
        protected:
                /**
@@ -122,14 +129,26 @@ namespace Ui
                Evas_Object *resetEvasObject();
                void destroyEvasObject();
 
-               void onDestroyed(Evas *e, Evas_Object *obj, void *event_info);
+               void onTypeCheck(Evas_Object *obj, void *eventInfo);
+               void onDestroyed(Evas *e, Evas_Object *obj, void *eventInfo);
 
-               int m_Type;
                Evas_Object *m_Object;
                Ecore_Timer *m_CreateTimer;
        };
 
        template <typename ControlType>
+       ControlType *Control::getControl(Evas_Object *object)
+       {
+               return static_cast<ControlType *>(getControl(object, typeid(ControlType)));
+       }
+
+       template <typename ControlType>
+       ControlType *Control::findParent(Evas_Object *object)
+       {
+               return static_cast<ControlType *>(findParent(object, typeid(ControlType)));
+       }
+
+       template <typename ControlType>
        ControlType *Control::findParent() const
        {
                return findParent<ControlType>(m_Object);
index 125dbd3..918d123 100644 (file)
@@ -25,6 +25,8 @@ namespace Ui
        class EXPORT_API GenContainer : public Control
        {
        public:
+               DEFINE_CLASS_TYPE(GenContainer, Control)
+
                enum Type
                {
                        TypeGenlist,
index d4ce0c1..57d060c 100644 (file)
@@ -37,11 +37,7 @@ namespace Ui
                 */
                typedef std::function<bool()> LastPageCallback;
 
-               /**
-                * @brief Create navigator.
-                * @param[in]   type    Navigator type
-                */
-               explicit Navigator(NavigatorType type);
+               Navigator();
 
                /**
                 * @return Currently displayed page.
index 562a0bf..b49100e 100644 (file)
@@ -25,29 +25,21 @@ namespace Ui
        class Navigator;
 
        /**
-        * @brief Navigation type supported by Navigator
-        */
-       enum NavigatorType
-       {
-               TypeStackNavigator = TypeMax, /**< Allows navigation to the added View or the previous View */
-               TypeTabNavigator              /**< Allows navigation to any added View */
-       };
-
-       /**
         * @brief Represents content of a Window or Navigator page
         */
        class EXPORT_API View : public Control
        {
        public:
-               View(int type = TypeView);
+               DEFINE_CLASS_TYPE(View, Control)
+
+               View();
 
                /**
                 * @brief Get parent Navigator
                 * @param[in]   type    Navigator type
-                * @return Innermost parent Navigator of the specified type if exists,
-                *         otherwise nullptr
+                * @return Innermost parent Naviframe.
                 */
-               Navigator *getNavigator(NavigatorType type = TypeStackNavigator) const;
+               Navigator *getNavigator() const;
 
                /**
                 * @return NavigatorPage of this View
@@ -96,16 +88,13 @@ namespace Ui
        private:
                friend class Window;
                friend class Navigator;
-               void onNavigatorAttached(Navigator *stackNavi, Navigator *tabNavi, NavigatorPage *page);
+               void onNavigatorAttached(NavigatorPage *page);
                void onNavigation(bool isCurrent, int degree);
                void onRotation(int degree);
 
-               Navigator     *m_StackNavi;
-               Navigator     *m_TabNavi;
                NavigatorPage *m_Page;
-
-               bool          m_IsCurrent;
-               int           m_Rotation;
+               bool m_IsCurrent;
+               int m_Rotation;
        };
 }
 
index a837ff6..0d1d866 100644 (file)
 #include "Ui/Control.h"
 #include "Utils/Callback.h"
 
-#define CONTROL_DATA_KEY "Ui::Control"
+#define EVENT_TYPE_CHECK "type_check"
 
 using namespace Ui;
 
-Control::Control(int type)
-       : m_Type(type), m_Object(nullptr), m_CreateTimer(nullptr)
+namespace
+{
+       struct TypeCheckInfo
+       {
+               const std::type_info &type;
+               Control *object;
+       };
+}
+
+Control::Control()
+       : m_Object(nullptr), m_CreateTimer(nullptr)
 {
 }
 
@@ -76,26 +85,22 @@ void Control::resetCreateTimer()
        }
 }
 
-int Control::getType() const
-{
-       return m_Type;
-}
-
 Evas_Object *Control::getEvasObject() const
 {
        return m_Object;
 }
 
-Control *Control::findParent(int type) const
+Control *Control::getControl(Evas_Object *object, const std::type_info &type)
 {
-       return findParent(getEvasObject(), type);
+       TypeCheckInfo checkInfo = { type, nullptr };
+       evas_object_smart_callback_call(object, EVENT_TYPE_CHECK, &checkInfo);
+       return checkInfo.object;
 }
 
-Control *Control::findParent(Evas_Object *object, int type)
+Control *Control::findParent(Evas_Object *object, const std::type_info &type)
 {
        while (object) {
-               Control *control = getControl(object);
-               if (control && control->getType() == type) {
+               if (auto control = getControl(object, type)) {
                        return control;
                }
                object = elm_object_parent_widget_get(object);
@@ -104,18 +109,11 @@ Control *Control::findParent(Evas_Object *object, int type)
        return nullptr;
 }
 
-Control *Control::getControl(Evas_Object *object)
-{
-       return (Control *) evas_object_data_get(object, CONTROL_DATA_KEY);
-}
-
 void Control::setEvasObject(Evas_Object *object)
 {
        m_Object = object;
-       if (!evas_object_data_get(m_Object, CONTROL_DATA_KEY)) {
-               evas_object_data_set(m_Object, CONTROL_DATA_KEY, this);
-       }
-
+       evas_object_smart_callback_add(m_Object, EVENT_TYPE_CHECK,
+                       makeCallback(&Control::onTypeCheck), this);
        evas_object_event_callback_add(m_Object, EVAS_CALLBACK_DEL,
                        (Evas_Object_Event_Cb) makeCallback(&Control::onDestroy), this);
        evas_object_event_callback_add(m_Object, EVAS_CALLBACK_FREE,
@@ -125,6 +123,8 @@ void Control::setEvasObject(Evas_Object *object)
 Evas_Object *Control::resetEvasObject()
 {
        Evas_Object *object = m_Object;
+       evas_object_smart_callback_del_full(m_Object, EVENT_TYPE_CHECK,
+                       makeCallback(&Control::onTypeCheck), this);
        evas_object_event_callback_del_full(m_Object, EVAS_CALLBACK_DEL,
                        (Evas_Object_Event_Cb) makeCallback(&Control::onDestroy), this);
        evas_object_event_callback_del_full(m_Object, EVAS_CALLBACK_FREE,
@@ -141,7 +141,17 @@ void Control::destroyEvasObject()
        }
 }
 
-void Control::onDestroyed(Evas *e, Evas_Object *obj, void *event_info)
+void Control::onTypeCheck(Evas_Object *obj, void *eventInfo)
+{
+       auto checkInfo = (TypeCheckInfo *) eventInfo;
+       if (!checkInfo->object) {
+               if (typeid(*this) == checkInfo->type || hasType(checkInfo->type)) {
+                       checkInfo->object = this;
+               }
+       }
+}
+
+void Control::onDestroyed(Evas *e, Evas_Object *obj, void *eventInfo)
 {
        m_Object = nullptr;
        delete this;
index de9a707..9708e18 100644 (file)
@@ -105,7 +105,7 @@ GenGroupItem *GenItem::getParentItem() const
 GenContainer *GenItem::getParent() const
 {
        Evas_Object *genlist = elm_object_item_widget_get(getObjectItem());
-       return static_cast<GenContainer *>(Control::getControl(genlist));
+       return Control::getControl<GenContainer>(genlist);
 }
 
 GenItem *GenItem::getNextItem() const
index 0cca7f2..36e20cf 100644 (file)
  */
 
 #include "Ui/Naviframe.h"
-#include "Ui/NaviframePage.h"
-#include "Ui/View.h"
 #include "Utils/Callback.h"
 
 using namespace Ui;
 
+namespace Ui
+{
+       template <>
+       Navigator *Control::findParent<Navigator>(Evas_Object *object)
+       {
+               return findParent<Naviframe>(object);
+       }
+}
+
 Naviframe::Naviframe()
-       : Navigator(TypeStackNavigator), m_Job(nullptr),
+       : m_Job(nullptr),
          m_IsFirstPagePrevButtonVisible(false)
 {
 }
index 8c2ddc0..bc294da 100644 (file)
 
 using namespace Ui;
 
-namespace Ui
-{
-       template <>
-       Navigator *Control::findParent<Navigator>(Evas_Object *object)
-       {
-               return static_cast<Navigator *>(findParent(object, TypeStackNavigator));
-       }
-}
-
-Navigator::Navigator(NavigatorType type)
-       : View(type), m_CurrentPage(nullptr)
+Navigator::Navigator()
+       : m_CurrentPage(nullptr)
 {
 }
 
@@ -44,17 +35,9 @@ void Navigator::addView(View *view)
                return;
        }
 
-       Navigator *stackNavi = m_StackNavi;
-       Navigator *tabNavi = m_TabNavi;
-       if (getType() == TypeStackNavigator) {
-               stackNavi = this;
-       } else {
-               tabNavi = this;
-       }
-
        NavigatorPage *page = addPage(view);
        page->onNavigatorAttached(this, view);
-       view->onNavigatorAttached(stackNavi, tabNavi, page);
+       view->onNavigatorAttached(page);
 
        if (!m_CurrentPage) {
                navigateTo(view);
@@ -63,7 +46,7 @@ void Navigator::addView(View *view)
 
 bool Navigator::removeView(View *view)
 {
-       if (!view || view->getNavigator(NavigatorType(getType())) != this) {
+       if (!view) {
                return false;
        }
 
@@ -87,7 +70,7 @@ void Navigator::navigateTo(View *view)
                return;
        }
 
-       if (view->getNavigator(NavigatorType(getType())) != this) {
+       if (!view->getNavigator()) {
                addView(view);
        }
 
index f44ee5c..d776654 100644 (file)
@@ -25,8 +25,7 @@ using namespace Ui;
 using namespace std::placeholders;
 
 TabNavigator::TabNavigator(Selector *selector)
-       : Navigator(TypeTabNavigator),
-         m_Selector(selector)
+       : m_Selector(selector)
 {
        if (m_Selector) {
                m_Selector->setSelectCallback(std::bind(&TabNavigator::onSelected, this, _1));
index 4896570..989853f 100644 (file)
  */
 
 #include "Ui/View.h"
+#include "Ui/Navigator.h"
 
 using namespace Ui;
 
-namespace Ui
-{
-       template <>
-       View *Control::findParent<View>(Evas_Object *object)
-       {
-               return static_cast<View *>(findParent(object, TypeView));
-       }
-}
-
-View::View(int type)
-       : Control(type),
-         m_StackNavi(nullptr), m_TabNavi(nullptr), m_Page(nullptr),
+View::View()
+       : m_Page(nullptr),
          m_IsCurrent(false), m_Rotation(-1)
 {
 }
 
-Navigator *View::getNavigator(NavigatorType type) const
+Navigator *View::getNavigator() const
 {
-       return type == TypeStackNavigator ? m_StackNavi : m_TabNavi;
+       return findParent<Navigator>();
 }
 
 NavigatorPage *View::getPage() const
@@ -54,11 +45,8 @@ int View::getRotation() const
        return m_Rotation;
 }
 
-void View::onNavigatorAttached(Navigator *stackNavi, Navigator *tabNavi, NavigatorPage *page)
+void View::onNavigatorAttached(NavigatorPage *page)
 {
-       m_StackNavi = stackNavi;
-       m_TabNavi = tabNavi;
-
        if (m_Page) {
                m_Page->close();
        }
index 6a32d50..618af40 100644 (file)
@@ -28,12 +28,12 @@ namespace Ui
        template <>
        Window *Control::findParent<Window>(Evas_Object *object)
        {
-               return static_cast<Window *>(getControl(elm_object_top_widget_get(object)));
+               return getControl<Window>(elm_object_top_widget_get(object));
        }
 }
 
 Window::Window()
-       : Control(TypeWindow), m_Conform(nullptr), m_Layout(nullptr), m_MainView(nullptr)
+       : m_Conform(nullptr), m_Layout(nullptr), m_MainView(nullptr)
 {
 }
 
index 8bf281c..ad63c3b 100644 (file)
@@ -99,8 +99,7 @@ bool BasicInfoItem::onLongpressed()
        }
 
        Evas_Object *layout = elm_object_item_part_content_get(getObjectItem(), PART_THUMBNAIL);
-       Ui::Thumbnail *thumbnail = static_cast<Ui::Thumbnail *>(Ui::Control::getControl(layout));
-       Evas_Object *image = thumbnail->getImage();
+       Evas_Object *image = Ui::Control::getControl<Ui::Thumbnail>(layout)->getImage();
 
        auto menu = new Ui::Menu();
        menu->create(getParent()->getEvasObject());