Improved key-input focus manager performance 09/29509/2
authorDavid Steele <david.steele@partner.samsung.com>
Mon, 27 Oct 2014 17:06:12 +0000 (17:06 +0000)
committerDavid Steele <david.steele@partner.samsung.com>
Tue, 28 Oct 2014 17:12:55 +0000 (17:12 +0000)
[model]        KIRAN
[binary_type]  Lite
[customer]     OPEN
[issue#]       N/A
[problem]      KeyInput focus manager uses actor ID's and traverses the
entire actor tree for all focus methods.
[cause]        Bad programming
[solution]     Changed stack to use BaseObject pointers. Track object lifetime
using the registry (Controls are automatically registered).
[team]         Graphics
[request]      N/A
[horizontal_expansion]  N/A

Change-Id: I4e49f0ca5adb990a71bedb8a4b5e6c08114db43c
Signed-off-by: David Steele <david.steele@partner.samsung.com>
automated-tests/src/dali-toolkit-unmanaged/utc-Dali-KeyInputFocusManager.cpp
base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp
base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h

index 2e087c3..ab377f6 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/integration-api/events/key-event-integ.h>
 
+#include "dummy-control.h"
 
 using namespace Dali;
 using namespace Toolkit;
@@ -125,21 +126,78 @@ int UtcDaliKeyInputFocusManagerGet(void)
   END_TEST;
 }
 
-int UtcDaliKeyInputFocusManagerSetFocus(void)
+int UtcDaliKeyInputFocusManagerSetFocus01(void)
 {
   ToolkitTestApplication application;
   Stage stage = Stage::GetCurrent();
 
-  tet_infoline(" UtcDaliKeyInputFocusManagerSetFocus");
+  tet_infoline(" Check that there is no focused control. Add a control to the stack. Check it is now the focused actor and receives KeyInputFocusGained signal");
 
   KeyInputFocusManager manager = KeyInputFocusManager::Get();
   DALI_TEST_CHECK(manager);
 
-  PushButton pushButton1 = PushButton::New();
-  stage.Add( pushButton1 );
+  Control focusedControl = manager.GetCurrentFocusControl();
+  DALI_TEST_CHECK( ! focusedControl );
+
+  DummyControl dummy = DummyControl::New(true);
+  DummyControlImplOverride& dummyImpl = static_cast<DummyControlImplOverride&>(dummy.GetImplementation());
+  dummy.SetSize(100.0f, 100.0f);
+  stage.Add( dummy );
+  DALI_TEST_CHECK( ! dummyImpl.keyInputFocusGained );
+
+  manager.SetFocus( dummy );
+  DALI_TEST_CHECK( dummy.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummyImpl.keyInputFocusGained );
+
+  focusedControl = manager.GetCurrentFocusControl();
+  DALI_TEST_CHECK( focusedControl );
+  DALI_TEST_CHECK( focusedControl == dummy );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerSetFocus02(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Add a control to the stack. Check it is now the focused actor and receives KeyInputFocusGained signal. Add another control - check that the first control receives KeyInputFocusLost");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  stage.Add( dummy1 );
+
+  manager.SetFocus( dummy1 );
+  DALI_TEST_CHECK( dummy1.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  stage.Add( dummy2 );
+
+  manager.SetFocus( dummy2 );
+  DALI_TEST_CHECK( dummy2.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+
 
-  manager.SetFocus(pushButton1);
-  DALI_TEST_CHECK(pushButton1.HasKeyInputFocus());
   END_TEST;
 }
 
@@ -148,53 +206,355 @@ int UtcDaliKeyInputFocusManagerGetCurrentFocusControl(void)
   ToolkitTestApplication application;
   Stage stage = Stage::GetCurrent();
 
-  tet_infoline(" UtcDaliKeyInputFocusManagerGetCurrentFocusControl");
+  tet_infoline(" Add 2 controls, check they each get focused. Re-focus the first control - ensure it's now got focus (check signals)");
 
   KeyInputFocusManager manager = KeyInputFocusManager::Get();
   DALI_TEST_CHECK(manager);
 
-  PushButton pushButton1 = PushButton::New();
-  PushButton pushButton2 = PushButton::New();
-  stage.Add( pushButton1 );
-  stage.Add( pushButton2 );
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl() );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK( dummy2 == manager.GetCurrentFocusControl() );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  // Reset signal received
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  END_TEST;
+}
 
-  manager.SetFocus(pushButton1);
-  DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl());
+int UtcDaliKeyInputFocusManagerRemoveFocus01(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
 
-  manager.SetFocus(pushButton2);
-  DALI_TEST_CHECK(pushButton2 == manager.GetCurrentFocusControl());
+  tet_infoline(" Add 3 focus controls. Test that removing the topmost informs the next control that it now has focus, Test that the bottommost control doesn't receive anything. ");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy2);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy1);
+  DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
 
