//	Zinc Application Framework - M_STR.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_ctype.hpp>
#include <z_string.hpp>
#include <z_cursor.hpp>
#include "m_str.hpp"
#include "m_win.hpp"

#include <limits.h>

#if defined(__linux__)
	// These are also used by formatted string.
	int LINUX_TILE_WIDTH = 16;
	int LINUX_TILE_HEIGHT = 4;
	char linuxTile[] = { 0x55, 0x55, 0xee, 0xee, 0x55, 0x55, 0xba, 0xbb };
#endif

// ----- MtfString widget definition ----------------------------------------

XmOffsetPtr MtfString::offsets;

XtActionsRec MtfString::action[] =
{
	{ "ZafMouse",			(XtActionProc)MtfWindowObject::mouse },
	{ "ZafCallDefault", (XtActionProc)call_default },
	{ "ZafDragDrop",	(XtActionProc)drag_drop },
	{ "ZafEnter",		(XtActionProc)enter },
	{ "ZafExtendAdjust",	  (XtActionProc)extend_adjust },
	{ "ZafExtendEnd",		  (XtActionProc)extend_end },
	{ "ZafExtendStart",	  (XtActionProc)extend_start },
	{ "ZafFocusIn",		(XtActionProc)focus_in },
	{ "ZafGrabFocus",		(XtActionProc)grab_focus },
	{ "ZafHelp", 		(XtActionProc)help },
	{ "ZafLeave",		(XtActionProc)leave }
};

char MtfString::translations[] =
	"<Key>osfActivate:		ZafCallDefault()\n\
	 <Key>osfSelect:		ZafCallDefault()\n\
	 ~s ~m ~a <Key>Return:	ZafCallDefault()\n\
	 ~c ~m ~a <Btn1Motion>:		ZafExtendAdjust()\n\
	 ~c ~m ~a <Btn1Up>:			ZafExtendEnd()\n\
	 ~c s ~m ~a <Btn1Down>:	ZafExtendStart()\n\
	 ~c ~s ~m ~a <Btn1Down>:	ZafGrabFocus()\n\
	 <Btn2Down>:			ZafDragDrop()\n\
	 <Btn3Down>:			ZafMouse()\n\
	 <Btn3Up>:				ZafMouse()\n\
	 <Btn3Motion>:			ZafMouse()\n\
	 <Enter>:				ZafEnter()\n\
	 <FocusIn>:				ZafFocusIn()\n\
	 <Key>F1:				ZafHelp()\n\
	 <Key>osfHelp:			ZafHelp()\n\
	 <Leave>:				ZafLeave()";

MtfStringClassRec MtfString::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmTextFieldClassRec,	// superclass
		"ZafString", 						// class_name
		sizeof(MtfStringPart), 			// widget_size (data part)
		MtfString::classInitialize,	// class_initialize
		0,									// class_part_initialize
		false,								// class inited
		0,									// initialize
		0,									// initialize_hook
		XtInheritRealize,					// realize
		action,								// actions
		XtNumber(action),					// num_actions
		0, 									// resources
		0, 									// num_resources
		NULLQUARK,							// xrm_class
		true,								// compress_motion
		XtExposeCompressMultiple,			// compress_exposure
		true,								// compress_enterleave
		false,								// visible_interest
		0, 									// destroy
		XtInheritResize,					// resize
		(XtExposeProc)expose,				// expose
		0,									// set_values
		0, 									// set_values_hook
		XtInheritSetValuesAlmost,			// set_values_almost
		0, 									// get_values_hook
		XtInheritAcceptFocus,				// accept_focus
		XtVersionDontCheck,					// version
		0, 									// callback_private
		XtInheritTranslations,				// tm_table
		XtInheritQueryGeometry, 			// query_geometry
		XtInheritDisplayAccelerator,		// display_accelerator
		0,									// extension
	},
	// --- XmPrimitiveClassPart ---
	{
		(XtWidgetProc)highlight,			// border_highlight
		(XtWidgetProc)unhighlight,			// border_unhighlight
		XtInheritTranslations,				// translations
		0,									// arm_and_activate
		0,									// syn_resources
		0,									// num_syn_resources
		0									// extension
	},
	// --- XmTextFieldClassPart ---
	{
		0									// extension
	},
	// --- MtfStringClassPart ---
	{
		0									// extension
	}
};

