/* $Header$ */

// base WP text object class implementation

/**************** Changes ******************
Date			Edit				Bug					Description
06-Oct-22	rmm11749		ST/WO/2704	Issues with HTML (docview) when printed to a report.
17-Mar-22	rmm11484								Improved appearance of HTML displayed by docview component.
19-Dec-17	rmm_emat								Text editor for Omnis language.
01-Sep-14	rmm8428			ST/EC/1346	HTML control printing issues.
20-Jul-07	rmm6171									Improved layout of properties and methods in online help - special Omnis alignment value.
12-Jun-06	rmm5813			ST/HP/070		Problem with word wrapping.
25-Oct-04	rmm5128									Crash caused by divide by zero.
16-Jan-04	rmm4831									Table borders were partly white on the Mac.
02 JUN 02 mpm5308			st/ec/742		Fixes problems with cells which span multiple rows and columns
27 MAR 02 mpm5094			st/ec/687		Fixes table problems when some rows have less cells than others
22 MAY 00	mpm4700									Implements printing of document
25-Jan-00	rmm3608			ST/EC/357		Fixed crash.
10 NOV 99 mlr0007									Fixed memory Leak
08 NOV 99 mlr0006									Added Rtf support
********************************************/

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

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

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

#include "htmlctrl.he"	// rmm11749

// ###############################################################################
// ################# WPTableCellClass definition #################################
// ###############################################################################


class WPTableCellClass : public WPObjectClass
{
	public:
		WPTableCellClass( WPObjectClass* pParent, WPDocClass* pDocumentObj );
		~WPTableCellClass();

		static	WPTableCellClass*	make( WPObjectClass* pParent, WPDocClass* pDocumentObj, WPTableCellInfoStruct* pTableCellInfo, qldim pCellPadding );
		static	void		paintBorder(WPTableComonInfoStruct* pInfo, WNDpaintStruct* pPaintStruct, qlrect* pRect);	// rmm11484: Removed inset appearance parameter

		virtual void		initData( WPObjInfoStruct* pObjInfo ,printInfo* pInfo);
		virtual void		addRowInfo( WPObjInfoStruct* pObjInfo );
		virtual void		addParaInfo( WPObjInfoStruct* pObjInfo );
		virtual void		paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff );
		virtual	qlong		message( WPObjInfoStruct* pObjInfo, eWPMessage pMessage, qldim pHorzOff, qldim pVertOff, LPARAM lParam1, LPARAM lParam2 );
		virtual qcol		getBackColor();
		
						void		initOffsets( qldim pHorzOffset, qldim pVertOffset );
						
						qshort	rowSpan() { return mTableCellInfo.mRowSpan; }
						qshort	colSpan()	{ return mTableCellInfo.mColSpan; }
						
						qldim		width()		{ return mCellRect.width(); }
						qldim		height()	{ return mCellRect.height(); }
						void		width( qldim pWidth ) { mCellRect.width( pWidth ); }
						void		height( qldim pHeight ) { mCellRect.height( pHeight ); }
		virtual qprierr addToPrintJob(  printInfo* pInfo,EXTCompInfo* eci,WPObjInfoStruct* pObjInfo ,qldim& pHorzOff, qldim& pVertOff); // mpm4700
		virtual qbool		tableCellWithNoWrap() { return mTableCellInfo.mNoWrap; } // rmm_emat

		WPTableCellInfoStruct		mTableCellInfo;
		qlrect									mCellRect;
		qlrect									mOwnerRect;
		qldim										mHorzOffset;
		qldim										mVertOffset;
		qldim										mCellPadding;
		qshort									mRow;
		qshort									mCol;
};


// ###############################################################################
// ################# WPTableCellClass Public #####################################
// ###############################################################################


WPTableCellClass::WPTableCellClass( WPObjectClass* pParent, WPDocClass* pDocumentObj )
								 :WPObjectClass( pParent, pDocumentObj )
{
}


WPTableCellClass::~WPTableCellClass()
{
}

// rmm4831: define macro for default light border colour, and use it in place of GDI_COLOR_3DLIGHT below
#ifdef iswin32
	#define WP_LIGHT_BORDER_COLOR GDI_COLOR_3DLIGHT
