/*
* 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: 
*
*/

// AknForm.cpp
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.
//


#include <AknForm.h>
#include <AknQueryDialog.h>
#include <eikdialg.h>
#include <eikmenub.h>
#include <eikenv.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <uikon/eikenvinterface.h>
#endif
#include <eikappui.h>
#include <eiklabel.h>
#include <eikedwin.h>
#include <barsread.h>

#include <avkon.hrh>
#include <avkon.rsg>
#include <aknnotedialog.h>
#include <eikcapc.h>
#include "aknenv.h"
#include <eikedwin.h>

#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
#include <gfxtranseffect/gfxtranseffect.h>
#endif

/**
 * Local Panic Function and Panic Codes  (Shared by AknDialog & AknForm)
 */
enum TPanicCodes
	{
	EGeneralFormPanic,
	ENoMenuBar,
	EMenuCommandUnknown
	};

void Panic(TPanicCodes aPanic)
	{
	_LIT(kForm, "AVKON-FORM");
	User::Panic(kForm, aPanic);
	}

/**
 * Constructor 
 */
EXPORT_C CAknForm::CAknForm() 
	{
#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
    GfxTransEffect::Deregister( this );
#endif
    iWsBufferRequestID = iAvkonEnv->RequestWsBuffer( 16000 ); 
	}

/**
 * Creates a default Form menu using default form menu resource.
 * (note that the parameter, a new menu bar resource, is saved for later.
 */
EXPORT_C void CAknForm::ConstructL(TInt aMenuBarId)
	{
	iMenuBarId = aMenuBarId;
	CAknDialog::ConstructL(R_AVKON_FORM_MENUBAR);
	}

/**
 *
 */
EXPORT_C CAknForm::~CAknForm() 
	{
    // cancels large WS client buffer required by form
    iAvkonEnv->CancelWsBufferRequest( iWsBufferRequestID );
	}

/**
 * This function intialises the items on the menu.  It's used to disable and enable menu items and may be
 * over riden to add new ones.
 * In addition it adds menu items which have been provided in the ContsructL in the form of a Menu Bar resource.
 * Instead of using the Menu Bar directly it extracts the menu panes and adds them to it's own menu pane.
 * It must be called in the DynInitMenuPaneL() function of any derived class before anything else!!
 *
 */
EXPORT_C void CAknForm::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane) 
	{
	if (aResourceId == R_AVKON_FORM_MENUPANE)
		{
		if (iMenuBarId)
			{
					
			TResourceReader reader;
			iCoeEnv->CreateResourceReaderLC(reader, iMenuBarId);

			TInt count = reader.ReadInt16();  // Number of menu panes
			while (count--)
				{
				TInt menuPaneResourceId = reader.ReadInt32();
				reader.ReadTPtrC(); // read and ignore the rest...
				reader.ReadInt32();
				reader.ReadTPtrC();
				reader.ReadInt16();
				reader.ReadInt16();
				reader.ReadInt32(); 
				aMenuPane->AddMenuItemsL(menuPaneResourceId, 0, ETrue); // at the top, with a separator
				}
			CleanupStack::PopAndDestroy(); // Resource Reader
			}

		TBool editOptionDimmed = IsEditable();
		aMenuPane->SetItemDimmed(EAknFormCmdEdit, editOptionDimmed);
		aMenuPane->SetItemDimmed(EAknFormCmdSave, !editOptionDimmed);
		aMenuPane->SetItemDimmed(EAknFormCmdLabel, !editOptionDimmed);
		aMenuPane->SetItemDimmed(EAknFormCmdAdd, !editOptionDimmed);
		aMenuPane->SetItemDimmed(EAknFormCmdDelete, !editOptionDimmed);
		}
	}

/**
 *From MEikCommandObserver (act on the menu selection if menu is showing - pass on to client if not processed here)
 */
EXPORT_C void CAknForm::ProcessCommandL(TInt aCommandId)
	{
	CAknDialog::ProcessCommandL(aCommandId);

	switch (aCommandId)
		{
		case EAknFormCmdEdit : // Change into edit state
			if (!IsEditable())
				SetEditableL(ETrue);
			break;
		case EAknFormCmdAdd : // Add Field to Form (display dialog)
			AddItemL();
			break;
		case EAknFormCmdSave : // Save form data (must be implemented by Child) and revert to View Mode
			if (SaveFormDataL()) 
				{
				SetChangesPending( EFalse );
				TBool hasEditModeOnly = FormFlagsFromActivePage()&EEikFormEditModeOnly;
				if (!hasEditModeOnly)
				SetEditableL(EFalse);
				}
			break;
		case EAknFormCmdLabel : // Edit selected label (display dialog)
			EditCurrentLabelL();
			break;
		case EAknFormCmdDelete : // Delete selected item (control)
			DeleteCurrentItemL();
			break;
		default :
			// Default action is to do nothing.
			// Mustn't panic as this function might be called by a child which has already
			// acted upon an action which it has added to the menu.
			break;
		}
	}


