// EIKGTED.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <txtglobl.h>
#include <txtrich.h>
#include <fldinfo.h>
#include <prnsetup.h>
#include <frmprint.h>
#include <frmpage.h>
#include <badesca.h>
#include <barsread.h>
#include <eikgted.h>
#include <eikenv.h>
#include <eikfindd.h>
#include <eikfontd.h>
#include <eikparad.h>
#include <eiktabdg.h>
#include <eikbutb.h>
#include <eikcmbut.h>
#include <eiklbbut.h>
#include <eikdlgtb.h>
#include <eikdef.hrh>
#include <eikprtpv.h>
#include <eikprtdg.h>
#include <eiktxtut.h>
#include <eikedwin.hrh>
#include <eikpriv.hrh>
#include <eikcmds.hrh>
#include <eikon.rsg>
#include <eikon.mbg>
#include <eikpriv.rsg>

EXPORT_C CEikGlobalTextEditor::CEikGlobalTextEditor()
	{ }

EXPORT_C CEikGlobalTextEditor::CEikGlobalTextEditor(const TEikBorder& aBorder)
	: CEikEdwin(aBorder)
	{ }

EXPORT_C CEikGlobalTextEditor::~CEikGlobalTextEditor()
	{
	delete iFindList;
	delete iReplaceList;
	delete iFindModel;
	if (~iEdwinUserFlags&EKeepDocument)
		{
		delete iParaFormatLayer;
		delete iCharFormatLayer;
		}
	delete iLineCursor;
	}

EXPORT_C void CEikGlobalTextEditor::ConstructL(const CCoeControl* aParent,TInt aNumberOfLines,TInt aTextLimit,
											   TInt aEdwinFlags,TInt aFontControlFalgs,
											   TInt aFontNameFlags)
	{
	iNumberOfLines=aNumberOfLines;
	iTextLimit=aTextLimit;
	iEdwinUserFlags|=aEdwinFlags;
	iFontControlFlags=aFontControlFalgs;
	iFontNameFlags=aFontNameFlags;
	if (aParent)
		SetContainerWindowL(*aParent);
	else
		SetContainerWindowL();
	BaseConstructL();
	}

EXPORT_C void CEikGlobalTextEditor::BaseConstructL()
	{
	if (iEdwinUserFlags&ELineCursor)
		SetLineCursorBitmapL(NULL);
	if (iEdwinUserFlags&EUserSuppliedText)
	    return;
	iParaFormatLayer=CEikonEnv::NewDefaultParaFormatLayerL();
	iCharFormatLayer=CEikonEnv::NewDefaultCharFormatLayerL();
	TCharFormat charFormat;
	TCharFormatMask charMask;
	iCharFormatLayer->Sense(charFormat,charMask);
	charFormat.iFontSpec.iTypeface.SetAttributes(EikFontUtils::TypefaceAttributes(*(iEikonEnv->ScreenDevice()),charFormat.iFontSpec.iTypeface.iName));
	charMask.SetAttrib(EAttFontTypeface);
	iCharFormatLayer->SetL(charFormat,charMask);
	CreateTextAndLayoutL(iParaFormatLayer,iCharFormatLayer);
	}

EXPORT_C void CEikGlobalTextEditor::ConstructFromResourceL(TResourceReader& aReader)
	{
	iSize.iWidth=aReader.ReadInt16();
	TInt height=aReader.ReadInt16();
	iNumberOfLines=aReader.ReadInt16();
	iTextLimit=aReader.ReadInt16();
	iEdwinUserFlags|=aReader.ReadInt32();
	(TInt&)iFontControlFlags=aReader.ReadInt16();
	(TInt&)iFontNameFlags=aReader.ReadInt16();
	BaseConstructL();
	iSize.iHeight=height;
	}

EXPORT_C void CEikGlobalTextEditor::SetButtonGroup(CEikDialogToolBar* aButtonGroup)
	{
	iButGroup=aButtonGroup;
	}