#else
	#define WP_LIGHT_BORDER_COLOR ((qcol) 0xe0e0e0)
#endif

WPTableCellClass*	WPTableCellClass::make( WPObjectClass* pParent, WPDocClass* pDocumentObj, WPTableCellInfoStruct* pTableCellInfo, qldim pCellPadding )
{
	WPTableCellClass* obj = new WPTableCellClass( pParent, pDocumentObj );
	obj->mCellPadding = pCellPadding;
	
	// initialize cell info
	obj->mTableCellInfo = *pTableCellInfo;
	WPTableCellInfoStruct& cellInfo = obj->mTableCellInfo;
	cellInfo.mBorderColorLight = ( cellInfo.mBorderColorLight == GDI_COLOR_QDEFAULT ? 
																	( cellInfo.mBorderColor == GDI_COLOR_QDEFAULT ? WP_LIGHT_BORDER_COLOR : cellInfo.mBorderColor ) : 
																	cellInfo.mBorderColorLight
																);
	cellInfo.mBorderColorDark = 	( cellInfo.mBorderColorDark == GDI_COLOR_QDEFAULT ? 
																	( cellInfo.mBorderColor == GDI_COLOR_QDEFAULT ? GDI_COLOR_3DSHADOW : cellInfo.mBorderColor ) : 
																	cellInfo.mBorderColorDark
																);
	
	return obj;
}


void WPTableCellClass::paintBorder( WPTableComonInfoStruct* pInfo, WNDpaintStruct* pPaintStruct, qlrect* pRect)	// rmm11484
{
	qrect r; pRect->conv( &r );
	qulong cnt = pInfo->mBorderSize;
	HDC& dc = pPaintStruct->hdc;
	if ( cnt )
	{
		// Start rmm11484: Use a hairline pen
		qpen theQpen(1, pInfo->mBorderColorDark, patFill, qtrue);
		HPEN pen = GDIcreatePen(&theQpen);
		HPEN savedPen = GDIselectObject(dc, pen);
		// End rmm11484
		for ( qulong cnt = pInfo->mBorderSize ; cnt ; cnt-- )
		{
			GDImoveTo( dc, r.left, r.bottom );
			GDIlineTo( dc, r.left, r.top );
			GDIlineTo( dc, r.right, r.top );
			GDIlineTo( dc, r.right, r.bottom );
			GDIlineTo( dc, r.left, r.bottom );
			GDIinsetRect( &r, 1, 1 );
		}
		GDIselectObject( dc, savedPen );
		GDIdeleteObject( pen ); // rmm11484
	}
	if ( pInfo->mBackColor != GDI_COLOR_QDEFAULT )
	{
		GDIsetTextColor( dc, pInfo->mBackColor );
		GDIfillRect( dc, &r, GDIgetStockBrush( BLACK_BRUSH ) );
	}
}


void WPTableCellClass::initData( WPObjInfoStruct* pObjInfo ,printInfo* pInfo)
{
	qldim minWidth = mCellPadding * 2 + 12;
	mCellRect = pObjInfo->mRowRect;
	if ( width() < minWidth ) width(minWidth);
	mOwnerRect = mCellRect;
	qldim inset = mTableCellInfo.mBorderSize + mCellPadding;
	mOwnerRect.inset( inset, inset );
	mOwnerRect.height( 0 );
	pObjInfo->mRowRect = mOwnerRect;
	pObjInfo->mOwnerRect = mOwnerRect;
	pObjInfo->mOwnerRect.width( 0 );
	pObjInfo->mOwnerRect.height( 0 );
	
	WPObjectClass::initData( pObjInfo,pInfo);
	
	// grow the cell rect if required
	mOwnerRect.unionRect( &mOwnerRect, &pObjInfo->mOwnerRect );
	if ( mOwnerRect.height() < 12 ) mOwnerRect.height(12);
	qldim min = mOwnerRect.width() + inset * 2;
	if ( min > width() ) width( min );
	min = mOwnerRect.height() + inset * 2;
	if ( mTableCellInfo.mHeight > min ) min = mTableCellInfo.mHeight;
	if ( min > height() ) height( min );
	
	//if ( mOwnerRect.right + inset > mCellRect.right ) mCellRect.right = mOwnerRect.right + inset;
	//if ( mOwnerRect.bottom + inset > mCellRect.bottom ) mCellRect.bottom = mOwnerRect.bottom + inset;
	
}


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


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