/**
 *		From CEikDialog (thence  MEikDialogPageObserver)
 *		If deleting then this routine must not do anything (the default tries to access the control
 *		which has just been deleted!)
 */
EXPORT_C void CAknForm::PrepareForFocusTransitionL()
	{
	if (!Deleting())
		CAknDialog::PrepareForFocusTransitionL();
	}



/**
 *
 * From CEikDialog - Use this to pop up the options menu or close the dialog.
 * Will call SaveFormDataL() before closing if data has been edited.
 * Will NOT permit exit if attempt to save data fails.
 */
EXPORT_C  TBool CAknForm::OkToExitL(TInt aButtonId) 
	{
	TBool hasEditModeOnly = FormFlagsFromActivePage()&EEikFormEditModeOnly;

	if (iMenuBar)
		HideMenu();

	if (aButtonId == EAknSoftkeyOptions)
		{
		DisplayMenuL();
		return EFalse;
		}
	else if ( aButtonId  == EAknSoftkeyBack)
		{
		if (IsEditable())
			{
			TBool mayExitEditMode = ETrue;
			if (UnsavedEdit())
				{
				if ( QuerySaveChangesL() )
					{
					// User has chosen to save. Attempt to save.  Implementation of this
					// may in some situations return EFalse.  This will prevent leaving edit 
					// mode
					mayExitEditMode = SaveFormDataL(); 
					if ( mayExitEditMode )
						SetChangesPending( EFalse );
					}
				else // introduced to allow users to re-set data when a save is undesired.
					DoNotSaveFormDataL();
				}
			if (hasEditModeOnly)
				{
				if ( !mayExitEditMode )
					return EFalse; // stay in Form because save failed  
				}
			else
				{
				if ( mayExitEditMode )
                    {
                    SetEditableL( EFalse ); // go out of edit mode of Form
                    CEikCaptionedControl* line = Line( IdOfFocusControl() );
                    if ( line )
                        {
                        line->SetEditableL( EFalse );
                        line->SetCurrent( EFalse );
                        line->DrawDeferred(); // otherwise will be partly redrawn
                        }
                    }
				return EFalse; // remain in form ( but in view mode if save was OK).
                }

			} // end of if (IsEditable())

		return ETrue;
		}
    else if (aButtonId == EAknSoftkeyChange)
        {
    	if (ControlOrNull(IdOfFocusControl()))
    	    {
    	    // we need to inform popup field about MSK event
            TKeyEvent event = { EKeyOK, EKeyOK, EModifierPureKeycode, 0 };
        	Line(IdOfFocusControl())->OfferKeyEventL(event, EEventKey );
    	    }
        }
	return EFalse;
	}

EXPORT_C void CAknForm::HandleResourceChange(TInt aType)
	{
	CEikDialog::HandleResourceChange(aType);
	}



/**
 * This routine should be re-implemented by the client to save the contents of the form.
 * The re-implementation can call this function to display the 'Saved' dialog.
 * (CAknForm::SaveFormDataL())
 *
 * This should return ETrue unless there was a problem saving that the user can circumvent
 * If it is a serious system problem, then a Leave should be generated
 *
 * Note that the changes pending flag is not cleared here ( but you could if you want to ); 
 * it is the responsibility of the caller to clear iff return is ETrue.
 */
EXPORT_C  TBool CAknForm::SaveFormDataL()
	{
	return (ETrue);
	}

/**
 * This routine may be overridden.  Default displays 'Save Changes Dialog Yes/No'
 * Returns ETrue if Changes are requested to be saved and then are successfully saved
 * 
 * Re-implementation may put data validation here (as an alternative to over-riding
 * OkToExit - which is a more complicated method )
 *
 * Note that this routine does not perform the changes itself. 
 */
EXPORT_C TBool CAknForm::QuerySaveChangesL()
	{
	CAknQueryDialog* saveChangesDialog = CAknQueryDialog::NewL();
	TInt option = saveChangesDialog->ExecuteLD(R_AVKON_FORM_DEFAULT_SAVE_CHANGES_DIALOG);
	return ( option );
	}

EXPORT_C void CAknForm::SetChangesPending(TBool aChangesPending)
	{
	SetFormFlag( EUnsavedEdit, aChangesPending );
	}


/**
 * This routine may be overridden.  Default displays old label as caption and editor for new one
 * Uses customised dialog 
 */
