/* $Header$ */

// base html control implementation

/* *************** Changes ******************
Date			Edit				Bug					Description
12-Jul-24	CR0963			ST/PF/1450	Fix crash with empty dataname variable and data handle.
02-Nov-22	rmm11790								Resize code assistant help panel vertically to show as much help as possible using available screen space.
06-Oct-22	rmm11749		ST/WO/2704	Issues with HTML (docview) when printed to a report.
02-Mar-22	rmm11466								Implemented new build numbering and serial numbers to support Studio Now releases and periodic releases.
04-Jan-22	rmm11379								Improved performance setting edit menu state, and removed OLE2 entries from Windows edit menu. Also added similar logic for file menu state.
08-Jun-21	rmm11042		ST/DB/1334	When necessary add horizontal scrollbar to code assistant HTML help.
14-Apr-21	rmm10984								Removed compiler warnings on Windows platform.
10-Mar-21	rmm10949								Added editor for config.json.
20-Oct-20	rmm10716		ST/WO/2583	Online help did not space or wrap example code correctly. Also fixed cursor issue with docview control.
13-Mar-20	CRMAC1014								macOS changes for 10.14 SDK and later.
20-Sep-19	rmm10253		ST/DB/1143	Code assistant did not include evAnimationsComplete for window class $event.
29-Jan-19 rmm9935									Drag and drop highlighting using rectangle inside frame improved (very erratic on Cocoa, and flickered during drag and drop scrolling).
19-Dec-17	rmm_emat								Text editor for Omnis language.
25-Oct-16	rmm9123									Implemented $exportjson() and $importjson().
30-Aug-16	rmm9025			ST/NV/059		Added support for long pathnames to FileOps and to core qfile.
11-Jul-16	rmm8965									VS2015 compiler issues.
29-Apr-16	rmm8896									Issues with localised decimal pt etc in components.
22-Apr-16	rmm8886									Issue with links within pages.
14-Apr-16	rmm8862									Flicker while changing pages in Omnis help window.
07-May-15	rmm8573									Various COCOA issues.
01-May-15	CR0205									Cocoa changes.
21-Oct-14	rmm8448									Memory leaks.
01-Sep-14	rmm8428			ST/EC/1346	HTML control printing issues.
03-Jun-14	rmm8351			ST/EC/1292	Search words were no longer highlighted.
02-Oct-13	rmm8115			ST/WO/2280	Fixed crash in HTML control in design mode.
19-Aug-13	rmm64bitux							Linux 64 bit port.
05-Dec-12	rmm7750									Printing HTML using dataname did not work.
17-Jul-09	rmm6671			ST/EC/1187	Setting docview to empty text did not clear previous HTML.
27-Jul-07	rmm6183			ST/BE/161		Noticed some localisation issues in docview.
25-Jul-07	rmm6181									Changed font for help pages.
01-Jun-07	rmm6084									Cursor did not change from watch cursor after clicking on hyperlink.
26-Apr-97	rmm6051			ST/EC/1098	Added copy support to help viewer.
27-Apr-06	rmm5732			ST/RC/979		HTML object did not print on reports.
06-Dec-05	pkmach_o								pkmacho compiler changes - gStringTable now allocated and not a global static
20-Jun-05	AE6589			st/hi/1432: HTML printdocument wasn't laying out objects correctly
01-Jul-04	AE6479			ST/EC/823: 	HTML now supports filepath
30-Jun-04	rmm5006									Multiple select knobs were missing from quite a few components.
16-Mar-04	rmm4899			ST/EC/811		Fixed flicker when drawing docview control - especially evident when resizing Omnis help window.
24-Nov-03	rmm4799			ST/HP/046		Added control over point size for fixed width font used by pre and xmp tags.
05-Sep-03	AE6336			ST/WO/1557: $printdocument was hiding ctrls but then not showing them!?!
01-Apr-03	rmm4400									HTML control stopped keys that it does not use from working.
12-Feb-03	rmmdocgen								Studio 4.0 documentation generator.
23-Sep-02	AE6139			ST/EC/644: 	Added key support to docview (html/rtf viewers)
03-Sep-01	AE6120			ST/EC/678: 	Docview failing to load images when path assigned during initialization
10-Jan-01	rmm4006			ST/EC/624		Setting document path in property manager and then opening window did not work.
10-Jan-01	rmm4005			ST/EC/622		RTF viewer methods were not displayed in property manager.
10-Jan-01	rmm4004			ST/EC/623		Added descriptions to properties and methods.
18-Aug-00 MHn0136									Fixed bug with mac file filters.
02-Aug-00	AE5100			ST/WO/1177: Pure virtual error
26 JUN 00 MHCARBON								Mac Specific changes for OSX.
22 MAY 00	mpm4700									Implements printing of document
10 APR 00	mpm4599			st/ec/463		$startanimatescroll crashes if interval of zero is specified
23-Mar-00	mlr0024			ST/EC/469		Dont allow scrolling if report
03-Mar-00	mlr0017			ST/EC/426		Stoped cPropDocName being called within parsing ( as parsing sets title &
																	if then the user resets doc name - recursive)
22-Feb-00	rmm3658			ST/EC/446		Fixed GPF.
22-Feb-00	rmm3656			ST/EC/438		Return status values from methods.
22-Feb-00	rmm3655			ST/EC/437		$startanimatescroll caused screen corruption on completion
22-Feb-00	rmm3654			ST/EC/432		Scroll bar did not redraw sometimes.
22-Feb-00	rmm3653			ST/EC/425		Property inspector did not update after changing document name.
25-Jan-00	AE5002									GPF when deleting html objects
08 NOV 99 mlr0006									Added Rtf support
31 AUG 99 mpm4575									Fixes cursor flashing
********************************************/

#include <extcomp.he>
#include <extfval.he>
#include <hwnd.he>
#include <gdi.he>
#include <stdlib.h>
#include "htmlctrl.he"


#ifndef	_WPHTML_HE_
#include "wphtml.he"		// pkmach_o
#endif

#ifndef	_WPRTF_HE_
#include "wprtf.he"			// pkmach_o
#endif

#ifndef	_WPPARA_HE_
#include "wppara.he"		// pkmach_o
#endif

#ifndef	_WPTEXT_HE_
#include "wptext.he"		// pkmach_o
#endif

#ifndef	_WPIMAGE_HE_
#include "wpimage.he"		// pkmach_o
#endif

#ifndef	_WPTABLE_HE_
#include "wptable.he"		// pkmach_o
#endif


// ###############################################################################
// ################# Event Parameters and Events #################################
// ###############################################################################

const qshort cWPeventParamCount = 1;
ECOparam WPeventParam[cWPeventParamCount] =
{
	5099, fftInteger, 0, 0,
};


const qshort cWPpluginEventParamCount = 6;
ECOparam WPpluginEventParam[cWPpluginEventParamCount] =
{
	5099, fftInteger, 0, 0,
	5100, fftCharacter, 0, 0,
	5101, fftList, 0, 0,
	5102, fftInteger, EXTD_FLAG_PARAMALTER, 0,
	5103, fftInteger, EXTD_FLAG_PARAMALTER, 0,
	5104, fftInteger, EXTD_FLAG_PARAMALTER, 0
};

const qshort cWPtitleEventParamCount = 2;
ECOparam WPtitleEventParam[cWPtitleEventParamCount] =
{
	5099, fftInteger, 0, 0,
	5110, fftCharacter, 0, 0
};

const qshort cWPhyperlinkEventParamCount = 5;
ECOparam WPhyperlinkEventParam[cWPhyperlinkEventParamCount] = 
{
	5099, fftInteger, 0, 0,
	5120,	fftCharacter, 0, 0,
	5121,	fftCharacter, 0, 0,
	5122,	fftCharacter, 0, 0,
	5123,	fftCharacter, 0, 0,
};

const qshort cWPXpluginEventParamCount = 7;
ECOparam WPXpluginEventParam[cWPXpluginEventParamCount] =
{
	5099, fftInteger, 0, 0,
	5130, fftCharacter, 0, 0,
	5131, fftCharacter, 0, 0,
	5132, fftList, 0, 0,
	5133, fftInteger, EXTD_FLAG_PARAMALTER, 0,
	5134, fftInteger, EXTD_FLAG_PARAMALTER, 0,
	5135, fftInteger, EXTD_FLAG_PARAMALTER, 0
};

const qshort cWPeventTagEventParamCount = 3;
ECOparam WPeventTagEventParam[cWPeventTagEventParamCount] =
{
	5099, fftInteger, 0, 0,
	5140, fftCharacter, 0, 0,
	5141, fftCharacter, 0, 0,
};


const qshort cWPexecTagEventParamCount = 3;
ECOparam WPexecTagEventParam[cWPexecTagEventParamCount] = 
{
	5099, fftInteger, 0, 0,
	5150, fftCharacter, 0, 0,
	5151, fftList, 0, 0,
};


const qshort cWPeventsCount = 8;
ECOmethodEvent WPevents[cWPeventsCount] =
{
	cWPcreatePluginEvent,				5000, 0,			cWPpluginEventParamCount, &WPpluginEventParam[0], 0, 0,
	cWPdestroyPluginEvent,			5001, 0,			cWPeventParamCount, &WPeventParam[0], 0, 0,
	cWPsetTitleEvent, 					5002, 0, 			cWPtitleEventParamCount, &WPtitleEventParam[0], 0, 0,
	cWPendAnimateEvent,					5003,	0,			cWPeventParamCount, &WPeventParam[0], 0, 0,
	cWPhyperlinkEvent,					5004,	0,			cWPhyperlinkEventParamCount, &WPhyperlinkEventParam[0], 0, 0,
	cWPcreateXCompPluginEvent, 	5005, 0,			cWPXpluginEventParamCount, &WPXpluginEventParam[0], 0, 0,
	cWPeventTagEvent,						5006,	0,			cWPeventTagEventParamCount, &WPeventTagEventParam[0], 0, 0,
	cWPexecTagEvent,						5007,	0,			cWPexecTagEventParamCount, &WPexecTagEventParam[0], 0, 0,
};

