DirectPrint/DirectPrintApp/engine/src/directprintengine.cpp
author Steven Cao <steven.1.cao@nokia.com>
Tue, 11 May 2010 14:10:02 +0800
changeset 15 2275db202402
parent 12 613a5ff70823
permissions -rw-r--r--
Pickup K3's code

/*
* Copyright (c) 2010 Kanrikogaku Kenkyusho, Ltd.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:
* Kanrikogaku Kenkyusho, Ltd. - Initial contribution
*
* Contributors:
*
* Description:
* {Description of the file}
*
*/

#include <pdrport.h>				// CFilePrinterPort
#include <TXTETEXT.H>				// CEditableText
#include <TXTRICH.H>				// CRichText
#include <FLDBLTIN.H>				// CPageNumField
#include <flddef.h>					// KPageNumberFieldUid, KNumPagesFieldUid
#include <stringloader.h>			// StringLoader
#include <xmlengdocument.h>			// RXmlEngDocument
#include <xmlengelement.h>			// TXmlEngElement
#include <xmlengattr.h>				// TXmlEngAttr
#include <xmlengnodelist.h>			// RXmlEngNodeList
#include <bautils.h>				// BaflUtils
#include <eikenv.h>					// CEikonEnv

#include "clog.h"
#include <directprintapp.rsg>
#include "directprintengine.h"
#include "directprintband.h"
#include "directprintengineobserver.h"
#include "directprintmodel.h"
#include "directprintbanduid.h"

//! Default Page spec in Twips
#define KDefaultPageSpecInTwips TPageSpec(TPageSpec::EPortrait,TSize(11906,16838))

CDirectPrintEngine::CDirectPrintEngine(CDirectPrintModel& aModel)
	: iModel(aModel)
	{
	}

CDirectPrintEngine::~CDirectPrintEngine()
	{
	if (iProgressDialog)
		{
		TRAP_IGNORE(iProgressDialog->ProcessFinishedL());
		delete iProgressDialog;
		iProgressDialog = NULL;
		}

	if (iPrintBand)
		{
		delete iPrintBand;
		iPrintBand = NULL;
		}

	iPrintSetup->FreeModelList();
	delete iPrintSetup;
	delete iProgressMessage;
	iFs.Close();
	}

CDirectPrintEngine* CDirectPrintEngine::NewL(CDirectPrintModel& aModel)
	{
	CDirectPrintEngine* self = CDirectPrintEngine::NewLC(aModel);
	CleanupStack::Pop(self);
	return self;
	}

