/* $Header$ */

// base WP text object class implementation

/**************** Changes ******************
Date			Edit				Bug					Description
20-Apr-23	rmm11949								Use IDE window colour as background colour of docview HTML viewer (results in the same background, cross-platform - macOS was too light in dark mode).
02-Mar-23	rmm11865								Added "Omnis macOS System" font, to provide the equivalent of "Omnis Windows System".
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.
04-Jul-22	rmm11648		ST/DB/1350	Changes to improve the look of the code assistant and docgen generated HTML.
26-Nov-20	rmm10800		ST/DC/801		Omnis help viewer did not draw selected text on Big Sur.  Changed the help viewer to draw selected text using the method highlight colour.
06-Nov-20	rmm10755		ST/DB/1271	Clicking on a link in the code assistant help panel for a command or function now opens the link in the help viewer.
11-Dec-19	rmm10340		ST/RC/1318	Crash printing HTML control with no data or path on a report on Linux.
03-Jan-19	rmm9887			ST/HE/1560	Problems viewing and printing Omnis help pages.
19-Dec-17	rmm_emat								Text editor for Omnis language.
11-Jul-16	rmm8965									VS2015 compiler issues.
12-Apr-16	rmm8853									Help window appearance issues.
01-May-15	CR0205									Cocoa changes.
19-Aug-13	rmm64bitux							Linux 64 bit port.
25-Jul-07	rmm6181									Changed font for help pages.
12-Jan-07	rmm5953			ST/HE/915		Copy to clipboard from docview added unnecessary carriage return(s) to the end of the data.
18-Oct-06	AE6732			ST/RC/1012: Crash in docview
07-Jul-04	rmmCW9									CodeWarrior 9 changes.
05-Sep-03	AE6336			ST/WO/1557: $printdocument was hiding ctrls but then not showing them!?!
21-Mar-03	AE6220			ST/HP/043: 	Crash on XP when viewing certain files.
27-Mar-02	AE6075			ST/EC/689 	Crash with docview when using $printdocument with no current document
20 NOV 01 mpm5023a								Now make copy of data prior to converting for returning to data field
22 MAY 00	mpm4700									Implements printing of document
08 NOV 99 mlr0006									Added Rtf support
30-Jul-99 MHUX001                 Unix Changes.
********************************************/

#ifndef _extcomp_
#include "extcomp.he" // jmg_includecasing
#endif

#ifndef	_WPDOC_HE_
#include "wpdoc.he" // jmg_includecasing
#endif

// ###############################################################################
// ################# WPDocInfoStruct Public #####################################
// ###############################################################################


void WPDocInfoStruct::init( eWPdocType pDocType )
{
	// intialize colors
	mBackColor = GDI_COLOR_IDE_WINDOW;	// rmm11949: was GDI_COLOR_WINDOW
	// Start rmm8853
	mTextColor = GDI_COLOR_WINDOWTEXT;
	
	mALinkColor = GDI_COLOR_HIGHLIGHT;
	mVLinkColor = GDI_COLOR_OMNIS_SET_PROPERTY; 
	mLinkColor = GDI_COLOR_HOTLIGHT;	
	// End rmm8853
	
	// intialize margins
	mLeftMargin = mTopMargin = 5;

	// intialize styles
	if ( mStylesCnt ) delete [] mStyles;
	mStyles = new WPTextInfoStruct[10];
	if ( mStyles )
	{
		mStylesAlloc = 10;
		mStylesCnt = WP_DOCINFO_LASTSTYLE + 1; // rmm11749
		// prepare basic info
		WPTextInfoStruct ti;
		{
			// Start rmm6181: changed the default font names
			#if defined(isunix)
				str255 fntName(QTEXT("Omnis Unix System"));
			#elif defined(ismacosx)
				str255 fntName(QTEXT("Omnis macOS System")); // rmm11865
			#else
				str255 fntName(QTEXT("Omnis Windows System"));
			#endif
			// End rmm6181
			qfnt tmpFnt; GDIsetFontName( &tmpFnt, &fntName[1], fntName.length() );
			ti.mFontNum = GDIgetFontNumber( &tmpFnt );
		}
		ti.mFontSize = 2;	// rmm6181
		ti.mFontSizeMode = eWPFontSizeHtml;
		ti.mFontStyBold = ti.mFontStyItalic = ti.mFontStyUnderline = qfalse;
		ti.mTextColor = GDI_COLOR_WINDOWTEXT; // rmm8853
		ti.mSet = WPTEXT_FONTNUMSET|WPTEXT_FONTSIZESET|WPTEXT_FONTSIZEMODE|
							WPTEXT_FONTSTYBSET|WPTEXT_FONTSTYISET|WPTEXT_FONTSTYUSET|
							WPTEXT_TEXTCOLORSET;
		mStyles[WP_DOCINFO_BASESTYLE] = ti;
		
		ti.mFontStyBold = qtrue;
		ti.mFontSize = 7;
		mStyles[WP_DOCINFO_HEADERSTYLE] = ti;
		ti.mFontSize = 6;
		mStyles[WP_DOCINFO_HEADER1STYLE] = ti;
		ti.mFontSize = 5;
		mStyles[WP_DOCINFO_HEADER2STYLE] = ti;
		ti.mFontSize = 4;
		mStyles[WP_DOCINFO_HEADER3STYLE] = ti;
		ti.mFontSize = 3;
		mStyles[WP_DOCINFO_HEADER4STYLE] = ti;
		ti.mFontSize = 2;
		mStyles[WP_DOCINFO_HEADER5STYLE] = ti;
		ti.mFontSize = 1;
		mStyles[WP_DOCINFO_HEADER6STYLE] = ti;
	}
}


