/*******************************************************************************
 JX2DPlotWidget.cc

	JX2DPlotWidget class.

	Copyright @ 1997 by Glenn W. Bach. All rights reserved.

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

#include <JX2DPlotWidget.h>
#include <JXPlotLabelDialog.h>
#include <JXPlotScaleDialog.h>
#include <JXPlotRangeDialog.h>
#include <JXCurveOptionsDialog.h>
#include <JXCursorMarkTableDir.h>
#include <JXCursorMarkTable.h>

#include <JXWindowPainter.h>
#include <JXWindowDirector.h>
#include <JXDragPainter.h>
#include <JXColormap.h>
#include <JXTextMenu.h>
#include <JXMenuBar.h>
#include <JXFontSizeMenu.h>
#include <JXFontNameMenu.h>
#include <JXWindow.h>
#include <JXDisplay.h>
#include <JXPSPrinter.h>

#include <JXCursor.h>
#include <jXPainterUtil.h>
#include <jXConstants.h>
#include <jXGlobals.h>

#include <JString.h>
#include <jAssert.h>

// setup information

const JFileVersion kCurrentSetupVersion = 2;	// must begin with digit >= 2

	// version 2:  added version number and itsPSPrintName

// Options menu

static const JCharacter* kOptionsMenuTitleStr = "Options";
static const JCharacter* kOptionsMenuStr =
	"    Change scale..."
	"  | Reset scale "
	"%l| Show frame %b"
	"  | Show grid %b"
	"  | Show legend %b"
	"%l| Copy scale to range"
	"  | Change range..."
	"  | Clear range "
	"%l| Change labels..."
	"  | Change curve options..."
	"  | Remove curve ";

enum
{
	kScaleCmd = 1,
	kResetScaleCmd,
	kShowFrameCmd,
	kShowGridCmd,
	kShowLegendCmd,
	kSetPlotRangeCmd,
	kChangeRangeCmd,
	kClearPlotRangeCmd,
	kChangeLabelsCmd,
	kCurveOptionsCmd,
	kRemoveCurveCmd
};

// Cursor menu

static const JCharacter* kCursorMenuTitleStr = "Cursor";
static const JCharacter* kCursorMenuStr =
	"    X cursor %b"
	"  | Y cursor %b"
	"  | Dual cursors %b"
	"%l| Mark cursor"
	"  | Remove all marks"
	"  | Remove mark"
	"%l| Show mark window";

enum
{
	kXCursorCmd = 1,
	kYCursorCmd,
	kDualCursorsCmd,
	kMarkCursorCmd,
	kRemoveAllMarksCmd,
	kRemoveMarkCmd,
	kMarkWindowCmd
};

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

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

JX2DPlotWidget::JX2DPlotWidget
	(
	JXMenuBar* 			menuBar,
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXWidget(enclosure, hSizing, vSizing, x,y, w,h),
	J2DPlotWidget(GetColormap()->GetBlackColor(),
				  GetColormap()->GetWhiteColor(),
				  GetColormap()->GetGray80Color(),
				  GetColormap()->GetRedColor())
{
	SetBorderWidth(kJXDefaultBorderWidth);
	JXColormap* colormap = GetColormap();
	SetBackColor(colormap->GetWhiteColor());
	AddColor(JGetCurrColormap()->GetRedColor());
	AddColor(colormap->GetBlueColor());
	AddColor(colormap->GetMagentaColor());
	AddColor(colormap->GetDarkGreenColor());

	itsOptionsMenu = menuBar->AppendTextMenu(kOptionsMenuTitleStr);
	assert( itsOptionsMenu != NULL );
	itsOptionsMenu->SetMenuItems(kOptionsMenuStr);
	itsOptionsMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsOptionsMenu);

	itsRemoveCurveMenu = new JXTextMenu(itsOptionsMenu, kRemoveCurveCmd, menuBar);
	assert( itsRemoveCurveMenu != NULL );
	itsRemoveCurveMenu->SetMenuItems("a");
	itsRemoveCurveMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsRemoveCurveMenu);

	itsCursorMenu = menuBar->AppendTextMenu(kCursorMenuTitleStr);
	itsCursorMenu->SetMenuItems(kCursorMenuStr);
	itsCursorMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsCursorMenu);

	itsMarkMenu = new JXTextMenu(itsCursorMenu, kRemoveMarkCmd, menuBar);
	assert( itsMarkMenu != NULL );
	itsMarkMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsMarkMenu);
	UpdateMarkMenu();

	itsPlotLabelDialog 		= NULL;
	itsPlotScaleDialog 		= NULL;
	itsPlotRangeDialog		= NULL;
	itsCurveOptionsDialog 	= NULL;

	itsMarkDir =
		new JXCursorMarkTableDir(GetWindow()->GetDirector(), this);
	assert(itsMarkDir != NULL);

	JXDisplay* display = GetDisplay();
	itsDragXCursor     = JXGetDragVertLineCursor(display);
	itsDragYCursor     = JXGetDragHorizLineCursor(display);

	itsPSPrinter = NULL;

	WantInput(kTrue, kTrue);
}

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

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

JX2DPlotWidget::~JX2DPlotWidget()
{
}

/*******************************************************************************
 Draw

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

void
JX2DPlotWidget::Draw
	(
	JXWindowPainter& p,
	const JRect& rect
	)
{
	PWDraw(p, rect);
}

/*******************************************************************************
 DrawBorder

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

void
JX2DPlotWidget::DrawBorder
	(
	JXWindowPainter& p,
	const JRect& frame
	)
{
	JXDrawDownFrame(p, frame, GetBorderWidth());
}

/*******************************************************************************
 HandleKeyPress


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

void
JX2DPlotWidget::HandleKeyPress
	(
	const int key,
	const JXKeyModifiers& modifiers
	)
{
	PWHandleKeyPress(key, modifiers.shift(), modifiers.meta(), kFalse);
}

/******************************************************************************
 HandleMouseDown (virtual protected)

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

void
JX2DPlotWidget::HandleMouseDown
	(
	const JPoint&			pt,
	const JXMouseButton		button,
	const JSize				clickCount,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	if (button == kJXLeftButton)
		{
		PWHandleMouseDown(pt, clickCount);
		}
}

/******************************************************************************
 HandleMouseDrag (virtual protected)

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

void
JX2DPlotWidget::HandleMouseDrag
	(
	const JPoint&			pt,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	if (buttonStates.left())
		{
		PWHandleMouseDrag(pt);
		}
}

/******************************************************************************
 HandleMouseUp (virtual protected)

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

void
JX2DPlotWidget::HandleMouseUp
	(
	const JPoint&			pt,
	const JXMouseButton		button,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	if (button == kJXLeftButton)
		{
		PWHandleMouseUp(pt, modifiers.meta());
		}
}

/*******************************************************************************
 BoundsResized

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

void
JX2DPlotWidget::BoundsResized
	(
	const JCoordinate dw,
	const JCoordinate dh
	)
{
	JXWidget::BoundsResized(dw,dh);
	PWBoundsChanged();
}

/*******************************************************************************
 PWGetGUIWidth (protected)

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

JSize
JX2DPlotWidget::PWGetGUIWidth()
	const
{
	return GetApertureWidth();
}

/*******************************************************************************
 PWGetGUIHeight (protected)

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

JSize
JX2DPlotWidget::PWGetGUIHeight()
	const
{
	return GetApertureHeight();
}

/*******************************************************************************
 Receive

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

void
JX2DPlotWidget::Receive
	(
	JBroadcaster* sender,
	const JBroadcaster::Message& message
	)
{
	if (sender == itsOptionsMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleOptionsMenu(selection->GetIndex());
		}

	else if (sender == itsOptionsMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateOptionsMenu();
		}

	else if (sender == itsRemoveCurveMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleRemoveCurveMenu(selection->GetIndex());
		}

	else if (sender == itsRemoveCurveMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateRemoveCurveMenu();
		}

	else if (sender == itsCursorMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleCursorMenu(selection->GetIndex());
		}

	else if (sender == itsCursorMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateCursorMenu();
		}

	else if (sender == itsMarkMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleMarkMenu(selection->GetIndex());
		}

	else if (sender == itsPlotLabelDialog && message.Is(JXDialogDirector::kDeactivated))
		{
		const JXDialogDirector::Deactivated* info =
			dynamic_cast(const JXDialogDirector::Deactivated*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			GetNewLabels();
			}
		itsPlotLabelDialog = NULL;
		}

	else if (sender == itsPlotScaleDialog && message.Is(JXDialogDirector::kDeactivated))
		{
		const JXDialogDirector::Deactivated* info =
			dynamic_cast(const JXDialogDirector::Deactivated*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			GetNewScale();
			}
		itsPlotScaleDialog = NULL;
		}

	else if (sender == itsPlotRangeDialog && message.Is(JXDialogDirector::kDeactivated))
		{
		const JXDialogDirector::Deactivated* info =
			dynamic_cast(const JXDialogDirector::Deactivated*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			GetNewRange();
			}
		itsPlotRangeDialog = NULL;
		}

	else if (sender == itsCurveOptionsDialog && message.Is(JXDialogDirector::kDeactivated))
		{
		const JXDialogDirector::Deactivated* info =
			dynamic_cast(const JXDialogDirector::Deactivated*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			GetNewCurveOptions();
			}
		itsCurveOptionsDialog = NULL;
		}

	else if (sender == itsPSPrinter &&
			 message.Is(JPrinter::kPrintSetupFinished))
		{
		const JPrinter::PrintSetupFinished* info =
			dynamic_cast(const JPrinter::PrintSetupFinished*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			itsPSPrintName = itsPSPrinter->GetFileName();
			Print(*itsPSPrinter);
			}
		StopListening(itsPSPrinter);
		}

	else
		{
		J2DPlotWidget::Receive(sender,message);
		JXWidget::Receive(sender, message);
		}
}

/*******************************************************************************
 UpdateOptionsMenu

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

void
JX2DPlotWidget::UpdateOptionsMenu()
{
	if (FrameIsVisible())
		{
		itsOptionsMenu->CheckItem(kShowFrameCmd);
		}

	if (GridIsVisible())
		{
		itsOptionsMenu->CheckItem(kShowGridCmd);
		}

	if (LegendIsVisible())
		{
		itsOptionsMenu->CheckItem(kShowLegendCmd);
		}
}

/*******************************************************************************
 HandleOptionsMenu

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

void
JX2DPlotWidget::HandleOptionsMenu
	(
	const JIndex index
	)
{
	if (index == kCurveOptionsCmd)
		{
		ChangeCurveOptions(1);
		}

	if (index == kScaleCmd)
		{
		ChangeScale();
		}

	else if (index == kResetScaleCmd)
		{
		ResetScaling();
		}

	else if (index == kSetPlotRangeCmd)
		{
		SetRange();
		}

	else if (index == kChangeRangeCmd)
		{
		ChangeRange();
		}

	else if (index == kClearPlotRangeCmd)
		{
		ClearRange();
		}

	else if (index == kChangeLabelsCmd)
		{
		ChangeLabels(kNoLabel);
		}

	else if (index == kShowFrameCmd)
		{
		if (FrameIsVisible())
			{
			ShowFrame(kFalse);
			}
		else
			{
			ShowFrame(kTrue);
			}

		}

	else if (index == kShowGridCmd)
		{
		if (GridIsVisible())
			{
			ShowGrid(kFalse);
			}
		else
			{
			ShowGrid(kTrue);
			}
		}

	else if (index == kShowLegendCmd)
		{
		if (LegendIsVisible())
			{
			ShowLegend(kFalse);
			}
		else
			{
			ShowLegend(kTrue);
			}
		}
}

/*******************************************************************************
 ChangeLabels

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

void
JX2DPlotWidget::ChangeLabels
	(
	const LabelSelection selection
	)
{
	assert (itsPlotLabelDialog == NULL);
	itsPlotLabelDialog =
		new JXPlotLabelDialog((GetWindow())->GetDirector(),
								GetTitle(), GetXLabel(), GetYLabel(),
								GetFontName(), GetFontSize(), selection);
	assert (itsPlotLabelDialog != NULL);
	ListenTo(itsPlotLabelDialog);
	itsPlotLabelDialog->BeginDialog();
}

/*******************************************************************************
 GetNewLabels


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

void
JX2DPlotWidget::GetNewLabels()
{
	assert( itsPlotLabelDialog != NULL );
	JString title;
	JString xLabel;
	JString yLabel;

	itsPlotLabelDialog->GetLabels(&title, &xLabel, &yLabel);
	SetTitle(title);
	SetXLabel(xLabel);
	SetYLabel(yLabel);
	SetFontName(itsPlotLabelDialog->GetFontName());
	SetFontSize(itsPlotLabelDialog->GetFontSize());
}

/*******************************************************************************
 ChangeScale


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

void
JX2DPlotWidget::ChangeScale
	(
	const JBoolean xAxis
	)
{
	assert (itsPlotScaleDialog == NULL);
	JFloat xmax;
	JFloat xmin;
	JFloat xinc;
	JFloat ymax;
	JFloat ymin;
	JFloat yinc;
	GetXScaling(&xmin, &xmax, &xinc);
	GetYScaling(&ymin, &ymax, &yinc);
/*	if (!XAxisIsLinear())
		{
		xmin = pow(10, xmin);
		xmax = pow(10, xmax);
		xinc = pow(10, xinc);
		}
	if (!YAxisIsLinear())
		{
		ymin = pow(10, ymin);
		ymax = pow(10, ymax);
		yinc = pow(10, yinc);
		}
*/
	itsPlotScaleDialog =
		new JXPlotScaleDialog((GetWindow())->GetDirector(),
			xmax, xmin, xinc, XAxisIsLinear(), ymax, ymin, yinc, YAxisIsLinear());
	assert (itsPlotScaleDialog != NULL);
	ListenTo(itsPlotScaleDialog);
	itsPlotScaleDialog->BeginDialog();
	itsPlotScaleDialog->EditXAxis(xAxis);
}

