/******************************************************************************
 GMessageEditor.cc

	<Description>

	BASE CLASS = public JXTEBase

	Copyright © 1997 by Glenn W. Bach.  All rights reserved.
	
	Base code generated by Codemill v0.1.0

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

#include <GMessageEditor.h>
#include <GPrefsMgr.h>
#include <GMGlobals.h>
#include <JXSpellChecker.h>

#include "checkspell.xpm"

#include <JXTextMenu.h>
#include <JXScrollbarSet.h>
#include <JXScrollbar.h>
#include <JXFontManager.h>
#include <JXWindow.h>
#include <JXWindowDirector.h>

#include <JFontStyle.h>
#include <JFontManager.h>

#include <jAssert.h>

// Edit menu

static const JCharacter* kPasteQuotedStr = "Paste quoted";
static const JCharacter* kQuoteSelectedStr   = "Quote selected";
static const JCharacter* kCheckSpellingStr     = "Check spelling";
static const JCharacter* kCheckSelectedSpellingStr  = "Check spelling for selection";

static const JCharacter* kPasteQuotedID = "PasteQuoted::Arrow";
static const JCharacter* kQuoteSelectedID   = "QuoteSelected::Arrow";
static const JCharacter* kCheckSpellingID     = "CheckSpelling::Arrow";
static const JCharacter* kCheckSelectedSpellingID  = "CheckSpellingSelection::Arrow";

enum
{
	kPasteQuotedCmd = 0,
	kQuoteSelectedCmd,
	kCheckSpellingCmd,
	kCheckSelectedSpellingCmd
};

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

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

GMessageEditor::GMessageEditor
	(
	JXMenuBar* 			menuBar, 
	JXScrollbarSet* 	scrollbarSet, 
	JXContainer* 		enclosure,
	const HSizingOption	hSizing, 
	const VSizingOption vSizing,
	const JCoordinate 	x, 
	const JCoordinate 	y,
	const JCoordinate 	w, 
	const JCoordinate 	h
	)
	:
   JXSRTextBase(kFullEditor, kFalse, kFalse, scrollbarSet, enclosure, 
   				hSizing, vSizing, x, y, w, h)
{
	WantInput(kTrue, kTrue);
	ShouldAllowDragAndDrop(kTrue);
	UseMultipleUndo();
	(scrollbarSet->GetVScrollbar())->SetScrollDelay(0);

	SetPTPrinter(GMGetPTPrinter());
	AppendEditMenu(menuBar, JXMenu::kMacintoshStyle, kTrue, kTrue, kFalse, kFalse);
	JXTextMenu* editMenu;
	GetEditMenu(&editMenu);
	const JSize editCount = editMenu->GetItemCount();
	itsStartEditCmd = editCount + 1;
	editMenu->ShowSeparatorAfter(editCount);
	editMenu->AppendItem(kPasteQuotedStr, kFalse, kFalse, "", "Meta-Shift-V", kPasteQuotedID);
	editMenu->AppendItem(kQuoteSelectedStr, kFalse, kFalse, NULL, NULL, kQuoteSelectedID);
	editMenu->ShowSeparatorAfter(editCount+2);
	editMenu->AppendItem(kCheckSpellingStr, kFalse, kFalse, NULL, NULL, kCheckSpellingID);
	editMenu->AppendItem(kCheckSelectedSpellingStr, kFalse, kFalse, "", "Meta-Shift-L", kCheckSelectedSpellingID);

	editMenu->SetItemImage(itsStartEditCmd + kCheckSpellingCmd, checkspell);

	AppendSearchReplaceMenu(GetSearchDialog(), menuBar, 
									JXMenu::kMacintoshStyle);

	SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), GGetPrefsMgr()->GetDefaultFontSize());
	JSize tabChars = GGetPrefsMgr()->GetTabCharWidth();
	SetCRMTabCharCount(tabChars);
	JCoordinate charWidth = 
		TEGetFontManager()->GetCharWidth(GGetPrefsMgr()->GetDefaultMonoFont(),
			GGetPrefsMgr()->GetDefaultFontSize(), JFontStyle(), ' ');
	SetDefaultTabWidth(charWidth * tabChars);
	itsSpellChecker = NULL;

	CRMRuleList* rules = new CRMRuleList();
	assert(rules != NULL);
	JTextEditor::CRMRule rule("[[:space:]]*(>+[[:space:]]*)+", "[[:space:]]*(>+[[:space:]]*)+", "$0");
	rules->AppendElement(rule);
	SetCRMRuleList(rules, kTrue);
	SetAsActiveTextEditor();

	ListenTo(GGetPrefsMgr());
}

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

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

GMessageEditor::~GMessageEditor()
{
}

/******************************************************************************
 CRMIsPrefixChar

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

JBoolean
GMessageEditor::CRMIsPrefixChar
	(
	const JCharacter c
	)
	const
{
	return JConvertToBoolean( c == ' ' || c == '\t' || c == '>' );
}

/******************************************************************************
 GetPasteText

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

JBoolean
GMessageEditor::GetPasteText
	(
	JString* text
	)
{
	JRunArray<Font> style;
	if (TEOwnsClipboard())
		{
		GetClipboard(text);
		return kTrue;
		}
	else if (TEGetExternalClipboard(text, &style))
		{
		return kTrue;
		}
	return kFalse;
}

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

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

void
GMessageEditor::Receive
	(
	JBroadcaster* sender,
	const JBroadcaster::Message& message
	)
{
	if (sender == itsSpellChecker && message.Is(JXSpellChecker::kSpellCheckFinished))
		{
		JXSpellChecker::SpellCheckFinished* info =
			dynamic_cast(JXSpellChecker::SpellCheckFinished*, &message);
		assert(info != NULL);
		if (!info->FoundErrors() && GGetPrefsMgr()->IsReportingSCErrors())
			{
			JGetUserNotification()->DisplayMessage("No errors were found.");
			}
		delete itsSpellChecker;
		itsSpellChecker = NULL;
//		TEActivate();
//		GetWindow()->GetDirector()->Resume();
		}
	else if (sender == GGetPrefsMgr() && message.Is(GPrefsMgr::kFontChanged))
		{
		JString fontName 	= GGetPrefsMgr()->GetDefaultMonoFont();
		JSize fontSize		= GGetPrefsMgr()->GetDefaultFontSize();
		JBoolean changed = 
			JConvertToBoolean(
				(fontName != GetDefaultFontName()) ||
				(fontSize != GetDefaultFontSize()));
		if (changed)
			{
			const JFontManager* fontMgr = GetFontManager();
			const JFloat h1 = fontMgr->GetLineHeight(GetDefaultFontName(),
													 GetDefaultFontSize(), JFontStyle());
			const JFloat h2 = fontMgr->GetLineHeight(fontName, fontSize, JFontStyle());
			JFloat vScrollScale    = h2 / h1;

			JXScrollbar *hScrollbar, *vScrollbar;
			const JBoolean ok = GetScrollbars(&hScrollbar, &vScrollbar);
			assert( ok );
			vScrollbar->PrepareForScaledMaxValue(vScrollScale);

			JSize tabCharCount = GGetPrefsMgr()->GetTabCharWidth();

			SetAllFontNameAndSize(fontName, fontSize, tabCharCount, kFalse, kFalse);
			}
		}
	else
		{
		JXTextMenu* editMenu;
		GetEditMenu(&editMenu);
		if (sender == editMenu)
			{
			if (message.Is(JXMenu::kItemSelected))
				{
				 const JXMenu::ItemSelected* selection =
					dynamic_cast(const JXMenu::ItemSelected*, &message);
				assert( selection != NULL );
				HandleEditMenu(selection->GetIndex());
				}
			else if (message.Is(JXMenu::kNeedsUpdate))
				{
				UpdateEditMenu();
				}
			}
		JXSRTextBase::Receive(sender, message);
		}
}

/******************************************************************************
 UpdateMessageMenu 


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

void
GMessageEditor::UpdateEditMenu()
{
	JXTextMenu* editMenu;
	GetEditMenu(&editMenu);
	if (GSpellCheckEnabled())
		{
		editMenu->EnableItem(kCheckSpellingCmd + itsStartEditCmd);
		}
	if (HasSelection())
		{		
		editMenu->EnableItem(kQuoteSelectedCmd + itsStartEditCmd);
		}
	editMenu->EnableItem(kPasteQuotedCmd + itsStartEditCmd);
}

/******************************************************************************
 HandleEditMenu 


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

void
GMessageEditor::HandleEditMenu
	(
	const JIndex mindex
	)
{
	JIndex index = mindex - itsStartEditCmd;
	if (index == kPasteQuotedCmd)
		{
		JString text;
		if (GetPasteText(&text))
			{
			GQuoteString(&text, kTrue);
			Paste(text);
			}
		JIndex startIndex;
		GetCaretLocation(&startIndex);

		SelectLine(GetLineForChar(startIndex));
		TEScrollToSelection(kFalse);
		SetCaretLocation(startIndex);

		}
	else if (index == kQuoteSelectedCmd)
		{
		JIndex start;
		JIndex end;
		if (GetSelection(&start, &end))
			{
			JIndex lineStart 	= GetLineForChar(start);
			JIndex lineEnd 		= GetLineForChar(end);
			SetSelection(GetLineStart(lineStart), GetLineEnd(lineEnd));
			}
		JString text;
		if (GetSelection(&text))
			{
			GQuoteString(&text, kTrue);
			Paste(text);
			}
		}
	else if (index == kCheckSpellingCmd)
		{
		itsSpellChecker = new JXSpellChecker(this);
		assert(itsSpellChecker != NULL);
		ListenTo(itsSpellChecker);
		itsSpellChecker->CheckWords();
//		GetWindow()->GetDirector()->Suspend();
//		TEActivate();
		}
}

/******************************************************************************
 GetPlainTextTabWidth (virtual protected)

	Derived classes must override this function in order to print tabs
	correctly from PrintPlainText().  They should return the number of
	spaces that the tab should be converted to.

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

JSize
GMessageEditor::GetPlainTextTabWidth
	(
	const JIndex charIndex,
	const JIndex textColumn
	)
	const
{
	return 8 - (textColumn % 8);
}

/******************************************************************************
 IsCharacterInWord (virtual protected)

	Returns kTrue if the given character should be considered part of
	a word.  The default definition is [A-Za-z0-9].

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

JBoolean
GMessageEditor::IsCharacterInWord
	(
	const JString&	text,
	const JIndex	charIndex
	)
	const
{
	if (JXTEBase::IsCharacterInWord(text, charIndex))
		{
		return kTrue;
		}
	return JConvertToBoolean(text.GetCharacter(charIndex) == '\'');
}