qshort WPDocInfoStruct::addStyle( WPTextInfoStruct* pStyle )
{
	if ( mStylesCnt == mStylesAlloc )
	{
		WPTextInfoStruct* newStyles = new WPTextInfoStruct[mStylesAlloc+10];
		MEMmovel( mStyles, newStyles, sizeof(WPTextInfoStruct) * mStylesCnt );
		delete [] mStyles;
		mStyles = newStyles;
		mStylesAlloc += 10;
	}
	mStylesCnt++;
	mStyles[mStylesCnt] = *pStyle;
	return mStylesCnt;
}


// ###############################################################################
// ################# WPDocClass Public ###########################################
// ###############################################################################

extern qbool gRunningVista;	// rmm_emat
WPDocClass::WPDocClass( HWND pCrlHwnd, HWND pEventHwnd, qlong pIdent, qbool pPrinting, qbool pCodeAssistant) // mpm4700 // rmm_emat
					 :WPObjectClass(0,0), mTextInfo(mParagraphInfo.mTextInfo)
{
	mHwnd = pCrlHwnd;
	mEventHwnd = pEventHwnd ? pEventHwnd : mHwnd;
	mIdent = pIdent;
	mFontSizeAdj = 0;
	mBulletLevel = 0;
	mBulletClass = NULL; // AE6220
	mLinkInfo = NULL;
	mDocHan = mOrigDocHan = 0; // mpm5023a
	mSelRgn = 0;
	mPrinting = pPrinting; // mpm4700
	mPluginCreated = qfalse;	// rmm10340

	// Start rmm_emat
	mCodeAssistant = pCodeAssistant;
	if (mCodeAssistant)
		mParagraphInfo.mSpaceAfter = mParagraphInfo.mSpaceBefore = 2;	// rmm11790

	static qshort sWPfontSizes[7] = { 8, 10, 12, 14, 18, 24, 36 };
	static qshort sWPfontSubSizes[7] = { 6, 8, 10, 12, 14, 18, 24 };
	memcpy(mWPfontSizes, sWPfontSizes, sizeof(sWPfontSizes));
	memcpy(mWPfontSubSizes, sWPfontSubSizes, sizeof(sWPfontSubSizes));
	#ifdef ismacosx
		mWPfontSizes[1] = 12;
	#elif defined(isunix)
		mWPfontSizes[1] = 11;
	#else
		if (gRunningVista)
		{
			mWPfontSizes[0] = 9;
			mWPfontSubSizes[1] = 9;
		}
	#endif
	if (mCodeAssistant)
	{
		#ifndef ismacosx
			// Start rmm11648
			mWPfontSizes[0] = mWPfontSizes[1] = 9;
			mWPfontSizes[2] = 11;
			mWPfontSizes[3] = 12;
			mWPfontSizes[4] = mWPfontSizes[5] = mWPfontSizes[6] = 12;
			// End rmm11648
		#else
			mWPfontSizes[4] = mWPfontSizes[5] = mWPfontSizes[6] = 14;
		#endif
		sWPfontSubSizes[4] = sWPfontSubSizes[5] = sWPfontSubSizes[6] = 13;
	}
	// End rmm_emat
}