EXPORT_C void CEikGlobalTextEditor::SetLineCursorBitmapL(CFbsBitmap* aBitmap)
	{
	delete iLineCursor;
	if (aBitmap)
		iLineCursor=aBitmap;
	else
		iLineCursor=iEikonEnv->CreateBitmapL(TPtrC(),EMbmEikonLncusr1);
	iLineCursorWidth=iLineCursor->SizeInPixels().iWidth+2; // +2 because FORM 075 subtracts 2 pixels for label margin
	iEdwinUserFlags|=ELineCursor;
	if (iTextView)
		{
		iTextView->SetLineCursorBitmap(aBitmap);
		SetLineCursorDetailsL();
		}
	}

EXPORT_C TInt CEikGlobalTextEditor::LineCursorWidth() const
	{
	return iLineCursorWidth;
	}

EXPORT_C void CEikGlobalTextEditor::ActivateL()
	{
	if (!iTextView)
		CreateTextViewL();
	iTextView->SetLineCursorBitmap(iLineCursor);
	CEikEdwin::ActivateL();
	UpdateButtonGroup();
	}

TBool CEikGlobalTextEditor::DoFindL()
	{
	if (iFindModel->iText.Length()>TextLength())
		{
		DisplayFindTextNotFound(iFindModel->iText);
		return EFalse;
		}
	TBool found=EFalse;
	TRAPD(ret,found=FindL(&iFindModel->iText,iFindModel->iFlags));
	if (ret!=KErrNone)
		User::Leave(ret);
	else
		{
		if (!found)
			{
			DisplayFindTextNotFound(iFindModel->iText);
			return EFalse;
			}
		}
	return ETrue;
	}

void CEikGlobalTextEditor::CheckDocumentNotEmptyL()
	{
	if (!TextLength())
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_NOTHING_TO_FIND);
	}

void CEikGlobalTextEditor::CreateFindModelL()
	{
	if (!iFindModel)
		{
		iFindModel=new(ELeave) SEdwinFindModel;
		iFindModel->iFlags=0;
		}
	if (!iFindList)
		iFindList=new(ELeave) CDesCArrayFlat(5);
	if (!iReplaceList)
		iReplaceList=new(ELeave) CDesCArrayFlat(5);
	}

EXPORT_C void CEikGlobalTextEditor::RunFindDialogL()
	{
	CreateFindModelL();
	CheckDocumentNotEmptyL();
	GetTextForFindL();
	CEikDialog* dialog=new(ELeave) CEikEdwinFindDialog(iFindModel, iFindList);
	iFindModel->iFlags&=(~EFindAgain);
	if (dialog->ExecuteLD(R_EIK_DIALOG_FIND))
		DoFindL();
	}

EXPORT_C void CEikGlobalTextEditor::RunFindAgainDialogL()
	{
	CheckDocumentNotEmptyL();
	CreateFindModelL();
	if (!iFindModel->iText.Length())
		GetTextForFindL();
	if (!iFindModel->iText.Length())
		RunFindDialogL();
	else
		{
		iFindModel->iFlags|=EFindAgain;
		DoFindL();
		}
	}

void CEikGlobalTextEditor::GetTextForFindL()
	{
	TInt pos=0;
	TBuf<EEikEdwinFindStringMaxLen>* findText=new(ELeave) TBuf<EEikEdwinFindStringMaxLen>;
	CleanupStack::PushL(findText);
	GetFindText(findText);
	TInt retcode=iFindList->Find(*findText,pos);
	if (retcode)
		iFindList->InsertL(0,*findText);
	iFindModel->iText=*findText;
	CleanupStack::PopAndDestroy();
	}