const qshort cWPRTFeventsCount = 4;
ECOmethodEvent WPRTFevents[cWPRTFeventsCount] =
{
	cWPcreatePluginEvent,				5000, 0,			cWPpluginEventParamCount, &WPpluginEventParam[0], 0, 0,
	cWPdestroyPluginEvent,			5001, 0,			cWPeventParamCount, &WPeventParam[0], 0, 0,
	cWPsetTitleEvent, 					5002, 0, 			cWPtitleEventParamCount, &WPtitleEventParam[0], 0, 0,
	cWPendAnimateEvent,					5003,	0,			cWPeventParamCount, &WPeventParam[0], 0, 0,
};


// ###############################################################################
// ################# Methods #####################################################
// ###############################################################################

const qshort cWPanimateScrollParamCount = 3;
ECOparam WPanimateScrollParam[cWPanimateScrollParamCount] =
{
	4100, fftInteger, 0, 0,
	4101, fftInteger, 0, 0,
	4102, fftInteger, 0, 0,
};

const qshort cWPpathConvParamCount = 1;
ECOparam WPpathConvParam[cWPpathConvParamCount] =
{
	4110, fftCharacter, EXTD_FLAG_PARAMALTER, 0,
};

const qshort cWPgetSelTextParamCount = 1;
ECOparam WPgetSelTextParam[cWPgetSelTextParamCount] =
{
	4120, fftCharacter, EXTD_FLAG_PARAMALTER, 0,
};

const qshort cStartAnimateScroll = 101;
const qshort cStopAnimateScroll = 102;
const	qshort cPathToApi = 103;
const qshort cPathToHtml = 104;
const qshort cGetSelText = 105;
const qshort cPrint = 106;

const qshort cWPmethodsCount = 6;
ECOmethodEvent WPmethods[cWPmethodsCount] =
{
	cStartAnimateScroll,	4000, 0,	cWPanimateScrollParamCount,	&WPanimateScrollParam[0], 0,	0,
	cStopAnimateScroll,		4001,	0,	0,													0,												0,	0,
	cPathToApi,						4002,	0,	cWPpathConvParamCount,			&WPpathConvParam[0],			0,	0,
	cPathToHtml,					4003,	0,	cWPpathConvParamCount,			&WPpathConvParam[0],			0,	0,
	cGetSelText,					4004, 0,	cWPgetSelTextParamCount,		&WPgetSelTextParam[0],		0,	0,
	cPrint,								4005, 0,	0,	0,		0,	0,
};

// ###############################################################################
// ################# Properties ##################################################
// ###############################################################################

const qshort cHTMLCtrlPropertiesCount = 8;	// rmm4799	 AE6479
const qshort cRtfCtrlPropertiesCount = 5;		// rmm4005

const qshort 
			cPropDocName = 1,
			cPropFontSizeAdj = 2,
			cPropEventHwnd = 3,
			cPropSrchWords = 4,
			cPropPointSizeForPreAndXmp = 5,	// rmm4799
			cInternalPropCodeAssistant = 1000,	// rmm_emat: Internal value, not exposed in property table, set to any value to indicate the control is being used by the code assistant
			cInternalPropDocumentHeight = 0;		// rmm11790: Internal value, not exposed in property table, used to get document height (zero, so no initial parameter needs to be passed to get property)
			
		
ECOproperty HTMLCtrlProperties[cHTMLCtrlPropertiesCount] =
{ 
//		propid							resourceid,   datatype,			propflags																		propFlags2, 		enumStart, 		enumEnd
			anumHorzscroll,			0, 						fftBoolean, 	0, 																					EXTD_EFLAG_EXT_PROPERTIES_CRB, 0, 0, // rmm9123
			anumVertscroll,			0, 						fftBoolean, 	0, 																					EXTD_EFLAG_EXT_PROPERTIES_CRB, 0, 0, // rmm9123
			cPropDocName,				3000, 				fftCharacter, EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_BUTTON, 			0,							0, 						0,
			cPropFontSizeAdj,		3001, 				fftInteger, 	EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_RUNTIMEONLY, 0,							0, 						0,
			cPropEventHwnd,			3002,					fftInteger,		EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_RUNTIMEONLY,	0,							0, 						0,
			cPropSrchWords,			3003,					fftCharacter,	EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_RUNTIMEONLY,	0,							0, 						0,
			anumFieldname,			0, 						fftCharacter, EXTD_FLAG_PRIMEDATA, 												0,							0, 						0,
			cPropPointSizeForPreAndXmp, 3004,	fftInteger,		EXTD_FLAG_PROPCUSTOM,												0,							0,						0,	// rmm4799
};

ECOproperty RtfCtrlProperties[cRtfCtrlPropertiesCount] =
{ 
//		propid							resourceid,   datatype,			propflags																		propFlags2, 		enumStart, 		enumEnd
			anumHorzscroll,			0, 						fftBoolean, 	0, 																					EXTD_EFLAG_EXT_PROPERTIES_CRB, 0, 0, // rmm9123
			anumVertscroll,			0, 						fftBoolean, 	0, 																					EXTD_EFLAG_EXT_PROPERTIES_CRB, 0, 0, // rmm9123
			anumFieldname,			0, 						fftBinary,		EXTD_FLAG_PRIMEDATA, 												0,							0, 						0,
			cPropDocName,				3000, 				fftCharacter, EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_BUTTON, 			0,							0, 						0,
			cPropEventHwnd,			3002,					fftInteger,		EXTD_FLAG_PROPCUSTOM|EXTD_FLAG_RUNTIMEONLY,	0,							0, 						0,
	};




// ###############################################################################
// ################# class tqfWPObject ###########################################
// ###############################################################################

tqfWPObject::tqfWPObject( HWND pFieldHWnd, int compId, qbool pIsReport )
{
	mIsReport = pIsReport;
	mHWnd = pFieldHWnd;	// we remember the objects child window for later drawing 
	mDoc = 0; mEventHwnd = 0;
	mHAnimateOn = mVAnimateOn = qfalse;
	mInLink = mInDragSelect = mInParsing = mMustRebuild = qfalse;
	mTrackLinkInfo = 0;
	mCompId = compId ;
	mSourceIsText = mPrinting = mCreateDocumentWhenInitDone = mSourceStrIsMine = qfalse; // mpm4700 // rmm4006 // rmm8448
	mSourceStr = NULL;
	mPointSizeForPreAndXmp = 10;	// rmm4799: default to previously hard-coded value
	if (( !pIsReport ) && ECOisDesign(mHWnd) )
	{
		qulong style = WNDgetWindowLong( mHWnd, GWL_EXSTYLE );
		style |= WND_REDRAWONSIZE;
		WNDsetWindowLong( mHWnd, GWL_EXSTYLE, style);
	}
	mCodeAssistant = qfalse;	// rmm_emat
}

// Generic destruction
tqfWPObject::~tqfWPObject()
{
	// Insert any memory deletion code or general cleanup code
	mInInit=qtrue;
	if ( mDoc ) delete mDoc;
	mInInit=qfalse;
	WNDsendMessage(0, WM_CONTROL, DETACH_PRIPROC_FROM_PRINT_JOB, (LPARAM)this); // rmm8428: Detach this object from the print job (to prevent the core trying to call it for the deleted object)
	freeSourceStr();	// rmm8448
}

// rmm8448
void tqfWPObject::freeSourceStr()
{
	if (mSourceStr)
	{
		if (mSourceStrIsMine)
		{
			HANglobalFree(mSourceStr);
			mSourceStrIsMine = qfalse;
		}
		mSourceStr = 0;
	}
}

class tqfld
{
	public:
		void*		VTable;
		HWND		mHwnd;
		HWND		mFrameHwnd;

		qlong		mValid;
	  qlong   mType;
	  qlong   mId;
	  qlong   mUnique;

	  tqfld*  mParent;
  	tqfld*  mAboveSibling;
		tqfld*	mBelowSibling;
		tqfld*	mTopChild;
		tqfld*	mBottomChild;

		qdim		mHorzScrollAmt;
		qdim		mVertScrollAmt;
};


void tqfWPObject::setScrollAmt( qdim pHorzScrollAmt, qdim pVertScrollAmt )
{
	tqfld* fld = (tqfld*)WNDgetProcInst( mHWnd );
	fld->mHorzScrollAmt = pHorzScrollAmt;
	fld->mVertScrollAmt = pVertScrollAmt;
}


void tqfWPObject::getScrollAmt( qdim& pHorzScrollAmt, qdim& pVertScrollAmt )
{
	tqfld* fld = (tqfld*)WNDgetProcInst( mHWnd );
	pHorzScrollAmt = fld->mHorzScrollAmt;
	pVertScrollAmt = fld->mVertScrollAmt;
}


void tqfWPObject::setScrollRange()
{
	qbool isDesign = ECOisDesign(mHWnd);	// rmm8115
	qdim horzScrollAmt, vertScrollAmt; getScrollAmt( horzScrollAmt, vertScrollAmt );
	qlong width = 0, height = 0;
	if ( mDoc )
	{
		mDoc->getDocumentInfo( eWPdocInfoWidth, 0, width );
		mDoc->getDocumentInfo( eWPdocInfoHeight, 0, height );
	}
	// Start rmm11042: Determine which scrollbars are required
	if (mCodeAssistant)
	{
		static qdim sScrollBarWidth = 0;
		if (!sScrollBarWidth)
		{
			#ifdef ismacosx
				sScrollBarWidth = WNDgetOSXscrollBarWidth();
			#elif defined(isunix)
				sScrollBarWidth = 16;
			#else
				NONCLIENTMETRICS ncm;
				memset(&ncm, 0, sizeof(NONCLIENTMETRICS));
				ncm.cbSize = sizeof(NONCLIENTMETRICS);
				if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, FALSE, (PVOID)&ncm, FALSE))
					sScrollBarWidth = GDIconvToDesign(ncm.iScrollWidth, qfalse);
				else
					sScrollBarWidth = 16;
			#endif
		}
		// Whether there is a vertical or horizontal scrollbar depends on the size of the document
		qrect wr;
		WNDgetWindowRect(mHWnd, &wr);
		WNDborderStruct bs;
		WNDgetBorderSpec(mHWnd, &bs);
		WNDinsetBorderRect(mHWnd, &wr, &bs);
		
		qulong style = WNDgetWindowLong(mHWnd, GWL_STYLE);
		qlong oldStyle = style;
		if (height <= wr.height() && width <= wr.width())
		{
			// Do not need scrollbars
			style &= ~(WS_HSCROLL | WS_VSCROLL);
		}
		else if (height > wr.height() && width <= (wr.width() - sScrollBarWidth))
		{
			// Vertical only
			style &= ~WS_HSCROLL;
			style |= WS_VSCROLL;
		}
		else if (width > wr.width() && height <= (wr.height() - sScrollBarWidth))
		{
			// Horizontal only
			style |= WS_HSCROLL;
			style &= ~WS_VSCROLL;
		}
		else
		{
			// Both
			style |= (WS_VSCROLL | WS_HSCROLL);
		}
		if (oldStyle != style)
			WNDsetWindowLong(mHWnd, GWL_STYLE, style);
	}
	// End rmm11042
	qrect cRect; WNDgetClientRect(mHWnd, &cRect);
	if (horzScrollAmt)
		WNDsetScrollRange(mHWnd, SB_HORZ, 0, isDesign ? 0 : qdim(width / horzScrollAmt), isDesign ? 0 : cRect.width() / horzScrollAmt, qtrue);	// rmm8115
	if (vertScrollAmt)
		WNDsetScrollRange(mHWnd, SB_VERT, 0, isDesign ? 0 : qdim(height / vertScrollAmt), isDesign ? 0 : cRect.height() / vertScrollAmt, qtrue); // rmm8115
}