WPDocClass::~WPDocClass()
{
	EXTfldval fval; fval.setLong( mIdent );
	if (!mPrinting && !mCodeAssistant && mPluginCreated) ECOsendEvent( mEventHwnd, cWPdestroyPluginEvent, &fval, 1, qtrue ); // mpm4700 // rmm_emat // rmm10340
	
	if ( mDocInfo.mStyles ) delete [] mDocInfo.mStyles;
	if ( mLinkInfo ) delete mLinkInfo;
 	if ( mDocHan ) HANglobalFree( mDocHan );
 	if ( mOrigDocHan ) HANglobalFree( mOrigDocHan ); // mpm5023a
 	if ( mSelRgn ) GDIdeleteRgn( mSelRgn );
}


void WPDocClass::initData( WPObjInfoStruct* pObjInfo,printInfo* pInfo )
{
	if ( mSelRgn ) { GDIdeleteRgn( mSelRgn ); mSelRgn = 0; }
	HWND child = WNDgetWindow( mHwnd, GW_CHILD );
	while ( child )
	{
		WNDshowWindow( child, SW_HIDE );
		child = WNDgetWindow( child, GW_HWNDNEXT );
	}
	
	mDocRect = pObjInfo->mRowRect;
	pObjInfo->mRowRect.left += mDocInfo.mLeftMargin;
	pObjInfo->mRowRect.top += mDocInfo.mTopMargin;
	pObjInfo->mOwnerRect = pObjInfo->mRowRect;
	pObjInfo->mOwnerRect.right = pObjInfo->mOwnerRect.left - 1;
	pObjInfo->mOwnerRect.bottom = pObjInfo->mOwnerRect.top - 1;
	pObjInfo->mNoWrap = qfalse;
	WPObjectClass::initData( pObjInfo,pInfo );
}

// AE6336
void WPDocClass::endInitData()
{
	HWND child = WNDgetWindow( mHwnd, GW_CHILD );
	while ( child )
	{
		WNDshowWindow( child, SW_SHOW );
		child = WNDgetWindow( child, GW_HWNDNEXT );
	}
}


void WPDocClass::addRowInfo( WPObjInfoStruct* pObjInfo )
{
	mDocRect.unionRect( &mDocRect, &pObjInfo->mOwnerRect );
}


void WPDocClass::addParaInfo( WPObjInfoStruct* pObjInfo )
{
	mDocRect.unionRect( &mDocRect, &pObjInfo->mOwnerRect );
}


void WPDocClass::paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff )
{
	checkSelRgn( pHorzOff, pVertOff );
	// Start rmm10800
	if (mSelRgn)
	{
		GDIsetTextColor(pPaintStruct->hdc, GDI_COLOR_OMNIS_HIGHLIGHT_METHOD);
		GDIfillRgn(pPaintStruct->hdc, mSelRgn, GDIgetStockBrush(BLACK_BRUSH));
	}
	// End rmm10800
	WPObjectClass::paint( pObjInfo, pPaintStruct, pHorzOff, pVertOff );
}