EXPORT_C void CEikGlobalTextEditor::RunReplaceDialogL()
	{
	CreateFindModelL();
	CheckDocumentNotEmptyL();
	GetTextForFindL();
	CEikDialog* dialog=new(ELeave) CEikEdwinReplaceDialog(iFindModel, iFindList, iReplaceList);
	if (dialog->ExecuteLD(R_EIK_DIALOG_REPLACE))
		{
		if (!DoFindL())
			return;
		CEikDialog* dialog=new(ELeave) CEikEdwinReplaceOptionDialog(this,iFindModel);
		if (!dialog->ExecuteLD(R_EIK_DIALOG_REPLACE_OPTIONS))
			{
			if (SelectionLength())
				ClearSelectionL();  
			return;
			}
		if (iFindModel->iReplaceOption==EReplaceAll)
			{ // display busy message
			iEikonEnv->BusyMsgL(R_EIK_TBUF_REPLACING_BUSYMSG,500000); // 0.5 seconds
			DrawNow();
			ForceScrollBarUpdateL();
			ReplaceAllL(iFindModel);
			iEikonEnv->BusyMsgCancel();
			}
		iEikonEnv->InfoMsg(R_EIK_TBUF_REPLACE_FINISHED);
	 	if (SelectionLength())
			ClearSelectionL();  
		}
	}

EXPORT_C TKeyResponse CEikGlobalTextEditor::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	if (iEdwinUserFlags&EDisplayOnly)
		return EKeyWasConsumed;
	if (!(aKeyEvent.iModifiers&EModifierCtrl) || aKeyEvent.iModifiers&EModifierPureKeycode)
		return CEikEdwin::OfferKeyEventL(aKeyEvent,aType);
	TBool formatChanged=ETrue;
	TFontStyleFlags fontFlag=EStandard;
	TBuf<24> buf;
	if (aKeyEvent.iModifiers&EModifierShift)
			iCoeEnv->ReadResource(buf,R_EIK_EDWIN_SHIFT_CTRL_HOTKEYS);
	else
		iCoeEnv->ReadResource(buf,R_EIK_EDWIN_CTRL_HOTKEYS);
	const TInt ret=buf.Locate(TChar(aKeyEvent.iCode+'a'-1));
	switch (ret)
		{
	case EHotKeyBold:
		CheckNotReadOnlyL();
		fontFlag=EBold;
		break;
	case EHotKeyItalic:
		CheckNotReadOnlyL();
		fontFlag=EItalic;
		break;
	case EHotKeyUnderline:
		CheckNotReadOnlyL();
		fontFlag=EUnderline;
		break;
	case EHotKeyFont:
		CheckNotReadOnlyL();
		RunFontDialogL(iFontNameFlags,iGraphicsDevice, iFontControlFlags);
		break;
	default:
		formatChanged=EFalse;
		}
	if (formatChanged)
		{
		if (fontFlag!=EStandard && !(aKeyEvent.iModifiers&EModifierShift))
			BoldItalicUnderlineEventL(fontFlag);
		if (iButGroup)
			UpdateButtonGroup();
		return EKeyWasConsumed;
		}
	return CEikEdwin::OfferKeyEventL(aKeyEvent,aType);
	}

EXPORT_C void CEikGlobalTextEditor::UpdateButtonGroup()
	{
	if (!iButGroup)
		return;
	TCharFormat charFormat;
	TCharFormatMask mask;
	const TCursorSelection selection=Selection();
	GlobalText()->GetCharFormat(charFormat,mask,selection.LowerPos(),selection.Length());
	CEikButtonBase* but=STATIC_CAST(CEikLabeledButton*,iButGroup->ControlById(EEikCidFontBoldBut))->Button();
	if (but)
		{
		CEikButtonBase::TState state=((charFormat.iFontSpec.iFontStyle.StrokeWeight()==EStrokeWeightBold)?
			CEikButtonBase::ESet : CEikButtonBase::EClear);
		if (but->State()!=state)
			{
			but->SetState(state);
			but->DrawNow();
			}
		}
	but=STATIC_CAST(CEikLabeledButton*,iButGroup->ControlById(EEikCidFontItalicBut))->Button();
	if (but)
		{
		CEikButtonBase::TState state=((charFormat.iFontSpec.iFontStyle.Posture()==EPostureItalic)?
			CEikButtonBase::ESet : CEikButtonBase::EClear);
		if (but->State()!=state)
			{
			but->SetState(state);
			but->DrawNow();
			}
		}
	but=STATIC_CAST(CEikLabeledButton*,iButGroup->ControlById(EEikCidFontUnderlineBut))->Button();
	if (but)
		{
		CEikButtonBase::TState state=((charFormat.iFontPresentation.iUnderline==EUnderlineOn)?
			CEikButtonBase::ESet : CEikButtonBase::EClear);
		if (but->State()!=state)
			{
			but->SetState(state);
			but->DrawNow();
			}
		}
	}

