1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef META_SRC_OBJECT_HIERARCHY_OBSERVER_H
16 #define META_SRC_OBJECT_HIERARCHY_OBSERVER_H
17
18 #include <mutex>
19 #include <shared_mutex>
20
21 #include <base/containers/unordered_map.h>
22
23 #include <meta/api/event_handler.h>
24 #include <meta/base/interface_macros.h>
25 #include <meta/base/namespace.h>
26 #include <meta/ext/event_impl.h>
27 #include <meta/interface/builtin_objects.h>
28 #include <meta/interface/intf_attachment.h>
29 #include <meta/interface/intf_object_hierarchy_observer.h>
30
31 #include "object.h"
32
META_BEGIN_NAMESPACE()33 META_BEGIN_NAMESPACE()
34
35 namespace Internal {
36
37 class ObjectHierarchyObserver;
38
39 class ObjectChangeListener final {
40 public:
41 META_NO_COPY_MOVE(ObjectChangeListener)
42 ObjectChangeListener() = delete;
43 ~ObjectChangeListener();
44
45 ObjectChangeListener(const IObject::Ptr& object, HierarchyChangeObjectType myType, const IObject::WeakPtr& parent,
46 ObjectHierarchyObserver* observer, HierarchyChangeModeValue mode);
47
48 HierarchyChangeObjectType GetType() const
49 {
50 return type_;
51 }
52
53 private:
54 bool Subscribe(HierarchyChangeModeValue mode);
55 void Unsubscribe();
56
57 void SubscribeContainer(const IObject::Ptr& object);
58 void SubscribeAttachment(const IObject::Ptr& object);
59
60 IObject::WeakPtr object_;
61 HierarchyChangeObjectType type_;
62 IObject::WeakPtr parent_;
63
64 // Currently IContent does not support "OnChanging" and so the content might be destroyed already
65 // which would make it impossible to notify about
66 IObject::Ptr content_;
67
68 ObjectHierarchyObserver* observer_ {};
69 BASE_NS::vector<EventHandler> handlers_;
70 bool containerPreTransaction_ { false };
71 bool attachmentPreTransaction_ { false };
72
73 void NotifyObjectChangedOp();
74 void NotifyContainerChangeOp(
75 const ChildChangedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType);
76 void NotifyContainerMoveOp(
77 const ChildChangedInfo& info, HierarchyChangeType operation, HierarchyChangeObjectType objectType);
78 void NotifyContentChangeOp();
79 };
80
81 class ObjectHierarchyObserver final : public IntroduceInterfaces<MetaObject, IObjectHierarchyObserver, IAttachment> {
82 META_OBJECT(ObjectHierarchyObserver, META_NS::ClassId::ObjectHierarchyObserver, IntroduceInterfaces)
83 public:
84 void HierarchyChanged(const HierarchyChangedInfo& info, ObjectChangeListener* listener);
85
86 META_BEGIN_STATIC_DATA()
87 META_STATIC_EVENT_DATA(IObjectHierarchyObserver, IOnHierarchyChanged, OnHierarchyChanged)
88 META_STATIC_PROPERTY_DATA(IAttachment, IObject::WeakPtr, DataContext)
89 META_STATIC_PROPERTY_DATA(IAttachment, IAttach::WeakPtr, AttachedTo, {}, DEFAULT_PROPERTY_FLAGS_NO_SER)
90 META_END_STATIC_DATA()
91 META_IMPLEMENT_EVENT(IOnHierarchyChanged, OnHierarchyChanged)
92 META_IMPLEMENT_READONLY_PROPERTY(IObject::WeakPtr, DataContext)
93 META_IMPLEMENT_READONLY_PROPERTY(IAttach::WeakPtr, AttachedTo)
94
95 protected: // LifeCycle
96 bool Build(const IMetadata::Ptr&) override;
97 void Destroy() override;
98
99 protected: // IObjectHierarchyObserver
100 void SetTarget(const IObject::Ptr& root, HierarchyChangeModeValue mode) override;
101 IObject::Ptr GetTarget() const override;
102 BASE_NS::vector<IObject::Ptr> GetAllObserved() const override;
103
104 protected: // IAttachment
105 bool Attaching(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext) override;
106 bool Detaching(const META_NS::IAttach::Ptr& target) override;
107
108 private:
109 void Subscribe(const IObject::Ptr& root, HierarchyChangeObjectType type, const IObject::WeakPtr& parent = nullptr);
110 void Unsubscribe(const IObject::Ptr& root);
111 void ClearSubscriptions();
112 void NotifyOnDetach();
113
114 HierarchyChangeModeValue mode_ {};
115 IObject::WeakPtr root_;
116
117 struct Subscription final {
118 META_NO_COPY(Subscription)
119 Subscription(IObject::WeakPtr object, BASE_NS::unique_ptr<ObjectChangeListener>&& listener)
120 : object_(BASE_NS::move(object)), listener_(BASE_NS::move(listener))
121 {}
122 ~Subscription() = default;
123 Subscription(Subscription&& other) noexcept = default;
124 Subscription& operator=(Subscription&& other) = default;
125 IObject::WeakPtr object_;
126 BASE_NS::unique_ptr<ObjectChangeListener> listener_;
127 };
128
129 void AddSubscription(const IObject::Ptr& object, HierarchyChangeObjectType type, const IObject::WeakPtr& parent);
130 void RemoveSubscription(const IObject::Ptr& object);
131
132 void AddImmediateChild(const HierarchyChangedInfo& info);
133 void RemoveImmediateChild(const HierarchyChangedInfo& info);
134
135 BASE_NS::unordered_map<ObjectChangeListener*, Subscription> subscriptions_;
136 struct ImmediateChild {
137 BASE_NS::weak_ptr<IObject> object;
138 HierarchyChangeObjectType type {};
139 };
140 bool keepTrackOfImmediate_ {};
141 BASE_NS::vector<ImmediateChild> immediateChildren_;
142 mutable std::shared_mutex mutex_;
143 };
144
145 } // namespace Internal
146
147 META_END_NAMESPACE()
148
149 #endif // META_SRC_OBJECT_HIERARCHY_OBSERVER_H
150