qbool tqfWPObject::getSelText( EXTCompInfo* eci ) // rmm3656
{
	EXTParamInfo* param = ECOfindParamNum( eci, 1 );
	if ( param )
	{
		EXTfldval fval( (qfldval)param->mData );
		fval.setEmpty(fftCharacter, dpDefault);	// rmm9025
		if ( mDoc )
		{
			qldim hoff, voff; getOffset( hoff, voff );
			mDoc->copySelRect( &fval, hoff, voff );
		}
		ECOsetParameterChanged( eci, 1 );
		return qtrue;	// rmm3656
	}
	return qfalse;	// rmm3656
}


qprierr tqfWPObject::PriProc( PRIjob pJob, UINT pMessage, WPARAM wParam, LPARAM lParam )
{
	switch ( pMessage )
	{
		case PM_INIT_PAGE:
		{
			PRIpageStruct* pageStruct = (PRIpageStruct*)lParam;
			qbool isPagedReport = qbool(wParam);
			if ( pageStruct->mPage.mVert == 1 && pageStruct->mPage.mHorz == 1 ) // we only need to do it the once
			{
				qpridim ht = PRItextHeight( pJob, &mHeaderFont ) * 2;
				pageStruct->mHeaderBounds = pageStruct->mFooterBounds = pageStruct->mPrintBounds;
				pageStruct->mHeaderBounds.height( ht );
				pageStruct->mFooterBounds.top = pageStruct->mFooterBounds.bottom - ht + 1;
				pageStruct->mLocalBounds.top += ht; // make room for header and footer
				pageStruct->mLocalBounds.bottom -= ht;
				mPrintBounds = pageStruct->mLocalBounds; mPrintBounds.offset( -mPrintBounds.left, -mPrintBounds.top );
			}
			else if ( !isPagedReport )
			{
				pageStruct->mLocalBounds.top -= pageStruct->mHeaderBounds.height();
				pageStruct->mHeaderBounds.setEmpty();
			}
			pageStruct->mGlobalBounds.width( pageStruct->mLocalBounds.width() ); 
			pageStruct->mGlobalBounds.height( pageStruct->mLocalBounds.height() ); 
			mCurPage = pageStruct->mPage.mVert;
			break;
		}
		case PM_ADD_HEADER_OBJECTS:
		{
			// prepare static text
			static str255 ptxt;
			if ( !ptxt.length() )
			{
				RESloadString( gInstLib, 6000, ptxt );
				qshort p = ptxt.pos( '1' ); ptxt[p] = PRI_OBJ_PGCNT_PAGE;
				p = ptxt.pos( '2' ); ptxt[p] = PRI_OBJ_PGCNT_CNT;
			}
			// prepare header pos info
			PRIpageStruct* pageStruct = (PRIpageStruct*)lParam;
			qpripos thePos = qpripos( ePosHeader, pageStruct->mPage, pageStruct->mHeaderBounds );
			thePos.offset( -thePos.left, -thePos.top );
			thePos.inset( PRI_MM, 0 );
			// add the page number
			PRIobjectStruct obj(qnil); EXTfldval fval; fval.setChar( ptxt );
			obj.mType = PRI_OBJ_PGCNT;
			obj.mPos = thePos;
			obj.mData = fval.getFldVal();
			obj.mHorzExtend = obj.mVertExtend = qfalse;
			obj.mTextSpec.mFnt = mHeaderFont;
			obj.mTextSpec.mSty = styPlain;
			obj.mTextSpec.mTextColor = GDI_COLOR_QBLACK;
			obj.mTextSpec.mJst = jstRight;
			qprierr err = doPRIaddObject( pJob, &obj );
			// add the date
			if ( !err )
			{
				obj.mType = PRI_OBJ_TEXT;
				obj.mPos = thePos;
				obj.mTextSpec.mJst = jstLeft;
				fval.setChar( mDate );
				err = doPRIaddObject( pJob, &obj );
			}
			// add the title
			if ( !err )
			{
				obj.mPos = thePos;
				obj.mTextSpec.mJst = jstCenter;
				mDoc->getTitle( fval );
				err = doPRIaddObject( pJob, &obj );
			}
			// prepare footer pos & add the filename
			if ( !err )
			{
				thePos = qpripos( ePosFooter, pageStruct->mPage, pageStruct->mFooterBounds );
				thePos.offset( -thePos.left, -thePos.top );
				thePos.top = thePos.bottom - PRItextHeight( pJob, &mHeaderFont );
				obj.mPos = thePos;
				obj.mTextSpec.mJst = jstCenter;
				fval.setChar( mDocName );
				err = doPRIaddObject( pJob, &obj );
			}
			return err;
		}
		case PM_OUT_PRINTER:
		case PM_OUT_PAGE:
		case PM_OUT_PREVIEW:
		case PM_OUT_DISK:
		{
			return PRIdefOutputProc( pJob, NULL, pMessage, lParam, 0, 0 );
		}
		case PM_CLOSE:
		{
			break;
		}
	}
	return PRI_ERR_NONE;
}

// Start rmm8428
#if defined(iswin32) && !defined(isunix)
	static qchar sFntNameHelv[] = { 'T', 'a', 'h', 'o', 'm', 'a', 0 };
#endif
// End rmm8428
qprierr tqfWPObject::print( EXTCompInfo* eci ) // mpm4700
{
	if ( !mDoc ) return PRI_ERR_NONE;
	qprierr err = PRIopen();
	if ( !err )
	{
		{ // prepare the date
			str31 calc(QTEXT("jst(#D,'D:w, n D, y')")); 
			calc[7] = ECOgetFsch();	// rmm6183 // rmm8896
			ECOreplaceSeparators(calc);
			EXTfldval calcFval, resultFval;
			calcFval.setCalculation( eci->mInstLocp, ctyCalculation, &calc[1], calc[0] );
			calcFval.evalCalculation( resultFval, eci->mInstLocp, NULL, qfalse );
			resultFval.getChar( mDate );
		}
		str255 docName = mDocName; qshort p;
		while ((p = docName.pos('/')) != 0) docName.deleet( 1, p );
		PRIdestParmStruct destParms = *ECOgetDeviceParms( eci->mInstLocp );
		destParms.mShowBounds = qtrue;
		PRIparmStruct jobParms(qnil);
		jobParms.mApp = ECOgetApp( eci->mInstLocp );
		jobParms.mDocName = &docName;
		jobParms.mProc = this;
		//jobParms.mAutoEject = qtrue;
		jobParms.mHorzPages = qtrue;
		jobParms.mDestParms = &destParms;
		
		// prepare header font
		#if defined(iswin32) && !defined(isunix)
			mHeaderFont = qfnt(sFntNameHelv, 6, 0x22);	// rmm8428
		#else
			mHeaderFont = fnt6Gen;
		#endif
		
		qlong savedScale = PRIgetPageSetupItem( destParms.mPageSetup, PRI_PS_HSCALE );
		{ // adjust scaling to fit on page horizontally
			qprirect paperBounds, printBounds; PRIgetPaperDimensions( destParms.mPageSetup, &paperBounds, &printBounds );
			qpridim minWidth = PRIconvFromScreen( qdim(mDoc->getMinWidth()), qfalse )+PRI_MM*10;
			if ( minWidth > printBounds.width() )
			{
				qlong scale = savedScale * printBounds.width() / minWidth;
				PRIsetPageSetupItem( destParms.mPageSetup, PRI_PS_HSCALE, scale );
				GDIfontSetSize( &mHeaderFont, qshort(6 * 100 / scale) );
			}
		}

		err = PRIstartJob( &jobParms );
		if ( !err )
		{
			if ( destParms.mDest == PRI_DEST_PRINTER )
			{
				qbool ok; err = PRIopenJobSetupDialog( jobParms.mJob, &ok );
				if (!err && !ok)
				{
					err = PRI_ERR_ABORT;
					// Start rmm8448
					PRIsetError(jobParms.mJob, PRI_ERR_ABORT);
					PRIendJob(jobParms.mJob); 
					// End rmm8448
				}
			}
			if ( !err ) err = PRIstartPage( jobParms.mJob ); // this initializes mPrintBounds
			if ( !err )
			{
				mPrintBounds.left += PRI_MM*5; mPrintBounds.right -= PRI_MM*5;
				// create temp document for printing				
				mPrinting = qtrue;
/*AE6589 Why lay it out again?
				WPDocClass* savedDoc = mDoc; mDoc = 0; 
				qshort fontSizeAdj = savedDoc->fontSizeAdj();
				mInParsing = qtrue;
				if ( mCompId == OBJECT_ID1 )
					mDoc = WPHtmlClass::make( mHWnd, mEventHwnd, 1000, qtrue, 0, mDocName, 0 );
				else
					mDoc = WPRtfClass::make( mHWnd, mEventHwnd, 1000, qtrue, 0, mDocName, 0 );
				mDoc->fontSizeAdj( fontSizeAdj );
				mInParsing = qfalse;
*/
				// initialize temp document
				qrect r; PRIconvRectToScreen( &mPrintBounds, &r );
				WPObjInfoStruct rowInfo;
				rowInfo.mRowRect = r;
				rowInfo.mRowRect.bottom = rowInfo.mRowRect.top - 1;
				rowInfo.mOwnerRect = rowInfo.mRowRect;
				if ( mDoc )
				{ // AE6597 Added this to resize
					WPObjInfoStruct rowInfo; 
					rowInfo.mRowRect = r;
					rowInfo.mRowRect.bottom = rowInfo.mRowRect.top - 1;
					rowInfo.mOwnerRect = rowInfo.mRowRect;
					if ( mHWnd ) 
					{
						mDoc->initData( &rowInfo );
					}
				}
//AE6589				mDoc->initData( &rowInfo );
//AE6589				mDoc->endInitData(); // AE6336
				// add document to print job
				PRIobjectStruct objInfo(qnil);
				objInfo.mIdent = 1000; objInfo.mType = PRI_OBJ_EXTERNAL;
				objInfo.mPos = mPrintBounds;
				objInfo.mPos.mMode = ePosGlobal;
				objInfo.mData = 0;
				objInfo.mHorzExtend = objInfo.mVertExtend = objInfo.mGrowSection = qtrue;
				printInfo pinfo; pinfo.mJob = jobParms.mJob; pinfo.mObj = &objInfo;
				qldim horzOff=0, vertOff=0;
				err = mDoc->addToPrintJob(&pinfo,eci,NULL,horzOff,vertOff);
				// delete temp document and restore control
//AE6589				if (mDoc) { mInInit=qtrue; delete mDoc; mInInit=qfalse; }
//AE6589				mDoc = savedDoc; 
				mPrinting = qfalse;
			
				if ( err )
					PRIendJob( jobParms.mJob );
				else
					err = PRIendJob( jobParms.mJob );
				initDocument(qfalse);	// AE6597 Undo resize
			}
		}
		
		PRIsetPageSetupItem( destParms.mPageSetup, PRI_PS_HSCALE, savedScale );
	
		PRIclose();
	}
	return err;
}