EXPORT_C void CEikGlobalTextEditor::SetGraphicsDevice(CGraphicsDevice* aGraphicsDevice)
	{
	iGraphicsDevice=aGraphicsDevice;
	}

EXPORT_C TBool CEikGlobalTextEditor::RunFontDialogL(TInt aFontDialogFlags,CGraphicsDevice* aGraphicsDevice, 
													TInt aFontControlFlags)
	{
	TCursorSelection selection=Selection();
	TInt selectionLength=selection.Length();
	//get backgroundcolor
	CParaFormat paraFormat;
	TParaFormatMask variesMask;
	GlobalText()->GetParaFormatL(&paraFormat,variesMask,selection.LowerPos(),selectionLength);

	TCharFormat charFormat;
	TCharFormatMask charMask;
	TCharFormatMask charUndeterminedMask;
	TBuf<KTextSelectionMaxLen> buf;
	GlobalText()->GetCharFormat(charFormat,charUndeterminedMask,selection.LowerPos(),selectionLength);
	if (selectionLength>KTextSelectionMaxLen)
		selectionLength=KTextSelectionMaxLen;
	GlobalText()->Extract(buf,selection.LowerPos(),selectionLength);
	TInt offset=buf.Locate(CEditableText::EParagraphDelimiter); 
	if (offset!=KErrNotFound)   // chop off buf if paragraph end
		buf.SetLength(offset);
	TCharFormat originalFormat=charFormat;
	TCharFormatMask oldcharMask;
	CEikFontDialog* dialog=new(ELeave) CEikFontDialog(charFormat,charMask,charUndeterminedMask,buf,
													aFontDialogFlags,aGraphicsDevice,aFontControlFlags,
													paraFormat.iFillColor);
	if (!dialog->ExecuteLD(R_EIK_DIALOG_FONT) || (originalFormat.IsEqual(charFormat) && charMask==oldcharMask))
		return(EFalse);
	ApplyCharFormatL(charFormat,charMask);
	UpdateButtonGroup();
	return(ETrue);
	}

EXPORT_C void CEikGlobalTextEditor::ApplyCharFormatL(TCharFormat& aCharFormat,TCharFormatMask& aCharMask)
	{
	const TCursorSelection selection=Selection();
	GlobalText()->ApplyCharFormatL(aCharFormat,aCharMask,selection.LowerPos(),selection.Length());
	if (iEdwinInternalFlags&ERichText)
		{
		if (selection.Length()==0)
			iTextView->MatchCursorHeightL(aCharFormat.iFontSpec);
		else
			iTextView->HandleRangeFormatChangeL(selection,EFalse);
		}
	else
		{
		TViewYPosQualifier yPosQualifier;
		yPosQualifier.SetMakeLineFullyVisible();
		iTextView->HandleGlobalChangeL(yPosQualifier);
		}
	UpdateScrollBarsL();
	ReportEdwinEventL(MEikEdwinObserver::EEventFormatChanged);
	}

EXPORT_C void CEikGlobalTextEditor::ApplyParaFormatL(CParaFormat* aParaFormat,TParaFormatMask& aParaMask)
	{
	TCursorSelection selection=Selection();
	GlobalText()->ApplyParaFormatL(aParaFormat,aParaMask,selection.LowerPos(),selection.Length());
	if (iEdwinInternalFlags&ERichText)
		iTextView->HandleRangeFormatChangeL(selection,ETrue);
	else
		{
		TViewYPosQualifier yPosQualifier;
		yPosQualifier.SetMakeLineFullyVisible();
		iTextView->HandleGlobalChangeL(yPosQualifier); // !! NotifyForwardChangedL() may be better for rich text case
		}
	UpdateScrollBarsL();
	ReportEdwinEventL(MEikEdwinObserver::EEventFormatChanged);
	}


