javauis/lcdui_akn/lcdui/src/CMIDAlertDialog.cpp
branchRCL_3
changeset 19 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdui/src/CMIDAlertDialog.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,615 @@
+/*
+* Copyright (c) 2003 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:  Alert dialog implementation for Series 60
+*
+*/
+
+
+#include "CMIDAlert.h"
+#include "CMIDAlertDialog.h"
+#include "CMIDDisplayable.h"
+#include "CMIDCommandList.h"
+#include "CMIDUtils.h"
+
+// using TAlertDialogLineId enumeration
+#include "lcdui.hrh"
+// macros definitions for resources
+#include <lcdui.rsg>
+
+// using CAknBitmapAnimation and CBitmapAnimClientData
+// - in CheckAndSetAnimationModeL and UpdateGaugeInAlertL functions
+// for animation in gauge
+#include <aknnotecontrol.h>
+#include <eikprogi.h>
+// using CEikCaptionedControl
+// - in CheckAndSetAnimationModeL and UpdateGaugeInAlertL functions
+#include <eikcapc.h>
+
+#include <AknDef.h>
+#include <aknappui.h>
+
+// macros definitions for outputing logs
+#include <j2me/jdebug.h>
+
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+#include <touchfeedback.h>
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+
+
+/** This macro is executed each time a trapped call returns an error code different than KErrNone */
+#undef  TRAP_INSTRUMENTATION_LEAVE
+#define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDDisplayable.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult);
+
+
+/** CMIDAlertDialog::CMIDAlertDialog */
+CMIDAlertDialog* CMIDAlertDialog::NewL(CMIDAlert* aAlert,CMIDDisplayable* aDisplayable)
+{
+    CMIDAlertDialog* self = new(ELeave) CMIDAlertDialog(aAlert, aDisplayable);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+}
+//
+CMIDAlertDialog::CMIDAlertDialog(CMIDAlert* aAlert, CMIDDisplayable* aDisplayable) :
+        iParent(aAlert), iDisplayable(aDisplayable)
+{
+    iGaugeResourceType = EPopupFormUnknown;
+
+}
+
+/** CMIDAlertDialog::~CMIDAlertDialog */
+CMIDAlertDialog::~CMIDAlertDialog()
+{
+    if (iGauge)
+    {
+        iGauge->SetGaugeListenerFromAlert(NULL);
+        iGauge = NULL;
+    }
+}
+
+/** CMIDAlertDialog::PreLayoutDynInitL */
+void CMIDAlertDialog::PreLayoutDynInitL()
+{
+    // Check if there is a gauge.... and create it...
+    // NOTE: the type and properties need to be set here also...
+    CAknPopupForm::PreLayoutDynInitL();
+}
+
+/** When showing dialogs set their CBA into CMIDDisplayable and then use
+the logic of CMIDDisplayable::InitializeCbasL() to set the correct CBA
+commands. However modeless dialogs always have empty CBAs. When not
+showing we must reset the parent CBAs.
+*/
+void CMIDAlertDialog::UpdateCbasL()
+{
+    if (iShowing)
+    {
+        iDisplayable->SetCba(&ButtonGroupContainer());
+
+        if (iParent->IsModal())
+        {
+            iDisplayable->InitializeCbasL();
+        }
+        else
+        {
+            ButtonGroupContainer().SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY);
+        }
+
+        CCoeControl* cba = ButtonGroupContainer().ButtonGroup()->AsControl();
+        cba->DrawableWindow()->SetOrdinalPosition(0);
+        cba->MakeVisible(ETrue);
+        cba->DrawNow();
+    }
+    else
+    {
+        //restore parent CBAs
+        iDisplayable->SetCba(iDisplayable->MenuHandler()->Cba());
+    }
+}
+
+/** CMIDAlertDialog::PostLayoutDynInitL */
+void CMIDAlertDialog::PostLayoutDynInitL()
+{
+    CAknPopupForm::PostLayoutDynInitL();
+    // Above call is starting the animation. In case of updating gauge
+    // we will stop it and midlet will update it later.
+    CheckAndSetAnimationModeL();
+}
+
+/** CMIDAlertDialog::InsertGaugeIntoDialogL
+ Insert/remove the gauge in Alert */
+void CMIDAlertDialog::InsertGaugeIntoDialogL()
+{
+    DEBUG("CMIDAlertDialog::InsertGaugeIntoDialogL <");
+
+    TBool skipVisibilityChange = EFalse;
+
+    // skipping disabling visibility change in case of error
+    // where incremental update type gauge wasn't show
+    if (iGauge)
+    {
+        if (iGauge->GetIndefiniteState() == MMIDGauge::EIncrementalUpdating
+                && iShowing == EFalse)
+        {
+            skipVisibilityChange = ETrue;
+        }
+    }
+
+    if (!skipVisibilityChange)
+    {
+        DisableVisibilityChange(ETrue);
+    }
+
+
+    TInt gaugeVal = iGauge ? iGauge->GetValue() : -1;
+
+    //remove any existing gauge
+    if (iGaugeResourceType != EPopupFormUnknown)
+    {
+        DeleteControl(iGaugeResourceType);
+        iGaugeResourceType = EPopupFormUnknown;
+    }
+
+    //add the new gauge
+    if (iGauge)
+    {
+        iGauge->SetGaugeListenerFromAlert(this);
+        DEBUG("CMIDAlertDialog::InsertGaugeIntoDialogL - InsertControlL()");
+
+        if (iGauge->GetMaxValue() > 0)
+        { // definite type Gauge
+            // progressbar adding
+            InsertControlL(0, R_MIDP_ALERT_PROGI_LINE, EFalse);
+            iGaugeResourceType = EPopupFormProgbar;
+            iGauge->UpdateProgressInfo(CAknPopupForm::ProgressInfo());
+        }
+        else
+        {
+            iGaugeResourceType = EPopupFormWaitAnim;
+            switch (iGauge->GetIndefiniteState())
+            {
+            case MMIDGauge::EContinuousIdle: // continuous idle
+            {   //r_midp_alert_wait_animation_continouse_idle_line
+                InsertControlL(0, R_MIDP_ALERT_WAIT_ANIMATION_CONTINUOUS_IDLE_LINE, ETrue);
+                break;
+            }
+            case MMIDGauge::EContinuousRunning: // continuous running
+            {
+                InsertControlL(0, R_MIDP_ALERT_WAIT_ANIMATION_CONTINUOUS_RUNNING_LINE, ETrue);
+                break;
+            }
+            case MMIDGauge::EIncrementalUpdating: //incremental updating
+            {
+                InsertControlL(0, R_MIDP_ALERT_WAIT_BAR_INCREM_LINE, ETrue);
+                break;
+            }
+            case MMIDGauge::EIncrementalIdle: //incremental idle
+            {
+                InsertControlL(0, R_MIDP_ALERT_WAIT_BAR_INCREM_IDLE_LINE, ETrue);
+                break;
+            }
+            default:
+                ASSERT(EFalse);
+                break;
+            }
+        }
+    }
+
+    DEBUG("CMIDAlertDialog::InsertGaugeIntoDialogL - UpdateGaugeInAlertL()");
+
+    UpdateGaugeInAlertL(gaugeVal);
+
+    // skipping enabling visibility change in case of error
+    // where incremental update type gauge wasn't show
+    if (!skipVisibilityChange)
+    {
+        DisableVisibilityChange(EFalse);
+    }
+
+    DEBUG("CMIDAlertDialog::InsertGaugeIntoDialogL >");
+}
+
+/** CMIDAlertDialog::CheckAndSetAnimationMode */
+void CMIDAlertDialog::CheckAndSetAnimationModeL()
+{
+    DEBUG("CMIDAlertDialog::CheckAndSetAnimationModeL <");
+
+    TBitFlags flags = Flags();
+    if (iGauge && (iGauge->GetIndefiniteState() == MMIDGauge::EIncrementalUpdating)
+            && flags.IsSet(EPopupFormWaitAnim))
+    {
+        CCoeControl* coe = GetControlByControlTypeL(EPopupFormWaitAnim)->iControl;
+        CAknBitmapAnimation* ani = REINTERPRET_CAST(CAknBitmapAnimation*, coe);
+
+
+        DEBUG("CMIDAlertDialog::CheckAndSetAnimationModeL - CancelAnimation()");
+        ani->CancelAnimation();
+
+        CBitmapAnimClientData* animClientData = ani->BitmapAnimData();
+        iGaugeFrameCount = animClientData->FrameArray().Count();
+
+        // A non-interactive Gauge that has indefinite range will exist in one of four states:
+        // continuous-idle, incremental-idle, continuous-running, or incremental-updating.
+        // These states are intended to indicate to the user that some level of activity is
+        // occurring. With incremental-updating, progress can be indicated to the user even
+        // though there is no known endpoint to the activity.
+        if (iGauge->GetMaxValue() < 0)
+        { //CBitmapAnimClientData::TPlayMode::
+            DEBUG("CMIDAlertDialog::CheckAndSetAnimationModeL - SetPlayModeL()");
+            ani->Animation().SetPlayModeL(CBitmapAnimClientData::ECycle);
+            iIncrementalFrameCounter = 0;
+            DEBUG("CMIDAlertDialog::CheckAndSetAnimationModeL - SetFrameIndexL()");
+            ani->SetFrameIndexL(iIncrementalFrameCounter++);
+        }
+    }
+    DEBUG("CMIDAlertDialog::CheckAndSetAnimationModeL >");
+}
+
+
+/**
+*/
+void CMIDAlertDialog::UpdateGaugeInAlertL(TInt aValue)
+{
+    if (iGauge && aValue >= 0 &&
+            (iGauge->GetIndefiniteState() == MMIDGauge::EIncrementalUpdating ||
+             iGauge->GetMaxValue() > 0))
+    {
+        TBitFlags flags = Flags();
+        if (flags.IsSet(EPopupFormWaitAnim))
+        {
+            CCoeControl* coe = GetControlByControlTypeL(EPopupFormWaitAnim)->iControl;
+            CAknBitmapAnimation* ani = REINTERPRET_CAST(CAknBitmapAnimation*, coe);
+            if (iGaugeFrameCount < 1)
+                iGaugeFrameCount = 1;
+            ani->SetFrameIndexL(iIncrementalFrameCounter++ % iGaugeFrameCount);
+        }
+        else
+        {
+            // draw and update the progress bar
+            SetProgressBarAndDraw(aValue);
+            //draw of Alert
+            DrawDeferred();
+        }
+    }
+}
+
+
+void CMIDAlertDialog::GaugeTypeInAlertChangedL()
+{
+    // create new gauge type in wait dialog
+    InsertGaugeIntoDialogL();
+    CheckAndSetAnimationModeL();
+
+    // redraw gauge
+    DrawDeferred();
+}
+
+/** If the alert is timed (not modal) and if we receive a valid key event then
+we dismiss the dialog. Otherwise we pass on the key event to CAknPopupForm,
+which will take care of scrolling text for example. @see CMIDUtils::IgnoreKeyEvent()
+for key events that are ignored (eg. flip open or flip close key events. */
+TKeyResponse CMIDAlertDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
+{
+    //DEBUG START
+    if (aType == EEventKeyDown)
+    {
+        DEBUG_INT2("CMIDAlertDialog::OfferKeyEventL - key down, scan code %d key code %d",
+                   aKeyEvent.iScanCode, aKeyEvent.iCode);
+    }
+    else if (aType == EEventKey)
+    {
+        DEBUG_INT2("CMIDAlertDialog::OfferKeyEventL - key event, scan code %d key code %d",
+                   aKeyEvent.iScanCode, aKeyEvent.iCode);
+    }
+    else if (aType == EEventKeyUp)
+    {
+        DEBUG_INT2("CMIDAlertDialog::OfferKeyEventL - key up, scan code %d key code %d",
+                   aKeyEvent.iScanCode, aKeyEvent.iCode);
+    }
+    //DEBUG END
+
+    if (!iParent->IsModal() && (aType == EEventKey) && !CMIDUtils::IgnoreKeyEvent(aKeyEvent.iCode))
+    { // if not modal then pressing any valid key should dismiss it
+        iParent->TryToDismissDialog();
+        return EKeyWasConsumed;
+    }
+    //Enter_Key have a same function as Selection key.
+#ifdef RD_JAVA_S60_RELEASE_9_2
+    if (iParent->IsModal() && (aType == EEventKey) && (aKeyEvent.iCode == EKeyEnter || aKeyEvent.iCode == EKeyDevice3))
+#else
+    if (iParent->IsModal() && (aType == EEventKey) &&   aKeyEvent.iCode == EKeyEnter)
+#endif // RD_JAVA_S60_RELEASE_9_2
+    {
+        OkToExitL(iDisplayable->MainCommandList()->CommandOffset());
+        return EKeyWasConsumed;
+    }
+    return CAknPopupForm::OfferKeyEventL(aKeyEvent, aType);
+}
+
+/** Modal dialogs must let the displayable handle commands whereas modeless
+dialogs can just exit on any key (including a CBA key). However we cannot
+exit directly, we must post a java side event and wait for the java request
+to dismiss the dialog. This is why we return EFalse. */
+TBool CMIDAlertDialog::OkToExitL(TInt aCommandId)
+{
+    if (iParent->IsModal())
+    {
+        TInt offset = iDisplayable->MainCommandList()->CommandOffset();
+
+        if (aCommandId == EAknSoftkeyOptions)   // 3000
+        {
+            iDisplayable->MenuHandler()->ProcessCommandL(EAknSoftkeyOptions);
+        }
+        else if (aCommandId - offset < 0)   // aCommandId value is over 3000 - used by MSK
+        {
+            iDisplayable->ProcessCommandL(aCommandId);
+        }
+        else // aCommandId value is 7000 and over - used by LSK, RSK and EnterKey
+        {
+            CMIDCommand* tempCmd = NULL;
+            CMIDCommand* command = NULL;
+            TBool isMaped = EFalse;
+            TInt mapedCnt = ENone;
+            TInt mapedId = ENone;
+
+            // number of all commands
+            TInt numberOfCommands = iDisplayable->CommandCount();
+            // number of Ok and Item commands
+            TInt numberOfOkOptionsCommands = iDisplayable->NumCommandsForOkOptionsMenu();
+            // command ID which is get from aCommandId
+            TInt commandId = aCommandId - offset;
+
+            if (numberOfCommands > 0)
+            {
+                // Go through every midlet command, and save its ID if maped
+                // and also count maped commands.
+                for (TInt i = 0; i < numberOfCommands; i++)
+                {
+                    tempCmd = iDisplayable->MainCommandList()->At(i).iCommand;
+                    if (tempCmd->IsMappedToSoftKey())
+                    {
+                        mapedId = i;
+                        isMaped = ETrue;
+                        mapedCnt++;
+                    }
+                }
+
+                // If there are more than one maped command (LSK & RSK maped)
+                // or maped command is different than commandId (EnterKey used),
+                // set CMIDCommand command with this command, which index
+                // is the same as commandId value.
+                if (mapedCnt > 1 || mapedId != commandId)
+                {
+                    command = iDisplayable->MainCommandList()->At(commandId).iCommand;
+                }
+                else // Else if there are one or zero command maped.
+                {
+                    if (isMaped)   // One command maped.
+                    {
+                        command = iDisplayable->MainCommandList()->At(mapedId).iCommand;
+                    }
+                    else // Zero commands maped.
+                    {
+                        command = iDisplayable->MainCommandList()->At(0).iCommand;
+                    }
+                }
+
+                // type of the command
+                TInt commandType = command->CommandType();
+
+                // If there aren't any EExit, EBack, ECancel and EStop
+                // command mapped and there are still some commands
+                // show menu, else process with maped command.
+                if (commandType != MMIDCommand::EExit &&
+                        commandType != MMIDCommand::EBack &&
+                        commandType != MMIDCommand::ECancel &&
+                        commandType != MMIDCommand::EStop &&
+                        numberOfOkOptionsCommands > 1)
+                {
+                    iDisplayable->MenuHandler()->ShowMenuL(CMIDMenuHandler::EOkMenu);
+                }
+                else
+                {
+                    iDisplayable->ProcessCommandL(aCommandId);
+                }
+            }
+        }
+    }
+    else
+    {
+        iParent->TryToDismissDialog();
+    }
+
+    //The dialog can only be dismissed java side or else we'll end
+    //up with the alert displayed and no dialog
+    return EFalse;
+}
+
+/** */
+void CMIDAlertDialog::SetGaugeL(CMIDGaugeItem* aGauge)
+{
+    DEBUG("CMIDAlertDialog::SetGaugeL <");
+
+    if (iGauge)
+    {
+        iGauge->SetGaugeListenerFromAlert(NULL);
+    }
+    iGauge = (CMIDNonInteractiveGauge*)(aGauge);
+
+    DEBUG("CMIDAlertDialog::SetGaugeL - InsertGaugeIntoDialogL");
+    InsertGaugeIntoDialogL();
+
+    DEBUG("CMIDAlertDialog::SetGaugeL - CheckAndSetAnimationModeL");
+    CheckAndSetAnimationModeL();
+
+    DrawDeferred();
+    DEBUG("CMIDAlertDialog::SetGaugeL >");
+}
+
+/** Show a pre-created dialog. Dialogs are created as soon
+as Alerts are created java side. This is not necessarily when
+the dialog must be displayed. */
+void CMIDAlertDialog::ShowL(TBool aShow)
+{
+    if (aShow != iShowing)
+    {
+        if (aShow)
+        {
+            iShowing = ETrue;
+            RouseSleepingDialog();
+
+#ifdef RD_SCALABLE_UI_V2
+            SetPointerCapture(ETrue);
+#endif
+        }
+        else
+        {
+            ExitSleepingDialog();
+
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+            if (iButtonDownReceived)
+            {
+                //do feedback if alert was closed by tapping
+                MTouchFeedback* feedback = MTouchFeedback::Instance();
+                if (feedback)
+                {
+                    feedback->InstantFeedback(ETouchFeedbackPopUp);
+                }
+            }
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+
+#ifdef RD_SCALABLE_UI_V2
+            SetPointerCapture(EFalse);
+            iButtonDownReceived = EFalse;
+#endif
+            iShowing = EFalse; //attention: iShowing must be true when dismissing
+            // a dialog or else MakeVisible() won't execute and
+            // we won't update the fader's stack, @see MakeVisible()
+        }
+
+        UpdateCbasL();
+    }
+}
+
+/** Because CAknPopupForm calls MakeVisible(ETrue) in several
+places, including LayoutAndDraw() and because we don't want to
+become visible when we are not showing, we had to override the
+MakeVisible() method and pass on the call only when we are
+showing. Also, CMIDAlert can disable temporarily the MakeVisible
+calls by setting iVisibilityChangeDisabled via DisableVisibilityChange().
+This is because when we call SetTitle() or SetImage() we must insert
+or remove controls into the dialog and popup form does MakeVisible(EFalse)
+and then MakeVisible(ETrue) after the control has been added or removed.
+This results in an unpleasant appearing and disappearing of the dialog
+because we add or remove more than one control. */
+void CMIDAlertDialog::MakeVisible(TBool aVisible)
+{
+    if (iShowing && !iVisibilityChangeDisabled)
+    {
+        if (aVisible)
+        {
+            //re-layouting done just before dialog is shown
+            //to be sure layout is correct in CAknPopupForm
+            CAknPopupForm::SizeChanged();
+        }
+        CAknPopupForm::MakeVisible(aVisible);
+    }
+}
+
+
+#ifdef RD_SCALABLE_UI_V2
+/**
+ * Closes timed alert on EButton1Up event. Detecting long taps is done through
+ * CMIDAlert::TryDetectLongTapL.
+ */
+void CMIDAlertDialog::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+{
+    if (AknLayoutUtils::PenEnabled())
+    {
+        // Long tap may be canceled by dragging pointer out of alert area,
+        // need to make sure that events are forwarded to long tap detector in this case.
+        if ((AlertRegionContains(aPointerEvent.iPosition) ||
+                aPointerEvent.iType != TPointerEvent::EButton1Down) &&
+                iParent->TryDetectLongTapL(aPointerEvent))
+        {
+            return;
+        }
+
+        switch (aPointerEvent.iType)
+        {
+        case TPointerEvent::EButton1Down:
+            iButtonDownReceived = ETrue;
+            break;
+        case TPointerEvent::EButton1Up:
+            if (!iParent->IsModal() && iButtonDownReceived)
+            {
+                iParent->TryToDismissDialog();
+            }
+            break;
+        case TPointerEvent::EDrag:
+            break;
+        default:
+            break;
+        }
+
+    }
+}
+#endif
+
+
+/** Disable the MakeVisible() calls. See @MakeVisible() */
+void CMIDAlertDialog::DisableVisibilityChange(TBool aDisable)
+{
+    iVisibilityChangeDisabled = aDisable;
+}
+
+/** We disable unnecessary layout operation in an attempt to optimise because of
+    defect OULM-6K4C2X. This would not be needed if CAknPopupForm::InsertControlL()
+    would not call LayoutAndDraw() every time and also CAknPopupForm::SetSizeAndPosition()
+    results in the execution of SizeChanged() 3 times. So a lot of layout operations get
+    in the way of performance. */
+void CMIDAlertDialog::SizeChanged()
+{
+    if (!iVisibilityChangeDisabled || iShowing)
+    {
+        CAknPopupForm::SizeChanged();
+    }
+}
+
+void CMIDAlertDialog::HandleResourceChange(TInt aType)
+{
+    if (aType == KEikDynamicLayoutVariantSwitch)
+    {
+        LayoutAndDraw();
+
+        TRAP_IGNORE(InsertGaugeIntoDialogL(); CheckAndSetAnimationModeL(););
+
+        DrawDeferred();
+    }
+    else
+    {
+        CAknPopupForm::HandleResourceChange(aType);
+    }
+}
+
+#ifdef RD_SCALABLE_UI_V2
+TBool CMIDAlertDialog::AlertRegionContains(const TPoint& aPoint)
+{
+    return (aPoint.iX >= 0 && aPoint.iX <= iSize.iWidth &&
+            aPoint.iY >= 0 && aPoint.iY <= iSize.iHeight);
+}
+#endif
+
+// End of File