qprierr WPDocClass::addToPrintJob(  printInfo* pInfo, EXTCompInfo* eci, WPObjInfoStruct* pObjInfo2, // mpm4700
																		qldim& pHorz, qldim& pVert )
{
	// Start rmm9887: Do not use $appearance colors
	if (ECOreadBooleanConfigurationItem("docview", "printWithDefaultColors", qtrue))
		WNDsendMessage(0, WM_CONTROL, PRINT_WITH_DEFAULT_COLORS, (LPARAM)pInfo->mJob);	
	// Get page info so we can resize text objects if necessary
	PRIgetPageInfo(pInfo->mJob, &mPageInfo);
	// End rmm9887

	qrect screenRect ;
	qprirect tempRect = (qprirect) pInfo->mObj->mPos;									// rmmCW9
	PRIconvRectToScreen(&tempRect, &screenRect);											// rmmCW9
	mDocRect = screenRect;

	WPObjInfoStruct pObjInfo ;

	pObjInfo.mRowRect.left = mDocRect.left + mDocInfo.mLeftMargin;
	pObjInfo.mRowRect.top = mDocRect.top + mDocInfo.mTopMargin;
	pObjInfo.mRowRect.right = mDocRect.right ;
	pObjInfo.mRowRect.bottom = mDocRect.bottom;

	pObjInfo.mOwnerRect = pObjInfo.mRowRect;
	pObjInfo.mOwnerRect.right = pObjInfo.mOwnerRect.left - 1;
	pObjInfo.mOwnerRect.bottom = pObjInfo.mOwnerRect.top - 1;
	pObjInfo.mNoWrap = qfalse;
	WPObjectClass::initData( &pObjInfo ,pInfo);

	// AE6732 Pass in pObjInfo here. It used to be NULL but was dereferenced further down the call chain
	return WPObjectClass::addToPrintJob(pInfo,eci,&pObjInfo,pHorz,pVert);
}

qbool WPDocClass::eraseBackground( HWND pHwnd, HDC pHdc )
{
	qrect cRect; WNDgetClientRect( pHwnd, &cRect );
	GDIsetTextColor( pHdc, mDocInfo.mBackColor );
	GDIfillRect( pHdc, &cRect, GDIgetStockBrush( BLACK_BRUSH ) );
	return qtrue;
}

qbool GDI_OPTION_CLICK_ON = qfalse;

void WPDocClass::setSelRect( qlrect* pRect, qldim pHorzOff, qldim pVertOff )
{
	// Start rmm10800
	auto invalSelRgn = [this]()
	{
		WNDinvalidateRgn(mHwnd, mSelRgn);
	};
	// End rmm10800
	checkSelRgn(pHorzOff, pVertOff);
	if (pRect)
	{
		mSelRect = *pRect;
		WPgetCharRangeStruct charRangeInfo; WPObjInfoStruct objInfo;
		charRangeInfo.mSelRect = *pRect;
		message(&objInfo, eWPMessGetCharRange, pHorzOff, pVertOff, (LPARAM)&charRangeInfo, 0);
		mSelFstChar = charRangeInfo.mFstChar;
		mSelLstChar = charRangeInfo.mLstChar;
		message(&objInfo, eWPMessGetCharRangeRgn, pHorzOff, pVertOff, (LPARAM)&charRangeInfo, 0);
		if ( charRangeInfo.mSelRgn )
		{
			if ( mSelRgn )
			{
				GDIrgnXor( mSelRgn, charRangeInfo.mSelRgn, mSelRgn );
				invalSelRgn();	// rmm10800
				GDIdeleteRgn( mSelRgn );
				mSelRgn = charRangeInfo.mSelRgn;
			}
			else
			{
				mSelRgn = charRangeInfo.mSelRgn;
				invalSelRgn();	// rmm10800
			}
			return;
		}
	}
	
	if ( mSelRgn )
	{
		invalSelRgn();	// rmm10800
		GDIdeleteRgn( mSelRgn );
		mSelRgn = 0;
	}
}


qbool WPDocClass::copySelRect( EXTfldval* pFldVal, qldim pHorzOff, qldim pVertOff )
{
	checkSelRgn( pHorzOff, pVertOff );
	if ( mSelRgn )
	{
		WPgetCharRangeStruct charRangeInfo; WPObjInfoStruct objInfo;
		charRangeInfo.mFstChar = mSelFstChar;
		charRangeInfo.mLstChar = mSelLstChar;
		charRangeInfo.mSelRgn = mSelRgn;
		message( &objInfo, eWPMessCopyCharRange, pHorzOff, pVertOff, (LPARAM)&charRangeInfo, (LPARAM)pFldVal );
		// Start rmm5953: strip trailing carriage returns if present
		qlong copiedLen = pFldVal->getCharLen();
		if (!copiedLen)
			return qfalse;
		qchar *copyData = new qchar[copiedLen];
		qlong len;
		pFldVal->getChar(copiedLen, copyData, len);
		qlong newLen = copiedLen;
		for (qlong i = copiedLen - 1; i >= 0; --i)
		{
			if ((qchar) 13 == copyData[i])
				--newLen;
			else
				break;
		}
		if (!newLen)
			return qfalse;
		pFldVal->setChar(copyData, newLen);
		delete [] copyData;
		// End rmm5953
		return qtrue;
	}
	return qfalse;
}