void WPTableCellClass::paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff )
{
	if ( firstChild() ) // only paint if we have any children
	{
		// paint border and background
		qlrect lr = mCellRect; lr.offset( pHorzOff, pVertOff );
		paintBorder( &mTableCellInfo, pPaintStruct, &lr);	// rmm11484
		
		// paint children
		pHorzOff += mCellRect.left + mHorzOffset;
		pVertOff += mCellRect.top + mVertOffset;
		WPObjectClass::paint( pObjInfo, pPaintStruct, pHorzOff, pVertOff );
	}
}


qlong WPTableCellClass::message( WPObjInfoStruct* pObjInfo, eWPMessage pMessage, qldim pHorzOff, qldim pVertOff, LPARAM lParam1, LPARAM lParam2 )
{
	qlrect lr = mCellRect; lr.offset( pHorzOff, pVertOff );
	if ( pMessage == eWPMessFindPt && !lr.ptInRect( (qpoint*)lParam1 ) ) return 0L;
	pHorzOff += mCellRect.left + mHorzOffset;
	pVertOff += mCellRect.top + mVertOffset;
	qlong result = WPObjectClass::message( pObjInfo, pMessage, pHorzOff, pVertOff, lParam1, lParam2 );
	if ( pMessage == eWPMessGetCharRange && !result )
	{
		WPgetCharRangeStruct* charRangeInfo = (WPgetCharRangeStruct*)lParam1;
		qpoint pt; pt.h = charRangeInfo->mSelRect.right; pt.v = charRangeInfo->mSelRect.bottom;
		if ( lr.ptInRect( &pt ) ) result = 1L;
	}
	else if ( pMessage == eWPMessCopyCharRange )
	{
		WPgetCharRangeStruct* charRangeInfo = (WPgetCharRangeStruct*)lParam1;
		qrect r; lr.conv( &r );
		if ( GDIrectInRegion( charRangeInfo->mSelRgn, &r ) )
		{
			EXTfldval* fldval = (EXTfldval*)lParam2;
			WPTableClass* table = (WPTableClass*)mParent;
			if ( table->colCnt() == mCol ) fldval->concat( (qchar)13 );
		}
	}
	return result;
}


qcol WPTableCellClass::getBackColor()
{
	if ( mTableCellInfo.mBackColor == GDI_COLOR_QDEFAULT )
		return WPObjectClass::getBackColor();
	else
		return mTableCellInfo.mBackColor;
}


void WPTableCellClass::initOffsets( qldim pHorzOffset, qldim pVertOffset )
{
	mCellRect.offset( pHorzOffset, pVertOffset );
	qldim inset = ( mTableCellInfo.mBorderSize + mCellPadding ) * 2;
	mHorzOffset = mVertOffset = 0;
	switch ( mTableCellInfo.mHAlign )
	{
		case eWPHAcenter:
			mHorzOffset = ( width() - mOwnerRect.width() - inset ) / 2;
			break;
		case eWPHAright:
			mHorzOffset = width() - mOwnerRect.width() - inset;
			break;
	}
	switch ( mTableCellInfo.mVAlign )
	{
		case eWPVAmiddle:
			mVertOffset = ( height() - mOwnerRect.height() - inset ) / 2;
			break;
		case eWPVAbottom:
		case eWPVAbaseline:
			mVertOffset = height() - mOwnerRect.height() - inset;
			break;
	}
}

