TextView - Right to Left implementation.
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / focus-manager / keyboard-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 "keyboard-focus-manager-impl.h"
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/control.h>
23 #include <dali-toolkit/public-api/controls/control-impl.h>
24 #include <dali-toolkit/public-api/focus-manager/focus-manager.h>
25 #include <dali-toolkit/public-api/focus-manager/keyinput-focus-manager.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Internal
35 {
36
37 namespace // unnamed namespace
38 {
39
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEYBOARD_FOCUS_MANAGER");
42 #endif
43
44 const std::string IS_FOCUS_GROUP_PROPERTY_NAME("is-keyboard-focus-group"); // This property will be replaced by a flag in Control.
45
46 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "keyboard_focus.png";
47 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
48
49 BaseHandle Create()
50 {
51   BaseHandle handle = KeyboardFocusManager::Get();
52
53   if ( !handle )
54   {
55     SingletonService singletonService( SingletonService::Get() );
56     if ( singletonService )
57     {
58       Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager( new Internal::KeyboardFocusManager() );
59       singletonService.Register( typeid( manager ), manager );
60       handle = manager;
61     }
62   }
63
64   return handle;
65 }
66 TypeRegistration KEYBOARD_FOCUS_MANAGER_TYPE( typeid(Dali::Toolkit::KeyboardFocusManager), typeid(Dali::BaseHandle), Create, true /* Create instance at startup */ );
67
68 } // unnamed namespace
69
70 Toolkit::KeyboardFocusManager KeyboardFocusManager::Get()
71 {
72   Toolkit::KeyboardFocusManager manager;
73
74   SingletonService singletonService( SingletonService::Get() );
75   if ( singletonService )
76   {
77     // Check whether the keyboard focus manager is already created
78     Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::KeyboardFocusManager ) );
79     if(handle)
80     {
81       // If so, downcast the handle of singleton to keyboard focus manager
82       manager = Toolkit::KeyboardFocusManager( dynamic_cast< KeyboardFocusManager* >( handle.GetObjectPtr() ) );
83     }
84   }
85
86   return manager;
87 }
88
89 KeyboardFocusManager::KeyboardFocusManager()
90 : mCurrentFocusActor(0),
91   mFocusIndicatorActor(Actor()),
92   mFocusGroupLoopEnabled(false),
93   mIsKeyboardFocusEnabled(false),
94   mIsFocusIndicatorEnabled(false),
95   mIsWaitingKeyboardFocusChangeCommit(false),
96   mSlotDelegate(this)
97 {
98   CreateDefaultFocusIndicatorActor();
99
100   OnPhysicalKeyboardStatusChanged(PhysicalKeyboard::Get());
101
102   Toolkit::KeyInputFocusManager::Get().UnhandledKeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
103   Stage::GetCurrent().TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouched);
104   PhysicalKeyboard::Get().StatusChangedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnPhysicalKeyboardStatusChanged);
105 }
106
107 KeyboardFocusManager::~KeyboardFocusManager()
108 {
109 }
110
111 bool KeyboardFocusManager::SetCurrentFocusActor(Actor actor)
112 {
113   DALI_ASSERT_DEBUG( !mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?" );
114
115   if(actor)
116   {
117     return DoSetCurrentFocusActor(actor.GetId());
118   }
119
120   return false;
121 }
122
123 bool KeyboardFocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
124 {
125   Actor rootActor = Stage::GetCurrent().GetRootLayer();
126   Actor actor = rootActor.FindChildById(actorID);
127
128   // Check whether the actor is in the stage
129   if(actor)
130   {
131     // Set the focus only when the actor is keyboard focusable
132     if(actor.IsKeyboardFocusable())
133     {
134       // Draw the focus indicator upon the focused actor
135       if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
136       {
137         actor.Add(mFocusIndicatorActor);
138       }
139
140       // Send notification for the change of focus actor
141       if( !mFocusChangedSignalV2.Empty() )
142       {
143         mFocusChangedSignalV2.Emit(GetCurrentFocusActor(), actor);
144       }
145
146       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__);
147
148       // Save the current focused actor
149       mCurrentFocusActor = actorID;
150
151       // Move the accessibility focus to the same actor
152 //      Toolkit::FocusManager focusManager = Toolkit::FocusManager::Get();
153 //      focusManager.SetCurrentFocusActor(actor);
154
155       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
156       return true;
157     }
158   }
159
160   DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
161   return false;
162 }
163
164 Actor KeyboardFocusManager::GetCurrentFocusActor()
165 {
166   Actor rootActor = Stage::GetCurrent().GetRootLayer();
167   return rootActor.FindChildById(mCurrentFocusActor);
168 }
169
170 Actor KeyboardFocusManager::GetCurrentFocusGroup()
171 {
172   return GetFocusGroup(GetCurrentFocusActor());
173 }
174
175 bool KeyboardFocusManager::IsLayoutControl(Actor actor) const
176 {
177   Toolkit::Control control = Toolkit::Control::DownCast(actor);
178   return control && control.GetImplementation().IsKeyboardNavigationSupported();
179 }
180
181 Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const
182 {
183   // Get the actor's parent layout control that supports two dimensional keyboard navigation
184   Actor rootActor = Stage::GetCurrent().GetRootLayer();
185   Actor parent;
186   if(actor)
187   {
188     parent = actor.GetParent();
189   }
190
191   while( parent && !IsLayoutControl(parent) && parent != rootActor )
192   {
193     parent = parent.GetParent();
194   }
195
196   return Toolkit::Control::DownCast(parent);
197 }
198
199 bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocusNavigationDirection direction)
200 {
201   Actor currentFocusActor = GetCurrentFocusActor();
202
203   bool succeed = false;
204
205   // Go through the actor's hierarchy until we find a layout control that knows how to move the focus
206   Toolkit::Control parentLayoutControl = GetParentLayoutControl(currentFocusActor);
207   while(parentLayoutControl && !succeed)
208   {
209     succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction);
210     parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
211   }
212
213   if(!succeed && !mPreFocusChangeSignalV2.Empty())
214   {
215     // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to
216     mIsWaitingKeyboardFocusChangeCommit = true;
217     Actor nextFocusableActor = mPreFocusChangeSignalV2.Emit(currentFocusActor, Actor(), direction);
218     mIsWaitingKeyboardFocusChangeCommit = false;
219
220     if ( nextFocusableActor && nextFocusableActor.IsKeyboardFocusable() )
221     {
222       // Whether the next focusable actor is a layout control
223       if(IsLayoutControl(nextFocusableActor))
224       {
225         // If so, move the focus inside it.
226         Toolkit::Control layoutControl = Toolkit::Control::DownCast(nextFocusableActor);
227         succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
228       }
229       else
230       {
231         // Otherwise, just set focus to the next focusable actor
232         succeed = SetCurrentFocusActor(nextFocusableActor);
233       }
234     }
235   }
236
237   return succeed;
238 }
239
240 bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction)
241 {
242   // Ask the control for the next actor to focus
243   Actor nextFocusableActor = control.GetImplementation().GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled);
244   if(nextFocusableActor)
245   {
246     if(!nextFocusableActor.IsKeyboardFocusable())
247     {
248       // If the actor is not focusable, ask the same layout control for the next actor to focus
249       return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction);
250     }
251     else
252     {
253       Actor currentFocusActor = GetCurrentFocusActor();
254       Actor committedFocusActor = nextFocusableActor;
255
256       // We will try to move the focus to the actor. Emit a signal to notify the proposed actor to focus
257       // Signal handler can check the proposed actor and return a different actor if it wishes.
258       if( !mPreFocusChangeSignalV2.Empty() )
259       {
260         mIsWaitingKeyboardFocusChangeCommit = true;
261         committedFocusActor = mPreFocusChangeSignalV2.Emit(currentFocusActor, nextFocusableActor, direction);
262         mIsWaitingKeyboardFocusChangeCommit = false;
263       }
264
265       if (committedFocusActor && committedFocusActor.IsKeyboardFocusable())
266       {
267         // Whether the commited focusable actor is a layout control
268         if(IsLayoutControl(committedFocusActor))
269         {
270           // If so, move the focus inside it.
271           Toolkit::Control layoutControl = Toolkit::Control::DownCast(committedFocusActor);
272           return DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
273         }
274         else
275         {
276           // Otherwise, just set focus to the next focusable actor
277           if(committedFocusActor == nextFocusableActor)
278           {
279             // If the application hasn't changed our proposed actor, we informs the layout control we will
280             // move the focus to what the control returns. The control might wish to perform some actions
281             // before the focus is actually moved.
282             control.GetImplementation().OnKeyboardFocusChangeCommitted(committedFocusActor);
283           }
284
285           return SetCurrentFocusActor(committedFocusActor);
286         }
287       }
288       else
289       {
290         return false;
291       }
292     }
293   }
294   else
295   {
296     // No more actor can be focused in the given direction within the same layout control.
297     return false;
298   }
299 }
300
301 bool KeyboardFocusManager::DoMoveFocusToNextFocusGroup(bool forward)
302 {
303   bool succeed = false;
304
305   // Get the parent layout control of the current focus group
306   Toolkit::Control parentLayoutControl = GetParentLayoutControl(GetCurrentFocusGroup());
307
308   while(parentLayoutControl && !succeed)
309   {
310     // If the current focus group has a parent layout control, we can probably automatically
311     // move the focus to the next focus group in the forward or backward direction.
312     Toolkit::Control::KeyboardFocusNavigationDirection direction = forward ? Toolkit::Control::Right : Toolkit::Control::Left;
313     succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction);
314     parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
315   }
316
317   if(!mFocusGroupChangedSignalV2.Empty())
318   {
319     // Emit a focus group changed signal. The applicaton can move the focus to a new focus group
320     mFocusGroupChangedSignalV2.Emit(GetCurrentFocusActor(), forward);
321   }
322
323   return succeed;
324 }
325
326 void KeyboardFocusManager::DoActivate(Actor actor)
327 {
328   if(actor)
329   {
330     Toolkit::Control control = Toolkit::Control::DownCast(actor);
331     if(control)
332     {
333       // Notify the control that it is activated
334       control.GetImplementation().OnActivated();
335     }
336
337     // Send notification for the activation of focused actor
338     if( !mFocusedActorActivatedSignalV2.Empty() )
339     {
340       mFocusedActorActivatedSignalV2.Emit(actor);
341     }
342   }
343 }
344
345 void KeyboardFocusManager::ClearFocus()
346 {
347   Actor actor = GetCurrentFocusActor();
348   if(actor)
349   {
350     if(mFocusIndicatorActor)
351     {
352       actor.Remove(mFocusIndicatorActor);
353     }
354
355     // Send notification for the change of focus actor
356     if( !mFocusChangedSignalV2.Empty() )
357     {
358       mFocusChangedSignalV2.Emit(actor, Actor());
359     }
360   }
361
362   mCurrentFocusActor = 0;
363   mIsFocusIndicatorEnabled = false;
364 }
365
366 void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
367 {
368   mFocusGroupLoopEnabled = enabled;
369 }
370
371 bool KeyboardFocusManager::GetFocusGroupLoop() const
372 {
373   return mFocusGroupLoopEnabled;
374 }
375
376 void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
377 {
378   if(actor)
379   {
380     // Create focus group property if not already created.
381     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
382     if(propertyIsFocusGroup == Property::INVALID_INDEX)
383     {
384       propertyIsFocusGroup = actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup);
385     }
386     else
387     {
388       actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
389     }
390   }
391 }
392
393 bool KeyboardFocusManager::IsFocusGroup(Actor actor) const
394 {
395   // Check whether the actor is a focus group
396   bool isFocusGroup = false;
397
398   if(actor)
399   {
400     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
401     if(propertyIsFocusGroup != Property::INVALID_INDEX)
402     {
403       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
404     }
405   }
406
407   return isFocusGroup;
408 }
409
410 Actor KeyboardFocusManager::GetFocusGroup(Actor actor)
411 {
412   // Go through the actor's hierarchy to check which focus group the actor belongs to
413   while (actor && !IsFocusGroup(actor))
414   {
415     actor = actor.GetParent();
416   }
417
418   return actor;
419 }
420
421 void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator)
422 {
423   if(mFocusIndicatorActor != indicator)
424   {
425     Actor currentFocusActor = GetCurrentFocusActor();
426     if(currentFocusActor)
427     {
428       // The new focus indicator should be added to the current focused actor immediately
429       if(mFocusIndicatorActor)
430       {
431         currentFocusActor.Remove(mFocusIndicatorActor);
432       }
433
434       if(indicator)
435       {
436         currentFocusActor.Add(indicator);
437       }
438     }
439
440     mFocusIndicatorActor = indicator;
441   }
442 }
443
444 Actor KeyboardFocusManager::GetFocusIndicatorActor()
445 {
446   return mFocusIndicatorActor;
447 }
448
449 void KeyboardFocusManager::CreateDefaultFocusIndicatorActor()
450 {
451   // Create a focus indicator actor shared by all the keyboard focusable actors
452   Image borderImage = Image::New(FOCUS_BORDER_IMAGE_PATH);
453
454   ImageActor focusIndicator = ImageActor::New(borderImage);
455   focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
456   focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
457   focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
458   focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
459
460   // Apply size constraint to the focus indicator
461   Constraint constraint = Constraint::New<Vector3>(Actor::SIZE,
462                                                    ParentSource(Actor::SIZE),
463                                                    EqualToConstraint());
464   focusIndicator.ApplyConstraint(constraint);
465
466   SetFocusIndicatorActor(focusIndicator);
467 }
468
469 void KeyboardFocusManager::OnPhysicalKeyboardStatusChanged(PhysicalKeyboard keyboard)
470 {
471   mIsKeyboardFocusEnabled = keyboard.IsAttached();
472
473   if(mIsKeyboardFocusEnabled)
474   {
475     // Show indicator when keyboard focus turned on if there is focused actor.
476     Actor actor = GetCurrentFocusActor();
477     if(actor)
478     {
479       if(mFocusIndicatorActor)
480       {
481         actor.Add(mFocusIndicatorActor);
482       }
483     }
484     mIsFocusIndicatorEnabled = true;
485   }
486   else
487   {
488     // Hide indicator when keyboard focus turned off
489     Actor actor = GetCurrentFocusActor();
490     if(actor)
491     {
492       actor.Remove(mFocusIndicatorActor);
493     }
494     mIsFocusIndicatorEnabled = false;
495   }
496 }
497
498 void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
499 {
500   if(!mIsKeyboardFocusEnabled)
501   {
502     return;
503   }
504
505   AccessibilityManager accessibilityManager = AccessibilityManager::Get();
506   bool isAccessibilityEnabled = accessibilityManager.IsEnabled();
507
508   Toolkit::FocusManager accessibilityFocusManager = Toolkit::FocusManager::Get();
509
510   std::string keyName = event.keyPressedName;
511
512   bool isFocusStartableKey = false;
513
514   if(event.state == KeyEvent::Down)
515   {
516     if (keyName == "Left")
517     {
518       if(!isAccessibilityEnabled)
519       {
520         if(!mIsFocusIndicatorEnabled)
521         {
522           // Show focus indicator
523           mIsFocusIndicatorEnabled = true;
524         }
525         else
526         {
527           // Move the focus towards left
528           MoveFocus(Toolkit::Control::Left);
529         }
530
531         isFocusStartableKey = true;
532       }
533       else
534       {
535         // Move the accessibility focus backward
536         accessibilityFocusManager.MoveFocusBackward();
537       }
538     }
539     else if (keyName == "Right")
540     {
541       if(!isAccessibilityEnabled)
542       {
543         if(!mIsFocusIndicatorEnabled)
544         {
545           // Show focus indicator
546           mIsFocusIndicatorEnabled = true;
547         }
548         else
549         {
550           // Move the focus towards right
551           MoveFocus(Toolkit::Control::Right);
552         }
553
554         isFocusStartableKey = true;
555       }
556       else
557       {
558         // Move the accessibility focus forward
559         accessibilityFocusManager.MoveFocusForward();
560       }
561
562       isFocusStartableKey = true;
563     }
564     else if (keyName == "Up" && !isAccessibilityEnabled)
565     {
566       if(!mIsFocusIndicatorEnabled)
567       {
568         // Show focus indicator
569         mIsFocusIndicatorEnabled = true;
570       }
571       else
572       {
573         // Move the focus towards up
574         MoveFocus(Toolkit::Control::Up);
575       }
576
577       isFocusStartableKey = true;
578     }
579     else if (keyName == "Down" && !isAccessibilityEnabled)
580     {
581       if(!mIsFocusIndicatorEnabled)
582       {
583         // Show focus indicator
584         mIsFocusIndicatorEnabled = true;
585       }
586       else
587       {
588         // Move the focus towards down
589         MoveFocus(Toolkit::Control::Down);
590       }
591
592       isFocusStartableKey = true;
593     }
594     else if (keyName == "Tab" && !isAccessibilityEnabled)
595     {
596       if(!mIsFocusIndicatorEnabled)
597       {
598         // Show focus indicator
599         mIsFocusIndicatorEnabled = true;
600       }
601       else
602       {
603         // "Tab" key changes the focus group in the forward direction and
604         // "Shift-Tab" key changes it in the backward direction.
605         DoMoveFocusToNextFocusGroup(!event.IsShiftModifier());
606       }
607
608       isFocusStartableKey = true;
609     }
610     else if (keyName == "space" && !isAccessibilityEnabled)
611     {
612       if(!mIsFocusIndicatorEnabled)
613       {
614         // Show focus indicator
615         mIsFocusIndicatorEnabled = true;
616       }
617
618       isFocusStartableKey = true;
619     }
620     else if (keyName == "" && !isAccessibilityEnabled)
621     {
622       // Check the fake key event for evas-plugin case
623       if(!mIsFocusIndicatorEnabled)
624       {
625         // Show focus indicator
626         mIsFocusIndicatorEnabled = true;
627       }
628
629       isFocusStartableKey = true;
630     }
631     else if (keyName == "Backspace" && !isAccessibilityEnabled)
632     {
633       // Emit signal to go back to the previous view???
634     }
635   }
636   else if(event.state == KeyEvent::Up)
637   {
638     if (keyName == "Return")
639     {
640       if(!mIsFocusIndicatorEnabled && !isAccessibilityEnabled)
641       {
642         // Show focus indicator
643         mIsFocusIndicatorEnabled = true;
644       }
645       else
646       {
647         // Activate the focused actor
648         Actor actor;
649         if(!isAccessibilityEnabled)
650         {
651           actor = GetCurrentFocusActor();
652         }
653         else
654         {
655           actor = accessibilityFocusManager.GetCurrentFocusActor();
656         }
657
658         if(actor)
659         {
660           DoActivate(actor);
661         }
662       }
663
664       isFocusStartableKey = true;
665     }
666   }
667
668   if(isFocusStartableKey && mIsFocusIndicatorEnabled && !isAccessibilityEnabled)
669   {
670     Actor actor = GetCurrentFocusActor();
671     if( !actor )
672     {
673       // No actor is focused but keyboard focus is activated by the key press
674       // Let's try to move the initial focus
675       MoveFocus(Toolkit::Control::Right);
676     }
677     else if(mFocusIndicatorActor)
678     {
679       // Make sure the focused actor is highlighted
680       actor.Add(mFocusIndicatorActor);
681     }
682   }
683 }
684
685 void KeyboardFocusManager::OnTouched(const TouchEvent& touchEvent)
686 {
687   // Clear the focus when user touch the screen
688   ClearFocus();
689 }
690
691 Toolkit::KeyboardFocusManager::PreFocusChangeSignalV2& KeyboardFocusManager::PreFocusChangeSignal()
692 {
693   return mPreFocusChangeSignalV2;
694 }
695
696 Toolkit::KeyboardFocusManager::FocusChangedSignalV2& KeyboardFocusManager::FocusChangedSignal()
697 {
698   return mFocusChangedSignalV2;
699 }
700
701 Toolkit::KeyboardFocusManager::FocusGroupChangedSignalV2& KeyboardFocusManager::FocusGroupChangedSignal()
702 {
703   return mFocusGroupChangedSignalV2;
704 }
705
706 Toolkit::KeyboardFocusManager::FocusedActorActivatedSignalV2& KeyboardFocusManager::FocusedActorActivatedSignal()
707 {
708   return mFocusedActorActivatedSignalV2;
709 }
710
711 bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
712 {
713   Dali::BaseHandle handle( object );
714
715   bool connected( true );
716   KeyboardFocusManager* manager = dynamic_cast<KeyboardFocusManager*>(object);
717
718   if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_PRE_FOCUS_CHANGE == signalName )
719   {
720     manager->PreFocusChangeSignal().Connect( tracker, functor );
721   }
722   if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUS_CHANGED == signalName )
723   {
724     manager->FocusChangedSignal().Connect( tracker, functor );
725   }
726   if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUS_GROUP_CHANGED == signalName )
727   {
728     manager->FocusGroupChangedSignal().Connect( tracker, functor );
729   }
730   else if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
731   {
732     manager->FocusedActorActivatedSignal().Connect( tracker, functor );
733   }
734   else
735   {
736     // signalName does not match any signal
737     connected = false;
738   }
739
740   return connected;
741 }
742
743 } // namespace Internal
744
745 } // namespace Toolkit
746
747 } // namespace Dali