private void transformSourceFile(SourceFile sourceFile) {
		SourcePathTransformer pathTransformer =
			UserDataPathTransformer.getPathTransformer(sourceFilesTableModel.getProgram());
		String existing = pathTransformer.getTransformedPath(sourceFile, true);
		GValuesMap valueMap = new GValuesMap();
		valueMap.defineFile(DESTINATION, new File(existing));
		valueMap.setValidator((map, status) -> {
			File targetFile = valueMap.getFile(DESTINATION);
			if (targetFile == null || !targetFile.exists()) {
				status.setStatusText("File does not exist", MessageType.ERROR);
				return false;
			}
			if (targetFile.isDirectory()) {
				status.setStatusText("Must specify a file", MessageType.ERROR);
				return false;
			}
			return true;
		});
		ValuesMapDialog mapDialog = new ValuesMapDialog("Enter File Tranform",
			"Transform for " + sourceFile.toString(), valueMap);
		tool.showDialog(mapDialog, this);
		GValuesMap results = mapDialog.getValues();
		if (results == null) {
			return;
		}

		try {
			String path = results.getFile(DESTINATION).getCanonicalPath();
			URI uri = new File(path).toURI().normalize();
			pathTransformer.addFileTransform(sourceFile, uri.getPath());
		}
		catch (IOException e) {
			Msg.showError(this, sourceFilesTable, "IOException getting canonical path",
				e.getMessage());
		}

		sourceFilesTableModel.refresh();
		transformsModel.reload();
	}
Sets isStale to {@code true} when {@code rec} has an event type relevant to the source
file table.  If the event type is {@link ProgramEvent#SOURCE_FILE_REMOVED}, any associated
file transform is also removed.

@param rec program change record
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/sourcefilestable/SourceFilesTableProvider.java