// rmm64bitux: Moved eWPdocInfoStyle to separate call capable of handling 64 bit pointers
qbool WPDocClass::getDocumentInfo( eWPdocInfoSwitch pSwitch, qlong pSubSwitch, qlong& pInfo )
{
	switch ( pSwitch )
	{
		case eWPdocInfoFontSizeAdj:
			pInfo = mFontSizeAdj;
			return qtrue;
		case eWPdocInfoBackColor:
			pInfo = (qlong)mDocInfo.mBackColor;
			return qtrue;
		case eWPdocInfoTextColor:
			pInfo = (qlong)mDocInfo.mTextColor;
			return qtrue;
		case eWPdocInfoALinkColor:
			pInfo = (qlong)mDocInfo.mALinkColor;
			return qtrue;
		case eWPdocInfoVLinkColor:
			pInfo = (qlong)mDocInfo.mVLinkColor;
			return qtrue;
		case eWPdocInfoLinkColor:
			pInfo = (qlong)mDocInfo.mLinkColor;
			return qtrue;
		case eWPdocInfoLeftMargin:
			pInfo = (qlong)mDocInfo.mLeftMargin;
			return qtrue;
		case eWPdocInfoTopMargin:
			pInfo = (qlong)mDocInfo.mTopMargin;
			return qtrue;
		case eWPdocInfoWidth:
			pInfo = (qlong)mDocRect.width();
			return qtrue;
		case eWPdocInfoHeight:
			pInfo = (qlong)mDocRect.height();
			return qtrue;
	}
	return qfalse;
}

// rmm64bitux:
qbool WPDocClass::getDocumentInfoPtr( eWPdocInfoSwitch pSwitch, qlong pSubSwitch, qlongptr& pInfo )
{
	switch ( pSwitch )
	{
		case eWPdocInfoStyle:
			if ( pSubSwitch >= 0 && pSubSwitch < mDocInfo.mStylesCnt )
			{
				pInfo = (qlongptr)&mDocInfo.mStyles[pSubSwitch];
				return qtrue;
			}
			break;
	}
	return qfalse;
}

HWND WPDocClass::getPlugin( const strxxx& pPluginType, EXTqlist& pProperties, qldim& pWidth, qldim& pHeight )
{
	if (!mPrinting && !mCodeAssistant) // mpm4700 // rmm_emat
	{
		EXTfldval fvals[6];
		fvals[0].setLong( mIdent );
		fvals[1].setChar( pPluginType );
		fvals[2].setList( &pProperties, qtrue );
		fvals[3].setLong(0);
		fvals[4].setLong(pWidth);
		fvals[5].setLong(pHeight);
		if (ECOsendEvent(mEventHwnd, cWPcreatePluginEvent, &fvals[0], 6, qtrue))
		{
			mPluginCreated = qtrue;	// rmm10340
			#ifdef is64bit	// rmm8965
				HWND plugin = (HWND)fvals[3].getLong64();
			#else
				HWND plugin = (HWND)fvals[3].getLong();
			#endif
			if ( plugin )
			{
				WNDshowWindow( plugin, SW_HIDE );
				WNDsetParent( plugin, mHwnd );
				pWidth = fvals[4].getLong();
				pHeight = fvals[5].getLong();
			}
			return plugin;
		}
	}
	return 0;
}