qbool tqfWPObject::startAnimateScroll( EXTCompInfo* eci )	// rmm3656
{
	if ( !mDoc ) return qfalse;	// rmm3656
	if ( mHAnimateOn || mVAnimateOn ) stopAnimateScroll();
	qdim horzScrollUnits = 0, vertScrollUnits = 0;
	qlong interval = 500;
	EXTParamInfo* param = ECOfindParamNum( eci, 1 );
	if ( param )
	{
		EXTfldval fval( (qfldval)param->mData );
		horzScrollUnits = (qdim)fval.getLong();
		mHAnimateOn = horzScrollUnits != 0;
	}
	param = ECOfindParamNum( eci, 2 );
	if ( param )
	{
		EXTfldval fval( (qfldval)param->mData );
		vertScrollUnits = (qdim)fval.getLong();
		mVAnimateOn = vertScrollUnits != 0;
	}
	param = ECOfindParamNum( eci, 3 );
	if ( param )
	{
		EXTfldval fval( (qfldval)param->mData );
		interval = fval.getLong(); if ( interval < 1 ) interval = 1; // mpm4599
	}
	if (!horzScrollUnits) horzScrollUnits = 8;	// rmm3658: zero scroll amount values are not good news
	if (!vertScrollUnits) vertScrollUnits = 8;	// rmm3658
	setScrollAmt( horzScrollUnits, vertScrollUnits );
	setScrollRange();
	WNDsetTimer( mHWnd, 1000, interval );
	return qtrue;	// rmm3656
}


qbool tqfWPObject::stopAnimateScroll() // rmm3656
{
	if ( mHAnimateOn || mVAnimateOn )
	{
		WNDkillTimer( mHWnd, 1000 );
		mHAnimateOn = mVAnimateOn = qfalse;
		setScrollAmt( 8, 8 );
		setScrollRange();
		WNDinvalidateRect(mHWnd, NULL);	// rmm3655: need to do this, since the scroll amounts could well have changed
		return qtrue;	// rmm3656
	}
	return qfalse;	// rmm3656
}


void tqfWPObject::doAnimateScroll()
{
	if ( mHAnimateOn )
	{
		qdim pos1; WNDgetScrollPos( mHWnd, SB_HORZ, &pos1 );
		WNDsendMessage( mHWnd, WM_HSCROLL, SB_LINEDOWN, 0 );
		qdim pos2; WNDgetScrollPos( mHWnd, SB_HORZ, &pos2 );
		if ( pos1 == pos2 ) mHAnimateOn = qfalse;
	}
	if ( mVAnimateOn )
	{
		qdim pos1; WNDgetScrollPos( mHWnd, SB_VERT, &pos1 );
		WNDsendMessage( mHWnd, WM_VSCROLL, SB_LINEDOWN, 0 );
		qdim pos2; WNDgetScrollPos( mHWnd, SB_VERT, &pos2 );
		if ( pos1 == pos2 ) mVAnimateOn = qfalse;
	}
	if ( !mHAnimateOn && !mVAnimateOn )
	{
		WNDkillTimer( mHWnd, 1000 );
		EXTfldval fval; fval.setLong( mDoc->ident() );
		if (mDoc && !mCodeAssistant) ECOsendEvent( mDoc->eventHwnd(), cWPendAnimateEvent, &fval, 1, qtrue ); // rmm_emat
		setScrollAmt( 8, 8 );
		setScrollRange();
		WNDinvalidateRect(mHWnd, NULL);	// rmm3655: need to do this, since the scroll amounts could well have changed
	}
}


// AE6139
qbool tqfWPObject::scrollByKey( vchar pVChar)
{
	qbool acceptedKey = qtrue;
	UINT message;
	WPARAM wParam;
	
	switch (pVChar)
	{                              
		case vcUp:			message = WM_VSCROLL;		wParam = SB_LINEUP; 		break;
		case vcDown:		message = WM_VSCROLL;		wParam = SB_LINEDOWN; 	break;
		case vcLeft:		message = WM_HSCROLL;		wParam = SB_LINELEFT; 	break;
		case vcRight:		message = WM_HSCROLL;		wParam = SB_LINERIGHT; 	break;
		case vcPup:			message = WM_VSCROLL;		wParam = SB_PAGEUP; 		break;
		case vcPdown:		message = WM_VSCROLL;		wParam = SB_PAGEDOWN; 	break;
		case vcPleft:		message = WM_HSCROLL;		wParam = SB_PAGELEFT; 	break;
		case vcPright:	message = WM_HSCROLL;		wParam = SB_PAGERIGHT; 	break;
		case vcHome:		message = WM_VSCROLL;		wParam = SB_TOP; 				break;
		case vcEnd:			message = WM_VSCROLL;		wParam = SB_BOTTOM; 		break;
		default:				acceptedKey = qfalse;
	}
	if (acceptedKey)
	{
		WNDsendMessage( mHWnd, message, wParam, 0 );
	}
	return acceptedKey;
}

void tqfWPObject::doUser1Message( HWND pHwnd )
{
	WPObjInfoStruct objInfo;
	qldim hoff, voff; getOffset( hoff, voff );
	if ( mDoc->message( &objInfo, eWPMessFindHwnd, -hoff, -voff, (LPARAM)pHwnd, 0 ) )
	{
		paintObject( &objInfo );
	}
}

