/******************************************************************************
 JXEditTable.cc

	We implement most of the routines required to use JTable's editing
	mechanism for in-place editing.  To use these routines, a derived class
	only needs to override JTable::ExtractInputData() and the following
	routines:

		CreateXInputField
			Create an input field to edit the specified cell and return
			the object as a JXInputField.

		DeleteXInputField
			Delete the active input field.

	BASE CLASS = JXTable

	Copyright © 1996 by John Lindal. All rights reserved.

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

#include <JXEditTable.h>
#include <JXWindow.h>
#include <JXInputField.h>
#include <jXEventUtil.h>
#include <jXKeysym.h>
#include <jASCIIConstants.h>
#include <jAssert.h>

/******************************************************************************
 Constructor (protected)

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

JXEditTable::JXEditTable
	(
	const JCoordinate	defRowHeight,
	const JCoordinate	defColWidth,
	JXScrollbarSet*		scrollbarSet,
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXTable(defRowHeight, defColWidth, scrollbarSet,
			enclosure, hSizing, vSizing, x,y, w,h)
{
	itsInputField      = NULL;
	itsEditMenuHandler = NULL;
	WantInput(kTrue, kTrue);		// tab moves to next column
	SetBackColor(GetFocusColor());	// remain white when input has focus
}

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

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

JXEditTable::~JXEditTable()
{
}

/******************************************************************************
 IsEditable (virtual)

	Derived classes should override this if there are some cells that
	cannot be edited.

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

JBoolean
JXEditTable::IsEditable
	(
	const JPoint& cell
	)
	const
{
	return kTrue;
}

/******************************************************************************
 CreateInputField (virtual protected)

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

JBoolean
JXEditTable::CreateInputField
	(
	const JPoint&	cell,
	const JRect&	cellRect
	)
{
	itsInputField = CreateXInputField(cell, cellRect.left, cellRect.top,
									  cellRect.width(), cellRect.height());
	assert( itsInputField != NULL );
	itsInputField->SetTable(this);
	itsInputField->SetFocusColor(GetFocusColor());

	if (itsEditMenuHandler != NULL && itsEditMenuHandler->HasEditMenu())
		{
		itsInputField->ShareEditMenu(itsEditMenuHandler, kFalse, kFalse);
		}

	if (itsInputField->Focus())
		{
		return kTrue;
		}
	else
		{
		DeleteInputField();
		return kFalse;
		}
}

/******************************************************************************
 DeleteInputField (virtual protected)

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

void
JXEditTable::DeleteInputField()
{
	if (itsInputField != NULL)
		{
		DeleteXInputField();
		itsInputField = NULL;
		}
}

/******************************************************************************
 Adjusting the input field (virtual protected)

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

void
JXEditTable::PlaceInputField
	(
	const JCoordinate x,
	const JCoordinate y
	)
{
	assert( itsInputField != NULL );
	itsInputField->Place(x,y);
}

void
JXEditTable::MoveInputField
	(
	const JCoordinate dx,
	const JCoordinate dy
	)
{
	assert( itsInputField != NULL );
	itsInputField->Move(dx,dy);
}

void
JXEditTable::SetInputFieldSize
	(
	const JCoordinate w,
	const JCoordinate h
	)
{
	assert( itsInputField != NULL );
	itsInputField->SetSize(w,h);
}

void
JXEditTable::ResizeInputField
	(
	const JCoordinate dw,
	const JCoordinate dh
	)
{
	assert( itsInputField != NULL );
	itsInputField->AdjustSize(dw,dh);
}

/******************************************************************************
 HandleKeyPress (virtual)

	Return - move down, TAB - move right, shift - opposite direction

	Meta: arrows or keypad numbers move in obvious directions

	Meta-Return: EndEditing()

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

void
JXEditTable::HandleKeyPress
	(
	const int				key,
	const JXKeyModifiers&	modifiers
	)
{
	const JBoolean shiftOn = modifiers.shift();
	const JBoolean metaOn  = modifiers.meta();

	JXWindow* window = GetWindow();

	if (key == kJReturnKey && metaOn)
		{
		EndEditing();
		}
	else if (key == kJReturnKey && shiftOn)
		{
		ShiftEditing(0,-1);
		}
	else if (key == kJReturnKey)
		{
		ShiftEditing(0,1);
		}

	else if (key == kJTabKey && shiftOn)
		{
		ShiftEditing(-1,0);
		}
	else if (key == kJTabKey)
		{
		ShiftEditing(1,0);
		}

	else if (metaOn && (key == kJUpArrow || key == '8'))
		{
		ShiftEditing(0,-1);
		}
	else if (metaOn && (key == kJDownArrow || key == '2'))
		{
		ShiftEditing(0,1);
		}
	else if (metaOn && (key == kJLeftArrow || key == '4'))
		{
		ShiftEditing(-1,0);
		}
	else if (metaOn && (key == kJRightArrow || key == '6'))
		{
		ShiftEditing(1,0);
		}

	else if (key == kJEscapeKey)
		{
		CancelEditing();
		}

	else
		{
		JXTable::HandleKeyPress(key, modifiers);
		}
}

/******************************************************************************
 WantsInputFieldKey (virtual)

	Returns kTrue if it wants to preempt the input field from getting the key.

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

JBoolean
JXEditTable::WantsInputFieldKey
	(
	const int				key,
	const JXKeyModifiers&	modifiers
	)
	const
{
	return JConvertToBoolean(
		key == kJReturnKey || key == kJTabKey || key == kJEscapeKey ||
		(modifiers.meta() &&
		 (key == kJUpArrow || key == '8' ||
		  key == kJDownArrow || key == '2' ||
		  key == kJLeftArrow || key == '4' ||
		  key == kJRightArrow || key == '6')));
}

/******************************************************************************
 GetEditMenuHandler

	Returns JXTEBase* that can then be used for AppendEditMenu() or
	ShareEditMenu().

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

JXTEBase*
JXEditTable::GetEditMenuHandler()
	const
{
	if (itsEditMenuHandler == NULL)
		{
		JXEditTable* me = const_cast<JXEditTable*>(this);
		me->itsEditMenuHandler =
			new JXInputField(me, JXWidget::kFixedLeft, JXWidget::kFixedTop,
							 0,0, 10,10);
		assert( itsEditMenuHandler != NULL );
		itsEditMenuHandler->Hide();
		}

	return itsEditMenuHandler;
}
