[dali_2.1.0] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-anchor-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/text-controls/text-anchor-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/object/property-helper-devel.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27
28 // INTERNAL INCLUDES
29
30 // DEVEL INCLUDES
31 #include <dali-toolkit/devel-api/controls/control-devel.h>
32
33 using namespace Dali::Toolkit::Text;
34
35 namespace Dali
36 {
37 namespace Toolkit
38 {
39 namespace Internal
40 {
41 namespace
42 {
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
45 #endif
46
47 // Type registration
48 BaseHandle Create()
49 {
50   return Toolkit::TextAnchor::New();
51 }
52
53 // clang-format off
54 // Setup properties, signals and actions using the type-registry.
55 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextAnchor, Toolkit::Control, Create);
56
57 DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "startCharacterIndex", INTEGER, START_CHARACTER_INDEX)
58 DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "endCharacterIndex",   INTEGER, END_CHARACTER_INDEX  )
59 DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "uri",                 STRING,  URI        )
60
61 DALI_TYPE_REGISTRATION_END()
62 // clang-format on
63
64 } // namespace
65
66 Toolkit::TextAnchor TextAnchor::New()
67 {
68   // Create the implementation, temporarily owned by this handle on stack
69   IntrusivePtr<TextAnchor> impl = new TextAnchor();
70
71   // Pass ownership to CustomActor handle
72   Toolkit::TextAnchor handle(*impl);
73
74   // Second-phase init of the implementation
75   // This can only be done after the CustomActor connection has been made...
76   impl->Initialize();
77
78   return handle;
79 }
80
81 Property::Value TextAnchor::GetProperty(BaseObject* object, Property::Index index)
82 {
83   Property::Value value;
84
85   Toolkit::TextAnchor anchor = Toolkit::TextAnchor::DownCast(Dali::BaseHandle(object));
86
87   if(anchor)
88   {
89     TextAnchor& impl(GetImpl(anchor));
90
91     switch(index)
92     {
93       case Toolkit::TextAnchor::Property::START_CHARACTER_INDEX:
94       {
95         value = impl.mStartCharacterIndex;
96         break;
97       }
98       case Toolkit::TextAnchor::Property::END_CHARACTER_INDEX:
99       {
100         value = impl.mEndCharacterIndex;
101         break;
102       }
103       case Toolkit::TextAnchor::Property::URI:
104       {
105         value = impl.mUri;
106         break;
107       }
108     }
109   }
110
111   return value;
112 }
113
114 void TextAnchor::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
115 {
116   Toolkit::TextAnchor anchor = Toolkit::TextAnchor::DownCast(Dali::BaseHandle(object));
117
118   if(anchor)
119   {
120     TextAnchor& impl(GetImpl(anchor));
121     switch(index)
122     {
123       case Toolkit::TextAnchor::Property::START_CHARACTER_INDEX:
124       {
125         value.Get(impl.mStartCharacterIndex);
126         break;
127       }
128
129       case Toolkit::TextAnchor::Property::END_CHARACTER_INDEX:
130       {
131         value.Get(impl.mEndCharacterIndex);
132         break;
133       }
134
135       case Toolkit::TextAnchor::Property::URI:
136       {
137         value.Get(impl.mUri);
138         break;
139       }
140     }
141   }
142 }
143
144 void TextAnchor::OnInitialize()
145 {
146   Actor self = Self();
147
148   // Enable highlightability
149   self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
150
151   DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
152     return std::unique_ptr<Dali::Accessibility::Accessible>(
153       new AccessibleImpl(actor, Dali::Accessibility::Role::LINK));
154   });
155 }
156
157 TextAnchor::TextAnchor()
158 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))
159 {
160 }
161
162 TextAnchor::~TextAnchor()
163 {
164 }
165
166 int32_t TextAnchor::AccessibleImpl::GetEndIndex() const
167 {
168   auto self = Toolkit::TextAnchor::DownCast(Self());
169   return self.GetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX).Get<int>();
170 }
171
172 int32_t TextAnchor::AccessibleImpl::GetStartIndex() const
173 {
174   auto self = Toolkit::TextAnchor::DownCast(Self());
175   return self.GetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX).Get<int>();
176 }
177
178 int32_t TextAnchor::AccessibleImpl::GetAnchorCount() const
179 {
180   return 1;
181 }
182
183 Dali::Accessibility::Accessible* TextAnchor::AccessibleImpl::GetAnchorAccessible(int32_t anchorIndex) const
184 {
185   return Control::Impl::GetAccessibilityObject(Self());
186 }
187
188 std::string TextAnchor::AccessibleImpl::GetAnchorUri(int32_t anchorIndex) const
189 {
190   auto self = Toolkit::TextAnchor::DownCast(Self());
191   return self.GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
192 }
193
194 bool TextAnchor::AccessibleImpl::IsValid() const
195 {
196   return !GetAnchorUri(0).empty();
197 }
198
199 bool TextAnchor::OnAccessibilityActivated()
200 {
201   auto uri = Self().GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
202   if(!uri.empty())
203   {
204     Dali::Actor                                  current                             = Self();
205     Dali::Toolkit::Text::AnchorControlInterface* parentImplementationAnchorInterface = nullptr;
206     while(!current.GetProperty<bool>(Actor::Property::IS_ROOT) && !parentImplementationAnchorInterface)
207     {
208       Dali::Actor            parentAsActor        = current.GetParent();
209       Dali::CustomActor      parentAsCustomActor  = Dali::CustomActor::DownCast(parentAsActor);
210       Dali::CustomActorImpl& parentImplementation = parentAsCustomActor.GetImplementation();
211       parentImplementationAnchorInterface         = dynamic_cast<Dali::Toolkit::Text::AnchorControlInterface*>(&parentImplementation);
212       current                                     = parentAsActor;
213     }
214     if(parentImplementationAnchorInterface)
215     {
216       parentImplementationAnchorInterface->AnchorClicked(uri);
217       return true;
218     }
219     else
220     {
221       DALI_LOG_ERROR("TextAnchor::OnAccessibilityActivate cannot find ancestor actor implementing Dali::Toolkit::Text::AnchorControlInterface.\n");
222     }
223   }
224   return false;
225 }
226
227 } // namespace Internal
228
229 } // namespace Toolkit
230
231 } // namespace Dali