qlong	tqfWPObject::property( HWND pHwnd, LPARAM pMessage, EXTCompInfo* eci, qbool pButtonPressed )
{
	qbool	done = qtrue;
	qlong	propId = ECOgetId(eci);
	switch ( pMessage )
	{
		case ECM_GETPROPERTY:
		{
			EXTfldval fval;
			switch (propId)
			{
				case anumHorzscroll:
				case anumVertscroll:
				{
					qulong style = WNDgetWindowLong( pHwnd, GWL_STYLE );
					qulong val = ( propId == anumHorzscroll ? style & WS_HSCROLL : style & WS_VSCROLL );
					fval.setLong( val ? qtrue : qfalse );
					break;
				}
				case cPropDocName:
				{
					fval.setChar( mDocName );
					break;
				}
				case cPropFontSizeAdj:
				{
					fval.setLong( mDoc ? mDoc->fontSizeAdj() : 0 );
					break;
				}
				case cPropEventHwnd:
				{
					fval.setLongPtr( (qlongptr)mEventHwnd ); // rmm64bitux
					break;
				}
				case cPropSrchWords:
				{
					fval.setChar( mSrchWords );
					break;
				}
				case cPropPointSizeForPreAndXmp:	// rmm4799
				{
					fval.setLong(mPointSizeForPreAndXmp);
					break;
				}
				case cInternalPropDocumentHeight:	// rmm11790
				{
					qlong height = 0;
					if (mDoc)
						mDoc->getDocumentInfo(eWPdocInfoHeight, 0, height);
					fval.setLong(height);
					break;
				}
				default:
					done = qfalse;
					break;
			}
			if (done) ECOaddParam(eci,&fval);
			break;
		}
		case ECM_PROPERTYCANASSIGN:
		{
			switch (propId)
			{
				case anumHorzscroll:
				case anumVertscroll:
				case cPropSrchWords:
					if (mIsReport) // mlr0024
						done = qfalse;
					else
						done = qtrue;
						break;
				case cPropDocName:
				case cPropFontSizeAdj:
				case cPropEventHwnd:
				case cPropPointSizeForPreAndXmp:	// rmm4799
						done = qtrue;
						break;
				default:
						done = qfalse;
						break;
			}
			break;
		}
		case ECM_SETPROPERTY:
		{
			EXTParamInfo* param = ECOfindParamNum( eci, 1 );
			if ( param )
			{

				EXTfldval fval( (qfldval)param->mData );
				switch (propId)
				{
					case anumHorzscroll:
					case anumVertscroll:
					{
						if ( mIsReport ) // mlr0024
							break;
						qulong style = WNDgetWindowLong( pHwnd, GWL_STYLE );
						if ( propId == anumHorzscroll )
						{
							style = fval.getLong() ? style | WS_HSCROLL : style & ~WS_HSCROLL;
							WNDsetScrollRange(pHwnd, SB_HORZ, 0, 0, 0, qtrue );	// rmm3654
						}
						else	
						{
							style = fval.getLong() ? style | WS_VSCROLL : style & ~WS_VSCROLL;
							WNDsetScrollRange(pHwnd, SB_VERT, 0, 0, 0, qtrue );	// rmm3654
						}	
						WNDsetWindowLong( pHwnd, GWL_STYLE, style );
						setScrollRange();	// rmm3654
						break;
					}
					case cPropDocName:
					{
						if ( mInParsing == qtrue) //mlr0017 cant change name while still doing this
						// as could become recursive
						{
							done = qfalse ; 
						}
						else if (mInInit) // rmm4006
						{
							fval.getChar(mDocName);
							WPHtmlClass::apiToHtmlPath(mDocName);
							mCreateDocumentWhenInitDone = qtrue;
						}
						else
						{
							qbool ok = qtrue;
							mSourceIsText=qfalse;
							freeSourceStr();	// rmm8448
							str255 oldDoc = mDocName; 
							WPHtmlClass::htmlToApiPath( oldDoc );
							if ( pButtonPressed )
							{
								if ( mCompId == OBJECT_ID1 ) 
								// MHn0136 begins
									#ifdef isunix
										ok = ECOloadFileDialog( gInstLib, mHWnd, 10000, 10001, mDocName, NULL );
									#endif
									#ifdef iswin32
										#ifndef isunix
											ok = ECOloadFileDialog( gInstLib, mHWnd, 10000, 10002, mDocName, NULL );
										#endif
									#endif
									#ifdef ismac
											ok = ECOloadFileDialog( gInstLib, mHWnd, 10000, 10003, mDocName, NULL );
									#endif
								else
									#ifdef isunix
										ok = ECOloadFileDialog( gInstLib, mHWnd, 20000, 20001, mDocName, NULL );
									#endif
									#ifdef iswin32
										#ifndef isunix
											ok = ECOloadFileDialog( gInstLib, mHWnd, 20000, 20002, mDocName, NULL );
										#endif
									#endif
									#ifdef ismac
										ok = ECOloadFileDialog( gInstLib, mHWnd, 20000, 20003, mDocName, NULL );
									#endif
								// MHn0136 ends
							}
							else
							{
								fval.getChar( mDocName );
							}
							WPHtmlClass::apiToHtmlPath( mDocName );
							str255 newDoc = mDocName; 
							WPHtmlClass::htmlToApiPath( newDoc );
							if ( ok )
							{
								if ( mMustRebuild || newDoc != oldDoc || !mDoc )
								{
									mMustRebuild = qfalse;
									createDocument();
									// so rtf can be databound both ways .
									if ( mCompId == OBJECT_ID_RTF ) 
										bindData(eci);
								}
								else
								{
									positionBookmark();
									WNDinvalidateRect( mHWnd, NULL );
								}
								ECOupdatePropInsp(mHWnd, cPropDocName);	// rmm3653
							}
						}//mlr0017 end of not already parsing
						break;
					}
					case cPropFontSizeAdj:
					{
						if ( mDoc && mDoc->fontSizeAdj( (qshort)fval.getLong() ) && !ECOisDesign(mHWnd) )
						{
							initDocument();
						}
						break;
					}
					case cPropEventHwnd:
					{
						#ifdef is64bit // rmm8965
							mEventHwnd = (HWND)fval.getLong64();
						#else
							mEventHwnd = (HWND)fval.getLong();
						#endif
						break;
					}
					case cPropSrchWords:
					{
						str255 srchWords; fval.getChar( srchWords );
						if ( srchWords != mSrchWords )
						{
							mMustRebuild = qtrue;
							fval.getChar( mSrchWords );
						}
						break;
					}
					case cPropPointSizeForPreAndXmp:	// rmm4799
					{
						qshort newPointSize = (qshort) fval.getLong();
						if (newPointSize >= 2 && newPointSize <= 63 && newPointSize != mPointSizeForPreAndXmp) // rmm8886: Check to see if it has changed
						{
							mPointSizeForPreAndXmp = newPointSize;
							createDocument();
						}
						break;
					}
					case cInternalPropCodeAssistant:	// rmm_emat
						mCodeAssistant = qtrue;
						break;
					default:
						done = qfalse;
						break;
				}
			}
			break;
		}
		case ECM_INBUILT_OVERRIDE:
		{
			switch (propId)
			{
				case anumHorzscroll:
				case anumVertscroll:
					done = qtrue;
					break;
				default:
					done = qfalse;
					break;
			}
			break;
		}
	}
	return done;
}


void tqfWPObject::getOffset( qldim& pHorzOff, qldim& pVertOff )
{
	qdim hUnits, vUnits; getScrollAmt( hUnits, vUnits );
	qdim pos;
	WNDgetScrollPos( mHWnd, SB_HORZ, &pos );
	pHorzOff = qldim(pos) * hUnits;
	WNDgetScrollPos( mHWnd, SB_VERT, &pos );
	pVertOff = qldim(pos) * vUnits;
}


void tqfWPObject::paintObject( WPObjInfoStruct* pObjInfo )
{
	BLOCKVAR WNDpaintStruct ps;	// CRMAC1014
	pObjInfo->mOwnerRect.conv( &ps.rcPaint );
	ps.hdc = WNDstartDraw( mHWnd );
	pObjInfo->mOwner->paint( pObjInfo, &ps, 0, 0 );
	WNDendDraw( mHWnd, ps.hdc );
}


// You need to paint your control
qbool tqfWPObject::paint()
{
	if ( !mInParsing && !mDoc ) 
	{
		if ( (mSourceIsText == qfalse ) &&(mDocName.length() ))
			createDocument();
		// if mSourceIsText is set then set data should have been called
		// But if required would need to get fldname & data & pass
		// it inputfrom text 
	}
	WNDpaintStruct paintStruct;
	WNDbeginPaint( mHWnd, &paintStruct );
	// Start rmm4899: draw offscreen, unless in design mode
	if (ECOisDesign(mHWnd))
	{
		// In design mode, background was erased in response to erase background message.

		// rmm4899: design mode drawing moved here
		// If in design mode, then call drawNumber & drawMultiKnobs to draw design
		// numbers and multiknobs, if required.

		// Dont want to scroll if in design mode
		// rmm8115: WNDsetScrollRange( mHWnd, SB_HORZ, 0, 0, 0, qtrue );
		// rmm8115: WNDsetScrollRange( mHWnd, SB_VERT, 0, 0, 0, qtrue );

		ECOdrawNumber(mHWnd,paintStruct.hdc);
		ECOdrawDesignName(mHWnd,paintStruct.hdc);

		// paint the report design mode dotted outline if we didn't have a border
		// note cant tell if window or report.
		// have to use WNDgetWindowLong (GWL_EXSTYLE) & set style|=WND_REDRAWONSIZE;
		if ( mHWnd && ECOisDesign( mHWnd ) )
		{
			qrect cRect; WNDgetClientRect( mHWnd, &cRect );
		
			GDIsetTextColor( paintStruct.hdc, GDI_COLOR_QDKGREEN );
			GDIsetClipRect(  paintStruct.hdc, &cRect );
			GDIinsetRect( &cRect, 1, 1 );
			GDIexcludeClipRect(  paintStruct.hdc, &cRect );
			GDIinflateRect( &cRect, 1, 1 );

			HBRUSH brush = GDIcreateBrush( patGrayFrame ) ;
			GDIfillRect(  paintStruct.hdc, &cRect, brush );
			GDIdeleteObject( brush );

			GDIclearClip( paintStruct.hdc );
		} 
	}
	else
	{
		qrect cRect;
		WNDgetClientRect(mHWnd, &cRect);
		HDC tmpDC = paintStruct.hdc;
		qrect rcPaint = paintStruct.rcPaint; 
		void *offscreenPaintInfo = GDIoffscreenPaintBegin(NULL, tmpDC, cRect, rcPaint);
		if (offscreenPaintInfo != NULL)
		{
			WNDpaintStruct ps = paintStruct;
			ps.hdc = tmpDC;
			if (mDoc) 
			{
				mDoc->eraseBackground(mHWnd, tmpDC);

				qldim hoff, voff;
				getOffset( hoff, voff );
				mDoc->paint( 0, &ps, -hoff, -voff );
			}
			GDIoffscreenPaintEnd(offscreenPaintInfo);
		}		
	}
	// End rmm4899
	ECOdrawMultiKnobs(mHWnd,paintStruct.hdc); // rmm5006: moved here, to allow for $selected at runtime
	WNDendPaint( mHWnd, &paintStruct );	
	
	return qtrue;
}

void tqfWPObject::createDocument(void)
{
	if ( !ECOisDesign(mHWnd) && !mInInit )
	{
		qshort fontSizeAdj = 0;
		if ( mDoc )
		{
			fontSizeAdj = mDoc->fontSizeAdj(); 
			// AE5002
			mInInit=qtrue;
			ECOdisableTestesc dt;	// rmm8862: prevent nested paint due to testesc()
			delete mDoc; mDoc = 0;
			mInInit=qfalse;
		}
		if ( mHWnd && !mPrinting )
		{
			stopAnimateScroll();
			WNDsetScrollPos( mHWnd, SB_VERT, 0, qtrue );
			WNDsetScrollPos( mHWnd, SB_HORZ, 0, qtrue );
		}
		mInParsing = qtrue;
		EXTfldval fval; ECOgetProperty( mHWnd, anumIdent, fval );
		if ( mCompId == OBJECT_ID1 )
			mDoc = WPHtmlClass::make( mHWnd, mEventHwnd, fval.getLong(), mPrinting, 0, mDocName, mPointSizeForPreAndXmp, mCodeAssistant, mSrchWords.cString() ); // mpm4700 // rmm4799 // rmm_emat
		else
			mDoc = WPRtfClass::make( mHWnd, mEventHwnd, fval.getLong(), mPrinting, 0, mDocName, mSrchWords.cString() ); // mpm4700
		mDoc->fontSizeAdj( fontSizeAdj );
		// rmm8351: mSrchWords = qnil;
		mInParsing = qfalse;
		if ( mHWnd)
			initDocument();
		mSourceIsText=qfalse;
		freeSourceStr();	// rmm8448
		if ( mDoc)
			mSourceStr = mDoc->docHan();
	}
	return;	
}

