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 
16 #ifndef META_API_PROPERTY_DEFAULT_VALUE_BIND_H
17 #define META_API_PROPERTY_DEFAULT_VALUE_BIND_H
18 
19 #include <meta/api/make_callback.h>
20 #include <meta/base/interface_macros.h>
21 #include <meta/interface/property/property.h>
22 #include <meta/interface/property/property_events.h>
23 
META_BEGIN_NAMESPACE()24 META_BEGIN_NAMESPACE()
25 
26 /**
27  * @brief A helper class for binding the default value of a property to the value of a source property
28  */
29 class DefaultValueBind final {
30 public:
31     DefaultValueBind() = default;
32     explicit DefaultValueBind(const IProperty::Ptr& property) : property_(property) {}
33     ~DefaultValueBind()
34     {
35         UnBind();
36         property_.reset();
37     }
38     DefaultValueBind(const DefaultValueBind& other) : property_(other.property_)
39     {
40         Bind(other.source_.lock());
41     }
42     DefaultValueBind(DefaultValueBind&& other) : property_(other.property_)
43     {
44         Bind(other.source_.lock());
45         other.UnBind();
46         other.property_ = nullptr;
47     }
48     DefaultValueBind& operator=(const DefaultValueBind& other)
49     {
50         UnBind();
51         property_ = other.property_;
52         Bind(other.source_.lock());
53         return *this;
54     }
55     DefaultValueBind& operator=(DefaultValueBind&& other)
56     {
57         UnBind();
58         property_ = other.property_;
59         Bind(other.source_.lock());
60         other.UnBind();
61         other.property_ = nullptr;
62         return *this;
63     }
64 
65     bool Bind(const IProperty::ConstPtr& source)
66     {
67         if (source == source_.lock()) {
68             return true; // No change
69         }
70         UnBind();
71         const auto property = property_.lock();
72         if (property && source) {
73             source_ = source;
74             token_ = source->OnChanged()->AddHandler(MakeCallback<IOnChanged>([this]() {
75                 const auto property = property_.lock();
76                 const auto source = source_.lock();
77                 if (property && source) {
78                     if (auto s = interface_cast<IStackProperty>(property)) {
79                         s->SetDefaultValue(source->GetValue());
80                     }
81                 }
82             }));
83             if (auto s = interface_cast<IStackProperty>(property)) {
84                 s->SetDefaultValue(source->GetValue());
85             }
86         }
87         return token_ != 0;
88     }
89     void UnBind()
90     {
91         if (token_) {
92             if (const auto source = source_.lock()) {
93                 source->OnChanged()->RemoveHandler(token_);
94             }
95             token_ = {};
96             source_.reset();
97         }
98     }
99     void SetProperty(const IProperty::Ptr& property)
100     {
101         UnBind();
102         property_ = property;
103     }
104     IProperty::Ptr GetProperty() const
105     {
106         return property_.lock();
107     }
108     bool IsDefaultValue() const
109     {
110         if (token_) {
111             if (auto p = GetProperty()) {
112                 PropertyLock s { p };
113                 return s.IsDefaultValue();
114             }
115         }
116         return false;
117     }
118 
119 private:
120     IProperty::WeakPtr property_;
121     IProperty::ConstWeakPtr source_;
122     IEvent::Token token_ {};
123 };
124 
125 META_END_NAMESPACE()
126 
127 #endif
128