CDirectPrintEngine* CDirectPrintEngine::NewLC(CDirectPrintModel& aModel)
	{
	CDirectPrintEngine* self = new(ELeave) CDirectPrintEngine(aModel);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

void CDirectPrintEngine::ConstructL()
	{
	LOG("CDirectPrintEngine::ConstructL BEGIN");
	iFs.Connect();

	iPrintSetup = CPrintSetup::NewL();
	iPrintSetup->AddPrinterDriverDirL(KDefaultPrinterDriverPath);
	iModelList = iPrintSetup->ModelNameListL(iFs);

#ifdef _DEBUG
	LOG1("ModelCount=[%d]", ModelCount());
	for (TInt i=0; i < ModelCount(); i++)
		{
		TPrinterModelEntry entry = (*iModelList)[i];
		RDebug::Print(_L("[%d][%S][%d] "), i, &(entry.iModelName), entry.iRequiresPrinterPort);
		LOG1("ModelName=[%S]", &(entry.iModelName));
		}
#endif
	// read progress message
	iProgressMessage = StringLoader::LoadL( R_DIRECTPRINT_MSG_PRINTING_PROGRESS );

	LOG("CDirectPrintEngine::ConstructL END");
	}

void CDirectPrintEngine::SetObserver(MDirectPrintEngineObserver* aObserver)
	{
	iObserver = aObserver;
	}

/**
  Override of base class virtual.
  Notifies that a print or print preview operation is about to begin.
 */
void CDirectPrintEngine::NotifyPrintStarted(TPrintParameters /*aPrintParams*/)
	{
	iPageCounter = 0;
	TRAPD(err, StartPrintProgressNoteL());
	iLastError = err;
	}

/**
  Override of base class virtual.\n
  Notifies that a band is about to be printed used to display print progress information,
  including the current page number.\n
  It is called immediately before each band is printed.\n
 */
void CDirectPrintEngine::NotifyBandPrinted(TInt /*aPercent*/, TInt aCurrentPageNum, TInt /*aCurrentCopyNum*/)
	{
	if (iPageCounter==0)
		{
		// start print
		}
	if (iPageCounter<aCurrentPageNum)
		{
		// next page
		iPageCounter = aCurrentPageNum;
		TRAPD(err, UpdatePrintProgressNoteL(iPageCounter));
		iLastError = err;
		}
	}

/**
  Override of base class virtual.\n
  Notifies that the print or print preview operation has completed.\n
  used to display information about how the operation completed,
  for example any errors that occurred.\n
 */
void CDirectPrintEngine::NotifyPrintEnded(TInt aErr)
	{
	CActiveScheduler::Stop();
	TInt err = KErrNone;

	if (aErr == KErrNone)
		{
		if (iObserver)
			{
			TRAP(err, iObserver->HandlePrintEventL(MDirectPrintEngineObserver::EDirectPrintEngineEventFinishCreatePrintData, 0, KNullDesC));
			}
		}
	else
		{
		switch (aErr)
			{
		case KErrCancel:
			if (iObserver)
				{
				TRAP(err, iObserver->HandlePrintEventL(MDirectPrintEngineObserver::EDirectPrintEngineEventCancelCreatePrintData, aErr, KNullDesC));
				}
			break;
		default:
			if (iObserver)
				{
				TRAP(err, iObserver->HandlePrintEventL(MDirectPrintEngineObserver::EDirectPrintEngineEventErrorCreatePrintData, aErr, KNullDesC));
				}
			break;
			}
		}

	TRAP(err, EndPrintProgressNoteL());
	}

/**
  Override of base class virtual.\n
  Returns the number of pages in the current document.\n
  @return - TInt (Number of pages).\n
 */
TInt CDirectPrintEngine::UpdateFieldNumPages()const
	{
	return iMaxPageNum;
	}


void CDirectPrintEngine::PrintL()
	{
	
	// set the total page
	iMaxPageNum = 1;
	iPrintSetup->Header()->SetNumPagesInfo(*this);

	TInt modelNum = iModelList->UidToNum(ModelUid(iModelIndex));
	iPrintSetup->CreatePrinterDeviceL(modelNum);

	// create a port if necessary
	CPrinterPort* port=NULL;
	if ((*iModelList)[modelNum].iRequiresPrinterPort)
		{
#ifdef __WINSCW__
		port = CFilePrinterPort::NewL(_L("c:\\fpr.pcl"));
#else
//		port = CFilePrinterPort::NewL(_L("e:\\fpr.pcl"));
		port = CFilePrinterPort::NewL(_L("c:\\fpr.pcl"));
#endif
		}

	iPrintSetup->PrinterDevice()->SelectPageSpecInTwips(KDefaultPageSpecInTwips);
	iPrintSetup->iPageMarginsInTwips.iHeaderOffset = 720;
	iPrintSetup->iPageMarginsInTwips.iFooterOffset = 0;
	iPrintSetup->iPageMarginsInTwips.iMargins.iLeft = 1440; // 1 inch
	iPrintSetup->iPageMarginsInTwips.iMargins.iRight = 1440;
	iPrintSetup->iPageMarginsInTwips.iMargins.iTop = 1440;
	iPrintSetup->iPageMarginsInTwips.iMargins.iBottom = 1440;

	if (iObserver)
		{
		iObserver->HandlePrintEventL(MDirectPrintEngineObserver::EDirectPrintEngineEventStartCreatePrintData, 0, KNullDesC);
		}
	

	TRAPD(err, DoPrintL(port));
	if (err == KErrNone)
		{
		CActiveScheduler::Start(); // stopped by killing it - subtle...
		}
	else
		{
		if (iObserver)
			{
			iObserver->HandlePrintEventL(MDirectPrintEngineObserver::EDirectPrintEngineEventErrorCreatePrintData, err, KNullDesC);
			}
		}

//	if (iPrintBand)
//		{
//		delete iPrintBand;
//		iPrintBand = NULL;
//		}
	}

void CDirectPrintEngine::DoPrintL(CPrinterPort* aPort)
	{
	// create a header
	iPrintSetup->Header()->CreateTextL();
	TBuf<40> buf(_L("This is the header on page  out of "));
	buf.Append(CEditableText::EParagraphDelimiter);
	iPrintSetup->Header()->Text()->InsertL(0,buf);
	CTextField* pNumberfield=iPrintSetup->Header()->Text()->NewTextFieldL(KPageNumberFieldUid);
	iPrintSetup->Header()->Text()->InsertFieldL(27,pNumberfield,KPageNumberFieldUid);  
	CNumPagesField* numPagesField=(CNumPagesField*)iPrintSetup->Header()->Text()->NewTextFieldL(KNumPagesFieldUid);
	iPrintSetup->Header()->Text()->InsertFieldL(35,numPagesField,KNumPagesFieldUid);  
	iPrintSetup->Header()->Text()->UpdateFieldL(27);
	iPrintSetup->Header()->Text()->UpdateFieldL(35);
	iPrintSetup->Header()->SetFirstPageToPrintTo(1); // no header on first 3 pages

	iPrintSetup->Footer()->CreateTextL();
	TBuf<40> buf2(_L("This is the footer on page "));
	buf2.Append(CEditableText::EParagraphDelimiter);
	iPrintSetup->Footer()->Text()->InsertL(0,buf2);
	CTextField* pNumberfield2=iPrintSetup->Footer()->Text()->NewTextFieldL(KPageNumberFieldUid);
	iPrintSetup->Footer()->Text()->InsertFieldL(27,pNumberfield2,KPageNumberFieldUid);	
	iPrintSetup->Footer()->Text()->UpdateFieldL(27);

	// start print to file
	iPrintSetup->iNumOfFirstPage = 1;
	TPrintParameters params;
	params.iFirstPage = 1; // don't print the first page at all, ie print page no's 3-6
	params.iLastPage = 1;
	params.iNumCopies = 1;
	TPageSpec spec;
	spec.iPortraitPageSize = KA4PaperSizeInTwips;
	spec.iOrientation = TPageSpec::EPortrait;
	iPrintSetup->PrinterDevice()->SelectPageSpecInTwips(spec);

	//===========================
	// start printing
	//===========================
	iPrintSetup->StartPrintL(params, *(PageRegionPrinter()), aPort, this);

	}


TInt CDirectPrintEngine::ModelCount()
	{
	return iModelList->ModelCount();
	}

void CDirectPrintEngine::ModelName(TInt aIndex, TDes& aDes)
	{
	TPtrC name((*iModelList)[aIndex].iModelName);
	if (name.Length() <= aDes.MaxLength())
		{
		aDes.Copy(name);
		}
	}

TUid CDirectPrintEngine::ModelUid(TInt aIndex)
	{
	return (*iModelList)[aIndex].iUid;
	}

void CDirectPrintEngine::SetUseModel(TInt aIndex)
	{
	iModelIndex = aIndex;
	}

void CDirectPrintEngine::StartPrintProgressNoteL()
	{
	// Delete possible previous CAknProgressDialog.
	delete iProgressDialog;
	iProgressDialog = NULL;

	// Create new CAknProgressDialog.
	iProgressDialog = new ( ELeave ) CAknProgressDialog( reinterpret_cast
														 <CEikDialog**> 
														 ( &iProgressDialog ) );
	
	iProgressDialog->SetCallback( this );
	iProgressDialog->PrepareLC( R_DIRECTPRINT_PRINT_PROGRESS_NOTE );
	iProgressInfo = iProgressDialog->GetProgressInfoL();
	iProgressInfo->SetFinalValue( iMaxPageNum );

	TBuf<32> msg;
	msg.AppendFormat(*iProgressMessage, iPageCounter, iMaxPageNum);
	iProgressDialog->SetTextL(msg);
	iProgressDialog->RunLD();
	}

void CDirectPrintEngine::EndPrintProgressNoteL()
	{
	if (iProgressDialog)
		{
		iProgressDialog->ProcessFinishedL();
		delete iProgressDialog;
		iProgressDialog = NULL;
		}
	}

void CDirectPrintEngine::UpdatePrintProgressNoteL(TInt aPage)
	{
	if (iProgressInfo)
		{
		TBuf<32> msg;
		msg.AppendFormat(*iProgressMessage, aPage, iMaxPageNum);
		iProgressDialog->SetTextL(msg);
		iProgressInfo->SetAndDraw(aPage);
		}
	}

void CDirectPrintEngine::DialogDismissedL( TInt /*aButtonId*/ )
	{
	if (iPrintSetup)
		{
		iPrintSetup->EndPrint();
		}
	}

void CDirectPrintEngine::StartPrintPreviewL()
	{
	// Clear previous object
	EndPrintPreview();

	// set the total page
	iMaxPageNum = 1;
	iPrintSetup->Header()->SetNumPagesInfo(*this);

	TInt modelNum = iModelList->UidToNum(ModelUid(iModelIndex));
	iPrintSetup->CreatePrinterDeviceL(modelNum);

	// create a port if necessary
	//CPrinterPort* port=NULL;
	//if ((*iModelList)[modelNum].iRequiresPrinterPort)
	//	{
	//	port = CFilePrinterPort::NewL(_L("e:\\fpr.pcl"));
	//	}

	iPrintSetup->PrinterDevice()->SelectPageSpecInTwips(KDefaultPageSpecInTwips);
	iPrintSetup->iPageMarginsInTwips.iHeaderOffset = 720;
	iPrintSetup->iPageMarginsInTwips.iFooterOffset = 0;
	iPrintSetup->iPageMarginsInTwips.iMargins.iLeft = 1440; // 1 inch
	iPrintSetup->iPageMarginsInTwips.iMargins.iRight = 1440;
	iPrintSetup->iPageMarginsInTwips.iMargins.iTop = 1440;
	iPrintSetup->iPageMarginsInTwips.iMargins.iBottom = 1440;
	}

void CDirectPrintEngine::EndPrintPreview()
	{
	}

void CDirectPrintEngine::SetParamL(RXmlEngDocument* aParam)
	{
	LOG("CDirectPrintEngine::SetParamL BEGIN");

	iParam = aParam;
	if ( iPrintBand )
		{
		delete iPrintBand;
		iPrintBand = NULL;
		}

	_LIT8(KElementRecogMode, "RecognizeMode");
	_LIT8(KElementRecogModeAttr, "mode");
	_LIT8(KElementRecogModeValueFile, "PrintRecognizeModeFile");
	_LIT8(KElementRecogModeValuePlugin, "PrintRecognizeModePlugin");
	_LIT8(KElementFile, "PrintFile");
	_LIT8(KElementFileAttr, "file");
	_LIT8(KElementPluginUid, "PluginUid");
	_LIT8(KElementPluginUidAttr, "uid");

	TXmlEngElement element = iParam->DocumentElement().FirstChild().AsElement();
	HBufC* filename = NULL;
	TUint uidValue = 0;

	enum {
		EParamModeFile	 = 0x0001,
		EParamModePlugin = 0x0002,
		EParamFileExist   = 0x0008,
		EParamPluginExist = 0x0010
	};
	TUint paramFlag = 0;

	while (element.NotNull())
		{
		if (element.Name().CompareF(KElementRecogMode()) == 0)
			{
			TXmlEngAttr attr = element.AttributeNodeL(KElementRecogModeAttr,KNullDesC8);
			if(attr.Value().CompareF(KElementRecogModeValueFile) == 0)
				{
				paramFlag |= EParamModeFile;
				LOG("Param:Mode=File");
				}
			else if(attr.Value().CompareF(KElementRecogModeValuePlugin) == 0)
				{
				paramFlag |= EParamModePlugin;
				LOG("Param:Mode=Plugin");
				}
			else
				{
				LOG("[Error] Param:Mode=Not set");
				break;
				}
			}
		else if (element.Name().CompareF(KElementFile()) == 0)
			{
			TXmlEngAttr attr = element.AttributeNodeL(KElementFileAttr,KNullDesC8);
			filename = HBufC::NewLC(attr.Value().Length());
			TPtr ptr(filename->Des());
			ptr.Copy(attr.Value());
			if (ptr.Length() > 0)
				{
				LOG1("Param:FileName UID=[%S]", &ptr);
				if (BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), ptr))
					{
					paramFlag |= EParamFileExist;
					}
				}
			if (!(paramFlag & EParamFileExist))
				{
				LOG("[Error] File not exist");
				}
			}
		else if (element.Name().CompareF(KElementPluginUid()) == 0)
			{
			TXmlEngAttr attr = element.AttributeNodeL(KElementPluginUidAttr,KNullDesC8);
			//HBufC8* bufUid = HBufC8::NewLC(attr.Value().Length());
			//TPtr8 ptr(bufUid->Des());
			HBufC* bufUid = HBufC::NewLC(attr.Value().Length());
			TPtr ptr(bufUid->Des());
			ptr.Copy(attr.Value());
			//_LIT8(KHeadOfHexString, "0x");
			_LIT(KHeadOfHexString, "0x");
			const TInt KUidStingLength = 8;
			if (ptr.Left(KHeadOfHexString().Length()).CompareF(KHeadOfHexString()) == 0)
				{
				ptr.Delete(0, KHeadOfHexString().Length());
				}
			if (ptr.Length() == KUidStingLength)
				{
				//TBuf<8> bufUid;
				//bufUid.Copy(ptr);
				//TLex lex(bufUid);
				TLex lex(ptr);
				if (lex.Val(uidValue,EHex) == KErrNone)
					{
					LOG1("Param:Plugin UID=[0x%X]", uidValue);
					paramFlag |= EParamPluginExist;
					}
				else
					{
					LOG("[Error] Convert from HEX string to int");
					}
				}
			if (!(paramFlag & EParamPluginExist))
				{
				LOG("[Error] File not exist");
		  		}
			CleanupStack::PopAndDestroy(bufUid); //bufUid
			}

		if (paramFlag == (EParamFileExist|EParamModeFile)
		 || paramFlag == (EParamPluginExist|EParamModePlugin))
			{
			break;
			}
		element = element.NextSibling().AsElement();
		}

	if (paramFlag == (EParamFileExist|EParamModeFile)
	 && filename)
		{
		TPtrC ptr(filename->Des());
		SearchPluginFromFilenameL(ptr);
		}
	if (paramFlag == (EParamPluginExist|EParamModePlugin)
	 && uidValue)
		{
		TUid uid = TUid::Uid(uidValue);
		LoadPluginFromUidL(uid);
		}

	if (filename)
		{
		CleanupStack::PopAndDestroy(filename); //filename
		}

	if ( !iPrintBand )
		{
		// error xml parameter
		User::Leave(KErrArgument);
		}

	LOG("CDirectPrintEngine::SetParamL END");
	}

