--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/src/aknglobalpopupprioritycontroller.cpp Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,622 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: System for managing global popup window priorities
+*
+*/
+
+
+#include "aknglobalpopupprioritycontroller.h"
+#include "AknPopupFader.h"
+#include <eikenv.h>
+#include <e32hashtab.h>
+#include <coecntrl.h>
+#include <eikappui.h>
+
+const TUid KAknGlobalPopupPriorityControllerStaticId = { 0x102835a0 };
+const TInt KAknGlobalPopupPriorityControllerMaxStack = 10;
+
+const TInt KControlStackSleepFlags = ECoeStackFlagRefusesAllKeys|ECoeStackFlagRefusesFocus;
+
+enum TGppcPanic
+ {
+ EGppcPanic_DontSupportMultipleSubPopups,
+ EGppcPanic_DontSupportMultipleParents
+ };
+
+void GppcPanic(TGppcPanic aReason)
+ {
+ _LIT(KReason, "AknGppc");
+ User::Panic(KReason, aReason);
+ }
+
+
+// hash an identity functions required by RHashMap
+template<typename T>
+TUint32 GeneralPtrHash(T* const & aPtr)
+ {
+ return DefaultHash::Integer((TInt)aPtr);
+ }
+
+template<typename T>
+TBool GeneralPtrIdentity(T* const & aP1, T* const & aP2)
+ {
+ return aP1 == aP2;
+ }
+
+
+NONSHARABLE_CLASS(CAknGlobalPopupPriorityController) : public CCoeStatic
+ {
+public:
+ static void CreateInstanceL();
+ static CAknGlobalPopupPriorityController* Instance();
+
+ void AllowGlobalPopups(TBool aAllow);
+ void SetPopupPriorityL(CCoeControl* aPopup, TInt aPriority);
+ void RemovePopup(CCoeControl* aPopup);
+ void ShowPopup(CCoeControl* aPopup, TBool aShow);
+ void SetRootWinOrdinalPosition(TInt aOrdinalPosition);
+ void AddSubPopupL(CCoeControl* aPopup, CCoeControl* aSubPopup);
+ void AddPopupToControlStackL(CCoeControl* aPopup,TInt aPriority,TInt aStackingFlags);
+ void FadeBehindPopupL(CCoeControl* aPopup, MAknFadedComponent* aFadedComponent);
+ void RouseSleepingPopup(CCoeControl* aPopup, TBool aRoused);
+
+ TBool GlobalPopupsAllowed();
+private:
+ CAknGlobalPopupPriorityController();
+ ~CAknGlobalPopupPriorityController();
+ void ConstructL();
+
+ TInt PopupPriority(CCoeControl* aPopup) const;
+ TBool AddToStack(CCoeControl* aPopup);
+ TBool RemoveFromStack(CCoeControl* aPopup);
+ void SetWindowGroupPriority();
+ void SetPopupWindowPositions(CCoeControl* aPopup, TInt aWindowPos);
+ void SetPopupChainKeyPositionsL(CCoeControl* aPopup);
+ void SetPopupKeyPositionsL(CCoeControl* aPopup);
+ CCoeControl* RootPopup(CCoeControl* aTip) const;
+ CCoeControl* TopPopup() const;
+ TBool PopupIsShown(CCoeControl* aPopup) const;
+ void DoFadeBehindPopup(CCoeControl* aPopup);
+ TInt MinChainWindowPosition(CCoeControl* aPopup) const;
+
+private:
+ struct TPopupInfo
+ {
+ public:
+ TPopupInfo();
+
+ public:
+ TInt iPopupPriority;
+ TInt iControlStackPriority;
+ TInt iControlStackFlags;
+ CCoeControl* iSubPopup; // not owned
+ CCoeControl* iParent; // not owned
+ MAknFadedComponent* iFadedComponent; // not owned
+ };
+
+private:
+ TPopupInfo* PopupInfo(CCoeControl* aPopup);
+ const TPopupInfo* PopupInfo(CCoeControl* aPopup) const;
+ TPopupInfo& PopupInfoL(CCoeControl* aPopup);
+
+private:
+ RHashMap<CCoeControl*, TPopupInfo> iPopupInfoMap;
+ // The stack of currently shown popups (the CCoeControls are not owned)
+ RArray<CCoeControl*> iShownStack;
+ TBool iGlobalPopupsAllowed;
+ TInt iOrdinalPosition;
+ CEikAppUi* iAppUi; // not owned
+ };
+
+
+CAknGlobalPopupPriorityController::TPopupInfo::TPopupInfo()
+: iPopupPriority(0), iControlStackPriority(KErrNotFound), iControlStackFlags(0), iSubPopup(NULL), iParent(NULL), iFadedComponent(NULL)
+ {
+ }
+
+
+void CAknGlobalPopupPriorityController::CreateInstanceL()
+ {
+ if (!CAknGlobalPopupPriorityController::Instance())
+ {
+ CAknGlobalPopupPriorityController* self = new(ELeave) CAknGlobalPopupPriorityController(); // CCoeEnv takes ownership immediately
+ self->ConstructL();
+ }
+ }
+
+CAknGlobalPopupPriorityController* CAknGlobalPopupPriorityController::Instance()
+ {
+ return static_cast<CAknGlobalPopupPriorityController*>(CCoeEnv::Static(KAknGlobalPopupPriorityControllerStaticId));
+ }
+
+void CAknGlobalPopupPriorityController::AllowGlobalPopups(TBool aAllow)
+ {
+ iGlobalPopupsAllowed = aAllow;
+ SetWindowGroupPriority();
+ CCoeControl* top = TopPopup();
+ if (top)
+ {
+ TRAP_IGNORE(SetPopupChainKeyPositionsL(top));
+ DoFadeBehindPopup(top);
+ }
+ }
+
+TBool CAknGlobalPopupPriorityController::GlobalPopupsAllowed()
+ {
+ return iGlobalPopupsAllowed;
+ }
+
+void CAknGlobalPopupPriorityController::SetPopupPriorityL(CCoeControl* aPopup, TInt aPriority)
+ {
+ PopupInfoL(aPopup).iPopupPriority = aPriority;
+
+ // Update the active popup stack
+ if (PopupIsShown(aPopup))
+ {
+ ShowPopup(aPopup, ETrue);
+ }
+ }
+
+void CAknGlobalPopupPriorityController::RemovePopup(CCoeControl* aPopup)
+ {
+ // Update the active popup stack
+ if (PopupIsShown(aPopup))
+ {
+ ShowPopup(aPopup, EFalse);
+ }
+
+ // Remove sub-popup from parent
+ TPopupInfo* info = PopupInfo(aPopup);
+ if (info && info->iParent)
+ {
+ TPopupInfo* pInfo = PopupInfo(info->iParent);
+ if (pInfo)
+ pInfo->iSubPopup = NULL;
+ }
+
+ // Remove the popup and sub popups from the map
+ CCoeControl* popup = aPopup;
+ while (popup)
+ {
+ CCoeControl* next = NULL;
+ TPopupInfo* info = PopupInfo(popup);
+ if (info)
+ next = info->iSubPopup;
+ iPopupInfoMap.Remove(popup);
+ popup = next;
+ }
+ }
+
+TInt CAknGlobalPopupPriorityController::PopupPriority(CCoeControl* aPopup) const
+ {
+ const TPopupInfo* info = PopupInfo(aPopup);
+ return info ? info->iPopupPriority : 0;
+ }
+
+void CAknGlobalPopupPriorityController::ShowPopup(CCoeControl* aPopup, TBool aShow)
+ {
+ // update the stack
+ CCoeControl* oldTop = TopPopup();
+ if (aShow)
+ {
+ AddToStack(aPopup);
+ TRAP_IGNORE(SetPopupChainKeyPositionsL(aPopup));
+ }
+ else
+ {
+ RemoveFromStack(aPopup);
+ }
+ DoFadeBehindPopup(aPopup);
+ CCoeControl* newTop = TopPopup();
+
+ // update the top popup
+ if (oldTop != newTop)
+ {
+ // set window group priority
+ SetWindowGroupPriority();
+
+ // an existing popup is now top
+ if (newTop != aPopup)
+ {
+ TRAP_IGNORE(SetPopupChainKeyPositionsL(newTop));
+ DoFadeBehindPopup(newTop);
+ }
+ }
+ }
+
+void CAknGlobalPopupPriorityController::SetRootWinOrdinalPosition(TInt aOrdinalPosition)
+ {
+ iOrdinalPosition = aOrdinalPosition;
+ }
+
+void CAknGlobalPopupPriorityController::SetWindowGroupPriority()
+ {
+ TInt newPriority;
+ if (iShownStack.Count() > 0 && iGlobalPopupsAllowed)
+ {
+ CCoeControl* topPopup = iShownStack[0];
+ TInt priority = PopupPriority(topPopup);
+ newPriority = ECoeWinPriorityAlwaysAtFront + priority;
+ }
+ else
+ {
+ newPriority = ECoeWinPriorityNeverAtFront;
+ }
+ CEikonEnv::Static()->RootWin().SetOrdinalPosition(iOrdinalPosition, newPriority);
+ }
+
+TBool CAknGlobalPopupPriorityController::AddToStack(CCoeControl* aPopup)
+ {
+ // remove it from the stack if already there
+ TInt priorPos = iShownStack.Find(aPopup);
+ if (priorPos != KErrNotFound)
+ {
+ iShownStack.Remove(priorPos);
+ }
+
+ // stack size is limited, do not add new items if it would cause overflow
+ TInt count = iShownStack.Count();
+ if (count >= KAknGlobalPopupPriorityControllerMaxStack)
+ {
+ return EFalse;
+ }
+
+ // insert it at correct position in the stack
+ // also calculate min and max window z-order position
+ TInt priority = PopupPriority(aPopup);
+ TInt insertPos = -1;
+ TInt minWindowPosition = 0;
+ TInt maxWindowPosition = KMaxTInt;
+ for (TInt ii=0; ii<count; ii++)
+ {
+ CCoeControl* stacked = iShownStack[ii];
+ TInt shownPriority = PopupPriority(stacked);
+ if (priority >= shownPriority)
+ {
+ maxWindowPosition = MinChainWindowPosition(stacked);
+ iShownStack.Insert(aPopup, ii); // will not fail because overflow is already checked
+ insertPos = ii;
+ break;
+ }
+ minWindowPosition = stacked->DrawableWindow()->OrdinalPosition();
+ }
+ if (insertPos == -1)
+ {
+ insertPos = count;
+ iShownStack.Append(aPopup); // will not fail because overflow is already checked
+ }
+
+ // set popup window z-order position, if necessary
+ // it should be behind any higher priority popup and infront
+ // of any lower priority popup
+ TInt popupWindowPosition = aPopup->DrawableWindow()->OrdinalPosition();
+ if (popupWindowPosition < minWindowPosition)
+ popupWindowPosition = minWindowPosition+1;
+ else if (popupWindowPosition > maxWindowPosition)
+ popupWindowPosition = maxWindowPosition;
+ SetPopupWindowPositions(aPopup, popupWindowPosition);
+
+ // return true (top changed) if top item was moved or added
+ return priorPos == 0 || insertPos == 0;
+ }
+
+void CAknGlobalPopupPriorityController::SetPopupWindowPositions(
+ CCoeControl* aPopup, TInt aWindowPos)
+ {
+ TBool isSub = EFalse;
+ while (aPopup)
+ {
+ TInt currentPos = aPopup->DrawableWindow()->OrdinalPosition();
+ if (isSub && currentPos < aWindowPos)
+ {
+ // adjust one forward, so that we don't go behind the parent window
+ aWindowPos--;
+ }
+
+ aPopup->DrawableWindow()->SetOrdinalPosition(aWindowPos);
+ const TPopupInfo* info = PopupInfo(aPopup);
+ if (info)
+ {
+ aPopup = info->iSubPopup;
+ }
+ else
+ {
+ aPopup = NULL;
+ }
+ isSub = ETrue;
+ }
+ }
+
+void CAknGlobalPopupPriorityController::SetPopupChainKeyPositionsL(CCoeControl* aPopup)
+ {
+ bool top = aPopup == TopPopup();
+ while (aPopup)
+ {
+ const TPopupInfo* info = PopupInfo(aPopup);
+ CCoeControl* next = NULL;
+ if (info && info->iControlStackPriority != KErrNotFound)
+ {
+ next = info->iSubPopup;
+ iAppUi->RemoveFromStack(aPopup);
+ TInt flags = top ? info->iControlStackFlags : KControlStackSleepFlags;
+ iAppUi->AddToStackL(aPopup, info->iControlStackPriority, flags);
+ }
+ aPopup = next;
+ }
+ }
+
+void CAknGlobalPopupPriorityController::SetPopupKeyPositionsL(CCoeControl* aPopup)
+ {
+ bool top = RootPopup(aPopup) == TopPopup();
+ const TPopupInfo* info = PopupInfo(aPopup);
+ if (info && info->iControlStackPriority != KErrNotFound)
+ {
+ iAppUi->RemoveFromStack(aPopup);
+ TInt flags = top ? info->iControlStackFlags : KControlStackSleepFlags;
+ iAppUi->AddToStackL(aPopup, info->iControlStackPriority, flags);
+ }
+ }
+
+TBool CAknGlobalPopupPriorityController::RemoveFromStack(CCoeControl* aPopup)
+ {
+ // only if it's already in the stack
+ TInt pos = iShownStack.Find(aPopup);
+ if (pos == KErrNotFound)
+ {
+ return EFalse;
+ }
+ else
+ {
+ iShownStack.Remove(pos);
+ return pos == 0;
+ }
+ }
+
+CAknGlobalPopupPriorityController::CAknGlobalPopupPriorityController()
+: CCoeStatic(KAknGlobalPopupPriorityControllerStaticId),
+ iPopupInfoMap(THashFunction32<CCoeControl*>(&GeneralPtrHash), TIdentityRelation<CCoeControl*>(&GeneralPtrIdentity)),
+ iGlobalPopupsAllowed(EFalse),
+ iAppUi(CEikonEnv::Static()->EikAppUi())
+ {
+ }
+
+CAknGlobalPopupPriorityController::~CAknGlobalPopupPriorityController()
+ {
+ iPopupInfoMap.Close();
+ iShownStack.Close();
+ }
+
+void CAknGlobalPopupPriorityController::ConstructL()
+ {
+ iShownStack.Reserve(KAknGlobalPopupPriorityControllerMaxStack);
+ }
+
+CAknGlobalPopupPriorityController::TPopupInfo* CAknGlobalPopupPriorityController::PopupInfo(CCoeControl* aPopup)
+ {
+ TPopupInfo* info = iPopupInfoMap.Find(aPopup);
+ return info;
+ }
+
+const CAknGlobalPopupPriorityController::TPopupInfo* CAknGlobalPopupPriorityController::PopupInfo(CCoeControl* aPopup) const
+ {
+ const TPopupInfo* info = iPopupInfoMap.Find(aPopup);
+ return info;
+ }
+
+CAknGlobalPopupPriorityController::TPopupInfo& CAknGlobalPopupPriorityController::PopupInfoL(CCoeControl* aPopup)
+ {
+ TPopupInfo* info = PopupInfo(aPopup);
+ if (info)
+ return *info;
+ iPopupInfoMap.InsertL(aPopup, TPopupInfo());
+ return *PopupInfo(aPopup);
+ }
+
+void CAknGlobalPopupPriorityController::AddSubPopupL(CCoeControl* aPopup, CCoeControl* aSubPopup)
+ {
+ // Below 3 rows of calling PopupInfoL() look like a little uncomfortable,
+ // because PopupInfoL will add new element in its hash map.
+ // So, a new element may be inserted when calling PopupInfoL(aSubPopup).
+ // It may will lead to the change of aPopup address returned from the first calling PopupInfoL(aPopup).
+ // So, we need to get the parent reference again.
+ PopupInfoL(aPopup);
+ TPopupInfo& sub = PopupInfoL(aSubPopup);
+ TPopupInfo& parent = PopupInfoL(aPopup);
+
+ __ASSERT_DEBUG(parent.iSubPopup == NULL || parent.iSubPopup == aSubPopup, GppcPanic(EGppcPanic_DontSupportMultipleSubPopups));
+ __ASSERT_DEBUG(sub.iParent == NULL || sub.iParent == aPopup, GppcPanic(EGppcPanic_DontSupportMultipleParents));
+ parent.iSubPopup = aSubPopup;
+ sub.iParent = aPopup;
+ // put it at the same window position as its parent
+ aSubPopup->DrawableWindow()->SetOrdinalPosition(aPopup->DrawableWindow()->OrdinalPosition());
+ }
+
+
+void CAknGlobalPopupPriorityController::AddPopupToControlStackL(CCoeControl* aPopup,TInt aPriority,TInt aStackingFlags)
+ {
+ TPopupInfo& info = PopupInfoL(aPopup);
+ info.iControlStackPriority = aPriority;
+ info.iControlStackFlags = aStackingFlags;
+ SetPopupKeyPositionsL(aPopup);
+ }
+
+CCoeControl* CAknGlobalPopupPriorityController::RootPopup(CCoeControl* aTip) const
+ {
+ const TPopupInfo* info;
+ info = PopupInfo(aTip);
+ while (info && info->iParent)
+ {
+ aTip = info->iParent;
+ info = PopupInfo(aTip);
+ }
+
+
+ return aTip;
+ }
+
+CCoeControl* CAknGlobalPopupPriorityController::TopPopup() const
+ {
+ if (iShownStack.Count() > 0 && iGlobalPopupsAllowed)
+ return iShownStack[0];
+ else
+ return NULL;
+ }
+
+TBool CAknGlobalPopupPriorityController::PopupIsShown(CCoeControl* aPopup) const
+ {
+ TInt pos = iShownStack.Find(aPopup);
+ return pos != KErrNotFound;
+ }
+
+void CAknGlobalPopupPriorityController::FadeBehindPopupL(CCoeControl* aPopup, MAknFadedComponent* aFadedComponent)
+ {
+ TPopupInfo& info = PopupInfoL(aPopup);
+ info.iFadedComponent = aFadedComponent;
+ DoFadeBehindPopup(aPopup);
+ }
+
+void CAknGlobalPopupPriorityController::DoFadeBehindPopup(CCoeControl* aPopup)
+ {
+ TBool top = aPopup == TopPopup();
+ TPopupInfo* info = PopupInfo(aPopup);
+ if (!info || !info->iFadedComponent)
+ return;
+ TAknPopupFader fader;
+ fader.FadeBehindPopup(info->iFadedComponent, aPopup, top);
+ }
+
+void CAknGlobalPopupPriorityController::RouseSleepingPopup(CCoeControl* aPopup, TBool aRoused)
+ {
+ TInt pri = ECoeStackPriorityDialog;
+ TInt flags = 0;
+ TPopupInfo* info = PopupInfo(aPopup);
+ if (info)
+ {
+ pri = info->iControlStackPriority;
+ flags = info->iControlStackFlags;
+ }
+ if (aRoused)
+ flags = flags & ~KControlStackSleepFlags;
+ else
+ flags = flags | KControlStackSleepFlags;
+ TRAP_IGNORE(AddPopupToControlStackL(aPopup, pri, flags));
+ }
+
+TInt CAknGlobalPopupPriorityController::MinChainWindowPosition(CCoeControl* aPopup) const
+ {
+ TInt pos = aPopup->DrawableWindow()->OrdinalPosition();
+ const TPopupInfo* info = PopupInfo(aPopup);
+ while (info && info->iSubPopup)
+ {
+ aPopup = info->iSubPopup;
+ pos = Min(pos, aPopup->DrawableWindow()->OrdinalPosition());
+ info = PopupInfo(aPopup);
+ }
+ return pos;
+ }
+
+
+EXPORT_C void AknGlobalPopupPriorityController::EnablePriorityControlL()
+ {
+ CAknGlobalPopupPriorityController::CreateInstanceL();
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::AllowGlobalPopups(TBool aAllow)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->AllowGlobalPopups(aAllow);
+ }
+
+EXPORT_C TBool AknGlobalPopupPriorityController::GlobalPopupsAllowed()
+ {
+ TBool globalPopupsAllowed = ETrue;
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ globalPopupsAllowed = instance->GlobalPopupsAllowed();
+ return globalPopupsAllowed;
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::SetPopupPriorityL(CCoeControl& aPopup, TInt aPriority)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->SetPopupPriorityL(&aPopup, aPriority);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::RemovePopupPriority(CCoeControl& aPopup)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->RemovePopup(&aPopup);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::ShowPopup(CCoeControl& aPopup, TBool aShow)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->ShowPopup(&aPopup, aShow);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::SetRootWinOrdinalPosition(TInt aOrdinalPosition)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->SetRootWinOrdinalPosition(aOrdinalPosition);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::AddSubPopupL(CCoeControl& aPopup, CCoeControl& aSubPopup)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->AddSubPopupL(&aPopup, &aSubPopup);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::AddPopupToControlStackL(CCoeControl& aPopup,TInt aPriority,TInt aStackingFlags)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->AddPopupToControlStackL(&aPopup, aPriority, aStackingFlags);
+ else
+ {
+ CEikAppUi* appUi = CEikonEnv::Static()->EikAppUi();
+ if (appUi)
+ {
+ appUi->RemoveFromStack(&aPopup);
+ appUi->AddToStackL(&aPopup, aPriority, aStackingFlags);
+ }
+ }
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::RouseSleepingPopup(CCoeControl& aPopup, TBool aRoused)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ instance->RouseSleepingPopup(&aPopup, aRoused);
+ else
+ CEikonEnv::Static()->RouseSleepingDialog(&aPopup, aRoused);
+ }
+
+EXPORT_C void AknGlobalPopupPriorityController::FadeBehindPopup(CCoeControl& aPopup, TAknPopupFader& aFader, MAknFadedComponent& aFadedComponent, TBool aFade)
+ {
+ CAknGlobalPopupPriorityController* instance = CAknGlobalPopupPriorityController::Instance();
+ if (instance)
+ {
+ TRAP_IGNORE(instance->FadeBehindPopupL(&aPopup, &aFadedComponent));
+ }
+ else
+ {
+ aFader.FadeBehindPopup(&aFadedComponent, &aPopup, aFade);
+ }
+ }