-  manager.SetFocus(pushButton1);
-  DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl());
   END_TEST;
 }
 
-int UtcDaliKeyInputFocusManagerRemoveFocus(void)
+int UtcDaliKeyInputFocusManagerRemoveFocus02(void)
 {
   ToolkitTestApplication application;
   Stage stage = Stage::GetCurrent();
 
-  tet_infoline(" UtcDaliKeyInputFocusManagerRemoveFocus");
+  tet_infoline(" Add 3 focus controls. Test that removing the bottommost doesn't change the focused control" );
 
   KeyInputFocusManager manager = KeyInputFocusManager::Get();
   DALI_TEST_CHECK(manager);
 
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  DummyControl dummy3 = DummyControl::New(true);
+  DummyControlImplOverride& dummy3Impl = static_cast<DummyControlImplOverride&>(dummy3.GetImplementation());
+  dummy3.SetSize(100.0f, 100.0f);
+  stage.Add( dummy3 );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+
+  manager.SetFocus(dummy3);
+  DALI_TEST_CHECK(dummy3 == manager.GetCurrentFocusControl());
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+  dummy3Impl.keyInputFocusGained = false;
+  dummy3Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy1);
+  DALI_TEST_CHECK(dummy3 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+  dummy3Impl.keyInputFocusGained = false;
+  dummy3Impl.keyInputFocusLost = false;
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerRemoveFocus03(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Add 2 focus controls. Remove each of them from the bottom up. Test that the stack is now empty. Add a new control - check that it correctly has focus" );
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy1);
+  DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy2);
+  DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  PushButton pushButton1 = PushButton::New();
+  stage.Add( pushButton1 );
+  manager.SetFocus( pushButton1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( pushButton1 == manager.GetCurrentFocusControl());
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerRemoveFocus04(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Test what happens if the removed control is not on the focus stack");
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
   PushButton pushButton1 = PushButton::New();
   PushButton pushButton2 = PushButton::New();
   stage.Add( pushButton1 );
   stage.Add( pushButton2 );
+  manager.SetFocus( pushButton1 );
+  manager.SetFocus( pushButton2 );
 
-  manager.SetFocus(pushButton1);
-  DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl());
+  PushButton pushButton3 = PushButton::New();
+  stage.Add( pushButton3 );
+  manager.RemoveFocus( pushButton3 );
+  DALI_TEST_CHECK( pushButton2 == manager.GetCurrentFocusControl());
+  END_TEST;
+}
 
-  manager.SetFocus(pushButton2);
-  DALI_TEST_CHECK(pushButton2 == manager.GetCurrentFocusControl());
+int UtcDaliKeyInputFocusManagerDestroyObject01(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
 
-  manager.RemoveFocus(pushButton2);
-  DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl());
+  tet_infoline(" Add 2 controls to the stack. Unparent and destroy the topmost. Check that it is removed from the stack, and that the bottommost is correctly focused" );
 
-  manager.RemoveFocus(pushButton1);
-  DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl());
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  {
+    DummyControl dummy2 = DummyControl::New(true);
+    DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+    dummy2.SetSize(100.0f, 100.0f);
+    stage.Add( dummy2 );
+    DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+    DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+    manager.SetFocus(dummy1);
+    DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+
+    manager.SetFocus(dummy2);
+    DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+
+    dummy1Impl.keyInputFocusGained = false;
+    dummy1Impl.keyInputFocusLost = false;
+    dummy2Impl.keyInputFocusGained = false;
+    dummy2Impl.keyInputFocusLost = false;
+
+    stage.Remove(dummy2);
+  }
+
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerDestroyObject02(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Add 2 controls to the stack. Destroy a different actor entirely. Check that the stack is un-affected.");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  DummyControlImplOverride& dummy1Impl = static_cast<DummyControlImplOverride&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+
+  DummyControl dummy2 = DummyControl::New(true);
+  DummyControlImplOverride& dummy2Impl = static_cast<DummyControlImplOverride&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl());
+
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  {
+    BitmapImage image = CreateBitmapImage();
+    ImageActor imageActor = ImageActor::New( image );
+    stage.Add( imageActor );
+    imageActor.SetSize(100, 100);
+
+    application.SendNotification();
+    application.Render();
+
+    stage.Remove( imageActor );
+  }
+
+  DALI_TEST_CHECK( dummy2 == manager.GetCurrentFocusControl());
   END_TEST;
 }
 