void tqfWPObject::inputFromText( EXTfldval fval)
{
	// copied from create doc .
	freeSourceStr();	// rmm8448
	mSourceStr =	fval.getHandle( qtrue );
	mSourceStrIsMine = qtrue;	// rmm8448
	// cant work with the qhandle must work with qHandlePtr
	qHandlePtr sourcePtr = qHandlePtr( mSourceStr, 0 );
	if ( !!sourcePtr && sourcePtr.dataLen() > 0 )	// CR0963 : guard against empty handle
		mSourceIsText=qtrue;
	else 
		mSourceIsText=qfalse ;
	// rmm6671: always need to rebuild, to clear control if source is empty: if ( mSourceIsText)
	{
		mMustRebuild = qtrue;
		mDocName = QTEXT("") ;
		if ( !ECOisDesign(mHWnd) && !mInInit )
		{	
			qshort fontSizeAdj = 0;
			if ( mDoc ) 
			{ fontSizeAdj = mDoc->fontSizeAdj(); delete mDoc; mDoc = 0; }
			if ( mHWnd)
			{
				stopAnimateScroll();
				WNDsetScrollPos( mHWnd, SB_VERT, 0, qtrue );
				WNDsetScrollPos( mHWnd, SB_HORZ, 0, qtrue );
			}
			mInParsing = qtrue;	
			if ( mCompId == OBJECT_ID1 )	// AE6479
				mDoc = WPHtmlClass::make( mHWnd, mEventHwnd, fval.getLong(), mPrinting, 0, &fval,mPointSizeForPreAndXmp,mCodeAssistant,mSrchWords.cString() ); // rmm_emat
			else
				mDoc = WPRtfClass::make( mHWnd, mEventHwnd, fval.getLong(), mPrinting, 0, &fval ); // mpm4700
			mDoc->fontSizeAdj( fontSizeAdj );
			mSrchWords = qnil;
			mInParsing = qfalse;
			initDocument();
			mMustRebuild = qfalse;
		}
	}	
	return;	
}

void tqfWPObject::initDocument( qbool pPositionBookmark )
{
	qrect cRect; WNDgetClientRect( mHWnd, &cRect );
	if ( mDoc )
	{
		WPObjInfoStruct rowInfo; 
		rowInfo.mRowRect = cRect;
		if (!mCodeAssistant) // rmm_emat
			rowInfo.mRowRect.inset( 3, 3 );
		rowInfo.mRowRect.bottom = rowInfo.mRowRect.top - 1;
		rowInfo.mOwnerRect = rowInfo.mRowRect;
		if ( mHWnd ) 
		{
			mDoc->initData( &rowInfo );
			setScrollRange();
			if ( pPositionBookmark ) positionBookmark();
		}
	}
	else 	if ( mHWnd ) setScrollRange();
	if ( mHWnd )	
		WNDinvalidateRect( mHWnd, NULL );
}

str15 BOOKMARK_TOP(QTEXT("TOP"));

void tqfWPObject::positionBookmark()
{
	str255 bookmark = mDocName;
	WPObjInfoStruct objInfo; qlong result = 0;
	qldim hoff, voff; getOffset( hoff, voff );
	qbool gotoTop = qfalse;	// rmmdocgen
	if ( mDoc->getBookmark( bookmark ) )
	{
		result = mDoc->message( &objInfo, eWPMessFindBookmark, -hoff, -voff, (LPARAM)&bookmark, 0 );
		if ( !result && !bookmark.uprCmp( BOOKMARK_TOP ) ) // rmmdocgen: !..uprCmp
		{
			result = 1;
			objInfo.mOwnerRect.top = 0;
			gotoTop = qtrue;	// rmmdocgen
		}
	}
	else
	{
		result = mDoc->message( &objInfo, eWPMessFindSearchWord, -hoff, -voff, 0, 0 );
		if ( result )
		{
			// rmmdocgen: there was a problem if the text was near the start of the page
			qrect cRect; WNDgetClientRect( mHWnd, &cRect );
			qlrect saveOwnerRect = objInfo.mOwnerRect;
			objInfo.mOwnerRect.offset( 0, -(cRect.height() / 2) );
			if (objInfo.mOwnerRect.top < 0) objInfo.mOwnerRect = saveOwnerRect;
		}
	}
	if ( result )
	{
		qdim hUnits, vUnits; getScrollAmt( hUnits, vUnits );
		qdim pos; WNDgetScrollPos( mHWnd, SB_VERT, &pos );
		WPARAM wParam = SB_THUMBPOSITION; LPARAM lParam = gotoTop ? 0 : (objInfo.mOwnerRect.top / vUnits + pos - 1); // rmmdocgen
		// rmm8886: Do not combine lParam and wParam for windows, as this will be treated as an Omnis scroll message by the core, so the parameters are already correct
		WNDsendMessage( mHWnd, WM_VSCROLL, wParam, lParam );
	}
}


void tqfWPObject::sizeChanged()
{
	if ( mDoc )
	{
		initDocument( qfalse );
		WNDredrawWindow( mHWnd, 0, 0, WND_RW_PAINT | WND_RW_ERASE | WND_RW_INVALIDATE );
	}

}

static qlong ticdelay = 2;

qbool tqfWPObject::autoScroll( HWND hwnd, qpoint* pPoint )
{
	qbool posChanged = qfalse;
	static qlong lasttics = 0;
	qbool ok = abs(ECOgetTickCount() - lasttics) >= ticdelay; // rmm8573
	if ( ok && mInDragSelect )
	{
		lasttics = ECOgetTickCount(); // rmm8573
		qrect cRect; WNDgetClientRect( hwnd, &cRect );
		UINT message = 0; WPARAM wParam; qdim amnt = 8;
		if ( pPoint->v > cRect.bottom )
		{
			amnt = (pPoint->v - cRect.bottom) / 8;
			message = WM_VSCROLL; wParam = SB_LINEDOWN;
		}
		else if ( pPoint->v < cRect.top )
		{
			amnt = (cRect.top - pPoint->v) / 8;
			message = WM_VSCROLL; wParam = SB_LINEUP;
		}
		else if ( pPoint->h > cRect.right )
		{
			amnt = (pPoint->h - cRect.right) / 8;
			message = WM_HSCROLL; wParam = SB_LINERIGHT;
		}
		else if ( pPoint->h < cRect.left )
		{
			amnt = (cRect.left - pPoint->h) / 8;
			message = WM_HSCROLL; wParam = SB_LINELEFT;
		}
			
		if ( message ) 
		{
			qldim oldhoff, oldvoff; getOffset( oldhoff, oldvoff );
			ticdelay = 2 - amnt; if ( ticdelay < 0 ) ticdelay = 0;
			WNDsendMessage( mHWnd, message, wParam, 0 );
			qldim newhoff, newvoff; getOffset( newhoff, newvoff );
			if ( newhoff != oldhoff || newvoff != oldvoff )
			{
				mSelRect.offset( oldhoff - newhoff, oldvoff - newvoff );
				posChanged = qtrue;// if we get here let it run into the next case
			}
		}
	}
	return posChanged;
}

qlong tqfWPObject::setData( EXTCompInfo* eci,qfldval pData)
{
	// pData will be set when printing. 
	EXTParamInfo* param = pData ? 0 : ECOfindParamNum(eci,1);
	if ( pData || ( param && param->mData ) )
	{
		EXTfldval fldval( pData ? pData : (qfldval)param->mData ); 
		inputFromText(fldval);
			return 1L;
	}
	return 0L; // Bad
} 
qlong tqfWPObject::bindData( EXTCompInfo* eci)
{
	qlong rtnval = 0;
	if ( mDoc && ( mDoc->docHan()))
	{
		EXTfldval fldname ;
		if ( ECOgetProperty( mHWnd, anumFieldname, fldname ) )
		{
			str255 dataStr; 
			fldname.getChar ( dataStr );
			if (!!dataStr) // rmm4006
			{
				EXTfldval fldval(dataStr,qtrue,eci->mInstLocp);
				fldval.setHandle( fftBinary, mDoc->docHan() , qtrue ); 
				rtnval = 1;
			}
		} 
	}
	return rtnval;
} 
// not sure where this is called & what to do ? Looks 
// similar to bind data but cant substitute.

qlong tqfWPObject::getData( EXTCompInfo* eci)
{
	qlong rtnval = 0;
	if ( mDoc && ( mDoc->docHan()))
	{
		EXTfldval exfldval;
		ECOaddParam(eci,&exfldval);
		exfldval.setHandle( fftPicture, mDoc->docHan() , qtrue ); 
		rtnval = 1; 
	}
	return rtnval; // Bad
} 
qlong tqfWPObject::cmpData( EXTCompInfo* eci)
{
	qlong rtnval = 0;
	EXTParamInfo* param = ECOfindParamNum(eci,1);
	if ( mDoc && ( mDoc->docHan()) &&  param && param->mData )
	{
		qHandlePtr  myDataPtr( mDoc->docHan(), 0 );
		EXTfldval fldval( (qfldval)param->mData );
		qHandle cmpdata = fldval.getHandle (qfalse);
		if ( !cmpdata )
			return DATA_CMPDATA_DIFFER;
		qHandlePtr  cmpDataPtr ( cmpdata, 0 );

		if ( cmpDataPtr.dataLen() != myDataPtr.dataLen() )
			return DATA_CMPDATA_DIFFER;

		if ( MEMmemcmp( *cmpDataPtr, *myDataPtr, myDataPtr.dataLen() )==0 )
			rtnval = DATA_CMPDATA_SAME;
		else
			rtnval = DATA_CMPDATA_DIFFER;
	}
	return rtnval;
} 

qprierr tqfWPObject::addToPrintJob( HWND hWnd, printInfo* pInfo, EXTCompInfo* eci ) // mpm4700
{
	pInfo->mObj->mType = PRI_OBJ_TEXT;
	// Dont know at this point if document or txt.
	str255 tempDocName = mDocName ;
	WPHtmlClass::htmlToApiPath( tempDocName );
	if (tempDocName[0] > 0)	// rmm7750: If there is data and no file name, print the data
		mSourceIsText = qfalse ;
	else 
	{
		if (mCompId == OBJECT_ID1) mSourceIsText = qfalse;	// rmm7750
		EXTfldval fval((qfldval)pInfo->mObj->mData );
		freeSourceStr();	// rmm8448
		mSourceStr =	fval.getHandle( qtrue );
		mSourceStrIsMine = qtrue;	// rmm8448
		qHandlePtr sourcePtr = qHandlePtr(mSourceStr, 0);
		if ( sourcePtr.dataLen()> 0 )
			mSourceIsText = qtrue ;
	}
	if ( mDoc == NULL )
	{
		if ( mSourceIsText)
			setData(eci,pInfo->mObj->mData);
		else
			createDocument();
	}
	qprierr err = PRI_ERR_NONE;
	if ( mDoc != NULL )
	{
		qldim horzOff=0, vertOff=0;
		err = mDoc->addToPrintJob(pInfo,eci,NULL,horzOff,vertOff);
	}
	return err;
}

