/******************************************************************************
 JTextEditor.h

	Interface for the JTextEditor class

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

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

#ifndef _H_JTextEditor
#define _H_JTextEditor

#include <JBroadcaster.h>
#include <JFontStyle.h>
#include <JRect.h>
#include <JRunArray.h>
#include <JPtrArray-JString.h>
#include <JTEHTMLScanner.h>	// for HTMLError
#include <JPtrStack.h>		// for HTMLLexerState

class JRegex;
class JPainter;
class JPagePrinter;
class JFontManager;
class JColormap;
class JTEUndoBase;
class JTEUndoTextBase;
class JTEUndoTyping;
class JTEUndoDrop;
class JTEUndoStyle;
class JTEUndoTabShift;

class JTextEditor : virtual public JBroadcaster
{
	friend class JTEUndoTextBase;
	friend class JTEUndoDrop;
	friend class JTEUndoStyle;
	friend class JTEUndoTabShift;

	friend class JTEHTMLScanner;

public:

	enum Type
	{
		kFullEditor,
		kSelectableText,
		kStaticText
	};

	enum PlainTextFormat
	{
		kUNIXText,
		kMacintoshText,
		kDOSText
	};

	enum CmdIndex
	{
		kSeparatorCmd = 1,	// always disabled, use if menu separator is separate item

		kUndoCmd,
		kRedoCmd,
		kCutCmd,
		kCopyCmd,
		kPasteCmd,
		kDeleteSelCmd,
		kSelectAllCmd,
		kCleanRightMarginCmd,
		kCoerceRightMarginCmd,
		kShiftSelLeftCmd,
		kShiftSelRightCmd,
		kToggleReadOnlyCmd,

		kCmdCount = kToggleReadOnlyCmd
	};

	struct Font
	{
		JFontID		id;
		JSize		size;
		JFontStyle	style;

		Font()
			:
			id(0), size(kJDefaultFontSize), style()
		{ };

		Font(const JFontID anID, const JSize aSize,
			 const JFontStyle& aStyle)
			:
			id(anID), size(aSize), style(aStyle)
		{ };
	};

	enum CaretMotion
	{
		kMoveByCharacter,
		kMoveByPartialWord,
		kMoveByWord,
		kMoveByLine
	};

	enum
	{
		kMinLeftMarginWidth = 2
	};

	enum HTMLListType
	{
		kHTMLNoList,
		kHTMLUnordList,
		kHTMLOrdList,
		kHTMLDefTermList,
		kHTMLDefDataList	// same as kHTMLDefTermList, but extra tab indenting
	};

	struct CRMRule
	{
		JRegex*	first;		// match and replace
		JRegex* rest;		// match

		CRMRule()
			:
			first(NULL), rest(NULL)
		{ };

		CRMRule(JRegex* f, JRegex* r)
			:
			first(f), rest(r)
		{ };

		CRMRule(const JCharacter* firstPattern, const JCharacter* restPattern,
				const JCharacter* replacePattern)
			:
			first(CreateFirst(firstPattern, replacePattern)),
			rest(CreateRest(restPattern))
		{ };

		static JRegex*	CreateFirst(const JCharacter* pattern,
									const JCharacter* replacePattern);
		static JRegex*	CreateRest(const JCharacter* pattern);
	};

	class CRMRuleList : public JArray<CRMRule>
	{
	public:

		CRMRuleList(const JArrayBlockSize aBlockSize = 5)
			:
			JArray<CRMRule>(aBlockSize)
		{ };

		CRMRuleList(const CRMRuleList& source);

		void	DeleteAll();
	};

public:

	JTextEditor(const Type type, const JBoolean breakCROnly,
				const JBoolean pasteStyledText,
				const JFontManager* fontManager, JColormap* colormap,
				const JColorIndex caretColor, const JColorIndex selectionColor,
				const JColorIndex outlineColor, const JColorIndex dragColor,
				const JCoordinate width);
	JTextEditor(const JTextEditor& source);

	virtual ~JTextEditor();

	Type		GetType() const;
	JBoolean	IsReadOnly() const;
	JBoolean	WillPasteStyledText() const;

	JBoolean	WillBreakCROnly() const;
	void		SetBreakCROnly(const JBoolean breakCROnly);

	JBoolean				IsEmpty() const;
	JSize					GetTextLength() const;
	const JString&			GetText() const;
	const JRunArray<Font>&	GetStyles() const;
	JBoolean				SetText(const JCharacter* text,
									const JRunArray<Font>* style = NULL);

	JBoolean	ReadPlainText(const JCharacter* fileName, PlainTextFormat* format);
	void		WritePlainText(const JCharacter* fileName, const PlainTextFormat format) const;
	void		WritePlainText(ostream& output, const PlainTextFormat format) const;

	void		ReadHTML(istream& input);
	JBoolean	ReadUNIXManOutput(istream& input, const JBoolean allowCancel = kFalse);

	JBoolean	ReadPrivateFormat(istream& input);
	void		WritePrivateFormat(ostream& output) const;

	JBoolean	SearchForward(const JCharacter* searchStr,
							  const JBoolean caseSensitive, const JBoolean entireWord,
							  const JBoolean wrapSearch, JBoolean* wrapped);
	JBoolean	SearchBackward(const JCharacter* searchStr,
							   const JBoolean caseSensitive, const JBoolean entireWord,
							   const JBoolean wrapSearch, JBoolean* wrapped);
	JBoolean	SelectionMatches(const JCharacter* searchStr,
								 const JBoolean caseSensitive, const JBoolean entireWord);

	JBoolean	SearchForward(const JRegex& regex, const JBoolean entireWord,
							  const JBoolean wrapSearch, JBoolean* wrapped,
							  JArray<JIndexRange>* submatchList);
	JBoolean	SearchBackward(const JRegex& regex, const JBoolean entireWord,
							   const JBoolean wrapSearch, JBoolean* wrapped,
							   JArray<JIndexRange>* submatchList);
	JBoolean	SelectionMatches(const JRegex& regex, const JBoolean entireWord,
								 JArray<JIndexRange>* submatchList);

	JBoolean	SearchForward(const JFontStyle& style,
							  const JBoolean wrapSearch, JBoolean* wrapped);
	JBoolean	SearchBackward(const JFontStyle& style,
							   const JBoolean wrapSearch, JBoolean* wrapped);

	const JFontManager*	TEGetFontManager() const;
	JColormap*			TEGetColormap() const;

	const JCharacter*	GetFontName(const JIndex charIndex) const;
	JSize				GetFontSize(const JIndex charIndex) const;
	JFontStyle			GetFontStyle(const JIndex charIndex) const;
	void				GetFont(const JIndex charIndex, JString* name,
								JSize* size, JFontStyle* style) const;

	JBoolean	SetFontName(const JIndex startIndex, const JIndex endIndex,
							const JCharacter* name, const JBoolean clearUndo);
	JBoolean	SetFontSize(const JIndex startIndex, const JIndex endIndex,
							const JSize size, const JBoolean clearUndo);
	JBoolean	SetFontStyle(const JIndex startIndex, const JIndex endIndex,
							 const JFontStyle& style, const JBoolean clearUndo);
	void		SetFont(const JIndex startIndex,const JIndex endIndex,
						const JCharacter* name, const JSize size,
						const JFontStyle& style, const JBoolean clearUndo);

	JBoolean	GetCaretLocation(JIndex* charIndex) const;
	void		SetCaretLocation(const JIndex charIndex);

	JBoolean	HasSelection() const;
	JBoolean	GetSelection(JIndex* startIndex, JIndex* endIndex) const;
	JBoolean	GetSelection(JIndexRange* range) const;
	JBoolean	GetSelection(JString* text) const;
	JBoolean	GetSelection(JString* text, JRunArray<Font>* style) const;
	void		SetSelection(const JIndex startIndex, const JIndex endIndex);
	void		SetSelection(const JIndexRange& range);
	JBoolean	TEScrollToSelection(const JBoolean centerInDisplay);

	JIndex		GetInsertionIndex() const;
	JBoolean	IsEntireWord(const JIndex startIndex, const JIndex endIndex) const;
	JBoolean	IsEntireWord(const JIndexRange& range) const;
	JIndex		GetWordStart(const JIndex charIndex) const;
	JIndex		GetWordEnd(const JIndex charIndex) const;
	JIndex		GetPartialWordStart(const JIndex charIndex) const;
	JIndex		GetPartialWordEnd(const JIndex charIndex) const;
	JIndex		GetParagraphStart(const JIndex charIndex) const;
	JIndex		GetParagraphEnd(const JIndex charIndex) const;
	void		GoToBeginningOfLine();
	void		GoToEndOfLine();

	const JCharacter*	GetCurrentFontName() const;
	JSize				GetCurrentFontSize() const;
	JFontStyle			GetCurrentFontStyle() const;
	void				GetCurrentFont(JString* name, JSize* size, JFontStyle* style) const;

	void	SetCurrentFontName(const JCharacter* name);
	void	SetCurrentFontSize(const JSize size);
	void	SetCurrentFontBold(const JBoolean bold);
	void	SetCurrentFontItalic(const JBoolean italic);
	void	SetCurrentFontUnderline(const JSize count);
	void	SetCurrentFontStrike(const JBoolean strike);
	void	SetCurrentFontColor(const JColorIndex color);
	void	SetCurrentFontStyle(const JFontStyle& style);
	void	SetCurrentFont(const JCharacter* name, const JSize size,
						   const JFontStyle& style);

	const JCharacter*	GetDefaultFontName() const;
	JSize				GetDefaultFontSize() const;
	const JFontStyle&	GetDefaultFontStyle() const;
	void				GetDefaultFont(JString* name, JSize* size,
									   JFontStyle* style) const;
	void				GetDefaultFont(JFontID* id, JSize* size,
									   JFontStyle* style) const;

	void	SetDefaultFontName(const JCharacter* name);
	void	SetDefaultFontSize(const JSize size);
	void	SetDefaultFontStyle(const JFontStyle& style);
	void	SetDefaultFont(const JCharacter* name, const JSize size,
						   const JFontStyle& style = JFontStyle());
	void	SetDefaultFont(const JFontID id, const JSize size,
						   const JFontStyle& style = JFontStyle());

	JCoordinate	GetDefaultTabWidth() const;
	void		SetDefaultTabWidth(const JCoordinate width);
	void		TabSelectionLeft(const JSize tabCount = 1);
	void		TabSelectionRight(const JSize tabCount = 1);

	JBoolean	WillAutoIndent() const;
	void		ShouldAutoIndent(const JBoolean doIt);

	JBoolean	WillMoveToFrontOfText() const;
	void		ShouldMoveToFrontOfText(const JBoolean doIt);

	JSize		GetLineCount() const;
	JIndex		GetLineForChar(const JIndex charIndex) const;
	void		GoToLine(const JIndex lineIndex);
	void		SelectLine(const JIndex lineIndex);
	JIndex		GetLineLength(const JIndex lineIndex) const;
	JIndex		GetLineStart(const JIndex lineIndex) const;
	JIndex		GetLineEnd(const JIndex lineIndex) const;
	JCoordinate	GetLineTop(const JIndex lineIndex) const;
	JCoordinate	GetLineBottom(const JIndex lineIndex) const;
	JSize		GetLineHeight(const JIndex lineIndex) const;

	void	Undo();
	void	Redo();
	void	ClearUndo();
	void	DeactivateCurrentUndo();

	JBoolean	IsUsingMultipleUndo() const;
	void		UseMultipleUndo(const JBoolean doIt = kTrue);

	JSize		GetUndoDepth() const;
	void		SetUndoDepth(const JSize maxUndoCount);

	void	DeleteSelection();
	void	DeleteToStartOfWord();
	void	DeleteToEndOfWord();
	void	SelectAll();

	// internal clipboard

	void	Cut();
	void	Copy();
	void	Paste();

	// other source

	JBoolean	Cut(JString* text, JRunArray<Font>* style = NULL);
	JBoolean	Copy(JString* text, JRunArray<Font>* style = NULL) const;
	void		Paste(const JCharacter* text, const JRunArray<Font>* style = NULL);

	JBoolean	GetClipboard(JString* text, JRunArray<Font>* style = NULL) const;

	static JBoolean	ContainsIllegalChars(const JString& text);
	static JBoolean	ContainsIllegalChars(const JCharacter* text, const JSize length);
	static JBoolean	RemoveIllegalChars(JString* text, JRunArray<Font>* style = NULL);

	void	Paginate(const JCoordinate pageHeight,
					 JArray<JCoordinate>* breakpts) const;
	void	Print(JPagePrinter& p);

	JBoolean	CleanRightMargin(const JBoolean coerce, JIndexRange* reformatRange);

	JSize		GetCRMLineWidth() const;
	void		SetCRMLineWidth(const JSize charCount);

	JSize		GetCRMTabCharCount() const;
	void		SetCRMTabCharCount(const JSize charCount);

	JBoolean	GetCRMRuleList(const CRMRuleList** ruleList) const;
	void		SetCRMRuleList(CRMRuleList* ruleList,
							   const JBoolean teOwnsRuleList);
	void		ClearCRMRuleList();

	JBoolean	AllowsDragAndDrop() const;
	void		ShouldAllowDragAndDrop(const JBoolean allow);

	static JBoolean	WillCopyWhenSelect();
	static void		ShouldCopyWhenSelect(const JBoolean copy);

	JCoordinate	TEGetMinPreferredGUIWidth() const;

	JColorIndex	GetCaretColor() const;
	void		SetCaretColor(const JColorIndex color);
	JColorIndex	GetSelectionColor() const;
	void		SetSelectionColor(const JColorIndex color);
	JColorIndex	GetSelectionOutlineColor() const;
	void		SetSelectionOutlineColor(const JColorIndex color);
	JColorIndex	GetDragColor() const;
	void		SetDragColor(const JColorIndex color);

	JBoolean	IndexValid(const JIndex charIndex) const;

protected:

#if defined __VCPP__ || defined __KCC
public:
#endif

	struct CaretLocation
	{
		JIndex charIndex;	// caret is in front of this character in the buffer
		JIndex lineIndex;	// caret is on this line of text

		CaretLocation()
			:
			charIndex(0),
			lineIndex(0)
		{ };

		CaretLocation(const JIndex ch, const JIndex line)
			:
			charIndex(ch),
			lineIndex(line)
		{ };
	};

	struct HTMLLexerState
	{
		JTextEditor*							te;
		Font									font;
		JString									fontName;
		JStack<JArray<Font>,Font>				fontStack;
		JPtrStack<JArray<JString*>,JString*>	fontNameStack;
		const Font								blankLineFont;

		HTMLListType								listType;
		JIndex										listIndex;
		JStack<JArray<HTMLListType>,HTMLListType>	listTypeStack;
		JStack<JArray<JIndex>,JIndex>				listIndexStack;

		JSize		indentCount;		// # of blockquote cmds
		JSize		newlineCount;		// number of trailing newlines
		JBoolean	appendWS;			// kTrue if need whitespace in front of next word
		JBoolean	inPreformatBlock;	// kTrue if inside <pre>
		JBoolean	inDocHeader;		// kTrue if inside <head>

		HTMLLexerState(JTextEditor* editor);

		void		PushCurrentFont();
		JBoolean	PopFont();
		void		UpdateFontID();
		Font		GetWSFont();

		void		NewList(const HTMLListType type);
		void		NewListItem();
		void		IndentForListItem(const Font& wsFont);
		JBoolean	EndList();

		void		ReportError(const JCharacter* errStr);
	};

	friend struct HTMLLexerState;

protected:

	JBoolean	TEIsActive() const;
	void		TEActivate();
	void		TEDeactivate();

	JBoolean	TESelectionIsActive() const;
	void		TEActivateSelection();
	void		TEDeactivateSelection();

	JBoolean	TECaretIsVisible() const;
	void		TEShowCaret();
	void		TEHideCaret();

	void	SetType(const Type type);
	void	ShouldPasteStyledText(const JBoolean pasteStyled);

	void				RecalcAll(const JBoolean needAdjustStyles);
	JArray<JBoolean>	GetCmdStatus(JString* crmActionText, JString* crm2ActionText,
									 JBoolean* isReadOnly) const;

	void		TEDraw(JPainter& p, const JRect& rect);

	JBoolean	TEWillDragAndDrop(const JPoint& pt, const JBoolean extendSelection,
								  const JBoolean dropCopy) const;
	void		TEHandleMouseDown(const JPoint& pt, const JSize clickCount,
								  const JBoolean extendSelection,
								  const JBoolean partialWord);
	void		TEHandleMouseDrag(const JPoint& pt);
	void		TEHandleMouseUp(const JBoolean dropCopy);
	JBoolean	TEHitSamePart(const JPoint& pt1, const JPoint& pt2) const;

	virtual void		TEDisplayBusyCursor() const = 0;

	virtual JBoolean	TEBeginDND() = 0;
	void				TEDNDFinished();
	void				TEHandleDNDEnter();
	void				TEHandleDNDHere(const JPoint& pt, const JBoolean dropOnSelf);
	void				TEHandleDNDLeave();
	void				TEHandleDNDDrop(const JPoint& pt, const JBoolean dropOnSelf,
										const JBoolean dropCopy);
	virtual void		TEPasteDropData() = 0;

	JBoolean	TEIsDragging() const;
	JBoolean	TEHandleKeyPress(const JCharacter key, const JBoolean selectText,
								 const CaretMotion motion);

	JCoordinate	TEGetBoundsWidth() const;
	void		TESetBoundsWidth(const JCoordinate width);

	JCoordinate	TEGetLeftMarginWidth() const;
	void		TESetLeftMarginWidth(const JCoordinate width);

	virtual void		TERefresh() = 0;
	virtual void		TERefreshRect(const JRect& rect) = 0;
	void				TERefreshLines(const JIndex first, const JIndex last);
	virtual void		TEUpdateDisplay() = 0;
	virtual void		TERedraw() = 0;
	virtual void		TESetGUIBounds(const JCoordinate w, const JCoordinate h,
									   const JCoordinate changeY) = 0;
	virtual JBoolean	TEScrollToRect(const JRect& rect,
									   const JBoolean centerInDisplay) = 0;
	virtual JBoolean	TEScrollForDrag(const JPoint& pt) = 0;
	virtual void		TESetVertScrollStep(const JCoordinate vStep) = 0;
	virtual void		TEClipboardChanged() = 0;
	virtual JBoolean	TEOwnsClipboard() const = 0;
	virtual JBoolean	TEGetExternalClipboard(JString* text, JRunArray<Font>* style) const = 0;
	virtual void		TECaretShouldBlink(const JBoolean blink) = 0;

	void				TEClearClipboard();
	void				TEClearDragClip();

	virtual JCoordinate	GetTabWidth(const JIndex charIndex, const JCoordinate x) const;

	virtual JCoordinate	GetPrintHeaderHeight(JPagePrinter& p) const;
	virtual JCoordinate	GetPrintFooterHeight(JPagePrinter& p) const;
	virtual void		DrawPrintHeader(JPagePrinter& p, const JCoordinate headerHeight);
	virtual void		DrawPrintFooter(JPagePrinter& p, const JCoordinate footerHeight);

	virtual void	CRMConvertTab(JString* charBuffer, JSize* charCount,
								  const JSize currentLineWidth) const;
	virtual JSize	CRMGetTabWidth(const JIndex textColumn) const;

	virtual void	AdjustStylesBeforeRecalc(const JString& buffer, JRunArray<Font>* styles,
											 JIndexRange* recalcRange, JIndexRange* redrawRange,
											 const JBoolean deletion);

	JBoolean	GetInternalClipboard(const JString** text,
									 const JRunArray<Font>** style = NULL) const;
	JBoolean	GetDragClip(const JString** text,
							const JRunArray<Font>** style = NULL) const;

	virtual JBoolean	IsCharacterInWord(const JString& text,
										  const JIndex charIndex) const;

	JBoolean		GetCaretLocation(CaretLocation* caretLoc) const;
	CaretLocation	CalcCaretLocation(const JPoint& pt) const;
	void			MoveCaretVert(const JInteger deltaLines);
	JBoolean		EndsWithNewline() const;

	Font		GetFont(const JIndex charIndex) const;
	void		SetFont(const JIndex startIndex,const JIndex endIndex,
						const Font& f, const JBoolean clearUndo);
	void		SetFont(const JIndex startIndex, const JRunArray<Font>& f,
						const JBoolean clearUndo);
	Font		GetCurrentFont() const;
	void		SetCurrentFont(const Font& f);
	const Font&	GetDefaultFont() const;
	void		SetDefaultFont(const Font& f);
	void		SetAllFontNameAndSize(const JCharacter* name, const JSize size,
									  const JCoordinate tabWidth,
									  const JBoolean breakCROnly,
									  const JBoolean clearUndo);

	static JBoolean	ReadPrivateFormat(istream& input, const JTextEditor* te,
									  JString* text, JRunArray<Font>* style);

	void		WritePrivateFormat(ostream& output, const JFileVersion vers,
								   const JIndex startIndex, const JIndex endIndex) const;
	void		WritePrivateFormat(ostream& output, const JFileVersion vers,
								   const JString& text, const JRunArray<Font>& style) const;
	JBoolean	WriteClipboardPrivateFormat(ostream& output, const JFileVersion vers) const;
	JBoolean	WriteDragClipPrivateFormat(ostream& output, const JFileVersion vers) const;

	static void	WritePrivateFormat(ostream& output, const JTextEditor* te,
								   const JFileVersion vers, const JString& text,
								   const JRunArray<Font>& style,
								   const JIndex startIndex, const JIndex endIndex);

	virtual void	PrepareToReadHTML();
	virtual void	ReadHTMLFinished();
	virtual void	HandleHTMLWord(const JCharacter* word, const JIndexRange& range);
	virtual void	HandleHTMLWhitespace(const JCharacter* space, const JIndexRange& range);
	virtual void	HandleHTMLTag(const JString& name, const JStringPtrMap<JString>& attr,
								  const JIndexRange& range);
	virtual void	HandleHTMLComment(const JIndexRange& range);
	virtual void	HandleHTMLError(const JHTMLScanner::HTMLError err, const JCharacter* errStr,
									const JIndexRange& range);

private:

	enum DragType
	{
		kInvalidDrag,
		kSelectDrag,
		kSelectPartialWordDrag,
		kSelectWordDrag,
		kSelectLineDrag,
		kDragAndDrop,
		kLocalDragAndDrop
	};

	enum UndoState
	{
		kIdle,
		kUndo,
		kRedo
	};

	enum CRMStatus
	{
		kFoundWord,
		kFoundNewLine,
		kFinished
	};

#if defined __VCPP__ || defined __KCC
public:
#endif

	struct LineGeometry
	{
		JCoordinate height;		// height of line
		JCoordinate ascent;		// offset to font baseline

		LineGeometry()
			:
			height(0),
			ascent(0)
		{ };

		LineGeometry(const JCoordinate aHeight, const JCoordinate anAscent)
			:
			height(aHeight),
			ascent(anAscent)
		{ };
	};

private:

	Type				itsType;
	JString*			itsBuffer;
	JRunArray<Font>*	itsStyles;
	JBoolean			itsActiveFlag;
	JBoolean			itsPasteStyledTextFlag;		// kTrue => paste styled text
	JBoolean			itsPerformDNDFlag;			// kTrue => drag-and-drop enabled
	JBoolean			itsAutoIndentFlag;			// kTrue => auto-indent after newline enabled
	JBoolean			itsMoveToFrontOfTextFlag;	// kTrue => left arrow w/ moveEOL puts caret after whitespace
	static JBoolean		itsCopyWhenSelectFlag;		// kTrue => SetSelection() calls Copy()

	const JFontManager*	itsFontMgr;
	Font				itsDefFont;

	JColormap*				itsColormap;			// not owned
	JArray<JColorIndex>*	itsCustomColors;		// can be NULL
	JColorIndex				itsCaretColor;
	JColorIndex				itsSelectionColor;
	JColorIndex				itsSelectionOutlineColor;
	JColorIndex				itsDragColor;

	JTEUndoBase*				itsUndo;			// can be NULL
	JPtrArray<JTEUndoBase>*		itsUndoList;		// NULL if not multiple undo
	JIndex						itsFirstRedoIndex;	// range [1:count+1]
	UndoState					itsUndoState;
	JSize						itsMaxUndoCount;	// maximum length of itsUndoList

	JCoordinate					itsWidth;			// pixels -- width of widest line
	JCoordinate					itsHeight;			// pixels
	JCoordinate					itsGUIWidth;		// pixels -- available width of widget aperture
	JCoordinate					itsLeftMarginWidth;	// pixels
	JCoordinate					itsDefTabWidth;		// pixels
	JCoordinate					itsMaxWordWidth;	// pixels -- widest single word; only if word wrap
	JArray<JIndex>*				itsLineStarts;		// index of first character on each line
	JRunArray<LineGeometry>*	itsLineGeom;		// geometry of each line

	// information for Recalc

	JBoolean	itsBreakCROnlyFlag;			// kFalse => break line at whitespace
	JSize		itsPrevBufLength;			// buffer length after last Recalc

	// used while active

	JBoolean		itsSelActiveFlag;		// kTrue => draw solid selection
	JBoolean		itsCaretVisibleFlag;	// kTrue => draw caret
	CaretLocation	itsCaretLoc;			// insertion point is -at- this character
	JCoordinate		itsCaretX;				// horizontal location used by MoveCaretVert()
	Font			itsInsertionFont;		// style for characters that user types
	JIndexRange		itsSelection;			// caret is visible if this is empty

	// clipboard

	JString*			itsClipText;		// can be NULL
	JRunArray<Font>*	itsClipStyle;		// can be NULL

	// Drag-And-Drop

	JString*			itsDragText;		// can be NULL
	JRunArray<Font>*	itsDragStyle;		// can be NULL

	// used during printing

	JBoolean	itsIsPrintingFlag;

	// used during drag

	DragType		itsDragType;
	DragType		itsPrevDragType;	// so extend selection will maintain drag type
	JPoint			itsStartPt;
	JPoint			itsPrevPt;
	JIndex			itsSelectionPivot;	// insertion point about which to pivot selection
	JIndexRange		itsWordSelPivot;	// range of characters to keep selected
	JIndex			itsLineSelPivot;	// line about which to pivot selection
	CaretLocation	itsDropLoc;			// insertion point at which to drop the dragged text
	JBoolean		itsIsDragSourceFlag;// kTrue => is dragging even if itsDragType == kInvalidDrag

	// information for CleanRightMargin()

	JSize	itsCRMLineWidth;
	JSize	itsCRMTabCharCount;

	CRMRuleList*	itsCRMRuleList;
	JBoolean		itsOwnsCRMRulesFlag;

	// used while reading HTML

	HTMLLexerState*	itsHTMLLexerState;	// NULL when not reading HTML

private:

	void		Recalc(const JIndex startChar, const JSize minCharCount,
					   const JBoolean deletion, const JBoolean needAdjustStyles = kTrue);
	void		Recalc(const CaretLocation caretLoc, const JSize minCharCount,
					   const JBoolean deletion, const JBoolean needAdjustStyles = kTrue);
	void		Recalc1(const JSize bufLength, const CaretLocation caretLoc,
						const JSize origMinCharCount, JCoordinate* maxLineWidth,
						JIndex* firstLineIndex, JIndex* lastLineIndex);
	JSize		RecalcLine(const JSize bufLength, const JIndex firstCharIndex,
						   const JIndex lineIndex, JCoordinate* lineWidth,
						   JIndex* runIndex, JIndex* firstInRun);
	JBoolean	LocateNextWhitespace(const JSize bufLength, JIndex* startIndex) const;
	JSize		GetSubwordForLine(const JSize bufLength, const JIndex lineIndex,
								  const JIndex startIndex, JCoordinate* lineWidth) const;
	JSize		IncludeWhitespaceOnLine(const JSize bufLength, const JIndex startIndex,
										JCoordinate* lineWidth, JBoolean* endOfLine,
										JIndex* runIndex, JIndex* firstInRun) const;
	JBoolean	NoPrevWhitespaceOnLine(const JCharacter* str, const CaretLocation startLoc) const;

	void	TEDrawText(JPainter& p, const JRect& rect);
	void	TEDrawLine(JPainter& p, const JCoordinate top, const LineGeometry geom,
					   const JIndex lineIndex, JIndex* runIndex, JIndex* firstInRun);
	void	TEDrawSelection(JPainter& p, const JRect& rect, const JIndex startVisLine,
							const JCoordinate startVisLineTop);
	void	TEDrawCaret(JPainter& p, const CaretLocation caretLoc);

	void	TEGetDoubleClickSelection(const CaretLocation caretLoc, const JBoolean partialWord,
									  const JBoolean dragging, JIndexRange* range);

	Font		CalcInsertionFont(const JIndex charIndex) const;
	void		DropSelection(const JIndex dropLoc, const JBoolean dropCopy);

	JBoolean			GetCurrentUndo(JTEUndoBase** undo) const;
	JBoolean			GetCurrentRedo(JTEUndoBase** redo) const;
	void				NewUndo(JTEUndoBase* undo);
	void				SameUndo(JTEUndoBase* undo);
	void				ReplaceUndo(JTEUndoBase* oldUndo, JTEUndoBase* newUndo);
	void				ClearOutdatedUndo();
	JTEUndoTyping*		GetTypingUndo(JBoolean* isNew);
	JTEUndoStyle*		GetStyleUndo(JBoolean* isNew);
	JTEUndoTabShift*	GetTabShiftUndo(const JIndex startLine, JBoolean* isNew);

	void	PrivatePaste(const JCharacter* text, const JRunArray<Font>* style);
	void	InsertText(const JIndex charIndex, const JCharacter* text,
					   const JRunArray<Font>* style = NULL);
	void	DeleteText(const JIndex startIndex, const JIndex endIndex);
	void	DeleteText(const JIndexRange& range);

	void	TECreateClipboard();
	void	TECreateDragClip();

	void			SetCaretLocation(const CaretLocation caretLoc);
	CaretLocation	CalcCaretLocation(const JIndex charIndex) const;
	JIndex			CalcLineIndex(const JCoordinate y, JCoordinate* lineTop) const;
	JBoolean		TEScrollTo(const CaretLocation caretLoc);
	JRect			CalcCaretRect(const CaretLocation caretLoc) const;
	void			TERefreshCaret(const CaretLocation caretLoc);

	JCoordinate	GetCharLeft(const CaretLocation charLoc) const;
	JCoordinate	GetCharRight(const CaretLocation charLoc) const;
	JCoordinate	GetCharWidth(const CaretLocation charLoc) const;
	JCoordinate	GetStringWidth(const JIndex startIndex, const JIndex endIndex) const;
	JCoordinate	GetStringWidth(const JIndex startIndex, const JIndex endIndex,
							   JIndex* runIndex, JIndex* firstInRun) const;

	void	PrivateSetBreakCROnly(const JBoolean breakCROnly);
	void	TEGUIWidthChanged();

	JCoordinate	GetEWNHeight() const;

	JBoolean	SetText1(const JRunArray<Font>* style);
	JRect		CalcLocalDNDRect(const JPoint& pt) const;

	void	AutoIndent(JTEUndoTyping* typingUndo);

	JBoolean	PrivateCleanRightMargin(const JBoolean coerce,
										JIndexRange* origTextRange,
										JString* newText, JRunArray<Font>* newStyles,
										JIndex* newCaretIndex) const;
	JBoolean	CRMGetRange(const JIndex caretChar, const JBoolean coerce,
							JIndexRange* range, JIndex* textStartIndex,
							JString* firstLinePrefix, JSize* firstPrefixLength,
							JString* restLinePrefix, JSize* restPrefixLength,
							JIndex* returnRuleIndex) const;
	JBoolean	CRMGetPrefix(JIndex* startChar, const JIndex endChar,
							 JString* linePrefix, JSize* prefixLength,
							 JIndex* ruleIndex) const;
	JIndexRange	CRMMatchPrefix(const JIndexRange& textRange, JIndex* ruleIndex) const;
	JBoolean	CRMLineMatchesRest(const JIndexRange& range) const;
	JSize		CRMCalcPrefixLength(JString* linePrefix) const;
	JString		CRMBuildRestPrefix(const JString& firstLinePrefix,
								   const JIndex ruleIndex, JSize* prefixLength) const;
	void		CRMTossLinePrefix(JIndex* charIndex, const JIndex endChar,
								  const JIndex ruleIndex) const;
	CRMStatus	CRMReadNextWord(JIndex* charIndex, const JIndex endIndex,
								JString* spaceBuffer, JSize* spaceCount,
								JString* wordBuffer, JRunArray<Font>* wordStyles,
								const JSize currentLineWidth,
								const JIndex origCaretIndex, JIndex* newCaretIndex,
								const JString& newText, const JBoolean requireSpace) const;
	int			CRMIsEOS(const JCharacter c) const;
	void		CRMAppendWord(JString* newText, JRunArray<Font>* newStyles,
							  JSize* currentLineWidth, JIndex* newCaretIndex,
							  const JString& spaceBuffer, const JSize spaceCount,
							  const JString& wordBuffer, const JRunArray<Font>& wordStyles,
							  const JString& linePrefix, const JSize prefixLength) const;

	JBoolean	LocateTab(const JIndex startIndex, const JIndex endIndex,
						  JIndex* tabIndex) const;

	void	HandleHTMLOnCmd(const JString& cmd, const JStringPtrMap<JString>& attr);
	void	HandleHTMLOffCmd(const JString& cmd, const JStringPtrMap<JString>& attr);
	void	SetFontForHTML(const JStringPtrMap<JString>& attr);

	void	AppendTextForHTML(const JString& text);
	void	AppendTextForHTML1(const JString& text);
	void 	AppendCharsForHTML(const JCharacter* text, const JTextEditor::Font& f);
	void 	AppendCharsForHTML(const JString& text, const JTextEditor::Font& f);
	void 	AppendNewlinesForHTML(const JSize count);

	Font	CalcWSFont(const Font& prevFont, const Font& nextFont) const;

	JColorIndex	ColorNameToColorIndex(const JCharacter* name) const;
	JColorIndex	RGBToColorIndex(const JRGB& color) const;

	// not allowed

	const JTextEditor& operator=(const JTextEditor& source);

public:

	// JBroadcaster messages

	static const JCharacter* kTypeChanged;
	static const JCharacter* kTextSet;
	static const JCharacter* kTextChanged;
	static const JCharacter* kCaretLineChanged;

	class TypeChanged : public JBroadcaster::Message
		{
		public:

			TypeChanged(const Type type)
				:
				JBroadcaster::Message(kTypeChanged),
				itsType(type)
				{ };

			Type
			GetNewType() const
			{
				return itsType;
			};

		private:

			Type	itsType;
		};

	class TextSet : public JBroadcaster::Message
		{
		public:

			TextSet()
				:
				JBroadcaster::Message(kTextSet)
				{ };
		};

	class TextChanged : public JBroadcaster::Message
		{
		public:

			TextChanged()
				:
				JBroadcaster::Message(kTextChanged)
				{ };
		};

	class CaretLineChanged : public JBroadcaster::Message
		{
		public:

			CaretLineChanged(const JIndex lineIndex)
				:
				JBroadcaster::Message(kCaretLineChanged),
				itsLineIndex(lineIndex)
				{ };

			JIndex
			GetLineIndex() const
			{
				return itsLineIndex;
			};

		private:

			JIndex itsLineIndex;
		};
};


/******************************************************************************
 GetType

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

inline JTextEditor::Type
JTextEditor::GetType()
	const
{
	return itsType;
}

/******************************************************************************
 IsReadOnly

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

inline JBoolean
JTextEditor::IsReadOnly()
	const
{
	return JConvertToBoolean( itsType != kFullEditor );
}

/******************************************************************************
 TEIsActive (protected)

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

inline JBoolean
JTextEditor::TEIsActive()
	const
{
	return itsActiveFlag;
}

/******************************************************************************
 TEActivate (protected)

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

inline void
JTextEditor::TEActivate()
{
	if (!itsActiveFlag)
		{
		itsActiveFlag = kTrue;
		TERefresh();
		}
}

/******************************************************************************
 TEDeactivate (protected)

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

inline void
JTextEditor::TEDeactivate()
{
	if (itsActiveFlag)
		{
		itsActiveFlag = kFalse;
		TERefresh();
		}
}

/******************************************************************************
 TESelectionIsActive (protected)

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

inline JBoolean
JTextEditor::TESelectionIsActive()
	const
{
	return itsSelActiveFlag;
}

/******************************************************************************
 TEActivateSelection (protected)

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

inline void
JTextEditor::TEActivateSelection()
{
	if (!itsSelActiveFlag)
		{
		itsSelActiveFlag = kTrue;
		TERefresh();
		}
}

/******************************************************************************
 TEDeactivateSelection (protected)

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

inline void
JTextEditor::TEDeactivateSelection()
{
	if (itsSelActiveFlag)
		{
		itsSelActiveFlag = kFalse;
		TERefresh();
		}
}

/******************************************************************************
 TECaretIsVisible (protected)

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

inline JBoolean
JTextEditor::TECaretIsVisible()
	const
{
	return itsCaretVisibleFlag;
}

/******************************************************************************
 TEShowCaret (protected)

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

inline void
JTextEditor::TEShowCaret()
{
	if (!itsCaretVisibleFlag)
		{
		itsCaretVisibleFlag = kTrue;
		TERefreshCaret(itsCaretLoc);
		}
}

/******************************************************************************
 TEHideCaret (protected)

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

inline void
JTextEditor::TEHideCaret()
{
	if (itsCaretVisibleFlag)
		{
		itsCaretVisibleFlag = kFalse;
		TERefreshCaret(itsCaretLoc);
		}
}

/******************************************************************************
 IsEmpty

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

inline JBoolean
JTextEditor::IsEmpty()
	const
{
	return itsBuffer->IsEmpty();
}

/******************************************************************************
 GetText

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

inline const JString&
JTextEditor::GetText()
	const
{
	return *itsBuffer;
}

/******************************************************************************
 GetTextLength

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

inline JSize
JTextEditor::GetTextLength()
	const
{
	return itsBuffer->GetLength();
}

/******************************************************************************
 IndexValid

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

inline JBoolean
JTextEditor::IndexValid
	(
	const JIndex charIndex
	)
	const
{
	return itsBuffer->IndexValid(charIndex);
}

/******************************************************************************
 GetStyles

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

inline const JRunArray<JTextEditor::Font>&
JTextEditor::GetStyles()
	const
{
	return *itsStyles;
}

/******************************************************************************
 Selection

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

inline JBoolean
JTextEditor::HasSelection()
	const
{
	return JNegate( itsSelection.IsEmpty() );
}

inline JBoolean
JTextEditor::GetSelection
	(
	JIndex* startIndex,
	JIndex* endIndex
	)
	const
{
	*startIndex = itsSelection.first;
	*endIndex   = itsSelection.last;
	return JNegate( itsSelection.IsEmpty() );
}

inline JBoolean
JTextEditor::GetSelection
	(
	JIndexRange* range
	)
	const
{
	*range = itsSelection;
	return JNegate( itsSelection.IsEmpty() );
}

inline void
JTextEditor::SetSelection
	(
	const JIndexRange& range
	)
{
	SetSelection(range.first, range.last);
}

/******************************************************************************
 Multiple undo

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

inline JBoolean
JTextEditor::IsUsingMultipleUndo()
	const
{
	return JConvertToBoolean( itsUndoList != NULL );
}

inline JSize
JTextEditor::GetUndoDepth()
	const
{
	return itsMaxUndoCount;
}

/******************************************************************************
 IsEntireWord

	Return kTrue if the given character range is a single, complete word.

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

inline JBoolean
JTextEditor::IsEntireWord
	(
	const JIndex startIndex,
	const JIndex endIndex
	)
	const
{
	return JConvertToBoolean(
			GetWordStart(endIndex) == startIndex &&
			GetWordEnd(startIndex) == endIndex );
}

inline JBoolean
JTextEditor::IsEntireWord
	(
	const JIndexRange& range
	)
	const
{
	return IsEntireWord(range.first, range.last);
}

/******************************************************************************
 TEGetFontManager

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

inline const JFontManager*
JTextEditor::TEGetFontManager()
	const
{
	return itsFontMgr;
}

/******************************************************************************
 TEGetColormap

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

inline JColormap*
JTextEditor::TEGetColormap()
	const
{
	return itsColormap;
}

/******************************************************************************
 Allow paste styled text

	ShouldPasteStyled() is protected because most derived classes won't
	be written to expect it to change.

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

inline JBoolean
JTextEditor::WillPasteStyledText()
	const
{
	return itsPasteStyledTextFlag;
}

// protected

inline void
JTextEditor::ShouldPasteStyledText
	(
	const JBoolean pasteStyled
	)
{
	itsPasteStyledTextFlag = pasteStyled;
}

/******************************************************************************
 Get default font

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

inline JSize
JTextEditor::GetDefaultFontSize()
	const
{
	return itsDefFont.size;
}

inline const JFontStyle&
JTextEditor::GetDefaultFontStyle()
	const
{
	return itsDefFont.style;
}

inline void
JTextEditor::GetDefaultFont
	(
	JFontID*	id,
	JSize*		size,
	JFontStyle*	style
	)
	const
{
	*id    = itsDefFont.id;
	*size  = itsDefFont.size;
	*style = itsDefFont.style;
}

// protected

inline const JTextEditor::Font&
JTextEditor::GetDefaultFont()
	const
{
	return itsDefFont;
}

/******************************************************************************
 Set default font

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

inline void
JTextEditor::SetDefaultFont
	(
	const JCharacter*	name,
	const JSize			size,
	const JFontStyle&	style
	)
{
	itsDefFont.size  = size;
	itsDefFont.style = style;
	SetDefaultFontName(name);	// last, so itsDefFont.id gets set correctly
}

// protected

inline void
JTextEditor::SetDefaultFont
	(
	const Font& f
	)
{
	SetDefaultFont(f.id, f.size, f.style);
}

/******************************************************************************
 Default tab width

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

inline JCoordinate
JTextEditor::GetDefaultTabWidth()
	const
{
	return itsDefTabWidth;
}

inline void
JTextEditor::SetDefaultTabWidth
	(
	const JCoordinate width
	)
{
	if (width != itsDefTabWidth)
		{
		itsDefTabWidth = width;
		RecalcAll(kFalse);
		}
}

/******************************************************************************
 Auto indenting

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

inline JBoolean
JTextEditor::WillAutoIndent()
	const
{
	return itsAutoIndentFlag;
}

inline void
JTextEditor::ShouldAutoIndent
	(
	const JBoolean doIt
	)
{
	itsAutoIndentFlag = doIt;
}

/******************************************************************************
 Move caret to front of text instead of front of line

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

inline JBoolean
JTextEditor::WillMoveToFrontOfText()
	const
{
	return itsMoveToFrontOfTextFlag;
}

inline void
JTextEditor::ShouldMoveToFrontOfText
	(
	const JBoolean doIt
	)
{
	itsMoveToFrontOfTextFlag = doIt;
}

/******************************************************************************
 Automatically copy when select text (static)

	This is primarily useful under the X Window System.  It is static
	because all text should work the same way.

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

inline JBoolean
JTextEditor::WillCopyWhenSelect()
{
	return itsCopyWhenSelectFlag;
}

inline void
JTextEditor::ShouldCopyWhenSelect
	(
	const JBoolean copy
	)
{
	itsCopyWhenSelectFlag = copy;
}

/******************************************************************************
 Drag-And-Drop

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

inline JBoolean
JTextEditor::AllowsDragAndDrop()
	const
{
	return itsPerformDNDFlag;
}

inline void
JTextEditor::ShouldAllowDragAndDrop
	(
	const JBoolean allow
	)
{
	itsPerformDNDFlag = allow;
}

/******************************************************************************
 CleanRightMargin() parameters

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

inline JSize
JTextEditor::GetCRMLineWidth()
	const
{
	return itsCRMLineWidth;
}

inline void
JTextEditor::SetCRMLineWidth
	(
	const JSize charCount
	)
{
	itsCRMLineWidth = charCount;
}

inline JSize
JTextEditor::GetCRMTabCharCount()
	const
{
	return itsCRMTabCharCount;
}

inline void
JTextEditor::SetCRMTabCharCount
	(
	const JSize charCount
	)
{
	itsCRMTabCharCount = charCount;
}

inline JBoolean
JTextEditor::GetCRMRuleList
	(
	const CRMRuleList** ruleList
	)
	const
{
	*ruleList = itsCRMRuleList;
	return JI2B( itsCRMRuleList != NULL );
}

/******************************************************************************
 TEGetBoundsWidth (protected)

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

inline JCoordinate
JTextEditor::TEGetBoundsWidth()
	const
{
	return itsWidth;
}

/******************************************************************************
 TEGetLeftMarginWidth (protected)

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

inline JCoordinate
JTextEditor::TEGetLeftMarginWidth()
	const
{
	return itsLeftMarginWidth;
}

/******************************************************************************
 WillBreakCROnly

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

inline JBoolean
JTextEditor::WillBreakCROnly()
	const
{
	return itsBreakCROnlyFlag;
}

/******************************************************************************
 GetLineCount

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

inline JSize
JTextEditor::GetLineCount()
	const
{
	return itsLineStarts->GetElementCount();
}

/******************************************************************************
 GetLineStart

	Returns the first character on the specified line.

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

inline JIndex
JTextEditor::GetLineStart
	(
	const JIndex lineIndex
	)
	const
{
	return itsLineStarts->GetElement(lineIndex);
}

/******************************************************************************
 GetLineLength

	Returns the length of the specified line.

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

inline JSize
JTextEditor::GetLineLength
	(
	const JIndex lineIndex
	)
	const
{
	return (GetLineEnd(lineIndex) - GetLineStart(lineIndex) + 1);
}

/******************************************************************************
 GetLineHeight

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

inline JSize
JTextEditor::GetLineHeight
	(
	const JIndex lineIndex
	)
	const
{
	return (itsLineGeom->GetElement(lineIndex)).height;
}

/******************************************************************************
 GetLineBottom

	Returns the bottom of the specified line.

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

inline JCoordinate
JTextEditor::GetLineBottom
	(
	const JIndex lineIndex
	)
	const
{
	return (GetLineTop(lineIndex) + GetLineHeight(lineIndex) - 1);
}

/******************************************************************************
 GetCharRight (private)

	Returns the ending x coordinate of the specified character.

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

inline JCoordinate
JTextEditor::GetCharRight
	(
	const CaretLocation charLoc
	)
	const
{
	return GetCharLeft(charLoc) + GetCharWidth(charLoc);
}

/******************************************************************************
 GetCaretLocation

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

inline JBoolean
JTextEditor::GetCaretLocation
	(
	JIndex* charIndex
	)
	const
{
	*charIndex = itsCaretLoc.charIndex;
	return itsSelection.IsEmpty();
}

// protected

inline JBoolean
JTextEditor::GetCaretLocation
	(
	CaretLocation* caretLoc
	)
	const
{
	*caretLoc = itsCaretLoc;
	return itsSelection.IsEmpty();
}

/******************************************************************************
 CalcCaretLocation (private)

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

inline JTextEditor::CaretLocation
JTextEditor::CalcCaretLocation
	(
	const JIndex charIndex
	)
	const
{
	return CaretLocation(charIndex, GetLineForChar(charIndex));
}

/******************************************************************************
 Recalc (private)

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

inline void
JTextEditor::Recalc
	(
	const JIndex	startChar,
	const JSize		minCharCount,
	const JBoolean	deletion,
	const JBoolean	needAdjustStyles
	)
{
	Recalc(CalcCaretLocation(startChar), minCharCount, deletion, needAdjustStyles);
}

/******************************************************************************
 Font access (protected)

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

inline JTextEditor::Font
JTextEditor::GetFont
	(
	const JIndex charIndex
	)
	const
{
	return itsStyles->GetElement(charIndex);
}

/******************************************************************************
 EndsWithNewline (protected)

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

inline JBoolean
JTextEditor::EndsWithNewline()
	const
{
	return JConvertToBoolean(
				!itsBuffer->IsEmpty() &&
				itsBuffer->GetLastCharacter() == '\n' );
}

/******************************************************************************
 ContainsIllegalChars (static)

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

inline JBoolean
JTextEditor::ContainsIllegalChars
	(
	const JString& text
	)
{
	return ContainsIllegalChars(text, text.GetLength());
}

/******************************************************************************
 Colors

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

inline JColorIndex
JTextEditor::GetCaretColor()
	const
{
	return itsCaretColor;
}

inline void
JTextEditor::SetCaretColor
	(
	const JColorIndex color
	)
{
	itsCaretColor = color;
	TERefreshCaret(itsCaretLoc);
}

inline JColorIndex
JTextEditor::GetSelectionColor()
	const
{
	return itsSelectionColor;
}

inline void
JTextEditor::SetSelectionColor
	(
	const JColorIndex color
	)
{
	itsSelectionColor = color;
	if (!itsSelection.IsEmpty())
		{
		TERefresh();
		}
}

inline JColorIndex
JTextEditor::GetSelectionOutlineColor()
	const
{
	return itsSelectionOutlineColor;
}

inline void
JTextEditor::SetSelectionOutlineColor
	(
	const JColorIndex color
	)
{
	itsSelectionOutlineColor = color;
	if (!itsSelection.IsEmpty())
		{
		TERefresh();
		}
}

inline JColorIndex
JTextEditor::GetDragColor()
	const
{
	return itsDragColor;
}

inline void
JTextEditor::SetDragColor
	(
	const JColorIndex color
	)
{
	itsDragColor = color;
}

/******************************************************************************
 Dragging (protected)

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

inline JBoolean
JTextEditor::TEIsDragging()
	const
{
	return JI2B( itsDragType != kInvalidDrag || itsIsDragSourceFlag );
}

inline void
JTextEditor::TEDNDFinished()
{
	itsIsDragSourceFlag = kFalse;
}

/******************************************************************************
 CaretLocation operators

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

inline int
operator==
	(
	const JTextEditor::CaretLocation& l1,
	const JTextEditor::CaretLocation& l2
	)
{
	return (l1.charIndex == l2.charIndex);
}

inline int
operator!=
	(
	const JTextEditor::CaretLocation& l1,
	const JTextEditor::CaretLocation& l2
	)
{
	return (l1.charIndex != l2.charIndex);
}

/******************************************************************************
 Font operators

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

inline int
operator==
	(
	const JTextEditor::Font& f1,
	const JTextEditor::Font& f2
	)
{
	return (f1.id == f2.id && f1.size == f2.size && f1.style == f2.style);
}

inline int
operator!=
	(
	const JTextEditor::Font& f1,
	const JTextEditor::Font& f2
	)
{
	return !(f1 == f2);
}

/******************************************************************************
 LineGeometry operators

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

inline int
operator==
	(
	const JTextEditor::LineGeometry& g1,
	const JTextEditor::LineGeometry& g2
	)
{
	return (g1.height == g2.height && g1.ascent == g2.ascent);
}

inline int
operator!=
	(
	const JTextEditor::LineGeometry& g1,
	const JTextEditor::LineGeometry& g2
	)
{
	return !(g1 == g2);
}

#endif