qprierr WPTableCellClass::addToPrintJob( printInfo* pInfo, EXTCompInfo* eci, WPObjInfoStruct* pObjInfo, // mpm4700
																					qldim& pHorzOff, qldim& pVertOff )
{
	qprierr err = PRI_ERR_NONE;
	pInfo->mObj->mData = NULL ;
	qcol backcolor = getBackColor();
	if ( backcolor == GDI_COLOR_QDEFAULT ) backcolor = GDI_COLOR_QWHITE;
	{
		PRIobjectStruct obj = *pInfo->mObj;
		obj.mType = PRI_OBJ_RECT ;
		if (mTableCellInfo.mBorderSize > 0)
		{
			obj.mBorder.set(WND_BORD_PLAIN, qpen(mTableCellInfo.mBorderSize, mTableCellInfo.mBorderColor));
			obj.mFillPat = patFill; // rmm11749
		}
		else
		{
			obj.mBorder.set(WND_BORD_NONE, qpen(0, colBlack, patTransparent));	// rmm8428
			obj.mFillPat = (colWhite == backcolor) ? patTransparent : patFill;	// rmm11749
		}
		obj.mBackFillColor = backcolor;
		obj.mForeFillColor = backcolor;
		qlrect tmpRect = mCellRect;
		tmpRect.offset( pHorzOff, pVertOff );
		tmpRect.convto( &obj.mPos );
		err = tqfWPObject::doPRIaddObject( pInfo->mJob, &obj );
	}
	if ( !err && firstChild() ) // only print if we have any children
	{
		qldim horzOffset = pHorzOff + mCellRect.left + mHorzOffset;
		qldim vertOffset = pVertOff + mCellRect.top + mVertOffset;
		qldim old = vertOffset;
		err = WPObjectClass::addToPrintJob(pInfo,eci,pObjInfo,horzOffset,vertOffset );
		if ( vertOffset > old ) pVertOff += vertOffset-old;
	}
	return err;
}

// ###############################################################################
// ################# WPTableClass Public #########################################
// ###############################################################################


WPTableClass::WPTableClass( WPObjectClass* pParent, WPDocClass* pDocumentObj )
						:WPObjectClass( pParent, pDocumentObj )
{
	mRowCnt = mColCnt = mCellsAlloc = mCurRow = mCurCol = 0;
	mCells = 0;
}


WPTableClass::~WPTableClass()
{
	if ( mCellsAlloc ) //mlr007
	{
		delete [] mCells;
		mCellsAlloc = 0 ;
		mCells = NULL ;
	}
}


WPTableClass* WPTableClass::make( WPObjectClass* pParent, WPDocClass* pDocumentObj, WPTableInfoStruct* pTableInfo )
{
	WPTableClass* obj = new WPTableClass( pParent, pDocumentObj );
	
	// initilize table info
	obj->mTableInfo = *pTableInfo;
	WPTableInfoStruct& tableInfo = obj->mTableInfo;
	tableInfo.mBorderColorLight = ( tableInfo.mBorderColorLight == GDI_COLOR_QDEFAULT ? 
																	( tableInfo.mBorderColor == GDI_COLOR_QDEFAULT ? WP_LIGHT_BORDER_COLOR : tableInfo.mBorderColor ) : 
																	tableInfo.mBorderColorLight
																);
	tableInfo.mBorderColorDark = 	( tableInfo.mBorderColorDark == GDI_COLOR_QDEFAULT ? 
																	( tableInfo.mBorderColor == GDI_COLOR_QDEFAULT ? GDI_COLOR_3DSHADOW : tableInfo.mBorderColor ) : 
																	tableInfo.mBorderColorDark
																);

	return obj;
}