@@ -296,7 +656,7 @@ int UtcDaliKeyInputFocusManagerSignalUnhandledKeyEvent(void)
   DALI_TEST_CHECK(event.keyName == data.receivedKeyEvent.keyPressedName );
   DALI_TEST_CHECK(event.keyCode == data.receivedKeyEvent.keyCode);
   DALI_TEST_CHECK(event.keyString == data.receivedKeyEvent.keyPressed );
-  DALI_TEST_CHECK(static_cast<int>( event.state ) == static_cast<int>( data.receivedKeyEvent.state ) );
+  DALI_TEST_CHECK(event.state == static_cast<Integration::KeyEvent::State>(data.receivedKeyEvent.state) );
 
   data.Reset();
 
index 954ce3a..65a9ec9 100644 (file)
@@ -39,52 +39,48 @@ KeyInputFocusManager::KeyInputFocusManager()
 : mSlotDelegate( this )
 {
   Stage::GetCurrent().KeyEventSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
+  mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
+  mObjectRegistry.ObjectDestroyedSignal().Connect( this, &KeyInputFocusManager::OnObjectDestroyed );
 }
 
 KeyInputFocusManager::~KeyInputFocusManager()
 {
 }
 
-void KeyInputFocusManager::SetFocus(Toolkit::Control control)
+void KeyInputFocusManager::SetFocus( Toolkit::Control control )
 {
-  if(!control)
+  if( !control )
   {
-   //No-op
+    // No-op
     return;
   }
 
-  unsigned int actorID = control.GetId();
+  FocusStackIterator pos = FindFocusControlInStack( control );
 
-  ActorQueueIterator pos = std::find( mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorID);
-
-  if((!mFocusActorsQueue.empty()) && (pos == mFocusActorsQueue.begin()))
+  if( ( mFocusStack.Count() != 0 ) && ( pos == mFocusStack.End()-1 ) )
   {
-    //Actor allready in front, so No-op
+    // Control already in front, so No-op
     return;
   }
 
-  if(pos != mFocusActorsQueue.end())
+  if( pos != mFocusStack.End() )
   {
-    //A previously focused actor wants to regain focus
-    mFocusActorsQueue.erase(pos);
+    // A previously focused control wants to regain focus
+    mFocusStack.Erase( pos );
   }
   else
   {
-    control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusActorStageDisconnection );
+    control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
   }
 
-  Dali::Toolkit::Control previousFocusControl;
-  if(!mFocusActorsQueue.empty())
+  Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
+  if( previousFocusControl )
   {
-    previousFocusControl = Dali::Toolkit::Control::DownCast(Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front()));
-    if(previousFocusControl)
-    {
-      // Notify the control that it has lost key input focus
-      previousFocusControl.GetImplementation().OnKeyInputFocusLost();
-    }
+    // Notify the control that it has lost key input focus
+    previousFocusControl.GetImplementation().OnKeyInputFocusLost();
   }
 
-  mFocusActorsQueue.push_front(actorID);
+  mFocusStack.PushBack( &control.GetBaseObject() );
 
   // Tell the new actor that it has gained focus.
   control.GetImplementation().OnKeyInputFocusGained();
@@ -96,72 +92,60 @@ void KeyInputFocusManager::SetFocus(Toolkit::Control control)
   }
 }
 
-Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
-{
-  Toolkit::Control currentFocusControl;
-
-  if(!mFocusActorsQueue.empty())
-  {
-    currentFocusControl = Dali::Toolkit::Control::DownCast(Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front()));
-  }
-
-  return currentFocusControl;
-}
-
-void KeyInputFocusManager::RemoveFocus(Toolkit::Control control)
+void KeyInputFocusManager::RemoveFocus( Toolkit::Control control )
 {
-  if(control)
+  if( control )
   {
-    unsigned int actorId = control.GetId();
-    ActorQueueIterator pos = std::find( mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorId);
-
-    if(pos != mFocusActorsQueue.end())
+    FocusStackIterator pos = FindFocusControlInStack( control );
+    if( pos != mFocusStack.End() )
     {
-      control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusActorStageDisconnection );
+      control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
 
       // Notify the control that it has lost key input focus
       control.GetImplementation().OnKeyInputFocusLost();
 
-      if(pos == mFocusActorsQueue.begin())
+      // If this is the top-most actor, pop it and change focus to the previous control
+      if( pos == mFocusStack.End() - 1 )
       {
-        Actor previousFocusActor;
-
-        mFocusActorsQueue.erase(pos);
-        if(!mFocusActorsQueue.empty())
-        {
-          previousFocusActor = Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front());
-        }
+        mFocusStack.Erase( pos );
 
-        Dali::Toolkit::Control previouscontrol = Dali::Toolkit::Control::DownCast(previousFocusActor);
-        if(previouscontrol)
+        Toolkit::Control previouslyFocusedControl = GetCurrentFocusControl();
+        if( previouslyFocusedControl )
         {
-          // Tell the new actor that it has gained focus.
-          previouscontrol.GetImplementation().OnKeyInputFocusGained();
+          // Tell the control that it has gained focus.
+          previouslyFocusedControl.GetImplementation().OnKeyInputFocusGained();
         }
       }
       else
       {
-        //If the removed actor is not currently focused, then no need to emit signal.
-        mFocusActorsQueue.erase(pos);
+        // If the removed control is not currently focused, then no need to emit signal.
+        mFocusStack.Erase( pos );
       }
-
     }
   }
 }
 
-bool KeyInputFocusManager::IsKeyboardListener(Toolkit::Control control) const
+Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
 {
-  bool result = false;
+  Toolkit::Control currentControl;
 
-  if(!mFocusActorsQueue.empty())
+  FocusStack::SizeType count = mFocusStack.Count();
+  if( count != 0 )
   {
-    unsigned int actorId = control.GetId();
-    ActorQueueConstIterator pos = std::find(mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorId);
+    BaseObject* object = mFocusStack[ count - 1 ];
+    BaseHandle handle( object );
+    currentControl = Dali::Toolkit::Control::DownCast( handle );
+  }
+  return currentControl;
+}
 
-    if(pos != mFocusActorsQueue.end())
-    {
-      result = true;
-    }
+bool KeyInputFocusManager::IsKeyboardListener( Toolkit::Control control ) const
+{
+  bool result = false;
+
+  if( FindFocusControlInStack( control ) != mFocusStack.End() )
+  {
+    result = true;
   }
 
   return result;
@@ -177,27 +161,34 @@ Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalV2& KeyInputFocusManager::
   return mUnhandledKeyEventSignalV2;
 }
 
-void KeyInputFocusManager::OnKeyEvent(const KeyEvent& event)
+KeyInputFocusManager::FocusStackIterator KeyInputFocusManager::FindFocusControlInStack( Toolkit::Control control ) const
 {
-  bool consumed = false;
-
-  ActorQueueIterator iter = mFocusActorsQueue.begin();
+  BaseObject* controlObject = &control.GetBaseObject();
+  return std::find( mFocusStack.Begin(), mFocusStack.End(), controlObject );
+}
 
-  Layer rootLayer = Stage::GetCurrent().GetRootLayer();
+void KeyInputFocusManager::OnKeyEvent( const KeyEvent& event )
+{
+  bool consumed = false;
 
-  while(!mFocusActorsQueue.empty() && !consumed && (iter != mFocusActorsQueue.end()))
+  if( mFocusStack.Count() > 0 )
   {
-    Actor actor = rootLayer.FindChildById(*iter);
-    Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
-    if(control)
+    FocusStack::SizeType index = mFocusStack.Count();
+    while( mFocusStack.Count() != 0 && !consumed && index > 0 )
     {
-      // Notify the control about the key event
-      consumed = control.GetImplementation().EmitKeyEventSignal(event);
+      --index;
+      BaseObject* object = mFocusStack[ index ];
+      BaseHandle handle( object );
+      Toolkit::Control control = Toolkit::Control::DownCast( object );
+      if( control )
+      {
+        // Notify the control about the key event
+        consumed = control.GetImplementation().EmitKeyEventSignal( event );
+      }
     }
-    iter++;
   }
 
-  if(!consumed)
+  if( !consumed )
   {
     // Emit signal to inform that a key event is not consumed.
     if( !mUnhandledKeyEventSignalV2.Empty() )
@@ -207,9 +198,21 @@ void KeyInputFocusManager::OnKeyEvent(const KeyEvent& event)
   }
 }
 