qbool tqfWPObject::mouse( HWND hwnd, LPARAM Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci )
{
	qpoint pt; WNDmakePoint( lParam, &pt );
	switch ( Msg )
	{
		case WM_NULL:
		case WM_MOUSEMOVE:
		{
			if ( mDoc )
			{
				if ( mInLink )
				{
					qrect r; mTrackObj.mOwnerRect.conv( &r );
					qbool inRect = GDIptInRect( &r, &pt );
					if ( inRect != mTrackLinkInfo->mActive )
					{
						mTrackLinkInfo->mActive = inRect;
						mTrackObj.mOwner->setLinkInfo( mTrackLinkInfo );
						paintObject( &mTrackObj );
					}
				}
				else if ( mInDragSelect )
				{
					if ( !autoScroll( hwnd, &pt ) && Msg == WM_NULL ) break;
					qldim hoff, voff; getOffset( hoff, voff );
					mSelRect.bottom = pt.v;
					mSelRect.right = pt.h;
					qlrect lr = mSelRect; lr.normVertPt();
					mDoc->setSelRect( &lr, -hoff, -voff );
				}
				else
				{
					WPObjInfoStruct objInfo; HCURSOR cursor = WND_CURS_DEFAULT;
					if (!mCodeAssistant)	// rmm_emat
					{
						qldim hoff, voff; getOffset(hoff, voff);
						if (mDoc->message(&objInfo, eWPMessFindPt, -hoff, -voff, (LPARAM)&pt, 0))
							cursor = objInfo.mOwner->getCursor(&objInfo, &pt);
					}
					WNDsetCursor( cursor );
				}
				return qtrue;
			}
			break;
		}
		case WM_LBUTTONDOWN:
		{
			if ( mDoc )
			{
				qbool shiftPressed = isShift();
				qldim hoff, voff; getOffset( hoff, voff );
				if ( !shiftPressed ) mDoc->setSelRect( 0, -hoff, -voff );
				if ( mDoc->message( &mTrackObj, eWPMessFindPt, -hoff, -voff, (LPARAM)&pt, 0 ) )
				{
					if ((mTrackLinkInfo = mTrackObj.mOwner->getLinkInfo()) != 0)
					{
						mInLink = qtrue;
						mTrackLinkInfo->mActive = qtrue;
						mTrackObj.mOwner->setLinkInfo( mTrackLinkInfo );
						paintObject( &mTrackObj );
					}
				}
				if ( !mTrackLinkInfo )
				{
					mInDragSelect = qtrue;
					if ( shiftPressed && mDoc->haveSelection() )
					{
						qldim hoff, voff; getOffset( hoff, voff );
						mDoc->getSelRect( &mSelRect );
						mSelRect.bottom = pt.v;
						mSelRect.right = pt.h;
						qlrect lr = mSelRect; lr.normVertPt();
						mDoc->setSelRect( &lr, -hoff, -voff );
					}
					else
					{
						mSelRect.top = mSelRect.bottom = pt.v;
						mSelRect.left = mSelRect.right = pt.h;
					}
					WNDsetCursor( WND_CURS_IBEAM );
				}
				WNDsetCapture( hwnd, WND_CAPTURE_MOUSE );
				return qtrue;
			}
			break;
		}
		case WM_LBUTTONUP:
		{
			if ( WNDhasCapture( hwnd, WND_CAPTURE_MOUSE ) ) WNDreleaseCapture( WND_CAPTURE_MOUSE );
			if ( mInLink )
			{
				mInLink = qfalse;
				qrect r; mTrackObj.mOwnerRect.conv( &r );
				qbool inRect = GDIptInRect( &r, &pt );
				mTrackLinkInfo->mActive = qfalse;
				if ( inRect ) mTrackLinkInfo->mVisited = qtrue;
				mTrackObj.mOwner->setLinkInfo( mTrackLinkInfo );
				paintObject( &mTrackObj );
				if ( inRect ) mDoc->sendHyperlinkEvent( mTrackLinkInfo );
				mTrackLinkInfo = 0;
				// Start rmm6084: post WM_MOUSEMOVE to make sure the cursor changes - we need to post the message 
				// so it arrives after exiting testesc, meaning that the cursor can then be set.
				qpoint pt;
				WNDgetCursorPos(&pt);
				WNDmapWindowPoint(HWND_DESKTOP, hwnd, &pt);
				WNDpostMessage(hwnd, WM_MOUSEMOVE, 0, WNDmakeLong(&pt));
				// End rmm6084
				return qtrue;
			}
			else if ( mInDragSelect )
			{
				qldim hoff, voff; getOffset( hoff, voff );
				mSelRect.bottom = pt.v;
				mSelRect.right = pt.h;
				qlrect lr = mSelRect; lr.normVertPt();
				mDoc->setSelRect( &lr, -hoff, -voff );
				mInDragSelect = qfalse;
				WNDsetCursor( WND_CURS_DEFAULT );
			}
			break;
		}
	}
	return qfalse;
}

// Start rmm11749
/**
	Used in place of PRIaddObject, to modify colours when printing to report (since dark mode otherwise looks bad)
	@param[in]			pJob				Identifies the print job
	@param[in]			pObject			The object to add to the print job

	@return PRI_ERR_NONE for success, or a non-zero error code
*/
qprierr tqfWPObject::doPRIaddObject(PRIjob pJob, PRIobjectStruct* pObject)
{
	auto mapColor = [](qcol& pColor)
	{
		if (GDI_COLOR_WINDOWTEXT == pColor)
			pColor = colBlack;
		else if (GDI_COLOR_WINDOW == pColor)
			pColor = colWhite;
		else if (GDI_COLOR_HOTLIGHT == pColor)
			pColor = GDImakeQcol(0, 0, 255);
	};

	mapColor(pObject->mForeFillColor);
	mapColor(pObject->mBackFillColor);
	mapColor(pObject->mBorder.mColor);
	mapColor(pObject->mBorder.mLineStyle.mColor);
	mapColor(pObject->mTextSpec.mTextColor);
	return PRIaddObject(pJob, pObject);
}
// End rmm11749