void MtfString::call_default(MtfString *mtfObject, XEvent *, String *, Cardinal *)
{
	// First, call the class, then call the root.
	ZafString *zafObject = GetZincObject(mtfObject);
	zafObject->Event(L_SELECT);
	if (DynamicPtrCast(zafObject->RootObject(), ZafWindow)->DefaultButton())
		zafObject->RootObject()->Event(L_SELECT);
}

void MtfString::changed(MtfString *, ZafString *object, XmTextVerifyCallbackStruct *)
{
	// Modify the object changed flag.
	object->SetChanged(true);
}

void MtfString::classInitialize()
{
	XmResolvePartOffsets((WidgetClass) &(MtfString::classRecord),
	 &(MtfString::offsets));
}

void MtfString::drag_drop(MtfString *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	ZafString *string = GetZincObject(mtfObject);
	if (!string->CopyDraggable() && !string->MoveDraggable() && !string->LinkDraggable())
	{
		XtCallActionProc((Widget)mtfObject, "copy-primary", xEvent, param, *nparams);
		ZafIChar *currentValue;
		// XmNvaluesWcs (Unicode) does not work on Sun OS 4 so use XmNvalue.
#if defined(ZAF_UNICODE) && !defined(_SUNOS4) 
		XtVaSetValues((Widget)mtfObject, XmNvalueWcs, &currentValue, NULL);
#else
		XtVaGetValues((Widget)mtfObject, XmNvalue, &currentValue, NULL);
#endif
		string->StringData()->SetText(currentValue);
		XtFree((char *)currentValue);
	}
	else
	{
		// Begin the drag/drop operation.
		ZafEventStruct event(S_BEGIN_DRAG, xEvent);
		string->Event(event);
	}
}