EXPORT_C void CEikGlobalTextEditor::RunParaDialogsL(TInt aCommand)
	{
	CParaFormat* paraFormat=CParaFormat::NewLC();
	TParaFormatMask paraMask;
	TParaFormatMask paraUndeterminedMask;
	TCursorSelection selection=Selection();
	TInt selectionLength=selection.Length();
	GlobalText()->GetParaFormatL(paraFormat,paraUndeterminedMask,selection.LowerPos(),selectionLength);
	CEikDialog* dialog=NULL;
	TInt resourceId=0;
	switch (aCommand)
		{
	case EEikCmdParaAlign:
		dialog=new(ELeave) CEikAlignDialog(paraFormat,paraMask, paraUndeterminedMask);
		resourceId=R_EIK_DIALOG_ALIGNMENT;
		break;
	case EEikCmdParaSpacing:
		dialog=new(ELeave) CEikSpaceDialog(paraFormat,paraMask,paraUndeterminedMask);
		resourceId=R_EIK_DIALOG_SPACE;
		break;
	case EEikCmdParaBorder:
		{
		dialog=new(ELeave) CEikBorderDialog(paraFormat,paraMask,paraUndeterminedMask);
		TInt numColors;
		TInt numGrays;
		TDisplayMode defaultMode=iEikonEnv->WsSession().GetDefModeMaxNumColors(numColors,numGrays);
		resourceId=((defaultMode>=EColor16) ? R_EIK_DIALOG_BORDER_COLOR2 : R_EIK_DIALOG_BORDER_COLOR);
		break;
		}
	default:
		CleanupStack::PopAndDestroy();
		return;
		}
	if (dialog->ExecuteLD(resourceId))
		ApplyParaFormatL(paraFormat,paraMask);
	CleanupStack::PopAndDestroy();
	}

EXPORT_C void CEikGlobalTextEditor::RunTabsDialogL(TInt aPageWidth)
	{
	CParaFormat* paraFormat=CParaFormat::NewLC();
	TParaFormatMask paraMask;
	TParaFormatMask paraUndeterminedMask;
	TCursorSelection selection=Selection();
	TInt selectionLength=selection.Length();
	GlobalText()->GetParaFormatL(paraFormat,paraUndeterminedMask,selection.LowerPos(),selectionLength);
	CEikDialog* dialog=new(ELeave) CEikTabsDialog(paraFormat,paraMask, paraUndeterminedMask, aPageWidth);
	if (dialog->ExecuteLD(R_EIK_DIALOG_TABS))
		ApplyParaFormatL(paraFormat,paraMask);
	CleanupStack::PopAndDestroy();
	}

EXPORT_C void CEikGlobalTextEditor::RunIndentsDialogL(TInt aPageWidth)
	{
	CParaFormat* paraFormat=CParaFormat::NewLC();
	TParaFormatMask paraMask;
	TParaFormatMask paraUndeterminedMask;
	TCursorSelection selection=Selection();
	TInt selectionLength=selection.Length();
	GlobalText()->GetParaFormatL(paraFormat,paraUndeterminedMask,selection.LowerPos(),selectionLength);
	CEikDialog* dialog=new(ELeave) CEikIndentDialog(paraFormat,paraMask, paraUndeterminedMask, aPageWidth);
	if (dialog->ExecuteLD(R_EIK_DIALOG_INDENTS))
		ApplyParaFormatL(paraFormat,paraMask);
	CleanupStack::PopAndDestroy();
	}

