Include <string> to compensate for core inclusion cleanup
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / keyinput-focus-manager-impl.cpp
1 /*
2  * Copyright (c) 2014 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 "keyinput-focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/common/stage.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/controls/control-impl.h>
27 #include <dali/integration-api/debug.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Internal
36 {
37
38 namespace
39 {
40
41 // Signals
42
43 const char* const SIGNAL_KEY_INPUT_FOCUS_CHANGED = "key-input-focus-changed";
44 const char* const SIGNAL_UNHANDLED_KEY_EVENT =     "unhandled-key-event";
45
46 }
47
48 KeyInputFocusManager::KeyInputFocusManager()
49 : mSlotDelegate( this )
50 {
51   Stage::GetCurrent().KeyEventSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
52   mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
53   mObjectRegistry.ObjectDestroyedSignal().Connect( this, &KeyInputFocusManager::OnObjectDestroyed );
54 }
55
56 KeyInputFocusManager::~KeyInputFocusManager()
57 {
58 }
59
60 void KeyInputFocusManager::SetFocus( Toolkit::Control control )
61 {
62   if( !control )
63   {
64     // No-op
65     return;
66   }
67
68   FocusStackIterator pos = FindFocusControlInStack( control );
69
70   if( ( mFocusStack.Count() != 0 ) && ( pos == mFocusStack.End()-1 ) )
71   {
72     // Control already in front, so No-op
73     return;
74   }
75
76   if( pos != mFocusStack.End() )
77   {
78     // A previously focused control wants to regain focus
79     mFocusStack.Erase( pos );
80   }
81   else
82   {
83     control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
84   }
85
86   Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
87   if( previousFocusControl )
88   {
89     // Notify the control that it has lost key input focus
90     previousFocusControl.GetImplementation().OnKeyInputFocusLost();
91   }
92
93   mFocusStack.PushBack( &control.GetBaseObject() );
94
95   // Tell the new actor that it has gained focus.
96   control.GetImplementation().OnKeyInputFocusGained();
97
98   // Emit the signal to inform focus change to the application.
99   if ( !mKeyInputFocusChangedSignal.Empty() )
100   {
101     mKeyInputFocusChangedSignal.Emit( control, previousFocusControl );
102   }
103 }
104
105 void KeyInputFocusManager::RemoveFocus( Toolkit::Control control )
106 {
107   if( control )
108   {
109     FocusStackIterator pos = FindFocusControlInStack( control );
110     if( pos != mFocusStack.End() )
111     {
112       control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
113
114       // Notify the control that it has lost key input focus
115       control.GetImplementation().OnKeyInputFocusLost();
116
117       // If this is the top-most actor, pop it and change focus to the previous control
118       if( pos == mFocusStack.End() - 1 )
119       {
120         mFocusStack.Erase( pos );
121
122         Toolkit::Control previouslyFocusedControl = GetCurrentFocusControl();
123         if( previouslyFocusedControl )
124         {
125           // Tell the control that it has gained focus.
126           previouslyFocusedControl.GetImplementation().OnKeyInputFocusGained();
127         }
128       }
129       else
130       {
131         // If the removed control is not currently focused, then no need to emit signal.
132         mFocusStack.Erase( pos );
133       }
134     }
135   }
136 }
137
138 Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
139 {
140   Toolkit::Control currentControl;
141
142   FocusStack::SizeType count = mFocusStack.Count();
143   if( count != 0 )
144   {
145     BaseObject* object = mFocusStack[ count - 1 ];
146     BaseHandle handle( object );
147     currentControl = Dali::Toolkit::Control::DownCast( handle );
148   }
149   return currentControl;
150 }
151
152 bool KeyInputFocusManager::IsKeyboardListener( Toolkit::Control control ) const
153 {
154   bool result = false;
155
156   if( FindFocusControlInStack( control ) != mFocusStack.End() )
157   {
158     result = true;
159   }
160
161   return result;
162 }
163
164 Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
165 {
166   return mKeyInputFocusChangedSignal;
167 }
168
169 Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalType& KeyInputFocusManager::UnhandledKeyEventSignal()
170 {
171   return mUnhandledKeyEventSignal;
172 }
173
174 KeyInputFocusManager::FocusStackIterator KeyInputFocusManager::FindFocusControlInStack( Toolkit::Control control ) const
175 {
176   BaseObject* controlObject = &control.GetBaseObject();
177   return std::find( mFocusStack.Begin(), mFocusStack.End(), controlObject );
178 }
179
180 void KeyInputFocusManager::OnKeyEvent( const KeyEvent& event )
181 {
182   bool consumed = false;
183
184   if( mFocusStack.Count() > 0 )
185   {
186     FocusStack::SizeType index = mFocusStack.Count();
187     while( mFocusStack.Count() != 0 && !consumed && index > 0 )
188     {
189       --index;
190       BaseObject* object = mFocusStack[ index ];
191       BaseHandle handle( object );
192       Toolkit::Control control = Toolkit::Control::DownCast( object );
193       if( control )
194       {
195         // Notify the control about the key event
196         consumed = control.GetImplementation().EmitKeyEventSignal( event );
197       }
198     }
199   }
200
201   if( !consumed )
202   {
203     // Emit signal to inform that a key event is not consumed.
204     if( !mUnhandledKeyEventSignal.Empty() )
205     {
206       mUnhandledKeyEventSignal.Emit(event);
207     }
208   }
209 }
210
211 void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor )
212 {
213   RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) );
214 }
215
216 void KeyInputFocusManager::OnObjectDestroyed( const Dali::RefObject* object )
217 {
218   // The object is already destroyed. Don't create handles to it, or try sending
219   // signals to it. Remove it's pointer from the stack.
220   const BaseObject* baseObject = static_cast<const BaseObject*>( object );
221   FocusStackIterator pos = std::find( mFocusStack.Begin(), mFocusStack.End(), baseObject );
222   if( pos != mFocusStack.End() )
223   {
224     mFocusStack.Erase( pos );
225   }
226 }
227
228 bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
229 {
230   Dali::BaseHandle handle( object );
231
232   bool connected( true );
233   KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>( object );
234
235   if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_CHANGED ) )
236   {
237     manager->KeyInputFocusChangedSignal().Connect( tracker, functor );
238   }
239   else if( 0 == strcmp( signalName.c_str(), SIGNAL_UNHANDLED_KEY_EVENT ) )
240   {
241     manager->UnhandledKeyEventSignal().Connect( tracker, functor );
242   }
243   else
244   {
245     // signalName does not match any signal
246     connected = false;
247   }
248
249   return connected;
250 }
251
252 } // namespace Internal
253
254 } // namespace Toolkit
255
256 } // namespace Dali