void WPTableClass::initData( WPObjInfoStruct* pObjInfo,printInfo* pInfo )
{
	if ( mParent ) mParent->newPara( pObjInfo );
	if ( mTableInfo.mWidth < 0 )
		pObjInfo->mOwnerRect.width( pObjInfo->mRowRect.width() * (-mTableInfo.mWidth) / 100 );
	else
		pObjInfo->mOwnerRect.width( mTableInfo.mWidth );
		
	pObjInfo->mOwnerRect.height( 12 + mTableInfo.mCellSpacing*2 + mTableInfo.mCellPadding*2 );
	
	// intialize all the cells by column
	qldim cellHSpace = pObjInfo->mOwnerRect.width() - ( mTableInfo.mCellSpacing * ( mColCnt + 1 ) ) - mTableInfo.mBorderSize * 2;
	
	WPObjInfoStruct rowInfo;
	rowInfo.mRowRect.left = 0;
	rowInfo.mRowRect.top = 0;
	rowInfo.mRowRect.bottom = -1;
	rowInfo.mNoWrap = qfalse;
	
	// initialize all cells once and remember the width for each column
	WPTableCellClass* cell; qbool isPrimary;
	qldim* colWidths = new qldim[mColCnt+1]; MEMmemFillByte( colWidths, (mColCnt+1)*sizeof(qldim), 0 );
	qldim* maxWidths = new qldim[mColCnt+1]; MEMmemFillByte( maxWidths, (mColCnt+1)*sizeof(qldim), 0 );
	qldim* rowHeights = new qldim[mRowCnt+1]; MEMmemFillByte( rowHeights, (mRowCnt+1)*sizeof(qldim), 0 );
	qshort row, col;
	// mpm5308 begins
	// calculate an average max width based on all true cells of a row 
	qshort totRealCols = 0;
	for ( row = 1 ; row <= mRowCnt ; row++ )
	{
		qshort realCols = 0;
		for ( col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( isPrimary ) { realCols++; maxWidths[col] = 1; }
		}
		if ( realCols > totRealCols ) totRealCols = realCols;
	}
	qldim avMaxWidth = cellHSpace / (totRealCols ? totRealCols : 1); // rmm5128: prevent divide by zero crash
	// Start rmm6171: Omnis alignment sizes the columns using the text (designed for properties etc in online help)
	if (eWPHAomnis == mTableInfo.mHAlign)
	{
		for ( col = 1 ; col <= mColCnt ; col++ ) maxWidths[col] = 1;
	}
	else
	{
		// End rmm6171
		for ( col = 1 ; col <= mColCnt ; col++ ) maxWidths[col] = avMaxWidth * maxWidths[col];
	}
	// mpm5308 ends

	for ( row = 1 ; row <= mRowCnt ; row++ )
	{
		for ( col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				rowInfo.mOwner = cell;
				rowInfo.mRowRect.setEmpty();
				rowInfo.mOwnerRect = rowInfo.mRowRect;
				rowInfo.mNoWrap = qtrue;
				cell->initData( &rowInfo,pInfo);
				if ( cell->colSpan() == 1 )
				{
					if ( maxWidths[col] < cell->width() ) maxWidths[col] = cell->width();
				}
				
				rowInfo.mNoWrap = qfalse;
				rowInfo.mRowRect.setEmpty();
				qldim width = cell->mTableCellInfo.mWidth;
				if ( !width ) width = 12;
				if ( width < 0 )
					rowInfo.mRowRect.width( cellHSpace * (-width) / 100 );
				else
					rowInfo.mRowRect.width( width );
				rowInfo.mOwnerRect = rowInfo.mRowRect;
				cell->initData( &rowInfo,pInfo);
				if ( cell->colSpan() == 1 )
				{
					if ( colWidths[col] < cell->width() ) colWidths[col] = cell->width();
				}
			}
		}
	}
	
	// if we have space over, distribute it amongst the columns
	qldim totWidth = 0, totMaxWidth = 0;
	for ( col = 1 ; col <= mColCnt ; col++ ) { totWidth += colWidths[col]; totMaxWidth += maxWidths[col]; }
	if (!totMaxWidth) totMaxWidth = 1;	// rmm5128: prevent divide by zero crash
	if ( totWidth < cellHSpace )
	{
		qldim spare = cellHSpace - totWidth;
		if (eWPHAomnis != mTableInfo.mHAlign) // rmm6171
		{
			for ( qshort col = 1 ; col <= mColCnt ; col++ ) colWidths[col] += spare * maxWidths[col] / totMaxWidth;
		}
		else
		{
			// rmm6171: Give space over to last column, for Omnis alignment
			colWidths[mColCnt] += spare;
		}
	}
	
	// now establish col widths from cells which span more then 1 column or row
	for ( row = 1 ; row <= mRowCnt ; row++ )	// PKHTML
	{
		for ( col = 1 ; col <= mColCnt ; col++ )	//PKHTML
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary && cell->colSpan() > 1 )
			{
				totWidth = -mTableInfo.mCellSpacing;
				qshort span = cell->colSpan();
				while ( span )
				{
					span--;
					totWidth += colWidths[col+span] + mTableInfo.mCellSpacing;
				}
				qldim adj = cell->width() - totWidth;
				span = cell->colSpan();
				if ( adj > 0 ) while ( span )
				{
					qldim adj2 = adj / span;
					span--;
					colWidths[col+span] += adj2;
					adj -= adj2;
				}
			}
		}
	}
	
	// now intialize cells who's width differs, a second time // rmm5813: see below
	// at the same time build row heights of cells which only span 1 row
	for ( row = 1 ; row <= mRowCnt ; row++ )		// PKHTML
	{
		for ( col = 1 ; col <= mColCnt ; col++ )	// PKHTML
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				qldim width;
				if ( cell->colSpan() == 1 )
					width = colWidths[col];
				else
				{
					width = -mTableInfo.mCellSpacing;
					qshort span = cell->colSpan();
					while ( span )
					{
						span--;
						width += colWidths[col+span] + mTableInfo.mCellSpacing;
					}
				}
				// rmm5813: always do this, to force subsequent lines in the cell to word-wrap: if ( cell->width() != width )
				{
					rowInfo.mOwner = cell;
					rowInfo.mRowRect.setEmpty();
					rowInfo.mRowRect.width( width );
					cell->initData( &rowInfo,pInfo);
				}
				if ( cell->height() > rowHeights[row] ) rowHeights[row] = cell->height();
			}
		}
	}	
	
	// now we can deal with row heights of cells which span more then 1 row
	for ( row = 1 ; row <= mRowCnt ; row++ )  // PKHTML
	{
		for ( col = 1 ; col <= mColCnt ; col++ )		// PKHTML
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary && cell->rowSpan() > 1 )
			{
				qldim totHeight = -mTableInfo.mCellSpacing;
				qshort span = cell->rowSpan();
				while ( span )
				{
					span--;
					totHeight += rowHeights[row+span] + mTableInfo.mCellSpacing;
				}
				qldim adj = cell->height() - totHeight;
				span = cell->rowSpan();
				if ( adj > 0 ) while ( span )
				{
					qldim adj2 = adj / span;
					span--;
					rowHeights[row+span] += adj2;
					adj -= adj2;
				}
			}
		}
	}
	
	// now set the correct height for each cell
	// at the same time initialize the cells offsets
	qldim voff = 0;
	for ( row = 1 ; row <= mRowCnt ; row++ )		// PKHTML
	{
		qldim hoff = 0;
		for ( col = 1 ; col <= mColCnt ; col++ )		// PKHTML
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				qldim height;
				if ( cell->rowSpan() == 1 )
					height = rowHeights[row];
				else
				{
					height = -mTableInfo.mCellSpacing;
					qshort span = cell->rowSpan();
					while ( span )
					{
						span--;
						height += rowHeights[row+span] + mTableInfo.mCellSpacing;
					}
				}
				cell->height( height );
				cell->initOffsets( hoff, voff );
			}
			hoff += colWidths[col] + mTableInfo.mCellSpacing;
		}
		voff += rowHeights[row] + mTableInfo.mCellSpacing;
	}	
	
	// set the tables overall size
	qldim width = mTableInfo.mCellSpacing + mTableInfo.mBorderSize * 2;
	qldim height = mTableInfo.mCellSpacing + mTableInfo.mBorderSize * 2;
	for ( col = 1 ; col <= mColCnt ; col++ ) width += colWidths[col] + mTableInfo.mCellSpacing;  // PKHTML
	for (	row = 1 ; row <= mRowCnt ; row++ ) height += rowHeights[row] + mTableInfo.mCellSpacing;	// PKHTML
	pObjInfo->mOwnerRect.width( width );
	pObjInfo->mOwnerRect.height( height);
	
	delete [] colWidths;
	delete [] maxWidths;
	delete [] rowHeights;
	
	// deal with alignment
	qldim remainder = pObjInfo->mRowRect.width() - pObjInfo->mOwnerRect.width();
	if ( remainder > 0 ) switch ( mTableInfo.mHAlign )
	{
		case eWPHAcenter:
			pObjInfo->mOwnerRect.offset( remainder / 2, 0 );
			break;
		case eWPHAright:
			pObjInfo->mOwnerRect.offset( remainder, 0 );
			break;
	}
	
	mOwnerRect = pObjInfo->mOwnerRect;
	if ( mParent )
	{
		mParent->addParaInfo( pObjInfo );
		mParent->newPara( pObjInfo );
	}
}