qbool gRunningVista = qfalse;	// rmm6181
// Component library entry point (name as declared in resource 31000 )
extern "C" LRESULT OMNISWNDPROC HTMLCtrlWndProc(HWND hwnd, UINT Msg,WPARAM wParam,LPARAM lParam,EXTCompInfo* eci)
{
	 // Initialize callback tables - THIS MUST BE DONE 
   ECOsetupCallbacks(hwnd, eci);		
	 switch (Msg)
	 {
			// WM_PAINT - standard paint message
			case WM_PAINT:
			{
				// First find the object in the libraries chain of objects
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				// and if its good, call the paint function
				if ( NULL!=object && !object->mInInit && object->paint() ) // AE5002
					return qtrue;
				break;
			} 
			
			case WM_ERASEBKGND:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					if ( object->mIsReport ) 
						break;
					if ( object->mDoc )
					{
						// rmm4899: erase now occurs when drawing offscreen, except when in design mode
						if (ECOisDesign(hwnd)) object->mDoc->eraseBackground( hwnd, (HDC)wParam );
					}
					else
					{
						HDC dc = (HDC)wParam;
						qrect cRect; WNDgetClientRect( hwnd, &cRect );
						GDIsetTextColor( dc, GDI_COLOR_WINDOW );
						GDIfillRect( dc, &cRect, GDIgetStockBrush( BLACK_BRUSH ) );
					} 
					return 1L;
				}
				return 0L;
			}
			
			case WM_TIMER:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					object->doAnimateScroll();
				}
				return 0L;
			}
			
			case WM_EXUSER+1:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					object->doUser1Message( (HWND)lParam );
					return 1L;
				}
				return 0L;
			}
			case WM_SETCURSOR: // mpm4575
			{
				// Start rmm10716: Allow default cursor setting outside the client area
				if (LOWORD(qword4(lParam)) != HTCLIENT)
					break;
				// End rmm10716
				if (!ECOisDesign(hwnd)) return 1L; // we deal with cursor setting on WM_MOUSEMOVE and WM_NULL messages // rmm4004
			}
			case WM_MOUSEMOVE:
			case WM_LBUTTONDOWN:
			case WM_LBUTTONUP:
			case WM_NULL:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( NULL!=object )
				{
					if ( object->mouse( hwnd, Msg, wParam, lParam, eci ) )
						return 1L;
				}
				break;
			} 

			case WM_MOUSEWHEEL:	// rmm8115
			{
				if (ECOisDesign(hwnd))
					return 0L;
				break;
			}
			
			// ECM_OBJCONSTRUCT - this is a message to create a new object.
			case ECM_OBJCONSTRUCT:				
			{
				// Allocate a new object
				// need to pass in eci so know what sort .
				qbool reportObj = (qbool)wParam;
				
				tqfWPObject* object = new tqfWPObject( hwnd ,eci->mCompId ,reportObj);
				// and insert into a chain of objects. The OMNIS library will maintain this chain
				ECOinsertObject( eci, hwnd, (void*)object );
				return qtrue;
			}    
			
			// ECM_OBJDESTRUCT - this is a message to inform you to delete the object
			case ECM_OBJDESTRUCT:					
			{
				// First find the object in the libraries chain of objects, 
				// this call if ok also removes the object from the chain.
				tqfWPObject* object = (tqfWPObject*)ECOremoveObject( eci, hwnd );
				if ( NULL!=object )
				{
					// Now you can delete the object you previous allocated
					// Note: The hwnd passed on ECM_OBJCONSTRUCT should not be deleted, as
					// it was created and will be destroyed by OMNIS
					delete object;
				}
				return qtrue;
			}
	 		
	 		case ECM_CONNECT:
      {
				// Start rmm6181
				#ifdef iswin32
					DWORD verinfo = WNDwinGetVersion(); // rmm10984
					if ((verinfo & 0xff) >= 6)
						gRunningVista = qtrue;
				#endif
				// End rmm6181
				WPHtmlClass::init();	// rmmuni
				WPRtfClass::init();		// rmmuni
        return ECOmakeConnectFlags(EXT_FLAG_ALWAYS_USABLE|EXT_FLAG_LOADED |EXT_FLAG_REMAINLOADED); // Return external flags // rmm10253: Always usable and remain loaded (otherwise code assistant behaves strangely when listing $control events for a window class) // rmm11466
      } 
      
      case ECM_DISCONNECT:
      { 
				WPHtmlClass::term();	// rmmuni
				WPRtfClass::term();		// rmmuni
        return qtrue;
      }

      // ECM_GETCOMPLIBINFO - this is sent by OMNIS to find out the name of the library, and
      // the number of components this library supports
      case ECM_GETCOMPLIBINFO:
      {
      	return ECOreturnCompInfo( gInstLib, eci, LIB_RES_NAME, OBJECT_COUNT );
      }

      // ECM_GETCOMPICON - this is sent by OMNIS to get an icon for the OMNIS component store and
      // external component browser. You need to always supply an icon in your resource file.
			case ECM_GETCOMPICON:
			{
				// OMNIS will call you once per component for an icon.
				// HTMLCTRL_ICON is defined in the header and included in the resource file
				if ( eci->mCompId==OBJECT_ID1 ) return ECOreturnIcon( gInstLib, eci, HTMLCTRL_ICON );
				if ( eci->mCompId==OBJECT_ID_RTF ) return ECOreturnIcon( gInstLib, eci, RTFVIEW_ICON );
				return qfalse;
			}

			// ECM_GETCOMPID - this message is sent by OMNIS to get information about each component in this library
			// wParam is a number from 1 to the number of components return on the ECM_GETCOMPLIBINFO message.
			//
			// For each call you should return the internal object ID and the type of object it is.
			// The object id will be used for other calls such as ECM_GETCOMPICON 
			// 
			// The object type is for example : cObjType_Basic 		- a basic window object or 
			//																	cRepObjType_Basic	- a basic report object.
			// 																	There are others 	- see BLYTH examples and headers
			case ECM_GETCOMPID:
			{
				if ( wParam==1 )
					return ECOreturnCompID( gInstLib, eci, OBJECT_ID1, cObjType_Basic|cRepObjType_Basic  );
				if ( wParam==2 )
					return ECOreturnCompID( gInstLib, eci, OBJECT_ID_RTF, cObjType_Basic|cRepObjType_Basic );
				return 0L;
			}
			
			case ECM_GETEVENTNAME:
			{
				if ( eci->mCompId==OBJECT_ID1 )
					return ECOreturnEvents(gInstLib,eci,&WPevents[0],cWPeventsCount);
				else
					return ECOreturnEvents(gInstLib,eci,&WPRTFevents[0],cWPRTFeventsCount);
			}
			
			case ECM_GETMETHODNAME:
			{
				return ECOreturnMethods( gInstLib, eci, &WPmethods[0], cWPmethodsCount );
			}

			case ECM_GETPROPNAME:
			{
				if ( eci->mCompId==OBJECT_ID1 )
					return ECOreturnProperties( gInstLib, eci, &HTMLCtrlProperties[0], cHTMLCtrlPropertiesCount );
				else
					return ECOreturnProperties( gInstLib, eci, &RtfCtrlProperties[0], cRtfCtrlPropertiesCount );
			}
			
			case ECM_METHODCALL:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				EXTfldval returnVal;					// rmm3656
				qlong returnStatus = qfalse;	// rmm3656
				if ( object )
				{
					qlong methodID = ECOgetId(eci);
					switch(methodID)
					{
						case cStartAnimateScroll: returnStatus = object->startAnimateScroll( eci ); break;	// rmm3656
						case cStopAnimateScroll: returnStatus = object->stopAnimateScroll(); break;					// rmm3656
						case cPathToApi:
						case cPathToHtml:
						{
							EXTParamInfo* param = ECOfindParamNum( eci, 1 );
							if ( param )
							{
								EXTfldval fval( (qfldval)param->mData );
								str255 path; fval.getChar( path );
								if ( methodID == cPathToApi )
									WPHtmlClass::htmlToApiPath( path );
								else
									WPHtmlClass::apiToHtmlPath( path );
								fval.setChar( path );
								ECOsetParameterChanged( eci, 1 );
								returnStatus = qtrue;	// rmm3656
							}
							break;
						}
						case cGetSelText: returnStatus = object->getSelText( eci ); break; // rmm3656
						case cPrint: returnStatus = object->print( eci ); break; // mpm4700
					}
				}
				returnVal.setLong(returnStatus);	// rmm3656
				ECOaddParam(eci, &returnVal);			// rmm3656
				return 1L;
			}
			
			case ECM_PROPERTYCANASSIGN:
			case ECM_PROPERTYCALCTYPE:
			case ECM_SETPROPERTY:
			case ECM_GETPROPERTY:
			case ECM_INBUILT_OVERRIDE:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
					return object->property( hwnd, Msg, eci, wParam==ECM_WPARAM_PROPBUTTON );
				else
					return 0L;
			}
			
			case WM_CONTROL: // AE6120
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					// Old code which was in ECM_OBJINITIALIZE
					if (!object->mInInit && object->mCreateDocumentWhenInitDone)
					{ 
						object->createDocument();
						// so rtf can be databound both ways .
						if (object->mCompId == OBJECT_ID_RTF) 
							object->bindData(eci);
					}
				}
				break;
			}
			case ECM_OBJINITIALIZE:
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					object->mInInit = !(qbool)wParam;
					// Start rmm4006
					if (!object->mInInit && object->mCreateDocumentWhenInitDone)
					{
						if (hwnd) WNDpostMessage(hwnd,WM_CONTROL,0,0);	 // AE6120 Post a message and process later // rmm5732: only do it later if hwnd is present (note: hwnd is zero for reports)
						// Start rmm5732: case for reports
						else 
						{
							object->createDocument();
							// so rtf can be databound both ways .
							if (object->mCompId == OBJECT_ID_RTF) 
								object->bindData(eci);
						}
						// End rmm5732
					}
					// End rmm4006
				}
				break;
			}
		case ECM_SETPRIMARYDATA: case ECM_GETPRIMARYDATA:	case ECM_CMPPRIMARYDATA: case ECM_GETPRIMARYDATALEN:
		{
			tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
			// For fields which don't have a dataname to avoid losing the data
			// we will ignore data messages.
			//	Here is the fldname stuff for the rtf control to be databound
			if ( object && !object->mIsReport ) // Not that we get data msgs during printing, but..
			{
#ifdef isXCOMPLIB
				EXTfldval fldname;
				if ( ECOgetProperty( hwnd, anumFieldname, fldname ) )
				{
					str255 str; 
					fldname.getChar ( str );
					if ( !str )
						object = NULL;
				}
				else
					object = NULL;
#endif
			}	
			if (object)	switch (Msg)
			{
				case ECM_SETPRIMARYDATA: return object->setData(eci);
				case ECM_GETPRIMARYDATA: return object->getData(eci);
				case ECM_CMPPRIMARYDATA: return object->cmpData(eci);
				case ECM_GETPRIMARYDATALEN: return object->getData(eci);
			}
			return 0L;
		}
		case ECM_CANADDTOPRINTJOB: return 1L; // mpm4522 begins
		case ECM_ADDTOPRINTJOB:
		{
			tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
			if ( object )
			{
				object->addToPrintJob( hwnd, (printInfo*)lParam, eci );
				return 1L;
			}
			break;
		} // mpm4522 ends
		case ECM_PRINTMAPPING: return 1L;
		case WM_WINDOWPOSCHANGED:
		{
			WNDwindowPosMessageStruct* windowPosInfo = (WNDwindowPosMessageStruct*)lParam;
			if (windowPosInfo->size()  || windowPosInfo->frameChange()) // rmm3654: added check for SWP_FRAMECHANGED
			{
				tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
				if (object) object->sizeChanged();
			}
			break;
		}
		case ECM_GETVERSION:	// mpm5094
		{
			return ECOreturnVersion(1,4); // rmm4799 ae6479
		}                                                                 
		case WM_KEYDOWN: // AE6139
		{
			tqfWPObject* object = (tqfWPObject*)ECOfindObject( eci, hwnd );
			if ( object )
			{
				vchar	vch = ((qkey*)lParam)->getVChar();
				if (ECOhasFocus(hwnd) && object->scrollByKey(vch)) return qtrue; // rmm4400 // rmm10949: Make sure control has the focus before scrolling by key
			}
			break;
		}
		// Start rmm6051
		case WM_FLD_SETMENU:
		{
			tqfWPObject *object = (tqfWPObject * ) ECOfindObject(eci, hwnd);
			if (object && MM_EDIT == wParam)
			{
				FLDeditState *state = (FLDeditState *) lParam;
        state->mUndo = qfalse;
        state->mCut = qfalse;
        state->mPaste = qfalse;
        state->mCopy = (qbool) (object->mDoc && object->mDoc->haveSelection());
        state->mClear = qfalse;
        state->mPasteff = qfalse;
				return 1L;
			}
			break;
		}
		case WM_FLD_EXECMENU: 
		{
			tqfWPObject *object = (tqfWPObject * ) ECOfindObject(eci, hwnd);
			if (object && MM_EDIT == wParam)
			{
				switch ( lParam )
				{
					case MI_COPY:
					{
						if (object->mDoc)
						{
							EXTfldval fval;
							qldim hoff, voff; 
							object->getOffset(hoff, voff);
							object->mDoc->copySelRect(&fval, hoff, voff);
							qHandle han = fval.getHandle(qfalse);
							ECOclipboardSetText(han);
						}
						return 1L;
					}
				}
				break;
			}			
			break;
		}
		// End rmm6051
	}

	// As a final result this must ALWAYS be called. It handles all other messages that this component
	// decides to ignore.
	return WNDdefWindowProc(hwnd,Msg,wParam,lParam,eci);
}
// End of file
