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