[AT-SPI] Squashed implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / popup / confirmation-popup-impl.cpp
1 /*
2  * Copyright (c) 2020 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 "confirmation-popup-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <cstring>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Internal
36 {
37
38 namespace
39 {
40
41 /*
42  * This struct is used to define all details required about a dynamically created signal.
43  */
44 struct ControlDetailType
45 {
46   const char* signalName;
47   const char* controlName;
48   const char* connectSignalPropertyName;
49 };
50
51 /* A table of all control details. These details are kept in one place for maintainability.
52  *  Name of the signal     | Name of the control  | Name of the property which lets the
53  *  the app-developer      | which will provide   | app developer choose which signal
54  *  can connect to.        | the signal.          | within the control to connect to.    */
55 const ControlDetailType ControlDetails[] = {
56   { "controlSignalOk",       "controlOk",           "connectSignalOkSelected"     },
57   { "controlSignalCancel",   "controlCancel",       "connectSignalCancelSelected" },
58 };
59 const unsigned int ControlDetailsCount = sizeof( ControlDetails ) / sizeof( ControlDetails[0] );
60
61 // To give sensible default behaviour to save the connect signal properties being set.
62 const char* const DEFAULT_CONNECT_SIGNAL_NAME = "clicked";
63
64 BaseHandle Create()
65 {
66   return Toolkit::ConfirmationPopup::New();
67 }
68
69 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ConfirmationPopup, Toolkit::Popup, Create )
70
71 DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[0].connectSignalPropertyName, STRING, CONNECT_SIGNAL_OK_SELECTED     )
72 DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[1].connectSignalPropertyName, STRING, CONNECT_SIGNAL_CANCEL_SELECTED )
73
74 // Note: We do not use the macros for signal registration as we do not want to redefine the signal name strings.
75 // We have predefined them for optimal signal name to control name lookup.
76 SignalConnectorType signalConnector1( typeRegistration, ControlDetails[0].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal );
77 SignalConnectorType signalConnector2( typeRegistration, ControlDetails[1].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal );
78
79 DALI_TYPE_REGISTRATION_END()
80
81 } // Unnamed namespace
82
83 Dali::Toolkit::ConfirmationPopup ConfirmationPopup::New()
84 {
85   // Create the implementation, temporarily owned on stack.
86   IntrusivePtr< ConfirmationPopup > internalConfirmationPopup = new ConfirmationPopup();
87
88   // Pass ownership to CustomActor
89   Dali::Toolkit::ConfirmationPopup confirmationPopup( *internalConfirmationPopup );
90
91   // Second-phase initialisation of the implementation.
92   // This can only be done after the CustomActor connection has been made...
93   internalConfirmationPopup->Initialize();
94
95   return confirmationPopup;
96 }
97
98 ConfirmationPopup::ConfirmationPopup()
99 : Toolkit::Internal::Popup()
100 {
101   mControlSignals.reserve( MAXIMUM_NUMBER_OF_CONTROLS );
102   mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_OK ] = DEFAULT_CONNECT_SIGNAL_NAME;
103   mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_CANCEL ] = DEFAULT_CONNECT_SIGNAL_NAME;
104   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
105     return std::unique_ptr< Dali::Accessibility::Accessible >(
106         new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::DIALOG, true ) );
107   } );
108 }
109
110 ConfirmationPopup::~ConfirmationPopup()
111 {
112   for( SignalContainerType::iterator i = mControlSignals.begin(); i != mControlSignals.end(); ++i )
113   {
114     delete ( i->second );
115   }
116   mControlSignals.clear();
117 }
118
119 void ConfirmationPopup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
120 {
121   Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) );
122
123   if ( popup )
124   {
125     ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) );
126
127     switch ( propertyIndex )
128     {
129       case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED:
130       {
131         popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK, value.Get< std::string >() );
132         break;
133       }
134       case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED:
135       {
136         popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL, value.Get< std::string >() );
137         break;
138       }
139     }
140   }
141 }
142
143 Property::Value ConfirmationPopup::GetProperty( BaseObject* object, Property::Index propertyIndex )
144 {
145   Property::Value value;
146
147   Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) );
148
149   if ( popup )
150   {
151     ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) );
152
153     switch ( propertyIndex )
154     {
155       case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED:
156       {
157         value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK );
158         break;
159       }
160       case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED:
161       {
162         value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL );
163         break;
164       }
165     }
166   }
167
168   return value;
169 }
170
171 void ConfirmationPopup::SetControlSignalName( const unsigned int controlNumber, const std::string& signalName )
172 {
173   if( controlNumber < ControlDetailsCount )
174   {
175     mControlSignalNames[ controlNumber ] = signalName;
176   }
177 }
178
179 std::string ConfirmationPopup::GetControlSignalName( unsigned int controlNumber ) const
180 {
181   if( controlNumber < ControlDetailsCount )
182   {
183     return mControlSignalNames[ controlNumber ];
184   }
185
186   return "";
187 }
188
189 bool ConfirmationPopup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
190 {
191   Dali::BaseHandle handle( object );
192   Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( handle );
193
194   // Look up the requested signal, attempting to create it dynamically if it doesn't exist.
195   SignalDelegate* signalDelegate = Dali::Toolkit::GetDerivedImplementation( popup ).GetControlSignal( signalName );
196   if( signalDelegate )
197   {
198     // The signal delegate was created successfully, attempt to connect it to a callback if specified.
199     // If none is specified, the creation is still successful as the signal delegate can connect at a later time.
200     if( functor )
201     {
202       signalDelegate->Connect( tracker, functor );
203     }
204     return true;
205   }
206
207   // The signal could not be created.
208   return false;
209 }
210
211 SignalDelegate* ConfirmationPopup::GetControlSignal( const std::string& signalName )
212 {
213   // Check if the specified signal name already exists.
214   SignalContainerType::iterator end = mControlSignals.end();
215   for( SignalContainerType::iterator iter = mControlSignals.begin(); iter != end; ++iter )
216   {
217     // Find the first non-connected signal by matching signal name.
218     if( ( signalName == iter->first ) && ( !iter->second->IsConnected() ) )
219     {
220       // The requested signal (delegate) already exists, just return it.
221       return iter->second;
222     }
223   }
224
225   // The signal doesn't exist, or it does but it's already connected to something else.
226   // To make a new connection to an existing signal, we need a new delegate,
227   // as delegates house a signal connection functor each.
228   // Check the signal name is valid and if so create the signal dynamically.
229   for( unsigned int i = 0; i < ControlDetailsCount; ++i )
230   {
231     if( 0 == strcmp( signalName.c_str(), ControlDetails[ i ].signalName ) )
232     {
233       // The signal name is valid, check the respective actor to connect to exists.
234       Actor connectActor = Self().FindChildByName( ControlDetails[ i ].controlName );
235       if( connectActor )
236       {
237         // The actor exists, set up a signal delegate that will allow the application developer
238         // to connect the actor signal directly to their callback.
239         // Note: We don't use the GetControlSignalName() here for speedup, as we know the array bound is capped.
240         SignalDelegate* signalDelegate = new SignalDelegate( connectActor, mControlSignalNames[ i ] );
241
242         // Store the delegate with the signal name so we know what signals have been dynamically created so far.
243         mControlSignals.push_back( std::make_pair( signalName, signalDelegate ) );
244
245         // Return the delegate to allow connection to the newly created signal.
246         return signalDelegate;
247       }
248
249       // Signal name valid but could not connect to the control,
250       return NULL;
251     }
252   }
253
254   // Signal name was not found (invalid).
255   return NULL;
256 }
257
258
259 } // namespace Internal
260
261 } // namespace Toolkit
262
263 } // namespace Dali