[AT-SPI] Require ControlAccessible for Control
[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::make_unique<TextAnchorAccessible>(actor, Dali::Accessibility::Role::LINK);
153   });
154 }
155
156 TextAnchor::TextAnchor()
157 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
158   mStartCharacterIndex(0),
159   mEndCharacterIndex(0),
160   mUri()
161 {
162 }
163
164 TextAnchor::~TextAnchor()
165 {
166 }
167
168 int32_t TextAnchor::TextAnchorAccessible::GetEndIndex() const
169 {
170   auto self = Toolkit::TextAnchor::DownCast(Self());
171   return self.GetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX).Get<int>();
172 }
173
174 int32_t TextAnchor::TextAnchorAccessible::GetStartIndex() const
175 {
176   auto self = Toolkit::TextAnchor::DownCast(Self());
177   return self.GetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX).Get<int>();
178 }
179
180 int32_t TextAnchor::TextAnchorAccessible::GetAnchorCount() const
181 {
182   return 1;
183 }
184
185 Dali::Accessibility::Accessible* TextAnchor::TextAnchorAccessible::GetAnchorAccessible(int32_t anchorIndex) const
186 {
187   return const_cast<TextAnchorAccessible*>(this);
188 }
189
190 std::string TextAnchor::TextAnchorAccessible::GetAnchorUri(int32_t anchorIndex) const
191 {
192   auto self = Toolkit::TextAnchor::DownCast(Self());
193   return self.GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
194 }
195
196 bool TextAnchor::TextAnchorAccessible::IsValid() const
197 {
198   return !GetAnchorUri(0).empty();
199 }
200
201 bool TextAnchor::OnAccessibilityActivated()
202 {
203   auto uri = Self().GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
204   if(!uri.empty())
205   {
206     Dali::Actor                                  current                             = Self();
207     Dali::Toolkit::Text::AnchorControlInterface* parentImplementationAnchorInterface = nullptr;
208     while(!current.GetProperty<bool>(Actor::Property::IS_ROOT) && !parentImplementationAnchorInterface)
209     {
210       Dali::Actor            parentAsActor        = current.GetParent();
211       Dali::CustomActor      parentAsCustomActor  = Dali::CustomActor::DownCast(parentAsActor);
212       Dali::CustomActorImpl& parentImplementation = parentAsCustomActor.GetImplementation();
213       parentImplementationAnchorInterface         = dynamic_cast<Dali::Toolkit::Text::AnchorControlInterface*>(&parentImplementation);
214       current                                     = parentAsActor;
215     }
216     if(parentImplementationAnchorInterface)
217     {
218       parentImplementationAnchorInterface->AnchorClicked(uri);
219       return true;
220     }
221     else
222     {
223       DALI_LOG_ERROR("TextAnchor::OnAccessibilityActivate cannot find ancestor actor implementing Dali::Toolkit::Text::AnchorControlInterface.\n");
224     }
225   }
226   return false;
227 }
228
229 } // namespace Internal
230
231 } // namespace Toolkit
232
233 } // namespace Dali