void CDirectPrintEngine::SearchPluginFromFilenameL(const TDesC& aFileName)
	{
	LOG("CDirectPrintEngine::SearchPluginFromFilenameL START");
	RImplInfoPtrArray infoArray;
	TUid interface = TUid::Uid(KDirectPrintBandInterfaceUid);
	REComSession::ListImplementationsL( interface, infoArray );
	CleanupClosePushL( infoArray );
	LOG1("CDirectPrintEngine::SearchPluginFromFilenameL infoArray.Count(): %d", infoArray.Count());

	TParsePtrC parse(aFileName);

	TPtrC8 dataType;
	TPtrC16 dispName;
	TPtrC8 opaqueData;
	HBufC* dataTypeBuf = NULL;
	TBool bFound = EFalse;
	TInt findLen;
	const TChar KDataTypeSeparator = '|';

	for( TInt i = 0; i < infoArray.Count(); i++ )
		{
		LOG1("[InfoArray] i=%d", i);
		CImplementationInformation* info = infoArray[i];
		dataType.Set( info->DataType() );
		dispName.Set( info->DisplayName() );
		opaqueData.Set( info->OpaqueData() );

		dataTypeBuf = HBufC::NewLC( dataType.Length() );
		TPtr dataTypePtr(dataTypeBuf->Des());
		dataTypePtr.Copy( dataType );

		LOG1("[DataType]=[%S]", &dataTypePtr);
		FOREVER
			{
			findLen = dataTypePtr.Locate( KDataTypeSeparator );
			if (findLen < 0)
				{
				// the separator is not found
				if (dataTypePtr.Length() > 0)
					{
					findLen = dataTypePtr.Length();
					}
				else
					{
					break;
					}
				}
//			LOG1("[Compare]=[%S]", &(dataTypePtr.Left( findLen )));
//			LOG1("[Ext]=[%S]", &(parse.Ext()));
//			LOG1("[Comp]=[%S]", &(dataTypePtr.Left( findLen )));
			if ( parse.Ext().CompareF( dataTypePtr.Left( findLen ) ) == 0 )
				{
				bFound = ETrue;
				break;
				}
			dataTypePtr.Delete( 0, findLen+1 );
			}

		CleanupStack::PopAndDestroy(dataTypeBuf); // dataTypeBuf
		
		if ( bFound )
			{
			LOG("Match!!!");
			LoadPluginFromUidL(info->ImplementationUid());
			break;
			}
		}

	infoArray.ResetAndDestroy();
	CleanupStack::PopAndDestroy(&infoArray); // infoArray

	LOG("CDirectPrintEngine::SearchPluginFromFilenameL End");
	}

void CDirectPrintEngine::LoadPluginFromUidL(const TUid aUid)
	{
	LOG1("CDirectPrintEngine::LoadPluginFromUidL(0x%X) Start", aUid.iUid);

	CDirectPrintBand* band = NULL;
	band = CDirectPrintBand::NewL(aUid);
	TCleanupItem clItem( CleanupBand, band );
	CleanupStack::PushL( clItem );
	band->InitPrintBandL( iPrintSetup,
						  iParam,
						  KNullDesC );
	CleanupStack::Pop(); // band
	iPrintBand = band;

	LOG("CDirectPrintEngine::LoadPluginFromUidL End");
	}

void CDirectPrintEngine::CleanupBand( TAny* aData )
	{
	LOG("[CDirectPrintEngine::CleanupBand]\t Begin");

	CDirectPrintBand* band = (CDirectPrintBand*)aData;
	delete band;

	LOG("[CDirectPrintEngine::CleanupBand]\t End");
	}



// End of file