void WPTableClass::paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff )
{
	// paint border and background
	qlrect lr = mOwnerRect; lr.offset( pHorzOff, pVertOff );
	WPTableCellClass::paintBorder( &mTableInfo, pPaintStruct, &lr );

	// paint the cells
	pHorzOff += mOwnerRect.left + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	pVertOff += mOwnerRect.top + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	
	WPTableCellClass* cell; qbool isPrimary;
	for ( qshort row = 1 ; row <= mRowCnt ; row++ )
	{
		for ( qshort col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary ) cell->paint( pObjInfo, pPaintStruct, pHorzOff, pVertOff );
		}
	}
}


qldim WPTableClass::getMinWidth() // mpm4700
{
	return mOwnerRect.width() + mOwnerRect.left;
}


static qshort sSecID = 0;
qprierr WPTableClass::addToPrintJob(  printInfo* pInfo, EXTCompInfo* eci, WPObjInfoStruct* pObjInfo, // mpm4700
																			qldim& pHorzOff, qldim& pVertOff)
{
	qldim horzOffset = pHorzOff, vertOffset = pVertOff;
	qprierr err = PRI_ERR_NONE;
	PRIsectionStruct secInfo(qnil);
	if ( mTableInfo.mBorderSize > 0 )
	{
		sSecID++;
		secInfo.mIdent = sSecID;
		secInfo.mPos = pInfo->mObj->mPos;
		secInfo.mFloatBottom = qtrue;
		qlrect tmpRect = mOwnerRect;
		tmpRect.offset( horzOffset, vertOffset );
		tmpRect.convto( &secInfo.mPos );
		err = PRIcreateSection( pInfo->mJob, &secInfo );
		if ( !err )
		{
			PRIobjectStruct obj = *pInfo->mObj;
			obj.mType = PRI_OBJ_BORDER ;
			obj.mBorder.set(WND_BORD_PLAIN,qpen(mTableInfo.mBorderSize,mTableInfo.mBorderColor),mTableInfo.mBorderSize,0,mTableInfo.mBorderColor) ;
			obj.mForeFillColor = GDI_COLOR_QWHITE;
			obj.mBackFillColor = GDI_COLOR_QWHITE;
			obj.mFillPat = patFill; // mpm4700
			obj.mFloatBottom = qtrue;
			tmpRect.offset( -tmpRect.left, -tmpRect.top );
			tmpRect.convto( &obj.mPos );
			obj.mPos.mMode = ePosSection;
			obj.mPos.mSectID = secInfo.mIdent;
			err = tqfWPObject::doPRIaddObject( pInfo->mJob, &obj );
		}
	}	
	horzOffset += mOwnerRect.left + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	vertOffset += mOwnerRect.top + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	pInfo->mObj->mBackFillColor=getBackColor();
	
	WPTableCellClass* cell; qbool isPrimary; qpridim theOff = 0;
	if (!err) for ( qshort row = 1 ; row <= mRowCnt ; row++ )
	{
		qlrect tmpRect; qbool isfirst = qtrue; qshort col;
		for ( col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				if ( isfirst )
					tmpRect = cell->mCellRect;
				else
					tmpRect.unionRect( &tmpRect, &cell->mCellRect );
			}
		}
		qpripos pos = pInfo->mObj->mPos;
		tmpRect.offset( horzOffset, vertOffset );
		tmpRect.convto( &pos );
		
		PRIconvPos( pInfo->mJob, &pos, ePosLocal );
		if ( pos.mMode == ePosLocal )
		{
			qpripos pos2 = pos;
			PRIconvPos( pInfo->mJob, &pos2, eBndsLocal );
			if ( pos.bottom > pos2.bottom )
			{
				qpridim off = pos2.bottom - pos.top + 1;
				theOff += off; vertOffset += PRIconvToScreen( off, qtrue );
			}
		}
		
		for ( col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				qldim old = vertOffset;
				err = cell->addToPrintJob(pInfo ,eci, pObjInfo, horzOffset, vertOffset);
				if ( vertOffset > old )
				{
					theOff += PRIconvFromScreen( qdim(vertOffset - old), qtrue );
				}
			}
			if ( err >= PRI_ERR_MANAGER_CLOSED ) break;
		}
	}
	
	if ( secInfo.mIdent )
	{
		if (theOff) PRIgrowSection( pInfo->mJob, secInfo.mIdent, 0, theOff );
		PRIdeleteSection( pInfo->mJob, secInfo.mIdent );
	}
	if ( theOff ) pVertOff += PRIconvToScreen( theOff, qtrue );
	return err;
}


