JString
JXPathInput::GetTextForChoosePath()
	const
{
	JString text = GetText();
	if (text.IsEmpty() && HasBasePath())
		{
		text = itsBasePath;
		}
	else if (!text.IsEmpty() && JIsRelativePath(text) && HasBasePath())
		{
		text = JCombinePathAndName(itsBasePath, text);
		}
	return text;
}
JString
JXFileInput::GetTextForChooseFile()
	const
{
	JString text = GetText();
	if (text.IsEmpty() && HasBasePath())
		{
		text = itsBasePath;
		JAppendDirSeparator(&text);
		}
	if (text.EndsWith(ACE_DIRECTORY_SEPARATOR_STR))
		{
		text.AppendCharacter('*');
		}
	if (!text.IsEmpty() && JIsRelativePath(text) && HasBasePath())
		{
		text = JCombinePathAndName(itsBasePath, text);
		}
	return text;
}
JBoolean
JXFileInput::InputValid()
{
	if (itsAllowInvalidFileFlag)
		{
		return kJTrue;
		}
	else if (!JXInputField::InputValid())
		{
		return kJFalse;
		}

	const JString& text = GetText();
	if (text.IsEmpty())
		{
		return JNegate(IsRequired());
		}

	JString fullName;
	const JCharacter* errID = NULL;
	if (JIsRelativePath(text) && !HasBasePath())
		{
		errID = kNoRelPathID;
		RecalcAll(kJTrue);
		}
	else if (!JConvertToAbsolutePath(text, itsBasePath, &fullName) ||
			 !JFileExists(fullName))
		{
		errID = kDoesNotExistID;
		}
	else if (itsRequireReadFlag && !JFileReadable(fullName))
		{
		errID = kUnreadableID;
		}
	else if (itsRequireWriteFlag && !JFileWritable(fullName))
		{
		errID = kUnwritableID;
		}
	else if (itsRequireExecFlag && !JFileExecutable(fullName))
		{
		errID = kCannotExecID;
		}

	if (JStringEmpty(errID))
		{
		return kJTrue;
		}
	else
		{
		(JGetUserNotification())->ReportError(JGetString(errID));
		return kJFalse;
		}
}
JBoolean
JXPathInput::GetPath
	(
	JString* path
	)
	const
{
	const JString& text = GetText();
	return JI2B(!text.IsEmpty() &&
				(JIsAbsolutePath(text) || HasBasePath()) &&
				JConvertToAbsolutePath(text, itsBasePath, path) &&
				JDirectoryExists(*path) &&
				JDirectoryReadable(*path) &&
				JCanEnterDirectory(*path) &&
				(!itsRequireWriteFlag || JDirectoryWritable(*path)));
}
JBoolean
JXFileInput::GetFile
	(
	JString* fullName
	)
	const
{
	const JString& text = GetText();
	return JI2B(!text.IsEmpty() &&
				(!JIsRelativePath(text) || HasBasePath()) &&
				JConvertToAbsolutePath(text, itsBasePath, fullName) &&
				JFileExists(*fullName) &&
				(!itsRequireReadFlag  || JFileReadable(*fullName)) &&
				(!itsRequireWriteFlag || JFileWritable(*fullName)) &&
				(!itsRequireExecFlag  || JFileExecutable(*fullName)));
}
void
JXPathInput::AdjustStylesBeforeRecalc
	(
	const JString&		buffer,
	JRunArray<Font>*	styles,
	JIndexRange*		recalcRange,
	JIndexRange*		redrawRange,
	const JBoolean		deletion
	)
{
	const JColormap* colormap = GetColormap();
	const JSize totalLength   = buffer.GetLength();

	JString fullPath = buffer;
	if ((JIsRelativePath(buffer) && !HasBasePath()) ||
		!JExpandHomeDirShortcut(buffer, &fullPath))
		{
		fullPath.Clear();
		}

	// Last clause because if JConvertToAbsolutePath() succeeds, we don't
	// want to further modify fullName.

	else if (JIsRelativePath(buffer) &&
			 !JConvertToAbsolutePath(buffer, itsBasePath, &fullPath))
		{
		if (HasBasePath())
			{
			fullPath = JCombinePathAndName(itsBasePath, buffer);
			}
		else
			{
			fullPath.Clear();
			}
		}

	JSize errLength;
	if (fullPath.IsEmpty())
		{
		errLength = totalLength;
		}
	else
		{
		const JString closestDir = JGetClosestDirectory(fullPath, itsRequireWriteFlag);
		if (fullPath.BeginsWith(closestDir))
			{
			errLength = fullPath.GetLength() - closestDir.GetLength();
			}
		else
			{
			errLength = totalLength;
			}
		}

	if (errLength > 0 && buffer.EndsWith(kThisDirSuffix))
		{
		errLength++;	// trailing . is trimmed
		}

	Font f = styles->GetFirstElement();

	styles->RemoveAll();
	if (errLength >= totalLength)
		{
		f.style.color = colormap->GetRedColor();
		styles->AppendElements(f, totalLength);
		}
	else
		{
		f.style.color = colormap->GetBlackColor();
		styles->AppendElements(f, totalLength - errLength);

		if (errLength > 0)
			{
			f.style.color = colormap->GetRedColor();
			styles->AppendElements(f, errLength);
			}
		}

	*redrawRange += JIndexRange(1, totalLength);
}
JBoolean
JXPathInput::InputValid()
{
	if (itsAllowInvalidPathFlag)
		{
		return kJTrue;
		}
	else if (!JXInputField::InputValid())
		{
		return kJFalse;
		}

	const JString& text = GetText();
	if (text.IsEmpty())		// paranoia -- JXInputField should have reported
		{
		return !IsRequired();
		}

	JString path;
	if (JIsRelativePath(text) && !HasBasePath())
		{
		(JGetUserNotification())->ReportError(JGetString(kNoRelPathID));
		RecalcAll(kJTrue);
		return kJFalse;
		}
	if (!JConvertToAbsolutePath(text, itsBasePath, &path))
		{
		(JGetUserNotification())->ReportError(JGetString(kInvalidPathID));
		RecalcAll(kJTrue);
		return kJFalse;
		}

	const JString currDir = JGetCurrentDirectory();
	const JError err      = JChangeDirectory(path);
	JChangeDirectory(currDir);

	if (err.OK())
		{
		if (!JDirectoryReadable(path))
			{
			(JGetUserNotification())->ReportError(JGetString(kUnreadableID));
			RecalcAll(kJTrue);
			return kJFalse;
			}
		else if (itsRequireWriteFlag && !JDirectoryWritable(path))
			{
			(JGetUserNotification())->ReportError(JGetString(kUnwritableID));
			RecalcAll(kJTrue);
			return kJFalse;
			}
		else
			{
			return kJTrue;
			}
		}

	const JCharacter* errID;
	if (err == kJAccessDenied)
		{
		errID = kAccessDeniedID;
		}
	else if (err == kJBadPath)
		{
		errID = kBadPathID;
		}
	else if (err == kJComponentNotDirectory)
		{
		errID = kCompNotDirID;
		}
	else
		{
		errID = kInvalidDirID;
		}

	(JGetUserNotification())->ReportError(JGetString(errID));
	RecalcAll(kJTrue);
	return kJFalse;
}