-void KeyInputFocusManager::OnFocusActorStageDisconnection( Dali::Actor actor )
+void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor )
 {
-  RemoveFocus(Dali::Toolkit::Control::DownCast(actor));
+  RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) );
+}
+
+void KeyInputFocusManager::OnObjectDestroyed( const Dali::RefObject* object )
+{
+  // The object is already destroyed. Don't create handles to it, or try sending
+  // signals to it. Remove it's pointer from the stack.
+  const BaseObject* baseObject = static_cast<const BaseObject*>( object );
+  FocusStackIterator pos = std::find( mFocusStack.Begin(), mFocusStack.End(), baseObject );
+  if( pos != mFocusStack.End() )
+  {
+    mFocusStack.Erase( pos );
+  }
 }
 
 bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
index 43bd783..3db0743 100644 (file)
@@ -20,8 +20,8 @@
 
 // EXTERNAL INCLUDES
 #include <string>
-#include <deque>
 #include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/object-registry.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/focus-manager/keyinput-focus-manager.h>
@@ -41,13 +41,11 @@ class KeyInputFocusManager;
 /**
  * @copydoc Toolkit::KeyInputFocusManager
  */
-class KeyInputFocusManager : public Dali::BaseObject
+class KeyInputFocusManager : public Dali::BaseObject, public Dali::ConnectionTracker
 {
 public:
-
-  typedef std::deque< unsigned int > ActorQueue;
-  typedef std::deque< unsigned int >::iterator ActorQueueIterator;
-  typedef std::deque< unsigned int >::const_iterator ActorQueueConstIterator;
+  typedef Dali::Vector< Dali::BaseObject* > FocusStack;
+  typedef FocusStack::Iterator FocusStackIterator;
 
   /**
    * Construct a new KeyInputFocusManager.
@@ -60,14 +58,14 @@ public:
   void SetFocus(Toolkit::Control control);
 
   /**
-   * @copydoc Toolkit::GetCurrentFocusControl
+   * @copydoc Toolkit::RemoveFocus
    */
-  Toolkit::Control GetCurrentFocusControl() const;
+  void RemoveFocus(Toolkit::Control control);
 
   /**
-   * @copydoc Toolkit::RemoveFocus
+   * @copydoc Toolkit::GetCurrentFocusControl
    */
-  void RemoveFocus(Toolkit::Control control);
+  Toolkit::Control GetCurrentFocusControl() const;
 
   /**
    * @copydoc Toolkit::IsKeyboardListener
@@ -107,16 +105,29 @@ protected:
 private:
 
   /**
+   * Search for a control in the focus stack.
+   * @param[in] control The control for which to search
+   * @return An iterator to the control. If not found, this will equate to the
+   * mFocusStack.End() iterator.
+   */
+  FocusStackIterator FindFocusControlInStack( Toolkit::Control control ) const;
+
+  /**
    * Callback for the key event when no actor in the stage has gained the key input focus
    * @param[in] event The KeyEvent event.
    */
   void OnKeyEvent(const KeyEvent& event);
 
   /**
-   * Signal handler called when a focused Actor is removed from Stage.
-   * @param[in]  actor  The actor removed from stage.
+   * Signal handler called when a focused Control is removed from Stage.
+   * @param[in]  control  The control removed from stage.
    */
-  void OnFocusActorStageDisconnection( Dali::Actor actor );
+  void OnFocusControlStageDisconnection( Dali::Actor control );
+
+  /**
+   * Signal handler called when an actor is destroyed.
+   */
+  void OnObjectDestroyed(const Dali::RefObject* object);
 
 private:
 
@@ -134,9 +145,9 @@ private:
   Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalV2 mUnhandledKeyEventSignalV2;
 
   // Keyboard events are sent to the current focus actor, which will be the actor on the top of the focus actors stack.
-  ActorQueue mFocusActorsQueue;
-
+  FocusStack mFocusStack;
   SlotDelegate< KeyInputFocusManager > mSlotDelegate;
+  ObjectRegistry mObjectRegistry;
 };
 
 } // namespace Internal