/*******************************************************************************
 ChangeScale


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

void
JX2DPlotWidget::ChangeScale()
{
	ChangeScale(kTrue);
}

/*******************************************************************************
 GetNewScale


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

void
JX2DPlotWidget::GetNewScale()
{
	assert( itsPlotScaleDialog != NULL );

	JFloat xmax;
	JFloat xmin;
	JFloat xinc;
	JFloat ymax;
	JFloat ymin;
	JFloat yinc;
	JBoolean xLinear;
	JBoolean yLinear;

	itsPlotScaleDialog->GetScaleValues(&xmax, &xmin, &xinc, &xLinear, &ymax, &ymin, &yinc, &yLinear);
	if (xLinear)
		{
		SetXScaling(xmin, xmax, xinc);
		}
	else
		{
		if (xmin <= 0)
			{
			xmin = 1;
			}
		SetXScaling(log10(xmin), log10(xmax), 0);
		}
	if (yLinear)
		{
		SetYScaling(ymin, ymax, yinc);
		}
	else
		{
		if (ymin <= 0)
			{
			ymin = 1;
			}
		SetYScaling(log10(ymin), log10(ymax), 0);
		}
	SetXAxisLinear(xLinear);
	SetYAxisLinear(yLinear);
}

/*******************************************************************************
 ChangeRange (private)


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

void
JX2DPlotWidget::ChangeRange()
{
	assert (itsPlotRangeDialog == NULL);
	JFloat xmax, xmin, ymax, ymin;
	if (!GetRange(&xmin, &xmax, &ymin, &ymax))
		{
		JFloat xinc, yinc;
		GetXScaling(&xmin, &xmax, &xinc);
		GetYScaling(&ymin, &ymax, &yinc);
		}
	itsPlotRangeDialog =
		new JXPlotRangeDialog((GetWindow())->GetDirector(),
			xmax, xmin, ymax, ymin);
	assert (itsPlotRangeDialog != NULL);
	ListenTo(itsPlotRangeDialog);
	itsPlotRangeDialog->BeginDialog();
}

/*******************************************************************************
 GetNewRange (private)


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

void
JX2DPlotWidget::GetNewRange()
{
	assert( itsPlotRangeDialog != NULL );

	JFloat xmax, xmin, ymax, ymin;
	if (itsPlotRangeDialog->GetRangeValues(&xmax, &xmin, &ymax, &ymin))
		{
		SetRange(xmin, xmax, ymin, ymax);
		}
	else
		{
		ClearRange();
		}
}

/*******************************************************************************
 PWRefreshRect (protected)

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

void
JX2DPlotWidget::PWRefreshRect
	(
	const JRect& rect
	)
{
	RefreshRect(rect);
}

/*******************************************************************************
 PWRedraw (protected)

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

void
JX2DPlotWidget::PWRedraw()
{
	Redraw();
}

/*******************************************************************************
 PWRedrawRect (protected)

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

void
JX2DPlotWidget::PWRedrawRect
	(
	const JRect& rect
	)
{
	RedrawRect(rect);
}

/*******************************************************************************
 PWRefreshUpdate (protected)

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

void
JX2DPlotWidget::PWRefreshUpdate()
{
	GetWindow()->Update();
}


/*******************************************************************************
 PWForceRefresh (protected)

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

void
JX2DPlotWidget::PWForceRefresh()
{
	Refresh();
}

/*******************************************************************************
 PWCreateDragInsidePainter (protected)


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

JPainter*
JX2DPlotWidget::PWCreateDragInsidePainter()
{
	return CreateDragInsidePainter();
}

/*******************************************************************************
 PWGetDragPainter (protected)


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

JPainter*
JX2DPlotWidget::PWGetDragPainter()
{
	return GetDragPainter();
}

/*******************************************************************************
 PWDeleteDragPainter (protected)


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

void
JX2DPlotWidget::PWDeleteDragPainter()
{
	DeleteDragPainter();
}

/*******************************************************************************
 ChangeCurveOptions

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

void
JX2DPlotWidget::ChangeCurveOptions()
{
	ChangeCurveOptions(itsCurrentCurve);
}

/*******************************************************************************
 ChangeCurveOptions

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

void
JX2DPlotWidget::ChangeCurveOptions
	(
	const JIndex index
	)
{
	assert (itsCurveOptionsDialog == NULL);
	itsCurveOptionsDialog =
		new JXCurveOptionsDialog((GetWindow())->GetDirector(), GetCurveInfoArray(), index);
	assert (itsCurveOptionsDialog != NULL);
	ListenTo(itsCurveOptionsDialog);
	itsCurveOptionsDialog->BeginDialog();
}

/*******************************************************************************
 GetNewCurveOptions


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

void
JX2DPlotWidget::GetNewCurveOptions()
{
	assert( itsCurveOptionsDialog != NULL );
	SetCurveInfoArray(itsCurveOptionsDialog->GetCurveInfoArray());
}

/*******************************************************************************
 UpdateRemoveCurveMenu


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

void
JX2DPlotWidget::UpdateRemoveCurveMenu()
{
	JSize count = itsRemoveCurveMenu->GetItemCount();

	for (JSize j = 1; j <= count; j++)
		{
		itsRemoveCurveMenu->DeleteItem(1);
		}

	JPtrArray<JString> curveNames;
	GetCurveNames(&curveNames);

	JSize curves = curveNames.GetElementCount();

	for (JSize i = 1; i <= curves; i++)
		{
		itsRemoveCurveMenu->AppendItem(*(curveNames.NthElement(i)));
		if (CurveIsProtected(i))
			{
			itsRemoveCurveMenu->DisableItem(i);
			}
		}
}

/*******************************************************************************
 HandleRemoveCurveMenu


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

void
JX2DPlotWidget::HandleRemoveCurveMenu
	(
	const JIndex index
	)
{
	RemoveCurve(index);
}

/*******************************************************************************
 UpdateCursorMenu


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

void
JX2DPlotWidget::UpdateCursorMenu()
{
	if (XCursorVisible())
		{
		itsCursorMenu->CheckItem(kXCursorCmd);
		}

	if (YCursorVisible())
		{
		itsCursorMenu->CheckItem(kYCursorCmd);
		}

	if (DualCursorsVisible())
		{
		itsCursorMenu->CheckItem(kDualCursorsCmd);
		}

	if (CursorIsSelected())
		{
		itsCursorMenu->EnableItem(kMarkCursorCmd);
		}
	else
		{
		itsCursorMenu->DisableItem(kMarkCursorCmd);
		}

	if ( (GetXMarkCount() > 0) || (GetYMarkCount() > 0))
		{
		itsCursorMenu->EnableItem(kRemoveAllMarksCmd);
		}
	else
		{
		itsCursorMenu->DisableItem(kRemoveAllMarksCmd);
		}
}

/*******************************************************************************
 HandleCursorMenu


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

void
JX2DPlotWidget::HandleCursorMenu
	(
	const JIndex index
	)
{
	if (index == kXCursorCmd)
		{
		ToggleXCursor();
		}
	else if (index == kYCursorCmd)
		{
		ToggleYCursor();
		}
	else if (index == kDualCursorsCmd)
		{
		ToggleDualCursors();
		}
	else if (index == kMarkCursorCmd)
		{
		MarkCurrentCursor();
		UpdateMarkMenu();
		}
	else if (index == kRemoveAllMarksCmd)
		{
		RemoveAllMarks();
		}
	else if (index == kMarkWindowCmd)
		{
		itsMarkDir->Activate();
		}
}

/*******************************************************************************
 UpdateMarkMenu


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

void
JX2DPlotWidget::UpdateMarkMenu()
{
	itsMarkMenu->RemoveAllItems();
	JSize i;
	for (i = 1; i <= GetXMarkCount(); i++)
		{
		JString str("x");
		str += JString(i);
		itsMarkMenu->AppendItem(str);
		}
	for (i = 1; i <= GetYMarkCount(); i++)
		{
		JString str("y");
		str += JString(i);
		itsMarkMenu->AppendItem(str);
		}
	if ((GetXMarkCount() == 0) && (GetYMarkCount() == 0))
		{
		itsCursorMenu->DisableItem(kRemoveMarkCmd);
		}
	else
		{
		itsCursorMenu->EnableItem(kRemoveMarkCmd);
		}
}

/*******************************************************************************
 HandleMarkMenu


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

void
JX2DPlotWidget::HandleMarkMenu
	(
	const JIndex index
	)
{
	JIndex realIndex;
	JSize xCount = GetXMarkCount();
	if (index > xCount)
		{
		realIndex = index - xCount;
		RemoveYMark(realIndex);
		}
	else
		{
		RemoveXMark(index);
		}
	UpdateMarkMenu();
	Refresh();
}

/*******************************************************************************
 ProtectionChanged


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

void
JX2DPlotWidget::ProtectionChanged()
{
	UpdateRemoveCurveMenu();
}

/******************************************************************************
 SetPSPrinter

	Call this to provide a JXPSPrinter object for this plot.  This object
	does *not* take ownership of the printer object.

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

void
JX2DPlotWidget::SetPSPrinter
	(
	JXPSPrinter* p
	)
{
	if (itsPSPrinter != NULL)
		{
		StopListening(itsPSPrinter);
		}
	itsPSPrinter = p;
}

/******************************************************************************
 HandlePSPageSetup

	You must call SetPSPrinter() before using this routine.

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

void
JX2DPlotWidget::HandlePSPageSetup()
{
	assert( itsPSPrinter != NULL );

	itsPSPrinter->BeginUserPageSetup();
}

/******************************************************************************
 PrintPS

	You must call SetPSPrinter() before using this routine.

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

void
JX2DPlotWidget::PrintPS()
{
	assert( itsPSPrinter != NULL );

	itsPSPrinter->SetFileName(itsPSPrintName);
	itsPSPrinter->BeginUserPrintSetup();
	ListenTo(itsPSPrinter);
}

/******************************************************************************
 PrintMarks (virtual protected)

	Returns kFalse if printing was cancelled.

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

JBoolean
JX2DPlotWidget::PrintMarks
	(
	JPagePrinter&	p,
	const JBoolean	putOnSamePage,
	const JRect&	partialPageRect
	)
{
	return itsMarkDir->GetTable()->TableDrawArea(p, putOnSamePage, partialPageRect);
}

/******************************************************************************
 PWXReadSetup

	This uses assert() to check the version number because we cannot use
	a marker to skip the data (since it contains objects), so it is the
	client's responsibility to check whether or not the file can be
	read (via a higher level version number).

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

void
JX2DPlotWidget::PWXReadSetup
	(
	istream& input
	)
{
	JFileVersion vers = 0;
	input >> ws;
	const JCharacter c1 = input.peek();
	if ('2' <= c1 && c1 <= '9')			// version 1 => leave it for J2DPlotWidget
		{
		input >> vers;
		assert( vers <= kCurrentSetupVersion );
		}

	J2DPlotWidget::PWReadSetup(input);

	itsMarkDir->ReadSetup(input);
	JBoolean active;
	input >> active;
	if (active)
		{
		itsMarkDir->Activate();
		}

	if (vers >= 2)
		{
		input >> itsPSPrintName;
		}
}

/******************************************************************************
 PWXWriteSetup

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

void
JX2DPlotWidget::PWXWriteSetup
	(
	ostream& output
	)
	const
{
	output << kCurrentSetupVersion;

	output << ' ';
	J2DPlotWidget::PWWriteSetup(output);

	output << ' ';
	itsMarkDir->WriteSetup(output);
	output << ' ' << itsMarkDir->IsActive();

	output << ' ' << itsPSPrintName;
}

/******************************************************************************
 AdjustCursor (virtual protected)

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

void
JX2DPlotWidget::AdjustCursor
	(
	const JPoint&			pt,
	const JXKeyModifiers&	modifiers
	)
{
	PWDisplayCursor(GetMouseCursor(pt));
}

/******************************************************************************
 PWDisplayCursor (virtual protected)

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

void
JX2DPlotWidget::PWDisplayCursor
	(
	const MouseCursor cursor
	)
{
	if (cursor == kZoomCursor)
		{
		DisplayCursor(kJXCrosshairCursor);
		}
	else if (cursor == kDragXCursor)
		{
		DisplayCursor(itsDragXCursor);
		}
	else if (cursor == kDragYCursor)
		{
		DisplayCursor(itsDragYCursor);
		}
	else
		{
		assert( cursor == kDblClickChangeCursor );
		DisplayCursor(kJXDefaultCursor);
		}
}