qlong WPTableClass::message( WPObjInfoStruct* pObjInfo, eWPMessage pMessage, qldim pHorzOff, qldim pVertOff, LPARAM lParam1, LPARAM lParam2 )
{
	qlong result = 0;
	pHorzOff += mOwnerRect.left + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	pVertOff += mOwnerRect.top + mTableInfo.mBorderSize + mTableInfo.mCellSpacing;
	WPTableCellClass* cell; qbool isPrimary;
	for ( qshort row = 1 ; row <= mRowCnt ; row++ )
	{
		for ( qshort col = 1 ; col <= mColCnt ; col++ )
		{
			cell = getCell( row, col, isPrimary );
			if ( cell && isPrimary )
			{
				if ((result = cell->message( pObjInfo, pMessage, pHorzOff, pVertOff, lParam1, lParam2 )) != 0) return result;
			}
		}
	}
	return result;
}


qcol WPTableClass::getBackColor()
{
	if ( mTableInfo.mBackColor == GDI_COLOR_QDEFAULT )
		return WPObjectClass::getBackColor();
	else
		return mTableInfo.mBackColor;
}


WPObjectClass* WPTableClass::addCell( WPTableCellInfoStruct* pTableCellInfo, qbool pStartNewRow )
{
	if ( pStartNewRow )
	{
		mCurRow++; mCurCol = 0;
	}
	mCurCol++;

	// do we need to increase array size?
	// take into account rowspan and colspan
	if ( ! allocCells( mCurRow + pTableCellInfo->mRowSpan - 1, mCurCol + pTableCellInfo->mColSpan - 1 ) )
		return 0;

	// check if we can have the cell
	qbool isPrimary;
	WPTableCellClass* cell = getCell( mCurRow, mCurCol, isPrimary );
	if ( cell )
	{	// cell is occupied
		return addCell( pTableCellInfo, qfalse );
	}
	else
	{
		cell = WPTableCellClass::make( this, mDocumentObj, pTableCellInfo, mTableInfo.mCellPadding );
		cell->mRow = mCurRow; cell->mCol = mCurCol; // set row and column of the beginning of the cell
		// mpm5308 begins
		for ( qshort row = 0 ; row < cell->rowSpan() ; row ++ )
		{
			for ( qshort col = 0 ; col < cell->colSpan() ; col ++ )
			{
				setCell( mCurRow + row, mCurCol + col, cell );
			}
		}
		if ( cell->colSpan() > 1 ) mCurCol += ( cell->colSpan() - 1 );
		// mpm5308 ends
		return cell;
	}
}


