/*
* Copyright (c) 2002 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:
* Implementation of CAknProgressDialog.
*
*/
// AknProgressDialog.cpp: implementation of the CAknProgressDialog class.
//
//////////////////////////////////////////////////////////////////////
#include <AknProgressDialog.h>
#include <aknprogresstimer.h>
#include <aknnotecontrol.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikcba.h>
#include <avkon.hrh>
#include "aknnoteattributes.h"
#include <akninputblock.h>
#include "akntrace.h"
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
#include <gfxtranseffect/gfxtranseffect.h>
#include <akntransitionutils.h>
#endif
#include <AknTasHook.h> // for testability hooks
NONSHARABLE_CLASS(CAknProgressDialog::CCancelWhileHidden) : public CBase, public MAknInputBlockCancelHandler
{
public:
static CCancelWhileHidden* NewL(CAknProgressDialog* aAknProgressDialog);
~CCancelWhileHidden();
private: // from MAknInputBlockCancelHandler
void AknInputBlockCancel();
private:
CCancelWhileHidden(CAknProgressDialog* aAknProgressDialog);
void ConstructL();
private:
CAknProgressDialog* iAknProgressDialog;
CAknInputBlock* iBlock;
};
CAknProgressDialog::CCancelWhileHidden* CAknProgressDialog::CCancelWhileHidden::NewL(CAknProgressDialog* aAknProgressDialog)
{
CCancelWhileHidden* self = new(ELeave) CCancelWhileHidden(aAknProgressDialog);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CAknProgressDialog::CCancelWhileHidden::~CCancelWhileHidden()
{
if (iBlock)
iBlock->SetCancelHandler(NULL);
delete iBlock;
}
void CAknProgressDialog::CCancelWhileHidden::AknInputBlockCancel()
{
TKeyEvent key;
key.iRepeats=0;
key.iCode=EKeyEscape;
key.iModifiers=0;
key.iScanCode = EStdKeyNull;
TRAP_IGNORE(iAknProgressDialog->OfferKeyEventL(key, EEventKey));
}
CAknProgressDialog::CCancelWhileHidden::CCancelWhileHidden(CAknProgressDialog* aAknProgressDialog)
: iAknProgressDialog(aAknProgressDialog)
{
}
void CAknProgressDialog::CCancelWhileHidden::ConstructL()
{
iBlock = CAknInputBlock::NewCancelHandlerLC(this);
CleanupStack::Pop(iBlock);
}
const TInt KMinProcessTimeToShowDialog = 2000; // 0.002 sec
const TInt KMinTimeDialogOnScreen = 1500000; // 1.5 sec
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
EXPORT_C CAknProgressDialog::CAknProgressDialog(TInt aFinalValue,TInt anIncrement,
TInt anInterval,CEikDialog** aSelfPtr) :
CAknNoteDialog(aSelfPtr),iInternalTimerControl(ETrue)
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE("aFinalValue = %d anIncrement = %d anInterval = %d", aFinalValue, anIncrement, anInterval);
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
GfxTransEffect::Register( this, KGfxWaitNoteControlUid );
#endif
iModel.iFinalValue = aFinalValue;
iModel.iHundreths = anInterval;
iModel.iIncrement = anIncrement;
iModel.iRunning = EFalse;
AKNTASHOOK_ADD( this, "CAknProgressDialog" );
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C CAknProgressDialog::CAknProgressDialog(CEikDialog** aSelfPtr) :
CAknNoteDialog(aSelfPtr),iInternalTimerControl(EFalse)
{
_AKNTRACE_FUNC_ENTER;
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
GfxTransEffect::Register( this, KGfxWaitNoteControlUid );
#endif
AKNTASHOOK_ADD( this, "CAknProgressDialog" );
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C CAknProgressDialog::CAknProgressDialog(CEikDialog** aSelfPtr,
TBool aVisibilityDelayOff)
: CAknNoteDialog(aSelfPtr),
iVisibilityDelayOff( aVisibilityDelayOff ),
iInternalTimerControl(EFalse)
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE("iVisibilityDelayOff = %d ", aVisibilityDelayOff);
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
GfxTransEffect::Register( this, KGfxWaitNoteControlUid );
#endif
AKNTASHOOK_ADD( this, "CAknProgressDialog" );
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C CAknProgressDialog::~CAknProgressDialog()
{
_AKNTRACE_FUNC_ENTER;
AKNTASHOOK_REMOVE();
if ( iInternalTimerControl )
{
PlayTone();
}
iEikonEnv->RemoveFromStack(this);
delete iCancelWhileHidden;
delete iProgressTimer;
delete iProgressDialogTimer;
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CAknProgressDialog::PreLayoutDynInitL()
{
//If the progress bar is to be controlled externally, it won't be updated
//through this dialog class
if (iInternalTimerControl)
{
CAknNoteControl* note = NoteControl();
if (!iProgressTimer)
{
iProgressTimer = new (ELeave) CAknProgressTimer;
iProgressTimer->ConstructL(&iModel,note,TCallBack(StaticDeleteL,this));
}
}
TransferControlAttributes();
// Key events should be reveived even when invisible
MEikButtonGroup* cba = ButtonGroupContainer().ButtonGroup();
STATIC_CAST( CEikCba*, cba)->SetButtonGroupFlags( cba->ButtonGroupFlags() |
EAknCBAFlagRespondWhenInvisible );
}
TInt CAknProgressDialog::DialogTimerCallback(TAny* aPtr)
{
return STATIC_CAST(CAknProgressDialog*, aPtr)->DialogTimerEvent();
}
TInt CAknProgressDialog::DialogTimerEvent()
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE("CAknProgressDialog::DialogTimerEvent iState = %d", iState);
switch ( iState )
{
case EProcessOnDisplayOff:
{
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
TBool doTransEffect = !IsVisible();
GfxTransEffect::Abort();
//register even if we don't do effect now so we can get one when closing dialog
GfxTransEffect::Register( this, KGfxWaitNoteControlUid );
TBool rsWasEnabled( EFalse );
if ( doTransEffect )
{
CAknTransitionUtils::SetData(EDontAnimateBitmaps, (TAny*)this);
if( !CAknEnv::Static()->TransparencyEnabled() && Window().IsRedrawStoreEnabled() )
{
rsWasEnabled = ETrue;
// disable redrawstore during transition to avoid
// drawing problems behind FSW
Window().EnableRedrawStore( EFalse );
}
CAknTransitionUtils::SetAllParents(this);
GfxTransEffect::Begin(this, KGfxControlAppearAction);
GfxTransEffect::NotifyExternalState(ECaptureComponentsBegin, (const TDesC8*)this);
}
#endif // RD_UI_TRANSITION_EFFECTS_POPUPS
// Display dialog
iState = EProcessOnDisplayOn;
ControlAttributes()->InvalidateLayout();
Layout();
CEikDialog::SlideDialog(); // this does nothing is sliding is disabled
DrawableWindow()->SetOrdinalPosition(0);
MakeVisible(ETrue);
CCoeControl* cba = ButtonGroupContainer().ButtonGroup()->AsControl();
iEikonEnv->RemoveFromStack(cba);
TRAP_IGNORE(iEikonEnv->EikAppUi()->AddToStackL(cba, ECoeStackPriorityCba, ECoeStackFlagRefusesFocus)); // Won't fail since we just removed it (and array will not reallocate)
cba->DrawableWindow()->SetOrdinalPosition(0);
cba->MakeVisible(ETrue);
ReportUserActivity();
PlayTone();
delete iCancelWhileHidden;
iCancelWhileHidden = NULL;
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
if ( doTransEffect )
{
TRect demarcation;
CAknTransitionUtils::GetDemarcation(CAknTransitionUtils::EPopup,
demarcation);
GfxTransEffect::SetDemarcation(this, demarcation);
GfxTransEffect::NotifyExternalState(ECaptureComponentsEnd, (const TDesC8*)this);
GfxTransEffect::End(this);
if( !CAknEnv::Static()->TransparencyEnabled() && rsWasEnabled )
{
// if redrawstore was on before transition,
// enable it again
Window().EnableRedrawStore( ETrue );
}
CAknTransitionUtils::RemoveData(EDontAnimateBitmaps);
}
#endif // RD_UI_TRANSITION_EFFECTS_POPUPS
break;
}
case EProcessOnDisplayOn:
iState = EProcessOnDisplayOnCanBeDismissed;
delete iProgressDialogTimer;
iProgressDialogTimer = NULL;
break;
case EProcessOffDisplayOff:
case EProcessOffDisplayOn:
delete iProgressDialogTimer;
iProgressDialogTimer = NULL;
ReportUserActivity();
PlayTone();
TRAP_IGNORE(TryExitL( EAknSoftkeyDone ));
break;
default:
delete iProgressDialogTimer;
iProgressDialogTimer = NULL;
}
_AKNTRACE_FUNC_EXIT;
return KErrNone;
}
EXPORT_C void CAknProgressDialog::ProcessFinishedL()
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE("CAknProgressDialog::ProcessFinishedL iState = %d", iState);
switch ( iState )
{
case EProcessOnDisplayOff:
case EProcessOnDisplayOnCanBeDismissed:
iState = EProcessOffDisplayOff;
delete iProgressDialogTimer;
iProgressDialogTimer = NULL;
ReportUserActivity();
PlayTone();
TryExitL( EAknSoftkeyDone );
break;
case EProcessOnDisplayOn:
iState = EProcessOffDisplayOn;
break;
default:
break;
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CAknProgressDialog::RunLD()
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE("RunLD iInternalTimerControl = %d iVisibilityDelayOff = %d", iInternalTimerControl, iVisibilityDelayOff);
CAknNoteControl* note = NoteControl();
note->CreateProgressBarL();
if (iInternalTimerControl)
{
if ( ((iModel.iFinalValue/iModel.iIncrement*iModel.iHundreths)*10000) < KMinProcessTimeToShowDialog )
{
CleanupStack::Pop(); // this
TryExitL( EAknSoftkeyDone );
return 0;
}
iState = EProcessOnDisplayOn;
iModel.iRunning = ETrue;
iEikonEnv->EikAppUi()->AddToStackL(this,ECoeStackPriorityDialog,ECoeStackFlagRefusesAllKeys);
return (CAknNoteDialog::RunLD());
}
iProgressDialogTimer = CPeriodic::NewL(CActive::EPriorityStandard);
if ( !iVisibilityDelayOff )
{
//TR deregister since we'll show this transition in callback
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
GfxTransEffect::Deregister( this );
#endif
iState = EProcessOnDisplayOff;
// start timer
iProgressDialogTimer->Start(TTimeIntervalMicroSeconds32(KMinProcessTimeToShowDialog),
TTimeIntervalMicroSeconds32(KMinTimeDialogOnScreen),
TCallBack(DialogTimerCallback, this) );
// Make the dialog unvisible
ButtonGroupContainer().MakeVisible(EFalse);
MakeVisible(EFalse);
// Add to stack to capture key events. This prevents user to continue working while
// the dialog is unvisible
iEikonEnv->EikAppUi()->AddToStackL(this,ECoeStackPriorityDialog);
// Allow detection and cancellation as a dialog while hidden
delete iCancelWhileHidden;
iCancelWhileHidden = NULL;
iCancelWhileHidden = CCancelWhileHidden::NewL(this);
}
else
{
MakeVisible( ETrue );
ButtonGroupContainer().MakeVisible( ETrue );
iState = EProcessOnDisplayOn;
// start timer
iProgressDialogTimer->Start(TTimeIntervalMicroSeconds32(KMinTimeDialogOnScreen),
TTimeIntervalMicroSeconds32(KMinTimeDialogOnScreen),
TCallBack(DialogTimerCallback, this) );
iEikonEnv->EikAppUi()->AddToStackL(this,ECoeStackPriorityDialog,ECoeStackFlagRefusesAllKeys);
}
_AKNTRACE_FUNC_EXIT;
return CAknNoteDialog::RunLD();
}
EXPORT_C CEikProgressInfo* CAknProgressDialog::GetProgressInfoL()
{
CAknNoteControl* note = NoteControl();
if ( !(note->GetProgressInfo()) )
{
note->CreateProgressBarL();
}
return note->GetProgressInfo();
}
EXPORT_C TKeyResponse CAknProgressDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
{
if ( aType != EEventKey )
{
return CAknNoteDialog::OfferKeyEventL(aKeyEvent,aType);
}
TInt cmdLeft = ButtonGroupContainer().ButtonGroup()->CommandId(0);
TInt cmdRight = ButtonGroupContainer().ButtonGroup()->CommandId(2);
if ( iState != EProcessOnDisplayOff )
{
// If left softkey is empty, disable ok key
if ( aKeyEvent.iCode == EKeyOK &&
( cmdLeft == 0 || cmdLeft == EAknSoftkeyEmpty ) )
{
return EKeyWasConsumed;
}
// If LSK and RSK are both empty, let note ignores enter key.
if (cmdLeft == EAknSoftkeyEmpty && cmdRight== EAknSoftkeyEmpty &&
aKeyEvent.iCode == EKeyEnter)
{
return EKeyWasConsumed;
}
return CEikDialog::OfferKeyEventL(aKeyEvent,aType);
}
else
{ // a dialog should ALWAYS be dismissed on the escape key.
if (aType == EEventKey && aKeyEvent.iCode == EKeyEscape)
return CEikDialog::OfferKeyEventL(aKeyEvent,aType);
return EKeyWasConsumed;
}
}
EXPORT_C TBool CAknProgressDialog::OkToExitL(TInt aButtonId)
{
_AKNTRACE_FUNC_ENTER;
// if dialog is invisible and app isn't exiting, eg during view switch,
// don't stop the progress dialog - it's most likely part of some
// asynchronous operation.
if ((iState == EProcessOnDisplayOff && !CAknEnv::AppWithShutterRunning()) ||
aButtonId == EAknSoftkeyEmpty )
{
_AKNTRACE("CAknProgressDialog::OkToExitL return for EProcessOnDisplayOff");
delete iCancelWhileHidden;
iCancelWhileHidden = NULL;
return EFalse;
}
if ( iCallback )
{
_AKNTRACE("CAknProgressDialog::OkToExitL succeed to execut DialogDismissedL");
iCallback->DialogDismissedL(aButtonId);
}
_AKNTRACE_FUNC_EXIT;
return ETrue;
}
//-------------------------------------------------------------------------------------
// CAknProgressDialog::HandlePointerEventL()
// Empty implementation to overwrite the implementation of CAknNoteDialog.
// CAknNoteDialog closes it self when up pointer event is captured. This
// should not.
//-------------------------------------------------------------------------------------
//
EXPORT_C void CAknProgressDialog::HandlePointerEventL(const TPointerEvent& /*aPointerEvent*/ )
{
// Empty overwriting of function
}
EXPORT_C void* CAknProgressDialog::ExtensionInterface( TUid /*aInterface*/ )
{
return NULL;
}
EXPORT_C void CAknProgressDialog::SetCallback(MProgressDialogCallback* aCallback)
{
iCallback = aCallback;
}
EXPORT_C void CAknProgressDialog::CEikDialog_Reserved_1()
{
}
EXPORT_C void CAknProgressDialog::CEikDialog_Reserved_2()
{
}
EXPORT_C void CAknProgressDialog::CAknNoteDialog_Reserved()
{
}
// End of File