HWND WPDocClass::getXCompPlugin( str80& pComponentLib, str80& pComponentCtrl, EXTqlist* pProperties,
																	qldim& pWidth, qldim& pHeight )
{
	if (!mPrinting && !mCodeAssistant) // mpm4700 // rmm_emat
	{
		EXTfldval fvals[7];
		fvals[0].setLong( mIdent );
		fvals[1].setChar( pComponentLib );
		fvals[2].setChar( pComponentCtrl );
		fvals[3].setList( pProperties, qtrue );
		fvals[4].setLong(0);
		fvals[5].setLong(pWidth);
		fvals[6].setLong(pHeight);
		if (ECOsendEvent(mEventHwnd, cWPcreateXCompPluginEvent, &fvals[0], 7, qtrue))
		{
			mPluginCreated = qtrue;	// rmm10340
			#ifdef is64bit	// rmm8965
				HWND plugin = (HWND)fvals[4].getLong64();
			#else
				HWND plugin = (HWND)fvals[4].getLong();
			#endif
			if ( plugin )
			{
				WNDshowWindow( plugin, SW_HIDE );
				WNDsetParent( plugin, mHwnd );
				pWidth = fvals[5].getLong();
				pHeight = fvals[6].getLong();
			}
			return plugin;
		}
	}
	return 0;
}



void WPDocClass::sendHyperlinkEvent( WPLinkInfoStruct* pLinkInfo )
{
	str255 href(pLinkInfo->mHRef); // rmm10755
	if (!mPrinting && !mCodeAssistant) // mpm4700 // rmm_emat
	{
		fullPath(href);
		
		EXTfldval fvals[5];
		fvals[0].setLong( mIdent );
		fvals[1].setChar( href );
		fvals[2].setChar( pLinkInfo->mName );
		fvals[3].setChar( pLinkInfo->mTarget );
		fvals[4].setChar( pLinkInfo->mTitle );
		ECOsendEvent(mEventHwnd, cWPhyperlinkEvent, &fvals[0], 5, qtrue);
	}
	// Start rmm10755
	else if (mCodeAssistant)
	{
		fullPath(href, qtrue);
		WNDsendMessage(0, WM_CONTROL, OPEN_IDE_HELP, LPARAM(&href));
	}
	// End rmm10755
}


qbool WPDocClass::fontSizeAdj( qshort pFontSizeAdj )
{
	if ( pFontSizeAdj >= -3 && pFontSizeAdj <= 3 )
	{
		if ( pFontSizeAdj != mFontSizeAdj )
		{
			mFontSizeAdj = pFontSizeAdj;
			return qtrue;
		}
	}
	return qfalse;
}




// ###############################################################################
// ################# WPDocClass Protected ########################################
// ###############################################################################

void WPDocClass::checkSelRgn( qldim pHorzOff, qldim pVertOff )
{
	if ( mSelRgn )
	{
		qldim hdiff = pHorzOff - mSelRgnHOff;
		qldim vdiff = pVertOff - mSelRgnVOff;
		if ( hdiff || vdiff )
		{
			GDIoffsetRgn( mSelRgn, hdiff, vdiff );
			mSelRect.offset( hdiff, vdiff );
		}
	}
	mSelRgnHOff = pHorzOff;
	mSelRgnVOff = pVertOff;
}


void WPDocClass::push_( qlongptr pVal, qlong pSet, qlong pFlag ) // rmm64bitux
{
	mStackVal[mStackPtr] = pVal;
	mStackSet[mStackPtr] = pSet & pFlag;
	mStackType[mStackPtr] = pFlag;
	mStackPtr++;
}


qlongptr WPDocClass::pop_( qlong& pSet, qlong pFlag ) // rmm64bitux
{
	qlong stkptr = mStackPtr - 1;
	while ( stkptr >= 0 )
	{
		if ( mStackType[stkptr] == pFlag )
		{
			qlongptr val = mStackVal[stkptr]; // rmm64bitux
			pSet &= ~pFlag; pSet |= mStackSet[stkptr];
			mStackType[stkptr] = 0;
			if ( ( stkptr + 1 ) == mStackPtr )
			{
				while ( stkptr >= 0 && !mStackType[stkptr] ) stkptr--;
				mStackPtr = ++stkptr;
			}
			return val;
		}
		stkptr--;
	}
	return 0;
}


/* eof */