qbool WPTableClass::allocCells( qshort pRow, qshort pCol )
{ // mpm5094 begins
	if ( pCol < mColCnt ) pCol = mColCnt;
	if ( pRow < mRowCnt ) pRow = mRowCnt;
	qshort needed = pRow * pCol;
	if ( needed > mCellsAlloc || pCol > mColCnt )
	{
		needed+=10;
		WPTableCellClass** cells = new WPTableCellClass*[needed];
		if ( cells )
		{
			MEMmemFillByte( cells, needed*sizeof(WPTableCellClass*), 0 );
			if ( mCellsAlloc )
			{
				for ( qshort row = 0 ; row < mRowCnt ; row++ )
				{
					for ( qshort col = 0; col < mColCnt ; col++ )
					{
						cells[row*pCol+col] = mCells[row*mColCnt+col];
					}
				}
				delete [] mCells;
			}
			mCells = cells;
			mCellsAlloc = needed;
		}
		else
		{
			return qfalse;
		}
	}
	mRowCnt = pRow;
	mColCnt = pCol;
	return qtrue;
} // mpm5094 ends


WPTableCellClass* WPTableClass::getCell( qshort pRow, qshort pCol, qbool& pIsPrimary )
{
	WPTableCellClass* cell = mCells[(pRow-1)*mColCnt+pCol-1];
	if ( cell )
	{
		pIsPrimary = cell->mRow == pRow && cell->mCol == pCol;
	}
	return cell;
}


/* eof */






