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