/******************************************************************************
 JXStyleTable.cc

	Stores font and style information for JXEditTable.  The font and size
	are restricted to be table-wide, while the style can be changed for
	each cell.

	BASE CLASS = JXEditTable

	Copyright © 1996-97 by John Lindal. All rights reserved.

 ******************************************************************************/

#include <JXStyleTable.h>
#include <JXStyleTableThunksTask.h>
#include <JXInputField.h>
#include <JXColormap.h>
#include <jXConstants.h>
#include <jXGlobals.h>
#include <JFontManager.h>
#include <JString.h>
#include <jAssert.h>

const JSize kDefaultFontSize = kJXDefaultFontSize;

const JCoordinate kDefColWidth  = 100;
const JCoordinate kVMarginWidth = 1;

/******************************************************************************
 Constructor

 ******************************************************************************/

JXStyleTable::JXStyleTable
	(
	JXScrollbarSet*		scrollbarSet,
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXEditTable(1,kDefColWidth, scrollbarSet, enclosure,
				hSizing,vSizing, x,y, w,h)
{
	itsFontName = new JString;
	assert( itsFontName != NULL );

	itsStyleData = new JAuxTableData<JFontStyle>(this, JFontStyle());
	assert( itsStyleData != NULL );

	SetFont(JGetDefaultFontName(), kDefaultFontSize);

	itsProcessMessagesFlag = kTrue;
//	ListenTo(this);		// egcs thunks
	ListenTo(itsStyleData);

	// work-around for egcs thunks bug

	JXStyleTableThunksTask* task = new JXStyleTableThunksTask(this);
	assert( task != NULL );
	(JXGetApplication())->InstallUrgentTask(task);
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JXStyleTable::~JXStyleTable()
{
	UpdateAllColors(kFalse);

	delete itsFontName;
	delete itsStyleData;
}

/******************************************************************************
 SetFont

 ******************************************************************************/

void
JXStyleTable::SetFont
	(
	const JCharacter*	name,
	const JSize			size
	)
{
	*itsFontName = name;
	itsFontSize  = size;

	const JSize rowHeight = 2*kVMarginWidth +
		(GetFontManager())->GetLineHeight(*itsFontName, itsFontSize, JFontStyle());
	SetDefaultRowHeight(rowHeight);
	SetAllRowHeights(rowHeight);
	TableRefresh();

	JXInputField* input = NULL;
	if (GetXInputField(&input))
		{
		input->SetFontName(name);
		input->SetFontSize(size);
		}

	FontChanged(*itsFontName, itsFontSize);
}

/******************************************************************************
 FontChanged (virtual protected)

	Called after font has been changed.  The default is to do nothing.

 ******************************************************************************/

void
JXStyleTable::FontChanged
	(
	const JString&	name,
	const JSize		size
	)
{
}

/******************************************************************************
 SetCellStyle

 ******************************************************************************/

void
JXStyleTable::SetCellStyle
	(
	const JPoint&		cell,
	const JFontStyle&	style
	)
{
	const JFontStyle origStyle = GetCellStyle(cell);
	if (style != origStyle)
		{
		if (style.color != origStyle.color)
			{
			JXColormap* colormap = GetColormap();
			colormap->DeallocateColor(origStyle.color);
			colormap->UsingColor(style.color);
			}

		itsStyleData->SetElement(cell, style);

		JPoint editCell;
		JXInputField* input = NULL;
		if (GetEditedCell(&editCell) && editCell == cell &&
			GetXInputField(&input))
			{
			input->SetFontStyle(style);
			}

		CellStyleChanged(cell, style);
		}
}

/******************************************************************************
 CellStyleChanged (virtual protected)

	Called after cell style has been changed.  The default is to do nothing.

 ******************************************************************************/

void
JXStyleTable::CellStyleChanged
	(
	const JPoint&		cell,
	const JFontStyle&	style
	)
{
}

/******************************************************************************
 Receive (virtual protected)

	We ignore RectChanged because we handle it in SetCellStyle().

 ******************************************************************************/

void
JXStyleTable::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	// row created

	if (itsProcessMessagesFlag &&
		sender == itsStyleData && message.Is(JTableData::kRowInserted))
		{
		const JTableData::RowInserted* info =
			dynamic_cast(const JTableData::RowInserted*, &message);
		assert( info != NULL );
		UpdateRowColors(info->GetIndex(), kTrue);
		}

	else if (itsProcessMessagesFlag &&
			 sender == itsStyleData && message.Is(JTableData::kRowDuplicated))
		{
		const JTableData::RowDuplicated* info =
			dynamic_cast(const JTableData::RowDuplicated*, &message);
		assert( info != NULL );
		UpdateRowColors(info->GetNewIndex(), kTrue);
		}

	// column created

	else if (itsProcessMessagesFlag &&
			 sender == itsStyleData && message.Is(JTableData::kColInserted))
		{
		const JTableData::ColInserted* info =
			dynamic_cast(const JTableData::ColInserted*, &message);
		assert( info != NULL );
		UpdateColColors(info->GetIndex(), kTrue);
		}

	else if (itsProcessMessagesFlag &&
			 sender == itsStyleData && message.Is(JTableData::kColDuplicated))
		{
		const JTableData::ColDuplicated* info =
			dynamic_cast(const JTableData::ColDuplicated*, &message);
		assert( info != NULL );
		UpdateColColors(info->GetNewIndex(), kTrue);
		}

	// something about to be removed

	else if (itsProcessMessagesFlag &&
			 sender == this && message.Is(JTable::kPrepareForTableDataMessage))
		{
		const JTable::PrepareForTableDataMessage* info =
			dynamic_cast(const JTable::PrepareForTableDataMessage*, &message);
		assert( info != NULL );
		const Message& nextMessage = info->GetMessage();

		// rows

		if (nextMessage.Is(JTableData::kRowRemoved))
			{
			const JTableData::RowRemoved* nextInfo =
				dynamic_cast(const JTableData::RowRemoved*, &nextMessage);
			assert( nextInfo != NULL );
			UpdateRowColors(nextInfo->GetIndex(), kFalse);
			}

		else if (nextMessage.Is(JTableData::kAllRowsRemoved))
			{
			UpdateAllColors(kFalse);
			}

		// columns

		else if (nextMessage.Is(JTableData::kColRemoved))
			{
			const JTableData::ColRemoved* nextInfo =
				dynamic_cast(const JTableData::ColRemoved*, &nextMessage);
			assert( nextInfo != NULL );
			UpdateColColors(nextInfo->GetIndex(), kFalse);
			}

		else if (nextMessage.Is(JTableData::kAllColsRemoved))
			{
			UpdateAllColors(kFalse);
			}
		}

	// new JTableData object

	else if (sender == this && message.Is(JTable::kPrepareForTableDataChange))
		{
		itsProcessMessagesFlag = kFalse;
		UpdateAllColors(kFalse);
		// This is safe because everything is reset to the default color.
		}
	else if (sender == this && message.Is(JTable::kTableDataChanged))
		{
		UpdateAllColors(kTrue);
		itsProcessMessagesFlag = kTrue;
		}

	// always pass down our own messages

	JXEditTable::Receive(sender, message);
}

/******************************************************************************
 UpdateAllColors (private)

 ******************************************************************************/

void
JXStyleTable::UpdateAllColors
	(
	const JBoolean allocate
	)
{
	JXColormap* colormap              = GetColormap();
	const JRunArray<JFontStyle>& data = itsStyleData->GetData();
	const JSize runCount              = data.GetRunCount();
	for (JIndex i=1; i<=runCount; i++)
		{
		const JFontStyle& style = data.GetRunDataRef(i);
		const JSize runLength   = data.GetRunLength(i);
		for (JIndex j=1; j<=runLength; j++)
			{
			if (allocate)
				{
				colormap->UsingColor(style.color);
				}
			else
				{
				colormap->DeallocateColor(style.color);
				}
			}
		}
}

/******************************************************************************
 UpdateRowColors (private)

 ******************************************************************************/

void
JXStyleTable::UpdateRowColors
	(
	const JIndex	rowIndex,
	const JBoolean	allocate
	)
{
	JXColormap* colormap = GetColormap();
	const JSize colCount = GetColCount();
	for (JIndex i=1; i<=colCount; i++)
		{
		const JFontStyle style = GetCellStyle(JPoint(i, rowIndex));
		if (allocate)
			{
			colormap->UsingColor(style.color);
			}
		else
			{
			colormap->DeallocateColor(style.color);
			}
		}
}

/******************************************************************************
 UpdateColColors (private)

 ******************************************************************************/

void
JXStyleTable::UpdateColColors
	(
	const JIndex	colIndex,
	const JBoolean	allocate
	)
{
	JXColormap* colormap = GetColormap();
	const JSize rowCount = GetRowCount();
	for (JIndex i=1; i<=rowCount; i++)
		{
		const JFontStyle style = GetCellStyle(JPoint(colIndex, i));
		if (allocate)
			{
			colormap->UsingColor(style.color);
			}
		else
			{
			colormap->DeallocateColor(style.color);
			}
		}
}