void MtfString::enter(MtfString *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Perform the motif enter and match with zinc.
	XtCallActionProc((Widget)mtfObject, "enter", xEvent, param, *nparams);
	ZafEventStruct event(N_MOUSE_ENTER, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfString::expose(MtfString *mtfObject, XEvent *xEvent, Region xRegion)
{
	// Draw the object.
	ZafEventStruct event(E_MOTIF, xEvent);
	XRectangle xRect;
	XClipBox(xRegion, &xRect);
  	event.region.Assign(xRect.x, xRect.y, xRect.width, xRect.height, ZAF_PIXEL);
	GetZincObject(mtfObject)->Draw(event, E_MOTIF);
}

void MtfString::extend_adjust(MtfString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;

  	XtCallActionProc((Widget)mtfObject, "extend-adjust", xEvent, params, *nparams);
}

void MtfString::extend_end(MtfString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;

	XtCallActionProc((Widget)mtfObject, "extend-end", xEvent, params, *nparams);
}

void MtfString::extend_start(MtfString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;

	XtCallActionProc((Widget)mtfObject, "extend-start", xEvent, params, *nparams);
}

void MtfString::focus_in(MtfString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	// Chain to the base class.
	XtCallActionProc((Widget)mtfObject, "focusIn", xEvent, params, *nparams);
	if (!mtfObject->primitive.have_traversal)
		return; // Object is not really getting the keyboard focus.

	// Reflect changes to Zinc.
	ZafString *zafObject = GetZincObject(mtfObject);
	zafObject->NotifyFocus(zafObject, true);
}

void MtfString::grab_focus(MtfString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;
	XtCallActionProc((Widget)mtfObject, "grab-focus", xEvent, params, *nparams);
}

void MtfString::highlight(MtfString *mtfObject)
{
	// Draw the button highlight.
	ZafString *zafObject = GetZincObject(mtfObject);
	ZafRegionStruct drawRegion = zafObject->BeginDraw();
	zafObject->DrawFocus(drawRegion, S_CURRENT);
	zafObject->EndDraw();
}

void MtfString::input_filter(MtfString *, ZafString *object, XmTextVerifyCallbackStruct *callback)
{
	// Set up the variables.
	int startOffset = (int)callback->startPos;
	int endOffset = (int)callback->endPos;
	char *mtfText = callback->text->ptr;
	int mtfLength = callback->text->length;
	ZafStringData *zncText = object->StringData();

	// If input_filter was called from OSSetText(), then the event will
	// be null and the motif and Zinc text are already up-to-date.
	if (!callback->event)
	{
		callback->doit = true;
		return;
	}

	// Insert/Delete the text.
	if (mtfLength <= endOffset - startOffset) // delete
	{
		int offset1 = endOffset;
		int offset2 = startOffset;
		while (zncText->Char(offset1))
			zncText->SetChar(offset2++, zncText->Char(offset1++));
		zncText->SetChar(offset2, '\0');
	}
	if (mtfLength) // insert
	{
		int offset1 = zncText->Length();
		int offset2 = offset1 + mtfLength;
		while (offset1 >= startOffset)
			zncText->SetChar(offset2--, zncText->Char(offset1--));
	}

	// Manipulate the anticipated input.
	for (int i = 0; i < mtfLength; i++)
	{
		// Copy to the zinc text.
		if (object->VariableName() && isspace(mtfText[i]))
			mtfText[i] = '_';
		zncText->SetChar(startOffset++, mtfText[i]);

		// Handle password, upper-, lower-, and variable-name case.
		if (object->Password())
			mtfText[i] = '*';
		else if (object->LowerCase() && isupper(mtfText[i]))
			mtfText[i] = tolower(mtfText[i]);
		else if (object->UpperCase() && islower(mtfText[i]))
			mtfText[i] = toupper(mtfText[i]);
	}

	// Update the status flags.
	callback->doit = true;
}

void MtfString::leave(MtfString *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Perform the motif enter and match with zinc.
	XtCallActionProc((Widget)mtfObject, "leave", xEvent, param, *nparams);
	ZafEventStruct event(N_MOUSE_LEAVE, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfString::unhighlight(MtfString *mtfObject)
{
	// Draw the button highlight.
	ZafString *zafObject = GetZincObject(mtfObject);
	ZafRegionStruct drawRegion = zafObject->BeginDraw();
	zafObject->DrawFocus(drawRegion, S_NON_CURRENT);
	zafObject->EndDraw();
}

// ----- ZafString ----------------------------------------------------------

int ZafString::CursorOffset(void) const
{
	// Reset the string position.
	XmTextPosition textPosition = 0;
	if (screenID)
		XtVaGetValues(screenID, XmNcursorPosition, &textPosition, 0);
	return ((int)textPosition);
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafString::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Check for draw errors.
	if (!screenID)
		return (S_ERROR);

	// Draw the text.
	if (SystemObject() && (hzJustify == ZAF_HZ_LEFT || Focus()))
	{
		// Defer drawing to the motif widget.
		(*xmTextFieldClassRec.core_class.expose)
			(screenID, event.osEvent.type ? (XEvent *)&event.osEvent : ZAF_NULLP(XEvent), (_XRegion *)event.data);
	}
	else
	{
		// Compute the actual draw region.
		ZafPaletteState state = PaletteState();
		ZafRegionStruct drawRegion = BeginDraw();

		// Draw the focus.
		DrawFocus(drawRegion, Focus() ? S_CURRENT : S_NON_CURRENT);

		// Draw the border.
		if (Bordered())
			DrawBorder(drawRegion, ccode);

		// Fill the background.
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, state));
		display->Rectangle(drawRegion, 0, true);

		// Convert, then draw the text.
		drawRegion.left += ZAF_TEXT_MARGIN_SIZE;
		drawRegion.right -= ZAF_TEXT_MARGIN_SIZE;
		if (Bordered() || SystemObject())
		{
			drawRegion.top += ZAF_TEXT_MARGIN_SIZE;
			drawRegion.bottom -= ZAF_TEXT_MARGIN_SIZE;
		}
		display->SetClipRegion(drawRegion);
		display->SetPalette(LogicalPalette(ZAF_PM_TEXT, state));

		ZafIChar *text = stringData->DynamicText();
		if (Password() || LowerCase() || UpperCase())
		{
			for (ZafIChar *temp = text; *temp; temp++)
				if (Password())
					*temp = '*';
				else if (LowerCase() && isupper(*temp))
					*temp = tolower(*temp);
				else if (UpperCase() && islower(*temp))
					*temp = toupper(*temp);
		}
		display->Text(drawRegion, text, -1, hzJustify, (zafRegion.Height() > display->cellHeight) ? ZAF_VT_TOP : ZAF_VT_CENTER);
		delete []text;

		// Restore the draw operation.
		EndDraw();
	}

	// Return the control code.
	return (ccode);
}
#endif

ZafEventType ZafString::Event(const ZafEventStruct &event)
{
	// Check for edit mode.
	ZafEventType ccode = event.type;
	if (editMode && event.InputType() == L_LOGICAL_EVENT)
		return (ZafWindowObject::Event(event));
	else if (event.InputType() == E_KEY)
		ccode = LogicalEvent(event);

	// Check for zinc events.
	switch (ccode)
	{
	case S_DEINITIALIZE:
		{
#if defined(__linux__)
		MtfString *mtfObject = MtfString::GetMotifWidget(screenID);
		if (SystemObject() && LinuxTileStipple((Widget)mtfObject))
		{
			XFreePixmap(XtDisplay(mtfObject), LinuxTileStipple((Widget)mtfObject));
			LinuxTileStipple((Widget)mtfObject) = 0;
		}
#endif
		ccode = ZafWindowObject::Event(event);
		}
		break;

	// ----- Action messages -----
	case S_CURRENT:
		// Check for special conditions.
		ccode = ZafWindowObject::Event(event);
		if (screenID && SystemObject())													
		{
			// If text was pasted to the string need to update the StringData.
			ZafIChar *currentValue;
#if defined(ZAF_UNICODE)
			XtVaGetValues((Widget)screenID, XmNvalueWcs, &currentValue, NULL);
#else
			XtVaGetValues((Widget)screenID, XmNvalue, &currentValue, NULL);
#endif
			StringData()->SetText(currentValue);
			XtFree((char *)currentValue);
		
			if (hzJustify != ZAF_HZ_LEFT)
				RedisplayData();
			if (AutoClear())
				XmTextSetSelection(screenID, 0, XmTextGetLastPosition(screenID), CurrentTime);
		}
		break;

	case S_NON_CURRENT:
		// Check for special conditions.
		ccode = ZafWindowObject::Event(event);
		if (screenID && SystemObject())
		{
			XmTextClearSelection(screenID, CurrentTime);
			if (hzJustify != ZAF_HZ_LEFT)
				RedisplayData();
		}
		break;

	case L_SELECT:
	case N_NON_CURRENT:
		{
		// Syncronize text buffers.
		ZafIChar *oldText = strdup(stringData->Text());
		OSGetText();

		// Set changed only if the text is really different.
		if (strcmp(oldText, stringData->Text()) != 0)
			SetChanged(true);
		delete []oldText;
		// Call the associated user function.
		ccode = ZafWindowObject::Event(event);

		// Update the field status.
		unanswered = (stringData->Length() == 0) ? true : false;
		invalid = (ccode == ZAF_ERROR_LEAVE_INVALID) ? true : false;
		}
		break;

	case L_CUT:
	case S_CUT:
		XmTextFieldCut(screenID, CurrentTime);
		break;

	case S_COPY:
		XmTextFieldCopy(screenID, CurrentTime);
		break;

	case S_PASTE:
		XmTextFieldPaste(screenID);
#		if defined(ZAF_UNICODE)
		stringData->SetText(XmTextFieldGetStringWcs(screenID));
#		else
		stringData->SetText(XmTextFieldGetString(screenID));
#		endif
		break;

	case S_COPY_DATA:
		{
		ZafWindowObject *object = event.windowObject;
		ZafString *string = DynamicPtrCast(object, ZafString);
		if (string)
			stringData->SetText(*string->StringData());
		}
		break;

	case S_SET_DATA:
		{
		ZafWindowObject *object = event.windowObject;
		if (object)
		{
			ZafString *string = DynamicPtrCast(object, ZafString);
			if (string)
				SetStringData(string->StringData());
		}
		else
			SetStringData(new ZafStringData(*stringData));
		}
		break;

	case S_UPDATE_OBJECT:
		OSSetText();
		break;

	case S_UPDATE_DATA:
		OSGetText();
		break;

	case S_VALID_CHECK:
		if (!Invalid())
			ccode = S_VALID;
		else if (AllowInvalid() && !newData)
			ccode = S_INVALID;
		else
			ccode = S_ERROR;
		break;

	case S_HOT_KEY:
		ccode = S_ERROR;
		break;

	// ----- Default or unknown messages -----
	default:
		ccode = ZafWindowObject::Event(event);
		break;
	}

	// Return the control code.
	return (ccode);
}

ZafError ZafString::SetCursorOffset(int offset)
{
	// Make sure the request is valid.
	if (!screenID)
		return (ZAF_ERROR_INVALID);

	// Reset the string position.
	XmTextPosition textPosition = (XmTextPosition)offset;
	XtVaSetValues(screenID, XmNcursorPosition, textPosition, 0);
	return (ZAF_ERROR_NONE);
}

bool ZafString::SetSelected(bool setSelected)
{
	// Defer to the base class.
	return (ZafWindowObject::SetSelected(setSelected));
}

// ----- OS Specific Functions ----------------------------------------------

ZafEventType ZafString::OSEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

ZafError ZafString::OSGetText(void)
{
	// Contents are always up-to-date because of input_filter,
	// but notification needs to be sent to the other objects.
	if (stringData->NotifyCount() > 1)
		stringData->UpdateObjects(ZAF_NULLP(ZafNotifyObject));
	return (ZAF_ERROR_NONE);
}

void ZafString::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Check for a non-system object.
	if (!screenID)
		return;
	else if (!SystemObject())
	{
		parent->OSMapPalette(palette, type, state);
		return;
	}

	// Determine the proper palette.
	XGCValues values;
	XtGCMask mask = GCForeground | GCBackground | GCFillStyle;
	MtfString *mtfObject = MtfString::GetMotifWidget(screenID);
  	if (type == ZAF_PM_TEXT || type == ZAF_PM_HOT_KEY)
 	{
 		// Get the font the object is using.
 		mask |= GCFont;
 		XmFontList fontList = 0;
 		XtVaGetValues(screenID, "fontList", &fontList, 0);
 		XFontStruct *font = ((ZafScreenDisplay *)Display())->MtfGetFont(fontList);
 		values.font = font->fid;

 	   values.foreground = mtfObject->primitive.foreground;
    	values.background = mtfObject->core.background_pixel;
 		if (state & ZAF_PM_DISABLED)
 		{
 			mask |= GCTile;
 			values.fill_style = FillTiled;
#if defined(__linux__)
 			// The liniux tile_stipple pixmap is created with the depth of one so
 			// it we need to create on of the correct depth.
 			if (!LinuxTileStipple((Widget)mtfObject))
 				LinuxTileStipple((Widget)mtfObject) = XCreatePixmapFromBitmapData(XtDisplay(screenID),
 				 XtWindow(screenID), linuxTile, LINUX_TILE_WIDTH, LINUX_TILE_HEIGHT, 
 				 values.foreground, values.background, mtfObject->core.depth);
 			values.tile = LinuxTileStipple((Widget)mtfObject);
#else
			values.tile = mtfObject->text.stipple_tile;
#endif	
 		}
 		else
 			values.fill_style = FillSolid;
 		palette.osPalette = XtGetGC(screenID, mask, &values);
 	}
 	else if (type == ZAF_PM_BACKGROUND)
 	{
 	   values.foreground = mtfObject->core.background_pixel;
     	values.background = mtfObject->primitive.foreground;
 		values.fill_style = FillSolid;
 		palette.osPalette = XtGetGC(screenID, mask, &values);
 	}
 	else
 		ZafWindowObject::OSMapPalette(palette, type, state);
}

void ZafString::OSRegisterObject(void)
{
	// Create the motif widget.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	
	// Find what the text margin should be.
	Display()->SetFont(Font());
	ZafRegionStruct textHeight = Display()->TextSize(ZAF_ITEXT("Ky"));
	int margin = (zafRegion.Height() - textHeight.Height()) / 2;
	if (Bordered())
		margin -= 2 * ZAF_BORDER_SIZE;
	if (margin > ZAF_TEXT_MARGIN_SIZE)
		margin = ZAF_TEXT_MARGIN_SIZE;

	screenID = parent->OSScreenID(ZAF_CLIENTID);
	screenID = XtVaCreateWidget(name,
		(WidgetClass)&MtfString::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNsensitive, Disabled(false) ? false : true,
		XmNtraversalOn, Noncurrent() ? false : true,
		XmNshadowThickness, Bordered() ? ZAF_BORDER_SIZE : 0,
		XmNeditable, (ViewOnly() || Disabled(false) || 
		 Noncurrent()) ? false : true,
		XmNcursorPositionVisible, (ViewOnly() || Disabled(false) || Noncurrent()) ? false : true,
		XmNblinkRate, ZafCursor::BlinkRate(),
		XmNmarginHeight, margin < 0 ? 0 : margin,
		0);
	OSSetText();

	// Override translations.
	XtTranslations translationTable = XtParseTranslationTable(MtfString::translations);
	XtOverrideTranslations(screenID, translationTable);

	// special callbacks
	XtAddCallback(screenID, XmNactivateCallback, 
		(XtCallbackProc)MtfString::activate, (XtPointer)this);
	XtAddCallback(screenID, XmNvalueChangedCallback, 
		(XtCallbackProc)MtfString::changed, (XtPointer)this);
	XtAddCallback(screenID, XmNmodifyVerifyCallback, 
		(XtCallbackProc)MtfString::input_filter, (XtPointer)this);

#if defined(__linux__)
	MtfString *mtfObject = MtfString::GetMotifWidget(screenID);
	LinuxTileStipple((Widget)mtfObject) = 0;
#endif

	// Add edit mode overrides.
	ZafEditModeRegister(this);

	// Add drag/drop capabilities.
	ZafDropSiteRegister(this);
}

ZafError ZafString::OSSetText(void)
{
	// Set the os text.
	if (screenID && SystemObject())
	{
		// Reset the OS information.
		int maxLength = stringData->MaxLength();
		// If maxLength is -1 set it to the largest int. (Default value on Motif)
		if (maxLength < 0)
			maxLength = INT_MAX;
		if (VariableName())
		{
			for (int i = stringData->Length() - 1; i >= 0; i--)
				if (isspace(stringData->Char(i)))
					stringData->SetChar(i, '_');
		}
		if (LowerCase())
		{
			for (int i = stringData->Length() - 1; i >= 0; i--)
				if (isupper(stringData->Char(i)))
					stringData->SetChar(i, tolower(stringData->Char(i)));
		}
		if (UpperCase())
		{
			for (int i = stringData->Length() - 1; i >= 0; i--)
				if (islower(stringData->Char(i)))
					stringData->SetChar(i, toupper(stringData->Char(i)));
		}

#		if defined(ZAF_UNICODE)
		// Handle password.
		wchar_t *osText = stringData->DynamicOSWText();
		if (Password())
		{
			for (wchar_t *temp = osText; *temp; temp++)
				*temp = '*';
		}
		XtVaSetValues(screenID,
			XmNmaxLength, maxLength,
			XmNvalueWcs, osText,
			0);
		delete []osText;
#		else
		char *osText = stringData->DynamicOSText();
		if (Password())
		{
			for (char *temp = osText; *temp; temp++)
				*temp = '*';
		}
		XtVaSetValues(screenID,
			XmNmaxLength, maxLength,
			XmNvalue, osText,
			0);
		delete []osText;
#		endif

		// We must explicitly re-draw the text since setting the text
		// does not automatically call expose().
		if (hzJustify != ZAF_HZ_LEFT)
			RedisplayData();
	}
	else if (screenID && AutomaticUpdate())
		ZafWindowObject::Event(S_REDISPLAY_DATA);

	return (ZAF_ERROR_NONE);
}

void ZafString::OSSize(void)
{
	// Defer to the base class.
	ZafWindowObject::OSSize();
}

ZafError ZafString::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
// Default to the base class.
	return (ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes));
}