EXPORT_C void CAknForm::EditCurrentLabelL() 
	{
	const TInt KFurtherTextIrrelevant=30;
	if (!ControlOrNull(IdOfFocusControl()))
		return;
	TPtrC originalLabel = Line(IdOfFocusControl())->GetFullCaptionText();
	TBuf<KFurtherTextIrrelevant> buf= originalLabel.Left(KFurtherTextIrrelevant);
	TResourceReader reader ;
	iCoeEnv->CreateResourceReaderLC( reader, R_AVKON_TEXT_EDIT_LABEL_QUERY_TEXT ) ;
	HBufC* editLabelQueryPrompt = reader.ReadHBufCL();
	CleanupStack::PushL(editLabelQueryPrompt);
	CAknTextQueryDialog* dlg = CAknTextQueryDialog::NewL(buf);
	dlg->PrepareLC(R_AVKON_DEFAULT_EDIT_LABEL_QUERY);
	dlg->SetPromptL(*editLabelQueryPrompt);
	TInt queryOk = dlg->RunLD();
	CleanupStack::PopAndDestroy(); // editLabelQueryPrompt
	CleanupStack::PopAndDestroy(); // reader
  	if(queryOk == EAknSoftkeyOk)
		{	
		SetFormFlag( EUnsavedEdit, ETrue );
		TRAP_IGNORE(Line(IdOfFocusControl())->SetCaptionL(buf));
		}
	DrawNow();
	}

/**
 * This routine may be overridden.  Default displays delete item? Yes/No
 * Deletes Item on return from Dialog before returning
 */
EXPORT_C void CAknForm::DeleteCurrentItemL() 
	{
	CAknQueryDialog* deleteItemDialog = CAknQueryDialog::NewL();
	TInt option = deleteItemDialog->ExecuteLD(R_AVKON_FORM_DEFAULT_DELETE_ITEM_DIALOG);
	if (option == EAknSoftkeyYes)
		{
		SetFormFlag( EDeleting, ETrue );

		TInt LineForDeletion = IdOfFocusControl();

		if (LineForDeletion)
			{
			DeleteLine(LineForDeletion);
			SetFormFlag( EUnsavedEdit, ETrue );
			}
		DrawNow();
		SetFormFlag( EDeleting, EFalse );
		}
	}

/**
 * This routine may be overridden.  Default displays Add Item
 * Uses customised dialog
 */
EXPORT_C void CAknForm::AddItemL() 
	{	
	}


/**
 * 
 */
EXPORT_C TBool CAknForm::UnsavedEdit() const
	{
	return (iFlags & EUnsavedEdit);
	}

EXPORT_C TBool CAknForm::Deleting() const
	{
	return (iFlags & EDeleting);
	}


EXPORT_C void CAknForm::PostLayoutDynInitL()
	{
	if (FormFlagsFromActivePage()&EEikFormEditModeOnly)
		SetEditableL(ETrue);
	else 
		SetEditableL(EFalse);
	}

/*
Overridden, so that the form can tell if a line's state has changed.
This is used to decide when to save changes.
*/

EXPORT_C void CAknForm::HandleControlStateChangeL(TInt aControlId)
	{
	SetChangesPending(ETrue);
	CAknDialog::HandleControlStateChangeL(aControlId);
	}

/*
This is added, so that anyone adding lines either in PreLayoutDynInit or SetInitialCurrentLine
should have the lines in a consistent state.
*/
EXPORT_C void CAknForm::SetInitialCurrentLine()
	{
	// call SetEditableL again to put controls in consistent state.
	
	TRAP_IGNORE(SetEditableL(IsEditable()));  // re-run the seteditable to ensure any added lines are in consistent state.
	// ignore e.  
	CAknDialog::SetInitialCurrentLine();
	}

EXPORT_C void CAknForm::SetFormFlag(enum CAknForm::TFlags aFlagPattern, TBool aSetTheFlag )
	{
	if ( aSetTheFlag )
		iFlags |= aFlagPattern;
	else
		iFlags &= (~aFlagPattern);
	}

EXPORT_C void CAknForm::HandlePointerEventL(const TPointerEvent& aPointerEvent) 
    { 
    CAknDialog::HandlePointerEventL(aPointerEvent); 
    }

EXPORT_C void* CAknForm::ExtensionInterface( TUid /*aInterface*/ ) 
    { 
    return NULL;
    }


EXPORT_C void CAknForm::DoNotSaveFormDataL() 
	{
	
	}; 

EXPORT_C void CAknForm::CEikDialog_Reserved_1() 
	{
	
	}

EXPORT_C void CAknForm::CEikDialog_Reserved_2() 
	{
	
	}

EXPORT_C void CAknForm::CAknDialog_Reserved() 
	{
	
	}

EXPORT_C void CAknForm::CAknForm_Reserved() 
	{
	
	}

void CAknForm::DoLayout()
	{
	Layout();
	}