EXPORT_C void CEikGlobalTextEditor::BoldItalicUnderlineEventL(TInt aFontFlag)
	{
	TCharFormat charFormat;
	TCharFormatMask applyMask;
	const TCursorSelection selection=Selection();
	const TInt selLength=selection.Length();
	TInt startPos,wordLength;
	GetWordInfo(selection.iAnchorPos,startPos,wordLength);
	if (selLength)
		GlobalText()->GetCharFormat(charFormat,applyMask,selection.LowerPos(),selLength);
	else if (selection.iCursorPos==startPos+wordLength)
		GlobalText()->GetCharFormat(charFormat,applyMask,startPos+wordLength,0);
	else
		GlobalText()->GetCharFormat(charFormat,applyMask,selection.iCursorPos,0);
	applyMask.ClearAll();
	//
	switch (aFontFlag)
		{
	case EBold:
		charFormat.iFontSpec.iFontStyle.SetStrokeWeight(charFormat.iFontSpec.iFontStyle.StrokeWeight()? EStrokeWeightNormal : EStrokeWeightBold);
		applyMask.SetAttrib(EAttFontStrokeWeight);
		break;
	case EItalic:
		charFormat.iFontSpec.iFontStyle.SetPosture(charFormat.iFontSpec.iFontStyle.Posture()? EPostureUpright : EPostureItalic);
		applyMask.SetAttrib(EAttFontPosture);
		break;
	case EUnderline:
		charFormat.iFontPresentation.iUnderline=(charFormat.iFontPresentation.iUnderline)?EUnderlineOff : EUnderlineOn;
		applyMask.SetAttrib(EAttFontUnderline);
		break;
	default:
		return;
		}
	if (selLength)
		ApplyCharFormatL(charFormat,applyMask);
	else
		{
		if (selection.iCursorPos==startPos+wordLength && iEdwinInternalFlags&ERichText)
			GlobalText()->ApplyCharFormatL(charFormat,applyMask,startPos+wordLength,0);
		else
			{
			const TInt length=(selection.iCursorPos==startPos? 0 : wordLength);
			GlobalText()->ApplyCharFormatL(charFormat,applyMask,startPos,length);
			if (iEdwinInternalFlags&ERichText)
				iTextView->HandleRangeFormatChangeL(TCursorSelection(startPos,startPos+wordLength),EFalse);
			else
				{
				TViewYPosQualifier yPosQualifier;
				yPosQualifier.SetMakeLineFullyVisible();
				iTextView->HandleGlobalChangeL(yPosQualifier);
				}
			UpdateScrollBarsL();
			}
		ReportEdwinEventL(MEikEdwinObserver::EEventFormatChanged);
		}
	UpdateButtonGroup();
	}

EXPORT_C CGlobalText* CEikGlobalTextEditor::GlobalText() const
	{
	return((CGlobalText*)iText);
	}

EXPORT_C TBool CEikGlobalTextEditor::RunPaginateDialogL(CPrintSetup* aPrintSetup,CArrayFix<TInt>* aCharsPerPage)
	{
	TBool cancel=EFalse;
	CTextPaginator* paginator=CTextPaginator::NewL(aPrintSetup->PrinterDevice(),aCharsPerPage,-100);
	CleanupStack::PushL(paginator);
	paginator->SetPageMarginsInTwips(aPrintSetup->iPageMarginsInTwips.iMargins);
	paginator->SetPageSpecInTwips(aPrintSetup->PrinterDevice()->CurrentPageSpecInTwips());
	paginator->SetDocumentL(GlobalText());
	CEikPaginateDialog* dialog=new(ELeave) CEikPaginateDialog(paginator);
	if (!dialog->ExecuteLD(R_EIK_DIALOG_PAGINATE))
		cancel=ETrue;
	else
		{
		if (TextLayout()->NonPrintingCharsVisibility().PageBreaksVisible())
			Window().Invalidate(Rect());
		}
	CleanupStack::PopAndDestroy(); //paginator;
	return cancel;
	}

EXPORT_C void CEikGlobalTextEditor::Reserved_1()
	{}

EXPORT_C void CEikGlobalTextEditor::Reserved_2()
	{}

EXPORT_C void CEikGlobalTextEditor::Reserved_3()
	{}
